diff --git a/PEE-chrome.crx b/PEE-chrome.crx deleted file mode 100644 index 4a505dd..0000000 Binary files a/PEE-chrome.crx and /dev/null differ diff --git a/build-chrome.js b/build-chrome.js index ef8d6a0..ded0296 100644 --- a/build-chrome.js +++ b/build-chrome.js @@ -6,14 +6,14 @@ import { writeFileSync, readFileSync, copyFileSync } from 'fs' import esbuild from "esbuild"; import esbuildSvelte from "esbuild-svelte"; import sveltePreprocess from "svelte-preprocess"; -import path from 'path'; +//import path from 'path'; -import ChromeExtension from 'crx'; +//import ChromeExtension from 'crx'; -const crx = new ChromeExtension({ - codebase: 'https://github.com/coomdev/pngextraembedder/raw/branch/%E4%B8%AD%E5%87%BA%E3%81%97/PEE-chrome.crx', - privateKey: readFileSync('./key.pem') -}); +//const crx = new ChromeExtension({ +// codebase: 'https://github.com/coomdev/pngextraembedder/raw/branch/%E4%B8%AD%E5%87%BA%E3%81%97/PEE-chrome.crx', +// privateKey: readFileSync('./key.pem') +//}); let res = spawnSync("git", ["rev-list", "--count", "HEAD"]); let rev = +res.stdout; @@ -58,7 +58,7 @@ const domains = [ const manif = { "manifest_version": 2, - "update_url": "https://github.com/coomdev/pngextraembedder/raw/branch/%E4%B8%AD%E5%87%BA%E3%81%97/chrome_update.xml", +// "update_url": "https://github.com/coomdev/pngextraembedder/raw/branch/%E4%B8%AD%E5%87%BA%E3%81%97/chrome_update.xml", "name": "PngExtraEmbedder", "description": "Discover embedded files on 4chan and archives!", "version": "0." + rev, @@ -95,7 +95,7 @@ const manif = { const manif3 = { "manifest_version": 3, - "update_url": "https://github.com/coomdev/pngextraembedder/raw/branch/%E4%B8%AD%E5%87%BA%E3%81%97/chrome_update.xml", +// "update_url": "https://github.com/coomdev/pngextraembedder/raw/branch/%E4%B8%AD%E5%87%BA%E3%81%97/chrome_update.xml", "name": "PngExtraEmbedder", "description": "Discover embedded files on 4chan and archives!", "version": "0." + rev, @@ -103,11 +103,11 @@ const manif3 = { "64": "1449696017588.png" }, "permissions": [ - "notifications", - "clipboardWrite", - "activeTab", + //"notifications", + //"clipboardWrite", + //"activeTab", "declarativeNetRequestWithHostAccess", - "contextMenus", + //"contextMenus", ], host_permissions: domains, //"host_permissions":[""], @@ -195,9 +195,9 @@ const manif3 = { writeFileSync('./chrome/manifest.json', JSON.stringify(lmanif, null, 2)); copyFileSync("./logo.png", "./chrome/1449696017588.png"); - const ext = await crx.load('./chrome'); - const crxBuffer = await ext.pack(); - const updateXML = crx.generateUpdateXML(); - writeFileSync('./chrome_update.xml', updateXML); - writeFileSync('./PEE-chrome.crx', crxBuffer); + //const ext = await crx.load('./chrome'); + //const crxBuffer = await ext.pack(); + //const updateXML = crx.generateUpdateXML(); + //writeFileSync('./chrome_update.xml', updateXML); + //writeFileSync('./PEE-chrome.crx', crxBuffer); })(); diff --git a/chrome/b4k/board.js b/chrome/b4k/board.js new file mode 100644 index 0000000..c729ecb --- /dev/null +++ b/chrome/b4k/board.js @@ -0,0 +1,1544 @@ +var bindFunctions = function() +{ + // the following block of code deals with drag and drop of images for MD5 hashing + var search_dropdown = jQuery('#search_form_image'); + + if (isEventSupported('dragstart') && isEventSupported('drop') && !!window.FileReader) + { + search_dropdown.on('dragover', function(e) { + e.preventDefault(); + e.stopPropagation(); + e.originalEvent.dataTransfer.dropEffect = 'copy'; + }); + + search_dropdown.on('dragenter', function(e) { + e.preventDefault(); + e.stopPropagation(); + }); + + search_dropdown.on('drop', function(event) { + if (event.originalEvent.dataTransfer){ + if (event.originalEvent.dataTransfer.files.length) { + event.preventDefault(); + event.stopPropagation(); + + findSameImageFromFile(event.originalEvent.dataTransfer); + } + } + }); + } + + var is_posting = false; + + var clickCallbacks = { + + checkAll: function(el, post, event) + { + var checkboxes = el.parent().parent().find('input[type=checkbox]'); + checkboxes.each(function(id, element) { + jQuery(element).attr('checked', 'checked'); + }); + el.parent().find('.uncheck').show(); + el.hide(); + }, + + uncheckAll: function(el, post, event) + { + var checkboxes = el.parent().parent().find('input[type=checkbox]'); + checkboxes.each(function(id, element) { + jQuery(element).attr('checked', false); + }); + el.parent().find('.check').show(); + el.hide(); + }, + + hideThread: function(el, post, event) + { + var hiddenBoardThreads = JSON.parse(localStorage.getItem("hiddenBoardThreads/" + el.data("board"))) || {}; + var num = el.data("doc-id"); + + hiddenBoardThreads[num] = true; + localStorage.setItem("hiddenBoardThreads/" + el.data("board"), JSON.stringify(hiddenBoardThreads)); + + jQuery(".doc_id_" + num).hide(); + jQuery(".stub_doc_id_" + num).show(); + }, + + showThread: function(el, post, event) + { + var hiddenBoardThreads = JSON.parse(localStorage.getItem("hiddenBoardThreads/" + el.data("board"))) || {}; + var num = el.data("doc-id"); + + delete hiddenBoardThreads[num]; + localStorage.setItem("hiddenBoardThreads/" + el.data("board"), JSON.stringify(hiddenBoardThreads)); + + jQuery(".doc_id_" + num).show(); + jQuery(".stub_doc_id_" + num).hide(); + }, + + hidePost: function(el, post, event) + { + var hiddenBoardPosts = JSON.parse(localStorage.getItem("hiddenBoardPosts/" + el.data("board"))) || {}; + var num = el.data("doc-id"); + + hiddenBoardPosts[num] = true; + localStorage.setItem("hiddenBoardPosts/" + el.data("board"), JSON.stringify(hiddenBoardPosts)); + + jQuery(".doc_id_" + num).hide(); + jQuery(".stub_doc_id_" + num).show(); + }, + + showPost: function(el, post, event) + { + var hiddenBoardPosts = JSON.parse(localStorage.getItem("hiddenBoardPosts/" + el.data("board"))) || {}; + var num = el.data("doc-id"); + + delete hiddenBoardPosts[num]; + localStorage.setItem("hiddenBoardPosts/" + el.data("board"), JSON.stringify(hiddenBoardPosts)); + + jQuery(".doc_id_" + num).show(); + jQuery(".stub_doc_id_" + num).hide(); + }, + + highlight: function(el, post, event) + { + if (post) + { + toggleHighlight(post); + } + }, + + quote: function(el, post, event) + { + jQuery("#reply_chennodiscursus").insertAtCaret(">>" + post + "\n"); + }, + + comment: function(el, post, event) + { + var file_el = jQuery("#file_image"); + var progress_pos = 0; + var progress_el = jQuery("#reply .progress .bar"); + + // if there's an image and the browser doesn't support FormData, use a normal upload process + if (file_el.val() && window.FormData === undefined) + { + return true; + } + + if (is_posting) + { + return false; + } + + is_posting = true; + + var originalText = el.attr('value'); + var el_parent = el.parent(); + el.attr({'value': backend_vars.gettext['submit_state']}); + el_parent.find('[name=reply_gattai]').attr({disabled:'disabled'}); + el_parent.find('[name=reply_gattai_spoilered]').attr({disabled:'disabled'}); + //el.parent().find('[name=reply_gattai], [name=reply_gattai_spoilered]') + + // to make sure nobody gets pissed off with a blocked button + var buttonTimeout = setTimeout(function(){ + el.attr({'value': originalText}); + el.removeAttr('disabled'); + }, 10000); + + var reply_alert = jQuery('#reply_ajax_notices'); + reply_alert.removeClass('error').removeClass('success'); + + var data_obj = { + reply_numero: jQuery("#reply_numero").val(), + reply_bokunonome: jQuery("#reply_bokunonome").val(), + reply_elitterae: jQuery("#reply_elitterae").val(), + reply_talkingde: jQuery("#reply_talkingde").val(), + reply_chennodiscursus: jQuery("#reply_chennodiscursus").val(), + reply_nymphassword: jQuery("#reply_nymphassword").val(), + reply_postas: jQuery("#reply_postas").val() === undefined ? 'N' : jQuery("#reply_postas").val(), + reply_gattai: 'Submit', + reply_last_limit: typeof backend_vars.last_limit === "undefined" ? null : backend_vars.last_limit, + latest_doc_id: backend_vars.latest_doc_id, + theme: backend_vars.selected_theme + }; + + if(typeof jQuery("#recaptcha_challenge_field").val() !== 'undefined' && typeof jQuery("#recaptcha_response_field").val() !== 'undefined') { + data_obj['recaptcha_challenge_field'] = jQuery("#recaptcha_challenge_field").val(); + data_obj['recaptcha_response_field'] = jQuery("#recaptcha_response_field").val(); + } else if(typeof jQuery("#g-recaptcha-response").val() !== 'undefined') { + data_obj['recaptcha2_response_field'] = jQuery("#g-recaptcha-response").val(); + } + + // sets the type of submit (reply_gattai, reply_gattai_spoilered) + data_obj[el.attr('name')] = true; + + // support for checkbox spoiler + if (el_parent.find('[name=reply_spoiler]:checked').length) + { + data_obj.reply_spoiler = true; + } + + data_obj[backend_vars.csrf_token_key] = getCookie(backend_vars.csrf_token_key); + + progress_el.parent().animate({'opacity': '1.0'}, 300); + + var ajax_object = { + url: backend_vars.site_url + backend_vars.board_shortname + '/submit/' , + dataType: 'json', + type: 'POST', + data: data_obj, + cache: false, + xhr: function() { + var xhr = jQuery.ajaxSettings.xhr(); + if (xhr instanceof window.XMLHttpRequest) { + xhr.upload.addEventListener('progress', function(evt){ + var progress_local = Math.ceil(evt.loaded / evt.total * 100); + if (evt.lengthComputable && progress_pos !== progress_local) + { + progress_pos = progress_local; + progress_el.css('width', (progress_pos) + '%'); + } + }, false); + } + return xhr; + }, + success: function(data, textStatus, jqXHR) { + if (typeof window.Recaptcha !== "undefined") + { + window.Recaptcha.reload(); + } + if (typeof window.grecaptcha !== "undefined") { + grecaptcha.reset(); + } + + jQuery("#recaptcha_response_field").val(''); + if (typeof data.captcha !== "undefined") + { + if(recaptcha2.enabled && typeof window.grecaptcha === "undefined") { + jQuery('.recaptcha_widget').html('

