var optSpecs = [];
var nashi = {opts: []}, inputMinSize = 300, fullWidthExpansion = false;
var shortcutKeys = {};
function extract_num(q) {
return parseInt(q.attr('id'), 10);
}
function parent_post($el) {
return $el.closest('article, section');
}
function parent_model($el) {
var $a = parent_post($el);
var op = extract_num($a);
if (!op)
return null;
if ($a.is('section'))
return Threads.get(op);
var $s = $a.parent('section');
if (!$s.length) {
// when we have better hover/inline expansion we will have to
// deal with this, probably by setting data-op on the post
console.warn($a, "'s parent is not thread?!");
return null;
}
var num = op;
op = extract_num($s);
return Threads.lookup(num, op);
}
(function () {
/* OPTIONS LIST */
optSpecs.push(option_inline_expansion);
if (window.devicePixelRatio > 1)
optSpecs.push(option_high_res);
optSpecs.push(option_thumbs);
optSpecs.push(option_autocomplete);
optSpecs.push(option_backlinks);
optSpecs.push(option_reply_at_right);
optSpecs.push(option_theme);
optSpecs.push(option_last_n);
_.defaults(options, {
lastn: config.THREAD_LAST_N,
inlinefit: 'width',
});
options = new Backbone.Model(options);
nashi.upload = !!$('').prop('disabled');
if (window.screen && screen.width <= 480) {
inputMinSize = 50;
fullWidthExpansion = true;
}
function load_ident() {
try {
var id = JSON.parse(localStorage.ident);
if (id.name)
$name.val(id.name);
if (id.email)
$email.val(id.email);
}
catch (e) {}
}
function save_ident() {
try {
var name = $name.val(), email = $email.val();
if (email == 'misaki') {
$email.val('');
$.getScript(mediaURL + 'js/login.js');
email = false;
}
else if (is_sage(email) && !is_noko(email))
email = false;
var id = {};
if (name || email) {
if (name)
id.name = name;
if (email)
id.email = email;
localStorage.setItem('ident', JSON.stringify(id));
}
else
localStorage.removeItem('ident');
}
catch (e) {}
}
options.on('change', function () {
try {
localStorage.options = JSON.stringify(options);
}
catch (e) {}
});
/* LAST N CONFIG */
function option_last_n(n) {
if (!reasonable_last_n(n))
return;
$.cookie('lastn', n);
// should really load/hide posts as appropriate
}
option_last_n.id = 'lastn';
option_last_n.label = '[Last #]';
option_last_n.type = 'positive';
oneeSama.lastN = options.get('lastn');
options.on('change:lastn', function (model, lastN) {
oneeSama.lastN = lastN;
});
/* THEMES */
var themes = [
'moe',
'gar',
'mawaru',
'moon',
'ashita',
'console',
'tea',
'higan',
'homu',
'me',
'yakui',
];
function option_theme(theme) {
if (theme) {
var css = theme + '.css?v=' + themeVersion;
$('#theme').attr('href', mediaURL + 'css/' + css);
}
}
option_theme.id = 'board.$BOARD.theme';
option_theme.label = 'Theme';
option_theme.type = themes;
/* THUMBNAIL OPTIONS */
var revealSetup = false;
function option_thumbs(type) {
$.cookie('thumb', type);
// really ought to apply the style immediately
// need pinky/mid distinction in the model to do properly
oneeSama.thumbStyle = type;
var hide = type == 'hide';
if (hide)
$('img').hide();
else
$('img').show();
if (hide && !revealSetup)
$DOC.on('click', 'article', reveal_thumbnail);
else if (!hide && revealSetup)
$DOC.off('click', 'article', reveal_thumbnail);
revealSetup = hide;
}
option_thumbs.id = 'board.$BOARD.thumbs';
option_thumbs.label = 'Thumbnails';
option_thumbs.type = thumbStyles;
/* Alt-click a post to reveal its thumbnail if hidden */
function reveal_thumbnail(event) {
if (!event.altKey)
return;
var $article = $(event.target);
var $img = $article.find('img');
if ($img.length) {
with_dom(function () { $img.show(); });
return false;
}
/* look up the image info and make the thumbnail */
var thread = Threads.get(extract_num($article.closest('section')));
if (!thread)
return;
var post = thread.get('replies').get(extract_num($article));
if (!post)
return;
var info = post.get('image');
if (!info)
return;
with_dom(function () {
var img = oneeSama.gazou_img(info, false);
var $img = $.parseHTML(flatten(img.html).join(''));
$article.find('figcaption').after($img);
});
return false;
}
/* REPLY AT RIGHT */
function option_reply_at_right(r) {
if (r)
$('', {
id: 'reply-at-right',
text: 'aside { margin: -26px 0 2px auto; }',
}).appendTo('head');
else
$('#reply-at-right').remove();
}
option_reply_at_right.id = 'replyright';
option_reply_at_right.label = '[Reply] at right';
option_reply_at_right.type = 'checkbox';
/* AUTOCOMPLETE */
function option_autocomplete(b) {
if (postForm)
postForm.model.set('autocomplete', b);
}
option_autocomplete.id = 'autocomplete';
option_autocomplete.label = 'Auto-complete';
option_autocomplete.type = 'checkbox';
/* BACKLINKS */
function option_backlinks(b) {
if (b)
$('small').remove();
else
show_backlinks();
}
option_backlinks.id = 'nobacklinks';
option_backlinks.label = 'Backlinks';
option_backlinks.type = 'revcheckbox';
function show_backlinks() {
if (load_thread_backlinks) {
with_dom(function () {
$('section').each(function () {
load_thread_backlinks($(this));
});
});
load_thread_backlinks = null;
return;
}
Threads.each(function (thread) {
thread.get('replies').each(function (reply) {
if (reply.has('backlinks'))
reply.trigger('change:backlinks');
});
});
}
var load_thread_backlinks = function ($section) {
var op = extract_num($section);
var replies = Threads.get(op).get('replies');
$section.find('blockquote a').each(function () {
var $a = $(this);
var m = $a.attr('href').match(/^\d*#(\d+)$/);
if (!m)
return;
var destId = parseInt(m[1], 10);
if (!replies.get(destId)) // local backlinks only for now
return;
var src = replies.get(extract_num(parent_post($a)));
if (!src)
return;
var update = {};
update[destId] = op;
add_post_links(src, update, op);
});
};
/* INLINE EXPANSION */
function option_inline_expansion() {
/* TODO: do it live */
}
option_inline_expansion.id = 'inlinefit';
option_inline_expansion.label = 'Expansion';
option_inline_expansion.type = ['none', 'full', 'width', 'height', 'both'];
option_inline_expansion.labels = ['no', 'full-size', 'fit to width',
'fit to height', 'fit to both'];
function option_high_res() {
}
option_high_res.id = 'nohighres';
option_high_res.label = 'High-res expansions';
option_high_res.type = 'revcheckbox';
$DOC.on('mouseup', 'img, video', function (event) {
/* Bypass expansion for non-left mouse clicks */
if (options.get('inlinefit') != 'none' && event.which > 1) {
var img = $(this);
img.data('skipExpand', true);
setTimeout(function () {
img.removeData('skipExpand');
}, 100);
}
});
$DOC.on('click', 'img, video', function (event) {
if (options.get('inlinefit') != 'none') {
var $target = $(this);
if (!$target.data('skipExpand'))
toggle_expansion($target, event);
}
});
function toggle_expansion(img, event) {
var href = img.parent().attr('href');
if (/^\.\.\/outbound\//.test(href))
return;
if (event.metaKey)
return;
event.preventDefault();
var expand = !img.data('thumbSrc');
img.closest('article').toggleClass('expanded', expand);
var $imgs = img;
if (THREAD && (event.altKey || event.shiftKey)) {
var post = img.closest('article');
if (post.length)
$imgs = post.nextAll(':has(img):lt(4)').andSelf();
else
$imgs = img.closest('section').children(
':has(img):lt(5)');
$imgs = $imgs.find('img');
}
with_dom(function () {
$imgs.each(function () {
var $img = $(this);
if (expand)
expand_image($img);
else {
contract_image($img, event);
event = null; // de-zoom to first image only
}
});
});
}
function contract_image($img, event) {
var thumb = $img.data('thumbSrc');
if (!thumb)
return;
// try to keep the thumbnail in-window for large images
var h = $img.height();
var th = parseInt($img.data('thumbHeight'), 10);
if (event) {
var y = $img.offset().top, t = $(window).scrollTop();
if (y < t && th < h)
window.scrollBy(0, Math.max(th - h,
y - t - event.clientY + th/2));
}
if (fullWidthExpansion)
contract_full_width(parent_post($img));
$img.replaceWith($('')
.width($img.data('thumbWidth')).height(th)
.attr('src', thumb));
}
function expand_image($img) {
if ($img.data('thumbSrc'))
return;
var a = $img.parent();
var href = a.attr('href');
if (!href)
return;
var cap = a.siblings('figcaption').text();
var dims = cap.match(/(\d+)x(\d+)/);
var video = /^Video/.test(cap);
if (!dims)
return;
var tw = $img.width(), th = $img.height();
var w = parseInt(dims[1], 10), h = parseInt(dims[2], 10);
// if this is a high-density screen, reduce image size appropriately
var r = window.devicePixelRatio;
if (!options.get('nohighres') && !video && r && r > 1) {
var min = 1000;
if ((w > min || h > min) && w/r > tw && h/r > th) {
w /= r;
h /= r;
}
}
$img.remove();
$img = $(video ? '