summaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
Diffstat (limited to 'js')
-rw-r--r--js/auto-scroll.js27
-rw-r--r--js/catalog-search.js15
-rw-r--r--js/catalog.js35
-rw-r--r--js/comment-toolbar.js383
-rw-r--r--js/expand-all-images.js14
-rw-r--r--js/expand-too-long.js2
-rw-r--r--js/favorites.js2
-rw-r--r--js/file-selector.js3
-rw-r--r--js/fix-report-delete-submit.js67
-rw-r--r--js/forced-anon.js72
-rw-r--r--js/hide-images.js2
-rw-r--r--js/hide-threads.js2
-rw-r--r--js/id_colors.js16
-rw-r--r--js/image-hover.js1
-rw-r--r--js/infinite-scroll.js89
-rw-r--r--js/inline-expanding.js204
-rw-r--r--js/inline.js8
-rw-r--r--js/jquery.mixitup.min.js106
-rw-r--r--js/local-time.js80
-rw-r--r--js/no-animated-gif.js23
-rw-r--r--js/options/fav.js72
-rw-r--r--js/options/user-css.js2
-rw-r--r--js/options/user-js.js2
-rw-r--r--js/post-filter.js852
-rw-r--r--js/post-hover.js5
-rw-r--r--js/post-menu.js211
-rw-r--r--js/quick-reply.js2
-rw-r--r--js/show-own-posts.js2
-rw-r--r--js/thread-watcher.js42
-rw-r--r--js/toggle-images.js2
30 files changed, 2117 insertions, 226 deletions
diff --git a/js/auto-scroll.js b/js/auto-scroll.js
new file mode 100644
index 00000000..b8343f5e
--- /dev/null
+++ b/js/auto-scroll.js
@@ -0,0 +1,27 @@
+$('document').ready(function () {
+ var autoScroll = localStorage['autoScroll'] ? true : false;
+ if (window.Options && Options.get_tab('general')){
+ Options.extend_tab('general','<label id=\'autoScroll\'><input type=\'checkbox\' />' + ' Scroll to new posts' + '</label>');
+ $('#autoScroll').find('input').prop('checked', autoScroll);
+ }
+ $('#autoScroll').on('change', function() {
+ if(autoScroll) {
+ delete localStorage.autoScroll;
+ } else {
+ localStorage.autoScroll = true;
+ }
+ autoScroll =! autoScroll
+ if(active_page == 'thread')
+ $('input.auto-scroll').prop('checked', autoScroll);
+ });
+ if (active_page == 'thread') {
+ $('span[id="updater"]').children('a').after(' (<input class="auto-scroll" type="checkbox"></input> Scroll to New posts)');
+ $('input.auto-scroll').prop('checked', autoScroll);
+ $(document).on('new_post', function (e, post) {
+ if ($('input.auto-scroll').prop('checked'))
+ {
+ scrollTo(0, $(post).offset().top - window.innerHeight + $(post).outerHeight(true));
+ }
+ });
+ }
+});
diff --git a/js/catalog-search.js b/js/catalog-search.js
index b3c9c49e..fc39b1ce 100644
--- a/js/catalog-search.js
+++ b/js/catalog-search.js
@@ -17,6 +17,21 @@ var catalogSearch = function() {
$threads = $('.threads .thread'),
$searchLabel = $('<label for="catalog_search">Search: </label>'),
$searchBox = $('<input id="catalog_search" type="text" placeholder="Search" />');
+ function searchToggle() {
+ var button = $('#catalog_search_button');
+
+ if (!button.data('expanded')) {
+ button.data('expanded', '1');
+ button.text('Close');
+ $('.catalog_search').append(' <input id="search_field" style="border: inset 1px;">');
+ $('#search_field').focus();
+ } else {
+ button.removeData('expanded');
+ button.text('Search');
+ $('.catalog_search').children().last().remove();
+ $('div[id="Grid"]>.mix').each(function () { $(this).css('display', 'inline-block'); });
+ }
+ }
$controls.append($searchLabel)
.append($searchBox);
diff --git a/js/catalog.js b/js/catalog.js
index f64e22d4..9adaeaef 100644
--- a/js/catalog.js
+++ b/js/catalog.js
@@ -1,8 +1,16 @@
if (active_page == 'catalog') $(function(){
+ if (localStorage.catalog !== undefined) {
+ var catalog = JSON.parse(localStorage.catalog);
+ } else {
+ var catalog = {};
+ localStorage.catalog = JSON.stringify(catalog);
+ }
$("#sort_by").change(function(){
var value = this.value;
- $("#sort-"+value).trigger("click");
+ $('#Grid').mixItUp('sort', (value == "random" ? value : "sticky:desc " + value));
+ catalog.sort_by = value;
+ localStorage.catalog = JSON.stringify(catalog);
});
$("#image_size").change(function(){
@@ -11,7 +19,30 @@ if (active_page == 'catalog') $(function(){
$(".grid-li").removeClass("grid-size-small");
$(".grid-li").removeClass("grid-size-large");
$(".grid-li").addClass("grid-size-"+value);
+ catalog.image_size = value;
+ localStorage.catalog = JSON.stringify(catalog);
});
- $('#Grid').mixitup({});
+ $('#Grid').mixItUp({
+ animation: {
+ enable: false
+ }
+ });
+
+ if (catalog.sort_by !== undefined) {
+ $('#sort_by').val(catalog.sort_by).trigger('change');
+ }
+ if (catalog.image_size !== undefined) {
+ $('#image_size').val(catalog.image_size).trigger('change');
+ }
+
+ $('div.thread').on('click', function(e) {
+ if ($(this).css('overflow-y') === 'hidden') {
+ $(this).css('overflow-y', 'auto');
+ $(this).css('width', '100%');
+ } else {
+ $(this).css('overflow-y', 'hidden');
+ $(this).css('width', 'auto');
+ }
+ });
});
diff --git a/js/comment-toolbar.js b/js/comment-toolbar.js
new file mode 100644
index 00000000..51aa9808
--- /dev/null
+++ b/js/comment-toolbar.js
@@ -0,0 +1,383 @@
+/*
+ * comment-toolbar.js
+ * - Adds a toolbar above the commenting area containing most of 8Chan's formatting options
+ * - Press Esc to close quick-reply window when it's in focus
+ *
+ * Usage:
+ * $config['additional_javascript'][] = 'js/jquery.min.js';
+ * $config['additional_javascript'][] = 'js/comment-toolbar.js';
+ */
+if (active_page == 'thread' || active_page == 'index') {
+ var formatText = (function($){
+ "use strict";
+ var self = {};
+ self.rules = {
+ spoiler: {
+ text: _('Spoiler'),
+ key: 's',
+ multiline: false,
+ exclusiveline: false,
+ prefix:'**',
+ suffix:'**'
+ },
+ italics: {
+ text: _('Italics'),
+ key: 'i',
+ multiline: false,
+ exclusiveline: false,
+ prefix: "''",
+ suffix: "''"
+ },
+ bold: {
+ text: _('Bold'),
+ key: 'b',
+ multiline: false,
+ exclusiveline: false,
+ prefix: "'''",
+ suffix: "'''"
+ },
+ underline: {
+ text: _('Underline'),
+ key: 'u',
+ multiline: false,
+ exclusiveline: false,
+ prefix:'__',
+ suffix:'__'
+ },
+ code: {
+ text: _('Code'),
+ key: 'f',
+ multiline: true,
+ exclusiveline: false,
+ prefix: '[code]',
+ suffix: '[/code]'
+ },
+ strike: {
+ text: _('Strike'),
+ key: 'd',
+ multiline:false,
+ exclusiveline:false,
+ prefix:'~~',
+ suffix:'~~'
+ },
+ heading: {
+ text: _('Heading'),
+ key: 'r',
+ multiline:false,
+ exclusiveline:true,
+ prefix:'==',
+ suffix:'=='
+ }
+ };
+
+ self.toolbar_wrap = function(node) {
+ var parent = $(node).parents('form[name="post"]');
+ self.wrap(parent.find('#body')[0],'textarea[name="body"]', parent.find('.format-text > select')[0].value, false);
+ };
+
+ self.wrap = function(ref, target, option, expandedwrap) {
+ // clean and validate arguments
+ if (ref == null) return;
+ var settings = {multiline: false, exclusiveline: false, prefix:'', suffix: null};
+ $.extend(settings,JSON.parse(localStorage.formatText_rules)[option]);
+
+ // resolve targets into array of proper node elements
+ // yea, this is overly verbose, oh well.
+ var res = [];
+ if (target instanceof Array) {
+ for (var indexa in target) {
+ if (target.hasOwnProperty(indexa)) {
+ if (typeof target[indexa] == 'string') {
+ var nodes = $(target[indexa]);
+ for (var indexb in nodes) {
+ if (indexa.hasOwnProperty(indexb)) res.push(nodes[indexb]);
+ }
+ } else {
+ res.push(target[indexa]);
+ }
+ }
+ }
+ } else {
+ if (typeof target == 'string') {
+ var nodes = $(target);
+ for (var index in nodes) {
+ if (nodes.hasOwnProperty(index)) res.push(nodes[index]);
+ }
+ } else {
+ res.push(target);
+ }
+ }
+ target = res;
+ //record scroll top to restore it later.
+ var scrollTop = ref.scrollTop;
+
+ //We will restore the selection later, so record the current selection
+ var selectionStart = ref.selectionStart;
+ var selectionEnd = ref.selectionEnd;
+
+ var text = ref.value;
+ var before = text.substring(0, selectionStart);
+ var selected = text.substring(selectionStart, selectionEnd);
+ var after = text.substring(selectionEnd);
+ var whiteSpace = [" ","\t"];
+ var breakSpace = ["\r","\n"];
+ var cursor;
+
+ // handles multiline selections on formatting that doesn't support spanning over multiple lines
+ if (!settings.multiline) selected = selected.replace(/(\r|\n|\r\n)/g,settings.suffix +"$1"+ settings.prefix);
+
+ // handles formatting that requires it to be on it's own line OR if the user wishes to expand the wrap to the nearest linebreak
+ if (settings.exclusiveline || expandedwrap) {
+ // buffer the begining of the selection until a linebreak
+ cursor = before.length -1;
+ while (cursor >= 0 && breakSpace.indexOf(before.charAt(cursor)) == -1) {
+ cursor--;
+ }
+ selected = before.substring(cursor +1) + selected;
+ before = before.substring(0, cursor +1);
+
+ // buffer the end of the selection until a linebreak
+ cursor = 0;
+ while (cursor < after.length && breakSpace.indexOf(after.charAt(cursor)) == -1) {
+ cursor++;
+ }
+ selected += after.substring(0, cursor);
+ after = after.substring(cursor);
+ }
+
+ // set values
+ var res = before + settings.prefix + selected + settings.suffix + after;
+ $(target).val(res);
+
+ // restore the selection area and scroll of the reference
+ ref.selectionEnd = before.length + settings.prefix.length + selected.length;
+ if (selectionStart === selectionEnd) {
+ ref.selectionStart = ref.selectionEnd;
+ } else {
+ ref.selectionStart = before.length + settings.prefix.length;
+ }
+ ref.scrollTop = scrollTop;
+ };
+
+ self.build_toolbars = function(){
+ if (localStorage.formatText_toolbar == 'true'){
+ // remove existing toolbars
+ if ($('.format-text').length > 0) $('.format-text').remove();
+
+ // Place toolbar above each textarea input
+ var name, options = '', rules = JSON.parse(localStorage.formatText_rules);
+ for (var index in rules) {
+ if (!rules.hasOwnProperty(index)) continue;
+ name = rules[index].text;
+
+ //add hint if key exists
+ if (rules[index].key) {
+ name += ' (CTRL + '+ rules[index].key.toUpperCase() +')';
+ }
+ options += '<option value="'+ index +'">'+ name +'</option>';
+ }
+ $('[name="body"]').before('<div class="format-text"><a href="javascript:;" onclick="formatText.toolbar_wrap(this);">Wrap</a><select>'+ options +'</select></div>');
+ $('body').append('<style>#quick-reply .format-text>a{width:15%;display:inline-block;text-align:center;}#quick-reply .format-text>select{width:85%;};</style>');
+ }
+ };
+
+ self.add_rule = function(rule, index){
+ if (rule === undefined) rule = {
+ text: 'New Rule',
+ key: '',
+ multiline:false,
+ exclusiveline:false,
+ prefix:'',
+ suffix:''
+ }
+
+ // generate an id for the rule
+ if (index === undefined) {
+ var rules = JSON.parse(localStorage.formatText_rules);
+ while (rules[index] || index === undefined) {
+ index = ''
+ index +='abcdefghijklmnopqrstuvwxyz'.substr(Math.floor(Math.random()*26),1);
+ index +='abcdefghijklmnopqrstuvwxyz'.substr(Math.floor(Math.random()*26),1);
+ index +='abcdefghijklmnopqrstuvwxyz'.substr(Math.floor(Math.random()*26),1);
+ }
+ }
+ if (window.Options && Options.get_tab('formatting')){
+ var html = $('<div class="format_rule" name="'+ index +'"></div>').html('\
+ <input type="text" name="text" class="format_option" size="10" value=\"'+ rule.text.replace(/"/g, '&quot;') +'\">\
+ <input type="checkbox" name="multiline" class="format_option" '+ (rule.multiline ? 'checked' : '') +'>\
+ <input type="checkbox" name="exclusiveline" class="format_option" '+ (rule.exclusiveline ? 'checked' : '') +'>\
+ <input type="text" name="prefix" class="format_option" size="8" value=\"'+ (rule.prefix ? rule.prefix.replace(/"/g, '&quot;') : '') +'\">\
+ <input type="text" name="suffix" class="format_option" size="8" value=\"'+ (rule.suffix ? rule.suffix.replace(/"/g, '&quot;') : '') +'\">\
+ <input type="text" name="key" class="format_option" size="2" maxlength="1" value=\"'+ rule.key +'\">\
+ <input type="button" value="X" onclick="if(confirm(\'Do you wish to remove the '+ rule.text +' formatting rule?\'))$(this).parent().remove();">\
+ ');
+
+ if ($('.format_rule').length > 0) {
+ $('.format_rule').last().after(html);
+ } else {
+ Options.extend_tab('formatting', html);
+ }
+ }
+ };
+
+ self.save_rules = function(){
+ var rule, newrules = {}, rules = $('.format_rule');
+ for (var index=0;rules[index];index++) {
+ rule = $(rules[index]);
+ newrules[rule.attr('name')] = {
+ text: rule.find('[name="text"]').val(),
+ key: rule.find('[name="key"]').val(),
+ prefix: rule.find('[name="prefix"]').val(),
+ suffix: rule.find('[name="suffix"]').val(),
+ multiline: rule.find('[name="multiline"]').is(':checked'),
+ exclusiveline: rule.find('[name="exclusiveline"]').is(':checked')
+ };
+ }
+ localStorage.formatText_rules = JSON.stringify(newrules);
+ self.build_toolbars();
+ };
+
+ self.reset_rules = function(to_default) {
+ $('.format_rule').remove();
+ var rules;
+ if (to_default) rules = self.rules;
+ else rules = JSON.parse(localStorage.formatText_rules);
+ for (var index in rules){
+ if (!rules.hasOwnProperty(index)) continue;
+ self.add_rule(rules[index], index);
+ }
+ };
+
+ // setup default rules for customizing
+ if (!localStorage.formatText_rules) localStorage.formatText_rules = JSON.stringify(self.rules);
+
+ // setup code to be ran when page is ready (work around for main.js compilation).
+ $(document).ready(function(){
+ // Add settings to Options panel general tab
+ if (window.Options && Options.get_tab('general')) {
+ var s1 = '#formatText_keybinds>input', s2 = '#formatText_toolbar>input', e = 'change';
+ Options.extend_tab('general', '\
+ <fieldset>\
+ <legend>Formatting Options</legend>\
+ <label id="formatText_keybinds"><input type="checkbox">' + _('Enable formatting keybinds') + '</label>\
+ <label id="formatText_toolbar"><input type="checkbox">' + _('Show formatting toolbar') + '</label>\
+ </fieldset>\
+ ');
+ } else {
+ var s1 = '#formatText_keybinds', s2 = '#formatText_toolbar', e = 'click';
+ $('hr:first').before('<div id="formatText_keybinds" style="text-align:right"><a class="unimportant" href="javascript:void(0)">'+ _('Enable formatting keybinds') +'</a></div>');
+ $('hr:first').before('<div id="formatText_toolbar" style="text-align:right"><a class="unimportant" href="javascript:void(0)">'+ _('Show formatting toolbar') +'</a></div>');
+ }
+
+ // add the tab for customizing the format settings
+ if (window.Options && !Options.get_tab('formatting')) {
+ Options.add_tab('formatting', 'angle-right', _('Customize Formatting'));
+ Options.extend_tab('formatting', '\
+ <style>\
+ .format_option{\
+ margin-right:5px;\
+ overflow:initial;\
+ font-size:15px;\
+ }\
+ .format_option[type="text"]{\
+ text-align:center;\
+ padding-bottom: 2px;\
+ padding-top: 2px;\
+ }\
+ .format_option:last-child{\
+ margin-right:0;\
+ }\
+ fieldset{\
+ margin-top:5px;\
+ }\
+ </style>\
+ ');
+
+ // Data control row
+ Options.extend_tab('formatting', '\
+ <button onclick="formatText.add_rule();">'+_('Add Rule')+'</button>\
+ <button onclick="formatText.save_rules();">'+_('Save Rules')+'</button>\
+ <button onclick="formatText.reset_rules(false);">'+_('Revert')+'</button>\
+ <button onclick="formatText.reset_rules(true);">'+_('Reset to Default')+'</button>\
+ ');
+
+ // Descriptor row
+ Options.extend_tab('formatting', '\
+ <span class="format_option" style="margin-left:25px;">Name</span>\
+ <span class="format_option" style="margin-left:45px;" title="Multi-line: Allow formatted area to contain linebreaks.">ML</span>\
+ <span class="format_option" style="margin-left:0px;" title="Exclusive-line: Require formatted area to start after and end before a linebreak.">EL</span>\
+ <span class="format_option" style="margin-left:25px;" title="Text injected at the start of a format area.">Prefix</span>\
+ <span class="format_option" style="margin-left:60px;" title="Text injected at the end of a format area.">Suffix</span>\
+ <span class="format_option" style="margin-left:40px;" title="Optional keybind value to allow keyboard shortcut access.">Key</span>\
+ ');
+
+ // Rule rows
+ var rules = JSON.parse(localStorage.formatText_rules);
+ for (var index in rules){
+ if (!rules.hasOwnProperty(index)) continue;
+ self.add_rule(rules[index], index);
+ }
+ }
+
+ // setting for enabling formatting keybinds
+ $(s1).on(e, function(e) {
+ console.log('Keybind');
+ if (!localStorage.formatText_keybinds || localStorage.formatText_keybinds == 'false') {
+ localStorage.formatText_keybinds = 'true';
+ if (window.Options && Options.get_tab('general')) e.target.checked = true;
+ } else {
+ localStorage.formatText_keybinds = 'false';
+ if (window.Options && Options.get_tab('general')) e.target.checked = false;
+ }
+ });
+
+ // setting for toolbar injection
+ $(s2).on(e, function(e) {
+ console.log('Toolbar');
+ if (!localStorage.formatText_toolbar || localStorage.formatText_toolbar == 'false') {
+ localStorage.formatText_toolbar = 'true';
+ if (window.Options && Options.get_tab('general')) e.target.checked = true;
+ formatText.build_toolbars();
+ } else {
+ localStorage.formatText_toolbar = 'false';
+ if (window.Options && Options.get_tab('general')) e.target.checked = false;
+ $('.format-text').remove();
+ }
+ });
+
+ // make sure the tab settings are switch properly at loadup
+ if (window.Options && Options.get_tab('general')) {
+ if (localStorage.formatText_keybinds == 'true') $(s1)[0].checked = true;
+ else $(s1)[0].checked = false;
+ if (localStorage.formatText_toolbar == 'true') $(s2)[0].checked = true;
+ else $(s2)[0].checked = false;
+ }
+
+ // Initial toolbar injection
+ formatText.build_toolbars();
+
+ //attach listener to <body> so it also works on quick-reply box
+ $('body').on('keydown', '[name="body"]', function(e) {
+ if (!localStorage.formatText_keybinds || localStorage.formatText_keybinds == 'false') return;
+ var key = String.fromCharCode(e.which).toLowerCase();
+ var rules = JSON.parse(localStorage.formatText_rules);
+ for (var index in rules) {
+ if (!rules.hasOwnProperty(index)) continue;
+ if (key === rules[index].key && e.ctrlKey) {
+ e.preventDefault();
+ if (e.shiftKey) {
+ formatText.wrap(e.target, 'textarea[name="body"]', index, true);
+ } else {
+ formatText.wrap(e.target, 'textarea[name="body"]', index, false);
+ }
+ }
+ }
+ });
+
+ // Signal that comment-toolbar loading has completed.
+ $(document).trigger('formatText');
+ });
+
+ return self;
+ })(jQuery);
+}
diff --git a/js/expand-all-images.js b/js/expand-all-images.js
index 5545045c..c110f51c 100644
--- a/js/expand-all-images.js
+++ b/js/expand-all-images.js
@@ -23,7 +23,15 @@ onready(function(){
.text(_('Expand all images'))
.click(function() {
$('a img.post-image').each(function() {
- if (!$(this).parent()[0].dataset.expanded)
+ // Don't expand YouTube embeds
+ if ($(this).parent().parent().hasClass('video-container'))
+ return;
+
+ // or WEBM
+ if (/^\/player\.php\?/.test($(this).parent().attr('href')))
+ return;
+
+ if (!$(this).parent().data('expanded'))
$(this).parent().click();
});
@@ -34,8 +42,8 @@ onready(function(){
$('div#shrink-all-images a')
.text(_('Shrink all images'))
.click(function(){
- $('a img.post-image').each(function() {
- if ($(this).parent()[0].dataset.expanded)
+ $('a img.full-image').each(function() {
+ if ($(this).parent().data('expanded'))
$(this).parent().click();
});
$(this).parent().remove();
diff --git a/js/expand-too-long.js b/js/expand-too-long.js
index d6ea43af..bbadb5f1 100644
--- a/js/expand-too-long.js
+++ b/js/expand-too-long.js
@@ -17,7 +17,7 @@ $(function() {
e.preventDefault();
var url = $(this).attr('href');
- var body = $(this).parent().parent();
+ var body = $(this).parents('.body');
$.ajax({
url: url,
diff --git a/js/favorites.js b/js/favorites.js
index daf7b732..027dc243 100644
--- a/js/favorites.js
+++ b/js/favorites.js
@@ -50,7 +50,7 @@ function add_favorites() {
$('.boardlist').append(boards);
};
-if (active_page == 'thread' || active_page == 'index') {
+if (active_page == 'thread' || active_page == 'index' || active_page == 'catalog' || active_page == 'ukko') {
$(document).ready(function(){
var favorites = JSON.parse(localStorage.favorites);
var is_board_favorite = ~$.inArray(board_name, favorites);
diff --git a/js/file-selector.js b/js/file-selector.js
index 207a5ae9..c2b5381b 100644
--- a/js/file-selector.js
+++ b/js/file-selector.js
@@ -1,8 +1,9 @@
/*
- * file-selector.js - Add support for drag and drop file selection, and paste from clipbboard on supported browsers.
+ * file-selector.js - Add support for drag and drop file selection, and paste from clipboard on supported browsers.
*
* Usage:
* $config['additional_javascript'][] = 'js/jquery.min.js';
+ * $config['additional_javascript'][] = 'js/ajax.js';
* $config['additional_javascript'][] = 'js/file-selector.js';
*/
function init_file_selector(max_images) {
diff --git a/js/fix-report-delete-submit.js b/js/fix-report-delete-submit.js
index 73b6dd9c..f5cda9ad 100644
--- a/js/fix-report-delete-submit.js
+++ b/js/fix-report-delete-submit.js
@@ -1,26 +1,69 @@
/*
* fix-report-delete-submit.js
- * https://github.com/savetheinternet/Tinyboard/blob/master/js/fix-report-delete-submit.js
- *
- * Fixes a known bug regarding the delete/report submit buttons.
- *
- * Released under the MIT license
- * Copyright (c) 2012 Michael Save <savetheinternet@tinyboard.org>
*
* Usage:
* $config['additional_javascript'][] = 'js/jquery.min.js';
+ * $config['additional_javascript'][] = 'js/post-menu.js';
* $config['additional_javascript'][] = 'js/fix-report-delete-submit.js';
*
*/
-$(document).ready(function(){
- $('form[name="postcontrols"] div.delete input:not([type="checkbox"]):not([type="submit"]):not([type="hidden"])').keypress(function(e) {
- if(e.which == 13) {
+if (active_page == 'thread' || active_page == 'index' || active_page == 'ukko') {
+$(document).on('menu_ready', function(){
+var Menu = window.Menu;
+
+if ($('#delete-fields #password').length) {
+ Menu.add_item("delete_post_menu", _("Delete post"));
+ Menu.add_item("delete_file_menu", _("Delete file"));
+ Menu.onclick(function(e, $buf) {
+ var ele = e.target.parentElement.parentElement;
+ var $ele = $(ele);
+ var threadId = $ele.parent().attr('id').replace('thread_', '');
+ var postId = $ele.find('.post_no').not('[id]').text();
+ var board_name = $ele.parent().data('board');
+
+ $buf.find('#delete_post_menu,#delete_file_menu').click(function(e) {
e.preventDefault();
- $(this).next().click();
- return false;
+ $('#delete_'+postId).prop('checked', 'checked');
+
+ if ($(this).attr('id') === 'delete_file_menu') {
+ $('#delete_file').prop('checked', 'checked');
+ } else {
+ $('#delete_file').prop('checked', '');
+ }
+ $('input[type="hidden"][name="board"]').val(board_name);
+ $('input[name=delete][type=submit]').click();
+ });
+ });
+}
+
+Menu.add_item("report_menu", _("Report"));
+//Menu.add_item("global_report_menu", _("Global report"));
+Menu.onclick(function(e, $buf) {
+ var ele = e.target.parentElement.parentElement;
+ var $ele = $(ele);
+ var threadId = $ele.parent().attr('id').replace('thread_', '');
+ var postId = $ele.find('.post_no').not('[id]').text();
+ var board_name = $ele.parent().data('board');
+
+ $buf.find('#report_menu,#global_report_menu').click(function(e) {
+ if ($(this).attr('id') === "global_report_menu") {
+ var global = '&global';
+ } else {
+ var global = '';
}
- return true;
+ window.open(configRoot+'report.php?board='+board_name+'&post=delete_'+postId+global, "", (global?"width=600, height=575":"width=500, height=275"));
});
});
+$(document).on('new_post', function(){
+ $('input.delete').hide();
+});
+$('input.delete').hide();
+$('#post-moderation-fields').hide();
+});
+
+if (typeof window.Menu !== "undefined") {
+ $(document).trigger('menu_ready');
+}
+}
diff --git a/js/forced-anon.js b/js/forced-anon.js
index 11327ec9..26d0cb4f 100644
--- a/js/forced-anon.js
+++ b/js/forced-anon.js
@@ -18,10 +18,10 @@
if (active_page == 'ukko' || active_page == 'thread' || active_page == 'index' || (window.Options && Options.get_tab('general')))
$(document).ready(function() {
var force_anon = function() {
- if($(this).children('a.capcode').length == 0) {
+ if ($(this).children('a.capcode').length == 0) {
var id = $(this).parent().children('a.post_no:eq(1)').text();
- if($(this).children('a.email').length != 0)
+ if ($(this).children('a.email').length != 0)
var p = $(this).children('a.email');
else
var p = $(this);
@@ -29,7 +29,7 @@ $(document).ready(function() {
old_info[id] = {'name': p.children('span.name').text(), 'trip': p.children('span.trip').text()};
p.children('span.name').text('Anonymous');
- if(p.children('span.trip').length != 0)
+ if (p.children('span.trip').length != 0)
p.children('span.trip').text('');
}
};
@@ -40,44 +40,60 @@ $(document).ready(function() {
var disable_fa = function() {
$('p.intro label').each(function() {
- if($(this).children('a.capcode').length == 0) {
+ if ($(this).children('a.capcode').length == 0) {
var id = $(this).parent().children('a.post_no:eq(1)').text();
if(old_info[id]) {
- if($(this).children('a.email').length != 0)
+ if ($(this).children('a.email').length != 0)
var p = $(this).children('a.email');
else
var p = $(this);
p.children('span.name').text(old_info[id]['name']);
- if(p.children('span.trip').length != 0)
+ if (p.children('span.trip').length != 0)
p.children('span.trip').text(old_info[id]['trip']);
}
}
});
};
+ var toggle_id = function() {
+ if (localStorage.hideids == 'true'){
+ $(this).addClass('hidden');
+ } else {
+ $(this).removeClass('hidden');
+ }
+ };
+
old_info = {};
forced_anon = localStorage['forcedanon'] ? true : false;
- var selector, event;
- if (window.Options && Options.get_tab('general')) {
- selector = '#forced-anon';
- event = 'change';
- Options.extend_tab("general", "<label id='forced-anon'><input type='checkbox' />"+_('Forced anonymity')+"</label>");
- }
- else {
- selector = '#forced-anon';
- event = 'click';
+ if (window.Options && Options.get_tab('general')) {
+ var s1 = '#hide-ids', s2 = '#forced-anon', e = 'change';
+ Options.extend_tab("general", "<label id='hide-ids'><input type='checkbox' /> "+_('Hide IDs')+"</label>");
+ Options.extend_tab("general", "<label id='forced-anon'><input type='checkbox' /> "+_('Forced anonymity')+"</label>");
+ }
+ else {
+ var s1 = '#hide-ids', s2 = '#forced-anon', e = 'click';
+ $('hr:first').before('<div id="hide-ids" style="text-align:right"><a class="unimportant" href="javascript:void(0)">Hide IDs</a></div>');
$('hr:first').before('<div id="forced-anon" style="text-align:right"><a class="unimportant" href="javascript:void(0)">-</a></div>');
$('div#forced-anon a').text(_('Forced anonymity')+' (' + (forced_anon ? _('enabled') : _('disabled')) + ')');
- }
+ }
+ $(s1).on(e, function(e) {
+ if (!localStorage.hideids || localStorage.hideids == 'false') {
+ localStorage.hideids = 'true';
+ if (window.Options && Options.get_tab('general')) e.target.checked = true;
+ } else {
+ localStorage.hideids = 'false';
+ if (window.Options && Options.get_tab('general')) e.target.checked = false;
+ }
+ $('.poster_id').each(toggle_id);
+ });
- $(selector).on(event, function() {
+ $(s2).on(e, function() {
forced_anon = !forced_anon;
-
- if(forced_anon) {
+ if (forced_anon) {
$('div#forced-anon a').text(_('Forced anonymity')+' ('+_('enabled')+')');
localStorage.forcedanon = true;
enable_fa();
@@ -86,21 +102,27 @@ $(document).ready(function() {
delete localStorage.forcedanon;
disable_fa();
}
-
return false;
});
+ // initial option setup on script load
+ if (localStorage.hideids == 'true'){
+ if (window.Options && Options.get_tab('general')) $('#hide-ids>input').prop('checked',true);
+ $('.poster_id').each(toggle_id);
+ }
+
if(forced_anon) {
enable_fa();
-
- if (window.Options && Options.get_tab('general')) {
- $('#toggle-locked-threads>input').prop('checked', true);
- }
+ if (window.Options && Options.get_tab('general')) {
+ $('#toggle-locked-threads>input').prop('checked', true);
+ }
}
$(document).on('new_post', function(e, post) {
- if(forced_anon)
+ if (forced_anon)
$(post).find('p.intro label').each(force_anon);
+ if (localStorage.hideids == 'true')
+ $(post).find('.poster_id').each(toggle_id);
});
});
diff --git a/js/hide-images.js b/js/hide-images.js
index 323a1a1f..4fdad891 100644
--- a/js/hide-images.js
+++ b/js/hide-images.js
@@ -77,7 +77,7 @@ $(document).ready(function(){
$(this).hide().after(show_link);
- if ($(img).parent()[0].dataset.expanded == 'true') {
+ if ($(img).parent().data('expanded') == 'true') {
$(img).parent().click();
}
diff --git a/js/hide-threads.js b/js/hide-threads.js
index 175018ed..47417d39 100644
--- a/js/hide-threads.js
+++ b/js/hide-threads.js
@@ -36,7 +36,7 @@ $(document).ready(function(){
}
}
- var fields_to_hide = 'div.post,div.video-container,video,iframe,img:not(.unanimated),canvas,p.fileinfo,a.hide-thread-link,div.new-posts,br';
+ var fields_to_hide = 'div.file,div.post,div.video-container,video,iframe,img:not(.unanimated),canvas,p.fileinfo,a.hide-thread-link,div.new-posts,br';
var do_hide_threads = function() {
var id = $(this).children('p.intro').children('a.post_no:eq(1)').text();
diff --git a/js/id_colors.js b/js/id_colors.js
index 17f8b4d9..55454476 100644
--- a/js/id_colors.js
+++ b/js/id_colors.js
@@ -1,18 +1,18 @@
if (active_page == 'thread' || active_page == 'index') {
$(document).ready(function(){
if (window.Options && Options.get_tab('general')) {
- selector = '#color-ids>input';
- event = 'change';
+ var selector = '#color-ids>input';
+ var e = 'change';
Options.extend_tab("general", "<label id='color-ids'><input type='checkbox' /> "+_('Color IDs')+"</label>");
}
else {
- selector = '#color-ids';
- event = 'click';
+ var selector = '#color-ids';
+ var e = 'click';
$('hr:first').before('<div id="color-ids" style="text-align:right"><a class="unimportant" href="javascript:void(0)">'+_('Color IDs')+'</a></div>')
}
- $(selector).on(event, function() {
+ $(selector).on(e, function() {
if (localStorage.color_ids === 'true') {
localStorage.color_ids = 'false';
} else {
@@ -50,12 +50,6 @@ if (active_page == 'thread' || active_page == 'index') {
"border-radius": "8px",
"color": ft
});
-
- $(el).mouseover(function() {
- $(this).css('color', '#800000'); // how about a CSS :hover rule instead?
- }).mouseout(function() {
- $(this).css('color', ft);
- });
}
$(".poster_id").each(function(k, v){
diff --git a/js/image-hover.js b/js/image-hover.js
index 93d61702..66e908d7 100644
--- a/js/image-hover.js
+++ b/js/image-hover.js
@@ -180,3 +180,4 @@ function imageHoverEnd() { //Pashe, WTFPL
initImageHover();
});
}
+
diff --git a/js/infinite-scroll.js b/js/infinite-scroll.js
index e212f9d6..b3c5c7ae 100644
--- a/js/infinite-scroll.js
+++ b/js/infinite-scroll.js
@@ -21,7 +21,7 @@ var activate = function() {
if (document.location.hash != '#all') return false;
$(window).on("scroll", function() {
- scrolltest();
+ scrolltest();
});
scrolltest();
@@ -30,53 +30,54 @@ var activate = function() {
var scrolltest = function() {
if ($(window).scrollTop() + $(window).height() + 1000 > $(document).height() && !loading) {
- load_next_page();
+ load_next_page();
}
};
var load_next_page = function() {
- if (loading) return;
- loading = true;
-
- var this_page = $(".pages a.selected:last");
- var next_page = this_page.next();
-
- var href = next_page.prop("href");
- if (!href) return;
-
- var boardheader = $('<h2>'+_('Page')+' '+next_page.html()+'</h2>');
- var loading_ind = $('<h2>'+_('Loading...')+'</h2>').insertBefore('form[name="postcontrols"]>.delete:first');
-
- $.get(href, function(data) {
- var doc = $(data);
-
- loading_ind.remove();
- boardheader.insertBefore('form[name="postcontrols"]>.delete:first');
-
- var i = 0;
-
- doc.find('div[id*="thread_"]').each(function() {
- var checkout = $(this).attr('id').replace('thread_', '');
- var $this = this;
-
- if ($('div#thread_' + checkout).length == 0) {
- // Delay DOM insertion to lessen the lag.
- setTimeout(function() {
- $($this).insertBefore('form[name="postcontrols"]>.delete:first');
- $(document).trigger('new_post', $this);
- $($this).hide().slideDown();
- }, 500*i);
- i++;
- }
- });
- setTimeout(function() {
- loading = false;
- scrolltest();
- }, 500*(i+1));
-
- next_page.addClass('selected');
- });
-
+ if (loading) return;
+ loading = true;
+
+ var this_page = $(".pages a.selected:last");
+ var next_page = this_page.next();
+
+ var href = next_page.prop("href");
+ if (!href) return;
+
+ var boardheader = $('<h2>'+_('Page')+' '+next_page.html()+'</h2>');
+ var loading_ind = $('<h2>'+_('Loading...')+'</h2>').insertBefore('#post-moderation-fields');
+
+ $.get(href, function(data) {
+ var doc = $(data);
+
+ loading_ind.remove();
+ boardheader.insertBefore('#post-moderation-fields');
+
+ var i = 0;
+
+ doc.find('div[id*="thread_"]').each(function() {
+ var checkout = $(this).attr('id').replace('thread_', '');
+ var $this = this;
+
+ if ($('div#thread_' + checkout).length == 0) {
+ // Delay DOM insertion to lessen the lag.
+ setTimeout(function() {
+ $($this).insertBefore('#post-moderation-fields');
+ $(document).trigger('new_post', $this);
+ $($this).hide().slideDown();
+ }, 500*i);
+
+ i++;
+ }
+ });
+
+ setTimeout(function() {
+ loading = false;
+ scrolltest();
+ }, 500*(i+1));
+
+ next_page.addClass('selected');
+ });
};
var button = $("<a href='#all'>"+_("All")+" </a>").prependTo(".pages");
diff --git a/js/inline-expanding.js b/js/inline-expanding.js
index 4d0cb03d..5db95c09 100644
--- a/js/inline-expanding.js
+++ b/js/inline-expanding.js
@@ -7,65 +7,201 @@
* Copyright (c) 2013-2014 Marcin Łabanowski <marcin@6irc.net>
*
* Usage:
- * // $config['additional_javascript'][] = 'js/jquery.min.js';
+ * $config['additional_javascript'][] = 'js/jquery.min.js';
* $config['additional_javascript'][] = 'js/inline-expanding.js';
*
*/
-onready(function(){
+$(document).ready(function(){
+ 'use strict';
+
+ var DEFAULT_MAX = 5; // default maximum image loads
var inline_expand_post = function() {
var link = this.getElementsByTagName('a');
+ var loadingQueue = (function () {
+ var MAX_IMAGES = localStorage.inline_expand_max || DEFAULT_MAX; // maximum number of images to load concurrently, 0 to disable
+ var loading = 0; // number of images that is currently loading
+ var waiting = []; // waiting queue
+
+ var enqueue = function (ele) {
+ waiting.push(ele);
+ };
+ var dequeue = function () {
+ return waiting.shift();
+ };
+ var update = function() {
+ var ele;
+ while (loading < MAX_IMAGES || MAX_IMAGES === 0) {
+ ele = dequeue();
+ if (ele) {
+ ++loading;
+ ele.deferred.resolve();
+ } else {
+ return;
+ }
+ }
+ };
+ return {
+ remove: function (ele) {
+ var i = waiting.indexOf(ele);
+ if (i > -1) {
+ waiting.splice(i, 1);
+ }
+ if ($(ele).data('imageLoading') === 'true') {
+ $(ele).data('imageLoading', 'false');
+ clearTimeout(ele.timeout);
+ --loading;
+ }
+ },
+ add: function (ele) {
+ ele.deferred = $.Deferred();
+ ele.deferred.done(function () {
+ var $loadstart = $.Deferred();
+ var thumb = ele.childNodes[0];
+ var img = ele.childNodes[1];
+
+ var onLoadStart = function (img) {
+ if (img.naturalWidth) {
+ $loadstart.resolve(img, thumb);
+ } else {
+ return (ele.timeout = setTimeout(onLoadStart, 30, img));
+ }
+ };
+
+ $(img).one('load', function () {
+ $.when($loadstart).done(function () {
+ // once fully loaded, update the waiting queue
+ --loading;
+ $(ele).data('imageLoading', 'false');
+ update();
+ });
+ });
+ $loadstart.done(function (img, thumb) {
+ thumb.style.display = 'none';
+ img.style.display = '';
+ });
+
+ img.setAttribute('src', ele.href);
+ $(ele).data('imageLoading', 'true');
+ ele.timeout = onLoadStart(img);
+ });
+
+ if (loading < MAX_IMAGES || MAX_IMAGES === 0) {
+ ++loading;
+ ele.deferred.resolve();
+ } else {
+ enqueue(ele);
+ }
+
+ }
+ };
+ })();
+
for (var i = 0; i < link.length; i++) {
- if (typeof link[i] == "object" && link[i].childNodes && typeof link[i].childNodes[0] !== 'undefined' && link[i].childNodes[0].src && link[i].childNodes[0].className.match(/post-image/) && !link[i].className.match(/file/)) {
- link[i].childNodes[0].style.maxWidth = '98%';
+ if (typeof link[i] == "object" && link[i].childNodes && typeof link[i].childNodes[0] !== 'undefined' &&
+ link[i].childNodes[0].src && link[i].childNodes[0].className.match(/post-image/) && !link[i].className.match(/file/)) {
link[i].onclick = function(e) {
- if (this.childNodes[0].className == 'hidden')
+ var img, post_body, still_open, canvas, scroll;
+ var thumb = this.childNodes[0];
+ var padding = 5;
+ var boardlist = $('.boardlist')[0];
+
+
+ if (thumb.className == 'hidden')
return false;
- if (e.which == 2 || e.metaKey)
+ if (e.which == 2 || e.ctrlKey) // open in new tab
return true;
- if (!this.dataset.src) {
+ if (!$(this).data('expanded')) {
+
+ if (~this.parentNode.className.indexOf('multifile'))
+ $(this).data('width', this.parentNode.style.width);
+
this.parentNode.removeAttribute('style');
- this.dataset.expanded = 'true';
+ $(this).data('expanded', 'true');
- if (this.childNodes[0].tagName === 'CANVAS') {
- this.removeChild(this.childNodes[0]);
- this.childNodes[0].style.display = 'block';
+ if (thumb.tagName === 'CANVAS') {
+ canvas = thumb;
+ thumb = thumb.nextSibling;
+ this.removeChild(canvas);
+ canvas.style.display = 'block';
}
- this.dataset.src= this.childNodes[0].src;
- this.dataset.width = this.childNodes[0].style.width;
- this.dataset.height = this.childNodes[0].style.height;
-
+ thumb.style.opacity = '0.4';
+ thumb.style.filter = 'alpha(opacity=40)';
- this.childNodes[0].src = this.href;
- this.childNodes[0].style.width = 'auto';
- this.childNodes[0].style.height = 'auto';
- this.childNodes[0].style.opacity = '0.4';
- this.childNodes[0].style.filter = 'alpha(opacity=40)';
- this.childNodes[0].onload = function() {
- this.style.opacity = '';
- delete this.style.filter;
- }
+ img = document.createElement('img');
+ img.className = 'full-image';
+ img.style.display = 'none';
+ img.setAttribute('alt', 'Fullsized image');
+ this.appendChild(img);
+
+ loadingQueue.add(this);
} else {
+ loadingQueue.remove(this);
+
+ scroll = false;
+
+ // scroll to thumb if not triggered by 'shrink all image'
+ if (e.target.className == 'full-image') {
+ scroll = true;
+ }
+
if (~this.parentNode.className.indexOf('multifile'))
- this.parentNode.style.width = (parseInt(this.dataset.width)+40)+'px';
- this.childNodes[0].src = this.dataset.src;
- this.childNodes[0].style.width = this.dataset.width;
- this.childNodes[0].style.height = this.dataset.height;
- delete this.dataset.expanded;
- delete this.dataset.src;
- delete this.childNodes[0].style.opacity;
- delete this.childNodes[0].style.filter;
+ this.parentNode.style.width = $(this).data('width');
+
+ thumb.style.opacity = '';
+ thumb.style.display = '';
+ if (thumb.nextSibling) this.removeChild(thumb.nextSibling); //full image loaded or loading
+ $(this).removeData('expanded');
+ delete thumb.style.filter;
+
+ // do the scrolling after page reflow
+ if (scroll) {
+ post_body = $(thumb).parentsUntil('form > div').last();
+
+ // on multifile posts, determin how many other images are still expanded
+ still_open = post_body.find('.post-image').filter(function(){
+ return $(this).parent().data('expanded') == 'true';
+ }).length;
+
+ // deal with differnt boards' menu styles
+ if ($(boardlist).css('position') == 'fixed')
+ padding += boardlist.getBoundingClientRect().height;
+
+ if (still_open > 0) {
+ if (thumb.getBoundingClientRect().top - padding < 0)
+ $(document).scrollTop($(thumb).parent().parent().offset().top - padding);
+ } else {
+ if (post_body[0].getBoundingClientRect().top - padding < 0)
+ $(document).scrollTop(post_body.offset().top - padding);
+ }
+ }
if (localStorage.no_animated_gif === 'true' && typeof unanimate_gif === 'function') {
- unanimate_gif(this.childNodes[0]);
+ unanimate_gif(thumb);
}
}
return false;
- }
+ };
}
}
+ };
+
+ // setting up user option
+ if (window.Options && Options.get_tab('general')) {
+ Options.extend_tab('general', '<span id="inline-expand-max">'+ _('Number of simultaneous image downloads (0 to disable): ') +
+ '<input type="number" step="1" min="0" size="4"></span>');
+ $('#inline-expand-max input')
+ .css('width', '50px')
+ .val(localStorage.inline_expand_max || DEFAULT_MAX)
+ .on('change', function (e) {
+ // validation in case some fucktard tries to enter a negative floating point number
+ var n = parseInt(e.target.value);
+ var val = (n<0) ? 0 : n;
+
+ localStorage.inline_expand_max = val;
+ });
}
if (window.jQuery) {
diff --git a/js/inline.js b/js/inline.js
index 4f8c9a72..e581b79d 100644
--- a/js/inline.js
+++ b/js/inline.js
@@ -123,8 +123,8 @@ $(document).ready(function() {
$clone.insertAfter(link.node)
}
- App.options.add('useInlining', 'Enable inlining')
- App.options.add('hidePost', 'Hide inlined backlinked posts')
+ App.options.add('useInlining', _('Enable inlining'))
+ App.options.add('hidePost', _('Hide inlined backlinked posts'))
$('head').append(
'<style>' +
@@ -138,8 +138,8 @@ $(document).ready(function() {
// don't attach to outbound links
if (App.options.get('useInlining')) {
- var assign_inline = function() {
- $('.body a:not([rel]), .mentioned a')
+ var assign_inline = function() {
+ $('.body a[href*="'+location.pathname+'"]').not('[rel]').not('.toolong > a').add('.mentioned a')
.attr('onclick', null)// XXX disable highlightReply
.off('click')
.click(inline)
diff --git a/js/jquery.mixitup.min.js b/js/jquery.mixitup.min.js
index 5b4e4ce0..719424a2 100644
--- a/js/jquery.mixitup.min.js
+++ b/js/jquery.mixitup.min.js
@@ -1,43 +1,67 @@
/*
-* MIXITUP - A CSS3 and JQuery Filter & Sort Plugin
-* Version: 1.5.5
-* License: Creative Commons Attribution-NoDerivs 3.0 Unported - CC BY-ND 3.0
-* http://creativecommons.org/licenses/by-nd/3.0/
-* This software may be used freely on commercial and non-commercial projects with attribution to the author/copyright holder.
-* Author: Patrick Kunka
-* Copyright 2012-2013 Patrick Kunka, Barrel LLC, All Rights Reserved
-*
-* http://mixitup.io
-*/
+ Copyright 2014 KunkaLabs Limited.
+ @author KunkaLabs Limited.
+ @link https://mixitup.kunkalabs.com
+
+ @license Commercial use requires a commercial license.
+ https://mixitup.kunkalabs.com/licenses/
-(function(d){function r(e,c,l,b,a){function f(){n.unbind("webkitTransitionEnd transitionend otransitionend oTransitionEnd");c&&x(c,l,b,a);a.startOrder=[];a.newOrder=[];a.origSort=[];a.checkSort=[];v.removeStyle(a.prefix+"filter, filter, "+a.prefix+"transform, transform, opacity, display").css(a.clean).removeAttr("data-checksum");window.atob||v.css({display:"none",opacity:"0"});n.removeStyle(a.prefix+"transition, transition, "+a.prefix+"perspective, perspective, "+a.prefix+"perspective-origin, perspective-origin, "+
-(a.resizeContainer?"height":""));"list"==a.layoutMode?(p.css({display:a.targetDisplayList,opacity:"1"}),a.origDisplay=a.targetDisplayList):(p.css({display:a.targetDisplayGrid,opacity:"1"}),a.origDisplay=a.targetDisplayGrid);a.origLayout=a.layoutMode;setTimeout(function(){v.removeStyle(a.prefix+"transition, transition");a.mixing=!1;if("function"==typeof a.onMixEnd){var b=a.onMixEnd.call(this,a);a=b?b:a}})}clearInterval(a.failsafe);a.mixing=!0;a.filter=e;if("function"==typeof a.onMixStart){var g=a.onMixStart.call(this,
-a);a=g?g:a}for(var k=a.transitionSpeed,g=0;2>g;g++){var h=0==g?h=a.prefix:"";a.transition[h+"transition"]="all "+k+"ms linear";a.transition[h+"transform"]=h+"translate3d(0,0,0)";a.perspective[h+"perspective"]=a.perspectiveDistance+"px";a.perspective[h+"perspective-origin"]=a.perspectiveOrigin}var w=a.targetSelector,v=b.find(w);v.each(function(){this.data={}});var n=v.parent();n.css(a.perspective);a.easingFallback="ease-in-out";"smooth"==a.easing&&(a.easing="cubic-bezier(0.25, 0.46, 0.45, 0.94)");
-"snap"==a.easing&&(a.easing="cubic-bezier(0.77, 0, 0.175, 1)");"windback"==a.easing&&(a.easing="cubic-bezier(0.175, 0.885, 0.320, 1.275)",a.easingFallback="cubic-bezier(0.175, 0.885, 0.320, 1)");"windup"==a.easing&&(a.easing="cubic-bezier(0.6, -0.28, 0.735, 0.045)",a.easingFallback="cubic-bezier(0.6, 0.28, 0.735, 0.045)");g="list"==a.layoutMode&&null!=a.listEffects?a.listEffects:a.effects;Array.prototype.indexOf&&(a.fade=-1<g.indexOf("fade")?"0":"",a.scale=-1<g.indexOf("scale")?"scale(.01)":"",a.rotateZ=
--1<g.indexOf("rotateZ")?"rotate(180deg)":"",a.rotateY=-1<g.indexOf("rotateY")?"rotateY(90deg)":"",a.rotateX=-1<g.indexOf("rotateX")?"rotateX(90deg)":"",a.blur=-1<g.indexOf("blur")?"blur(8px)":"",a.grayscale=-1<g.indexOf("grayscale")?"grayscale(100%)":"");var p=d(),s=d(),t=[],r=!1;"string"===typeof e?t=z(e):(r=!0,d.each(e,function(a){t[a]=z(this)}));"or"==a.filterLogic?(""==t[0]&&t.shift(),1>t.length?s=s.add(b.find(w+":visible")):v.each(function(){var a=d(this);if(r){var b=0;d.each(t,function(d){this.length?
-a.is("."+this.join(", ."))&&b++:0<b&&b++});b==t.length?p=p.add(a):s=s.add(a)}else a.is("."+t.join(", ."))?p=p.add(a):s=s.add(a)})):(p=p.add(n.find(w+"."+t.join("."))),s=s.add(n.find(w+":not(."+t.join(".")+"):visible")));e=p.length;var u=d(),q=d(),m=d();s.each(function(){var a=d(this);"none"!=a.css("display")&&(u=u.add(a),m=m.add(a))});if(p.filter(":visible").length==e&&!u.length&&!c){if(a.origLayout==a.layoutMode)return f(),!1;if(1==p.length)return"list"==a.layoutMode?(b.addClass(a.listClass),b.removeClass(a.gridClass),
-m.css("display",a.targetDisplayList)):(b.addClass(a.gridClass),b.removeClass(a.listClass),m.css("display",a.targetDisplayGrid)),f(),!1}a.origHeight=n.height();if(p.length){b.removeClass(a.failClass);p.each(function(){var a=d(this);"none"==a.css("display")?q=q.add(a):m=m.add(a)});if(a.origLayout!=a.layoutMode&&!1==a.animateGridList)return"list"==a.layoutMode?(b.addClass(a.listClass),b.removeClass(a.gridClass),m.css("display",a.targetDisplayList)):(b.addClass(a.gridClass),b.removeClass(a.listClass),
-m.css("display",a.targetDisplayGrid)),f(),!1;if(!window.atob)return f(),!1;v.css(a.clean);m.each(function(){this.data.origPos=d(this).offset()});"list"==a.layoutMode?(b.addClass(a.listClass),b.removeClass(a.gridClass),q.css("display",a.targetDisplayList)):(b.addClass(a.gridClass),b.removeClass(a.listClass),q.css("display",a.targetDisplayGrid));q.each(function(){this.data.showInterPos=d(this).offset()});u.each(function(){this.data.hideInterPos=d(this).offset()});m.each(function(){this.data.preInterPos=
-d(this).offset()});"list"==a.layoutMode?m.css("display",a.targetDisplayList):m.css("display",a.targetDisplayGrid);c&&x(c,l,b,a);if(c&&A(a.origSort,a.checkSort))return f(),!1;u.hide();q.each(function(a){this.data.finalPos=d(this).offset()});m.each(function(){this.data.finalPrePos=d(this).offset()});a.newHeight=n.height();c&&x("reset",null,b,a);q.hide();m.css("display",a.origDisplay);"block"==a.origDisplay?(b.addClass(a.listClass),q.css("display",a.targetDisplayList)):(b.removeClass(a.listClass),q.css("display",
-a.targetDisplayGrid));a.resizeContainer&&n.css("height",a.origHeight+"px");e={};for(g=0;2>g;g++)h=0==g?h=a.prefix:"",e[h+"transform"]=a.scale+" "+a.rotateX+" "+a.rotateY+" "+a.rotateZ,e[h+"filter"]=a.blur+" "+a.grayscale;q.css(e);m.each(function(){var b=this.data,c=d(this);c.hasClass("mix_tohide")?(b.preTX=b.origPos.left-b.hideInterPos.left,b.preTY=b.origPos.top-b.hideInterPos.top):(b.preTX=b.origPos.left-b.preInterPos.left,b.preTY=b.origPos.top-b.preInterPos.top);for(var e={},k=0;2>k;k++){var h=
-0==k?h=a.prefix:"";e[h+"transform"]="translate("+b.preTX+"px,"+b.preTY+"px)"}c.css(e)});"list"==a.layoutMode?(b.addClass(a.listClass),b.removeClass(a.gridClass)):(b.addClass(a.gridClass),b.removeClass(a.listClass));setTimeout(function(){if(a.resizeContainer){for(var b={},c=0;2>c;c++){var e=0==c?e=a.prefix:"";b[e+"transition"]="all "+k+"ms ease-in-out";b.height=a.newHeight+"px"}n.css(b)}u.css("opacity",a.fade);q.css("opacity",1);q.each(function(){var b=this.data;b.tX=b.finalPos.left-b.showInterPos.left;
-b.tY=b.finalPos.top-b.showInterPos.top;for(var c={},e=0;2>e;e++){var h=0==e?h=a.prefix:"";c[h+"transition-property"]=h+"transform, "+h+"filter, opacity";c[h+"transition-timing-function"]=a.easing+", linear, linear";c[h+"transition-duration"]=k+"ms";c[h+"transition-delay"]="0";c[h+"transform"]="translate("+b.tX+"px,"+b.tY+"px)";c[h+"filter"]="none"}d(this).css("-webkit-transition","all "+k+"ms "+a.easingFallback).css(c)});m.each(function(){var b=this.data;b.tX=0!=b.finalPrePos.left?b.finalPrePos.left-
-b.preInterPos.left:0;b.tY=0!=b.finalPrePos.left?b.finalPrePos.top-b.preInterPos.top:0;for(var c={},e=0;2>e;e++){var h=0==e?h=a.prefix:"";c[h+"transition"]="all "+k+"ms "+a.easing;c[h+"transform"]="translate("+b.tX+"px,"+b.tY+"px)"}d(this).css("-webkit-transition","all "+k+"ms "+a.easingFallback).css(c)});b={};for(c=0;2>c;c++)e=0==c?e=a.prefix:"",b[e+"transition"]="all "+k+"ms "+a.easing+", "+e+"filter "+k+"ms linear, opacity "+k+"ms linear",b[e+"transform"]=a.scale+" "+a.rotateX+" "+a.rotateY+" "+
-a.rotateZ,b[e+"filter"]=a.blur+" "+a.grayscale,b.opacity=a.fade;u.css(b);n.bind("webkitTransitionEnd transitionend otransitionend oTransitionEnd",function(a){if(-1<a.originalEvent.propertyName.indexOf("transform")||-1<a.originalEvent.propertyName.indexOf("opacity"))-1<w.indexOf(".")?d(a.target).hasClass(w.replace(".",""))&&f():d(a.target).is(w)&&f()})},10);a.failsafe=setTimeout(function(){a.mixing&&f()},k+400)}else{a.resizeContainer&&n.css("height",a.origHeight+"px");if(!window.atob)return f(),!1;
-u=s;setTimeout(function(){n.css(a.perspective);if(a.resizeContainer){for(var c={},e=0;2>e;e++){var d=0==e?d=a.prefix:"";c[d+"transition"]="height "+k+"ms ease-in-out";c.height=a.minHeight+"px"}n.css(c)}v.css(a.transition);if(s.length){c={};for(e=0;2>e;e++)d=0==e?d=a.prefix:"",c[d+"transform"]=a.scale+" "+a.rotateX+" "+a.rotateY+" "+a.rotateZ,c[d+"filter"]=a.blur+" "+a.grayscale,c.opacity=a.fade;u.css(c);n.bind("webkitTransitionEnd transitionend otransitionend oTransitionEnd",function(c){if(-1<c.originalEvent.propertyName.indexOf("transform")||
--1<c.originalEvent.propertyName.indexOf("opacity"))b.addClass(a.failClass),f()})}else a.mixing=!1},10)}}function x(e,c,l,b){function a(a,b){var c=isNaN(1*a.attr(e))?a.attr(e).toLowerCase():1*a.attr(e),d=isNaN(1*b.attr(e))?b.attr(e).toLowerCase():1*b.attr(e);return c<d?-1:c>d?1:0}function f(a){"asc"==c?k.prepend(a).prepend(" "):k.append(a).append(" ")}function g(a){a=a.slice();for(var b=a.length,c=b;c--;){var e=parseInt(Math.random()*b),d=a[c];a[c]=a[e];a[e]=d}return a}l.find(b.targetSelector).wrapAll('<div class="mix_sorter"/>');
-var k=l.find(".mix_sorter");b.origSort.length||k.find(b.targetSelector+":visible").each(function(){d(this).wrap("<s/>");b.origSort.push(d(this).parent().html().replace(/\s+/g,""));d(this).unwrap()});k.empty();if("reset"==e)d.each(b.startOrder,function(){k.append(this).append(" ")});else if("default"==e)d.each(b.origOrder,function(){f(this)});else if("random"==e)b.newOrder.length||(b.newOrder=g(b.startOrder)),d.each(b.newOrder,function(){k.append(this).append(" ")});else if("custom"==e)d.each(c,function(){f(this)});
-else{if("undefined"===typeof b.origOrder[0].attr(e))return console.log("No such attribute found. Terminating"),!1;b.newOrder.length||(d.each(b.origOrder,function(){b.newOrder.push(d(this))}),b.newOrder.sort(a));d.each(b.newOrder,function(){f(this)})}b.checkSort=[];k.find(b.targetSelector+":visible").each(function(a){var c=d(this);0==a&&c.attr("data-checksum","1");c.wrap("<s/>");b.checkSort.push(c.parent().html().replace(/\s+/g,""));c.unwrap()});l.find(b.targetSelector).unwrap()}function B(e){for(var c=
-["Webkit","Moz","O","ms"],d=0;d<c.length;d++)if(c[d]+"Transition"in e.style)return c[d];return"transition"in e.style?"":!1}function A(e,c){if(e.length!=c.length)return!1;for(var d=0;d<c.length;d++)if(e[d].compare&&!e[d].compare(c[d])||e[d]!==c[d])return!1;return!0}function z(e){e=e.replace(/\s{2,}/g," ");var c=e.split(" ");d.each(c,function(d){"all"==this&&(c[d]="mix_all")});""==c[0]&&c.shift();return c}var y={init:function(e){return this.each(function(){var c=window.navigator.appVersion.match(/Chrome\/(\d+)\./),
-c=c?parseInt(c[1],10):!1,l=function(a){a=document.getElementById(a);var b=a.parentElement,c=document.createElement("div"),d=document.createDocumentFragment();b.insertBefore(c,a);d.appendChild(a);b.replaceChild(a,c)};(c&&31==c||32==c)&&l(this.id);var b={targetSelector:".mix",filterSelector:".filter",sortSelector:".sort",buttonEvent:"click",effects:["fade","scale"],listEffects:null,easing:"smooth",layoutMode:"grid",targetDisplayGrid:"inline-block",targetDisplayList:"block",listClass:"",gridClass:"",
-transitionSpeed:600,showOnLoad:"all",sortOnLoad:!1,multiFilter:!1,filterLogic:"or",resizeContainer:!0,minHeight:0,failClass:"fail",perspectiveDistance:"3000",perspectiveOrigin:"50% 50%",animateGridList:!0,onMixLoad:null,onMixStart:null,onMixEnd:null,container:null,origOrder:[],startOrder:[],newOrder:[],origSort:[],checkSort:[],filter:"",mixing:!1,origDisplay:"",origLayout:"",origHeight:0,newHeight:0,isTouch:!1,resetDelay:0,failsafe:null,prefix:"",easingFallback:"ease-in-out",transition:{},perspective:{},
-clean:{},fade:"1",scale:"",rotateX:"",rotateY:"",rotateZ:"",blur:"",grayscale:""};e&&d.extend(b,e);this.config=b;d.support.touch="ontouchend"in document;d.support.touch&&(b.isTouch=!0,b.resetDelay=350);b.container=d(this);var a=b.container;b.prefix=B(a[0]);b.prefix=b.prefix?"-"+b.prefix.toLowerCase()+"-":"";a.find(b.targetSelector).each(function(){b.origOrder.push(d(this))});if(b.sortOnLoad){var f;d.isArray(b.sortOnLoad)?(c=b.sortOnLoad[0],f=b.sortOnLoad[1],d(b.sortSelector+"[data-sort="+b.sortOnLoad[0]+
-"][data-order="+b.sortOnLoad[1]+"]").addClass("active")):(d(b.sortSelector+"[data-sort="+b.sortOnLoad+"]").addClass("active"),c=b.sortOnLoad,b.sortOnLoad="desc");x(c,f,a,b)}for(f=0;2>f;f++)c=0==f?c=b.prefix:"",b.transition[c+"transition"]="all "+b.transitionSpeed+"ms ease-in-out",b.perspective[c+"perspective"]=b.perspectiveDistance+"px",b.perspective[c+"perspective-origin"]=b.perspectiveOrigin;for(f=0;2>f;f++)c=0==f?c=b.prefix:"",b.clean[c+"transition"]="none";"list"==b.layoutMode?(a.addClass(b.listClass),
-b.origDisplay=b.targetDisplayList):(a.addClass(b.gridClass),b.origDisplay=b.targetDisplayGrid);b.origLayout=b.layoutMode;f=b.showOnLoad.split(" ");d.each(f,function(){d(b.filterSelector+'[data-filter="'+this+'"]').addClass("active")});a.find(b.targetSelector).addClass("mix_all");"all"==f[0]&&(f[0]="mix_all",b.showOnLoad="mix_all");var g=d();d.each(f,function(){g=g.add(d("."+this))});g.each(function(){var a=d(this);"list"==b.layoutMode?a.css("display",b.targetDisplayList):a.css("display",b.targetDisplayGrid);
-a.css(b.transition)});setTimeout(function(){b.mixing=!0;g.css("opacity","1");setTimeout(function(){"list"==b.layoutMode?g.removeStyle(b.prefix+"transition, transition").css({display:b.targetDisplayList,opacity:1}):g.removeStyle(b.prefix+"transition, transition").css({display:b.targetDisplayGrid,opacity:1});b.mixing=!1;if("function"==typeof b.onMixLoad){var a=b.onMixLoad.call(this,b);b=a?a:b}},b.transitionSpeed)},10);b.filter=b.showOnLoad;d(b.sortSelector).bind(b.buttonEvent,function(){if(!b.mixing){var c=
-d(this),e=c.attr("data-sort"),f=c.attr("data-order");if(!c.hasClass("active"))d(b.sortSelector).removeClass("active"),c.addClass("active");else if("random"!=e)return!1;a.find(b.targetSelector).each(function(){b.startOrder.push(d(this))});r(b.filter,e,f,a,b)}});d(b.filterSelector).bind(b.buttonEvent,function(){if(!b.mixing){var c=d(this);if(!1==b.multiFilter)d(b.filterSelector).removeClass("active"),c.addClass("active"),b.filter=c.attr("data-filter"),d(b.filterSelector+'[data-filter="'+b.filter+'"]').addClass("active");
-else{var e=c.attr("data-filter");c.hasClass("active")?(c.removeClass("active"),b.filter=b.filter.replace(RegExp("(\\s|^)"+e),"")):(c.addClass("active"),b.filter=b.filter+" "+e)}r(b.filter,null,null,a,b)}})})},toGrid:function(){return this.each(function(){var e=this.config;"grid"!=e.layoutMode&&(e.layoutMode="grid",r(e.filter,null,null,d(this),e))})},toList:function(){return this.each(function(){var e=this.config;"list"!=e.layoutMode&&(e.layoutMode="list",r(e.filter,null,null,d(this),e))})},filter:function(e){return this.each(function(){var c=
-this.config;c.mixing||(d(c.filterSelector).removeClass("active"),d(c.filterSelector+'[data-filter="'+e+'"]').addClass("active"),r(e,null,null,d(this),c))})},sort:function(e){return this.each(function(){var c=this.config,l=d(this);if(!c.mixing){d(c.sortSelector).removeClass("active");if(d.isArray(e)){var b=e[0],a=e[1];d(c.sortSelector+'[data-sort="'+e[0]+'"][data-order="'+e[1]+'"]').addClass("active")}else d(c.sortSelector+'[data-sort="'+e+'"]').addClass("active"),b=e,a="desc";l.find(c.targetSelector).each(function(){c.startOrder.push(d(this))});
-r(c.filter,b,a,l,c)}})},multimix:function(e){return this.each(function(){var c=this.config,l=d(this);multiOut={filter:c.filter,sort:null,order:"desc",layoutMode:c.layoutMode};d.extend(multiOut,e);c.mixing||(d(c.filterSelector).add(c.sortSelector).removeClass("active"),d(c.filterSelector+'[data-filter="'+multiOut.filter+'"]').addClass("active"),"undefined"!==typeof multiOut.sort&&(d(c.sortSelector+'[data-sort="'+multiOut.sort+'"][data-order="'+multiOut.order+'"]').addClass("active"),l.find(c.targetSelector).each(function(){c.startOrder.push(d(this))})),
-c.layoutMode=multiOut.layoutMode,r(multiOut.filter,multiOut.sort,multiOut.order,l,c))})},remix:function(e){return this.each(function(){var c=this.config,l=d(this);c.origOrder=[];l.find(c.targetSelector).each(function(){var b=d(this);b.addClass("mix_all");c.origOrder.push(b)});c.mixing||"undefined"===typeof e||(d(c.filterSelector).removeClass("active"),d(c.filterSelector+'[data-filter="'+e+'"]').addClass("active"),r(e,null,null,l,c))})}};d.fn.mixitup=function(d,c){if(y[d])return y[d].apply(this,Array.prototype.slice.call(arguments,
-1));if("object"===typeof d||!d)return y.init.apply(this,arguments)};d.fn.removeStyle=function(e){return this.each(function(){var c=d(this);e=e.replace(/\s+/g,"");var l=e.split(",");d.each(l,function(){var b=RegExp(this.toString()+"[^;]+;?","g");c.attr("style",function(a,c){if(c)return c.replace(b,"")})})})}})(jQuery); \ No newline at end of file
+ Non-commercial use permitted under terms of CC-BY-NC license.
+ http://creativecommons.org/licenses/by-nc/3.0/
+*/
+(function(f,l){f.MixItUp=function(){this._execAction("_constructor",0);f.extend(this,{selectors:{target:".mix",filter:".filter",sort:".sort"},animation:{enable:!0,effects:"fade scale",duration:600,easing:"ease",perspectiveDistance:"3000",perspectiveOrigin:"50% 50%",queue:!0,queueLimit:1,animateChangeLayout:!1,animateResizeContainer:!0,animateResizeTargets:!1,staggerSequence:!1,reverseOut:!1},callbacks:{onMixLoad:!1,onMixStart:!1,onMixBusy:!1,onMixEnd:!1,onMixFail:!1,_user:!1},controls:{enable:!0,
+live:!1,toggleFilterButtons:!1,toggleLogic:"or",activeClass:"active"},layout:{display:"inline-block",containerClass:"",containerClassFail:"fail"},load:{filter:"all",sort:!1},_$body:null,_$container:null,_$targets:null,_$parent:null,_$sortButtons:null,_$filterButtons:null,_suckMode:!1,_mixing:!1,_sorting:!1,_clicking:!1,_loading:!0,_changingLayout:!1,_changingClass:!1,_changingDisplay:!1,_origOrder:[],_startOrder:[],_newOrder:[],_activeFilter:null,_toggleArray:[],_toggleString:"",_activeSort:"default:asc",
+_newSort:null,_startHeight:null,_newHeight:null,_incPadding:!0,_newDisplay:null,_newClass:null,_targetsBound:0,_targetsDone:0,_queue:[],_$show:f(),_$hide:f()});this._execAction("_constructor",1)};f.MixItUp.prototype={constructor:f.MixItUp,_instances:{},_handled:{_filter:{},_sort:{}},_bound:{_filter:{},_sort:{}},_actions:{},_filters:{},extend:function(a){for(var c in a)f.MixItUp.prototype[c]=a[c]},addAction:function(a,c,b,d){f.MixItUp.prototype._addHook("_actions",a,c,b,d)},addFilter:function(a,c,
+b,d){f.MixItUp.prototype._addHook("_filters",a,c,b,d)},_addHook:function(a,c,b,d,e){a=f.MixItUp.prototype[a];var g={};e=1===e||"post"===e?"post":"pre";g[c]={};g[c][e]={};g[c][e][b]=d;f.extend(!0,a,g)},_init:function(a,c){this._execAction("_init",0,arguments);c&&f.extend(!0,this,c);this._$body=f("body");this._domNode=a;this._$container=f(a);this._$container.addClass(this.layout.containerClass);this._id=a.id;this._platformDetect();this._brake=this._getPrefixedCSS("transition","none");this._refresh(!0);
+this._$parent=this._$targets.parent().length?this._$targets.parent():this._$container;this.load.sort&&(this._newSort=this._parseSort(this.load.sort),this._activeSort=this._newSortString=this.load.sort,this._sort(),this._printSort());this._activeFilter="all"===this.load.filter?this.selectors.target:"none"===this.load.filter?"":this.load.filter;this.controls.enable&&this._bindHandlers();if(this.controls.toggleFilterButtons){this._buildToggleArray();for(var b=0;b<this._toggleArray.length;b++)this._updateControls({filter:this._toggleArray[b],
+sort:this._activeSort},!0)}else this.controls.enable&&this._updateControls({filter:this._activeFilter,sort:this._activeSort});this._filter();this._init=!0;this._$container.data("mixItUp",this);this._execAction("_init",1,arguments);this._buildState();this._$targets.css(this._brake);this._goMix(this.animation.enable)},_platformDetect:function(){var a=["Webkit","Moz","O","ms"],c=["webkit","moz"],b=window.navigator.appVersion.match(/Chrome\/(\d+)\./)||!1,d="undefined"!==typeof InstallTrigger,e=function(b){for(var c=
+0;c<a.length;c++)if(a[c]+"Transition"in b.style)return{prefix:"-"+a[c].toLowerCase()+"-",vendor:a[c]};return"transition"in b.style?"":!1}(this._domNode);this._execAction("_platformDetect",0);this._chrome=b?parseInt(b[1],10):!1;this._ff=d?parseInt(window.navigator.userAgent.match(/rv:([^)]+)\)/)[1]):!1;this._prefix=e.prefix;this._vendor=e.vendor;(this._suckMode=window.atob&&this._prefix?!1:!0)&&(this.animation.enable=!1);this._ff&&4>=this._ff&&(this.animation.enable=!1);for(b=0;b<c.length&&!window.requestAnimationFrame;b++)window.requestAnimationFrame=
+window[c[b]+"RequestAnimationFrame"];"function"!==typeof Object.getPrototypeOf&&(Object.getPrototypeOf="object"===typeof"test".__proto__?function(a){return a.__proto__}:function(a){return a.constructor.prototype});this._domNode.nextElementSibling===l&&Object.defineProperty(Element.prototype,"nextElementSibling",{get:function(){for(var a=this.nextSibling;a;){if(1===a.nodeType)return a;a=a.nextSibling}return null}});this._execAction("_platformDetect",1)},_refresh:function(a,c){this._execAction("_refresh",
+0,arguments);this._$targets=this._$container.find(this.selectors.target);for(var b=0;b<this._$targets.length;b++){var d=this._$targets[b];if(d.dataset===l||c){d.dataset={};for(var e=0;e<d.attributes.length;e++){var g=d.attributes[e],k=g.name,g=g.value;-1<k.indexOf("data-")&&(k=this._helpers._camelCase(k.substring(5,k.length)),d.dataset[k]=g)}}d.mixParent===l&&(d.mixParent=this._id)}if(this._$targets.length&&a||!this._origOrder.length&&this._$targets.length)for(this._origOrder=[],b=0;b<this._$targets.length;b++)d=
+this._$targets[b],this._origOrder.push(d);this._execAction("_refresh",1,arguments)},_bindHandlers:function(){var a=this,c=f.MixItUp.prototype._bound._filter,b=f.MixItUp.prototype._bound._sort;a._execAction("_bindHandlers",0);if(a.controls.live)a._$body.on("click.mixItUp."+a._id,a.selectors.sort,function(){a._processClick(f(this),"sort")}).on("click.mixItUp."+a._id,a.selectors.filter,function(){a._processClick(f(this),"filter")});else a._$sortButtons=f(a.selectors.sort),a._$filterButtons=f(a.selectors.filter),
+a._$sortButtons.on("click.mixItUp."+a._id,function(){a._processClick(f(this),"sort")}),a._$filterButtons.on("click.mixItUp."+a._id,function(){a._processClick(f(this),"filter")});c[a.selectors.filter]=c[a.selectors.filter]===l?1:c[a.selectors.filter]+1;b[a.selectors.sort]=b[a.selectors.sort]===l?1:b[a.selectors.sort]+1;a._execAction("_bindHandlers",1)},_processClick:function(a,c){var b=this,d=function(a,c,d){var e=f.MixItUp.prototype;e._handled["_"+c][b.selectors[c]]=e._handled["_"+c][b.selectors[c]]===
+l?1:e._handled["_"+c][b.selectors[c]]+1;e._handled["_"+c][b.selectors[c]]===e._bound["_"+c][b.selectors[c]]&&(a[(d?"remove":"add")+"Class"](b.controls.activeClass),delete e._handled["_"+c][b.selectors[c]])};b._execAction("_processClick",0,arguments);if(!b._mixing||b.animation.queue&&b._queue.length<b.animation.queueLimit){b._clicking=!0;if("sort"===c){var e=a.attr("data-sort");if(!a.hasClass(b.controls.activeClass)||-1<e.indexOf("random"))f(b.selectors.sort).removeClass(b.controls.activeClass),d(a,
+c),b.sort(e)}if("filter"===c){var g=a.attr("data-filter"),e="or"===b.controls.toggleLogic?",":"";b.controls.toggleFilterButtons?(b._buildToggleArray(),a.hasClass(b.controls.activeClass)?(d(a,c,!0),d=b._toggleArray.indexOf(g),b._toggleArray.splice(d,1)):(d(a,c),b._toggleArray.push(g)),b._toggleArray=f.grep(b._toggleArray,function(a){return a}),b._toggleString=b._toggleArray.join(e),b.filter(b._toggleString)):a.hasClass(b.controls.activeClass)||(f(b.selectors.filter).removeClass(b.controls.activeClass),
+d(a,c),b.filter(g))}b._execAction("_processClick",1,arguments)}else"function"===typeof b.callbacks.onMixBusy&&b.callbacks.onMixBusy.call(b._domNode,b._state,b),b._execAction("_processClickBusy",1,arguments)},_buildToggleArray:function(){var a=this._activeFilter.replace(/\s/g,"");this._execAction("_buildToggleArray",0,arguments);if("or"===this.controls.toggleLogic)this._toggleArray=a.split(",");else{this._toggleArray=a.split(".");!this._toggleArray[0]&&this._toggleArray.shift();for(var a=0,c;c=this._toggleArray[a];a++)this._toggleArray[a]=
+"."+c}this._execAction("_buildToggleArray",1,arguments)},_updateControls:function(a,c){var b={filter:a.filter,sort:a.sort},d="filter",e=null;this._execAction("_updateControls",0,arguments);a.filter===l&&(b.filter=this._activeFilter);a.sort===l&&(b.sort=this._activeSort);b.filter===this.selectors.target&&(b.filter="all");for(var g=0;2>g;g++){if(e=this.controls.live?f(this.selectors[d]):this["_$"+d+"Buttons"]){var k="[data-"+d+'="'+b[d]+'"]';c&&"filter"===d&&"none"!==b.filter&&""!==b.filter?e.filter(k).addClass(this.controls.activeClass):
+e.removeClass(this.controls.activeClass).filter(k).addClass(this.controls.activeClass)}d="sort"}this._execAction("_updateControls",1,arguments)},_filter:function(){this._execAction("_filter",0);for(var a=0;a<this._$targets.length;a++){var c=f(this._$targets[a]);c.is(this._activeFilter)?this._$show=this._$show.add(c):this._$hide=this._$hide.add(c)}this._execAction("_filter",1)},_sort:function(){var a=this,c=function(a){a=a.slice();for(var b=a.length,c=b;c--;){var f=parseInt(Math.random()*b),h=a[c];
+a[c]=a[f];a[f]=h}return a};a._execAction("_sort",0);a._startOrder=[];for(var b=0;b<a._$targets.length;b++)a._startOrder.push(a._$targets[b]);switch(a._newSort[0].sortBy){case "default":a._newOrder=a._origOrder;break;case "random":a._newOrder=c(a._startOrder);break;case "custom":a._newOrder=a._newSort[0].order;break;default:a._newOrder=a._startOrder.concat().sort(function(b,c){return a._compare(b,c)})}a._execAction("_sort",1)},_compare:function(a,c,b){b=b?b:0;var d=this,e=d._newSort[b].order,g=function(a){return a.dataset[d._newSort[b].sortBy]||
+0},f=isNaN(1*g(a))?g(a).toLowerCase():1*g(a),g=isNaN(1*g(c))?g(c).toLowerCase():1*g(c);return f<g?"asc"===e?-1:1:f>g?"asc"===e?1:-1:f===g&&d._newSort.length>b+1?d._compare(a,c,b+1):0},_printSort:function(a){var c=a?this._startOrder:this._newOrder,b=this._$parent[0].querySelectorAll(this.selectors.target),d=b.length?b[b.length-1].nextElementSibling:null,e=document.createDocumentFragment();this._execAction("_printSort",0,arguments);for(var g=0;g<b.length;g++){var f=b[g],h=f.nextSibling;"absolute"!==
+f.style.position&&(h&&"#text"===h.nodeName&&this._$parent[0].removeChild(h),this._$parent[0].removeChild(f))}for(g=0;g<c.length;g++)b=c[g],"default"!==this._newSort[0].sortBy||"desc"!==this._newSort[0].order||a?(e.appendChild(b),e.appendChild(document.createTextNode(" "))):(e.insertBefore(b,e.firstChild),e.insertBefore(document.createTextNode(" "),b));d?this._$parent[0].insertBefore(e,d):this._$parent[0].appendChild(e);this._execAction("_printSort",1,arguments)},_parseSort:function(a){for(var c="string"===
+typeof a?a.split(" "):[a],b=[],d=0;d<c.length;d++){var e="string"===typeof a?c[d].split(":"):["custom",c[d]],e={sortBy:this._helpers._camelCase(e[0]),order:e[1]||"asc"};b.push(e);if("default"===e.sortBy||"random"===e.sortBy)break}return this._execFilter("_parseSort",b,arguments)},_parseEffects:function(){var a=this,c={opacity:"",transformIn:"",transformOut:"",filter:""},b=function(b,c,d){return-1<a.animation.effects.indexOf(b)?c&&(b=a.animation.effects.indexOf(b+"("),-1<b)?(b=a.animation.effects.substring(b),
+{val:/\(([^)]+)\)/.exec(b)[1]}):!0:!1},d=function(a,d){for(var f=[["scale",".01"],["translateX","20px"],["translateY","20px"],["translateZ","20px"],["rotateX","90deg"],["rotateY","90deg"],["rotateZ","180deg"]],h=0;h<f.length;h++){var m=f[h][0],l=f[h][1],p=d&&"scale"!==m,q=c[a],n;b(m)?(n=m+"(",m=b(m,!0).val||l,p=p?"-"===m.charAt(0)?m.substr(1,m.length):"-"+m:m,n=n+p+") "):n="";c[a]=q+n}};c.opacity=b("fade")?b("fade",!0).val||"0":"1";d("transformIn");a.animation.reverseOut?d("transformOut",!0):c.transformOut=
+c.transformIn;c.transition={};c.transition=a._getPrefixedCSS("transition","all "+a.animation.duration+"ms "+a.animation.easing+", opacity "+a.animation.duration+"ms linear");a.animation.stagger=b("stagger")?!0:!1;a.animation.staggerDuration=parseInt(b("stagger")?b("stagger",!0).val?b("stagger",!0).val:100:100);return a._execFilter("_parseEffects",c)},_buildState:function(a){var c={};this._execAction("_buildState",0);c={activeFilter:""===this._activeFilter?"none":this._activeFilter,activeSort:a&&this._newSortString?
+this._newSortString:this._activeSort,fail:!this._$show.length&&""!==this._activeFilter,$targets:this._$targets,$show:this._$show,$hide:this._$hide,totalTargets:this._$targets.length,totalShow:this._$show.length,totalHide:this._$hide.length,display:a&&this._newDisplay?this._newDisplay:this.layout.display};if(a)return this._execFilter("_buildState",c);this._state=c;this._execAction("_buildState",1)},_goMix:function(a){var c=this,b=function(){if(c._chrome&&31===c._chrome){var a=c._$parent[0],b=a.parentElement,
+e=document.createElement("div"),f=document.createDocumentFragment();b.insertBefore(e,a);f.appendChild(a);b.replaceChild(a,e)}c._setInter();d()},d=function(){var a=window.pageYOffset,b=window.pageXOffset;c._getInterMixData();c._setFinal();c._getFinalMixData();window.pageYOffset!==a&&window.scrollTo(b,a);c._prepTargets();window.requestAnimationFrame?requestAnimationFrame(e):setTimeout(function(){e()},20)},e=function(){c._animateTargets();0===c._targetsBound&&c._cleanUp()},f=c._buildState(!0);c._execAction("_goMix",
+0,arguments);!c.animation.duration&&(a=!1);c._mixing=!0;c._$container.removeClass(c.layout.containerClassFail);"function"===typeof c.callbacks.onMixStart&&c.callbacks.onMixStart.call(c._domNode,c._state,f,c);c._$container.trigger("mixStart",[c._state,f,c]);c._getOrigMixData();a&&!c._suckMode?window.requestAnimationFrame?requestAnimationFrame(b):b():c._cleanUp();c._execAction("_goMix",1,arguments)},_getTargetData:function(a,c){var b;a.dataset[c+"PosX"]=a.offsetLeft;a.dataset[c+"PosY"]=a.offsetTop;
+this.animation.animateResizeTargets&&(b=window.getComputedStyle(a),a.dataset[c+"MarginBottom"]=parseInt(b.marginBottom),a.dataset[c+"MarginRight"]=parseInt(b.marginRight),a.dataset[c+"Width"]=a.offsetWidth,a.dataset[c+"Height"]=a.offsetHeight)},_getOrigMixData:function(){var a=this._suckMode?{boxSizing:""}:window.getComputedStyle(this._$parent[0]);this._incPadding="border-box"===(a.boxSizing||a[this._vendor+"BoxSizing"]);this._execAction("_getOrigMixData",0);!this._suckMode&&(this.effects=this._parseEffects());
+this._$toHide=this._$hide.filter(":visible");this._$toShow=this._$show.filter(":hidden");this._$pre=this._$targets.filter(":visible");this._startHeight=this._incPadding?this._$parent.outerHeight():this._$parent.height();for(a=0;a<this._$pre.length;a++)this._getTargetData(this._$pre[a],"orig");this._execAction("_getOrigMixData",1)},_setInter:function(){this._execAction("_setInter",0);this._changingLayout&&this.animation.animateChangeLayout?(this._$toShow.css("display",this._newDisplay),this._changingClass&&
+this._$container.removeClass(this.layout.containerClass).addClass(this._newClass)):this._$toShow.css("display",this.layout.display);this._execAction("_setInter",1)},_getInterMixData:function(){this._execAction("_getInterMixData",0);for(var a=0;a<this._$toShow.length;a++){var c=this._$toShow[a];this._getTargetData(c,"inter")}for(a=0;a<this._$pre.length;a++)c=this._$pre[a],this._getTargetData(c,"inter");this._execAction("_getInterMixData",1)},_setFinal:function(){this._execAction("_setFinal",0);this._sorting&&
+this._printSort();this._$toHide.removeStyle("display");this._changingLayout&&this.animation.animateChangeLayout&&this._$pre.css("display",this._newDisplay);this._execAction("_setFinal",1)},_getFinalMixData:function(){this._execAction("_getFinalMixData",0);for(var a=0;a<this._$toShow.length;a++){var c=this._$toShow[a];this._getTargetData(c,"final")}for(a=0;a<this._$pre.length;a++)c=this._$pre[a],this._getTargetData(c,"final");this._newHeight=this._incPadding?this._$parent.outerHeight():this._$parent.height();
+this._sorting&&this._printSort(!0);this._$toShow.removeStyle("display");this._$pre.css("display",this.layout.display);this._changingClass&&this.animation.animateChangeLayout&&this._$container.removeClass(this._newClass).addClass(this.layout.containerClass);this._execAction("_getFinalMixData",1)},_prepTargets:function(){var a={_in:this._getPrefixedCSS("transform",this.effects.transformIn),_out:this._getPrefixedCSS("transform",this.effects.transformOut)};this._execAction("_prepTargets",0);this.animation.animateResizeContainer&&
+this._$parent.css("height",this._startHeight+"px");for(var c=0;c<this._$toShow.length;c++){var b=this._$toShow[c],d=f(b);b.style.opacity=this.effects.opacity;b.style.display=this._changingLayout&&this.animation.animateChangeLayout?this._newDisplay:this.layout.display;d.css(a._in);this.animation.animateResizeTargets&&(b.style.width=b.dataset.finalWidth+"px",b.style.height=b.dataset.finalHeight+"px",b.style.marginRight=-(b.dataset.finalWidth-b.dataset.interWidth)+1*b.dataset.finalMarginRight+"px",b.style.marginBottom=
+-(b.dataset.finalHeight-b.dataset.interHeight)+1*b.dataset.finalMarginBottom+"px")}for(c=0;c<this._$pre.length;c++)b=this._$pre[c],d=f(b),a=this._getPrefixedCSS("transform","translate("+(b.dataset.origPosX-b.dataset.interPosX)+"px,"+(b.dataset.origPosY-b.dataset.interPosY)+"px)"),d.css(a),this.animation.animateResizeTargets&&(b.style.width=b.dataset.origWidth+"px",b.style.height=b.dataset.origHeight+"px",b.dataset.origWidth-b.dataset.finalWidth&&(b.style.marginRight=-(b.dataset.origWidth-b.dataset.interWidth)+
+1*b.dataset.origMarginRight+"px"),b.dataset.origHeight-b.dataset.finalHeight&&(b.style.marginBottom=-(b.dataset.origHeight-b.dataset.interHeight)+1*b.dataset.origMarginBottom+"px"));this._execAction("_prepTargets",1)},_animateTargets:function(){var a,c;this._execAction("_animateTargets",0);this._targetsBound=this._targetsDone=0;this._$parent.css(this._getPrefixedCSS("perspective",this.animation.perspectiveDistance+"px")).css(this._getPrefixedCSS("perspective-origin",this.animation.perspectiveOrigin));
+this.animation.animateResizeContainer&&this._$parent.css(this._getPrefixedCSS("transition","height "+this.animation.duration+"ms ease")).css("height",this._newHeight+"px");for(var b=0;b<this._$toShow.length;b++){var d=this._$toShow[b],e=f(d);a=d.dataset.finalPosX-d.dataset.interPosX;c=d.dataset.finalPosY-d.dataset.interPosY;var g=this._getDelay(b),k={};d.style.opacity="";for(d=0;2>d;d++){var h=0===d?h=this._prefix:"";this._ff&&20>=this._ff&&(k[h+"transition-property"]="all",k[h+"transition-timing-function"]=
+this.animation.easing+"ms",k[h+"transition-duration"]=this.animation.duration+"ms");k[h+"transition-delay"]=g+"ms";k[h+"transform"]="translate("+a+"px,"+c+"px)"}(this.effects.transform||this.effects.opacity)&&this._bindTargetDone(e);this._ff&&20>=this._ff?e.css(k):e.css(this.effects.transition).css(k)}for(b=0;b<this._$pre.length;b++)d=this._$pre[b],e=f(d),a=d.dataset.finalPosX-d.dataset.interPosX,c=d.dataset.finalPosY-d.dataset.interPosY,g=this._getDelay(b),d.dataset.finalPosX===d.dataset.origPosX&&
+d.dataset.finalPosY===d.dataset.origPosY||this._bindTargetDone(e),e.css(this._getPrefixedCSS("transition","all "+this.animation.duration+"ms "+this.animation.easing+" "+g+"ms")),e.css(this._getPrefixedCSS("transform","translate("+a+"px,"+c+"px)")),this.animation.animateResizeTargets&&(d.dataset.origWidth-d.dataset.finalWidth&&1*d.dataset.finalWidth&&(d.style.width=d.dataset.finalWidth+"px",d.style.marginRight=-(d.dataset.finalWidth-d.dataset.interWidth)+1*d.dataset.finalMarginRight+"px"),d.dataset.origHeight-
+d.dataset.finalHeight&&1*d.dataset.finalHeight&&(d.style.height=d.dataset.finalHeight+"px",d.style.marginBottom=-(d.dataset.finalHeight-d.dataset.interHeight)+1*d.dataset.finalMarginBottom+"px"));this._changingClass&&this._$container.removeClass(this.layout.containerClass).addClass(this._newClass);for(b=0;b<this._$toHide.length;b++){d=this._$toHide[b];e=f(d);g=this._getDelay(b);a={};for(d=0;2>d;d++)h=0===d?h=this._prefix:"",a[h+"transition-delay"]=g+"ms",a[h+"transform"]=this.effects.transformOut,
+a.opacity=this.effects.opacity;e.css(this.effects.transition).css(a);(this.effects.transform||this.effects.opacity)&&this._bindTargetDone(e)}this._execAction("_animateTargets",1)},_bindTargetDone:function(a){var c=this,b=a[0];c._execAction("_bindTargetDone",0,arguments);b.dataset.bound||(b.dataset.bound=!0,c._targetsBound++,a.on("webkitTransitionEnd.mixItUp transitionend.mixItUp",function(d){(-1<d.originalEvent.propertyName.indexOf("transform")||-1<d.originalEvent.propertyName.indexOf("opacity"))&&
+f(d.originalEvent.target).is(c.selectors.target)&&(a.off(".mixItUp"),delete b.dataset.bound,c._targetDone())}));c._execAction("_bindTargetDone",1,arguments)},_targetDone:function(){this._execAction("_targetDone",0);this._targetsDone++;this._targetsDone===this._targetsBound&&this._cleanUp();this._execAction("_targetDone",1)},_cleanUp:function(){var a=this,c=a.animation.animateResizeTargets?"transform opacity width height margin-bottom margin-right":"transform opacity";unBrake=function(){a._$targets.removeStyle("transition",
+a._prefix)};a._execAction("_cleanUp",0);a._changingLayout?a._$show.css("display",a._newDisplay):a._$show.css("display",a.layout.display);a._$targets.css(a._brake);a._$targets.removeStyle(c,a._prefix).removeAttr("data-inter-pos-x data-inter-pos-y data-final-pos-x data-final-pos-y data-orig-pos-x data-orig-pos-y data-orig-height data-orig-width data-final-height data-final-width data-inter-width data-inter-height data-orig-margin-right data-orig-margin-bottom data-inter-margin-right data-inter-margin-bottom data-final-margin-right data-final-margin-bottom");
+a._$hide.removeStyle("display");a._$parent.removeStyle("height transition perspective-distance perspective perspective-origin-x perspective-origin-y perspective-origin perspectiveOrigin",a._prefix);a._sorting&&(a._printSort(),a._activeSort=a._newSortString,a._sorting=!1);a._changingLayout&&(a._changingDisplay&&(a.layout.display=a._newDisplay,a._changingDisplay=!1),a._changingClass&&(a._$parent.removeClass(a.layout.containerClass).addClass(a._newClass),a.layout.containerClass=a._newClass,a._changingClass=
+!1),a._changingLayout=!1);a._refresh();a._buildState();a._state.fail&&a._$container.addClass(a.layout.containerClassFail);a._$show=f();a._$hide=f();window.requestAnimationFrame&&requestAnimationFrame(unBrake);a._mixing=!1;"function"===typeof a.callbacks._user&&a.callbacks._user.call(a._domNode,a._state,a);"function"===typeof a.callbacks.onMixEnd&&a.callbacks.onMixEnd.call(a._domNode,a._state,a);a._$container.trigger("mixEnd",[a._state,a]);a._state.fail&&("function"===typeof a.callbacks.onMixFail&&
+a.callbacks.onMixFail.call(a._domNode,a._state,a),a._$container.trigger("mixFail",[a._state,a]));a._loading&&("function"===typeof a.callbacks.onMixLoad&&a.callbacks.onMixLoad.call(a._domNode,a._state,a),a._$container.trigger("mixLoad",[a._state,a]));a._queue.length&&(a._execAction("_queue",0),a.multiMix(a._queue[0][0],a._queue[0][1],a._queue[0][2]),a._queue.splice(0,1));a._execAction("_cleanUp",1);a._loading=!1},_getPrefixedCSS:function(a,c,b){var d={};for(i=0;2>i;i++){var e=0===i?this._prefix:"";
+b?d[e+a]=e+c:d[e+a]=c}return this._execFilter("_getPrefixedCSS",d,arguments)},_getDelay:function(a){var c="function"===typeof this.animation.staggerSequence?this.animation.staggerSequence.call(this._domNode,a,this._state):a;return this._execFilter("_getDelay",this.animation.stagger?c*this.animation.staggerDuration:0,arguments)},_parseMultiMixArgs:function(a){for(var c={command:null,animate:this.animation.enable,callback:null},b=0;b<a.length;b++){var d=a[b];null!==d&&("object"===typeof d||"string"===
+typeof d?c.command=d:"boolean"===typeof d?c.animate=d:"function"===typeof d&&(c.callback=d))}return this._execFilter("_parseMultiMixArgs",c,arguments)},_parseInsertArgs:function(a){for(var c={index:0,$object:f(),multiMix:{filter:this._state.activeFilter},callback:null},b=0;b<a.length;b++){var d=a[b];"number"===typeof d?c.index=d:"object"===typeof d&&d instanceof f?c.$object=d:"object"===typeof d&&this._helpers._isElement(d)?c.$object=f(d):"object"===typeof d&&null!==d?c.multiMix=d:"boolean"!==typeof d||
+d?"function"===typeof d&&(c.callback=d):c.multiMix=!1}return this._execFilter("_parseInsertArgs",c,arguments)},_execAction:function(a,c,b){c=c?"post":"pre";if(!this._actions.isEmptyObject&&this._actions.hasOwnProperty(a))for(var d in this._actions[a][c])this._actions[a][c][d].call(this,b)},_execFilter:function(a,c,b){if(!this._filters.isEmptyObject&&this._filters.hasOwnProperty(a))for(var d in this._filters[a])return this._filters[a][d].call(this,b);else return c},_helpers:{_camelCase:function(a){return a.replace(/-([a-z])/g,
+function(a){return a[1].toUpperCase()})},_isElement:function(a){return window.HTMLElement?a instanceof HTMLElement:null!==a&&1===a.nodeType&&"string"===a.nodeName}},isMixing:function(){return this._execFilter("isMixing",this._mixing)},filter:function(){var a=this._parseMultiMixArgs(arguments);this._clicking&&(this._toggleString="");this.multiMix({filter:a.command},a.animate,a.callback)},sort:function(){var a=this._parseMultiMixArgs(arguments);this.multiMix({sort:a.command},a.animate,a.callback)},
+changeLayout:function(){var a=this._parseMultiMixArgs(arguments);this.multiMix({changeLayout:a.command},a.animate,a.callback)},multiMix:function(){var a=this._parseMultiMixArgs(arguments);this._execAction("multiMix",0,arguments);if(this._mixing)this.animation.queue&&this._queue.length<this.animation.queueLimit?(this._queue.push(arguments),this.controls.enable&&!this._clicking&&this._updateControls(a.command),this._execAction("multiMixQueue",1,arguments)):("function"===typeof this.callbacks.onMixBusy&&
+this.callbacks.onMixBusy.call(this._domNode,this._state,this),this._$container.trigger("mixBusy",[this._state,this]),this._execAction("multiMixBusy",1,arguments));else{this.controls.enable&&!this._clicking&&(this.controls.toggleFilterButtons&&this._buildToggleArray(),this._updateControls(a.command,this.controls.toggleFilterButtons));2>this._queue.length&&(this._clicking=!1);delete this.callbacks._user;a.callback&&(this.callbacks._user=a.callback);var c=a.command.sort,b=a.command.filter,d=a.command.changeLayout;
+this._refresh();c&&(this._newSort=this._parseSort(c),this._newSortString=c,this._sorting=!0,this._sort());b!==l&&(this._activeFilter=b="all"===b?this.selectors.target:b);this._filter();d&&(this._newDisplay="string"===typeof d?d:d.display||this.layout.display,this._newClass=d.containerClass||"",this._newDisplay!==this.layout.display||this._newClass!==this.layout.containerClass)&&(this._changingLayout=!0,this._changingClass=this._newClass!==this.layout.containerClass,this._changingDisplay=this._newDisplay!==
+this.layout.display);this._$targets.css(this._brake);this._goMix(a.animate^this.animation.enable?a.animate:this.animation.enable);this._execAction("multiMix",1,arguments)}},insert:function(){var a=this._parseInsertArgs(arguments),c="function"===typeof a.callback?a.callback:null,b=document.createDocumentFragment(),d;this._refresh();d=this._$targets.length?a.index<this._$targets.length||!this._$targets.length?this._$targets[a.index]:this._$targets[this._$targets.length-1].nextElementSibling:this._$parent[0].children[0];
+this._execAction("insert",0,arguments);if(a.$object){for(var e=0;e<a.$object.length;e++)b.appendChild(a.$object[e]),b.appendChild(document.createTextNode(" "));this._$parent[0].insertBefore(b,d)}this._execAction("insert",1,arguments);"object"===typeof a.multiMix&&this.multiMix(a.multiMix,c)},prepend:function(){var a=this._parseInsertArgs(arguments);this.insert(0,a.$object,a.multiMix,a.callback)},append:function(){var a=this._parseInsertArgs(arguments);this.insert(this._state.totalTargets,a.$object,
+a.multiMix,a.callback)},getOption:function(a){var c=function(a,c){for(var e=c.split("."),f=e.pop(),k=e.length,h=1,m=e[0]||c;(a=a[m])&&h<k;)m=e[h],h++;if(a!==l)return a[f]!==l?a[f]:a};return a?this._execFilter("getOption",c(this,a),arguments):this},setOptions:function(a){this._execAction("setOptions",0,arguments);"object"===typeof a&&f.extend(!0,this,a);this._execAction("setOptions",1,arguments)},getState:function(){return this._execFilter("getState",this._state,this)},forceRefresh:function(){this._refresh(!1,
+!0)},destroy:function(a){this._execAction("destroy",0,arguments);this._$body.add(f(this.selectors.sort)).add(f(this.selectors.filter)).off(".mixItUp");for(var c=0;c<this._$targets.length;c++){var b=this._$targets[c];a&&(b.style.display="");delete b.mixParent}this._execAction("destroy",1,arguments);delete f.MixItUp.prototype._instances[this._id]}};f.fn.mixItUp=function(){var a=arguments,c=[],b,d=function(a,b){var c=new f.MixItUp;c._execAction("_instantiate",0,arguments);a.id=a.id?a.id:"MixItUp"+("00000"+
+(16777216*Math.random()<<0).toString(16)).substr(-6).toUpperCase();c._instances[a.id]||(c._instances[a.id]=c,c._init(a,b));c._execAction("_instantiate",1,arguments)};b=this.each(function(){if(a&&"string"===typeof a[0]){var b=f.MixItUp.prototype._instances[this.id];"isLoaded"===a[0]?c.push(b?!0:!1):(b=b[a[0]](a[1],a[2],a[3]),b!==l&&c.push(b))}else d(this,a[0])});return c.length?1<c.length?c:c[0]:b};f.fn.removeStyle=function(a,c){c=c?c:"";return this.each(function(){for(var b=a.split(" "),d=0;d<b.length;d++)for(var e=
+0;4>e;e++){switch(e){case 0:var g=b[d];break;case 1:g=f.MixItUp.prototype._helpers._camelCase(g);break;case 2:g=c+b[d];break;case 3:g=f.MixItUp.prototype._helpers._camelCase(c+b[d])}this.style[g]!==l&&"unknown"!==typeof this.style[g]&&0<this.style[g].length&&(this.style[g]="");if(!c&&1===e)break}this.attributes&&this.attributes.style&&this.attributes.style!==l&&""===this.attributes.style.value&&this.attributes.removeNamedItem("style")})}})(jQuery);
diff --git a/js/local-time.js b/js/local-time.js
index a4e25d6d..a821579f 100644
--- a/js/local-time.js
+++ b/js/local-time.js
@@ -13,7 +13,9 @@
*
*/
-onready(function(){
+$(document).ready(function(){
+ 'use strict';
+
var iso8601 = function(s) {
s = s.replace(/\.\d\d\d+/,""); // remove milliseconds
s = s.replace(/-/,"/").replace(/-/,"/");
@@ -36,28 +38,78 @@ onready(function(){
return strftime(window.post_date, t, datelocale);
};
+ function timeDifference(current, previous) {
+
+ var msPerMinute = 60 * 1000;
+ var msPerHour = msPerMinute * 60;
+ var msPerDay = msPerHour * 24;
+ var msPerMonth = msPerDay * 30;
+ var msPerYear = msPerDay * 365;
+
+ var elapsed = current - previous;
+
+ if (elapsed < msPerMinute) {
+ return 'Just now';
+ } else if (elapsed < msPerHour) {
+ return Math.round(elapsed/msPerMinute) + (Math.round(elapsed/msPerMinute)<=1 ? ' minute ago':' minutes ago');
+ } else if (elapsed < msPerDay ) {
+ return Math.round(elapsed/msPerHour ) + (Math.round(elapsed/msPerHour)<=1 ? ' hour ago':' hours ago');
+ } else if (elapsed < msPerMonth) {
+ return Math.round(elapsed/msPerDay) + (Math.round(elapsed/msPerDay)<=1 ? ' day ago':' days ago');
+ } else if (elapsed < msPerYear) {
+ return Math.round(elapsed/msPerMonth) + (Math.round(elapsed/msPerMonth)<=1 ? ' month ago':' months ago');
+ } else {
+ return Math.round(elapsed/msPerYear ) + (Math.round(elapsed/msPerYear)<=1 ? ' year ago':' years ago');
+ }
+ }
+
var do_localtime = function(elem) {
var times = elem.getElementsByTagName('time');
-
+ var currentTime = Date.now();
+
for(var i = 0; i < times.length; i++) {
- if(typeof times[i].getAttribute('data-local') == 'undefined')
- continue;
-
- var t = iso8601(times[i].getAttribute('datetime'));
-
-
+ var t = times[i].getAttribute('datetime');
+ var postTime = new Date(t);
+
times[i].setAttribute('data-local', 'true');
- times[i].innerHTML = dateformat(t);
- };
+
+ if (!localStorage.show_relative_time || localStorage.show_relative_time === 'false') {
+ times[i].innerHTML = dateformat(iso8601(t));
+ times[i].setAttribute('title', timeDifference(currentTime, postTime.getTime()));
+ } else {
+ times[i].innerHTML = timeDifference(currentTime, postTime.getTime());
+ times[i].setAttribute('title', dateformat(iso8601(t)));
+ }
+
+ }
};
- do_localtime(document);
-
- if (window.jQuery) {
+ if (window.Options && Options.get_tab('general') && window.jQuery) {
+ var interval_id;
+ Options.extend_tab('general', '<label id="show-relative-time"><input type="checkbox">' + _('Show relative time') + '</label>');
+
+ $('#show-relative-time>input').on('change', function() {
+ if (localStorage.show_relative_time === 'true') {
+ localStorage.show_relative_time = 'false';
+ clearInterval(interval_id);
+ } else {
+ localStorage.show_relative_time = 'true';
+ interval_id = setInterval(do_localtime, 30000, document);
+ }
+ // no need to refresh page
+ do_localtime(document);
+ });
+
+ if (localStorage.show_relative_time === 'true') {
+ $('#show-relative-time>input').attr('checked','checked');
+ interval_id = setInterval(do_localtime, 30000, document);
+ }
+
// allow to work with auto-reload.js, etc.
$(document).on('new_post', function(e, post) {
do_localtime(post);
});
}
-});
+ do_localtime(document);
+});
diff --git a/js/no-animated-gif.js b/js/no-animated-gif.js
index a10a6497..42c841ab 100644
--- a/js/no-animated-gif.js
+++ b/js/no-animated-gif.js
@@ -11,8 +11,9 @@
* //$config['additional_javascript'][] = 'js/options/general.js';
* $config['additional_javascript'][] = 'js/no-animated-gif.js';
*/
-
function unanimate_gif(e) {
+ if ($(e).closest('.thread').children('.thread-hidden').length > 0) return;
+
if (active_page === "catalog")
var c = $('<canvas class="thread-image"></canvas>');
else
@@ -34,13 +35,19 @@ function unanimate_gif(e) {
$(e).addClass("unanimated").hide();
}
+$(function(){
+
+var gif_finder = 'img.post-image[src$=".gif"], img.thread-image[src$=".gif"]';
+
function no_animated_gif() {
- var anim_gifs = $('img.post-image[src$=".gif"], img.thread-image[src$=".gif"]');
+ var anim_gifs = $(gif_finder);
localStorage.no_animated_gif = true;
$('#no-animated-gif>a').text(_('Animate GIFs'));
$('#no-animated-gif>input').prop('checked', true);
$.each(anim_gifs, function(i, e) {unanimate_gif(e)} );
+
+ $(document).on('new_post', new_post_handler);
}
function animated_gif() {
@@ -49,10 +56,17 @@ function animated_gif() {
localStorage.no_animated_gif = false;
$('#no-animated-gif>a').text(_('Unanimate GIFs'));
$('#no-animated-gif>input').prop('checked', false);
+
+ $(document).off('new_post', new_post_handler);
+}
+
+function new_post_handler(e, post) {
+ $(post).find(gif_finder).each(function(k, v) {
+ unanimate_gif(v);
+ });
}
if (active_page == 'thread' || active_page == 'index' || active_page == 'ukko' || active_page == 'catalog') {
- $(function(){
var selector, event;
if (window.Options && Options.get_tab('general')) {
selector = '#no-animated-gif>input';
@@ -75,5 +89,6 @@ if (active_page == 'thread' || active_page == 'index' || active_page == 'ukko' |
if (localStorage.no_animated_gif === 'true')
no_animated_gif();
- });
}
+
+});
diff --git a/js/options/fav.js b/js/options/fav.js
new file mode 100644
index 00000000..17ccb337
--- /dev/null
+++ b/js/options/fav.js
@@ -0,0 +1,72 @@
+$(document).ready(function(){
+//Creating functions
+var generateList = function(){
+ var favStor = [];
+ for(var i=1; i<favorites.length+1; i++){
+ favStor.push($("#sortable > div:nth-child("+i+")").html());
+ }
+ return favStor;
+} //This will generate a list of boards based off of the list on the screen
+function removeBoard(boardNumber){
+ favorites.splice(boardNumber, 1);
+ localStorage.favorites = JSON.stringify(favorites);
+ $("#sortable > div:nth-child("+(boardNumber+1)+")").remove();
+ $("#minusList > div:nth-child("+(favorites.length+1)+")").remove();
+ add_favorites();
+} //This removes a board from favorites, localStorage.favorites and the page
+function addBoard(){
+ $("#sortable").append("<div>"+($("#plusBox").val())+"</div>");
+ $("#minusList").append( $('<div data-board="'+favorites.length+'" style="cursor: pointer; margin-right: 5px">-</div>').on('click', function(e){removeBoard($(this).data('board'));}) );
+ favorites.push($("#plusBox").val());
+ localStorage.favorites = JSON.stringify(favorites);
+ $("#plusBox").val(""); //Removing text from textbox
+ add_favorites();
+} //This adds the text inside the textbox to favorites, localStorage.favorites and the page
+
+var favorites = JSON.parse(localStorage.favorites);
+Options.add_tab('fav-tab','star',_("Favorites"));
+
+//Pregenerating list of boards
+var favList = $('<div id="sortable" style="cursor: pointer; display: inline-block">');
+for(var i=0; i<favorites.length; i++){
+ favList.append( $('<div>'+favorites[i]+'</div>') );
+}
+
+//Creating list of minus symbols to remove unwanted boards
+var minusList = $('<div id="minusList" style="color: #0000FF; display: inline-block">');
+for(var i=0; i<favorites.length; i++){
+ minusList.append( $('<div data-board="'+i+'" style="cursor: pointer; margin-right: 5px">-</div>').on('click', function(e){removeBoard($(this).data('board'));}) );
+}
+
+//Help message so people understand how sorting boards works
+$("<span>"+_("Drag the boards to sort them.")+"</span><br><br>").appendTo(Options.get_tab('fav-tab').content);
+
+//Adding list of boards and minus symbols to remove boards with
+$(minusList).appendTo(Options.get_tab('fav-tab').content); //Adding the list of minus symbols to the tab
+$(favList).appendTo(Options.get_tab('fav-tab').content); //Adding the list of favorite boards to the tab
+
+//Adding spacing and text box to right boards into
+var addDiv = $("<div id='favs-add-board'>");
+
+var plusBox = $("<input id=\"plusBox\" type=\"text\">").appendTo(addDiv);
+plusBox.keydown(function( event ) {
+ if(event.keyCode == 13){
+ $("#plus").click();
+ }
+});
+
+//Adding plus symbol to use to add board
+$("<div id=\"plus\">+</div>").css({
+ cursor: "pointer",
+ color: "#0000FF"
+}).on('click', function(e){addBoard()}).appendTo(addDiv);
+
+addDiv.appendTo(Options.get_tab('fav-tab').content); //Adding the plus button
+
+favList.sortable(); //Making boards with sortable id use the sortable jquery function
+favList.on('sortstop', function() {
+ favorites = generateList();
+ localStorage.favorites = JSON.stringify(favorites);
+ add_favorites();
+});
+});
diff --git a/js/options/user-css.js b/js/options/user-css.js
index 840bcd1f..fed91ab3 100644
--- a/js/options/user-css.js
+++ b/js/options/user-css.js
@@ -17,7 +17,7 @@ var textarea = $("<textarea></textarea>").css({
"font-size": 12,
position: "absolute",
top: 35, bottom: 35,
- width: "calc(100% - 12px)", margin: 0, padding: 0, border: "1px solid black",
+ width: "calc(100% - 20px)", margin: 0, padding: "4px", border: "1px solid black",
left: 5, right: 5
}).appendTo(tab.content);
var submit = $("<input type='button' value='"+_("Update custom CSS")+"'>").css({
diff --git a/js/options/user-js.js b/js/options/user-js.js
index 0b7d140f..0ba9b1d0 100644
--- a/js/options/user-js.js
+++ b/js/options/user-js.js
@@ -17,7 +17,7 @@ var textarea = $("<textarea></textarea>").css({
"font-size": 12,
position: "absolute",
top: 35, bottom: 35,
- width: "calc(100% - 12px)", margin: 0, padding: 0, border: "1px solid black",
+ width: "calc(100% - 20px)", margin: 0, padding: "4px", border: "1px solid black",
left: 5, right: 5
}).appendTo(tab.content);
var submit = $("<input type='button' value='"+_("Update custom Javascript")+"'>").css({
diff --git a/js/post-filter.js b/js/post-filter.js
new file mode 100644
index 00000000..3bf55a51
--- /dev/null
+++ b/js/post-filter.js
@@ -0,0 +1,852 @@
+if (active_page === 'thread' || active_page === 'index' || active_page === 'catalog' || active_page === 'ukko') {
+ $(document).on('menu_ready', function () {
+ 'use strict';
+
+ // returns blacklist object from storage
+ function getList() {
+ return JSON.parse(localStorage.postFilter);
+ }
+
+ // stores blacklist into storage and reruns the filter
+ function setList(blacklist) {
+ localStorage.postFilter = JSON.stringify(blacklist);
+ $(document).trigger('filter_page');
+ }
+
+ // unit: seconds
+ function timestamp() {
+ return Math.floor((new Date()).getTime() / 1000);
+ }
+
+ function initList(list, boardId, threadId) {
+ if (typeof list.postFilter[boardId] == 'undefined') {
+ list.postFilter[boardId] = {};
+ list.nextPurge[boardId] = {};
+ }
+ if (typeof list.postFilter[boardId][threadId] == 'undefined') {
+ list.postFilter[boardId][threadId] = [];
+ }
+ list.nextPurge[boardId][threadId] = {timestamp: timestamp(), interval: 86400}; // 86400 seconds == 1 day
+ }
+
+ function addFilter(type, value, useRegex) {
+ var list = getList();
+ var filter = list.generalFilter;
+ var obj = {
+ type: type,
+ value: value,
+ regex: useRegex
+ };
+
+ for (var i=0; i<filter.length; i++) {
+ if (filter[i].type == type && filter[i].value == value && filter[i].regex == useRegex)
+ return;
+ }
+
+ filter.push(obj);
+ setList(list);
+ drawFilterList();
+ }
+
+ function removeFilter(type, value, useRegex) {
+ var list = getList();
+ var filter = list.generalFilter;
+
+ for (var i=0; i<filter.length; i++) {
+ if (filter[i].type == type && filter[i].value == value && filter[i].regex == useRegex) {
+ filter.splice(i, 1);
+ break;
+ }
+ }
+
+ setList(list);
+ drawFilterList();
+ }
+
+ function nameSpanToString(el) {
+ var s = '';
+
+ $.each($(el).contents(), function(k,v) {
+ if (v.nodeName === 'IMG')
+ s=s+$(v).attr('alt')
+
+ if (v.nodeName === '#text')
+ s=s+v.nodeValue
+ });
+ return s.trim();
+ }
+
+ var blacklist = {
+ add: {
+ post: function (boardId, threadId, postId, hideReplies) {
+ var list = getList();
+ var filter = list.postFilter;
+
+ initList(list, boardId, threadId);
+
+ for (var i in filter[boardId][threadId]) {
+ if (filter[boardId][threadId][i].post == postId) return;
+ }
+ filter[boardId][threadId].push({
+ post: postId,
+ hideReplies: hideReplies
+ });
+ setList(list);
+ },
+ uid: function (boardId, threadId, uniqueId, hideReplies) {
+ var list = getList();
+ var filter = list.postFilter;
+
+ initList(list, boardId, threadId);
+
+ for (var i in filter[boardId][threadId]) {
+ if (filter[boardId][threadId][i].uid == uniqueId) return;
+ }
+ filter[boardId][threadId].push({
+ uid: uniqueId,
+ hideReplies: hideReplies
+ });
+ setList(list);
+ }
+ },
+ remove: {
+ post: function (boardId, threadId, postId) {
+ var list = getList();
+ var filter = list.postFilter;
+
+ // thread already pruned
+ if (typeof filter[boardId] == 'undefined' || typeof filter[boardId][threadId] == 'undefined')
+ return;
+
+ for (var i=0; i<filter[boardId][threadId].length; i++) {
+ if (filter[boardId][threadId][i].post == postId) {
+ filter[boardId][threadId].splice(i, 1);
+ break;
+ }
+ }
+
+ if ($.isEmptyObject(filter[boardId][threadId])) {
+ delete filter[boardId][threadId];
+ delete list.nextPurge[boardId][threadId];
+
+ if ($.isEmptyObject(filter[boardId])) {
+ delete filter[boardId];
+ delete list.nextPurge[boardId];
+ }
+ }
+ setList(list);
+ },
+ uid: function (boardId, threadId, uniqueId) {
+ var list = getList();
+ var filter = list.postFilter;
+
+ // thread already pruned
+ if (typeof filter[boardId] == 'undefined' || typeof filter[boardId][threadId] == 'undefined')
+ return;
+
+ for (var i=0; i<filter[boardId][threadId].length; i++) {
+ if (filter[boardId][threadId][i].uid == uniqueId) {
+ filter[boardId][threadId].splice(i, 1);
+ break;
+ }
+ }
+
+ if ($.isEmptyObject(filter[boardId][threadId])) {
+ delete filter[boardId][threadId];
+ delete list.nextPurge[boardId][threadId];
+
+ if ($.isEmptyObject(filter[boardId])) {
+ delete filter[boardId];
+ delete list.nextPurge[boardId];
+ }
+ }
+ setList(list);
+ }
+ }
+ };
+
+ /*
+ * hide/show the specified thread/post
+ */
+ function hide(ele) {
+ var $ele = $(ele);
+
+ if ($(ele).data('hidden'))
+ return;
+
+ $(ele).data('hidden', true);
+ if ($ele.hasClass('op')) {
+ $ele.parent().find('.body, .files, .video-container').not($ele.children('.reply').children()).hide();
+
+ // hide thread replies on index view
+ if (active_page == 'index' || active_page == 'ukko') $ele.parent().find('.omitted, .reply:not(.hidden), post_no, .mentioned, br').hide();
+ } else {
+ // normal posts
+ $ele.children('.body, .files, .video-container').hide();
+ }
+ }
+ function show(ele) {
+ var $ele = $(ele);
+
+ $(ele).data('hidden', false);
+ if ($ele.hasClass('op')) {
+ $ele.parent().find('.body, .files, .video-container').show();
+ if (active_page == 'index') $ele.parent().find('.omitted, .reply:not(.hidden), post_no, .mentioned, br').show();
+ } else {
+ // normal posts
+ $ele.children('.body, .files, .video-container').show();
+ }
+ }
+
+ /*
+ * create filter menu when the button is clicked
+ */
+ function initPostMenu(pageData) {
+ var Menu = window.Menu;
+ var submenu;
+ Menu.add_item('filter-menu-hide', _('Hide post'));
+ Menu.add_item('filter-menu-unhide', _('Unhide post'));
+
+ submenu = Menu.add_submenu('filter-menu-add', _('Add filter'));
+ submenu.add_item('filter-add-post-plus', _('Post +'), _('Hide post and all replies'));
+ submenu.add_item('filter-add-id', _('ID'));
+ submenu.add_item('filter-add-id-plus', _('ID +'), _('Hide ID and all replies'));
+ submenu.add_item('filter-add-name', _('Name'));
+ submenu.add_item('filter-add-trip', _('Tripcode'));
+
+ submenu = Menu.add_submenu('filter-menu-remove', _('Remove filter'));
+ submenu.add_item('filter-remove-id', _('ID'));
+ submenu.add_item('filter-remove-name', _('Name'));
+ submenu.add_item('filter-remove-trip', _('Tripcode'));
+
+ Menu.onclick(function (e, $buffer) {
+ var ele = e.target.parentElement.parentElement;
+ var $ele = $(ele);
+
+ var threadId = $ele.parent().attr('id').replace('thread_', '');
+ var boardId = $ele.parent().data('board');
+ var postId = $ele.find('.post_no').not('[id]').text();
+ if (pageData.hasUID) {
+ var postUid = $ele.find('.poster_id').text();
+ }
+
+ var postName;
+ var postTrip = '';
+ if (!pageData.forcedAnon) {
+ postName = (typeof $ele.find('.name').contents()[0] == 'undefined') ? '' : nameSpanToString($ele.find('.name')[0]);
+ postTrip = $ele.find('.trip').text();
+ }
+
+ /* display logic and bind click handlers
+ */
+
+ // unhide button
+ if ($ele.data('hidden')) {
+ $buffer.find('#filter-menu-unhide').click(function () {
+ // if hidden due to post id, remove it from blacklist
+ // otherwise just show this post
+ blacklist.remove.post(boardId, threadId, postId);
+ show(ele);
+ });
+ $buffer.find('#filter-menu-hide').addClass('hidden');
+ } else {
+ $buffer.find('#filter-menu-unhide').addClass('hidden');
+ $buffer.find('#filter-menu-hide').click(function () {
+ blacklist.add.post(boardId, threadId, postId, false);
+ });
+ }
+
+ // post id
+ if (!$ele.data('hiddenByPost')) {
+ $buffer.find('#filter-add-post-plus').click(function () {
+ blacklist.add.post(boardId, threadId, postId, true);
+ });
+ } else {
+ $buffer.find('#filter-add-post-plus').addClass('hidden');
+ }
+
+ // UID
+ if (pageData.hasUID && !$ele.data('hiddenByUid')) {
+ $buffer.find('#filter-add-id').click(function () {
+ blacklist.add.uid(boardId, threadId, postUid, false);
+ });
+ $buffer.find('#filter-add-id-plus').click(function () {
+ blacklist.add.uid(boardId, threadId, postUid, true);
+ });
+
+ $buffer.find('#filter-remove-id').addClass('hidden');
+ } else if (pageData.hasUID) {
+ $buffer.find('#filter-remove-id').click(function () {
+ blacklist.remove.uid(boardId, threadId, postUid);
+ });
+
+ $buffer.find('#filter-add-id').addClass('hidden');
+ $buffer.find('#filter-add-id-plus').addClass('hidden');
+ } else {
+ // board doesn't use UID
+ $buffer.find('#filter-add-id').addClass('hidden');
+ $buffer.find('#filter-add-id-plus').addClass('hidden');
+ $buffer.find('#filter-remove-id').addClass('hidden');
+ }
+
+ // name
+ if (!pageData.forcedAnon && !$ele.data('hiddenByName')) {
+ $buffer.find('#filter-add-name').click(function () {
+ addFilter('name', postName, false);
+ });
+
+ $buffer.find('#filter-remove-name').addClass('hidden');
+ } else if (!pageData.forcedAnon) {
+ $buffer.find('#filter-remove-name').click(function () {
+ removeFilter('name', postName, false);
+ });
+
+ $buffer.find('#filter-add-name').addClass('hidden');
+ } else {
+ // board has forced anon
+ $buffer.find('#filter-remove-name').addClass('hidden');
+ $buffer.find('#filter-add-name').addClass('hidden');
+ }
+
+ // tripcode
+ if (!pageData.forcedAnon && !$ele.data('hiddenByTrip') && postTrip !== '') {
+ $buffer.find('#filter-add-trip').click(function () {
+ addFilter('trip', postTrip, false);
+ });
+
+ $buffer.find('#filter-remove-trip').addClass('hidden');
+ } else if (!pageData.forcedAnon && postTrip !== '') {
+ $buffer.find('#filter-remove-trip').click(function () {
+ removeFilter('trip', postTrip, false);
+ });
+
+ $buffer.find('#filter-add-trip').addClass('hidden');
+ } else {
+ // board has forced anon
+ $buffer.find('#filter-remove-trip').addClass('hidden');
+ $buffer.find('#filter-add-trip').addClass('hidden');
+ }
+
+ /* hide sub menus if all items are hidden
+ */
+ if (!$buffer.find('#filter-menu-remove > ul').children().not('.hidden').length) {
+ $buffer.find('#filter-menu-remove').addClass('hidden');
+ }
+ if (!$buffer.find('#filter-menu-add > ul').children().not('.hidden').length) {
+ $buffer.find('#filter-menu-add').addClass('hidden');
+ }
+ });
+ }
+
+ /*
+ * hide/unhide thread on index view
+ */
+ function quickToggle(ele, threadId, pageData) {
+ /*if ($(ele).find('.hide-thread-link').length)
+ $('.hide-thread-link').remove();*/
+
+ if ($(ele).hasClass('op') && !$(ele).find('.hide-thread-link').length) {
+ $('<a class="hide-thread-link" style="float:left;margin-right:5px" href="javascript:void(0)">[' + ($(ele).data('hidden') ? '+' : '&ndash;') + ']</a>')
+ .insertBefore($(ele).find(':not(h2,h2 *):first'))
+ .click(function() {
+ var postId = $(ele).find('.post_no').not('[id]').text();
+ var hidden = $(ele).data('hidden');
+ var boardId = $(ele).parents('.thread').data('board');
+
+ if (hidden) {
+ blacklist.remove.post(boardId, threadId, postId, false);
+ $(this).html('[&ndash;]');
+ } else {
+ blacklist.add.post(boardId, threadId, postId, false);
+ $(this).text('[+]');
+ }
+ });
+ }
+ }
+
+ /*
+ * determine whether the reply post should be hidden
+ * - applies to all posts on page load or filtering rule change
+ * - apply to new posts on thread updates
+ * - must explicitly set the state of each attributes because filter will reapply to all posts after filtering rule change
+ */
+ function filter(post, threadId, pageData) {
+ var $post = $(post);
+
+ var list = getList();
+ var postId = $post.find('.post_no').not('[id]').text();
+ var name, trip, uid, subject, comment;
+ var i, length, array, rule, pattern; // temp variables
+
+ var boardId = $post.data('board');
+ if (!boardId) boardId = $post.parents('.thread').data('board');
+
+ var localList = pageData.localList;
+ var noReplyList = pageData.noReplyList;
+ var hasUID = pageData.hasUID;
+ var forcedAnon = pageData.forcedAnon;
+
+ var hasTrip = ($post.find('.trip').length > 0);
+ var hasSub = ($post.find('.subject').length > 0);
+
+ $post.data('hidden', false);
+ $post.data('hiddenByUid', false);
+ $post.data('hiddenByPost', false);
+ $post.data('hiddenByName', false);
+ $post.data('hiddenByTrip', false);
+ $post.data('hiddenBySubject', false);
+ $post.data('hiddenByComment', false);
+
+ // add post with matched UID to localList
+ if (hasUID &&
+ typeof list.postFilter[boardId] != 'undefined' &&
+ typeof list.postFilter[boardId][threadId] != 'undefined') {
+ uid = $post.find('.poster_id').text();
+ array = list.postFilter[boardId][threadId];
+
+ for (i=0; i<array.length; i++) {
+ if (array[i].uid == uid) {
+ $post.data('hiddenByUid', true);
+ localList.push(postId);
+ if (array[i].hideReplies) noReplyList.push(postId);
+ break;
+ }
+ }
+ }
+
+ // match localList
+ if (localList.length) {
+ if ($.inArray(postId, localList) != -1) {
+ if ($post.data('hiddenByUid') !== true) $post.data('hiddenByPost', true);
+ hide(post);
+ }
+ }
+
+ // matches generalFilter
+ if (!forcedAnon)
+ name = (typeof $post.find('.name').contents()[0] == 'undefined') ? '' : nameSpanToString($post.find('.name')[0]);
+ if (!forcedAnon && hasTrip)
+ trip = $post.find('.trip').text();
+ if (hasSub)
+ subject = $post.find('.subject').text();
+
+ array = $post.find('.body').contents().filter(function () {if ($(this).text() !== '') return true;}).toArray();
+ array = $.map(array, function (ele) {
+ return $(ele).text().trim();
+ });
+ comment = array.join(' ');
+
+
+ for (i = 0, length = list.generalFilter.length; i < length; i++) {
+ rule = list.generalFilter[i];
+
+ if (rule.regex) {
+ pattern = new RegExp(rule.value);
+ switch (rule.type) {
+ case 'name':
+ if (!forcedAnon && pattern.test(name)) {
+ $post.data('hiddenByName', true);
+ hide(post);
+ }
+ break;
+ case 'trip':
+ if (!forcedAnon && hasTrip && pattern.test(trip)) {
+ $post.data('hiddenByTrip', true);
+ hide(post);
+ }
+ break;
+ case 'sub':
+ if (hasSub && pattern.test(subject)) {
+ $post.data('hiddenBySubject', true);
+ hide(post);
+ }
+ break;
+ case 'com':
+ if (pattern.test(comment)) {
+ $post.data('hiddenByComment', true);
+ hide(post);
+ }
+ break;
+ }
+ } else {
+ switch (rule.type) {
+ case 'name':
+ if (!forcedAnon && rule.value == name) {
+ $post.data('hiddenByName', true);
+ hide(post);
+ }
+ break;
+ case 'trip':
+ if (!forcedAnon && hasTrip && rule.value == trip) {
+ $post.data('hiddenByTrip', true);
+ hide(post);
+ }
+ break;
+ case 'sub':
+ pattern = new RegExp('\\b'+ rule.value+ '\\b');
+ if (hasSub && pattern.test(subject)) {
+ $post.data('hiddenBySubject', true);
+ hide(post);
+ }
+ break;
+ case 'com':
+ pattern = new RegExp('\\b'+ rule.value+ '\\b');
+ if (pattern.test(comment)) {
+ $post.data('hiddenByComment', true);
+ hide(post);
+ }
+ break;
+ }
+ }
+ }
+
+ // check for link to filtered posts
+ $post.find('.body a').not('[rel="nofollow"]').each(function () {
+ var replyId = $(this).text().match(/^>>(\d+)$/);
+
+ if (!replyId)
+ return;
+
+ replyId = replyId[1];
+ if ($.inArray(replyId, noReplyList) != -1) {
+ hide(post);
+ }
+ });
+
+ // post didn't match any filters
+ if (!$post.data('hidden')) {
+ show(post);
+ }
+ }
+
+ /* (re)runs the filter on the entire page
+ */
+ function filterPage(pageData) {
+ var list = getList();
+
+ if (active_page != 'catalog') {
+
+ // empty the local and no-reply list
+ pageData.localList = [];
+ pageData.noReplyList = [];
+
+ $('.thread').each(function () {
+ var $thread = $(this);
+ // disregard the hidden threads constructed by post-hover.js
+ if ($thread.css('display') == 'none')
+ return;
+
+ var threadId = $thread.attr('id').replace('thread_', '');
+ var boardId = $thread.data('board');
+ var op = $thread.children('.op')[0];
+ var i, array; // temp variables
+
+ // add posts to localList and noReplyList
+ if (typeof list.postFilter[boardId] != 'undefined' && typeof list.postFilter[boardId][threadId] != 'undefined') {
+ array = list.postFilter[boardId][threadId];
+ for (i=0; i<array.length; i++) {
+ if ( typeof array[i].post == 'undefined')
+ continue;
+
+ pageData.localList.push(array[i].post);
+ if (array[i].hideReplies) pageData.noReplyList.push(array[i].post);
+ }
+ }
+ // run filter on OP
+ filter(op, threadId, pageData);
+ quickToggle(op, threadId, pageData);
+
+ // iterate filter over each post
+ if (!$(op).data('hidden') || active_page == 'thread') {
+ $thread.find('.reply').not('.hidden').each(function () {
+ filter(this, threadId, pageData);
+ });
+ }
+
+ });
+ } else {
+ var postFilter = list.postFilter[pageData.boardId];
+ var $collection = $('.mix');
+
+ if ($.isEmptyObject(postFilter))
+ return;
+
+ // for each thread that has filtering rules
+ // check if filter contains thread OP and remove the thread from catalog
+ $.each(postFilter, function (key, thread) {
+ var threadId = key;
+ $.each(thread, function () {
+ if (this.post == threadId) {
+ $collection.filter('[data-id='+ threadId +']').remove();
+ }
+ });
+ });
+ }
+ }
+
+ function initStyle() {
+ var $ele, cssStyle, cssString;
+
+ $ele = $('<div>').addClass('post reply').hide().appendTo('body');
+ cssStyle = $ele.css(['background-color', 'border-color']);
+ cssStyle.hoverBg = $('body').css('background-color');
+ $ele.remove();
+
+ cssString = '\n/*** Generated by post-filter ***/\n' +
+ '#filter-control input[type=text] {width: 130px;}' +
+ '#filter-control input[type=checkbox] {vertical-align: middle;}' +
+ '#filter-control #clear {float: right;}\n' +
+ '#filter-container {margin-top: 20px; border: 1px solid; height: 270px; overflow: auto;}\n' +
+ '#filter-list {width: 100%; border-collapse: collapse;}\n' +
+ '#filter-list th {text-align: center; height: 20px; font-size: 14px; border-bottom: 1px solid;}\n' +
+ '#filter-list th:nth-child(1) {text-align: center; width: 70px;}\n' +
+ '#filter-list th:nth-child(2) {text-align: left;}\n' +
+ '#filter-list th:nth-child(3) {text-align: center; width: 58px;}\n' +
+ '#filter-list tr:not(#header) {height: 22px;}\n' +
+ '#filter-list tr:nth-child(even) {background-color:rgba(255, 255, 255, 0.5);}\n' +
+ '#filter-list td:nth-child(1) {text-align: center; width: 70px;}\n' +
+ '#filter-list td:nth-child(3) {text-align: center; width: 58px;}\n' +
+ '#confirm {text-align: right; margin-bottom: -18px; padding-top: 2px; font-size: 14px; color: #FF0000;}';
+
+ if (!$('style.generated-css').length) $('<style class="generated-css">').appendTo('head');
+ $('style.generated-css').html($('style.generated-css').html() + cssString);
+ }
+
+ function drawFilterList() {
+ var list = getList().generalFilter;
+ var $ele = $('#filter-list');
+ var $row, i, length, obj, val;
+
+ var typeName = {
+ name: 'name',
+ trip: 'tripcode',
+ sub: 'subject',
+ com: 'comment'
+ };
+
+ $ele.empty();
+
+ $ele.append('<tr id="header"><th>Type</th><th>Content</th><th>Remove</th></tr>');
+ for (i = 0, length = list.length; i < length; i++) {
+ obj = list[i];
+
+ // display formatting
+ val = (obj.regex) ? '/'+ obj.value +'/' : obj.value;
+
+ $row = $('<tr>');
+ $row.append(
+ '<td>'+ typeName[obj.type] +'</td>',
+ '<td>'+ val +'</td>',
+ $('<td>').append(
+ $('<a>').html('X')
+ .addClass('del-btn')
+ .attr('href', '#')
+ .data('type', obj.type)
+ .data('val', obj.value)
+ .data('useRegex', obj.regex)
+ )
+ );
+ $ele.append($row);
+ }
+ }
+
+ function initOptionsPanel() {
+ if (window.Options && !Options.get_tab('filter')) {
+ Options.add_tab('filter', 'list', _('Filters'));
+ Options.extend_tab('filter',
+ '<div id="filter-control">' +
+ '<select>' +
+ '<option value="name">'+_('Name')+'</option>' +
+ '<option value="trip">'+_('Tripcode')+'</option>' +
+ '<option value="sub">'+_('Subject')+'</option>' +
+ '<option value="com">'+_('Comment')+'</option>' +
+ '</select>' +
+ '<input type="text">' +
+ '<input type="checkbox">' +
+ 'regex ' +
+ '<button id="set-filter">'+_('Add')+'</button>' +
+ '<button id="clear">'+_('Clear all filters')+'</button>' +
+ '<div id="confirm" class="hidden">' +
+ _('This will clear all filtering rules including hidden posts.')+' <a id="confirm-y" href="#">'+_('yes')+'</a> | <a id="confirm-n" href="#">'+_('no')+'</a>' +
+ '</div>' +
+ '</div>' +
+ '<div id="filter-container"><table id="filter-list"></table></div>'
+ );
+ drawFilterList();
+
+ // control buttons
+ $('#filter-control').on('click', '#set-filter', function () {
+ var type = $('#filter-control select option:selected').val();
+ var value = $('#filter-control input[type=text]').val();
+ var useRegex = $('#filter-control input[type=checkbox]').prop('checked');
+
+ //clear the input form
+ $('#filter-control input[type=text]').val('');
+
+ addFilter(type, value, useRegex);
+ drawFilterList();
+ });
+ $('#filter-control').on('click', '#clear', function () {
+ $('#filter-control #clear').addClass('hidden');
+ $('#filter-control #confirm').removeClass('hidden');
+ });
+ $('#filter-control').on('click', '#confirm-y', function (e) {
+ e.preventDefault();
+
+ $('#filter-control #clear').removeClass('hidden');
+ $('#filter-control #confirm').addClass('hidden');
+ setList({
+ generalFilter: [],
+ postFilter: {},
+ nextPurge: {},
+ lastPurge: timestamp()
+ });
+ drawFilterList();
+ });
+ $('#filter-control').on('click', '#confirm-n', function (e) {
+ e.preventDefault();
+
+ $('#filter-control #clear').removeClass('hidden');
+ $('#filter-control #confirm').addClass('hidden');
+ });
+
+
+ // remove button
+ $('#filter-list').on('click', '.del-btn', function (e) {
+ e.preventDefault();
+
+ var $ele = $(e.target);
+ var type = $ele.data('type');
+ var val = $ele.data('val');
+ var useRegex = $ele.data('useRegex');
+
+ removeFilter(type, val, useRegex);
+ });
+ }
+ }
+
+ /*
+ * clear out pruned threads
+ */
+ function purge() {
+ var list = getList();
+ var board, thread, boardId, threadId;
+ var deferred;
+ var requestArray = [];
+
+ var successHandler = function (boardId, threadId) {
+ return function () {
+ // thread still alive, keep it in the list and increase the time between checks.
+ var list = getList();
+ var thread = list.nextPurge[boardId][threadId];
+
+ thread.timestamp = timestamp();
+ thread.interval = Math.floor(thread.interval * 1.5);
+ setList(list);
+ };
+ };
+ var errorHandler = function (boardId, threadId) {
+ return function (xhr) {
+ if (xhr.status == 404) {
+ var list = getList();
+
+ delete list.nextPurge[boardId][threadId];
+ delete list.postFilter[boardId][threadId];
+ if ($.isEmptyObject(list.nextPurge[boardId])) delete list.nextPurge[boardId];
+ if ($.isEmptyObject(list.postFilter[boardId])) delete list.postFilter[boardId];
+ setList(list);
+ }
+ };
+ };
+
+ if ((timestamp() - list.lastPurge) < 86400) // less than 1 day
+ return;
+
+ for (boardId in list.nextPurge) {
+ board = list.nextPurge[boardId];
+ for (threadId in board) {
+ thread = board[threadId];
+ if (timestamp() > (thread.timestamp + thread.interval)) {
+ // check if thread is pruned
+ deferred = $.ajax({
+ cache: false,
+ url: '/'+ boardId +'/res/'+ threadId +'.json',
+ success: successHandler(boardId, threadId),
+ error: errorHandler(boardId, threadId)
+ });
+ requestArray.push(deferred);
+ }
+ }
+ }
+
+ // when all requests complete
+ $.when.apply($, requestArray).always(function () {
+ var list = getList();
+ list.lastPurge = timestamp();
+ setList(list);
+ });
+ }
+
+ function init() {
+ if (typeof localStorage.postFilter === 'undefined') {
+ localStorage.postFilter = JSON.stringify({
+ generalFilter: [],
+ postFilter: {},
+ nextPurge: {},
+ lastPurge: timestamp()
+ });
+ }
+
+ var pageData = {
+ boardId: board_name, // get the id from the global variable
+ localList: [], // all the blacklisted post IDs or UIDs that apply to the current page
+ noReplyList: [], // any posts that replies to the contents of this list shall be hidden
+ hasUID: (document.getElementsByClassName('poster_id').length > 0),
+ forcedAnon: ($('th:contains(Name)').length === 0) // tests by looking for the Name label on the reply form
+ };
+
+ initStyle();
+ initOptionsPanel();
+ initPostMenu(pageData);
+ filterPage(pageData);
+
+ // on new posts
+ $(document).on('new_post', function (e, post) {
+ var threadId;
+
+ if ($(post).hasClass('reply')) {
+ threadId = $(post).parents('.thread').attr('id').replace('thread_', '');
+ } else {
+ threadId = $(post).attr('id').replace('thread_', '');
+ post = $(post).children('.op')[0];
+ }
+
+ filter(post, threadId, pageData);
+ quickToggle(post, threadId, pageData);
+ });
+
+ $(document).on('filter_page', function () {
+ filterPage(pageData);
+ });
+
+ // shift+click on catalog to hide thread
+ if (active_page == 'catalog') {
+ $(document).on('click', '.mix', function(e) {
+ if (e.shiftKey) {
+ var threadId = $(this).data('id').toString();
+ var postId = threadId;
+ blacklist.add.post(pageData.boardId, threadId, postId, false);
+ }
+ });
+ }
+
+ // clear out the old threads
+ purge();
+ }
+ init();
+ });
+
+ if (typeof window.Menu !== "undefined") {
+ $(document).trigger('menu_ready');
+ }
+}
diff --git a/js/post-hover.js b/js/post-hover.js
index e21cacf7..e78b57e8 100644
--- a/js/post-hover.js
+++ b/js/post-hover.js
@@ -54,10 +54,7 @@ onready(function(){
hovered_at = {'x': e.pageX, 'y': e.pageY};
var start_hover = function($link) {
- if($.contains($post[0], $link[0])) {
- // link links to itself or to op; ignore
- }
- else if($post.is(':visible') &&
+ if ($post.is(':visible') &&
$post.offset().top >= $(window).scrollTop() &&
$post.offset().top + $post.height() <= $(window).scrollTop() + $(window).height()) {
// post is in view
diff --git a/js/post-menu.js b/js/post-menu.js
new file mode 100644
index 00000000..6018dfdb
--- /dev/null
+++ b/js/post-menu.js
@@ -0,0 +1,211 @@
+/*
+ * post-menu.js - adds dropdown menu to posts
+ *
+ * Creates a global Menu object with four public methods:
+ *
+ * Menu.onclick(fnc)
+ * registers a function to be executed after button click, before the menu is displayed
+ * Menu.add_item(id, text[, title])
+ * adds an item to the top level of menu
+ * Menu.add_submenu(id, text)
+ * creates and returns a List object through which to manipulate the content of the submenu
+ * Menu.get_submenu(id)
+ * returns the submenu with the specified id from the top level menu
+ *
+ * The List object contains all the methods from Menu except onclick()
+ *
+ * Example usage:
+ * Menu.add_item('filter-menu-hide', 'Hide post');
+ * Menu.add_item('filter-menu-unhide', 'Unhide post');
+ *
+ * submenu = Menu.add_submenu('filter-menu-add', 'Add filter');
+ * submenu.add_item('filter-add-post-plus', 'Post +', 'Hide post and all replies');
+ * submenu.add_item('filter-add-id', 'ID');
+ *
+ * Usage:
+ * $config['additional_javascript'][] = 'js/jquery.min.js';
+ * $config['additional_javascript'][] = 'js/post-menu.js';
+ */
+$(document).ready(function () {
+
+var List = function (menuId, text) {
+ this.id = menuId;
+ this.text = text;
+ this.items = [];
+
+ this.add_item = function (itemId, text, title) {
+ this.items.push(new Item(itemId, text, title));
+ };
+ this.list_items = function () {
+ var array = [];
+ var i, length, obj, $ele;
+
+ if ($.isEmptyObject(this.items))
+ return;
+
+ length = this.items.length;
+ for (i = 0; i < length; i++) {
+ obj = this.items[i];
+
+ $ele = $('<li>', {id: obj.id}).text(obj.text);
+ if ('title' in obj) $ele.attr('title', obj.title);
+
+ if (obj instanceof Item) {
+ $ele.addClass('post-item');
+ } else {
+ $ele.addClass('post-submenu');
+
+ $ele.prepend(obj.list_items());
+ $ele.append($('<span>', {class: 'post-menu-arrow'}).text('»'));
+ }
+
+ array.push($ele);
+ }
+
+ return $('<ul>').append(array);
+ };
+ this.add_submenu = function (menuId, text) {
+ var ele = new List(menuId, text);
+ this.items.push(ele);
+ return ele;
+ };
+ this.get_submenu = function (menuId) {
+ for (var i = 0; i < this.items.length; i++) {
+ if ((this.items[i] instanceof Item) || this.items[i].id != menuId) continue;
+ return this.items[i];
+ }
+ };
+};
+
+var Item = function (itemId, text, title) {
+ this.id = itemId;
+ this.text = text;
+
+ // optional
+ if (typeof title != 'undefined') this.title = title;
+};
+
+function buildMenu(e) {
+ var pos = $(e.target).offset();
+ var i, length;
+
+ var $menu = $('<div class="post-menu"></div>').append(mainMenu.list_items());
+
+ // execute registered click handlers
+ length = onclick_callbacks.length;
+ for (i = 0; i < length; i++) {
+ onclick_callbacks[i](e, $menu);
+ }
+
+ // set menu position and append to page
+ $menu.css({top: pos.top, left: pos.left + 20});
+ $('body').append($menu);
+}
+
+function addButton(post) {
+ var $ele = $(post);
+ $ele.find('input.delete').after(
+ $('<a>', {href: '#', class: 'post-btn', title: 'Post menu'}).text('▶')
+ );
+}
+
+
+/* * * * * * * * * *
+ Public methods
+ * * * * * * * * * */
+var Menu = {};
+var mainMenu = new List();
+var onclick_callbacks = [];
+
+Menu.onclick = function (fnc) {
+ onclick_callbacks.push(fnc);
+};
+
+Menu.add_item = function (itemId, text, title) {
+ mainMenu.add_item(itemId, text, title);
+};
+
+Menu.add_submenu = function (menuId, text) {
+ return mainMenu.add_submenu(menuId, text);
+};
+
+Menu.get_submenu = function (id) {
+ return mainMenu.get_submenu(id);
+};
+
+window.Menu = Menu;
+
+
+/* * * * * * * *
+ Initialize
+ * * * * * * * */
+
+/* Styling
+ */
+var $ele, cssStyle, cssString;
+
+$ele = $('<div>').addClass('post reply').hide().appendTo('body');
+cssStyle = $ele.css(['border-top-color']);
+cssStyle.hoverBg = $('body').css('background-color');
+$ele.remove();
+
+cssString =
+ '\n/*** Generated by post-menu ***/\n' +
+ '.post-menu {position: absolute; font-size: 12px; line-height: 1.3em;}\n' +
+ '.post-menu ul {\n' +
+ ' background-color: '+ cssStyle['border-top-color'] +'; border: 1px solid #666;\n' +
+ ' list-style: none; padding: 0; margin: 0; white-space: nowrap;\n}\n' +
+ '.post-menu .post-submenu{white-space: normal; width: 90px;}' +
+ '.post-menu .post-submenu>ul{white-space: nowrap; width: auto;}' +
+ '.post-menu li {cursor: pointer; position: relative; padding: 4px 4px; vertical-align: middle;}\n' +
+ '.post-menu li:hover {background-color: '+ cssStyle.hoverBg +';}\n' +
+ '.post-menu ul ul {display: none; position: absolute;}\n' +
+ '.post-menu li:hover>ul {display: block; left: 100%; margin-top: -3px;}\n' +
+ '.post-menu-arrow {float: right; margin-left: 10px;}\n' +
+ '.post-menu.hidden, .post-menu .hidden {display: none;}\n' +
+ '.post-btn {transition: transform 0.1s; width: 15px; text-align: center; font-size: 10pt; opacity: 0.8; text-decoration: none; margin: -6px 0px 0px -5px !important; display: inline-block;}\n' +
+ '.post-btn:hover {opacity: 1;}\n' +
+ '.post-btn-open {transform: rotate(90deg);}\n';
+
+if (!$('style.generated-css').length) $('<style class="generated-css">').appendTo('head');
+$('style.generated-css').html($('style.generated-css').html() + cssString);
+
+/* Add buttons
+ */
+$('.reply:not(.hidden), .thread>.op').each(function () {
+ addButton(this);
+ });
+
+ /* event handlers
+ */
+$('form[name=postcontrols]').on('click', '.post-btn', function (e) {
+ e.preventDefault();
+ var post = e.target.parentElement.parentElement;
+ $('.post-menu').remove();
+
+ if ($(e.target).hasClass('post-btn-open')) {
+ $('.post-btn-open').removeClass('post-btn-open');
+ } else {
+ // close previous button
+ $('.post-btn-open').removeClass('post-btn-open');
+ $(post).find('.post-btn').addClass('post-btn-open');
+
+ buildMenu(e);
+ }
+});
+
+$(document).on('click', function (e){
+ if ($(e.target).hasClass('post-btn') || $(e.target).hasClass('post-submenu'))
+ return;
+
+ $('.post-menu').remove();
+ $('.post-btn-open').removeClass('post-btn-open');
+});
+
+// on new posts
+$(document).on('new_post', function (e, post) {
+ addButton(post);
+});
+
+$(document).trigger('menu_ready');
+});
diff --git a/js/quick-reply.js b/js/quick-reply.js
index 43981a48..f31af6af 100644
--- a/js/quick-reply.js
+++ b/js/quick-reply.js
@@ -283,7 +283,7 @@
$postForm.find('br').remove();
$postForm.find('table').prepend('<tr><th colspan="2">\
<span class="handle">\
- <a class="close-btn" href="javascript:void(0)">X</a>\
+ <a class="close-btn" href="javascript:void(0)">×</a>\
' + _('Quick Reply') + '\
</span>\
</th></tr>');
diff --git a/js/show-own-posts.js b/js/show-own-posts.js
index 8b83f4cd..e26f5abd 100644
--- a/js/show-own-posts.js
+++ b/js/show-own-posts.js
@@ -33,7 +33,7 @@ var update_own = function() {
if (posts[board] && posts[board].indexOf(id) !== -1) { // Own post!
$(this).addClass('you');
- $(this).find('span.name').first().append(' '+_('(You)'));
+ $(this).find('span.name').first().append(' <span class="own_post">'+_('(You)')+'</span>');
}
// Update references
diff --git a/js/thread-watcher.js b/js/thread-watcher.js
index 22656e48..0796193b 100644
--- a/js/thread-watcher.js
+++ b/js/thread-watcher.js
@@ -28,10 +28,10 @@ watchlist.render = function(reset) {
JSON.parse(localStorage.watchlist).forEach(function(e, i) {
//look at line 69, that's what (e) is here.
threads.push('<div class="watchlist-inner" id="watchlist-'+i+'">' +
- '<span>Board: '+e[0]+'</span>&nbsp' +
- '<span>Thread: '+'<a href="'+e[3]+'">'+e[1]+'</a></span>&nbsp' +
- '<span>Replies: '+e[2]+'</span>&nbsp' +
- '<a class="watchlist-remove">[Unwatch]</a>'+
+ '<span>/'+e[0]+'/ - ' +
+ '<a href="'+e[3]+'">'+e[1].replace("thread_", _("Thread #"))+'</a>' +
+ ' ('+e[2]+') </span>' +
+ '<a class="watchlist-remove">X</a>'+
'</div>');
});
if ($('#watchlist').length) {
@@ -40,17 +40,15 @@ watchlist.render = function(reset) {
$('#watchlist').append(threads.join(''));
} else {
//If the watchlist has not yet been rendered, create it.
- $('form[name="post"]').before(
+ var menuStyle = getComputedStyle($('.boardlist')[0]);
+ $((active_page == 'ukko') ? 'hr:first' : (active_page == 'catalog') ? 'body>span:first' : 'form[name="post"]').before(
$('<div id="watchlist">'+
'<div class="watchlist-controls">'+
- '<span><a id="clearList">[Clear List]</a></span>&nbsp'+
- '<span><a id="clearGhosts">[Clear Ghosts]</a></span>'+
+ '<span><a id="clearList">['+_('Clear List')+']</a></span>&nbsp'+
+ '<span><a id="clearGhosts">['+_('Clear Ghosts')+']</a></span>'+
'</div>'+
threads.join('')+
- '</div>').css({
- background: $('.reply').css('background'),
- borderColor : $('.reply').css('border-color')
- }));
+ '</div>').css("background-color", menuStyle.backgroundColor).css("border", menuStyle.borderBottomWidth+" "+menuStyle.borderBottomStyle+" "+menuStyle.borderBottomColor));
}
return this;
};
@@ -62,6 +60,8 @@ watchlist.render = function(reset) {
watchlist.add = function(sel) {
var threadName, threadInfo;
+ var board_name = $(sel).parents('.thread').data('board');
+
if (active_page === 'thread') {
if ($('.subject').length){
//If a subject is given, use the first 20 characters as the thread name.
@@ -72,7 +72,7 @@ watchlist.add = function(sel) {
//board name, thread name as defined above, current amount of posts, thread url
threadInfo = [board_name, threadName, $('.post').length, location.href];
- } else if (active_page === 'index') {
+ } else if (active_page === 'index' || active_page === 'ukko') {
var postCount;
//Figure out the post count.
@@ -81,8 +81,8 @@ watchlist.add = function(sel) {
} else {
postCount = $(sel).parents('.op').siblings('.post').length+1;
}
- //Grab the reply link.
- var threadLink = $(sel).siblings('a:contains("[Reply]")').attr('href');
+ //Grab the reply link.;
+ var threadLink = $(sel).siblings('a:not(.watchThread)').last().attr('href');
//Figure out the thread name. If anon, use the thread id.
if ($(sel).parent().find('.subject').length) {
threadName = $(sel).parent().find('.subject').text().substring(0,20);
@@ -144,16 +144,21 @@ watchlist.exists = function(sel) {
};
$(document).ready(function(){
+ if (!(active_page == 'thread' || active_page == 'index' || active_page == 'catalog' || active_page == 'ukko')) {
+ return;
+ }
+
//Append the watchlist toggle button.
- $('.boardlist').append('<span>[ <a id="watchlist-toggle">watchlist</a> ]</span>');
+ $('.boardlist').append('<span>[ <a class="watchlist-toggle" href="#">'+_('watchlist')+'</a> ]</span>');
//Append a watch thread button after every OP.
- $('.op>.intro').append('<a class="watchThread">[Watch Thread]</a>');
+ $('.op>.intro').append('<a class="watchThread" href="#">['+_('Watch Thread')+']</a>');
//Draw the watchlist, hidden.
watchlist.render();
//Show or hide the watchlist.
- $('#watchlist-toggle').on('click', function(e) {
+ $('.watchlist-toggle').on('click', function(e) {
+ e.preventDefault();
//if ctrl+click, reset the watchlist.
if (e.ctrlKey) {
watchlist.render(true);
@@ -167,7 +172,8 @@ $(document).ready(function(){
//Trigger the watchlist add function.
//The selector is passed as an argument in case the page is not a thread.
- $('.watchThread').on('click', function() {
+ $('.watchThread').on('click', function(e) {
+ e.preventDefault();
watchlist.add(this).render();
});
diff --git a/js/toggle-images.js b/js/toggle-images.js
index b8940252..c3636d29 100644
--- a/js/toggle-images.js
+++ b/js/toggle-images.js
@@ -20,7 +20,7 @@ $(document).ready(function(){
$('<style type="text/css"> img.hidden{ opacity: 0.1; background: grey; border: 1px solid #000; } </style>').appendTo($('head'));
var hideImage = function() {
- if ($(this).parent()[0].dataset.expanded == 'true') {
+ if ($(this).parent().data('expanded') == 'true') {
$(this).parent().click();
}
$(this)