You might be a bot! Enter a reCAPTCHA to continue.

\ +
\ + ') + } + jQuery('.recaptcha_widget').show(); + jQuery('.rules_box').hide(); + return false; + } + + if (typeof data.error !== "undefined") + { + reply_alert.html(data.error); + reply_alert.addClass('error'); // deals with showing the alert + return false; + } + + jQuery('.rules_box').show(); + jQuery('.recaptcha_widget').hide(); + + reply_alert.html(data.success); + reply_alert.addClass('success'); // deals with showing the alert + jQuery("#reply_chennodiscursus").val(""); + jQuery("#reply_nymphassword").val(getCookie('reply_password')); + file_el.replaceWith(''); + + + // redirect in case of new threads + if (data_obj.reply_numero < 1) + { + window.location = backend_vars.site_url + backend_vars.board_shortname + '/thread/' + + data.thread_num + '/'; + return false; + } + + insertPost(data, textStatus, jqXHR); + }, + error: function(jqXHR, textStatus, errorThrown) { + reply_alert.html('Connection error.'); + reply_alert.addClass('error'); + reply_alert.show(); + }, + complete: function() { + // clear button's timeout, we can deal with the rest now + is_posting = false; + clearTimeout(buttonTimeout); + el.attr({'value': originalText}); + el_parent.find('[name=reply_gattai]').removeAttr('disabled'); + el_parent.find('[name=reply_gattai_spoilered]').removeAttr('disabled'); + progress_el.css('width', '0%'); + progress_el.parent().animate({'opacity': '0.0'}, 300); + } + }; + + // if we have FormData support, we can upload files! + if (window.FormData !== undefined) + { + ajax_object.processData = false; + ajax_object.contentType = false; + var data_formdata = new FormData(); + jQuery.each(data_obj, function(id, val){ + data_formdata.append(id, val); + }); + + if (typeof file_el[0] !== 'undefined' && typeof file_el[0].files !== 'undefined') + { + data_formdata.append('file_image', file_el[0].files[0]) + } + + ajax_object.data = data_formdata; + } + + jqxhr = jQuery.ajax(ajax_object); + + event.preventDefault(); + }, + + realtimeThread: function(el, post, event) + { + realtimethread(); + event.preventDefault(); + }, + + expandThread: function(el, post, event) + { + var thread_num = el.data('thread-num'); + + if (! el.data('expanded')) + { + el.spin('small'); + jQuery.ajax({ + url: backend_vars.api_url + '_/api/chan/thread/', + dataType: 'json', + type: 'GET', + data: { + num : thread_num, + board: backend_vars.board_shortname, + theme: backend_vars.selected_theme + }, + success: function(data, textStatus, jqXHR){ + insertPost(data, textStatus, jqXHR); + var post_count = 0; + var media_count = 0; + jQuery.each(data[thread_num].posts, function(id, val){ + post_count++; + if (val.media !== null) + { + media_count++; + } + }); + var thread = jQuery('article.thread[data-thread-num=' + thread_num + '] '); + var displayed_string = post_count + ' posts ' + + (media_count > 0 ? 'and ' + media_count + ' ' + (media_count == 1 ? 'image' : 'images') : '') + ' displayed'; + thread.find('.omitted_text').text(displayed_string); + el.data('expanded', true).html(''); + el.spin(false); + } + }); + } + else + { + var thread = jQuery('article.thread[data-thread-num=' + thread_num + ']'); + var articles = thread.find('aside.posts article'); + articles.slice(0, articles.length - 5).hide(); + var post_count = articles.filter(':hidden').length; + var media_count = articles.find('.thread_image_box:hidden').length; + var omitted_string = post_count + ' posts ' + + (media_count > 0 ? 'and ' + media_count + ' ' + (media_count == 1 ? 'image' : 'images') : '') + ' omitted'; + thread.find('.omitted_text').text(omitted_string); + el.data('expanded', false).html(''); + } + + return false; + }, + + clearSearch: function(el, post, event) + { + var form = jQuery('.advanced_search').find('form'); + form.find(':input').not(':input[type=submit]').not(':input[type=reset]').val(''); + + // keep the first radio set + var done_names = []; + form.find('[type=radio]').each(function (idx) { + if (!jQuery.inArray(jQuery(this).attr('name'), done_names)) + { + jQuery(this).attr('checked', true); + done_names.push(jQuery(this).attr('name')); + } + }); + }, + + mod: function(el, post, event) + { + el.attr({'disabled': 'disabled'}); + _data = { + board: el.data('board'), + id: el.data('id'), + ip: el.data('ip'), + action: el.data('action'), + global: el.data('global'), + theme: backend_vars.selected_theme + }; + _data[backend_vars.csrf_token_key] = getCookie(backend_vars.csrf_token_key); + jQuery.ajax({ + url: backend_vars.api_url + '_/api/chan/mod_actions/', + dataType: 'json', + type: 'POST', + cache: false, + data: _data, + success: function(data){ + el.removeAttr('disabled'); + if (typeof data.error !== "undefined") + { + alert(data.error); + return false; + } + + // might need to be upgraded to array support + switch(el.data('action')) + { + case 'remove_post': + jQuery('.doc_id_' + el.data('id')).remove(); + break; + case 'delete_image': + jQuery('.doc_id_' + el.data('doc-id')).find('.thread_image_box:eq(0) img') + .attr('src', backend_vars.images['missing_image']) + .css({ + width: backend_vars.images['missing_image_width'], + height: backend_vars.images['missing_image_height'] + }); + break; + case 'delete_report': + el.closest('.report_reason').remove(); + break; + case 'ban_user': + jQuery('.doc_id_' + el.data('id')).find('[data-action=ban_user]').text('Banned'); + break; + case 'ban_image': + jQuery('.doc_id_' + el.data('doc-id')).find('.thread_image_box:eq(0) img') + .attr('src', backend_vars.images['banned_image']) + .css({ + width: backend_vars.images['banned_image_width'], + height: backend_vars.images['banned_image_height'] + }); + break; + case 'delete_all_reports': + $(".report_reason").each(function(){ + $(this).remove(); + }); + break; + default: + el.closest('.report_reason').append(data.success); + break; + } + }, + error: function(jqXHR, textStatus, errorThrown) { + + }, + complete: function() { + } + }); + return false; + }, + + activateModeration: function(el, post, event) + { + jQuery('.post_mod_controls button[data-function]').attr({'disabled': 'disabled'}); + setTimeout(function(){ + jQuery('.post_mod_controls button[data-function]').removeAttr('disabled'); + }, 700); + jQuery('.post_mod_controls').show(); + jQuery('button[data-function=activateModeration]').parent().hide(); + }, + + activateExtraMod: function(el, post, event) + { + jQuery('.post_extra_mod button[data-function]').attr({'disabled': 'disabled'}); + setTimeout(function(){ + jQuery('.post_extra_mod button[data-function]').removeAttr('disabled'); + }, 700); + jQuery('.post_extra_mod').show(); + jQuery('button[data-function=activateExtraMod]').parent().hide(); + }, + + closeModal: function(el, post) + { + el.closest(".modal").modal('hide'); + return false; + }, + + 'delete': function(el, post, event) + { + var modal = jQuery("#post_tools_modal"); + var foolfuuka_reply_password = getCookie('foolfuuka_reply_password'); + modal.find(".title").html('Delete » Post No. ' + el.data("post-id")); + modal.find(".modal-error").html(''); + modal.find(".modal-loading").hide(); + modal.find(".modal-information").html('\ + Password\n\ + \n\ + \n\ + '); + modal.find(".submitModal").data("action", 'delete'); + modal.find(".modal-password").val(backend_vars.user_pass); + }, + + report: function(el, post, event) + { + var modal = jQuery("#post_tools_modal"); + modal.find(".title").html('Report » Post No.' + el.data("post-id")); + modal.find(".modal-error").html(''); + modal.find(".modal-loading").hide(); + modal.find(".modal-information").html('Report Multiple\ + \n\ + \n\ + Comment\n\ + \n\ + Note: Requests for content removal and take-downs must be sent via email.'); + modal.find(".submitModal").data("action", 'report'); + }, + + addBulkReport: function(el, post, event) { + jQuery('article.thread, article.post').each(function () { + if (typeof jQuery(this).attr('data-board') != 'undefined') { + jQuery(this).find('a[data-function=report]:eq(0)').replaceWith('' + + 'Report Selected'); + } + }); + el.closest(".modal").modal('hide'); + }, + + bulkReport: function(el, post, event) { + var modal = jQuery("#post_tools_modal"); + modal.find(".title").html('Report Posts'); + modal.find(".modal-error").html(''); + modal.find(".modal-loading").hide(); + modal.find(".modal-information").html('Selected posts:
'); + jQuery('.bulkreportselect:checked').each(function () { + modal.find(".modal-information").append('>>>/' + $(this).attr('data-board') + '/' + $(this).attr('data-num') + '
'); + }); + modal.find(".modal-information").append('
Comment\n\ + \n\ + Note: Requests for content removal and take-downs must be sent via email.'); + modal.find(".submitModal").data("action", 'bulk-report'); + }, + + ban: function(el, post, event) + { + var modal = jQuery("#post_tools_modal"); + modal.find(".title").html('Ban user with IP ' + el.data("ip")); + modal.find(".modal-error").html(''); + modal.find(".modal-loading").hide(); + modal.find(".modal-information").html('\ + \n\ + IP\n\ +
\n\ + Days\n\ +
\n\ + Only this board\n\ +
\n\ + Global\n\ +
\n\ + Comment\n\ + \n\ + \ + \n\ + '); + modal.find(".submitModal").data("action", 'ban'); + }, + + editPost: function(el, post, event) + { + var modal = jQuery("#post_tools_modal"); + modal.find(".title").html('Edit Post No. ' + el.data("post-id")); + modal.find(".modal-error").html(''); + modal.find(".modal-loading").show(); + modal.find(".modal-information").html('Bulk Edit\ +
\ + \n\ + \n\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ + \ + '); + modal.find(".submitModal").data("action", 'edit-post'); + jQuery.ajax({ + url: backend_vars.api_url + '_/api/chan/post/' , + dataType: 'json', + type: 'GET', + cache: false, + data: { + board: el.data('board'), + num: el.data('post-id') + }, + success: function(data){ + jQuery("input[name='edit-subject']").val(data.title); + jQuery("input[name='edit-name']").val(data.name); + jQuery("input[name='edit-trip']").val(data.trip); + jQuery("input[name='edit-email']").val(data.email); + jQuery("input[name='edit-country']").val(data.poster_country); + jQuery("input[name='edit-poster_hash']").val(data.poster_hash); + jQuery("select[name='edit-capcode']").val(data.capcode); + jQuery("textarea[name='edit-comment']").val(data.comment); + if(data.media != null) { + modal.find(".modal-information").append('

Media

\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ + '); + jQuery("input[name='media_id']").val(data.media.media_id); + jQuery("input[name='edit-filename']").val(data.media.media_filename); + if(data.media.spoiler == 1) { + jQuery("input[name='edit-spoiler']").click(); + } + jQuery("input[name='edit-media_w']").val(data.media.media_w); + jQuery("input[name='edit-media_h']").val(data.media.media_h); + jQuery("input[name='edit-preview_w']").val(data.media.preview_w); + jQuery("input[name='edit-preview_h']").val(data.media.preview_h); + } + }, + error: function() { + console.log('post not found'); + el.closest(".modal").modal('hide'); + }, + complete: function() { + modal.find(".modal-information").append('
'); + modal.find(".modal-loading").hide(); + } + }); + }, + + addBulkEdit: function(el, post, event) { + jQuery('article.thread, article.post').each(function () { + if (typeof jQuery(this).attr('data-board') != 'undefined') { + jQuery('' + + 'Edit Selected') + .prependTo($(this).find('.post_data:first')); + } + }); + el.closest(".modal").modal('hide'); + }, + + bulkEdit: function(el, post, event) { + var modal = jQuery("#post_tools_modal"); + modal.find(".title").html('Edit Posts'); + modal.find(".modal-error").html(''); + modal.find(".modal-loading").hide(); + modal.find(".modal-information").html('This will only modify specified fields. Leave blank to not modify that field.

' + + 'Selected posts:
'); + jQuery('.bulkselect:checked').each(function () { + modal.find(".modal-information").append('>>>/' + $(this).attr('data-board') + '/' + $(this).attr('data-num') + '
'); + }); + modal.find(".modal-information").append('
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ + \ +

Media

\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ + '); + modal.find(".submitModal").data("action", 'bulk-edit'); + }, + + addBulkMod: function(el, post, event) { + jQuery('article.thread, article.post').each(function () { + if (typeof jQuery(this).attr('data-board') != 'undefined') { + jQuery(this).find('a[data-function=delete]:eq(0)').replaceWith('' + + 'Mod Selected'); + } + }); + }, + + bulkMod: function(el, post, event) { + var modal = jQuery("#post_tools_modal"); + modal.find(".title").html('Mod Posts'); + modal.find(".modal-error").html(''); + modal.find(".modal-loading").hide(); + modal.find(".modal-information").html('Selected posts:
'); + jQuery('.bulkmodselect:checked').each(function () { + modal.find(".modal-information").append('>>>/' + $(this).attr('data-board') + '/' + $(this).attr('data-num') + '
'); + }); + modal.find(".modal-information").append('
Select action
' + + '
\ + \ + \ + \ + \ +
'); + modal.find(".submitModal").data("action", 'bulk-mod'); + }, + + submitModal: function(el, post, event) + { + var modal = jQuery("#post_tools_modal"); + var loading = modal.find(".modal-loading"); + var action = el.data("action"); + var _board = modal.find(".modal-board").val(); + var _doc_id = modal.find(".modal-post-id").val(); + var _href = backend_vars.api_url+'_/api/chan/user_actions/'; + var _data = {}; + + if (action == 'report') { + _data = { + action: 'report', + board: _board, + doc_id: _doc_id, + reason: modal.find(".modal-comment").val(), + csrf_fool: backend_vars.csrf_hash + }; + } + else if (action == 'report_media') { + _data = { + action: 'report_media', + board: _board, + media_id: modal.find(".modal-media-id").val(), + reason: modal.find(".modal-comment").val(), + csrf_fool: backend_vars.csrf_hash + }; + } + else if (action == 'delete') { + _data = { + action: 'delete', + board: _board, + doc_id: _doc_id, + password: modal.find(".modal-password").val(), + csrf_fool: backend_vars.csrf_hash + }; + } + else if (action == 'ban') + { + _href = backend_vars.api_url+'_/api/chan/mod_actions/'; + _data = { + action: 'ban_user', + board: modal.find('.modal-board').val(), + board_ban: modal.find('input:radio[name=board]:checked').val(), + length: modal.find('.modal-days').val() * 24 * 60 * 60, + ip: modal.find('.modal-ip').val(), + reason: modal.find('.modal-comment').val(), + doc_id: _doc_id + }; + if ($('input[name=delete_user]').is(':checked')) { + _data.delete_user = true; + } + if ($('input[name=ban_public]').is(':checked')) { + _data.ban_public = true; + } + } + else if (action == 'edit-post') + { + _href = backend_vars.api_url+'_/api/chan/edit_post/'; + _data = { + action: 'edit_post', + board: modal.find('.modal-board').val(), + doc_id: modal.find('.modal-post-id').val(), + subject: modal.find("input[name='edit-subject']").val(), + name: modal.find("input[name='edit-name']").val(), + trip: modal.find("input[name='edit-trip']").val(), + email: modal.find("input[name='edit-email']").val(), + poster_country: modal.find("input[name='edit-country']").val(), + poster_hash: modal.find("input[name='edit-poster_hash']").val(), + capcode: modal.find("select[name='edit-capcode']").val(), + comment: modal.find("textarea[name='edit-comment']").val(), + csrf_fool: backend_vars.csrf_hash + }; + if ($('input[name=transparency]').is(':checked')) { + _data.transparency = true; + } + if(modal.find("input[name='media_id']").val() != null) { + _data.media_edit = true; + _data.filename = modal.find("input[name='edit-filename']").val(); + _data.media_w = modal.find("input[name='edit-media_w']").val(); + _data.media_h = modal.find("input[name='edit-media_h']").val(); + _data.preview_w = modal.find("input[name='edit-preview_w']").val(); + _data.preview_h = modal.find("input[name='edit-preview_h']").val(); + if ($('input[name=edit-spoiler]').is(':checked')) { + _data.spoiler = 1; + } else { + _data.spoiler = 0; + } + } + } + else if (action == 'bulk-edit') { + _href = backend_vars.api_url + '_/api/chan/edit_post/'; + + _data = { + action: 'bulk_edit', + subject: modal.find("input[name='edit-subject']").val(), + name: modal.find("input[name='edit-name']").val(), + trip: modal.find("input[name='edit-trip']").val(), + email: modal.find("input[name='edit-email']").val(), + poster_country: modal.find("input[name='edit-country']").val(), + poster_hash: modal.find("input[name='edit-poster_hash']").val(), + capcode: modal.find("select[name='edit-capcode']").val(), + comment: modal.find("textarea[name='edit-comment']").val(), + filename: modal.find("input[name='edit-filename']").val(), + media_w: modal.find("input[name='edit-media_w']").val(), + media_h: modal.find("input[name='edit-media_h']").val(), + preview_w: modal.find("input[name='edit-preview_w']").val(), + preview_h: modal.find("input[name='edit-preview_h']").val(), + csrf_fool: backend_vars.csrf_hash, + posts: [] + }; + if ($('input[name=edit-spoiler]').is(':checked')) { + _data.spoiler = 1; + } else { + _data.spoiler = 0; + } + jQuery('.bulkselect:checked').each(function () { + _data.posts.push({ + radix: $(this).attr('data-board'), + doc_id: $(this).attr('data-doc-id') + } + ); + }); + } + else if (action == 'bulk-report') { + _data = { + action: 'bulk_report', + reason: modal.find(".modal-comment").val(), + csrf_fool: backend_vars.csrf_hash, + posts: [] + }; + jQuery('.bulkreportselect:checked').each(function () { + _data.posts.push({ + radix: $(this).attr('data-board'), + doc_id: $(this).attr('data-doc-id'), + num: $(this).attr('data-num') + } + ); + }); + } + else if (action == 'bulk-mod') { + _href = backend_vars.api_url+'_/api/chan/bulk_mod/'; + _data = { + action: 'bulk_mod', + mod_function: $('input[name=modaction]:checked').val(), + csrf_fool: backend_vars.csrf_hash, + posts: [] + }; + jQuery('.bulkmodselect:checked').each(function () { + _data.posts.push({ + radix: $(this).attr('data-board'), + doc_id: $(this).attr('data-doc-id'), + num: $(this).attr('data-num') + } + ); + }); + } + else { + // Stop It! Unable to determine which action to use. + return false; + } + + _data[backend_vars.csrf_token_key] = getCookie(backend_vars.csrf_token_key); + + jQuery.post(_href, _data, function(result) { + loading.hide(); + if (typeof result.error !== 'undefined') { + modal.find(".modal-error").html('
×

' + result.error + '

').show(); + return false; + } + modal.modal('hide'); + + if (action == 'delete') { + jQuery('.doc_id_' + _doc_id).hide(); + } + if (action == 'report') { + jQuery('.doc_id_' + _doc_id).find('.text:eq(0)').after('
' + result.success + '
'); + } + if (action == 'edit-post') { + jQuery('.doc_id_' + _doc_id).find('.text:eq(0)').after('
' + result.success + '
'); + } + if (action == 'bulk-edit') { + jQuery('div.container').after('
' + result.success + '
'); + } + if (action == 'bulk-report') { + jQuery('div.container').after('
' + result.success + '
'); + } + if (action == 'bulk-mod') { + jQuery('div.container').after('
' + result.success + '
'); + } + }, 'json'); + return false; + }, + + clearLatestSearches: function(el, post, event) + { + setCookie('search_latest_5', '', 0, '/', backend_vars.cookie_domain); + jQuery('li.latest_search').each(function(idx){ + jQuery(this).remove(); + }); + }, + + searchUser: function(el, post, event) + { + window.location.href = backend_vars.site_url + el.data('board') + + '/search/poster_ip/' + el.data('poster-ip'); + }, + + searchUserGlobal: function(el, post, event) + { + window.location.href = backend_vars.site_url + '_/search/poster_ip/' + el.data('poster-ip'); + }, + + toggleExif: function(el, post, event) + { + jQuery(".exiftable."+post).toggle(); + }, + + searchhilight: function(el, post, event) + { + if (el.is(':checked')) { + setCookie("searchhilight_enabled", true, 90, '/', backend_vars.cookie_domain); + if (jQuery("span[data-markjs='true']").length) { + jQuery("span[data-markjs='true']").addClass("highlight"); + } else if (typeof backend_vars.search_args !== "undefined") { + highlightSearchResults(); + } + } else { + setCookie("searchhilight_enabled", false, 90, '/', backend_vars.cookie_domain); + jQuery("span[data-markjs='true']").removeClass("highlight"); + } + } + }; + + + // unite all the onclick functions in here + jQuery(document.body).on("click", "a[data-function], button[data-function], input[data-function]", function(event) { + var el = jQuery(this); + var post = el.data("post"); + return clickCallbacks[el.data("function")](el, post, event); + }); + + jQuery(document.body).on("mousedown touchstart", ".search_box, .search-query", function(event) { + event.stopPropagation(); + }); + + jQuery(document.body).on("mousedown touchstart", function(event) { + var search_input = jQuery('#search_form_comment'); + jQuery('.search-query').val(search_input.val()); + jQuery('.search_box').hide(); + }); + + jQuery(document.body).on("mousedown touchstart", ".search-query", function() { + var el = jQuery(this); + var offset = el.offset(); + var width = el.outerWidth(); + var search_box = jQuery('.search_box'); + var comment_wrap = search_box.find('.comment_wrap'); + var comment_wrap_pos = comment_wrap.position(); + search_box.css({top: (offset.top - 11) + 'px', right: (jQuery(window).width() - (offset.left + width) - 16) + 'px'}).show(); + el.parents('.open').removeClass('open'); + search_box.find('input[name=text]').focus(); + return false; + }); + + // how could we make it work well on cellphones? + if (/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent)) + { + return false; + } + + + // variable for ajax backlinks that we can clear them if the mouse hovered out + var backlink_jqxhr; + var timeout; + var posts_being_fetched = []; // posts that are being xhr'd right now + var show_post_board; + var show_post_num; // the number of the post that has to show in the xhr callback, when 0 don't run popups + + // hover functions go here + jQuery("#main").on("mouseover mouseout", "article a[data-backlink]", function(event) + { + + if (event.type == "mouseover") + { + + var backlink = jQuery("#backlink"); + var el = jQuery(this); + + var pos = el.offset(); + var height = el.height(); + var width = el.width(); + + if (el.attr('data-backlink') != 'true') + { + // gallery + var thread_id = el.attr('data-backlink'); + quote = backend_vars.threads_data[thread_id]; + backlink.css('display', 'block'); + backlink.html(quote.formatted); + } + else if (jQuery('#' + el.data('post')).hasClass('post')) + { + // normal posts + var toClone = jQuery('#' + el.data('post')); + if (toClone.length == 0) + return false; + backlink.css('display', 'block'); + backlink.html(toClone.clone().show()); + } + else if (typeof backend_vars.loaded_posts[el.data('board') + ':' + el.data('post')] !== 'undefined') + { + // if we know the post doesn't exist + if (backend_vars.loaded_posts[el.data('board') + ':' + el.data('post')] === false) + { + shakeBacklink(el); + return false; + } + var data = backend_vars.loaded_posts[el.data('board') + ':' + el.data('post')]; + backlink.html(data.formatted); + backlink.css('display', 'block'); + } + else + { + show_post_board = el.data('board'); + show_post_num = el.data('post'); + + // avoid multiple connections + if (posts_being_fetched[el.data('board') + ':' + el.data('post')]) { + return false; + } + + timeout = setTimeout(function() { + var backlink_spin = el; + backlink_spin.spin('small'); + backlink_jqxhr = jQuery.ajax({ + url: backend_vars.api_url + '_/api/chan/post/' , + dataType: 'json', + type: 'GET', + cache: false, + data: { + board: el.data('board'), + num: el.data('post'), + theme: backend_vars.selected_theme + }, + success: function(data){ + backlink_spin.spin(false); + if (typeof data.error !== "undefined") + { + backend_vars.loaded_posts[el.data('board') + ':' + el.data('post')] = false; + shakeBacklink(el); + return false; + } + backend_vars.loaded_posts[el.data('board') + ':' + el.data('post')] = data; + + // avoid showing the post if the mouse is not there anymore + if (show_post_board === el.data('board') && show_post_num === el.data('post')) + { + backlink.html(data.formatted); + backlink.find("time").localize('ddd dd mmm yyyy HH:MM:ss'); + backlink.css('display', 'block'); + showBacklink(backlink, pos, height, width); + } + }, + error: function() { + shakeBacklink(el); + }, + complete: function() { + posts_being_fetched[el.data('board') + ':' + el.data('post')] = false; + } + }); + return false; + }, 50); + } + + backlink.find("time").localize('ddd dd mmm yyyy HH:MM:ss'); + showBacklink(backlink, pos, height, width); + } + else + { + show_post_board = false; + show_post_num = false; + clearTimeout(timeout); + jQuery("#backlink").css('display', 'none').html(''); + } + }); +}; + +var hideThreads = function() +{ + if (typeof backend_vars.board_shortname !== "undefined" && typeof backend_vars.thread_id === "undefined") + { + var hiddenBoardThreads = JSON.parse(localStorage.getItem("hiddenBoardThreads/" + backend_vars.board_shortname)) || {}; + + for (var num in hiddenBoardThreads) + { + jQuery(".doc_id_" + num).hide(); + jQuery(".stub_doc_id_" + num).show(); + } + } +}; + +var hidePosts = function() +{ + if (typeof backend_vars.board_shortname !== "undefined") + { + var hiddenBoardPosts = JSON.parse(localStorage.getItem("hiddenBoardPosts/" + backend_vars.board_shortname)) || {}; + + for (var num in hiddenBoardPosts) + { + jQuery(".doc_id_" + num).hide(); + jQuery(".stub_doc_id_" + num).show(); + } + } +}; + +var shakeBacklink = function(el) +{ + el.css({position:'relative'}); + el.animate({left: '-5px'},100) + .animate({left: '+5px'}, 100) + .animate({left: '-5px'}, 100) + .animate({left: '+5px'}, 100) + .animate({left: '+0px'}, 100, 'linear', function(){ + el.css({position:'static'}); + }); + +}; + +var showBacklink = function(backlink, pos, height, width) +{ + if (jQuery(window).width()/2 < pos.left + width/2) + { + backlink.css({ + right: (jQuery(window).width() - pos.left - width) + 'px', + top: (pos.top + height + 3) + 'px', + left: 'auto' + }); + } + else + { + backlink.css({ + left: (pos.left) + 'px', + top: (pos.top + height + 3) + 'px', + right: 'auto' + }); + } + + backlink.find('.stub').remove(); +}; + +var backlinkify = function(elem, post_id, subnum) +{ + var backlinks = {}; + if (subnum > 0) + { + post_id += "_" + subnum; + } + + elem.find("a[data-backlink=true]").each(function(idx, post) { + if (jQuery(post).text().indexOf('/') >= 0) + { + return true; + } + + var p_id = jQuery(post).attr('data-post'); + var board_shortname = jQuery(post).attr('data-board'); + + if (typeof backlinks[p_id] === "undefined") + { + backlinks[p_id] = []; + } + + if (typeof backend_vars.last_limit === "undefined") + { + if (typeof backend_vars.thread_id === "undefined") + { + backlinks[p_id].push('>>' + post_id.replace('_', ',') + ''); + + // convert /post/ links to real urls + if (jQuery('#' + p_id).length) + { + jQuery(post).attr('href', backend_vars.site_url + board_shortname + '/post/' + p_id); + } + } + else + { + backlinks[p_id].push('>>' + post_id.replace('_', ',') + ''); + + // convert /post/ links to real urls + if (jQuery('#' + p_id).length) + { + if (backend_vars.thread_id == p_id) + { + jQuery(post).addClass('op'); + } + + jQuery(post).attr('href', backend_vars.site_url + board_shortname + '/thread/' + backend_vars.thread_id + '/#' + p_id); + } + } + } + else + { + backlinks[p_id].push('>>' + post_id.replace('_', ',') + ''); + + // convert /post/ links to real urls + if (jQuery('#' + p_id).length) + { + jQuery(post).attr('href', backend_vars.site_url + board_shortname + '/last/' + backend_vars.last_limit + '/' + backend_vars.thread_id + '/#' + p_id); + } + } + + backlinks[p_id] = eliminateDuplicates(backlinks[p_id]); + }); + + jQuery.each(backlinks, function(key, val){ + var post = jQuery("#" + key); + if (post.length == 0) + return false; + + var post_backlink = post.find(".post_backlink:eq(0)"); + var already_backlinked = post_backlink.text().replace('>>', '').split(' '); + jQuery.each(already_backlinked, function(i,v){ + if (typeof val[v] !== "undefined") + { + delete val[v]; + } + }); + + if (post_backlink.find('[data-post=' + post_id + ']').length == 0) + { + post_backlink.html(post_backlink.html() + ((post_backlink.html().length > 0)?" ":"") + val.join(" ")); + post_backlink.parent().show(); + } + }); +}; + +var timelapse = 10; +var currentlapse = 0; +var realtimethread = function(){ + clearTimeout(currentlapse); + jQuery.ajax({ + url: backend_vars.api_url + '_/api/chan/thread/', + dataType: 'json', + type: 'GET', + data: { + num : backend_vars.thread_id, + board: backend_vars.board_shortname, + latest_doc_id: backend_vars.latest_doc_id, + theme: backend_vars.selected_theme, + last_limit: typeof backend_vars.last_limit === "undefined" ? null : backend_vars.last_limit + }, + success: insertPost, + error: function(jqXHR, textStatus, errorThrown) { + //timelapse = 10; + }, + complete: function() { + currentlapse = setTimeout(realtimethread, timelapse*1000); + } + }); + + return false; +}; + +var ghost = false; +var insertPost = function(data, textStatus, jqXHR) +{ + var w_height = jQuery(document).height(); + var found_posts = false; + + if (data !== null) + { + jQuery.each(data, function(id, val) + { + if (typeof val.posts !== "undefined") + { + var aside = jQuery('article.thread[data-thread-num=' + id + '] aside.posts'); + jQuery.each(val.posts, function(idx, value) + { + found_posts = true; + var post = jQuery(value.formatted); + + post.find("time").localize('ddd dd mmm yyyy HH:MM:ss'); + post.find('[rel=tooltip]').tooltip({ + placement: 'top', + delay: 200 + }); + + post.find('[rel=tooltip_right]').tooltip({ + placement: 'right', + delay: 200 + }); + + // avoid inserting twice + if (jQuery('.doc_id_' + value.doc_id).length != 0) + { + jQuery('.doc_id_' + value.doc_id).remove(); + } + + aside.append(post); + backlinkify(post, value.num, value.subnum); + + $('pre,code').each(function(i, block) { + hljs.highlightBlock(block); + }); + + if(backend_vars.latest_doc_id < value.doc_id) + { + backend_vars.latest_doc_id = value.doc_id; + } + + // update comment box when encountering ghost posts + if (ghost === false && value.subnum > 0) + { + jQuery("#file_image").parent().remove(); + jQuery("#reply_chennodiscursus").attr("placeholder", backend_vars.gettext['ghost_mode']); + + ghost = true; + } + }); + } + }); + } + + if (found_posts) + { + if (jQuery('#reply :focus').length > 0) + { + window.scrollBy(0, jQuery(document).height() - w_height); + } + + enableRealtimeThread(); + + timelapse = 10; + } + else + { + if (timelapse < 120) + { + timelapse += 5; + } + } +}; + +var findSameImageFromFile = function(obj) +{ + var reader = new FileReader(); + reader.onloadend = function(evt){ + if (evt.target.readyState == FileReader.DONE) { + var fileContents = evt.target.result; + var digestBytes = Crypto.MD5(Crypto.charenc.Binary.stringToBytes(fileContents), { + asBytes: true + }); + var digestBase64 = Crypto.util.bytesToBase64(digestBytes); + var digestBase64URL = digestBase64.replace('==', '').replace(/\//g, '_').replace(/\+/g, '-'); + jQuery('#search_form_image').val(digestBase64URL); + } + }; + + reader.readAsBinaryString(obj.files[0]); +}; + +var toggleHighlight = function(id) +{ + var classn = 'highlight'; + jQuery("article").each(function() { + var post = jQuery(this); + + if (post.hasClass(classn)) + { + post.removeClass(classn); + } + + if (post.attr("id") == id) + { + post.addClass(classn); + } + }) +}; + +var realtime = false; +var enableRealtimeThread = function() +{ + if (realtime == false) + { + realtime = true; + + jQuery('.js_hook_realtimethread').html(backend_vars.gettext['thread_is_real_time'] + ' ' + backend_vars.gettext['update_now'] + ''); + setTimeout(realtimethread, 10000); + } +}; + +var highlightSearchResults = function() +{ + jQuery.each(backend_vars.search_args, function(id, val) + { + var selector; + if (id == "text") { + selector = "div.text"; + } else if (id == "filename") { + selector = "a.post_file_filename" + } else if (id == "username") { + selector = "span.post_author" + } else if (id == "subject") { + selector = "h2.post_title"; + } else if (id == "tripcode") { + selector = "span.post_tripcode"; + } else if (id == "uid") { + selector = "span.poster_hash"; + } else { + return true; + } + if (selector != "") { + val = val.replace(/[\.\*\^\|'"!]/g, " "); + jQuery( selector ).mark(val, { + "element": "span", + "className": "highlight" + }); + } + }); +}; + +jQuery(document).ready(function() { + + // settings + jQuery.support.cors = true; + backend_vars.loaded_posts = []; + + // check if input[date] is supported, so we can use by default input[text] with placeholder without breaking w3 + var i = document.createElement("input"); + i.setAttribute("type", "date"); + if (i.type !== "text") + { + jQuery('#date_end').replaceWith(jQuery('').attr({id: 'date_end', name: 'end', type: 'date'})); + jQuery('#date_start').replaceWith(jQuery('').attr({id: 'date_start', name: 'start', type: 'date'})); + } + + // opera doesn't play well with the modal transition + if (navigator.appName == "Opera" && navigator.userAgent.match(/Version\/12\./)) + { + $('#post_tools_modal').removeClass('fade'); + } + + // firefox sucks at styling input, so we need to add size="", that guess what? It's not w3 compliant! + jQuery('#file_image').attr({size: '16'}); + + var post = location.href.split(/#/); + if (post[1]) { + if (post[1].match(/^q\d+(_\d+)?$/)) { + post[1] = post[1].replace('q', '').replace('_', ','); + jQuery("#reply_chennodiscursus").append(">>" + post[1] + "\n"); + post[1] = post[1].replace(',', '_'); + + } + + toggleHighlight(post[1]); + jQuery('#'+post[1].replace('q', ''))[0].scrollIntoView( true ); + } + + if (typeof backend_vars.thread_id !== "undefined" && (Math.round(new Date().getTime() / 1000) - backend_vars.latest_timestamp < 6 * 60 * 60)) + { + enableRealtimeThread(); + } + + bindFunctions(); + hideThreads(); + hidePosts(); + + // localize and add 4chan tooltip where title + jQuery("article time").localize('ddd dd mmm yyyy HH:MM:ss').filter('[title]').tooltip({ + placement: 'top', + delay: 300, + animation: false + }); + + jQuery('input[title]').tooltip({ + placement: 'right', + delay: 200, + animation: false + }); + + jQuery('li.latest_search').tooltip({ + placement: 'left', + animation: false + }); + + jQuery('#thread_o_matic .thread_image_box').tooltip({ + placement: 'bottom', + animation: true + }); + + if (typeof backend_vars.search_args !== "undefined" && getCookie("searchhilight_enabled") == "true") { + highlightSearchResults(); + } +}); + +$.fn.extend({ + insertAtCaret: function(text){ + var obj; + + if (typeof this[0].name !== 'undefined') + { + obj = this[0]; + } + else + { + obj = this; + } + + var insPos = obj.selectionStart, endPos = obj.selectionEnd; + + obj.value = obj.value.substring(0, insPos) + text + obj.value.substring(endPos, obj.value.length); + obj.selectionStart = insPos + text.length; + obj.selectionEnd = insPos + text.length; + } +}); diff --git a/chrome/b4k/bootstrap.min.js b/chrome/b4k/bootstrap.min.js new file mode 100644 index 0000000..6eeb15c --- /dev/null +++ b/chrome/b4k/bootstrap.min.js @@ -0,0 +1,6 @@ +/*! +* Bootstrap.js by @fat & @mdo +* Copyright 2012 Twitter, Inc. +* http://www.apache.org/licenses/LICENSE-2.0.txt +*/ +!function($){"use strict";$(function(){$.support.transition=function(){var transitionEnd=function(){var name,el=document.createElement("bootstrap"),transEndEventNames={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(name in transEndEventNames)if(void 0!==el.style[name])return transEndEventNames[name]}();return transitionEnd&&{end:transitionEnd}}()})}(window.jQuery),!function($){"use strict";var dismiss='[data-dismiss="alert"]',Alert=function(el){$(el).on("click",dismiss,this.close)};Alert.prototype.close=function(e){function removeElement(){$parent.trigger("closed").remove()}var $parent,$this=$(this),selector=$this.attr("data-target");selector||(selector=$this.attr("href"),selector=selector&&selector.replace(/.*(?=#[^\s]*$)/,"")),$parent=$(selector),e&&e.preventDefault(),$parent.length||($parent=$this.hasClass("alert")?$this:$this.parent()),$parent.trigger(e=$.Event("close")),e.isDefaultPrevented()||($parent.removeClass("in"),$.support.transition&&$parent.hasClass("fade")?$parent.on($.support.transition.end,removeElement):removeElement())};var old=$.fn.alert;$.fn.alert=function(option){return this.each(function(){var $this=$(this),data=$this.data("alert");data||$this.data("alert",data=new Alert(this)),"string"==typeof option&&data[option].call($this)})},$.fn.alert.Constructor=Alert,$.fn.alert.noConflict=function(){return $.fn.alert=old,this},$(document).on("click.alert.data-api",dismiss,Alert.prototype.close)}(window.jQuery),!function($){"use strict";var Button=function(element,options){this.$element=$(element),this.options=$.extend({},$.fn.button.defaults,options)};Button.prototype.setState=function(state){var d="disabled",$el=this.$element,data=$el.data(),val=$el.is("input")?"val":"html";state+="Text",data.resetText||$el.data("resetText",$el[val]()),$el[val](data[state]||this.options[state]),setTimeout(function(){"loadingText"==state?$el.addClass(d).attr(d,d):$el.removeClass(d).removeAttr(d)},0)},Button.prototype.toggle=function(){var $parent=this.$element.closest('[data-toggle="buttons-radio"]');$parent&&$parent.find(".active").removeClass("active"),this.$element.toggleClass("active")};var old=$.fn.button;$.fn.button=function(option){return this.each(function(){var $this=$(this),data=$this.data("button"),options="object"==typeof option&&option;data||$this.data("button",data=new Button(this,options)),"toggle"==option?data.toggle():option&&data.setState(option)})},$.fn.button.defaults={loadingText:"loading..."},$.fn.button.Constructor=Button,$.fn.button.noConflict=function(){return $.fn.button=old,this},$(document).on("click.button.data-api","[data-toggle^=button]",function(e){var $btn=$(e.target);$btn.hasClass("btn")||($btn=$btn.closest(".btn")),$btn.button("toggle")})}(window.jQuery),!function($){"use strict";var Carousel=function(element,options){this.$element=$(element),this.options=options,"hover"==this.options.pause&&this.$element.on("mouseenter",$.proxy(this.pause,this)).on("mouseleave",$.proxy(this.cycle,this))};Carousel.prototype={cycle:function(e){return e||(this.paused=!1),this.options.interval&&!this.paused&&(this.interval=setInterval($.proxy(this.next,this),this.options.interval)),this},to:function(pos){var $active=this.$element.find(".item.active"),children=$active.parent().children(),activePos=children.index($active),that=this;if(!(pos>children.length-1||0>pos))return this.sliding?this.$element.one("slid",function(){that.to(pos)}):activePos==pos?this.pause().cycle():this.slide(pos>activePos?"next":"prev",$(children[pos]))},pause:function(e){return e||(this.paused=!0),this.$element.find(".next, .prev").length&&$.support.transition.end&&(this.$element.trigger($.support.transition.end),this.cycle()),clearInterval(this.interval),this.interval=null,this},next:function(){return this.sliding?void 0:this.slide("next")},prev:function(){return this.sliding?void 0:this.slide("prev")},slide:function(type,next){var e,$active=this.$element.find(".item.active"),$next=next||$active[type](),isCycling=this.interval,direction="next"==type?"left":"right",fallback="next"==type?"first":"last",that=this;if(this.sliding=!0,isCycling&&this.pause(),$next=$next.length?$next:this.$element.find(".item")[fallback](),e=$.Event("slide",{relatedTarget:$next[0]}),!$next.hasClass("active")){if($.support.transition&&this.$element.hasClass("slide")){if(this.$element.trigger(e),e.isDefaultPrevented())return;$next.addClass(type),$next[0].offsetWidth,$active.addClass(direction),$next.addClass(direction),this.$element.one($.support.transition.end,function(){$next.removeClass([type,direction].join(" ")).addClass("active"),$active.removeClass(["active",direction].join(" ")),that.sliding=!1,setTimeout(function(){that.$element.trigger("slid")},0)})}else{if(this.$element.trigger(e),e.isDefaultPrevented())return;$active.removeClass("active"),$next.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return isCycling&&this.cycle(),this}}};var old=$.fn.carousel;$.fn.carousel=function(option){return this.each(function(){var $this=$(this),data=$this.data("carousel"),options=$.extend({},$.fn.carousel.defaults,"object"==typeof option&&option),action="string"==typeof option?option:options.slide;data||$this.data("carousel",data=new Carousel(this,options)),"number"==typeof option?data.to(option):action?data[action]():options.interval&&data.cycle()})},$.fn.carousel.defaults={interval:5e3,pause:"hover"},$.fn.carousel.Constructor=Carousel,$.fn.carousel.noConflict=function(){return $.fn.carousel=old,this},$(document).on("click.carousel.data-api","[data-slide]",function(e){var href,$this=$(this),$target=$($this.attr("data-target")||(href=$this.attr("href"))&&href.replace(/.*(?=#[^\s]+$)/,"")),options=$.extend({},$target.data(),$this.data());$target.carousel(options),e.preventDefault()})}(window.jQuery),!function($){"use strict";var Collapse=function(element,options){this.$element=$(element),this.options=$.extend({},$.fn.collapse.defaults,options),this.options.parent&&(this.$parent=$(this.options.parent)),this.options.toggle&&this.toggle()};Collapse.prototype={constructor:Collapse,dimension:function(){var hasWidth=this.$element.hasClass("width");return hasWidth?"width":"height"},show:function(){var dimension,scroll,actives,hasData;if(!this.transitioning){if(dimension=this.dimension(),scroll=$.camelCase(["scroll",dimension].join("-")),actives=this.$parent&&this.$parent.find("> .accordion-group > .in"),actives&&actives.length){if(hasData=actives.data("collapse"),hasData&&hasData.transitioning)return;actives.collapse("hide"),hasData||actives.data("collapse",null)}this.$element[dimension](0),this.transition("addClass",$.Event("show"),"shown"),$.support.transition&&this.$element[dimension](this.$element[0][scroll])}},hide:function(){var dimension;this.transitioning||(dimension=this.dimension(),this.reset(this.$element[dimension]()),this.transition("removeClass",$.Event("hide"),"hidden"),this.$element[dimension](0))},reset:function(size){var dimension=this.dimension();return this.$element.removeClass("collapse")[dimension](size||"auto")[0].offsetWidth,this.$element[null!==size?"addClass":"removeClass"]("collapse"),this},transition:function(method,startEvent,completeEvent){var that=this,complete=function(){"show"==startEvent.type&&that.reset(),that.transitioning=0,that.$element.trigger(completeEvent)};this.$element.trigger(startEvent),startEvent.isDefaultPrevented()||(this.transitioning=1,this.$element[method]("in"),$.support.transition&&this.$element.hasClass("collapse")?this.$element.one($.support.transition.end,complete):complete())},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var old=$.fn.collapse;$.fn.collapse=function(option){return this.each(function(){var $this=$(this),data=$this.data("collapse"),options="object"==typeof option&&option;data||$this.data("collapse",data=new Collapse(this,options)),"string"==typeof option&&data[option]()})},$.fn.collapse.defaults={toggle:!0},$.fn.collapse.Constructor=Collapse,$.fn.collapse.noConflict=function(){return $.fn.collapse=old,this},$(document).on("click.collapse.data-api","[data-toggle=collapse]",function(e){var href,$this=$(this),target=$this.attr("data-target")||e.preventDefault()||(href=$this.attr("href"))&&href.replace(/.*(?=#[^\s]+$)/,""),option=$(target).data("collapse")?"toggle":$this.data();$this[$(target).hasClass("in")?"addClass":"removeClass"]("collapsed"),$(target).collapse(option)})}(window.jQuery),!function($){"use strict";function clearMenus(){$(toggle).each(function(){getParent($(this)).removeClass("open")})}function getParent($this){var $parent,selector=$this.attr("data-target");return selector||(selector=$this.attr("href"),selector=selector&&/#/.test(selector)&&selector.replace(/.*(?=#[^\s]*$)/,"")),$parent=$(selector),$parent.length||($parent=$this.parent()),$parent}var toggle="[data-toggle=dropdown]",Dropdown=function(element){var $el=$(element).on("click.dropdown.data-api",this.toggle);$("html").on("click.dropdown.data-api",function(){$el.parent().removeClass("open")})};Dropdown.prototype={constructor:Dropdown,toggle:function(){var $parent,isActive,$this=$(this);if(!$this.is(".disabled, :disabled"))return $parent=getParent($this),isActive=$parent.hasClass("open"),clearMenus(),isActive||$parent.toggleClass("open"),$this.focus(),!1},keydown:function(e){var $this,$items,$parent,isActive,index;if(/(38|40|27)/.test(e.keyCode)&&($this=$(this),e.preventDefault(),e.stopPropagation(),!$this.is(".disabled, :disabled"))){if($parent=getParent($this),isActive=$parent.hasClass("open"),!isActive||isActive&&27==e.keyCode)return $this.click();$items=$("[role=menu] li:not(.divider):visible a",$parent),$items.length&&(index=$items.index($items.filter(":focus")),38==e.keyCode&&index>0&&index--,40==e.keyCode&&$items.length-1>index&&index++,~index||(index=0),$items.eq(index).focus())}}};var old=$.fn.dropdown;$.fn.dropdown=function(option){return this.each(function(){var $this=$(this),data=$this.data("dropdown");data||$this.data("dropdown",data=new Dropdown(this)),"string"==typeof option&&data[option].call($this)})},$.fn.dropdown.Constructor=Dropdown,$.fn.dropdown.noConflict=function(){return $.fn.dropdown=old,this},$(document).on("click.dropdown.data-api touchstart.dropdown.data-api",clearMenus).on("click.dropdown touchstart.dropdown.data-api",".dropdown form",function(e){e.stopPropagation()}).on("touchstart.dropdown.data-api",".dropdown-menu",function(e){e.stopPropagation()}).on("click.dropdown.data-api touchstart.dropdown.data-api",toggle,Dropdown.prototype.toggle).on("keydown.dropdown.data-api touchstart.dropdown.data-api",toggle+", [role=menu]",Dropdown.prototype.keydown)}(window.jQuery),!function($){"use strict";var Modal=function(element,options){this.options=options,this.$element=$(element).delegate('[data-dismiss="modal"]',"click.dismiss.modal",$.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};Modal.prototype={constructor:Modal,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var that=this,e=$.Event("show");this.$element.trigger(e),this.isShown||e.isDefaultPrevented()||(this.isShown=!0,this.escape(),this.backdrop(function(){var transition=$.support.transition&&that.$element.hasClass("fade");that.$element.parent().length||that.$element.appendTo(document.body),that.$element.show(),transition&&that.$element[0].offsetWidth,that.$element.addClass("in").attr("aria-hidden",!1),that.enforceFocus(),transition?that.$element.one($.support.transition.end,function(){that.$element.focus().trigger("shown")}):that.$element.focus().trigger("shown")}))},hide:function(e){e&&e.preventDefault(),e=$.Event("hide"),this.$element.trigger(e),this.isShown&&!e.isDefaultPrevented()&&(this.isShown=!1,this.escape(),$(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),$.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal())},enforceFocus:function(){var that=this;$(document).on("focusin.modal",function(e){that.$element[0]===e.target||that.$element.has(e.target).length||that.$element.focus()})},escape:function(){var that=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(e){27==e.which&&that.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var that=this,timeout=setTimeout(function(){that.$element.off($.support.transition.end),that.hideModal()},500);this.$element.one($.support.transition.end,function(){clearTimeout(timeout),that.hideModal()})},hideModal:function(){this.$element.hide().trigger("hidden"),this.backdrop()},removeBackdrop:function(){this.$backdrop.remove(),this.$backdrop=null},backdrop:function(callback){var animate=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var doAnimate=$.support.transition&&animate;this.$backdrop=$('