Conflicts: CHANGELOG.md Gruntfile.coffee LICENSE README.md builds/appchan-x.user.js builds/crx/manifest.json builds/crx/script.js latest.js package.json src/General/Config.coffee src/General/css/style.css src/Posting/QR.captcha.coffee src/Posting/QR.coffee
18016 lines
816 KiB
JavaScript
18016 lines
816 KiB
JavaScript
// Generated by CoffeeScript
|
|
// ==UserScript==
|
|
// @name appchan x
|
|
// @version 2.9.10
|
|
// @minGMVer 1.14
|
|
// @minFFVer 26
|
|
// @namespace zixaphir
|
|
// @description The most comprehensive 4chan userscript.
|
|
// @license MIT; https://github.com/zixaphir/appchan-x/blob/master/LICENSE
|
|
// @match *://*.4chan.org/*
|
|
// @match *://boards.4chan.org/*
|
|
// @match *://sys.4chan.org/*
|
|
// @match *://a.4cdn.org/*
|
|
// @match *://i.4cdn.org/*
|
|
// @grant GM_getValue
|
|
// @grant GM_setValue
|
|
// @grant GM_deleteValue
|
|
// @grant GM_listValues
|
|
// @grant GM_openInTab
|
|
// @grant GM_xmlhttpRequest
|
|
// @run-at document-start
|
|
// @updateURL https://github.com/zixaphir/appchan-x/raw/stable/builds/appchan-x.meta.js
|
|
// @downloadURL https://github.com/zixaphir/appchan-x/raw/stable/builds/appchan-x.user.js
|
|
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAElBMVEX///8EZgR8ulSk0oT///8EAgQ1A88mAAAAAXRSTlMAQObYZgAAAIpJREFUeF6t0sENwjAMhWF84N4H6gAYMUBkdQMYwfuvwmstEeD4kl892P0OaaWcpga2/K0SGII1HNBXARgu7veoY3ANd+esgMHZIz85u0EABrbms3pl/bkC1Tn5ihGOfQwqHeZ/FdYdirEMgCG2ZAQWDTL0m9FvjAhcvoGNAK2gZhGYYX9+ZgFm9gaiNmNkMENY4QAAAABJRU5ErkJggg==
|
|
// ==/UserScript==
|
|
|
|
/*
|
|
* appchan x - Version 2.9.10 - 2014-04-03
|
|
*
|
|
* Licensed under the MIT license.
|
|
* https://github.com/zixaphir/appchan-x/blob/master/LICENSE
|
|
*
|
|
* Appchan X Copyright © 2013-2013 Zixaphir <zixaphirmoxphar@gmail.com>
|
|
* http://zixaphir.github.io/appchan-x/
|
|
* 4chan x Copyright © 2009-2011 James Campos <james.r.campos@gmail.com>
|
|
* https://github.com/aeosynth/4chan-x
|
|
* 4chan x Copyright © 2012-2014 Nicolas Stepien <stepien.nicolas@gmail.com>
|
|
* https://4chan-x.just-believe.in/
|
|
* 4chan x Copyright © 2013-2014 Jordan Bates <saudrapsmann@gmail.com>
|
|
* http://seaweedchan.github.io/4chan-x/
|
|
* 4chan x Copyright © 2012-2014 ihavenoface
|
|
* http://ihavenoface.github.io/4chan-x/
|
|
* 4chan SS Copyright © 2011-2013 Ahodesuka
|
|
* https://github.com/ahodesuka/4chan-Style-Script/
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person
|
|
* obtaining a copy of this software and associated documentation
|
|
* files (the "Software"), to deal in the Software without
|
|
* restriction, including without limitation the rights to use,
|
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following
|
|
* conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
* OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* Contributors:
|
|
* aeosynth
|
|
* mayhemydg
|
|
* noface
|
|
* !K.WeEabo0o
|
|
* blaise
|
|
* that4chanwolf
|
|
* desuwa
|
|
* seaweed
|
|
* e000
|
|
* ahodesuka
|
|
* Shou
|
|
* ferongr
|
|
* xat
|
|
* Ongpot
|
|
* thisisanon
|
|
* Anonymous
|
|
* Seiba
|
|
* herpaderpderp
|
|
* WakiMiko
|
|
* btmcsweeney
|
|
* AppleBloom
|
|
* detharonil
|
|
*
|
|
* All the people who've taken the time to write bug reports.
|
|
*
|
|
* Thank you.
|
|
*/
|
|
|
|
/*
|
|
* Contains data from external sources:
|
|
*
|
|
* audio/beep.wav from http://freesound.org/people/pierrecartoons1979/sounds/90112/
|
|
* cc-by-nc-3.0
|
|
*
|
|
* 4chan/4chan-JS (https://github.com/4chan/4chan-JS)
|
|
* Copyright (c) 2012-2013, 4chan LLC
|
|
* All rights reserved.
|
|
*
|
|
* license: https://github.com/4chan/4chan-JS/blob/master/LICENSE
|
|
*
|
|
* jsColor: (http://jscolor.com/)
|
|
* Copyright (c) Jan Odvarko, http://odvarko.cz
|
|
*
|
|
* license: http://www.gnu.org/copyleft/lesser.html
|
|
*
|
|
*/
|
|
'use strict';
|
|
|
|
(function() {
|
|
var $, $$, Anonymize, ArchiveLink, AutoGIF, Banner, Board, Build, Callbacks, CatalogLinks, CatalogThread, Clone, Color, Conf, Config, CustomCSS, DataBoard, DeleteLink, Dice, DownloadLink, Emoji, ExpandComment, ExpandThread, FappeTyme, Favicon, FileInfo, Filter, Flash, Fourchan, Gallery, Get, GlobalMessage, Header, IDColor, ImageExpand, ImageHover, ImageLoader, Index, InfiniScroll, JSColor, Keybinds, Labels, Linkify, Main, MascotTools, Mascots, Menu, Nav, Navigate, Notice, PSAHiding, Polyfill, Post, PostHiding, QR, QuoteBacklink, QuoteInline, QuoteMarkers, QuotePreview, QuoteStrikeThrough, QuoteThreading, Quotify, RandomAccessList, Recursive, Redirect, RelativeDates, RemoveSpoilers, Report, ReportLink, RevealSpoilers, Rice, Sauce, Settings, SimpleDict, Style, ThemeTools, Themes, Thread, ThreadExcerpt, ThreadStats, ThreadUpdater, ThreadWatcher, Time, UI, Unread, c, d, doc, editMascot, editTheme, g, userNavigation,
|
|
__slice = [].slice,
|
|
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
|
|
__hasProp = {}.hasOwnProperty,
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
|
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
|
|
|
Array.prototype.indexOf = function(val, i) {
|
|
var len;
|
|
i || (i = 0);
|
|
len = this.length;
|
|
while (i < len) {
|
|
if (this[i] === val) {
|
|
return i;
|
|
}
|
|
i++;
|
|
}
|
|
return -1;
|
|
};
|
|
|
|
__indexOf = [].indexOf;
|
|
|
|
Config = {
|
|
main: {
|
|
'Miscellaneous': {
|
|
'JSON Navigation': [true, 'Use JSON for loading the Board Index and Threads. Also allows searching and sorting the board index and infinite scolling.'],
|
|
'Catalog Links': [true, 'Add toggle link in header menu to turn Navigation links into links to each board\'s catalog.'],
|
|
'External Catalog': [false, 'Link to external catalog instead of the internal one.'],
|
|
'Desktop Notifications': [false, 'Enables desktop notifications across various appchan x features.'],
|
|
'404 Redirect': [true, 'Redirect dead threads and images.'],
|
|
'Keybinds': [true, 'Bind actions to keyboard shortcuts.'],
|
|
'Time Formatting': [true, 'Localize and format timestamps.'],
|
|
'Relative Post Dates': [true, 'Display dates like "3 minutes ago". Tooltip shows the timestamp.'],
|
|
'File Info Formatting': [true, 'Reformat the file information.'],
|
|
'Thread Expansion': [true, 'Add buttons to expand threads.'],
|
|
'Comment Expansion': [false, 'Expand Comments that are too long to display on the index. Does not work with JSON Navigation.'],
|
|
'Index Navigation': [false, 'Add buttons to navigate between threads.'],
|
|
'Reply Navigation': [false, 'Add buttons to navigate to top / bottom of thread.'],
|
|
'Show Dice Roll': [true, 'Show dice that were entered into the email field.'],
|
|
'Color User IDs': [false, 'Assign unique colors to user IDs on boards that use them'],
|
|
'Remove Spoilers': [false, 'Remove all spoilers in text.'],
|
|
'Reveal Spoilers': [false, 'Indicate spoilers if Remove Spoilers is enabled, or make the text appear hovered if Remove Spoiler is disabled.']
|
|
},
|
|
'Linkification': {
|
|
'Linkify': [true, 'Convert text into links where applicable.'],
|
|
'Embedding': [true, 'Embed supported services.'],
|
|
'Auto-embed': [false, 'Auto-embed Linkify Embeds.'],
|
|
'Link Title': [true, 'Replace the link of a supported site with its actual title. Currently Supported: YouTube, Vimeo, SoundCloud, and Github gists']
|
|
},
|
|
'Filtering': {
|
|
'Anonymize': [false, 'Make everyone Anonymous.'],
|
|
'Filter': [true, 'Self-moderation placebo.'],
|
|
'Recursive Hiding': [true, 'Hide replies of hidden posts, recursively.'],
|
|
'Post Hiding': [false, 'Add buttons to hide posts.'],
|
|
'Filtered Backlinks': [true, 'When enabled, shows backlinks to filtered posts with a line-through decoration. Otherwise, hides the backlinks.'],
|
|
'Stubs': [true, 'Show stubs of hidden threads / replies.']
|
|
},
|
|
'Images': {
|
|
'Image Expansion': [true, 'Expand images.'],
|
|
'Image Hover': [true, 'Show full image on mouseover.'],
|
|
'Image Hover in Catalog': [false, 'Show a floating expanded image on hover in the catalog.'],
|
|
'Gallery': [true, 'Adds a simple and cute image gallery.'],
|
|
'Sauce': [true, 'Add sauce links to images.'],
|
|
'Reveal Spoiler Thumbnails': [false, 'Replace spoiler thumbnails with the original image.'],
|
|
'Replace GIF': [false, 'Replace thumbnail of gifs with its actual image.'],
|
|
'Replace PNG': [false, 'Replace pngs.'],
|
|
'Replace JPG': [false, 'Replace jpgs.'],
|
|
'Image Prefetching': [false, 'Preload images'],
|
|
'Fappe Tyme': [false, 'Hide posts without images when toggled. *hint* *hint*'],
|
|
'Werk Tyme': [false, 'Hide all post images when toggled.']
|
|
},
|
|
'Menu': {
|
|
'Menu': [true, 'Add a drop-down menu to posts.'],
|
|
'Report Link': [true, 'Add a report link to the menu.'],
|
|
'Post Hiding Link': [true, 'Add a link to hide posts.'],
|
|
'Delete Link': [true, 'Add post and image deletion links to the menu.'],
|
|
'Archive Link': [true, 'Add an archive link to the menu.']
|
|
},
|
|
'Monitoring': {
|
|
'Thread Updater': [true, 'Fetch and insert new replies. Has more options in its own dialog.'],
|
|
'Unread Count': [true, 'Show the unread posts count in the tab title.'],
|
|
'Hide Unread Count at (0)': [false, 'Hide the unread posts count in the tab title when it reaches 0.'],
|
|
'Unread Favicon': [true, 'Show a different favicon when there are unread posts.'],
|
|
'Unread Line': [true, 'Show a line to distinguish read posts from unread ones.'],
|
|
'Scroll to Last Read Post': [true, 'Scroll back to the last read post when reopening a thread.'],
|
|
'Thread Excerpt': [true, 'Show an excerpt of the thread in the tab title.'],
|
|
'Thread Stats': [true, 'Display reply and image count.'],
|
|
'Page Count in Stats': [false, 'Display the page count in the thread stats as well.'],
|
|
'Updater and Stats in Header': [true, 'Places the thread updater and thread stats in the header instead of floating them.'],
|
|
'Thread Watcher': [true, 'Bookmark threads.']
|
|
},
|
|
'Posting': {
|
|
'Header Shortcut': [true, 'Add a shortcut to the header to toggle the QR.'],
|
|
'Page Shortcut': [false, 'Add a shortcut to the top of the page to toggle the QR.'],
|
|
'Persistent QR': [true, 'The Quick reply won\'t disappear after posting.'],
|
|
'Auto Hide QR': [true, 'Automatically hide the quick reply when posting.'],
|
|
'Open Post in New Tab': [true, 'Open new threads or replies to a thread from the index in a new tab.'],
|
|
'Remember Subject': [false, 'Remember the subject field, instead of resetting after posting.'],
|
|
'Remember Spoiler': [false, 'Remember the spoiler state, instead of resetting after posting.'],
|
|
'Remember QR Size': [false, 'Remember the size of the quick reply\'s comment field.'],
|
|
'Cooldown': [true, 'Indicate the remaining time before posting again.'],
|
|
'Posting Success Notifications': [true, 'Show notifications on successful post creation or file uploading.'],
|
|
'Captcha Warning Notifications': [true, 'When disabled, shows a red border on the CAPTCHA input until a key is pressed instead of a notification.'],
|
|
'Dump List Before Comment': [false, 'Position of the QR\'s Dump List.'],
|
|
'Auto-load captcha': [false, 'Automatically load the captcha when you open a thread']
|
|
},
|
|
'Quote Links': {
|
|
'Quote Backlinks': [true, 'Add quote backlinks.'],
|
|
'OP Backlinks': [true, 'Add backlinks to the OP.'],
|
|
'Quote Inlining': [true, 'Inline quoted post on click.'],
|
|
'Quote Hash Navigation': [false, 'Include an extra link after quotes for autoscrolling to quoted posts.'],
|
|
'Forward Hiding': [true, 'Hide original posts of inlined backlinks.'],
|
|
'Quote Previewing': [true, 'Show quoted post on hover.'],
|
|
'Quote Highlighting': [true, 'Highlight the previewed post.'],
|
|
'Resurrect Quotes': [true, 'Link dead quotes to the archives.'],
|
|
'Quoted Title': [false, 'Change the page title to reflect you\'ve been quoted.'],
|
|
'Highlight Posts Quoting You': [false, 'Highlights any posts that contain a quote to your post.'],
|
|
'Highlight Own Posts': [false, 'Highlights own posts if Quote Markers are enabled.'],
|
|
'Quote Threading': [false, 'Thread conversations'],
|
|
'Mark Quotes of You': [true, 'Add \'(You)\' to quotes linking to your posts.'],
|
|
'Mark OP Quotes': [true, 'Add \'(OP)\' to OP quotes.'],
|
|
'Mark Cross-thread Quotes': [true, 'Add \'(Cross-thread)\' to cross-threads quotes.', 'Highlights own posts if Quote Markers are enabled.']
|
|
}
|
|
},
|
|
imageExpansion: {
|
|
'Fit width': [false, ''],
|
|
'Fit height': [false, ''],
|
|
'Expand spoilers': [true, 'Expand all images along with spoilers.'],
|
|
'Expand from here': [false, 'Expand all images only from current position to thread end.'],
|
|
'Advance on contract': [false, 'Advance to next post when contracting an expanded image.']
|
|
},
|
|
gallery: {
|
|
'Hide Thumbnails': [false],
|
|
'Fit Width': [true],
|
|
'Fit Height': [true]
|
|
},
|
|
style: {
|
|
Interface: {
|
|
'Single Column Mode': [true, 'Presents options in a single column, rather than in blocks.'],
|
|
'Sidebar': ['normal', 'Alter the sidebar size. Completely hiding it can cause content to overlap, but with the correct option combinations can create a minimal 4chan layout that has more efficient screen real-estate than vanilla 4chan.', ['large', 'normal', 'minimal', 'hide']],
|
|
'Sidebar Location': ['right', 'The side of the page the sidebar content is on. It is highly recommended that you do not hide the sidebar if you change this option.', ['left', 'right']],
|
|
'Top Thread Padding': ['0', 'Add some spacing between the top edge of document and the threads.', 'text'],
|
|
'Bottom Thread Padding': ['0', 'Add some spacing between the bottom edge of document and the threads.', 'text'],
|
|
'Left Thread Padding': ['0', 'Add some spacing between the left edge of document and the threads.', 'text'],
|
|
'Right Thread Padding': ['0', 'Add some spacing between the right edge of document and the threads.', 'text'],
|
|
'Announcements': ['slideout', 'The style of announcements and the ability to hide them.', ['4chan default', 'slideout', 'hide']],
|
|
'Board Title': ['at sidebar top', 'The positioning of the board\'s logo and subtitle.', ['at sidebar top', 'at sidebar bottom', 'at top', 'under post form', 'hide']],
|
|
'Custom Board Titles': [false, 'Customize Board Titles by shift-clicking the board title or subtitle.'],
|
|
'Persistent Custom Board Titles': [false, 'Forces custom board titles to be persistent, even if moot updates the board titles.'],
|
|
'Board Subtitle': [true, 'Show the board subtitle.'],
|
|
'4chan Banner': ['at sidebar top', 'The positioning of 4chan\'s image banner.', ['at sidebar top', 'at sidebar bottom', 'under post form', 'at top', 'hide']],
|
|
'Icon Orientation': ['horizontal', 'Change the orientation of the appchan x icons.', ['horizontal', 'vertical']],
|
|
'Slideout Watcher': [true, 'Adds an icon you can hover over to show the watcher, as opposed to having the watcher always visible.'],
|
|
'Hide Navlinks': [false, 'Hides the UI at the top of the page that allows you to navigate between pages, like "Return", "Catalog", "Bottom".']
|
|
},
|
|
Posts: {
|
|
'Alternate Post Colors': [false, 'Make post background colors alternate every other post.'],
|
|
'Color Reply Headings': [false, 'Give the post info a background.'],
|
|
'Color File Info': [false, 'Give the file info a background.'],
|
|
'OP Background': [false, 'Adds a border and background color to the OP Post, as if it were a reply.'],
|
|
'Backlinks Position': ['default', 'The position of backlinks in relation to the post.', ['default', 'lower left', 'lower right']],
|
|
'Filtered Backlinks': [true, 'Hide backlinks to filtered posts.'],
|
|
'Force Reply Break': [false, 'Force replies to occupy their own line and not be adjacent to the OP image.'],
|
|
'Fit Width Replies': [true, 'Replies fit the entire width of the page.'],
|
|
'Indent Replies': [false, 'Indent posts under the OP.'],
|
|
'Hide Delete UI': [false, 'Hides vanilla report and delete functionality and UI. This does not affect Appchan\'s Menu functionality.'],
|
|
'Post Spacing': ['2', 'The amount of space between replies.', 'text'],
|
|
'Vertical Post Padding': ['5', 'The vertical padding around post content of replies.', 'text'],
|
|
'Horizontal Post Padding': ['20', 'The horizontal padding around post content of replies.', 'text'],
|
|
'Hide Horizontal Rules': [false, 'Hides lines between threads.'],
|
|
'Backlink Icons': [false, 'Replaces backlink text with a small, compact icon.'],
|
|
'Compact File Text': [false, 'Shrink the font of the file text to be less obtrusive.']
|
|
},
|
|
Aesthetics: {
|
|
'4chan SS Navigation': [false, 'Try to emulate the appearance of 4chan SS\'s Navigation.'],
|
|
'4chan SS Sidebar': [false, 'Try to emulate the appearance of 4chan SS\'s Sidebar.'],
|
|
'4chan Banner Reflection': [false, 'Adds reflection effects to 4chan\'s image banner.'],
|
|
'Faded 4chan Banner': [true, 'Make 4chan\'s image banner translucent.'],
|
|
'Hide Ads': [false, 'Block advertisements. It\'s probably better to use AdBlock for this.'],
|
|
'Shrink Ads': [false, 'Make 4chan advertisements smaller.'],
|
|
'Fade Ads': [true, 'Make 4chan\'s ads translucent.'],
|
|
'Bolds': [true, 'Bold text for names and such.'],
|
|
'Italics': [false, 'Give tripcodes italics.'],
|
|
'Sidebar Glow': [false, 'Adds a glow to the sidebar\'s text.'],
|
|
'Circle Checkboxes': [false, 'Make checkboxes circular.'],
|
|
'Font': ['sans-serif', 'The font used by all elements of 4chan.', 'text'],
|
|
'Font Size': ['13', 'The font size of posts and various UI. This changes most, but not all, font sizes.', 'text'],
|
|
'Icons': ['oneechan', 'Icon theme which Appchan will use.', ['oneechan', '4chan SS']],
|
|
'Invisible Icons': [false, 'Makes icons invisible unless hovered. Invisible really is "invisible", so don\'t use it if you don\'t have your icons memorized or don\'t use keybinds.'],
|
|
'Quote Shadows': [true, 'Add shadows to the quote previews and inline quotes.'],
|
|
'Rounded Edges': [false, 'Round the edges of various 4chan elements.'],
|
|
'Underline Links': [false, 'Put lines under hyperlinks.'],
|
|
'NSFW/SFW Themes': [false, 'Choose your theme based on the SFW status of the board you are viewing.']
|
|
},
|
|
Mascots: {
|
|
'Mascots': [true, 'Add a pretty picture of your waifu to Appchan.'],
|
|
'Click to Toggle': [true, 'Click your current mascot to switch between your enabled mascots.'],
|
|
'Mascot Location': ['sidebar', 'Change where your mascot is located.', ['sidebar', 'opposite']],
|
|
'Mascot Position': ['default', 'Change where your mascot is placed in relation to the post form.', ['above post form', 'default', 'bottom', 'middle']],
|
|
'Mascots Overlap Posts': [true, 'Mascots overlap threads and posts.'],
|
|
'NSFW/SFW Mascots': [false, 'Enable or disable mascots based on the SFW status of the board you are viewing.'],
|
|
'Grayscale Mascots': [false, 'Force mascots to be monochrome.'],
|
|
'Mascot Opacity': ['1.00', 'Make Mascots transparent.', 'text'],
|
|
'Hide Mascots on Catalog': [false, 'Do not show mascots on the official catalog pages.'],
|
|
'Silhouettize Mascots': [false, 'Apply a filter to mascots to try to turn them into silhouettes.'],
|
|
'Silhouette Contrast': ['0', 'A number to increase the contrast of silhouettes. Suggested values: 0, 8, 16 ...', 'text']
|
|
},
|
|
Navigation: {
|
|
'Navigation Alignment': ['left', 'Change the text alignment of the navigation.', ['left', 'center', 'right']],
|
|
'Slideout Navigation': ['compact', 'How the slideout navigation will be displayed.', ['compact', 'list', 'hide']],
|
|
'Pagination': ['sticky bottom', 'The position of 4chan page navigation', ['sticky top', 'sticky bottom', 'top', 'bottom', 'on side', 'hide']],
|
|
'Pagination Alignment': ['center', 'Change the text alignment of the pagination.', ['left', 'center', 'right']],
|
|
'Hide Navigation Decorations': [false, 'Hide non-link text in the board navigation and pagination. This also disables the delimiters in <code>Custom Navigation</code>']
|
|
},
|
|
'Post Form': {
|
|
'Compact Post Form Inputs': [true, 'Use compact inputs on the post form.'],
|
|
'Show Post Form Header': [false, 'Force the Post Form to have a header.'],
|
|
'Post Form Style': ['tabbed slideout', 'How the post form will sit on the page.', ['fixed', 'slideout', 'tabbed slideout', 'float']],
|
|
'Post Form Slideout Transitions': [true, 'Animate slideouts for the post form.'],
|
|
'Transparent Post Form': [false, 'Make the post form almost invisible.'],
|
|
'Post Form Decorations': [false, 'Add a border and background to the post form (does not apply to the "float" post form style.'],
|
|
'Textarea Resize': ['vertical', 'Options to resize the post form\'s comment box.', ['both', 'horizontal', 'vertical', 'none']],
|
|
'Tripcode Hider': [true, 'Intelligent name field hiding.'],
|
|
'Images Overlap Post Form': [true, 'Images expand over the post form and sidebar content, usually used with "Expand images" set to "full".'],
|
|
'Captcha Filter': [true, 'Apply an SVG filter to the captcha to make it match your theme. WARNING: May cause invisible captchas.']
|
|
},
|
|
Indicators: {
|
|
'Emoji': ['enabled', 'Add icons besides usernames with triggered e-mails, like sega and neko.', ['enabled', 'disable ponies', 'only ponies', 'disable']],
|
|
'Emoji Position': ['before', 'Position of emoji icons.', ['before', 'after']],
|
|
'Emoji Spacing': ['5', 'Add some spacing between emoji and text.', 'text']
|
|
}
|
|
},
|
|
threadWatcher: {
|
|
'Current Board': [false, 'Only show watched threads from the current board.'],
|
|
'Auto Watch': [true, 'Automatically watch threads you start.'],
|
|
'Auto Watch Reply': [false, 'Automatically watch threads you reply to.'],
|
|
'Auto Prune': [false, 'Automatically prune 404\'d threads.']
|
|
},
|
|
filter: {
|
|
name: "# Filter any namefags:\n#/^(?!Anonymous$)/",
|
|
uniqueID: "# Filter a specific ID:\n#/Txhvk1Tl/",
|
|
tripcode: "# Filter any tripfag\n#/^!/",
|
|
capcode: "# Set a custom class for mods:\n#/Mod$/;highlight:mod;op:yes\n# Set a custom class for moot:\n#/Admin$/;highlight:moot;op:yes",
|
|
email: "",
|
|
subject: "# Filter Generals on /v/:\n#/general/i;boards:v;op:only",
|
|
comment: "# Filter Stallman copypasta on /g/:\n#/what you\'re refer+ing to as linux/i;boards:g",
|
|
flag: '',
|
|
filename: '',
|
|
dimensions: "# Highlight potential wallpapers:\n#/1920x1080/;op:yes;highlight;top:no;boards:w,wg",
|
|
filesize: '',
|
|
MD5: ''
|
|
},
|
|
sauces: "https://www.google.com/searchbyimage?image_url=%TURL\nhttp://iqdb.org/?url=%TURL\n#//tineye.com/search?url=%TURL\n#http://saucenao.com/search.php?url=%TURL\n#http://3d.iqdb.org/?url=%TURL\n#http://regex.info/exif.cgi?imgurl=%URL\n# uploaders:\n#http://imgur.com/upload?url=%URL;text:Upload to imgur\n#http://ompldr.org/upload?url1=%URL;text:Upload to ompldr\n# \"View Same\" in archives:\n#//archive.foolz.us/_/search/image/%MD5/;text:View same on foolz\n#//archive.foolz.us/%board/search/image/%MD5/;text:View same on foolz /%board/\n#//archive.installgentoo.net/%board/image/%MD5;text:View same on installgentoo /%board/",
|
|
FappeT: {
|
|
fappe: false,
|
|
werk: false
|
|
},
|
|
'Custom CSS': false,
|
|
Index: {
|
|
'Index Mode': 'paged',
|
|
'Previous Index Mode': 'paged',
|
|
'Index Sort': 'bump',
|
|
'Index Size': 'small',
|
|
'Threads per Page': 0,
|
|
'Open threads in a new tab': false,
|
|
'Show Replies': true,
|
|
'Refreshed Navigation': false
|
|
},
|
|
Header: {
|
|
'Fixed Header': true,
|
|
'Header auto-hide': false,
|
|
'Header auto-hide on scroll': false,
|
|
'Bottom Header': false,
|
|
'Header catalog links': false,
|
|
'Bottom Board List': true,
|
|
'Custom Board Navigation': true
|
|
},
|
|
boardnav: "[ toggle-all ]\n[current-title]\n[external-text:\"FAQ\",\"https://github.com/ccd0/4chan-x/wiki/Frequently-Asked-Questions\"]",
|
|
QR: {
|
|
'QR.personas': "#email:\"sage\";boards:jp;always"
|
|
},
|
|
time: '%m/%d/%y(%a)%H:%M:%S',
|
|
backlink: '>>%id',
|
|
fileInfo: '%L (%p%s, %r)',
|
|
favicon: 'ferongr',
|
|
usercss: "/* Tripcode Italics: */\n/*\nspan.postertrip {\nfont-style: italic;\n}\n*/\n\n/* Add a rounded border to thumbnails (but not expanded images): */\n/*\n.fileThumb > img:first-child {\nborder: solid 2px rgba(0,0,100,0.5);\nborder-radius: 10px;\n}\n*/\n\n/* Make highlighted posts look inset on the page: */\n/*\ndiv.post:target,\ndiv.post.highlight {\nbox-shadow: inset 2px 2px 2px rgba(0,0,0,0.2);\n}\n*/",
|
|
hotkeys: {
|
|
'Toggle board list': ['Ctrl+b', 'Toggle the full board list.'],
|
|
'Toggle header': ['Shift+h', 'Toggle the auto-hide option of the header.'],
|
|
'Open empty QR': ['i', 'Open QR without post number inserted.'],
|
|
'Open QR': ['Shift+i', 'Open QR with post number inserted.'],
|
|
'Open settings': ['Alt+o', 'Open Settings.'],
|
|
'Close': ['Esc', 'Close Settings, Notifications or QR.'],
|
|
'Spoiler tags': ['Ctrl+s', 'Insert spoiler tags.'],
|
|
'Code tags': ['Alt+c', 'Insert code tags.'],
|
|
'Eqn tags': ['Alt+e', 'Insert eqn tags.'],
|
|
'Math tags': ['Alt+m', 'Insert math tags.'],
|
|
'Toggle sage': ['Alt+s', 'Toggle sage in email field.'],
|
|
'Submit QR': ['Ctrl+Enter', 'Submit post.'],
|
|
'Post Without Name': ['Alt+n', 'Clear name field and then submits post.'],
|
|
'Watch': ['w', 'Watch thread.'],
|
|
'Update': ['r', 'Update the thread now.'],
|
|
'Expand image': ['Shift+e', 'Expand selected image.'],
|
|
'Expand images': ['e', 'Expand all images.'],
|
|
'Open Gallery': ['g', 'Opens the gallery.'],
|
|
'fappeTyme': ['f', 'Fappe Tyme.'],
|
|
'werkTyme': ['Shift+w', 'Werk Tyme'],
|
|
'Front page': ['0', 'Jump to page 0.'],
|
|
'Open front page': ['Shift+0', 'Open page 0 in a new tab.'],
|
|
'Next page': ['Shift+Right', 'Jump to the next page.'],
|
|
'Previous page': ['Shift+Left', 'Jump to the previous page.'],
|
|
'Search form': ['Ctrl+Alt+s', 'Focus the search field on the board index.'],
|
|
'Paged mode': ['Alt+1', 'Sets the index mode to paged.'],
|
|
'All pages mode': ['Alt+2', 'Sets the index mode to all threads.'],
|
|
'Catalog mode': ['Alt+3', 'Sets the index mode to catalog.'],
|
|
'Cycle sort type': ['Alt+x', 'Cycle through index sort types.'],
|
|
'Next thread': ['Shift+Down', 'See next thread.'],
|
|
'Previous thread': ['Shift+Up', 'See previous thread.'],
|
|
'Expand thread': ['Ctrl+e', 'Expand thread.'],
|
|
'Open thread': ['o', 'Open thread in current tab.'],
|
|
'Open thread tab': ['Shift+o', 'Open thread in new tab.'],
|
|
'Next reply': ['j', 'Select next reply.'],
|
|
'Previous reply': ['k', 'Select previous reply.'],
|
|
'Deselect reply': ['Shift+d', 'Deselect reply.'],
|
|
'Hide': ['x', 'Hide thread.'],
|
|
'Previous Post Quoting You': ['Alt+Up', 'Scroll to the previous post that quotes you.'],
|
|
'Next Post Quoting You': ['Alt+Down', 'Scroll to the next post that quotes you.']
|
|
},
|
|
updater: {
|
|
checkbox: {
|
|
'Beep': [false, 'Beep on new post to completely read thread.'],
|
|
'Auto Scroll': [false, 'Scroll updated posts into view. Only enabled at bottom of page.'],
|
|
'Bottom Scroll': [false, 'Always scroll to the bottom, not the first new post. Useful for event threads.'],
|
|
'Scroll BG': [false, 'Auto-scroll background tabs.'],
|
|
'Auto Update': [true, 'Automatically fetch new posts.'],
|
|
'Optional Increase': [false, 'Increase the intervals between updates on threads without new posts.']
|
|
},
|
|
'Interval': 30
|
|
},
|
|
embedWidth: 640,
|
|
embedHeight: 390,
|
|
theme: 'Yotsuba B',
|
|
'theme_sfw': 'Yotsuba B',
|
|
'theme_nsfw': 'Yotsuba',
|
|
mascot: ''
|
|
};
|
|
|
|
editTheme = {};
|
|
|
|
editMascot = {};
|
|
|
|
userNavigation = {};
|
|
|
|
Conf = {};
|
|
|
|
c = console;
|
|
|
|
d = document;
|
|
|
|
doc = d.documentElement;
|
|
|
|
g = {
|
|
VERSION: '2.9.10',
|
|
NAMESPACE: 'appchan_x.',
|
|
boards: {}
|
|
};
|
|
|
|
Mascots = {
|
|
'Akiyama_Mio': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibrWLbKvjRnHZS.png'
|
|
},
|
|
'Akiyama_Mio_2': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibmZgHvl3ZSxYk.png'
|
|
},
|
|
'Akiyama_Mio_3': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/irFbpefCFt1cT.png',
|
|
center: true
|
|
},
|
|
'Applejack': {
|
|
category: 'Ponies',
|
|
image: '//i.minus.com/inZ8jSVsEhfnC.png',
|
|
center: true
|
|
},
|
|
'Asuka_Langley_Soryu': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ib2z9ME9QKEBaS.png',
|
|
center: true
|
|
},
|
|
'Asuka_Langley_Soryu_2': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iI3QR5SywNfg9.png',
|
|
center: true
|
|
},
|
|
'Asuka_Langley_Soryu_3': {
|
|
category: 'Anime',
|
|
image: '//i4.minus.com/jbq2hFrE4q75KT.png',
|
|
center: true
|
|
},
|
|
'Asuka_Langley_Soryu_4': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibiiInQGLGnYNj.png',
|
|
center: true
|
|
},
|
|
'Asuka_Langley_Soryu_6': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibzbnBcaEtoqck.png',
|
|
position: 'bottom'
|
|
},
|
|
'Ayanami_Rei': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ib0ft5OmqRZx2r.png',
|
|
center: true
|
|
},
|
|
'Ayase': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibmArq5Wb4Po4v.png',
|
|
center: true
|
|
},
|
|
'BLACK_ROCK_SHOOTER': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibMe9MrTMdvAT.png',
|
|
center: true
|
|
},
|
|
'Brioche_d_Arquien': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibobXYJ2k3JXK.png',
|
|
center: true
|
|
},
|
|
'CC': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iwndO4Pn6SO0X.png',
|
|
center: true
|
|
},
|
|
'Chie': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ib0HI16h9FSjSp.png',
|
|
center: true
|
|
},
|
|
'Cirno_2': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iSZ06ZxrcqAKq.png',
|
|
center: true
|
|
},
|
|
'Dawn_Hikari': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iL3J1EmcDkFzE.png',
|
|
center: true
|
|
},
|
|
'Doppleganger': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iPvv86W9r3Rxm.png'
|
|
},
|
|
'Dragonkid': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iq9fuyWSjIDWf.png',
|
|
center: true
|
|
},
|
|
'Dragonkid_2': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/i7sdxK3G12RB6.png',
|
|
center: true
|
|
},
|
|
'Eclair': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibsk5mMYVR5zuA.png',
|
|
center: true
|
|
},
|
|
'Evangeline_AK_McDowell': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibuq7a8zWKi2gl.png',
|
|
center: true
|
|
},
|
|
'Fluttershy': {
|
|
category: 'Ponies',
|
|
image: '//i.minus.com/ibwEFEGlRm0Uxy.png'
|
|
},
|
|
'Fluttershy_2': {
|
|
category: 'Ponies',
|
|
image: '//i.minus.com/ibjtz6EU2OFPgh.png',
|
|
center: true
|
|
},
|
|
'Fluttershy_Cutiemark': {
|
|
category: 'Ponies',
|
|
image: '//i.minus.com/i5WVpIAlHQdhs.png',
|
|
center: true
|
|
},
|
|
'Fujiwara_no_Mokou': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibpwDyMGodvni6.png'
|
|
},
|
|
'Furudo_Erika': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iCrRzQ8WvHiSM.png',
|
|
center: true
|
|
},
|
|
'Gally': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iblWZGuSlWtDI6.png',
|
|
center: true
|
|
},
|
|
'Gasai_Yuno': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iEQsK6K85jX2n.png'
|
|
},
|
|
'George_Costanza': {
|
|
category: 'Western',
|
|
image: '//i.minus.com/iFWdpFGfzLs6v.png'
|
|
},
|
|
'Hanako': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iRLF8gCIZbGjo.png',
|
|
center: true
|
|
},
|
|
'Hasekura_Youko': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iqBTFZf5UhLpR.png',
|
|
center: true
|
|
},
|
|
'Hatsune_Miku_3': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iLJ4uDTcg1T8r.png',
|
|
center: true
|
|
},
|
|
'Hatsune_Miku_4': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibjkPMLT8Uxitp.png',
|
|
center: true
|
|
},
|
|
'Hatsune_Miku_5': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/i9Evu9dyvok4G.png',
|
|
center: true
|
|
},
|
|
'Hirasawa_Yui': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iuGe5uDaTNmhR.png',
|
|
center: true
|
|
},
|
|
'Homura_Akemi': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iPtrwFEEtPLhn.png'
|
|
},
|
|
'Horo': {
|
|
category: 'Silhouette',
|
|
image: '//i.minus.com/ibbMKiznORGJ00.png',
|
|
silhouette: true
|
|
},
|
|
'Horo_2': {
|
|
category: 'Silhouette',
|
|
image: '//i.minus.com/ibyT9dlTe1HN5P.png',
|
|
silhouette: true,
|
|
width: 205
|
|
},
|
|
'Ika_Musume': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibqVu5GNfKx5bC.png',
|
|
center: true
|
|
},
|
|
'Ika_Musume_2': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibhnEiE8HabEqC.png',
|
|
center: true
|
|
},
|
|
'Iwakura_Lain': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iBXRRT19scoHf.png',
|
|
center: true
|
|
},
|
|
'Iwakura_Lain_2': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ioMltWNYUWeJ3.png',
|
|
center: true
|
|
},
|
|
'KOn_Girls': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibndVLiH09uINs.png',
|
|
center: true
|
|
},
|
|
'Kagamine_Rin_2': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/jbkL01TIeJwEN6.png'
|
|
},
|
|
'Kagari_Izuriha': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ihaFHsvFfL0vH.png'
|
|
},
|
|
'Kaname_Madoka': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iRuEFK8cdAHxB.png',
|
|
center: true
|
|
},
|
|
'Karina': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iUADBOpQYPfeP.png',
|
|
center: true
|
|
},
|
|
'Kigurumi_Harokitei': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibb17W5i3rQvut.png',
|
|
center: true
|
|
},
|
|
'Kinomoto_Sakura': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iVmsLKa4zLwZR.png',
|
|
center: true
|
|
},
|
|
'Kirisame_Marisa': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibikDZH5CZ0V30.png'
|
|
},
|
|
'Koiwai_Yotsuba': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iKFKyVVBato2N.png',
|
|
center: true
|
|
},
|
|
'Koko': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ieVyNMSjXpBs2.png',
|
|
center: true
|
|
},
|
|
'Kotobuki_Tsumugi': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/i6doAUnM6jMAY.png',
|
|
center: true
|
|
},
|
|
'Kurisu_Makise': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ib1eMtRHdvc9ix.png'
|
|
},
|
|
'Kuroko_Shirai': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/i3K8F7lu2SHfn.png'
|
|
},
|
|
'Kyouko_Sakura': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iMrFOS1mfzIJP.png',
|
|
center: true
|
|
},
|
|
'Kyubee': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iD0SEJPeZa0Dw.png'
|
|
},
|
|
'Kyubee_2': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iGlKiDZvM3xi8.png',
|
|
center: true
|
|
},
|
|
'Li_Syaoran': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ib0IWPBRSHyiDe.png'
|
|
},
|
|
'Link': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibd1JShAMTdJBH.png',
|
|
center: true
|
|
},
|
|
'Lizardgirl': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/is7h27Q6lsmyx.png'
|
|
},
|
|
'Luka': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/inds5h2BOmVBy.png'
|
|
},
|
|
'Madotsuki': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ik6QYfTfgx9Za.png'
|
|
},
|
|
'Makoto': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/i7q6aOuUqqA9F.png',
|
|
center: true
|
|
},
|
|
'Mantis': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iBmluUJOZivY2.png'
|
|
},
|
|
'Megurine_Luka': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibxe63yidpz9Gz.png',
|
|
center: true
|
|
},
|
|
'Mei_Sunohara': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/i7ElzNY4xQHHz.png',
|
|
center: true
|
|
},
|
|
'Millefiori': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ifVzPtH8JHXjl.png',
|
|
center: true
|
|
},
|
|
'Millefiori_2': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iMSUiQxRBylQG.png',
|
|
center: true
|
|
},
|
|
'Millefiori_3': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iDOe3ltSvOYXZ.png',
|
|
center: true
|
|
},
|
|
'Misaki_Mei': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/icmYGJ9vIOFjr.png',
|
|
center: true
|
|
},
|
|
'Mizunashi_Akari': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iNy9kHlNsUoVK.png',
|
|
center: true
|
|
},
|
|
'Motoko': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/irFtkWWyMChSA.png',
|
|
center: true
|
|
},
|
|
'Nagato_Yuki': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/it3pEawWIxY84.png',
|
|
center: true
|
|
},
|
|
'Nagato_Yuki_2': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iuspcZbLvmqpb.png',
|
|
center: true
|
|
},
|
|
'Nagato_Yuki_3': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibndIkldw4njbD.png',
|
|
center: true
|
|
},
|
|
'Nagato_Yuki_5': {
|
|
category: 'Silhouette',
|
|
width: 202,
|
|
image: '//i.minus.com/iFQQPEaC3aEV7.png',
|
|
silhouette: true,
|
|
center: true
|
|
},
|
|
'Nakano_Azusa': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iiptfoMlr4v1k.png'
|
|
},
|
|
'Nichijou': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iE8lbZ5f3OT2B.png'
|
|
},
|
|
'Noir_VinoCacao': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibo8aCWF0OwNwP.png',
|
|
center: true
|
|
},
|
|
'Pinkie_Pie': {
|
|
category: 'Ponies',
|
|
image: '//i.minus.com/ib1kcpqxvsyZWG.png',
|
|
center: true
|
|
},
|
|
'Pinkie_Pie_2': {
|
|
category: 'Ponies',
|
|
image: '//i.minus.com/i8QRRgE7iKpw7.png',
|
|
center: true
|
|
},
|
|
'Oshino_Shinobu': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibwhAyR6D7OBAB.png'
|
|
},
|
|
'Oshino_Shinobu_2': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibqoNiWzynsVvg.png',
|
|
position: 'bottom'
|
|
},
|
|
'Patchouli_Knowledge': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibnOEAxXaKlctB.png',
|
|
center: true
|
|
},
|
|
'Patchouli_Knowledge_2': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/i1MOPTmohOsMD.png'
|
|
},
|
|
'Pink_Doggy': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/i1SpWAzfcIEQc.png',
|
|
center: true
|
|
},
|
|
'Pink_Hair': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibdwMaIPwdscao.png',
|
|
center: true
|
|
},
|
|
'Railgun_2': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iNhpDDO0GSTeM.png',
|
|
center: true
|
|
},
|
|
'Railgun_3': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iiW02dmqUwRcy.png'
|
|
},
|
|
'Railgun_4': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iR3j0mGgd1927.png',
|
|
center: true
|
|
},
|
|
'Rainbow_Dash': {
|
|
category: 'Ponies',
|
|
image: '//i.minus.com/ibthr5EDMZHV9j.png',
|
|
center: true
|
|
},
|
|
'Rarity': {
|
|
category: 'Ponies',
|
|
image: '//i.minus.com/ibkraGhhUh25CU.png',
|
|
center: true
|
|
},
|
|
'Revi': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ivUMKcy5ow6Ab.png',
|
|
position: 'bottom',
|
|
center: true
|
|
},
|
|
'Ruri_Gokou': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibtZo1fdOk8NCB.png',
|
|
position: 'bottom',
|
|
center: true
|
|
},
|
|
'Ryuu': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iecVz4p2SuqK4.png',
|
|
position: 'bottom'
|
|
},
|
|
'Samus_Aran': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iWG1GFJ89A05p.png',
|
|
center: true
|
|
},
|
|
'Samus_Aran_2': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibl4efsNtHpkXg.png'
|
|
},
|
|
'Shana': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ib2cTJMF0cYIde.png',
|
|
center: true
|
|
},
|
|
'Shana_2': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ioRICGu0Ipzj9.png',
|
|
center: true
|
|
},
|
|
'Shiki': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iIZm1JxxDIDQ1.png'
|
|
},
|
|
'Shinji_and_Girls': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/itMrEn56GzvzE.png',
|
|
center: true
|
|
},
|
|
'Shinonome_Hakase': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iocCwDCnNgI19.png',
|
|
center: true
|
|
},
|
|
'Shirakiin_Ririchiyo': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/i1m0rdzmVLYLa.png',
|
|
position: 'bottom',
|
|
center: true
|
|
},
|
|
'Shirohibe': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iGu91k3KZeg00.png',
|
|
position: 'bottom'
|
|
},
|
|
'Suruga_Kanbaru': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/irEL7AgC80qKD.png',
|
|
center: true
|
|
},
|
|
'Suzumiya_Haruhi': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iM9qMfUNh9Qi9.png',
|
|
center: true
|
|
},
|
|
'Suzumiya_Haruhi_2': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibnomd5iasjceY.png',
|
|
center: true
|
|
},
|
|
'Tardis': {
|
|
category: 'Western',
|
|
image: '//i.minus.com/iQL2bwpDfOgk.png',
|
|
center: true
|
|
},
|
|
'Tewi_Inaba': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ib2k9lwQIkmb66.png'
|
|
},
|
|
'Tomozo_Kaoru': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/islUcBaPRYAgv.png',
|
|
center: true
|
|
},
|
|
'Twilight_Sparkle': {
|
|
category: 'Ponies',
|
|
image: '//i.minus.com/ibnMYVTZEykrKU.png',
|
|
center: true
|
|
},
|
|
'White_Curious': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ibfkj5osu99axe.png',
|
|
center: true
|
|
},
|
|
'Yakumo_Ran': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ivKqn8vL9A8cQ.png'
|
|
},
|
|
'Yin': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iL9DlVtaAGFdq.png'
|
|
},
|
|
'Yin_2': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/izkTpyjr1XlLR.png',
|
|
center: true
|
|
},
|
|
'Yoko_Littner_2': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/i7aUDY4h9uB1T.png',
|
|
center: true
|
|
},
|
|
'Yoko_Littner_3': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iYVd5DhCmB7VJ.png',
|
|
center: true
|
|
},
|
|
'Yozora_Mikazuki': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iIFEsDzoDALQd.png'
|
|
},
|
|
'Yuzuki_Yukari': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/iYQOz0iGM9ygq.png',
|
|
center: true
|
|
},
|
|
'Yukkikaze': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/ioQJAnyXebHDJ.png',
|
|
center: true
|
|
},
|
|
'Yukkihaze_2': {
|
|
category: 'Anime',
|
|
image: '//i.minus.com/inpgaDlJtZ9Sc.png',
|
|
center: true
|
|
}
|
|
};
|
|
|
|
Themes = {
|
|
'AppChan': {
|
|
'Author': 'Zixaphir',
|
|
'Author Tripcode': '!..NoTrip..',
|
|
'Background Color': 'rgba(44,44,44,1)',
|
|
'Thread Wrapper Background': 'rgba(0,0,0,0)',
|
|
'Thread Wrapper Border': 'rgba(0,0,0,0)',
|
|
'Dialog Background': 'rgba(44,44,44,1)',
|
|
'Dialog Border': 'rgba(44,44,44,1)',
|
|
'Reply Background': 'rgba(51,51,51,1)',
|
|
'Reply Border': 'rgba(51,51,51,1)',
|
|
'Highlighted Reply Background': 'rgba(57,57,57,1)',
|
|
'Highlighted Reply Border': 'rgba(57,57,57,1)',
|
|
'Backlinked Reply Outline': 'rgba(98,124,141,1)',
|
|
'Input Background': 'rgba(51,51,51,1)',
|
|
'Input Border': 'rgba(51,51,51,1)',
|
|
'Checkbox Background': 'rgba(68,68,68,1)',
|
|
'Checkbox Border': 'rgba(68,68,68,1)',
|
|
'Buttons Background': 'rgba(48,48,48,1)',
|
|
'Buttons Border': 'rgba(48,48,48,1)',
|
|
'Focused Input Background': 'rgba(63,63,63,1)',
|
|
'Focused Input Border': 'rgba(63,63,63,1)',
|
|
'Hovered Input Background': 'rgba(57,57,57,1)',
|
|
'Hovered Input Border': 'rgba(57,57,57,1)',
|
|
'Navigation Background': 'rgba(44,44,44,0.9)',
|
|
'Navigation Border': 'rgba(44,44,44,0.9)',
|
|
'Quotelinks': 'rgb(79,95,143)',
|
|
'Backlinks': 'rgb(79,95,143)',
|
|
'Links': 'rgb(102,136,170)',
|
|
'Hovered Links': 'rgb(78,110,142)',
|
|
'Navigation Links': 'rgb(170,170,170)',
|
|
'Hovered Navigation Links': 'rgb(78,110,142)',
|
|
'Names': 'rgb(170,170,170)',
|
|
'Tripcodes': 'rgb(170,170,170)',
|
|
'Emails': 'rgb(102,136,170)',
|
|
'Subjects': 'rgb(144,144,144)',
|
|
'Text': 'rgb(170,170,170)',
|
|
'Inputs': 'rgb(170,170,170)',
|
|
'Post Numbers': 'rgb(102,136,170)',
|
|
'Greentext': 'rgb(120,153,34)',
|
|
'Sage': 'rgb(150,150,150)',
|
|
'Board Title': 'rgb(170,170,170)',
|
|
'Timestamps': 'rgb(170,170,170)',
|
|
'Warnings': 'rgb(102,136,170)',
|
|
'Shadow Color': 'rgba(0,0,0,.1)',
|
|
'Custom CSS': ''
|
|
},
|
|
'BakaBT': {
|
|
'Author': 'seaweed',
|
|
'Author Tripcode': '!POMF.9waa',
|
|
'Background Image': 'url("http://i.imgur.com/rTkxi.jpg")',
|
|
'Background Attachment': 'fixed',
|
|
'Background Position': '20px 20px',
|
|
'Background Repeat': 'repeat',
|
|
'Background Color': 'rgba(238,238,238,1)',
|
|
'Thread Wrapper Background': 'rgba(255,255,255,1)',
|
|
'Thread Wrapper Border': 'rgba(204,204,204,1)',
|
|
'Dialog Background': 'rgba(238,221,255,1)',
|
|
'Dialog Border': 'rgba(238,221,255,1)',
|
|
'Reply Background': 'rgba(238,221,255,1)',
|
|
'Reply Border': 'rgba(209,162,255,1)',
|
|
'Highlighted Reply Background': 'rgba(238,221,255,1)',
|
|
'Highlighted Reply Border': 'rgba(209,162,255,1)',
|
|
'Backlinked Reply Outline': 'rgba(204,101,99,1)',
|
|
'Input Background': 'rgba(255,255,255,1)',
|
|
'Input Border': 'rgba(204,204,204,1)',
|
|
'Checkbox Background': 'rgba(255,255,238,1)',
|
|
'Checkbox Border': 'rgba(204,204,204,1)',
|
|
'Buttons Background': 'rgba(255,255,255,1)',
|
|
'Buttons Border': 'rgba(204,204,204,1)',
|
|
'Focused Input Background': 'rgba(255,255,255,1)',
|
|
'Focused Input Border': 'rgba(209,162,255,1)',
|
|
'Hovered Input Background': 'rgba(238,221,255,1)',
|
|
'Hovered Input Border': 'rgba(204,204,204,1)',
|
|
'Navigation Background': 'rgba(255,255,255,0.8)',
|
|
'Navigation Border': 'rgba(255,255,255,0.8)',
|
|
'Quotelinks': 'rgb(146,92,141)',
|
|
'Backlinks': 'rgb(146,92,141)',
|
|
'Links': 'rgb(133,76,158)',
|
|
'Hovered Links': 'rgb(198,23,230)',
|
|
'Navigation Links': 'rgb(17,17,17)',
|
|
'Hovered Navigation Links': 'rgb(198,23,230)',
|
|
'Names': 'rgb(133,76,158)',
|
|
'Tripcodes': 'rgb(146,92,141)',
|
|
'Emails': 'rgb(133,76,158)',
|
|
'Subjects': 'rgb(17,17,17)',
|
|
'Text': 'rgb(0,0,0)',
|
|
'Inputs': 'rgb(0,0,0)',
|
|
'Post Numbers': 'rgb(146,92,141)',
|
|
'Greentext': 'rgb(129,153,65)',
|
|
'Sage': 'rgb(146,92,141)',
|
|
'Board Title': 'rgb(133,76,158)',
|
|
'Timestamps': 'rgb(0,0,0)',
|
|
'Warnings': 'rgb(133,76,158)',
|
|
'Shadow Color': 'rgba(0,0,0,.05)',
|
|
'Custom CSS': ".board {\n box-shadow: 0px 10px 10px 2px rgba(128,128,128,0.5);\n border-radius: 3px;\n}\n.board .thread {\n padding:10px;\n}\n#appchanx-settings.reply.dialog,\n#appchanx-settings .dialog {\n background-color:#FFF;\n color:#000;\n border:2px solid #CCC;\n}\n#appchanx-settings ul {\n border-bottom:1px solid #DBD8D2;\n}\n#appchanx-settings ul:last-of-type{\n border:none;\n}\n#qp div.post{\n background-color:rgba(255,255,255,0.9);\n border:1px solid #D1A2FF;\n color:#000;\n}"
|
|
},
|
|
'Blackberry Jam': {
|
|
'Author': 'seaweed',
|
|
'Author Tripcode': '!POMF.9waa',
|
|
'Dialog Background': 'rgba(27,27,27,1)',
|
|
'Dialog Border': 'rgba(27,27,27,1)',
|
|
'Background Color': 'rgba(45,45,45,1)',
|
|
'Thread Wrapper Background': 'rgba(0,0,0,0)',
|
|
'Thread Wrapper Border': 'rgba(0,0,0,0)',
|
|
'Reply Background': 'rgba(27,27,27,1)',
|
|
'Reply Border': 'rgba(38,38,38,1)',
|
|
'Highlighted Reply Background': 'rgba(17,17,17,1)',
|
|
'Highlighted Reply Border': 'rgba(17,17,17,1)',
|
|
'Backlinked Reply Outline': 'rgba(103,204,232,1)',
|
|
'Checkbox Background': 'rgba(51,51,51,1)',
|
|
'Checkbox Border': 'rgba(51,51,51,1)',
|
|
'Input Background': 'rgba(27,27,27,1)',
|
|
'Input Border': 'rgba(27,27,27,1)',
|
|
'Focused Input Background': 'rgba(27,27,27,1)',
|
|
'Focused Input Border': 'rgba(27,27,27,1)',
|
|
'Hovered Input Background': 'rgba(17,17,17,1)',
|
|
'Hovered Input Border': 'rgba(17,17,17,1)',
|
|
'Buttons Background': 'rgba(27,27,27,1)',
|
|
'Buttons Border': 'rgba(27,27,27,1)',
|
|
'Navigation Background': 'rgba(45,45,45,0.9)',
|
|
'Navigation Border': 'rgba(45,45,45,0.9)',
|
|
'Links': 'rgb(218,105,224)',
|
|
'Hovered Links': 'rgb(255,0,255)',
|
|
'Navigation Links': 'rgb(241,241,241)',
|
|
'Hovered Navigation Links': 'rgb(255,0,255)',
|
|
'Subjects': 'rgb(241,241,241)',
|
|
'Names': 'rgb(103,204,232)',
|
|
'Sage': 'rgb(103,204,232)',
|
|
'Tripcodes': 'rgb(103,204,232)',
|
|
'Emails': 'rgb(218,105,224)',
|
|
'Post Numbers': 'rgb(218,105,224)',
|
|
'Text': 'rgb(241,241,241)',
|
|
'Quotelinks': 'rgb(223,153,247)',
|
|
'Backlinks': 'rgb(223,153,247)',
|
|
'Greentext': 'rgb(108,204,102)',
|
|
'Board Title': 'rgb(103,204,232)',
|
|
'Timestamps': 'rgb(218,105,224)',
|
|
'Inputs': 'rgb(218,105,224)',
|
|
'Warnings': 'rgb(103,204,232)',
|
|
'Shadow Color': 'rgba(0,0,0,.1)',
|
|
'Custom CSS': ".reply.post {\n box-shadow: inset 0px 1px 2px 1px #111;\n}\n#qr {\n box-shadow: none;\n}\n#qr textarea,\n#qr input[name=\"name\"],\n#qr input[name=\"email\"],\n#qr input[name=\"sub\"],\n#qr input[title=\"Verification\"] {\n box-shadow: inset 0px 1px 2px 0px #111;\n}\n#qp .post {\n background-color: rgba(29,29,33,1);\n border: 1px solid rgba(95,137,172,0.4);\n}"
|
|
},
|
|
'Midnight Caek': {
|
|
'Author': 'Zixaphir',
|
|
'Author Tripcode': '!M.........',
|
|
'Background Color': 'rgba(16,16,16,1)',
|
|
'Thread Wrapper Background': 'rgba(0,0,0,0)',
|
|
'Thread Wrapper Border': 'rgba(0,0,0,0)',
|
|
'Dialog Background': 'rgba(28,28,28,1)',
|
|
'Dialog Border': 'rgba(28,28,28,1)',
|
|
'Reply Background': 'rgba(28,28,28,1)',
|
|
'Reply Border': 'rgba(28,28,28,1)',
|
|
'Highlighted Reply Background': 'rgba(24,24,24,1)',
|
|
'Highlighted Reply Border': 'rgba(24,24,24,1)',
|
|
'Backlinked Reply Outline': 'rgba(98,124,141,1)',
|
|
'Input Background': 'rgba(28,28,28,1)',
|
|
'Input Border': 'rgba(28,28,28,1)',
|
|
'Hovered Input Background': 'rgba(24,24,24,1)',
|
|
'Hovered Input Border': 'rgba(24,24,24,1)',
|
|
'Focused Input Background': 'rgba(16,16,16,1)',
|
|
'Focused Input Border': 'rgba(28,28,28,1)',
|
|
'Checkbox Background': 'rgba(0,0,0,1)',
|
|
'Checkbox Border': 'rgba(60,60,60,1)',
|
|
'Buttons Background': 'rgba(24,24,24,1)',
|
|
'Buttons Border': 'rgba(24,24,24,1)',
|
|
'Navigation Background': 'rgba(16,16,16,0.9)',
|
|
'Navigation Border': 'rgba(16,16,16,0.9)',
|
|
'Quotelinks': 'rgb(71,71,91)',
|
|
'Backlinks': 'rgb(66,66,71)',
|
|
'Links': 'rgb(87,87,123)',
|
|
'Hovered Links': 'rgb(71,71,91)',
|
|
'Navigation Links': 'rgb(144,144,144)',
|
|
'Hovered Navigation Links': 'rgb(71,71,91)',
|
|
'Names': 'rgb(124,45,45)',
|
|
'Tripcodes': 'rgb(62,113,87)',
|
|
'Emails': 'rgb(68,68,68)',
|
|
'Subjects': 'rgb(170,170,170)',
|
|
'Text': 'rgb(144,144,144)',
|
|
'Inputs': 'rgb(144,144,144)',
|
|
'Post Numbers': 'rgb(144,144,144)',
|
|
'Greentext': 'rgb(113,121,62)',
|
|
'Sage': 'rgb(68,68,68)',
|
|
'Board Title': 'rgb(144,144,144)',
|
|
'Timestamps': 'rgb(144,144,144)',
|
|
'Warnings': 'rgb(87,87,123)',
|
|
'Shadow Color': 'rgba(0,0,0,.1)',
|
|
'Custom CSS': ''
|
|
},
|
|
'Minimalistic Mayhem': {
|
|
'Author': 'Mayhem',
|
|
'Author Tripcode': '!MayhemYDG.',
|
|
'Background Image': 'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAAAXNSR0IArs4c6QAAACdJREFUCNdNxzEBADAMwzCnOMwfWYDs2JNPCgCoH9m0zQa4jXob4AGJFwxchPNwQAAAAABJRU5ErkJggg==")',
|
|
'Background Color': 'rgba(25,25,25,1)',
|
|
'Dialog Background': 'rgba(34,34,34,1)',
|
|
'Dialog Border': 'rgba(41,41,41,1)',
|
|
'Thread Wrapper Background': 'rgba(34,34,34,1)',
|
|
'Thread Wrapper Border': 'rgba(0,0,0,1)',
|
|
'Reply Background': 'rgba(51,51,51,1)',
|
|
'Reply Border': 'rgba(17,17,17,1)',
|
|
'Highlighted Reply Background': 'rgba(37,38,42,1)',
|
|
'Highlighted Reply Border': 'rgba(85,85,85,1)',
|
|
'Backlinked Reply Outline': 'rgba(98,124,141,1)',
|
|
'Checkbox Background': 'rgba(57,57,57,1)',
|
|
'Checkbox Border': 'rgba(25,25,25,1)',
|
|
'Input Background': 'rgba(34,34,34,1)',
|
|
'Input Border': 'rgba(21,21,21,1)',
|
|
'Focused Input Background': 'rgba(32,32,32,1)',
|
|
'Focused Input Border': 'rgba(102,102,102,1)',
|
|
'Hovered Input Background': 'rgba(24,24,24,1)',
|
|
'Hovered Input Border': 'rgba(21,21,21,1)',
|
|
'Buttons Background': 'rgba(32,32,32,1)',
|
|
'Buttons Border': 'rgba(16,16,16,1)',
|
|
'Navigation Background': 'rgba(26,26,26,0.9)',
|
|
'Navigation Border': 'rgba(26,26,26,0.9)',
|
|
'Links': 'rgb(85,156,122)',
|
|
'Hovered Links': 'rgb(199,222,26)',
|
|
'Navigation Links': 'rgb(144,144,144)',
|
|
'Hovered Navigation Links': 'rgb(198,23,230)',
|
|
'Subjects': 'rgb(72,98,115)',
|
|
'Names': 'rgb(46,136,166)',
|
|
'Sage': 'rgb(124,45,45)',
|
|
'Tripcodes': 'rgb(140,93,42)',
|
|
'Emails': 'rgb(174,43,41)',
|
|
'Post Numbers': 'rgb(137,115,153)',
|
|
'Text': 'rgb(221,221,221)',
|
|
'Quotelinks': 'rgb(139,164,70)',
|
|
'Backlinks': 'rgb(139,164,70)',
|
|
'Greentext': 'rgb(139,164,70)',
|
|
'Board Title': 'rgb(187,187,187)',
|
|
'Timestamps': 'rgb(221,221,221)',
|
|
'Inputs': 'rgb(187,187,187)',
|
|
'Warnings': 'rgb(87,87,123)',
|
|
'Shadow Color': 'rgba(0,0,0,.1)',
|
|
'Custom CSS': ".nameBlock > .useremail > postertrip {\n color: rgb(137,115,153);\n}\na.backlink:hover {\n color: rgb(198,23,230);\n}\n.reply:target,\n.reply.highlight:target {\n background:rgb(37,38,42);\n}\n[alt=\"sticky\"] + a {\n color: rgb(242,141,0);\n}\n[alt=\"closed\"] + a {\n color: rgb(178,171,130);\n}\ninput:checked .rice {\n border-color:rgb(21,21,21);\n}\ninput[type=\"submit\"],\ninput[type=\"button\"],\nbutton {\n background: linear-gradient(#393939, #292929);\n border: 1px solid #191919;\n color: #AAA;\n text-shadow: 0 1px 1px #191919;\n}\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\nbackground-color: #393939;\n border: 1px solid #191919;\n}\ninput[type=\"checkbox\"]:checked,\ninput[type=\"radio\"]:checked {\n background: linear-gradient(#595959, #393939);\n border: 1px solid #151515;\n}\n.board .thread {\n padding: 7px;\n}\n.subject:hover,\ndiv.post:hover .subject {\n color: #3F8DBF !important;\n}\n.postertrip:hover,\ndiv.post:hover .postertrip {\n color:#CC7212 !important;\n}\n.name:hover,\ndiv.post:hover .name {\n color: #0AAEE7 !important;\n}\n.name,\n.subject,\n.postertrip {\n -webkit-transition:color .3s ease-in-out;\n -moz-transition:color .3s ease-in-out;\n -o-transition:color .3s ease-in-out;\n}"
|
|
},
|
|
'ObsidianChan': {
|
|
'Author': 'seaweed',
|
|
'Author Tripcode': '!POMF.9waa',
|
|
'Background Image': 'url("http://i.imgur.com/sbi8u.png")',
|
|
'Background Attachment': 'fixed',
|
|
'Dialog Background': 'rgba(0,0,0,0.7)',
|
|
'Dialog Border': 'rgba(0,0,0,0.7)',
|
|
'Background Color': 'rgba(0,0,0,1)',
|
|
'Thread Wrapper Background': 'rgba(0,0,0,0.3)',
|
|
'Thread Wrapper Border': 'rgba(51,51,51,1)',
|
|
'Reply Background': 'rgba(0,0,0,0.6)',
|
|
'Reply Border': 'rgba(0,0,0,0.6)',
|
|
'Highlighted Reply Background': 'rgba(0,0,0,0.4)',
|
|
'Highlighted Reply Border': 'rgba(0,0,0,0.4)',
|
|
'Backlinked Reply Outline': 'rgba(98,124,141,1)',
|
|
'Checkbox Background': 'rgba(68,68,68,1)',
|
|
'Checkbox Border': 'rgba(68,68,68,1)',
|
|
'Input Background': 'rgba(0,0,0,0.6)',
|
|
'Input Border': 'rgba(0,0,0,0.6)',
|
|
'Hovered Input Background': 'rgba(0,0,0,0.4)',
|
|
'Hovered Input Border': 'rgba(0,0,0,0.4)',
|
|
'Focused Input Background': 'rgba(0,0,0,0.4)',
|
|
'Focused Input Border': 'rgba(0,0,0,0.4)',
|
|
'Buttons Background': 'rgba(0,0,0,0.4)',
|
|
'Buttons Border': 'rgba(0,0,0,0.4)',
|
|
'Navigation Background': 'rgba(0,0,0,0.7)',
|
|
'Navigation Border': 'rgba(0,0,0,0.7)',
|
|
'Links': 'rgb(0,255,255)',
|
|
'Hovered Links': 'rgb(0,255,255)',
|
|
'Navigation Links': 'rgb(253,254,255)',
|
|
'Hovered Navigation Links': 'rgb(253,254,255)',
|
|
'Subjects': 'rgb(144,144,144)',
|
|
'Names': 'rgb(253,254,255)',
|
|
'Sage': 'rgb(253,254,255)',
|
|
'Tripcodes': 'rgb(255,82,203)',
|
|
'Emails': 'rgb(0,255,255)',
|
|
'Post Numbers': 'rgb(0,255,255)',
|
|
'Text': 'rgb(253,254,255)',
|
|
'Quotelinks': 'rgb(0,255,255)',
|
|
'Backlinks': 'rgb(0,255,255)',
|
|
'Greentext': 'rgb(67,204,103)',
|
|
'Board Title': 'rgb(253,254,255)',
|
|
'Timestamps': 'rgb(253,254,255)',
|
|
'Inputs': 'rgb(253,254,255)',
|
|
'Warnings': 'rgb(0,255,255)',
|
|
'Shadow Color': 'rgba(0,0,0,.1)',
|
|
'Custom CSS': "#qp div.post{\n background-color:rgba(0,0,0,0.8);\n border: 1px solid #333;\n}\n#qr {\n background-color: rgba(0,0,0,0.7);\n border: 1px solid #333;\n}"
|
|
},
|
|
'PaisleyChan': {
|
|
'Author': 'Ubuntufriend',
|
|
'Author Tripcode': '!TRip.C0d3',
|
|
'Background Image': 'url(http://i.imgur.com/DRaZf.jpg)',
|
|
'Background Attachment': 'fixed',
|
|
'Background Repeat': 'repeat',
|
|
'Background Color': 'rgba(19,19,19,1)',
|
|
'Dialog Background': 'rgba(16,16,16,1)',
|
|
'Dialog Border': 'rgba(16,16,16,1)',
|
|
'Thread Wrapper Background': 'rgba(52,56,56,0.3)',
|
|
'Thread Wrapper Border': 'rgba(52,56,56,0.3)',
|
|
'Reply Background': 'rgba(52,56,56,1)',
|
|
'Reply Border': 'rgba(0,0,0,0)',
|
|
'Highlighted Reply Background': 'rgba(0,0,0,0)',
|
|
'Highlighted Reply Border': 'rgba(0,0,0,0)',
|
|
'Backlinked Reply Outline': 'rgba(98,124,141,1)',
|
|
'Checkbox Background': 'rgba(34,34,34,1)',
|
|
'Checkbox Border': 'rgba(60,60,60,1)',
|
|
'Input Background': 'rgba(28,28,28,1)',
|
|
'Input Border': 'rgba(28,28,28,1)',
|
|
'Hovered Input Background': 'rgba(24,24,24,1)',
|
|
'Hovered Input Border': 'rgba(24,24,24,1)',
|
|
'Focused Input Background': 'rgba(32,32,32,1)',
|
|
'Focused Input Border': 'rgba(32,32,32,1)',
|
|
'Buttons Background': 'rgba(32,32,32,1)',
|
|
'Buttons Border': 'rgba(32,32,32,1)',
|
|
'Navigation Background': 'rgba(16,16,16,0.9)',
|
|
'Navigation Border': 'rgba(16,16,16,0.9)',
|
|
'Links': 'rgb(187,187,187)',
|
|
'Hovered Links': 'rgb(0,223,252)',
|
|
'Navigation Links': 'rgb(153,153,153)',
|
|
'Hovered Navigation Links': 'rgb(0,223,252)',
|
|
'Subjects': 'rgb(170,170,170)',
|
|
'Names': 'rgb(128,172,206)',
|
|
'Sage': 'rgb(153,153,153)',
|
|
'Tripcodes': 'rgb(128,172,206)',
|
|
'Emails': 'rgb(187,187,187)',
|
|
'Post Numbers': 'rgb(153,153,153)',
|
|
'Text': 'rgb(153,153,153)',
|
|
'Quotelinks': 'rgb(212,212,212)',
|
|
'Backlinks': 'rgb(212,212,212)',
|
|
'Greentext': 'rgb(152,185,98)',
|
|
'Board Title': 'rgb(153,153,153)',
|
|
'Timestamps': 'rgb(153,153,153)',
|
|
'Inputs': 'rgb(153,153,153)',
|
|
'Warnings': 'rgb(187,187,187)',
|
|
'Shadow Color': 'rgba(0,0,0,.1)',
|
|
'Custom CSS': "#appchanx-settings {\n background-color: rgba(16,16,16,1) !important;\n}\n#delform blockquote {\n border-radius:3px;\n color:#bbb;\n background:#343838;\n padding:8px;\n box-shadow:0px 0px 20px rgba(25,25,25,0.6);\n border:1px solid #343838;\n border-bottom:2px solid #444848;\n border-radius:0px 6px 6px 6px;\n padding-top:15px;\n}\n.name {\n font-weight:800;\n}\n.nameBlock > .useremail > .name:hover,\n.nameBlock> .useremail> .postertrip:hover {\n color:#00dffc;\n}\na.forwardlink {\n color:#608cae;\n font-weight:800;\n}\ndiv.reply,\n.reply.highlight {\n padding:0;\n}\n#qp div.post {\n border:1px solid rgba(128,172,206,0.5) !important;\n background-color: rgba(24,24,24,0.9) !important;\n}\n.name,\n.postertrip {\n text-shadow:0px 0px 6px rgba(20,20,20,0.9);\n font-weight:bold;\n background:#343838;\n border:1px solid #343838;\n border-radius:5px 5px 0px 0px;\n padding:4px 6px;\n padding-top:2px;\n}\n.board,\n.board blockquote {\n margin:0 10px 15px 0 !important;\n padding:0px;\n}\na {\n -moz-transition:all 0.5s ease;\n -webkit-transition:all 0.5s ease;\n -o-transition:all 0.5s ease;\n}\na.pointer{\n font-weight:bold;\n font-weight:normal;\n color:#777;\n padding-right:5px;\n}\n.board .opContainer,\n.board .replyContainer {\n opacity:0.45;\n transition:all 0.5s ease;\n}\n.board .opContainer:hover,\n.board .replyContainer:hover {\n opacity:1;\n}\n.reply.post,\n.reply.highlight {\n background:transparent;\n border:0px;\n padding:0px;\n padding-bottom:0px;\n border-radius:6px;\n}\n#delform blockquote {\n padding:5px;\n background:#343838;\n margin-top:0px;\n min-height:20px;\n padding-top:10px;\n clear:none;\n}\n#delform blockquote::after {\n content: ' ';\n clear: both;\n}\n#delform .file + blockquote {\n margin-top: -1.4em !important;\n padding-top: 1.4em !important;\n padding-left:165px !important;\n}\n.file {\n margin-top: 2px;\n}\na.backlink{\nborder:1px solid #343838;\nborder-radius:5px 5px 0px 0px;\nbackground:#343838;\npadding:2px 4px 2px;\n text-decoration:none;\n}\na.forwardlink{\n color:#608CAE;\n text-shadow:0 0 6px rgba(96,140,174,0.8);\n}\n.subject{\n font-weight: bold;\n letter-spacing: 3px;\n background: transparent;\n}\n.reply.post {\n background-color: rgba(0,0,0,0) !important;\n border: none !important;\n}\n#qp div.post .name,\n#qp div.post a.backlink,\n#qp div.post blockquote {\n background:none !important;\n border:none !important;\n box-shadow:none !important;\n border-radius:0px !important;\n}"
|
|
},
|
|
'Photon': {
|
|
'Author': 'seaweed',
|
|
'Author Tripcode': '!POMF.9waa',
|
|
'Background Color': 'rgba(238,238,238,1)',
|
|
'Dialog Background': 'rgba(238,238,238,1)',
|
|
'Dialog Border': 'rgba(204,204,204,1)',
|
|
'Thread Wrapper Background': 'rgba(0,0,0,0)',
|
|
'Thread Wrapper Border': 'rgba(0,0,0,0)',
|
|
'Reply Background': 'rgba(221,221,221,1)',
|
|
'Reply Border': 'rgba(204,204,204,1)',
|
|
'Highlighted Reply Background': 'rgba(204,204,204,1)',
|
|
'Highlighted Reply Border': 'rgba(204,204,204,1)',
|
|
'Backlinked Reply Outline': 'rgba(98,124,141,1)',
|
|
'Checkbox Background': 'rgba(255,255,238)',
|
|
'Checkbox Border': 'rgba(255,255,238)',
|
|
'Input Background': 'rgba(255,255,255,1)',
|
|
'Input Border': 'rgba(204,204,204,1)',
|
|
'Hovered Input Background': 'rgba(204,204,204,1)',
|
|
'Hovered Input Border': 'rgba(204,204,204,1)',
|
|
'Focused Input Background': 'rgba(255,255,255,1)',
|
|
'Focused Input Border': 'rgba(0,74,153,1)',
|
|
'Buttons Background': 'rgba(255,255,238,1)',
|
|
'Buttons Border': 'rgba(204,204,204,1)',
|
|
'Navigation Background': 'rgba(238,238,238,0.9)',
|
|
'Navigation Border': 'rgba(238,238,238,0.9)',
|
|
'Links': 'rgb(255,102,0)',
|
|
'Hovered Links': 'rgb(255,51,0)',
|
|
'Navigation Links': 'rgb(17,17,17)',
|
|
'Hovered Navigation Links': 'rgb(255,51,0)',
|
|
'Subjects': 'rgb(17,17,17)',
|
|
'Names': 'rgb(0,74,153)',
|
|
'Sage': 'rgb(51,51,51)',
|
|
'Tripcodes': 'rgb(255,51,0)',
|
|
'Emails': 'rgb(255,102,0)',
|
|
'Post Numbers': 'rgb(51,51,51)',
|
|
'Text': 'rgb(51,51,51)',
|
|
'Quotelinks': 'rgb(17,17,17)',
|
|
'Backlinks': 'rgb(17,17,17)',
|
|
'Greentext': 'rgb(120,153,34)',
|
|
'Board Title': 'rgb(0,74,153)',
|
|
'Timestamps': 'rgb(51,51,51)',
|
|
'Inputs': 'rgb(0,0,0)',
|
|
'Warnings': 'rgb(51,51,51)',
|
|
'Shadow Color': 'rgba(0,0,0,.05)',
|
|
'Custom CSS': ".fileText{\n color: rgb(102,102,102);\n}\n.boardTitle {\n color: #004a99 !important;\n text-shadow: 1px 1px 1px #222 !important;\n}\n.boardSubtitle,\n.boardBanner .boardSubtitle > a {\n text-shadow: none !important;\n}"
|
|
},
|
|
'RedUX': {
|
|
'Author': 'Zixaphir',
|
|
'Author Tripcode': '!VGsTHECURE',
|
|
'Background Image': 'linear-gradient(rgba(210,210,210,0.7), rgba(240,240,240,0.4) 400px, rgba(240,240,240,0.3)), url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIQAAACEAQMAAABrihHkAAAABlBMVEX///8AAABVwtN+AAAAAnRSTlMASuCaZbYAAAA+SURBVHhe7c2xCQAgDAXRKywsHcFRdDNxchtBkhHk4Lp88ui7hhaztBCkyYZ7fFHzI/Jk/GRpaWlpaWlpaR3scHNQSY3kigAAAABJRU5ErkJggg==")',
|
|
'Background Attachment': 'fixed, scroll',
|
|
'Background Position': 'top, center',
|
|
'Background Repeat': 'no-repeat, repeat',
|
|
'Background Color': 'rgba(238,242,255,1)',
|
|
'Thread Wrapper Background': 'rgb(230,230,230)',
|
|
'Thread Wrapper Border': 'rgba(204,204,204,1)',
|
|
'Dialog Background': 'linear-gradient(rgb(222,222,222), rgb(240,240,240) 200px, rgb(240,240,240))',
|
|
'Dialog Border': 'rgb(220,210,210)',
|
|
'Reply Background': 'rgba(230,230,230,1)',
|
|
'Reply Border': 'rgba(204,204,204,1)',
|
|
'Highlighted Reply Background': 'rgba(219,219,219,1)',
|
|
'Highlighted Reply Border': 'rgba(219,219,219,1)',
|
|
'Backlinked Reply Outline': 'rgba(98,124,141,1)',
|
|
'Input Background': 'linear-gradient(rgb(222,222,222), rgb(240,240,240)), rgb(240,240,240)',
|
|
'Input Border': 'rgb(220,210,210)',
|
|
'Hovered Input Background': 'linear-gradient(rgba(214,186,208,0.7), rgb(240,240,240)), rgb(240,240,240)',
|
|
'Hovered Input Border': 'rgba(214,186,208,1)',
|
|
'Focused Input Background': 'rgb(240,240,240)',
|
|
'Focused Input Border': 'rgb(220,210,210)',
|
|
'Checkbox Background': 'rgba(238,242,255,1)',
|
|
'Checkbox Border': 'rgba(180,180,180,1)',
|
|
'Buttons Background': 'linear-gradient(rgb(222,222,222), rgb(240,240,240)), rgb(240,240,240)',
|
|
'Buttons Border': 'rgb(220,210,210)',
|
|
'Navigation Background': 'rgba(230,230,230,0.8)',
|
|
'Navigation Border': 'rgba(204,204,204,1)',
|
|
'Quotelinks': 'rgb(153,51,51)',
|
|
'Backlinks': 'rgb(153,51,51)',
|
|
'Links': 'rgb(87,87,123)',
|
|
'Hovered Links': 'rgb(221,0,0)',
|
|
'Navigation Links': 'rgb(0,0,0)',
|
|
'Hovered Navigation Links': 'rgb(87,87,123)',
|
|
'Names': 'rgb(119,51,51)',
|
|
'Tripcodes': 'rgb(119,51,51)',
|
|
'Emails': 'rgb(87,87,123)',
|
|
'Subjects': 'rgb(15,12,93)',
|
|
'Text': 'rgb(0,0,0)',
|
|
'Inputs': 'rgb(0,0,0)',
|
|
'Post Numbers': 'rgb(0,0,0)',
|
|
'Greentext': 'rgb(34,133,34)',
|
|
'Sage': 'rgb(87,87,123)',
|
|
'Board Title': 'rgb(119,51,51)',
|
|
'Timestamps': 'rgb(0,0,0)',
|
|
'Warnings': 'rgb(87,87,123)',
|
|
'Shadow Color': 'rgba(0,0,0,.07)',
|
|
'Custom CSS': ".board .reply {\n background-color: transparent;\n border-color: #ccc transparent transparent transparent;\n border-style: solid;\n border-radius: 0 !important;\n margin-bottom: 0;\n}\n#themes {\n text-shadow: none;\n}\n#qp {\n text-shadow: 1px 0 0 rgb(0,0,0),\n 1px 1px 0 rgb(0,0,0),\n 0 1px 0 rgb(0,0,0),\n 1px 1px 2px rgb(0,0,0);\n}\n#qp .op.post,\n#qp .reply.post {\n border: 1px rgba(0,0,0,0.7) solid;\n background: linear-gradient(to right, rgba(0,0,0,0.7), rgba(0,0,0,0.5)), transparent;\n}\n#qp div.post,\n#qp .pln,\n#qp .postNum a {\n color: #fcd;\n}\n#qp .dateTime {\n color: #fcd !important;\n}\n#qp .subject,\n#qp .nameBlock > .useremail > .name,\n#qp .nameBlock > .useremail > .postertrip,\n#qp .name,\n#qp .postertrip,\n#qp .trip {\n color: #ffaac0 !important;\n}\n#qp a {\n color: #aaaac8;\n}\n.boardBanner a,\n#qp a.backlink,\n#qp span.quote > a.quotelink {\n color: rgb(255,255,255);\n}\n#qp span.quote {\n color: rgb(130,163,100);\n}\n.board {\n box-shadow: 0 20px 40px 10px rgba(0,0,0,0.1);\n border-radius: 4px;\n}\n:not(#themes) .rice {\n box-shadow:rgba(170, 170, 170,0.3) 0 1px;\n}\n#qp .prettyprint {\n background-color: rgba(0,0,0,0.3);\n border: 1px solid rgba(0,0,0,0.5);\n}\n#qp span.tag {\n color: #96562c;\n}\n#qp span.pun {\n color: #5b6f2a;\n}\n#qp span.com {\n color: #a34443;\n}\n#qp span.str,\n#qp span.atv {\n color: #8ba446;\n}\n#qp span.kwd {\n color: #987d3e;\n}\n#qp span.typ,\n#qp span.atn {\n color: #897399;\n}\n#qp span.lit {\n color: #558773;\n}"
|
|
},
|
|
'Solarized': {
|
|
'Author': 'ubuntufriend',
|
|
'Author Tripcode': '!TRip.C0d',
|
|
'Background Color': 'rgba(7,54,66,1)',
|
|
'Dialog Background': 'rgba(0,43,54,1)',
|
|
'Dialog Border': 'rgba(0,43,54,1)',
|
|
'Thread Wrapper Background': 'rgba(0,0,0,0)',
|
|
'Thread Wrapper Border': 'rgba(0,0,0,0)',
|
|
'Reply Background': 'rgba(0,43,54,1)',
|
|
'Reply Border': 'rgba(0,43,54,1)',
|
|
'Highlighted Reply Background': 'rgba(7,54,66,1)',
|
|
'Highlighted Reply Border': 'rgba(7,54,66,1)',
|
|
'Backlinked Reply Outline': 'rgba(98,124,141,1)',
|
|
'Checkbox Background': 'rgba(88,110,117,1)',
|
|
'Checkbox Border': 'rgba(88,110,117,1)',
|
|
'Input Background': 'rgba(0,43,54,1)',
|
|
'Input Border': 'rgba(0,43,54,1)',
|
|
'Hovered Input Background': 'rgba(7,54,66,1)',
|
|
'Hovered Input Border': 'rgba(7,54,66,1)',
|
|
'Focused Input Background': 'rgba(7,54,66,1)',
|
|
'Focused Input Border': 'rgba(7,54,66,1)',
|
|
'Buttons Background': 'rgba(0,43,54,1)',
|
|
'Buttons Border': 'rgba(0,43,54,1)',
|
|
'Navigation Background': 'rgba(7,54,66,1)',
|
|
'Navigation Border': 'rgba(7,54,66,1)',
|
|
'Links': 'rgb(108,113,196)',
|
|
'Hovered Links': 'rgb(211,54,130)',
|
|
'Navigation Links': 'rgb(147,161,161)',
|
|
'Hovered Navigation Links': 'rgb(211,54,130)',
|
|
'Subjects': 'rgb(203,75,22)',
|
|
'Names': 'rgb(88,110,117)',
|
|
'Sage': 'rgb(108,113,196)',
|
|
'Tripcodes': 'rgb(42,161,152)',
|
|
'Emails': 'rgb(108,113,196)',
|
|
'Post Numbers': 'rgb(147,161,161)',
|
|
'Text': 'rgb(147,161,161)',
|
|
'Quotelinks': 'rgb(79,95,143)',
|
|
'Backlinks': 'rgb(79,95,143)',
|
|
'Greentext': 'rgb(133,153,0)',
|
|
'Board Title': 'rgb(147,161,161)',
|
|
'Timestamps': 'rgb(147,161,161)',
|
|
'Inputs': 'rgb(147,161,161)',
|
|
'Warnings': 'rgb(108,113,196)',
|
|
'Shadow Color': 'rgba(0,0,0,.1)',
|
|
'Custom CSS': "#qp div.post {\n background-color:rgba(7,54,66,0.9);\n border:1px solid rgba(79,95,143,0.9);\n}"
|
|
},
|
|
'Yotsuba': {
|
|
'Author': 'moot',
|
|
'Author Tripcode': '!Ep8pui8Vw2',
|
|
'Background Image': 'linear-gradient(rgb(254,214,175), rgb(255,255,238) 200px, rgb(255,255,238))',
|
|
'Background Color': 'rgba(255,255,238,1)',
|
|
'Dialog Background': 'rgba(240,224,214,1)',
|
|
'Dialog Border': 'rgba(217,191,183,1)',
|
|
'Thread Wrapper Background': 'rgba(0,0,0,0)',
|
|
'Thread Wrapper Border': 'rgba(0,0,0,0)',
|
|
'Reply Background': 'rgba(240,224,214,1)',
|
|
'Reply Border': 'rgba(217,191,183,1)',
|
|
'Highlighted Reply Background': 'rgba(240,192,176,1)',
|
|
'Highlighted Reply Border': 'rgba(217,191,183,1)',
|
|
'Backlinked Reply Outline': 'rgba(98,124,141,1)',
|
|
'Checkbox Background': 'rgba(255,255,238,1)',
|
|
'Checkbox Border': 'rgba(217,191,183,1)',
|
|
'Input Background': 'rgba(240,224,214,1)',
|
|
'Input Border': 'rgba(217,191,183,1)',
|
|
'Hovered Input Background': 'rgba(240,224,214,1)',
|
|
'Hovered Input Border': 'rgba(217,191,183,1)',
|
|
'Focused Input Background': 'rgba(255,255,255,1)',
|
|
'Focused Input Border': 'rgba(128,0,0,1)',
|
|
'Buttons Background': 'rgba(240,192,176,1)',
|
|
'Buttons Border': 'rgba(217,191,183,1)',
|
|
'Navigation Background': 'rgba(240,192,176,0.7)',
|
|
'Navigation Border': 'rgba(217,191,183,1)',
|
|
'Links': 'rgb(186,0,0)',
|
|
'Hovered Links': 'rgb(221,0,0)',
|
|
'Navigation Links': 'rgb(128,0,0)',
|
|
'Hovered Navigation Links': 'rgb(221,0,0)',
|
|
'Subjects': 'rgb(204,17,5)',
|
|
'Names': 'rgb(17,119,67)',
|
|
'Sage': 'rgb(204,17,17)',
|
|
'Tripcodes': 'rgb(34,136,84)',
|
|
'Emails': 'rgb(186,0,0)',
|
|
'Post Numbers': 'rgb(128,0,0)',
|
|
'Text': 'rgb(128,0,0)',
|
|
'Quotelinks': 'rgb(221,0,0)',
|
|
'Backlinks': 'rgb(220,0,0)',
|
|
'Greentext': 'rgb(120,153,34)',
|
|
'Board Title': 'rgb(204,17,5)',
|
|
'Timestamps': 'rgb(186,0,0)',
|
|
'Inputs': 'rgb(0,0,0)',
|
|
'Warnings': 'rgb(128,0,0)',
|
|
'Shadow Color': 'rgba(0,0,0,.05)',
|
|
'Custom CSS': "#qp div.post {\n background-color:rgba(240,192,176,1);\n box-shadow:5px 5px 5px rgba(128,128,128,0.5);\n}\n.reply.post {\n border-color: transparent rgba(240,224,214,1) rgba(240,224,214,1) transparent;\n}"
|
|
},
|
|
'Yotsuba B': {
|
|
'Author': 'moot',
|
|
'Author Tripcode': '!Ep8pui8Vw2',
|
|
'Background Image': 'linear-gradient(rgb(209,213,238), rgb(238,242,255) 200px, rgb(238,242,255))',
|
|
'Background Color': 'rgba(238,242,255,1)',
|
|
'Dialog Background': 'rgba(214,218,240,1)',
|
|
'Dialog Border': 'rgba(183,197,217,1)',
|
|
'Thread Wrapper Background': 'rgba(0,0,0,0)',
|
|
'Thread Wrapper Border': 'rgba(0,0,0,0)',
|
|
'Reply Background': 'rgba(214,218,240,1)',
|
|
'Reply Border': 'rgba(183,197,217,1)',
|
|
'Highlighted Reply Background': 'rgba(214,186,208,1)',
|
|
'Highlighted Reply Border': 'rgba(183,197,217,1)',
|
|
'Backlinked Reply Outline': 'rgba(98,124,141,1)',
|
|
'Checkbox Background': 'rgba(238,242,255,1)',
|
|
'Checkbox Border': 'rgba(183,197,217,1)',
|
|
'Input Background': 'rgba(238,242,255,1)',
|
|
'Input Border': 'rgba(183,197,217,1)',
|
|
'Hovered Input Background': 'rgba(214,186,208,1)',
|
|
'Hovered Input Border': 'rgba(183,197,217,1)',
|
|
'Focused Input Background': 'rgba(214,218,240,1)',
|
|
'Focused Input Border': 'rgba(153,136,238,1)',
|
|
'Buttons Background': 'rgba(214,218,240,1)',
|
|
'Buttons Border': 'rgba(183,197,217,1)',
|
|
'Navigation Background': 'rgba(211,215,238,0.7)',
|
|
'Navigation Border': 'rgba(183,197,217,1)',
|
|
'Links': 'rgb(52,52,92)',
|
|
'Hovered Links': 'rgb(221,0,0)',
|
|
'Navigation Links': 'rgb(0,0,0)',
|
|
'Hovered Navigation Links': 'rgb(221,0,0)',
|
|
'Subjects': 'rgb(15,12,93)',
|
|
'Names': 'rgb(17,119,67)',
|
|
'Sage': 'rgb(153,0,0)',
|
|
'Tripcodes': 'rgb(34,136,84)',
|
|
'Emails': 'rgb(87,87,123)',
|
|
'Post Numbers': 'rgb(0,0,0)',
|
|
'Text': 'rgb(0,0,0)',
|
|
'Quotelinks': 'rgb(221,0,0)',
|
|
'Backlinks': 'rgb(52,52,92)',
|
|
'Greentext': 'rgb(120,153,34)',
|
|
'Board Title': 'rgb(175,10,15)',
|
|
'Timestamps': 'rgb(0,0,0)',
|
|
'Inputs': 'rgb(0,0,0)',
|
|
'Warnings': 'rgb(87,87,123)',
|
|
'Shadow Color': 'rgba(0,0,0,.05)',
|
|
'Custom CSS': "#qp div.post {\n background-color:rgba(214,186,208,1);\n box-shadow:5px 5px 5px rgba(128,128,128,0.5);\n}\n.reply.post {\n border-color: transparent rgba(183,197,217,1) rgba(183,197,217,1) transparent;\n}"
|
|
},
|
|
'Zenburned': {
|
|
'Author': 'lazy',
|
|
'Author Tripcode': '!HONKYn7h1.',
|
|
'Background Color': 'rgba(63,63,63,1)',
|
|
'Dialog Background': 'rgba(87,87,87,1)',
|
|
'Dialog Border': 'rgba(87,87,87,1)',
|
|
'Thread Wrapper Background': 'rgba(0,0,0,0)',
|
|
'Thread Wrapper Border': 'rgba(0,0,0,0)',
|
|
'Reply Background': 'rgba(87,87,87,1)',
|
|
'Reply Border': 'rgba(87,87,87,1)',
|
|
'Highlighted Reply Background': 'rgba(38,38,38,1)',
|
|
'Highlighted Reply Border': 'rgba(38,38,38,1)',
|
|
'Backlinked Reply Outline': 'rgba(98,124,141,1)',
|
|
'Checkbox Background': 'rgba(63,63,63,1)',
|
|
'Checkbox Border': 'rgba(136,136,136,1)',
|
|
'Input Background': 'rgba(87,87,87,1)',
|
|
'Input Border': 'rgba(136,136,136,1)',
|
|
'Hovered Input Background': 'rgba(38,38,38,1)',
|
|
'Hovered Input Border': 'rgba(38,38,38,1)',
|
|
'Focused Input Background': 'rgba(38,38,38,1)',
|
|
'Focused Input Border': 'rgba(153,136,238,1)',
|
|
'Buttons Background': 'rgba(49,60,54,1)',
|
|
'Buttons Border': 'rgba(136,136,136,1)',
|
|
'Navigation Background': 'rgba(63,63,63,0.9)',
|
|
'Navigation Border': 'rgba(63,63,63,0.9)',
|
|
'Links': 'rgb(239,220,188)',
|
|
'Hovered Links': 'rgb(248,248,147)',
|
|
'Navigation Links': 'rgb(220,220,204)',
|
|
'Hovered Navigation Links': 'rgb(248,248,147)',
|
|
'Subjects': 'rgb(170,170,170)',
|
|
'Names': 'rgb(192,190,209)',
|
|
'Sage': 'rgb(220,220,204)',
|
|
'Tripcodes': 'rgb(140,208,211)',
|
|
'Emails': 'rgb(239,220,188)',
|
|
'Post Numbers': 'rgb(220,220,204)',
|
|
'Text': 'rgb(220,220,204)',
|
|
'Quotelinks': 'rgb(220,163,163)',
|
|
'Backlinks': 'rgb(220,163,163)',
|
|
'Greentext': 'rgb(127,159,127)',
|
|
'Board Title': 'rgb(220,220,204)',
|
|
'Timestamps': 'rgb(220,220,204)',
|
|
'Inputs': 'rgb(220,220,204)',
|
|
'Warnings': 'rgb(239,220,188)',
|
|
'Shadow Color': 'rgba(0,0,0,.1)',
|
|
'Custom CSS': ''
|
|
},
|
|
"ピンク": {
|
|
"Author": "DrooidKun",
|
|
"Author Tripcode": "!/Apk/MRkGM",
|
|
"Background Color": "rgb(255,255,255)",
|
|
"Dialog Background": "rgba(242,242,242,.98)",
|
|
"Dialog Border": "rgb(240,240,240)",
|
|
"Thread Wrapper Background": "rgba(0,0,0,0)",
|
|
"Thread Wrapper Border": "rgba(0,0,0,0)",
|
|
"Reply Background": "rgba(242,242,242,1.0)",
|
|
"Reply Border": "rgb(240,240,240)",
|
|
"Highlighted Reply Background": "rgba(238,238,238,1.0)",
|
|
"Highlighted Reply Border": "rgb(191,122,180)",
|
|
"Backlinked Reply Outline": "rgb(191,122,180)",
|
|
"Checkbox Background": "rgba(240,240,240,1.0)",
|
|
"Checkbox Border": "rgb(222,222,222)",
|
|
"Input Background": "rgba(240,240,240,1.0)",
|
|
"Input Border": "rgb(222,222,222)",
|
|
"Hovered Input Background": "rgba(224,224,224,1.0)",
|
|
"Hovered Input Border": "rgb(222,222,222)",
|
|
"Focused Input Background": "rgba(224,224,224,1.0)",
|
|
"Focused Input Border": "rgb(222,222,222)",
|
|
"Buttons Background": "rgba(240,240,240,1.0)",
|
|
"Buttons Border": "rgb(222,222,222)",
|
|
"Navigation Background": "rgba(255,255,255,0.8)",
|
|
"Navigation Border": "rgb(242,242,242)",
|
|
"Quotelinks": "rgb(191,122,180)",
|
|
"Links": "rgb(191,122,180)",
|
|
"Hovered Links": "rgb(198,105,201)",
|
|
"Navigation Links": "rgb(77,77,76)",
|
|
"Hovered Navigation Links": "rgb(198,105,201)",
|
|
"Subjects": "rgb(77,77,77)",
|
|
"Names": "rgb(204,94,193)",
|
|
"Sage": "rgb(200,40,41)",
|
|
"Tripcodes": "rgb(198,105,201)",
|
|
"Emails": "rgb(191,122,180)",
|
|
"Post Numbers": "rgb(191,122,180)",
|
|
"Text": "rgb(77,77,76)",
|
|
"Backlinks": "rgb(191,122,180)",
|
|
"Greentext": "rgb(113,140,0)",
|
|
"Board Title": "rgb(77,77,76)",
|
|
"Timestamps": "rgb(77,77,76)",
|
|
"Inputs": "rgb(77,77,76)",
|
|
"Warnings": "rgb(200,40,41)",
|
|
"Shadow Color": "rgba(0,0,0,0.05)",
|
|
"Custom CSS": ".rice {\n box-shadow:rgba(255,255,255,.3) 0 1px;\n}\nnput[type=password]:hover,\ninput[type=text]:not([disabled]):hover,\ninput#fs_search:hover,\ninput.field:hover,\n.webkit select:hover,\ntextarea:hover,\n#appchanx-settings input:not([type=checkbox]):hover {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\ninput[type=password]:focus,\ninput[type=text]:focus,\ninput#fs_search:focus,\ninput.field:focus,\n.webkit select:focus,\ntextarea:focus,\n#appchanx-settings input:focus {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\nbutton,\ninput,\ntextarea,\n.rice {\n transition:background .2s,box-shadow .2s;\n}\n.boardTitle {\n color: #cc5ec1 !important;\n text-shadow: 1px 1px 1px #772E28 !important;\n}\n.boardSubtitle,\n.boardBanner .boardSubtitle > a {\n text-shadow: none !important;\n}"
|
|
},
|
|
"Yotsuba Purple": {
|
|
"Author": "seaweed",
|
|
"Author Tripcode": "!POMF.9waa",
|
|
"Background Image": "linear-gradient(rgba(238,221,255,1.0), rgba(248,243,254,1) 200px, rgba(248,243,254,1))",
|
|
"Background Color": "rgb(248,243,254)",
|
|
"Dialog Background": "rgba(238,221,255,.98)",
|
|
"Dialog Border": "rgb(202,183,217)",
|
|
"Thread Wrapper Background": "rgba(0,0,0,0)",
|
|
"Thread Wrapper Border": "rgba(0,0,0,0)",
|
|
"Reply Background": "rgba(238,221,255,1.0)",
|
|
"Reply Border": "rgb(202,183,217)",
|
|
"Highlighted Reply Background": "rgba(234,217,251,1.0)",
|
|
"Highlighted Reply Border": "rgb(150,37,148)",
|
|
"Backlinked Reply Outline": "rgb(150,37,148)",
|
|
"Checkbox Background": "rgba(255,255,255,1.0)",
|
|
"Checkbox Border": "rgb(202,183,217)",
|
|
"Input Background": "rgba(255,255,255,1.0)",
|
|
"Input Border": "rgb(202,183,217)",
|
|
"Hovered Input Background": "rgba(239,239,239,1.0)",
|
|
"Hovered Input Border": "rgb(202,183,217)",
|
|
"Focused Input Background": "rgba(239,239,239,1.0)",
|
|
"Focused Input Border": "rgb(202,183,217)",
|
|
"Buttons Background": "rgba(255,255,255,1.0)",
|
|
"Buttons Border": "rgb(202,183,217)",
|
|
"Navigation Background": "rgba(229, 219, 240,.9)",
|
|
"Navigation Border": "rgb(238,221,255)",
|
|
"Quotelinks": "rgb(150,37,148)",
|
|
"Links": "rgb(150,37,148)",
|
|
"Hovered Links": "rgb(178,44,170)",
|
|
"Navigation Links": "rgb(0,0,0)",
|
|
"Hovered Navigation Links": "rgb(178,44,170)",
|
|
"Subjects": "rgb(15,12,93)",
|
|
"Names": "rgb(89,17,119)",
|
|
"Sage": "rgb(153,0,0)",
|
|
"Tripcodes": "rgb(178,44,170)",
|
|
"Emails": "rgb(150,37,148)",
|
|
"Post Numbers": "rgb(150,37,148)",
|
|
"Text": "rgb(0,0,0)",
|
|
"Backlinks": "rgb(150,37,148)",
|
|
"Greentext": "rgb(120,153,34)",
|
|
"Board Title": "rgb(0,0,0)",
|
|
"Timestamps": "rgb(0,0,0)",
|
|
"Inputs": "rgb(0,0,0)",
|
|
"Warnings": "rgb(153,0,0)",
|
|
"Shadow Color": "rgba(0,0,0,.05)",
|
|
"Custom CSS": ".rice {\n box-shadow:rgba(255,253,255,.3) 0 1px;\n}\ninput[type=password]:hover,\ninput[type=text]:not([disabled]):hover,\ninput#fs_search:hover,\ninput.field:hover,\ntextarea:hover,\n#appchanx-settings input:not([type=checkbox]):hover {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\ninput[type=password]:focus,\ninput[type=text]:focus,\ninput#fs_search:focus,\ninput.field:focus,\ntextarea:focus,\n#appchanx-settings input:focus {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\nbutton,\ninput,\ntextarea,\n.rice {\n transition:background .2s,box-shadow .2s;\n}\n.boardTitle {\n color: #591177 !important;\n text-shadow: 1px 1px 1px #222 !important;\n}\n.boardSubtitle,\n.boardBanner .boardSubtitle > a {\n text-shadow: none !important;\n}\n.postNum a {\n color: #000000 !important;\n}\n.reply.post {\n border-color: transparent rgb(202,183,217) rgb(202,183,217) transparent;\n}"
|
|
},
|
|
"Vimyanized Dark": {
|
|
"Author": "seaweed",
|
|
"Author Tripcode": "!POMF.9waa",
|
|
"Background Color": "rgb(9,13,15)",
|
|
"Dialog Background": "rgba(13,17,20,.98)",
|
|
"Dialog Border": "rgb(11,19,22)",
|
|
"Thread Wrapper Background": "rgba(13,17,20,.5)",
|
|
"Thread Wrapper Border": "rgba(11,19,22,.9)",
|
|
"Reply Background": "rgba(13,17,20,.9)",
|
|
"Reply Border": "rgb(11,19,22)",
|
|
"Highlighted Reply Background": "rgba(9,13,16,.9)",
|
|
"Highlighted Reply Border": "rgb(83,189,177)",
|
|
"Backlinked Reply Outline": "rgb(83,189,177)",
|
|
"Checkbox Background": "rgba(9,13,15,.9)",
|
|
"Checkbox Border": "rgb(11,19,22)",
|
|
"Input Background": "rgba(9,13,15,.9)",
|
|
"Input Border": "rgb(11,19,22)",
|
|
"Hovered Input Background": "rgba(0,0,0,.9)",
|
|
"Hovered Input Border": "rgb(11,19,22)",
|
|
"Focused Input Background": "rgba(0,0,0,.9)",
|
|
"Focused Input Border": "rgb(11,19,22)",
|
|
"Buttons Background": "rgba(9,13,15,.9)",
|
|
"Buttons Border": "rgb(11,19,22)",
|
|
"Navigation Background": "rgba(9,13,15,0.8)",
|
|
"Navigation Border": "rgb(13,17,20)",
|
|
"Quotelinks": "rgb(83,189,177)",
|
|
"Links": "rgb(83,189,177)",
|
|
"Hovered Links": "rgb(48,144,181)",
|
|
"Navigation Links": "rgb(248,248,248)",
|
|
"Hovered Navigation Links": "rgb(48,144,181)",
|
|
"Subjects": "rgb(184,140,209)",
|
|
"Names": "rgb(214,62,52)",
|
|
"Sage": "rgb(79,79,79)",
|
|
"Tripcodes": "rgb(212,182,60)",
|
|
"Emails": "rgb(83,189,177)",
|
|
"Post Numbers": "rgb(83,189,177)",
|
|
"Text": "rgb(248,248,248)",
|
|
"Backlinks": "rgb(83,189,177)",
|
|
"Greentext": "rgb(150,200,59)",
|
|
"Board Title": "rgb(248,248,248)",
|
|
"Timestamps": "rgb(221,221,221)",
|
|
"Inputs": "rgb(248,248,248)",
|
|
"Warnings": "rgb(79,79,79)",
|
|
"Shadow Color": "rgba(0,0,0,.1)",
|
|
"Custom CSS": ".board .thread {\n padding: 1px;\n}\n.rice {\n box-shadow:rgba(45,49,52,.3) 0 1px;\n}\ninput[type=password]:hover,\ninput[type=text]:not([disabled]):hover,\ninput#fs_search:hover,\ninput.field:hover,\n.webkit select:hover,\ntextarea:hover,\n#appchanx-settings input:not([type=checkbox]):hover {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\ninput[type=password]:focus,\ninput[type=text]:focus,\ninput#fs_search:focus,\ninput.field:focus,\n.webkit select:focus,\ntextarea:focus,\n#appchanx-settings input:focus {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\nbutton,\ninput,\ntextarea,\n.rice {\n transition:background .2s,box-shadow .2s;\n}"
|
|
},
|
|
"Tomorrow Night": {
|
|
"Author": "Chris Kempson",
|
|
"Author Tripcode": "!.pC/AHOKAg",
|
|
"Background Color": "rgb(29,31,33)",
|
|
"Dialog Background": "rgba(40,42,46,.98)",
|
|
"Dialog Border": "rgb(55,59,65)",
|
|
"Thread Wrapper Background": "rgba(40,42,46,.5)",
|
|
"Thread Wrapper Border": "rgba(55,59,65,.9)",
|
|
"Reply Background": "rgba(40,42,46,.9)",
|
|
"Reply Border": "rgb(55,59,65)",
|
|
"Highlighted Reply Background": "rgba(36,38,42,.9)",
|
|
"Highlighted Reply Border": "rgb(129,162,190)",
|
|
"Backlinked Reply Outline": "rgb(129,162,190)",
|
|
"Checkbox Background": "rgba(40,42,46,.9)",
|
|
"Checkbox Border": "rgb(29,31,33)",
|
|
"Input Background": "rgba(40,42,46,.9)",
|
|
"Input Border": "rgb(29,31,33)",
|
|
"Hovered Input Background": "rgba(24,26,30,.9)",
|
|
"Hovered Input Border": "rgb(29,31,33)",
|
|
"Focused Input Background": "rgba(24,26,30,.9)",
|
|
"Focused Input Border": "rgb(29,31,33)",
|
|
"Buttons Background": "rgba(40,42,46,.9)",
|
|
"Buttons Border": "rgb(29,31,33)",
|
|
"Navigation Background": "rgba(29,31,33,0.8)",
|
|
"Navigation Border": "rgb(40,42,46)",
|
|
"Quotelinks": "rgb(129,162,190)",
|
|
"Links": "rgb(129,162,190)",
|
|
"Hovered Links": "rgb(204,102,102)",
|
|
"Navigation Links": "rgb(197,200,198)",
|
|
"Hovered Navigation Links": "rgb(204,102,102)",
|
|
"Subjects": "rgb(178,148,187)",
|
|
"Names": "rgb(129,162,190)",
|
|
"Sage": "rgb(204,102,102)",
|
|
"Tripcodes": "rgb(138,190,183)",
|
|
"Emails": "rgb(129,162,190)",
|
|
"Post Numbers": "rgb(129,162,190)",
|
|
"Text": "rgb(197,200,198)",
|
|
"Backlinks": "rgb(129,162,190)",
|
|
"Greentext": "rgb(181,189,104)",
|
|
"Board Title": "rgb(197,200,198)",
|
|
"Timestamps": "rgb(197,200,198)",
|
|
"Inputs": "rgb(197,200,198)",
|
|
"Warnings": "rgb(204,102,102)",
|
|
"Shadow Color": "rgba(0,0,0,.1)",
|
|
"Custom CSS": ".board .thread {\n padding: 1px;\n}\n.rice {\n box-shadow:rgba(72,74,78,.3) 0 1px;\n}\ninput[type=password]:hover,\ninput[type=text]:not([disabled]):hover,\ninput#fs_search:hover,\ninput.field:hover,\n.webkit select:hover,\ntextarea:hover,\n#appchanx-settings input:not([type=checkbox]):hover {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\ninput[type=password]:focus,\ninput[type=text]:focus,\ninput#fs_search:focus,\ninput.field:focus,\n.webkit select:focus,\ntextarea:focus,\n#appchanx-settings input:focus {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\nbutton,\ninput,\ntextarea,\n.rice {\n transition:background .2s,box-shadow .2s;\n}"
|
|
},
|
|
"Solarized Light": {
|
|
"Author": "seaweed",
|
|
"Author Tripcode": "!POMF.9waa",
|
|
"Background Color": "rgb(240,240,240)",
|
|
"Dialog Background": "rgba(253,246,227,.98)",
|
|
"Dialog Border": "rgb(230,223,206)",
|
|
"Thread Wrapper Background": "rgba(0,0,0,0)",
|
|
"Thread Wrapper Border": "rgba(0,0,0,0)",
|
|
"Reply Background": "rgba(253,246,227,1.0)",
|
|
"Reply Border": "rgb(230,223,206)",
|
|
"Highlighted Reply Background": "rgba(249,242,223,1.0)",
|
|
"Highlighted Reply Border": "rgb(108,113,196)",
|
|
"Backlinked Reply Outline": "rgb(108,113,196)",
|
|
"Checkbox Background": "rgba(255,255,255,1.0)",
|
|
"Checkbox Border": "rgb(204,204,204)",
|
|
"Input Background": "rgba(255,255,255,1.0)",
|
|
"Input Border": "rgb(204,204,204)",
|
|
"Hovered Input Background": "rgba(239,239,239,1.0)",
|
|
"Hovered Input Border": "rgb(204,204,204)",
|
|
"Focused Input Background": "rgba(239,239,239,1.0)",
|
|
"Focused Input Border": "rgb(204,204,204)",
|
|
"Buttons Background": "rgba(255,255,255,1.0)",
|
|
"Buttons Border": "rgb(204,204,204)",
|
|
"Navigation Background": "rgba(240,240,240,0.8)",
|
|
"Navigation Border": "rgb(253,246,227)",
|
|
"Quotelinks": "rgb(108,113,196)",
|
|
"Links": "rgb(108,113,196)",
|
|
"Hovered Links": "rgb(211,54,130)",
|
|
"Navigation Links": "rgb(101,123,131)",
|
|
"Hovered Navigation Links": "rgb(211,54,130)",
|
|
"Subjects": "rgb(181,137,0)",
|
|
"Names": "rgb(101,123,131)",
|
|
"Sage": "rgb(153,0,0)",
|
|
"Tripcodes": "rgb(42,161,152)",
|
|
"Emails": "rgb(108,113,196)",
|
|
"Post Numbers": "rgb(108,113,196)",
|
|
"Text": "rgb(101,123,131)",
|
|
"Backlinks": "rgb(108,113,196)",
|
|
"Greentext": "rgb(133,153,0)",
|
|
"Board Title": "rgb(101,123,131)",
|
|
"Timestamps": "rgb(101,123,131)",
|
|
"Inputs": "rgb(101,123,131)",
|
|
"Warnings": "rgb(153,0,0)",
|
|
"Shadow Color": "rgba(0,0,0,.05)",
|
|
"Custom CSS": ".rice {\n box-shadow:rgba(255,255,255,.3) 0 1px;\n}\ninput[type=password]:hover,\ninput[type=text]:not([disabled]):hover,\ninput#fs_search:hover,\ninput.field:hover,\n.webkit select:hover,\ntextarea:hover,\n#appchanx-settings input:not([type=checkbox]):hover {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\ninput[type=password]:focus,\ninput[type=text]:focus,\ninput#fs_search:focus,\ninput.field:focus,\n.webkit select:focus,\ntextarea:focus,\n#appchanx-settings input:focus {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\nbutton,\ninput,\ntextarea,\n.rice {\n transition:background .2s,box-shadow .2s;\n}\n.boardTitle {\n color: #b58900 !important;\n text-shadow: 1px 1px 1px #999 !important;\n}\n.boardSubtitle,\n.boardBanner .boardSubtitle > a {\n text-shadow: none !important;\n}\n.postNum a {\n color: #657b83 !important;\n}"
|
|
},
|
|
"Muted": {
|
|
"Author": "seaweed",
|
|
"Author Tripcode": "!POMF.9waa",
|
|
"Background Color": "rgb(255,255,255)",
|
|
"Dialog Background": "rgba(245,242,233,.98)",
|
|
"Dialog Border": "rgb(204,204,204)",
|
|
"Thread Wrapper Background": "rgba(245,242,233,.5)",
|
|
"Thread Wrapper Border": "rgba(204,204,204,.9)",
|
|
"Reply Background": "rgba(245,242,233,.9)",
|
|
"Reply Border": "rgb(204,204,204)",
|
|
"Highlighted Reply Background": "rgba(241,238,229,.9)",
|
|
"Highlighted Reply Border": "rgb(188,49,42)",
|
|
"Backlinked Reply Outline": "rgb(188,49,42)",
|
|
"Checkbox Background": "rgba(255,255,255,.9)",
|
|
"Checkbox Border": "rgb(204,204,204)",
|
|
"Input Background": "rgba(255,255,255,.9)",
|
|
"Input Border": "rgb(204,204,204)",
|
|
"Hovered Input Background": "rgba(239,239,239,.9)",
|
|
"Hovered Input Border": "rgb(204,204,204)",
|
|
"Focused Input Background": "rgba(239,239,239,.9)",
|
|
"Focused Input Border": "rgb(204,204,204)",
|
|
"Buttons Background": "rgba(255,255,255,.9)",
|
|
"Buttons Border": "rgb(204,204,204)",
|
|
"Navigation Background": "rgba(255,255,255,0.8)",
|
|
"Navigation Border": "rgb(245,242,233)",
|
|
"Quotelinks": "rgb(188,49,42)",
|
|
"Links": "rgb(188,49,42)",
|
|
"Hovered Links": "rgb(142,34,32)",
|
|
"Navigation Links": "rgb(57,55,53)",
|
|
"Hovered Navigation Links": "rgb(142,34,32)",
|
|
"Subjects": "rgb(17,17,17)",
|
|
"Names": "rgb(44,100,160)",
|
|
"Sage": "rgb(153,0,0)",
|
|
"Tripcodes": "rgb(204,101,99)",
|
|
"Emails": "rgb(188,49,42)",
|
|
"Post Numbers": "rgb(188,49,42)",
|
|
"Text": "rgb(57,55,53)",
|
|
"Backlinks": "rgb(188,49,42)",
|
|
"Greentext": "rgb(120,153,34)",
|
|
"Board Title": "rgb(57,55,53)",
|
|
"Timestamps": "rgb(51,51,51)",
|
|
"Inputs": "rgb(57,55,53)",
|
|
"Warnings": "rgb(153,0,0)",
|
|
"Shadow Color": "rgba(0,0,0,.05)",
|
|
"Custom CSS": ".board .thread {\n padding: 1px;\n}\n.rice {\n box-shadow:rgba(255,255,255,.3) 0 1px;\n}\ninput[type=password]:hover,\ninput[type=text]:not([disabled]):hover,\ninput#fs_search:hover,\ninput.field:hover,\n.webkit select:hover,\ntextarea:hover,\n#appchanx-settings input:not([type=checkbox]):hover {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\ninput[type=password]:focus,\ninput[type=text]:focus,\ninput#fs_search:focus,\ninput.field:focus,\n.webkit select:focus,\ntextarea:focus,\n#appchanx-settings input:focus {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\nbutton,\ninput,\ntextarea,\n.rice {\n transition:background .2s,box-shadow .2s;\n}\n.boardTitle{\ncolor:#bc312a!important;\n text-shadow:1px 1px 1px #772e28 !important;\n}\n.boardSubtitle,\n.boardBanner .boardSubtitle > a {\n text-shadow:none!important;\n}\n.postNum a {\n color:#111111!important;\n}\ndiv.reply a.quotelink{\n color:#bc312a!important;\n}"
|
|
},
|
|
"Monokai": {
|
|
"Author": "seaweed",
|
|
"Author Tripcode": "!POMF.9waa",
|
|
"Background Color": "rgb(32,33,28)",
|
|
"Dialog Background": "rgba(39,40,34,.98)",
|
|
"Dialog Border": "rgb(45,46,39)",
|
|
"Thread Wrapper Background": "rgba(0,0,0,0)",
|
|
"Thread Wrapper Border": "rgba(0,0,0,0)",
|
|
"Reply Background": "rgba(39,40,34,1.0)",
|
|
"Reply Border": "rgb(45,46,39)",
|
|
"Highlighted Reply Background": "rgba(35,36,30,1.0)",
|
|
"Highlighted Reply Border": "rgb(226,219,116)",
|
|
"Backlinked Reply Outline": "rgb(226,219,116)",
|
|
"Checkbox Background": "rgba(32,33,28,1.0)",
|
|
"Checkbox Border": "rgb(23,23,19)",
|
|
"Input Background": "rgba(32,33,28,1.0)",
|
|
"Input Border": "rgb(23,23,19)",
|
|
"Hovered Input Background": "rgba(16,17,12,1.0)",
|
|
"Hovered Input Border": "rgb(23,23,19)",
|
|
"Focused Input Background": "rgba(16,17,12,1.0)",
|
|
"Focused Input Border": "rgb(23,23,19)",
|
|
"Buttons Background": "rgba(32,33,28,1.0)",
|
|
"Buttons Border": "rgb(23,23,19)",
|
|
"Navigation Background": "rgba(32,33,28,0.8)",
|
|
"Navigation Border": "rgb(39,40,34)",
|
|
"Quotelinks": "rgb(226,219,116)",
|
|
"Links": "rgb(226,219,116)",
|
|
"Hovered Links": "rgb(174,129,255)",
|
|
"Navigation Links": "rgb(248,248,242)",
|
|
"Hovered Navigation Links": "rgb(174,129,255)",
|
|
"Subjects": "rgb(174,129,255)",
|
|
"Names": "rgb(90,192,204)",
|
|
"Sage": "rgb(79,79,79)",
|
|
"Tripcodes": "rgb(250,130,32)",
|
|
"Emails": "rgb(226,219,116)",
|
|
"Post Numbers": "rgb(226,219,116)",
|
|
"Text": "rgb(248,248,242)",
|
|
"Backlinks": "rgb(226,219,116)",
|
|
"Greentext": "rgb(162,204,40)",
|
|
"Board Title": "rgb(248,248,242)",
|
|
"Timestamps": "rgb(248,248,242)",
|
|
"Inputs": "rgb(248,248,242)",
|
|
"Warnings": "rgb(79,79,79)",
|
|
"Shadow Color": "rgba(0,0,0,.12)",
|
|
"Custom CSS": ".rice {\n box-shadow:rgba(71,72,66,.3) 0 1px;\n}\ninput[type=password]:hover,\ninput[type=text]:not([disabled]):hover,\ninput#fs_search:hover,\ninput.field:hover,\n.webkit select:hover,\ntextarea:hover,\n#appchanx-settings input:not([type=checkbox]):hover {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\ninput[type=password]:focus,\ninput[type=text]:focus,\ninput#fs_search:focus,\ninput.field:focus,\n.webkit select:focus,\ntextarea:focus,\n#appchanx-settings input:focus {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\nbutton,\ninput,\ntextarea,\n.rice {\n transition:background .2s,box-shadow .2s;\n}"
|
|
},
|
|
"Dark Flat": {
|
|
"Author": "Ahoka",
|
|
"Author Tripcode": "!.pC/AHOKAg",
|
|
"Background Image": "url(\"data:image/gif;base64,R0lGODlhAwADAIAAAB0dHRkZGSH5BADoAwAALAAAAAADAAMAAAIDDG5YADs=\")",
|
|
"Background Attachment": "fixed",
|
|
"Background Position": "top left",
|
|
"Background Repeat": "repeat",
|
|
"Background Color": "rgb(32,32,32)",
|
|
"Dialog Background": "rgba(35,36,37,.98)",
|
|
"Dialog Border": "rgb(41,42,43)",
|
|
"Thread Wrapper Background": "rgba(35,36,37,.5)",
|
|
"Thread Wrapper Border": "rgba(41,42,43,.9)",
|
|
"Reply Background": "rgba(35,36,37,.9)",
|
|
"Reply Border": "rgba(35,36,37,.9)",
|
|
"Highlighted Reply Background": "rgba(31,32,33,.9)",
|
|
"Highlighted Reply Border": "rgb(172,155,176)",
|
|
"Backlinked Reply Outline": "rgb(172,155,176)",
|
|
"Checkbox Background": "rgba(24,25,26,.9)",
|
|
"Checkbox Border": "rgb(18,19,20)",
|
|
"Input Background": "rgba(24,25,26,.9)",
|
|
"Input Border": "rgb(18,19,20)",
|
|
"Hovered Input Background": "rgba(8,9,10,.9)",
|
|
"Hovered Input Border": "rgb(18,19,20)",
|
|
"Focused Input Background": "rgba(8,9,10,.9)",
|
|
"Focused Input Border": "rgb(18,19,20)",
|
|
"Buttons Background": "rgba(24,25,26,.9)",
|
|
"Buttons Border": "rgb(18,19,20)",
|
|
"Navigation Background": "rgba(32,32,32,0.8)",
|
|
"Navigation Border": "rgb(35,36,37)",
|
|
"Quotelinks": "rgb(172,155,176)",
|
|
"Links": "rgb(172,155,176)",
|
|
"Hovered Links": "rgb(111,153,180)",
|
|
"Navigation Links": "rgb(221,221,221)",
|
|
"Hovered Navigation Links": "rgb(111,153,180)",
|
|
"Subjects": "rgb(147,144,201)",
|
|
"Names": "rgb(168,198,217)",
|
|
"Sage": "rgb(201,144,144)",
|
|
"Tripcodes": "rgb(212,192,149)",
|
|
"Emails": "rgb(172,155,176)",
|
|
"Post Numbers": "rgb(172,155,176)",
|
|
"Text": "rgb(221,221,221)",
|
|
"Backlinks": "rgb(172,155,176)",
|
|
"Greentext": "rgb(179,196,94)",
|
|
"Board Title": "rgb(221,221,221)",
|
|
"Timestamps": "rgb(221,221,221)",
|
|
"Inputs": "rgb(221,221,221)",
|
|
"Warnings": "rgb(201,144,144)",
|
|
"Shadow Color": "rgba(0,0,0,.1)",
|
|
"Custom CSS": ".board .thread {\n padding: 1px;\n}\n.rice {\n box-shadow:rgba(67,68,69,.3) 0 1px;\n}\ninput[type=password]:hover,\ninput[type=text]:not([disabled]):hover,\ninput#fs_search:hover,\ninput.field:hover,\n.webkit select:hover,\ntextarea:hover,\n#appchanx-settings input:not([type=checkbox]):hover {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\ninput[type=password]:focus,\ninput[type=text]:focus,\ninput#fs_search:focus,\ninput.field:focus,\n.webkit select:focus,\ntextarea:focus,\n#appchanx-settings input:focus {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\nbutton,\ninput,\ntextarea,\n.rice {\n transition:background .2s,box-shadow .2s;\n}"
|
|
},
|
|
"Blackboard": {
|
|
"Author": "seaweed",
|
|
"Author Tripcode": "!POMF.9waa",
|
|
"Background Color": "rgb(10,13,28)",
|
|
"Dialog Background": "rgba(12,16,33,.98)",
|
|
"Dialog Border": "rgb(14,18,40)",
|
|
"Thread Wrapper Background": "rgba(0,0,0,0)",
|
|
"Thread Wrapper Border": "rgba(0,0,0,0)",
|
|
"Reply Background": "rgba(12,16,33,1.0)",
|
|
"Reply Border": "rgb(14,18,40)",
|
|
"Highlighted Reply Background": "rgba(8,12,29,1.0)",
|
|
"Highlighted Reply Border": "rgb(251,222,45)",
|
|
"Backlinked Reply Outline": "rgb(251,222,45)",
|
|
"Checkbox Background": "rgba(12,16,33,1.0)",
|
|
"Checkbox Border": "rgb(8,11,22)",
|
|
"Input Background": "rgba(12,16,33,1.0)",
|
|
"Input Border": "rgb(8,11,22)",
|
|
"Hovered Input Background": "rgba(0,0,17,1.0)",
|
|
"Hovered Input Border": "rgb(8,11,22)",
|
|
"Focused Input Background": "rgba(0,0,17,1.0)",
|
|
"Focused Input Border": "rgb(8,11,22)",
|
|
"Buttons Background": "rgba(12,16,33,1.0)",
|
|
"Buttons Border": "rgb(8,11,22)",
|
|
"Navigation Background": "rgba(10,13,28,0.8)",
|
|
"Navigation Border": "rgb(12,16,33)",
|
|
"Quotelinks": "rgb(251,222,45)",
|
|
"Links": "rgb(251,222,45)",
|
|
"Hovered Links": "rgb(75,101,204)",
|
|
"Navigation Links": "rgb(248,248,248)",
|
|
"Hovered Navigation Links": "rgb(75,101,204)",
|
|
"Subjects": "rgb(255,100,0)",
|
|
"Names": "rgb(141,166,206)",
|
|
"Sage": "rgb(79,79,79)",
|
|
"Tripcodes": "rgb(255,100,0)",
|
|
"Emails": "rgb(251,222,45)",
|
|
"Post Numbers": "rgb(251,222,45)",
|
|
"Text": "rgb(248,248,248)",
|
|
"Backlinks": "rgb(251,222,45)",
|
|
"Greentext": "rgb(154,207,8)",
|
|
"Board Title": "rgb(248,248,248)",
|
|
"Timestamps": "rgb(221,221,221)",
|
|
"Inputs": "rgb(248,248,248)",
|
|
"Warnings": "rgb(79,79,79)",
|
|
"Shadow Color": "rgba(0,0,0,.1)",
|
|
"Custom CSS": ".rice {\n box-shadow:rgba(44,48,65,.3) 0 1px;\n}\ninput[type=password]:hover,\ninput[type=text]:not([disabled]):hover,\ninput#fs_search:hover,\ninput.field:hover,\n.webkit select:hover,\ntextarea:hover,\n#appchanx-settings input:not([type=checkbox]):hover {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\ninput[type=password]:focus,\ninput[type=text]:focus,\ninput#fs_search:focus,\ninput.field:focus,\n.webkit select:focus,\ntextarea:focus,\n#appchanx-settings input:focus {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\nbutton,\ninput,\ntextarea,\n.rice {\n transition:background .2s,box-shadow .2s;\n}\n.postInfo {\n box-shadow: 0px 2px 3px #0A0A0A;\n}\n#qp .postInfo,\n.inline .postInfo {\n box-shadow: none;\n}"
|
|
},
|
|
"4chan Rewired": {
|
|
"Author": "",
|
|
"Author Tripcode": "!K.WeEabo0o",
|
|
"Background Color": "rgb(244,244,244)",
|
|
"Dialog Background": "rgba(239,239,239,.98)",
|
|
"Dialog Border": "rgb(212,212,212)",
|
|
"Thread Wrapper Background": "rgba(0,0,0,0)",
|
|
"Thread Wrapper Border": "rgba(0,0,0,0)",
|
|
"Reply Background": "linear-gradient(rgba(244,244,244,0.9), rgba(239,239,239,0.9)), rgba(239,239,239,1)",
|
|
"Reply Border": "rgb(212,212,212)",
|
|
"Highlighted Reply Background": "linear-gradient(rgba(250,250,250,.9), rgba(230,230,230,0.9))",
|
|
"Highlighted Reply Border": "rgb(191,127,63)",
|
|
"Backlinked Reply Outline": "rgba(191,127,63,0.5)",
|
|
"Checkbox Background": "rgba(228,228,228,.9)",
|
|
"Checkbox Border": "rgb(204,204,204)",
|
|
"Input Background": "rgba(244,244,244,0.9)",
|
|
"Input Border": "rgb(204,204,204)",
|
|
"Hovered Input Background": "rgba(212,212,212,.9)",
|
|
"Hovered Input Border": "rgb(204,204,204)",
|
|
"Focused Input Background": "rgba(212,212,212,.9)",
|
|
"Focused Input Border": "rgb(204,204,204)",
|
|
"Buttons Background": "rgba(244,244,244,0.9)",
|
|
"Buttons Border": "rgb(204,204,204)",
|
|
"Navigation Background": "rgba(244,244,244,0.8)",
|
|
"Navigation Border": "rgb(239,239,239)",
|
|
"Quotelinks": "rgb(191,127,63)",
|
|
"Links": "rgb(191,127,63)",
|
|
"Hovered Links": "rgb(191,127,63)",
|
|
"Navigation Links": "rgba(0,0,0,.7)",
|
|
"Hovered Navigation Links": "rgb(211,54,130)",
|
|
"Subjects": "rgba(0,0,0,.7)",
|
|
"Names": "rgba(0,0,0,.7)",
|
|
"Sage": "rgb(204,102,102)",
|
|
"Tripcodes": "rgb(191,127,63)",
|
|
"Emails": "rgb(191,127,63)",
|
|
"Post Numbers": "rgb(191,127,63)",
|
|
"Text": "rgba(0,0,0,.7)",
|
|
"Backlinks": "rgb(191,127,63)",
|
|
"Greentext": "rgb(107,122,30)",
|
|
"Board Title": "rgba(0,0,0,.7)",
|
|
"Timestamps": "rgba(0,0,0,.7)",
|
|
"Inputs": "rgba(0,0,0,.7)",
|
|
"Warnings": "rgb(204,102,102)",
|
|
"Shadow Color": "rgba(0,0,0,.07)",
|
|
"Custom CSS": ".rice {\n box-shadow:rgba(255,255,255,.3) 0 1px;\n}\ninput[type=password]:hover,\ninput[type=text]:not([disabled]):hover,\ninput#fs_search:hover,\ninput.field:hover,\n.webkit select:hover,\ntextarea:hover,\n#appchanx-settings input:not([type=checkbox]):hover {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\n.reply.post,\n.op.post {\n background-color: transparent !important;\n}\ninput[type=password]:focus,\ninput[type=text]:focus,\ninput#fs_search:focus,\ninput.field:focus,\n.webkit select:focus,\ntextarea:focus,\n#appchanx-settings input:focus {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\na {\n -moz-transition: text-shadow .2s;\n -o-transition: text-shadow .2s;\n -webkit-transition: text-shadow .2s;\n}\na:hover {\n text-shadow: 0 0 3px rgba(232,118,0,.7);\n}\nbutton,\ninput,\ntextarea,\n.rice {\n transition:\n background .2s,\n box-shadow .2s;\n}\n.subject:not(:empty)::after {\n content: \" by\";\n font-weight: normal;\n}"
|
|
},
|
|
"4chan Dark Upgrade": {
|
|
"Author": "Ahoka",
|
|
"Author Tripcode": "!.pC/AHOKAg",
|
|
"Background Image": "url(\"http://i.minus.com/iNkJoDJkLU0co.png\")",
|
|
"Background Attachment": "fixed",
|
|
"Background Position": "top left",
|
|
"Background Repeat": "repeat",
|
|
"Background Color": "rgb(36,36,36)",
|
|
"Dialog Background": "rgba(51,51,51,.98)",
|
|
"Dialog Border": "rgb(58,58,58)",
|
|
"Thread Wrapper Background": "rgba(51,51,51,.5)",
|
|
"Thread Wrapper Border": "rgba(58,58,58,.9)",
|
|
"Reply Background": "rgba(51,51,51,.9)",
|
|
"Reply Border": "rgb(58,58,58)",
|
|
"Highlighted Reply Background": "rgba(47,47,47,.9)",
|
|
"Highlighted Reply Border": "rgb(221,221,221)",
|
|
"Backlinked Reply Outline": "rgb(221,221,221)",
|
|
"Checkbox Background": "rgba(47,47,47,.9)",
|
|
"Checkbox Border": "rgb(15,15,15)",
|
|
"Input Background": "rgba(47,47,47,.9)",
|
|
"Input Border": "rgb(15,15,15)",
|
|
"Hovered Input Background": "rgba(31,31,31,.9)",
|
|
"Hovered Input Border": "rgb(15,15,15)",
|
|
"Focused Input Background": "rgba(31,31,31,.9)",
|
|
"Focused Input Border": "rgb(15,15,15)",
|
|
"Buttons Background": "rgba(47,47,47,.9)",
|
|
"Buttons Border": "rgb(15,15,15)",
|
|
"Navigation Background": "rgba(36,36,36,0.8)",
|
|
"Navigation Border": "rgb(51,51,51)",
|
|
"Quotelinks": "rgb(221,221,221)",
|
|
"Links": "rgb(221,221,221)",
|
|
"Hovered Links": "rgb(238,238,238)",
|
|
"Navigation Links": "rgb(255,255,255)",
|
|
"Hovered Navigation Links": "rgb(238,238,238)",
|
|
"Subjects": "rgb(153,153,153)",
|
|
"Names": "rgb(255,255,255)",
|
|
"Sage": "rgb(177,115,133)",
|
|
"Tripcodes": "rgb(167,220,231)",
|
|
"Emails": "rgb(221,221,221)",
|
|
"Post Numbers": "rgb(221,221,221)",
|
|
"Text": "rgb(255,255,255)",
|
|
"Backlinks": "rgb(221,221,221)",
|
|
"Greentext": "rgb(99,153,91)",
|
|
"Board Title": "rgb(255,255,255)",
|
|
"Timestamps": "rgb(170,170,170)",
|
|
"Inputs": "rgb(255,255,255)",
|
|
"Warnings": "rgb(177,115,133)",
|
|
"Shadow Color": "rgba(0,0,0,0.2)",
|
|
"Custom CSS": ".board .thread {\n padding: 3px 4px;\n}\n.rice {\n box-shadow:rgba(83,83,83,.3) 0 1px;\n}\ninput[type=password]:hover,\ninput[type=text]:not([disabled]):hover,\ninput#fs_search:hover,\ninput.field:hover,\n.webkit select:hover,\ntextarea:hover,\n#appchanx-settings input:not([type=checkbox]):hover {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\ninput[type=password]:focus,\ninput[type=text]:focus,\ninput#fs_search:focus,\ninput.field:focus,\n.webkit select:focus,\ntextarea:focus,\n#appchanx-settings input:focus {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\nbutton,\ninput,\ntextarea,\n.rice {\n transition:background .2s,box-shadow .2s;\n}\n#delform {\n background: rgba(22,22,22,.8) !important;\n border: 0 !important;\n padding: 1px !important;\n box-shadow: rgba(0,0,0,.8) 0 0 10px;\n}\ndiv.reply.post {\n background-image: url('data:image/gif;base64,R0lGODdhCQAJAIgAADMzMysrKywAAAAACQAJAAACDwxgeMrZF5Jckz1UXaYQFgA7');\n border-bottom: #1f1f1f !important;\n}\n.board .thread:not(.stub) {\n background: 0 !important\n}\na:not([href='javascript:;']){\n text-shadow: #0f0f0f 0 1px;\n}"
|
|
},
|
|
"安心院なじみ ": {
|
|
"Author": "Ahoka",
|
|
"Author Tripcode": "!.pC/AHOKAg",
|
|
"Background Image": "url(\"http://i.imgur.com/RewHm.png\")",
|
|
"Background Attachment": "fixed",
|
|
"Background Position": "bottom right",
|
|
"Background Repeat": "no-repeat",
|
|
"Background Color": "rgb(255,255,255)",
|
|
"Dialog Background": "rgba(239,239,239,.98)",
|
|
"Dialog Border": "rgb(214,214,214)",
|
|
"Thread Wrapper Background": "rgba(239,239,239,.4)",
|
|
"Thread Wrapper Border": "rgba(214,214,214,.9)",
|
|
"Reply Background": "rgba(239,239,239,.9)",
|
|
"Reply Border": "rgb(214,214,214)",
|
|
"Highlighted Reply Background": "rgba(235,235,235,.9)",
|
|
"Highlighted Reply Border": "rgb(191,128,64)",
|
|
"Backlinked Reply Outline": "rgb(191,128,64)",
|
|
"Checkbox Background": "rgba(204,204,204,.9)",
|
|
"Checkbox Border": "rgb(187,187,187)",
|
|
"Input Background": "rgba(204,204,204,.9)",
|
|
"Input Border": "rgb(187,187,187)",
|
|
"Hovered Input Background": "rgba(188,188,188,.9)",
|
|
"Hovered Input Border": "rgb(187,187,187)",
|
|
"Focused Input Background": "rgba(188,188,188,.9)",
|
|
"Focused Input Border": "rgb(187,187,187)",
|
|
"Buttons Background": "rgba(204,204,204,.9)",
|
|
"Buttons Border": "rgb(187,187,187)",
|
|
"Navigation Background": "rgba(255,255,255,0.8)",
|
|
"Navigation Border": "rgb(239,239,239)",
|
|
"Quotelinks": "rgb(191,128,64)",
|
|
"Links": "rgb(191,128,64)",
|
|
"Hovered Links": "rgb(191,128,64)",
|
|
"Navigation Links": "rgb(77,77,76)",
|
|
"Hovered Navigation Links": "rgb(191,128,64)",
|
|
"Subjects": "rgb(77,77,77)",
|
|
"Names": "rgb(43,128,194)",
|
|
"Sage": "rgb(200,40,41)",
|
|
"Tripcodes": "rgb(62,153,159)",
|
|
"Emails": "rgb(191,128,64)",
|
|
"Post Numbers": "rgb(191,128,64)",
|
|
"Text": "rgb(77,77,76)",
|
|
"Backlinks": "rgb(191,128,64)",
|
|
"Greentext": "rgb(113,140,0)",
|
|
"Board Title": "rgb(77,77,76)",
|
|
"Timestamps": "rgb(77,77,76)",
|
|
"Inputs": "rgb(77,77,76)",
|
|
"Warnings": "rgb(200,40,41)",
|
|
"Shadow Color": "rgba(0,0,0,.05)",
|
|
"Custom CSS": ".board .thread {\n padding: 1px;\n}\n.rice {\n box-shadow:rgba(255,255,255,.3) 0 1px;\n}\ninput[type=password]:hover,\ninput[type=text]:not([disabled]):hover,\ninput#fs_search:hover,\ninput.field:hover,\n.webkit select:hover,\ntextarea:hover,\n#appchanx-settings input:not([type=checkbox]):hover {\n box-shadow: inset rgba(0,0,0,.2) 0 1px 2px;\n}\ninput[type=password]:focus,\ninput[type=text]:focus,\ninput#fs_search:focus,\ninput.field:focus,\n.webkit select:focus,\ntextarea:focus,\n#appchanx-settings input:focus {\n box-shadow: inset rgba(0,0,0,.2) 0 1px 2px;\n}\nbutton,\ninput,\ntextarea,\n.rice {\n transition: background .2s,box-shadow .2s;\n}"
|
|
},
|
|
"violaceous": {
|
|
"Author": "Anonymous",
|
|
"Author Tripcode": "!MaSoOdDwDw",
|
|
"Background Color": "rgb(18,19,20)",
|
|
"Dialog Background": "rgba(27,27,27,.98)",
|
|
"Dialog Border": "rgb(41,42,43)",
|
|
"Thread Wrapper Background": "rgba(27,27,27,.5)",
|
|
"Thread Wrapper Border": "rgba(41,42,43,.9)",
|
|
"Reply Background": "rgba(27,27,27,.9)",
|
|
"Reply Border": "rgba(27,27,27,.9)",
|
|
"Highlighted Reply Background": "rgba(31,31,31,.9)",
|
|
"Highlighted Reply Border": "rgb(42,127,160)",
|
|
"Backlinked Reply Outline": "rgb(42,127,160)",
|
|
"Checkbox Background": "rgba(24,25,26,.9)",
|
|
"Checkbox Border": "rgb(18,19,20)",
|
|
"Input Background": "rgba(24,25,26,.9)",
|
|
"Input Border": "rgb(18,19,20)",
|
|
"Hovered Input Background": "rgba(40,41,42,.9)",
|
|
"Hovered Input Border": "rgb(18,19,20)",
|
|
"Focused Input Background": "rgba(40,41,42,.9)",
|
|
"Focused Input Border": "rgb(18,19,20)",
|
|
"Buttons Background": "rgba(24,25,26,.9)",
|
|
"Buttons Border": "rgb(18,19,20)",
|
|
"Navigation Background": "rgba(18,19,20,0.8)",
|
|
"Navigation Border": "rgb(27,27,27)",
|
|
"Quotelinks": "rgb(42,127,160)",
|
|
"Links": "rgb(42,127,160)",
|
|
"Hovered Links": "rgb(48,144,181)",
|
|
"Navigation Links": "rgb(221,221,221)",
|
|
"Hovered Navigation Links": "rgb(48,144,181)",
|
|
"Subjects": "rgb(6,152,154)",
|
|
"Names": "rgb(164,151,176)",
|
|
"Sage": "rgb(79,79,79)",
|
|
"Tripcodes": "rgb(189,43,131)",
|
|
"Emails": "rgb(42,127,160)",
|
|
"Post Numbers": "rgb(42,127,160)",
|
|
"Text": "rgb(221,221,221)",
|
|
"Backlinks": "rgb(42,127,160)",
|
|
"Greentext": "rgb(0,171,63)",
|
|
"Board Title": "rgb(221,221,221)",
|
|
"Timestamps": "rgb(221,221,221)",
|
|
"Inputs": "rgb(221,221,221)",
|
|
"Warnings": "rgb(79,79,79)",
|
|
"Shadow Color": "rgba(0,0,0,.1)",
|
|
"Custom CSS": ".board .thread {\n padding: 1px;\n}\n.rice {\n box-shadow:rgba(59,59,59,.3) 0 1px;\n}\ninput[type=password]:hover,\ninput[type=text]:not([disabled]):hover,\ninput#fs_search:hover,\ninput.field:hover,\n.webkit select:hover,\ntextarea:hover,\n#appchanx-settings input:not([type=checkbox]):hover {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\ninput[type=password]:focus,\ninput[type=text]:focus,\ninput#fs_search:focus,\ninput.field:focus,\n.webkit select:focus,\ntextarea:focus,\n#appchanx-settings input:focus {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\nbutton,\ninput,\ntextarea,\n.rice {\n transition:background .2s,box-shadow .2s;\n}"
|
|
},
|
|
"Mesa": {
|
|
"Author": "Tristan",
|
|
"Author Tripcode": "!..NoTrip..",
|
|
"Background Color": "#3c212a",
|
|
"Thread Wrapper Background": "rgba(0,0,0,0)",
|
|
"Thread Wrapper Border": "rgba(0,0,0,0)",
|
|
"Dialog Background": "#3c212a",
|
|
"Dialog Border": "#171717",
|
|
"Reply Background": "#3c212a",
|
|
"Reply Border": "#171717",
|
|
"Highlighted Reply Background": "#3c212a",
|
|
"Highlighted Reply Border": "#bfa977",
|
|
"Backlinked Reply Outline": "#bfa977",
|
|
"Input Background": "#3c212a",
|
|
"Input Border": "#171717",
|
|
"Checkbox Background": "#3c212a",
|
|
"Checkbox Border": "#171717",
|
|
"Buttons Background": "#3c212a",
|
|
"Buttons Border": "#171717",
|
|
"Focused Input Background": "#3c212a",
|
|
"Focused Input Border": "#171717",
|
|
"Hovered Input Background": "#3c212a",
|
|
"Hovered Input Border": "#171717",
|
|
"Navigation Background": "#3c212a",
|
|
"Navigation Border": "#171717",
|
|
"Quotelinks": "#bfa977",
|
|
"Backlinks": "#bfa977",
|
|
"Links": "#bfa977",
|
|
"Hovered Links": "#aa4775",
|
|
"Navigation Links": "#bfa977",
|
|
"Hovered Navigation Links": "#aa4775",
|
|
"Names": "#bfa977",
|
|
"Tripcodes": "#aa6d89",
|
|
"Emails": "#9c8aaa",
|
|
"Subjects": "#bfa977",
|
|
"Text": "#BFA977",
|
|
"Inputs": "#bfa977",
|
|
"Post Numbers": "#bfa977",
|
|
"Greentext": "#99848b",
|
|
"Sage": "rgb(150,150,150)",
|
|
"Board Title": "#aa9d8d",
|
|
"Timestamps": "#aa9d8d",
|
|
"Warnings": "#aa8575",
|
|
"Shadow Color": "rgba(0,0,0,.1)",
|
|
"Custom CSS": "",
|
|
"Background Image": "",
|
|
"Background Attachment": "",
|
|
"Background Position": "",
|
|
"Background Repeat": ""
|
|
},
|
|
"White Rainbow": {
|
|
"Author": "Shiro",
|
|
"Author Tripcode": "!i.Neko0OEM",
|
|
"Background Image": "url('http://subtlepatterns.com/patterns/paper_fibers.png')",
|
|
"Background Attachment": "fixed",
|
|
"Background Position": "top left",
|
|
"Background Repeat": "repeat",
|
|
"Background Color": "rgb(255,255,255)",
|
|
"Dialog Background": "rgba(239,239,239,.98)",
|
|
"Dialog Border": "rgb(214,214,214)",
|
|
"Thread Wrapper Background": "rgba(239,239,239,.98)",
|
|
"Thread Wrapper Border": "rgba(214,214,214,.4)",
|
|
"Reply Background": "rgba(255,255,255,.90)",
|
|
"Reply Border": "rgb(214,214,214)",
|
|
"Highlighted Reply Background": "rgba(239,239,239,.90)",
|
|
"Highlighted Reply Border": "#b84818",
|
|
"Backlinked Reply Outline": "#b84818",
|
|
"Checkbox Background": "rgba(239,239,239,.98)",
|
|
"Checkbox Border": "rgb(187,187,187)",
|
|
"Input Background": "#fffffff",
|
|
"Input Border": "rgb(187,187,187)",
|
|
"Hovered Input Background": "#f0f0f0",
|
|
"Hovered Input Border": "rgb(187,187,187)",
|
|
"Focused Input Background": "#f0f0f0",
|
|
"Focused Input Border": "rgb(187,187,187)",
|
|
"Buttons Background": "rgba(239,239,239,.98)",
|
|
"Buttons Border": "rgb(187,187,187)",
|
|
"Navigation Background": "rgba(255,255,255,0.8)",
|
|
"Navigation Border": "rgb(239,239,239)",
|
|
"Quotelinks": "#7a2634",
|
|
"Links": "#7a2634",
|
|
"Hovered Links": "#c24646",
|
|
"Navigation Links": "#404d41",
|
|
"Hovered Navigation Links": "#527054",
|
|
"Subjects": "#5533ff",
|
|
"Names": "#242ca3",
|
|
"Sage": "#6910ad",
|
|
"Tripcodes": "#0c76ab",
|
|
"Emails": "#0c76ab",
|
|
"Post Numbers": "#b86e2e",
|
|
"Text": "#242423",
|
|
"Backlinks": "#7a2634",
|
|
"Greentext": "#10610a",
|
|
"Board Title": "#000000",
|
|
"Timestamps": "#00913f",
|
|
"Inputs": "#242423",
|
|
"Warnings": "rgb(200,40,41)",
|
|
"Shadow Color": "#b0b0b0",
|
|
"Custom CSS": ".board .thread {\n padding: 1px;\n}\n.rice {\n box-shadow:rgba(255,255,255,.3) 0 1px;\n}\ninput[type=password]:hover,\ninput[type=text]:not([disabled]):hover,\ninput#fs_search:hover,\ninput.field:hover,\n.webkit select:hover,\ntextarea:hover,\n#options input:not([type=checkbox]):hover {\n box-shadow: inset rgba(0,0,0,.2) 0 1px 2px;\n}\ninput[type=password]:focus,\ninput[type=text]:focus,\ninput#fs_search:focus,\ninput.field:focus,\n.webkit select:focus,\ntextarea:focus,\n#options input:focus {\n box-shadow: inset rgba(200,200,200,.2) 0 1px 2px;\n}\nbutton,\ninput,\ntextarea,\n.rice {\n transition: background .2s,box-shadow .2s;\n}"
|
|
},
|
|
"Genergray": {
|
|
"Author": "Zixaphir",
|
|
"Author Tripcode": "!M.........",
|
|
"Background Image": "",
|
|
"Background Attachment": "",
|
|
"Background Position": "",
|
|
"Background Repeat": "",
|
|
"Background Color": "rgba(32,32,32,1)",
|
|
"Thread Wrapper Background": "rgba(24,24,24,1)",
|
|
"Thread Wrapper Border": "rgba(30,30,30,1)",
|
|
"Dialog Background": "rgba(32,32,32,1)",
|
|
"Dialog Border": "rgba(20,20,20,1)",
|
|
"Reply Background": "rgba(32,32,32,1)",
|
|
"Reply Border": "rgba(20,20,20,1)",
|
|
"Highlighted Reply Background": "rgba(24,24,24,1)",
|
|
"Highlighted Reply Border": "rgba(24,24,24,1)",
|
|
"Backlinked Reply Outline": "rgba(98,124,141,1)",
|
|
"Input Background": "rgba(32,32,32,1)",
|
|
"Input Border": "rgba(28,28,28,1)",
|
|
"Hovered Input Background": "rgba(24,24,24,1)",
|
|
"Hovered Input Border": "rgba(24,24,24,1)",
|
|
"Focused Input Background": "rgba(16,16,16,1)",
|
|
"Focused Input Border": "rgba(28,28,28,1)",
|
|
"Checkbox Background": "rgb(25,25,25)",
|
|
"Checkbox Border": "rgb(20,20,20)",
|
|
"Buttons Background": "rgba(20,20,20,1)",
|
|
"Buttons Border": "rgb(16,16,16)",
|
|
"Navigation Background": "rgba(16,16,16,0.9)",
|
|
"Navigation Border": "rgba(16,16,16,0.9)",
|
|
"Quotelinks": "rgb(71,140,161)",
|
|
"Backlinks": "rgba(71,140,161, 0.8)",
|
|
"Links": "rgb(141,141,160)",
|
|
"Hovered Links": "rgb(141,190,255)",
|
|
"Navigation Links": "rgb(51,145,175)",
|
|
"Hovered Navigation Links": "rgb(141,190,255)",
|
|
"Names": "rgb(150,150,150)",
|
|
"Tripcodes": "rgb(255,255,255)",
|
|
"Emails": "rgb(68,68,68)",
|
|
"Subjects": "rgb(255,100,100)",
|
|
"Text": "rgb(235,255,235)",
|
|
"Inputs": "rgb(144,144,144)",
|
|
"Post Numbers": "rgb(150,150,150)",
|
|
"Greentext": "rgb(113,121,62)",
|
|
"Sage": "rgb(68,68,68)",
|
|
"Board Title": "rgb(194,194,194)",
|
|
"Timestamps": "rgb(100,100,100)",
|
|
"Warnings": "rgb(215,0,0)",
|
|
"Shadow Color": "rgba(0,0,0,.1)",
|
|
"Custom CSS": ".board .thread {\n padding: 2px;\n box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.3) inset, rgba(70,70,70,.5) 1px 1px;\n}\n#header-bar,\ninput,\ntextarea,\n.field,\n.inline .op,\n.pagelist,\n.prettyprint,\n.post.reply,\n.rice,\n.selectrice {\n box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.2) inset, rgba(70,70,70,.3) 1px 1px;\n}\n#qr .selectrice {\n box-shadow: none;\n}\n#header-bar {\n padding: 1px 3px;\n}\n.dialog {\n box-shadow: 0px 0px 4px rgba(0, 0, 0, .3) inset, 1px 1px 5px rgba(0,0,0,0.2);\n}\n.threadContainer {\n border: none;\n box-shadow: 0px 0px 3px rgba(0, 0, 0, .3) inset, rgba(70,70,70,.3) 1px 1px;\n padding: 2px 0;\n margin-left: 20px;\n}\ninput[type=password]:hover,\ninput[type=text]:not([disabled]):hover,\ninput#fs_search:hover,\ninput.field:hover,\n.webkit select:hover,\ntextarea:hover,\n#appchanx-settings input:not([type=checkbox]):hover {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\ninput[type=password]:focus,\ninput[type=text]:focus,\ninput#fs_search:focus,\ninput.field:focus,\n.webkit select:focus,\ntextarea:focus,\n#appchanx-settings input:focus {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\nbutton,\ninput,\ntextarea,\n.rice {\n transition:background .2s,box-shadow .2s;\n}"
|
|
},
|
|
"Frost": {
|
|
"Author": "Zixaphir",
|
|
"Author Tripcode": "!M.........",
|
|
"Background Image": "",
|
|
"Background Attachment": "",
|
|
"Background Position": "",
|
|
"Background Repeat": "",
|
|
"Background Color": "rgba(230,230,230,1)",
|
|
"Thread Wrapper Background": "rgba(235,235,235,1)",
|
|
"Thread Wrapper Border": "rgba(215,215,215,1)",
|
|
"Dialog Background": "rgba(230,230,230,1)",
|
|
"Dialog Border": "rgba(255,255,255,1)",
|
|
"Reply Background": "rgba(230,230,230,1)",
|
|
"Reply Border": "rgba(220,220,220,1)",
|
|
"Highlighted Reply Background": "rgba(244,244,244,1)",
|
|
"Highlighted Reply Border": "rgba(220,220,220,1)",
|
|
"Backlinked Reply Outline": "rgba(98,124,141,1)",
|
|
"Input Background": "rgba(244,244,244,1)",
|
|
"Input Border": "rgba(220,220,220,1)",
|
|
"Hovered Input Background": "rgba(220,220,220,1)",
|
|
"Hovered Input Border": "rgba(200,200,200,1)",
|
|
"Focused Input Background": "rgba(255,255,255,1)",
|
|
"Focused Input Border": "rgba(200,200,200,1)",
|
|
"Checkbox Background": "rgba(200,200,200,1)",
|
|
"Checkbox Border": "rgba(190,190,190,1)",
|
|
"Buttons Background": "rgba(255,255,255,1)",
|
|
"Buttons Border": "rgba(220,220,220,1)",
|
|
"Navigation Background": "rgba(244,244,244,1)",
|
|
"Navigation Border": "rgba(230,230,230,0.9)",
|
|
"Quotelinks": "rgb(61,110,121)",
|
|
"Backlinks": "rgba(51,145,175, 0.9)",
|
|
"Links": "rgb(62,62,160)",
|
|
"Hovered Links": "rgb(101,0,150)",
|
|
"Navigation Links": "rgb(51,145,175)",
|
|
"Hovered Navigation Links": "rgb(141,190,255)",
|
|
"Names": "rgb(100,100,100)",
|
|
"Tripcodes": "rgb(0,125,0)",
|
|
"Emails": "rgb(68,68,68)",
|
|
"Subjects": "rgb(95,0,0)",
|
|
"Text": "rgb(0,0,0)",
|
|
"Inputs": "rgb(0,0,0)",
|
|
"Post Numbers": "rgb(80,80,80)",
|
|
"Greentext": "rgb(113,121,62)",
|
|
"Sage": "rgb(68,68,68)",
|
|
"Board Title": "rgb(0,0,0)",
|
|
"Timestamps": "rgb(100,100,100)",
|
|
"Warnings": "rgb(215,0,0)",
|
|
"Shadow Color": "rgba(0,0,0,.1)",
|
|
"Custom CSS": ".board .thread {\n padding: 2px;\n box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.1) inset, rgba(255,255,255,.5) 1px 1px;\n}\n#header-bar,\ninput,\ntextarea,\n.field,\n.inline .op,\n.pagelist,\n.prettyprint,\n.post.reply,\n.rice,\n.selectrice {\n box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.1) inset, rgba(255,255,255,.8) 1px 1px;\n}\n#qr .selectrice {\n box-shadow: none;\n}\n#header-bar {\n padding: 1px 3px;\n}\n.dialog {\n box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.1) inset, rgba(255,255,255,.5) 1px 1px;\n}\n.threadContainer {\n border: none;\n box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.1) inset, rgba(255,255,255,.5) 1px 1px;\n padding: 2px 0;\n margin-left: 20px;\n}\ninput[type=password]:hover,\ninput[type=text]:not([disabled]):hover,\ninput#fs_search:hover,\ninput.field:hover,\n.webkit select:hover,\ntextarea:hover,\n#appchanx-settings input:not([type=checkbox]):hover {\n box-shadow: inset rgba(0,0,0,.1) 0 1px 2px;\n}\ninput[type=password]:focus,\ninput[type=text]:focus,\ninput#fs_search:focus,\ninput.field:focus,\n.webkit select:focus,\ntextarea:focus,\n#appchanx-settings input:focus {\n box-shadow: inset rgba(0,0,0,.1) 0 1px 2px;\n}\nbutton,\ninput,\ntextarea,\n.rice {\n transition: background .2s,box-shadow .2s;\n}"
|
|
},
|
|
"Clone": {
|
|
"Author": "Zixaphir",
|
|
"Author Tripcode": "!M.........",
|
|
"Background Image": "",
|
|
"Background Attachment": "",
|
|
"Background Position": "",
|
|
"Background Repeat": "",
|
|
"Background Color": "#1e1e1e",
|
|
"Thread Wrapper Background": "rgba(0,0,0,0)",
|
|
"Thread Wrapper Border": "#111111",
|
|
"Dialog Background": "#222222",
|
|
"Dialog Border": "#111111",
|
|
"Reply Background": "#222222",
|
|
"Reply Border": "#111111",
|
|
"Highlighted Reply Background": "#141414",
|
|
"Highlighted Reply Border": "#111111",
|
|
"Backlinked Reply Outline": "#6d6d8c",
|
|
"Input Background": "#222222",
|
|
"Input Border": "#111111",
|
|
"Hovered Input Background": "#111111",
|
|
"Hovered Input Border": "#171717",
|
|
"Focused Input Background": "#1e1e1e",
|
|
"Focused Input Border": "#111111",
|
|
"Checkbox Background": "#242424",
|
|
"Checkbox Border": "#0f0f0f",
|
|
"Buttons Background": "#171717",
|
|
"Buttons Border": "#111111",
|
|
"Navigation Background": "rgba(30,30,30,0.9)",
|
|
"Navigation Border": "#111111",
|
|
"Quotelinks": "#6d6d8c",
|
|
"Backlinks": "#55555c",
|
|
"Links": "#57577a",
|
|
"Hovered Links": "#8787ad",
|
|
"Navigation Links": "#bababa",
|
|
"Hovered Navigation Links": "#676785",
|
|
"Names": "#6e753c",
|
|
"Tripcodes": "#94531c",
|
|
"Emails": "#5e5e5e",
|
|
"Subjects": "#ababab",
|
|
"Text": "#8c8c8c",
|
|
"Inputs": "#8c8c8c",
|
|
"Post Numbers": "#6b6b6b",
|
|
"Greentext": "#6e753c",
|
|
"Sage": "#592110",
|
|
"Board Title": "#8c8c8c",
|
|
"Timestamps": "#7d7d7d",
|
|
"Warnings": "#7b1126",
|
|
"Shadow Color": "rgba(0,0,0,.1)",
|
|
"Custom CSS": ".rice {\n box-shadow: 1px 1px rgba(50,50,50,0.4), inset 1px 1px 2px rgba(0,0,0,0.3);\n}\n.reply.post {\n margin: 0 !important;\n border-radius: 0;\n}\n.board .replyContainer,\n#unread-line {\n margin: -1px;\n}\n#qp {\n border: none !important;\n}\n#unread-line {\n padding: 1px;\n border: 1px solid #111 !important;\n background-color: #933;\n}"
|
|
}
|
|
};
|
|
|
|
$ = function(selector, root) {
|
|
if (root == null) {
|
|
root = d.body;
|
|
}
|
|
return root.querySelector(selector);
|
|
};
|
|
|
|
$.extend = function(obj, prop) {
|
|
var key, val;
|
|
for (key in prop) {
|
|
val = prop[key];
|
|
if (prop.hasOwnProperty(key)) {
|
|
obj[key] = val;
|
|
}
|
|
}
|
|
};
|
|
|
|
$.DAY = 24 * ($.HOUR = 60 * ($.MINUTE = 60 * ($.SECOND = 1000)));
|
|
|
|
$.id = function(id) {
|
|
return d.getElementById(id);
|
|
};
|
|
|
|
$.ready = function(fc) {
|
|
var cb;
|
|
if (d.readyState !== 'loading') {
|
|
$.queueTask(fc);
|
|
return;
|
|
}
|
|
cb = function() {
|
|
$.off(d, 'DOMContentLoaded', cb);
|
|
return fc();
|
|
};
|
|
return $.on(d, 'DOMContentLoaded', cb);
|
|
};
|
|
|
|
$.formData = function(form) {
|
|
var fd, key, val;
|
|
if (form instanceof HTMLFormElement) {
|
|
return new FormData(form);
|
|
}
|
|
fd = new FormData();
|
|
for (key in form) {
|
|
val = form[key];
|
|
if (val) {
|
|
if (typeof val === 'object' && 'newName' in val) {
|
|
fd.append(key, val, val.newName);
|
|
} else {
|
|
fd.append(key, val);
|
|
}
|
|
}
|
|
}
|
|
return fd;
|
|
};
|
|
|
|
$.extend = function(object, properties) {
|
|
var key, val;
|
|
for (key in properties) {
|
|
val = properties[key];
|
|
object[key] = val;
|
|
}
|
|
};
|
|
|
|
$.ajax = (function() {
|
|
var lastModified;
|
|
lastModified = {};
|
|
return function(url, options, extra) {
|
|
var form, r, sync, type, upCallbacks, whenModified;
|
|
if (extra == null) {
|
|
extra = {};
|
|
}
|
|
type = extra.type, whenModified = extra.whenModified, upCallbacks = extra.upCallbacks, form = extra.form, sync = extra.sync;
|
|
r = new XMLHttpRequest();
|
|
type || (type = form && 'post' || 'get');
|
|
r.open(type, url, !sync);
|
|
if (whenModified) {
|
|
if (url in lastModified) {
|
|
r.setRequestHeader('If-Modified-Since', lastModified[url]);
|
|
}
|
|
$.on(r, 'load', function() {
|
|
return lastModified[url] = r.getResponseHeader('Last-Modified');
|
|
});
|
|
}
|
|
if (/\.json$/.test(url)) {
|
|
r.responseType = 'json';
|
|
}
|
|
$.extend(r, options);
|
|
$.extend(r.upload, upCallbacks);
|
|
r.send(form);
|
|
return r;
|
|
};
|
|
})();
|
|
|
|
$.cache = (function() {
|
|
var reqs;
|
|
reqs = {};
|
|
return function(url, cb, options) {
|
|
var err, req, rm;
|
|
if (req = reqs[url]) {
|
|
if (req.readyState === 4) {
|
|
cb.call(req, req.evt);
|
|
} else {
|
|
req.callbacks.push(cb);
|
|
}
|
|
return;
|
|
}
|
|
rm = function() {
|
|
return delete reqs[url];
|
|
};
|
|
try {
|
|
req = $.ajax(url, options);
|
|
} catch (_error) {
|
|
err = _error;
|
|
return;
|
|
}
|
|
$.on(req, 'load', function(e) {
|
|
var _i, _len, _ref;
|
|
_ref = this.callbacks;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
cb = _ref[_i];
|
|
cb.call(this, e);
|
|
}
|
|
this.evt = e;
|
|
return delete this.callbacks;
|
|
});
|
|
$.on(req, 'abort error', rm);
|
|
req.callbacks = [cb];
|
|
return reqs[url] = req;
|
|
};
|
|
})();
|
|
|
|
$.cb = {
|
|
checked: function() {
|
|
$.set(this.name, this.checked);
|
|
return Conf[this.name] = this.checked;
|
|
},
|
|
value: function() {
|
|
$.set(this.name, this.value.trim());
|
|
return Conf[this.name] = this.value;
|
|
}
|
|
};
|
|
|
|
$.asap = function(test, cb) {
|
|
if (test()) {
|
|
return cb();
|
|
} else {
|
|
return setTimeout($.asap, 25, test, cb);
|
|
}
|
|
};
|
|
|
|
$.addStyle = function(css, id) {
|
|
var style;
|
|
style = $.el('style', {
|
|
id: id,
|
|
textContent: css
|
|
});
|
|
$.asap((function() {
|
|
return d.head;
|
|
}), function() {
|
|
return $.add(d.head, style);
|
|
});
|
|
return style;
|
|
};
|
|
|
|
$.x = function(path, root) {
|
|
root || (root = d.body);
|
|
return d.evaluate(path, root, null, 8, null).singleNodeValue;
|
|
};
|
|
|
|
$.X = function(path, root) {
|
|
root || (root = d.body);
|
|
return d.evaluate(path, root, null, 7, null);
|
|
};
|
|
|
|
$.addClass = function() {
|
|
var className, el, _ref;
|
|
el = arguments[0], className = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
|
|
return (_ref = el.classList).add.apply(_ref, className);
|
|
};
|
|
|
|
$.rmClass = function() {
|
|
var className, el, _ref;
|
|
el = arguments[0], className = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
|
|
return (_ref = el.classList).remove.apply(_ref, className);
|
|
};
|
|
|
|
$.toggleClass = function(el, className) {
|
|
return el.classList.toggle(className);
|
|
};
|
|
|
|
$.hasClass = function(el, className) {
|
|
return __indexOf.call(el.classList, className) >= 0;
|
|
};
|
|
|
|
$.rm = function(el) {
|
|
return el.remove();
|
|
};
|
|
|
|
$.rmAll = function(root) {
|
|
return root.textContent = null;
|
|
};
|
|
|
|
$.tn = function(s) {
|
|
return d.createTextNode(s);
|
|
};
|
|
|
|
$.frag = function() {
|
|
return d.createDocumentFragment();
|
|
};
|
|
|
|
$.nodes = function(nodes) {
|
|
var frag, node, _i, _len;
|
|
if (!(nodes instanceof Array)) {
|
|
return nodes;
|
|
}
|
|
frag = $.frag();
|
|
for (_i = 0, _len = nodes.length; _i < _len; _i++) {
|
|
node = nodes[_i];
|
|
frag.appendChild(node);
|
|
}
|
|
return frag;
|
|
};
|
|
|
|
$.add = function(parent, el) {
|
|
return parent.appendChild($.nodes(el));
|
|
};
|
|
|
|
$.prepend = function(parent, el) {
|
|
return parent.insertBefore($.nodes(el), parent.firstChild);
|
|
};
|
|
|
|
$.after = function(root, el) {
|
|
return root.parentNode.insertBefore($.nodes(el), root.nextSibling);
|
|
};
|
|
|
|
$.before = function(root, el) {
|
|
return root.parentNode.insertBefore($.nodes(el), root);
|
|
};
|
|
|
|
$.replace = function(root, el) {
|
|
return root.parentNode.replaceChild($.nodes(el), root);
|
|
};
|
|
|
|
$.el = function(tag, properties) {
|
|
var el;
|
|
el = d.createElement(tag);
|
|
if (properties) {
|
|
$.extend(el, properties);
|
|
}
|
|
return el;
|
|
};
|
|
|
|
$.on = function(el, events, handler) {
|
|
var event, _i, _len, _ref;
|
|
_ref = events.split(' ');
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
event = _ref[_i];
|
|
el.addEventListener(event, handler, false);
|
|
}
|
|
};
|
|
|
|
$.off = function(el, events, handler) {
|
|
var event, _i, _len, _ref;
|
|
_ref = events.split(' ');
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
event = _ref[_i];
|
|
el.removeEventListener(event, handler, false);
|
|
}
|
|
};
|
|
|
|
$.event = function(event, detail, root) {
|
|
if (root == null) {
|
|
root = d;
|
|
}
|
|
return root.dispatchEvent(new CustomEvent(event, {
|
|
bubbles: true,
|
|
detail: detail
|
|
}));
|
|
};
|
|
|
|
$.open = GM_openInTab;
|
|
|
|
$.debounce = function(wait, fn) {
|
|
var args, exec, lastCall, that, timeout;
|
|
lastCall = 0;
|
|
timeout = null;
|
|
that = null;
|
|
args = null;
|
|
exec = function() {
|
|
lastCall = Date.now();
|
|
return fn.apply(that, args);
|
|
};
|
|
return function() {
|
|
args = arguments;
|
|
that = this;
|
|
if (lastCall < Date.now() - wait) {
|
|
return exec();
|
|
}
|
|
clearTimeout(timeout);
|
|
return timeout = setTimeout(exec, wait);
|
|
};
|
|
};
|
|
|
|
$.queueTask = (function() {
|
|
var execTask, taskChannel, taskQueue;
|
|
taskQueue = [];
|
|
execTask = function() {
|
|
var args, func, task;
|
|
task = taskQueue.shift();
|
|
func = task[0];
|
|
args = Array.prototype.slice.call(task, 1);
|
|
return func.apply(func, args);
|
|
};
|
|
if (window.MessageChannel) {
|
|
taskChannel = new MessageChannel();
|
|
taskChannel.port1.onmessage = execTask;
|
|
return function() {
|
|
taskQueue.push(arguments);
|
|
return taskChannel.port2.postMessage(null);
|
|
};
|
|
} else {
|
|
return function() {
|
|
taskQueue.push(arguments);
|
|
return setTimeout(execTask, 0);
|
|
};
|
|
}
|
|
})();
|
|
|
|
$.globalEval = function(code) {
|
|
var script;
|
|
script = $.el('script', {
|
|
textContent: code
|
|
});
|
|
$.add(d.head || doc, script);
|
|
return $.rm(script);
|
|
};
|
|
|
|
$.bytesToString = function(size) {
|
|
var unit;
|
|
unit = 0;
|
|
while (size >= 1024) {
|
|
size /= 1024;
|
|
unit++;
|
|
}
|
|
size = unit > 1 ? Math.round(size * 100) / 100 : Math.round(size);
|
|
return "" + size + " " + ['B', 'KB', 'MB', 'GB'][unit];
|
|
};
|
|
|
|
$.minmax = function(value, min, max) {
|
|
return (value < min ? min : value > max ? max : value);
|
|
};
|
|
|
|
$.item = function(key, val) {
|
|
var item;
|
|
item = {};
|
|
item[key] = val;
|
|
return item;
|
|
};
|
|
|
|
$.syncing = {};
|
|
|
|
$.sync = (function() {
|
|
$.on(window, 'storage', function(_arg) {
|
|
var cb, key, newValue;
|
|
key = _arg.key, newValue = _arg.newValue;
|
|
if (cb = $.syncing[key]) {
|
|
return cb(JSON.parse(newValue), key);
|
|
}
|
|
});
|
|
return function(key, cb) {
|
|
return $.syncing[g.NAMESPACE + key] = cb;
|
|
};
|
|
})();
|
|
|
|
$.desync = function(key) {
|
|
return delete $.syncing[g.NAMESPACE + key];
|
|
};
|
|
|
|
$["delete"] = function(keys) {
|
|
var key, _i, _len;
|
|
if (!(keys instanceof Array)) {
|
|
keys = [keys];
|
|
}
|
|
for (_i = 0, _len = keys.length; _i < _len; _i++) {
|
|
key = keys[_i];
|
|
key = g.NAMESPACE + key;
|
|
localStorage.removeItem(key);
|
|
GM_deleteValue(key);
|
|
}
|
|
};
|
|
|
|
$.get = function(key, val, cb) {
|
|
var items;
|
|
if (typeof cb === 'function') {
|
|
items = $.item(key, val);
|
|
} else {
|
|
items = key;
|
|
cb = val;
|
|
}
|
|
return $.queueTask(function() {
|
|
for (key in items) {
|
|
if (val = GM_getValue(g.NAMESPACE + key)) {
|
|
items[key] = JSON.parse(val);
|
|
}
|
|
}
|
|
return cb(items);
|
|
});
|
|
};
|
|
|
|
$.set = (function() {
|
|
var set;
|
|
set = function(key, val) {
|
|
key = g.NAMESPACE + key;
|
|
val = JSON.stringify(val);
|
|
if (key in $.syncing) {
|
|
localStorage.setItem(key, val);
|
|
}
|
|
return GM_setValue(key, val);
|
|
};
|
|
return function(keys, val) {
|
|
var key;
|
|
if (typeof keys === 'string') {
|
|
set(keys, val);
|
|
return;
|
|
}
|
|
for (key in keys) {
|
|
val = keys[key];
|
|
set(key, val);
|
|
}
|
|
};
|
|
})();
|
|
|
|
$.clear = function(cb) {
|
|
$["delete"](GM_listValues().map(function(key) {
|
|
return key.replace(g.NAMESPACE, '');
|
|
}));
|
|
return typeof cb === "function" ? cb() : void 0;
|
|
};
|
|
|
|
$.remove = function(arr, value) {
|
|
var i;
|
|
i = arr.indexOf(value);
|
|
if (i === -1) {
|
|
return false;
|
|
}
|
|
arr.splice(i, 1);
|
|
return true;
|
|
};
|
|
|
|
$$ = function(selector, root) {
|
|
if (root == null) {
|
|
root = d.body;
|
|
}
|
|
return __slice.call(root.querySelectorAll(selector));
|
|
};
|
|
|
|
Callbacks = (function() {
|
|
function Callbacks(type) {
|
|
this.type = type;
|
|
this.keys = [];
|
|
}
|
|
|
|
Callbacks.prototype.push = function(_arg) {
|
|
var cb, name;
|
|
name = _arg.name, cb = _arg.cb;
|
|
if (this[name]) {
|
|
this.connect(name);
|
|
}
|
|
if (!this[name]) {
|
|
this.keys.push(name);
|
|
}
|
|
return this[name] = cb;
|
|
};
|
|
|
|
Callbacks.prototype.connect = function(name) {
|
|
if (this[name].disconnected) {
|
|
return delete this[name].disconnected;
|
|
}
|
|
};
|
|
|
|
Callbacks.prototype.disconnect = function(name) {
|
|
if (this[name]) {
|
|
return this[name].disconnected = true;
|
|
}
|
|
};
|
|
|
|
Callbacks.prototype.execute = function(nodes) {
|
|
var cb, err, errors, i, j, name, node;
|
|
i = 0;
|
|
while (name = this.keys[i++]) {
|
|
j = 0;
|
|
cb = this[name];
|
|
while (node = nodes[j++]) {
|
|
try {
|
|
if (!cb.disconnected) {
|
|
cb.call(node);
|
|
}
|
|
} catch (_error) {
|
|
err = _error;
|
|
if (!errors) {
|
|
errors = [];
|
|
}
|
|
errors.push({
|
|
message: ['"', name, '" crashed on node ', this.type, ' No.', node.ID, ' (', node.board, ').'].join(''),
|
|
error: err
|
|
});
|
|
}
|
|
}
|
|
}
|
|
if (errors) {
|
|
return Main.handleErrors(errors);
|
|
}
|
|
};
|
|
|
|
return Callbacks;
|
|
|
|
})();
|
|
|
|
Board = (function() {
|
|
Board.prototype.toString = function() {
|
|
return this.ID;
|
|
};
|
|
|
|
function Board(ID) {
|
|
this.ID = ID;
|
|
this.threads = new SimpleDict;
|
|
this.posts = new SimpleDict;
|
|
g.boards[this] = this;
|
|
}
|
|
|
|
return Board;
|
|
|
|
})();
|
|
|
|
Thread = (function() {
|
|
Thread.callbacks = new Callbacks('Thread');
|
|
|
|
Thread.prototype.toString = function() {
|
|
return this.ID;
|
|
};
|
|
|
|
function Thread(ID, board) {
|
|
this.ID = ID;
|
|
this.board = board;
|
|
this.fullID = "" + this.board + "." + this.ID;
|
|
this.posts = new SimpleDict;
|
|
this.isDead = false;
|
|
this.isHidden = false;
|
|
this.isOnTop = false;
|
|
this.isPinned = false;
|
|
this.isSticky = false;
|
|
this.isClosed = false;
|
|
this.postLimit = false;
|
|
this.fileLimit = false;
|
|
this.OP = null;
|
|
this.catalogView = null;
|
|
g.threads.push(this.fullID, board.threads.push(this, this));
|
|
}
|
|
|
|
Thread.prototype.setPage = function(pageNum) {
|
|
var icon, key, _i, _len, _ref;
|
|
icon = $('.page-num', this.OP.nodes.info);
|
|
_ref = ['title', 'textContent'];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
key = _ref[_i];
|
|
icon[key] = icon[key].replace(/\d+/, pageNum);
|
|
}
|
|
if (this.catalogView) {
|
|
return this.catalogView.nodes.pageCount.textContent = pageNum;
|
|
}
|
|
};
|
|
|
|
Thread.prototype.setCount = function(type, count, reachedLimit) {
|
|
var el;
|
|
if (!this.catalogView) {
|
|
return;
|
|
}
|
|
el = this.catalogView.nodes["" + type + "Count"];
|
|
el.textContent = count;
|
|
return (reachedLimit ? $.addClass : $.rmClass)(el, 'warning');
|
|
};
|
|
|
|
Thread.prototype.setStatus = function(type, status) {
|
|
var icon, name, root, typeLC;
|
|
name = "is" + type;
|
|
if (this[name] === status) {
|
|
return;
|
|
}
|
|
this[name] = status;
|
|
if (!this.OP) {
|
|
return;
|
|
}
|
|
typeLC = type.toLowerCase();
|
|
if (!status) {
|
|
$.rm($("." + typeLC + "Icon", this.OP.nodes.info));
|
|
if (this.catalogView) {
|
|
$.rm($("." + typeLC + "Icon", this.catalogView.nodes.icons));
|
|
}
|
|
return;
|
|
}
|
|
icon = $.el('img', {
|
|
src: "" + Build.staticPath + typeLC + Build.gifIcon,
|
|
title: type,
|
|
className: "" + typeLC + "Icon"
|
|
});
|
|
root = type === 'Closed' && this.isSticky ? $('.stickyIcon', this.OP.nodes.info) : g.VIEW === 'index' ? $('.page-num', this.OP.nodes.info) : $('[title="Quote this post"]', this.OP.nodes.info);
|
|
$.after(root, [$.tn(' '), icon]);
|
|
if (!this.catalogView) {
|
|
return;
|
|
}
|
|
return (type === 'Sticky' && this.isClosed ? $.prepend : $.add)(this.catalogView.nodes.icons, icon.cloneNode());
|
|
};
|
|
|
|
Thread.prototype.pin = function() {
|
|
this.isPinned = true;
|
|
if (this.catalogView) {
|
|
return $.addClass(this.catalogView.nodes.root, 'pinned');
|
|
}
|
|
};
|
|
|
|
Thread.prototype.unpin = function() {
|
|
this.isPinned = false;
|
|
if (this.catalogView) {
|
|
return $.rmClass(this.catalogView.nodes.root, 'pinned');
|
|
}
|
|
};
|
|
|
|
Thread.prototype.hide = function() {
|
|
var button;
|
|
if (this.isHidden) {
|
|
return;
|
|
}
|
|
this.isHidden = true;
|
|
if (button = $('.hide-post-button', this.OP.nodes.root)) {
|
|
return $.replace(button, PostHiding.makeButton(false));
|
|
}
|
|
};
|
|
|
|
Thread.prototype.show = function() {
|
|
var button;
|
|
if (!this.isHidden) {
|
|
return;
|
|
}
|
|
this.isHidden = false;
|
|
if (button = $('.show-post-button', this.OP.nodes.root)) {
|
|
return $.replace(button, PostHiding.makeButton(true));
|
|
}
|
|
};
|
|
|
|
Thread.prototype.kill = function() {
|
|
return this.isDead = true;
|
|
};
|
|
|
|
Thread.prototype.collect = function() {
|
|
this.posts.forEach(function(post) {
|
|
return post.collect();
|
|
});
|
|
g.threads.rm(this.fullID);
|
|
return this.board.threads.rm(this);
|
|
};
|
|
|
|
return Thread;
|
|
|
|
})();
|
|
|
|
CatalogThread = (function() {
|
|
CatalogThread.callbacks = new Callbacks('Catalog Thread');
|
|
|
|
CatalogThread.prototype.toString = function() {
|
|
return this.ID;
|
|
};
|
|
|
|
function CatalogThread(root, thread) {
|
|
this.thread = thread;
|
|
this.ID = this.thread.ID;
|
|
this.board = this.thread.board;
|
|
this.nodes = {
|
|
root: root,
|
|
thumb: $('.thumb', root),
|
|
icons: $('.thread-icons', root),
|
|
postCount: $('.post-count', root),
|
|
fileCount: $('.file-count', root),
|
|
pageCount: $('.page-count', root)
|
|
};
|
|
this.thread.catalogView = this;
|
|
}
|
|
|
|
return CatalogThread;
|
|
|
|
})();
|
|
|
|
Post = (function() {
|
|
Post.callbacks = new Callbacks('Post');
|
|
|
|
Post.prototype.toString = function() {
|
|
return this.ID;
|
|
};
|
|
|
|
function Post(root, thread, board, that) {
|
|
var capcode, date, email, flag, info, name, post, subject, tripcode, uniqueID;
|
|
this.thread = thread;
|
|
this.board = board;
|
|
if (that == null) {
|
|
that = {};
|
|
}
|
|
this.ID = +root.id.slice(2);
|
|
this.fullID = "" + this.board + "." + this.ID;
|
|
post = $('.post', root);
|
|
info = $('.postInfo', post);
|
|
if (that.isOriginalMarkup) {
|
|
this.cleanup(root, post);
|
|
}
|
|
root.dataset.fullID = this.fullID;
|
|
this.nodes = {
|
|
root: root,
|
|
post: post,
|
|
info: info,
|
|
comment: $('.postMessage', post),
|
|
links: [],
|
|
quotelinks: [],
|
|
backlinks: info.getElementsByClassName('backlink')
|
|
};
|
|
if (!(this.isReply = $.hasClass(post, 'reply'))) {
|
|
this.thread.OP = this;
|
|
this.thread.isSticky = !!$('.stickyIcon', info);
|
|
this.thread.isClosed = !!$('.closedIcon', info);
|
|
}
|
|
this.info = {};
|
|
if (subject = $('.subject', info)) {
|
|
this.nodes.subject = subject;
|
|
this.info.subject = subject.textContent;
|
|
}
|
|
if (name = $('.name', info)) {
|
|
this.nodes.name = name;
|
|
this.info.name = name.textContent;
|
|
}
|
|
if (email = $('.useremail', info)) {
|
|
this.nodes.email = email;
|
|
this.info.email = decodeURIComponent(email.href.slice(7));
|
|
}
|
|
if (tripcode = $('.postertrip', info)) {
|
|
this.nodes.tripcode = tripcode;
|
|
this.info.tripcode = tripcode.textContent;
|
|
}
|
|
if (uniqueID = $('.posteruid', info)) {
|
|
this.nodes.uniqueID = uniqueID;
|
|
this.info.uniqueID = uniqueID.firstElementChild.textContent;
|
|
}
|
|
if (capcode = $('.capcode.hand', info)) {
|
|
this.nodes.capcode = capcode;
|
|
this.info.capcode = capcode.textContent.replace('## ', '');
|
|
}
|
|
if (flag = $('.flag, .countryFlag', info)) {
|
|
this.nodes.flag = flag;
|
|
this.info.flag = flag.title;
|
|
}
|
|
if (date = $('.dateTime', info)) {
|
|
this.nodes.date = date;
|
|
this.info.date = new Date(date.dataset.utc * 1000);
|
|
}
|
|
this.parseComment();
|
|
this.parseQuotes();
|
|
this.parseFile(that);
|
|
this.labels = [];
|
|
this.highlights = [];
|
|
this.isDead = false;
|
|
this.isHidden = false;
|
|
this.clones = [];
|
|
g.posts.push(this.fullID, thread.posts.push(this, board.posts.push(this, this)));
|
|
if (that.isArchived) {
|
|
this.kill();
|
|
}
|
|
}
|
|
|
|
Post.prototype.parseComment = function() {
|
|
var bq, i, node, nodes, text;
|
|
this.nodes.comment.normalize();
|
|
bq = this.nodes.comment.cloneNode(true);
|
|
nodes = $$('.abbr, .exif, b', bq);
|
|
i = 0;
|
|
while (node = nodes[i++]) {
|
|
$.rm(node);
|
|
}
|
|
text = "";
|
|
nodes = $.X('.//br|.//text()', bq);
|
|
i = 0;
|
|
while (node = nodes.snapshotItem(i++)) {
|
|
text += node.data || '\n';
|
|
}
|
|
return this.info.comment = text.trim().replace(/\s+$/gm, '');
|
|
};
|
|
|
|
Post.prototype.parseQuotes = function() {
|
|
var quotelink, _i, _len, _ref;
|
|
this.quotes = [];
|
|
_ref = $$('.quotelink', this.nodes.comment);
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
quotelink = _ref[_i];
|
|
this.parseQuote(quotelink);
|
|
}
|
|
};
|
|
|
|
Post.prototype.parseQuote = function(quotelink) {
|
|
var fullID, match;
|
|
if (!(match = quotelink.href.match(/boards\.4chan\.org\/([^\/]+)\/res\/\d+#p(\d+)$/))) {
|
|
return;
|
|
}
|
|
this.nodes.quotelinks.push(quotelink);
|
|
if (this.isClone) {
|
|
return;
|
|
}
|
|
fullID = "" + match[1] + "." + match[2];
|
|
if (__indexOf.call(this.quotes, fullID) < 0) {
|
|
return this.quotes.push(fullID);
|
|
}
|
|
};
|
|
|
|
Post.prototype.parseFile = function(that) {
|
|
var anchor, fileEl, fileText, nameNode, size, thumb, unit;
|
|
if (!((fileEl = $('.file', this.nodes.post)) && (thumb = $('img[data-md5]', fileEl)))) {
|
|
return;
|
|
}
|
|
anchor = thumb.parentNode;
|
|
fileText = fileEl.firstElementChild;
|
|
this.file = {
|
|
text: fileText,
|
|
thumb: thumb,
|
|
URL: anchor.href,
|
|
size: thumb.alt.match(/[\d.]+\s\w+/)[0],
|
|
MD5: thumb.dataset.md5,
|
|
isSpoiler: $.hasClass(anchor, 'imgspoiler')
|
|
};
|
|
size = +this.file.size.match(/[\d.]+/)[0];
|
|
unit = ['B', 'KB', 'MB', 'GB'].indexOf(this.file.size.match(/\w+$/)[0]);
|
|
while (unit-- > 0) {
|
|
size *= 1024;
|
|
}
|
|
this.file.sizeInBytes = size;
|
|
this.file.thumbURL = that.isArchived ? thumb.src : "" + location.protocol + "//t.4cdn.org/" + this.board + "/thumb/" + (this.file.URL.match(/(\d+)\./)[1]) + "s.jpg";
|
|
this.file.name = (nameNode = $('span', fileText)) ? nameNode.title || nameNode.textContent : fileText.title;
|
|
if (this.file.isImage = /(jpg|png|gif)$/i.test(this.file.name)) {
|
|
return this.file.dimensions = fileText.textContent.match(/\d+x\d+/)[0];
|
|
}
|
|
};
|
|
|
|
Post.prototype.cleanup = function(root, post) {
|
|
var node, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2;
|
|
_ref = $$('.mobile', root);
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
node = _ref[_i];
|
|
$.rm(node);
|
|
}
|
|
_ref1 = $$('[id]', post);
|
|
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
|
node = _ref1[_j];
|
|
node.removeAttribute('id');
|
|
}
|
|
_ref2 = $$('.desktop', root);
|
|
for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
|
|
node = _ref2[_k];
|
|
$.rmClass(node, 'desktop');
|
|
}
|
|
};
|
|
|
|
Post.prototype.getNameBlock = function() {
|
|
if (Conf['Anonymize']) {
|
|
return 'Anonymous';
|
|
} else {
|
|
return $('.nameBlock', this.nodes.info).textContent.trim();
|
|
}
|
|
};
|
|
|
|
Post.prototype.hide = function(label, makeStub, hideRecursively) {
|
|
var quotelink, _i, _len, _ref;
|
|
if (makeStub == null) {
|
|
makeStub = Conf['Stubs'];
|
|
}
|
|
if (hideRecursively == null) {
|
|
hideRecursively = Conf['Recursive Hiding'];
|
|
}
|
|
if (__indexOf.call(this.labels, label) < 0) {
|
|
this.labels.push(label);
|
|
}
|
|
if (this.isHidden) {
|
|
return;
|
|
}
|
|
this.isHidden = true;
|
|
_ref = Get.allQuotelinksLinkingTo(this);
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
quotelink = _ref[_i];
|
|
$.addClass(quotelink, 'filtered');
|
|
}
|
|
if (hideRecursively) {
|
|
label = "Recursively hidden for quoting No." + this;
|
|
Recursive.apply('hide', this, label, makeStub, true);
|
|
Recursive.add('hide', this, label, makeStub, true);
|
|
}
|
|
PostHiding.saveHiddenState(this, {
|
|
thisPost: true,
|
|
hideRecursively: hideRecursively,
|
|
makeStub: makeStub
|
|
});
|
|
if (!this.isReply) {
|
|
this.thread.hide();
|
|
return;
|
|
}
|
|
if (!makeStub) {
|
|
this.nodes.root.hidden = true;
|
|
return;
|
|
}
|
|
this.nodes.post.hidden = true;
|
|
this.nodes.post.previousElementSibling.hidden = true;
|
|
this.nodes.stub = $.el('div', {
|
|
className: 'stub'
|
|
});
|
|
$.add(this.nodes.stub, [PostHiding.makeButton(false), $.tn(" " + (this.getNameBlock()))]);
|
|
if (Conf['Menu']) {
|
|
$.add(this.nodes.stub, Menu.makeButton());
|
|
}
|
|
return $.prepend(this.nodes.root, this.nodes.stub);
|
|
};
|
|
|
|
Post.prototype.show = function(showRecursively) {
|
|
var quotelink, _i, _len, _ref;
|
|
if (showRecursively == null) {
|
|
showRecursively = Conf['Recursive Hiding'];
|
|
}
|
|
if (!this.isHidden) {
|
|
return;
|
|
}
|
|
this.isHidden = false;
|
|
this.labels = this.labels.filter(function(label) {
|
|
return !/^(Manually hidden|Recursively hidden|Hidden by)/.test(label);
|
|
});
|
|
_ref = Get.allQuotelinksLinkingTo(this);
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
quotelink = _ref[_i];
|
|
$.rmClass(quotelink, 'filtered');
|
|
}
|
|
if (showRecursively) {
|
|
Recursive.apply('show', this, true);
|
|
Recursive.rm('hide', this);
|
|
}
|
|
PostHiding.saveHiddenState(this, {
|
|
thisPost: true,
|
|
hideRecursively: showRecursively,
|
|
makeStub: !!this.nodes.stub
|
|
});
|
|
if (!this.isReply) {
|
|
this.thread.show();
|
|
return;
|
|
}
|
|
if (!this.nodes.stub) {
|
|
this.nodes.root.hidden = false;
|
|
return;
|
|
}
|
|
this.nodes.post.hidden = false;
|
|
this.nodes.post.previousElementSibling.hidden = false;
|
|
$.rm(this.nodes.stub);
|
|
return delete this.nodes.stub;
|
|
};
|
|
|
|
Post.prototype.highlight = function(label, highlight, top) {
|
|
this.labels.push(label);
|
|
if (__indexOf.call(this.highlights, highlight) < 0) {
|
|
this.highlights.push(highlight);
|
|
$.addClass(this.nodes.root, highlight);
|
|
}
|
|
if (!this.isReply && top) {
|
|
return this.thread.isOnTop = true;
|
|
}
|
|
};
|
|
|
|
Post.prototype.kill = function(file) {
|
|
var clone, quotelink, strong, _i, _j, _len, _len1, _ref, _ref1;
|
|
if (file) {
|
|
if (this.file.isDead) {
|
|
return;
|
|
}
|
|
this.file.isDead = true;
|
|
$.addClass(this.nodes.root, 'deleted-file');
|
|
} else {
|
|
if (this.isDead) {
|
|
return;
|
|
}
|
|
this.isDead = true;
|
|
$.addClass(this.nodes.root, 'deleted-post');
|
|
}
|
|
if (!(strong = $('strong.warning', this.nodes.info))) {
|
|
strong = $.el('strong', {
|
|
className: 'warning fa'
|
|
});
|
|
$.after($('input', this.nodes.info), strong);
|
|
}
|
|
strong.textContent = file ? '\uf070' : '\uf014';
|
|
strong.title = "" + (file ? 'File' : 'Post') + " Deleted";
|
|
if (this.isClone) {
|
|
return;
|
|
}
|
|
_ref = this.clones;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
clone = _ref[_i];
|
|
clone.kill(file);
|
|
}
|
|
if (file) {
|
|
return;
|
|
}
|
|
_ref1 = Get.allQuotelinksLinkingTo(this);
|
|
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
|
quotelink = _ref1[_j];
|
|
if (!(!$.hasClass(quotelink, 'deadlink'))) {
|
|
continue;
|
|
}
|
|
$.addClass(quotelink, 'deadlink');
|
|
QuoteMarkers.parseQuotelink(Get.postFromNode(quotelink), quotelink, true);
|
|
}
|
|
};
|
|
|
|
Post.prototype.resurrect = function() {
|
|
var clone, quotelink, strong, _i, _j, _len, _len1, _ref, _ref1;
|
|
delete this.isDead;
|
|
$.rmClass(this.nodes.root, 'deleted-post');
|
|
strong = $('strong.warning', this.nodes.info);
|
|
if (this.file && this.file.isDead) {
|
|
strong.textContent = '[File deleted]';
|
|
} else {
|
|
$.rm(strong);
|
|
}
|
|
if (this.isClone) {
|
|
return;
|
|
}
|
|
_ref = this.clones;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
clone = _ref[_i];
|
|
clone.resurrect();
|
|
}
|
|
_ref1 = Get.allQuotelinksLinkingTo(this);
|
|
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
|
quotelink = _ref1[_j];
|
|
if (!($.hasClass(quotelink, 'deadlink'))) {
|
|
continue;
|
|
}
|
|
$.rmClass(quotelink, 'deadlink');
|
|
QuoteMarkers.parseQuotelink(Get.postFromNode(quotelink), quotelink, true);
|
|
}
|
|
};
|
|
|
|
Post.prototype.collect = function() {
|
|
this.kill();
|
|
g.posts.rm(this.fullID);
|
|
this.thread.posts.rm(this);
|
|
return this.board.posts.rm(this);
|
|
};
|
|
|
|
Post.prototype.addClone = function(context) {
|
|
return new Clone(this, context);
|
|
};
|
|
|
|
Post.prototype.rmClone = function(index) {
|
|
var clone, _i, _len, _ref;
|
|
this.clones.splice(index, 1);
|
|
_ref = this.clones.slice(index);
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
clone = _ref[_i];
|
|
clone.nodes.root.dataset.clone = index++;
|
|
}
|
|
};
|
|
|
|
return Post;
|
|
|
|
})();
|
|
|
|
Clone = (function(_super) {
|
|
__extends(Clone, _super);
|
|
|
|
function Clone(origin, context) {
|
|
var file, info, inline, inlined, key, nodes, post, root, val, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _ref3;
|
|
this.origin = origin;
|
|
this.context = context;
|
|
_ref = ['ID', 'fullID', 'board', 'thread', 'info', 'quotes', 'isReply'];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
key = _ref[_i];
|
|
this[key] = origin[key];
|
|
}
|
|
nodes = origin.nodes;
|
|
root = nodes.root.cloneNode(true);
|
|
post = $('.post', root);
|
|
info = $('.postInfo', post);
|
|
this.nodes = {
|
|
root: root,
|
|
post: post,
|
|
info: info,
|
|
comment: $('.postMessage', post),
|
|
quotelinks: [],
|
|
backlinks: info.getElementsByClassName('backlink')
|
|
};
|
|
_ref1 = $$('.inline', post);
|
|
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
|
inline = _ref1[_j];
|
|
$.rm(inline);
|
|
}
|
|
_ref2 = $$('.inlined', post);
|
|
for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
|
|
inlined = _ref2[_k];
|
|
$.rmClass(inlined, 'inlined');
|
|
}
|
|
root.hidden = post.hidden = false;
|
|
$.rmClass(root, 'forwarded');
|
|
$.rmClass(post, 'highlight');
|
|
if (nodes.subject) {
|
|
this.nodes.subject = $('.subject', info);
|
|
}
|
|
if (nodes.name) {
|
|
this.nodes.name = $('.name', info);
|
|
}
|
|
if (nodes.email) {
|
|
this.nodes.email = $('.useremail', info);
|
|
}
|
|
if (nodes.tripcode) {
|
|
this.nodes.tripcode = $('.postertrip', info);
|
|
}
|
|
if (nodes.uniqueID) {
|
|
this.nodes.uniqueID = $('.posteruid', info);
|
|
}
|
|
if (nodes.capcode) {
|
|
this.nodes.capcode = $('.capcode', info);
|
|
}
|
|
if (nodes.flag) {
|
|
this.nodes.flag = $('.countryFlag', info);
|
|
}
|
|
if (nodes.date) {
|
|
this.nodes.date = $('.dateTime', info);
|
|
}
|
|
this.parseQuotes();
|
|
if (origin.file) {
|
|
this.file = {};
|
|
_ref3 = origin.file;
|
|
for (key in _ref3) {
|
|
val = _ref3[key];
|
|
this.file[key] = val;
|
|
}
|
|
file = $('.file', post);
|
|
this.file.text = file.firstElementChild;
|
|
this.file.thumb = $('img[data-md5]', file);
|
|
this.file.fullImage = $('.full-image', file);
|
|
}
|
|
if (origin.isDead) {
|
|
this.isDead = true;
|
|
}
|
|
this.isClone = true;
|
|
root.dataset.clone = origin.clones.push(this) - 1;
|
|
}
|
|
|
|
return Clone;
|
|
|
|
})(Post);
|
|
|
|
DataBoard = (function() {
|
|
DataBoard.keys = ['pinnedThreads', 'hiddenPosts', 'lastReadPosts', 'yourPosts', 'watchedThreads'];
|
|
|
|
function DataBoard(key, sync, dontClean) {
|
|
var init;
|
|
this.key = key;
|
|
this.onSync = __bind(this.onSync, this);
|
|
this.data = Conf[key];
|
|
$.sync(key, this.onSync);
|
|
if (!dontClean) {
|
|
this.clean();
|
|
}
|
|
if (!sync) {
|
|
return;
|
|
}
|
|
init = (function(_this) {
|
|
return function() {
|
|
$.off(d, '4chanXInitFinished', init);
|
|
return _this.sync = sync;
|
|
};
|
|
})(this);
|
|
$.on(d, '4chanXInitFinished', init);
|
|
}
|
|
|
|
DataBoard.prototype.save = function() {
|
|
return $.set(this.key, this.data);
|
|
};
|
|
|
|
DataBoard.prototype["delete"] = function(_arg) {
|
|
var boardID, postID, threadID;
|
|
boardID = _arg.boardID, threadID = _arg.threadID, postID = _arg.postID;
|
|
if (postID) {
|
|
delete this.data.boards[boardID][threadID][postID];
|
|
this.deleteIfEmpty({
|
|
boardID: boardID,
|
|
threadID: threadID
|
|
});
|
|
} else if (threadID) {
|
|
delete this.data.boards[boardID][threadID];
|
|
this.deleteIfEmpty({
|
|
boardID: boardID
|
|
});
|
|
} else {
|
|
delete this.data.boards[boardID];
|
|
}
|
|
return this.save();
|
|
};
|
|
|
|
DataBoard.prototype.deleteIfEmpty = function(_arg) {
|
|
var boardID, threadID;
|
|
boardID = _arg.boardID, threadID = _arg.threadID;
|
|
if (threadID) {
|
|
if (!Object.keys(this.data.boards[boardID][threadID]).length) {
|
|
delete this.data.boards[boardID][threadID];
|
|
return this.deleteIfEmpty({
|
|
boardID: boardID
|
|
});
|
|
}
|
|
} else if (!Object.keys(this.data.boards[boardID]).length) {
|
|
return delete this.data.boards[boardID];
|
|
}
|
|
};
|
|
|
|
DataBoard.prototype.set = function(_arg) {
|
|
var boardID, postID, threadID, val, _base, _base1, _base2;
|
|
boardID = _arg.boardID, threadID = _arg.threadID, postID = _arg.postID, val = _arg.val;
|
|
if (postID !== void 0) {
|
|
((_base = ((_base1 = this.data.boards)[boardID] || (_base1[boardID] = {})))[threadID] || (_base[threadID] = {}))[postID] = val;
|
|
} else if (threadID !== void 0) {
|
|
((_base2 = this.data.boards)[boardID] || (_base2[boardID] = {}))[threadID] = val;
|
|
} else {
|
|
this.data.boards[boardID] = val;
|
|
}
|
|
return this.save();
|
|
};
|
|
|
|
DataBoard.prototype.get = function(_arg) {
|
|
var ID, board, boardID, defaultValue, postID, thread, threadID, val, _i, _len;
|
|
boardID = _arg.boardID, threadID = _arg.threadID, postID = _arg.postID, defaultValue = _arg.defaultValue;
|
|
if (board = this.data.boards[boardID]) {
|
|
if (!threadID) {
|
|
if (postID) {
|
|
for (thread = _i = 0, _len = board.length; _i < _len; thread = ++_i) {
|
|
ID = board[thread];
|
|
if (postID in thread) {
|
|
val = thread[postID];
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
val = board;
|
|
}
|
|
} else if (thread = board[threadID]) {
|
|
val = postID ? thread[postID] : thread;
|
|
}
|
|
}
|
|
return val || defaultValue;
|
|
};
|
|
|
|
DataBoard.prototype.clean = function() {
|
|
var boardID, keys, now, _i, _len;
|
|
now = Date.now();
|
|
if ((this.data.lastChecked || 0) > now - 2 * $.HOUR) {
|
|
return;
|
|
}
|
|
keys = Object.keys(this.data.boards);
|
|
if (!keys.length) {
|
|
return;
|
|
}
|
|
for (_i = 0, _len = keys.length; _i < _len; _i++) {
|
|
boardID = keys[_i];
|
|
this.deleteIfEmpty({
|
|
boardID: boardID
|
|
});
|
|
if (boardID in this.data.boards) {
|
|
this.ajaxClean(boardID);
|
|
}
|
|
}
|
|
this.data.lastChecked = now;
|
|
return this.save();
|
|
};
|
|
|
|
DataBoard.prototype.ajaxClean = function(boardID) {
|
|
return $.cache("//a.4cdn.org/" + boardID + "/threads.json", (function(_this) {
|
|
return function(e) {
|
|
var board, count, page, thread, threads, _i, _j, _len, _len1, _ref, _ref1;
|
|
if (e.target.status !== 200) {
|
|
if (e.target.status === 404) {
|
|
_this["delete"]({
|
|
boardID: boardID
|
|
});
|
|
}
|
|
return;
|
|
}
|
|
board = _this.data.boards[boardID];
|
|
threads = {};
|
|
_ref = e.target.response;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
page = _ref[_i];
|
|
_ref1 = page.threads;
|
|
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
|
thread = _ref1[_j];
|
|
if (thread.no in board) {
|
|
threads[thread.no] = board[thread.no];
|
|
}
|
|
}
|
|
}
|
|
count = Object.keys(threads).length;
|
|
if (count === Object.keys(board).length) {
|
|
return;
|
|
}
|
|
if (count) {
|
|
return _this.set({
|
|
boardID: boardID,
|
|
val: threads
|
|
});
|
|
} else {
|
|
return _this["delete"]({
|
|
boardID: boardID
|
|
});
|
|
}
|
|
};
|
|
})(this));
|
|
};
|
|
|
|
DataBoard.prototype.onSync = function(data) {
|
|
this.data = data || {
|
|
boards: {}
|
|
};
|
|
return typeof this.sync === "function" ? this.sync() : void 0;
|
|
};
|
|
|
|
DataBoard.prototype.disconnect = function() {
|
|
$.desync(this.key);
|
|
delete this.sync;
|
|
return delete this.data;
|
|
};
|
|
|
|
return DataBoard;
|
|
|
|
})();
|
|
|
|
Notice = (function() {
|
|
function Notice(type, content, timeout) {
|
|
this.timeout = timeout;
|
|
this.close = __bind(this.close, this);
|
|
this.add = __bind(this.add, this);
|
|
this.el = $.el('div', {
|
|
innerHTML: '<a href=javascript:; class="close fa" title=Close>\uf00d</a><div class=message></div>'
|
|
});
|
|
this.el.style.opacity = 0;
|
|
this.setType(type);
|
|
$.on(this.el.firstElementChild, 'click', this.close);
|
|
if (typeof content === 'string') {
|
|
content = $.tn(content);
|
|
}
|
|
$.add(this.el.lastElementChild, content);
|
|
$.ready(this.add);
|
|
}
|
|
|
|
Notice.prototype.setType = function(type) {
|
|
return this.el.className = "notification " + type;
|
|
};
|
|
|
|
Notice.prototype.add = function() {
|
|
if (d.hidden) {
|
|
$.on(d, 'visibilitychange', this.add);
|
|
return;
|
|
}
|
|
$.off(d, 'visibilitychange', this.add);
|
|
$.add(Header.noticesRoot, this.el);
|
|
this.el.clientHeight;
|
|
this.el.style.opacity = 1;
|
|
if (this.timeout) {
|
|
return setTimeout(this.close, this.timeout * $.SECOND);
|
|
}
|
|
};
|
|
|
|
Notice.prototype.close = function() {
|
|
$.off(d, 'visibilitychange', this.add);
|
|
return $.rm(this.el);
|
|
};
|
|
|
|
return Notice;
|
|
|
|
})();
|
|
|
|
RandomAccessList = (function() {
|
|
function RandomAccessList(items) {
|
|
var item, _i, _len;
|
|
this.length = 0;
|
|
if (items) {
|
|
for (_i = 0, _len = items.length; _i < _len; _i++) {
|
|
item = items[_i];
|
|
this.push(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
RandomAccessList.prototype.push = function(data) {
|
|
var ID, item, last;
|
|
ID = data.ID;
|
|
ID || (ID = data.id);
|
|
if (this[ID]) {
|
|
return;
|
|
}
|
|
last = this.last;
|
|
this[ID] = item = {
|
|
prev: last,
|
|
next: null,
|
|
data: data,
|
|
ID: ID
|
|
};
|
|
item.prev = last;
|
|
this.last = last ? last.next = item : this.first = item;
|
|
return this.length++;
|
|
};
|
|
|
|
RandomAccessList.prototype.before = function(root, item) {
|
|
var prev;
|
|
if (item.next === root) {
|
|
return;
|
|
}
|
|
this.rmi(item);
|
|
prev = root.prev;
|
|
root.prev = item;
|
|
item.next = root;
|
|
item.prev = prev;
|
|
if (prev) {
|
|
return prev.next = item;
|
|
}
|
|
};
|
|
|
|
RandomAccessList.prototype.after = function(root, item) {
|
|
var next;
|
|
if (item.prev === root) {
|
|
return;
|
|
}
|
|
this.rmi(item);
|
|
next = root.next;
|
|
root.next = item;
|
|
item.prev = root;
|
|
item.next = next;
|
|
if (next) {
|
|
return next.prev = item;
|
|
}
|
|
};
|
|
|
|
RandomAccessList.prototype.prepend = function(item) {
|
|
var first;
|
|
first = this.first;
|
|
if (item === first || !this[item.ID]) {
|
|
return;
|
|
}
|
|
this.rmi(item);
|
|
item.next = first;
|
|
first.prev = item;
|
|
this.first = item;
|
|
return delete item.prev;
|
|
};
|
|
|
|
RandomAccessList.prototype.shift = function() {
|
|
return this.rm(this.first.ID);
|
|
};
|
|
|
|
RandomAccessList.prototype.order = function() {
|
|
var item, order;
|
|
order = [item = this.first];
|
|
while (item = item.next) {
|
|
order.push(item);
|
|
}
|
|
return order;
|
|
};
|
|
|
|
RandomAccessList.prototype.rm = function(ID) {
|
|
var item;
|
|
item = this[ID];
|
|
if (!item) {
|
|
return;
|
|
}
|
|
delete this[ID];
|
|
this.length--;
|
|
this.rmi(item);
|
|
delete item.next;
|
|
return delete item.prev;
|
|
};
|
|
|
|
RandomAccessList.prototype.rmi = function(item) {
|
|
var next, prev;
|
|
prev = item.prev, next = item.next;
|
|
if (prev) {
|
|
prev.next = next;
|
|
} else {
|
|
this.first = next;
|
|
}
|
|
if (next) {
|
|
return next.prev = prev;
|
|
} else {
|
|
return this.last = prev;
|
|
}
|
|
};
|
|
|
|
return RandomAccessList;
|
|
|
|
})();
|
|
|
|
SimpleDict = (function() {
|
|
function SimpleDict() {
|
|
this.keys = [];
|
|
}
|
|
|
|
SimpleDict.prototype.push = function(key, data) {
|
|
key = "" + key;
|
|
if (!this[key]) {
|
|
this.keys.push(key);
|
|
}
|
|
return this[key] = data;
|
|
};
|
|
|
|
SimpleDict.prototype.rm = function(key) {
|
|
var i;
|
|
key = "" + key;
|
|
if ((i = this.keys.indexOf(key)) !== -1) {
|
|
this.keys.splice(i, 1);
|
|
return delete this[key];
|
|
}
|
|
};
|
|
|
|
SimpleDict.prototype.forEach = function(fn) {
|
|
var key, _i, _len, _ref;
|
|
_ref = __slice.call(this.keys);
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
key = _ref[_i];
|
|
fn(this[key]);
|
|
}
|
|
};
|
|
|
|
return SimpleDict;
|
|
|
|
})();
|
|
|
|
Polyfill = {
|
|
init: function() {},
|
|
notificationPermission: function() {
|
|
if (!window.Notification || 'permission' in Notification || !window.webkitNotifications) {
|
|
return;
|
|
}
|
|
return Object.defineProperty(Notification, 'permission', {
|
|
get: function() {
|
|
switch (webkitNotifications.checkPermission()) {
|
|
case 0:
|
|
return 'granted';
|
|
case 1:
|
|
return 'default';
|
|
case 2:
|
|
return 'denied';
|
|
}
|
|
}
|
|
});
|
|
},
|
|
toBlob: function() {
|
|
var _base;
|
|
return (_base = HTMLCanvasElement.prototype).toBlob || (_base.toBlob = function(cb) {
|
|
var data, i, l, ui8a, _i;
|
|
data = atob(this.toDataURL().slice(22));
|
|
l = data.length;
|
|
ui8a = new Uint8Array(l);
|
|
for (i = _i = 0; _i < l; i = _i += 1) {
|
|
ui8a[i] = data.charCodeAt(i);
|
|
}
|
|
return cb(new Blob([ui8a], {
|
|
type: 'image/png'
|
|
}));
|
|
});
|
|
},
|
|
visibility: function() {
|
|
if ('visibilityState' in d) {
|
|
return;
|
|
}
|
|
Object.defineProperties(HTMLDocument.prototype, {
|
|
visibilityState: {
|
|
get: function() {
|
|
return this.webkitVisibilityState;
|
|
}
|
|
},
|
|
hidden: {
|
|
get: function() {
|
|
return this.webkitHidden;
|
|
}
|
|
}
|
|
});
|
|
return $.on(d, 'webkitvisibilitychange', function() {
|
|
return $.event('visibilitychange');
|
|
});
|
|
}
|
|
};
|
|
|
|
Header = {
|
|
init: function() {
|
|
var barFixedToggler, barPositionToggler, customNavToggler, editCustomNav, headerToggler, menuButton, scrollHeaderToggler;
|
|
this.menu = new UI.Menu('header');
|
|
menuButton = $.el('span', {
|
|
className: 'menu-button a-icon',
|
|
id: 'main-menu'
|
|
});
|
|
barFixedToggler = $.el('label', {
|
|
innerHTML: '<input type=checkbox name="Fixed Header"> Fixed Header'
|
|
});
|
|
headerToggler = $.el('label', {
|
|
innerHTML: '<input type=checkbox name="Header auto-hide"> Auto-hide header'
|
|
});
|
|
scrollHeaderToggler = $.el('label', {
|
|
innerHTML: '<input type=checkbox name="Header auto-hide on scroll"> Auto-hide header on scroll'
|
|
});
|
|
barPositionToggler = $.el('label', {
|
|
innerHTML: '<input type=checkbox name="Bottom Header"> Bottom header'
|
|
});
|
|
customNavToggler = $.el('label', {
|
|
innerHTML: '<input type=checkbox name="Custom Board Navigation"> Custom board navigation'
|
|
});
|
|
editCustomNav = $.el('a', {
|
|
textContent: 'Edit custom board navigation',
|
|
href: 'javascript:;'
|
|
});
|
|
this.barFixedToggler = barFixedToggler.firstElementChild;
|
|
this.scrollHeaderToggler = scrollHeaderToggler.firstElementChild;
|
|
this.barPositionToggler = barPositionToggler.firstElementChild;
|
|
this.headerToggler = headerToggler.firstElementChild;
|
|
this.customNavToggler = customNavToggler.firstElementChild;
|
|
$.on(menuButton, 'click', this.menuToggle);
|
|
$.on(this.headerToggler, 'change', this.toggleBarVisibility);
|
|
$.on(this.barFixedToggler, 'change', this.toggleBarFixed);
|
|
$.on(this.scrollHeaderToggler, 'change', this.setHideBarOnScroll);
|
|
$.on(this.barPositionToggler, 'change', this.toggleBarPosition);
|
|
$.on(this.headerToggler, 'change', this.toggleBarVisibility);
|
|
$.on(this.customNavToggler, 'change', this.toggleCustomNav);
|
|
$.on(editCustomNav, 'click', this.editCustomNav);
|
|
this.setBarFixed(Conf['Fixed Header']);
|
|
this.setHideBarOnScroll(Conf['Header auto-hide on scroll']);
|
|
this.setBarVisibility(Conf['Header auto-hide']);
|
|
$.sync('Fixed Header', this.setBarFixed);
|
|
$.sync('Header auto-hide on scroll', this.setHideBarOnScroll);
|
|
$.sync('Bottom Header', this.setBarPosition);
|
|
$.sync('Header auto-hide', this.setBarVisibility);
|
|
this.addShortcut(menuButton);
|
|
$.event('AddMenuEntry', {
|
|
type: 'header',
|
|
el: $.el('span', {
|
|
textContent: 'Header'
|
|
}),
|
|
order: 107,
|
|
subEntries: [
|
|
{
|
|
el: barFixedToggler
|
|
}, {
|
|
el: headerToggler
|
|
}, {
|
|
el: scrollHeaderToggler
|
|
}, {
|
|
el: barPositionToggler
|
|
}, {
|
|
el: customNavToggler
|
|
}, {
|
|
el: editCustomNav
|
|
}
|
|
]
|
|
});
|
|
$.on(window, 'load hashchange', Header.hashScroll);
|
|
$.on(d, 'CreateNotification', this.createNotification);
|
|
this.enableDesktopNotifications();
|
|
this.addShortcut(menuButton, true);
|
|
$.asap((function() {
|
|
return d.body;
|
|
}), (function(_this) {
|
|
return function() {
|
|
if (!Main.isThisPageLegit()) {
|
|
return;
|
|
}
|
|
$.asap((function() {
|
|
return $.id('boardNavMobile') || d.readyState !== 'loading';
|
|
}), Header.setBoardList);
|
|
$.prepend(d.body, _this.bar);
|
|
$.add(d.body, Header.hover);
|
|
return _this.setBarPosition(Conf['Bottom Header']);
|
|
};
|
|
})(this));
|
|
return $.ready((function(_this) {
|
|
return function() {
|
|
var a, footer, _i, _len, _ref, _results;
|
|
if (a = $("a[href*='/" + g.BOARD + "/']", footer = $.id('boardNavDesktopFoot'))) {
|
|
a.className = 'current';
|
|
}
|
|
if (Conf['JSON Navigation']) {
|
|
_ref = $$('a', footer);
|
|
_results = [];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
a = _ref[_i];
|
|
_results.push($.on(a, 'click', Navigate.navigate));
|
|
}
|
|
return _results;
|
|
}
|
|
};
|
|
})(this));
|
|
},
|
|
bar: $.el('div', {
|
|
id: 'header-bar'
|
|
}),
|
|
noticesRoot: $.el('div', {
|
|
id: 'notifications'
|
|
}),
|
|
stats: $.el('span', {
|
|
id: 'a-stats'
|
|
}),
|
|
icons: $.el('span', {
|
|
id: 'a-icons'
|
|
}),
|
|
hover: $.el('div', {
|
|
id: 'hoverUI'
|
|
}),
|
|
toggle: $.el('div', {
|
|
id: 'scroll-marker'
|
|
}),
|
|
initReady: function() {
|
|
Header.setBoardList();
|
|
return Header.addNav();
|
|
},
|
|
setBoardList: function() {
|
|
var a, boardList, btn, fourchannav, fullBoardList, shortcuts, _i, _len, _ref;
|
|
fourchannav = $.id('boardNavDesktop');
|
|
Header.boardList = boardList = $.el('span', {
|
|
id: 'board-list',
|
|
innerHTML: "<span id=custom-board-list></span><span id=full-board-list hidden><span class='hide-board-list-container brackets-wrap'><a href=javascript:; class='hide-board-list-button'> - </a></span> " + fourchannav.innerHTML + "</span>"
|
|
});
|
|
_ref = $$('a', boardList);
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
a = _ref[_i];
|
|
if (Conf['JSON Navigation']) {
|
|
$.on(a, 'click', Navigate.navigate);
|
|
}
|
|
if (a.pathname.split('/')[1] === g.BOARD.ID) {
|
|
a.className = 'current';
|
|
}
|
|
}
|
|
fullBoardList = $('#full-board-list', boardList);
|
|
btn = $('.hide-board-list-button', fullBoardList);
|
|
$.on(btn, 'click', Header.toggleBoardList);
|
|
$.rm($('#navtopright', fullBoardList));
|
|
shortcuts = $.el('span', {
|
|
id: 'shortcuts'
|
|
});
|
|
$.add(shortcuts, [Header.stats, Header.icons]);
|
|
$.prepend(d.body, shortcuts);
|
|
$.add(boardList, fullBoardList);
|
|
$.add(Header.bar, [Header.boardList, Header.toggle]);
|
|
Header.setCustomNav(Conf['Custom Board Navigation']);
|
|
Header.generateBoardList(Conf['boardnav'].replace(/(\r\n|\n|\r)/g, ' '));
|
|
$.sync('Custom Board Navigation', Header.setCustomNav);
|
|
return $.sync('boardnav', Header.generateBoardList);
|
|
},
|
|
generateBoardList: function(text) {
|
|
var as, list, nodes, re;
|
|
list = $('#custom-board-list', Header.boardList);
|
|
$.rmAll(list);
|
|
if (!text) {
|
|
return;
|
|
}
|
|
as = $$('#full-board-list a[title]', Header.boardList);
|
|
re = /[\w@]+(-(all|title|replace|full|archive|(mode|sort|text|url):"[^"]+"(\,"[^"]+[^"]")?))*|[^\w@]+/g;
|
|
nodes = text.match(re).map(function(t) {
|
|
var a, board, boardID, href, m, type, _i, _len;
|
|
if (/^[^\w@]/.test(t)) {
|
|
return $.tn(t);
|
|
}
|
|
if (/^toggle-all/.test(t)) {
|
|
a = $.el('a', {
|
|
className: 'show-board-list-button',
|
|
textContent: (t.match(/-text:"(.+)"/) || [null, '+'])[1],
|
|
href: 'javascript:;'
|
|
});
|
|
$.on(a, 'click', Header.toggleBoardList);
|
|
return a;
|
|
}
|
|
if (/^external/.test(t)) {
|
|
a = $.el('a', {
|
|
href: (t.match(/\,"(.+)"/) || [null, '+'])[1],
|
|
textContent: (t.match(/-text:"(.+)"\,/) || [null, '+'])[1],
|
|
className: 'external'
|
|
});
|
|
return a;
|
|
}
|
|
board = /^current/.test(t) ? g.BOARD.ID : t.match(/^[^-]+/)[0];
|
|
boardID = t.split('-')[0];
|
|
if (boardID === 'current') {
|
|
boardID = g.BOARD.ID;
|
|
}
|
|
for (_i = 0, _len = as.length; _i < _len; _i++) {
|
|
a = as[_i];
|
|
if (!(a.textContent === boardID)) {
|
|
continue;
|
|
}
|
|
a = a.cloneNode();
|
|
break;
|
|
}
|
|
if (a.parentNode) {
|
|
return $.tn(boardID);
|
|
}
|
|
if (Conf['JSON Navigation']) {
|
|
$.on(a, 'click', Navigate.navigate);
|
|
}
|
|
a.textContent = /-title/.test(t) || /-replace/.test(t) && boardID === g.BOARD.ID ? a.title : /-full/.test(t) ? "/" + boardID + "/ - " + a.title : (m = t.match(/-text:"([^"]+)"/)) ? m[1] : boardID;
|
|
if (/-archive/.test(t)) {
|
|
if (href = Redirect.to('board', {
|
|
boardID: boardID
|
|
})) {
|
|
a.href = href;
|
|
} else {
|
|
return a.firstChild;
|
|
}
|
|
}
|
|
if (m = t.match(/-mode:"([^"]+)"/)) {
|
|
type = m[1].toLowerCase();
|
|
a.dataset.indexMode = (function() {
|
|
switch (type) {
|
|
case 'all threads':
|
|
return 'all pages';
|
|
case 'paged':
|
|
case 'catalog':
|
|
return type;
|
|
default:
|
|
return 'paged';
|
|
}
|
|
})();
|
|
}
|
|
if (m = t.match(/-sort:"([^"]+)"/)) {
|
|
type = m[1].toLowerCase();
|
|
a.dataset.indexSort = (function() {
|
|
switch (type) {
|
|
case 'bump order':
|
|
return 'bump';
|
|
case 'last reply':
|
|
return 'lastreply';
|
|
case 'creation date':
|
|
return 'birth';
|
|
case 'reply count':
|
|
return 'replycount';
|
|
case 'file count':
|
|
return 'filecount';
|
|
default:
|
|
return 'bump';
|
|
}
|
|
})();
|
|
}
|
|
if (boardID === '@') {
|
|
$.addClass(a, 'navSmall');
|
|
}
|
|
return a;
|
|
});
|
|
return $.add(list, nodes);
|
|
},
|
|
toggleBoardList: function() {
|
|
var bar, custom, full, showBoardList;
|
|
bar = Header.bar;
|
|
custom = $('#custom-board-list', bar);
|
|
full = $('#full-board-list', bar);
|
|
showBoardList = !full.hidden;
|
|
custom.hidden = !showBoardList;
|
|
return full.hidden = showBoardList;
|
|
},
|
|
setBarFixed: function(fixed) {
|
|
Header.barFixedToggler.checked = fixed;
|
|
if (fixed) {
|
|
$.addClass(doc, 'fixed');
|
|
return $.addClass(Header.bar, 'dialog');
|
|
} else {
|
|
$.rmClass(doc, 'fixed');
|
|
return $.rmClass(Header.bar, 'dialog');
|
|
}
|
|
},
|
|
toggleBarFixed: function() {
|
|
$.event('CloseMenu');
|
|
Header.setBarFixed(this.checked);
|
|
Conf['Fixed Header'] = this.checked;
|
|
return $.set('Fixed Header', this.checked);
|
|
},
|
|
setBarVisibility: function(hide) {
|
|
Header.headerToggler.checked = hide;
|
|
return (hide ? $.addClass : $.rmClass)(Header.bar, 'autohide');
|
|
},
|
|
toggleBarVisibility: function(e) {
|
|
var hide;
|
|
hide = this.checked;
|
|
Conf['Header auto-hide'] = hide;
|
|
$.set('Header auto-hide', hide);
|
|
return Header.setBarVisibility(hide);
|
|
},
|
|
setHideBarOnScroll: function(hide) {
|
|
Header.scrollHeaderToggler.checked = hide;
|
|
if (hide) {
|
|
$.on(window, 'scroll', Header.hideBarOnScroll);
|
|
return;
|
|
}
|
|
$.off(window, 'scroll', Header.hideBarOnScroll);
|
|
$.rmClass(Header.bar, 'scroll');
|
|
if (!Conf['Header auto-hide']) {
|
|
return $.rmClass(Header.bar, 'autohide');
|
|
}
|
|
},
|
|
toggleHideBarOnScroll: function(e) {
|
|
var hide;
|
|
hide = this.checked;
|
|
$.cb.checked.call(this);
|
|
return Header.setHideBarOnScroll(hide);
|
|
},
|
|
hideBarOnScroll: function() {
|
|
var offsetY;
|
|
offsetY = window.pageYOffset;
|
|
if (offsetY > (Header.previousOffset || 0)) {
|
|
$.addClass(Header.bar, 'autohide', 'scroll');
|
|
} else {
|
|
$.rmClass(Header.bar, 'autohide', 'scroll');
|
|
}
|
|
return Header.previousOffset = offsetY;
|
|
},
|
|
setBarPosition: function(bottom) {
|
|
var args;
|
|
Header.barPositionToggler.checked = bottom;
|
|
$.event('CloseMenu');
|
|
args = bottom ? ['bottom-header', 'top-header', 'bottom', 'after'] : ['top-header', 'bottom-header', 'top', 'add'];
|
|
$.addClass(doc, args[0]);
|
|
$.rmClass(doc, args[1]);
|
|
Header.bar.parentNode.className = args[2];
|
|
return $[args[3]](Header.bar, Header.noticesRoot);
|
|
},
|
|
toggleBarPosition: function() {
|
|
$.cb.checked.call(this);
|
|
return Header.setBarPosition(this.checked);
|
|
},
|
|
setCustomNav: function(show) {
|
|
var btn, cust, full, _ref;
|
|
Header.customNavToggler.checked = show;
|
|
cust = $('#custom-board-list', Header.bar);
|
|
full = $('#full-board-list', Header.bar);
|
|
btn = $('.hide-board-list-button', full);
|
|
return _ref = show ? [false, true] : [true, false], cust.hidden = _ref[0], full.hidden = _ref[1], _ref;
|
|
},
|
|
toggleCustomNav: function() {
|
|
$.cb.checked.call(this);
|
|
return Header.setCustomNav(this.checked);
|
|
},
|
|
editCustomNav: function() {
|
|
var settings;
|
|
Settings.open('Advanced');
|
|
settings = $.id('fourchanx-settings');
|
|
return $('input[name=boardnav]', settings).focus();
|
|
},
|
|
hashScroll: function() {
|
|
var hash, post;
|
|
hash = this.location.hash.slice(1);
|
|
if (!(/^p\d+$/.test(hash) && (post = $.id(hash)))) {
|
|
return;
|
|
}
|
|
if ((Get.postFromNode(post)).isHidden) {
|
|
return;
|
|
}
|
|
return Header.scrollTo(post);
|
|
},
|
|
scrollTo: function(root, down, needed) {
|
|
var height, x;
|
|
if (down) {
|
|
x = Header.getBottomOf(root);
|
|
if (Conf['Header auto-hide on scroll'] && Conf['Bottom header']) {
|
|
height = Header.bar.getBoundingClientRect().height;
|
|
if (x <= 0) {
|
|
if (!Header.isHidden()) {
|
|
x += height;
|
|
}
|
|
} else {
|
|
if (Header.isHidden()) {
|
|
x -= height;
|
|
}
|
|
}
|
|
}
|
|
if (!(needed && x >= 0)) {
|
|
return window.scrollBy(0, -x);
|
|
}
|
|
} else {
|
|
x = Header.getTopOf(root);
|
|
if (Conf['Header auto-hide on scroll'] && !Conf['Bottom header']) {
|
|
height = Header.bar.getBoundingClientRect().height;
|
|
if (x >= 0) {
|
|
if (!Header.isHidden()) {
|
|
x += height;
|
|
}
|
|
} else {
|
|
if (Header.isHidden()) {
|
|
x -= height;
|
|
}
|
|
}
|
|
}
|
|
if (!(needed && x >= 0)) {
|
|
return window.scrollBy(0, x);
|
|
}
|
|
}
|
|
},
|
|
scrollToIfNeeded: function(root, down) {
|
|
return Header.scrollTo(root, down, true);
|
|
},
|
|
getTopOf: function(root) {
|
|
var headRect, top;
|
|
top = root.getBoundingClientRect().top;
|
|
if (Conf['Fixed Header'] && !Conf['Bottom Header']) {
|
|
headRect = Header.toggle.getBoundingClientRect();
|
|
top -= headRect.top + headRect.height - 10;
|
|
}
|
|
return top;
|
|
},
|
|
getBottomOf: function(root) {
|
|
var bottom, clientHeight, headRect;
|
|
clientHeight = doc.clientHeight;
|
|
bottom = clientHeight - root.getBoundingClientRect().bottom;
|
|
if (Conf['Bottom Header']) {
|
|
headRect = Header.toggle.getBoundingClientRect();
|
|
bottom -= clientHeight - headRect.bottom + headRect.height - 10;
|
|
}
|
|
return bottom;
|
|
},
|
|
isHidden: function() {
|
|
var top;
|
|
top = Header.bar.getBoundingClientRect().top;
|
|
if (Conf['Bottom header']) {
|
|
return top === doc.clientHeight;
|
|
} else {
|
|
return top < 0;
|
|
}
|
|
},
|
|
addShortcut: function(el, icon) {
|
|
$.addClass(el, 'shortcut');
|
|
return $.add(Header[icon ? 'icons' : 'stats'], el);
|
|
},
|
|
rmShortcut: function(el, icon) {
|
|
return $.rm(icon ? el.parentElement : el);
|
|
},
|
|
menuToggle: function(e) {
|
|
return Header.menu.toggle(e, this, g);
|
|
},
|
|
createNotification: function(e) {
|
|
var cb, content, lifetime, notice, type, _ref;
|
|
_ref = e.detail, type = _ref.type, content = _ref.content, lifetime = _ref.lifetime, cb = _ref.cb;
|
|
notice = new Notice(type, content, lifetime);
|
|
if (cb) {
|
|
return cb(notice);
|
|
}
|
|
},
|
|
areNotificationsEnabled: false,
|
|
enableDesktopNotifications: function() {
|
|
var authorize, disable, el, notice, _ref;
|
|
if (!(window.Notification && Conf['Desktop Notifications'])) {
|
|
return;
|
|
}
|
|
switch (Notification.permission) {
|
|
case 'granted':
|
|
Header.areNotificationsEnabled = true;
|
|
return;
|
|
case 'denied':
|
|
return;
|
|
}
|
|
el = $.el('span', {
|
|
innerHTML: "Desktop notification permissions are not granted.\n[<a href='https://github.com/MayhemYDG/4chan-x/wiki/FAQ#desktop-notifications' target=_blank>FAQ</a>]<br>\n<button>Authorize</button> or <button>Disable</button>"
|
|
});
|
|
_ref = $$('button', el), authorize = _ref[0], disable = _ref[1];
|
|
$.on(authorize, 'click', function() {
|
|
return Notification.requestPermission(function(status) {
|
|
Header.areNotificationsEnabled = status === 'granted';
|
|
if (status === 'default') {
|
|
return;
|
|
}
|
|
return notice.close();
|
|
});
|
|
});
|
|
$.on(disable, 'click', function() {
|
|
$.set('Desktop Notifications', false);
|
|
return notice.close();
|
|
});
|
|
return notice = new Notice('info', el);
|
|
}
|
|
};
|
|
|
|
Index = {
|
|
showHiddenThreads: false,
|
|
init: function() {
|
|
var input, label, modeEntry, name, refNavEntry, repliesEntry, returnLink, select, sortEntry, targetEntry, threadNumEntry, threadsNumInput, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2;
|
|
if (g.BOARD.ID === 'f' || !Conf['JSON Navigation']) {
|
|
return;
|
|
}
|
|
this.board = "" + g.BOARD;
|
|
this.button = $.el('a', {
|
|
className: 'index-refresh-shortcut fa',
|
|
title: 'Refresh Index',
|
|
href: 'javascript:;',
|
|
textContent: "\uf021"
|
|
});
|
|
$.on(this.button, 'click', this.update);
|
|
Header.addShortcut(this.button, 1);
|
|
this.db = new DataBoard('pinnedThreads');
|
|
Thread.callbacks.push({
|
|
name: 'Thread Pinning',
|
|
cb: this.threadNode
|
|
});
|
|
CatalogThread.callbacks.push({
|
|
name: 'Catalog Features',
|
|
cb: this.catalogNode
|
|
});
|
|
modeEntry = {
|
|
el: $.el('span', {
|
|
textContent: 'Index mode'
|
|
}),
|
|
subEntries: [
|
|
{
|
|
el: $.el('label', {
|
|
innerHTML: '<input type=radio name="Index Mode" value="paged"> Paged'
|
|
})
|
|
}, {
|
|
el: $.el('label', {
|
|
innerHTML: '<input type=radio name="Index Mode" value="infinite"> Infinite scrolling'
|
|
})
|
|
}, {
|
|
el: $.el('label', {
|
|
innerHTML: '<input type=radio name="Index Mode" value="all pages"> All threads'
|
|
})
|
|
}
|
|
]
|
|
};
|
|
_ref = modeEntry.subEntries;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
label = _ref[_i];
|
|
input = label.el.firstChild;
|
|
input.checked = Conf['Index Mode'] === input.value;
|
|
$.on(input, 'change', $.cb.value);
|
|
$.on(input, 'change', this.cb.mode);
|
|
}
|
|
sortEntry = {
|
|
el: $.el('span', {
|
|
textContent: 'Sort by'
|
|
})
|
|
};
|
|
threadNumEntry = {
|
|
el: $.el('span', {
|
|
textContent: 'Threads per page'
|
|
}),
|
|
subEntries: [
|
|
{
|
|
el: $.el('label', {
|
|
innerHTML: '<input type=number min=0 name="Threads per Page">',
|
|
title: 'Use 0 for default value'
|
|
})
|
|
}
|
|
]
|
|
};
|
|
threadsNumInput = threadNumEntry.subEntries[0].el.firstChild;
|
|
threadsNumInput.value = Conf['Threads per Page'];
|
|
$.on(threadsNumInput, 'change', $.cb.value);
|
|
$.on(threadsNumInput, 'change', this.cb.threadsNum);
|
|
targetEntry = {
|
|
el: $.el('label', {
|
|
innerHTML: '<input type=checkbox name="Open threads in a new tab"> Open threads in a new tab',
|
|
title: 'Catalog-only setting.'
|
|
})
|
|
};
|
|
repliesEntry = {
|
|
el: $.el('label', {
|
|
innerHTML: '<input type=checkbox name="Show Replies"> Show replies'
|
|
})
|
|
};
|
|
refNavEntry = {
|
|
el: $.el('label', {
|
|
innerHTML: '<input type=checkbox name="Refreshed Navigation"> Refreshed navigation',
|
|
title: 'Refresh index when navigating through pages.'
|
|
})
|
|
};
|
|
_ref1 = [targetEntry, repliesEntry, refNavEntry];
|
|
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
|
label = _ref1[_j];
|
|
input = label.el.firstChild;
|
|
name = input.name;
|
|
input.checked = Conf[name];
|
|
$.on(input, 'change', $.cb.checked);
|
|
switch (name) {
|
|
case 'Open threads in a new tab':
|
|
$.on(input, 'change', this.cb.target);
|
|
break;
|
|
case 'Show Replies':
|
|
$.on(input, 'change', this.cb.replies);
|
|
}
|
|
}
|
|
$.event('AddMenuEntry', {
|
|
type: 'header',
|
|
el: $.el('span', {
|
|
textContent: 'Index Navigation'
|
|
}),
|
|
order: 98,
|
|
subEntries: [threadNumEntry, targetEntry, repliesEntry, refNavEntry]
|
|
});
|
|
$.addClass(doc, 'index-loading');
|
|
this.root = $.el('div', {
|
|
className: 'board'
|
|
});
|
|
this.pagelist = $.el('div', {
|
|
className: 'pagelist',
|
|
hidden: true,
|
|
innerHTML: "<div class=\"prev\"><a><</a></div><div class=\"pages\"></div><div class=\"next\"><a>></a></div>"
|
|
});
|
|
this.navLinks = $.el('div', {
|
|
className: 'navLinks',
|
|
innerHTML: "<span id=\"index-menu\"><input type=\"search\" id=\"index-search\" class=\"field\" placeholder=\"Search\"><a id=\"index-search-clear\" class=\"fa fa-times-circle\" href=\"javascript:;\"></a> <time id=\"index-last-refresh\" title=\"Last index refresh\">...</time><span id=\"hidden-label\" hidden> — <span id=\"hidden-count\"></span> <span id=\"hidden-toggle\">[<a href=\"javascript:;\">Show</a>]</span></span><span style='flex: 1'></span><select id=\"index-mode\" name=\"Index Mode\"><option disabled>Index Mode</option><option value=\"paged\">Paged</option><option value=\"infinite\">Infinite Scrolling</option><option value=\"all pages\">All threads</option><option value=\"catalog\">Catalog</option></select><select id=\"index-sort\" name=\"Index Sort\"><option disabled>Index Sort</option><option value=\"bump\">Bump order</option><option value=\"lastreply\">Last reply</option><option value=\"birth\">Creation date</option><option value=\"replycount\">Reply count</option><option value=\"filecount\">File count</option></select><select id=\"index-size\" name=\"Index Size\"><option disabled>Image Size</option><option value=\"small\">Small</option><option value=\"large\">Large</option></select></span>"
|
|
});
|
|
this.searchInput = $('#index-search', this.navLinks);
|
|
this.searchTest(true);
|
|
this.hideLabel = $('#hidden-label', this.navLinks);
|
|
this.selectMode = $('#index-mode', this.navLinks);
|
|
this.selectSort = $('#index-sort', this.navLinks);
|
|
this.selectSize = $('#index-size', this.navLinks);
|
|
$.on(this.searchInput, 'input', this.onSearchInput);
|
|
$.on($('#index-search-clear', this.navLinks), 'click', this.clearSearch);
|
|
$.on($('#hidden-toggle a', this.navLinks), 'click', this.cb.toggleHiddenThreads);
|
|
_ref2 = [this.selectMode, this.selectSort, this.selectSize];
|
|
for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
|
|
select = _ref2[_k];
|
|
select.value = Conf[select.name];
|
|
$.on(select, 'change', $.cb.value);
|
|
}
|
|
$.on(this.selectMode, 'change', this.cb.mode);
|
|
$.on(this.selectSort, 'change', this.cb.sort);
|
|
$.on(this.selectSize, 'change', this.cb.size);
|
|
Rice.nodes(this.navLinks);
|
|
this.currentPage = this.getCurrentPage();
|
|
$.on(d, 'scroll', Index.scroll);
|
|
$.on(this.pagelist, 'click', this.cb.pageNav);
|
|
returnLink = $.el('a', {
|
|
id: 'returnIcon',
|
|
className: 'a-icon',
|
|
href: '.././'
|
|
});
|
|
this.catalogLink = $.el('a', {
|
|
id: 'catalogIcon',
|
|
className: 'a-icon',
|
|
href: "//boards.4chan.org/" + g.BOARD.ID + "/"
|
|
});
|
|
this.catalogLink.dataset.indexMode = 'catalog';
|
|
$.on(returnLink, 'click', function(e) {
|
|
if (g.VIEW === 'index') {
|
|
Index.setIndexMode(Conf['Previous Index Mode']);
|
|
e.preventDefault();
|
|
return;
|
|
}
|
|
return Navigate.navigate.call(this, e);
|
|
});
|
|
$.on(this.catalogLink, 'click', Navigate.navigate);
|
|
Header.addShortcut(this.catalogLink, true);
|
|
Header.addShortcut(returnLink, true);
|
|
if (g.VIEW === 'index') {
|
|
this.update();
|
|
this.cb.toggleCatalogMode();
|
|
}
|
|
$.asap((function() {
|
|
return $('.board', doc) || d.readyState !== 'loading';
|
|
}), function() {
|
|
var board, navLink, _l, _len3, _ref3;
|
|
_ref3 = $$('.navLinks');
|
|
for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) {
|
|
navLink = _ref3[_l];
|
|
$.rm(navLink);
|
|
}
|
|
$.after($.x('child::form/preceding-sibling::hr[1]'), Index.navLinks);
|
|
if (g.VIEW !== 'index') {
|
|
return;
|
|
}
|
|
board = $('.board');
|
|
$.replace(board, Index.root);
|
|
return d.implementation.createDocument(null, null, null).appendChild(board);
|
|
});
|
|
return $.asap((function() {
|
|
return $('.pagelist', doc) || d.readyState !== 'loading';
|
|
}), function() {
|
|
var pagelist;
|
|
if (pagelist = $('.pagelist')) {
|
|
$.replace(pagelist, Index.pagelist);
|
|
} else {
|
|
$.after($.id('delform'), Index.pagelist);
|
|
}
|
|
return $.rmClass(doc, 'index-loading');
|
|
});
|
|
},
|
|
scroll: function() {
|
|
if (Index.req || Conf['Index Mode'] !== 'infinite' || (window.scrollY <= doc.scrollHeight - (300 + window.innerHeight)) || g.VIEW === 'thread') {
|
|
return;
|
|
}
|
|
Index.pageNum = (Index.pageNum || Index.getCurrentPage()) + 1;
|
|
if (Index.pageNum >= Index.pagesNum) {
|
|
return Index.endNotice();
|
|
}
|
|
return Index.buildIndex(true);
|
|
},
|
|
endNotice: (function() {
|
|
var notify, reset;
|
|
notify = false;
|
|
reset = function() {
|
|
return notify = false;
|
|
};
|
|
return function() {
|
|
if (notify) {
|
|
return;
|
|
}
|
|
notify = true;
|
|
new Notice('info', "Last page reached.", 2);
|
|
return setTimeout(reset, 3 * $.SECOND);
|
|
};
|
|
})(),
|
|
menu: {
|
|
init: function() {
|
|
if (g.VIEW !== 'index' || !Conf['Menu'] || g.BOARD.ID === 'f') {
|
|
return;
|
|
}
|
|
return $.event('AddMenuEntry', {
|
|
type: 'post',
|
|
el: $.el('a', {
|
|
href: 'javascript:;'
|
|
}),
|
|
order: 19,
|
|
open: function(_arg) {
|
|
var thread;
|
|
thread = _arg.thread;
|
|
if (Conf['Index Mode'] !== 'catalog') {
|
|
return false;
|
|
}
|
|
this.el.textContent = thread.isPinned ? 'Unpin thread' : 'Pin thread';
|
|
if (this.cb) {
|
|
$.off(this.el, 'click', this.cb);
|
|
}
|
|
this.cb = function() {
|
|
$.event('CloseMenu');
|
|
return Index.togglePin(thread);
|
|
};
|
|
$.on(this.el, 'click', this.cb);
|
|
return true;
|
|
}
|
|
});
|
|
}
|
|
},
|
|
threadNode: function() {
|
|
if (g.VIEW !== 'index') {
|
|
return;
|
|
}
|
|
if (!Index.db.get({
|
|
boardID: this.board.ID,
|
|
threadID: this.ID
|
|
})) {
|
|
return;
|
|
}
|
|
return this.pin();
|
|
},
|
|
catalogNode: function() {
|
|
$.on(this.nodes.thumb, 'click', Index.onClick);
|
|
if (Conf['Image Hover in Catalog']) {
|
|
return;
|
|
}
|
|
return $.on(this.nodes.thumb, 'mouseover', Index.onOver);
|
|
},
|
|
onClick: function(e) {
|
|
var thread;
|
|
if (e.button !== 0) {
|
|
return;
|
|
}
|
|
thread = g.threads[this.parentNode.dataset.fullID];
|
|
if (e.shiftKey) {
|
|
PostHiding.toggle(thread.OP);
|
|
} else if (e.altKey) {
|
|
Index.togglePin(thread);
|
|
} else {
|
|
Navigate.navigate.call(this);
|
|
}
|
|
return e.preventDefault();
|
|
},
|
|
onOver: function(e) {
|
|
var el, nodes;
|
|
nodes = g.threads[this.parentNode.dataset.fullID].OP.nodes;
|
|
el = $.el('div', {
|
|
innerHTML: '<div class=post><div class=postInfo></div></div>',
|
|
className: 'thread-info dialog',
|
|
hidden: true
|
|
});
|
|
$.add(el.firstElementChild.firstElementChild, [$('.nameBlock', nodes.info).cloneNode(true), $.tn(' '), nodes.date.cloneNode(true)]);
|
|
$.add(Header.hover, el);
|
|
UI.hover({
|
|
root: this,
|
|
el: el,
|
|
latestEvent: e,
|
|
endEvents: 'mouseout',
|
|
offsetX: 15,
|
|
offsetY: -20
|
|
});
|
|
return setTimeout((function() {
|
|
if (el.parentNode) {
|
|
return el.hidden = false;
|
|
}
|
|
}), .25 * $.SECOND);
|
|
},
|
|
togglePin: function(thread) {
|
|
var data;
|
|
data = {
|
|
boardID: thread.board.ID,
|
|
threadID: thread.ID
|
|
};
|
|
if (thread.isPinned) {
|
|
thread.unpin();
|
|
Index.db["delete"](data);
|
|
} else {
|
|
thread.pin();
|
|
data.val = true;
|
|
Index.db.set(data);
|
|
}
|
|
Index.sort();
|
|
return Index.buildIndex();
|
|
},
|
|
setIndexMode: function(mode) {
|
|
Index.selectMode.value = mode;
|
|
return $.event('change', null, Index.selectMode);
|
|
},
|
|
cycleSortType: function() {
|
|
var i, option, type, types, _i, _len;
|
|
types = [];
|
|
i = 0;
|
|
while (option = Index.selectSort.options[i++]) {
|
|
if (!option.disabled) {
|
|
types.push(option);
|
|
}
|
|
}
|
|
for (i = _i = 0, _len = types.length; _i < _len; i = ++_i) {
|
|
type = types[i];
|
|
if (type.selected) {
|
|
break;
|
|
}
|
|
}
|
|
types[(i + 1) % types.length].selected = true;
|
|
return $.event('change', null, Index.selectSort);
|
|
},
|
|
catalogSwitch: function() {
|
|
return $.get('JSON Navigation', true, function(items) {
|
|
var hash;
|
|
if (!items['JSON Navigation']) {
|
|
return;
|
|
}
|
|
$.set('Index Mode', 'catalog');
|
|
hash = window.location.hash;
|
|
return window.location = './' + hash;
|
|
});
|
|
},
|
|
searchTest: function(init) {
|
|
var hash, match;
|
|
if (!(hash = window.location.hash)) {
|
|
return false;
|
|
}
|
|
if (!(match = hash.match(/s=([\w]+)/))) {
|
|
return false;
|
|
}
|
|
this.searchInput.value = match[1];
|
|
if (init) {
|
|
$.on(d, '4chanXInitFinished', Index.onSearchInput);
|
|
} else {
|
|
Index.onSearchInput();
|
|
}
|
|
return true;
|
|
},
|
|
setupNavLinks: function() {
|
|
var el, _i, _len, _ref;
|
|
_ref = $$('.navLinks.desktop > a');
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
el = _ref[_i];
|
|
if (el.getAttribute('href') === '.././catalog') {
|
|
el.href = '.././';
|
|
}
|
|
$.on(el, 'click', function() {
|
|
switch (this.textContent) {
|
|
case 'Return':
|
|
return $.set('Index Mode', Conf['Previous Index Mode']);
|
|
case 'Catalog':
|
|
return $.set('Index Mode', 'catalog');
|
|
}
|
|
});
|
|
}
|
|
},
|
|
cb: {
|
|
toggleCatalogMode: function() {
|
|
if (Conf['Index Mode'] === 'catalog') {
|
|
$.addClass(doc, 'catalog-mode');
|
|
} else {
|
|
$.rmClass(doc, 'catalog-mode');
|
|
}
|
|
return Index.cb.size();
|
|
},
|
|
toggleHiddenThreads: function() {
|
|
$('#hidden-toggle a', Index.navLinks).textContent = (Index.showHiddenThreads = !Index.showHiddenThreads) ? 'Hide' : 'Show';
|
|
Index.sort();
|
|
if (Conf['Index Mode'] === 'paged' && Index.getCurrentPage() > 0) {
|
|
return Index.pageNav(0);
|
|
} else {
|
|
return Index.buildIndex();
|
|
}
|
|
},
|
|
mode: function(e) {
|
|
var mode;
|
|
Index.cb.toggleCatalogMode();
|
|
Index.togglePagelist();
|
|
if (e) {
|
|
Index.buildIndex();
|
|
}
|
|
mode = Conf['Index Mode'];
|
|
if (mode !== 'catalog' && mode !== Conf['Previous Index Mode']) {
|
|
Conf['Previous Index Mode'] = mode;
|
|
return $.set('Previous Index Mode', mode);
|
|
}
|
|
},
|
|
sort: function(e) {
|
|
Index.sort();
|
|
if (e) {
|
|
return Index.buildIndex();
|
|
}
|
|
},
|
|
size: function(e) {
|
|
if (Conf['Index Mode'] !== 'catalog') {
|
|
$.rmClass(Index.root, 'catalog-small');
|
|
$.rmClass(Index.root, 'catalog-large');
|
|
} else if (Conf['Index Size'] === 'small') {
|
|
$.addClass(Index.root, 'catalog-small');
|
|
$.rmClass(Index.root, 'catalog-large');
|
|
} else {
|
|
$.addClass(Index.root, 'catalog-large');
|
|
$.rmClass(Index.root, 'catalog-small');
|
|
}
|
|
if (e) {
|
|
return Index.buildIndex();
|
|
}
|
|
},
|
|
threadsNum: function() {
|
|
if (Conf['Index Mode'] !== 'paged') {
|
|
return;
|
|
}
|
|
return Index.buildIndex();
|
|
},
|
|
target: function() {
|
|
return g.BOARD.threads.forEach(function(thread) {
|
|
var thumb;
|
|
if (!thread.catalogView) {
|
|
return;
|
|
}
|
|
thumb = thread.catalogView.nodes.thumb;
|
|
if (Conf['Open threads in a new tab']) {
|
|
return thumb.target = '_blank';
|
|
} else {
|
|
return thumb.removeAttribute('target');
|
|
}
|
|
});
|
|
},
|
|
replies: function() {
|
|
Index.buildThreads();
|
|
Index.sort();
|
|
return Index.buildIndex();
|
|
},
|
|
pageNav: function(e) {
|
|
var a;
|
|
if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) {
|
|
return;
|
|
}
|
|
switch (e.target.nodeName) {
|
|
case 'BUTTON':
|
|
a = e.target.parentNode;
|
|
break;
|
|
case 'A':
|
|
a = e.target;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
e.preventDefault();
|
|
if (Index.cb.indexNav(a, true)) {
|
|
return;
|
|
}
|
|
return Index.userPageNav(+a.pathname.split('/')[2]);
|
|
},
|
|
headerNav: function(e) {
|
|
var a, needChange, onSameIndex;
|
|
a = e.target;
|
|
if (e.button !== 0 || a.nodeName !== 'A' || a.hostname !== 'boards.4chan.org') {
|
|
return;
|
|
}
|
|
onSameIndex = g.VIEW === 'index' && a.pathname.split('/')[1] === g.BOARD.ID;
|
|
needChange = Index.cb.indexNav(a, onSameIndex);
|
|
if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || !onSameIndex) {
|
|
return;
|
|
}
|
|
e.preventDefault();
|
|
if (!needChange) {
|
|
return Index.update();
|
|
}
|
|
},
|
|
indexNav: function(a, onSameIndex) {
|
|
var indexMode, indexSort, needChange, _ref;
|
|
_ref = a.dataset, indexMode = _ref.indexMode, indexSort = _ref.indexSort;
|
|
if (indexMode && Conf['Index Mode'] !== indexMode) {
|
|
$.set('Index Mode', indexMode);
|
|
Conf['Index Mode'] = indexMode;
|
|
if (onSameIndex) {
|
|
Index.selectMode.value = indexMode;
|
|
Index.cb.mode();
|
|
needChange = true;
|
|
}
|
|
}
|
|
if (indexSort && Conf['Index Sort'] !== indexSort) {
|
|
$.set('Index Sort', indexSort);
|
|
Conf['Index Sort'] = indexSort;
|
|
if (onSameIndex) {
|
|
Index.selectSort.value = indexSort;
|
|
Index.cb.sort();
|
|
needChange = true;
|
|
}
|
|
}
|
|
if (needChange) {
|
|
Index.buildIndex();
|
|
Index.scrollToIndex();
|
|
}
|
|
return needChange;
|
|
}
|
|
},
|
|
scrollToIndex: function() {
|
|
return Header.scrollToIfNeeded(Index.navLinks);
|
|
},
|
|
getCurrentPage: function() {
|
|
if (Conf['Index Mode'] === 'infinite' && Index.pageNum) {
|
|
return Index.pageNum;
|
|
}
|
|
return +window.location.pathname.split('/')[2];
|
|
},
|
|
userPageNav: function(pageNum) {
|
|
if (Conf['Refreshed Navigation'] && Conf['Index Mode'] !== 'all pages') {
|
|
return Index.update(pageNum);
|
|
} else {
|
|
return Index.pageNav(pageNum);
|
|
}
|
|
},
|
|
pageNav: function(pageNum) {
|
|
if (Index.currentPage === pageNum && !Index.root.parentElement) {
|
|
return;
|
|
}
|
|
history.pushState(null, '', pageNum === 0 ? './' : pageNum);
|
|
return Index.pageLoad(pageNum);
|
|
},
|
|
pageLoad: function(pageNum) {
|
|
Index.currentPage = pageNum;
|
|
if (Conf['Index Mode'] === 'all pages') {
|
|
return;
|
|
}
|
|
Index.buildIndex();
|
|
return Index.scrollToIndex();
|
|
},
|
|
getThreadsNumPerPage: function() {
|
|
if (Conf['Threads per Page'] > 0) {
|
|
return +Conf['Threads per Page'];
|
|
} else {
|
|
return Index.threadsNumPerPage;
|
|
}
|
|
},
|
|
getPagesNum: function() {
|
|
return Math.ceil(Index.sortedThreads.length / Index.getThreadsNumPerPage());
|
|
},
|
|
getMaxPageNum: function() {
|
|
return Math.max(0, Index.getPagesNum() - 1);
|
|
},
|
|
togglePagelist: function() {
|
|
return Index.pagelist.hidden = Conf['Index Mode'] !== 'paged';
|
|
},
|
|
buildPagelist: function() {
|
|
var a, i, maxPageNum, nodes, pagesRoot, _i;
|
|
pagesRoot = $('.pages', Index.pagelist);
|
|
maxPageNum = Index.getMaxPageNum();
|
|
if (pagesRoot.childElementCount !== maxPageNum + 1) {
|
|
nodes = [];
|
|
for (i = _i = 0; _i <= maxPageNum; i = _i += 1) {
|
|
a = $.el('a', {
|
|
textContent: i,
|
|
href: i ? i : './'
|
|
});
|
|
nodes.push($.tn('['), a, $.tn('] '));
|
|
}
|
|
$.rmAll(pagesRoot);
|
|
$.add(pagesRoot, nodes);
|
|
}
|
|
return Index.togglePagelist();
|
|
},
|
|
setPage: function(pageNum) {
|
|
var a, href, maxPageNum, next, pagesRoot, prev, strong;
|
|
pageNum || (pageNum = Index.getCurrentPage());
|
|
maxPageNum = Index.getMaxPageNum();
|
|
pagesRoot = $('.pages', Index.pagelist);
|
|
prev = pagesRoot.previousSibling.firstChild;
|
|
next = pagesRoot.nextSibling.firstChild;
|
|
href = Math.max(pageNum - 1, 0);
|
|
prev.href = href === 0 ? './' : href;
|
|
prev.firstChild.disabled = href === pageNum;
|
|
href = Math.min(pageNum + 1, maxPageNum);
|
|
next.href = href === 0 ? './' : href;
|
|
next.firstChild.disabled = href === pageNum;
|
|
if (strong = $('strong', pagesRoot)) {
|
|
if (+strong.textContent === pageNum) {
|
|
return;
|
|
}
|
|
$.replace(strong, strong.firstChild);
|
|
} else {
|
|
strong = $.el('strong');
|
|
}
|
|
if (!(a = pagesRoot.children[pageNum])) {
|
|
return;
|
|
}
|
|
$.before(a, strong);
|
|
return $.add(strong, a);
|
|
},
|
|
updateHideLabel: function() {
|
|
var hiddenCount, thread, threadID, _ref, _ref1;
|
|
hiddenCount = 0;
|
|
_ref = g.BOARD.threads;
|
|
for (threadID in _ref) {
|
|
thread = _ref[threadID];
|
|
if (thread.isHidden) {
|
|
if (_ref1 = thread.ID, __indexOf.call(Index.liveThreadData.keys, _ref1) >= 0) {
|
|
hiddenCount++;
|
|
}
|
|
}
|
|
}
|
|
if (!hiddenCount) {
|
|
Index.hideLabel.hidden = true;
|
|
if (Index.showHiddenThreads) {
|
|
Index.cb.toggleHiddenThreads();
|
|
}
|
|
return;
|
|
}
|
|
Index.hideLabel.hidden = false;
|
|
return $('#hidden-count', Index.hideLabel).textContent = hiddenCount === 1 ? '1 hidden thread' : "" + hiddenCount + " hidden threads";
|
|
},
|
|
update: function(pageNum) {
|
|
var board, now, onload, sortedThreads, _ref, _ref1;
|
|
if (!navigator.onLine) {
|
|
return;
|
|
}
|
|
if (g.VIEW === 'thread') {
|
|
if (Conf['Thread Updater']) {
|
|
return ThreadUpdater.update();
|
|
}
|
|
return;
|
|
}
|
|
if (!(d.readyState === 'loading' || Index.root.parentElement)) {
|
|
$.replace($('.board'), Index.root);
|
|
}
|
|
delete Index.pageNum;
|
|
if ((_ref = Index.req) != null) {
|
|
_ref.abort();
|
|
}
|
|
if ((_ref1 = Index.notice) != null) {
|
|
_ref1.close();
|
|
}
|
|
sortedThreads = Index.sortedThreads;
|
|
if (sortedThreads) {
|
|
board = sortedThreads[0].board.ID;
|
|
}
|
|
now = Date.now();
|
|
$.ready(function() {
|
|
return Index.nTimeout = setTimeout((function() {
|
|
if (Index.req && !Index.notice) {
|
|
return Index.notice = new Notice('info', 'Refreshing index...', 2);
|
|
}
|
|
}), 3 * $.SECOND - (Date.now() - now));
|
|
});
|
|
if (typeof pageNum !== 'number') {
|
|
pageNum = null;
|
|
}
|
|
onload = function(e) {
|
|
return Index.load(e, pageNum);
|
|
};
|
|
Index.req = $.ajax("//a.4cdn.org/" + g.BOARD.ID + "/catalog.json", {
|
|
onabort: onload,
|
|
onloadend: onload
|
|
}, {
|
|
whenModified: board === g.BOARD.ID
|
|
});
|
|
return $.addClass(Index.button, 'fa-spin');
|
|
},
|
|
load: function(e, pageNum) {
|
|
var err, nTimeout, notice, req, timeEl, _ref;
|
|
$.rmClass(Index.button, 'fa-spin');
|
|
req = Index.req, notice = Index.notice, nTimeout = Index.nTimeout;
|
|
if (nTimeout) {
|
|
clearTimeout(nTimeout);
|
|
}
|
|
delete Index.nTimeout;
|
|
delete Index.req;
|
|
delete Index.notice;
|
|
if (e.type === 'abort') {
|
|
req.onloadend = null;
|
|
notice.close();
|
|
return;
|
|
}
|
|
if ((_ref = req.status) !== 200 && _ref !== 304) {
|
|
err = "Index refresh failed. Error " + req.statusText + " (" + req.status + ")";
|
|
if (notice) {
|
|
notice.setType('warning');
|
|
notice.el.lastElementChild.textContent = err;
|
|
setTimeout(notice.close, $.SECOND);
|
|
} else {
|
|
new Notice('warning', err, 1);
|
|
}
|
|
return;
|
|
}
|
|
Navigate.title();
|
|
try {
|
|
if (req.status === 200) {
|
|
Index.parse(req.response, pageNum);
|
|
} else if (req.status === 304) {
|
|
Index.pageNav(pageNum || 0);
|
|
}
|
|
} catch (_error) {
|
|
err = _error;
|
|
c.error("Index failure: " + err.message, err.stack);
|
|
if (notice) {
|
|
notice.setType('error');
|
|
notice.el.lastElementChild.textContent = 'Index refresh failed.';
|
|
setTimeout(notice.close, $.SECOND);
|
|
} else {
|
|
new Notice('error', 'Index refresh failed.', 1);
|
|
}
|
|
return;
|
|
}
|
|
timeEl = $('time#index-last-refresh', Index.navLinks);
|
|
timeEl.dataset.utc = Date.parse(req.getResponseHeader('Last-Modified'));
|
|
RelativeDates.update(timeEl);
|
|
return Index.scrollToIndex();
|
|
},
|
|
parse: function(pages, pageNum) {
|
|
Index.parseThreadList(pages);
|
|
Index.buildThreads();
|
|
Index.sort();
|
|
if (pageNum != null) {
|
|
Index.pageNav(pageNum);
|
|
return;
|
|
}
|
|
return Index.buildIndex();
|
|
},
|
|
parseThreadList: function(pages) {
|
|
var i, j, live, page, thread, threads;
|
|
Index.threadsNumPerPage = pages[0].threads.length;
|
|
live = new SimpleDict();
|
|
i = 0;
|
|
while (page = pages[i++]) {
|
|
j = 0;
|
|
threads = page.threads;
|
|
while (thread = threads[j++]) {
|
|
live.push(thread.no, thread);
|
|
}
|
|
}
|
|
Index.liveThreadData = live;
|
|
return g.BOARD.threads.forEach(function(thread) {
|
|
var _ref;
|
|
if (_ref = thread.ID, __indexOf.call(Index.liveThreadData.keys, _ref) < 0) {
|
|
return thread.collect();
|
|
}
|
|
});
|
|
},
|
|
buildThreads: function() {
|
|
var errors, posts, threads;
|
|
threads = [];
|
|
posts = [];
|
|
errors = null;
|
|
Index.liveThreadData.forEach(function(threadData) {
|
|
var err, thread, threadRoot;
|
|
threadRoot = Build.thread(g.BOARD, threadData);
|
|
if (thread = g.BOARD.threads[threadData.no]) {
|
|
thread.setPage(Math.floor(i / Index.threadsNumPerPage));
|
|
thread.setCount('post', threadData.replies + 1, threadData.bumplimit);
|
|
thread.setCount('file', threadData.images + !!threadData.ext, threadData.imagelimit);
|
|
thread.setStatus('Sticky', !!threadData.sticky);
|
|
thread.setStatus('Closed', !!threadData.closed);
|
|
} else {
|
|
thread = new Thread(threadData.no, g.BOARD);
|
|
threads.push(thread);
|
|
}
|
|
if (thread.ID in thread.posts) {
|
|
return;
|
|
}
|
|
try {
|
|
return posts.push(new Post($('.opContainer', threadRoot), thread, g.BOARD));
|
|
} catch (_error) {
|
|
err = _error;
|
|
if (!errors) {
|
|
errors = [];
|
|
}
|
|
return errors.push({
|
|
message: "Parsing of Thread No." + thread + " failed. Thread will be skipped.",
|
|
error: err
|
|
});
|
|
}
|
|
});
|
|
if (errors) {
|
|
Main.handleErrors(errors);
|
|
}
|
|
Thread.callbacks.execute(threads);
|
|
Post.callbacks.execute(posts);
|
|
Index.updateHideLabel();
|
|
return $.event('IndexRefresh');
|
|
},
|
|
buildReplies: function(thread) {
|
|
var data, err, errors, lastReplies, node, nodes, post, posts, _i, _len;
|
|
if (!Conf['Show Replies']) {
|
|
return;
|
|
}
|
|
posts = [];
|
|
if (!(lastReplies = Index.liveThreadData[thread.ID].last_replies)) {
|
|
return;
|
|
}
|
|
nodes = [];
|
|
for (_i = 0, _len = lastReplies.length; _i < _len; _i++) {
|
|
data = lastReplies[_i];
|
|
if (post = thread.posts[data.no]) {
|
|
nodes.push(post.nodes.root);
|
|
continue;
|
|
}
|
|
nodes.push(node = Build.postFromObject(data, thread.board.ID));
|
|
try {
|
|
posts.push(new Post(node, thread, thread.board));
|
|
} catch (_error) {
|
|
err = _error;
|
|
if (!errors) {
|
|
errors = [];
|
|
}
|
|
errors.push({
|
|
message: "Parsing of Post No." + data.no + " failed. Post will be skipped.",
|
|
error: err
|
|
});
|
|
}
|
|
$.add(thread.OP.nodes.root.parentNode, nodes);
|
|
}
|
|
if (errors) {
|
|
Main.handleErrors(errors);
|
|
}
|
|
return Post.callbacks.execute(posts);
|
|
},
|
|
buildCatalogViews: function() {
|
|
var catalogThreads, i, nodes, root, size, thread;
|
|
catalogThreads = [];
|
|
nodes = [];
|
|
i = 0;
|
|
size = Conf['Index Size'] === 'small' ? 150 : 250;
|
|
while (thread = Index.sortedThreads[i++]) {
|
|
if (!thread.catalogView) {
|
|
catalogThreads.push(new CatalogThread(Build.catalogThread(thread), thread));
|
|
}
|
|
root = thread.catalogView.nodes.root;
|
|
Index.sizeSingleCatalogNode(root, size);
|
|
nodes.push(root);
|
|
}
|
|
CatalogThread.callbacks.execute(catalogThreads);
|
|
return nodes;
|
|
},
|
|
sizeSingleCatalogNode: function(node, size) {
|
|
var height, ratio, thumb, width, _ref;
|
|
thumb = node.firstElementChild;
|
|
_ref = thumb.dataset, width = _ref.width, height = _ref.height;
|
|
if (!width) {
|
|
return;
|
|
}
|
|
ratio = size / Math.max(width, height);
|
|
thumb.style.width = width * ratio + 'px';
|
|
return thumb.style.height = height * ratio + 'px';
|
|
},
|
|
sort: function() {
|
|
var i, liveData, sortedThreadIDs, sortedThreads, thread, threadID;
|
|
sortedThreads = [];
|
|
sortedThreadIDs = [];
|
|
liveData = [];
|
|
Index.liveThreadData.forEach(function(data) {
|
|
return liveData.push(data);
|
|
});
|
|
({
|
|
'bump': function() {
|
|
return sortedThreadIDs = Index.liveThreadData.keys;
|
|
},
|
|
'lastreply': function() {
|
|
var data, i;
|
|
liveData.sort(function(a, b) {
|
|
var _ref, _ref1;
|
|
if ('last_replies' in a) {
|
|
_ref = a.last_replies, a = _ref[_ref.length - 1];
|
|
}
|
|
if ('last_replies' in b) {
|
|
_ref1 = b.last_replies, b = _ref1[_ref1.length - 1];
|
|
}
|
|
return b.no - a.no;
|
|
});
|
|
i = 0;
|
|
while (data = liveData[i++]) {
|
|
sortedThreadIDs.push(data.no);
|
|
}
|
|
},
|
|
'birth': function() {
|
|
return sortedThreadIDs = __slice.call(Index.liveThreadData.keys).sort(function(a, b) {
|
|
return b - a;
|
|
});
|
|
},
|
|
'replycount': function() {
|
|
var data, i;
|
|
liveData.sort(function(a, b) {
|
|
return b.replies - a.replies;
|
|
});
|
|
i = 0;
|
|
while (data = liveData[i++]) {
|
|
sortedThreadIDs.push(data.no);
|
|
}
|
|
},
|
|
'filecount': function() {
|
|
var data, i;
|
|
liveData = [];
|
|
Index.liveThreadData.forEach(function(data) {
|
|
return liveData.push(data);
|
|
});
|
|
liveData.sort(function(a, b) {
|
|
return b.images - a.images;
|
|
});
|
|
i = 0;
|
|
while (data = liveData[i++]) {
|
|
sortedThreadIDs.push(data.no);
|
|
}
|
|
}
|
|
})[Conf['Index Sort']]();
|
|
i = 0;
|
|
while (threadID = sortedThreadIDs[i++]) {
|
|
sortedThreads.push(g.BOARD.threads[threadID]);
|
|
}
|
|
Index.sortedThreads = [];
|
|
i = 0;
|
|
while (thread = sortedThreads[i++]) {
|
|
if (thread.isHidden === Index.showHiddenThreads) {
|
|
Index.sortedThreads.push(thread);
|
|
}
|
|
}
|
|
if (Index.isSearching) {
|
|
Index.sortedThreads = Index.querySearch(Index.searchInput.value) || Index.sortedThreads;
|
|
}
|
|
Index.sortOnTop(function(thread) {
|
|
return thread.isSticky;
|
|
});
|
|
return Index.sortOnTop(function(thread) {
|
|
return thread.isOnTop || thread.isPinned;
|
|
});
|
|
},
|
|
sortOnTop: function(match) {
|
|
var i, offset, thread, _i, _len, _ref;
|
|
offset = 0;
|
|
_ref = Index.sortedThreads;
|
|
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
|
|
thread = _ref[i];
|
|
if (match(thread)) {
|
|
Index.sortedThreads.splice(offset++, 0, Index.sortedThreads.splice(i, 1)[0]);
|
|
}
|
|
}
|
|
},
|
|
buildIndex: function(infinite) {
|
|
var i, max, nodes, pageNum, sortedThreads, thread, threads, threadsPerPage;
|
|
sortedThreads = Index.sortedThreads;
|
|
switch (Conf['Index Mode']) {
|
|
case 'paged':
|
|
case 'infinite':
|
|
pageNum = Index.getCurrentPage();
|
|
if (pageNum > Index.getMaxPageNum()) {
|
|
Index.pageNav(Index.getMaxPageNum());
|
|
return;
|
|
}
|
|
threadsPerPage = Index.getThreadsNumPerPage();
|
|
nodes = [];
|
|
threads = [];
|
|
i = threadsPerPage * pageNum;
|
|
max = i + threadsPerPage;
|
|
while (i < max && (thread = sortedThreads[i++])) {
|
|
threads.push(thread);
|
|
nodes.push(thread.OP.nodes.root.parentNode, $.el('hr'));
|
|
Index.buildReplies(thread);
|
|
}
|
|
Index.buildPagelist();
|
|
Index.setPage();
|
|
break;
|
|
case 'catalog':
|
|
nodes = Index.buildCatalogViews();
|
|
break;
|
|
default:
|
|
nodes = [];
|
|
i = 0;
|
|
while (thread = sortedThreads[i++]) {
|
|
nodes.push(thread.OP.nodes.root.parentNode, $.el('hr'));
|
|
Index.buildReplies(thread);
|
|
}
|
|
}
|
|
if (!infinite) {
|
|
$.rmAll(Index.root);
|
|
}
|
|
$.add(Index.root, nodes);
|
|
return $.event('IndexBuild', nodes);
|
|
},
|
|
isSearching: false,
|
|
clearSearch: function() {
|
|
Index.searchInput.value = null;
|
|
Index.onSearchInput();
|
|
return Index.searchInput.focus();
|
|
},
|
|
onSearchInput: function() {
|
|
var pageNum, _ref, _ref1;
|
|
if (Index.isSearching = !!Index.searchInput.value.trim()) {
|
|
if (!Index.searchInput.dataset.searching) {
|
|
Index.searchInput.dataset.searching = 1;
|
|
Index.pageBeforeSearch = Index.getCurrentPage();
|
|
pageNum = 0;
|
|
} else {
|
|
pageNum = Index.getCurrentPage();
|
|
}
|
|
} else {
|
|
if (!Index.searchInput.dataset.searching) {
|
|
return;
|
|
}
|
|
pageNum = Index.pageBeforeSearch;
|
|
delete Index.pageBeforeSearch;
|
|
Index.searchInput.removeAttribute('data-searching');
|
|
}
|
|
Index.sort();
|
|
if (((_ref = Conf['Index Mode']) === 'paged' || _ref === 'infinite') && ((_ref1 = Index.currentPage) !== pageNum && _ref1 !== Index.getMaxPageNum())) {
|
|
return Index.pageNav(pageNum);
|
|
} else {
|
|
Index.buildIndex();
|
|
return Index.setPage();
|
|
}
|
|
},
|
|
querySearch: function(query) {
|
|
var keywords;
|
|
if (!(keywords = query.toLowerCase().match(/\S+/g))) {
|
|
return;
|
|
}
|
|
return Index.search(keywords);
|
|
},
|
|
search: function(keywords) {
|
|
var filtered, i, sortedThreads, thread;
|
|
filtered = [];
|
|
i = 0;
|
|
sortedThreads = Index.sortedThreads;
|
|
while (thread = sortedThreads[i++]) {
|
|
if (Index.searchMatch(thread, keywords)) {
|
|
filtered.push(thread);
|
|
}
|
|
}
|
|
return Index.sortedThreads = filtered;
|
|
},
|
|
searchMatch: function(thread, keywords) {
|
|
var file, info, key, keyword, text, _i, _j, _len, _len1, _ref, _ref1;
|
|
_ref = thread.OP, info = _ref.info, file = _ref.file;
|
|
text = [];
|
|
_ref1 = ['comment', 'subject', 'name', 'tripcode', 'email'];
|
|
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
|
|
key = _ref1[_i];
|
|
if (key in info) {
|
|
text.push(info[key]);
|
|
}
|
|
}
|
|
if (file) {
|
|
text.push(file.name);
|
|
}
|
|
text = text.join(' ').toLowerCase();
|
|
for (_j = 0, _len1 = keywords.length; _j < _len1; _j++) {
|
|
keyword = keywords[_j];
|
|
if (-1 === text.indexOf(keyword)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
|
|
Build = {
|
|
staticPath: '//s.4cdn.org/image/',
|
|
gifIcon: window.devicePixelRatio >= 2 ? '@2x.gif' : '.gif',
|
|
spoilerRange: {},
|
|
shortFilename: function(filename, isReply) {
|
|
var threshold;
|
|
threshold = isReply ? 30 : 40;
|
|
if (filename.length - 4 > threshold) {
|
|
return "" + filename.slice(0, threshold - 5) + "(...)." + filename.slice(-3);
|
|
} else {
|
|
return filename;
|
|
}
|
|
},
|
|
thumbRotate: (function() {
|
|
var n;
|
|
n = 0;
|
|
return function() {
|
|
return n = (n + 1) % 3;
|
|
};
|
|
})(),
|
|
postFromObject: function(data, boardID) {
|
|
var o;
|
|
o = {
|
|
postID: data.no,
|
|
threadID: data.resto || data.no,
|
|
boardID: boardID,
|
|
name: data.name,
|
|
capcode: data.capcode,
|
|
tripcode: data.trip,
|
|
uniqueID: data.id,
|
|
email: data.email ? encodeURI(data.email.replace(/"/g, '"')) : '',
|
|
subject: data.sub,
|
|
flagCode: data.country,
|
|
flagName: data.country_name,
|
|
date: data.now,
|
|
dateUTC: data.time,
|
|
comment: data.com,
|
|
isSticky: !!data.sticky,
|
|
isClosed: !!data.closed
|
|
};
|
|
if (data.ext || data.filedeleted) {
|
|
o.file = {
|
|
name: data.filename + data.ext,
|
|
timestamp: "" + data.tim + data.ext,
|
|
url: boardID === 'f' ? "//i.4cdn.org/" + boardID + "/src/" + data.filename + data.ext : "//i.4cdn.org/" + boardID + "/src/" + data.tim + data.ext,
|
|
height: data.h,
|
|
width: data.w,
|
|
MD5: data.md5,
|
|
size: data.fsize,
|
|
turl: "//" + (Build.thumbRotate()) + ".t.4cdn.org/" + boardID + "/thumb/" + data.tim + "s.jpg",
|
|
theight: data.tn_h,
|
|
twidth: data.tn_w,
|
|
isSpoiler: !!data.spoiler,
|
|
isDeleted: !!data.filedeleted
|
|
};
|
|
}
|
|
return Build.post(o);
|
|
},
|
|
post: function(o, isArchived) {
|
|
|
|
/*
|
|
This function contains code from 4chan-JS (https://github.com/4chan/4chan-JS).
|
|
@license: https://github.com/4chan/4chan-JS/blob/master/LICENSE
|
|
*/
|
|
var a, boardID, capcode, capcodeClass, capcodeIcon, capcodeStart, closed, comment, container, date, dateUTC, email, emailEnd, emailStart, file, fileDims, fileHTML, fileInfo, fileSize, fileThumb, filename, flag, flagCode, flagName, gifIcon, href, imgSrc, isClosed, isOP, isSticky, name, pageIcon, pageNum, postID, quote, replyLink, shortFilename, spoilerRange, staticPath, sticky, subject, threadID, tripcode, uniqueID, userID, _i, _len, _ref;
|
|
postID = o.postID, threadID = o.threadID, boardID = o.boardID, name = o.name, capcode = o.capcode, tripcode = o.tripcode, uniqueID = o.uniqueID, email = o.email, subject = o.subject, flagCode = o.flagCode, flagName = o.flagName, date = o.date, dateUTC = o.dateUTC, isSticky = o.isSticky, isClosed = o.isClosed, comment = o.comment, file = o.file;
|
|
isOP = postID === threadID;
|
|
staticPath = Build.staticPath, gifIcon = Build.gifIcon;
|
|
tripcode = tripcode ? " <span class=postertrip>" + tripcode + "</span>" : '';
|
|
if (email) {
|
|
emailStart = '<a href="mailto:' + email + '" class="useremail">';
|
|
emailEnd = '</a>';
|
|
} else {
|
|
emailStart = '';
|
|
emailEnd = '';
|
|
}
|
|
switch (capcode) {
|
|
case 'admin':
|
|
case 'admin_highlight':
|
|
capcodeClass = " capcodeAdmin";
|
|
capcodeStart = " <strong class='capcode hand id_admin'" + "title='Highlight posts by the Administrator'>## Admin</strong>";
|
|
capcodeIcon = (" <img src='" + staticPath + "adminicon" + gifIcon + "' ") + "title='This user is the 4chan Administrator.' class=identityIcon>";
|
|
break;
|
|
case 'mod':
|
|
capcodeClass = " capcodeMod";
|
|
capcodeStart = " <strong class='capcode hand id_mod' " + "title='Highlight posts by Moderators'>## Mod</strong>";
|
|
capcodeIcon = (" <img src='" + staticPath + "modicon" + gifIcon + "' ") + "title='This user is a 4chan Moderator.' class=identityIcon>";
|
|
break;
|
|
case 'developer':
|
|
capcodeClass = " capcodeDeveloper";
|
|
capcodeStart = " <strong class='capcode hand id_developer' " + "title='Highlight posts by Developers'>## Developer</strong>";
|
|
capcodeIcon = (" <img src='" + staticPath + "developericon" + gifIcon + "' ") + "title='This user is a 4chan Developer.' class=identityIcon>";
|
|
break;
|
|
default:
|
|
capcodeClass = '';
|
|
capcodeStart = '';
|
|
capcodeIcon = '';
|
|
}
|
|
userID = !capcode && uniqueID ? (" <span class='posteruid id_" + uniqueID + "'>(ID: ") + ("<span class=hand title='Highlight posts by this ID'>" + uniqueID + "</span>)</span> ") : '';
|
|
flag = !flagCode ? '' : boardID === 'pol' ? " <img src='" + staticPath + "country/troll/" + (flagCode.toLowerCase()) + ".gif' title='" + flagName + "' class=countryFlag>" : " <span title='" + flagName + "' class='flag flag-" + (flagCode.toLowerCase()) + "'></span>";
|
|
if (file != null ? file.isDeleted : void 0) {
|
|
fileHTML = isOP ? "<div class=file><span class=fileThumb>" + ("<img src='" + staticPath + "filedeleted" + gifIcon + "' class=fileDeleted>") + "</span></div>" : "<div class=file><span class=fileThumb>" + ("<img src='" + staticPath + "filedeleted-res" + gifIcon + "' class=fileDeletedRes>") + "</span></div>";
|
|
} else if (file) {
|
|
fileSize = $.bytesToString(file.size);
|
|
fileThumb = file.turl;
|
|
if (file.isSpoiler) {
|
|
fileSize = "Spoiler Image, " + fileSize;
|
|
if (!isArchived) {
|
|
fileThumb = "" + staticPath + "spoiler";
|
|
if (spoilerRange = Build.spoilerRange[boardID]) {
|
|
fileThumb += ("-" + boardID) + Math.floor(1 + spoilerRange * Math.random());
|
|
}
|
|
fileThumb += '.png';
|
|
file.twidth = file.theight = 100;
|
|
}
|
|
}
|
|
imgSrc = boardID === 'f' ? '' : ("<a class='fileThumb" + (file.isSpoiler ? ' imgspoiler' : '') + "' href='" + file.url + "' target=_blank>") + ("<img src='" + fileThumb + "' alt='" + fileSize + "' data-md5=" + file.MD5 + " style='height: " + file.theight + "px; width: " + file.twidth + "px;'>") + "</a>";
|
|
a = $.el('a', {
|
|
innerHTML: file.name
|
|
});
|
|
filename = a.textContent.replace(/%22/g, '"');
|
|
a.textContent = Build.shortFilename(filename);
|
|
shortFilename = a.innerHTML;
|
|
a.textContent = filename;
|
|
filename = a.innerHTML.replace(/'/g, ''');
|
|
fileDims = file.name.slice(-3) === 'pdf' ? 'PDF' : "" + file.width + "x" + file.height;
|
|
fileInfo = ("<div class=fileText" + (file.isSpoiler ? " title='" + filename + "'" : '') + ">File: <a href='" + file.url + "' target=_blank>" + file.timestamp + "</a>") + ("-(" + fileSize + ", " + fileDims + (file.isSpoiler ? '' : ", <span" + (filename !== shortFilename ? " title='" + filename + "'" : '') + ">" + shortFilename + "</span>")) + ")</div>";
|
|
fileHTML = "<div class=file>" + fileInfo + imgSrc + "</div>";
|
|
} else {
|
|
fileHTML = '';
|
|
}
|
|
sticky = isSticky ? " <img src=" + staticPath + "sticky" + gifIcon + " title=Sticky class=stickyIcon>" : '';
|
|
closed = isClosed ? " <img src=" + staticPath + "closed" + gifIcon + " title=Closed class=closedIcon>" : '';
|
|
if (isOP && g.VIEW === 'index') {
|
|
pageNum = Math.floor(Index.liveThreadData.keys.indexOf("" + postID) / Index.threadsNumPerPage);
|
|
pageIcon = " <span class=page-num title='This thread is on page " + pageNum + " in the original index.'>Page " + pageNum + "</span>";
|
|
replyLink = " <span>[<a href='/" + boardID + "/res/" + threadID + "' class=replylink>Reply</a>]</span>";
|
|
} else {
|
|
pageIcon = replyLink = '';
|
|
}
|
|
container = $.el('div', {
|
|
id: "pc" + postID,
|
|
className: "postContainer " + (isOP ? 'op' : 'reply') + "Container",
|
|
innerHTML: "" + (isOP ? '' : "<div class=sideArrows>>></div>") + "<div id=p" + postID + " class='post " + (isOP ? 'op' : 'reply') + (capcodeIcon === 'admin_highlight' ? ' highlightPost' : '') + "'>" + (isOP ? fileHTML : '') + "<div class='postInfo'><input type=checkbox name=" + postID + " value=delete>" + ' ' + "<span class=subject>" + (subject || '') + "</span>" + ' ' + "<span class='nameBlock" + capcodeClass + "'>" + emailStart + "<span class=name>" + (name || '') + "</span>" + (tripcode + capcodeStart + emailEnd + capcodeIcon + userID + flag) + "</span>" + " " + "<span class=dateTime data-utc=" + dateUTC + ">" + date + "</span>" + ' ' + "<span class='postNum'><a href=" + ("/" + boardID + "/res/" + threadID + "#p" + postID) + " title='Highlight this post'>No.</a><a href='" + (g.VIEW === 'thread' && g.THREADID === +threadID ? "javascript:quote(" + postID + ")" : "/" + boardID + "/res/" + threadID + "#q" + postID) + "' title='Quote this post'>" + postID + "</a>" + (pageIcon + sticky + closed + replyLink) + "</span></div>" + (isOP ? '' : fileHTML) + "<blockquote class=postMessage>" + (comment || '') + "</blockquote>" + ' ' + "</div>"
|
|
});
|
|
_ref = $$('.quotelink', container);
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
quote = _ref[_i];
|
|
href = quote.getAttribute('href');
|
|
if (href[0] === '/') {
|
|
continue;
|
|
}
|
|
quote.href = "/" + boardID + "/res/" + href;
|
|
}
|
|
return container;
|
|
},
|
|
summary: function(boardID, threadID, posts, files) {
|
|
var text;
|
|
text = [];
|
|
text.push("" + posts + " post" + (posts > 1 ? 's' : ''));
|
|
if (files) {
|
|
text.push("and " + files + " image repl" + (files > 1 ? 'ies' : 'y'));
|
|
}
|
|
text.push('omitted.');
|
|
return $.el('a', {
|
|
className: 'summary',
|
|
textContent: text.join(' '),
|
|
href: "/" + boardID + "/res/" + threadID
|
|
});
|
|
},
|
|
thread: function(board, data, full) {
|
|
var OP, root;
|
|
Build.spoilerRange[board] = data.custom_spoiler;
|
|
if ((OP = board.posts[data.no]) && (root = OP.nodes.root.parentNode)) {
|
|
$.rmAll(root);
|
|
$.add(root, OP.nodes.root);
|
|
} else {
|
|
root = $.el('div', {
|
|
className: 'thread',
|
|
id: "t" + data.no
|
|
});
|
|
$.add(root, Build[full ? 'fullThread' : 'excerptThread'](board, data, OP));
|
|
}
|
|
return root;
|
|
},
|
|
excerptThread: function(board, data, OP) {
|
|
var files, nodes, posts, _ref;
|
|
nodes = [OP ? OP.nodes.root : Build.postFromObject(data, board.ID)];
|
|
if (data.omitted_posts || !Conf['Show Replies'] && data.replies) {
|
|
_ref = Conf['Show Replies'] ? [data.omitted_posts, data.omitted_images] : [data.replies, data.images], posts = _ref[0], files = _ref[1];
|
|
nodes.push(Build.summary(board.ID, data.no, posts, files));
|
|
}
|
|
return nodes;
|
|
},
|
|
fullThread: function(board, data) {
|
|
return Build.postFromObject(data, board.ID);
|
|
},
|
|
catalogThread: function(thread) {
|
|
var comment, data, fileCount, gifIcon, pageCount, postCount, pp, quotelink, root, spoilerRange, src, staticPath, subject, thumb, _i, _j, _len, _len1, _ref, _ref1;
|
|
staticPath = Build.staticPath, gifIcon = Build.gifIcon;
|
|
data = Index.liveThreadData[thread.ID];
|
|
postCount = data.replies + 1;
|
|
fileCount = data.images + !!data.ext;
|
|
pageCount = Math.floor(Index.liveThreadData.keys.indexOf("" + thread.ID) / Index.threadsNumPerPage);
|
|
subject = thread.OP.info.subject ? "<div class='subject'>" + thread.OP.info.subject + "</div>" : '';
|
|
comment = thread.OP.nodes.comment.innerHTML.replace(/(<br>\s*){2,}/g, '<br>');
|
|
root = $.el('div', {
|
|
className: 'catalog-thread',
|
|
innerHTML: "<a href=\"/" + thread.board + "/res/" + thread.ID + "\" class=\"thumb\"></a><div class=\"thread-stats\" title=\"Post count / File count / Page count\"><span class=\"post-count\">" + postCount + "</span> / <span class=\"file-count\">" + fileCount + "</span> / <span class=\"page-count\">" + pageCount + "</span><span class=\"thread-icons\"></span></div>" + subject + "<div class=\"comment\">" + comment + "</div>"
|
|
});
|
|
root.dataset.fullID = thread.fullID;
|
|
if (thread.isPinned) {
|
|
$.addClass(root, 'pinned');
|
|
}
|
|
if (thread.OP.highlights.length) {
|
|
$.addClass.apply($, [root].concat(__slice.call(thread.OP.highlights)));
|
|
}
|
|
thumb = root.firstElementChild;
|
|
if (data.spoiler && !Conf['Reveal Spoiler Thumbnails']) {
|
|
src = "" + staticPath + "spoiler";
|
|
if (spoilerRange = Build.spoilerRange[thread.board]) {
|
|
src += ("-" + thread.board) + Math.floor(1 + spoilerRange * Math.random());
|
|
}
|
|
src += '.png';
|
|
$.addClass(thumb, 'spoiler-file');
|
|
} else if (data.filedeleted) {
|
|
src = "" + staticPath + "filedeleted-res" + gifIcon;
|
|
$.addClass(thumb, 'deleted-file');
|
|
} else if (thread.OP.file) {
|
|
src = thread.OP.file.thumbURL;
|
|
thumb.dataset.width = data.tn_w;
|
|
thumb.dataset.height = data.tn_h;
|
|
} else {
|
|
src = "" + staticPath + "nofile.png";
|
|
$.addClass(thumb, 'no-file');
|
|
}
|
|
thumb.style.backgroundImage = "url(" + src + ")";
|
|
if (Conf['Open threads in a new tab']) {
|
|
thumb.target = '_blank';
|
|
}
|
|
_ref = $$('.quotelink', root.lastElementChild);
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
quotelink = _ref[_i];
|
|
$.replace(quotelink, __slice.call(quotelink.childNodes));
|
|
}
|
|
_ref1 = $$('.prettyprint', root.lastElementChild);
|
|
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
|
pp = _ref1[_j];
|
|
$.replace(pp, $.tn(pp.textContent));
|
|
}
|
|
if (thread.isSticky) {
|
|
$.add($('.thread-icons', root), $.el('img', {
|
|
src: "" + staticPath + "sticky" + gifIcon,
|
|
className: 'stickyIcon',
|
|
title: 'Sticky'
|
|
}));
|
|
}
|
|
if (thread.isClosed) {
|
|
$.add($('.thread-icons', root), $.el('img', {
|
|
src: "" + staticPath + "closed" + gifIcon,
|
|
className: 'closedIcon',
|
|
title: 'Closed'
|
|
}));
|
|
}
|
|
if (data.bumplimit) {
|
|
$.addClass($('.post-count', root), 'warning');
|
|
}
|
|
if (data.imagelimit) {
|
|
$.addClass($('.file-count', root), 'warning');
|
|
}
|
|
return root;
|
|
}
|
|
};
|
|
|
|
Get = {
|
|
threadExcerpt: function(thread) {
|
|
var OP, excerpt, _ref;
|
|
OP = thread.OP;
|
|
excerpt = ((_ref = OP.info.subject) != null ? _ref.trim() : void 0) || OP.info.comment.replace(/\n+/g, ' // ') || OP.getNameBlock();
|
|
if (excerpt.length > 70) {
|
|
excerpt = "" + excerpt.slice(0, 67) + "...";
|
|
}
|
|
return "/" + thread.board + "/ - " + excerpt;
|
|
},
|
|
threadFromRoot: function(root) {
|
|
return g.threads[$('.opContainer', root).dataset.fullID];
|
|
},
|
|
threadFromNode: function(node) {
|
|
return Get.threadFromRoot($.x('ancestor::div[@class="thread"]', node));
|
|
},
|
|
postFromRoot: function(root) {
|
|
var index, post;
|
|
post = g.posts[root.dataset.fullID];
|
|
if (index = root.dataset.clone) {
|
|
return post.clones[index];
|
|
} else {
|
|
return post;
|
|
}
|
|
},
|
|
postFromNode: function(node) {
|
|
return Get.postFromRoot($.x('ancestor::div[contains(@class,"postContainer")][1]', node));
|
|
},
|
|
contextFromNode: function(node) {
|
|
return Get.postFromRoot($.x('ancestor::div[@class="thread"]', node).firstElementChild);
|
|
},
|
|
postDataFromLink: function(link) {
|
|
var boardID, path, postID, threadID, _ref;
|
|
if (link.hostname === 'boards.4chan.org') {
|
|
path = link.pathname.split('/');
|
|
boardID = path[1];
|
|
threadID = path[3];
|
|
postID = link.hash.slice(2);
|
|
} else {
|
|
_ref = link.dataset, boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
|
|
threadID || (threadID = 0);
|
|
}
|
|
return {
|
|
boardID: boardID,
|
|
threadID: +threadID,
|
|
postID: +postID
|
|
};
|
|
},
|
|
allQuotelinksLinkingTo: function(post) {
|
|
var fullID, handleQuotes, posts, qPost, quote, quotelinks, _i, _len, _ref;
|
|
quotelinks = [];
|
|
posts = g.posts;
|
|
fullID = {
|
|
post: post
|
|
};
|
|
handleQuotes = function(qPost, type) {
|
|
var clone, _i, _len, _ref;
|
|
quotelinks.push.apply(quotelinks, qPost.nodes[type]);
|
|
_ref = qPost.clones;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
clone = _ref[_i];
|
|
quotelinks.push.apply(quotelinks, clone.nodes[type]);
|
|
}
|
|
};
|
|
posts.forEach(function(qPost) {
|
|
if (__indexOf.call(qPost.quotes, fullID) >= 0) {
|
|
return handleQuotes(qPost, 'quotelinks');
|
|
}
|
|
});
|
|
if (Conf['Quote Backlinks']) {
|
|
_ref = post.quotes;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
quote = _ref[_i];
|
|
if (qPost = posts[quote]) {
|
|
handleQuotes(qPost, 'backlinks');
|
|
}
|
|
}
|
|
}
|
|
return quotelinks.filter(function(quotelink) {
|
|
var boardID, postID, _ref1;
|
|
_ref1 = Get.postDataFromLink(quotelink), boardID = _ref1.boardID, postID = _ref1.postID;
|
|
return boardID === post.board.ID && postID === post.ID;
|
|
});
|
|
},
|
|
postClone: function(boardID, threadID, postID, root, context) {
|
|
var post, url;
|
|
if (post = g.posts["" + boardID + "." + postID]) {
|
|
Get.insert(post, root, context);
|
|
return;
|
|
}
|
|
root.textContent = "Loading post No." + postID + "...";
|
|
if (threadID) {
|
|
return $.cache("//a.4cdn.org/" + boardID + "/res/" + threadID + ".json", function() {
|
|
return Get.fetchedPost(this, boardID, threadID, postID, root, context);
|
|
});
|
|
} else if (url = Redirect.to('post', {
|
|
boardID: boardID,
|
|
postID: postID
|
|
})) {
|
|
return $.cache(url, function() {
|
|
return Get.archivedPost(this, boardID, postID, root, context);
|
|
}, {
|
|
responseType: 'json',
|
|
withCredentials: url.archive.withCredentials
|
|
});
|
|
}
|
|
},
|
|
insert: function(post, root, context) {
|
|
var clone, nodes;
|
|
if (!root.parentNode) {
|
|
return;
|
|
}
|
|
clone = post.addClone(context);
|
|
Clone.callbacks.execute([clone]);
|
|
nodes = clone.nodes;
|
|
$.rmAll(nodes.root);
|
|
$.add(nodes.root, nodes.post);
|
|
$.rmAll(root);
|
|
return $.add(root, nodes.root);
|
|
},
|
|
fetchedPost: function(req, boardID, threadID, postID, root, context) {
|
|
var board, post, posts, status, thread, url, _i, _len;
|
|
if (post = g.posts["" + boardID + "." + postID]) {
|
|
Get.insert(post, root, context);
|
|
return;
|
|
}
|
|
status = req.status;
|
|
if (status !== 200 && status !== 304) {
|
|
if (url = Redirect.to('post', {
|
|
boardID: boardID,
|
|
postID: postID
|
|
})) {
|
|
$.cache(url, function() {
|
|
return Get.archivedPost(this, boardID, postID, root, context);
|
|
}, {
|
|
withCredentials: url.archive.withCredentials
|
|
});
|
|
} else {
|
|
$.addClass(root, 'warning');
|
|
root.textContent = status === 404 ? "Thread No." + threadID + " 404'd." : "Error " + req.statusText + " (" + req.status + ").";
|
|
}
|
|
return;
|
|
}
|
|
posts = req.response.posts;
|
|
Build.spoilerRange[boardID] = posts[0].custom_spoiler;
|
|
for (_i = 0, _len = posts.length; _i < _len; _i++) {
|
|
post = posts[_i];
|
|
if (post.no === postID) {
|
|
break;
|
|
}
|
|
}
|
|
if (post.no !== postID) {
|
|
if (url = Redirect.to('post', {
|
|
boardID: boardID,
|
|
postID: postID
|
|
})) {
|
|
$.cache(url, function() {
|
|
return Get.archivedPost(this, boardID, postID, root, context);
|
|
}, {
|
|
withCredentials: url.archive.withCredentials
|
|
});
|
|
} else {
|
|
$.addClass(root, 'warning');
|
|
root.textContent = "Post No." + postID + " was not found.";
|
|
}
|
|
return;
|
|
}
|
|
board = g.boards[boardID] || new Board(boardID);
|
|
thread = g.threads["" + boardID + "." + threadID] || new Thread(threadID, board);
|
|
post = new Post(Build.postFromObject(post, boardID), thread, board);
|
|
Post.callbacks.execute([post]);
|
|
return Get.insert(post, root, context);
|
|
},
|
|
archivedPost: function(req, boardID, postID, root, context) {
|
|
var board, bq, comment, data, o, post, thread, threadID, _ref, _ref1;
|
|
if (post = g.posts["" + boardID + "." + postID]) {
|
|
Get.insert(post, root, context);
|
|
return;
|
|
}
|
|
data = req.response;
|
|
if (data.error) {
|
|
$.addClass(root, 'warning');
|
|
root.textContent = data.error;
|
|
return;
|
|
}
|
|
bq = $.el('blockquote', {
|
|
textContent: data.comment
|
|
});
|
|
bq.innerHTML = bq.innerHTML.replace(/\n|\[\/?[a-z]+(:lit)?\]/g, Get.parseMarkup);
|
|
comment = bq.innerHTML.replace(/(^|>)(>[^<$]*)(<|$)/g, '$1<span class=quote>$2</span>$3').replace(/((>){2}(>\/[a-z\d]+\/)?\d+)/g, '<span class=deadlink>$1</span>');
|
|
threadID = +data.thread_num;
|
|
o = {
|
|
postID: postID,
|
|
threadID: threadID,
|
|
boardID: boardID,
|
|
name: data.name_processed,
|
|
capcode: (function() {
|
|
switch (data.capcode) {
|
|
case 'M':
|
|
return 'mod';
|
|
case 'A':
|
|
return 'admin';
|
|
case 'D':
|
|
return 'developer';
|
|
}
|
|
})(),
|
|
tripcode: data.trip,
|
|
uniqueID: data.poster_hash,
|
|
email: data.email ? encodeURI(data.email) : '',
|
|
subject: data.title_processed,
|
|
flagCode: data.poster_country,
|
|
flagName: data.poster_country_name_processed,
|
|
date: data.fourchan_date,
|
|
dateUTC: data.timestamp,
|
|
comment: comment
|
|
};
|
|
if ((_ref = data.media) != null ? _ref.media_filename : void 0) {
|
|
o.file = {
|
|
name: data.media.media_filename_processed,
|
|
timestamp: data.media.media_orig,
|
|
url: data.media.media_link || data.media.remote_media_link,
|
|
height: data.media.media_h,
|
|
width: data.media.media_w,
|
|
MD5: data.media.media_hash,
|
|
size: data.media.media_size,
|
|
turl: data.media.thumb_link || ("//t.4cdn.org/" + boardID + "/thumb/" + data.media.preview_orig),
|
|
theight: data.media.preview_h,
|
|
twidth: data.media.preview_w,
|
|
isSpoiler: data.media.spoiler === '1'
|
|
};
|
|
}
|
|
board = g.boards[boardID] || new Board(boardID);
|
|
thread = g.threads["" + boardID + "." + threadID] || new Thread(threadID, board);
|
|
post = new Post(Build.post(o, true), thread, board, {
|
|
isArchived: true
|
|
});
|
|
if ((_ref1 = $('.page-num', post.nodes.info)) != null) {
|
|
_ref1.hidden = true;
|
|
}
|
|
Post.callbacks.execute([post]);
|
|
return Get.insert(post, root, context);
|
|
},
|
|
parseMarkup: function(text) {
|
|
return {
|
|
'\n': '<br>',
|
|
'[b]': '<b>',
|
|
'[/b]': '</b>',
|
|
'[spoiler]': '<s>',
|
|
'[/spoiler]': '</s>',
|
|
'[code]': '<pre class=prettyprint>',
|
|
'[/code]': '</pre>',
|
|
'[moot]': '<div style="padding:5px;margin-left:.5em;border-color:#faa;border:2px dashed rgba(255,0,0,.1);border-radius:2px">',
|
|
'[/moot]': '</div>',
|
|
'[banned]': '<strong style="color: red;">',
|
|
'[/banned]': '</strong>'
|
|
}[text] || text.replace(':lit', '');
|
|
}
|
|
};
|
|
|
|
UI = (function() {
|
|
var Menu, dialog, drag, dragend, dragstart, hover, hoverend, hoverstart, touchend, touchmove;
|
|
dialog = function(id, position, html) {
|
|
var el, move;
|
|
el = $.el('div', {
|
|
className: 'dialog',
|
|
innerHTML: html,
|
|
id: id
|
|
});
|
|
el.style.cssText = position;
|
|
$.get("" + id + ".position", position, function(item) {
|
|
return el.style.cssText = item["" + id + ".position"];
|
|
});
|
|
move = $('.move', el);
|
|
$.on(move, 'touchstart mousedown', dragstart);
|
|
return el;
|
|
};
|
|
Menu = (function() {
|
|
var currentMenu, lastToggledButton;
|
|
|
|
currentMenu = null;
|
|
|
|
lastToggledButton = null;
|
|
|
|
function Menu(type) {
|
|
this.type = type;
|
|
this.rmEntry = __bind(this.rmEntry, this);
|
|
this.addEntry = __bind(this.addEntry, this);
|
|
this.onFocus = __bind(this.onFocus, this);
|
|
this.keybinds = __bind(this.keybinds, this);
|
|
this.close = __bind(this.close, this);
|
|
$.on(d, 'AddMenuEntry', this.addEntry);
|
|
$.on(d, 'rmMenuEntry', this.rmEntry);
|
|
this.entries = [];
|
|
}
|
|
|
|
Menu.prototype.makeMenu = function() {
|
|
var menu;
|
|
menu = $.el('div', {
|
|
className: 'dialog',
|
|
id: 'menu',
|
|
tabIndex: 0
|
|
});
|
|
$.on(menu, 'click', function(e) {
|
|
return e.stopPropagation();
|
|
});
|
|
$.on(menu, 'keydown', this.keybinds);
|
|
return menu;
|
|
};
|
|
|
|
Menu.prototype.toggle = function(e, button, data) {
|
|
var previousButton;
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
if (currentMenu) {
|
|
previousButton = lastToggledButton;
|
|
this.close();
|
|
if (previousButton === button) {
|
|
return;
|
|
}
|
|
}
|
|
if (!this.entries.length) {
|
|
return;
|
|
}
|
|
return this.open(button, data);
|
|
};
|
|
|
|
Menu.prototype.open = function(button, data) {
|
|
var bLeft, bRect, bTop, bottom, cHeight, cWidth, entry, left, mRect, menu, right, style, top, _i, _len, _ref, _ref1, _ref2;
|
|
menu = this.makeMenu();
|
|
currentMenu = menu;
|
|
lastToggledButton = button;
|
|
$.addClass(button, 'open');
|
|
this.entries.sort(function(first, second) {
|
|
return first.order - second.order;
|
|
});
|
|
_ref = this.entries;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
entry = _ref[_i];
|
|
this.insertEntry(entry, menu, data);
|
|
}
|
|
$.addClass(lastToggledButton, 'active');
|
|
$.on(d, 'click', this.close);
|
|
$.on(d, 'CloseMenu', this.close);
|
|
Rice.nodes(menu);
|
|
$.add(Header.hover, menu);
|
|
mRect = menu.getBoundingClientRect();
|
|
bRect = button.getBoundingClientRect();
|
|
bTop = window.scrollY + bRect.top;
|
|
bLeft = window.scrollX + bRect.left;
|
|
cHeight = doc.clientHeight;
|
|
cWidth = doc.clientWidth;
|
|
_ref1 = bRect.top + bRect.height + mRect.height < cHeight ? [bRect.bottom, null] : [null, cHeight - bRect.top], top = _ref1[0], bottom = _ref1[1];
|
|
_ref2 = bRect.left + mRect.width < cWidth ? [bRect.left, null] : [null, cWidth - bRect.right], left = _ref2[0], right = _ref2[1];
|
|
style = menu.style;
|
|
style.top = "" + top + "px";
|
|
style.right = "" + right + "px";
|
|
style.bottom = "" + bottom + "px";
|
|
style.left = "" + left + "px";
|
|
if (right) {
|
|
$.addClass(menu, 'left');
|
|
}
|
|
entry = $('.entry', menu);
|
|
this.focus(entry);
|
|
return menu.focus();
|
|
};
|
|
|
|
Menu.prototype.insertEntry = function(entry, parent, data) {
|
|
var subEntry, submenu, _i, _len, _ref;
|
|
if (typeof entry.open === 'function') {
|
|
if (!entry.open(data, (function(_this) {
|
|
return function(subEntry) {
|
|
_this.parseEntry(subEntry);
|
|
return entry.subEntries.push(subEntry);
|
|
};
|
|
})(this))) {
|
|
return;
|
|
}
|
|
}
|
|
$.add(parent, entry.el);
|
|
if (!entry.subEntries) {
|
|
return;
|
|
}
|
|
if (submenu = $('.submenu', entry.el)) {
|
|
$.rm(submenu);
|
|
}
|
|
submenu = $.el('div', {
|
|
className: 'dialog submenu'
|
|
});
|
|
_ref = entry.subEntries;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
subEntry = _ref[_i];
|
|
this.insertEntry(subEntry, submenu, data);
|
|
}
|
|
$.add(entry.el, submenu);
|
|
};
|
|
|
|
Menu.prototype.close = function() {
|
|
$.rm(currentMenu);
|
|
$.rmClass(lastToggledButton, 'open');
|
|
currentMenu = null;
|
|
lastToggledButton = null;
|
|
return $.off(d, 'click CloseMenu', this.close);
|
|
};
|
|
|
|
Menu.prototype.findNextEntry = function(entry, direction) {
|
|
var entries;
|
|
entries = __slice.call(entry.parentNode.children);
|
|
entries.sort(function(first, second) {
|
|
return first.style.order - second.style.order;
|
|
});
|
|
return entries[entries.indexOf(entry) + direction];
|
|
};
|
|
|
|
Menu.prototype.keybinds = function(e) {
|
|
var entry, next, nextPrev, subEntry, submenu;
|
|
entry = $('.focused', currentMenu);
|
|
while (subEntry = $('.focused', entry)) {
|
|
entry = subEntry;
|
|
}
|
|
switch (e.keyCode) {
|
|
case 27:
|
|
lastToggledButton.focus();
|
|
this.close();
|
|
break;
|
|
case 13:
|
|
case 32:
|
|
entry.click();
|
|
break;
|
|
case 38:
|
|
if (next = this.findNextEntry(entry, -1)) {
|
|
this.focus(next);
|
|
}
|
|
break;
|
|
case 40:
|
|
if (next = this.findNextEntry(entry, +1)) {
|
|
this.focus(next);
|
|
}
|
|
break;
|
|
case 39:
|
|
if ((submenu = $('.submenu', entry)) && (next = submenu.firstElementChild)) {
|
|
while (nextPrev = this.findNextEntry(next, -1)) {
|
|
next = nextPrev;
|
|
}
|
|
this.focus(next);
|
|
}
|
|
break;
|
|
case 37:
|
|
if (next = $.x('parent::*[contains(@class,"submenu")]/parent::*', entry)) {
|
|
this.focus(next);
|
|
}
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
e.preventDefault();
|
|
return e.stopPropagation();
|
|
};
|
|
|
|
Menu.prototype.onFocus = function(e) {
|
|
e.stopPropagation();
|
|
return this.focus(e.target);
|
|
};
|
|
|
|
Menu.prototype.focus = function(entry) {
|
|
var bottom, cHeight, cWidth, eRect, focused, left, right, sRect, style, submenu, top, _i, _len, _ref, _ref1, _ref2;
|
|
while (focused = $.x('parent::*/child::*[contains(@class,"focused")]', entry)) {
|
|
$.rmClass(focused, 'focused');
|
|
}
|
|
_ref = $$('.focused', entry);
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
focused = _ref[_i];
|
|
$.rmClass(focused, 'focused');
|
|
}
|
|
$.addClass(entry, 'focused');
|
|
if (!(submenu = $('.submenu', entry))) {
|
|
return;
|
|
}
|
|
sRect = submenu.getBoundingClientRect();
|
|
eRect = entry.getBoundingClientRect();
|
|
cHeight = doc.clientHeight;
|
|
cWidth = doc.clientWidth;
|
|
_ref1 = eRect.top + sRect.height < cHeight ? ['0px', 'auto'] : ['auto', '0px'], top = _ref1[0], bottom = _ref1[1];
|
|
_ref2 = eRect.right + sRect.width < cWidth - 150 ? ['100%', 'auto'] : ['auto', '100%'], left = _ref2[0], right = _ref2[1];
|
|
style = submenu.style;
|
|
style.top = top;
|
|
style.bottom = bottom;
|
|
style.left = left;
|
|
return style.right = right;
|
|
};
|
|
|
|
Menu.prototype.addEntry = function(e) {
|
|
var entry;
|
|
entry = e.detail;
|
|
if (entry.type !== this.type) {
|
|
return;
|
|
}
|
|
this.parseEntry(entry);
|
|
return this.entries.push(entry);
|
|
};
|
|
|
|
Menu.prototype.rmEntry = function(e) {
|
|
var entry, index;
|
|
entry = e.detail;
|
|
if (entry.type !== this.type) {
|
|
return;
|
|
}
|
|
index = this.entries.indexOf(entry);
|
|
return this.entries.splice(index, 1);
|
|
};
|
|
|
|
Menu.prototype.parseEntry = function(entry) {
|
|
var el, subEntries, subEntry, _i, _len;
|
|
el = entry.el, subEntries = entry.subEntries;
|
|
$.addClass(el, 'entry');
|
|
$.on(el, 'focus mouseover', this.onFocus);
|
|
el.style.order = entry.order || 100;
|
|
if (!subEntries) {
|
|
return;
|
|
}
|
|
$.addClass(el, 'has-submenu');
|
|
$.addClass(el, 'pfa');
|
|
for (_i = 0, _len = subEntries.length; _i < _len; _i++) {
|
|
subEntry = subEntries[_i];
|
|
this.parseEntry(subEntry);
|
|
}
|
|
};
|
|
|
|
return Menu;
|
|
|
|
})();
|
|
dragstart = function(e) {
|
|
var el, isTouching, o, rect, screenHeight, screenWidth, _ref, _ref1;
|
|
if (e.type === 'mousedown' && e.button !== 0) {
|
|
return;
|
|
}
|
|
e.preventDefault();
|
|
if (isTouching = e.type === 'touchstart') {
|
|
_ref = e.changedTouches, e = _ref[_ref.length - 1];
|
|
}
|
|
el = $.x('ancestor::div[contains(@class,"dialog")][1]', this);
|
|
rect = el.getBoundingClientRect();
|
|
screenHeight = doc.clientHeight;
|
|
screenWidth = doc.clientWidth;
|
|
o = {
|
|
id: el.id,
|
|
style: el.style,
|
|
dx: e.clientX - rect.left,
|
|
dy: e.clientY - rect.top,
|
|
height: screenHeight - rect.height,
|
|
width: screenWidth - rect.width,
|
|
screenHeight: screenHeight,
|
|
screenWidth: screenWidth,
|
|
isTouching: isTouching
|
|
};
|
|
_ref1 = Conf['Header auto-hide'] || !Conf['Fixed Header'] ? [0, 0] : Conf['Bottom Header'] ? [0, Header.bar.getBoundingClientRect().height] : [Header.bar.getBoundingClientRect().height, 0], o.topBorder = _ref1[0], o.bottomBorder = _ref1[1];
|
|
if (isTouching) {
|
|
o.identifier = e.identifier;
|
|
o.move = touchmove.bind(o);
|
|
o.up = touchend.bind(o);
|
|
$.on(d, 'touchmove', o.move);
|
|
return $.on(d, 'touchend touchcancel', o.up);
|
|
} else {
|
|
o.move = drag.bind(o);
|
|
o.up = dragend.bind(o);
|
|
$.on(d, 'mousemove', o.move);
|
|
return $.on(d, 'mouseup', o.up);
|
|
}
|
|
};
|
|
touchmove = function(e) {
|
|
var touch, _i, _len, _ref;
|
|
_ref = e.changedTouches;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
touch = _ref[_i];
|
|
if (touch.identifier === this.identifier) {
|
|
drag.call(this, touch);
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
drag = function(e) {
|
|
var bottom, clientX, clientY, left, right, style, top;
|
|
clientX = e.clientX, clientY = e.clientY;
|
|
left = clientX - this.dx;
|
|
left = left < 10 ? 0 : this.width - left < 10 ? null : left / this.screenWidth * 100 + '%';
|
|
top = clientY - this.dy;
|
|
top = top < (10 + this.topBorder) ? this.topBorder + 'px' : this.height - top < (10 + this.bottomBorder) ? null : top / this.screenHeight * 100 + '%';
|
|
right = left === null ? 0 : null;
|
|
bottom = top === null ? this.bottomBorder + 'px' : null;
|
|
style = this.style;
|
|
style.left = left;
|
|
style.right = right;
|
|
style.top = top;
|
|
return style.bottom = bottom;
|
|
};
|
|
touchend = function(e) {
|
|
var touch, _i, _len, _ref;
|
|
_ref = e.changedTouches;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
touch = _ref[_i];
|
|
if (touch.identifier === this.identifier) {
|
|
dragend.call(this);
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
dragend = function() {
|
|
if (this.isTouching) {
|
|
$.off(d, 'touchmove', this.move);
|
|
$.off(d, 'touchend touchcancel', this.up);
|
|
} else {
|
|
$.off(d, 'mousemove', this.move);
|
|
$.off(d, 'mouseup', this.up);
|
|
}
|
|
return $.set("" + this.id + ".position", this.style.cssText);
|
|
};
|
|
hoverstart = function(_arg) {
|
|
var asapTest, cb, el, endEvents, latestEvent, o, offsetX, offsetY, root;
|
|
root = _arg.root, el = _arg.el, latestEvent = _arg.latestEvent, endEvents = _arg.endEvents, asapTest = _arg.asapTest, cb = _arg.cb, offsetX = _arg.offsetX, offsetY = _arg.offsetY;
|
|
o = {
|
|
root: root,
|
|
el: el,
|
|
style: el.style,
|
|
cb: cb,
|
|
close: close,
|
|
endEvents: endEvents,
|
|
latestEvent: latestEvent,
|
|
clientHeight: doc.clientHeight,
|
|
clientWidth: doc.clientWidth,
|
|
offsetX: offsetX || 45,
|
|
offsetY: offsetY || -120
|
|
};
|
|
o.hover = hover.bind(o);
|
|
o.hoverend = hoverend.bind(o);
|
|
if (asapTest) {
|
|
$.asap(function() {
|
|
return !el.parentNode || asapTest();
|
|
}, function() {
|
|
if (el.parentNode) {
|
|
return o.hover(o.latestEvent);
|
|
}
|
|
});
|
|
}
|
|
$.on(root, endEvents, o.hoverend);
|
|
if ($.x('ancestor::div[contains(@class,"inline")][1]', root)) {
|
|
$.on(d, 'keydown', o.hoverend);
|
|
}
|
|
$.on(root, 'mousemove', o.hover);
|
|
o.workaround = function(e) {
|
|
if (!root.contains(e.target)) {
|
|
return o.hoverend();
|
|
}
|
|
};
|
|
return $.on(doc, 'mousemove', o.workaround);
|
|
};
|
|
hover = function(e) {
|
|
var clientX, clientY, height, left, right, top, _ref;
|
|
this.latestEvent = e;
|
|
height = this.el.offsetHeight + 25;
|
|
clientX = e.clientX, clientY = e.clientY;
|
|
top = clientY + this.offsetY;
|
|
top = this.clientHeight <= height || top <= 0 ? 0 : top + height >= this.clientHeight ? this.clientHeight - height : top;
|
|
_ref = clientX <= this.clientWidth / 2 ? [clientX + this.offsetX + 'px', null] : [null, this.clientWidth - clientX + this.offsetX + 'px'], left = _ref[0], right = _ref[1];
|
|
this.style.top = top + 'px';
|
|
this.style.left = left;
|
|
return this.style.right = right;
|
|
};
|
|
hoverend = function(e) {
|
|
if (e.type === 'keydown' && e.keyCode !== 13 || e.target.nodeName === "TEXTAREA") {
|
|
return;
|
|
}
|
|
$.rm(this.el);
|
|
$.off(this.root, this.endEvents, this.hoverend);
|
|
$.off(d, 'keydown', this.hoverend);
|
|
$.off(this.root, 'mousemove', this.hover);
|
|
$.off(doc, 'mousemove', this.workaround);
|
|
if (this.cb) {
|
|
return this.cb.call(this);
|
|
}
|
|
};
|
|
return {
|
|
dialog: dialog,
|
|
Menu: Menu,
|
|
hover: hoverstart
|
|
};
|
|
})();
|
|
|
|
Anonymize = {
|
|
init: function() {
|
|
if (!Conf['Anonymize']) {
|
|
return;
|
|
}
|
|
return Post.callbacks.push({
|
|
name: 'Anonymize',
|
|
cb: this.node
|
|
});
|
|
},
|
|
node: function() {
|
|
var email, name, tripcode, _ref;
|
|
if (this.info.capcode || this.isClone) {
|
|
return;
|
|
}
|
|
_ref = this.nodes, name = _ref.name, tripcode = _ref.tripcode, email = _ref.email;
|
|
if (this.info.name !== 'Anonymous') {
|
|
name.textContent = 'Anonymous';
|
|
}
|
|
if (tripcode) {
|
|
$.rm(tripcode);
|
|
delete this.nodes.tripcode;
|
|
}
|
|
if (this.info.email) {
|
|
$.replace(email, name);
|
|
return delete this.nodes.email;
|
|
}
|
|
}
|
|
};
|
|
|
|
Filter = {
|
|
filters: {},
|
|
init: function() {
|
|
var boards, err, filter, hl, key, op, regexp, stub, top, _i, _len, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
|
|
if (!Conf['Filter']) {
|
|
return;
|
|
}
|
|
if (!Conf['Filtered Backlinks']) {
|
|
$.addClass(doc, 'hide-backlinks');
|
|
}
|
|
for (key in Config.filter) {
|
|
this.filters[key] = [];
|
|
_ref = Conf[key].split('\n');
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
filter = _ref[_i];
|
|
if (filter[0] === '#') {
|
|
continue;
|
|
}
|
|
if (!(regexp = filter.match(/\/(.+)\/(\w*)/))) {
|
|
continue;
|
|
}
|
|
filter = filter.replace(regexp[0], '');
|
|
boards = ((_ref1 = filter.match(/boards:([^;]+)/)) != null ? _ref1[1].toLowerCase() : void 0) || 'global';
|
|
if (boards !== 'global' && (_ref2 = g.BOARD.ID, __indexOf.call(boards.split(','), _ref2) < 0)) {
|
|
continue;
|
|
}
|
|
if (key === 'uniqueID' || key === 'MD5') {
|
|
regexp = regexp[1];
|
|
} else {
|
|
try {
|
|
regexp = RegExp(regexp[1], regexp[2]);
|
|
} catch (_error) {
|
|
err = _error;
|
|
new Notice('warning', err.message, 60);
|
|
continue;
|
|
}
|
|
}
|
|
op = ((_ref3 = filter.match(/[^t]op:(yes|no|only)/)) != null ? _ref3[1] : void 0) || 'yes';
|
|
stub = (function() {
|
|
var _ref4;
|
|
switch ((_ref4 = filter.match(/stub:(yes|no)/)) != null ? _ref4[1] : void 0) {
|
|
case 'yes':
|
|
return true;
|
|
case 'no':
|
|
return false;
|
|
default:
|
|
return Conf['Stubs'];
|
|
}
|
|
})();
|
|
if (hl = /highlight/.test(filter)) {
|
|
hl = ((_ref4 = filter.match(/highlight:(\w+)/)) != null ? _ref4[1] : void 0) || 'filter-highlight';
|
|
top = ((_ref5 = filter.match(/top:(yes|no)/)) != null ? _ref5[1] : void 0) || 'yes';
|
|
top = top === 'yes';
|
|
}
|
|
this.filters[key].push({
|
|
hide: !hl,
|
|
op: op,
|
|
stub: stub,
|
|
"class": hl,
|
|
top: top,
|
|
match: regexp,
|
|
test: typeof regexp === 'string' ? Filter.stringTest : Filter.regexpTest
|
|
});
|
|
}
|
|
if (!this.filters[key].length) {
|
|
delete this.filters[key];
|
|
}
|
|
}
|
|
if (!Object.keys(this.filters).length) {
|
|
return;
|
|
}
|
|
return Post.callbacks.push({
|
|
name: 'Filter',
|
|
cb: this.node
|
|
});
|
|
},
|
|
node: function() {
|
|
var key, obj, value, _i, _len, _ref;
|
|
if (this.isClone) {
|
|
return;
|
|
}
|
|
for (key in Filter.filters) {
|
|
value = Filter[key](this);
|
|
if (value === false) {
|
|
continue;
|
|
}
|
|
_ref = Filter.filters[key];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
obj = _ref[_i];
|
|
if (!Filter.test(obj, value, this.isReply)) {
|
|
continue;
|
|
}
|
|
if (obj.hide) {
|
|
if (!(this.isReply || g.VIEW === 'index')) {
|
|
continue;
|
|
}
|
|
this.hide("Hidden by filtering the " + key + ": " + obj.match, obj.stub);
|
|
return;
|
|
}
|
|
this.highlight("Highlighted by filtering the " + key + ": " + obj.match, obj["class"], obj.top);
|
|
}
|
|
}
|
|
},
|
|
stringTest: function(string, value) {
|
|
return string === value;
|
|
},
|
|
regexpTest: function(regexp, value) {
|
|
return regexp.test(value);
|
|
},
|
|
test: function(_arg, value, isReply) {
|
|
var match, op, test;
|
|
test = _arg.test, match = _arg.match, op = _arg.op;
|
|
if (isReply && op === 'only' || !isReply && op === 'no') {
|
|
return false;
|
|
}
|
|
if (!test(match, value)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
},
|
|
name: function(post) {
|
|
if ('name' in post.info) {
|
|
return post.info.name;
|
|
}
|
|
return false;
|
|
},
|
|
uniqueID: function(post) {
|
|
if ('uniqueID' in post.info) {
|
|
return post.info.uniqueID;
|
|
}
|
|
return false;
|
|
},
|
|
tripcode: function(post) {
|
|
if ('tripcode' in post.info) {
|
|
return post.info.tripcode;
|
|
}
|
|
return false;
|
|
},
|
|
capcode: function(post) {
|
|
if ('capcode' in post.info) {
|
|
return post.info.capcode;
|
|
}
|
|
return false;
|
|
},
|
|
email: function(post) {
|
|
if ('email' in post.info) {
|
|
return post.info.email;
|
|
}
|
|
return false;
|
|
},
|
|
subject: function(post) {
|
|
if ('subject' in post.info) {
|
|
return post.info.subject || false;
|
|
}
|
|
return false;
|
|
},
|
|
comment: function(post) {
|
|
if ('comment' in post.info) {
|
|
return post.info.comment;
|
|
}
|
|
return false;
|
|
},
|
|
flag: function(post) {
|
|
if ('flag' in post.info) {
|
|
return post.info.flag;
|
|
}
|
|
return false;
|
|
},
|
|
filename: function(post) {
|
|
if (post.file) {
|
|
return post.file.name;
|
|
}
|
|
return false;
|
|
},
|
|
dimensions: function(post) {
|
|
if (post.file && post.file.isImage) {
|
|
return post.file.dimensions;
|
|
}
|
|
return false;
|
|
},
|
|
filesize: function(post) {
|
|
if (post.file) {
|
|
return post.file.size;
|
|
}
|
|
return false;
|
|
},
|
|
MD5: function(post) {
|
|
if (post.file) {
|
|
return post.file.MD5;
|
|
}
|
|
return false;
|
|
},
|
|
menu: {
|
|
init: function() {
|
|
var div, entry, type, _i, _len, _ref;
|
|
if (!Conf['Menu'] || !Conf['Filter']) {
|
|
return;
|
|
}
|
|
div = $.el('div', {
|
|
textContent: 'Filter'
|
|
});
|
|
entry = {
|
|
type: 'post',
|
|
el: div,
|
|
order: 50,
|
|
open: function(post) {
|
|
Filter.menu.post = post;
|
|
return true;
|
|
},
|
|
subEntries: []
|
|
};
|
|
_ref = [['Name', 'name'], ['Unique ID', 'uniqueID'], ['Tripcode', 'tripcode'], ['Capcode', 'capcode'], ['E-mail', 'email'], ['Subject', 'subject'], ['Comment', 'comment'], ['Flag', 'flag'], ['Filename', 'filename'], ['Image dimensions', 'dimensions'], ['Filesize', 'filesize'], ['Image MD5', 'MD5']];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
type = _ref[_i];
|
|
entry.subEntries.push(Filter.menu.createSubEntry(type[0], type[1]));
|
|
}
|
|
return $.event('AddMenuEntry', entry);
|
|
},
|
|
createSubEntry: function(text, type) {
|
|
var el;
|
|
el = $.el('a', {
|
|
href: 'javascript:;',
|
|
textContent: text
|
|
});
|
|
el.dataset.type = type;
|
|
$.on(el, 'click', Filter.menu.makeFilter);
|
|
return {
|
|
el: el,
|
|
open: function(post) {
|
|
var value;
|
|
value = Filter[type](post);
|
|
return value !== false;
|
|
}
|
|
};
|
|
},
|
|
makeFilter: function() {
|
|
var re, type, value;
|
|
type = this.dataset.type;
|
|
value = Filter[type](Filter.menu.post);
|
|
re = type === 'uniqueID' || type === 'MD5' ? value : value.replace(/\/|\\|\^|\$|\n|\.|\(|\)|\{|\}|\[|\]|\?|\*|\+|\|/g, function(c) {
|
|
if (c === '\n') {
|
|
return '\\n';
|
|
} else if (c === '\\') {
|
|
return '\\\\';
|
|
} else {
|
|
return "\\" + c;
|
|
}
|
|
});
|
|
re = type === 'uniqueID' || type === 'MD5' ? "/" + re + "/" : "/^" + re + "$/";
|
|
return $.get(type, Conf[type], function(item) {
|
|
var save, section, select, ta, tl;
|
|
save = item[type];
|
|
save = save ? "" + save + "\n" + re : re;
|
|
$.set(type, save);
|
|
Settings.open('Filter');
|
|
section = $('.section-container');
|
|
select = $('select[name=filter]', section);
|
|
select.value = type;
|
|
Settings.selectFilter.call(select);
|
|
ta = $('textarea', section);
|
|
tl = ta.textLength;
|
|
ta.setSelectionRange(tl, tl);
|
|
return ta.focus();
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
PostHiding = {
|
|
init: function() {
|
|
this.db = new DataBoard('hiddenPosts');
|
|
this.hideButton = $.el('a', {
|
|
className: 'hide-post-button fa',
|
|
href: 'javascript:;',
|
|
textContent: '\uf147'
|
|
});
|
|
this.showButton = $.el('a', {
|
|
className: 'show-post-button fa',
|
|
href: 'javascript:;',
|
|
textContent: '\uf196'
|
|
});
|
|
Post.callbacks.push({
|
|
name: 'Post Hiding',
|
|
cb: this.node
|
|
});
|
|
return $.get('hiddenThreads', null, function(_arg) {
|
|
var board, boardID, hiddenThreads, threadID, val, _base, _base1, _ref;
|
|
hiddenThreads = _arg.hiddenThreads;
|
|
if (!hiddenThreads) {
|
|
return;
|
|
}
|
|
_ref = hiddenThreads.boards;
|
|
for (boardID in _ref) {
|
|
board = _ref[boardID];
|
|
for (threadID in board) {
|
|
val = board[threadID];
|
|
((_base = ((_base1 = PostHiding.db.data.boards)[boardID] || (_base1[boardID] = {})))[threadID] || (_base[threadID] = {}))[threadID] = val;
|
|
}
|
|
}
|
|
PostHiding.db.save();
|
|
return $["delete"]('hiddenThreads');
|
|
});
|
|
},
|
|
node: function() {
|
|
var a, data, label;
|
|
if (!this.isReply && g.VIEW !== 'index' || this.isClone) {
|
|
return;
|
|
}
|
|
if (data = PostHiding.db.get({
|
|
boardID: this.board.ID,
|
|
threadID: this.thread.ID,
|
|
postID: this.ID
|
|
})) {
|
|
if (data.thisPost === false) {
|
|
label = "Recursively hidden for quoting No." + this;
|
|
Recursive.apply('hide', this, label, data.makeStub, true);
|
|
Recursive.add('hide', this, label, data.makeStub, true);
|
|
} else {
|
|
this.hide('Manually hidden', data.makeStub, data.hideRecursively);
|
|
}
|
|
}
|
|
if (!Conf['Post Hiding']) {
|
|
return;
|
|
}
|
|
if (this.isReply) {
|
|
a = PostHiding.makeButton(true);
|
|
if (this.isHidden) {
|
|
a.hidden = true;
|
|
}
|
|
return $.add($('.postInfo', this.nodes.post), a);
|
|
} else {
|
|
return $.add($('.postInfo', this.nodes.post), PostHiding.makeButton(!this.isHidden));
|
|
}
|
|
},
|
|
makeButton: function(hide) {
|
|
var a;
|
|
a = (hide ? PostHiding.hideButton : PostHiding.showButton).cloneNode(true);
|
|
$.on(a, 'click', PostHiding.onToggleClick);
|
|
return a;
|
|
},
|
|
onToggleClick: function() {
|
|
return PostHiding.toggle($.x('ancestor::div[contains(@class,"postContainer")][1]', this) ? Get.postFromNode(this) : Get.threadFromNode(this).OP);
|
|
},
|
|
toggle: function(post) {
|
|
var root;
|
|
if (post.isHidden) {
|
|
post.show();
|
|
} else {
|
|
post.hide('Manually hidden');
|
|
}
|
|
if (post.isReply) {
|
|
return;
|
|
}
|
|
Index.updateHideLabel();
|
|
if (Conf['Index Mode'] === 'all pages' || !Conf['JSON Navigation']) {
|
|
root = post.nodes.root.parentNode;
|
|
$.rm(root.nextElementSibling);
|
|
$.rm(root);
|
|
return;
|
|
}
|
|
Index.sort();
|
|
return Index.buildIndex();
|
|
},
|
|
saveHiddenState: function(post, val) {
|
|
var data;
|
|
data = {
|
|
boardID: post.board.ID,
|
|
threadID: post.thread.ID,
|
|
postID: post.ID
|
|
};
|
|
if (post.isHidden || val && !val.thisPost) {
|
|
data.val = val || {};
|
|
return PostHiding.db.set(data);
|
|
} else if (PostHiding.db.get(data)) {
|
|
return PostHiding.db["delete"](data);
|
|
}
|
|
},
|
|
menu: {
|
|
init: function() {
|
|
var apply, makeStub, replies, thisPost;
|
|
if (!Conf['Menu'] || !Conf['Post Hiding Link']) {
|
|
return;
|
|
}
|
|
apply = {
|
|
el: $.el('a', {
|
|
textContent: 'Apply',
|
|
href: 'javascript:;'
|
|
}),
|
|
open: function(post) {
|
|
if (this.cb) {
|
|
$.off(this.el, 'click', this.cb);
|
|
}
|
|
this.cb = function() {
|
|
return PostHiding.menu.hide(post);
|
|
};
|
|
$.on(this.el, 'click', this.cb);
|
|
return true;
|
|
}
|
|
};
|
|
thisPost = {
|
|
el: $.el('label', {
|
|
innerHTML: '<input type=checkbox name=thisPost checked> This post'
|
|
})
|
|
};
|
|
replies = {
|
|
el: $.el('label', {
|
|
innerHTML: "<input type=checkbox name=replies checked=" + Conf['Recursive Hiding'] + "> Hide replies"
|
|
})
|
|
};
|
|
makeStub = {
|
|
el: $.el('label', {
|
|
innerHTML: "<input type=checkbox name=makeStub checked=" + Conf['Stubs'] + "> Make stub"
|
|
})
|
|
};
|
|
$.event('AddMenuEntry', {
|
|
type: 'post',
|
|
el: $.el('div', {
|
|
textContent: 'Hide post',
|
|
className: 'hide-post-link'
|
|
}),
|
|
order: 20,
|
|
open: function(post) {
|
|
return !(post.isHidden || !post.isReply || post.isClone);
|
|
},
|
|
subEntries: [apply, thisPost, replies, makeStub]
|
|
});
|
|
apply = {
|
|
el: $.el('a', {
|
|
textContent: 'Apply',
|
|
href: 'javascript:;'
|
|
}),
|
|
open: function(post) {
|
|
if (this.cb) {
|
|
$.off(this.el, 'click', this.cb);
|
|
}
|
|
this.cb = function() {
|
|
return PostHiding.menu.show(post);
|
|
};
|
|
$.on(this.el, 'click', this.cb);
|
|
return true;
|
|
}
|
|
};
|
|
thisPost = {
|
|
el: $.el('label', {
|
|
innerHTML: '<input type=checkbox name=thisPost> This post'
|
|
}),
|
|
open: function(post) {
|
|
this.el.firstChild.checked = post.isHidden;
|
|
return true;
|
|
}
|
|
};
|
|
replies = {
|
|
el: $.el('label', {
|
|
innerHTML: '<input type=checkbox name=replies> Unhide replies'
|
|
}),
|
|
open: function(post) {
|
|
var data;
|
|
data = PostHiding.db.get({
|
|
boardID: post.board.ID,
|
|
threadID: post.thread.ID,
|
|
postID: post.ID
|
|
});
|
|
this.el.firstChild.checked = 'hideRecursively' in data ? data.hideRecursively : Conf['Recursive Hiding'];
|
|
return true;
|
|
}
|
|
};
|
|
$.event('AddMenuEntry', {
|
|
type: 'post',
|
|
el: $.el('div', {
|
|
textContent: 'Unhide post',
|
|
className: 'show-post-link'
|
|
}),
|
|
order: 20,
|
|
open: function(post) {
|
|
if (!post.isHidden || !post.isReply || post.isClone) {
|
|
return false;
|
|
}
|
|
if (!PostHiding.db.get({
|
|
boardID: post.board.ID,
|
|
threadID: post.thread.ID,
|
|
postID: post.ID
|
|
})) {
|
|
return false;
|
|
}
|
|
return true;
|
|
},
|
|
subEntries: [apply, thisPost, replies]
|
|
});
|
|
if (g.VIEW !== 'index') {
|
|
return;
|
|
}
|
|
return $.event('AddMenuEntry', {
|
|
type: 'post',
|
|
el: $.el('a', {
|
|
href: 'javascript:;'
|
|
}),
|
|
order: 20,
|
|
open: function(post) {
|
|
if (post.isReply) {
|
|
return false;
|
|
}
|
|
this.el.textContent = post.isHidden ? 'Unhide thread' : 'Hide thread';
|
|
if (this.cb) {
|
|
$.off(this.el, 'click', this.cb);
|
|
}
|
|
this.cb = function() {
|
|
$.event('CloseMenu');
|
|
return PostHiding.toggle(post);
|
|
};
|
|
$.on(this.el, 'click', this.cb);
|
|
return true;
|
|
}
|
|
});
|
|
},
|
|
hide: function(post) {
|
|
var label, makeStub, parent, replies, thisPost;
|
|
parent = this.parentNode;
|
|
thisPost = $('input[name=thisPost]', parent).checked;
|
|
replies = $('input[name=replies]', parent).checked;
|
|
makeStub = $('input[name=makeStub]', parent).checked;
|
|
label = 'Manually hidden';
|
|
if (thisPost) {
|
|
post.hide(label, makeStub, replies);
|
|
} else if (replies) {
|
|
Recursive.apply('hide', post, label, makeStub, true);
|
|
Recursive.add('hide', post, label, makeStub, true);
|
|
} else {
|
|
return;
|
|
}
|
|
if (!thisPost) {
|
|
PostHiding.saveHiddenState(post, {
|
|
thisPost: false,
|
|
hideRecursively: replies,
|
|
makeStub: makeStub
|
|
});
|
|
}
|
|
return $.event('CloseMenu');
|
|
},
|
|
show: function(post) {
|
|
var parent, replies, thisPost;
|
|
parent = this.parentNode;
|
|
thisPost = $('input[name=thisPost]', parent).checked;
|
|
replies = $('input[name=replies]', parent).checked;
|
|
if (thisPost) {
|
|
post.show(replies);
|
|
} else if (replies) {
|
|
Recursive.apply('show', post, true);
|
|
Recursive.rm('hide', post, true);
|
|
} else {
|
|
return;
|
|
}
|
|
if (!thisPost) {
|
|
PostHiding.saveHiddenState(post, {
|
|
thisPost: false,
|
|
hideRecursively: !replies,
|
|
makeStub: !!post.nodes.stub
|
|
});
|
|
}
|
|
return $.event('CloseMenu');
|
|
}
|
|
}
|
|
};
|
|
|
|
Recursive = {
|
|
recursives: {},
|
|
init: function() {
|
|
return Post.callbacks.push({
|
|
name: 'Recursive',
|
|
cb: this.node
|
|
});
|
|
},
|
|
node: function() {
|
|
var i, obj, quote, recursive, _i, _j, _len, _len1, _ref, _ref1;
|
|
if (this.isClone) {
|
|
return;
|
|
}
|
|
_ref = this.quotes;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
quote = _ref[_i];
|
|
if (obj = Recursive.recursives[quote]) {
|
|
_ref1 = obj.recursives;
|
|
for (i = _j = 0, _len1 = _ref1.length; _j < _len1; i = ++_j) {
|
|
recursive = _ref1[i];
|
|
this[recursive].apply(this, obj.args[i]);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
add: function() {
|
|
var args, obj, post, recursive, _base, _name;
|
|
recursive = arguments[0], post = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
|
|
obj = (_base = Recursive.recursives)[_name = post.fullID] || (_base[_name] = {
|
|
recursives: [],
|
|
args: []
|
|
});
|
|
obj.recursives.push(recursive);
|
|
return obj.args.push(args);
|
|
},
|
|
rm: function(recursive, post) {
|
|
var i, obj, rec, _i, _len, _ref;
|
|
if (!(obj = Recursive.recursives[post.fullID])) {
|
|
return;
|
|
}
|
|
_ref = obj.recursives;
|
|
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
|
|
rec = _ref[i];
|
|
if (!(rec === recursive)) {
|
|
continue;
|
|
}
|
|
obj.recursives.splice(i, 1);
|
|
obj.args.splice(i, 1);
|
|
}
|
|
},
|
|
apply: function() {
|
|
var args, fullID, post, recursive;
|
|
recursive = arguments[0], post = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
|
|
fullID = post.fullID;
|
|
return g.posts.forEach(function(post) {
|
|
if (__indexOf.call(post.quotes, fullID) >= 0) {
|
|
return post[recursive].apply(post, args);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
QuoteBacklink = {
|
|
init: function() {
|
|
var format;
|
|
if (!Conf['Quote Backlinks']) {
|
|
return;
|
|
}
|
|
format = Conf['backlink'].replace(/%id/g, "' + id + '");
|
|
this.funk = Function('id', "return '" + format + "'");
|
|
this.frag = $.nodes([
|
|
$.tn(' '), $.el('a', {
|
|
className: 'backlink'
|
|
})
|
|
]);
|
|
this.map = {};
|
|
Post.callbacks.push({
|
|
name: 'Quote Backlinking Part 1',
|
|
cb: this.firstNode
|
|
});
|
|
return Post.callbacks.push({
|
|
name: 'Quote Backlinking Part 2',
|
|
cb: this.secondNode
|
|
});
|
|
},
|
|
firstNode: function() {
|
|
var addNodes, container, post, quoteID, _base, _i, _j, _len, _len1, _ref, _ref1;
|
|
if (this.isClone) {
|
|
return;
|
|
}
|
|
addNodes = function(post, that) {
|
|
return $.add(post.nodes.backlinkContainer, QuoteBacklink.buildBacklink(post, that));
|
|
};
|
|
_ref = this.quotes;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
quoteID = _ref[_i];
|
|
((_base = QuoteBacklink.map)[quoteID] || (_base[quoteID] = [])).push(this.fullID);
|
|
if (!(((post = g.posts[quoteID]) != null) && (container = post.nodes.backlinkContainer))) {
|
|
continue;
|
|
}
|
|
addNodes(post, this);
|
|
_ref1 = post.clones;
|
|
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
|
post = _ref1[_j];
|
|
addNodes(post, this);
|
|
}
|
|
}
|
|
},
|
|
secondNode: function() {
|
|
var backlink, container, map, post, quoteID, _i, _j, _len, _len1, _ref;
|
|
if (!(this.isReply || Conf['OP Backlinks'])) {
|
|
return;
|
|
}
|
|
if (this.isClone) {
|
|
this.nodes.backlinkContainer = $('.backlink-container', this.nodes.info);
|
|
_ref = this.nodes.backlinks;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
backlink = _ref[_i];
|
|
QuoteMarkers.parseQuotelink(this, backlink, true, QuoteBacklink.funk(Get.postDataFromLink(backlink).postID));
|
|
}
|
|
return;
|
|
}
|
|
this.nodes.backlinkContainer = container = $.el('span', {
|
|
className: 'backlink-container'
|
|
});
|
|
if (map = QuoteBacklink.map[this.fullID]) {
|
|
for (_j = 0, _len1 = map.length; _j < _len1; _j++) {
|
|
quoteID = map[_j];
|
|
if (post = g.posts[quoteID]) {
|
|
$.add(container, QuoteBacklink.buildBacklink(this, post));
|
|
}
|
|
}
|
|
}
|
|
return $.add(this.nodes.info, container);
|
|
},
|
|
buildBacklink: function(quoted, quoter) {
|
|
var a, frag, hash, text;
|
|
frag = QuoteBacklink.frag.cloneNode(true);
|
|
a = frag.lastElementChild;
|
|
a.href = "/" + quoter.board + "/res/" + quoter.thread + "#p" + quoter;
|
|
a.textContent = text = QuoteBacklink.funk(quoter.ID);
|
|
if (quoter.isDead) {
|
|
$.addClass(a, 'deadlink');
|
|
}
|
|
if (quoter.isHidden) {
|
|
$.addClass(a, 'filtered');
|
|
}
|
|
QuoteMarkers.parseQuotelink(quoted, a, false, text);
|
|
if (Conf['Quote Previewing']) {
|
|
$.on(a, 'mouseover', QuotePreview.mouseover);
|
|
}
|
|
if (Conf['Quote Inlining']) {
|
|
$.on(a, 'click', QuoteInline.toggle);
|
|
if (Conf['Quote Hash Navigation']) {
|
|
hash = QuoteInline.qiQuote(a, quoter.isHidden);
|
|
}
|
|
}
|
|
if (Conf['JSON Navigation']) {
|
|
if (hash) {
|
|
Navigate.singleQuoteLink(hash);
|
|
} else if (!Conf['Quote Inlining']) {
|
|
Navigate.singleQuoteLink(a);
|
|
}
|
|
}
|
|
return frag;
|
|
}
|
|
};
|
|
|
|
QuoteInline = {
|
|
init: function() {
|
|
if (!Conf['Quote Inlining']) {
|
|
return;
|
|
}
|
|
this.process = Conf['Quote Hash Navigation'] ? function(link, clone) {
|
|
$.on(link, 'click', QuoteInline.toggle);
|
|
if (clone) {
|
|
return;
|
|
}
|
|
return QuoteInline.qiQuote(link, $.hasClass(link, 'filtered'));
|
|
} : function(link) {
|
|
return $.on(link, 'click', QuoteInline.toggle);
|
|
};
|
|
if (Conf['Comment Expansion']) {
|
|
ExpandComment.callbacks.push(this.node);
|
|
}
|
|
return Post.callbacks.push({
|
|
name: 'Quote Inlining',
|
|
cb: this.node
|
|
});
|
|
},
|
|
node: function() {
|
|
var isClone, link, process, _i, _j, _len, _len1, _ref, _ref1;
|
|
process = QuoteInline.process;
|
|
isClone = this.isClone;
|
|
_ref = this.nodes.quotelinks;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
link = _ref[_i];
|
|
process(link, isClone);
|
|
}
|
|
_ref1 = this.nodes.backlinks;
|
|
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
|
link = _ref1[_j];
|
|
process(link, isClone);
|
|
}
|
|
},
|
|
qiQuote: function(link, hidden) {
|
|
var name;
|
|
name = "hashlink";
|
|
if (hidden) {
|
|
name += "filtered";
|
|
}
|
|
return $.after(link, $.el('a', {
|
|
className: name,
|
|
textContent: '#',
|
|
href: link.href
|
|
}));
|
|
},
|
|
toggle: function(e) {
|
|
var boardID, context, postID, threadID, _ref;
|
|
if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) {
|
|
return;
|
|
}
|
|
e.preventDefault();
|
|
_ref = Get.postDataFromLink(this), boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
|
|
context = Get.contextFromNode(this);
|
|
if ($.hasClass(this, 'inlined')) {
|
|
QuoteInline.rm(this, boardID, threadID, postID, context);
|
|
} else {
|
|
if ($.x("ancestor::div[@id='pc" + postID + "']", this)) {
|
|
return;
|
|
}
|
|
QuoteInline.add(this, boardID, threadID, postID, context);
|
|
}
|
|
return this.classList.toggle('inlined');
|
|
},
|
|
findRoot: function(quotelink, isBacklink) {
|
|
if (isBacklink) {
|
|
return quotelink.parentNode.parentNode;
|
|
} else {
|
|
return $.x('ancestor-or-self::*[parent::blockquote][1]', quotelink);
|
|
}
|
|
},
|
|
add: function(quotelink, boardID, threadID, postID, context) {
|
|
var inline, isBacklink, post, qroot, root;
|
|
isBacklink = $.hasClass(quotelink, 'backlink');
|
|
inline = $.el('div', {
|
|
id: "i" + postID,
|
|
className: 'inline'
|
|
});
|
|
root = QuoteInline.findRoot(quotelink, isBacklink);
|
|
$.after(root, inline);
|
|
qroot = $.x('ancestor::*[contains(@class,"postContainer")][1]', root);
|
|
$.addClass(qroot, 'hasInline');
|
|
Get.postClone(boardID, threadID, postID, inline, context);
|
|
if (!((post = g.posts["" + boardID + "." + postID]) && context.thread === post.thread)) {
|
|
return;
|
|
}
|
|
if (isBacklink && Conf['Forward Hiding']) {
|
|
$.addClass(post.nodes.root, 'forwarded');
|
|
post.forwarded++ || (post.forwarded = 1);
|
|
}
|
|
if (!Unread.posts) {
|
|
return;
|
|
}
|
|
return Unread.readSinglePost(post);
|
|
},
|
|
rm: function(quotelink, boardID, threadID, postID, context) {
|
|
var el, inlined, isBacklink, post, qroot, root, _ref;
|
|
isBacklink = $.hasClass(quotelink, 'backlink');
|
|
root = QuoteInline.findRoot(quotelink, isBacklink);
|
|
root = $.x("following-sibling::div[@id='i" + postID + "'][1]", root);
|
|
qroot = $.x('ancestor::*[contains(@class,"postContainer")][1]', root);
|
|
$.rm(root);
|
|
if (!$('.inline', qroot)) {
|
|
$.rmClass(qroot, 'hasInline');
|
|
}
|
|
if (!(el = root.firstElementChild)) {
|
|
return;
|
|
}
|
|
post = g.posts["" + boardID + "." + postID];
|
|
post.rmClone(el.dataset.clone);
|
|
if (Conf['Forward Hiding'] && isBacklink && context.thread === g.threads["" + boardID + "." + threadID] && !--post.forwarded) {
|
|
delete post.forwarded;
|
|
$.rmClass(post.nodes.root, 'forwarded');
|
|
}
|
|
while (inlined = $('.inlined', el)) {
|
|
_ref = Get.postDataFromLink(inlined), boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
|
|
QuoteInline.rm(inlined, boardID, threadID, postID, context);
|
|
$.rmClass(inlined, 'inlined');
|
|
}
|
|
}
|
|
};
|
|
|
|
QuoteMarkers = {
|
|
init: function() {
|
|
if (Conf['Highlight Own Posts']) {
|
|
$.addClass(doc, 'highlight-own');
|
|
}
|
|
if (Conf['Highlight Posts Quoting You']) {
|
|
$.addClass(doc, 'highlight-you');
|
|
}
|
|
return Post.callbacks.push({
|
|
name: 'Quote Markers',
|
|
cb: this.node
|
|
});
|
|
},
|
|
node: function() {
|
|
var parseQuotelink, quotelink, _i, _len, _ref;
|
|
parseQuotelink = QuoteMarkers.parseQuotelink;
|
|
_ref = this.nodes.quotelinks;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
quotelink = _ref[_i];
|
|
parseQuotelink(this, quotelink, !!this.isClone);
|
|
}
|
|
},
|
|
parseQuotelink: function(post, quotelink, mayReset, customText) {
|
|
var board, boardID, markers, postID, text, thread, threadID, _ref, _ref1;
|
|
_ref = post.isClone ? post.context : post, board = _ref.board, thread = _ref.thread;
|
|
markers = [];
|
|
_ref1 = Get.postDataFromLink(quotelink), boardID = _ref1.boardID, threadID = _ref1.threadID, postID = _ref1.postID;
|
|
if (QR.db.get({
|
|
boardID: boardID,
|
|
threadID: threadID,
|
|
postID: postID
|
|
})) {
|
|
if (Conf['Mark Quotes of You']) {
|
|
markers.push('You');
|
|
}
|
|
$.addClass(post.nodes.root, 'quotesYou');
|
|
}
|
|
if (board.ID === boardID) {
|
|
if (Conf['Mark OP Quotes'] && thread.ID === postID) {
|
|
markers.push('OP');
|
|
}
|
|
if (Conf['Mark Cross-thread Quotes'] && (threadID && threadID !== thread.ID)) {
|
|
markers.push('Cross-thread');
|
|
}
|
|
}
|
|
if ($.hasClass(quotelink, 'deadlink')) {
|
|
markers.push('Dead');
|
|
}
|
|
text = customText ? customText : boardID === post.board.ID ? ">>" + postID : ">>>/" + boardID + "/" + postID;
|
|
if (markers.length) {
|
|
return quotelink.textContent = "" + text + "\u00A0(" + (markers.join('|')) + ")";
|
|
} else if (mayReset) {
|
|
return quotelink.textContent = text;
|
|
}
|
|
},
|
|
cb: {
|
|
seek: function(type) {
|
|
var post;
|
|
if (Conf['Mark Quotes of You'] && (post = QuoteMarkers.cb.findPost(type))) {
|
|
return QuoteMarkers.cb.scroll(post);
|
|
}
|
|
},
|
|
findPost: function(type) {
|
|
var i, index, len, post, posts;
|
|
posts = $$('.quotesYou');
|
|
if (!QuoteMarkers.lastRead) {
|
|
if (!(post = QuoteMarkers.lastRead = posts[0])) {
|
|
new Notice('warning', 'No posts are currently quoting you, loser.', 20);
|
|
return;
|
|
}
|
|
if (!Get.postFromRoot(post).isHidden) {
|
|
return post;
|
|
}
|
|
} else {
|
|
post = QuoteMarkers.lastRead;
|
|
}
|
|
len = posts.length - 1;
|
|
index = i = posts.indexOf(post);
|
|
while (true) {
|
|
if (index === (i = type === 'prev' ? i === 0 ? len : i - 1 : i === len ? 0 : i + 1)) {
|
|
break;
|
|
}
|
|
post = posts[i];
|
|
if (!Get.postFromRoot(post).isHidden) {
|
|
return post;
|
|
}
|
|
}
|
|
},
|
|
scroll: function(post) {
|
|
var highlight;
|
|
if (highlight = $('.highlight')) {
|
|
$.rmClass(highlight, 'highlight');
|
|
}
|
|
QuoteMarkers.lastRead = post;
|
|
window.location.hash = "#" + post.id;
|
|
Header.scrollTo(post);
|
|
return $.addClass($('.post', post), 'highlight');
|
|
}
|
|
}
|
|
};
|
|
|
|
QuotePreview = {
|
|
init: function() {
|
|
if (!Conf['Quote Previewing']) {
|
|
return;
|
|
}
|
|
if (Conf['Comment Expansion']) {
|
|
ExpandComment.callbacks.push(this.node);
|
|
}
|
|
return Post.callbacks.push({
|
|
name: 'Quote Previewing',
|
|
cb: this.node
|
|
});
|
|
},
|
|
node: function() {
|
|
var link, _i, _len, _ref;
|
|
_ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks));
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
link = _ref[_i];
|
|
$.on(link, 'mouseover', QuotePreview.mouseover);
|
|
}
|
|
},
|
|
mouseover: function(e) {
|
|
var boardID, clone, origin, post, postID, posts, qp, quote, quoterID, threadID, _i, _j, _len, _len1, _ref, _ref1;
|
|
if ($.hasClass(this, 'inlined')) {
|
|
return;
|
|
}
|
|
_ref = Get.postDataFromLink(this), boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
|
|
qp = $.el('div', {
|
|
id: 'qp',
|
|
className: 'dialog'
|
|
});
|
|
$.add(Header.hover, qp);
|
|
Get.postClone(boardID, threadID, postID, qp, Get.contextFromNode(this));
|
|
UI.hover({
|
|
root: this,
|
|
el: qp,
|
|
latestEvent: e,
|
|
endEvents: 'mouseout click',
|
|
cb: QuotePreview.mouseout,
|
|
asapTest: function() {
|
|
return qp.firstElementChild;
|
|
}
|
|
});
|
|
if (!(origin = g.posts["" + boardID + "." + postID])) {
|
|
return;
|
|
}
|
|
if (Conf['Quote Highlighting']) {
|
|
posts = [origin].concat(origin.clones);
|
|
posts.pop();
|
|
for (_i = 0, _len = posts.length; _i < _len; _i++) {
|
|
post = posts[_i];
|
|
$.addClass(post.nodes.post, 'qphl');
|
|
}
|
|
}
|
|
quoterID = $.x('ancestor::*[@id][1]', this).id.match(/\d+$/)[0];
|
|
clone = Get.postFromRoot(qp.firstChild);
|
|
_ref1 = clone.nodes.quotelinks.concat(__slice.call(clone.nodes.backlinks));
|
|
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
|
quote = _ref1[_j];
|
|
if (quote.hash.slice(2) === quoterID) {
|
|
$.addClass(quote, 'forwardlink');
|
|
}
|
|
}
|
|
},
|
|
mouseout: function() {
|
|
var clone, post, root, _i, _len, _ref;
|
|
if (!(root = this.el.firstElementChild)) {
|
|
return;
|
|
}
|
|
clone = Get.postFromRoot(root);
|
|
post = clone.origin;
|
|
post.rmClone(root.dataset.clone);
|
|
if (!Conf['Quote Highlighting']) {
|
|
return;
|
|
}
|
|
_ref = [post].concat(post.clones);
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
post = _ref[_i];
|
|
$.rmClass(post.nodes.post, 'qphl');
|
|
}
|
|
}
|
|
};
|
|
|
|
QuoteStrikeThrough = {
|
|
init: function() {
|
|
if (!Conf['Post Hiding'] && !Conf['Post Hiding Link'] && !Conf['Filter']) {
|
|
return;
|
|
}
|
|
return Post.callbacks.push({
|
|
name: 'Strike-through Quotes',
|
|
cb: this.node
|
|
});
|
|
},
|
|
node: function() {
|
|
var boardID, postID, quotelink, _i, _len, _ref, _ref1, _ref2;
|
|
if (this.isClone) {
|
|
return;
|
|
}
|
|
_ref = this.nodes.quotelinks;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
quotelink = _ref[_i];
|
|
_ref1 = Get.postDataFromLink(quotelink), boardID = _ref1.boardID, postID = _ref1.postID;
|
|
if ((_ref2 = g.posts["" + boardID + "." + postID]) != null ? _ref2.isHidden : void 0) {
|
|
$.addClass(quotelink, 'filtered');
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
/*
|
|
<3 aeosynth
|
|
*/
|
|
|
|
QuoteThreading = {
|
|
init: function() {
|
|
var input;
|
|
if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) {
|
|
return;
|
|
}
|
|
this.enabled = true;
|
|
this.controls = $.el('span', {
|
|
innerHTML: '<label><input id=threadingControl type=checkbox checked> Threading</label>'
|
|
});
|
|
input = $('input', this.controls);
|
|
$.on(input, 'change', this.toggle);
|
|
$.event('AddMenuEntry', this.entry = {
|
|
type: 'header',
|
|
el: this.controls,
|
|
order: 98
|
|
});
|
|
if (!Conf['Unread Count']) {
|
|
$.on(d, '4chanXInitFinished', this.ready);
|
|
}
|
|
return Post.callbacks.push({
|
|
name: 'Quote Threading',
|
|
cb: this.node
|
|
});
|
|
},
|
|
disconnect: function() {
|
|
var input;
|
|
if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) {
|
|
return;
|
|
}
|
|
input = $('input', this.controls);
|
|
$.off(input, 'change', this.toggle);
|
|
$.event('rmMenuEntry', this.entry);
|
|
delete this.enabled;
|
|
delete this.controls;
|
|
delete this.entry;
|
|
return Post.callbacks.disconnect('Quote Threading');
|
|
},
|
|
ready: function() {
|
|
$.off(d, '4chanXInitFinished', QuoteThreading.ready);
|
|
return QuoteThreading.force();
|
|
},
|
|
force: function() {
|
|
g.posts.forEach(function(post) {
|
|
if (post.cb) {
|
|
return post.cb(true);
|
|
}
|
|
});
|
|
if (Conf['Unread Count'] && Unread.thread.OP.nodes.root.parentElement.parentElement) {
|
|
Unread.read();
|
|
return Unread.update();
|
|
}
|
|
},
|
|
node: function() {
|
|
var keys, len, posts, quote, _i, _len, _ref;
|
|
posts = g.posts;
|
|
if (this.isClone || !QuoteThreading.enabled) {
|
|
return;
|
|
}
|
|
if (Conf['Unread Count']) {
|
|
Unread.posts.push(this);
|
|
}
|
|
if (this.thread.OP === this || this.isHidden) {
|
|
return;
|
|
}
|
|
keys = [];
|
|
len = g.BOARD.ID.length + 1;
|
|
_ref = this.quotes;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
quote = _ref[_i];
|
|
if ((quote.slice(len) < this.ID) && quote in posts) {
|
|
keys.push(quote);
|
|
}
|
|
}
|
|
if (keys.length !== 1) {
|
|
return;
|
|
}
|
|
this.threaded = keys[0];
|
|
return this.cb = QuoteThreading.nodeinsert;
|
|
},
|
|
nodeinsert: function(force) {
|
|
var bottom, height, post, posts, root, threadContainer, top, _ref;
|
|
post = g.posts[this.threaded];
|
|
if (this.thread.OP === post) {
|
|
return false;
|
|
}
|
|
posts = Unread.posts;
|
|
root = post.nodes.root;
|
|
if (!force) {
|
|
height = doc.clientHeight;
|
|
_ref = root.getBoundingClientRect(), bottom = _ref.bottom, top = _ref.top;
|
|
if (!((Conf['Unread Count'] && posts[post.ID]) || ((bottom < height) && (top > 0)))) {
|
|
return false;
|
|
}
|
|
}
|
|
if ($.hasClass(root, 'threadOP')) {
|
|
threadContainer = root.nextElementSibling;
|
|
post = Get.postFromRoot($.x('descendant::div[contains(@class,"postContainer")][last()]', threadContainer));
|
|
$.add(threadContainer, this.nodes.root);
|
|
} else {
|
|
threadContainer = $.el('div', {
|
|
className: 'threadContainer'
|
|
});
|
|
$.add(threadContainer, this.nodes.root);
|
|
$.after(root, threadContainer);
|
|
$.addClass(root, 'threadOP');
|
|
}
|
|
if (!Conf['Unread Count']) {
|
|
return true;
|
|
}
|
|
if (post = posts[post.ID]) {
|
|
posts.after(post, posts[this.ID]);
|
|
} else {
|
|
posts.prepend(posts[this.ID]);
|
|
}
|
|
return true;
|
|
},
|
|
toggle: function() {
|
|
var container, containers, nodes, post, posts, thread, _i, _j, _k, _len, _len1, _len2, _ref;
|
|
if (QuoteThreading.enabled = this.checked) {
|
|
QuoteThreading.force();
|
|
} else {
|
|
thread = $('.thread');
|
|
posts = [];
|
|
nodes = [];
|
|
g.posts.forEach(function(post) {
|
|
if (!(post === post.thread.OP || post.isClone)) {
|
|
return posts.push(post);
|
|
}
|
|
});
|
|
posts.sort(function(a, b) {
|
|
return a.ID - b.ID;
|
|
});
|
|
for (_i = 0, _len = posts.length; _i < _len; _i++) {
|
|
post = posts[_i];
|
|
nodes.push(post.nodes.root);
|
|
}
|
|
$.add(thread, nodes);
|
|
containers = $$('.threadContainer', thread);
|
|
for (_j = 0, _len1 = containers.length; _j < _len1; _j++) {
|
|
container = containers[_j];
|
|
$.rm(container);
|
|
}
|
|
_ref = $$('.threadOP');
|
|
for (_k = 0, _len2 = _ref.length; _k < _len2; _k++) {
|
|
post = _ref[_k];
|
|
$.rmClass(post, 'threadOP');
|
|
}
|
|
}
|
|
},
|
|
kb: function() {
|
|
var control;
|
|
control = $.id('threadingControl');
|
|
control.checked = !control.checked;
|
|
return QuoteThreading.toggle.call(control);
|
|
}
|
|
};
|
|
|
|
Quotify = {
|
|
init: function() {
|
|
if (!Conf['Resurrect Quotes']) {
|
|
return;
|
|
}
|
|
if (Conf['Comment Expansion']) {
|
|
ExpandComment.callbacks.push(this.node);
|
|
}
|
|
return Post.callbacks.push({
|
|
name: 'Resurrect Quotes',
|
|
cb: this.node
|
|
});
|
|
},
|
|
node: function() {
|
|
var deadlink, _i, _len, _ref;
|
|
_ref = $$('.deadlink', this.nodes.comment);
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
deadlink = _ref[_i];
|
|
if (this.isClone) {
|
|
if ($.hasClass(deadlink, 'quotelink')) {
|
|
this.nodes.quotelinks.push(deadlink);
|
|
}
|
|
} else {
|
|
Quotify.parseDeadlink.call(this, deadlink);
|
|
}
|
|
}
|
|
},
|
|
parseDeadlink: function(deadlink) {
|
|
var a, boardID, m, post, postID, quote, quoteID, redirect, _ref;
|
|
if ($.hasClass(deadlink.parentNode, 'prettyprint')) {
|
|
Quotify.fixDeadlink(deadlink);
|
|
return;
|
|
}
|
|
quote = deadlink.textContent;
|
|
if (!(postID = (_ref = quote.match(/\d+$/)) != null ? _ref[0] : void 0)) {
|
|
return;
|
|
}
|
|
if (postID[0] === '0') {
|
|
Quotify.fixDeadlink(deadlink);
|
|
return;
|
|
}
|
|
boardID = (m = quote.match(/^>>>\/([a-z\d]+)/)) ? m[1] : this.board.ID;
|
|
quoteID = "" + boardID + "." + postID;
|
|
if (post = g.posts[quoteID]) {
|
|
a = $.el('a', {
|
|
href: "/" + boardID + "/res/" + post.thread + "#p" + postID,
|
|
className: post.isDead ? 'quotelink deadlink' : 'quotelink',
|
|
textContent: quote
|
|
});
|
|
$.extend(a.dataset, {
|
|
boardID: boardID,
|
|
threadID: post.thread.ID,
|
|
postID: postID
|
|
});
|
|
} else if (redirect = Redirect.to('thread', {
|
|
boardID: boardID,
|
|
postID: postID
|
|
})) {
|
|
a = $.el('a', {
|
|
href: redirect,
|
|
className: 'deadlink',
|
|
textContent: quote,
|
|
target: '_blank'
|
|
});
|
|
if (Redirect.to('post', {
|
|
boardID: boardID,
|
|
postID: postID
|
|
})) {
|
|
$.addClass(a, 'quotelink');
|
|
$.extend(a.dataset, {
|
|
boardID: boardID,
|
|
postID: postID
|
|
});
|
|
}
|
|
}
|
|
if (__indexOf.call(this.quotes, quoteID) < 0) {
|
|
this.quotes.push(quoteID);
|
|
}
|
|
if (!a) {
|
|
deadlink.textContent = "" + quote + "\u00A0(Dead)";
|
|
return;
|
|
}
|
|
$.replace(deadlink, a);
|
|
if ($.hasClass(a, 'quotelink')) {
|
|
return this.nodes.quotelinks.push(a);
|
|
}
|
|
},
|
|
fixDeadlink: function(deadlink) {
|
|
var el, green;
|
|
if (!(el = deadlink.previousSibling) || el.nodeName === 'BR') {
|
|
green = $.el('span', {
|
|
className: 'quote'
|
|
});
|
|
$.before(deadlink, green);
|
|
$.add(green, deadlink);
|
|
}
|
|
return $.replace(deadlink, __slice.call(deadlink.childNodes));
|
|
}
|
|
};
|
|
|
|
Linkify = {
|
|
init: function() {
|
|
var type, _i, _len, _ref;
|
|
if (!Conf['Linkify']) {
|
|
return;
|
|
}
|
|
this.types = {};
|
|
_ref = this.ordered_types;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
type = _ref[_i];
|
|
this.types[type.key] = type;
|
|
}
|
|
if (Conf['Comment Expansion']) {
|
|
ExpandComment.callbacks.push(this.node);
|
|
}
|
|
if (Conf['Embedding'] || Conf['Link Title']) {
|
|
this.embedProcess = Function('link', "var data = this.services(link); if (data) { " + ((Conf['Embedding'] ? 'this.embed(data);\n' : '') + (Conf['Title Link'] ? 'this.title(data);' : '')) + " }");
|
|
}
|
|
return Post.callbacks.push({
|
|
name: 'Linkify',
|
|
cb: this.node
|
|
});
|
|
},
|
|
events: function(post) {
|
|
var el, i, items;
|
|
i = 0;
|
|
items = $$('.embedder', post.nodes.comment);
|
|
while (el = items[i++]) {
|
|
$.on(el, 'click', Linkify.cb.toggle);
|
|
if ($.hasClass(el, 'embedded')) {
|
|
Linkify.cb.toggle.call(el);
|
|
}
|
|
}
|
|
},
|
|
node: function() {
|
|
var data, end, endNode, i, index, length, link, links, node, result, saved, snapshot, space, test, word;
|
|
if (this.isClone) {
|
|
return (Conf['Embedding'] ? Linkify.events(this) : null);
|
|
}
|
|
if (!Linkify.regString.test(this.info.comment)) {
|
|
return;
|
|
}
|
|
test = /[^\s'"]+/g;
|
|
space = /[\s'"]/;
|
|
snapshot = $.X('.//br|.//text()', this.nodes.comment);
|
|
i = 0;
|
|
links = [];
|
|
while (node = snapshot.snapshotItem(i++)) {
|
|
data = node.data;
|
|
if (!data || node.parentElement.nodeName === "A") {
|
|
continue;
|
|
}
|
|
while (result = test.exec(data)) {
|
|
index = result.index;
|
|
endNode = node;
|
|
word = result[0];
|
|
if ((length = index + word.length) === data.length) {
|
|
test.lastIndex = 0;
|
|
while ((saved = snapshot.snapshotItem(i++))) {
|
|
if (saved.nodeName === 'BR') {
|
|
break;
|
|
}
|
|
endNode = saved;
|
|
data = saved.data;
|
|
word += data;
|
|
length = data.length;
|
|
if (end = space.exec(data)) {
|
|
test.lastIndex = length = end.index;
|
|
i--;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (Linkify.regString.exec(word)) {
|
|
links.push(Linkify.makeRange(node, endNode, index, length));
|
|
}
|
|
if (!(test.lastIndex && node === endNode)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
i = links.length;
|
|
while (i--) {
|
|
link = links[i];
|
|
Linkify.embedProcess(Linkify.makeLink(link, this));
|
|
}
|
|
},
|
|
embedProcess: function() {},
|
|
regString: /((https?|mailto|git|magnet|ftp|irc):([a-z\d%\/])|[-a-z\d]+[.](aero|asia|biz|cat|com|coop|info|int|jobs|mobi|museum|name|net|org|post|pro|tel|travel|xxx|edu|gov|mil|[a-z]{2})([:\/]|(?!.))|[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}|[-\w\d.@]+@[a-z\d.-]+\.[a-z\d])/i,
|
|
makeRange: function(startNode, endNode, startOffset, endOffset) {
|
|
var range;
|
|
range = document.createRange();
|
|
range.setStart(startNode, startOffset);
|
|
range.setEnd(endNode, endOffset);
|
|
return range;
|
|
},
|
|
makeLink: function(range) {
|
|
var a, i, t, text;
|
|
text = range.toString();
|
|
i = 0;
|
|
while (/[(\[{<>]/.test(text.charAt(i))) {
|
|
i++;
|
|
}
|
|
if (i) {
|
|
text = text.slice(i);
|
|
while (range.startOffset + i >= range.startContainer.data.length) {
|
|
i--;
|
|
}
|
|
if (i) {
|
|
range.setStart(range.startContainer, range.startOffset + i);
|
|
}
|
|
}
|
|
i = 0;
|
|
while (/[)\]}>.,]/.test(t = text.charAt(text.length - (1 + i)))) {
|
|
if (!(/[.,]/.test(t) || (text.match(/[()\[\]{}<>]/g)).length % 2)) {
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (i) {
|
|
text = text.slice(0, -i);
|
|
while (range.endOffset - i < 0) {
|
|
i--;
|
|
}
|
|
if (i) {
|
|
range.setEnd(range.endContainer, range.endOffset - i);
|
|
}
|
|
}
|
|
if (!/(mailto:|.+:\/\/)/.test(text)) {
|
|
text = (/@/.test(text) ? 'mailto:' : 'http://') + text;
|
|
}
|
|
a = $.el('a', {
|
|
className: 'linkify',
|
|
rel: 'nofollow noreferrer',
|
|
target: '_blank',
|
|
href: text
|
|
});
|
|
$.add(a, range.extractContents());
|
|
range.insertNode(a);
|
|
range.detach();
|
|
return a;
|
|
},
|
|
services: function(link) {
|
|
var href, match, type, _i, _len, _ref;
|
|
href = link.href;
|
|
_ref = Linkify.ordered_types;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
type = _ref[_i];
|
|
if (!(match = type.regExp.exec(href))) {
|
|
continue;
|
|
}
|
|
if (type.dummy) {
|
|
return;
|
|
}
|
|
return [type.key, match[1], match[2], link];
|
|
}
|
|
},
|
|
embed: function(data) {
|
|
var embed, href, key, link, name, options, uid, value, _ref;
|
|
key = data[0], uid = data[1], options = data[2], link = data[3];
|
|
href = link.href;
|
|
embed = $.el('a', {
|
|
className: 'embedder',
|
|
href: 'javascript:;',
|
|
textContent: '(embed)'
|
|
});
|
|
_ref = {
|
|
key: key,
|
|
href: href,
|
|
uid: uid,
|
|
options: options
|
|
};
|
|
for (name in _ref) {
|
|
value = _ref[name];
|
|
embed.dataset[name] = value;
|
|
}
|
|
embed.dataset.nodedata = link.innerHTML;
|
|
$.addClass(link, "" + embed.dataset.key);
|
|
$.on(embed, 'click', Linkify.cb.toggle);
|
|
$.after(link, [$.tn(' '), embed]);
|
|
if (Conf['Auto-embed']) {
|
|
Linkify.cb.toggle.call(embed);
|
|
}
|
|
return data.push(embed);
|
|
},
|
|
title: function(data) {
|
|
var embed, err, key, link, options, service, title, titles, uid;
|
|
key = data[0], uid = data[1], options = data[2], link = data[3], embed = data[4];
|
|
if (!(service = Linkify.types[key].title)) {
|
|
return;
|
|
}
|
|
titles = Conf['CachedTitles'];
|
|
if (title = titles[uid]) {
|
|
if (link) {
|
|
link.textContent = title[0];
|
|
}
|
|
if (Conf['Embedding']) {
|
|
return embed.dataset.title = title[0];
|
|
}
|
|
} else {
|
|
try {
|
|
return $.cache(service.api(uid), (function() {
|
|
return Linkify.cb.title(this, data);
|
|
}), {
|
|
responseType: 'json'
|
|
});
|
|
} catch (_error) {
|
|
err = _error;
|
|
if (link) {
|
|
link.innerHTML = "[" + key + "] <span class=warning>Title Link Blocked</span> (are you using NoScript?)</a>";
|
|
}
|
|
}
|
|
}
|
|
},
|
|
cb: {
|
|
toggle: function() {
|
|
var string, _ref;
|
|
_ref = $.hasClass(this, "embedded") ? ['unembed', '(embed)'] : ['embed', '(unembed)'], string = _ref[0], this.textContent = _ref[1];
|
|
$.replace(this.previousElementSibling, Linkify.cb[string](this));
|
|
return $.toggleClass(this, 'embedded');
|
|
},
|
|
embed: function(a) {
|
|
var el, style, type;
|
|
el = (type = Linkify.types[a.dataset.key]).el(a);
|
|
el.style.cssText = (style = type.style) ? style : "border: 0; width: 640px; height: 390px";
|
|
return el;
|
|
},
|
|
unembed: function(a) {
|
|
var el;
|
|
el = $.el('a', {
|
|
rel: 'nofollow noreferrer',
|
|
target: 'blank',
|
|
className: 'linkify',
|
|
href: a.dataset.href,
|
|
innerHTML: a.dataset.title || a.dataset.nodedata
|
|
});
|
|
$.addClass(el, a.dataset.key);
|
|
return el;
|
|
},
|
|
title: function(req, data) {
|
|
var embed, key, link, options, service, status, text, uid;
|
|
key = data[0], uid = data[1], options = data[2], link = data[3], embed = data[4];
|
|
status = req.status;
|
|
service = Linkify.types[key].title;
|
|
text = "[" + key + "] " + ((function() {
|
|
switch (status) {
|
|
case 200:
|
|
case 304:
|
|
return service.text(req.response);
|
|
case 404:
|
|
return "Not Found";
|
|
case 403:
|
|
return "Forbidden or Private";
|
|
default:
|
|
return "" + status + "'d";
|
|
}
|
|
})());
|
|
if (Conf['Embedding'] && (status === 200 || status === 304)) {
|
|
embed.dataset.title = text;
|
|
}
|
|
if (link) {
|
|
return link.textContent = text;
|
|
}
|
|
}
|
|
},
|
|
ordered_types: [
|
|
{
|
|
key: 'audio',
|
|
regExp: /(.*\.(mp3|ogg|wav))$/,
|
|
el: function(a) {
|
|
return $.el('audio', {
|
|
controls: 'controls',
|
|
preload: 'auto',
|
|
src: a.dataset.uid
|
|
});
|
|
}
|
|
}, {
|
|
key: 'gist',
|
|
regExp: /.*(?:gist.github.com.*\/)([^\/][^\/]*)$/,
|
|
el: function(a) {
|
|
var div;
|
|
return div = $.el('iframe', {
|
|
src: "http://www.purplegene.com/script?url=https://gist.github.com/" + a.dataset.uid + ".js"
|
|
});
|
|
},
|
|
title: {
|
|
api: function(uid) {
|
|
return "https://api.github.com/gists/" + uid;
|
|
},
|
|
text: function(_arg) {
|
|
var file, files;
|
|
files = _arg.files;
|
|
for (file in files) {
|
|
if (files.hasOwnProperty(file)) {
|
|
return file;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}, {
|
|
key: 'image',
|
|
regExp: /(http|www).*\.(gif|png|jpg|jpeg|bmp)$/,
|
|
style: 'border: 0; width: auto; height: auto;',
|
|
el: function(a) {
|
|
return $.el('div', {
|
|
innerHTML: "<a target=_blank href='" + a.dataset.href + "'><img src='" + a.dataset.href + "'></a>"
|
|
});
|
|
}
|
|
}, {
|
|
key: 'InstallGentoo',
|
|
regExp: /.*(?:paste.installgentoo.com\/view\/)([0-9a-z_]+)/,
|
|
el: function(a) {
|
|
return $.el('iframe', {
|
|
src: "http://paste.installgentoo.com/view/embed/" + a.dataset.uid
|
|
});
|
|
}
|
|
}, {
|
|
key: 'Twitter',
|
|
regExp: /.*twitter.com\/(.+\/status\/\d+)/,
|
|
el: function(a) {
|
|
return $.el('iframe', {
|
|
src: "https://twitframe.com/show?url=https://twitter.com/" + a.dataset.uid
|
|
});
|
|
}
|
|
}, {
|
|
key: 'LiveLeak',
|
|
regExp: /.*(?:liveleak.com\/view.+i=)([0-9a-z_]+)/,
|
|
el: function(a) {
|
|
var el;
|
|
el = $.el('iframe', {
|
|
width: "640",
|
|
height: "360",
|
|
src: "http://www.liveleak.com/ll_embed?i=" + a.dataset.uid,
|
|
frameborder: "0"
|
|
});
|
|
el.setAttribute("allowfullscreen", "true");
|
|
return el;
|
|
}
|
|
}, {
|
|
key: 'MediaCrush',
|
|
regExp: /.*(?:mediacru.sh\/)([0-9a-z_]+)/i,
|
|
style: 'border: 0;',
|
|
el: function(a) {
|
|
var el;
|
|
el = $.el('div');
|
|
$.cache("https://mediacru.sh/" + a.dataset.uid + ".json", function() {
|
|
var embed, file, files, status, type, _i, _j, _len, _len1, _ref;
|
|
status = this.status;
|
|
if (status !== 200 && status !== 304) {
|
|
return div.innerHTML = "ERROR " + status;
|
|
}
|
|
files = this.response.files;
|
|
_ref = ['video/mp4', 'video/ogv', 'image/svg+xml', 'image/png', 'image/gif', 'image/jpeg', 'image/svg', 'audio/mpeg'];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
type = _ref[_i];
|
|
for (_j = 0, _len1 = files.length; _j < _len1; _j++) {
|
|
file = files[_j];
|
|
if (file.type === type) {
|
|
embed = file;
|
|
break;
|
|
}
|
|
}
|
|
if (embed) {
|
|
break;
|
|
}
|
|
}
|
|
if (!embed) {
|
|
return div.innerHTML = "ERROR: Not a valid filetype";
|
|
}
|
|
return el.innerHTML = (function() {
|
|
switch (embed.type) {
|
|
case 'video/mp4':
|
|
case 'video/ogv':
|
|
return "<video autoplay loop>\n <source src=\"https://mediacru.sh/" + a.dataset.uid + ".mp4\" type=\"video/mp4;\">\n <source src=\"https://mediacru.sh/" + a.dataset.uid + ".ogv\" type=\"video/ogg; codecs='theora, vorbis'\">\n</video>";
|
|
case 'image/png':
|
|
case 'image/gif':
|
|
case 'image/jpeg':
|
|
return "<a target=_blank href='" + a.dataset.href + "'><img src='https://mediacru.sh/" + file.file + "'></a>";
|
|
case 'image/svg':
|
|
case 'image/svg+xml':
|
|
return "<embed src='https://mediacru.sh/" + file.file + "' type='image/svg+xml' />";
|
|
case 'audio/mpeg':
|
|
return "<audio controls><source src='https://mediacru.sh/" + file.file + "'></audio>";
|
|
default:
|
|
return "ERROR: No valid filetype.";
|
|
}
|
|
})();
|
|
});
|
|
return el;
|
|
}
|
|
}, {
|
|
key: 'pastebin',
|
|
regExp: /.*(?:pastebin.com\/(?!u\/))([^#\&\?]*).*/,
|
|
el: function(a) {
|
|
var div;
|
|
return div = $.el('iframe', {
|
|
src: "http://pastebin.com/embed_iframe.php?i=" + a.dataset.uid
|
|
});
|
|
}
|
|
}, {
|
|
key: 'gfycat',
|
|
regExp: /.*gfycat.com\/(?:iframe\/)?(\S*)/,
|
|
el: function(a) {
|
|
var div;
|
|
return div = $.el('iframe', {
|
|
src: "http://gfycat.com/iframe/" + a.dataset.uid
|
|
});
|
|
}
|
|
}, {
|
|
key: 'SoundCloud',
|
|
regExp: /.*(?:soundcloud.com\/|snd.sc\/)([^#\&\?]*).*/,
|
|
style: 'height: auto; width: 500px; display: inline-block;',
|
|
el: function(a) {
|
|
var div;
|
|
div = $.el('div', {
|
|
className: "soundcloud",
|
|
name: "soundcloud"
|
|
});
|
|
$.ajax("//soundcloud.com/oembed?show_artwork=false&&maxwidth=500px&show_comments=false&format=json&url=https://www.soundcloud.com/" + a.dataset.uid, {
|
|
onloadend: function() {
|
|
return div.innerHTML = JSON.parse(this.responseText).html;
|
|
}
|
|
}, false);
|
|
return div;
|
|
},
|
|
title: {
|
|
api: function(uid) {
|
|
return "//soundcloud.com/oembed?show_artwork=false&&maxwidth=500px&show_comments=false&format=json&url=https://www.soundcloud.com/" + uid;
|
|
},
|
|
text: function(_) {
|
|
return _.title;
|
|
}
|
|
}
|
|
}, {
|
|
key: 'StrawPoll',
|
|
regExp: /strawpoll\.me\/(?:embed_\d+\/)?(\d+)/,
|
|
style: 'border: 0; width: 600px; height: 406px;',
|
|
el: function(a) {
|
|
return $.el('iframe', {
|
|
src: "http://strawpoll.me/embed_1/" + a.dataset.uid
|
|
});
|
|
}
|
|
}, {
|
|
key: 'TwitchTV',
|
|
regExp: /.*(?:twitch.tv\/)([^#\&\?]*).*/,
|
|
style: "border: none; width: 640px; height: 360px;",
|
|
el: function(a) {
|
|
var channel, chapter, result, _;
|
|
if (result = /(\w+)\/(?:[a-z]\/)?(\d+)/i.exec(a.dataset.uid)) {
|
|
_ = result[0], channel = result[1], chapter = result[2];
|
|
return $.el('object', {
|
|
data: 'http://www.twitch.tv/widgets/archive_embed_player.swf',
|
|
innerHTML: "<param name='allowFullScreen' value='true' />\n<param name='flashvars' value='channel=" + channel + "&start_volume=25&auto_play=false" + (chapter ? "&chapter_id=" + chapter : "") + "' />"
|
|
});
|
|
} else {
|
|
channel = (/(\w+)/.exec(a.dataset.uid))[0];
|
|
return $.el('object', {
|
|
data: "http://www.twitch.tv/widgets/live_embed_player.swf?channel=" + channel,
|
|
innerHTML: "<param name=\"allowFullScreen\" value=\"true\" />\n<param name=\"movie\" value=\"http://www.twitch.tv/widgets/live_embed_player.swf\" />\n<param name=\"flashvars\" value=\"hostname=www.twitch.tv&channel=" + channel + "&auto_play=true&start_volume=25\" />"
|
|
});
|
|
}
|
|
}
|
|
}, {
|
|
key: 'Vocaroo',
|
|
regExp: /.*(?:vocaroo.com\/)([^#\&\?]*).*/,
|
|
style: 'border: 0; width: 150px; height: 45px;',
|
|
el: function(a) {
|
|
return $.el('object', {
|
|
innerHTML: "<embed src='http://vocaroo.com/player.swf?playMediaID=" + (a.dataset.uid.replace(/^i\//, '')) + "&autoplay=0' wmode='opaque' width='150' height='45' pluginspage='http://get.adobe.com/flashplayer/' type='application/x-shockwave-flash'></embed>"
|
|
});
|
|
}
|
|
}, {
|
|
key: 'Vimeo',
|
|
regExp: /.*(?:vimeo.com\/)([^#\&\?]*).*/,
|
|
el: function(a) {
|
|
return $.el('iframe', {
|
|
src: "//player.vimeo.com/video/" + a.dataset.uid + "?wmode=opaque"
|
|
});
|
|
},
|
|
title: {
|
|
api: function(uid) {
|
|
return "https://vimeo.com/api/oembed.json?url=http://vimeo.com/" + uid;
|
|
},
|
|
text: function(_) {
|
|
return _.title;
|
|
}
|
|
}
|
|
}, {
|
|
key: 'Vine',
|
|
regExp: /.*(?:vine.co\/)([^#\&\?]*).*/,
|
|
style: 'border: none; width: 500px; height: 500px;',
|
|
el: function(a) {
|
|
return $.el('iframe', {
|
|
src: "https://vine.co/" + a.dataset.uid + "/card"
|
|
});
|
|
}
|
|
}, {
|
|
key: 'YouTube',
|
|
regExp: /.*(?:youtu.be\/|youtube.*v=|youtube.*\/embed\/|youtube.*\/v\/|youtube.*videos\/)([^#\&\?]*)\??(t\=.*)?/,
|
|
el: function(a) {
|
|
var el;
|
|
el = $.el('iframe', {
|
|
src: "//www.youtube.com/embed/" + a.dataset.uid + (a.dataset.option ? '#' + a.dataset.option : '') + "?wmode=opaque"
|
|
});
|
|
el.setAttribute("allowfullscreen", "true");
|
|
return el;
|
|
},
|
|
title: {
|
|
api: function(uid) {
|
|
return "https://gdata.youtube.com/feeds/api/videos/" + uid + "?alt=json&fields=title/text(),yt:noembed,app:control/yt:state/@reasonCode";
|
|
},
|
|
text: function(data) {
|
|
return data.entry.title.$t;
|
|
}
|
|
}
|
|
}, {
|
|
key: 'Loopvid',
|
|
regExp: /.*loopvid.appspot.com\/.*/,
|
|
dummy: true
|
|
}, {
|
|
key: 'MediaFire',
|
|
regExp: /.*mediafire.com\/.*/,
|
|
dummy: true
|
|
}, {
|
|
key: 'video',
|
|
regExp: /(.*\.(ogv|webm|mp4))$/,
|
|
el: function(a) {
|
|
return $.el('video', {
|
|
controls: 'controls',
|
|
preload: 'auto',
|
|
src: a.dataset.uid
|
|
});
|
|
}
|
|
}
|
|
]
|
|
};
|
|
|
|
QR = {
|
|
mimeTypes: ['image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'application/x-shockwave-flash', ''],
|
|
init: function() {
|
|
var con, sc;
|
|
this.db = new DataBoard('yourPosts');
|
|
this.posts = [];
|
|
$.on(d, '4chanXInitFinished', this.initReady);
|
|
Post.callbacks.push({
|
|
name: 'Quick Reply',
|
|
cb: this.node
|
|
});
|
|
if (!(Conf['Header Shortcut'] || Conf['Page Shortcut'])) {
|
|
return;
|
|
}
|
|
sc = $.el('a', {
|
|
className: "qr-shortcut fa " + (!Conf['Persistent QR'] ? 'disabled' : ''),
|
|
textContent: '\uf075',
|
|
title: 'Quick Reply',
|
|
href: 'javascript:;'
|
|
});
|
|
$.on(sc, 'click', function() {
|
|
if (!QR.nodes || QR.nodes.el.hidden) {
|
|
$.event('CloseMenu');
|
|
QR.open();
|
|
QR.nodes.com.focus();
|
|
} else {
|
|
QR.close();
|
|
}
|
|
return $.toggleClass(this, 'disabled');
|
|
});
|
|
if (Conf['Header Shortcut']) {
|
|
return Header.addShortcut(sc, true);
|
|
}
|
|
$.addClass(sc, 'on-page');
|
|
$.rmClass(sc, 'fa');
|
|
sc.textContent = g.VIEW === 'thread' ? 'Reply to Thread' : 'Start a Thread';
|
|
con = $.el('div', {
|
|
className: 'center'
|
|
});
|
|
$.add(con, sc);
|
|
return $.asap((function() {
|
|
return d.body;
|
|
}), function() {
|
|
return $.asap((function() {
|
|
return $.id('postForm');
|
|
}), function() {
|
|
return $.before($.id('postForm'), con);
|
|
});
|
|
});
|
|
},
|
|
initReady: function() {
|
|
$.off(d, '4chanXInitFinished', this.initReady);
|
|
QR.postingIsEnabled = !!$.id('postForm');
|
|
if (!QR.postingIsEnabled) {
|
|
return;
|
|
}
|
|
$.on(d, 'QRGetSelectedPost', function(_arg) {
|
|
var cb;
|
|
cb = _arg.detail;
|
|
return cb(QR.selected);
|
|
});
|
|
$.on(d, 'QRAddPreSubmitHook', function(_arg) {
|
|
var cb;
|
|
cb = _arg.detail;
|
|
return QR.preSubmitHooks.push(cb);
|
|
});
|
|
$.on(d, 'dragover', QR.dragOver);
|
|
$.on(d, 'drop', QR.dropFile);
|
|
$.on(d, 'dragstart dragend', QR.drag);
|
|
$.on(d, 'IndexRefresh', QR.generatePostableThreadsList);
|
|
$.on(d, 'ThreadUpdate', QR.statusCheck);
|
|
if (!Conf['Persistent QR']) {
|
|
return;
|
|
}
|
|
QR.open();
|
|
if (Conf['Auto-Hide QR']) {
|
|
return QR.hide();
|
|
}
|
|
},
|
|
statusCheck: function() {
|
|
if (g.DEAD) {
|
|
return QR.abort();
|
|
} else {
|
|
return QR.status();
|
|
}
|
|
},
|
|
node: function() {
|
|
if (QR.db.get({
|
|
boardID: this.board.ID,
|
|
threadID: this.thread.ID,
|
|
postID: this.ID
|
|
})) {
|
|
$.addClass(this.nodes.root, 'your-post');
|
|
}
|
|
return $.on($('a[title="Quote this post"]', this.nodes.info), 'click', QR.quote);
|
|
},
|
|
persist: function() {
|
|
if (!QR.postingIsEnabled) {
|
|
return;
|
|
}
|
|
QR.open();
|
|
if (Conf['Auto Hide QR']) {
|
|
return QR.hide();
|
|
}
|
|
},
|
|
open: function() {
|
|
var err;
|
|
if (QR.nodes) {
|
|
QR.nodes.el.hidden = false;
|
|
QR.unhide();
|
|
return;
|
|
}
|
|
try {
|
|
return QR.dialog();
|
|
} catch (_error) {
|
|
err = _error;
|
|
delete QR.nodes;
|
|
return Main.handleErrors({
|
|
message: 'Quick Reply dialog creation crashed.',
|
|
error: err
|
|
});
|
|
}
|
|
},
|
|
close: function() {
|
|
var post, _i, _len, _ref;
|
|
if (QR.req) {
|
|
QR.abort();
|
|
return;
|
|
}
|
|
QR.nodes.el.hidden = true;
|
|
QR.cleanNotifications();
|
|
d.activeElement.blur();
|
|
$.rmClass(QR.nodes.el, 'dump');
|
|
if (!Conf['Captcha Warning Notifications']) {
|
|
if (QR.captcha.isEnabled) {
|
|
$.rmClass(QR.captcha.nodes.input, 'error');
|
|
}
|
|
}
|
|
if (Conf['QR Shortcut']) {
|
|
$.toggleClass($('.qr-shortcut'), 'disabled');
|
|
}
|
|
new QR.post(true);
|
|
_ref = QR.posts.splice(0, QR.posts.length - 1);
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
post = _ref[_i];
|
|
post["delete"]();
|
|
}
|
|
QR.cooldown.auto = false;
|
|
return QR.status();
|
|
},
|
|
focusin: function() {
|
|
return $.addClass(QR.nodes.el, 'focus');
|
|
},
|
|
focusout: function() {
|
|
return $.rmClass(QR.nodes.el, 'focus');
|
|
},
|
|
hide: function() {
|
|
d.activeElement.blur();
|
|
$.addClass(QR.nodes.el, 'autohide');
|
|
return QR.nodes.autohide.checked = true;
|
|
},
|
|
unhide: function() {
|
|
$.rmClass(QR.nodes.el, 'autohide');
|
|
return QR.nodes.autohide.checked = false;
|
|
},
|
|
toggleHide: function() {
|
|
if (this.checked) {
|
|
return QR.hide();
|
|
} else {
|
|
return QR.unhide();
|
|
}
|
|
},
|
|
error: function(err) {
|
|
var el;
|
|
QR.open();
|
|
if (typeof err === 'string') {
|
|
el = $.tn(err);
|
|
} else {
|
|
el = err;
|
|
el.removeAttribute('style');
|
|
}
|
|
if (QR.captcha.isEnabled && /captcha|verification/i.test(el.textContent)) {
|
|
QR.captcha.nodes.input.focus();
|
|
if (Conf['Captcha Warning Notifications'] && !d.hidden) {
|
|
QR.notify(el);
|
|
} else {
|
|
$.addClass(QR.captcha.nodes.input, 'error');
|
|
$.on(QR.captcha.nodes.input, 'keydown', function() {
|
|
return $.rmClass(QR.captcha.nodes.input, 'error');
|
|
});
|
|
}
|
|
} else {
|
|
QR.notify(el);
|
|
}
|
|
if (d.hidden) {
|
|
return alert(el.textContent);
|
|
}
|
|
},
|
|
notify: function(el) {
|
|
var notice, notif;
|
|
notice = new Notice('warning', el);
|
|
if (!(Header.areNotificationsEnabled && d.hidden)) {
|
|
return QR.notifications.push(notice);
|
|
} else {
|
|
notif = new Notification(el.textContent, {
|
|
body: el.textContent,
|
|
icon: Favicon.logo
|
|
});
|
|
return notif.onclick = function() {
|
|
return window.focus();
|
|
};
|
|
}
|
|
},
|
|
notifications: [],
|
|
cleanNotifications: function() {
|
|
var notification, _i, _len, _ref;
|
|
_ref = QR.notifications;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
notification = _ref[_i];
|
|
notification.close();
|
|
}
|
|
return QR.notifications = [];
|
|
},
|
|
status: function() {
|
|
var disabled, status, thread, value;
|
|
if (!QR.nodes) {
|
|
return;
|
|
}
|
|
thread = QR.posts[0].thread;
|
|
if (thread !== 'new' && g.threads["" + g.BOARD + "." + thread].isDead) {
|
|
value = 404;
|
|
disabled = true;
|
|
QR.cooldown.auto = false;
|
|
}
|
|
value = QR.req ? QR.req.progress : QR.cooldown.seconds || value;
|
|
status = QR.nodes.status;
|
|
status.value = !value ? 'Submit' : QR.cooldown.auto ? "Auto " + value : value;
|
|
return status.disabled = disabled || false;
|
|
},
|
|
quote: function(e) {
|
|
var ancestor, caretPos, com, frag, index, node, post, range, sel, text, thread, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _ref3;
|
|
if (e != null) {
|
|
e.preventDefault();
|
|
}
|
|
if (!QR.postingIsEnabled) {
|
|
return;
|
|
}
|
|
sel = d.getSelection();
|
|
post = Get.postFromNode(this);
|
|
text = ">>" + post + "\n";
|
|
if (sel.toString().trim() && post === Get.postFromNode(sel.anchorNode)) {
|
|
range = sel.getRangeAt(0);
|
|
frag = range.cloneContents();
|
|
ancestor = range.commonAncestorContainer;
|
|
if (ancestor.nodeName === '#text') {
|
|
if ($.x('ancestor::s', ancestor)) {
|
|
$.prepend(frag, $.tn('[spoiler]'));
|
|
$.add(frag, $.tn('[/spoiler]'));
|
|
}
|
|
if ($.x('ancestor::pre[contains(@class,"prettyprint")]', ancestor)) {
|
|
$.prepend(frag, $.tn('[code]'));
|
|
$.add(frag, $.tn('[/code]'));
|
|
}
|
|
}
|
|
_ref = $$('br', frag);
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
node = _ref[_i];
|
|
$.replace(node, $.tn('\n>'));
|
|
}
|
|
_ref1 = $$('s', frag);
|
|
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
|
node = _ref1[_j];
|
|
$.replace(node, [$.tn('[spoiler]')].concat(__slice.call(node.childNodes), [$.tn('[/spoiler]')]));
|
|
}
|
|
_ref2 = $$('.prettyprint', frag);
|
|
for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
|
|
node = _ref2[_k];
|
|
$.replace(node, [$.tn('[code]')].concat(__slice.call(node.childNodes), [$.tn('[/code]')]));
|
|
}
|
|
text += ">" + (frag.textContent.trim()) + "\n";
|
|
}
|
|
QR.open();
|
|
if (QR.selected.isLocked) {
|
|
index = QR.posts.indexOf(QR.selected);
|
|
(QR.posts[index + 1] || new QR.post()).select();
|
|
$.addClass(QR.nodes.el, 'dump');
|
|
QR.cooldown.auto = true;
|
|
}
|
|
_ref3 = QR.nodes, com = _ref3.com, thread = _ref3.thread;
|
|
if (!com.value) {
|
|
thread.value = Get.threadFromNode(this);
|
|
}
|
|
thread.nextElementSibling.firstElementChild.textContent = thread.options[thread.selectedIndex].textContent;
|
|
caretPos = com.selectionStart;
|
|
com.value = com.value.slice(0, caretPos) + text + com.value.slice(com.selectionEnd);
|
|
range = caretPos + text.length;
|
|
com.setSelectionRange(range, range);
|
|
com.focus();
|
|
QR.selected.save(com);
|
|
QR.selected.save(thread);
|
|
return $.rmClass($('.qr-shortcut'), 'disabled');
|
|
},
|
|
characterCount: function() {
|
|
var count, counter;
|
|
counter = QR.nodes.charCount;
|
|
count = QR.nodes.com.textLength;
|
|
counter.textContent = count;
|
|
counter.hidden = count < 1000;
|
|
return (count > 1500 ? $.addClass : $.rmClass)(counter, 'warning');
|
|
},
|
|
drag: function(e) {
|
|
var toggle;
|
|
toggle = e.type === 'dragstart' ? $.off : $.on;
|
|
toggle(d, 'dragover', QR.dragOver);
|
|
return toggle(d, 'drop', QR.dropFile);
|
|
},
|
|
dragOver: function(e) {
|
|
e.preventDefault();
|
|
return e.dataTransfer.dropEffect = 'copy';
|
|
},
|
|
dropFile: function(e) {
|
|
if (!e.dataTransfer.files.length) {
|
|
return;
|
|
}
|
|
e.preventDefault();
|
|
QR.open();
|
|
return QR.handleFiles(e.dataTransfer.files);
|
|
},
|
|
paste: function(e) {
|
|
var blob, files, item, _i, _len, _ref;
|
|
files = [];
|
|
_ref = e.clipboardData.items;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
item = _ref[_i];
|
|
if (!(item.kind === 'file')) {
|
|
continue;
|
|
}
|
|
blob = item.getAsFile();
|
|
blob.name = 'file';
|
|
if (blob.type) {
|
|
blob.name += '.' + blob.type.split('/')[1];
|
|
}
|
|
files.push(blob);
|
|
}
|
|
if (!files.length) {
|
|
return;
|
|
}
|
|
QR.open();
|
|
QR.handleFiles(files);
|
|
return $.addClass(QR.nodes.el, 'dump');
|
|
},
|
|
handleBlob: function(urlBlob, header, url) {
|
|
var blob, end, endnl, endsc, mime, name, name_end, name_start, start, _ref;
|
|
name = url.substr(url.lastIndexOf('/') + 1, url.length);
|
|
start = header.indexOf("Content-Type: ") + 14;
|
|
endsc = header.substr(start, header.length).indexOf(";");
|
|
endnl = header.substr(start, header.length).indexOf("\n") - 1;
|
|
end = endnl;
|
|
if (endsc !== -1 && endsc < endnl) {
|
|
end = endsc;
|
|
}
|
|
mime = header.substr(start, end);
|
|
blob = new Blob([urlBlob], {
|
|
type: mime
|
|
});
|
|
blob.name = url.substr(url.lastIndexOf('/') + 1, url.length);
|
|
name_start = header.indexOf('name="') + 6;
|
|
if (name_start - 6 !== -1) {
|
|
name_end = header.substr(name_start, header.length).indexOf('"');
|
|
blob.name = header.substr(name_start, name_end);
|
|
}
|
|
if (blob.type === null) {
|
|
return QR.error("Unsupported file type.");
|
|
}
|
|
if (_ref = blob.type, __indexOf.call(QR.mimeTypes, _ref) < 0) {
|
|
return QR.error("Unsupported file type.");
|
|
}
|
|
return QR.handleFiles([blob]);
|
|
},
|
|
handleUrl: function() {
|
|
var url;
|
|
url = prompt("Insert an url:");
|
|
if (url === null) {
|
|
return;
|
|
}
|
|
GM_xmlhttpRequest({
|
|
method: "GET",
|
|
url: url,
|
|
overrideMimeType: "text/plain; charset=x-user-defined",
|
|
onload: function(xhr) {
|
|
var data, i, r;
|
|
r = xhr.responseText;
|
|
data = new Uint8Array(r.length);
|
|
i = 0;
|
|
while (i < r.length) {
|
|
data[i] = r.charCodeAt(i);
|
|
i++;
|
|
}
|
|
QR.handleBlob(data, xhr.responseHeaders, url);
|
|
return;
|
|
return {
|
|
onerror: function(xhr) {
|
|
return QR.error("Can't load image.");
|
|
}
|
|
};
|
|
}
|
|
});
|
|
},
|
|
handleFiles: function(files) {
|
|
var file, isSingle, max, _i, _len;
|
|
if (this !== QR) {
|
|
files = __slice.call(this.files);
|
|
this.value = null;
|
|
}
|
|
if (!files.length) {
|
|
return;
|
|
}
|
|
max = QR.nodes.fileInput.max;
|
|
isSingle = files.length === 1;
|
|
QR.cleanNotifications();
|
|
for (_i = 0, _len = files.length; _i < _len; _i++) {
|
|
file = files[_i];
|
|
if (file.type === 'application/x-shockwave-flash') {
|
|
QR.handleFile(file, isSingle, max);
|
|
} else {
|
|
QR.checkDimensions(file, isSingle, max);
|
|
}
|
|
}
|
|
if (!isSingle) {
|
|
return $.addClass(QR.nodes.el, 'dump');
|
|
}
|
|
},
|
|
checkDimensions: function(file, isSingle, max) {
|
|
var img;
|
|
img = new Image();
|
|
img.onload = (function(_this) {
|
|
return function() {
|
|
var height, width;
|
|
height = img.height, width = img.width;
|
|
if (height > QR.max_heigth || width > QR.max_heigth) {
|
|
return QR.error("" + file.name + ": Image too large (image: " + img.height + "x" + img.width + "px, max: " + QR.max_heigth + "x" + QR.max_width + "px)");
|
|
}
|
|
if (height < QR.min_heigth || width < QR.min_heigth) {
|
|
return QR.error("" + file.name + ": Image too small (image: " + img.height + "x" + img.width + "px, min: " + QR.min_heigth + "x" + QR.min_width + "px)");
|
|
}
|
|
return QR.handleFile(file, isSingle, max);
|
|
};
|
|
})(this);
|
|
return img.src = URL.createObjectURL(file);
|
|
},
|
|
handleFile: function(file, isSingle, max) {
|
|
var post, _ref;
|
|
if (file.size > max) {
|
|
QR.error("" + file.name + ": File too large (file: " + ($.bytesToString(file.size)) + ", max: " + ($.bytesToString(max)) + ").");
|
|
return;
|
|
} else if (_ref = file.type, __indexOf.call(QR.mimeTypes, _ref) < 0) {
|
|
if (!/^text/.test(file.type)) {
|
|
QR.error("" + file.name + ": Unsupported file type.");
|
|
return;
|
|
}
|
|
if (isSingle) {
|
|
post = QR.selected;
|
|
} else if ((post = QR.posts[QR.posts.length - 1]).com) {
|
|
post = new QR.post();
|
|
}
|
|
post.pasteText(file);
|
|
return;
|
|
}
|
|
if (isSingle) {
|
|
post = QR.selected;
|
|
} else if ((post = QR.posts[QR.posts.length - 1]).file) {
|
|
post = new QR.post();
|
|
}
|
|
return post.setFile(file);
|
|
},
|
|
openFileInput: function(e) {
|
|
var _ref;
|
|
e.stopPropagation();
|
|
if (e.shiftKey && e.type === 'click') {
|
|
return QR.selected.rmFile();
|
|
}
|
|
if (e.ctrlKey && e.type === 'click') {
|
|
$.addClass(QR.nodes.filename, 'edit');
|
|
QR.nodes.filename.focus();
|
|
return;
|
|
}
|
|
if (e.target.nodeName === 'INPUT' || (e.keyCode && ((_ref = e.keyCode) !== 32 && _ref !== 13)) || e.ctrlKey) {
|
|
return;
|
|
}
|
|
e.preventDefault();
|
|
return QR.nodes.fileInput.click();
|
|
},
|
|
generatePostableThreadsList: function() {
|
|
var list, options, thread, val, _i, _len, _ref;
|
|
if (!QR.nodes) {
|
|
return;
|
|
}
|
|
list = QR.nodes.thread;
|
|
options = [list.firstChild];
|
|
_ref = g.BOARD.threads.keys;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
thread = _ref[_i];
|
|
options.push($.el('option', {
|
|
value: thread,
|
|
textContent: "No." + thread
|
|
}));
|
|
}
|
|
val = list.value;
|
|
$.rmAll(list);
|
|
$.add(list, options);
|
|
list.value = val;
|
|
if (!list.value) {
|
|
return;
|
|
}
|
|
list.value = g.VIEW === 'thread' ? g.THREADID : 'new';
|
|
if ($.hasClass(list, 'riced')) {
|
|
return list.nextElementSibling.firstChild.textContent = list.options[list.selectedIndex].textContent;
|
|
}
|
|
},
|
|
dialog: function() {
|
|
var dialog, elm, event, i, items, name, node, nodes, rules, save, setNode, _, _ref, _ref1;
|
|
QR.nodes = nodes = {
|
|
el: dialog = UI.dialog('qr', 'top:0;right:0;', "<div id=qrtab class=move><input type=checkbox id=autohide title=Auto-hide><div id=qr-thread-select><select data-name=thread title='Create a new thread / Reply'><option value=new>New thread</option></select></div><a href=javascript:; class='close fa' title=Close>\uf00d</a></div><form><div class=persona><input name=name data-name=name list=\"list-name\" placeholder=Name class=field size=1 tabindex=10><input name=email data-name=email list=\"list-email\" placeholder=E-mail class=field size=1 tabindex=20><input name=sub data-name=sub list=\"list-sub\" placeholder=Subject class=field size=1 tabindex=30> </div><div class=textarea><textarea data-name=com placeholder=Comment class=field tabindex=40></textarea><span id=char-count></span></div><div id=dump-list-container><div id=dump-list></div><a id=add-post href=javascript:; title=\"Add a post\" tabindex=50>+</a></div><div id=file-n-submit><span id=qr-filename-container class=field tabindex=60><span id=qr-no-file>No selected file</span><input id=\"qr-filename\" data-name=\"filename\" spellcheck=\"false\"><span id=qr-extras-container><label id=qr-spoiler-label><input type=checkbox id=qr-file-spoiler title='Spoiler image' tabindex=70></label><span class=description>Spoiler</span><a id=url-button><i class=\"fa\">\uf0c1</i></a><span class=description>Post from URL</span><a id=dump-button title='Dump list'>+</a><span class=description>Dump</span><a id=qr-filerm href=javascript:; title='Remove file' class=fa>\uf00d</a><span class=description>Remove File</span></span></span><input type=submit tabindex=80></div><input type=file multiple></form><datalist id=\"list-name\"></datalist><datalist id=\"list-email\"></datalist><datalist id=\"list-sub\"></datalist>")
|
|
};
|
|
setNode = function(name, query) {
|
|
return nodes[name] = $(query, dialog);
|
|
};
|
|
setNode('move', '.move');
|
|
setNode('autohide', '#autohide');
|
|
setNode('thread', 'select');
|
|
setNode('threadPar', '#qr-thread-select');
|
|
setNode('close', '.close');
|
|
setNode('form', 'form');
|
|
setNode('dumpButton', '#dump-button');
|
|
setNode('urlButton', '#url-button');
|
|
setNode('name', '[data-name=name]');
|
|
setNode('email', '[data-name=email]');
|
|
setNode('sub', '[data-name=sub]');
|
|
setNode('com', '[data-name=com]');
|
|
setNode('dumpList', '#dump-list');
|
|
setNode('addPost', '#add-post');
|
|
setNode('charCount', '#char-count');
|
|
setNode('fileSubmit', '#file-n-submit');
|
|
setNode('filesize', '#qr-filesize');
|
|
setNode('filename', '#qr-filename');
|
|
setNode('fileContainer', '#qr-filename-container');
|
|
setNode('fileRM', '#qr-filerm');
|
|
setNode('fileExtras', '#qr-extras-container');
|
|
setNode('spoiler', '#qr-file-spoiler');
|
|
setNode('spoilerPar', '#qr-spoiler-label');
|
|
setNode('status', '[type=submit]');
|
|
setNode('fileInput', '[type=file]');
|
|
rules = $('ul.rules').textContent.trim();
|
|
QR.min_width = QR.min_heigth = 1;
|
|
QR.max_width = QR.max_heigth = 5000;
|
|
try {
|
|
_ref = rules.match(/.+smaller than (\d+)x(\d+).+/), _ = _ref[0], QR.min_width = _ref[1], QR.min_heigth = _ref[2];
|
|
_ref1 = rules.match(/.+greater than (\d+)x(\d+).+/), _ = _ref1[0], QR.max_width = _ref1[1], QR.max_heigth = _ref1[2];
|
|
} catch (_error) {
|
|
null;
|
|
}
|
|
nodes.fileInput.max = $('input[name=MAX_FILE_SIZE]').value;
|
|
QR.spoiler = !!$('input[name=spoiler]');
|
|
if (QR.spoiler) {
|
|
$.addClass(QR.nodes.el, 'has-spoiler');
|
|
} else {
|
|
nodes.spoiler.parentElement.hidden = true;
|
|
}
|
|
if (Conf['Dump List Before Comment']) {
|
|
$.after(nodes.name.parentElement, nodes.dumpList.parentElement);
|
|
nodes.addPost.tabIndex = 35;
|
|
}
|
|
if (g.BOARD.ID === 'f') {
|
|
nodes.flashTag = $.el('select', {
|
|
name: 'filetag',
|
|
innerHTML: "<option value=0>Hentai</option>\n<option value=6>Porn</option>\n<option value=1>Japanese</option>\n<option value=2>Anime</option>\n<option value=3>Game</option>\n<option value=5>Loop</option>\n<option value=4 selected>Other</option>"
|
|
});
|
|
nodes.flashTag.dataset["default"] = '4';
|
|
$.add(nodes.form, nodes.flashTag);
|
|
}
|
|
QR.flagsInput();
|
|
$.on(nodes.filename.parentNode, 'click keydown', QR.openFileInput);
|
|
items = $$('*', QR.nodes.el);
|
|
i = 0;
|
|
while (elm = items[i++]) {
|
|
$.on(elm, 'blur', QR.focusout);
|
|
$.on(elm, 'focus', QR.focusin);
|
|
}
|
|
$.on(nodes.autohide, 'change', QR.toggleHide);
|
|
$.on(nodes.close, 'click', QR.close);
|
|
$.on(nodes.dumpButton, 'click', function() {
|
|
return nodes.el.classList.toggle('dump');
|
|
});
|
|
$.on(nodes.urlButton, 'click', QR.handleUrl);
|
|
$.on(nodes.addPost, 'click', function() {
|
|
return new QR.post(true);
|
|
});
|
|
$.on(nodes.form, 'submit', QR.submit);
|
|
$.on(nodes.filename, 'blur', function() {
|
|
return $.rmClass(this, 'edit');
|
|
});
|
|
$.on(nodes.fileRM, 'click', function() {
|
|
return QR.selected.rmFile();
|
|
});
|
|
$.on(nodes.fileExtras, 'click', function(e) {
|
|
return e.stopPropagation();
|
|
});
|
|
$.on(nodes.spoiler, 'change', function() {
|
|
return QR.selected.nodes.spoiler.click();
|
|
});
|
|
$.on(nodes.fileInput, 'change', QR.handleFiles);
|
|
items = ['spoilerPar', 'dumpButton', 'fileRM', 'urlButton'];
|
|
i = 0;
|
|
while (name = items[i++]) {
|
|
$.on(nodes[name], 'mouseover', QR.mouseover);
|
|
}
|
|
items = ['name', 'email', 'sub', 'com', 'filename', 'flag'];
|
|
i = 0;
|
|
save = function() {
|
|
return QR.selected.save(this);
|
|
};
|
|
while (name = items[i++]) {
|
|
if (!(node = nodes[name])) {
|
|
continue;
|
|
}
|
|
event = node.nodeName === 'SELECT' ? 'change' : 'input';
|
|
$.on(nodes[name], event, save);
|
|
}
|
|
$.on(nodes['name'], 'blur', QR.tripcodeHider);
|
|
$.on(nodes.thread, 'change', function() {
|
|
return QR.selected.save(this);
|
|
});
|
|
if (Conf['Remember QR Size']) {
|
|
$.get('QR Size', '', function(item) {
|
|
return nodes.com.style.cssText = item['QR Size'];
|
|
});
|
|
$.on(nodes.com, 'mouseup', function(e) {
|
|
if (e.button !== 0) {
|
|
return;
|
|
}
|
|
return $.set('QR Size', this.style.cssText);
|
|
});
|
|
}
|
|
QR.generatePostableThreadsList();
|
|
QR.persona.init();
|
|
new QR.post(true);
|
|
QR.status();
|
|
QR.cooldown.init();
|
|
QR.captcha.init();
|
|
Rice.nodes(dialog);
|
|
$.add(d.body, dialog);
|
|
if (Conf['Auto Hide QR']) {
|
|
nodes.autohide.click();
|
|
}
|
|
return $.event('QRDialogCreation', null, dialog);
|
|
},
|
|
tripcodeHider: function() {
|
|
var check;
|
|
check = /^.*##?.+/.test(this.value);
|
|
if (check && !this.className.match("\\btripped\\b")) {
|
|
return $.addClass(this, 'tripped');
|
|
} else if (!check && this.className.match("\\btripped\\b")) {
|
|
return $.rmClass(this, 'tripped');
|
|
}
|
|
},
|
|
flags: function() {
|
|
var flag, fn, select, _i, _len, _ref;
|
|
select = $.el('select', {
|
|
name: 'flag',
|
|
className: 'flagSelector'
|
|
});
|
|
fn = function(val) {
|
|
return $.add(select, $.el('option', {
|
|
value: val[0],
|
|
textContent: val[1]
|
|
}));
|
|
};
|
|
_ref = [['0', 'None'], ['US', 'American'], ['KP', 'Best Korean'], ['BL', 'Black Nationalist'], ['CM', 'Communist'], ['CF', 'Confederate'], ['RE', 'Conservative'], ['EU', 'European'], ['GY', 'Gay'], ['PC', 'Hippie'], ['IL', 'Israeli'], ['DM', 'Liberal'], ['RP', 'Libertarian'], ['MF', 'Muslim'], ['NZ', 'Nazi'], ['OB', 'Obama'], ['PR', 'Pirate'], ['RB', 'Rebel'], ['TP', 'Tea Partier'], ['TX', 'Texan'], ['TR', 'Tree Hugger'], ['WP', 'White Supremacist']];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
flag = _ref[_i];
|
|
fn(flag);
|
|
}
|
|
return select;
|
|
},
|
|
flagsInput: function() {
|
|
var flag, nodes;
|
|
nodes = QR.nodes;
|
|
if (!nodes) {
|
|
return;
|
|
}
|
|
if (nodes.flag) {
|
|
$.rm(nodes.flag);
|
|
delete nodes.flag;
|
|
}
|
|
if (g.BOARD.ID === 'pol') {
|
|
flag = QR.flags();
|
|
flag.dataset.name = 'flag';
|
|
flag.dataset["default"] = '0';
|
|
nodes.flag = flag;
|
|
return $.add(nodes.form, flag);
|
|
}
|
|
},
|
|
preSubmitHooks: [],
|
|
submit: function(e) {
|
|
var challenge, err, extra, filetag, formData, hook, options, post, response, textOnly, thread, threadID, _i, _len, _ref, _ref1;
|
|
if (e != null) {
|
|
e.preventDefault();
|
|
}
|
|
if (QR.req) {
|
|
QR.abort();
|
|
return;
|
|
}
|
|
if (QR.cooldown.seconds) {
|
|
QR.cooldown.auto = !QR.cooldown.auto;
|
|
QR.status();
|
|
return;
|
|
}
|
|
post = QR.posts[0];
|
|
post.forceSave();
|
|
if (g.BOARD.ID === 'f') {
|
|
filetag = QR.nodes.flashTag.value;
|
|
}
|
|
threadID = post.thread;
|
|
thread = g.BOARD.threads[threadID];
|
|
if (threadID === 'new') {
|
|
threadID = null;
|
|
if (g.BOARD.ID === 'vg' && !post.sub) {
|
|
err = 'New threads require a subject.';
|
|
} else if (!(post.file || (textOnly = !!$('input[name=textonly]', $.id('postForm'))))) {
|
|
err = 'No file selected.';
|
|
}
|
|
} else if (g.BOARD.threads[threadID].isClosed) {
|
|
err = 'You can\'t reply to this thread anymore.';
|
|
} else if (!(post.com || post.file)) {
|
|
err = 'No file selected.';
|
|
} else if (post.file && thread.fileLimit) {
|
|
err = 'Max limit of image replies has been reached.';
|
|
} else {
|
|
_ref = QR.preSubmitHooks;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
hook = _ref[_i];
|
|
if (err = hook(post, thread)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (QR.captcha.isEnabled && !err) {
|
|
_ref1 = QR.captcha.getOne(), challenge = _ref1.challenge, response = _ref1.response;
|
|
if (!response) {
|
|
err = 'No valid captcha.';
|
|
}
|
|
}
|
|
QR.cleanNotifications();
|
|
if (err) {
|
|
QR.cooldown.auto = false;
|
|
QR.status();
|
|
QR.error(err);
|
|
return;
|
|
}
|
|
QR.cooldown.auto = QR.posts.length > 1;
|
|
if (Conf['Auto Hide QR'] && !QR.cooldown.auto) {
|
|
QR.hide();
|
|
}
|
|
if (!QR.cooldown.auto && $.x('ancestor::div[@id="qr"]', d.activeElement)) {
|
|
d.activeElement.blur();
|
|
}
|
|
post.lock();
|
|
formData = {
|
|
resto: threadID,
|
|
name: post.name,
|
|
email: post.email,
|
|
sub: post.sub,
|
|
com: post.com,
|
|
upfile: post.file,
|
|
filetag: filetag,
|
|
spoiler: post.spoiler,
|
|
flag: post.flag,
|
|
textonly: textOnly,
|
|
mode: 'regist',
|
|
pwd: QR.persona.pwd,
|
|
recaptcha_challenge_field: challenge,
|
|
recaptcha_response_field: response
|
|
};
|
|
options = {
|
|
responseType: 'document',
|
|
withCredentials: true,
|
|
onload: QR.response,
|
|
onerror: function() {
|
|
delete QR.req;
|
|
if (QR.captcha.isEnabled) {
|
|
QR.captcha.destroy();
|
|
QR.captcha.setup();
|
|
}
|
|
post.unlock();
|
|
QR.cooldown.auto = false;
|
|
QR.status();
|
|
return QR.error($.el('span', {
|
|
innerHTML: "Connection error. You may have been <a href=//www.4chan.org/banned target=_blank>banned</a>.\n[<a href=\"https://github.com/seaweedchan/4chan-x/wiki/Frequently-Asked-Questions#what-does-4chan-x-encountered-an-error-while-posting-please-try-again-mean\" target=_blank>?</a>]"
|
|
}));
|
|
}
|
|
};
|
|
extra = {
|
|
form: $.formData(formData),
|
|
upCallbacks: {
|
|
onload: function() {
|
|
QR.req.isUploadFinished = true;
|
|
QR.req.uploadEndTime = Date.now();
|
|
QR.req.progress = '...';
|
|
return QR.status();
|
|
},
|
|
onprogress: function(e) {
|
|
QR.req.progress = "" + (Math.round(e.loaded / e.total * 100)) + "%";
|
|
return QR.status();
|
|
}
|
|
}
|
|
};
|
|
QR.req = $.ajax("https://sys.4chan.org/" + g.BOARD + "/post", options, extra);
|
|
QR.req.uploadStartTime = Date.now();
|
|
QR.req.progress = '...';
|
|
return QR.status();
|
|
},
|
|
response: function() {
|
|
var URL, ban, board, err, h1, isReply, m, post, postID, postsCount, req, resDoc, threadID, _, _ref, _ref1;
|
|
req = QR.req;
|
|
delete QR.req;
|
|
if (QR.captcha.isEnabled) {
|
|
QR.captcha.destroy();
|
|
}
|
|
post = QR.posts[0];
|
|
post.unlock();
|
|
resDoc = req.response;
|
|
if (ban = $('.banType', resDoc)) {
|
|
board = $('.board', resDoc).innerHTML;
|
|
err = $.el('span', {
|
|
innerHTML: ban.textContent.toLowerCase() === 'banned' ? "You are banned on " + board + "! ;_;<br>\nClick <a href=//www.4chan.org/banned target=_blank>here</a> to see the reason." : "You were issued a warning on " + board + " as " + ($('.nameBlock', resDoc).innerHTML) + ".<br>\nReason: " + ($('.reason', resDoc).innerHTML)
|
|
});
|
|
} else if (err = resDoc.getElementById('errmsg')) {
|
|
if ((_ref = $('a', err)) != null) {
|
|
_ref.target = '_blank';
|
|
}
|
|
} else if (resDoc.title !== 'Post successful!') {
|
|
err = 'Connection error with sys.4chan.org.';
|
|
} else if (req.status !== 200) {
|
|
err = "Error " + req.statusText + " (" + req.status + ")";
|
|
}
|
|
if (err) {
|
|
if (/captcha|verification/i.test(err.textContent) || err === 'Connection error with sys.4chan.org.') {
|
|
if (/mistyped/i.test(err.textContent)) {
|
|
err = 'You seem to have mistyped the CAPTCHA.';
|
|
} else if (/expired/i.test(err.textContent)) {
|
|
err = 'This CAPTCHA is no longer valid because it has expired.';
|
|
}
|
|
QR.cooldown.auto = false;
|
|
QR.cooldown.set({
|
|
delay: 2
|
|
});
|
|
} else if (err.textContent && (m = err.textContent.match(/wait\s+(\d+)\s+second/i))) {
|
|
QR.cooldown.auto = !QR.captcha.isEnabled;
|
|
QR.cooldown.set({
|
|
delay: m[1]
|
|
});
|
|
} else {
|
|
QR.cooldown.auto = false;
|
|
}
|
|
QR.status();
|
|
QR.error(err);
|
|
return;
|
|
}
|
|
h1 = $('h1', resDoc);
|
|
QR.cleanNotifications();
|
|
if (Conf['Posting Success Notifications']) {
|
|
QR.notifications.push(new Notice('success', h1.textContent, 5));
|
|
}
|
|
QR.persona.set(post);
|
|
_ref1 = h1.nextSibling.textContent.match(/thread:(\d+),no:(\d+)/), _ = _ref1[0], threadID = _ref1[1], postID = _ref1[2];
|
|
postID = +postID;
|
|
threadID = +threadID || postID;
|
|
isReply = threadID !== postID;
|
|
QR.db.set({
|
|
boardID: g.BOARD.ID,
|
|
threadID: threadID,
|
|
postID: postID,
|
|
val: true
|
|
});
|
|
ThreadUpdater.postID = postID;
|
|
$.event('QRPostSuccessful', {
|
|
board: g.BOARD,
|
|
threadID: threadID,
|
|
postID: postID
|
|
});
|
|
$.event('QRPostSuccessful_', {
|
|
threadID: threadID,
|
|
postID: postID
|
|
});
|
|
postsCount = QR.posts.length - 1;
|
|
QR.cooldown.auto = postsCount && isReply;
|
|
if (!(Conf['Persistent QR'] || QR.cooldown.auto)) {
|
|
QR.close();
|
|
} else {
|
|
post.rm();
|
|
}
|
|
QR.cooldown.set({
|
|
req: req,
|
|
post: post,
|
|
isReply: isReply,
|
|
threadID: threadID
|
|
});
|
|
URL = !isReply ? "/" + g.BOARD + "/res/" + threadID : g.VIEW === 'index' && !QR.cooldown.auto && Conf['Open Post in New Tab'] ? "/" + g.BOARD + "/res/" + threadID + "#p" + postID : void 0;
|
|
if (URL) {
|
|
if (Conf['Open Post in New Tab']) {
|
|
$.open(URL);
|
|
} else {
|
|
window.location = URL;
|
|
}
|
|
}
|
|
return QR.status();
|
|
},
|
|
abort: function() {
|
|
if (QR.req && !QR.req.isUploadFinished) {
|
|
QR.req.abort();
|
|
delete QR.req;
|
|
QR.posts[0].unlock();
|
|
QR.cooldown.auto = false;
|
|
QR.notifications.push(new Notice('info', 'QR upload aborted.', 5));
|
|
}
|
|
return QR.status();
|
|
},
|
|
mouseover: function(e) {
|
|
var mouseover;
|
|
mouseover = $.el('div', {
|
|
id: 'mouseover',
|
|
className: 'dialog'
|
|
});
|
|
$.add(Header.hover, mouseover);
|
|
mouseover.innerHTML = this.nextElementSibling.innerHTML;
|
|
UI.hover({
|
|
root: this,
|
|
el: mouseover,
|
|
latestEvent: e,
|
|
endEvents: 'mouseout',
|
|
asapTest: function() {
|
|
return true;
|
|
},
|
|
offsetX: 15,
|
|
offsetY: -5
|
|
});
|
|
}
|
|
};
|
|
|
|
QR.captcha = {
|
|
init: function() {
|
|
var imgContainer, input;
|
|
if (d.cookie.indexOf('pass_enabled=1') >= 0) {
|
|
return;
|
|
}
|
|
if (!(this.isEnabled = !!$.id('captchaContainer'))) {
|
|
return;
|
|
}
|
|
imgContainer = $.el('div', {
|
|
className: 'captcha-img',
|
|
title: 'Reload reCAPTCHA',
|
|
innerHTML: '<div><img></div>'
|
|
});
|
|
input = $.el('input', {
|
|
className: 'captcha-input field',
|
|
title: 'Verification',
|
|
autocomplete: 'off',
|
|
spellcheck: false,
|
|
tabIndex: 45
|
|
});
|
|
this.nodes = {
|
|
img: imgContainer.firstChild.firstChild,
|
|
input: input
|
|
};
|
|
$.on(input, 'blur', QR.focusout);
|
|
$.on(input, 'focus', QR.focusin);
|
|
$.addClass(QR.nodes.el, 'has-captcha');
|
|
$.after(QR.nodes.com.parentNode, [imgContainer, input]);
|
|
this.beforeSetup();
|
|
return this.afterSetup();
|
|
},
|
|
beforeSetup: function() {
|
|
var img, input, _ref;
|
|
_ref = this.nodes, img = _ref.img, input = _ref.input;
|
|
img.parentNode.parentNode.hidden = true;
|
|
input.value = '';
|
|
input.placeholder = 'Focus to load reCAPTCHA';
|
|
$.on(input, 'focus', this.setup);
|
|
this.setupObserver = new MutationObserver(this.afterSetup);
|
|
return this.setupObserver.observe($.id('captchaContainer'), {
|
|
childList: true
|
|
});
|
|
},
|
|
setup: function() {
|
|
return $.globalEval('loadRecaptcha()');
|
|
},
|
|
afterSetup: function() {
|
|
var challenge, img, input, _ref;
|
|
if (!(challenge = $.id('recaptcha_challenge_field_holder'))) {
|
|
return;
|
|
}
|
|
QR.captcha.setupObserver.disconnect();
|
|
delete QR.captcha.setupObserver;
|
|
_ref = QR.captcha.nodes, img = _ref.img, input = _ref.input;
|
|
img.parentNode.parentNode.hidden = false;
|
|
input.placeholder = 'Verification';
|
|
$.off(input, 'focus', QR.captcha.setup);
|
|
$.on(input, 'keydown', QR.captcha.keydown.bind(QR.captcha));
|
|
$.on(img.parentNode, 'click', QR.captcha.reload.bind(QR.captcha));
|
|
QR.captcha.nodes.challenge = challenge;
|
|
new MutationObserver(QR.captcha.load.bind(QR.captcha)).observe(challenge, {
|
|
childList: true,
|
|
subtree: true,
|
|
attributes: true
|
|
});
|
|
return QR.captcha.load();
|
|
},
|
|
destroy: function() {
|
|
$.globalEval('Recaptcha.destroy()');
|
|
return this.beforeSetup();
|
|
},
|
|
getOne: function() {
|
|
var challenge, response;
|
|
challenge = this.nodes.img.alt;
|
|
response = this.nodes.input.value.trim();
|
|
if (response && !/\s/.test(response)) {
|
|
response = "" + response + " " + response;
|
|
}
|
|
return {
|
|
challenge: challenge,
|
|
response: response
|
|
};
|
|
},
|
|
load: function() {
|
|
var challenge;
|
|
if (!this.nodes.challenge.firstChild) {
|
|
return;
|
|
}
|
|
challenge = this.nodes.challenge.firstChild.value;
|
|
this.nodes.img.alt = challenge;
|
|
this.nodes.img.src = "//www.google.com/recaptcha/api/image?c=" + challenge;
|
|
return this.nodes.input.value = null;
|
|
},
|
|
reload: function(focus) {
|
|
$.globalEval('Recaptcha.reload("t")');
|
|
if (focus) {
|
|
return this.nodes.input.focus();
|
|
}
|
|
},
|
|
keydown: function(e) {
|
|
if (e.keyCode === 8 && !this.nodes.input.value) {
|
|
this.reload();
|
|
} else {
|
|
return;
|
|
}
|
|
return e.preventDefault();
|
|
}
|
|
};
|
|
|
|
QR.cooldown = {
|
|
init: function() {
|
|
var key, setTimers, type;
|
|
if (!Conf['Cooldown']) {
|
|
return;
|
|
}
|
|
setTimers = (function(_this) {
|
|
return function(e) {
|
|
return QR.cooldown.types = e.detail;
|
|
};
|
|
})(this);
|
|
$.on(window, 'cooldown:timers', setTimers);
|
|
$.globalEval('window.dispatchEvent(new CustomEvent("cooldown:timers", {detail: cooldowns}))');
|
|
$.off(window, 'cooldown:timers', setTimers);
|
|
for (type in QR.cooldown.types) {
|
|
QR.cooldown.types[type] = +QR.cooldown.types[type];
|
|
}
|
|
key = "cooldown." + g.BOARD;
|
|
$.get(key, {}, function(item) {
|
|
QR.cooldown.cooldowns = item[key];
|
|
return QR.cooldown.start();
|
|
});
|
|
return $.sync(key, QR.cooldown.sync);
|
|
},
|
|
start: function() {
|
|
if (QR.cooldown.isCounting || !Object.keys(QR.cooldown.cooldowns).length) {
|
|
return;
|
|
}
|
|
QR.cooldown.isCounting = true;
|
|
return QR.cooldown.count();
|
|
},
|
|
sync: function(cooldowns) {
|
|
var id;
|
|
for (id in cooldowns) {
|
|
QR.cooldown.cooldowns[id] = cooldowns[id];
|
|
}
|
|
return QR.cooldown.start();
|
|
},
|
|
set: function(data) {
|
|
var cooldown, delay, isReply, post, req, start, threadID;
|
|
if (!Conf['Cooldown']) {
|
|
return;
|
|
}
|
|
req = data.req, post = data.post, isReply = data.isReply, threadID = data.threadID, delay = data.delay;
|
|
start = req ? req.uploadEndTime : Date.now();
|
|
if (delay) {
|
|
cooldown = {
|
|
delay: delay
|
|
};
|
|
} else {
|
|
cooldown = {
|
|
isReply: isReply,
|
|
threadID: threadID
|
|
};
|
|
}
|
|
QR.cooldown.cooldowns[start] = cooldown;
|
|
$.set("cooldown." + g.BOARD, QR.cooldown.cooldowns);
|
|
return QR.cooldown.start();
|
|
},
|
|
unset: function(id) {
|
|
delete QR.cooldown.cooldowns[id];
|
|
if (Object.keys(QR.cooldown.cooldowns).length) {
|
|
return $.set("cooldown." + g.BOARD, QR.cooldown.cooldowns);
|
|
} else {
|
|
return $["delete"]("cooldown." + g.BOARD);
|
|
}
|
|
},
|
|
count: function() {
|
|
var cooldown, cooldowns, elapsed, hasFile, isReply, maxTimer, now, post, seconds, start, type, types, update, _ref;
|
|
if (!Object.keys(QR.cooldown.cooldowns).length) {
|
|
$["delete"]("cooldown." + g.BOARD);
|
|
delete QR.cooldown.isCounting;
|
|
delete QR.cooldown.seconds;
|
|
QR.status();
|
|
return;
|
|
}
|
|
clearTimeout(QR.cooldown.timeout);
|
|
QR.cooldown.timeout = setTimeout(QR.cooldown.count, $.SECOND);
|
|
now = Date.now();
|
|
post = QR.posts[0];
|
|
isReply = post.thread !== 'new';
|
|
hasFile = !!post.file;
|
|
seconds = null;
|
|
_ref = QR.cooldown, types = _ref.types, cooldowns = _ref.cooldowns;
|
|
for (start in cooldowns) {
|
|
cooldown = cooldowns[start];
|
|
start = +start;
|
|
if ('delay' in cooldown) {
|
|
if (cooldown.delay) {
|
|
seconds = Math.max(seconds, cooldown.delay--);
|
|
} else {
|
|
seconds = Math.max(seconds, 0);
|
|
QR.cooldown.unset(start);
|
|
}
|
|
continue;
|
|
}
|
|
if (isReply === cooldown.isReply) {
|
|
elapsed = Math.floor((now - start) / $.SECOND);
|
|
if (elapsed < 0) {
|
|
QR.cooldown.unset(start);
|
|
continue;
|
|
}
|
|
type = !isReply ? 'thread' : hasFile ? 'image' : 'reply';
|
|
maxTimer = Math.max(types[type] || 0, types[type + '_intra'] || 0);
|
|
if (!((start <= now && now <= start + maxTimer * $.SECOND))) {
|
|
QR.cooldown.unset(start);
|
|
}
|
|
if (isReply && +post.thread === cooldown.threadID) {
|
|
type += '_intra';
|
|
}
|
|
seconds = Math.max(seconds, types[type] - elapsed);
|
|
}
|
|
}
|
|
update = seconds !== null || !!QR.cooldown.seconds;
|
|
QR.cooldown.seconds = seconds;
|
|
if (update) {
|
|
QR.status();
|
|
}
|
|
if (seconds === 0 && QR.cooldown.auto && !QR.req) {
|
|
return QR.submit();
|
|
}
|
|
}
|
|
};
|
|
|
|
QR.persona = {
|
|
pwd: '',
|
|
always: {},
|
|
init: function() {
|
|
QR.persona.getPassword();
|
|
return $.get('QR.personas', Conf['QR.personas'], function(_arg) {
|
|
var arr, item, personas, type, types, _i, _len, _ref;
|
|
personas = _arg['QR.personas'];
|
|
types = {
|
|
name: [],
|
|
email: [],
|
|
sub: []
|
|
};
|
|
_ref = personas.split('\n');
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
item = _ref[_i];
|
|
QR.persona.parseItem(item.trim(), types);
|
|
}
|
|
for (type in types) {
|
|
arr = types[type];
|
|
QR.persona.loadPersonas(type, arr);
|
|
}
|
|
});
|
|
},
|
|
parseItem: function(item, types) {
|
|
var boards, match, type, val, _ref, _ref1, _ref2;
|
|
if (item[0] === '#') {
|
|
return;
|
|
}
|
|
if (!(match = item.match(/(name|email|subject|password):"(.*)"/i))) {
|
|
return;
|
|
}
|
|
_ref = match, match = _ref[0], type = _ref[1], val = _ref[2];
|
|
item = item.replace(match, '');
|
|
boards = ((_ref1 = item.match(/boards:([^;]+)/i)) != null ? _ref1[1].toLowerCase() : void 0) || 'global';
|
|
if (boards !== 'global' && (_ref2 = g.BOARD.ID, __indexOf.call(boards.split(','), _ref2) < 0)) {
|
|
return;
|
|
}
|
|
if (type === 'password') {
|
|
QR.persona.pwd = val;
|
|
return;
|
|
}
|
|
if (type === 'subject') {
|
|
type = 'sub';
|
|
}
|
|
if (/always/i.test(item)) {
|
|
QR.persona.always[type] = val;
|
|
}
|
|
if (__indexOf.call(types[type], val) < 0) {
|
|
return types[type].push(val);
|
|
}
|
|
},
|
|
loadPersonas: function(type, arr) {
|
|
var list, val, _i, _len;
|
|
list = $("#list-" + type, QR.nodes.el);
|
|
for (_i = 0, _len = arr.length; _i < _len; _i++) {
|
|
val = arr[_i];
|
|
if (val) {
|
|
$.add(list, $.el('option', {
|
|
textContent: val
|
|
}));
|
|
}
|
|
}
|
|
},
|
|
getPassword: function() {
|
|
var input, m;
|
|
if (!QR.persona.pwd) {
|
|
QR.persona.pwd = (m = d.cookie.match(/4chan_pass=([^;]+)/)) ? decodeURIComponent(m[1]) : (input = $.id('postPassword')) ? input.value : $.id('delPassword').value;
|
|
}
|
|
return QR.persona.pwd;
|
|
},
|
|
get: function(cb) {
|
|
return $.get('QR.persona', {}, function(_arg) {
|
|
var persona;
|
|
persona = _arg['QR.persona'];
|
|
return cb(persona);
|
|
});
|
|
},
|
|
set: function(post) {
|
|
return $.get('QR.persona', {}, function(_arg) {
|
|
var persona;
|
|
persona = _arg['QR.persona'];
|
|
persona = {
|
|
name: post.name,
|
|
email: /^sage$/.test(post.email) ? persona.email : post.email,
|
|
sub: Conf['Remember Subject'] ? post.sub : void 0,
|
|
flag: post.flag
|
|
};
|
|
return $.set('QR.persona', persona);
|
|
});
|
|
}
|
|
};
|
|
|
|
QR.post = (function() {
|
|
function _Class(select) {
|
|
this.select = __bind(this.select, this);
|
|
var el, elm, event, prev, _i, _j, _len, _len1, _ref, _ref1, _ref2;
|
|
el = $.el('a', {
|
|
className: 'qr-preview',
|
|
draggable: true,
|
|
href: 'javascript:;',
|
|
innerHTML: '<a class="remove fa" title=Remove>\uf057</a><label hidden><input type=checkbox> Spoiler</label><span></span>'
|
|
});
|
|
this.nodes = {
|
|
el: el,
|
|
rm: el.firstChild,
|
|
label: $('label', el),
|
|
spoiler: $('input', el),
|
|
span: el.lastChild
|
|
};
|
|
_ref = $$('*', el);
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
elm = _ref[_i];
|
|
$.on(elm, 'blur', QR.focusout);
|
|
$.on(elm, 'focus', QR.focusin);
|
|
}
|
|
$.on(el, 'click', this.select);
|
|
$.on(this.nodes.rm, 'click', (function(_this) {
|
|
return function(e) {
|
|
e.stopPropagation();
|
|
return _this.rm();
|
|
};
|
|
})(this));
|
|
$.on(this.nodes.label, 'click', (function(_this) {
|
|
return function(e) {
|
|
return e.stopPropagation();
|
|
};
|
|
})(this));
|
|
$.on(this.nodes.spoiler, 'change', (function(_this) {
|
|
return function(e) {
|
|
_this.spoiler = e.target.checked;
|
|
if (_this === QR.selected) {
|
|
return QR.nodes.spoiler.checked = _this.spoiler;
|
|
}
|
|
};
|
|
})(this));
|
|
$.add(QR.nodes.dumpList, el);
|
|
_ref1 = ['dragStart', 'dragEnter', 'dragLeave', 'dragOver', 'dragEnd', 'drop'];
|
|
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
|
event = _ref1[_j];
|
|
$.on(el, event.toLowerCase(), this[event]);
|
|
}
|
|
this.thread = g.VIEW === 'thread' ? g.THREADID : 'new';
|
|
_ref2 = QR.posts, prev = _ref2[_ref2.length - 1];
|
|
QR.posts.push(this);
|
|
this.nodes.spoiler.checked = this.spoiler = prev && Conf['Remember Spoiler'] ? prev.spoiler : false;
|
|
QR.persona.get((function(_this) {
|
|
return function(persona) {
|
|
_this.name = 'name' in QR.persona.always ? QR.persona.always.name : prev ? prev.name : persona.name;
|
|
_this.email = 'email' in QR.persona.always ? QR.persona.always.email : prev && !/^sage$/.test(prev.email) ? prev.email : persona.email;
|
|
_this.sub = 'sub' in QR.persona.always ? QR.persona.always.sub : Conf['Remember Subject'] ? prev ? prev.sub : persona.sub : '';
|
|
if (QR.nodes.flag) {
|
|
_this.flag = prev ? prev.flag : persona.flag;
|
|
}
|
|
if (QR.selected === _this) {
|
|
return _this.load();
|
|
}
|
|
};
|
|
})(this));
|
|
if (select) {
|
|
this.select();
|
|
}
|
|
this.unlock();
|
|
}
|
|
|
|
_Class.prototype.rm = function() {
|
|
var index;
|
|
this["delete"]();
|
|
index = QR.posts.indexOf(this);
|
|
if (QR.posts.length === 1) {
|
|
new QR.post(true);
|
|
$.rmClass(QR.nodes.el, 'dump');
|
|
} else if (this === QR.selected) {
|
|
(QR.posts[index - 1] || QR.posts[index + 1]).select();
|
|
}
|
|
QR.posts.splice(index, 1);
|
|
return QR.status();
|
|
};
|
|
|
|
_Class.prototype["delete"] = function() {
|
|
$.rm(this.nodes.el);
|
|
return URL.revokeObjectURL(this.URL);
|
|
};
|
|
|
|
_Class.prototype.lock = function(lock) {
|
|
var name, node, _i, _len, _ref;
|
|
if (lock == null) {
|
|
lock = true;
|
|
}
|
|
this.isLocked = lock;
|
|
if (this !== QR.selected) {
|
|
return;
|
|
}
|
|
_ref = ['thread', 'name', 'email', 'sub', 'com', 'fileButton', 'filename', 'spoiler', 'flag'];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
name = _ref[_i];
|
|
if (node = QR.nodes[name]) {
|
|
node.disabled = lock;
|
|
}
|
|
}
|
|
if (QR.captcha.isEnabled) {
|
|
QR.captcha.nodes.input.disabled = lock;
|
|
}
|
|
this.nodes.rm.style.visibility = lock ? 'hidden' : '';
|
|
(lock ? $.off : $.on)(QR.nodes.filename.previousElementSibling, 'click', QR.openFileInput);
|
|
this.nodes.spoiler.disabled = lock;
|
|
return this.nodes.el.draggable = !lock;
|
|
};
|
|
|
|
_Class.prototype.unlock = function() {
|
|
return this.lock(false);
|
|
};
|
|
|
|
_Class.prototype.select = function() {
|
|
var rectEl, rectList;
|
|
if (QR.selected) {
|
|
QR.selected.nodes.el.id = null;
|
|
QR.selected.forceSave();
|
|
}
|
|
QR.selected = this;
|
|
this.lock(this.isLocked);
|
|
this.nodes.el.id = 'selected';
|
|
rectEl = this.nodes.el.getBoundingClientRect();
|
|
rectList = this.nodes.el.parentNode.getBoundingClientRect();
|
|
this.nodes.el.parentNode.scrollLeft += rectEl.left + rectEl.width / 2 - rectList.left - rectList.width / 2;
|
|
this.load();
|
|
return $.event('QRPostSelection', this);
|
|
};
|
|
|
|
_Class.prototype.load = function() {
|
|
var name, node, _i, _len, _ref;
|
|
_ref = ['thread', 'name', 'email', 'sub', 'com', 'filename', 'flag'];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
name = _ref[_i];
|
|
if (!(node = QR.nodes[name])) {
|
|
continue;
|
|
}
|
|
node.value = this[name] || node.dataset["default"] || null;
|
|
}
|
|
QR.tripcodeHider.call(QR.nodes['name']);
|
|
this.showFileData();
|
|
return QR.characterCount();
|
|
};
|
|
|
|
_Class.prototype.save = function(input) {
|
|
var name, _ref;
|
|
if (input.type === 'checkbox') {
|
|
this.spoiler = input.checked;
|
|
return;
|
|
}
|
|
name = input.dataset.name;
|
|
this[name] = input.value || input.dataset["default"] || null;
|
|
switch (name) {
|
|
case 'thread':
|
|
return QR.status();
|
|
case 'com':
|
|
this.nodes.span.textContent = this.com;
|
|
QR.characterCount();
|
|
if (QR.cooldown.auto && this === QR.posts[0] && (0 < (_ref = QR.cooldown.seconds) && _ref <= 5)) {
|
|
return QR.cooldown.auto = false;
|
|
}
|
|
break;
|
|
case 'filename':
|
|
if (!this.file) {
|
|
return;
|
|
}
|
|
this.file.newName = this.filename.replace(/[/\\]/g, '-');
|
|
if (!/\.(jpe?g|png|gif|pdf|swf)$/i.test(this.filename)) {
|
|
this.file.newName += '.jpg';
|
|
}
|
|
return this.updateFilename();
|
|
}
|
|
};
|
|
|
|
_Class.prototype.forceSave = function() {
|
|
var name, node, _i, _len, _ref;
|
|
if (this !== QR.selected) {
|
|
return;
|
|
}
|
|
_ref = ['thread', 'name', 'email', 'sub', 'com', 'filename', 'spoiler', 'flag'];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
name = _ref[_i];
|
|
if (!(node = QR.nodes[name])) {
|
|
continue;
|
|
}
|
|
this.save(node);
|
|
}
|
|
};
|
|
|
|
_Class.prototype.setFile = function(file) {
|
|
this.file = file;
|
|
this.filename = file.name;
|
|
this.filesize = $.bytesToString(file.size);
|
|
if (QR.spoiler) {
|
|
this.nodes.label.hidden = false;
|
|
}
|
|
URL.revokeObjectURL(this.URL);
|
|
if (this === QR.selected) {
|
|
this.showFileData();
|
|
} else {
|
|
this.updateFilename();
|
|
}
|
|
if (!/^image/.test(file.type)) {
|
|
this.nodes.el.style.backgroundImage = null;
|
|
return;
|
|
}
|
|
return this.setThumbnail();
|
|
};
|
|
|
|
_Class.prototype.setThumbnail = function() {
|
|
var fileURL, img;
|
|
img = $.el('img');
|
|
img.onload = (function(_this) {
|
|
return function() {
|
|
var cv, height, s, width;
|
|
s = 90 * 2 * window.devicePixelRatio;
|
|
if (_this.file.type === 'image/gif') {
|
|
s *= 3;
|
|
}
|
|
height = img.height, width = img.width;
|
|
if (height < s || width < s) {
|
|
_this.URL = fileURL;
|
|
_this.nodes.el.style.backgroundImage = "url(" + _this.URL + ")";
|
|
return;
|
|
}
|
|
if (height <= width) {
|
|
width = s / height * width;
|
|
height = s;
|
|
} else {
|
|
height = s / width * height;
|
|
width = s;
|
|
}
|
|
cv = $.el('canvas');
|
|
cv.height = img.height = height;
|
|
cv.width = img.width = width;
|
|
cv.getContext('2d').drawImage(img, 0, 0, width, height);
|
|
URL.revokeObjectURL(fileURL);
|
|
return cv.toBlob(function(blob) {
|
|
_this.URL = URL.createObjectURL(blob);
|
|
return _this.nodes.el.style.backgroundImage = "url(" + _this.URL + ")";
|
|
});
|
|
};
|
|
})(this);
|
|
fileURL = URL.createObjectURL(this.file);
|
|
return img.src = fileURL;
|
|
};
|
|
|
|
_Class.prototype.rmFile = function() {
|
|
if (this.isLocked) {
|
|
return;
|
|
}
|
|
delete this.file;
|
|
delete this.filename;
|
|
delete this.filesize;
|
|
this.nodes.el.title = null;
|
|
QR.nodes.fileContainer.title = '';
|
|
this.nodes.el.style.backgroundImage = null;
|
|
if (QR.spoiler) {
|
|
this.nodes.label.hidden = true;
|
|
}
|
|
this.showFileData();
|
|
return URL.revokeObjectURL(this.URL);
|
|
};
|
|
|
|
_Class.prototype.updateFilename = function() {
|
|
var title;
|
|
title = "" + this.filename + " (" + this.filesize + ")\nCtrl+click to edit filename. Shift+click to clear.";
|
|
this.nodes.el.title = title;
|
|
if (this !== QR.selected) {
|
|
return;
|
|
}
|
|
return QR.nodes.fileContainer.title = title;
|
|
};
|
|
|
|
_Class.prototype.showFileData = function() {
|
|
if (this.file) {
|
|
this.updateFilename();
|
|
QR.nodes.filename.value = this.filename;
|
|
QR.nodes.spoiler.checked = this.spoiler;
|
|
return $.addClass(QR.nodes.fileSubmit, 'has-file');
|
|
} else {
|
|
return $.rmClass(QR.nodes.fileSubmit, 'has-file');
|
|
}
|
|
};
|
|
|
|
_Class.prototype.pasteText = function(file) {
|
|
var reader;
|
|
reader = new FileReader();
|
|
reader.onload = (function(_this) {
|
|
return function(e) {
|
|
var text;
|
|
text = e.target.result;
|
|
if (_this.com) {
|
|
_this.com += "\n" + text;
|
|
} else {
|
|
_this.com = text;
|
|
}
|
|
if (QR.selected === _this) {
|
|
QR.nodes.com.value = _this.com;
|
|
}
|
|
return _this.nodes.span.textContent = _this.com;
|
|
};
|
|
})(this);
|
|
return reader.readAsText(file);
|
|
};
|
|
|
|
_Class.prototype.dragStart = function(e) {
|
|
e.dataTransfer.setDragImage(this, e.layerX, e.layerY);
|
|
return $.addClass(this, 'drag');
|
|
};
|
|
|
|
_Class.prototype.dragEnd = function() {
|
|
return $.rmClass(this, 'drag');
|
|
};
|
|
|
|
_Class.prototype.dragEnter = function() {
|
|
return $.addClass(this, 'over');
|
|
};
|
|
|
|
_Class.prototype.dragLeave = function() {
|
|
return $.rmClass(this, 'over');
|
|
};
|
|
|
|
_Class.prototype.dragOver = function(e) {
|
|
e.preventDefault();
|
|
return e.dataTransfer.dropEffect = 'move';
|
|
};
|
|
|
|
_Class.prototype.drop = function() {
|
|
var el, index, newIndex, oldIndex, post;
|
|
$.rmClass(this, 'over');
|
|
if (!this.draggable) {
|
|
return;
|
|
}
|
|
el = $('.drag', this.parentNode);
|
|
index = function(el) {
|
|
return __slice.call(el.parentNode.children).indexOf(el);
|
|
};
|
|
oldIndex = index(el);
|
|
newIndex = index(this);
|
|
(oldIndex < newIndex ? $.after : $.before)(this, el);
|
|
post = QR.posts.splice(oldIndex, 1)[0];
|
|
QR.posts.splice(newIndex, 0, post);
|
|
return QR.status();
|
|
};
|
|
|
|
return _Class;
|
|
|
|
})();
|
|
|
|
AutoGIF = {
|
|
init: function() {
|
|
var _ref;
|
|
if (!Conf['Auto-GIF'] || ((_ref = g.BOARD.ID) === 'gif' || _ref === 'wsg')) {
|
|
return;
|
|
}
|
|
Post.callbacks.push({
|
|
name: 'Auto-GIF',
|
|
cb: this.node
|
|
});
|
|
return CatalogThread.callbacks.push({
|
|
name: 'Auto-GIF',
|
|
cb: this.catalogNode
|
|
});
|
|
},
|
|
node: function() {
|
|
var URL, style, thumb, _ref, _ref1;
|
|
if (this.isClone || this.isHidden || this.thread.isHidden || !((_ref = this.file) != null ? _ref.isImage : void 0)) {
|
|
return;
|
|
}
|
|
_ref1 = this.file, thumb = _ref1.thumb, URL = _ref1.URL;
|
|
if (!(/gif$/.test(URL) && !/spoiler/.test(thumb.src))) {
|
|
return;
|
|
}
|
|
if (this.file.isSpoiler) {
|
|
style = thumb.style;
|
|
style.maxHeight = style.maxWidth = this.isReply ? '125px' : '250px';
|
|
}
|
|
return AutoGIF.replaceThumbnail(thumb, URL);
|
|
},
|
|
catalogNode: function() {
|
|
var OP, URL, _ref;
|
|
OP = this.thread.OP;
|
|
if (!((_ref = OP.file) != null ? _ref.isImage : void 0)) {
|
|
return;
|
|
}
|
|
URL = OP.file.URL;
|
|
if (!/gif$/.test(URL)) {
|
|
return;
|
|
}
|
|
return AutoGIF.replaceThumbnail(this.nodes.thumb, URL, true);
|
|
},
|
|
replaceThumbnail: function(thumb, URL, isBackground) {
|
|
var gif;
|
|
gif = $.el('img');
|
|
$.on(gif, 'load', function() {
|
|
if (isBackground) {
|
|
return thumb.style.backgroundImage = "url(" + URL + ")";
|
|
} else {
|
|
return thumb.src = URL;
|
|
}
|
|
});
|
|
return gif.src = URL;
|
|
}
|
|
};
|
|
|
|
FappeTyme = {
|
|
init: function() {
|
|
var el, lc, type, _i, _len, _ref;
|
|
if (!(Conf['Fappe Tyme'] || Conf['Werk Tyme']) || g.BOARD === 'f') {
|
|
return;
|
|
}
|
|
_ref = ["Fappe", "Werk"];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
type = _ref[_i];
|
|
if (!Conf["" + type + " Tyme"]) {
|
|
continue;
|
|
}
|
|
lc = type.toLowerCase();
|
|
FappeTyme[lc] = el = $.el('a', {
|
|
href: 'javascript:;',
|
|
id: "" + lc + "Tyme",
|
|
title: "" + type + " Tyme",
|
|
className: 'a-icon'
|
|
});
|
|
if (type === 'Werk') {
|
|
el.textContent = '\uf0b1';
|
|
el.className = 'fa';
|
|
}
|
|
$.on(el, 'click', FappeTyme.cb.toggle.bind({
|
|
name: "" + lc
|
|
}));
|
|
Header.addShortcut(el, true);
|
|
FappeTyme.cb.set(lc);
|
|
}
|
|
return Post.callbacks.push({
|
|
name: 'Fappe Tyme',
|
|
cb: this.node
|
|
});
|
|
},
|
|
node: function() {
|
|
if (this.file) {
|
|
return;
|
|
}
|
|
return $.addClass(this.nodes.root, "noFile");
|
|
},
|
|
cb: {
|
|
set: function(type) {
|
|
return $["" + (Conf[type] ? 'add' : 'rm') + "Class"](doc, "" + type + "Tyme");
|
|
},
|
|
toggle: function() {
|
|
Conf[this.name] = !Conf[this.name];
|
|
FappeTyme.cb.set(this.name);
|
|
return $.cb.checked.call({
|
|
name: this.name,
|
|
checked: Conf[this.name]
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
Gallery = {
|
|
init: function() {
|
|
var el;
|
|
if (g.BOARD === 'f' || !Conf['Gallery']) {
|
|
return;
|
|
}
|
|
el = $.el('a', {
|
|
href: 'javascript:;',
|
|
id: 'appchan-gal',
|
|
title: 'Gallery',
|
|
className: 'fa',
|
|
textContent: '\uf03e'
|
|
});
|
|
$.on(el, 'click', this.cb.toggle);
|
|
Header.addShortcut(el, true);
|
|
return Post.callbacks.push({
|
|
name: 'Gallery',
|
|
cb: this.node
|
|
});
|
|
},
|
|
node: function() {
|
|
var _ref;
|
|
if (!((_ref = this.file) != null ? _ref.isImage : void 0)) {
|
|
return;
|
|
}
|
|
if (Gallery.nodes) {
|
|
Gallery.generateThumb($('.file', this.nodes.root));
|
|
Gallery.nodes.total.textContent = Gallery.images.length;
|
|
}
|
|
if (!Conf['Image Expansion']) {
|
|
return $.on(this.file.thumb.parentNode, 'click', Gallery.cb.image);
|
|
}
|
|
},
|
|
build: function(image) {
|
|
var cb, createSubEntry, dialog, el, file, files, i, key, menuButton, name, nodes, value, _ref;
|
|
Gallery.images = [];
|
|
nodes = Gallery.nodes = {};
|
|
nodes.el = dialog = $.el('div', {
|
|
id: 'a-gallery',
|
|
innerHTML: "<div class=gal-viewport>\n <span class=gal-buttons>\n <a class=\"menu-button\" href=\"javascript:;\"><i class=\"fa\">\uf107</i></a>\n <a href=javascript:; class='gal-close fa'>\uf00d</a>\n </span>\n <a class=gal-name target=\"_blank\"></a>\n <span class=gal-count>\n <span class='count'></span> / <span class='total'></span>\n </span>\n <div class=gal-prev></div>\n <div class=gal-image>\n <a href=javascript:;><img></a>\n </div>\n <div class=gal-next></div>\n</div>\n<div class=gal-thumbnails></div>"
|
|
});
|
|
_ref = {
|
|
frame: '.gal-image',
|
|
name: '.gal-name',
|
|
count: '.count',
|
|
total: '.total',
|
|
thumbs: '.gal-thumbnails',
|
|
next: '.gal-image a',
|
|
current: '.gal-image img'
|
|
};
|
|
for (key in _ref) {
|
|
value = _ref[key];
|
|
nodes[key] = $(value, dialog);
|
|
}
|
|
menuButton = $('.menu-button', dialog);
|
|
nodes.menu = new UI.Menu('gallery');
|
|
cb = Gallery.cb;
|
|
$.on(nodes.frame, 'click', cb.blank);
|
|
$.on(nodes.current, 'click', cb.download);
|
|
$.on(nodes.next, 'click', cb.next);
|
|
$.on($('.gal-prev', dialog), 'click', cb.prev);
|
|
$.on($('.gal-next', dialog), 'click', cb.next);
|
|
$.on($('.gal-close', dialog), 'click', cb.close);
|
|
$.on(menuButton, 'click', function(e) {
|
|
return nodes.menu.toggle(e, this, g);
|
|
});
|
|
createSubEntry = Gallery.menu.createSubEntry;
|
|
for (name in Config.gallery) {
|
|
el = createSubEntry(name).el;
|
|
$.event('AddMenuEntry', {
|
|
type: 'gallery',
|
|
el: el,
|
|
order: 0
|
|
});
|
|
}
|
|
$.on(d, 'keydown', cb.keybinds);
|
|
$.off(d, 'keydown', Keybinds.keydown);
|
|
i = 0;
|
|
files = $$('.post .file');
|
|
while (file = files[i++]) {
|
|
if ($('.fileDeletedRes, .fileDeleted', file)) {
|
|
continue;
|
|
}
|
|
Gallery.generateThumb(file);
|
|
}
|
|
$.add(d.body, dialog);
|
|
nodes.thumbs.scrollTop = 0;
|
|
nodes.current.parentElement.scrollTop = 0;
|
|
Gallery.cb.open.call(image ? $("[href='" + (image.href.replace(/https?:/, '')) + "']", nodes.thumbs) : Gallery.images[0]);
|
|
d.body.style.overflow = 'hidden';
|
|
return nodes.total.textContent = --i;
|
|
},
|
|
generateThumb: function(file) {
|
|
var dupe, post, thumb, title;
|
|
post = Get.postFromNode(file);
|
|
title = ($('.fileText a', file)).textContent;
|
|
thumb = post.file.thumb.parentNode.cloneNode(true);
|
|
if (dupe = $('img + img', thumb)) {
|
|
$.rm(dupe);
|
|
}
|
|
thumb.className = 'gal-thumb';
|
|
thumb.title = title;
|
|
thumb.dataset.id = Gallery.images.length;
|
|
thumb.dataset.post = $('a[title="Highlight this post"]', post.nodes.info).href;
|
|
thumb.firstElementChild.style.cssText = '';
|
|
$.on(thumb, 'click', Gallery.cb.open);
|
|
Gallery.images.push(thumb);
|
|
return $.add(Gallery.nodes.thumbs, thumb);
|
|
},
|
|
cb: {
|
|
keybinds: function(e) {
|
|
var cb, key;
|
|
if (!(key = Keybinds.keyCode(e))) {
|
|
return;
|
|
}
|
|
cb = (function() {
|
|
switch (key) {
|
|
case 'Esc':
|
|
case Conf['Open Gallery']:
|
|
return Gallery.cb.close;
|
|
case 'Right':
|
|
case 'Enter':
|
|
return Gallery.cb.next;
|
|
case 'Left':
|
|
case '':
|
|
return Gallery.cb.prev;
|
|
}
|
|
})();
|
|
if (!cb) {
|
|
return;
|
|
}
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
return cb();
|
|
},
|
|
open: function(e) {
|
|
var el, img, name, nodes, rect, top;
|
|
if (e) {
|
|
e.preventDefault();
|
|
}
|
|
if (!this) {
|
|
return;
|
|
}
|
|
nodes = Gallery.nodes;
|
|
name = nodes.name;
|
|
if (el = $('.gal-highlight', nodes.thumbs)) {
|
|
$.rmClass(el, 'gal-highlight');
|
|
}
|
|
$.addClass(this, 'gal-highlight');
|
|
img = $.el('img', {
|
|
src: name.href = this.href,
|
|
title: name.download = name.textContent = this.title
|
|
});
|
|
$.extend(img.dataset, this.dataset);
|
|
$.replace(nodes.current, img);
|
|
nodes.count.textContent = +this.dataset.id + 1;
|
|
nodes.current = img;
|
|
nodes.frame.scrollTop = 0;
|
|
nodes.next.focus();
|
|
rect = this.getBoundingClientRect();
|
|
top = rect.top;
|
|
if (top > 0) {
|
|
top += rect.height - doc.clientHeight;
|
|
if (top < 0) {
|
|
return;
|
|
}
|
|
}
|
|
nodes.thumbs.scrollTop += top;
|
|
return $.on(img, 'error', function() {
|
|
return Gallery.cb.error(img, thumb);
|
|
});
|
|
},
|
|
image: function(e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
return Gallery.build(this);
|
|
},
|
|
error: function(img, thumb) {
|
|
var URL, post, revived, src;
|
|
post = Get.postFromLink($.el('a', {
|
|
href: img.dataset.post
|
|
}));
|
|
delete post.file.fullImage;
|
|
src = this.src.split('/');
|
|
if (src[2] === 'images.4chan.org') {
|
|
URL = Redirect.to('file', {
|
|
boardID: src[3],
|
|
filename: src[5]
|
|
});
|
|
if (URL) {
|
|
thumb.href = URL;
|
|
if (Gallery.nodes.current !== img) {
|
|
return;
|
|
}
|
|
revived = $.el('img', {
|
|
src: URL,
|
|
title: img.title
|
|
});
|
|
$.extend(revived.dataset, img.dataset);
|
|
$.replace(img, revived);
|
|
return;
|
|
}
|
|
if (g.DEAD || post.isDead || post.file.isDead) {
|
|
return;
|
|
}
|
|
}
|
|
return $.ajax("//api.4chan.org/" + post.board + "/res/" + post.thread + ".json", {
|
|
onload: function() {
|
|
var i, postObj, posts;
|
|
if (this.status !== 200) {
|
|
return;
|
|
}
|
|
i = 0;
|
|
posts = this.response.posts;
|
|
while (postObj = posts[i++]) {
|
|
if (postObj.no === post.ID) {
|
|
break;
|
|
}
|
|
}
|
|
if (!postObj.no) {
|
|
return post.kill();
|
|
}
|
|
if (postObj.filedeleted) {
|
|
return post.kill(true);
|
|
}
|
|
}
|
|
});
|
|
},
|
|
prev: function() {
|
|
return Gallery.cb.open.call(Gallery.images[+Gallery.nodes.current.dataset.id - 1]);
|
|
},
|
|
next: function() {
|
|
return Gallery.cb.open.call(Gallery.images[+Gallery.nodes.current.dataset.id + 1]);
|
|
},
|
|
toggle: function() {
|
|
return (Gallery.nodes ? Gallery.cb.close : Gallery.build)();
|
|
},
|
|
blank: function(e) {
|
|
if (e.target === this) {
|
|
return Gallery.cb.close();
|
|
}
|
|
},
|
|
close: function() {
|
|
$.rm(Gallery.nodes.el);
|
|
delete Gallery.nodes;
|
|
d.body.style.overflow = '';
|
|
$.off(d, 'keydown', Gallery.cb.keybinds);
|
|
return $.on(d, 'keydown', Keybinds.keydown);
|
|
},
|
|
setFitness: function() {
|
|
return (this.checked ? $.addClass : $.rmClass)(doc, "gal-" + (this.name.toLowerCase().replace(/\s+/g, '-')));
|
|
}
|
|
},
|
|
menu: {
|
|
init: function() {
|
|
var createSubEntry, el, name, subEntries;
|
|
if (!Conf['Gallery']) {
|
|
return;
|
|
}
|
|
el = $.el('span', {
|
|
textContent: 'Gallery',
|
|
className: 'gallery-link'
|
|
});
|
|
createSubEntry = Gallery.menu.createSubEntry;
|
|
subEntries = [];
|
|
for (name in Config.gallery) {
|
|
subEntries.push(createSubEntry(name));
|
|
}
|
|
return $.event('AddMenuEntry', {
|
|
type: 'header',
|
|
el: el,
|
|
order: 105,
|
|
subEntries: subEntries
|
|
});
|
|
},
|
|
createSubEntry: function(name) {
|
|
var input, label;
|
|
label = $.el('label', {
|
|
innerHTML: "<input type=checkbox name='" + name + "'> " + name
|
|
});
|
|
input = label.firstElementChild;
|
|
if (name === 'Fit Width' || name === 'Fit Height' || name === 'Hide Thumbnails') {
|
|
$.on(input, 'change', Gallery.cb.setFitness);
|
|
}
|
|
input.checked = Conf[name];
|
|
$.event('change', null, input);
|
|
$.on(input, 'change', $.cb.checked);
|
|
return {
|
|
el: label
|
|
};
|
|
}
|
|
}
|
|
};
|
|
|
|
ImageExpand = {
|
|
init: function() {
|
|
if (!Conf['Image Expansion']) {
|
|
return;
|
|
}
|
|
this.EAI = $.el('a', {
|
|
id: 'img-controls',
|
|
className: 'expand-all-shortcut a-icon',
|
|
title: 'Expand All Images',
|
|
href: 'javascript:;'
|
|
});
|
|
$.on(this.EAI, 'click', ImageExpand.cb.toggleAll);
|
|
Header.addShortcut(this.EAI, true);
|
|
return Post.callbacks.push({
|
|
name: 'Image Expansion',
|
|
cb: this.node
|
|
});
|
|
},
|
|
node: function() {
|
|
var thumb, _ref;
|
|
if (!((_ref = this.file) != null ? _ref.isImage : void 0)) {
|
|
return;
|
|
}
|
|
thumb = this.file.thumb;
|
|
$.on(thumb.parentNode, 'click', ImageExpand.cb.toggle);
|
|
if (this.isClone && $.hasClass(thumb, 'expanding')) {
|
|
ImageExpand.contract(this);
|
|
ImageExpand.expand(this);
|
|
return;
|
|
}
|
|
if (ImageExpand.on && !this.isHidden && (Conf['Expand spoilers'] || !this.file.isSpoiler)) {
|
|
return ImageExpand.expand(this);
|
|
}
|
|
},
|
|
cb: {
|
|
toggle: function(e) {
|
|
if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) {
|
|
return;
|
|
}
|
|
e.preventDefault();
|
|
return ImageExpand.toggle(Get.postFromNode(this));
|
|
},
|
|
toggleAll: function() {
|
|
var func;
|
|
$.event('CloseMenu');
|
|
if (ImageExpand.on = $.hasClass(ImageExpand.EAI, 'expand-all-shortcut')) {
|
|
ImageExpand.EAI.className = 'contract-all-shortcut a-icon';
|
|
ImageExpand.EAI.title = 'Contract All Images';
|
|
func = ImageExpand.expand;
|
|
} else {
|
|
ImageExpand.EAI.className = 'expand-all-shortcut a-icon';
|
|
ImageExpand.EAI.title = 'Expand All Images';
|
|
func = ImageExpand.contract;
|
|
}
|
|
return g.posts.forEach(function(post) {
|
|
var file, _i, _len, _ref;
|
|
_ref = [post].concat(post.clones);
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
post = _ref[_i];
|
|
file = post.file;
|
|
if (!(file && file.isImage && doc.contains(post.nodes.root))) {
|
|
return;
|
|
}
|
|
if (ImageExpand.on && (!Conf['Expand spoilers'] && file.isSpoiler || Conf['Expand from here'] && Header.getTopOf(file.thumb) < 0)) {
|
|
return;
|
|
}
|
|
$.queueTask(func, post);
|
|
}
|
|
});
|
|
},
|
|
setFitness: function() {
|
|
return (this.checked ? $.addClass : $.rmClass)(doc, this.name.toLowerCase().replace(/\s+/g, '-'));
|
|
}
|
|
},
|
|
toggle: function(post) {
|
|
var headRect, left, root, thumb, top, x, y, _ref;
|
|
thumb = post.file.thumb;
|
|
if (!(post.file.isExpanded || $.hasClass(thumb, 'expanding'))) {
|
|
ImageExpand.expand(post);
|
|
return;
|
|
}
|
|
root = post.nodes.root;
|
|
_ref = (Conf['Advance on contract'] ? (function() {
|
|
var next;
|
|
next = root;
|
|
while (next = $.x("following::div[contains(@class,'postContainer')][1]", next)) {
|
|
if ($('.stub', next) || next.offsetHeight === 0) {
|
|
continue;
|
|
}
|
|
return next;
|
|
}
|
|
return root;
|
|
})() : root).getBoundingClientRect(), top = _ref.top, left = _ref.left;
|
|
if (top < 0) {
|
|
y = top;
|
|
if (Conf['Fixed Header'] && !Conf['Bottom Header']) {
|
|
headRect = Header.bar.getBoundingClientRect();
|
|
y -= headRect.top + headRect.height;
|
|
}
|
|
}
|
|
if (left < 0) {
|
|
x = -window.scrollX;
|
|
}
|
|
if (x || y) {
|
|
window.scrollBy(x, y);
|
|
}
|
|
return ImageExpand.contract(post);
|
|
},
|
|
contract: function(post) {
|
|
$.rmClass(post.nodes.root, 'expanded-image');
|
|
$.rmClass(post.file.thumb, 'expanding');
|
|
return post.file.isExpanded = false;
|
|
},
|
|
expand: function(post, src) {
|
|
var img, thumb;
|
|
thumb = post.file.thumb;
|
|
if (post.file.isExpanded || $.hasClass(thumb, 'expanding')) {
|
|
return;
|
|
}
|
|
$.addClass(thumb, 'expanding');
|
|
if (post.file.fullImage) {
|
|
$.asap((function() {
|
|
return post.file.fullImage.naturalHeight;
|
|
}), function() {
|
|
return ImageExpand.completeExpand(post);
|
|
});
|
|
return;
|
|
}
|
|
post.file.fullImage = img = $.el('img', {
|
|
className: 'full-image',
|
|
src: src || post.file.URL
|
|
});
|
|
$.on(img, 'error', ImageExpand.error);
|
|
$.asap((function() {
|
|
return post.file.fullImage.naturalHeight;
|
|
}), function() {
|
|
return ImageExpand.completeExpand(post);
|
|
});
|
|
return $.after(thumb, img);
|
|
},
|
|
completeExpand: function(post) {
|
|
var bottom, thumb;
|
|
thumb = post.file.thumb;
|
|
if (!$.hasClass(thumb, 'expanding')) {
|
|
return;
|
|
}
|
|
post.file.isExpanded = true;
|
|
if (!post.nodes.root.parentNode) {
|
|
$.addClass(post.nodes.root, 'expanded-image');
|
|
$.rmClass(post.file.thumb, 'expanding');
|
|
return;
|
|
}
|
|
bottom = post.nodes.root.getBoundingClientRect().bottom;
|
|
return $.queueTask(function() {
|
|
$.addClass(post.nodes.root, 'expanded-image');
|
|
$.rmClass(post.file.thumb, 'expanding');
|
|
if (!(bottom <= 0)) {
|
|
return;
|
|
}
|
|
return window.scrollBy(0, post.nodes.root.getBoundingClientRect().bottom - bottom);
|
|
});
|
|
},
|
|
error: function() {
|
|
var URL, post, src, timeoutID;
|
|
post = Get.postFromNode(this);
|
|
$.rm(this);
|
|
delete post.file.fullImage;
|
|
if (!($.hasClass(post.file.thumb, 'expanding') || $.hasClass(post.nodes.root, 'expanded-image'))) {
|
|
return;
|
|
}
|
|
ImageExpand.contract(post);
|
|
src = this.src.split('/');
|
|
if (src[2] === 'i.4cdn.org') {
|
|
URL = Redirect.to('file', {
|
|
boardID: src[3],
|
|
filename: src[5]
|
|
});
|
|
if (URL) {
|
|
setTimeout(ImageExpand.expand, 10000, post, URL);
|
|
return;
|
|
}
|
|
if (g.DEAD || post.isDead || post.file.isDead) {
|
|
return;
|
|
}
|
|
}
|
|
timeoutID = setTimeout(ImageExpand.expand, 10000, post);
|
|
return $.ajax("//a.4cdn.org/" + post.board + "/res/" + post.thread + ".json", {
|
|
onload: function() {
|
|
var postObj, _i, _len, _ref;
|
|
if (this.status !== 200) {
|
|
return;
|
|
}
|
|
_ref = this.response.posts;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
postObj = _ref[_i];
|
|
if (postObj.no === post.ID) {
|
|
break;
|
|
}
|
|
}
|
|
if (postObj.no !== post.ID) {
|
|
clearTimeout(timeoutID);
|
|
return post.kill();
|
|
} else if (postObj.filedeleted) {
|
|
clearTimeout(timeoutID);
|
|
return post.kill(true);
|
|
}
|
|
}
|
|
});
|
|
},
|
|
menu: {
|
|
init: function() {
|
|
var conf, createSubEntry, el, name, subEntries, _ref;
|
|
if (!Conf['Image Expansion']) {
|
|
return;
|
|
}
|
|
el = $.el('span', {
|
|
textContent: 'Image Expansion',
|
|
className: 'image-expansion-link'
|
|
});
|
|
createSubEntry = ImageExpand.menu.createSubEntry;
|
|
subEntries = [];
|
|
_ref = Config.imageExpansion;
|
|
for (name in _ref) {
|
|
conf = _ref[name];
|
|
subEntries.push(createSubEntry(name, conf[1]));
|
|
}
|
|
return $.event('AddMenuEntry', {
|
|
type: 'header',
|
|
el: el,
|
|
order: 105,
|
|
subEntries: subEntries
|
|
});
|
|
},
|
|
createSubEntry: function(name, desc) {
|
|
var input, label;
|
|
label = $.el('label', {
|
|
innerHTML: "<input type=checkbox name='" + name + "'> " + name,
|
|
title: desc
|
|
});
|
|
input = label.firstElementChild;
|
|
if (name === 'Fit width' || name === 'Fit height') {
|
|
$.on(input, 'change', ImageExpand.cb.setFitness);
|
|
}
|
|
input.checked = Conf[name];
|
|
$.event('change', null, input);
|
|
$.on(input, 'change', $.cb.checked);
|
|
return {
|
|
el: label
|
|
};
|
|
}
|
|
}
|
|
};
|
|
|
|
ImageHover = {
|
|
init: function() {
|
|
if (Conf['Image Hover']) {
|
|
Post.callbacks.push({
|
|
name: 'Image Hover',
|
|
cb: this.node
|
|
});
|
|
}
|
|
if (Conf['Image Hover in Catalog']) {
|
|
return CatalogThread.callbacks.push({
|
|
name: 'Image Hover',
|
|
cb: this.catalogNode
|
|
});
|
|
}
|
|
},
|
|
node: function() {
|
|
var _ref;
|
|
if (!((_ref = this.file) != null ? _ref.isImage : void 0)) {
|
|
return;
|
|
}
|
|
return $.on(this.file.thumb, 'mouseover', ImageHover.mouseover);
|
|
},
|
|
catalogNode: function() {
|
|
var _ref;
|
|
if (!((_ref = this.thread.OP.file) != null ? _ref.isImage : void 0)) {
|
|
return;
|
|
}
|
|
return $.on(this.nodes.thumb, 'mouseover', ImageHover.mouseover);
|
|
},
|
|
mouseover: function(e) {
|
|
var el, post;
|
|
post = $.hasClass(this, 'thumb') ? g.posts[this.parentNode.dataset.fullID] : Get.postFromNode(this);
|
|
el = $.el('img', {
|
|
id: 'ihover',
|
|
src: post.file.URL
|
|
});
|
|
el.dataset.fullID = post.fullID;
|
|
$.add(Header.hover, el);
|
|
UI.hover({
|
|
root: this,
|
|
el: el,
|
|
latestEvent: e,
|
|
endEvents: 'mouseout click',
|
|
asapTest: function() {
|
|
return el.naturalHeight;
|
|
}
|
|
});
|
|
return $.on(el, 'error', ImageHover.error);
|
|
},
|
|
error: function() {
|
|
var URL, post, src, timeoutID;
|
|
if (!doc.contains(this)) {
|
|
return;
|
|
}
|
|
post = g.posts[this.dataset.fullID];
|
|
src = this.src.split('/');
|
|
if (src[2] === 'i.4cdn.org') {
|
|
URL = Redirect.to('file', {
|
|
boardID: src[3],
|
|
filename: src[5].replace(/\?.+$/, '')
|
|
});
|
|
if (URL) {
|
|
this.src = URL;
|
|
return;
|
|
}
|
|
if (g.DEAD || post.isDead || post.file.isDead) {
|
|
return;
|
|
}
|
|
}
|
|
timeoutID = setTimeout(((function(_this) {
|
|
return function() {
|
|
return _this.src = post.file.URL + '?' + Date.now();
|
|
};
|
|
})(this)), 3000);
|
|
return $.ajax("//a.4cdn.org/" + post.board + "/res/" + post.thread + ".json", {
|
|
onload: function() {
|
|
var postObj, _i, _len, _ref;
|
|
if (this.status !== 200) {
|
|
return;
|
|
}
|
|
_ref = this.response.posts;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
postObj = _ref[_i];
|
|
if (postObj.no === post.ID) {
|
|
break;
|
|
}
|
|
}
|
|
if (postObj.no !== post.ID) {
|
|
clearTimeout(timeoutID);
|
|
return post.kill();
|
|
} else if (postObj.filedeleted) {
|
|
clearTimeout(timeoutID);
|
|
return post.kill(true);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
ImageLoader = {
|
|
init: function() {
|
|
var prefetch;
|
|
if (!(Conf["Image Prefetching"] || Conf["Replace JPG"] || Conf["Replace PNG"] || Conf["Replace GIF"])) {
|
|
return;
|
|
}
|
|
Post.callbacks.push({
|
|
name: 'Image Replace',
|
|
cb: this.node
|
|
});
|
|
Thread.callbacks.push({
|
|
name: 'Image Replace',
|
|
cb: this.thread
|
|
});
|
|
if (!(Conf['Image Prefetching'] && g.VIEW === 'thread')) {
|
|
return;
|
|
}
|
|
prefetch = $.el('label', {
|
|
innerHTML: '<input type=checkbox name="prefetch"> Prefetch Images'
|
|
});
|
|
this.el = prefetch.firstElementChild;
|
|
$.on(this.el, 'change', this.toggle);
|
|
return $.event('AddMenuEntry', {
|
|
type: 'header',
|
|
el: prefetch,
|
|
order: 104
|
|
});
|
|
},
|
|
thread: function() {
|
|
return ImageLoader.thread = this;
|
|
},
|
|
node: function() {
|
|
var URL, img, string, style, thumb, type, _ref, _ref1;
|
|
if (this.isClone || this.isHidden || this.thread.isHidden || !((_ref = this.file) != null ? _ref.isImage : void 0)) {
|
|
return;
|
|
}
|
|
_ref1 = this.file, thumb = _ref1.thumb, URL = _ref1.URL;
|
|
if (!((Conf[string = "Replace " + ((type = (URL.match(/\w{3}$/))[0].toUpperCase()) === 'PEG' ? 'JPG' : type)] && !/spoiler/.test(thumb.src)) || Conf['prefetch'])) {
|
|
return;
|
|
}
|
|
if (this.file.isSpoiler) {
|
|
style = thumb.style;
|
|
style.maxHeight = style.maxWidth = this.isReply ? '125px' : '250px';
|
|
}
|
|
img = $.el('img');
|
|
if (Conf[string]) {
|
|
$.on(img, 'load', function() {
|
|
return thumb.src = URL;
|
|
});
|
|
}
|
|
return img.src = URL;
|
|
},
|
|
toggle: function() {
|
|
var enabled;
|
|
enabled = Conf['prefetch'] = this.checked;
|
|
if (enabled) {
|
|
ImageLoader.thread.posts.forEach(ImageLoader.node.call);
|
|
}
|
|
}
|
|
};
|
|
|
|
RevealSpoilers = {
|
|
init: function() {
|
|
if (!Conf['Reveal Spoiler Thumbnails']) {
|
|
return;
|
|
}
|
|
return Post.callbacks.push({
|
|
name: 'Reveal Spoiler Thumbnails',
|
|
cb: this.node
|
|
});
|
|
},
|
|
node: function() {
|
|
var thumb, _ref;
|
|
if (this.isClone || !((_ref = this.file) != null ? _ref.isSpoiler : void 0)) {
|
|
return;
|
|
}
|
|
thumb = this.file.thumb;
|
|
thumb.removeAttribute('style');
|
|
return thumb.src = this.file.thumbURL;
|
|
}
|
|
};
|
|
|
|
Sauce = {
|
|
init: function() {
|
|
var err, link, links, _i, _len, _ref;
|
|
if (!Conf['Sauce']) {
|
|
return;
|
|
}
|
|
links = [];
|
|
_ref = Conf['sauces'].split('\n');
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
link = _ref[_i];
|
|
try {
|
|
if (link[0] !== '#') {
|
|
links.push(this.createSauceLink(link.trim()));
|
|
}
|
|
} catch (_error) {
|
|
err = _error;
|
|
}
|
|
}
|
|
if (!links.length) {
|
|
return;
|
|
}
|
|
this.links = links;
|
|
this.link = $.el('a', {
|
|
target: '_blank'
|
|
});
|
|
return Post.callbacks.push({
|
|
name: 'Sauce',
|
|
cb: this.node
|
|
});
|
|
},
|
|
createSauceLink: function(link) {
|
|
var m, text;
|
|
link = link.replace(/%(T?URL|MD5|board|name)/g, function(parameter) {
|
|
var type;
|
|
return ((type = {
|
|
'%TURL': 'post.file.thumbURL',
|
|
'%URL': 'post.file.URL',
|
|
'%MD5': 'post.file.MD5',
|
|
'%board': 'post.board',
|
|
'%name': 'post.file.name'
|
|
}[parameter]) ? "' + encodeURIComponent(" + type + ") + '" : parameter);
|
|
});
|
|
text = (m = link.match(/;text:(.+)$/)) ? m[1] : link.match(/(\w+)\.\w+\//)[1];
|
|
link = link.replace(/;text:.+$/, '');
|
|
return Function('post', 'a', "a.href = '" + link + "';\na.textContent = '" + text + "';\nreturn a;");
|
|
},
|
|
node: function() {
|
|
var link, nodes, _i, _len, _ref;
|
|
if (this.isClone || !this.file) {
|
|
return;
|
|
}
|
|
nodes = [];
|
|
_ref = Sauce.links;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
link = _ref[_i];
|
|
nodes.push($.tn('\u00A0'), link(this, Sauce.link.cloneNode(true)));
|
|
}
|
|
return $.add(this.file.text, nodes);
|
|
}
|
|
};
|
|
|
|
ArchiveLink = {
|
|
init: function() {
|
|
var div, entry, type, _i, _len, _ref;
|
|
if (!Conf['Menu'] || !Conf['Archive Link']) {
|
|
return;
|
|
}
|
|
div = $.el('div', {
|
|
textContent: 'Archive'
|
|
});
|
|
entry = {
|
|
type: 'post',
|
|
el: div,
|
|
order: 90,
|
|
open: function(_arg) {
|
|
var ID, board, thread;
|
|
ID = _arg.ID, thread = _arg.thread, board = _arg.board;
|
|
return !!Redirect.to('thread', {
|
|
postID: ID,
|
|
threadID: thread.ID,
|
|
boardID: board.ID
|
|
});
|
|
},
|
|
subEntries: []
|
|
};
|
|
_ref = [['Post', 'post'], ['Name', 'name'], ['Tripcode', 'tripcode'], ['E-mail', 'email'], ['Subject', 'subject'], ['Filename', 'filename'], ['Image MD5', 'MD5']];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
type = _ref[_i];
|
|
entry.subEntries.push(this.createSubEntry(type[0], type[1]));
|
|
}
|
|
return $.event('AddMenuEntry', entry);
|
|
},
|
|
createSubEntry: function(text, type) {
|
|
var el, open;
|
|
el = $.el('a', {
|
|
textContent: text,
|
|
target: '_blank'
|
|
});
|
|
open = type === 'post' ? function(_arg) {
|
|
var ID, board, thread;
|
|
ID = _arg.ID, thread = _arg.thread, board = _arg.board;
|
|
el.href = Redirect.to('thread', {
|
|
postID: ID,
|
|
threadID: thread.ID,
|
|
boardID: board.ID
|
|
});
|
|
return true;
|
|
} : function(post) {
|
|
var value;
|
|
value = Filter[type](post);
|
|
if (!value) {
|
|
return false;
|
|
}
|
|
el.href = Redirect.to('search', {
|
|
boardID: post.board.ID,
|
|
type: type,
|
|
value: value,
|
|
isSearch: true
|
|
});
|
|
return true;
|
|
};
|
|
return {
|
|
el: el,
|
|
open: open
|
|
};
|
|
}
|
|
};
|
|
|
|
DeleteLink = {
|
|
init: function() {
|
|
var div, fileEl, fileEntry, postEl, postEntry;
|
|
if (!Conf['Menu'] || !Conf['Delete Link']) {
|
|
return;
|
|
}
|
|
div = $.el('div', {
|
|
className: 'delete-link',
|
|
textContent: 'Delete'
|
|
});
|
|
postEl = $.el('a', {
|
|
className: 'delete-post',
|
|
href: 'javascript:;'
|
|
});
|
|
fileEl = $.el('a', {
|
|
className: 'delete-file',
|
|
href: 'javascript:;'
|
|
});
|
|
postEntry = {
|
|
el: postEl,
|
|
open: function() {
|
|
postEl.textContent = 'Post';
|
|
$.on(postEl, 'click', DeleteLink["delete"]);
|
|
return true;
|
|
}
|
|
};
|
|
fileEntry = {
|
|
el: fileEl,
|
|
open: function(_arg) {
|
|
var file;
|
|
file = _arg.file;
|
|
if (!file || file.isDead) {
|
|
return false;
|
|
}
|
|
fileEl.textContent = 'File';
|
|
$.on(fileEl, 'click', DeleteLink["delete"]);
|
|
return true;
|
|
}
|
|
};
|
|
return $.event('AddMenuEntry', {
|
|
type: 'post',
|
|
el: div,
|
|
order: 40,
|
|
open: function(post) {
|
|
var node;
|
|
if (post.isDead) {
|
|
return false;
|
|
}
|
|
DeleteLink.post = post;
|
|
node = div.firstChild;
|
|
node.textContent = 'Delete';
|
|
DeleteLink.cooldown.start(post, node);
|
|
return true;
|
|
},
|
|
subEntries: [postEntry, fileEntry]
|
|
});
|
|
},
|
|
"delete": function() {
|
|
var fileOnly, form, link, post;
|
|
post = DeleteLink.post;
|
|
if (DeleteLink.cooldown.counting === post) {
|
|
return;
|
|
}
|
|
$.off(this, 'click', DeleteLink["delete"]);
|
|
fileOnly = $.hasClass(this, 'delete-file');
|
|
this.textContent = "Deleting " + (fileOnly ? 'file' : 'post') + "...";
|
|
form = {
|
|
mode: 'usrdel',
|
|
onlyimgdel: fileOnly,
|
|
pwd: QR.persona.getPassword()
|
|
};
|
|
form[post.ID] = 'delete';
|
|
link = this;
|
|
return $.ajax($.id('delform').action.replace("/" + g.BOARD + "/", "/" + post.board + "/"), {
|
|
responseType: 'document',
|
|
withCredentials: true,
|
|
onload: function() {
|
|
return DeleteLink.load(link, post, fileOnly, this.response);
|
|
},
|
|
onerror: function() {
|
|
return DeleteLink.error(link);
|
|
}
|
|
}, {
|
|
form: $.formData(form)
|
|
});
|
|
},
|
|
load: function(link, post, fileOnly, resDoc) {
|
|
var msg, s;
|
|
if (resDoc.title === '4chan - Banned') {
|
|
s = 'Banned!';
|
|
} else if (msg = resDoc.getElementById('errmsg')) {
|
|
s = msg.textContent;
|
|
$.on(link, 'click', DeleteLink["delete"]);
|
|
} else {
|
|
if (resDoc.title === 'Updating index...') {
|
|
(post.origin || post).kill(fileOnly);
|
|
}
|
|
s = 'Deleted';
|
|
}
|
|
return link.textContent = s;
|
|
},
|
|
error: function(link) {
|
|
link.textContent = 'Connection error, please retry.';
|
|
return $.on(link, 'click', DeleteLink["delete"]);
|
|
},
|
|
cooldown: {
|
|
start: function(post, node) {
|
|
var length, seconds;
|
|
if (!QR.db.get({
|
|
boardID: post.board.ID,
|
|
threadID: post.thread.ID,
|
|
postID: post.ID
|
|
})) {
|
|
delete DeleteLink.cooldown.counting;
|
|
return;
|
|
}
|
|
DeleteLink.cooldown.counting = post;
|
|
length = 60;
|
|
seconds = Math.ceil((length * $.SECOND - (Date.now() - post.info.date)) / $.SECOND);
|
|
return DeleteLink.cooldown.count(post, seconds, length, node);
|
|
},
|
|
count: function(post, seconds, length, node) {
|
|
if (DeleteLink.cooldown.counting !== post) {
|
|
return;
|
|
}
|
|
if (!((0 <= seconds && seconds <= length))) {
|
|
if (DeleteLink.cooldown.counting === post) {
|
|
node.textContent = 'Delete';
|
|
delete DeleteLink.cooldown.counting;
|
|
}
|
|
return;
|
|
}
|
|
setTimeout(DeleteLink.cooldown.count, 1000, post, seconds - 1, length, node);
|
|
return node.textContent = "Delete (" + seconds + ")";
|
|
}
|
|
}
|
|
};
|
|
|
|
DownloadLink = {
|
|
init: function() {
|
|
var a;
|
|
if (!Conf['Menu'] || !Conf['Download Link']) {
|
|
return;
|
|
}
|
|
a = $.el('a', {
|
|
className: 'download-link',
|
|
textContent: 'Download file'
|
|
});
|
|
return $.event('AddMenuEntry', {
|
|
type: 'post',
|
|
el: a,
|
|
order: 100,
|
|
open: function(_arg) {
|
|
var file;
|
|
file = _arg.file;
|
|
if (!file) {
|
|
return false;
|
|
}
|
|
a.href = file.URL;
|
|
a.download = file.name;
|
|
return true;
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
Labels = {
|
|
init: function() {
|
|
if (!Conf['Menu']) {
|
|
return;
|
|
}
|
|
return $.event('AddMenuEntry', {
|
|
type: 'post',
|
|
el: $.el('div', {
|
|
textContent: 'Labels'
|
|
}),
|
|
order: 60,
|
|
open: function(post, addSubEntry) {
|
|
var label, labels, _i, _len;
|
|
labels = (post.origin || post).labels;
|
|
if (!labels.length) {
|
|
return false;
|
|
}
|
|
this.subEntries.length = 0;
|
|
for (_i = 0, _len = labels.length; _i < _len; _i++) {
|
|
label = labels[_i];
|
|
addSubEntry({
|
|
el: $.el('div', {
|
|
textContent: label
|
|
})
|
|
});
|
|
}
|
|
return true;
|
|
},
|
|
subEntries: []
|
|
});
|
|
}
|
|
};
|
|
|
|
Menu = {
|
|
init: function() {
|
|
var a;
|
|
if (!Conf['Menu']) {
|
|
return;
|
|
}
|
|
a = $.el('a', {
|
|
className: 'menu-button',
|
|
innerHTML: '<i class="fa fa-bars"></i>',
|
|
href: 'javascript:;'
|
|
});
|
|
this.menu = new UI.Menu('post');
|
|
Post.callbacks.push({
|
|
name: 'Menu',
|
|
cb: this.node
|
|
});
|
|
return CatalogThread.callbacks.push({
|
|
name: 'Menu',
|
|
cb: this.catalogNode
|
|
});
|
|
},
|
|
node: function() {
|
|
if (this.isClone) {
|
|
$.on($('.menu-button', this.nodes.info), 'click', Menu.toggle);
|
|
return;
|
|
}
|
|
return $.add(this.nodes.info, Menu.makeButton());
|
|
},
|
|
catalogNode: function() {
|
|
return $.add(this.nodes.thumb, Menu.makeButton());
|
|
},
|
|
makeButton: (function() {
|
|
var a;
|
|
a = $.el('a', {
|
|
className: 'menu-button',
|
|
innerHTML: '<i class=fa>\uf107</i>',
|
|
href: 'javascript:;'
|
|
});
|
|
return function() {
|
|
var clone;
|
|
clone = a.cloneNode(true);
|
|
$.on(clone, 'click', Menu.toggle);
|
|
return clone;
|
|
};
|
|
})(),
|
|
toggle: function(e) {
|
|
var fullID;
|
|
fullID = $.x('ancestor::*[@data-full-i-d][1]', this).dataset.fullID;
|
|
return Menu.menu.toggle(e, this, g.posts[fullID]);
|
|
}
|
|
};
|
|
|
|
ReportLink = {
|
|
init: function() {
|
|
var a;
|
|
if (!Conf['Menu'] || !Conf['Report Link']) {
|
|
return;
|
|
}
|
|
a = $.el('a', {
|
|
className: 'report-link',
|
|
href: 'javascript:;',
|
|
textContent: 'Report this post'
|
|
});
|
|
$.on(a, 'click', ReportLink.report);
|
|
return $.event('AddMenuEntry', {
|
|
type: 'post',
|
|
el: a,
|
|
order: 10,
|
|
open: function(post) {
|
|
ReportLink.post = post;
|
|
return !post.isDead;
|
|
}
|
|
});
|
|
},
|
|
report: function() {
|
|
var id, post, set, url;
|
|
post = ReportLink.post;
|
|
url = "//sys.4chan.org/" + post.board + "/imgboard.php?mode=report&no=" + post;
|
|
id = Date.now();
|
|
set = "toolbar=0,scrollbars=0,location=0,status=1,menubar=0,resizable=1,width=685,height=200";
|
|
return window.open(url, id, set);
|
|
}
|
|
};
|
|
|
|
Favicon = {
|
|
init: function() {
|
|
var f, funreadDeadY, i, items, t;
|
|
items = {
|
|
ferongr: ['iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAFVBMVEX///9zBQC/AADpDAP/gID/q6voCwJJTwpOAAAAAXRSTlMAQObYZgAAAGJJREFUeF5Fi7ENg0AQBCfa/AFdDh2gdwPIogMK2E2+/xLslwOvdqRJhv+GQQPUCtJM7svankLrq/I+TY5e6Ueh1jyBMX7AFJi9vwfyVO4CbbO6jNYpp9GyVPbdkFhVgAQ2H0NOE5jk9DT8AAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAxUlEQVR42q1TOwrCQBB9s0FRtJI0WoqFtSLYegoP4gVSeJsUHsHSI3iFeIqRXXgwrhlXwYHHhLwPTB7B36abBCV+0pA4DUBQUNZYQptGtW3jtoKyxgoe0yrBCoyZfL/5ioQ3URZOXW9I341l3oo+NXEZiW4CEuIzvPECopED4OaZ3RNmeAm4u+a8Jr5f17VyVoL8fr8qcltzwlyyj2iqcgPOQ9ExkHAITgD75bYBe0A5S4H/P9htuWMF3QXoQpwaKeT+lnsC6JE5I6aq6fEAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAFVBMVEX///8AcH4AtswA2PJ55fKi6fIA1/FtpPADAAAAAXRSTlMAQObYZgAAAGJJREFUeF5Fi7ENg0AQBCfa/AFdDh2gdwPIogMK2E2+/xLslwOvdqRJhv+GQQPUCtJM7svankLrq/I+TY5e6Ueh1jyBMX7AFJi9vwfyVO4CbbO6jNYpp9GyVPbdkFhVgAQ2H0NOE5jk9DT8AAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAxElEQVQ4y2NgoBq4/vE/HJOsBiRQUIfA2AzBqQYqUfn00/9FLz+BaQxDCKqBmX7jExijKEDSDJPHrnnbGQhGV4RmOFwdVkNwhQMheYwQxhaIi7b9Z9A3gWAQm2BUoQOgRhgA8o7j1ozLC4LCyAZcx6kZI5qg4kLKqggDFFWxJySsUQVzlb4pwgAJaTRvokcVNgOqOv8zcHBCsL07DgNg8YsczzA5MxtUL+DMD8g0slxI/H8GQ/P/DJKyeKIRpglXZsIiBwBhP5O+VbI/JgAAAABJRU5ErkJggg==', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAFVBMVEX///8oeQBJ3ABV/wHM/7Lu/+ZU/gAqUP3dAAAAAXRSTlMAQObYZgAAAGJJREFUeF5Fi7ENg0AQBCfa/AFdDh2gdwPIogMK2E2+/xLslwOvdqRJhv+GQQPUCtJM7svankLrq/I+TY5e6Ueh1jyBMX7AFJi9vwfyVO4CbbO6jNYpp9GyVPbdkFhVgAQ2H0NOE5jk9DT8AAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAx0lEQVQ4y2NgoBYI+cfwH4ZJVgMS0KhEYGyG4FQDkzjzf9P/d/+fgWl0QwiqgSkI/c8IxsgKkDXD5LFq9rwDweiK0A2HqcNqCK5wICSPEcLYAtH+AMN/IXMIBrEJRie6OEgjDAC5x3FqxuUFNiEUA67j1IweTTBxBQ1puAG86jgSEraogskJWSBcwCGF5k30qMJmgMFEhv/MXBAs5oLDAFj8IsczTE7UEeECbhU8+QGZRpaTi2b4L2zF8J9TGk80wjThykzY5AAW/2O1C2mIbgAAAABJRU5ErkJggg=='],
|
|
'xat-': ['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'],
|
|
Mayhem: ['iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABFklEQVR4AZ2R4WqEMBCEFy1yiJQQ14gcIhIuFBFR+qPQ93+v66QMksrlTwMfkZ2ZZbMKTgVqYIDl3YAbeCM31lJP/Zul4MAEPJjBQGNDLGsz8PQ6aqLAP5PTdd1WlmU09mSKtdTDRgrkzspJPKq6RxMahfj9yhOzQEZwZAwfzrk1ox3MXibIN8hO4MAjeV72CemJGWblnRsOYOdoGw0jebB20BPAwKzUQPlrFhrXFw1Wagu9yuzZwINzVAZCURRL+gRr7Wd8Vtqg4Th/lsUmewyk9WQ/A7NiwJz5VV/GmO+MNjMrFvh/NPDMigHTaeJN09a27ZHRJmalBg54CgfvAGYSLpoHjlmpuAwFdzDy7oGS/qIpM9UPFGg1b1kUlssAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABR0lEQVR4AYWSQWq0QBCFCw0SRIK0PQ4hiIhEZBhEySLyewUPEMgqR/JIXiDhzz7kKKYePIZajEzDRxfV9dWU3SO6IiVWUsVxT5R75Y4gTmwNnUh4kCulUiuV8sjChDjmKtaUcHgmHsnNrMPh0IVhiMIjKZGzNXDoyhMzF7C89z2KtFGD+FoNXEUKZdgpaPM8P++cDXTtBDca7EyQK8+bXTufYBccuvLAG26UnqN1LCgI4g/lm7zTgSux4vk0J8rnKw3+m1//pBPbBrVyGZVNmiAITviEtm3t+D+2QcJx7GUxlN4594K4ZY75Xzh0JVWqnad6TdP0H+LRNBjHcYNDV5xS32qwaC4my7Lwn6guu5QoomgbdFmWDYhnM8E8zxscuhLzPWtKA/dGqUizrityX9M0YX+DQ1ciXobnP6vgfmTOM7Znnk70B58pPaEvx+epAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA/ElEQVR4AZ3RUWqEMBSF4ftQZAhSREQJIiIXpQwi+tSldkFdWPsLhyEE0ocKH2Fyzg1mNJ4KAQ1arTUeeJMH6qwTUJmCHjMcC6KKtbSIylzdXpl18J/k4fdTpUFmPLOOa9bGe+P4+n5RYYfLXuiMsAlXofBxK2QXpvwN/jqg+AY91vR+pStk+apZe0fEhhMXDhUmWXEoO9WNmrWAzvRPq7jnB2jvUGfWTEgPcJzZFTbZk/0Tnh5QI+af6lVGvq/Do2atwVL4VJ+3QrZo1lr4Pw5wzVqDWaV7SUvHrZDNmrWAHq7g0rphkS3LXDMBVqFGhxGT1gGdDFnWaab6BRmXRvbxDmYiAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABQElEQVR4AY2SQUrEQBBFS9CMNFEkhAQdYmiCIUgcZlYGc4VsBcGVF/AuWXme4F7RtXiVWF9+Y9MYtOHRTdX/NZWaEj2RYpQTJeEdK4fKPuA7DjSGXiQkU0qlUqxySmFMEsYsNSU8zEmK4OwdEbmkKCclYoGmolfWCGyenh1O0EJE2gXNWpFC2S0IGrCQ29EbdPCPAmEHmXIxByf8hDAPD71yzAnXypatbSgoAN8Pyju5h4deMUrqJk1z+0uBN+/XX+gxfoFK2QafUJO2aRq//Q+/QIx2wr+Kwq0rusrP/QKf9MTCtbQLf9U1wNvYnz3qug45S68kSvVXgbPbx3nvYPXNOI7cRPWySukK+DcGCvA+urqZ3RmGAbmSXjFK5rpwW8nhWVJP04TYa9/3uO/goVciDiPlZhW8c8ZAHuRSeqIv32FK/GYGL8YAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA/ElEQVR4AZ3RUWqEMBSF4ftQZAihDCKKiAQJShERQx+6o662e2p/4TCEQF468BEm95yLovFr4PBEq9PjgTd5wBcZp6559AiIWDAq6KXV3aJMUMfDOsTf7Mf/XaFBAvYiE9W16b74/vl8UeBAlKOSmWAzUiXwcavMkrrFE9QXVJ+gx5q9XvUVivmqrr1jxIYLCacCs6y6S8psGNU1hw4Bu4JHuUB3pzJBHZcviLiKV9jkyO4vxHyBx1h+qlcY5b2Wj+raE0vlU33dKrNFXWsR/7EgqmtPBIXuIw+dt8osqGsOPaIGSeeGRbZiFtVxsAYeHSbMOgd0MhSzTp3mD4RaQX4aW3NMAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABP0lEQVR4AYWS0UqFQBCGhziImNRBRImDmUgiIaF0kWSP4AMEXXXTE/QiPpL3UdR19Crb/PAvLEtyFj5mmfn/cdxd0RUokbJXEsZYCZUd4D72NBG8wkKmlEqtVMoFhTFJmKuoKelBTVIkjbNE5IainJTIeZqaXjkg8fp+Z7GCjiLQbWgOihTKsCFowUZtoNef4HgDf4JMuTbe8n/Br8NDr5zxhBul52i3FBQE+xflmzzTA69ESmpPmubunwZfztc/6IncBrXSe7/QkK5tW3f8H7dBjHH8q6Kwt033V6Hb4JeeWPgsq42rugfYZ92psWscRwMPvZIo9bEGD2+F2YUnBizLwpeoXnYpbQM34kAB9peP58aueZ4NPPRKxPusaRoYG6UizbquyH1O04T4RA+8EvAwUr6sgjFnDuReLaUn+ANygUa7+9SCWgAAAABJRU5ErkJggg=='],
|
|
'4chanJS': ['iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAD/AABnZ2f///8nFk05AAAAAXRSTlMAQObYZgAAAEFJREFUeNqNjgEKACAMAjvX/98cAkkxgmSgO8Bt/Ai4ApJ6KKhzF3OiEMDASrGB/QWgPEHsUpN+Ng9xAETMYhDrWmeHAMcmvycWAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAD/AAD///9nZ2f77Y6hAAAAAXRSTlMAQObYZgAAAEBJREFUeF6NjQEKACAMAnfW/98cAxFiBIngOsTqR8B1IGkeG9p5i7XabgAGZNigXgA8aoCUxvzWAIcBItGiSEwdccYA3BuRAWkAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAAul8NnZ2f////82iC9AAAAAXRSTlMAQObYZgAAAEFJREFUeNqNjgEKACAMAjvX/98cAkkxgmSgO8Bt/Ai4ApJ6KKhzF3OiEMDASrGB/QWgPEHsUpN+Ng9xAETMYhDrWmeHAMcmvycWAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAAul8P///9nZ2cgIeMlAAAAAXRSTlMAQObYZgAAAEBJREFUeF6NjQEKACAMAnfW/98cAxFiBIngOsTqR8B1IGkeG9p5i7XabgAGZNigXgA8aoCUxvzWAIcBItGiSEwdccYA3BuRAWkAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAElBMVEUBAAAAAABmzDNlyjJnZ2f///+6o7dfAAAAAXRSTlMAQObYZgAAAERJREFUeF6NjkEKADEIA51o///lJZfQxUsHITogWi8AvwZJuxmYa25xDooBLEwOWFTYAsYVhdorLZt9Ng9xCUTCUCQ2H3F4ANrZ2WNiAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAElBMVEUBAAAAAABmzDP///9lyjJnZ2cIHys9AAAAAXRSTlMAQObYZgAAAENJREFUeF6NjUEKwEAMAjNm9/9fLkEslFwqgjoEUn8EfAqSdrkwzj6ieyyTkQEVGWRvANfO1iEX620AjgBEwqR4Y+sBeGAA6d+vQ4IAAAAASUVORK5CYII='],
|
|
Original: ['iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEX/////AAD///8AAABBZmS3AAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAhElEQVR42q1RwQnAMAjMu5M4guAKXa4j5dUROo5tipSDcrFChUONd0di2m/hEGVOHDyIPufgwAFASDkpoSzmBrkJ2UMyR9LsJ3rvrqo3Rt1YMIMhhNnOxLMnoMFBxHyJAr2IOBFzA8U+6pLBdmEJTA0aMVjpDd6Loks0s5HZNwYx8tfZCZ0kll7ORffZAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEX///8ul8P///8AAACaqgkzAAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAALVBMVEUAAAAAAAAAAAAAAAABBQcHFx4KISoNLToaVW4oKCgul8M4ODg7OzvBwcH///8uS/CdAAAAA3RSTlMAx9dmesIgAAAAV0lEQVR42m2NWw6AIBAD1eILZO5/XI0UAgm7H9tOsu0yGWAQSOoFijHOxOANGqm/LczpOaXs4gISrPZ+gc2+hO5w2xdwgOjBFUIF+sEJrhUl9JFr+badFwR+BfqlmGUJAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEX///9mzDP///8AAACT0n1lAAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAALVBMVEUAAAAAAAAAAAAAAAAECAIQIAgWLAsePA8oKCg4ODg6dB07OztmzDPBwcH///+rsf3XAAAAA3RSTlMAx9dmesIgAAAAV0lEQVR42m2NWw6AIBAD1eIDhbn/cTVSCCTsfmw7ybbLZIBBIKkXKKU0E4M3aKT+tjCn5xiziwuIsNr7BTb7ErrDZV/AAaIHdwgV6AcnuFaU0Eeu5dt2XiUyBjCQ2bIrAAAAAElFTkSuQmCC'],
|
|
'Metro': ['iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAC/AABrZQDiAAAAAXRSTlMAQObYZgAAABJJREFUCB1jZGBgrMNAQEEc4gCSfAX5bRw/NQAAAABJRU5ErkJggg==', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAAAAAAAAAAHAAAdAAApAAAsAAA4AABsAACQAAC/AAD///9SVhtjAAAAA3RSTlMAPse+s4iwAAAAM0lEQVQIW2NggAGuVasWgDBpDDAQUoSaob0Jao73lgVojOitUEazBZRRvR3KmJa5AO4KAGBtLuMAuhIIAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAAA1/GhpCidAAAAAXRSTlMAQObYZgAAABJJREFUCB1jZGBgrMNAQEEc4gCSfAX5bRw/NQAAAABJRU5ErkJggg==', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAAAAAAAAAAACAkAISUALzQAMTcAQEcAeokAorYA1/H///8BrzTFAAAAA3RSTlMAPse+s4iwAAAAM0lEQVQIW2NggAGuVasWgDBpDDAQUoSaob0Jao73lgVojOitUEazBZRRvR3KmJa5AO4KAGBtLuMAuhIIAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAABV/wErM5hwAAAAAXRSTlMAQObYZgAAABJJREFUCB1jZGBgrMNAQEEc4gCSfAX5bRw/NQAAAABJRU5ErkJggg==', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAAAAAAAAAADCgANKAASOAATOwAZTAAwkQBAwQBV/wH////+Fmy4AAAAA3RSTlMAPse+s4iwAAAAM0lEQVQIW2NggAGuVasWgDBpDDAQUoSaob0Jao73lgVojOitUEazBZRRvR3KmJa5AO4KAGBtLuMAuhIIAAAAAElFTkSuQmCC']
|
|
}[Conf['favicon']];
|
|
f = Favicon;
|
|
t = 'data:image/png;base64,';
|
|
i = 0;
|
|
while (items[i]) {
|
|
items[i] = t + items[i++];
|
|
}
|
|
f.unreadDead = items[0], funreadDeadY = items[1], f.unreadSFW = items[2], f.unreadSFWY = items[3], f.unreadNSFW = items[4], f.unreadNSFWY = items[5];
|
|
return f.update();
|
|
},
|
|
update: function() {
|
|
if (this.SFW) {
|
|
this.unread = this.unreadSFW;
|
|
return this.unreadY = this.unreadSFWY;
|
|
} else {
|
|
this.unread = this.unreadNSFW;
|
|
return this.unreadY = this.unreadNSFWY;
|
|
}
|
|
},
|
|
dead: 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAP8AAP///////yH5BAEKAAIALAAAAAAQABAAAAIvlI+pq+D9DAgUoFkPDlbs7lFZKIJOJJ3MyraoB14jFpOcVMpzrnF3OKlZYsMWowAAOw==',
|
|
logo: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACABAMAAAAxEHz4AAAAElBMVEX///8EZgR8ulSk0oT///8EAgQ1A88mAAAAAXRSTlMAQObYZgAAAJtJREFUeF7t17ENgDAMBdGswAqswAqskP1XgUhG37JQQv25a1I4eR1CbopoS3295wIASD1SBZnecwEApO9RRurjPdLcAQDQY9UnBSDEBQAIRA3gfGkA9cfiAwDUHqCnHqDl/AGA0v8AAL4FgO0uAxUcc2cAQEtFjwQoLSMuAMBqsVwtpp4AwNDngPIGAPI5mVsCAELSuZybAQBEF/bX4X+FReD/AAAAAElFTkSuQmCC'
|
|
};
|
|
|
|
ThreadExcerpt = {
|
|
init: function() {
|
|
if (g.VIEW !== 'thread' || !Conf['Thread Excerpt']) {
|
|
return;
|
|
}
|
|
return Thread.callbacks.push({
|
|
name: 'Thread Excerpt',
|
|
cb: this.node
|
|
});
|
|
},
|
|
node: function() {
|
|
return d.title = Get.threadExcerpt(this);
|
|
},
|
|
disconnect: function() {
|
|
if (g.VIEW !== 'thread' || !Conf['Thread Excerpt']) {
|
|
return;
|
|
}
|
|
return Thread.callbacks.disconnect('Thread Excerpt');
|
|
}
|
|
};
|
|
|
|
ThreadStats = {
|
|
init: function() {
|
|
var sc;
|
|
if (g.VIEW !== 'thread' || !Conf['Thread Stats']) {
|
|
return;
|
|
}
|
|
if (Conf['Updater and Stats in Header']) {
|
|
this.dialog = sc = $.el('span', {
|
|
innerHTML: "[<span id=post-count>0</span> / <span id=file-count>0</span>" + (Conf["Page Count in Stats"] ? " / <span id=page-count>0</span>" : "") + "]",
|
|
id: 'thread-stats',
|
|
title: 'Post Count / File Count' + (Conf["Page Count in Stats"] ? " / Page Count" : "")
|
|
});
|
|
$.ready(function() {
|
|
return Header.addShortcut(sc);
|
|
});
|
|
} else {
|
|
this.dialog = sc = UI.dialog('thread-stats', 'bottom: 0px; right: 0px;', "<div class=move title='Post Count / File Count" + (Conf["Page Count in Stats"] ? " / Page Count" : "") + "'><span id=post-count>0</span> / <span id=file-count>0</span>" + (Conf["Page Count in Stats"] ? " / <span id=page-count>0</span>" : "") + "</div>");
|
|
$.ready((function(_this) {
|
|
return function() {
|
|
return $.add(d.body, sc);
|
|
};
|
|
})(this));
|
|
}
|
|
this.postCountEl = $('#post-count', sc);
|
|
this.fileCountEl = $('#file-count', sc);
|
|
this.pageCountEl = $('#page-count', sc);
|
|
return Thread.callbacks.push({
|
|
name: 'Thread Stats',
|
|
cb: this.node
|
|
});
|
|
},
|
|
node: function() {
|
|
var fileCount, postCount;
|
|
postCount = 0;
|
|
fileCount = 0;
|
|
this.posts.forEach(function(post) {
|
|
postCount++;
|
|
if (post.file) {
|
|
return fileCount++;
|
|
}
|
|
});
|
|
ThreadStats.thread = this;
|
|
ThreadStats.fetchPage();
|
|
ThreadStats.update(postCount, fileCount);
|
|
return $.on(d, 'ThreadUpdate', ThreadStats.onUpdate);
|
|
},
|
|
disconnect: function() {
|
|
if (g.VIEW !== 'thread' || !Conf['Thread Stats']) {
|
|
return;
|
|
}
|
|
if (Conf['Updater and Stats in Header']) {
|
|
Header.rmShortcut(this.dialog);
|
|
} else {
|
|
$.rm(this.dialog);
|
|
}
|
|
clearTimeout(this.timeout);
|
|
delete this.timeout;
|
|
delete this.thread;
|
|
delete this.postCountEl;
|
|
delete this.fileCountEl;
|
|
delete this.pageCountEl;
|
|
Thread.callbacks.disconnect('Thread Stats');
|
|
return $.off(d, 'ThreadUpdate', ThreadStats.onUpdate);
|
|
},
|
|
onUpdate: function(e) {
|
|
var fileCount, postCount, _ref;
|
|
if (e.detail[404]) {
|
|
return;
|
|
}
|
|
_ref = e.detail, postCount = _ref.postCount, fileCount = _ref.fileCount;
|
|
return ThreadStats.update(postCount, fileCount);
|
|
},
|
|
update: function(postCount, fileCount) {
|
|
var fileCountEl, postCountEl, thread;
|
|
thread = ThreadStats.thread, postCountEl = ThreadStats.postCountEl, fileCountEl = ThreadStats.fileCountEl;
|
|
postCountEl.textContent = postCount;
|
|
fileCountEl.textContent = fileCount;
|
|
(thread.postLimit && !thread.isSticky ? $.addClass : $.rmClass)(postCountEl, 'warning');
|
|
return (thread.fileLimit && !thread.isSticky ? $.addClass : $.rmClass)(fileCountEl, 'warning');
|
|
},
|
|
fetchPage: function() {
|
|
if (!Conf["Page Count in Stats"]) {
|
|
return;
|
|
}
|
|
if (ThreadStats.thread.isDead) {
|
|
ThreadStats.pageCountEl.textContent = 'Dead';
|
|
$.addClass(ThreadStats.pageCountEl, 'warning');
|
|
return;
|
|
}
|
|
ThreadStats.timeout = setTimeout(ThreadStats.fetchPage, 2 * $.MINUTE);
|
|
return $.ajax("//a.4cdn.org/" + ThreadStats.thread.board + "/threads.json", {
|
|
onload: ThreadStats.onThreadsLoad
|
|
}, {
|
|
whenModified: true
|
|
});
|
|
},
|
|
onThreadsLoad: function() {
|
|
var page, thread, _i, _j, _len, _len1, _ref, _ref1;
|
|
if (!(Conf["Page Count in Stats"] && this.status === 200)) {
|
|
return;
|
|
}
|
|
_ref = this.response;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
page = _ref[_i];
|
|
_ref1 = page.threads;
|
|
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
|
thread = _ref1[_j];
|
|
if (!(thread.no === ThreadStats.thread.ID)) {
|
|
continue;
|
|
}
|
|
ThreadStats.pageCountEl.textContent = page.page;
|
|
(page.page === this.response.length - 1 ? $.addClass : $.rmClass)(ThreadStats.pageCountEl, 'warning');
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
ThreadUpdater = {
|
|
init: function() {
|
|
var checked, conf, el, input, name, sc, subEntries, _ref;
|
|
if (g.VIEW !== 'thread' || !Conf['Thread Updater']) {
|
|
return;
|
|
}
|
|
if (Conf['Updater and Stats in Header']) {
|
|
this.dialog = sc = $.el('span', {
|
|
innerHTML: "[<span id=update-status></span><span id=update-timer title='Update now'></span>]\u00A0",
|
|
id: 'updater'
|
|
});
|
|
$.ready(function() {
|
|
return Header.addShortcut(sc);
|
|
});
|
|
} else {
|
|
this.dialog = sc = UI.dialog('updater', 'bottom: 0px; left: 0px;', "<div class=move><span id=update-status></span><span id=update-timer title='Update now'></span></div>");
|
|
$.addClass(doc, 'float');
|
|
$.ready(function() {
|
|
$.addClass(doc, 'float');
|
|
return $.add(d.body, sc);
|
|
});
|
|
}
|
|
this.checkPostCount = 0;
|
|
this.timer = $('#update-timer', sc);
|
|
this.status = $('#update-status', sc);
|
|
this.isUpdating = Conf['Auto Update'];
|
|
$.on(this.timer, 'click', this.update);
|
|
$.on(this.status, 'click', this.update);
|
|
subEntries = [];
|
|
_ref = Config.updater.checkbox;
|
|
for (name in _ref) {
|
|
conf = _ref[name];
|
|
checked = Conf[name] ? 'checked' : '';
|
|
el = $.el('label', {
|
|
title: "" + conf[1],
|
|
innerHTML: "<input name='" + name + "' type=checkbox " + checked + "> " + name
|
|
});
|
|
input = el.firstElementChild;
|
|
$.on(input, 'change', $.cb.checked);
|
|
if (input.name === 'Scroll BG') {
|
|
$.on(input, 'change', this.cb.scrollBG);
|
|
this.cb.scrollBG();
|
|
} else if (input.name === 'Auto Update') {
|
|
$.on(input, 'change', this.cb.update);
|
|
}
|
|
subEntries.push({
|
|
el: el
|
|
});
|
|
}
|
|
this.settings = $.el('span', {
|
|
innerHTML: '<a href=javascript:;>Interval</a>'
|
|
});
|
|
$.on(this.settings, 'click', this.intervalShortcut);
|
|
subEntries.push({
|
|
el: this.settings
|
|
});
|
|
$.event('AddMenuEntry', this.entry = {
|
|
type: 'header',
|
|
el: $.el('span', {
|
|
textContent: 'Updater'
|
|
}),
|
|
order: 110,
|
|
subEntries: subEntries
|
|
});
|
|
return Thread.callbacks.push({
|
|
name: 'Thread Updater',
|
|
cb: this.node
|
|
});
|
|
},
|
|
disconnect: function() {
|
|
var el, entry, input, name, _i, _j, _len, _len1, _ref, _ref1;
|
|
if (g.VIEW !== 'thread' || !Conf['Thread Updater']) {
|
|
return;
|
|
}
|
|
$.off(this.timer, 'click', this.update);
|
|
$.off(this.status, 'click', this.update);
|
|
if (this.timeoutID) {
|
|
clearTimeout(this.timeoutID);
|
|
}
|
|
_ref = this.entry.subEntries;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
entry = _ref[_i];
|
|
el = entry.el;
|
|
input = el.firstElementChild;
|
|
$.off(input, 'change', $.cb.checked);
|
|
$.off(input, 'change', this.cb.scrollBG);
|
|
$.off(input, 'change', this.cb.update);
|
|
}
|
|
$.off(this.settings, 'click', this.intervalShortcut);
|
|
$.off(window, 'online offline', this.cb.online);
|
|
$.off(d, 'QRPostSuccessful', this.cb.checkpost);
|
|
$.off(d, 'visibilitychange', this.cb.visibility);
|
|
this.set('timer', null);
|
|
this.set('status', 'Offline');
|
|
$.event('rmMenuEntry', this.entry);
|
|
if (Conf['Updater and Stats in Header']) {
|
|
Header.rmShortcut(this.dialog);
|
|
} else {
|
|
$.rmClass(doc, 'float');
|
|
$.rm(this.dialog);
|
|
}
|
|
_ref1 = ['checkPostCount', 'timer', 'status', 'isUpdating', 'entry', 'dialog', 'thread', 'root', 'lastPost', 'outdateCount', 'online', 'seconds', 'timeoutID'];
|
|
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
|
name = _ref1[_j];
|
|
delete this[name];
|
|
}
|
|
return Thread.callbacks.disconnect('Thread Updater');
|
|
},
|
|
node: function() {
|
|
ThreadUpdater.thread = this;
|
|
ThreadUpdater.root = this.OP.nodes.root.parentNode;
|
|
ThreadUpdater.lastPost = +this.posts.keys[this.posts.keys.length - 1];
|
|
ThreadUpdater.cb.interval.call($.el('input', {
|
|
value: Conf['Interval'],
|
|
name: 'Interval'
|
|
}));
|
|
$.on(window, 'online offline', ThreadUpdater.cb.online);
|
|
$.on(d, 'QRPostSuccessful', ThreadUpdater.cb.checkpost);
|
|
$.on(d, 'visibilitychange', ThreadUpdater.cb.visibility);
|
|
ThreadUpdater.cb.online();
|
|
return Rice.nodes(ThreadUpdater.dialog);
|
|
},
|
|
|
|
/*
|
|
http://freesound.org/people/pierrecartoons1979/sounds/90112/
|
|
cc-by-nc-3.0
|
|
*/
|
|
beep: 'data:audio/wav;base64,UklGRjQDAABXQVZFZm10IBAAAAABAAEAgD4AAIA+AAABAAgAc21wbDwAAABBAAADAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkYXRhzAIAAGMms8em0tleMV4zIpLVo8nhfSlcPR102Ki+5JspVEkdVtKzs+K1NEhUIT7DwKrcy0g6WygsrM2k1NpiLl0zIY/WpMrjgCdbPhxw2Kq+5Z4qUkkdU9K1s+K5NkVTITzBwqnczko3WikrqM+l1NxlLF0zIIvXpsnjgydZPhxs2ay95aIrUEkdUdC3suK8N0NUIjq+xKrcz002WioppdGm091pK1w0IIjYp8jkhydXPxxq2K295aUrTkoeTs65suK+OUFUIzi7xqrb0VA0WSoootKm0t5tKlo1H4TYqMfkiydWQBxm16+85actTEseS8y7seHAPD9TIza5yKra01QyWSson9On0d5wKVk2H4DYqcfkjidUQB1j1rG75KsvSkseScu8seDCPz1TJDW2yara1FYxWSwnm9Sn0N9zKVg2H33ZqsXkkihSQR1g1bK65K0wSEsfR8i+seDEQTxUJTOzy6rY1VowWC0mmNWoz993KVc3H3rYq8TklSlRQh1d1LS647AyR0wgRMbAsN/GRDpTJTKwzKrX1l4vVy4lldWpzt97KVY4IXbUr8LZljVPRCxhw7W3z6ZISkw1VK+4sMWvXEhSPk6buay9sm5JVkZNiLWqtrJ+TldNTnquqbCwilZXU1BwpKirrpNgWFhTaZmnpquZbFlbVmWOpaOonHZcXlljhaGhpZ1+YWBdYn2cn6GdhmdhYGN3lp2enIttY2Jjco+bnJuOdGZlZXCImJqakHpoZ2Zug5WYmZJ/bGlobX6RlpeSg3BqaW16jZSVkoZ0bGtteImSk5KIeG5tbnaFkJKRinxxbm91gY2QkIt/c3BwdH6Kj4+LgnZxcXR8iI2OjIR5c3J0e4WLjYuFe3VzdHmCioyLhn52dHR5gIiKioeAeHV1eH+GiYqHgXp2dnh9hIiJh4J8eHd4fIKHiIeDfXl4eHyBhoeHhH96eHmA',
|
|
cb: {
|
|
online: function() {
|
|
if (ThreadUpdater.online = navigator.onLine) {
|
|
ThreadUpdater.outdateCount = 0;
|
|
ThreadUpdater.setInterval();
|
|
ThreadUpdater.set('status', null, null);
|
|
return;
|
|
}
|
|
ThreadUpdater.set('timer', null);
|
|
return ThreadUpdater.set('status', 'Offline', 'warning');
|
|
},
|
|
post: function(e) {
|
|
if (!(ThreadUpdater.isUpdating && e.detail.threadID === ThreadUpdater.thread.ID)) {
|
|
return;
|
|
}
|
|
ThreadUpdater.outdateCount = 0;
|
|
if (ThreadUpdater.seconds > 2) {
|
|
return setTimeout(ThreadUpdater.update, 1000);
|
|
}
|
|
},
|
|
checkpost: function(e) {
|
|
if (!ThreadUpdater.checkPostCount) {
|
|
if (e.detail.threadID !== ThreadUpdater.thread.ID) {
|
|
return;
|
|
}
|
|
ThreadUpdater.seconds = 0;
|
|
ThreadUpdater.outdateCount = 0;
|
|
ThreadUpdater.set('timer', '...');
|
|
}
|
|
if (!(g.DEAD || ThreadUpdater.foundPost || ThreadUpdater.checkPostCount >= 5)) {
|
|
return setTimeout(ThreadUpdater.update, ++ThreadUpdater.checkPostCount * $.SECOND);
|
|
}
|
|
ThreadUpdater.setInterval();
|
|
ThreadUpdater.checkPostCount = 0;
|
|
delete ThreadUpdater.foundPost;
|
|
return delete ThreadUpdater.postID;
|
|
},
|
|
visibility: function() {
|
|
if (d.hidden) {
|
|
return;
|
|
}
|
|
ThreadUpdater.outdateCount = 0;
|
|
if (ThreadUpdater.seconds > ThreadUpdater.interval) {
|
|
return ThreadUpdater.setInterval();
|
|
}
|
|
},
|
|
scrollBG: function() {
|
|
return ThreadUpdater.scrollBG = Conf['Scroll BG'] ? function() {
|
|
return true;
|
|
} : function() {
|
|
return !d.hidden;
|
|
};
|
|
},
|
|
interval: function(e) {
|
|
var val;
|
|
val = parseInt(this.value, 10);
|
|
if (val < 1) {
|
|
val = 1;
|
|
}
|
|
ThreadUpdater.interval = this.value = val;
|
|
if (e) {
|
|
return $.cb.value.call(this);
|
|
}
|
|
},
|
|
load: function(e) {
|
|
var klass, req, text, _ref;
|
|
req = ThreadUpdater.req;
|
|
switch (req.status) {
|
|
case 200:
|
|
g.DEAD = false;
|
|
ThreadUpdater.parse(req.response.posts);
|
|
ThreadUpdater.setInterval();
|
|
break;
|
|
case 404:
|
|
g.DEAD = true;
|
|
ThreadUpdater.set('timer', null);
|
|
ThreadUpdater.set('status', '404', 'warning');
|
|
clearTimeout(ThreadUpdater.timeoutID);
|
|
ThreadUpdater.thread.kill();
|
|
$.event('ThreadUpdate', {
|
|
404: true,
|
|
thread: ThreadUpdater.thread
|
|
});
|
|
break;
|
|
default:
|
|
ThreadUpdater.outdateCount++;
|
|
ThreadUpdater.setInterval();
|
|
_ref = req.status === 304 ? [null, null] : ["" + req.statusText + " (" + req.status + ")", 'warning'], text = _ref[0], klass = _ref[1];
|
|
ThreadUpdater.set('status', text, klass);
|
|
}
|
|
if (ThreadUpdater.postID) {
|
|
return ThreadUpdater.cb.checkpost();
|
|
}
|
|
}
|
|
},
|
|
setInterval: function() {
|
|
var cur, i, j, limit;
|
|
i = ThreadUpdater.interval + 1;
|
|
if (Conf['Optional Increase']) {
|
|
cur = ThreadUpdater.outdateCount || 1;
|
|
limit = d.hidden ? 7 : 10;
|
|
j = cur <= limit ? cur : limit;
|
|
cur = (Math.floor(i * 0.1) || 1) * j * j;
|
|
ThreadUpdater.seconds = cur > i ? cur <= 300 ? cur : 300 : i;
|
|
} else {
|
|
ThreadUpdater.seconds = i;
|
|
}
|
|
ThreadUpdater.set('timer', ThreadUpdater.seconds);
|
|
return ThreadUpdater.count(true);
|
|
},
|
|
intervalShortcut: function() {
|
|
var settings;
|
|
Settings.open('Advanced');
|
|
settings = $.id('fourchanx-settings');
|
|
return $('input[name=Interval]', settings).focus();
|
|
},
|
|
set: function(name, text, klass) {
|
|
var el, node;
|
|
el = ThreadUpdater[name];
|
|
if (node = el.firstChild) {
|
|
node.data = text;
|
|
} else {
|
|
el.textContent = text;
|
|
}
|
|
if (klass !== void 0) {
|
|
return el.className = klass;
|
|
}
|
|
},
|
|
count: function(start) {
|
|
clearTimeout(ThreadUpdater.timeoutID);
|
|
if (start && ThreadUpdater.isUpdating && navigator.onLine) {
|
|
return ThreadUpdater.timeout();
|
|
}
|
|
},
|
|
timeout: function() {
|
|
var n;
|
|
ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000);
|
|
if (!(n = --ThreadUpdater.seconds)) {
|
|
return ThreadUpdater.update();
|
|
} else if (n <= -60) {
|
|
ThreadUpdater.set('status', 'Retrying', null);
|
|
return ThreadUpdater.update();
|
|
} else if (n > 0) {
|
|
return ThreadUpdater.set('timer', n);
|
|
}
|
|
},
|
|
update: function() {
|
|
var url, _ref;
|
|
if (!navigator.onLine) {
|
|
return;
|
|
}
|
|
ThreadUpdater.count();
|
|
if (Conf['Auto Update']) {
|
|
ThreadUpdater.set('timer', '...');
|
|
} else {
|
|
ThreadUpdater.set('timer', 'Update');
|
|
}
|
|
if ((_ref = ThreadUpdater.req) != null) {
|
|
_ref.abort();
|
|
}
|
|
url = "//a.4cdn.org/" + ThreadUpdater.thread.board + "/res/" + ThreadUpdater.thread + ".json";
|
|
return ThreadUpdater.req = $.ajax(url, {
|
|
onloadend: ThreadUpdater.cb.load
|
|
}, {
|
|
whenModified: true
|
|
});
|
|
},
|
|
updateThreadStatus: function(type, status) {
|
|
var change, hasChanged;
|
|
if (!(hasChanged = ThreadUpdater.thread["is" + type] !== status)) {
|
|
return;
|
|
}
|
|
ThreadUpdater.thread.setStatus(type, status);
|
|
change = type === 'Sticky' ? status ? 'now a sticky' : 'not a sticky anymore' : status ? 'now closed' : 'not closed anymore';
|
|
return new Notice('info', "The thread is " + change + ".", 30);
|
|
},
|
|
parse: function(postObjects) {
|
|
var OP, count, deletedFiles, deletedPosts, files, index, node, num, post, postObject, posts, root, scroll, sendEvent, _i, _j, _len, _len1;
|
|
OP = postObjects[0];
|
|
Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler;
|
|
ThreadUpdater.updateThreadStatus('Sticky', !!OP.sticky);
|
|
ThreadUpdater.updateThreadStatus('Closed', !!OP.closed);
|
|
ThreadUpdater.thread.postLimit = !!OP.bumplimit;
|
|
ThreadUpdater.thread.fileLimit = !!OP.imagelimit;
|
|
posts = [];
|
|
index = [];
|
|
files = [];
|
|
count = 0;
|
|
for (_i = 0, _len = postObjects.length; _i < _len; _i++) {
|
|
postObject = postObjects[_i];
|
|
num = postObject.no;
|
|
index.push(num);
|
|
if (postObject.fsize) {
|
|
files.push(num);
|
|
}
|
|
if (num <= ThreadUpdater.lastPost) {
|
|
continue;
|
|
}
|
|
count++;
|
|
node = Build.postFromObject(postObject, ThreadUpdater.thread.board.ID);
|
|
posts.push(new Post(node, ThreadUpdater.thread, ThreadUpdater.thread.board));
|
|
}
|
|
deletedPosts = [];
|
|
deletedFiles = [];
|
|
ThreadUpdater.thread.posts.forEach(function(post) {
|
|
var ID;
|
|
ID = +post.ID;
|
|
if (__indexOf.call(index, ID) < 0) {
|
|
post.kill();
|
|
deletedPosts.push(post);
|
|
} else if (post.isDead) {
|
|
post.resurrect();
|
|
} else if (post.file && !(post.file.isDead || __indexOf.call(files, ID) >= 0)) {
|
|
post.kill(true);
|
|
deletedFiles.push(post);
|
|
}
|
|
if (ThreadUpdater.postID && ThreadUpdater.postID === ID) {
|
|
return ThreadUpdater.foundPost = true;
|
|
}
|
|
});
|
|
sendEvent = function() {
|
|
return $.event('ThreadUpdate', {
|
|
404: false,
|
|
thread: ThreadUpdater.thread,
|
|
newPosts: posts,
|
|
deletedPosts: deletedPosts,
|
|
deletedFiles: deletedFiles,
|
|
postCount: OP.replies + 1,
|
|
fileCount: OP.images + (!!ThreadUpdater.thread.OP.file && !ThreadUpdater.thread.OP.file.isDead)
|
|
});
|
|
};
|
|
if (!count) {
|
|
ThreadUpdater.set('status', null, null);
|
|
ThreadUpdater.outdateCount++;
|
|
sendEvent();
|
|
return;
|
|
}
|
|
ThreadUpdater.set('status', "+" + count, 'new');
|
|
ThreadUpdater.outdateCount = 0;
|
|
if (Conf['Beep'] && d.hidden && Unread.posts && !Unread.posts.length) {
|
|
if (!ThreadUpdater.audio) {
|
|
ThreadUpdater.audio = $.el('audio', {
|
|
src: ThreadUpdater.beep
|
|
});
|
|
}
|
|
ThreadUpdater.audio.play();
|
|
}
|
|
ThreadUpdater.lastPost = posts[count - 1].ID;
|
|
Post.callbacks.execute(posts);
|
|
scroll = Conf['Auto Scroll'] && ThreadUpdater.scrollBG() && Header.getBottomOf(ThreadUpdater.root) > -75;
|
|
for (_j = 0, _len1 = posts.length; _j < _len1; _j++) {
|
|
post = posts[_j];
|
|
root = post.nodes.root;
|
|
if (post.cb) {
|
|
if (!post.cb()) {
|
|
$.add(ThreadUpdater.root, root);
|
|
}
|
|
} else {
|
|
$.add(ThreadUpdater.root, root);
|
|
}
|
|
}
|
|
sendEvent();
|
|
if (scroll) {
|
|
if (Conf['Bottom Scroll']) {
|
|
return window.scrollTo(0, d.body.clientHeight);
|
|
} else {
|
|
return Header.scrollTo(posts[0].nodes.root);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
ThreadWatcher = {
|
|
init: function() {
|
|
var now;
|
|
if (!Conf['Thread Watcher']) {
|
|
return;
|
|
}
|
|
this.db = new DataBoard('watchedThreads', this.refresh, true);
|
|
this.dialog = UI.dialog('thread-watcher', 'top: 50px; left: 0px;', "<div><span class=\"move\">Thread Watcher <span id=\"watcher-status\"></span></span><a class=\"menu-button\" href=\"javascript:;\"><i class=\"fa\">\uf107</i></a></div><div id=\"watched-threads\"></div>");
|
|
this.status = $('#watcher-status', this.dialog);
|
|
this.list = this.dialog.lastElementChild;
|
|
$.on(d, 'QRPostSuccessful', this.cb.post);
|
|
if (g.VIEW === 'thread') {
|
|
$.on(d, 'ThreadUpdate', this.cb.threadUpdate);
|
|
}
|
|
$.on(d, '4chanXInitFinished', this.ready);
|
|
switch (g.VIEW) {
|
|
case 'index':
|
|
$.on(d, 'IndexRefresh', this.cb.onIndexRefresh);
|
|
break;
|
|
case 'thread':
|
|
$.on(d, 'ThreadUpdate', this.cb.onThreadRefresh);
|
|
}
|
|
now = Date.now();
|
|
if ((this.db.data.lastChecked || 0) < now - 2 * $.HOUR) {
|
|
this.db.data.lastChecked = now;
|
|
ThreadWatcher.fetchAllStatus();
|
|
this.db.save();
|
|
}
|
|
return Thread.callbacks.push({
|
|
name: 'Thread Watcher',
|
|
cb: this.node
|
|
});
|
|
},
|
|
node: function() {
|
|
var toggler;
|
|
toggler = $.el('img', {
|
|
className: 'watch-thread-link'
|
|
});
|
|
$.on(toggler, 'click', ThreadWatcher.cb.toggle);
|
|
return $.before($('input', this.OP.nodes.post), toggler);
|
|
},
|
|
ready: function() {
|
|
var el;
|
|
$.off(d, '4chanXInitFinished', ThreadWatcher.ready);
|
|
if (!Main.isThisPageLegit()) {
|
|
return;
|
|
}
|
|
ThreadWatcher.refresh();
|
|
if (Conf['Slideout Watcher']) {
|
|
el = $.el('div', {
|
|
id: 'so-watcher',
|
|
innerHTML: '<i class=a-icon></a>'
|
|
});
|
|
Header.addShortcut(el, true);
|
|
} else {
|
|
el = d.body;
|
|
}
|
|
$.add(el, ThreadWatcher.dialog);
|
|
if (!Conf['Auto Watch']) {
|
|
return;
|
|
}
|
|
return $.get('AutoWatch', 0, function(_arg) {
|
|
var AutoWatch, thread;
|
|
AutoWatch = _arg.AutoWatch;
|
|
if (!(thread = g.BOARD.threads[AutoWatch])) {
|
|
return;
|
|
}
|
|
ThreadWatcher.add(thread);
|
|
return $["delete"]('AutoWatch');
|
|
});
|
|
},
|
|
cb: {
|
|
openAll: function() {
|
|
var a, _i, _len, _ref;
|
|
if ($.hasClass(this, 'disabled')) {
|
|
return;
|
|
}
|
|
_ref = $$('a[title]', ThreadWatcher.list);
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
a = _ref[_i];
|
|
$.open(a.href);
|
|
}
|
|
return $.event('CloseMenu');
|
|
},
|
|
checkThreads: function() {
|
|
if ($.hasClass(this, 'disabled')) {
|
|
return;
|
|
}
|
|
return ThreadWatcher.fetchAllStatus();
|
|
},
|
|
pruneDeads: function() {
|
|
var boardID, data, threadID, _i, _len, _ref, _ref1;
|
|
if ($.hasClass(this, 'disabled')) {
|
|
return;
|
|
}
|
|
_ref = ThreadWatcher.getAll();
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
_ref1 = _ref[_i], boardID = _ref1.boardID, threadID = _ref1.threadID, data = _ref1.data;
|
|
if (!data.isDead) {
|
|
continue;
|
|
}
|
|
delete ThreadWatcher.db.data.boards[boardID][threadID];
|
|
ThreadWatcher.db.deleteIfEmpty({
|
|
boardID: boardID
|
|
});
|
|
}
|
|
ThreadWatcher.db.save();
|
|
ThreadWatcher.refresh();
|
|
return $.event('CloseMenu');
|
|
},
|
|
toggle: function() {
|
|
return ThreadWatcher.toggle(Get.threadFromNode(this));
|
|
},
|
|
rm: function() {
|
|
var boardID, threadID, _ref;
|
|
_ref = this.parentNode.dataset.fullID.split('.'), boardID = _ref[0], threadID = _ref[1];
|
|
return ThreadWatcher.rm(boardID, +threadID);
|
|
},
|
|
post: function(e) {
|
|
var board, postID, threadID, _ref;
|
|
_ref = e.detail, board = _ref.board, postID = _ref.postID, threadID = _ref.threadID;
|
|
if (postID === threadID) {
|
|
if (Conf['Auto Watch']) {
|
|
return $.set('AutoWatch', threadID);
|
|
}
|
|
} else if (Conf['Auto Watch Reply']) {
|
|
return ThreadWatcher.add(board.threads[threadID]);
|
|
}
|
|
},
|
|
onIndexRefresh: function() {
|
|
var boardID, data, threadID, _ref;
|
|
boardID = g.BOARD.ID;
|
|
_ref = ThreadWatcher.db.data.boards[boardID];
|
|
for (threadID in _ref) {
|
|
data = _ref[threadID];
|
|
if (!data.isDead && !(threadID in g.BOARD.threads)) {
|
|
if (Conf['Auto Prune']) {
|
|
ThreadWatcher.db["delete"]({
|
|
boardID: boardID,
|
|
threadID: threadID
|
|
});
|
|
} else {
|
|
data.isDead = true;
|
|
ThreadWatcher.db.set({
|
|
boardID: boardID,
|
|
threadID: threadID,
|
|
val: data
|
|
});
|
|
}
|
|
}
|
|
}
|
|
return ThreadWatcher.refresh();
|
|
},
|
|
onThreadRefresh: function(e) {
|
|
var thread;
|
|
thread = e.detail.thread;
|
|
if (!(e.detail[404] && ThreadWatcher.db.get({
|
|
boardID: thread.board.ID,
|
|
threadID: thread.ID
|
|
}))) {
|
|
return;
|
|
}
|
|
return ThreadWatcher.add(thread);
|
|
}
|
|
},
|
|
fetchCount: {
|
|
fetched: 0,
|
|
fetching: 0
|
|
},
|
|
fetchAllStatus: function() {
|
|
var thread, threads, _i, _len;
|
|
if (!(threads = ThreadWatcher.getAll()).length) {
|
|
return;
|
|
}
|
|
ThreadWatcher.status.textContent = '...';
|
|
for (_i = 0, _len = threads.length; _i < _len; _i++) {
|
|
thread = threads[_i];
|
|
ThreadWatcher.fetchStatus(thread);
|
|
}
|
|
},
|
|
fetchStatus: function(_arg) {
|
|
var boardID, data, fetchCount, threadID;
|
|
boardID = _arg.boardID, threadID = _arg.threadID, data = _arg.data;
|
|
if (data.isDead) {
|
|
return;
|
|
}
|
|
fetchCount = ThreadWatcher.fetchCount;
|
|
fetchCount.fetching++;
|
|
return $.ajax("//a.4cdn.org/" + boardID + "/res/" + threadID + ".json", {
|
|
onloadend: function() {
|
|
var status;
|
|
fetchCount.fetched++;
|
|
if (fetchCount.fetched === fetchCount.fetching) {
|
|
fetchCount.fetched = 0;
|
|
fetchCount.fetching = 0;
|
|
status = '';
|
|
} else {
|
|
status = "" + (Math.round(fetchCount.fetched / fetchCount.fetching * 100)) + "%";
|
|
}
|
|
ThreadWatcher.status.textContent = status;
|
|
if (this.status !== 404) {
|
|
return;
|
|
}
|
|
if (Conf['Auto Prune']) {
|
|
ThreadWatcher.db["delete"]({
|
|
boardID: boardID,
|
|
threadID: threadID
|
|
});
|
|
} else {
|
|
data.isDead = true;
|
|
ThreadWatcher.db.set({
|
|
boardID: boardID,
|
|
threadID: threadID,
|
|
val: data
|
|
});
|
|
}
|
|
return ThreadWatcher.refresh();
|
|
}
|
|
}, {
|
|
type: 'head'
|
|
});
|
|
},
|
|
getAll: function() {
|
|
var all, boardID, data, threadID, threads, _ref;
|
|
all = [];
|
|
_ref = ThreadWatcher.db.data.boards;
|
|
for (boardID in _ref) {
|
|
threads = _ref[boardID];
|
|
if (Conf['Current Board'] && boardID !== g.BOARD.ID) {
|
|
continue;
|
|
}
|
|
for (threadID in threads) {
|
|
data = threads[threadID];
|
|
all.push({
|
|
boardID: boardID,
|
|
threadID: threadID,
|
|
data: data
|
|
});
|
|
}
|
|
}
|
|
return all;
|
|
},
|
|
makeLine: function(boardID, threadID, data) {
|
|
var div, fullID, href, link, x;
|
|
x = $.el('a', {
|
|
className: 'fa',
|
|
href: 'javascript:;',
|
|
textContent: '\uf00d'
|
|
});
|
|
$.on(x, 'click', ThreadWatcher.cb.rm);
|
|
if (data.isDead) {
|
|
href = Redirect.to('thread', {
|
|
boardID: boardID,
|
|
threadID: threadID
|
|
});
|
|
}
|
|
link = $.el('a', {
|
|
href: href || ("/" + boardID + "/res/" + threadID),
|
|
textContent: data.excerpt,
|
|
title: data.excerpt
|
|
});
|
|
div = $.el('div');
|
|
fullID = "" + boardID + "." + threadID;
|
|
div.dataset.fullID = fullID;
|
|
if (g.VIEW === 'thread' && fullID === ("" + g.BOARD + "." + g.THREADID)) {
|
|
$.addClass(div, 'current');
|
|
}
|
|
if (data.isDead) {
|
|
$.addClass(div, 'dead-thread');
|
|
}
|
|
$.add(div, [x, $.tn(' '), link]);
|
|
return div;
|
|
},
|
|
refresh: function() {
|
|
var boardID, data, helper, list, nodes, refresher, thread, threadID, threads, toggler, watched, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _ref3;
|
|
nodes = [];
|
|
_ref = ThreadWatcher.getAll();
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
_ref1 = _ref[_i], boardID = _ref1.boardID, threadID = _ref1.threadID, data = _ref1.data;
|
|
nodes.push(ThreadWatcher.makeLine(boardID, threadID, data));
|
|
}
|
|
list = ThreadWatcher.list;
|
|
$.rmAll(list);
|
|
$.add(list, nodes);
|
|
threads = g.BOARD.threads;
|
|
_ref2 = threads.keys;
|
|
for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
|
|
threadID = _ref2[_j];
|
|
thread = threads[threadID];
|
|
toggler = $('.watch-thread-link', thread.OP.nodes.post);
|
|
watched = ThreadWatcher.db.get({
|
|
boardID: thread.board.ID,
|
|
threadID: threadID
|
|
});
|
|
helper = watched ? ['addClass', 'Unwatch'] : ['rmClass', 'Watch'];
|
|
$[helper[0]](toggler, 'watched');
|
|
toggler.title = "" + helper[1] + " Thread";
|
|
}
|
|
_ref3 = ThreadWatcher.menu.refreshers;
|
|
for (_k = 0, _len2 = _ref3.length; _k < _len2; _k++) {
|
|
refresher = _ref3[_k];
|
|
refresher();
|
|
}
|
|
},
|
|
toggle: function(thread) {
|
|
var boardID, threadID;
|
|
boardID = thread.board.ID;
|
|
threadID = thread.ID;
|
|
if (ThreadWatcher.db.get({
|
|
boardID: boardID,
|
|
threadID: threadID
|
|
})) {
|
|
return ThreadWatcher.rm(boardID, threadID);
|
|
} else {
|
|
return ThreadWatcher.add(thread);
|
|
}
|
|
},
|
|
add: function(thread) {
|
|
var boardID, data, threadID;
|
|
data = {};
|
|
boardID = thread.board.ID;
|
|
threadID = thread.ID;
|
|
if (thread.isDead) {
|
|
if (Conf['Auto Prune'] && ThreadWatcher.db.get({
|
|
boardID: boardID,
|
|
threadID: threadID
|
|
})) {
|
|
ThreadWatcher.rm(boardID, threadID);
|
|
return;
|
|
}
|
|
data.isDead = true;
|
|
}
|
|
data.excerpt = Get.threadExcerpt(thread);
|
|
ThreadWatcher.db.set({
|
|
boardID: boardID,
|
|
threadID: threadID,
|
|
val: data
|
|
});
|
|
return ThreadWatcher.refresh();
|
|
},
|
|
rm: function(boardID, threadID) {
|
|
ThreadWatcher.db["delete"]({
|
|
boardID: boardID,
|
|
threadID: threadID
|
|
});
|
|
return ThreadWatcher.refresh();
|
|
},
|
|
convert: function(oldFormat) {
|
|
var boardID, data, newFormat, threadID, threads;
|
|
newFormat = {};
|
|
for (boardID in oldFormat) {
|
|
threads = oldFormat[boardID];
|
|
for (threadID in threads) {
|
|
data = threads[threadID];
|
|
(newFormat[boardID] || (newFormat[boardID] = {}))[threadID] = {
|
|
excerpt: data.textContent
|
|
};
|
|
}
|
|
}
|
|
return newFormat;
|
|
},
|
|
menu: {
|
|
refreshers: [],
|
|
init: function() {
|
|
var menu;
|
|
if (!Conf['Thread Watcher']) {
|
|
return;
|
|
}
|
|
menu = new UI.Menu('thread watcher');
|
|
$.on($('.menu-button', ThreadWatcher.dialog), 'click', function(e) {
|
|
return menu.toggle(e, this, ThreadWatcher);
|
|
});
|
|
this.addHeaderMenuEntry();
|
|
return this.addMenuEntries();
|
|
},
|
|
addHeaderMenuEntry: function() {
|
|
var entryEl;
|
|
if (g.VIEW !== 'thread') {
|
|
return;
|
|
}
|
|
entryEl = $.el('a', {
|
|
href: 'javascript:;'
|
|
});
|
|
$.event('AddMenuEntry', {
|
|
type: 'header',
|
|
el: entryEl,
|
|
order: 60
|
|
});
|
|
$.on(entryEl, 'click', function() {
|
|
return ThreadWatcher.toggle(g.threads["" + g.BOARD + "." + g.THREADID]);
|
|
});
|
|
return this.refreshers.push(function() {
|
|
var addClass, rmClass, text, _ref;
|
|
_ref = $('.current', ThreadWatcher.list) ? ['unwatch-thread', 'watch-thread', 'Unwatch thread'] : ['watch-thread', 'unwatch-thread', 'Watch thread'], addClass = _ref[0], rmClass = _ref[1], text = _ref[2];
|
|
$.addClass(entryEl, addClass);
|
|
$.rmClass(entryEl, rmClass);
|
|
return entryEl.textContent = text;
|
|
});
|
|
},
|
|
addMenuEntries: function() {
|
|
var cb, conf, entries, entry, name, refresh, subEntries, _i, _len, _ref, _ref1;
|
|
entries = [];
|
|
entries.push({
|
|
cb: ThreadWatcher.cb.openAll,
|
|
entry: {
|
|
type: 'thread watcher',
|
|
el: $.el('a', {
|
|
textContent: 'Open all threads'
|
|
})
|
|
},
|
|
refresh: function() {
|
|
return (ThreadWatcher.list.firstElementChild ? $.rmClass : $.addClass)(this.el, 'disabled');
|
|
}
|
|
});
|
|
entries.push({
|
|
cb: ThreadWatcher.cb.checkThreads,
|
|
entry: {
|
|
type: 'thread watcher',
|
|
el: $.el('a', {
|
|
textContent: 'Check 404\'d threads'
|
|
})
|
|
},
|
|
refresh: function() {
|
|
return ($('div:not(.dead-thread)', ThreadWatcher.list) ? $.rmClass : $.addClass)(this.el, 'disabled');
|
|
}
|
|
});
|
|
entries.push({
|
|
cb: ThreadWatcher.cb.pruneDeads,
|
|
entry: {
|
|
type: 'thread watcher',
|
|
el: $.el('a', {
|
|
textContent: 'Prune 404\'d threads'
|
|
})
|
|
},
|
|
refresh: function() {
|
|
return ($('.dead-thread', ThreadWatcher.list) ? $.rmClass : $.addClass)(this.el, 'disabled');
|
|
}
|
|
});
|
|
subEntries = [];
|
|
_ref = Config.threadWatcher;
|
|
for (name in _ref) {
|
|
conf = _ref[name];
|
|
subEntries.push(this.createSubEntry(name, conf[1]));
|
|
}
|
|
entries.push({
|
|
entry: {
|
|
type: 'thread watcher',
|
|
el: $.el('span', {
|
|
textContent: 'Settings'
|
|
}),
|
|
subEntries: subEntries
|
|
}
|
|
});
|
|
for (_i = 0, _len = entries.length; _i < _len; _i++) {
|
|
_ref1 = entries[_i], entry = _ref1.entry, cb = _ref1.cb, refresh = _ref1.refresh;
|
|
if (entry.el.nodeName === 'A') {
|
|
entry.el.href = 'javascript:;';
|
|
}
|
|
if (cb) {
|
|
$.on(entry.el, 'click', cb);
|
|
}
|
|
if (refresh) {
|
|
this.refreshers.push(refresh.bind(entry));
|
|
}
|
|
$.event('AddMenuEntry', entry);
|
|
}
|
|
},
|
|
createSubEntry: function(name, desc) {
|
|
var entry, input;
|
|
entry = {
|
|
type: 'thread watcher',
|
|
el: $.el('label', {
|
|
innerHTML: "<input type=checkbox name='" + name + "'> " + name,
|
|
title: desc
|
|
})
|
|
};
|
|
input = entry.el.firstElementChild;
|
|
input.checked = Conf[name];
|
|
$.on(input, 'change', $.cb.checked);
|
|
if (name === 'Current Board') {
|
|
$.on(input, 'change', ThreadWatcher.refresh);
|
|
}
|
|
return entry;
|
|
}
|
|
}
|
|
};
|
|
|
|
Unread = {
|
|
init: function() {
|
|
if (g.VIEW !== 'thread' || !Conf['Unread Count'] && !Conf['Unread Favicon'] && !Conf['Desktop Notifications']) {
|
|
return;
|
|
}
|
|
this.db = new DataBoard('lastReadPosts', this.sync);
|
|
this.hr = $.el('hr', {
|
|
id: 'unread-line'
|
|
});
|
|
this.posts = new RandomAccessList;
|
|
this.postsQuotingYou = [];
|
|
return Thread.callbacks.push({
|
|
name: 'Unread',
|
|
cb: this.node
|
|
});
|
|
},
|
|
disconnect: function() {
|
|
var hr, name, _i, _len, _ref;
|
|
if (g.VIEW !== 'thread' || !Conf['Unread Count'] && !Conf['Unread Favicon'] && !Conf['Desktop Notifications']) {
|
|
return;
|
|
}
|
|
Unread.db.disconnect();
|
|
if (hr = Unread.hr, Unread) {
|
|
$.rm(hr);
|
|
}
|
|
_ref = ['db', 'hr', 'posts', 'postsQuotingYou', 'thread', 'title', 'lastReadPost'];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
name = _ref[_i];
|
|
delete this[name];
|
|
}
|
|
$.off(d, '4chanXInitFinished', this.ready);
|
|
$.off(d, 'ThreadUpdate', this.onUpdate);
|
|
$.off(d, 'scroll visibilitychange', this.read);
|
|
if (Conf['Unread Line']) {
|
|
$.off(d, 'visibilitychange', this.setLine);
|
|
}
|
|
return Thread.callbacks.disconnect('Unread');
|
|
},
|
|
node: function() {
|
|
Unread.thread = this;
|
|
Unread.title = d.title;
|
|
Unread.lastReadPost = Unread.db.get({
|
|
boardID: this.board.ID,
|
|
threadID: this.ID,
|
|
defaultValue: 0
|
|
});
|
|
$.on(d, '4chanXInitFinished', Unread.ready);
|
|
$.on(d, 'ThreadUpdate', Unread.onUpdate);
|
|
$.on(d, 'scroll visibilitychange', Unread.read);
|
|
if (Conf['Unread Line']) {
|
|
return $.on(d, 'visibilitychange', Unread.setLine);
|
|
}
|
|
},
|
|
ready: function() {
|
|
var posts;
|
|
$.off(d, '4chanXInitFinished', Unread.ready);
|
|
if (!Conf['Quote Threading']) {
|
|
posts = [];
|
|
Unread.thread.posts.forEach(function(post) {
|
|
if (post.isReply) {
|
|
return posts.push(post);
|
|
}
|
|
});
|
|
Unread.addPosts(posts);
|
|
}
|
|
if (Conf['Quote Threading']) {
|
|
QuoteThreading.force();
|
|
}
|
|
if (Conf['Scroll to Last Read Post']) {
|
|
return Unread.scroll();
|
|
}
|
|
},
|
|
scroll: function() {
|
|
var down, hash, keys, post, posts, root;
|
|
if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) {
|
|
return;
|
|
}
|
|
if (post = Unread.posts.first) {
|
|
while (root = $.x('preceding-sibling::div[contains(@class,"replyContainer")][1]', post.data.nodes.root)) {
|
|
if (!(post = Get.postFromRoot(root)).isHidden) {
|
|
break;
|
|
}
|
|
}
|
|
if (!root) {
|
|
return;
|
|
}
|
|
down = true;
|
|
} else {
|
|
posts = Unread.thread.posts;
|
|
keys = posts.keys;
|
|
root = posts[keys[keys.length - 1]].nodes.root;
|
|
}
|
|
if (Header.getBottomOf(root) < 0) {
|
|
return Header.scrollTo(root, down);
|
|
}
|
|
},
|
|
sync: function() {
|
|
var ID, lastReadPost, post;
|
|
lastReadPost = Unread.db.get({
|
|
boardID: Unread.thread.board.ID,
|
|
threadID: Unread.thread.ID,
|
|
defaultValue: 0
|
|
});
|
|
if (!(Unread.lastReadPost < lastReadPost)) {
|
|
return;
|
|
}
|
|
Unread.lastReadPost = lastReadPost;
|
|
post = Unread.posts.first;
|
|
while (post) {
|
|
if ((ID = post.ID, post) > Unread.lastReadPost) {
|
|
break;
|
|
}
|
|
post = post.next;
|
|
Unread.posts.rm(ID);
|
|
}
|
|
Unread.readArray(Unread.postsQuotingYou);
|
|
if (Conf['Unread Line']) {
|
|
Unread.setLine();
|
|
}
|
|
return Unread.update();
|
|
},
|
|
addPosts: function(posts) {
|
|
var ID, post, _i, _len, _ref, _ref1;
|
|
for (_i = 0, _len = posts.length; _i < _len; _i++) {
|
|
post = posts[_i];
|
|
ID = post.ID;
|
|
if (ID <= Unread.lastReadPost || post.isHidden || QR.db.get({
|
|
boardID: post.board.ID,
|
|
threadID: post.thread.ID,
|
|
postID: ID
|
|
})) {
|
|
continue;
|
|
}
|
|
Unread.posts.push(post);
|
|
Unread.addPostQuotingYou(post);
|
|
}
|
|
if (Conf['Unread Line']) {
|
|
Unread.setLine((_ref = (_ref1 = Unread.posts.first) != null ? _ref1.data : void 0, __indexOf.call(posts, _ref) >= 0));
|
|
}
|
|
Unread.read();
|
|
return Unread.update();
|
|
},
|
|
addPostQuotingYou: function(post) {
|
|
var quotelink, _i, _len, _ref;
|
|
_ref = post.nodes.quotelinks;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
quotelink = _ref[_i];
|
|
if (!(QR.db.get(Get.postDataFromLink(quotelink)))) {
|
|
continue;
|
|
}
|
|
Unread.postsQuotingYou.push(post);
|
|
Unread.openNotification(post);
|
|
return;
|
|
}
|
|
},
|
|
openNotification: function(post) {
|
|
var notif;
|
|
if (!Header.areNotificationsEnabled) {
|
|
return;
|
|
}
|
|
notif = new Notification("" + (post.getNameBlock()) + " replied to you", {
|
|
body: post.info.comment,
|
|
icon: Favicon.logo
|
|
});
|
|
notif.onclick = function() {
|
|
Header.scrollToIfNeeded(post.nodes.root, true);
|
|
return window.focus();
|
|
};
|
|
return notif.onshow = function() {
|
|
return setTimeout(function() {
|
|
return notif.close();
|
|
}, 7 * $.SECOND);
|
|
};
|
|
},
|
|
onUpdate: function(e) {
|
|
if (e.detail[404]) {
|
|
return Unread.update();
|
|
} else if (!Conf['Quote Threading']) {
|
|
return Unread.addPosts(e.detail.newPosts);
|
|
} else {
|
|
Unread.read();
|
|
return Unread.update();
|
|
}
|
|
},
|
|
readSinglePost: function(post) {
|
|
var ID, i, posts;
|
|
ID = post.ID;
|
|
posts = Unread.posts;
|
|
if (!posts[ID]) {
|
|
return;
|
|
}
|
|
if (post === posts.first) {
|
|
Unread.lastReadPost = ID;
|
|
Unread.saveLastReadPost();
|
|
}
|
|
posts.rm(ID);
|
|
if ((i = Unread.postsQuotingYou.indexOf(post)) !== -1) {
|
|
Unread.postsQuotingYou.splice(i, 1);
|
|
}
|
|
return Unread.update();
|
|
},
|
|
readArray: function(arr) {
|
|
var i, post, _i, _len;
|
|
for (i = _i = 0, _len = arr.length; _i < _len; i = ++_i) {
|
|
post = arr[i];
|
|
if (post.ID > Unread.lastReadPost) {
|
|
break;
|
|
}
|
|
}
|
|
return arr.splice(0, i);
|
|
},
|
|
read: $.debounce(100, function(e) {
|
|
var ID, data, height, post, posts;
|
|
if (d.hidden || !Unread.posts.length) {
|
|
return;
|
|
}
|
|
height = doc.clientHeight;
|
|
posts = Unread.posts;
|
|
while (post = posts.first) {
|
|
if (!(Header.getBottomOf(post.data.nodes.root) > -1)) {
|
|
break;
|
|
}
|
|
ID = post.ID, data = post.data;
|
|
posts.rm(ID);
|
|
if (Conf['Mark Quotes of You'] && QR.db.get({
|
|
boardID: data.board.ID,
|
|
threadID: data.thread.ID,
|
|
postID: ID
|
|
})) {
|
|
QuoteYou.lastRead = data.nodes.root;
|
|
}
|
|
}
|
|
if (!ID) {
|
|
return;
|
|
}
|
|
if (Unread.lastReadPost < ID || !Unread.lastReadPost) {
|
|
Unread.lastReadPost = ID;
|
|
}
|
|
Unread.saveLastReadPost();
|
|
Unread.readArray(Unread.postsQuotingYou);
|
|
if (e) {
|
|
return Unread.update();
|
|
}
|
|
}),
|
|
saveLastReadPost: $.debounce(5 * $.SECOND, function() {
|
|
if (Unread.thread.isDead) {
|
|
return;
|
|
}
|
|
return Unread.db.set({
|
|
boardID: Unread.thread.board.ID,
|
|
threadID: Unread.thread.ID,
|
|
val: Unread.lastReadPost
|
|
});
|
|
}),
|
|
setLine: function(force) {
|
|
var post;
|
|
if (!(d.hidden || force === true)) {
|
|
return;
|
|
}
|
|
if (!(post = Unread.posts.first)) {
|
|
return $.rm(Unread.hr);
|
|
}
|
|
if ($.x('preceding-sibling::div[contains(@class,"replyContainer")]', post.data.nodes.root)) {
|
|
return $.before(post.data.nodes.root, Unread.hr);
|
|
}
|
|
},
|
|
update: function() {
|
|
var count;
|
|
count = Unread.posts.length;
|
|
if (Conf['Unread Count']) {
|
|
d.title = "" + (count || !Conf['Hide Unread Count at (0)'] ? "(" + count + ") " : '') + (g.DEAD ? Unread.title.replace('-', '- 404 -') : Unread.title);
|
|
}
|
|
if (!Conf['Unread Favicon']) {
|
|
return;
|
|
}
|
|
Favicon.el.href = g.DEAD ? Unread.postsQuotingYou[0] ? Favicon.unreadDeadY : count ? Favicon.unreadDead : Favicon.dead : count ? Unread.postsQuotingYou[0] ? Favicon.unreadY : Favicon.unread : Favicon["default"];
|
|
return $.add(d.head, Favicon.el);
|
|
}
|
|
};
|
|
|
|
Redirect = {
|
|
init: function() {
|
|
var archive, archives, boardID, boards, data, files, id, name, o, record, software, type, _i, _j, _len, _len1, _ref, _ref1, _ref2;
|
|
o = {
|
|
thread: {},
|
|
post: {},
|
|
file: {}
|
|
};
|
|
archives = {};
|
|
_ref = Redirect.archives;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
_ref1 = _ref[_i], name = _ref1.name, boards = _ref1.boards, files = _ref1.files, data = _ref1.data;
|
|
archives[name] = {
|
|
boards: boards,
|
|
files: files,
|
|
data: data
|
|
};
|
|
software = data.software;
|
|
for (_j = 0, _len1 = boards.length; _j < _len1; _j++) {
|
|
boardID = boards[_j];
|
|
if (!(boardID in o.thread)) {
|
|
o.thread[boardID] = data;
|
|
}
|
|
if (!(boardID in o.post || software !== 'foolfuuka')) {
|
|
o.post[boardID] = data;
|
|
}
|
|
if (!(boardID in o.file || __indexOf.call(files, boardID) < 0)) {
|
|
o.file[boardID] = data;
|
|
}
|
|
}
|
|
}
|
|
_ref2 = Conf['selectedArchives'];
|
|
for (boardID in _ref2) {
|
|
record = _ref2[boardID];
|
|
for (type in record) {
|
|
id = record[type];
|
|
if (!((archive = archives[id]))) {
|
|
continue;
|
|
}
|
|
boards = type === 'file' ? archive.files : archive.boards;
|
|
if (__indexOf.call(boards, boardID) < 0) {
|
|
continue;
|
|
}
|
|
o[type][boardID] = archive.data;
|
|
}
|
|
}
|
|
return Redirect.data = o;
|
|
},
|
|
archives: [
|
|
{
|
|
name: "Foolz",
|
|
boards: ["a", "biz", "co", "diy", "gd", "jp", "m", "sci", "sp", "tg", "tv", "v", "vg", "vp", "vr", "wsg"],
|
|
files: ["a", "biz", "diy", "gd", "jp", "m", "sci", "tg", "vg", "vp", "vr", "wsg"],
|
|
data: {
|
|
domain: "archive.foolz.us",
|
|
http: false,
|
|
https: true,
|
|
software: "foolfuuka"
|
|
}
|
|
}, {
|
|
name: "NSFW Foolz",
|
|
boards: ["u"],
|
|
files: ["u"],
|
|
data: {
|
|
domain: "nsfw.foolz.us",
|
|
http: false,
|
|
https: true,
|
|
software: "foolfuuka"
|
|
}
|
|
}, {
|
|
name: "The Dark Cave",
|
|
boards: ["c", "int", "out", "po"],
|
|
files: ["c", "po"],
|
|
data: {
|
|
domain: "archive.thedarkcave.org",
|
|
http: true,
|
|
https: true,
|
|
software: "foolfuuka"
|
|
}
|
|
}, {
|
|
name: "4plebs",
|
|
boards: ["adv", "hr", "o", "pol", "s4s", "tg", "trv", "tv", "x"],
|
|
files: ["adv", "hr", "o", "pol", "s4s", "tg", "trv", "tv", "x"],
|
|
data: {
|
|
domain: "archive.4plebs.org",
|
|
http: true,
|
|
https: true,
|
|
software: "foolfuuka"
|
|
}
|
|
}, {
|
|
name: "4plebs Flash Archive",
|
|
boards: ["f"],
|
|
files: ["f"],
|
|
data: {
|
|
domain: "flash.4plebs.org",
|
|
http: true,
|
|
https: true,
|
|
software: "foolfuuka"
|
|
}
|
|
}, {
|
|
name: "Nyafuu",
|
|
boards: ["c", "e", "w", "wg"],
|
|
files: ["c", "e", "w", "wg"],
|
|
data: {
|
|
domain: "archive.nyafuu.org",
|
|
http: true,
|
|
https: true,
|
|
software: "foolfuuka"
|
|
}
|
|
}, {
|
|
name: "Love is Over",
|
|
boards: ["d", "i"],
|
|
files: ["d", "i"],
|
|
data: {
|
|
domain: "loveisover.me",
|
|
http: true,
|
|
https: true,
|
|
software: "foolfuuka"
|
|
}
|
|
}, {
|
|
name: "Rebecca Black Tech",
|
|
boards: ["cgl", "g", "mu", "w"],
|
|
files: ["cgl", "g", "mu", "w"],
|
|
data: {
|
|
domain: "archive.rebeccablacktech.com",
|
|
http: true,
|
|
https: true,
|
|
software: "fuuka"
|
|
}
|
|
}, {
|
|
name: "Heinessen",
|
|
boards: ["an", "fit", "k", "mlp", "r9k", "toy"],
|
|
files: ["an", "fit", "k", "r9k", "toy"],
|
|
data: {
|
|
domain: "archive.heinessen.com",
|
|
http: true,
|
|
software: "fuuka"
|
|
}
|
|
}, {
|
|
name: "warosu",
|
|
boards: ["3", "biz", "cgl", "ck", "diy", "fa", "g", "ic", "jp", "lit", "sci", "tg", "vr"],
|
|
files: ["3", "biz", "cgl", "ck", "diy", "fa", "ic", "jp", "lit", "sci", "tg", "vr"],
|
|
data: {
|
|
domain: "fuuka.warosu.org",
|
|
https: true,
|
|
software: "fuuka"
|
|
}
|
|
}, {
|
|
name: "fgts",
|
|
boards: ["cm", "hm", "r", "soc", "y"],
|
|
files: ["cm", "hm", "r", "soc", "y"],
|
|
data: {
|
|
domain: "fgst.eu",
|
|
http: true,
|
|
https: true,
|
|
software: "foolfuuka"
|
|
}
|
|
}, {
|
|
name: "maware",
|
|
boards: ["t"],
|
|
files: ["t"],
|
|
data: {
|
|
domain: "archive.mawa.re",
|
|
http: true,
|
|
software: "foolfuuka"
|
|
}
|
|
}, {
|
|
name: "InstallGentoo",
|
|
boards: ["g", "t"],
|
|
files: ["g", "t"],
|
|
data: {
|
|
domain: "chan.installgentoo.com",
|
|
http: true,
|
|
software: "foolfuuka"
|
|
}
|
|
}, {
|
|
name: "Foolz Beta",
|
|
boards: ["a", "biz", "co", "d", "diy", "gd", "jp", "m", "mlp", "s4s", "sci", "sp", "tg", "tv", "u", "v", "vg", "vp", "vr", "wsg"],
|
|
files: ["a", "biz", "d", "diy", "gd", "jp", "m", "s4s", "sci", "tg", "u", "vg", "vp", "vr", "wsg"],
|
|
data: {
|
|
domain: "beta.foolz.us",
|
|
http: true,
|
|
https: true,
|
|
withCredentials: true,
|
|
software: "foolfuuka"
|
|
}
|
|
}
|
|
],
|
|
to: function(dest, data) {
|
|
var archive;
|
|
archive = (dest === 'search' || dest === 'board' ? Redirect.data.thread : Redirect.data[dest])[data.boardID];
|
|
if (!archive) {
|
|
return '';
|
|
}
|
|
return Redirect[dest](archive, data);
|
|
},
|
|
protocol: function(archive) {
|
|
var protocol;
|
|
protocol = location.protocol;
|
|
if (!archive[protocol.slice(0, -1)]) {
|
|
protocol = protocol === 'https:' ? 'http:' : 'https:';
|
|
}
|
|
return "" + protocol + "//";
|
|
},
|
|
thread: function(archive, _arg) {
|
|
var boardID, path, postID, threadID;
|
|
boardID = _arg.boardID, threadID = _arg.threadID, postID = _arg.postID;
|
|
path = threadID ? "" + boardID + "/thread/" + threadID : "" + boardID + "/post/" + postID;
|
|
if (archive.software === 'foolfuuka') {
|
|
path += '/';
|
|
}
|
|
if (threadID && postID) {
|
|
path += archive.software === 'foolfuuka' ? "#" + postID : "#p" + postID;
|
|
}
|
|
return "" + (Redirect.protocol(archive)) + archive.domain + "/" + path;
|
|
},
|
|
post: function(archive, _arg) {
|
|
var URL, boardID, postID;
|
|
boardID = _arg.boardID, postID = _arg.postID;
|
|
URL = new String("" + (Redirect.protocol(archive)) + archive.domain + "/_/api/chan/post/?board=" + boardID + "&num=" + postID);
|
|
URL.archive = archive;
|
|
return URL;
|
|
},
|
|
file: function(archive, _arg) {
|
|
var boardID, filename;
|
|
boardID = _arg.boardID, filename = _arg.filename;
|
|
return "" + (Redirect.protocol(archive)) + archive.domain + "/" + boardID + "/full_image/" + filename;
|
|
},
|
|
board: function(archive, _arg) {
|
|
var boardID;
|
|
boardID = _arg.boardID;
|
|
return "" + (Redirect.protocol(archive)) + archive.domain + "/" + boardID + "/";
|
|
},
|
|
search: function(archive, _arg) {
|
|
var boardID, path, type, value;
|
|
boardID = _arg.boardID, type = _arg.type, value = _arg.value;
|
|
type = type === 'name' ? 'username' : type === 'MD5' ? 'image' : type;
|
|
value = encodeURIComponent(value);
|
|
path = archive.software === 'foolfuuka' ? "" + boardID + "/search/" + type + "/" + value : "" + boardID + "/?task=search2&search_" + (type === 'image' ? 'media_hash' : type) + "=" + value;
|
|
return "" + (Redirect.protocol(archive)) + archive.domain + "/" + path;
|
|
}
|
|
};
|
|
|
|
Banner = {
|
|
init: function() {
|
|
return $.asap((function() {
|
|
return d.body;
|
|
}), function() {
|
|
return $.asap((function() {
|
|
return $('.abovePostForm');
|
|
}), Banner.ready);
|
|
});
|
|
},
|
|
ready: function() {
|
|
var banner, child, children, i, nodes, title;
|
|
banner = $(".boardBanner");
|
|
title = $.el("div", {
|
|
id: "boardTitle"
|
|
});
|
|
children = banner.children;
|
|
nodes = [];
|
|
i = 0;
|
|
while (child = children[i++]) {
|
|
if (i === 1) {
|
|
child.id = "Banner";
|
|
child.title = "Click to change";
|
|
$.on(child, 'click', Banner.cb.toggle);
|
|
continue;
|
|
}
|
|
nodes.push(child);
|
|
if (Conf['Custom Board Titles']) {
|
|
Banner.custom(child).title = "Ctrl+click to edit board " + (i === 3 ? 'sub' : '') + "title";
|
|
}
|
|
}
|
|
$.add(title, nodes);
|
|
$.after(banner, title);
|
|
},
|
|
cb: {
|
|
toggle: (function() {
|
|
var types;
|
|
types = {
|
|
jpg: 227,
|
|
png: 270,
|
|
gif: 253
|
|
};
|
|
return function() {
|
|
var num, type;
|
|
type = Object.keys(types)[Math.floor(3 * Math.random())];
|
|
num = Math.floor(types[type] * Math.random());
|
|
return this.src = "//static.4chan.org/image/title/" + num + "." + type;
|
|
};
|
|
})(),
|
|
click: function(e) {
|
|
if (e.ctrlKey) {
|
|
this.contentEditable = true;
|
|
return this.focus();
|
|
}
|
|
},
|
|
keydown: function(e) {
|
|
e.stopPropagation();
|
|
if (!e.shiftKey && e.keyCode === 13) {
|
|
return this.blur();
|
|
}
|
|
},
|
|
focus: function() {
|
|
var items, string, string2;
|
|
this.textContent = this.innerHTML;
|
|
string = "" + g.BOARD + "." + this.className;
|
|
string2 = "" + string + ".orig";
|
|
items = {
|
|
title: this.innerHTML
|
|
};
|
|
items[string] = '';
|
|
items[string2] = false;
|
|
$.get(items, function(items) {
|
|
if (!(items[string2] && items.title === items[string])) {
|
|
return $.set(string2, items.title);
|
|
}
|
|
});
|
|
},
|
|
blur: function() {
|
|
this.innerHTML = this.textContent;
|
|
this.contentEditable = false;
|
|
return $.set("" + g.BOARD + "." + this.className, this.textContent);
|
|
}
|
|
},
|
|
custom: function(child) {
|
|
var cachedTest, string;
|
|
cachedTest = child.innerHTML;
|
|
string = "" + g.BOARD + "." + child.className;
|
|
$.on(child, 'click keydown focus blur', function(e) {
|
|
return Banner.cb[e.type].apply(this, [e]);
|
|
});
|
|
$.get(string, cachedTest, function(item) {
|
|
var string2, title;
|
|
if (!(title = item[string])) {
|
|
return;
|
|
}
|
|
if (Conf['Persistent Custom Board Titles']) {
|
|
return child.innerHTML = title;
|
|
}
|
|
string2 = "" + string + ".orig";
|
|
return $.get(string2, cachedTest, function(itemb) {
|
|
if (cachedTest === itemb[string2]) {
|
|
return child.innerHTML = title;
|
|
} else {
|
|
$.set(string, cachedTest);
|
|
return $.set(string2, cachedTest);
|
|
}
|
|
});
|
|
});
|
|
return child;
|
|
}
|
|
};
|
|
|
|
Emoji = {
|
|
init: function() {
|
|
return Emoji.icons['PlanNine'] = Emoji.icons['Plan9'];
|
|
},
|
|
css: function() {
|
|
var category, css, icon, key, name, pony, _ref;
|
|
css = [];
|
|
_ref = Emoji.icons;
|
|
for (key in _ref) {
|
|
category = _ref[key];
|
|
if (!Emoji.icons.hasOwnProperty(key)) {
|
|
continue;
|
|
}
|
|
for (name in category) {
|
|
icon = category[name];
|
|
if (!category.hasOwnProperty(name)) {
|
|
continue;
|
|
}
|
|
css.push(".emoji-position-after:not(.emoji-disable):not(.emoji-" + (pony = key === "pony" ? 'disable-ponies' : 'only-ponies') + ") a.useremail[href*='" + name + "']:last-of-type::after, .emoji-position-after:not(.emoji-disable):not(.emoji-" + pony + ") a.useremail[href*='" + (name.toLowerCase()) + "']:last-of-type::after, .emoji-position-after:not(.emoji-disable):not(.emoji-" + pony + ") a.useremail[href*='" + (name.toUpperCase()) + "']:last-of-type::after, .emoji-position-before:not(.emoji-disable):not(.emoji-" + pony + ") a.useremail[href*='" + name + "']:last-of-type::before, .emoji-position-before:not(.emoji-disable):not(.emoji-" + pony + ") a.useremail[href*='" + (name.toLowerCase()) + "']:last-of-type::before, .emoji-position-before:not(.emoji-disable):not(.emoji-" + pony + ") a.useremail[href*='" + (name.toUpperCase()) + "']:last-of-type::before { content: url('data:image/png;base64," + icon + "'); }");
|
|
}
|
|
}
|
|
css.push(".sage-highlighting-image.sage-image-appchan.sage-highlight-position-after a.useremail[href*='sage']:last-of-type::after, .sage-highlighting-image.sage-image-appchan.sage-highlight-position-after a.useremail[href*='SAGE']:last-of-type::after, .sage-highlighting-image.sage-image-appchan.sage-highlight-position-after a.useremail[href*='Sage']:last-of-type::after, .sage-highlighting-image.sage-image-appchan.sage-highlight-position-before a.useremail[href*='sage']:last-of-type::before, .sage-highlighting-image.sage-image-appchan.sage-highlight-position-before a.useremail[href*='SAGE']:last-of-type::before, .sage-highlighting-image.sage-image-appchan.sage-highlight-position-before a.useremail[href*='Sage']:last-of-type::before { content: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAMAAAAolt3jAAABa1BMVEUAAACqrKiCgYIAAAAAAAAAAACHmX5pgl5NUEx/hnx4hXRSUVMiIyKwrbFzn19SbkZ1d3OvtqtpaWhcX1ooMyRsd2aWkZddkEV8vWGcpZl+kHd7jHNdYFuRmI4bHRthaV5WhUFsfGZReUBFZjdJazpGVUBnamYfHB9TeUMzSSpHgS1cY1k1NDUyOC8yWiFywVBoh1lDSEAZHBpucW0ICQgUHhBjfFhCRUA+QTtEQUUBAQFyo1praWspKigWFRZHU0F6j3E9Oz5VWFN0j2hncWONk4sAAABASDxJWkJKTUgAAAAvNC0fJR0DAwMAAAA9QzoWGhQAAAA8YytvrFOJsnlqyT9oqExqtkdrsExpsUsqQx9rpVJDbzBBbi5utk9jiFRuk11iqUR64k5Wf0JIZTpadk5om1BkyjmF1GRNY0FheFdXpjVXhz86XSp2yFJwslR3w1NbxitbtDWW5nNnilhFXTtYqDRwp1dSijiJ7H99AAAAUnRSTlMAJTgNGQml71ypu3cPEN/RDh8HBbOwQN7wVg4CAQZ28vs9EDluXjo58Ge8xwMy0P3+rV8cT73sawEdTv63NAa3rQwo4cUdAl3hWQSWvS8qqYsjEDiCzAAAAIVJREFUeNpFx7GKAQAYAOD/A7GbZVAWZTBZFGQw6LyCF/MIkiTdcOmWSzYbJVE2u1KX0J1v+8QDv/EkyS0yXF/NgeEILiHfyc74mICTQltqYXBeAWU9HGxU09YqqEvAElGjyZYjPyLqitjzHSEiGkrsfMWr0VLe+oy/djGP//YwfbeP8bN3Or0bkqEVblAAAAAASUVORK5CYII='); } .sage-highlighting-image.sage-image-4chan-ss.sage-highlight-position-after a.useremail[href*='sage']:last-of-type::after, .sage-highlighting-image.sage-image-4chan-ss.sage-highlight-position-after a.useremail[href*='SAGE']:last-of-type::after, .sage-highlighting-image.sage-image-4chan-ss.sage-highlight-position-after a.useremail[href*='Sage']:last-of-type::after, .sage-highlighting-image.sage-image-4chan-ss.sage-highlight-position-before a.useremail[href*='sage']:last-of-type::before, .sage-highlighting-image.sage-image-4chan-ss.sage-highlight-position-before a.useremail[href*='SAGE']:last-of-type::before, .sage-highlighting-image.sage-image-4chan-ss.sage-highlight-position-before a.useremail[href*='Sage']:last-of-type::before { content: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAANCAMAAACuAq9NAAABIFBMVEUAAAAAXwAAOAAAVQAAKgAAOgAALwAAagAATwAAdAAAYAAAYwAARAAAcgAANwAAOAABcwEBZAEBXwEAQwABbwEBaQEBWgEBTwECdAICaQIIcwgBWQEIXAcARAAALgACdAICbQICdAICcAIBVQEBTgEAQgAAQwAkjCIcexomgSIcbRtCnj9IpUNEmT5LoUNYtFE9lDtClD5dtVJqwmNCmEFMoEh1zGcnfCYnfCc6jzc7kDs9kjxAlUBDmEFInUNLoEpMoExOo0tPpExQpU1Rpk1Sp0pSp1JXrFVZrlhar1Rar1pes1xftFhhtmFit19juFxkuVxovWRrwGBuw2Juw2Nuw2Ruw2V0yWx1ym14zWt6z2980W6A1XGD2HSD2XSI3XdgUJhRAAAAN3RSTlMACAkJDBobHyBERUVHR3KIiYyNkJmanZ6rrq+ws7S5vL29vsLFxsfP0dLU5eXn5+vt7e34+fn5LB88GQAAAI1JREFUGFdNzjsSwjAMRdGn2PngmZAUVHQshP0vArYQYCYDlmxLos3tTncx4xjdAMCEhR1ApLup+bPxtgsQzZ2Mr4iPYROEU129g6it0jJCv6xqFJlpKbl2kr21Zsl/Mo0IBpmrqg7ZnPfgSnKuqhrKwO+AVrSUOjmo5VcEuHzH9CEAXaTDYZ88HGh++QNCDFZ4bvbHSQAAAABJRU5ErkJggg=='); }");
|
|
return css.join("");
|
|
},
|
|
icons: {
|
|
pony: {
|
|
'Pinkie': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAA3dJREFUGBlNwUtoXFUcB+Df/zzuY553pp2MmUwSk5TGpnamiokWRdNCSkCrUChKCnVZQUEUdy5sQZC6cyd2VWgoutCFXWTjIyp1UdqmEDBRsSZNmkmaZF6Zx32ccyzowu8j/M883pH5A9kBYfNkFOpu0OiulyqXmnhkDmdYHYJexzX1Ef51EQDhP9fxpjU0PDCd7IldYIxGVag3/KZ/ZX1p8/P0k/0U47qs291M2NS3f6ncuLeFeQ3A8KuYoNPoY/3e2Ej6scSnqUJ8gksmhC2y3OJHpSUHU0/3HU+WCuddyV6VSpVyYv/aUuPefWAP4iDG8AhJWyYYo972tg8DQ1wyWHGZSfcmZmQ+YeKTw1bQ70H8uJw3xtDp6NzG15VLf/DLWMBZHGPkwuWGyq7njLoZyzAiCtqRIddioifBxYBHIpeE0oaw0yoG7WA755dvi8Xih66BOSZj4rwds45bSQkuOeOCQYWG2PjjcEq94JwjQgQ+kCW+tBl3H7Ym4jnbE/nDmamwqz9mnEaYoBgiZaJIGW5zEIHEPheykMD2w12ztPIXCrZHec+GdOVAUI8ygjvifeHQESiNoKtMlIoRxSV0owMjAeY5+P3BKrbTDq3n02B/7yDTDkBANSXiewKgjFbahEwQe34IiVIfRNqCv1qDanQR9Di4+tU16N409o2WMXnyJeNWb9PO4s6WroZawOiSiozCoR7lPFUQezICCzXF+pPGYRna6/rotNqY/eJLUzh4mM5dP4Va0YXV45x0O9F9FhkN5auq4eznaq3WmP1pDkuibW5uraNaqyNh23ihPA6v7wAVS+PwXAGkbYiUnU3kYm8JzvgGpJGdG6vzm15+ce6H79/9bnnBhCxG702dwnTaw4nyM/jsiTHsHx+DEyjKWnGEUpBOyjTTgbpsNHyLojPe7PK3qci58NvNu0Gl0YA8NIxWp4MkdzCdK2Ci6iNYXIV6UEfUDBC2Q/A3WqVbUUfVucWftYhP9fLiFf7yRPGVmZmhE88dJVmpGRMqRH4E3emSbnQR3lkzaqNB3br/J39tb1ibJglGfJDZbMReb37Td/bFhcnB/iNppXNUbZEKFGBJ6FBT+9cVo5c3yd/trDV3OxdFDDHFOV8IffVJtNNOC+J3xtYqATWw0Mm6RIJ9YAy9rdtt07q1ZtjdVXCYFRBG4Bv8A+lliGhzN164AAAAAElFTkSuQmCC',
|
|
'Applejack': 'iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAYAAAAmlE46AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAv9JREFUOE9dkmtIU2EYx88Roi9FfahkfQmS6kNGEBRlZWSY5tylTKepqR8MHYGl2R1POm2u5bCVlzbog2Ze591pzZPZxUskDZLMMLSWzcIca3MXt7N/55woqhf+PC8Pz+99n+fPQxAEQf6vhINb1nG5/ISdobWXo+9eSd4tyM7OJimKImmaJhsaGjjmX/DGqfDQmkvRg1x+9YrlZPd18fdupXiu6mxkOAcqlUqyuLiYB/+cayfD1rKFH0w3pYEHV4/omhTCyieVcYEB7TEYSyX21Mita/6u/91qUBMV00JrjmKwMg4zI2fgnlfD90PLx+nhMyinIrb91SFBFqaHBevPHb7G/fS06jhs0wXwO8rBOLXws2Kct/k4//HKRE+jZD0Pl2buD2FnmOlVSUFrpJg15/JFgcWKP0Bg8Q6fs1sVs+11wmAebKaEuiG1CC81Yozci+cL4KoC3JUIuCp4+R23+Ee4Dr5bisZmJi7fJzpLRJZPOin8vSlwdSXDO54Hz+vT8LzLh3uuCIuzBfDa1DzMPcrJMVfkIHpVEu94uYgH/aaTvOxdJzDZkI76smhY2mVwDmfg8zM5RukcvH8pbx96mLiPMBTG0nSpGK7mePg6k+DsSUZbSQwem02oba3DRsFKzNQfx9sHSdi1dzve5Ow4xM+ozorY1K2U2MY0IrhbEuB7lIqB6gxY7B9R3XoHAoEAivN74O5LAaXNwvNLe9PlcjlJACANRaIRztFh1iRvfRyYx5kIOCwY+GCE9GIUOjrzwZjS4H16FV80UT1WqzWIWFhYIBsLhDf7y46Ck1UvATNKgXlxHgHbJDyub2DGVPC2s+bVyGDTx74ym80kwe2fKvNASN8NySK3NeayWNagNPj7WaP62Uhn8HdPkwyWW3IoEjdv0Ol0JGE0GvmV0+dFpj9SS5kOKuahr01Wwbb2lXV6aakjkfF1p8DXlwHnaB5yTm1bbzAYfs34e/+0pyNic+N2ruIWmQWXcdE1dUEGd9UYq6kle1mXqVW6imWIn290AGVZutJTAAAAAElFTkSuQmCC',
|
|
'Fluttershy': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAA2xJREFUOE9dU91PWmcYP2uybDfrxdIlu9vN/oglverWNN3Fmu1iN7vY2q4utnE2Nu26ukyrUUGwExGpn3xY+TyACjrskFrcEYoWnCAM4YAgcJjROkFA1q789nJczNaTPHnfk+f5/d7n4/dQ1Cvf3Ut3Xp//Qnze36gYCt56kIgJpyqRFvrvcIvxMNxhSa9eV993XJK/+yqO/zdf7j7tbRz1RdstLzOKReRoLxJSOzb7HyKtdCEumgErmEbwO03U2aR8738kzq8ln8e6bXlWYMWmZA6Z8SUk5U5ytyPeY0Oy1w5O50FO+wQ5jbtG4lK19L5BGehzb9sE19+JtFt2c8ZlJPvmwAqtSA06EWs3g+2aQnacwdbwAmLknuiZxaZ4FiTD6tLFvi+pBeenb/3mvvo4Yu3D5v1ZsP1axHpUiAo0iPyg41/dGiNgiQI5PXmdXkai92dkVItYbZ6YpVZWLrrKFSOynBip9W6U/7LwViqZ8SykRWpcR8BqJNlmJCZp1LLMkIxSAw6s39WHqUCo/mDnWTdKhwRUMaNMzvLh5NFZsaBIbD+rJ34jgsxtcLQH3IQbKakDoVZDmnpk+irA/fEjCkXlv+AawX+MEJQJcaFEY8bWAJdMgYxyESn5PILNumUqJNVVA4EG7OXlx8Bf3T2QyRuh0X2P5ad9pCQTcjtqDI3UwTMuReIeaaKagb9u6B6VVi9Wg1YRUhkhH1g6NKFf3gD/2gAYz08YVd5AdltDfDS2d2QIrH6DcNcwUjLHc+aC8AMqLrW/4EwesBoligUTCgc05h52IH9gwu6+ERwBb+9pkc0IwLJNWHPXIyrUIdysW2POd52gopIZjtOSpgzOI2NToVAmwD0D9osmvvZSxcCXtr5wA08627Ah0yHZ74D3ysBNXokR8XQ8q2SQM3gQbZtAPm1AiZRyNIUawZGFl5qIRqbBdk4Sndjy1iviIymzIquXldirWRXDzzdOZr63q8J66OqOf+2yL8be+nMr3fry91A9NlRjvKT9tx88Pt6Djdaps0RZxQRZmCzpbHrMBV9b5/YM/dn7tSCT/cNTvpauFdasR5xkkCaS9n07Kj0mIKm+GbujP5OQ/vI8Ofyomhx0sOmxhU9W6wYp5uOO12qB3guik2TuI2QPXmwpXLGnjSMf3RRdO1Hz/QNneMt7Iqmg5QAAAABJRU5ErkJggg==',
|
|
'Twilight': 'iVBORw0KGgoAAAANSUhEUgAAABIAAAAQCAYAAAAbBi9cAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAA6lJREFUOE+VlF9Mk1cYxj+Kc3+yXWimFxuk2zTIn4bQFkppF0hDNmBpBtgKixhhQZAhbSkFBp1uZWg3ZLRMxFKE0qKtrMy2E2ztn2+1tLQgbuJiorvQ7c5pgplZNjfmePZ9nwtZMm52kufqvOeX5zznfQ9B/M9l/8CXPP2R/6ajy+u0amZeoI8D2PpfTLqMlZQpT9vE2fPOc9l73302q7rs6Sz5K6zM3ZuJzD2EVf1VytejC4hNXoWj2/vlF71+FgVKIsZVHrbnEzLoPkYOqqtPNm7j1l1J4R9Y4wgVkOR3Qcvrg+uNXmTnt9zfmdcUFRd1XqQhC+eWMXP8MiwKdyUDOqMLEG49qYtYlhA+vQi7zocGmQHFYi2UnM9wq/RzNEsOQyDWMBIWtjNurjivw2ucg+toyM+A6LWZU72vvsqwFjwVZwrmrEvoq7DBLDDiltQAobidgeRRUipMTA0t32AU3hNzD7zGSANBZMi2UFe5nyZohrREB9dxEnMTS+jgnUBYMghv2afrbhhHb3aAnFxkQMHhOALDid8p0EHiKU6VklvQil0UiJakqBsf77dCmTmASPEAhoqPIEN4CGmCJvAkauzKfw/5pRr4J+JUTtfo693zGSM7iBdzan10sE9gh5AragNXoEKtvB+93ZMY0TthGraB92oJVlYewDTgQJ96DKTtiStXb8jvNoafIV7i19+lndC2X+bXPyqXffj4kmV+PYexY1aQMwnkv1YGWUUljryvQ0/dqfV9+Vs9zVTYLILKZ5UGsXMbb2/llJaWCN8OnzNMrxda9JNYjt+ENL0RrQol0nekQVtlRHA8gsWpZQhEmrviws5yIpXfcG87t+52UpY8NZXN3lIjPRiOReZxfugCA7s4EsCN727ArHChQiKDYGchRrumELbFEbQmkFvQ+ofg9TYX8Xx2zfnkLDmHbgM2m00M1tortQf06FC2Y2HqGgMjvSR+WfkVplYPzCoX3EOziDmuwjMSRk6BajVP1PYT/fzb/j0nZ7tmN+n3mUlpUTmCo1EGFHJE8NvDR/g+egd0fj5LDN6xKHo6bOAL1D/niTTRDUd2rMW13VBj/zFu/5YZBaYBp69j0blMPfs8zhj9KCjspPNZ+6fjd28IGld4MgIn5x/HJr9ByJRYDz5oS2B6KIT9Nf3IEaj+pCBrXFELOTERZm0Ichy+lHy2czZlpv+y80JfmILFVwPDsTvmo26SJ1I9zBU1/UVBfqAk35ujpb+RpL8BJjxIUjyXvSgAAAAASUVORK5CYII=',
|
|
'Rainbow': 'iVBORw0KGgoAAAANSUhEUgAAAA8AAAAQCAYAAADJViUEAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAA3tJREFUGBk9wV9MG3UAB/Dv7+531971aKGMlr+OwjoGBUZwRDrRBJwj0bHEmeiS6Xwyxn8x8UVNzHAPPvliFhMzsy0m8uDD5h/QZWoUNxYMBoZbZCBjZTBoKRwtLde7cv9+bg/6+ZDnzk6C44lw6f6whdOnETpzla+0803RMD3ZGSH95V62lzGQtMH9M7MhfpPUyIX5HE1uvNXDaCQgtykB70cR/4unrn3aqzYkZt7v18ZfezyTkfy0HlJ7FMWKEBJFpYMSVq7bngMlGvvc/OTiLzRYLp8K1waObaS16MDIRfupG9c6SuwCsSt2kJ+/B+3HMdC6MBofa0N1a2sVJTWj02mh4BFCCpV84jN4oHyX3KYEJAi2BWYR2CkPmMlBiOgwE0mYiymo1Qu0Mx4/8VLVnrtnF4VxfuCN9z5mDBA9FJt7mzDe3oXkjou69CqoxkA4gC9xQAggankMa7uTm3m32SLKD+Sz6XXGGCDJAv6j7di4MzqBo199Adk2EIqkQGQHDy3Ij2Q+bHr9g3UxyFHLdFyvJHAg+J/ipYgdjuMyzwELCfRsTWG/NQEwhqCVC0YLy/qKGJzmD77w9pHSoFyjbWWxtjAH5jIIHi8EKkCpq8JteCD2H0F2u4BwZhE+x8BEWbt6i6df8kr/s0+H/HKMc1yo02MYaG9APjGLxJ+T2NxYRV7fxu66GqjwYyrn2AG7YFGw4FygeYiXjva/KoipxoaKGPY1N+PJfRHEauvQaIj47vsLSN67i87ew6hOLGFeTS38FO45XhR8lQlffS0tmGViwbmCdKEb3tJSGLYLieMwMfQr1tZSqOzqheCVkDWIk7i/vvJ7WdVVxd96XWBU4kzb55qOiZvqJazmCxhLGzBFiqbnuzD71xyij8bxEN/XzXccf7PyxJ6+lkxuwknnftP4vorBd9O1mXBAnsbfaQW6VQadcWC7gmiIH0JlrBWuw+DYgFyiSGqu+O2NjZllPMBJRUevuH4Ipu1DyOefrS6RzmQN211iFGUtzSAcD8dh2Ll8cyStai8vra/8MQhgEADvjx/bX78c6rgT1ddl722/btSelEz69eaWoZqms1kwrGVt27xV1I1zgdWfRw6Ww8lmswQAo6QR2dnM6JC6HT3PEfvctjSsnx+3J1uob6qt6gAtSgEu4BbdV2KO80T3O0QQBFiWRQRBwL/txI3OlzkSKwAAAABJRU5ErkJggg==',
|
|
'Rarity': 'iVBORw0KGgoAAAANSUhEUgAAABMAAAAQCAYAAAD0xERiAAAEEElEQVR4Xm2SW2xURRyHfzPnsmcvlO4ulN1uF2sLrIpdJNS0KUZFUq1t0AiKkpASbyQSjRKENEGrPuCTiUoTjSENKAnFYKokbZOmIBaoTRXB1AjbWmrabmVpt3SvZ899PFnTxAe+ZF7+D998mf/gbmwt30131B58YM+WTw7vbTnW/+oTHZda6490723uPP1KY0fna40dh/Y0fFz/4pq3XRFEsATB/2i71EauvDcplHN173p8of2gnI8KPHLxm/AEqwgIARUEeywyS1dVPZ+9kJ6OHdB/uzF2BmcYXRIdHxkhO/0vR/e9+c4p7+pIO+92+wlHaGE+QV1lYWpLCe90kdKVTvJo80rqDTic4nJfk7c62kM3rltfgQpSLGOM4ZfR0apQIPQTpSR04uhVqhUYSkoItLyMVFaEIjNENpTg8ZbVyGYK6PpyHIYGBhCmLiYHZ2NDzxZlpwYHaX3V2mMet3sPpZSbjc/B5y+Fw8GDgWEukcbURBLR2jB0TcPpz4cwO5aBBQJuWSnsbC09eeN50tnZSYy0s6p5V+MwIVghSQ4iFwqQHBIIIcVjGEaxXtd1XO2P4dr3N6EqCvJyFoqmgvqDlqZqp+jxD4/z8etKGxjxm6ZJxmIxnB8YwNDQEGITE5iemQHHcRAEATYIVPvB8ZQRQu05D45QGPNx2PYNNFxWV21y/h0AiCiKkGUZcwsZnDjTg7cOtuOr098hYxLYQJIklK8ps5hoaAyM2ZeAFwRQEJi5FEclT/BpxZBKFhdkQimFx+NBTbQG+1pfQFZ34tZtFd29PTAtC+N2dU9vH/t18sKCwPP4r46DQ3QySzcGKBGERzRFpYl4CkubPdd3Fj1nu5GduAxvdQNIPgNV1zBw/hy6+y+D510xUZQYzwlM5CXT5iID+5RailLNDINN/ZUCoQTLlnkQj8dx8uRJW2DA7V2F6H0RGJoGt8vFgqF7c2vD0T4wMANgd0yjP2Mqb+Ty2RkqMrhhmbh+JYnk7TSWl/pwuP0DrIvWoX73EWx/LIIV3lKIgoitT21Dy7aWPzU125/JpbOLukrA8U1ly8uGwxWVz1CXwOvE0qHIGq4NJ4qPHApVoKurC4defw6bKigCwfLiRkMBPzavL39w5/tPChk5vV+ZvzVHUknm4DhB13RKeZ5LlthlzDAQG00jkykU/5VTYKgJiTANE6LkhKIqTNW0nKqpvYauj89PzX5jcqxG0/WmeGK6bj6V+IHPy7nfV/hWbS5kM0gnC5iMLWBjXfhnAA0FRQGz0XVtzmJsZEHOH52a+uPirubtOmw2BfYmg9cSP2YsJ7uIbxlpfaitdk3l/Q/rlv7FnVzucmXdPS+1HtjyD8dzWCIvy76/Z6bY5MTs4tfjn7HBjwZxN/4Fq6rr1ZuF0oUAAAAASUVORK5CYII=',
|
|
'Spike': 'iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAYAAAAmlE46AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAsFJREFUOE+Fk1tM0nEUx/9QPtCD7z30nE9sbbVeXJJR6j8DkVsIhg6HTqSXnBHSMMEbEy+AgPwVQpcgNy+kKLc/lCgF09Wquaab67kHX1pulif+mHRdne3sd3Z2Pt/fOee3H4J8N/ow2lrj4H64OljRfEXBIZ/k/3lWquXIrQl2ROAVA98jOro2XKUtvV9Dpj/iFV/ppwvLVfzThEBZGRWh0S4hmFx+rId2ysmMSU6WAAUeMfDcdYe0gUrGdUOl7rZXBDRdRQtRp1PeIRlVctIzk+lHR6itJnwC1nkbgOXgZlhO3h6RY9rZKYT7W9NUKpUklUqRKjPDQADEjYTz3SLgzQjzMWua/5E5xLpQrqOX/jEzamTc4LqEX/KQRwRMBwfEDgnUOyXAdgk+1zr5e0w7J/vA15OfN28PW5SnZlRuVT3WeMia5oHW1AthawSS40mIjcWhW98HfF89Ifa6qb+hqAA6FA5xzIp/dVncYDc/hkQOiI/jBcctCegwdRJgsERWcszpZTrKU/3S7s+Ff4vn9UG4aWbGyofoaB60d05dDJuiR/8DcXMCpLY24GPsrlRWcxZxKmaqF0aCsDy8ArgtAVFL/Jc2C4LWBEwFNLCUbt9PZrpEiEk2VjbmMYIdm4TQ6Cq4RmYB02CwZAlB2ByBkHEVYhYcEmEreNZl4F+/C8F0+0vE2x1IL3qDsDgZhKg5Bt7ULAgHa+HVzlt4v7MHMQyHpM8LrlQzuNdaIfJCub+R0Z5DfNrAxsJAEHJbhXhue5nQJmS3t2D73S6suVK5XBKiYQMs4B3xSEbZ83xTc3ljq5eMmNts5/3d82/8jicQDc0Cbo8BjiVyQsez4rYkeNRzfqfadUYgEJBRFCVRKBQS0tTUSM7BxaauUelyenwunnZ+SnhXDkKG0EGgb+5g4p5dpa5TFEkk1bmfQSu8/TfTXs+Z8UbptgAAAABJRU5ErkJggg=='
|
|
},
|
|
not: {
|
|
'Plan9': 'iVBORw0KGgoAAAANSUhEUgAAAAwAAAAPCAYAAAGn5h7fAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AoYAzE15J1s7QAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAACAElEQVQoz3WSz4sSARTHvzMjygpqYg3+KIhkE83DKtKlf0C9SrTRuZNEx0VowU6CuSeJNlwwpEO2kJ6SQBiIUAzFjRDF4wrjKosnGx3HmdehFDfpe/2+z/s++D5gU7IsEwRByICIiAEAIiIAYAFAXsjYVr/fLxMRNVvN+prJ5/OA3+/XERFNf02JyeVyDx0OxyvLNQsnimLKfcf9KRQKXQAAnE6nlf5qMpnQycnbP/kAoKoqsSwLAJhOp+AAwOv1otvtpqxWq73dbt/r9XqvEQ6HUalUEvF4XLd5IpvNZqlerzd5nlf6/f6tTCZjBACk0+nb+XxeW4UrikLJZPImAGA0Gq0NIqJyuSyyANDr9Q5Wu1utFvR6/SULAI1G4+vK8Pv90DTtGwsAJpPpaGUYDAZ0Op3PHAAEg8H3tVqtbrtu21sqyxuRSOQJk0ql9IvF4r7b7f7pcrlejkaj57IsH58Pzp8dvjhc/lsBk0gkbLFYrFqtVvd27+4qOk733ePxPDCbzVBVFfP5fCiK4rvhxfDN/qP9wSasGwwGMv1HiqJQsVg8ZlfTHMepkiR1t05gGJBGmM/nMBqNj9nN9kql0lNN064ARISzH2cQBAGz2ewLu2na7XYLwzBbvxYIBBCNRrFj3BmsAZ/PZ+J5/kOhUIAkSVeA8XiMZqt5efrx9OA3GfcgvyVno9cAAAAASUVORK5CYII=',
|
|
'Neko': 'iVBORw0KGgoAAAANSUhEUgAAABMAAAARCAMAAAAIRmf1AAACoFBMVEUAAABnUFZoUVddU1T6+PvFwLzn4eFXVlT/+vZpZGCgm5dKU1Cfnpz//flbWljr5uLp5OCalpNZWFb//f3r6+n28ff9+PRaVVH59Pr//vr38vj57/Dp7eyjn5zq8O5aVVJbYV9nVFhjUFRiWFlZVlFgZGOboJzm5uZhamfz9/bt8fDw6+drb26bl5j/8/lkX1z06uldWFS5r61UT0tfWlbDwr3Ew76moqNRTU7Mx8P75OpeY19pWl1XW1qzr6x5eHaLiojv7+1UT0xIU0uzqadVS0nV0MxkZGT5+PPk497///ra29Xq5eFtY2H28e2hnJignJlUUE1dXV2vrqxkY2FkYF/m3d5vZmfDuruhl5aZlJHx8O75+PZWVVP29vT/9fTj3trv6ubh5eRdXFqTkpBOTUtqZmX88/RMQ0T78vPEvr7HwcHDwsDq6ef///3Gx8H++fXEv7tZWVedmZZXXVudnJp0c3FZU1f79fnb1dlXUVVjXWFrZmy8t7359/qLj455e3q4s69vamZjX1zy4+avpaReWFz/+f1NR0vu6Ozp4+f48/lnYmi8ur3Iw7/69fHz7+xbV1SZmJZVUk1ZV1zq5ez++f/c196uqbDn4uj9+P7z7vRVVVXt6ORiXl/OycXHw8CPi4ihoJ5aWF3/+v/k3+axrLOsp67LzMZYU1m2sq9dWF5WUU1WUk/Au7eYlJGqpqObmphYVV749f7p5Or38fPu6OpiXFz38fH79vLz7urv6+hhYF5cWWKal6D//f/Z09Xg29exraqbl5RqaW6kpKTq5uPv7Of/+PDj29D//vP18Ozs5+OloJymoZ1ZVVJZWVlkYF2hnpmblIyspJmVjYKQi4enop5STUlRTUpcWUhqY1BgWT9ZUjhcV1NiXVkkhke3AAAABHRSTlMA5vjapJ+a9wAAAP9JREFUGBk9wA1EAwEAhuHv3dTQAkLiUlJFJWF0QDLFYDRXIMkomBgxNIYxhOk4wwCqQhQjxgxSGIsALFA5BiYbMZHajz1oJlx51sBJpf6Gd3zONcrqm/r1W8ByK0r+XV1LXyOLLnjW6hMGpu0u1IzPSdO17DgrGC6AadrVodGcDQYbhguP6wAvAaC0BRZQalkUQ8UQDz5tAof0XbejOFcV5xiUoCfjj3O/nf0ZbqAMPYmzU18KSDaRQ08qnfw+B2JNdAEQt2O5vctUGjhoIBU4ygPsj2Vh5zYopDK73hsirdkPTwGCbSHpiYFwYVVC/17pCFSBeUmoqwYQuZtWxx+BVEz0LeVKIQAAAABJRU5ErkJggg==',
|
|
'Madotsuki': 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAMAAADTRh9nAAAALVBMVEUAAAC3iopWLTtWPkHnvqUcBxx5GCZyAAARERGbdXJrRUyGRUyYbY23coZFGDRFGEYfAAAAAXRSTlMAQObYZgAAAGdJREFUeNpVywkOwCAQAkAXtPb+/3PLWklTiIlMtDiH4rvpVM22K+WvY+7Z/dOxZ2xkLmYpNWo6RoKMUQJ8SYiozEYiZAuLbCZQsGB+/hC4SwZsdV2rTjSR0+J9tzXL0B4RW5f9VbE94skEEpHbpw8AAAAASUVORK5CYII=',
|
|
'Sega': 'iVBORw0KGgoAAAANSUhEUgAAACwAAAALBAMAAAD2A3K8AAAAMFBMVEUAAACMjpOChImytLmdnqMrKzDIyM55dnkODQ94foQ7PkXm5Olsb3VUUVVhZmw8Sl6klHLxAAAAAXRSTlMAQObYZgAAANFJREFUGJVjYIACRiUlJUUGDHBk4syTkxQwhO3/rQ/4ZYsuymi3YEFUqAhC4LCJZJGIi1uimKKjk3KysbOxsaMnAwNLyqoopaXhttf2it1anrJqke1pr1DlBAZhicLnM5YXZ4RWlIYoezx0zrjYqG6czCDsYRzxIko6Q/qFaKy0690Ij0MxN8K2MIhJXF+hsfxJxuwdpYGVaUU3Mm5bqgKFOZOFit3Vp23J3pgsqLxFUXpLtlD5bgcGBs45794dn6mkOVFQUOjNmXPPz8ysOcAAANw6SHLtrqolAAAAAElFTkSuQmCC',
|
|
'Sakamoto': 'iVBORw0KGgoAAAANSUhEUgAAABEAAAAQCAYAAADwMZRfAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAxVJREFUOE+Nk19IU1EYwK+GQQTVQ39egh6ibKlzw91z7rn3bvfOmddNszl1bjKXc5rJJGmBUr7Yg9qTD0IalFgRBEYg6EDQQB+GovQyQgiaUZsoLcgHMcr069w7MgcGXfi453zn+37fv3MYZt/n99e76tzVj4JN/hP79fvXnV3hnNabwUBjoOHcgTYOu/JQspgTzsqKgn9BfD4vkWTzur287PqLVy+zM+yePB7KsRXLywTjnSpnZctBkPCdW8ccDuU55vBO8RXbkC/oP5ph19V5+7LIky0OY1BKbZEbLcFSt7u6pN7jLmltCVrr3DV5jY3+KovFEsccB1KJNVpefe10BqS2tqqO4/AuphBB4L/LkrRqNgtJs1lMypLls1kU38mytMLz/E8VIlutqVqX6/weZG52OttRXjbE0cP/FYLRlpVjDXuQ/r77x2XZPKkCHA4HBAIBkCQpAygIAvh8Pu2MZgO0Lz+QSa/sQfwN9RfpVN66XC6Ynp6GhYUFGBwczAC1t7fD0tISxONx6O7upgHILmsqvLcHodOggfiV/v5+SCaT4HQ6IRaLgdfr1bIRRREmJyfBZrNBNBqF+fl5sNsdgE2GiAbp6bmbdbXC7qWQbxMTE7C2tgY6nQ5SqRSEw2ENopaoZpCXlwdTU1NaoECgCbgiU6y8QH+ECYWaTymK7TWdys7MzIwGaWtrg42NDejo6AB1WjU1NZo+FArB2NgYrK6uQrAlCASxn2z6wkuMp87VIAhkE2MEAwMDkEgkYHx8HBYXF0HtkQpRy1BLiEQisLy8rPVNKSsFjEzrXH4+z1hlS4xDhKadNu7t7YPR0VHweDzAEVWfHru6HxkZgeHhYVAURYNjkylVWKArZjjMzqmdVi+QCsLUkQiEjvDvncEkvU7/qQ0Vgukeo48Go87IiCJnZNmipxiz7wXEbVDnbUxQOgM12h9n6qTq6NvapRdtkwaP0XK8RmPuYSbxYfaQ/sJJhjfknuFRURUi7AMOozcCwl94hLZp5F+EioDQVwqYI6jomZU1NFtM+rOSxZjVazcyvwHr/p/Kws1jegAAAABJRU5ErkJggg==',
|
|
'Baka': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAA0pJREFUOE91k3tI01EUx39JOpA0H4jNx0pbD3XTalISWf8YFlEgldqDsBLLyqjEKBCiLLWiggh6/KEV1WZ7OaelLZvDdDafNW1JFraWe/32+01FrUZ9uy4ylLpw4Z5z7/nc77n3HIqaMRIjZJyEcNX+uFCFeGmI/GZciEIsCFJUTvoAzDz+1y7K76MSwhX5hXl6z+WSbrzU2KB8YEGDwgrTaxZ3b7xHcaHhR3xw7Z5/UviB1ReP5XSg3+TAqYJOxMzWISFIC0GQDomhTVA9skCnsaAwp/vnMq66dBokNuBR9uFd7T9Z1zCunjci0qcRJUVdoJ3DYOhRnC/qBZ+jQbfeCc+37yjY2UEg0iwvJE0k9l8Z+8xqHmTgot0QLdQgTaQFQ2AsOzlHvOu1S5pwOLsHHo8HjHMCq2MazNvTlByKHyrJLDvdR25jMWRxYx5HjeMH2r1BDOOeguRua4OI14jx8a8YH5tA+al3EHKlW6mYOapb2oZBOOwMbEMseAE12L+jjUh3w+VipyAZ65oxn1NP/GMYGR6Ftn4Qsf7qa9S82Y/l/X122G0uL2TbxmZEz1WhXW8mUol8moXu+SCi/OoQ6VsDh3UUwyQ1k9GOaI5MTkX4yWTGHutvgI1F28sviAlRgxeoRm62HvsyW8En9pZ1TYgi6TntoyQtFm86rVgUoJZRvDnKMmXVAGxWmkAYOBwudBqGcHCvHulrGpGT2Uy+z4yT+QYsCXtCUpp8GxbKhx8gDK0ro+KjJGvzdjfDZnN6VdisLD5/JjArQ2zW66PJOj2lEZtStaBphkwah7K6kMJ/GEulp1bMWhAmMbTozOQRaWRtfoZVgjo4iRra4SYgGi26TwjxVeDKhR7Y7U606ixICq9tr7hd7+OthRWL7yUnJ1WPmXotqLhpRICPHCePtuFV6xdUPTAhcWEtRHEqfHpPyto4hPXLXnzflSEJnFaN3OCKDcsFsrEntR9RUmxARLAUgT5iBPuJsXWDBj0dZjRU9yNV+PTbpjTp9OA/pOSk24nRkXf1J462oPxcJ65f6ULlHSMulepRerYDgvj7A0cKpNz/tyTZqbzXO4t0ZZGQJ34RH11lFHIlA8LIqreCCMUZRY3cd2bwL/5/RmjNSXqtAAAAAElFTkSuQmCC',
|
|
'Ponyo': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAACAVBMVEUAAAAAAAA/AAC/AADMAACqAAC2AADGcQBMGQCyZgDMGRnEYgDMERHJGhrOGBjHeQvSISFPGgjNgyDQHh7MHx9QHgqBGhHLeQzQHh7OGRnSHR3WJCTTJCTQGxvQHx9jLBbKfxjPGxvPHh7QOB7TJCRrLRrTJCRZJhHbljjeqmN3OibaLS1+NyXYMDC8NzPaKyvYKyvaLS3YOincQEDorFvbKCjdNjbaKCjuypjZMjLcKyveLi6GRi/hOzvhMTHrs2ftxpHXLix/OCODOCeGSjOHRy2IPyqJQSqKSy6PTjmQQS6XSDGZMSefWUKgTzehUz2jVT2kVDqkbVSlWUGmUTema02qZUqrbkyrckCsMSmwNyywbEyyQTm0XkC1YkS1ak+1gVK2Qzu3iVq5Ni26Qjy6oHy9JiG9ZUnCb0vENCLFxcXGdVLGpIzJdVDKfFbMd1HNqILQysXScU7Sck/TwrDXRS3YSEbcS0rdLy7d0cHd3Nref1XfSknfflTfhFnf3tzgwp3hLi7hgFXhglfiLi7iRUTiTU3ihVnjMTHjSknkMDDlODjlOjrlOzvmPDzmrFzm0bbnTU3oT0/oUlLpU1PpVlbpWFjp1r7qW1vqYGDrvoHs1rnt0q7vwH/yz6HzypLz2bb306L43bn50Zr62Kv637r82Kf83LD83rb837f84b0dlQysAAAAQnRSTlMAAQQEBQYHCQoKCg0PExUXFx0fISgzOTtCRUVMTVJSXFxcXGNqa3BykJegp6mqtLS1t7/Jz9DU1trb3eTn8/X2/P3IgXZJAAAA30lEQVQoz2NggAJmSUUlPgYEYDNs6es150II6HfNmNZhIAznizlOmdzdONFWCsLlENVyTixPKZs004oFxFe3CfDLyI5zi2mb2iPHwCCoqhPYXNvU1FQd7FNjJsLAwCSfl5+bXldU3B6bJsHMwKCr5+Tu6hHtHxbqHR+pBjRAu9U3YmFCeFLOPBfPKBVeRgbZipCCqoblKxdVlgQlG1uyMrCYZqbWz148f0JWoVennTRQj4DR3AUrlixdMX1OqbUM2FncJstWAMEqC2UeqLv5Nez7ZzloCiH5lV1cgRPKBAApxz0bK1ScOQAAAABJRU5ErkJggg==',
|
|
'Rabite': 'iVBORw0KGgoAAAANSUhEUgAAABIAAAAQCAYAAAAbBi9cAAAD7klEQVQYGQXBW2xTZQDA8f93zmlPe7qOrVvXyzY2B6ybTLksIAImanTiDGimb/pAohISEx980TffTHwjPviiDxiNokajMSAQIwEGIwzYTWAFcZdudOt9bdfbuXz+fuLHrz9935bFnbr3yY/6Y/3O9PQkXk8T6UyeYHuY/u1RCvkyqWyBJo+XQyOvIRQFKSVut4fJG5cO5HPJlCZz42+MjvaM3l5ZayoWu0+oiuqABAAAAEAIQa1aIbV6D6/PQAiFdCrbkU3/cjGTN08rfp/fzvyVY/fTm+9WauN/bhTKfqFogAQAAEAgsC2bSmWT1rYmfD4vdXPy84NDQX9fwN2t+CND91qsIMnzizx/xBjp27p0pVjI90g0EAIABCBAKIJisYLV0Hl0f/zkth3F40rCjaH6DEUx+s5uRgO0LfeycPY+I0cCu/cNzk+a5eWxekMiFDf1ukO10sBsSBqmws3xX4+0G1dPifU6SsJNplJaF7OTE5jJ76/2lwcPJ2cSbPTcIjbSiyUMfv69fLE3Eo6HQuYeR5HNlbJVmJlOmh2e1cMHXxzUzXMmLX1Bvl2MHxdrS3GSq/cPqInTl2P1w+6V63PM1xL49qrsOjaEt70d3edDShBCYtXr5JaWuPDVHZ5zQhT36PM388PD6rN795LLOyu37q7+W639cTTQoWsD/X6697fiHxhkYibJb+cfs2egA3DQNDdnrqXpjUWZW5h2HlpPvR3eOhhXXEKnyevG0zJwZka+PjSxmV1pGi6jx2IgdC7NrvLxTxe4Mb2I5nKDojC3lOaLKw/YMbLPaQ/FUp2dIbRgWzvegA8j2Ar19LaO8q0uJTRITfFQz+c4OTbM0PYou3aGKaSKlPLwyZu7KFmwtUVqldTsCc32faA4AjKJxy814tlvlq/+8GVvp4rt8iGlpF4s0N7i5dj+CLn4fzz6J0N18wXSCYXekI7LMGjeYh1cWiihrS/GXx20/Oe6up9hqlQDKRGlDKrmwohEsUwbKTSiQ9vp1lQya5fpDBgIVUG4VFrD/sj12wt+TatUXwn6fdSLj2iYFrViCelKoQuB1aghjS0I3UCoIJEEu7xIBxzLQqNCannt8e3ZjZJmmtWas3YXuzGHzG7hYXOGAXcWt2Hgskzk5gZ2Uyu4dLBNcGxUu4HiVMklkszOej47dGAf6tjYsXRzw3onpOGOqC1MzVSZym8kvdYGml3SPR6JapZQagWURhmlkqeWzfFgPr/x953wh31Do99FoxE0f7BrZt7leXliauI9vSH1dS0Qb+s9eupCfKa1K8tb5sT8bpdab7Vte7MuXDZaOJ+tBK5LredsOPpEMdLVjWWZ/A+8EtJREuofIwAAAABJRU5ErkJggg==',
|
|
'Arch': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABCFBMVEUAAAAA//8rqtVAqtUQj88tpdIYks46otwVldUbktEaldMjldM2qNcXk9IWktQZkdIYlc8mnNUXlNEZktEZlNIYktIWlNMXktE7o9klmdMXktFHqdkXk9EWk9EYk9IlmtQXlNEXktAWk9AWlNEYlNFDptkZldMYk9E4otg/p9kXktEXk9AXlNA4otclmdQXk9IYktEXlNEwn9YXk9IXk9FFp9o3otgXk9FPrdwXk9E2otdCptkXk9E/ptkcldIXk9Edl9IXk9EjmdUXk9EXk9EXk9EbldIcldIjmdMmmtQsndUvntYyn9YyoNYzoNc0odc1odc2odc6pNg7pNg9pdlDp9pJqttOrdzlYlFbAAAARXRSTlMAAQYMEBEVFhgcHR0mLS8zNTY3PT4/RU1kdXp6e3+Cg4WIiYqMjZGXl5mbnqSnrbS3zMzV3OPk7Ozv8fT29vf4+fz8/f7SyXIjAAAAlUlEQVQYV1XNQwIDAQBD0dS2bdvmNLV5/5t0UU52728CvGayQLx8UWz1eKoXhdBqmRaF6mbdVfzZXWgetomfpY3b4Hruqb7B97hf9rtT5mNZ+7ggyaHuHTxzzqIxgUy+LG+RWSBFjrQAgAhJF+Ak6ykA0PRJOgAj2QlKAOTISkADKMM1Mg4YJmXr585cEozw2vE3m/8J5h8V7jsI1XAAAAAASUVORK5CYII=',
|
|
'CentOS': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAB5lBMVEUAAADy8tng4Ovs9tnk5O3c7bX44LLduNO1tdDh7r/eutj43q2kocX23az07N+qqsvUqcmXl7331ZXJj7r40o/Pn8T42qP63KjNw9n21p3Y387Ml7732JzR55z05MSxtMLGn8TC4Hx8eqt8e62Af6/B4HnG4oPC4HzH44fBf7LCgbOkoMTcsrmtn8PWqcfFtKrj4Jvs2ZOz2FnMqLXT3KfY5p60Z6NUU5XRuqHzwWSywqDn3JaiiLWahrWhkry5zJjRmqm1Z6P1wmb1y319fK632mK5cKi5nH+73Gu73Gy73W283W+9eK17e6y1yZS3aqRZWJdcW5ldXJplXZppaKBwb6VwcKV5eKswL306OYNPTpGkfK+m0kGpUJWq1EnEqIuXK3+Xh7ahP4qhkryMfK6BgK+CdpGMaKKMa6O9ea2+eq6+oYW/eq+NbqWVlL2Wlr7AjanA4HnA4HrBkqbBlafB33rCgbLCmKjCxIzC1mSs1UytV5mtxIWt1lCuz2evWpuvXJywxYzHjrvH4oXIjrrN2HXO5pTO5pXUlYnUlYvVl5Hb0G7e0XTg03rhr5fpzHPpzXTp0Hvtz3/wrDHytknyt0zyuE3yuVHzvVr0wGP1x3T1yHf1yXe0ZaL2zYP30o730pD31ZeRIcF5AAAAQ3RSTlMAFBkbHEhJS0xMTk5UWWBsd4SEiIiPkJCVlZaam6CjpK29wMPDxMTFxcnK193e3+Dg4uTn5+fo6e/v8/P4+fn7/P7+J4XBAAAAANNJREFUGFdjYIAAcW4oA0rJOFnywkVk1VVNWyf1OehpaQqABTW8213jJna5lfnECoMF1NqaC2MmdM5tyfKHCJi4FpV69nc05VTXK4D40hVVtR5ehjqZDUkJNjwMDKKOBeUlxcZ8EnbJiSnB5hwM7GbRuRnpulJyFvHZ7mlKLAwMXLZhofnh9tYLF8ycrs8EMkQ7Nc830K93/jznOZJgW1RcfIMiG3tmOM+aKgIWUI4KCYio6Z42e8pkiAC/oKC8VV2lgZiQEBvcP6xGioyo3uVkhvIBH9A0EWEgTIIAAAAASUVORK5CYII=',
|
|
'Debian': 'iVBORw0KGgoAAAANSUhEUgAAAA0AAAAQCAYAAADNo/U5AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAZ5JREFUOE+Nkk0oBHEYxv8fu5GQj3JwcaDkIAc5IpR87M7MKnIVJVKclaIQ5Sy5OLkgR7n5OigcSNpmd2c2Vyfl4KT8/muWiVU79TTv+7zv837NCBF6PG1X+NpZyEYSD9mIc+tHnBPe23B9xKrCuTmbQA/JKfABrhBswa1hH4A38IwfOxPdX1qcjiCQxO5NyrjKV70TnSbeRPwJvGN3i4yyqnEucPY8ZZX9GSEgGK+RvFfyjk2VKZxzBNG8wJWWgh/xtDOeUXZ7Slr6TrSLYL9N4SMgYTTcwdc2ArvJcElhSVcM6mCNSV8n9hA59yTU5UWMG6HIbLhIWlglgWiC2L4Z79qTdo40D6ISuOWwKCWHyk9Fv8ldpUHOuGTuynwSBUynddPdlbEosVpP9Eu4FnOsRzUYNTsdmZN/d5LDiqM0w+2CMdAFFsFGWgfXxZnheqe/z+0puwEM0HHYV3Z9Sgz8TEz7GkQvpuJ/36ggj2AaHLrSlkULWV5x+h2E8xkZL16YVjGNaAUscfZ/f6c/k9ywLKI2MMcRWl0RLy007idmRbQJ7RIfDAAAAABJRU5ErkJggg==',
|
|
'Elementary': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAACXBIWXMAAABIAAAASABGyWs+AAAAAmJLR0QA/4ePzL8AAAFuSURBVCiRfVG/S8NQEH4VimAHcXKS+otIsNb2vpc4W0QXF8FBqKOiIEgQKTgEK/gXBKEOIoIIgmMo6KSIkxYXHRxcqhjQQpQKOojES9K0mxwc7919d/fdd8IToemKLMKGw2bLoq5E8dDFyIALixZlAWvsd/BBhog1ACKGMiqkyiVU5SGO8EQzmV66QNmHMICrK4hjHXUt49dgHM+D7ekELslggK7AJVUbxicmo7l4yY56Yqwbrq4IpmZx6FweN9MdcOVQ8CrRpoBNedGGLzkXAWgFpyF13soWcHhAP7xsMkyPdOFRpoL6DXzDYYDehwF4NBUEO+UNbQd9cvhhCANsbYK/1zA9oWm4xbKf1nrwii3K8wgmWeLKVdSxhzfK+Wk5ixoOmIPFJHnNGit3D4/tShZol1Wp0jR3VYM1A6F+YWaTNI8T3OEMZjrBPeOsrtGS+iFUsbmqyn0iqRvHepf7WJApUpmaxeq2jvX/uf8A9h7IjHC1AQkAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTMtMTAtMTVUMjI6MjM6NTQrMDg6MDCQ664gAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDEzLTEwLTE1VDIyOjIzOjU0KzA4OjAw4bYWnAAAAABJRU5ErkJggg==',
|
|
'Fedora': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABPlBMVEUAAAApQXIpQXIpQXIqQ3UpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIqQ3QpQXIpQXIqRHYpQXIpQXIqQ3QqRHYpQXI8brT///8uTYMpQnM5Zqg5ZqnS1+I4ZaY4ZactSn8uRnYrQ3MrRXgsRHUsR3s8bbM8brMtSX4wUosxVI01XZw2X50vUIguToQvR3c6X5o6aKs6aq08Un8qQnM9VIFDWINJXohKcKlXapEqQ3UvUIc2X55bhcBdcJVgcpdhfapmd5tuk8dxgqJ1hKR5jbB6iah/m8Shudq3v9C4wNG/x9bFy9nFzNnFzNrIz9zK0NzK0t/O2+3P1eA2YaDU2eTb3+jb4Oje4urj6fHm6e/s7/Tz9fj3+fz7/P38/f3+/v83YaEa/NNxAAAAHnRSTlMABAoVGyY1SVlpeIuQsLfDzdHW4+3y8/b39/n6+vr4+ns8AAAAxklEQVQYGSXBhUJCQRRF0SNYgIooiPJ0zwXE7k6wu7s7//8HdGAteeFoPNne2lhfpYpIioqWWnkNeNv3X+87HXWSIni73/b2updvq1E4hffys8/ag5toUhRv0QpAn5tCcbyiXQBZN4mSQG62ZDf9Q2PdbhplyPacmPe56TZAwcyIOy4828fj7cp4DhTk3ToU7YoKdbleoGiXlKXVOToPbNkpZTEFv25uefXJDvASIWWGF+7M7GyJf4lqqZnBw+vzowEgHQtJfyetJP7BfFOIAAAAAElFTkSuQmCC',
|
|
'FreeBSD': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAADXklEQVQ4EQXBS2wUZQDA8f83j33M9rF9d7u4loaWklaDpkSo9KDGaIKUaGxshD2YSPRiuDVeTDyhBxosJCoa40ktpAkPDcUqAYVIpUSUPrAulEdD2bbb7e7ObGcfM/P5+4kwKDvq6yJ1FYYcvb+YAkqAHo/HQ7FYrFIoCiurq9ZXJ06YSOkA+kBzfX06bys3zHxS9EL0tXDVyZfefacqV+X/ZSJx5+qLbx98LhaL9RiGEZWlEsWC/Thd9q6Pf3vs2u6Orc83rFsvTwwfLf5obgywT1Vjh2Hh+rbNsnTssJdNLedK5aIrpSuldKVXKsnH4+Pyn6FDXn5tMef9O+3NvdkvP1V4+EYw2AoQ+KSx8dRYS6NXXnwovaItXduSrrkinWxGOmZWJi9OyOK9m1LmsjIz9IH8QUMOd3WfAQwNKCy2tJwbHB5+XasPaxIHmc4g7WWEZ1MquBiRFlJTf1E7+Tl/H/8asavPzTY1nWd2ZkMDRPeBeHPz5ojwsilEQCBvTSKunCF3M8FSNkBGVTHDYYrLj8jVNhDZ2SMa2zo3MTamaIC/u6Ojr3DtrOrvP0BpdATnyBeIhTxpR5ABUlKSUlXS1dWstbVxdz6hPL0l1quGqkLaKwNvVcjEXNRd/4mit4Z19DjefBEPyCKxgQJQcF28dBrHNDGTSZSezsjeff0hraa2Vs2vrvit81O4vj9xLJcC4ADrQA7YAGqBGsAql/EtLdFQE/L7dF1XZmdnSrbPMJfXoLDmolQK8gJyQBowgQhQDRQBD+hsraVhd4e5MH+/oExfvWLJ9q3/3S7qMpNH2hsS40kFS4EUUAMA2IANRIBXv4uzuO67c2PykqkA5YmZ6bN18YPi0Yoknxc4AsJPCMLVAk2BLKDosCWqs/PZaulkuxk9fekcUBAAQGDks5FT0W++3NuYuC0DVUL4DIEdlIQDAj0IRkigaMjArkFx0tf523sffrQHyKsAgHPhwoXLL+yP9/kePNhk5ExUTyKFkJVAUAiCFZrQup4Rv9ftuLV/6ONBYBVABQAArMvJ5MXW7duD6P62sD8UrPAFRU1TpeCpCnGvPZr7WW///v0jpw+VC9ZdAAABAAAAAMLo7drWrmQyPWG/r8tnaGIjaM05ujr16x/ZBFh5AACA/wGZnIuwraa4ZgAAAABJRU5ErkJggg==',
|
|
'Gentoo': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAB9VBMVEUAAAD///+AgICqqv+AgIC/v9+Ojqqii9GAgKptYZKQkOmPj/ddUYBgW4eVjeCTgfiWjO5wbJaZkvPBvepkXomYkNldV4Bzbpl6dJ+Uj7ynoO6Vi+1qZI63se2mnudjXYjOy+GCfaqZjvWlm/Pc2e+Oh7NeWIOWjfeXjeW1sd+gl+diXIfp5/KHgKnn5/F2cZx6c6ZgWoXc2e6dltrAvNu0scrX1eTOyujCvup4c5qpovVpY43///+6uPPJyPXq6fvm5vrz8/z8/P7+/v/d3PixqvmxrPSyrfe0sPO0sfS3tMve2/3r6vy6ufPz8/3d3fi3tM63tPO4tsu5tsu5tvO6tfe6t/Vva5KRjKy7tvW7t/W9vPO/vM+/vvPCwfPEw/TFwvTFxOfGxfTGxvTHxvTIx/TJx/aTiOrNzPXNzfXQzfnRzuHS0fbS0vbT0uHU0e/U0uTU0/bW0+zW1ffX1vfY1/jZ2Pjb2/jc2uSTiemVkLSlnvbe3PTe3vng3fzg3f3g4Pnh4Pnh4fri4enj4/nk5Prl5Prm4/ymn/bn5vro5/rp6O/p6funoPWsqs3t7Pvt7fXv7vzv7v3w7/nx7/3y8f3y8v3z8vytqPWuqPX09P319P319P719f339v739/34+P35+f37+/+uqev9/f6vqvSwrPQAR0dcAAAAPHRSTlMAAQIDBAgJCwwVFyAsNUFHSVBneH+Bh4mVmZmanKCxsrK2tr3ExtDW19rb4ODl5u3t7u/w8/T6+/z9/f4MkNJ1AAAA7UlEQVQYGQXBA2IDABAAwU1t27aNi1Pbtm0rtW277+wMgEN05nRWjBMAgCJgVUTed+sibQEg9EZEvm7V8x05LgCOJSKi1+8XdKmUhT5AyIuIvHUOLDWoyvKb/MG3uVRExuOTzvqUf6fDrthEfc/diXwczXbX/h7kpYCle+qETrQ7Y+1VDysbaYAiTER3bhhsKXpcn/QG8zgR0e7N9Cjrr0bCLTBNEJHXk4Whtv77ymArCBL5eVKvjfZuHS97mQEZn8+XhxVThuviRGcA0ss1xk3NRXW2nzUAeNZsL7Y25gbaAwCYuMUmR3jYAQDwDzDCPrxVMnjZAAAAAElFTkSuQmCC',
|
|
'OpenSUSE': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gIKDigueojqlAAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAADEklEQVQ4y5WTTWxUZRSGn/PdO9PpdKYjbRmmrWmm/00ptlS02FqjEgpRNCxo3Eg0auJCrJqYmGA0hEiC7ghroy40Rk0wppYiIbEBjQSlFEJFWksTqv21vwydmTv3Oy5GFho2PvvzvHnf5MA/XP5jqPPMtU8fWFr6q5P/MDT+uTM1PybcBZlbmD0dL9u0c2j8Cx2YPEqkoBzR7G9V0Y61RyueW0+Eq38NRt2XAX6c+Lqos2Zv6qcb/Wyv3pMXvNgfT9fGHioImcLcjbWLbtAEyPheNmtX1bMeG4IVwZayHmku6Z6LBst7Nld2jNxJPz/Zj/QNNqnFs1bVuOKiRgCLWBcRyNoUgqvhQETAob1sz8i+pkM7bq6Mpms3bUm5CAgB46IggBVEDKIWS44d9x6gK/6MpHLLCA7vXXysJuCEFnq3vC2fXTpkXMjfIfmNREBV8cjQXvo0YSfGwQttVIab8TTDW+2D0cMXunKTc+NfJeN1+8xdlxUH3+boLn+B01PHqSraxpttA4SdUlYyMySLt+pHV19qBMgLVFEFweD56yAWEWFm/TqJwnrm02O8+3MH4ytniQbiZHO3AxinZXhy8GEDoAgGy7pdpbfuKBFTguBwYuIw+xuP0VKyk0RBLW+0DnBl8Ttu+7dYSU+xnFvYbe70tgKFJsrVxZO88+AP7K0+SNau88HwEySKGmgt28XZ6Y85N/0hjjgE3Cglwcpl6TvVpCiIKJYcaqHAjdBbe4Sme7q5tPgtv8yeYCkzjxEl6ERoiHVmHql4/lpiY2WbvDrYqAiIku+uDhYla1PEguVUFNbzeNUrJEI1qCqz6d859+cn3Exfp654a6f0napXUSdvEIO1ihGLIICDMYbl7AxqBas59TUjyeJtNMa2Dz973/v75cDJWn/NW8w6xsVXD9cUEDAhsKDGx/dz+GTElbBJRlsDDRu6ZkNOZNdTza+NALgVRZu/fzL5ejTslup8eoLp1BhTq5fxxCNkwsTD1SSj9/vVxW23NpZW9sAAX145UgTwzegxUNUg/4P+0eP/euu/AVF+N0gj+MWXAAAAAElFTkSuQmCC',
|
|
'Mint': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAACVVBMVEUAAADh4eEAAAAAAAAAAAAAAAAAAAAsLCyXl5dgYGCnp6eTk5N3d3fBwcGqqqq8vLzNzc3Ozs7Ozs7Pz8/Pz9DQ0NHR0dLS0tLS0tPT09Pf3t/Pz8/i4eLb29vZ2drZ2tna2dra2trf3t/u7O/u7e/u7O/r6+vt7O/w7/Lw8PDy8fTz8fXz8fbx8fHz8/P19fb49/j49/n6+vuPxlmWyGOx437h9NDr9eD6/fj////+/v75/vTA5Jv6/fb7/fnL5bDL5q+AxjeDxUCEzTyGxUaGzjyHxkiHzz6J0D+Kxk6K0kCLyE2M00WNy06P00mSz1OUyF+W2FGX1FiY0F6Z02CZ21ac0Wiez2yfz2+f2mOh4GCi4GOi4WKi4mOk12+k3Wul32um1Hin0nun4G6n5Gin5Wmo23Op2Huq1n+q43Cr526s4Hit23+v6XSw34Cw34Gw6nWx4IKy4IOy44Cy63ez146z34az4IWz4YW03Y217nu38H2625e645G74pK83pu98Iq984W+4ZjA4px0tzDA5ZrB8ZDC5p7D55/E947F6KHF+JHH4qvH6qTI46/K5LLL5LN1tzLL5bN1uTDL57DM5bPM6qzM66/N5rTP6LbP6bTR6rfS573T67vT7LrV7r3X68XX7MHX773Y77/Y9rvZ8cHa7cjd88bi88/j8tTk8djk9tHm8trn89vo89zo9N3p9N3p9d7p9tvq9d/s+93s/dzy+erz+O73+vT4/PX5/fT5/fX5/vN1uzB3vTD6/ff6/fh5uTj8/fv9/vr9/vx8wjV/xDmrMRH0AAAAOXRSTlMAAAECAwQJDzk/RUlNU3F0kpSVlpeYmpucnaKjpKWqqqqtu8LExMTEzdTU1NXY4evy8vP+/v7+/v6LaR1mAAABDUlEQVQYGWPgk5QQFxMVERYSFODnYGZgYJA7vMfa2nrXbltbiyOW0mwMDApbuzsbq6sKslJiok0tFYECW9oalqwuyU2NjQoNjLfkYpC3tCxevDE5c/nShBUdfmZSDJw8Rr3zN0Ru2n/AaptlXa0G0FiDrnnrgizLsg95LVqfp8PAwGTQPnutv2VOmp3P9M352iABm5lrfC3T4+w8pkEEDJtmrPJeGBY8y9VmWSFQBYN+c892TzcXp2POlfVFIAGllQGWc2qSIsIz+kMqQALclsalOywXTJjUl+heDhJg1d1pcnBiy+S9+446tmoBBRjY9azMp9rbOzhMmWulycAIFGHhlVFWUVFRVVVXkwUAyhJUc5MwaMIAAAAASUVORK5CYII=',
|
|
'Osx': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABrVBMVEUAAAD///////+qqqr///+ZmZn///+qqqqAgID///////+tra339/eAgICoqKjx8fGMjIzm5ubh4eGPj4/g4ODIyMiAgICSkpKLi4vS1tbPz8+Xl5eMjIypqanIyMjW1tZ2dnbR0dGamprFxcV3d3d+fn60tbV3d3dcXFx3d3epqal7fHxxcXF+foCnp6hYWFhyc3Ojo6SMjI5fX196enp+fn6Li4xERERqamqgoKFpaWmFhoeen6A/Pz9QUFCWlpeSk5SUlZWUlZaOjo+Tk5RHR0cuLi5YWFgwMDAeHh40NDQ3Nzc6OjpcXF1rbG0XFxdSU1NVVVVXV1dZWVlbW1tnZ2lwcHABAQEEBAQXFxchISI+P0BISUpaW1xHR0kNDg4qKyszNDU1NTY9Pj8NDQ1cXF4XFxhSU1QSEhIDAwMrKywtLS4uLi4wMDFHSElISEggISE0NDVJSktNTU1FRUVWVlhGRkYEBAVBQUE0NTZQUVJQUVMFBQUqKitWV1lXV1daWlpaWlw+Pj8bGxtcXV9dXV1fX19fYGFgYGBkZGRlZmhpaWlsbGxwcHB2dna844Y9AAAAV3RSTlMAAQIDAwUFBggMDhkeICMkKCgqMDIzPj9ERFBib4CCg4iMjZCcnp+jqamrw83W1tvb3ePl6Ojp6+vs7u7v8PHy9PT09PT3+vr7/f39/f39/v7+/v7+/v50ou7NAAAA30lEQVR4XkXIY3vDYABG4SepMdq2bRSz/capzdm2fvOuDO397Rw0Ly4tz2QAQPbcxuZ2E/STJwfxPhWgG355fRrVAIVb1zeP9UDLfiSwkAcADe8fn7tFxWuEXFRDoer/OgoMTRBCumj8yJwPBo8Zhpk14U856/HI8n0ZUtpZ1udrSzfVneA4roNKjdrwpcMRilb8d8G60+lKnrpWcn9bO+B23w2O8Tzfq4aiNSZJqzn5O4Kw16h06fPZ+VUlUHfo97+VAEb7rSh2UgDd4/U+TBlQY7FMj5gBIGvcarVVfQPVPTG94D0j9QAAAABJRU5ErkJggg==',
|
|
'Rhel': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABj1BMVEUAAAD///////8AAAD///////8AAAD///8AAAD///////8AAAD///8AAAD+/v4AAAAAAAAAAAArKysAAAD///////8AAAAAAAAAAAAAAAD///8AAAAAAAAAAAD///8AAAD///8AAAAAAAAAAAAAAAB5eXn+/v5JSUnKysrS0tJ5eXmqqqqxsrL+/v4ZCgknJyeHh4eIiIjo6OgZCAdOTk7t7e3///8GCwwPAAArKyv19fX29vb9/f0EAAD////+/v4AAAAGBgYHAAAJAAAMAAANAQAPAQAVAQFyCQV9fX2pIRzmEQjn5+cBAAAFAAAAAADnEQjvEgn////uEQjyEgnsEQjzEgnxEgljBwPaEAj9EwnwEglHBQJHBQNNBQIBAAB3CQR5CQSHCgWLCgWRCgWTCwadDAWmDAapDAa/DgfKDwjWEAgGAADh4eHiEQjmEQjmEQkKAADoEQgLAQDtEQgMAQDuEQnvEQjvEQkPAQAfAgEuAwEvAwE8BAL1Egn3Egn4Egn6Egk+BAL+/v5CBQJrB0muAAAAT3RSTlMAAAMEBAkYGhsbMTRLUmpvcHeIjLe6vcHCxM3P0NbW3Ojp6u/w9ff5+fn6+vr6+/v7+/v8/Pz9/f39/f39/f7+/v7+/v7+/v7+/v7+/v7+Q8UoNAAAAO5JREFUeF4tiwVPA0EYRL9SXIsWl+LuxfcOd2Z3764quLu788NZNrxkksmbDP2R7vH6GioLs+iffEzNXd4+TqPErUUpVqMOvwgdzMPn1rv5vPsVeufBTaBK/bH2FPvkEUuIG5jIIc+sHYn/HJ3dC/Hxuo4y8s44dzwBbFkisHN8bVIdXs6jb+H97aCwbHEIqgcml64CD7YllNkAVQC940MLYe5YzvIeQAXNrd19Roc5MdzfdQLUUKaUYyuG9I8y1g4gj6hIak4X5cBIT2MquZJrJdOqpY11ZpAiqVwbY/C7KY1cRCrZxX4pWXVuiuq/hs49kg4OyP4AAAAASUVORK5CYII=',
|
|
'Sabayon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABvFBMVEUAAAAcUaYdVKwAAAAAAAUABAwWRY4YSZYhZtIhaNYHDx0KCgoFDBcKCgoRMmYSNm0fXL0fXb8AAAAYS5gaTp8fXLwgXsEGBgYFBQUZSpgZTZ4JFSgODg4IEiIOJkwOKVIkW7EnXbQLGzUTExMKGC8LHjwMIkITExMiIiIPEBEPJ00QEhMXOXAaPncOJEgoXbApXbEcHBwwMDAEAgAfHRgQDgo3NC8AAAAHBwcKCgoLCwsJCQkaGhofHx8lJSUwMDA0NDQ4ODiRkZEICQocHBweHh4GBgYHCg8mJiYnJycpKSkrKystLS0uLi4ICAgODg43NzcRERF1dXUUFBSjo6O1tbUbGxsEBAMLGS8MDA0iIiIjIyMkJCQNDQ0NHTYKCQkoKCgPDw8QEBArMDkKCgkRERIREhMxMTEyMjISIz00Njk1NTU2NjYCAgIVFRU5OTo5P0c8PD0+Pj4/QURAQEBHR0dKSkpMTExSUlJiYmJlZWVnZ2cWFhZ2dnZ4eHh8fHx9fX2FhYUXFxeVlZWXl5eYmJiZmZmcnJwZGRmlpaWrq6usrKyvr68KFiq/v7/FxcXY2Nji4uLn5+ft7e0yif9uAAAAN3RSTlMAAAApKSkqKioqg4OEhISEhoa1tra3t7y9vr7S09PT09TU+Pj5+fn5+/v7+/v7+/v7/v7+/v7+70RY/wAAAPlJREFUGBktwQNbQ2EYANC3lt3NtazltvDh+s52tm1z2f7Dfe3pHPiTllfT1V2bnw5xCVDUPruyub271VEMicCUTfQ6XEtritq/XA5MwVvw7NFydOB0e+WhQoCUzh5MxmcWPRZxxNHXmgo5doyxDd3ESPhaCNtzocrsY9BXFPHU7zdXQ+McTwhZ//lAhPC+ySZoIBuUUv77HVGbNTJYB5X4SnZh8hlBQuhYHq6ArPnphxdtP/p88vQqBBcyIKnFaD29vdO0+0tlwNiWDMCJ0ujOeejicEySRA6YUqfJs7qnur2mqRKI4wxKQFUDioGDf7psfXO9PlMHzC/HlDtslvM8zQAAAABJRU5ErkJggg==',
|
|
'Slackware': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AcEDi0qZWWDgAAAAx1JREFUOMt9kktoXHUchb/ffc1M7rySSdJMOknFPMRitLgoNKKI8ZHGKkgrjU8SitidimSh2UkXoQmoO1dGQSxJjdvOtqSaqlR0USEGSjVJGxuSmWR6M3fu4/93YX0g4rc9HA6cc4Q7DI+fpzz7PA8++2mxvZAeBZ4xhHtFcJRmXWsWvb36/OLcyxf5B/KHeYHy7DmGx1+YSDjmWTdlobTGMAStQGkNoLXS4tXDq7u7tUcWz49tA8jR8QUuzB5n5NTCV13F9JEo1JJwTLKuzU61QiOMcd0UDb+BncwQK3Rl15eNja3ui/Njq8aF2eMcO/XlBz0H8oO2ZUkum6A13WB99TtyzXlaCi24SaFa+ZFCzsG2DNnfkdbFjsI1APPhk+d6ujqznycdCxFozadYWvyMpx47wa+bPkGksKwUNnsk3TaCGASRXDZh5LpHXPPg4Rcni+3uYBxrtBbQghlscOVKmYHeEm0ZIZ9xyLffw41ND6VAa43SmjiMByzHYtjzwr9arfshxf5jOKlvKZfn8es77N2uks24PPfSFD/9Uvt7AtPKWmEU9d645eHYJo5tcKi/FX/zG+zmQxQH+rANk862DOW5N/hhaY64cJSa5xNFCgDDILZACMKYWAmh73HmzFsMlBQJ06LeiMinE1S3KzRCm5rXIIoUIoKIYCVM36urZFbEoiBLNMIhAE6/NsSB7h6SKZdL8xsUOnpx9j1KbTdARACIowArYe1ergfNT2i0mIbJys0GI6PT3N1/hJvrPxOFdRJNBQIy/FapI4Bpgohgcjuw+jq8jy8tV55MNBWI4ohS802CpizKv8q+FgALZAfYgSyAZtNro1oLaU1VvxCA029Oraxs7u/tKnXiNjn8HyKwur6lI++6vPK4V7IA7u+1Dyu1tr183ddNbkHuXP8/zEIYeFqiLRl6YO/p0bHJdflT/PD9qZa1W+ry99fcvlAlcZwUpuUAglIRYVgnDEIOlna4q0M/NPnuO1/PzMwg/045O/XeibUt5/Xangx6viSVFpK2jtMpvdyWCz+5ryf10clX3/amp6eZmJjgd441URWWJY8BAAAAAElFTkSuQmCC',
|
|
'Trisquel': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABjFBMVEX///8AAAAAAAAAAAAAADMAAGYAAAAAHFUAGWYAF10AImYAIGAAHloAHGMAKGsAGmYAJmYAJGEAKnUAJ1gAMXYAJnEAJGQAI2EAK28AK3cAGTEAMHgALXEALXgALG0AFUAAI2oAK3EAMngANoYALXMANIAAM4IANIIAL3gANIcANokANoQANYQAOY0ANIYANooAN4kAN40AOY0APZMANIUAOY0AO5AAPZUAPJAAP5MAPpQAQJUAOYsAPpYANoUAPpoAPpUAM4AAQJkAPZIAPJEAQpgAN4cAPpQAPZUAPJEAO4oAOosAOo8AQJoAOYsAO44AQpsAO48AQp0AP5UAQpoARJwAQ58ARaAAQZgAQ54AQ50AQpgARaIARqMARaMARaIAR6QARaIARaEASakARKEAR6MASqsARKEASKcAR6MARqYAR6UATbEATa8ARqUARKAAR6oARqMASKgATK8AR6QATbIATbAASq0AR6cASKgASqwAR6UASKcATa8ASqoASqwAS6wASKoAS60ATbHn4CTpAAAAhHRSTlMAAQIFBQUGCQoLDxAREhMUFBUYGhobHB0eHh8gIiIjJCQkJCYoLC0xMTE0NDo6Oz1BQUNHSUxOVFVVVldaWl5iY2RkZWZoamtsb3FycnR1ent9f4KDhIiJioyNkJGYm5+foqOkpqamqKmqrKytsLKzs7e4uLy8v8TFxcXGx8rO0NXY2eZc4XYcAAAAzUlEQVQYV2NggAMWdX12BiQglJ+SXqIMYqmHxQdJMzAEmXLKuCcyMTBYNWYmNTVYMARzMToqlAsycFYYSBppFFVp6nqa2VkVcDCIFXK7GfrrlWWISKjqpAUwMPDkibIz+Inn5iSHxxQn8AHN9Ig1d7DRzimtrasO5QJZwqhmrMoQ2Rwix8WIcANrTaqAT6AWQoC33t5Flj1CCS7AUenqrMJk7YRQEpXFb6LoawvjMjIJZ8dZ+maKMcHMZWST8or2lmdD2MPILKYlxgziAwCs9yR3GXo0vAAAAABJRU5ErkJggg==',
|
|
'Ubuntu': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABKVBMVEX////ojFzplGf1zbnqnHLvs5P10b3yuZv1xKrytZXvtJXys5LysI32waT0n3HxiVHwg0jxhk31kFn0h0zxf0P0hUrveTv2iU3yfkD1hEfyejv5eDLybSX0aR7zZxvyayH6ZxnxZBj4YhH7XAb5WALlUQLeTwHgUAHeTgHfTwD65NzdTQDdTQHdTgD31MfcTgLcTADcTQD////xt5/31Mf54dfmfE/dUAbeVQ/jcUDcTgHeWBnnflHohFvpjGbqkGztnX342Mz53dLgXiP65d399PHdUgrtoYLyu6Xzvaf76eLfXB/rkm/fWhvupojwrpTeVhTgYSfgYynzwa30xbL1ybnngFT31snngljhZS3539XhZzDiajbibDn77OX88Ovrl3X99vTjbz1fisGCAAAAMHRSTlMABgYGBwcHJiorMDA1NXGHjY2Nl5mZmZyfn6O5u8XHzc3X193j9fj4+vr6/f39/f08OUojAAAAxklEQVQYGS3BBULDQABFwY8WLdbiHjzI201Sd8Hd3e5/CJKWGUVio0u77vJYTP/iG7RsxhXpmDe0BDsHc12SpgzkyscnhVojZ8algT34KD5YGxTq4PYpabh+es3fXJSbXy8wIgeO7Dehkr2HFZnLn1SQIXToXcGWtivN7GmayO8brGsNKjZFKGs9WNWsIVP182fp58ZnHSY0ZKBYurO29ngLbr80Y4Bzz3v3fUhI6l2krbrPQqdCPdOGtmS32oYTjjHO5KBCf5XaKpkxFPzRAAAAAElFTkSuQmCC',
|
|
'Windows': 'iVBORw0KGgoAAAANSUhEUgAAABIAAAAQCAYAAAAbBi9cAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAA+pJREFUOE+F0n84FHYcB3CWSsL9ojo/6ik64c6PnTjmSS0limmrpBm2G002y++xzXRz6zE0R4nbw+RnTj/WD4sbanLkkAe55ccYlyNme4SrO9u9d13PI3/saZ+/vs/3831ez+f9eb5aWsuqy2mjRYeNUa7YmtjfTico7jNJ8z0eG24NB9vvnDrvufzpq89Npnr8VjMddNmuRh9rDfp36mFg91oM7qPIc5JdbDJq3An/JfCu7Hl53W2lpS220pP2OuniN299jAYbYizSENIoAgbCTdrTKtxOJVdvGo8psUwKy7Vxe4ez1YEVudGP8YEZzyveInFJ6mZRHHqYazDspw/pJwTIuERM5JIwmUdGdyo9K7/BszGzzg6fXzZHGJ8KvzQqXKOpoIeZLjofWR++BPWyCEnPY4xFGEKWQcLjMjKmr1MwfcMYwmz/Y4KOgNki0V5k1dkjUWCK93Kp2PMFFawos8cm1gZ2GqjLXktL4mbQPHLQ4B9ZDFE5+S356fQlyuJMqzH++HnTo6ui2OO1ko9Ul+4fxfd3d4F7k4YTReqpuFS88bGZUE2QNNDobuIq8Q5CduHb7lFJaTnvnym9ergjMWD/FG8zf+aKS3G9JO5C01Asah6wUXrvALKEDoitMMHhDKrKJdg8RU2s0EB2EWWur8dd7PDPFv6dUC0Gv3kAN36VPRGP/5k5NS6lljWxG0TDiSr1VKhoPwhevRMSqkwRxDObc/DavGtpP6zoi8XOyZfhnyNEvKANBU0P8VPfI/wyNCGXSn7wlEmyA9KrgmOKGth3eDVvPfyywq2dnUEv2R9qG2rLsH7xJXziKnWcI8tlTvEC7Mu8hROlImTU9aKqcwQ1vWOihWFu+sJknmph5CvxQh87c7bNh/NXo03hrMCosyvLmMNgMF7TQL6J1dsZIUVwjKqEO+cajp5vxPN439U/gKBt8PTcYHzL/BgHCyOf4unAISj6mFC2bYC82kB5Ls460NHRUVsDeYSXpGw7UgC7sAtwShDgzdM38W7BbURXtqpqhfmB8sEQuXwoCM/6faGQuGCxyxyKWhIm+PrSD495WL3cT0hhi8Whc3NbAs9KaOyCTvrJ8qkdX19XBeTUDU00+55USFzVU2yHstcaix0mUAjJkJeuRU868Ucmk0lcguiBnMAVxjbbdHV1yeq8+u4Hgo22huSG+iQXp83ftaxW3lsPZcs6KG5T8OwaAfJiPcxlrVRVRhvF02i0F/t5VbHZ7JWDfErKTLnhE3mFPuRFepg/uxqz6TqLv6euGj3ut87t/4ylvre3t3ZehOWWO1zjSFEqMVP4GfGb/DBykJcjmaZOoLsc+hcVY/LaAgcTQAAAAABJRU5ErkJggg==',
|
|
'OpenBSD': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAFo9M/3AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AoYAykIPu64pQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAADTklEQVQ4y32RXUxTdxjGn3N6eujoKT3SUkuk3VoBGfVjgFXAsZ7WkipyYXQbuu3CzUXZmGRbssnFEseFkWzgcGzGXky9MWL8TsC4IeFgtK4oAqOnG5vMVl1pCMVWQD7b/y5M6jLdflfvxfPked/nBQA0NDSChqnGVrLuGkES742NhJAdhAKAuk9yyUs5Gry7RQMZAARCWgivpQiPe71P5DUfH0xaqTL7m/iiLkJmphawa+e4SM2PvUyC4yUIBu8CnAQKAK53rCA5OUtQtStVpJ4Gw/FOBddZVKhCfq4MP4n6+at+DUsJm/e0G9JZzYEvI2tHwlEYjDxomkZ+3nG8WroRtHihZVOhVlorDQzh0okhcByDP4ZGcf+X9XAsvY5/RsBa7Kq5H/CqLctKyl/g08S2i6fq8W/MS3P34T9wNDVYSeDX1eTD9xhiLXbtB/Akwmmv6Kr+ICFkLpGhtNSM3qsSstS3oX8lSsmsxS6ZVn3j6PvVVqhUcvC8AtPxVPxwygVKvngN89WOjgVprggGA4eenjB4nsXsTASpC63I0wVTZYPR11FoKRB8Ax54PCFk6BhMTk5CPR3GSbHouGzknr/bYFq9EAvfc9Tu1sLjHcXNKxLuTOTgzOlOe7IHBc/beAXWpWmXlz8a84nhcLQ+ecVzsAEQrMWuMX+f9HZF2YPZ28FVSNfoPWqOzMUmqYMAJm7+/OOzXQFwHGpyEV+vi+yvtxBC9pDmpgJC4tvI3mo9GTitIxvW24nT7ug67HY/3eDs2bbyrVsrY2day70rV6kRfDAHk5lDLJqAmmeRiD9GJDKHvwb74R8G0mkTPjrQTTG122xkTTbwaV2b1H4u16JQKXGr7yG2b8/H1MQ09IsTSEmRwzf4CCwzD+dmE1re8CI7wwi5XNlFf9vaTXX4dWJg4LLl7h05fpNGwNAMWpp9CIVYNO/tRCzGwpDFQaVMQTS2CKY0BWr3GVGWNSXKACDDaA4Mh976pq9f5Sy09GgKlmeAMIBKzUKpU+BFoxJecRhUfAbMxDi4eADfHVmE79v7q575gvvYeVvjZ58LD5mwsKUyX0hnf0feslnQCWD4zxnc6reKisxsfH2oscqcmTmK/+Ow252cna7K52r+Bky6PqmoT5HBAAAAAElFTkSuQmCC',
|
|
'Gnu': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAHC/Qd8AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AoYAywUV5gQrwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAAmJLR0QA/4ePzL8AAAHHSURBVBgZZcFPSJNxAAbgt28uanSRapCsy0KK2CWCUYecB5HBolNsglZEsmAwaUvHaIu2YYty1bKGMKmgHIRbGEhURIEY/VHUQ+uwZcxEJSL5Ft+W5ubv7TMkip4HJglrPhHeUmAchWprBK+Kni9pukoAJAOF04j4y6Z9dZtu3sIT32lxXwxeRepwidP0mAF0p5JKPfBsLOMBQs/dJ3pehzcnQ+jc6SfFKlN8KMgEodLiQJWTFOyPY52mUbLmzANY4zro+xG8DVXn8UjOvg2WFSB69Oxo8Hx3F3CM2KsE2wO8LKbp5gWvtYK78zHKooM/eZFu9t0AUOCYIIf4IRfvOrIBKn12vEJyjtDhtx3QfV+dYPgO/qipOfeAgA0qn+UaW+TE9ZQjE0g63uhrpZh2yJyOPXKFe9uWrmTxtmpaSOwCgk5bWUfQywyt3MOOHmB4f9MyBu610ii3fRvlvBgRMrOc4mPmxQs2yPpylABObQ9FJxVyhAqXuEiyyOFiQcnT6TipBWDf6k9fGjwUWZgjF8V7PmVOlPmxkNmNvxhR136muELOclZ85QR73fiHBgZshM1e+UzBdzOmRvxPgmqLlKgl8mjGul/jG/ctzIC/LwAAAABJRU5ErkJggg==',
|
|
'CrunchBang': 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAQCAQAAAC45EetAAAA8ElEQVR4XnWOsUpCYQBGz1TIHYu2Qix6g0DEtSeQu/UIISJtUS8gJq61F1wcdMohcBDxKUR8hsz1xA/y44/cs3znbB+RJ0Skl3pSkeFQbUs79VAPzrwPFRmN1Ja0Ug/16I93+1oi4lKte+zMXv32WuoAm43lXMrqzbFncgWw21lORf4+/PREKpAhYqZuPXZ+T/3yXbZEajV1JavUQ104sRcq0myqc5mnHurWqc/7yhExVwuPncl+C4Bu13L60ueAwcByOtLhgAIRCzU38fRGTmSxUBvSSD3Ui1NvQkXWa7Uq1dRD9R17HiqyRUSy1NP6B7e1Yu2GtlUKAAAAAElFTkSuQmCC',
|
|
'Yuno': 'iVBORw0KGgoAAAANSUhEUgAAABgAAAAPCAYAAAD+pA/bAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAABDtJREFUOE+FlHtMm1UYxrtsi8aEgCb+oTFmZur+WNS5RaPERU10C2qGaBgb6hgwLwMmHTIKlIKlQIHSQrmU24BSSmnpBVooUmihtEC5yKWDjVu5uOkcEca4lG5E93j6EQmELX7Jky/fOed9fu973vMdGu0xT3Cgz57yXMZLDdXcy821PFWLKmuA6HqLMqtLX5POl4iYb2ukWW8IOOFe/qfe3/M4n0eOjwyZD8//bldODOk37N1yDJgl+LVdjEGLFKO9KkzZm8hbje7mIrTXZ7sMtTydrJh15H8hHW11XvN/jGS7VudcD5w34ZZzeQYb67fwYO03LN4exo1+LWzNxbA05O5QuzbHqRYn+++CHDx4YK9WLfaedfQzV5em54g5Zbi8OIml+VFMDLWQ7GXoaSmFWZsDZVGCO2u0EbkhHTrhFqi9PmelSsQ8tAtSVch60dpUeGe4kxgZxegzVkBzlQ2NKBG2+iJIMqMok9r8OLRIMqApToSqmAWTmk9B2+o2YW79oshU7ABcuvAFrVGWXkVKpBYoSaBSxIS2mINpiwbjZiUMZRloVfJQyaXDKObBpimBScpHFe8KmmXpaKhK3arGrBVuVBclHN2CiPNin1OVs1tVJYlQlyZBxA6DviQVo6ZaOKd7sTplw53BVugruBBzfsRslw7rZPxaczWutSpQV/gzJPxo1JexyfaxKBBpuiEx+tw+CpKdEvGWTprGlhcwqbIzL5/DYKMYndpK3L1hxf3ZfkrzwybUZjPhnOqmvlcmutFF1jis9QSShOrcWNSXJ1MA0ou/NZWc8Ddfe4VGO3bk0JON1dyMMlK+gmxNrZCFhZF2Kng7YNO0awt4b7wLNp2EqtAsF6ImP56SG0B6siovTYpIjg15gapCVhAfJRUyIBFEo6k8AyuTtkcC/qvG/XbDexulWJvqgYH0o0nKhVHFJ40XwFQnWM5OCX+XMg86c3KvVMSMapCmPpSTIygTxGKZZOcOXhrr3Mp4uzkFuG6B3ajE3TELDDU8qEmsmvRATxquKkxAnSTFjwKEfv3JU9JC5unG6rQ1bTkbQ4Yq/DVgxOqwBWt2K9Yne3ZCZvrgHO2k5paHzOhSiVCZSkdNTgzy40JRlPgDhDHBCxUZdCs91G8fLeK87zOl6XSOICZYXMGNhDqX9fDP/mbK2DXVi/szm03eLpejl5pzOfqwOt4JBT8OeYwQt/4R/BR0OzXiLCM5LOCji/4nXt46rpywgG+zor5RxgSdupBzJdglSY+5ZZbl3XNY6mbn7W0Lcx06zBg1WBjtcC6OmG+OmRTrFrnIUZESZeVeCpwh8TpiPsQ47/tloM97T+/6m8mg55mT3tStyL54mhlwwtszNvjzD8/6HH8i7PvvPPRioZdRWuDBZUR6pEWG7I8P9Xs1Jsj36MfvvO5J/+rTw58dP7afJPfBgeef3XGz/gskFVpJc4HwGwAAAABJRU5ErkJggg=='
|
|
}
|
|
}
|
|
};
|
|
|
|
GlobalMessage = {
|
|
init: function() {
|
|
return $.asap((function() {
|
|
return d.body;
|
|
}), function() {
|
|
return $.asap((function() {
|
|
return $.id('delform');
|
|
}), GlobalMessage.ready);
|
|
});
|
|
},
|
|
ready: function() {
|
|
var child, el, _i, _len, _ref;
|
|
if (el = $("#globalMessage", d.body)) {
|
|
_ref = el.children;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
child = _ref[_i];
|
|
child.cssText = "";
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
JSColor = {
|
|
css: function() {
|
|
return ".jscBox { width: 251px; height: 155px; } .jscBoxB, .jscPadB, .jscPadM, .jscSldB, .jscSldM, .jscBtn { position: absolute; clear: both; } .jscBoxB { left: 320px; bottom: 20px; z-index: 30; border: 1px solid; border-color: ThreeDHighlight ThreeDShadow ThreeDShadow ThreeDHighlight; background: ThreeDFace; } .jscPad { width: 181px; height: 101px; background-image: linear-gradient(to bottom, rgba(255,255,255,0), rgba(255,255,255,1)), linear-gradient(to right, rgb(255,0,0), rgb(255,255,0), rgb(0,255,0), rgb(0,255,255), rgb(0,0,255), rgb(255,0,255), rgb(255,0,0)); background-repeat: no-repeat; background-position: 0 0; } .jscPadB { left: 10px; top: 10px; border: 1px solid; border-color: ThreeDShadow ThreeDHighlight ThreeDHighlight ThreeDShadow; } .jscPadM { left: 0; top: 0; width: 200px; height: 121px; cursor: crosshair; background-image: url('data:image/gif;base64,R0lGODlhDwAPAKEBAAAAAP///////////yH5BAEKAAIALAAAAAAPAA8AAAIklB8Qx53b4otSUWcvyiz4/4AeQJbmKY4p1HHapBlwPL/uVRsFADs='); background-repeat: no-repeat; } .jscSld { width: 16px; height: 101px; background-image: linear-gradient(rgba(0,0,0,0), rgba(0,0,0,1)); } .jscSldB { right: 10px; top: 10px; border: 1px solid; border-color: ThreeDShadow ThreeDHighlight ThreeDHighlight ThreeDShadow; } .jscSldM { right: 0; top: 0; width: 36px; height: 121px; cursor: pointer; background-image: url('data:image/gif;base64,R0lGODlhBwALAKECAAAAAP///6g8eKg8eCH5BAEKAAIALAAAAAAHAAsAAAITTIQYcLnsgGxvijrxqdQq6DRJAQA7'); background-repeat: no-repeat; } .jscBtn { right: 10px; bottom: 10px; padding: 0 15px; height: 18px; border: 1px solid; border-color: ThreeDHighlight ThreeDShadow ThreeDShadow ThreeDHighlight; color: ButtonText; text-align: center; cursor: pointer; } .jscBtnS { line-height: 10px; }";
|
|
},
|
|
bind: function(el) {
|
|
if (!el.color) {
|
|
return el.color = new JSColor.color(el);
|
|
}
|
|
},
|
|
fetchElement: function(mixed) {
|
|
if (typeof mixed === "string") {
|
|
return $.id(mixed);
|
|
} else {
|
|
return mixed;
|
|
}
|
|
},
|
|
fireEvent: function(el, event) {
|
|
if (!el) {
|
|
return;
|
|
}
|
|
return $.event(event, null, el);
|
|
},
|
|
getRelMousePos: function(e) {
|
|
var x, y;
|
|
e || (e = window.event);
|
|
x = 0;
|
|
y = 0;
|
|
if (typeof e.offsetX === 'number') {
|
|
x = e.offsetX;
|
|
y = e.offsetY;
|
|
} else if (typeof e.layerX === 'number') {
|
|
x = e.layerX;
|
|
y = e.layerY;
|
|
}
|
|
return {
|
|
x: x,
|
|
y: y
|
|
};
|
|
},
|
|
color: function(target) {
|
|
var HSV_RGB, RGB_HSV, THIS, abortBlur, blurTarget, blurValue, drawPicker, holdPad, holdSld, isPickerOwner, leavePad, leaveSld, leaveStyle, leaveValue, redrawPad, redrawSld, removePicker, setPad, setSld, styleElement, valueElement;
|
|
this.hsv = [0, 0, 1];
|
|
this.rgb = [1, 1, 1];
|
|
this.valueElement = this.styleElement = target;
|
|
abortBlur = holdPad = holdSld = false;
|
|
this.hidePicker = function() {
|
|
if (isPickerOwner()) {
|
|
return removePicker();
|
|
}
|
|
};
|
|
this.showPicker = function() {
|
|
if (!isPickerOwner()) {
|
|
return drawPicker();
|
|
}
|
|
};
|
|
this.importColor = function() {
|
|
if (!valueElement) {
|
|
return this.exportColor();
|
|
} else {
|
|
if (!this.fromString(valueElement.value, leaveValue)) {
|
|
styleElement.style.backgroundColor = styleElement.jscStyle.backgroundColor;
|
|
return this.exportColor(leaveValue | leaveStyle);
|
|
}
|
|
}
|
|
};
|
|
this.exportColor = function(flags) {
|
|
var value;
|
|
if (!(flags & leaveValue) && valueElement) {
|
|
value = '#' + this.toString();
|
|
valueElement.value = value;
|
|
valueElement.previousSibling.value = value;
|
|
editTheme[valueElement.previousSibling.name] = value;
|
|
setTimeout(function() {
|
|
return Style.setTheme(editTheme);
|
|
});
|
|
}
|
|
if (!(flags & leaveStyle) && styleElement) {
|
|
styleElement.style.backgroundColor = '#' + this.toString();
|
|
}
|
|
if (!(flags & leavePad) && isPickerOwner()) {
|
|
redrawPad();
|
|
}
|
|
if (!(flags & leaveSld) && isPickerOwner()) {
|
|
return redrawSld();
|
|
}
|
|
};
|
|
this.fromHSV = function(h, s, v, flags) {
|
|
this.hsv = [h = h ? $.minmax(h, 0.0, 6.0) : this.hsv[0], s = s ? $.minmax(s, 0.0, 1.0) : this.hsv[1], v = v ? $.minmax(v, 0.0, 1.0) : this.hsv[2]];
|
|
this.rgb = HSV_RGB(h, s, v);
|
|
return this.exportColor(flags);
|
|
};
|
|
this.fromRGB = function(r, g, b, flags) {
|
|
var hsv;
|
|
r = r != null ? $.minmax(r, 0.0, 1.0) : this.rgb[0];
|
|
g = g != null ? $.minmax(g, 0.0, 1.0) : this.rgb[1];
|
|
b = b != null ? $.minmax(b, 0.0, 1.0) : this.rgb[2];
|
|
hsv = RGB_HSV(r, g, b);
|
|
if (hsv[0] != null) {
|
|
this.hsv[0] = $.minmax(hsv[0], 0.0, 6.0);
|
|
}
|
|
if (hsv[2] !== 0) {
|
|
this.hsv[1] = hsv[1] == null ? null : $.minmax(hsv[1], 0.0, 1.0);
|
|
}
|
|
this.hsv[2] = hsv[2] == null ? null : $.minmax(hsv[2], 0.0, 1.0);
|
|
this.rgb = HSV_RGB(this.hsv[0], this.hsv[1], this.hsv[2]);
|
|
return this.exportColor(flags);
|
|
};
|
|
this.fromString = function(number, flags) {
|
|
var m, val;
|
|
m = number.match(/^\W*([0-9A-F]{3}([0-9A-F]{3})?)\W*$/i);
|
|
if (!m) {
|
|
return false;
|
|
} else {
|
|
if (m[1].length === 6) {
|
|
this.fromRGB(parseInt(m[1].substr(0, 2), 16) / 255, parseInt(m[1].substr(2, 2), 16) / 255, parseInt(m[1].substr(4, 2), 16) / 255, flags);
|
|
} else {
|
|
this.fromRGB(parseInt((val = m[1].charAt(0)) + val, 16) / 255, parseInt((val = m[1].charAt(1)) + val, 16) / 255, parseInt((val = m[1].charAt(2)) + val, 16) / 255, flags);
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
this.toString = function() {
|
|
return (0x100 | Math.round(255 * this.rgb[0])).toString(16).substr(1) + (0x100 | Math.round(255 * this.rgb[1])).toString(16).substr(1) + (0x100 | Math.round(255 * this.rgb[2])).toString(16).substr(1);
|
|
};
|
|
RGB_HSV = function(r, g, b) {
|
|
var h, m, n, v;
|
|
n = (n = r < g ? r : g) < b ? n : b;
|
|
v = (v = r > g ? r : g) > b ? v : b;
|
|
m = v - n;
|
|
if (m === 0) {
|
|
return [null, 0, v];
|
|
}
|
|
h = r === n ? 3 + (b - g) / m : g === n ? 5 + (r - b) / m : 1 + (g - r) / m;
|
|
return [h === 6 ? 0 : h, m / v, v];
|
|
};
|
|
HSV_RGB = function(h, s, v) {
|
|
var f, i, m, n;
|
|
if (h == null) {
|
|
return [v, v, v];
|
|
}
|
|
i = Math.floor(h);
|
|
f = i % 2 ? h - i : 1 - (h - i);
|
|
m = v * (1 - s);
|
|
n = v * (1 - s * f);
|
|
switch (i) {
|
|
case 6:
|
|
case 0:
|
|
return [v, n, m];
|
|
case 1:
|
|
return [n, v, m];
|
|
case 2:
|
|
return [m, v, n];
|
|
case 3:
|
|
return [m, n, v];
|
|
case 4:
|
|
return [n, m, v];
|
|
case 5:
|
|
return [v, m, n];
|
|
}
|
|
};
|
|
removePicker = function() {
|
|
delete JSColor.picker.owner;
|
|
return $.rm(JSColor.picker.boxB);
|
|
};
|
|
drawPicker = function(x, y) {
|
|
var box, boxB, btn, btnS, elements, item, p, pad, padB, padM, sld, sldB, sldM, _i, _len;
|
|
if (!(p = JSColor.picker)) {
|
|
elements = ['box', 'boxB', 'pad', 'padB', 'padM', 'sld', 'sldB', 'sldM', 'btn'];
|
|
p = {};
|
|
for (_i = 0, _len = elements.length; _i < _len; _i++) {
|
|
item = elements[_i];
|
|
p[item] = $.el('div', {
|
|
className: "jsc" + (item.charAt(0).toUpperCase() + item.slice(1))
|
|
});
|
|
}
|
|
p.btnS = $.el('span', {
|
|
className: 'jscBtnS'
|
|
});
|
|
p.btnT = $.tn('Close');
|
|
JSColor.picker = p;
|
|
$.add(p.box, [p.sldB, p.sldM, p.padB, p.padM, p.btn]);
|
|
$.add(p.sldB, p.sld);
|
|
$.add(p.padB, p.pad);
|
|
$.add(p.btnS, p.btnT);
|
|
$.add(p.btn, p.btnS);
|
|
$.add(p.boxB, p.box);
|
|
}
|
|
box = p.box, boxB = p.boxB, btn = p.btn, btnS = p.btnS, pad = p.pad, padB = p.padB, padM = p.padM, sld = p.sld, sldB = p.sldB, sldM = p.sldM;
|
|
box.onmouseup = box.onmouseout = function() {
|
|
return target.focus();
|
|
};
|
|
box.onmousedown = function() {
|
|
return abortBlur = true;
|
|
};
|
|
box.onmousemove = function(e) {
|
|
if (holdPad || holdSld) {
|
|
holdPad && setPad(e);
|
|
holdSld && setSld(e);
|
|
if (d.selection) {
|
|
return d.selection.empty();
|
|
} else if (window.getSelection) {
|
|
return window.getSelection().removeAllRanges();
|
|
}
|
|
}
|
|
};
|
|
padM.onmouseup = padM.onmouseout = function() {
|
|
if (holdPad) {
|
|
holdPad = false;
|
|
return JSColor.fireEvent(valueElement, 'change');
|
|
}
|
|
};
|
|
padM.onmousedown = function(e) {
|
|
if (THIS.hsv[2] === 0) {
|
|
THIS.fromHSV(null, null, 1.0);
|
|
}
|
|
holdPad = true;
|
|
return setPad(e);
|
|
};
|
|
sldM.onmouseup = sldM.onmouseout = function() {
|
|
if (holdSld) {
|
|
holdSld = false;
|
|
return JSColor.fireEvent(valueElement, 'change');
|
|
}
|
|
};
|
|
sldM.onmousedown = function(e) {
|
|
holdSld = true;
|
|
return setSld(e);
|
|
};
|
|
btn.onmousedown = function() {
|
|
return THIS.hidePicker();
|
|
};
|
|
redrawPad();
|
|
redrawSld();
|
|
JSColor.picker.owner = THIS;
|
|
return $.add(ThemeTools.dialog, p.boxB);
|
|
};
|
|
redrawPad = function() {
|
|
var rgb;
|
|
JSColor.picker.padM.style.backgroundPosition = "" + (4 + Math.round((THIS.hsv[0] / 6) * 180)) + "px " + (4 + Math.round((1 - THIS.hsv[1]) * 100)) + "px";
|
|
rgb = HSV_RGB(THIS.hsv[0], THIS.hsv[1], 1);
|
|
JSColor.picker.sld.style.backgroundColor = "rgb(" + (rgb[0] * 100) + "%, " + (rgb[1] * 100) + "%, " + (rgb[2] * 100) + "%)";
|
|
};
|
|
redrawSld = function() {
|
|
return JSColor.picker.sldM.style.backgroundPosition = "0 " + (6 + Math.round((1 - THIS.hsv[2]) * 100)) + "px";
|
|
};
|
|
isPickerOwner = function() {
|
|
return JSColor.picker && JSColor.picker.owner === THIS;
|
|
};
|
|
blurTarget = function() {
|
|
if (valueElement === target) {
|
|
return THIS.importColor();
|
|
}
|
|
};
|
|
blurValue = function() {
|
|
if (valueElement !== target) {
|
|
return THIS.importColor();
|
|
}
|
|
};
|
|
setPad = function(e) {
|
|
var mpos, x, y;
|
|
mpos = JSColor.getRelMousePos(e);
|
|
x = mpos.x - 11;
|
|
y = mpos.y - 11;
|
|
return THIS.fromHSV(x * (1 / 30), 1 - y / 100, null, leaveSld);
|
|
};
|
|
setSld = function(e) {
|
|
var mpos, y;
|
|
mpos = JSColor.getRelMousePos(e);
|
|
y = mpos.y - 9;
|
|
return THIS.fromHSV(null, null, 1 - y / 100, leavePad);
|
|
};
|
|
THIS = this;
|
|
valueElement = JSColor.fetchElement(this.valueElement);
|
|
styleElement = JSColor.fetchElement(this.styleElement);
|
|
leaveValue = 1 << 0;
|
|
leaveStyle = 1 << 1;
|
|
leavePad = 1 << 2;
|
|
leaveSld = 1 << 3;
|
|
$.on(target, 'focus', function() {
|
|
return THIS.showPicker();
|
|
});
|
|
$.on(target, 'blur', function() {
|
|
if (!abortBlur) {
|
|
return window.setTimeout(function() {
|
|
abortBlur || blurTarget();
|
|
return abortBlur = false;
|
|
});
|
|
} else {
|
|
return abortBlur = false;
|
|
}
|
|
});
|
|
if (valueElement) {
|
|
$.on(valueElement, 'keyup input', function() {
|
|
return THIS.fromString(valueElement.value, leaveValue);
|
|
});
|
|
$.on(valueElement, 'blur', blurValue);
|
|
valueElement.setAttribute('autocomplete', 'off');
|
|
}
|
|
if (styleElement) {
|
|
styleElement.jscStyle = {
|
|
backgroundColor: styleElement.style.backgroundColor
|
|
};
|
|
}
|
|
return this.importColor();
|
|
}
|
|
};
|
|
|
|
MascotTools = {
|
|
init: function() {
|
|
if (!Conf['Mascots'] || (g.VIEW === 'catalog' && Conf['Hide Mascots on Catalog'])) {
|
|
return;
|
|
}
|
|
if (Conf['Click to Toggle']) {
|
|
$.on(this.el, 'mousedown', MascotTools.click);
|
|
}
|
|
$.on(doc, 'QRDialogCreation', MascotTools.position);
|
|
$.asap((function() {
|
|
return d.body;
|
|
}), (function(_this) {
|
|
return function() {
|
|
return $.add(d.body, _this.el);
|
|
};
|
|
})(this));
|
|
return MascotTools.toggle();
|
|
},
|
|
el: $.el('div', {
|
|
id: "mascot",
|
|
innerHTML: "<img>"
|
|
}),
|
|
change: function(mascot) {
|
|
var el, img;
|
|
if (Conf['Mascot Position'] === 'default') {
|
|
$.rmClass(doc, 'mascot-position-above-post-form');
|
|
$.rmClass(doc, 'mascot-position-bottom');
|
|
$.rmClass(doc, 'mascot-position-default');
|
|
$.addClass(doc, mascot.position === 'bottom' ? 'mascot-position-bottom' : 'mascot-position-above-post-form');
|
|
}
|
|
$[mascot.silhouette || Conf['Silhouettize Mascots'] ? 'addClass' : 'rmClass'](doc, 'silhouettize-mascots');
|
|
el = $.el('img');
|
|
img = this.el.firstElementChild;
|
|
if (mascot.image !== '') {
|
|
$.on(el, 'error', MascotTools.error);
|
|
el.src = mascot.image;
|
|
}
|
|
$.off(img, 'error', MascotTools.error);
|
|
$.replace(img, el);
|
|
return MascotTools.position(mascot);
|
|
},
|
|
error: function() {
|
|
var ctx, el;
|
|
if (!this.src) {
|
|
return;
|
|
}
|
|
if (MascotTools.imageError) {
|
|
this.src = MascotTools.imageError;
|
|
}
|
|
el = $.el('canvas', {
|
|
width: 248,
|
|
height: 100
|
|
});
|
|
ctx = el.getContext('2d');
|
|
ctx.font = "40px " + Conf['Font'];
|
|
ctx.fillStyle = (new Color((Themes[Conf[g.THEMESTRING]] || Themes[g.TYPE === 'sfw' ? 'Yotsuba B' : 'Yotsuba'])['Text'])).hex();
|
|
ctx.textAlign = 'center';
|
|
ctx.textBaseline = 'middle';
|
|
ctx.fillText("Mascot 404", 124, 50);
|
|
return el.toBlob((function(_this) {
|
|
return function(blob) {
|
|
return _this.src = MascotTools.imageError = URL.createObjectURL(blob);
|
|
};
|
|
})(this));
|
|
},
|
|
toggle: function() {
|
|
var el, enabled, i, len, mascot, name, string;
|
|
string = g.MASCOTSTRING;
|
|
enabled = Conf[string];
|
|
if (!(len = enabled.length)) {
|
|
return MascotTools.change({
|
|
image: ''
|
|
});
|
|
}
|
|
Conf['mascot'] = name = enabled[i = Math.floor(Math.random() * len)];
|
|
if (!(mascot = Mascots[name])) {
|
|
enabled.splice(i, 1);
|
|
if (el = this.el.firstElementChild) {
|
|
$.replace(el, $.el('img'));
|
|
}
|
|
$.set(string, Conf[string] = enabled);
|
|
return MascotTools.toggle();
|
|
}
|
|
return MascotTools.change(mascot);
|
|
},
|
|
categories: ['Custom', 'Anime', 'Ponies', 'Questionable', 'Silhouette', 'Western'],
|
|
dialog: function(key) {
|
|
var container, dialog, div, fileInput, fileRice, imageFn, input, item, layout, name, nameFn, option, optionHTML, saveCheck, saveVal, setting, updateMascot, value, _i, _len, _ref;
|
|
Conf['editMode'] = 'mascot';
|
|
if (Mascots[key]) {
|
|
editMascot = JSON.parse(JSON.stringify(Mascots[key]));
|
|
} else {
|
|
editMascot = {};
|
|
}
|
|
editMascot.name = key || '';
|
|
layout = {
|
|
name: ["Mascot Name", "", "text"],
|
|
image: ["Image", "", "text"],
|
|
category: ["Category", MascotTools.categories[0], "select", MascotTools.categories],
|
|
position: ["Position", "default", "select", ["default", "top", "bottom"]],
|
|
height: ["Height", "auto", "text"],
|
|
width: ["Width", "auto", "text"],
|
|
vOffset: ["Vertical Offset", "0", "number"],
|
|
hOffset: ["Horizontal Offset", "0", "number"],
|
|
center: ["Center Mascot", false, "checkbox"],
|
|
silhouette: ["Silhouette", false, "checkbox"]
|
|
};
|
|
dialog = $.el("div", {
|
|
id: "mascotConf",
|
|
className: "reply dialog",
|
|
innerHTML: "<div id=mascotcontent><center>\nPROTIP: Shift-Click the Mascot Image field to upload your own images!\n<br><a href='https://github.com/zixaphir/appchan-x/issues/126#issuecomment-14365049'>This may have some caveats.</a></center></div><div id=save><a href='javascript:;'>Save Mascot</a></div><div id=close><a href='javascript:;'>Close</a></div>"
|
|
});
|
|
container = $("#mascotcontent", dialog);
|
|
fileRice = function(e) {
|
|
if (e.shiftKey) {
|
|
return this.nextSibling.click();
|
|
}
|
|
};
|
|
updateMascot = function() {
|
|
return MascotTools.change(editMascot);
|
|
};
|
|
saveVal = function() {
|
|
editMascot[this.name] = this.value;
|
|
return updateMascot();
|
|
};
|
|
imageFn = function() {
|
|
if (MascotTools.URL === this.value) {
|
|
return MascotTools.change(editMascot);
|
|
} else if (MascotTools.URL) {
|
|
URL.revokeObjectURL(MascotTools.URL);
|
|
delete MascotTools.URL;
|
|
}
|
|
return saveVal.call(this);
|
|
};
|
|
nameFn = function() {
|
|
this.value = this.value.replace(/[^a-z-_0-9]/ig, "_");
|
|
if ((this.value !== "") && !/^[a-z]/i.test(this.value)) {
|
|
return alert("Mascot names must start with a letter.");
|
|
}
|
|
return saveVal.call(this);
|
|
};
|
|
saveCheck = function() {
|
|
editMascot[this.name] = this.checked ? true : false;
|
|
return updateMascot();
|
|
};
|
|
for (name in layout) {
|
|
item = layout[name];
|
|
value = editMascot[name] || (editMascot[name] = item[1]);
|
|
switch (item[2]) {
|
|
case "text":
|
|
div = this.input(item, name);
|
|
input = $('input', div);
|
|
switch (name) {
|
|
case 'image':
|
|
$.on(input, 'blur', imageFn);
|
|
fileInput = $.el('input', {
|
|
type: "file",
|
|
accept: "image/*",
|
|
title: "imagefile",
|
|
hidden: "hidden"
|
|
});
|
|
$.on(input, 'click', fileRice);
|
|
$.on(fileInput, 'change', MascotTools.uploadImage);
|
|
$.after(input, fileInput);
|
|
break;
|
|
case 'name':
|
|
$.on(input, 'blur', nameFn);
|
|
break;
|
|
default:
|
|
$.on(input, 'blur', saveVal);
|
|
}
|
|
break;
|
|
case "number":
|
|
div = this.input(item, name);
|
|
$.on($('input', div), 'blur', saveVal);
|
|
break;
|
|
case "select":
|
|
optionHTML = "<div class=optionlabel>" + item[0] + "</div><div class=option><select name='" + name + "' value='" + value + "'><br>";
|
|
_ref = item[3];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
option = _ref[_i];
|
|
optionHTML += "<option value=\"" + option + "\">" + option + "</option>";
|
|
}
|
|
optionHTML += "</select></div>";
|
|
div = $.el('div', {
|
|
className: "mascotvar",
|
|
innerHTML: optionHTML
|
|
});
|
|
setting = $("select", div);
|
|
setting.value = value;
|
|
$.on($('select', div), 'change', saveVal);
|
|
break;
|
|
case "checkbox":
|
|
div = $.el("div", {
|
|
className: "mascotvar",
|
|
innerHTML: "<label><input type=" + item[2] + " class=field name='" + name + "' " + (value ? 'checked' : void 0) + ">" + item[0] + "</label>"
|
|
});
|
|
$.on($('input', div), 'click', saveCheck);
|
|
}
|
|
$.add(container, div);
|
|
}
|
|
MascotTools.change(editMascot);
|
|
$.on($('#save > a', dialog), 'click', function() {
|
|
return MascotTools.save(editMascot);
|
|
});
|
|
$.on($('#close > a', dialog), 'click', MascotTools.close);
|
|
Rice.nodes(dialog);
|
|
return $.add(d.body, dialog);
|
|
},
|
|
input: function(item, name) {
|
|
var value;
|
|
value = editMascot[name];
|
|
editMascot[name] = value;
|
|
return $.el("div", {
|
|
className: "mascotvar",
|
|
innerHTML: "<div class=optionlabel>" + item[0] + "</div><div class=option><input type=" + item[2] + " class=field name='" + name + "' placeholder='" + item[0] + "' value='" + value + "'></div>"
|
|
});
|
|
},
|
|
uploadImage: function() {
|
|
var file, fileURL, img;
|
|
if (!(this.files && (file = this.files[0]))) {
|
|
return;
|
|
}
|
|
if (MascotTools.URL) {
|
|
URL.revokeObjectURL(MascotTools.URL);
|
|
}
|
|
img = $.el('img');
|
|
img.onload = (function(_this) {
|
|
return function() {
|
|
var cv, height, s, width;
|
|
s = 400;
|
|
width = img.width, height = img.height;
|
|
if (width <= s) {
|
|
MascotTools.setImage(fileURL);
|
|
_this.previousElementSibling.value = fileURL;
|
|
return;
|
|
}
|
|
cv = $.el('canvas', {
|
|
height: height = s / width * height,
|
|
width: width = s
|
|
});
|
|
cv.getContext('2d').drawImage(img, 0, 0, width, height);
|
|
URL.revokeObjectURL(fileURL);
|
|
return cv.toBlob(function(blob) {
|
|
var fileURL;
|
|
MascotTools.URL = fileURL = URL.createObjectURL(MascotTools.file = blob);
|
|
MascotTools.setImage(fileURL);
|
|
return _this.previousElementSibling.value = fileURL;
|
|
});
|
|
};
|
|
})(this);
|
|
MascotTools.URL = fileURL = URL.createObjectURL(MascotTools.file = file);
|
|
return img.src = fileURL;
|
|
},
|
|
setImage: function(fileURL) {
|
|
var reader;
|
|
reader = new FileReader();
|
|
reader.onload = function() {
|
|
return editMascot.image = reader.result;
|
|
};
|
|
return reader.readAsDataURL(MascotTools.file);
|
|
},
|
|
save: function(mascot) {
|
|
var image, name;
|
|
name = mascot.name, image = mascot.image;
|
|
if ((name == null) || name === "") {
|
|
alert("Please name your mascot.");
|
|
return;
|
|
}
|
|
if ((image == null) || image === "") {
|
|
alert("Your mascot must contain an image.");
|
|
return;
|
|
}
|
|
if (!mascot.category) {
|
|
mascot.category = MascotTools.categories[0];
|
|
}
|
|
if (Mascots[name]) {
|
|
if ($.remove(Conf["Deleted Mascots"], name)) {
|
|
$.set("Deleted Mascots", Conf["Deleted Mascots"]);
|
|
} else {
|
|
if (confirm("A mascot named \"" + name + "\" already exists. Would you like to over-write?")) {
|
|
delete Mascots[name];
|
|
} else {
|
|
return alert("Creation of \"" + name + "\" aborted.");
|
|
}
|
|
}
|
|
}
|
|
Mascots[name] = JSON.parse(JSON.stringify(mascot));
|
|
delete Mascots[name].name;
|
|
return $.get("userMascots", {}, function(_arg) {
|
|
var type, userMascots, _i, _len, _ref;
|
|
userMascots = _arg.userMascots;
|
|
userMascots[name] = Mascots[name];
|
|
$.set('userMascots', userMascots);
|
|
Conf["mascot"] = name;
|
|
_ref = ["Enabled Mascots", "Enabled Mascots sfw", "Enabled Mascots nsfw"];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
type = _ref[_i];
|
|
if (__indexOf.call(Conf[type], name) < 0) {
|
|
Conf[type].push(name);
|
|
$.set(type, Conf[type]);
|
|
}
|
|
}
|
|
return alert("Mascot \"" + name + "\" saved.");
|
|
});
|
|
},
|
|
click: function(e) {
|
|
if (e.button !== 0) {
|
|
return;
|
|
}
|
|
e.preventDefault();
|
|
return MascotTools.toggle();
|
|
},
|
|
close: function() {
|
|
Conf['editMode'] = false;
|
|
editMascot = {};
|
|
$.rm($.id('mascotConf'));
|
|
return Settings.open("Mascots");
|
|
},
|
|
importMascot: function() {
|
|
var file, reader;
|
|
file = this.files[0];
|
|
reader = new FileReader();
|
|
reader.onload = function(e) {
|
|
var err, mascots;
|
|
try {
|
|
mascots = JSON.parse(e.target.result);
|
|
} catch (_error) {
|
|
err = _error;
|
|
alert(err);
|
|
return;
|
|
}
|
|
return $.get("userMascots", {}, function(_arg) {
|
|
var userMascots;
|
|
userMascots = _arg.userMascots;
|
|
return MascotTools.load(mascots, userMascots);
|
|
});
|
|
};
|
|
return reader.readAsText(file);
|
|
},
|
|
load: function(mascots, userMascots) {
|
|
var ilen, imported, len, mascot, message, name, type, _i, _len, _ref;
|
|
len = Conf["Deleted Mascots"].length;
|
|
imported = [];
|
|
if (name = mascots["Mascot"]) {
|
|
MascotTools.parse(mascots, userMascots, imported);
|
|
} else if (mascots.length) {
|
|
for (_i = 0, _len = mascots.length; _i < _len; _i++) {
|
|
mascot = mascots[_i];
|
|
MascotTools.parse(mascot, userMascots, imported);
|
|
}
|
|
} else {
|
|
return new Notice('warning', "Failed to import mascot. Is file a properly formatted JSON file?", 5);
|
|
}
|
|
_ref = name && (ilen = imported.length) ? ["" + name + " successfully imported!", 'info'] : ilen ? ["" + ilen + " mascots successfully imported!", 'info'] : ["Failed to import any mascots. ;__;", 'info'], message = _ref[0], type = _ref[1];
|
|
$.set('userMascots', userMascots);
|
|
if (len !== Conf["Deleted Mascots"].length) {
|
|
$.set('Deleted Mascots', Conf['Deleted Mascots']);
|
|
}
|
|
new Notice(type, message, 10);
|
|
return Settings.openSection.call({
|
|
open: Settings.mascots,
|
|
hyphenatedTitle: 'mascots'
|
|
});
|
|
},
|
|
parse: function(mascot, userMascots, imported) {
|
|
var image, message, name;
|
|
if (!(name = mascot["Mascot"] && (image = mascot.image))) {
|
|
message = "Failed to import a mascot. File file has no " + (name ? 'image' : image ? 'name' : 'name nor image') + ".";
|
|
return new Notice('warning', message, 5);
|
|
}
|
|
delete mascot["Mascot"];
|
|
if (Mascots[name] && !$.remove(Conf["Deleted Mascots"], name)) {
|
|
if (!confirm("The mascot " + name + " already exists? Would you like to overwrite it?")) {
|
|
return;
|
|
}
|
|
}
|
|
return imported.push(userMascots[name] = Mascots[name] = mascot);
|
|
},
|
|
position: function(mascot) {
|
|
if (!Style.sheets.mascots) {
|
|
return;
|
|
}
|
|
(mascot.image != null) || (mascot = Mascots[Conf['mascot']] || {});
|
|
return Style.sheets.mascots.textContent = "#mascot img {\nheight: " + (mascot.height && isNaN(parseFloat(mascot.height)) ? mascot.height : mascot.height ? parseInt(mascot.height, 10) + 'px' : 'auto') + ";\nwidth: " + (mascot.width && isNaN(parseFloat(mascot.width)) ? mascot.width : mascot.width ? parseInt(mascot.width, 10) + 'px' : 'auto') + ";\n}\n#mascot {\nmargin: " + (mascot.vOffset || 0) + "px " + (mascot.hOffset || 0) + "px;\n}\n.sidebar-large #mascot {\nleft: " + (mascot.center ? 25 : 0) + "px;\nright: " + (mascot.center ? 25 : 0) + "px;\n}\n.mascot-position-above-post-form.post-form-style-fixed #mascot {\ntransform: translateY(-" + (QR.nodes ? QR.nodes.el.getBoundingClientRect().height : 0) + "px);\n}";
|
|
}
|
|
};
|
|
|
|
Rice = {
|
|
ul: $.el('ul', {
|
|
id: "selectrice"
|
|
}),
|
|
init: function() {
|
|
$.ready(this.initReady);
|
|
return Post.callbacks.push({
|
|
name: 'Rice Checkboxes',
|
|
cb: this.node
|
|
});
|
|
},
|
|
initReady: function() {
|
|
Rice.nodes(d.body);
|
|
return $.add(d.body, Rice.ul);
|
|
},
|
|
node: function() {
|
|
return Rice.checkbox($('.postInfo input', this.nodes.post));
|
|
},
|
|
nodes: function(root) {
|
|
var process;
|
|
root || (root = d.body);
|
|
process = Rice.process;
|
|
process($$('[type=checkbox]:not(.riced)', root), 'checkbox');
|
|
return process($$('select:not(.riced)', root), 'select');
|
|
},
|
|
process: function(items, type) {
|
|
var fn, item, _i, _len;
|
|
fn = Rice[type];
|
|
for (_i = 0, _len = items.length; _i < _len; _i++) {
|
|
item = items[_i];
|
|
fn(item);
|
|
}
|
|
},
|
|
cleanup: function() {
|
|
$.off(d, 'click scroll blur resize', Rice.cleanup);
|
|
$.rmAll(Rice.ul);
|
|
},
|
|
checkbox: function(input) {
|
|
var div;
|
|
if ($.hasClass(input, 'riced')) {
|
|
return;
|
|
}
|
|
$.addClass(input, 'riced');
|
|
div = $.el('div', {
|
|
className: 'rice'
|
|
});
|
|
div.check = input;
|
|
$.after(input, div);
|
|
return $.on(div, 'click', Rice.cb.check);
|
|
},
|
|
select: function(select) {
|
|
var div, _ref;
|
|
div = $.el('div', {
|
|
className: 'selectrice',
|
|
innerHTML: "<div>" + (((_ref = select.options[select.selectedIndex || '0']) != null ? _ref.textContent : void 0) || '') + "</div>"
|
|
});
|
|
$.on(div, 'click', Rice.cb.select);
|
|
$.on(div, 'keydown', Rice.cb.keybind);
|
|
$.after(select, div);
|
|
return $.addClass(select, 'riced');
|
|
},
|
|
cb: {
|
|
check: function(e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
return this.check.click();
|
|
},
|
|
option: function(e) {
|
|
var container, select;
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
if (this.dataset.disabled) {
|
|
return;
|
|
}
|
|
select = Rice.input;
|
|
container = select.nextElementSibling;
|
|
container.firstChild.textContent = this.textContent;
|
|
select.value = this.dataset.value;
|
|
$.event('change', null, select);
|
|
return Rice.cleanup();
|
|
},
|
|
select: function(e) {
|
|
var bottom, clientHeight, left, li, nodes, option, select, style, top, ul, width, _i, _len, _ref, _ref1;
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
ul = Rice.ul;
|
|
if (ul.children.length > 0) {
|
|
return Rice.cleanup();
|
|
}
|
|
_ref = this.getBoundingClientRect(), width = _ref.width, left = _ref.left, bottom = _ref.bottom, top = _ref.top;
|
|
clientHeight = d.documentElement.clientHeight;
|
|
style = ul.style;
|
|
style.cssText = ("width: " + width + "px; left: " + left + "px;") + (clientHeight - bottom < 200 ? "bottom: " + (clientHeight - top) + "px" : "top: " + bottom + "px");
|
|
Rice.input = select = this.previousSibling;
|
|
nodes = [];
|
|
_ref1 = select.options;
|
|
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
|
|
option = _ref1[_i];
|
|
li = $.el('li', {
|
|
textContent: option.textContent
|
|
});
|
|
li.dataset.value = option.value;
|
|
if (option.disabled) {
|
|
li.dataset.disabled = true;
|
|
}
|
|
$.on(li, 'click', Rice.cb.option);
|
|
nodes.push(li);
|
|
}
|
|
$.add(ul, nodes);
|
|
$.on(ul, 'click scroll blur', function(e) {
|
|
return e.stopPropagation();
|
|
});
|
|
return $.on(d, 'click scroll blur resize', Rice.cleanup);
|
|
}
|
|
}
|
|
};
|
|
|
|
Style = {
|
|
sheets: {},
|
|
init: function() {
|
|
var i, item, items, theme;
|
|
Style.svgs = {};
|
|
theme = Themes[Conf[g.THEMESTRING]] || Themes['Yotsuba B'];
|
|
items = [['layout', Style.layout], ['theme', Style.theme(theme)], ['emoji', Emoji.css()], ['dynamic', Style.dynamic()], ['padding', ""], ['mascots', ""]];
|
|
i = 0;
|
|
while (item = items[i++]) {
|
|
Style.sheets[item[0]] = $.addStyle(item[1], item[0]);
|
|
}
|
|
$.addStyle(JSColor.css(), 'jsColor');
|
|
$.asap((function() {
|
|
return d.body;
|
|
}), this.asapInit);
|
|
$.asap((function() {
|
|
return Header.bar.parentElement;
|
|
}), Style.padding);
|
|
$.on(window, "resize", Style.padding);
|
|
return $.ready(this.readyInit);
|
|
},
|
|
asapInit: function() {
|
|
var cat, hyphenated, name, setting, title, _ref;
|
|
$.addClass(doc, 'gecko');
|
|
$.addClass(doc, 'fourchan-x');
|
|
$.addClass(doc, 'appchan-x');
|
|
$.addClass(doc, g.VIEW);
|
|
Style.remStyle();
|
|
_ref = Config.style;
|
|
for (title in _ref) {
|
|
cat = _ref[title];
|
|
for (name in cat) {
|
|
setting = cat[name];
|
|
if (!Conf[name] || setting[2] === 'text' || (name === 'NSFW/SFW Themes' || name === 'NSFW/SFW Mascots')) {
|
|
continue;
|
|
}
|
|
hyphenated = ("" + name + (setting[2] ? " " + Conf[name] : "")).toLowerCase().replace(/^4/, 'four').replace(/\s+/g, '-');
|
|
$.addClass(doc, hyphenated);
|
|
}
|
|
}
|
|
},
|
|
readyInit: function() {
|
|
var exLink;
|
|
Style.iconPositions();
|
|
if (exLink = $("#navtopright .exlinksOptionsLink", d.body)) {
|
|
return $.on(exLink, "click", function() {
|
|
return setTimeout(Rice.nodes, 100);
|
|
});
|
|
}
|
|
},
|
|
remStyle: function() {
|
|
var item, _i, _j, _len, _len1, _ref, _ref1;
|
|
_ref = ['[title="switch"]', '[href="//s.4cdn.org/css/yotsubluemobile.540.css"]', '#base-css', '#mobile-css'];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
item = _ref[_i];
|
|
if (item = $(item, d.head)) {
|
|
item.disabled = true;
|
|
}
|
|
}
|
|
if (g.VIEW === 'home') {
|
|
_ref1 = $$('[rel="stylesheet"], style[type="text/css"]', d.head);
|
|
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
|
item = _ref1[_j];
|
|
item.disabled = true;
|
|
}
|
|
}
|
|
},
|
|
generateFilter: function(id, values) {
|
|
return "<svg xmlns='http://www.w3.org/2000/svg' height='0' color-interpolation-filters='sRGB'><filter id='" + id + "'><feColorMatrix " + values + " /></filter></svg>";
|
|
},
|
|
matrix: function() {
|
|
var arg, color, colors, hex, i, rgb, val, _i, _len;
|
|
colors = [];
|
|
rgb = ['r', 'g', 'b'];
|
|
for (_i = 0, _len = arguments.length; _i < _len; _i++) {
|
|
arg = arguments[_i];
|
|
hex = (new Color(arg)).raw;
|
|
color = {};
|
|
i = 0;
|
|
while (val = rgb[i]) {
|
|
color[val] = parseInt(hex.substr(2 * i++, 2), 16) / 255;
|
|
}
|
|
colors.push(color);
|
|
}
|
|
return colors;
|
|
},
|
|
filter: function(_arg) {
|
|
var bg, fg;
|
|
fg = _arg[0], bg = _arg[1];
|
|
return "" + bg.r + " " + (-fg.r) + " 0 0 " + fg.r + " " + bg.g + " " + (-fg.g) + " 0 0 " + fg.g + " " + bg.b + " " + (-fg.b) + " 0 0 " + fg.b;
|
|
},
|
|
silhouette: function(_arg) {
|
|
var fg;
|
|
fg = _arg[0];
|
|
return "0 0 0 0 " + fg.r + " 0 0 0 0 " + fg.g + " 0 0 0 0 " + fg.b;
|
|
},
|
|
layout: "/* Cleanup */ #absbot, #boardNavDesktop, #delPassword, #delform > hr:last-of-type, #navbotright, #postForm, #search-label, #search-label-bottom, #styleSwitcher, #togglePostForm, .boardBanner > div, .next form, .next span, .postingMode, .prev form, .prev span, .riced, .sideArrows, .stylechanger, body > br, body > div[style^=\"text-align\"], body > hr { display: none; } /* Empties */ #qr .warning:empty, #qr-thread-select:empty { display: none; } /* File Name Trunctuate / /p/ exif */ .exif, .file-info:hover .fntrunc, .file-info:not(:hover) .fnfull { display: none; } /* Unnecessary */ #qp input, #qp .rice, .inline .rice, .mobile { display: none !important; } /* Hidden Content */ .forwarded, .hidden, .hidden_thread ~ div, .hidden_thread ~ a, .replyContainer .stub ~ div, .replyContainer .stub ~ a, .stub + div, .thread > .stub:first-child ~ .postContainer, .thread > .stub:first-child ~ .summary, [hidden] { display: none !important; } /* Hidden UI */ #navtopright, #svg_filters, .cataloglink { z-index: 7; position: fixed; top: 100%; left: 100%; } /* Hide last horizontal rule, keep clear functionality. */ .board > hr:last-of-type { visibility: hidden; } /* Fappe Tyme */ .fappeTyme .thread > .noFile, .fappeTyme .threadContainer > .noFile { display: none; } /* Werk Tyme */ .werkTyme .post .file { display: none; } /* Index Features */ #index-menu { display: flex; } :root.thread #index-menu, :root.index-loading .navLinks, :root.index-loading .board, :root.index-loading .pagelist, :root.thread .pagelist { display: none; } :root:not(.catalog-mode) #index-size, :root:not(.catalog-mode) #index-size + .selectrice, .index:not(.catalog-mode) #returnIcon, .index.catalog-mode #catalogIcon { display: none; } #index-menu .selectrice { width: 110px; display: inline-block; } #index-search { padding-right: 1.5em; width: 100px; transition: color .25s, border-color .25s, width .25s; } #index-search:focus, #index-search[data-searching] { width: 200px; } #index-search-clear { margin-left: -1em; } #index-search:not([data-searching]) + #index-search-clear { display: none; } .catalog-mode .board { text-align: center; } .catalog-thread { display: inline-flex; text-align: left; flex-direction: column; align-items: center; margin: 0 2px 5px; word-break: break-word; vertical-align: top; } .catalog-small .catalog-thread { width: 165px; max-height: 320px; } .catalog-large .catalog-thread { width: 270px; max-height: 410px; } .thumb { flex-shrink: 0; position: relative; background-size: 100% 100%; background-repeat: no-repeat; background-position: center; border-radius: 2px; box-shadow: 0 0 5px rgba(0, 0, 0, .25); } .thumb:not(.deleted-file):not(.no-file) { min-width: 30px; min-height: 30px; } .thumb.spoiler-file { background-size: 100px; width: 100px; height: 100px; } .thumb.deleted-file { background-size: 127px 13px; width: 127px; height: 13px; padding: 20px 11px; } .thumb.no-file { background-size: 77px 13px; width: 77px; height: 13px; padding: 20px 36px; } .thread-icons > img { width: 1em; height: 1em; margin: 0; vertical-align: text-top; } .thumb:not(:hover):not(:focus) > .menu-button:not(.open):not(:focus) > i { display: none; } .thumb > .menu-button { position: absolute; top: 0; right: 0; } .thumb > .menu-button > i { width: 1em; height: 1em; padding: 1px; border-radius: 0 2px 0 2px; font-size: 14px; text-align: center; line-height: normal; } .thread-stats { flex-shrink: 0; cursor: help; font-size: 10px; font-weight: 700; margin-top: 2px; } .catalog-thread > .subject { flex-shrink: 0; font-weight: 700; line-height: 1; text-align: center; } .catalog-thread > .comment { flex-shrink: 1; align-self: stretch; overflow: hidden; text-align: center; } .thread-info { position: fixed; padding: 2px; border-radius: 2px; box-shadow: 0 0 5px rgba(0, 0, 0, .25); } .thread-info .post { margin: 0; } /* Defaults */ a { text-decoration: none; outline: none; } .underline-links a { text-decoration: underline; } body, html { min-height: 100%; -moz-box-sizing: border-box; } body { outline: none; min-height: 100%; } .sidebar-hide body { margin: 0 2px; } .sidebar-minimal body { margin: 0 20px; } .sidebar-normal body { margin: 0 252px } .sidebar-large body { margin: 0 303px; } .sidebar-location-right body { margin-left: 2px; } .sidebar-location-left body { margin-right: 2px; } body.unscroll { overflow: hidden; } .fourchan-ss-sidebar body::before { content: ''; position: fixed; top: 0; bottom: 0; -moz-box-sizing: border-box; display: block; z-index: 0; } .fourchan-ss-sidebar.sidebar-large body::before { width: 306px; } .fourchan-ss-sidebar.sidebar-normal body::before { width: 255px; } .fourchan-ss-sidebar.sidebar-minimal body::before { width: 23px; } .sidebar-location-right body::before { right: 0; } .sidebar-location-left body::before { left: 0; } .fourchan-ss-sidebar.sidebar-location-right body { padding-right: 2px; } .fourchan-ss-sidebar.sidebar-location-left body { padding-left: 2px; } hr { clear: both; border: 0; padding: 0; margin: 0 0 1px; } .hide-horizontal-rules hr { visibility: hidden; } th { text-align: left; } .center { text-align: center; } .ad-plea { text-align: center; font-size: .8em; } .dead-thread, .disabled { opacity: 0.4; } nav a, .pointer { cursor: pointer; } /* Symbols */ .menu-button i { vertical-align: middle; display: inline-block; margin: 2px 2px 3px; } .brackets-wrap::before { content: \" [\"; } .brackets-wrap::after { content: \"] \"; } /* Thread / Reply Nav */ #navPrev, #navNext { display: inline-block; border-right: 6px solid transparent; border-left: 6px solid transparent; opacity: 0.5; margin: 2px 1px; width: 0; height: 0; } #navPrev { border-bottom: 11px solid rgb(130,130,130); } #navNext { border-top: 11px solid rgb(130,130,130); } /* Header */ #header-bar { z-index: 6; border-width: 1px; padding: 1px 2px; border-style: solid; } .pagination-sticky-top .pagelist, .pagination-sticky-bottom .pagelist, #header-bar { left: 2px; right: 2px; } .navigation-alignment-center #header-bar { text-align: center; } .navigation-alignment-right #header-bar { text-align: right; } .sidebar-location-left.sidebar-large:not(.pagination-on-side):not(.fourchan-ss-navigation) .pagelist, .sidebar-location-left.sidebar-large #header-bar { left: 303px; } .sidebar-location-left.sidebar-normal:not(.pagination-on-side):not(.fourchan-ss-navigation) .pagelist, .sidebar-location-left.sidebar-normal #header-bar { left: 252px; } .sidebar-location-left.sidebar-minimal:not(.pagination-on-side):not(.fourchan-ss-navigation) .pagelist, .sidebar-location-left.sidebar-minimal:not(.fourchan-ss-navigation) #header-bar { left: 20px; } .sidebar-location-right.sidebar-large:not(.pagination-on-side):not(.fourchan-ss-navigation) .pagelist, .sidebar-location-right.sidebar-large #header-bar { right: 303px; } .sidebar-location-right.sidebar-normal:not(.pagination-on-side):not(.fourchan-ss-navigation) .pagelist, .sidebar-location-right.sidebar-normal #header-bar { right: 252px; } .sidebar-location-right.sidebar-minimal:not(.pagination-on-side):not(.fourchan-ss-navigation) .pagelist, .sidebar-location-right.sidebar-minimal:not(.fourchan-ss-navigation) #header-bar { right: 20px; } .fourchan-ss-navigation .pagelist, .fourchan-ss-navigation #header-bar { left: 0; right: 0; border-left: 0; border-right: 0; border-radius: 0 !important; } .hide-navigation-decorations #board-list { font-size: 0; color: transparent; word-spacing: 2px; } .fixed #header-bar.autohide { z-index: 24; } .fixed #header-bar { position: fixed; } .top-header #header-bar { top: 0; border-top-width: 0; } .rounded-edges.top-header #header-bar { border-radius: 0 0 3px 3px; } .fixed.bottom-header #header-bar { bottom: 0; border-bottom-width: 0; } .rounded-edges.bottom-header #header-bar { border-radius: 3px 3px 0 0; } .hide #header-bar { position: fixed; top: 110%; bottom: auto; } /* Header Autohide */ .fixed #header-bar.autohide:not(:hover) { box-shadow: none; transition: all .8s .6s cubic-bezier(.55, .055, .675, .19); } .fixed.top-header #header-bar.autohide:not(:hover) { margin-bottom: -1em; transform: translateY(-100%); } .fixed.bottom-header #header-bar.autohide:not(:hover) { transform: translateY(100%); } #scroll-marker { left: 0; right: 0; height: 10px; position: absolute; } #header-bar #scroll-marker { display: none; } .fixed #header-bar #scroll-marker { display: block; } .fixed.top-header header-bar #scroll-marker { top: 100%; } .fixed.bottom-header #header-bar #scroll-marker { bottom: 100%; } /* Notifications */ #notifications { position: fixed; top: 0; text-align: center; right: 0; left: 0; transition: all .8s .6s cubic-bezier(.55, .055, .675, .19); } .fixed.top-header #header-bar #notifications { position: absolute; top: 100%; } .notification { font-weight: 700; text-shadow: 0 1px 2px rgba(0, 0, 0, .5); box-shadow: 0 1px 2px rgba(0, 0, 0, .15); border-radius: 2px; margin: 1px auto; width: 500px; max-width: 100%; position: relative; transition: all .25s ease-in-out; } .notification.error { background-color: hsla(0, 100%, 38%, .9); } .notification.warning { background-color: hsla(36, 100%, 38%, .9); } .notification.info { background-color: hsla(200, 100%, 38%, .9); } .notification.success { background-color: hsla(104, 100%, 38%, .9); } .notification, .notification a { color: #fff !important; } .notification > .close { top: 0; padding: 2px; right: 4px; position: absolute; color: #fff; } .message { -moz-box-sizing: border-box; padding: 6px 20px; max-height: 200px; width: 100%; overflow: auto; } /* Shortcuts */ #shortcuts { position: fixed; display: flex; top: 0; padding: 1px; z-index: 16; flex-direction: row; max-height: 1.1em; overflow: visible; } .shortcut { margin: 0 1px; } .icon-orientation-vertical #a-icons .shortcut { margin: 0; } #a-icons, #a-stats { order: 0; display: flex; } #a-icons { order: 10; } #a-stats { height: 1.1em; } .sidebar-location-right #shortcuts { right: 0; } .sidebar-location-left #shortcuts { left: 0; } .sidebar-location-right .shortcut { align-self: flex-end; } .icon-orientation-vertical #a-icons { flex-direction: column; height: 200px; } .icon-orientation-horizontal #a-stats { height: 1em; } .icon-orientation-horizontal #a-stats, .icon-orientation-horizontal #a-icons, .sidebar-location-left #shortcuts { flex-direction: row-reverse; } .icon-orientation-horizontal.sidebar-location-left #a-stats, .icon-orientation-horizontal.sidebar-location-left #a-icons { flex-direction: row; } #thread-stats { order: 0; } #updater { order: 10; } #main-menu { order: 0; } #qr-shortcut { order: 10; } #img-controls { order: 20; } #appchan-gal { order: 25; } #fappeTyme { order: 30; } #werkTyme { order: 35; } #so-nav { order: 40; } #so-watcher { order: 50; } #so-psa { order: 60; } #navPrev { order: 70; } #navNext { order: 80; } #catalogIcon { order: 90; } #returnIcon { order: 100; } .icon-orientation-horizontal #so-psa #globalMessage, .icon-orientation-horizontal #so-watcher #thread-watcher, .icon-orientation-horizontal #so-nav #boardNavDesktopFoot { top: 15px !important; } .icon-orientation-vertical #so-psa, .icon-orientation-vertical #so-watcher, .icon-orientation-vertical #so-nav { position: relative; } .icon-orientation-vertical #so-psa #globalMessage, .icon-orientation-vertical #so-watcher #thread-watcher, .icon-orientation-vertical #so-nav #boardNavDesktopFoot { top: 0 !important; position: absolute !important; z-index: -1; } .sidebar-location-right.icon-orientation-vertical #so-psa #globalMessage, .sidebar-location-right.icon-orientation-vertical #so-watcher #thread-watcher, .sidebar-location-right.icon-orientation-vertical #so-nav #boardNavDesktopFoot { padding-right: 17px; } .sidebar-location-left.icon-orientation-vertical #so-psa #globalMessage, .sidebar-location-left.icon-orientation-vertical #so-watcher #thread-watcher, .sidebar-location-left.icon-orientation-vertical #so-nav #boardNavDesktopFoot { padding-left: 17px; } .a-icon, #shortcuts .fa { display: inline-block; width: 15px; height: 15px; content: \"\"; opacity: 0.5; cursor: pointer; } .invisible-icons .a-icon, .invisible-icons #shortcuts .fa { opacity: 0; } #so-nav, #so-watcher, #so-psa { line-height: 0; } .shortcut > div { line-height: normal; } #main-menu { background-position: 0 0; } #returnIcon { background-position: 0 -15px; } #so-watcher .a-icon { background-position: 0 -30px; } #so-psa .a-icon { background-position: 0 -45px; } #so-nav .a-icon { background-position: 0 -60px; } #img-controls { background-position: 0 -90px; } #catalogIcon { background-position: 0 -120px; } #fappeTyme { background-position: 0 -135px; } #navPrev:hover, #navNext:hover, .a-icon:hover, #shortcuts .fa:hover { opacity: 1 !important; } /* Updater / Thread Stats */ .float #thread-stats, .float #updater { position: fixed; z-index: 25; } #update-status.new::after { content: ', '; } /* Pagination */ .pagelist { border-style: solid; border-width: 1px; z-index: 6; } .pagination-alignment-center .pagelist { text-align: center; } .pagination-alignment-right .pagelist { text-align: right; } .pagination-sticky-top .pagelist { position: fixed; top: 0; border-top-width: 0; } .pagination-sticky-bottom .pagelist { position: fixed; bottom: 0; border-bottom-width: 0; } .pagination-top .pagelist { position: static; border-top-width: 0; } .pagination-bottom .pagelist { position: static; } .pagination-top.rounded-edges .pagelist, .pagination-sticky-top.rounded-edges .pagelist { border-radius: 0 0 3px 3px; } .pagination-bottom.rounded-edges .pagelist, .pagination-sticky-bottom.rounded-edges .pagelist { border-radius: 3px 3px 0 0; } .thread .pagelist, .pagination-hide .pagelist { display: none; } .pagination-on-side .pagelist { position: fixed; padding: 0; top: auto; bottom: 0.5em; margin: 0; background: none transparent !important; border: 0 none !important; text-align: right; } .pagination-on-side.post-form-style-fixed.show-post-form-header .pagelist { bottom: 23.1em; } .pagination-on-side.post-form-style-fixed .pagelist { bottom: 21.6em; } .sidebar-location-left.pagination-on-side .pagelist { transform: rotate(-90deg); transform-origin: bottom left; } .sidebar-location-right.pagination-on-side .pagelist { transform: rotate(90deg); transform-origin: bottom right; } .sidebar-location-right.sidebar-large.pagination-on-side .pagelist { left: auto; right: 301px; } .sidebar-location-left.sidebar-large.pagination-on-side .pagelist { right: auto; left: 301px; } .sidebar-location-right.sidebar-normal.pagination-on-side .pagelist { left: auto; right: 246px; } .sidebar-location-left.sidebar-normal.pagination-on-side .pagelist { right: auto; left: 246px; } .sidebar-location-right.sidebar-minimal.pagination-on-side .pagelist { left: auto; right: 246px; } .sidebar-location-left.sidebar-minimal.pagination-on-side .pagelist { right: auto; left: 18px; } .hide-navigation-decorations .pagelist { font-size: 0; color: transparent; word-spacing: 0; } .pagelist input, .pagelist div { vertical-align: middle; } .hide-navigation-decorations .pages a { margin: 0 1px; } .next, .pages, .prev { display: inline-block; margin: 0 3px; } /* Icons */ .icons-4chan-ss .a-icon { background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAACWCAMAAAA2YSLzAAAAPFBMVEVkZGRlZWVjY2NmZmZnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dZxmG7AAAAE3RSTlMFFQ0AJD8eQFRqf5CgssDM4+73gHqZRAAAA0pJREFUSMetVlmy5CgMZDMGxK7737Ulgcu8ejMREzHtD7sShJRaKWV/Psq3iz7QGwTF2BZ01hp3N6yasctZJANiN5ZlItDLtNkQDGNeMLU7EqmCbUwhkhZbwsIuNbyWPX7dIyHOrDYOc8SOiEUJjojN0EsWlCXRrq2qvJCsIjic2OcFrwrOpdmTimqVyWG7ZkrWy97p7z/hACd2FUetBcQDpTN+nuKsGng881L5xOz/VQ88xL/eQkyZT3axp+4dUMwvH0Pnhn6wSyR+8IdR4f43/v8XX1BHjXpjwy5RdEcQ7DiuzlBUsFD+GeIFEy6W0pKXoSZOiUz5tf99nvTDD/1sP9VRPvb/un86lT57SVqwSk8KR+L6kgTOlcZslRQe5WmJRKovETW7Anb+HzxUW4Xgnv11fuuj82aKXHz1Tzztx9v4VA9+/6le26B+3VhTC9RMPIr0qx4zaWNsnFRO0s8FWgEIFIRiVUAIlJGciqMmCwpQWyI/OplXA1RrXG1YI2svTQ3ufhWjNlKFqtXFI7Yg+zAXRcBZ+HygJuVHd0ys35bVn6QojLL5cZeVvPht/mVu/r/8s7GMXsLjv2s71GZhgjnEwsEVXogiSl/pl7LWra0IQgO3poTsieoYd4dhWfJlGWqyQf6sLxWt3/MRa4Im04ixeSdAWnxvqCX6tObVmzpZOPOZvrBNJF8gmGciBChsV+YdRYwnAvNpS4AnYFBm0KA2a35Unh+efxjercaLfV7wW0rtUTNl2j715al/9VtfutF+NZ/+aZSa+py/GCpRyvr17EsVLbRhmN++BBY/ik5/+YPK6bKnf2T8fh7P+uEYn0D3E4L3i6QHmvc3+k+8PN6Mb1w52tje6LbAi+M0FT4YneqVbpVDPnL2Xqx7m3tf9ENXHba9H/a/+X3z/+XfCnOo+Zy/o4SgY5Z6iq0nb+9Mc4JxL5f1qYs+xhTP/uiX/cMe4+hDHAfGnmGe+Ev+G88vnG7Ie20wHiUt/S1Kv+6BCM/9fkEfz73/9HNufQ4ZKdzvnwtS/LXltRcJB/yJ23H/mo89nPFa85Li3XOYu435LwTXKVWwO+cnlWFTB47L/AdfR//KI2bvF8sAb0c/M+1+YE3/oS77B8N+UUVHraV6AAAAAElFTkSuQmCC\"); } .icons-oneechan .a-icon { background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAACWCAMAAAA2YSLzAAAAPFBMVEVoaGhqampeXl5sbGxsbGxra2tsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGzXmsRLAAAAE3RSTlMAEAYnHBg2QExbcYaWqM++2+z4BMdvAwAAAtVJREFUSMfFVgmu3CAMhYRPAmb3/e9aL5Bl2kptVbXWSOSBsY15NmOMMZs1KnNExC+ezgV4MBtNMIw58+qX2REtQwiifdC6hwlNQBGfUlBzc+KYkP3IxH5hNvicCPXrMfEVi3ts2WrzaiN6jie2OI2GXbBfXiA/XPyexPpEHrHdyDV8YAt6vEYCVpJ3S7rXAZKkkfbnuR8Uk/32xsac6Y01La2ZfyIh1VrX9Rnfu5ygd6/XeQAGFxACkopDb3mkeXug48x5FCKhNzW+1j2t8/5EEwHTIfPm6G3aP37o/w/ir3QZ2V/xY0spdSxWL7MrLU7slmnDSY0UrH6CBJ/wFI3TNGECCDY9G4xmrpDkZvQMJ4q31EzLQuhipr7ag8ueFa+hUQy2d43nnPGg7NopHTUVyYlWpE+lUT4qfhDCnLpzB8oXLLJb4leptD/JblswOaZd0gRkDV0cJi69NNOUaclRpG6S1NPdRVPLjI3VSjWV8+FmaARknTxqfipl0tGR1DXvd0h251Ww/ZlaNQoaX3bqUS+IK6ZX4hysvuQinS+6n9638/6BbK4RLi6R11O8rPS4OnO66KHtw6yK96BWrg5QxDGcVzcoB8cYb/dE1zPO6C+pHxN0Ttw/JtJrx55+oV9Jq+ScF22IfBWDD+sHfTnBmKlpS99hPGSC4SBsi+dP3p0PjVBVedMdO3WoG57cAEbYVNkRHFROIzjYuGjoM7LOaEQKbtQjkuo5hCSMmezaNq3Gl6TE5J3ZLMu26SjpPJZo4h/9FJhT4JQJzjFXD7x54fBgzO9RvDH9Vl5vHIetcGHct1apLh/6gU3c2PYy5rrYh7a1NP29/H/G9xn/d+f7FNVcw9/H/9sf8ymXPnqdDd7Wx3OpzWRJuP8+iMTFe7wZq48Tce7QciNetUzku+pT/t4UHK/iIq2yPR/8y/315M/rWl1A/sM83phVh6+aeZY39OLNN4Y0P2GdHOWPAAAAAElFTkSuQmCC\"); } /* Banner & Board Title */ .boardBanner { line-height: 0; } .faded-4chan-banner .boardBanner { opacity: 0.5; transition: opacity 0.3s ease-in-out .5s; } .faded-4chan-banner .boardBanner:hover { opacity: 1; transition: opacity 0.3s ease-in; } /* From 4chan SS / OneeChan */ .fourchan-banner-reflection .boardBanner::after { background-image: -moz-element(#Banner); bottom: -100%; content: ''; left: 0; mask: url(\"data:image/svg+xml,<svg version='1.1' xmlns='http://www.w3.org/2000/svg'><defs><linearGradient gradientUnits='objectBoundingBox' id='gradient' x2='0' y2='1'><stop stop-offset='0'/><stop stop-color='white' offset='1'/></linearGradient><mask id='mask' maskUnits='objectBoundingBox' maskContentUnits='objectBoundingBox' x='0' y='0' width='100%' height='100%'> <rect fill='url(%23gradient)' width='1' height='1' /></mask></defs></svg>#mask\"); opacity: 0.3; position: absolute; right: 0; top: 100%; -moz-transform: scaleY(-1); z-index: -1; } .fourchan-banner-at-sidebar-top .boardBanner, .fourchan-banner-at-sidebar-bottom .boardBanner, .fourchan-banner-at-sidebar-bottom .boardBanner { position: fixed; } .fourchan-banner-at-sidebar-top .boardBanner { top: 18px; } .fourchan-banner-at-sidebar-bottom .boardBanner { bottom: 270px; } .fourchan-banner-under-post-form .boardBanner { bottom: 130px; } .board-title-at-sidebar-top.sidebar-location-right #boardTitle, .board-title-at-sidebar-bottom.sidebar-location-right #boardTitle, .board-title-under-post-form.sidebar-location-right #boardTitle, .fourchan-banner-at-sidebar-top.sidebar-location-right .boardBanner, .fourchan-banner-at-sidebar-bottom.sidebar-location-right .boardBanner, .fourchan-banner-under-post-form.sidebar-location-right .boardBanner { right: 2px; } .board-title-at-sidebar-top.sidebar-location-left #boardTitle, .board-title-at-sidebar-bottom.sidebar-location-left #boardTitle, .board-title-under-post-form.sidebar-location-left #boardTitle, .fourchan-banner-at-sidebar-top.sidebar-location-left .boardBanner, .fourchan-banner-at-sidebar-bottom.sidebar-location-left .boardBanner, .fourchan-banner-under-post-form.sidebar-location-left .boardBanner { left: 2px; } .board-title-at-sidebar-top #boardTitle, .board-title-at-sidebar-bottom #boardTitle, .board-title-under-post-form #boardTitle, .fourchan-banner-at-sidebar-top .boardBanner img, .fourchan-banner-at-sidebar-bottom .boardBanner img, .fourchan-banner-under-post-form .boardBanner img { width: 248px; } .board-title-at-sidebar-top.sidebar-large #boardTitle, .board-title-at-sidebar-bottom.sidebar-large #boardTitle, .board-title-under-post-form.sidebar-large #boardTitle, .fourchan-banner-at-sidebar-top.sidebar-large .boardBanner img, .fourchan-banner-at-sidebar-bottom.sidebar-large .boardBanner img, .fourchan-banner-under-post-form.sidebar-large .boardBanner img { width: 299px; } .fourchan-banner-at-top .boardBanner { position: relative; display: table; margin: 12px auto; text-align: center; } :root:not(.board-subtitle) .boardSubtitle, .board-title-hide #boardTitle, .fourchan-banner-hide .boardBanner { display: none; } #boardTitle { text-align: center; z-index: 4; } .board-title-at-sidebar-top #boardTitle, .board-title-at-sidebar-bottom #boardTitle, .board-title-under-post-form #boardTitle { position: fixed; } .board-title-at-sidebar-top.fourchan-banner-at-sidebar-top.sidebar-large #boardTitle { top: 121px; } .board-title-at-sidebar-top.fourchan-banner-at-sidebar-top #boardTitle { top: 104px; } .board-title-at-sidebar-top #boardTitle { top: 40px; } .board-title-at-sidebar-bottom #boardTitle { bottom: 280px; } .board-title-under-post-form #boardTitle { bottom: 140px; } /* Hover UI */ .move { cursor: pointer; } #ihover { position: fixed; max-height: 94vh; max-width: 75vw; z-index: 22; } #qp { position: fixed; z-index: 22; } #qp .postMessage::after { clear: both; display: block; content: \"\"; } #qp .full-image { max-height: 300px; max-width: 500px; } #menu { position: fixed; outline: none; z-index: 27; } /* Image Expansion */ .fit-width .full-image { max-width: 100%; } .gecko.fit-width .full-image { width: 100%; } .fit-height .full-image { max-height: 95vh; } .images-overlap-post-form .full-image { position: relative; z-index: 21; } /* Delete Buttons */ .hide-delete-ui .deleteform, .hide-delete-ui .post:not(#exlinks-options) .rice { display: none; } .deleteform { position: fixed; z-index: 18; width: 0; bottom: 0; right: 0; border-width: 1px 0 0 1px; border-style: solid; font-size: 0; color: transparent; } .deleteform:hover { width: auto; } .deleteform::before { z-index: 18; border-width: 1px 0 0 1px; border-style: solid; content: '\uf00d'; font-family: FontAwesome; font-weight: normal; font-style: normal; text-decoration: inherit; -webkit-font-smoothing: antialiased; font-size:14px !important; display: block; position: fixed; bottom: 0; right: 0; -moz-box-sizing: border-box; height: 1.6em; width: 1.4em; text-align: center; } .deleteform:hover::before { display: none; } .deleteform input { margin: 0 1px 0 0; } /* Slideout Navigation */ #boardNavDesktopFoot { position: fixed; text-align: center; font-size: 0; color: transparent; overflow-x: hidden; overflow-y: auto; -moz-box-sizing: border-box; width: 248px; } .sidebar-large #boardNavDesktopFoot { width: 299px; } .sidebar-location-right #boardNavDesktopFoot { right: 2px; } .sidebar-location-left #boardNavDesktopFoot { left: 2px; } #so-nav:hover #boardNavDesktopFoot { display: block; } #boardNavDesktopFoot { display: none; padding: 2px; } .slideout-navigation-hide #so-nav { display: none; } .slideout-navigation-compact #boardNavDesktopFoot { word-spacing: 1px; } .slideout-navigation-list #boardNavDesktopFoot a { display: block; } .slideout-navigation-list #boardNavDesktopFoot { max-height: 400px; } .slideout-navigation-list #boardNavDesktopFoot a::after { content: ' - ' attr(title); } .slideout-navigation-list #boardNavDesktopFoot a[href*='//boards.4chan.org/']::after, .slideout-navigation-list #boardNavDesktopFoot a[href*='//rs.4chan.org/']::after { content: '/ - ' attr(title); } .slideout-navigation-list #boardNavDesktopFoot a[href*='//boards.4chan.org/']::before, .slideout-navigation-list #boardNavDesktopFoot a[href*='//rs.4chan.org/']::before { content: '/'; } .slideout-navigation-hide #boardNavDesktopFoot { display: none; } /* Watcher */ #thread-watcher { position: fixed; z-index: 14; padding: 2px; } #thread-watcher { width: 200px; } #thread-watcher:not(:hover) { max-height: 200px; overflow: hidden; } .rounded-edges #thread-watcher { border-radius: 3px; } #watched-threads > div { max-height: 1.3em; overflow: hidden; } .slideout-watcher #thread-watcher { -moz-box-sizing: border-box; width: 248px; } .slideout-watcher.sidebar-large #boardNavDesktopFoot { width: 299px; } .slideout-watcher.sidebar-location-right #thread-watcher { left: auto !important; right: 2px !important; } .slideout-watcher.sidebar-location-left #thread-watcher { right: auto !important; left: 2px !important; } .slideout-watcher #thread-watcher .move { cursor: default; } .slideout-watcher.underline-links #thread-watcher .move { text-decoration: underline; } .slideout-watcher #thread-watcher > div { overflow: hidden; } .slideout-watcher #so-watcher:hover #thread-watcher { display: block; } .slideout-watcher #thread-watcher { display: none; overflow-y: auto; } .watch-thread-link { padding-top: 18px; width: 18px; height: 0px; display: inline-block; background-repeat: no-repeat; opacity: 0.2; position: relative; top: 1px; } .watch-thread-link.watched { opacity: 1; } /* Announcements */ #globalMessage { text-align: center; } .rounded-edges #globalMessage { border-radius: 3px; } .announcements-slideout #globalMessage { position: fixed; padding: 2px; width: 248px; } .announcements-slideout.sidebar-location-right #globalMessage { left: auto; right: 2px; } .announcements-slideout.sidebar-location-left #globalMessage { right: auto; left: 2px; } .announcements-slideout.sidebar-large #globalMessage { width: 299px; } .announcements-slideout #globalMessage h3 { margin: 0; } .announcements-slideout #globalMessage { -moz-box-sizing: border-box; display: none; } .announcements-slideout #so-psa:hover #globalMessage { display: block; } .announcements-hide #globalMessage { display: none !important; } /* Threads */ #threads, .rounded-edges .board > .thread { border-radius: 4px; } /* Thread Clearfix */ .thread > .threadContainer:last-of-type::after { display: block; content: ' '; clear: both; } /* Posts */ .expanding { opacity: .5; } .expanded-image > .post > .file > .fileThumb > img[data-md5], .post > .file > .fileThumb > .full-image { display: none; } .expanded-image > .post > .file > .fileThumb > .full-image { display: block; } .thread > .replyContainer:last-of-type .post { margin-bottom: 0; } .menu-button { position: relative; } .post .menu-button, .hide-post-button, .show-post-button span { float: right; } .post .menu-button, .hide-post-button { margin: 0 3px; opacity: 0; transition: opacity .3s ease-out 0s; } .post:hover .hide-post-button, .post:hover .menu-button, .inline .hide-post-button, .inline .menu-button { opacity: 1; } .color-user-ids .posteruid .hand { padding: .1em .3em; border-radius: 1em; font-size: 80%; } div.post div.postInfo { padding: 1px 3px; display: block !important; } .postInfo > span { vertical-align: bottom; } .bolds .subject, .bolds .name { font-weight: 600; } .italics .postertrip { font-style: italic; } .underline-links .replylink { text-decoration: underline; } .reply .fileText { padding: 0 3px; } .compact-file-text .fileText { font-size: .9em; } .fileThumb { float: left; margin: 3px 20px; outline: none; } .reply.post { -moz-box-sizing: border-box; display: inline-block; } .replyContainer { display: flex; } .fit-width-replies .reply.post { flex: 1 0; } .fit-width-replies .expanded-image .reply.post, .fit-width-replies .hasInline .reply.post { width: 100%; } .indent-replies #unread-line, .indent-replies .thread > .replyContainer, .indent-replies .threadContainer > .replyContainer { margin-left: 2em; } .rounded-edges .post { border-radius: 3px; } .spoiler, s { text-decoration: none; } /* Emoji */ a.useremail:last-of-type { vertical-align: top; } /* OP */ .watch-thread-link { vertical-align: bottom; } .op-background .op.post { -moz-box-sizing: border-box; } /* Force Reply Break */ .op-background .op.post .postMessage::after, .force-reply-break .op.post .postMessage::after { display: block; content: ' '; clear: both; } /* Summary */ .force-reply-break .summary { clear: both; } /* Inlined */ .inline { margin: 2px 8px 2px 2px; } .post .inline { margin: 2px; } .inline .replyContainer { display: inline-block; } /* Quotes */ .inlined { opacity: .5; } .underline-links .quotelink { text-decoration: underline; } .filtered, .quotelink.filtered { text-decoration: line-through !important; } .inline + .hashlink { display: none; } .hashlink::before { content: '\\00a0'; } /* Quote Threading */ .threadContainer { padding-left: 2em; border-left: 1px solid; } .indent-replies .threadContainer { margin-left: 2em; padding-left: 0; } .threadOP { clear: both; } /* Backlinks */ .underline-links .forwardlink, .underline-links .backlink { text-decoration: underline; } .backlink.dead { text-decoration: none; } .filtered-backlinks .filtered.backlink { display: none; } .backlinks-position-lower-left .container, .backlinks-position-lower-right .container { max-width: 100%; padding: 0 5px; } .backlinks-position-lower-left .reply.quoted, .backlinks-position-lower-right .reply.quoted { position: relative; padding-bottom: 1.7em; } .backlinks-position-lower-left .inline .reply.quoted, .backlinks-position-lower-right .inline .reply.quoted, .backlinks-position-lower-right #qp .reply.quoted, .backlinks-position-lower-left #qp .reply.quoted { position: static; padding-bottom: 0; } .backlinks-position-lower-right .reply .container, .backlinks-position-lower-left .reply .container { position: absolute; bottom: 0; padding: 0 5px; } .backlinks-position-lower-left .reply .container { left: 0; } .backlinks-position-lower-right .reply .container { right: 0; } .backlinks-position-lower-right .container::before, .backlinks-position-lower-left .reply .container::before { content: 'REPLIES: '; } .container:empty { display: none; } .backlinks-position-lower-left #qp .container, .backlinks-position-lower-left .inline .container, .backlinks-position-lower-right .inline .container, .backlinks-position-lower-right #qp .container { position: static; max-width: 100%; } .backlinks-position-lower-left #qp .container::before, .backlinks-position-lower-left .inline .container::before, .backlinks-position-lower-right #qp .container::before, .backlinks-position-lower-right .inline .container::before { content: ''; } .backlinks-position-lower-right .inline .container { float: none; } /* Fixes text spoilers */ .remove-spoilers.reveal-spoilers .spoiler::before, .remove-spoilers.reveal-spoilers s::before { content: '[spoiler]'; } .remove-spoilers.reveal-spoilers .spoiler::after, .remove-spoilers.reveal-spoilers s::after { content: '[/spoiler]'; } :root:not(.remove-spoilers).reveal-spoilers .spoilers:not(:hover), :root:not(.remove-spoilers).reveal-spoilers s:not(:hover) { color: white !important; } :root:not(.remove-spoilers) .spoiler:not(:hover) *, :root:not(.remove-spoilers) s:not(:hover) * { color: rgb(0,0,0) !important; text-shadow: none !important; } :root:not(.remove-spoilers) spoiler:not(:hover), :root:not(.remove-spoilers) s:not(:hover) { background-color: rgb(0,0,0); color: rgb(0,0,0) !important; text-shadow: none !important; } /* Code */ .prettyprint { -moz-box-sizing: border-box; font-family: monospace; display: inline-block; margin: 0 auto .1em 0; vertical-align: middle; white-space: pre-wrap; border-radius: 2px; overflow-x: auto; padding: 3px; max-width: 100%; } /* Menu */ .entry { border-bottom: 1px solid rgba(0,0,0,.25); cursor: pointer; display: block; outline: none; padding: 3px 1em 3px 7px; position: relative; text-decoration: none; white-space: nowrap; } .entry:last-child { border-bottom: 0; } .has-submenu::after { content: \"\uf141\"; display: inline-block; margin: .3em; position: absolute; right: .2em; } .submenu { display: none; position: absolute; top: -1px; } .focused > .submenu { display: block; } /* Stubs */ .fit-width-replies .stub { display: block; text-align: right; clear: both; } /* Element Replacing: */ /* Checkboxes */ .rice { cursor: pointer; width: .7em; height: .7em; margin: 2px 3px; display: inline-block; vertical-align: bottom; } input[type=checkbox]:checked + .rice { position: relative; } input[type=checkbox]:checked + .rice::after { content: \"\"; display: block; width: 4px; height: 10px; border-width: 0 3px 3px 0; border-style: solid; transform: rotate(45deg); position: absolute; left: 2px; bottom: -1px; } .rounded-edges .rice { border-radius: 2px;} } .circle-checkboxes .rice { border-radius: 6px;} } input:checked + .rice { background-attachment: scroll; background-repeat: no-repeat; background-position: bottom right; } /* Selects */ .selectrice { position: relative; cursor: default; overflow: hidden; text-align: left; } #settings .selectrice { display: inline-block; } .selectrice::after { content: \"\"; border-right: .25em solid transparent; border-left: .25em solid transparent; position: absolute; right: .4em; top: .5em; } .selectrice::before { content: \"\"; height: 1.6em; position: absolute; right: 1.3em; top: 0; } /* Select Dropdown */ #selectrice { padding: 0; margin: 0; position: fixed; max-height: 120px; overflow-y: auto; overflow-x: hidden; z-index: 32; } #selectrice:empty { display: none; } /* Post Form Shortcut */ .qr-shortcut.on-page { font-size: 250%; } /* Post Form */ #qr { z-index: 20; position: fixed; background: none; border: none; padding: 1px; min-width: 248px; background: transparent; border: 1px solid transparent; } .sidebar-large #qr { min-width: 299px; } .rounded-edges #qr, .rounded-edges #qrtab { border-radius: 3px 3px 0 0; } .post-form-style-fixed #qr { top: auto !important; } .sidebar-location-left:not(.post-form-style-float) #qr { left: 0 !important; right: auto !important; } .sidebar-location-right:not(.post-form-style-float) #qr { right: 0 !important; left: auto !important; } :root:not(.post-form-style-float) #qr { bottom: 0 !important; } .fourchan-ss-navigation.fixed.bottom-header:not(.post-form-style-float) #qr, .fourchan-ss-navigation.index.pagination-sticky-bottom:not(.post-form-style-float) #qr { bottom: 1.5em !important; } .post-form-style-slideout #qr { top: auto !important; } .post-form-style-slideout.sidebar-location-left #qr { transform: translateX(-93%); } .post-form-style-slideout.sidebar-location-right #qr { transform: translateX(93%); } .post-form-style-slideout #qr:hover, .post-form-style-slideout #qr.focus, .post-form-style-slideout #qr.dump { transform: translate(0); } .post-form-style-tabbed-slideout #qr { top: auto !important; } .post-form-style-tabbed-slideout.sidebar-location-left #qr { transform: translateX(-100%); } .post-form-style-tabbed-slideout.sidebar-location-right #qr { transform: translateX(100%); } .post-form-style-tabbed-slideout #qr:hover, .post-form-style-tabbed-slideout #qr.focus, .post-form-style-tabbed-slideout #qr.dump { transform: translateX(0); } .post-form-style-tabbed-slideout #qrtab { position: absolute; top: 0; width: 120px; text-align: center; border-width: 1px 1px 0 1px; cursor: default; } .post-form-style-tabbed-slideout.sidebar-location-left #qrtab { transform: rotate(90deg); transform-origin: bottom right; left: 100%; } .post-form-style-tabbed-slideout.sidebar-location-right #qrtab { transform: rotate(-90deg); transform-origin: bottom right; right: 100%; } .post-form-style-tabbed-slideout #qr:hover #qrtab, .post-form-style-tabbed-slideout #qr.focus #qrtab, .post-form-style-tabbed-slideout #qr.dump #qrtab { opacity: 0 !important; } .post-form-style-slideout #qrtab input, .post-form-style-slideout #qrtab .rice, .post-form-style-tabbed-slideout #qrtab input, .post-form-style-tabbed-slideout #qrtab .close, .post-form-style-tabbed-slideout #qrtab .rice, .post-form-style-tabbed-slideout #qrtab span { display: none; } .post-form-style-tabbed-slideout #qrtab .selectrice { text-align: center; } .transparent-post-form #qr { opacity: 0.2; transition: opacity .3s ease-in-out 1s; } .transparent-post-form #qr:hover, .transparent-post-form #qr.focus, .transparent-post-form #qr.dump { opacity: 1; transition: opacity .3s linear; } :root:not(.show-post-form-header):not(.post-form-style-float):not(.post-form-style-tabbed-slideout) #qrtab, .post-form-style-float .autohide:not(:hover):not(.focus) form, .show-post-form-header.post-form-style-fixed .autohide:not(:hover):not(.focus) form { display: none !important; } :root:not(.post-form-style-tabbed-slideout) #qrtab { margin-bottom: 1px; } #qr.autohide:not(:hover):not(.focus) #qrtab { margin-bottom: 0; } .post-form-slideout-transitions.post-form-style-slideout #qr, .post-form-slideout-transitions.post-form-style-tabbed-slideout #qr { transition: transform .3s ease-in-out 1s; } .post-form-slideout-transitions.post-form-style-tabbed-slideout #qr.dump, .post-form-slideout-transitions.post-form-style-tabbed-slideout #qr:hover, .post-form-slideout-transitions.post-form-style-tabbed-slideout #qr.focus, .post-form-slideout-transitions.post-form-style-slideout #qr.dump, .post-form-slideout-transitions.post-form-style-slideout #qr:hover, .post-form-slideout-transitions.post-form-style-slideout #qr.focus { transition: transform .3s linear; } .post-form-slideout-transitions #qrtab { transition: opacity .3s ease-in-out 1s; } .post-form-slideout-transitions #qr:hover #qrtab { transition: opacity .3s linear; } #qr .close { float: right; padding: 0 3px; } #qr .warning { min-height: 1.6em; vertical-align: middle; padding: 0 1px; border-width: 1px; border-style: solid; } .persona { display: flex; flex-direction: column; align-items: stretch; } .compact-post-form-inputs .persona { flex-direction: row; } #qr textarea.field { height: 11.6em; min-height: 6em; } #qr.has-captcha textarea.field { height: 6em; } .compact-post-form-inputs .persona input.field { flex: 1 1; margin: 0 0 0 1px; } .compact-post-form-inputs .persona input:focus { flex: 3 1; } .compact-post-form-inputs .persona input.field:first-child { margin: 0; } .compact-post-form-inputs #qr textarea.field { height: 14.9em; min-height: 9em; } .compact-post-form-inputs #qr.has-captcha textarea.field { height: 9em; } .tripcode-hider .tripped:not(:hover):not(:focus) { color: transparent !important; } .textarea-resize-horizontal #qr textarea { resize: horizontal; } .textarea-resize-vertical #qr textarea { resize: vertical; } .textarea-resize-both #qr textarea { resize: both; } .textarea-resize-none #qr textarea { resize: none; } .captcha-img div { margin: 1px 0 0; text-align: center; line-height: 0; background-color: #fff; } .captcha-img img { width: 246px; } .captcha-img, .captcha-img img { height: 4em; } .captcha-input { width: 100%; margin: 1px 0 0; } .field, .selectrice, button, input:not([type=radio]) { -moz-box-sizing: border-box; height: 1.6em; margin: 1px 0 0; vertical-align: bottom; padding: 0 1px; outline: none; transition: color .25s, border-color .25s, flex .25s; } .selectrice { padding-right: 1.6em; } #qr textarea { min-width: 100%; } #file-n-submit { display: flex } #qr [type='submit'] { width: 60px; } [type='file'] { position: absolute; opacity: 0; z-index: -1; } /* Fake File Input */ #qr-filename, #qr-filerm, .has-file #qr-no-file { display: none; } #qr-no-file, .has-file #qr-filename { display: block; } #qr-filename { border: medium none; vertical-align: top; padding: 0; margin: 0; height: auto; background: transparent none; overflow: hidden; text-overflow: ellipsis; width: 88%; } #qr-filename:not(.edit) { pointer-events: none; } .has-file #qr-filerm { display: inline-block; } #qr-extras-container { position: absolute; right: 0; top: 0; z-index: 2; } #qr-extras-container > label, #qr-extras-container > a { cursor: pointer; margin-right: 3px; } #qr-filename-container { -moz-box-sizing: border-box; display: inline-block; position: relative; margin-right: 1px; flex: 1 1; overflow: hidden; padding: 2px 1px 0; } /* Thread Select */ #qr-thread-select, #qr-thread-select .selectrice div { display: inline; } #qr-thread-select .selectrice { cursor: pointer; display: inline-block; width: 120px; border: none; background: none transparent; padding: 0; margin: 0; height: auto; } #qr-thread-select .selectrice::before, #qr-thread-select .selectrice::after { display: none; } /* Dumping UI */ .dump #dump-list-container { display: block; } #dump-list-container { display: none; position: relative; overflow-y: hidden; margin-top: 1px; } #dump-list { overflow-x: auto; overflow-y: hidden; white-space: nowrap; width: 248px; max-width: 100%; min-width: 100%; } #dump-list:hover { overflow-x: auto; } .qr-preview { -moz-box-sizing: border-box; counter-increment: thumbnails; cursor: move; display: inline-block; height: 90px; width: 90px; padding: 2px; opacity: .5; overflow: hidden; position: relative; text-shadow: 0 1px 1px #000; transition: opacity .25s ease-in-out; vertical-align: top; } .qr-preview:hover, .qr-preview:focus { opacity: .9; } .qr-preview::before { content: counter(thumbnails); color: #fff; position: absolute; top: 3px; right: 3px; text-shadow: 0 0 3px #000, 0 0 8px #000; } .qr-preview#selected { opacity: 1; } .qr-preview.drag { box-shadow: 0 0 10px rgba(0,0,0,.5); } .qr-preview.over { border-color: #fff; } .qr-preview > span { color: #fff; } .remove { background: none; color: #e00; font-weight: 700; padding: 3px; } a:only-of-type > .remove { display: none; } .remove:hover::after { content: \" Remove\"; } .qr-preview > label { background: rgba(0,0,0,.5); color: #fff; right: 0; bottom: 0; left: 0; position: absolute; text-align: center; } .qr-preview > label > input { margin: 0; } #add-post { cursor: pointer; font-size: 2em; position: absolute; top: 50%; right: 10px; transform: translateY(-50%); } /* Ads */ .fade-ads .topad img, .fade-ads .bottomad img { opacity: 0.3; transition: opacity .3s linear; } .fade-ads .topad img:hover, .fade-ads .bottomad img:hover { opacity: 1; } .hide-ads .bottomad + hr, .hide-ads .topad, .hide-ads .bottomad, .hide-ads .ad-plea { display: none; } .shrink-ads .topad a img, .shrink-ads .bottomad a img { width: 500px; height: auto; } /* Possibly temporary. Non-classed Ad Pleas only appear to be showing up in threads now? */ .mobile + .mobile + .center, body > .center, #delform > .center { display: none; } .ad-plea-middle, .middlead { display: none; } /* Mascot Positions */ #mascot { display: none; position: fixed; z-index: -1; bottom: 0; left: 0; right: 0; line-height: 0; } .click-to-toggle #mascot { cursor: pointer; } .mascot-position-above-post-form.post-form-style-fixed:not(.post-form-decorations) #mascot img { margin-bottom: -2px; } .mascots #mascot { display: block; } .sidebar-location-right.mascot-location-sidebar #mascot, .sidebar-location-left.mascot-location-opposite #mascot { left: auto; } .sidebar-location-left.mascot-location-sidebar #mascot, .sidebar-location-right.mascot-location-opposite #mascot { right: auto; } .sidebar-location-left.mascot-location-sidebar #mascot img, .sidebar-location-right.mascot-location-opposite #mascot img { transform: scaleX(-1); } .fourchan-ss-navigation.bottom-header.fixed #mascot, .fourchan-ss-navigation.index.pagination-sticky-bottom #mascot { bottom: 1.5em } .mascots-overlap-posts #mascot { z-index: 3; } .mascot-position-middle #mascot { bottom: 50% !important; transform: translateY(50%); } .mascot-position-top #mascot { bottom: auto !important; top: 17px; } /* Options */ #overlay { position: fixed; z-index: 30; top: 0; right: 0; left: 0; bottom: 0; background: rgba(0,0,0,.5); } #appchanx-settings { width: auto; left: 15%; right: 15%; top: 15%; bottom: 15%; position: fixed; z-index: 31; padding: .3em; } .rounded-edges #appchanx-settings, .rounded-edges #appchanx-settings fieldset, .rounded-edges .mascots-container, .rounded-edges .section-container, .rounded-edges .sections-list > a { border-radius: 3px; } .description { display: none; } #appchanx-settings h3, .section-keybinds, .section-mascots, .section-script, .style { text-align: center; } .section-keybinds table, .section-script fieldset, .section-style fieldset { text-align: left; } .section-keybinds table { margin: auto; } #appchanx-settings fieldset { padding: 5px 0; vertical-align: top; border: 0; margin: 0 3px 6px; display: inline-block; } .single-column-mode #appchanx-settings fieldset { display: block; margin: 0 auto 6px; } #appchanx-settings .section-advanced fieldset { display: block; margin: 0 auto 6px; } .section-advanced .archive-cell { min-width: 200px; } .section-advanced .selectrice { display: inline-block; clear: both; } .section-container { overflow: auto; position: absolute; top: 1.7em; right: 5px; bottom: 5px; left: 5px; padding: 5px; } .sections-list { padding: 0 3px; float: left; } .sections-list > a { cursor: pointer; position: relative; padding: 0 4px; z-index: 1; height: 1.4em; display: inline-block; border-width: 1px 1px 0 1px; border-color: transparent; border-style: solid; } .sections-list > a.tab-selected { border-style: solid; } .credits { float: right; } #appchanx-settings h3 { margin: 0; } .section-script fieldset > div, .section-style fieldset > div, .section-advanced fieldset > div { overflow: visible; padding: 0 5px 0 7px; } #appchanx-settings tr:nth-of-type(2n+1), .section-script fieldset > div:nth-of-type(2n+1), .section-advanced fieldset > div:nth-of-type(2n+1), .section-style fieldset > div:nth-of-type(2n+1), .section-keybinds tr:nth-of-type(2n+1), #selectrice li:nth-of-type(2n+1) { background-color: rgba(0, 0, 0, 0.05); } article li { margin: 10px 0 10px 2em; } #appchanx-settings .option { width: 50%; display: inline-block; vertical-align: bottom; } .option input { width: 100%; } .optionlabel { padding-left: 18px; } .rice + .optionlabel { padding-left: 0; } .section-script fieldset, .styleoption { text-align: left; } .section-style fieldset { width: 370px; } .section-script fieldset { width: 200px; } #mascotcontent, #themecontent, .suboptions { overflow: auto; position: absolute; top: 0; right: 0; bottom: 1.7em; left: 0; } #mascotcontent, #themecontent { padding: 5px; } #themecontent { top: 1.8em; } .mAlign { height: 250px; vertical-align: bottom; display: table-cell; line-height: 0; } #save, .stylesettings { position: absolute; right: 10px; bottom: 0; } .section-style .suboptions { bottom: 0; } .section-container textarea { font-family: monospace; min-height: 150px; resize: vertical; width: 100%; } /* Hover Functionality */ #mouseover { z-index: 33; position: fixed; max-width: 70%; } #mouseover:empty { display: none; } /* Mascot Tab */ #mascot_hide { padding: 3px; position: absolute; top: 2px; right: 18px; } #mascot_hide .rice { float: left; } #mascot_hide > div { height: 0; text-align: right; overflow: hidden; } #mascot_hide:hover > div { height: auto; } #mascot_hide label { width: 100%; display: block; clear: both; text-decoration: none; } .mascots-container { padding: 0; text-align: center; } .mascot, .mascotcontainer { overflow: hidden; } .mascot { position: relative; border: none; margin: 5px; padding: 0; width: 200px; display: inline-block; background-color: transparent; } .mascotcontainer { height: 250px; border: 0; margin: 0; max-height: 250px; cursor: pointer; bottom: 0; border-width: 0 1px 1px; border-style: solid; border-color: transparent; overflow: hidden; } .mascot img { max-width: 200px; } .export-button, .mascotname, #mascot-options { -moz-box-sizing: border-box; padding: 0; width: 100%; } #mascot-options { opacity: 0; transition: opacity .3s linear; } .mascot:hover #mascot-options { opacity: 1; } #mascot-options { position: absolute; bottom: 0; right: 0; left: 0; } .export-button { position: absolute; bottom: 1.7em; right: 0; left: 0; text-align: center; } #mascot-options a { display: inline-block; width: 33%; } #upload { position: absolute; width: 100px; left: 50%; margin-left: -50px; text-align: center; bottom: 0; } #mascots_batch { position: absolute; left: 10px; bottom: 0; } /* Themes Tab */ #themes h1 { position: absolute; right: 300px; bottom: 10px; margin: 0; transition: all .2s ease-in-out; opacity: 0; } #themes .selectedtheme h1 { right: 11px; opacity: 1; } #addthemes { position: absolute; left: 10px; bottom: 0; } .theme { margin: 1em; } /* Theme Editor */ #themeConf { position: fixed; top: 0; bottom: 0; width: 296px; z-index: 10; } .sidebar-location-right #themeConf { right: 2px; left: auto; } .sidebar-location-right #themeConf { left: 2px; right: auto; } #themebar input { width: 30%; } .option .color { width: 10%; border-left: none !important; color: transparent !important; } .option .colorfield { width: 90%; } .themevar textarea { min-width: 100%; max-width: 100%; height: 20em; resize: vertical; } /* Mascot Editor */ #mascotConf { position: fixed; height: 17em; bottom: 0; left: 50%; width: 500px; margin-left: -250px; overflow: auto; z-index: 10; } #mascotConf .option, #mascotConf .optionlabel { -moz-box-sizing: border-box; width: 50%; display: inline-block; vertical-align: middle; } #mascotConf .option input { width: 100%; } #close { position: absolute; left: 10px; bottom: 0; } /* Gallery */ #a-gallery { position: fixed; top: 0; bottom: 0; left: 0; right: 0; z-index: 26; display: flex; flex-direction: row; background: rgba(0,0,0,0.7); } .gal-viewport { display: flex; align-items: stretch; flex-direction: row; flex: 1 1 auto; } .gal-thumbnails { flex: 0 0 150px; overflow-y: auto; display: flex; flex-direction: column; align-items: stretch; text-align: center; background: rgba(0,0,0,.5); border-left: 1px solid #222; } .gal-hide-thumbnails .gal-thumbnails { display: none; } .gal-thumb img { max-width: 125px; max-height: 125px; height: auto; width: auto; } .gal-thumb { flex: 0 0 auto; padding: 3px; line-height: 0; transition: background .2s linear; } .gal-highlight { background: rgba(0, 190, 255,.8); } .gal-prev { order: 0; border-right: 1px solid #222; } .gal-next { order: 2; border-left: 1px solid #222; } .gal-prev, .gal-next { flex: 0 0 20px; position: relative; cursor: pointer; opacity: 0.7; background-color: rgba(0, 0, 0, 0.3); } .gal-prev:hover, .gal-next:hover { opacity: 1; } .gal-prev::after, .gal-next::after { position: absolute; top: 48.6%; transform: translateY(-50%) display: inline-block; border-top: 11px solid transparent; border-bottom: 11px solid transparent; content: \"\"; } .gal-prev::after { border-right: 12px solid #fff; right: 5px; } .gal-next::after { border-left: 12px solid #fff; right: 3px; } .gal-image { order: 1; flex: 1 0 auto; display: flex; align-items: flex-start; justify-content: space-around; overflow: auto; /* Flex > Non-Flex child max-width and overflow fix (Firefox only?) */ width: 1%; } .gal-image a { margin: auto; line-height: 0; } .gal-fit-width .gal-image img { max-width: 100%; } .gal-fit-height .gal-image img { max-height: 95vh; max-height: calc(100vh - 25px); } .gal-buttons { font-size: 2em; margin-right: 10px; top: 5px; color: #ffffff; text-shadow: 0px 0px 1px #000; } .gal-buttons, .gal-name, .gal-count { position: fixed; right: 178px; } .hide-thumbnails .gal-buttons, .hide-thumbnails .gal-count, .hide-thumbnails .gal-name { right: 28px; } .gal-name { bottom: 5px; background: rgba(0,0,0,0.6) !important; border-radius: 3px; padding: 1px 5px 2px 5px; text-decoration: none !important; color: #fff !important; } .gal-name:hover, .gal-close:hover { color: rgb(95, 95, 101) !important; } .gal-count { bottom: 26px; background: rgba(0,0,0,0.6) !important; border-radius: 3px; padding: 1px 5px 2px 5px; color: #fff !important; } /* Catalog */ #content .navLinks, #info .navLinks, .btn-wrap { display: block; } .hide-navlinks body > .navLinks { display: none; } .navLinks > .btn-wrap:not(:first-of-type)::before { content: ' - '; } .button { cursor: pointer; } #content .btn-wrap, #info .btn-wrap { display: inline-block; } #post-preview, #quote-preview { position: absolute; z-index: 22; } .rounded-edges #post-preview { border-radius: 3px; } #settings, #threads, #info .navLinks, #content .navLinks { text-align: center; } #threads .thread { vertical-align: top; display: inline-block; word-wrap: break-word; overflow: hidden; margin: 1px; padding: 5px 0 3px; text-align: center; } .extended-small .thread, .small .thread { width: 165px; max-height: 320px; } .small .teaser, .large .teaser { display: none; } .extended-large .thread, .large .thread { width: 270px; max-height: 410px; } .extended-small .thumb, .small .thumb { max-width: 150px; max-height: 150px; } .panel { position: fixed; top: 50% !important; left: 50%; transform: translate(-50%, -50%); padding: 5px; } .icon::after { display: inline-block; float: right; width: 1em; cursor: pointer; } .helpIcon::after { content: '?'; } .closeIcon::after { content: '\uf00d'; font-family: FontAwesome; font-weight: normal; font-style: normal; text-decoration: inherit; -webkit-font-smoothing: antialiased; font-size:14px !important; } /* Front Page */ #logo { text-align: center; } #doc { -moz-box-sizing: border-box; margin: 10px auto; width: 1006px; padding: 2px; position: relative; } .rounded-edges #doc, .rounded-edges #doc div { border-radius: 3px; } #boards .boxcontent { vertical-align: top; text-align: center; } #filter-container, #options-container { top: 4px; right: 8px; position: absolute; } #filtermenu, #optionsmenu { top: 100% !important; left: auto !important; right: 0 !important; } #boards .column { -moz-box-sizing: border-box; display: inline-block; width: 180px; text-align: left; vertical-align: top; } .bd ul, .boxcontent ul { vertical-align: top; padding: 0; margin: 0; } .right-box .boxcontent ul { padding: 0 10px; } .yuimenuitem, .boxcontent ul > li { list-style-type: none; } .boxbar { position: relative; } #doc h3, .boxbar h2 { margin: 0; } #doc h3 { text-decoration: none !important; } .underline-links #doc h3 { text-decoration: underline !important; } #ft, .box-outer { margin: 2px 0 0; overflow: hidden; } #ft, .boxbar, .boxcontent { padding: 0 8px; } .yui-module { position: absolute; } .yuimenuitem::before { content: \" [ ] \"; font-family: monospace; } .yuimenuitem-checked::before { content: \" [x] \" } .yui-g { overflow: hidden; } .yui-u { display: inline-block; vertical-align: top; width: 499px; float: right; } .yui-u.first { float: left; } #recent-images .boxcontent { text-align: center; } #ft { text-align: center; } #ft ul { padding: 0; } #ft li { list-style-type: none; display: inline-block; width: 100px; } #preview-tooltip-nws, #preview-tooltip-ws, #ft .fill, .clear-bug { display: none; } /* ExLinks */ #exlinks-options-content { padding: 5px; } /* /f/ */ [action*='/f/'] .fileInfo { padding-left: 5px !important; } [action*='/f/'] .subject, .name-col { max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; word-wrap: break-word; } div.swfSauce { margin-top: 5px !important; } .mobile.center { display:none!important; } table.flashListing { border-spacing: 1px !important; margin: 5px auto !important; } .flashListing td { padding: 2px !important; font-size: 9pt !important; text-align: center !important; margin: 0px !important; } #delform[action='https://sys.4chan.org/f/up.php'], #delform[action='https://sys.4chan.org/f/up.php'] .postblock { background: none !important; border: none !important; box-shadow: none !important; } /*! * Font Awesome 4.0.3 * the iconic font designed for Bootstrap * ------------------------------------------------------------------------------ * The full suite of pictographic icons, examples, and documentation can be * found at http://fontawesome.io. Stay up to date on Twitter at * http://twitter.com/fontawesome. * * License * ------------------------------------------------------------------------------ * - The Font Awesome font is licensed under SIL OFL 1.1 - * http://scripts.sil.org/OFL * - Font Awesome CSS, LESS, and SASS files are licensed under MIT License - * http://opensource.org/licenses/mit-license.html * - Font Awesome documentation licensed under CC BY 3.0 - * http://creativecommons.org/licenses/by/3.0/ * - Attribution is no longer required in Font Awesome 3.0, but much appreciated: * \"Font Awesome by Dave Gandy - http://fontawesome.io\" * * Author - Dave Gandy * ------------------------------------------------------------------------------ * Email: dave@fontawesome.io * Twitter: http://twitter.com/davegandy * Work: Lead Product Designer @ Kyruus - http://kyruus.com */ @font-face{font-family: 'FontAwesome';src: url('data:application/font-woff;base64,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') format('woff');font-weight:normal;font-style:normal;}.fa,.pfa::after,.pfa::before{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;speak:none;font-size:14px !important;}#shortcuts .fa {color:rgb(130,130,130) !important;}.fa-spin{-webkit-animation:spin 2s infinite linear;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;animation:spin 2s infinite linear}@-moz-keyframes spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0%{-o-transform:rotate(0deg)}100%{-o-transform:rotate(359deg)}}@-ms-keyframes spin{0%{-ms-transform:rotate(0deg)}100%{-ms-transform:rotate(359deg)}}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(359deg)}}",
|
|
dynamic: function() {
|
|
var editSpace, sidebarLocation;
|
|
sidebarLocation = Conf["Sidebar Location"] === "left" ? ["left", "right"] : ["right", "left"];
|
|
if (Conf['editMode'] === "theme") {
|
|
editSpace = {};
|
|
editSpace[sidebarLocation[1]] = 300;
|
|
editSpace[sidebarLocation[0]] = 0;
|
|
} else {
|
|
editSpace = {
|
|
left: 0,
|
|
right: 0
|
|
};
|
|
}
|
|
return "#boardNavDesktopFoot a, #header-bar a, #header-bar .shortcut > span, .deleteform::before, .field, .hide-navigation-decorations .pages a, .notification, .selectrice, body, button, input, textarea { font-size: " + (parseInt(Conf["Font Size"], 10)) + "px; } #boardTitle, .boardTitle a { font-size: " + (parseInt(Conf["Font Size"], 10) + 10) + "px; } .boardSubtitle, .boardSubtitle a { font-size: " + (parseInt(Conf["Font Size"], 10) - 1) + "px; } body, button, input, textarea { font-family: " + Conf["Font"] + "; } body { padding: 0 " + (parseInt(Conf["Right Thread Padding"], 10) + editSpace["right"]) + "px 0 " + (parseInt(Conf["Left Thread Padding"], 10) + editSpace["left"]) + "px; } .board > .thread { margin: " + (parseInt(Conf["Top Thread Padding"], 10)) + "px 0 " + (parseInt(Conf["Bottom Thread Padding"], 10)) + "px 0; } .post, .summary { margin-bottom: " + Conf["Post Spacing"] + "px; } .thread > .threadContainer:last-of-type { margin-bottom: -" + Conf["Post Spacing"] + "px; } .thread > .replyContainer > .reply.post { border-width: " + (Conf['Post Spacing'] === "0" ? "1px 1px 0 1px" : '1px') + "; } #post-preview, .postMessage { margin: " + Conf['Vertical Post Padding'] + "px " + Conf['Horizontal Post Padding'] + "px; } :root:not(fourchan-ss-navigation):not(.pagination-on-side) .pagelist, :root:not(fourchan-ss-navigation) #header-bar { margin-left: " + (parseInt(Conf["Left Thread Padding"], 10) + editSpace["right"]) + "px; margin-right: " + (parseInt(Conf["Right Thread Padding"], 10) + editSpace["left"]) + "px; } /* Emoji */ a.useremail:last-of-type::before { margin-right: " + (parseInt(Conf['Emoji Spacing'])) + "px; } a.useremail:last-of-type::after { margin-left: " + (parseInt(Conf['Emoji Spacing'])) + "px; } #mascot { opacity: " + Conf['Mascot Opacity'] + "; }";
|
|
},
|
|
setTheme: function(theme) {
|
|
return Style.sheets.theme.textContent = Style.theme(theme);
|
|
},
|
|
theme: function(theme) {
|
|
var bLink, background, backgroundC, bgColor, i, replyRGB, replybg, svg, svgs, _i, _len;
|
|
bgColor = new Color(backgroundC = theme["Background Color"]);
|
|
replybg = new Color(theme["Reply Background"]);
|
|
bLink = new Color(theme["Backlinks"]);
|
|
replyRGB = "rgb(" + (replybg.shiftRGB(parseInt(Conf['Silhouette Contrast'], 10), true)) + ")";
|
|
Style.lightTheme = bgColor.isLight();
|
|
svgs = [['captcha-filter', "values='" + (Style.filter(Style.matrix(theme["Text"], theme["Input Background"]))) + " 0 0 0 1 0'"], ['mascot-filter', "values='" + (Style.silhouette(Style.matrix(replyRGB))) + " 0 0 0 1 0'"], ['grayscale', 'id="color" type="saturate" values="0"'], ['icons-filter', "values='-.6 0 0 0 1 0 -.6 0 0 1 0 0 -.6 0 1 0 0 0 1 0'"]];
|
|
for (i = _i = 0, _len = svgs.length; _i < _len; i = ++_i) {
|
|
svg = svgs[i];
|
|
Style.svgs[svg[0].replace(/\-/, "")] = Style.generateFilter(svg[0], svg[1]);
|
|
}
|
|
return (".hide_thread_button span > span, .hide_reply_button span > span { background-color: " + theme["Links"] + "; } #mascot_hide label { border-bottom: 1px solid " + theme["Reply Border"] + "; } #content .thumb { box-shadow: 0 0 5px " + theme["Reply Border"] + "; } .export-button, .mascotname, #mascot-options { background: " + theme["Dialog Background"] + "; border: 1px solid " + theme["Buttons Border"] + "; } .highlight-you .opContainer.quotesYou, .highlight-own .opContainer.your-post, .opContainer.filter-highlight { box-shadow: inset 5px 0 " + theme["Backlinked Reply Outline"] + "; } .highlight-you .quotesYou > .reply, .highlight-own .your-post > .reply, .filter-highlight > .reply { box-shadow: -5px 0 " + theme["Backlinked Reply Outline"] + "; } hr { border-bottom: 1px solid " + theme["Reply Border"] + "; } hr#unread-line { border-bottom: 1px solid " + theme["Reply Background"] + "; visibility: visible; } .threadContainer { border-color: " + theme["Reply Border"] + " !important; } html { background: " + (backgroundC || '') + "; background-image: " + (theme["Background Image"] || '') + "; background-repeat: " + (theme["Background Repeat"] || '') + "; background-attachment: " + (theme["Background Attachment"] || '') + "; background-position: " + (theme["Background Position"] || '') + "; } .panel, .section-container, #exlinks-options-content, #themecontent { background: " + backgroundC + "; border: 1px solid " + theme["Reply Border"] + "; } .sections-list > a.tab-selected { background: " + backgroundC + "; border-color: " + theme["Reply Border"] + "; } .captcha-filter .captcha-img div { filter: url('data:image/svg+xml," + (Style.svgs.captchafilter.replace(/(\'|\")/g, '%22')) + "#captcha-filter'); } .silhouettize-mascots #mascot img, .silhouette img { filter: url('data:image/svg+xml," + (Style.svgs.mascotfilter.replace(/(\'|\")/g, '%22')) + "#mascot-filter'); } .grayscale-mascots #mascot { filter: url('data:image/svg+xml," + (Style.svgs.grayscale.replace(/(\'|\")/g, '%22')) + "#grayscale'); } #boardTitle { text-shadow: 1px 1px " + backgroundC + ", -1px -1px " + backgroundC + ", 1px -1px " + backgroundC + ", -1px 1px " + backgroundC + "; } .sidebar-glow #boardTitle { text-shadow: 1px 1px 1px " + backgroundC + ", -1px -1px 1px " + backgroundC + ", 1px -1px 1px " + backgroundC + ", -1px 1px 1px " + backgroundC + ", 0 2px 4px rgba(0,0,0,.6), 0 0 10px rgba(0,0,0,.6); } #exlinks-options, #appchanx-settings, #qrtab, input[type=\"submit\"], input[value=\"Report\"], span[style=\"left: 5px; position: absolute;\"] a { background: " + theme["Buttons Background"] + "; border: 1px solid " + theme["Buttons Border"] + "; } .enabled .mascotcontainer { background: " + theme["Buttons Background"] + "; border-color: " + theme["Buttons Border"] + "; } #dump, #qr-filename-container, #appchanx-settings input, .captcha-img, .dump #dump, .qr-preview, .selectrice, button, input, textarea { background: " + theme["Input Background"] + "; border: 1px solid " + theme["Input Border"] + "; } .has-file #qr-extras-container { background: " + theme["Input Background"] + "; } #dump:hover, #qr-filename-container:hover, .selectrice:hover, #selectrice li:hover, #selectrice li:nth-of-type(2n+1):hover, input:hover, textarea:hover { background: " + theme["Hovered Input Background"] + "; border-color: " + theme["Hovered Input Border"] + "; } .has-file #qr-filename-container:hover #qr-extras-container { background: " + theme["Hovered Input Background"] + "; } #dump:active, #dump:focus, #selectrice li:focus, .selectrice:focus, #qr-filename-container:active, #qr-filename-container:focus, input:focus, textarea:focus, textarea.field:focus { background: " + theme["Focused Input Background"] + "; border-color: " + theme["Focused Input Border"] + "; color: " + theme["Inputs"] + "; } .has-file #qr-filename-container:active #qr-extras-container, .has-file #qr-filename-container:focus #qr-extras-container { background: " + theme["Focused Input Background"] + "; } #ft, #mouseover, #post-preview, #qp .post, #threads > .thread, #xupdater, .box-outer, .reply.post { border-width: 1px; border-style: solid; border-color: " + theme["Reply Border"] + "; background: " + theme["Reply Background"] + "; } .exblock.reply, .reply.post.highlight, .reply.post:target { background: " + theme["Highlighted Reply Background"] + "; border: 1px solid " + theme["Highlighted Reply Border"] + "; } #header-bar, .pagelist { background: " + theme["Navigation Background"] + "; border-color: " + theme["Navigation Border"] + "; } #doc, #threads, .board > .thread { background: " + theme["Thread Wrapper Background"] + "; border: 1px solid " + theme["Thread Wrapper Border"] + "; } #boardNavDesktopFoot, #mascot_hide, #menu, #selectrice, #themeConf, #thread-watcher, #thread-watcher:hover, .announcements-slideout #globalMessage, .dialog, .post-form-style-float #qr, .post-form-decorations #qr, .submenu { background: " + theme["Dialog Background"] + "; border: 1px solid " + theme["Dialog Border"] + "; } #qp.dialog { border: none; } .watch-thread-link { background-image: url(\"data:image/svg+xml,<svg viewBox='0 0 26 26' preserveAspectRatio='true' xmlns='http://www.w3.org/2000/svg'><path fill='" + (theme["Post Numbers"].replace('#', '%23')) + "' d='M24.132,7.971c-2.203-2.205-5.916-2.098-8.25,0.235L15.5,8.588l-0.382-0.382c-2.334-2.333-6.047-2.44-8.25-0.235c-2.204,2.203-2.098,5.916,0.235,8.249l8.396,8.396l8.396-8.396C26.229,13.887,26.336,10.174,24.132,7.971z'/></svg>\"); } .deleteform::before, .deleteform, #qr .warning { background: " + theme["Input Background"] + "; border-color: " + theme["Input Border"] + "; } .disabledwarning, .warning { color: " + theme["Warnings"] + "; } #charCount { color: " + (Style.lightTheme ? "rgba(0,0,0,0.7)" : "rgba(255,255,255,0.7)") + "; } .postNum a { color: " + theme["Post Numbers"] + "; } .subject { color: " + theme["Subjects"] + " !important; } .dateTime, .post-ago { color: " + theme["Timestamps"] + " !important; } #fs_status a, #header-bar .shortcut > span, #updater #update-status:not(.new)::after, #showQR, .abbr, .boxbar, .boxcontent, .deleteform::before, .pages strong, .pln, .reply, .reply.highlight, .summary, body, button, span[style=\"left: 5px; position: absolute;\"] a, input, textarea { color: " + theme["Text"] + "; } #exlinks-options-content > table, #appchanx-settings fieldset, #selectrice { border-bottom: 1px solid " + theme["Reply Border"] + "; box-shadow: inset " + theme["Shadow Color"] + " 0 0 5px; } .quote + .spoiler:hover, .quote { color: " + theme["Greentext"] + "; } .forwardlink { border-bottom: 1px dashed " + theme["Backlinks"] + "; } .container::before { color: " + theme["Timestamps"] + "; } .quote-shadows #menu, .quote-shadows #post-preview, .quote-shadows #qp .opContainer, .quote-shadows #qp .replyContainer, .quote-shadows .submenu { box-shadow: 5px 5px 5px " + theme['Shadow Color'] + "; } .rice { background: " + theme["Checkbox Background"] + "; border: 1px solid " + theme["Checkbox Border"] + "; } .selectrice::before { border-left: 1px solid " + theme["Input Border"] + "; } .selectrice::after { border-top: .45em solid " + theme["Inputs"] + "; } .bd { background: " + theme["Buttons Background"] + "; border: 1px solid " + theme["Buttons Border"] + "; } .pages a, #header-bar a { color: " + theme["Navigation Links"] + "; } input[type=checkbox]:checked + .rice::after { border-color: " + theme["Inputs"] + "; } #addReply, #dump, .button, .entry, .replylink, a { color: " + theme["Links"] + "; } .backlink { color: " + theme["Backlinks"] + "; } .backlink-icons .backlink { background-image: url(\"data:image/svg+xml,<svg viewBox='0 0 30 30' preserveAspectRatio='true' xmlns='http://www.w3.org/2000/svg'><path fill='rgb(" + (bLink.rgb()) + ")' d='M12.981,9.073V6.817l-12.106,6.99l12.106,6.99v-2.422c3.285-0.002,9.052,0.28,9.052,2.269c0,2.78-6.023,4.263-6.023,4.263v2.132c0,0,13.53,0.463,13.53-9.823C29.54,9.134,17.952,8.831,12.981,9.073z'/></svg>\"); font-size: 0px !important; padding: 12px 12px 1px 1px; opacity: 0.6; } .qiQuote, .quotelink { color: " + theme["Quotelinks"] + "; } #addReply:hover, #dump:hover, .entry:hover, .replylink:hover, .qiQuote:hover, .quotelink:hover, a .name:hover, a .postertrip:hover, a:hover { color: " + theme["Hovered Links"] + "; } #header-bar a:hover, #boardTitle a:hover { color: " + theme["Hovered Navigation Links"] + "; } #boardTitle { color: " + theme["Board Title"] + "; } .name, .post-author { color: " + theme["Names"] + " !important; } .post-tripcode, .postertrip, .trip { color: " + theme["Tripcodes"] + " !important; } a .postertrip, a .name { color: " + theme["Emails"] + "; } .post.reply.qphl, .post.op.qphl { border-color: " + theme["Backlinked Reply Outline"] + "; background: " + theme["Highlighted Reply Background"] + "; } .quote-shadows .inline .post { box-shadow: 5px 5px 5px " + theme['Shadow Color'] + "; } .placeholder, #qr input::placeholder, #qr textarea::placeholder { color: " + (Style.lightTheme ? "rgba(0,0,0,0.3)" : "rgba(255,255,255,0.2)") + " !important; } #qr input:placeholder, #qr textarea:placeholder, .placeholder { color: " + (Style.lightTheme ? "rgba(0,0,0,0.3)" : "rgba(255,255,255,0.2)") + " !important; } #appchanx-settings fieldset, .boxcontent dd, .selectrice ul { border-color: " + (Style.lightTheme ? "rgba(0,0,0,0.1)" : "rgba(255,255,255,0.1)") + "; } #appchanx-settings li, #selectrice li:not(:first-of-type) { border-top: 1px solid " + (Style.lightTheme ? "rgba(0,0,0,0.05)" : "rgba(255,255,255,0.025)") + "; } .a-icon, #shortcuts .fa { " + (!Style.lightTheme ? "filter: url('data:image/svg+xml," + (Style.svgs.iconsfilter.replace(/(\'|\")/g, '%22')) + "#icons-filter');" : "") + " } .alternate-post-colors #threads > .thread:nth-of-type(2n+1), .alternate-post-colors .replyContainer:nth-of-type(2n+1) .post { background-image: linear-gradient(" + (replybg ? "rgba(" + (replybg.shiftRGB(-4, false)) + ",0.8), rgba(" + (replybg.shiftRGB(-4, false)) + ",0.8)" : Style.lightTheme ? "rgba(0,0,0,0.05), rgba(0,0,0,0.05)" : "rgba(255,255,255,0.02), rgba(255,255,255,0.02)") + "); } .color-reply-headings .boxbar, .color-reply-headings .postInfo { background: " + (replybg ? "rgba(" + (replybg.shiftRGB(-12, false)) + ",0.8)" : "rgba(0,0,0,0.1)") + "; border-bottom: 1px solid " + theme["Reply Border"] + " } .color-file-info .file { background: " + (replybg ? "rgba(" + (replybg.shiftRGB(-8, false)) + ",0.8)" : "rgba(0,0,0,0.1)") + "; border-bottom: 1px solid " + theme["Reply Border"] + " border-top: 1px solid " + theme["Reply Border"] + " } .color-reply.headings.color-file-info { border-top: none; } .op-background .op.post { background: " + theme["Reply Background"] + "; border: 1px solid " + theme["Reply Border"] + "; } .op-background .op.post:target .op-background .op.post.highlight { background: " + theme["Highlighted Reply Background"] + "; border: 1px solid " + theme["Highlighted Reply Border"] + "; } .fourchan-banner-at-sidebar-top.icon-orientation-vertical body::after { background: " + backgroundC + "; } .fourchan-banner-at-sidebar-top.icon-orientation-vertical.fourchan-ss-sidebar body::after, .fourchan-banner-at-sidebar-top.fourchan-ss-sidebar body::before { background: rgba(" + ((background = new Color(theme["Reply Background"])) ? background.shiftRGB(-18) : void 0) + ", 0.8); } .fourchan-ss-sidebar.sidebar-location-right body::before { border-left: 2px solid " + backgroundC + "; box-shadow: inset 1px 0 0 " + theme["Reply Border"] + ", -1px 0 0 " + theme["Reply Border"] + "; } .fourchan-ss-sidebar.sidebar-location-left body::before { border-right: 2px solid " + backgroundC + "; box-shadow: 1px 0 0 " + theme["Reply Border"] + ", inset -1px 0 0 " + theme["Reply Border"] + "; } .sage-highlighting-text.sage-highlight-position-before a.useremail[href*=\"sage\"]:last-of-type::before, .sage-highlighting-text.sage-highlight-position-before a.useremail[href*=\"Sage\"]:last-of-type::before, .sage-highlighting-text.sage-highlight-position-before a.useremail[href*=\"SAGE\"]:last-of-type::before, .sage-highlighting-text.sage-highlight-position-after a.useremail[href*=\"sage\"]:last-of-type::after, .sage-highlighting-text.sage-highlight-position-after a.useremail[href*=\"Sage\"]:last-of-type::after, .sage-highlighting-text.sage-highlight-position-after a.useremail[href*=\"SAGE\"]:last-of-type::after { content: \" (sage) \"; color: " + theme["Sage"] + "; } .quote-shadows #qr { box-shadow: 5px 5px 5px " + theme['Shadow Color'] + "; } /* /f/ */ .postblock { color: " + theme["Text"] + "; font-weight: bold; font-size: 10pt; } tbody > tr:nth-of-type(2n+1){ background: " + theme["Reply Background"] + " !important; } table.flashListing .highlightPost::after { content: '●'; color: " + theme["Text"] + "; position: relative; left: 12px; margin-left: -10px; } .flashListing > tbody { background: url('/image/fade.png') repeat-x scroll center top " + backgroundC + " !important; padding-top: 200px; } " + (theme["Custom CSS"].replace(/\s+/g, ' ').trim())) + ("" + (Style.lightTheme ? " .prettyprint { background-color: #e7e7e7 !important; border: 1px solid #dcdcdc !important; } .com { color: #dd0000 !important; } .str, .atv { color: #7fa61b !important; } .pun { color: #61663a !important; } .tag { color: #117743 !important; } .kwd { color: #5a6F9e !important; } .typ, .atn { color: #9474bd !important; } .lit { color: #368c72 !important; } " : " .prettyprint { background-color: rgba(0,0,0,.1) !important; border: 1px solid rgba(0,0,0,0.5) !important; } .tag { color: #96562c !important; } .pun { color: #5b6f2a !important; } .com { color: #a34443 !important; } .str, .atv { color: #8ba446 !important; } .kwd { color: #987d3e !important; } .typ, .atn { color: #897399 !important; } .lit { color: #558773 !important; } "));
|
|
},
|
|
iconPositions: function() {
|
|
var el, psa, psaIcon, slideNav;
|
|
slideNav = $.el('span', {
|
|
id: 'so-nav',
|
|
innerHTML: '<i class=a-icon></a>'
|
|
});
|
|
$.add(slideNav, $.id('boardNavDesktopFoot'));
|
|
Header.addShortcut(slideNav, true);
|
|
if (Conf['Announcements'] === 'slideout') {
|
|
if ((psa = $.id('globalMessage')) && !psa.hidden) {
|
|
psaIcon = $.el('i', {
|
|
id: 'so-psa',
|
|
innerHTML: '<i class=a-icon></a>'
|
|
});
|
|
$.add(psaIcon, psa);
|
|
Header.addShortcut(psaIcon, true);
|
|
}
|
|
}
|
|
if (!Conf['JSON Navigation'] && g.VIEW === 'thread') {
|
|
el = $('body > div.navLinks > a');
|
|
el.textContent = '';
|
|
el.id = 'returnIcon';
|
|
el.className = 'a-icon';
|
|
return Header.addShortcut(el, true);
|
|
}
|
|
},
|
|
padding: function() {
|
|
var navHeight, pageHeight, _ref;
|
|
navHeight = Header.bar.offsetHeight;
|
|
pageHeight = ((_ref = $('.pagelist', d.body)) != null ? _ref.offsetHeight : void 0) || 15;
|
|
return Style.sheets.padding.textContent = ("body { padding-bottom: 15px; padding-top: 15px; } .fourchan-ss-navigation.fixed.top-header:not(.autohide) body::before { top: " + navHeight + "px; } .fourchan-ss-navigation.fixed.bottom-header:not(.autohide) body::before { bottom: " + navHeight + "px; } .top-header:not(.autohide) body { padding-top: " + (navHeight + 1) + "px; } .bottom-header:not(.autohide) body { padding-bottom: " + (navHeight + 15) + "px; } ") + (pageHeight ? ".fourchan-ss-navigation.index.pagination-sticky-top body::before, .fourchan-ss-navigation.index.pagination-top body::before { top: " + pageHeight + "px; } .fourchan-ss-navigation.index.pagination-sticky-bottom body::before, .fourchan-ss-navigation.index.pagination-bottom body::before { bottom: " + pageHeight + "px; } .index.pagination-sticky-top body, .index.pagination-top body { padding-top: " + (pageHeight + 1) + "px; } .index.pagination-sticky-bottom body, .index.pagination-bottom body { padding-bottom: " + (pageHeight + 15) + "px; }" : '');
|
|
}
|
|
};
|
|
|
|
|
|
/*
|
|
Color adapted from 4chan Style Script
|
|
*/
|
|
|
|
ThemeTools = {
|
|
init: function(key) {
|
|
var colorInput, div, fileInput, header, input, item, layout, theme, themeContent, _i, _j, _len, _len1, _ref;
|
|
Conf['editMode'] = "theme";
|
|
theme = Themes[key];
|
|
if (theme) {
|
|
editTheme = JSON.parse(JSON.stringify(theme));
|
|
editTheme["Theme"] = Conf['userThemes'][key] ? key : key += " [custom]";
|
|
} else {
|
|
editTheme = JSON.parse(JSON.stringify(Themes['Yotsuba B']));
|
|
editTheme["Theme"] = "Untitled";
|
|
editTheme["Author"] = "Author";
|
|
editTheme["Author Tripcode"] = "Unknown";
|
|
}
|
|
layout = ["Background Image", "Background Attachment", "Background Position", "Background Repeat", "Background Color", "Thread Wrapper Background", "Thread Wrapper Border", "Dialog Background", "Dialog Border", "Reply Background", "Reply Border", "Highlighted Reply Background", "Highlighted Reply Border", "Backlinked Reply Outline", "Input Background", "Input Border", "Hovered Input Background", "Hovered Input Border", "Focused Input Background", "Focused Input Border", "Checkbox Background", "Checkbox Border", "Buttons Background", "Buttons Border", "Navigation Background", "Navigation Border", "Links", "Hovered Links", "Quotelinks", "Backlinks", "Navigation Links", "Hovered Navigation Links", "Names", "Tripcodes", "Emails", "Subjects", "Text", "Inputs", "Post Numbers", "Greentext", "Sage", "Board Title", "Timestamps", "Warnings", "Shadow Color"];
|
|
ThemeTools.dialog = $.el("div", {
|
|
id: "themeConf",
|
|
className: "reply dialog",
|
|
innerHTML: "<div id=themebar> </div> <hr> <div id=themecontent> </div> <div id=save> <a href='javascript:;'>Save</a> </div> <div id=upload> <a href='javascript:;'>Select Image</a> </div> <div id=close> <a href='javascript:;'>Close</a> </div>"
|
|
});
|
|
header = $.el("div", {
|
|
innerHTML: "<input class='field subject' name='Theme' placeholder='Theme' value='" + key + "'> by\n<input class='field name' name='Author' placeholder='Author' value='" + editTheme['Author'] + "'>\n<input class='field postertrip' name='Author Tripcode' placeholder='Author Tripcode' value='" + editTheme['Author Tripcode'] + "'>"
|
|
});
|
|
_ref = $$("input", header);
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
input = _ref[_i];
|
|
$.on(input, 'blur', function() {
|
|
return editTheme[this.name] = this.value;
|
|
});
|
|
}
|
|
$.add($('#themebar', ThemeTools.dialog), header);
|
|
themeContent = $('#themecontent', ThemeTools.dialog);
|
|
for (_j = 0, _len1 = layout.length; _j < _len1; _j++) {
|
|
item = layout[_j];
|
|
if (!editTheme[item]) {
|
|
editTheme[item] = '';
|
|
}
|
|
div = $.el("div", {
|
|
className: "themevar",
|
|
innerHTML: "<div class=optionname><b>" + item + "</b></div><div class=option><input name='" + item + "' placeholder='" + (item === "Background Image" ? "Shift+Click to upload image" : item) + "'>"
|
|
});
|
|
input = $('input', div);
|
|
input.value = editTheme[item];
|
|
switch (item) {
|
|
case "Background Image":
|
|
input.className = 'field';
|
|
fileInput = $.el('input', {
|
|
type: 'file',
|
|
accept: "image/*",
|
|
title: "BG Image",
|
|
hidden: "hidden"
|
|
});
|
|
$.on(input, 'click', function(evt) {
|
|
if (evt.shiftKey) {
|
|
return this.nextSibling.click();
|
|
}
|
|
});
|
|
$.on(fileInput, 'change', function(evt) {
|
|
return ThemeTools.uploadImage(evt, this);
|
|
});
|
|
$.after(input, fileInput);
|
|
break;
|
|
case "Background Attachment":
|
|
case "Background Position":
|
|
case "Background Repeat":
|
|
input.className = 'field';
|
|
break;
|
|
default:
|
|
input.className = "colorfield";
|
|
colorInput = $.el('input', {
|
|
className: 'color',
|
|
value: "#" + ((new Color(input.value)).hex())
|
|
});
|
|
JSColor.bind(colorInput);
|
|
$.after(input, colorInput);
|
|
}
|
|
$.on(input, 'blur', ThemeTools.apply);
|
|
$.add(themeContent, div);
|
|
}
|
|
if (!editTheme["Custom CSS"]) {
|
|
editTheme["Custom CSS"] = "";
|
|
}
|
|
div = $.el("div", {
|
|
className: "themevar",
|
|
innerHTML: "<div class=optionname><b>Custom CSS</b></div><div class=option><textarea name='Custom CSS' placeholder='Custom CSS'>" + editTheme['Custom CSS'] + "</textarea>"
|
|
});
|
|
$.on($('textarea', div), 'blur', function() {
|
|
editTheme["Custom CSS"] = this.value;
|
|
return Style.sheets.theme.textContent = Style.theme(editTheme);
|
|
});
|
|
$.add(themeContent, div);
|
|
$.on($('#save > a', ThemeTools.dialog), 'click', function() {
|
|
return ThemeTools.save(editTheme);
|
|
});
|
|
$.on($('#close > a', ThemeTools.dialog), 'click', ThemeTools.close);
|
|
$.add(d.body, ThemeTools.dialog);
|
|
return Style.sheets.theme.textContent = Style.theme(editTheme);
|
|
},
|
|
apply: function() {
|
|
var depth, i, len, toggle1, toggle2;
|
|
depth = 0;
|
|
toggle1 = false;
|
|
toggle2 = false;
|
|
len = this.value.length;
|
|
if (len < 1000) {
|
|
i = 0;
|
|
while (i < len) {
|
|
switch (this.value[i++]) {
|
|
case '(':
|
|
++depth;
|
|
break;
|
|
case ')':
|
|
--depth;
|
|
break;
|
|
case '"':
|
|
toggle1 = !toggle1;
|
|
break;
|
|
case "'":
|
|
toggle2 = !toggle2;
|
|
}
|
|
}
|
|
}
|
|
if ((depth !== 0) || toggle1 || toggle2) {
|
|
return alert("Syntax error on " + this.name + ".");
|
|
}
|
|
if (this.className === "colorfield") {
|
|
this.nextSibling.value = (new Color(this.value)).hex();
|
|
this.nextSibling.color.importColor();
|
|
}
|
|
editTheme[this.name] = this.value;
|
|
return Style.setTheme(editTheme);
|
|
},
|
|
uploadImage: function(evt, el) {
|
|
var file, reader;
|
|
file = evt.target.files[0];
|
|
reader = new FileReader();
|
|
reader.onload = function(evt) {
|
|
var val;
|
|
val = "url(\"" + evt.target.result + "\")";
|
|
el.previousSibling.value = val;
|
|
editTheme["Background Image"] = val;
|
|
return Style.sheets.theme.textContent = Style.theme(editTheme);
|
|
};
|
|
return reader.readAsDataURL(file);
|
|
},
|
|
importtheme: function(evt) {
|
|
var file, reader;
|
|
file = evt.target.files[0];
|
|
reader = new FileReader();
|
|
reader.onload = function(e) {
|
|
var bgColor, bgRPA, blinkColor, brderColor, err, imported, inputColor, inputbColor, jlinkColor, linkColor, linkHColor, mainColor, name, nameColor, quoteColor, sageColor, textColor, timeColor, titleColor, tripColor;
|
|
try {
|
|
imported = JSON.parse(e.target.result);
|
|
if (!imported) {
|
|
throw "Cannot parse file";
|
|
}
|
|
} catch (_error) {
|
|
err = _error;
|
|
alert(err);
|
|
return;
|
|
}
|
|
name = imported.name || imported['Theme'];
|
|
if (!name) {
|
|
alert("Theme file is invalid.");
|
|
return;
|
|
}
|
|
delete imported.name || imported['Theme'];
|
|
if (Themes[name] && !Themes[name]["Deleted"]) {
|
|
if (confirm('A theme with this name already exists. Would you like to over-write?')) {
|
|
delete Themes[name];
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
if (imported.bgColor) {
|
|
if (!imported.replyOp) {
|
|
imported.replyOp = "0.9";
|
|
}
|
|
bgRPA = imported.bgRPA ? imported.bgRPA.split(' ') : ['no-repeat', 'bottom', 'left', 'fixed'];
|
|
bgColor = new Color(imported.bgColor);
|
|
mainColor = new Color(imported.mainColor);
|
|
brderColor = new Color(imported.brderColor);
|
|
inputColor = new Color(imported.inputColor);
|
|
inputbColor = new Color(imported.inputbColor);
|
|
blinkColor = new Color(imported.blinkColor);
|
|
jlinkColor = new Color(imported.jlinkColor);
|
|
linkColor = new Color(imported.linkColor);
|
|
linkHColor = new Color(imported.linkHColor);
|
|
nameColor = new Color(imported.nameColor);
|
|
quoteColor = new Color(imported.quoteColor);
|
|
sageColor = new Color(imported.sageColor);
|
|
textColor = new Color(imported.textColor);
|
|
titleColor = new Color(imported.titleColor);
|
|
tripColor = new Color(imported.tripColor);
|
|
timeColor = new Color(imported.timeColor || imported.textColor);
|
|
Themes[name] = {
|
|
'Author': "Anonymous",
|
|
'Author Tripcode': "!POMF.9waa",
|
|
'Background Image': "url('" + (imported.bgImg || '') + "')",
|
|
'Background Attachment': "" + (bgRPA[3] || ''),
|
|
'Background Position': "" + (bgRPA[1] || '') + " " + (bgRPA[2] || ''),
|
|
'Background Repeat': "" + (bgRPA[0] || ''),
|
|
'Background Color': "rgb(" + (bgColor.rgb()) + ")",
|
|
'Dialog Background': "rgba(" + (mainColor.rgb()) + ",.98)",
|
|
'Dialog Border': "rgb(" + (brderColor.rgb()) + ")",
|
|
'Thread Wrapper Background': "rgba(0,0,0,0)",
|
|
'Thread Wrapper Border': "rgba(0,0,0,0)",
|
|
'Reply Background': "rgba(" + (mainColor.rgb()) + "," + imported.replyOp + ")",
|
|
'Reply Border': "rgb(" + (brderColor.rgb()) + ")",
|
|
'Highlighted Reply Background': "rgba(" + (mainColor.shiftRGB(4, true)) + "," + imported.replyOp + ")",
|
|
'Highlighted Reply Border': "rgb(" + (linkColor.rgb()) + ")",
|
|
'Backlinked Reply Outline': "rgb(" + (linkColor.rgb()) + ")",
|
|
'Checkbox Background': "rgba(" + (inputColor.rgb()) + "," + imported.replyOp + ")",
|
|
'Checkbox Border': "rgb(" + (inputbColor.rgb()) + ")",
|
|
'Input Background': "rgba(" + (inputColor.rgb()) + "," + imported.replyOp + ")",
|
|
'Input Border': "rgb(" + (inputbColor.rgb()) + ")",
|
|
'Hovered Input Background': "rgba(" + (inputColor.hover()) + "," + imported.replyOp + ")",
|
|
'Hovered Input Border': "rgb(" + (inputbColor.rgb()) + ")",
|
|
'Focused Input Background': "rgba(" + (inputColor.hover()) + "," + imported.replyOp + ")",
|
|
'Focused Input Border': "rgb(" + (inputbColor.rgb()) + ")",
|
|
'Buttons Background': "rgba(" + (inputColor.rgb()) + "," + imported.replyOp + ")",
|
|
'Buttons Border': "rgb(" + (inputbColor.rgb()) + ")",
|
|
'Navigation Background': "rgba(" + (bgColor.rgb()) + ",0.8)",
|
|
'Navigation Border': "rgb(" + (mainColor.rgb()) + ")",
|
|
'Quotelinks': "rgb(" + (linkColor.rgb()) + ")",
|
|
'Links': "rgb(" + (linkColor.rgb()) + ")",
|
|
'Hovered Links': "rgb(" + (linkHColor.rgb()) + ")",
|
|
'Navigation Links': "rgb(" + (textColor.rgb()) + ")",
|
|
'Hovered Navigation Links': "rgb(" + (linkHColor.rgb()) + ")",
|
|
'Subjects': "rgb(" + (titleColor.rgb()) + ")",
|
|
'Names': "rgb(" + (nameColor.rgb()) + ")",
|
|
'Sage': "rgb(" + (sageColor.rgb()) + ")",
|
|
'Tripcodes': "rgb(" + (tripColor.rgb()) + ")",
|
|
'Emails': "rgb(" + (linkColor.rgb()) + ")",
|
|
'Post Numbers': "rgb(" + (linkColor.rgb()) + ")",
|
|
'Text': "rgb(" + (textColor.rgb()) + ")",
|
|
'Backlinks': "rgb(" + (linkColor.rgb()) + ")",
|
|
'Greentext': "rgb(" + (quoteColor.rgb()) + ")",
|
|
'Board Title': "rgb(" + (textColor.rgb()) + ")",
|
|
'Timestamps': "rgb(" + (timeColor.rgb()) + ")",
|
|
'Inputs': "rgb(" + (textColor.rgb()) + ")",
|
|
'Warnings': "rgb(" + (sageColor.rgb()) + ")",
|
|
'Shadow Color': "rbga(0,0,0,0.1)",
|
|
'Custom CSS': ".board {\npadding: 1px 2px;\n}\n.rice {\nbox-shadow:rgba(" + mainColor.shiftRGB(32) + (",.3) 0 1px;\n}\ninput[type=password]:hover,\ninput[type=text]:not([disabled]):hover,\ninput#fs_search:hover,\ninput.field:hover,\ntextarea:hover,\n#options input:not([type=checkbox]):hover {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\ninput[type=password]:focus,\ninput[type=text]:focus,\ninput#fs_search:focus,\ninput.field:focus,\ntextarea:focus,\n#options input:focus {\n box-shadow:inset rgba(0,0,0,.2) 0 1px 2px;\n}\nbutton,\ninput,\ntextarea,\n.rice {\n transition:background .2s,box-shadow .2s;\n}\n " + (imported.customCSS || ''))
|
|
};
|
|
} else {
|
|
Themes[name] = imported;
|
|
}
|
|
return $.get("userThemes", {}, function(_arg) {
|
|
var userThemes;
|
|
userThemes = _arg.userThemes;
|
|
userThemes[name] = Themes[name];
|
|
$.set('userThemes', userThemes);
|
|
alert("Theme \"" + name + "\" imported!");
|
|
return Settings.openSection.call({
|
|
open: Settings.themes,
|
|
hyphenatedTitle: 'themes'
|
|
});
|
|
});
|
|
};
|
|
return reader.readAsText(file);
|
|
},
|
|
save: function(theme) {
|
|
var name;
|
|
name = theme["Theme"];
|
|
if (Themes[name] && !Themes[name]["Deleted"]) {
|
|
if (confirm("A theme with this name already exists. Would you like to over-write?")) {
|
|
delete Themes[name];
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
Themes[name] = JSON.parse(JSON.stringify(theme));
|
|
delete Themes[name]["Theme"];
|
|
return $.get("userThemes", {}, function(_arg) {
|
|
var userThemes;
|
|
userThemes = _arg.userThemes;
|
|
userThemes[name] = Themes[name];
|
|
$.set('userThemes', userThemes);
|
|
$.set('theme', Conf['theme'] = name);
|
|
return alert("Theme \"" + name + "\" saved.");
|
|
});
|
|
},
|
|
close: function() {
|
|
Conf['editMode'] = false;
|
|
Style.setTheme(Themes[Conf['theme']]);
|
|
$.rm($.id('themeConf'));
|
|
return Settings.open('Themes');
|
|
}
|
|
};
|
|
|
|
Color = (function() {
|
|
var colorToHex, minmax, shortToLong;
|
|
|
|
minmax = function(base) {
|
|
if (base < 0) {
|
|
return 0;
|
|
} else if (base > 255) {
|
|
return 255;
|
|
} else {
|
|
return base;
|
|
}
|
|
};
|
|
|
|
shortToLong = function(hex) {
|
|
var i, longHex;
|
|
longHex = [];
|
|
i = 0;
|
|
while (i < 3) {
|
|
longHex.push(hex.substr(i, 1));
|
|
i = Math.floor(longHex.length / 2);
|
|
}
|
|
return longHex.join("");
|
|
};
|
|
|
|
colorToHex = function(color) {
|
|
var digits, hex, len;
|
|
if (color.substr(0, 1) === '#') {
|
|
if (color.length !== 4) {
|
|
return color.slice(1);
|
|
} else {
|
|
return shortToLong(color.substr(1, 3));
|
|
}
|
|
}
|
|
len = color.length;
|
|
if (len === 3 || len === 6) {
|
|
if (/[0-9a-f]{3}/i.test(color)) {
|
|
if (color.length === 6) {
|
|
return color;
|
|
} else {
|
|
return shortToLong(color);
|
|
}
|
|
}
|
|
}
|
|
if (digits = color.match(/(.*?)rgba?\((\d+), ?(\d+), ?(\d+)(.*?)\)/)) {
|
|
hex = ((parseInt(digits[2], 10) << 16) | (parseInt(digits[3], 10) << 8) | (parseInt(digits[4], 10))).toString(16);
|
|
while (hex.length < 6) {
|
|
hex = "0" + hex;
|
|
}
|
|
return hex;
|
|
} else {
|
|
return "000000";
|
|
}
|
|
};
|
|
|
|
function Color(value) {
|
|
this.raw = colorToHex(value);
|
|
}
|
|
|
|
Color.prototype.hex = function() {
|
|
return "#" + this.raw;
|
|
};
|
|
|
|
Color.prototype.rgb = function() {
|
|
return this.privateRGB().join(",");
|
|
};
|
|
|
|
Color.prototype.hover = function() {
|
|
return this.shiftRGB(16, true);
|
|
};
|
|
|
|
Color.prototype.isLight = function() {
|
|
var rgb;
|
|
rgb = this.privateRGB();
|
|
return (rgb[0] * 0.299 + rgb[1] * 0.587 + rgb[2] * 0.114) > 125;
|
|
};
|
|
|
|
Color.prototype.privateRGB = function() {
|
|
var hex;
|
|
hex = parseInt(this.raw, 16);
|
|
return [(hex >> 16) & 0xFF, (hex >> 8) & 0xFF, hex & 0xFF];
|
|
};
|
|
|
|
Color.prototype.shiftRGB = function(shift, smart) {
|
|
var color, rgb, _i, _len, _ref;
|
|
if (smart) {
|
|
shift = (this.isLight() ? -1 : 1) * Math.abs(shift);
|
|
}
|
|
rgb = [];
|
|
_ref = this.privateRGB();
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
color = _ref[_i];
|
|
rgb.push(minmax(color + shift));
|
|
}
|
|
return rgb.join(",");
|
|
};
|
|
|
|
return Color;
|
|
|
|
})();
|
|
|
|
PSAHiding = {
|
|
init: function() {
|
|
$.addClass(doc, 'hide-announcement');
|
|
return $.on(d, '4chanXInitFinished', this.setup);
|
|
},
|
|
setup: function() {
|
|
var btn, entry, psa;
|
|
$.off(d, '4chanXInitFinished', PSAHiding.setup);
|
|
if (!(psa = $.id('globalMessage'))) {
|
|
return;
|
|
}
|
|
entry = {
|
|
type: 'header',
|
|
el: $.el('a', {
|
|
textContent: 'Show announcement',
|
|
className: 'show-announcement',
|
|
href: 'javascript:;'
|
|
}),
|
|
order: 50,
|
|
open: function() {
|
|
return psa.hidden;
|
|
}
|
|
};
|
|
$.event('AddMenuEntry', entry);
|
|
$.on(entry.el, 'click', PSAHiding.toggle);
|
|
PSAHiding.btn = btn = $.el('span', {
|
|
innerHTML: '[<a href=javascript:;>Dismiss</a>]',
|
|
title: 'Mark announcement as read and hide.',
|
|
className: 'hide-announcement',
|
|
href: 'javascript:;',
|
|
textContent: '[ - ]'
|
|
});
|
|
$.on(btn, 'click', PSAHiding.toggle);
|
|
$.get('hiddenPSA', 0, function(_arg) {
|
|
var hiddenPSA;
|
|
hiddenPSA = _arg.hiddenPSA;
|
|
PSAHiding.sync(hiddenPSA);
|
|
$.add(psa, btn);
|
|
return $.rmClass(doc, 'hide-announcement');
|
|
});
|
|
return $.sync('hiddenPSA', PSAHiding.sync);
|
|
},
|
|
toggle: function(e) {
|
|
var UTC;
|
|
if ($.hasClass(this, 'hide-announcement')) {
|
|
UTC = +$.id('globalMessage').dataset.utc;
|
|
$.set('hiddenPSA', UTC);
|
|
} else {
|
|
$.event('CloseMenu');
|
|
$["delete"]('hiddenPSA');
|
|
}
|
|
return PSAHiding.sync(UTC);
|
|
},
|
|
sync: function(UTC) {
|
|
var hr, psa;
|
|
psa = $.id('globalMessage');
|
|
psa.hidden = PSAHiding.btn.hidden = UTC && UTC >= +psa.dataset.utc ? true : false;
|
|
if ((hr = psa.nextElementSibling) && hr.nodeName === 'HR') {
|
|
return hr.hidden = psa.hidden;
|
|
}
|
|
}
|
|
};
|
|
|
|
CatalogLinks = {
|
|
init: function() {
|
|
var el, input;
|
|
if (!Conf['Catalog Links']) {
|
|
return;
|
|
}
|
|
CatalogLinks.el = el = $.el('label', {
|
|
id: 'toggleCatalog',
|
|
href: 'javascript:;',
|
|
innerHTML: "<input type=checkbox " + (Conf['Header catalog links'] ? 'checked' : '') + "> Catalog Links"
|
|
});
|
|
input = $('input', el);
|
|
$.on(input, 'change', this.toggle);
|
|
$.sync('Header catalog links', CatalogLinks.set);
|
|
$.event('AddMenuEntry', {
|
|
type: 'header',
|
|
el: el,
|
|
order: 95
|
|
});
|
|
return $.on(d, '4chanXInitFinished', function() {
|
|
return CatalogLinks.set(Conf['Header catalog links']);
|
|
});
|
|
},
|
|
toggle: function() {
|
|
$.event('CloseMenu');
|
|
$.set('Header catalog links', this.checked);
|
|
return CatalogLinks.set(this.checked);
|
|
},
|
|
set: function(useCatalog) {
|
|
var a, board, generateURL, path, _i, _len, _ref, _ref1;
|
|
path = useCatalog ? 'catalog' : '';
|
|
generateURL = useCatalog && Conf['External Catalog'] ? CatalogLinks.external : function(board) {
|
|
return a.href = "/" + board + "/" + path;
|
|
};
|
|
_ref = $$("#board-list a:not(.catalog), #boardNavDesktopFoot a");
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
a = _ref[_i];
|
|
if (((_ref1 = a.hostname) !== 'boards.4chan.org' && _ref1 !== 'catalog.neet.tv' && _ref1 !== '4index.gropes.us') || !(board = a.pathname.split('/')[1]) || (board === 'f' || board === 'status' || board === '4chan')) {
|
|
continue;
|
|
}
|
|
a.href = generateURL(board);
|
|
}
|
|
return CatalogLinks.el.title = "Turn catalog links " + (useCatalog ? 'off' : 'on') + ".";
|
|
},
|
|
external: function(board) {
|
|
switch (board) {
|
|
case 'a':
|
|
case 'c':
|
|
case 'g':
|
|
case 'co':
|
|
case 'k':
|
|
case 'm':
|
|
case 'o':
|
|
case 'p':
|
|
case 'v':
|
|
case 'vg':
|
|
case 'w':
|
|
case 'cm':
|
|
case '3':
|
|
case 'adv':
|
|
case 'an':
|
|
case 'cgl':
|
|
case 'ck':
|
|
case 'diy':
|
|
case 'fa':
|
|
case 'fit':
|
|
case 'int':
|
|
case 'jp':
|
|
case 'mlp':
|
|
case 'lit':
|
|
case 'mu':
|
|
case 'n':
|
|
case 'po':
|
|
case 'sci':
|
|
case 'toy':
|
|
case 'trv':
|
|
case 'tv':
|
|
case 'vp':
|
|
case 'x':
|
|
case 'q':
|
|
return "http://catalog.neet.tv/" + board;
|
|
case 'd':
|
|
case 'e':
|
|
case 'gif':
|
|
case 'h':
|
|
case 'hr':
|
|
case 'hc':
|
|
case 'r9k':
|
|
case 's':
|
|
case 'pol':
|
|
case 'soc':
|
|
case 'u':
|
|
case 'i':
|
|
case 'ic':
|
|
case 'hm':
|
|
case 'r':
|
|
case 'w':
|
|
case 'wg':
|
|
case 'wsg':
|
|
case 't':
|
|
case 'y':
|
|
return "http://4index.gropes.us/" + board;
|
|
default:
|
|
return "/" + board + "/catalog";
|
|
}
|
|
}
|
|
};
|
|
|
|
CustomCSS = {
|
|
init: function() {
|
|
if (!Conf['Custom CSS']) {
|
|
return;
|
|
}
|
|
return this.addStyle();
|
|
},
|
|
addStyle: function() {
|
|
return this.style = $.addStyle(Conf['usercss'], 'CustomCSS');
|
|
},
|
|
rmStyle: function() {
|
|
if (this.style) {
|
|
$.rm(this.style);
|
|
return delete this.style;
|
|
}
|
|
},
|
|
update: function() {
|
|
if (!this.style) {
|
|
return this.addStyle();
|
|
}
|
|
return this.style.textContent = Conf['usercss'];
|
|
}
|
|
};
|
|
|
|
Dice = {
|
|
init: function() {
|
|
if (g.BOARD.ID !== 'tg' || !Conf['Show Dice Roll']) {
|
|
return;
|
|
}
|
|
return Post.callbacks.push({
|
|
name: 'Show Dice Roll',
|
|
cb: this.node
|
|
});
|
|
},
|
|
node: function() {
|
|
var dicestats, roll, _ref;
|
|
if (this.isClone || !(dicestats = (_ref = this.info.email) != null ? _ref.match(/dice[+\s](\d+)d(\d+)/) : void 0)) {
|
|
return;
|
|
}
|
|
roll = $('b', this.nodes.comment).firstChild;
|
|
return roll.data = "Rolled " + dicestats[1] + "d" + dicestats[2] + ": " + (roll.data.slice(7));
|
|
}
|
|
};
|
|
|
|
ExpandComment = {
|
|
init: function() {
|
|
if (g.VIEW !== 'index' || !Conf['Comment Expansion'] || Conf['JSON Navigation']) {
|
|
return;
|
|
}
|
|
if (g.BOARD.ID === 'g') {
|
|
this.callbacks.push(Fourchan.code);
|
|
}
|
|
if (g.BOARD.ID === 'sci') {
|
|
this.callbacks.push(Fourchan.math);
|
|
}
|
|
return Post.callbacks.push({
|
|
name: 'Comment Expansion',
|
|
cb: this.node
|
|
});
|
|
},
|
|
node: function() {
|
|
var a;
|
|
if (a = $('.abbr > a:not([onclick])', this.nodes.comment)) {
|
|
return $.on(a, 'click', ExpandComment.cb);
|
|
}
|
|
},
|
|
callbacks: [],
|
|
cb: function(e) {
|
|
e.preventDefault();
|
|
return ExpandComment.expand(Get.postFromNode(this));
|
|
},
|
|
expand: function(post) {
|
|
var a;
|
|
if (post.nodes.longComment && !post.nodes.longComment.parentNode) {
|
|
$.replace(post.nodes.shortComment, post.nodes.longComment);
|
|
post.nodes.comment = post.nodes.longComment;
|
|
return;
|
|
}
|
|
if (!(a = $('.abbr > a', post.nodes.comment))) {
|
|
return;
|
|
}
|
|
a.textContent = "Post No." + post + " Loading...";
|
|
return $.cache("//api.4chan.org" + a.pathname + ".json", function() {
|
|
return ExpandComment.parse(this, a, post);
|
|
});
|
|
},
|
|
contract: function(post) {
|
|
var a;
|
|
if (!post.nodes.shortComment) {
|
|
return;
|
|
}
|
|
a = $('.abbr > a', post.nodes.shortComment);
|
|
a.textContent = 'here';
|
|
$.replace(post.nodes.longComment, post.nodes.shortComment);
|
|
return post.nodes.comment = post.nodes.shortComment;
|
|
},
|
|
parse: function(req, a, post) {
|
|
var callback, clone, comment, href, postObj, posts, quote, spoilerRange, status, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
|
|
status = req.status;
|
|
if (status !== 200 && status !== 304) {
|
|
a.textContent = "Error " + req.statusText + " (" + status + ")";
|
|
return;
|
|
}
|
|
posts = JSON.parse(req.response).posts;
|
|
if (spoilerRange = posts[0].custom_spoiler) {
|
|
Build.spoilerRange[g.BOARD] = spoilerRange;
|
|
}
|
|
for (_i = 0, _len = posts.length; _i < _len; _i++) {
|
|
postObj = posts[_i];
|
|
if (postObj.no === post.ID) {
|
|
break;
|
|
}
|
|
}
|
|
if (postObj.no !== post.ID) {
|
|
a.textContent = "Post No." + post + " not found.";
|
|
return;
|
|
}
|
|
comment = post.nodes.comment;
|
|
clone = comment.cloneNode(false);
|
|
clone.innerHTML = postObj.com;
|
|
_ref = $$('.quotelink', clone);
|
|
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
|
|
quote = _ref[_j];
|
|
href = quote.getAttribute('href');
|
|
if (href[0] === '/') {
|
|
continue;
|
|
}
|
|
quote.href = "/" + post.board + "/res/" + href;
|
|
}
|
|
post.nodes.shortComment = comment;
|
|
$.replace(comment, clone);
|
|
post.nodes.comment = post.nodes.longComment = clone;
|
|
post.parseComment();
|
|
post.parseQuotes();
|
|
_ref1 = ExpandComment.callbacks;
|
|
for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) {
|
|
callback = _ref1[_k];
|
|
callback.call(post);
|
|
}
|
|
}
|
|
};
|
|
|
|
ExpandThread = {
|
|
statuses: {},
|
|
init: function() {
|
|
if (g.VIEW === 'thread' || !Conf['Thread Expansion']) {
|
|
return;
|
|
}
|
|
return $.on(d, (Conf['JSON Navigation'] ? 'IndexRefresh' : '4chanXInitFinished'), this.onIndexRefresh);
|
|
},
|
|
setButton: function(thread) {
|
|
var a, summary;
|
|
if (!(summary = $.x('following-sibling::*[contains(@class,"summary")][1]', thread.OP.nodes.root))) {
|
|
return;
|
|
}
|
|
a = $.el('a', {
|
|
textContent: ExpandThread.text.apply(ExpandThread, ['+'].concat(__slice.call(summary.textContent.match(/\d+/g)))),
|
|
href: "" + thread.board.ID + "/res/" + thread.ID,
|
|
className: 'summary'
|
|
});
|
|
$.on(a, 'click', ExpandThread.cbToggle);
|
|
return $.replace(summary, a);
|
|
},
|
|
disconnect: function() {
|
|
this.refresh();
|
|
return $.off(d, 'IndexRefresh', this.onIndexRefresh);
|
|
},
|
|
refresh: function(disconnect) {
|
|
var status, threadID, _ref, _ref1;
|
|
if (g.VIEW === 'thread' || !Conf['Thread Expansion']) {
|
|
return;
|
|
}
|
|
_ref = ExpandThread.statuses;
|
|
for (threadID in _ref) {
|
|
status = _ref[threadID];
|
|
if ((_ref1 = status.req) != null) {
|
|
_ref1.abort();
|
|
}
|
|
delete ExpandThread.statuses[threadID];
|
|
}
|
|
},
|
|
onIndexRefresh: function() {
|
|
ExpandThread.refresh();
|
|
return g.BOARD.threads.forEach(function(thread) {
|
|
return ExpandThread.setButton(thread);
|
|
});
|
|
},
|
|
text: function(status, posts, files) {
|
|
return ("" + status + " " + posts + " post" + (posts > 1 ? 's' : '')) + (+files ? " and " + files + " image repl" + (files > 1 ? 'ies' : 'y') : "") + (" " + (status === '-' ? 'shown' : 'omitted') + ".");
|
|
},
|
|
cbToggle: function(e) {
|
|
if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) {
|
|
return;
|
|
}
|
|
e.preventDefault();
|
|
return ExpandThread.toggle(Get.threadFromNode(this));
|
|
},
|
|
toggle: function(thread) {
|
|
var a, threadRoot;
|
|
threadRoot = thread.OP.nodes.root.parentNode;
|
|
if (!(a = $('.summary', threadRoot))) {
|
|
return;
|
|
}
|
|
if (thread.ID in ExpandThread.statuses) {
|
|
return ExpandThread.contract(thread, a, threadRoot);
|
|
} else {
|
|
return ExpandThread.expand(thread, a, threadRoot);
|
|
}
|
|
},
|
|
expand: function(thread, a, threadRoot) {
|
|
var status;
|
|
ExpandThread.statuses[thread] = status = {};
|
|
a.textContent = ExpandThread.text.apply(ExpandThread, ['...'].concat(__slice.call(a.textContent.match(/\d+/g))));
|
|
return status.req = $.cache("//a.4cdn.org/" + thread.board + "/res/" + thread + ".json", function() {
|
|
delete status.req;
|
|
return ExpandThread.parse(this, thread, a);
|
|
});
|
|
},
|
|
contract: function(thread, a, threadRoot) {
|
|
var filesCount, inlined, num, postsCount, replies, reply, status, _i, _len;
|
|
status = ExpandThread.statuses[thread];
|
|
delete ExpandThread.statuses[thread];
|
|
if (status.req) {
|
|
status.req.abort();
|
|
if (a) {
|
|
a.textContent = ExpandThread.text.apply(ExpandThread, ['+'].concat(__slice.call(a.textContent.match(/\d+/g))));
|
|
}
|
|
return;
|
|
}
|
|
replies = $$('.thread > .replyContainer', threadRoot);
|
|
if (Conf['Show Replies']) {
|
|
num = (function() {
|
|
if (thread.isSticky) {
|
|
return 1;
|
|
} else {
|
|
switch (g.BOARD.ID) {
|
|
case 'b':
|
|
case 'vg':
|
|
return 3;
|
|
case 't':
|
|
return 1;
|
|
default:
|
|
return 5;
|
|
}
|
|
}
|
|
})();
|
|
replies = replies.slice(0, -num);
|
|
}
|
|
postsCount = 0;
|
|
filesCount = 0;
|
|
for (_i = 0, _len = replies.length; _i < _len; _i++) {
|
|
reply = replies[_i];
|
|
if (Conf['Quote Inlining']) {
|
|
while (inlined = $('.inlined', reply)) {
|
|
inlined.click();
|
|
}
|
|
}
|
|
postsCount++;
|
|
if ('file' in Get.postFromRoot(reply)) {
|
|
filesCount++;
|
|
}
|
|
$.rm(reply);
|
|
}
|
|
return a.textContent = ExpandThread.text('+', postsCount, filesCount);
|
|
},
|
|
parse: function(req, thread, a) {
|
|
var filesCount, post, postData, posts, postsCount, postsRoot, root, _i, _len, _ref, _ref1;
|
|
if ((_ref = req.status) !== 200 && _ref !== 304) {
|
|
a.textContent = "Error " + req.statusText + " (" + req.status + ")";
|
|
return;
|
|
}
|
|
Build.spoilerRange[thread.board] = req.response.posts[0].custom_spoiler;
|
|
posts = [];
|
|
postsRoot = [];
|
|
filesCount = 0;
|
|
_ref1 = req.response.posts;
|
|
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
|
|
postData = _ref1[_i];
|
|
if (postData.no === thread.ID) {
|
|
continue;
|
|
}
|
|
if (post = thread.posts[postData.no]) {
|
|
if ('file' in post) {
|
|
filesCount++;
|
|
}
|
|
postsRoot.push(post.nodes.root);
|
|
continue;
|
|
}
|
|
root = Build.postFromObject(postData, thread.board.ID);
|
|
post = new Post(root, thread, thread.board);
|
|
if ('file' in post) {
|
|
filesCount++;
|
|
}
|
|
posts.push(post);
|
|
postsRoot.push(root);
|
|
}
|
|
Post.callbacks.execute(posts);
|
|
$.after(a, postsRoot);
|
|
postsCount = postsRoot.length;
|
|
return a.textContent = ExpandThread.text('-', postsRoot.length, filesCount);
|
|
}
|
|
};
|
|
|
|
FileInfo = {
|
|
init: function() {
|
|
if (!Conf['File Info Formatting']) {
|
|
return;
|
|
}
|
|
this.funk = this.createFunc(Conf['fileInfo']);
|
|
return Post.callbacks.push({
|
|
name: 'File Info Formatting',
|
|
cb: this.node
|
|
});
|
|
},
|
|
node: function() {
|
|
if (!this.file || this.isClone) {
|
|
return;
|
|
}
|
|
return this.file.text.innerHTML = "<span class=file-info>" + (FileInfo.funk(FileInfo, this)) + "</span>";
|
|
},
|
|
createFunc: function(format) {
|
|
var code;
|
|
code = format.replace(/%(.)/g, function(s, c) {
|
|
if (c in FileInfo.formatters) {
|
|
return "' + FileInfo.formatters." + c + ".call(post) + '";
|
|
} else {
|
|
return s;
|
|
}
|
|
});
|
|
return Function('FileInfo', 'post', "return '" + code + "'");
|
|
},
|
|
convertUnit: function(size, unit) {
|
|
var i;
|
|
if (unit === 'B') {
|
|
return "" + (size.toFixed()) + " Bytes";
|
|
}
|
|
i = 1 + ['KB', 'MB'].indexOf(unit);
|
|
while (i--) {
|
|
size /= 1024;
|
|
}
|
|
size = unit === 'MB' ? Math.round(size * 100) / 100 : size.toFixed();
|
|
return "" + size + " " + unit;
|
|
},
|
|
escape: function(name) {
|
|
return name.replace(/<|>/g, function(c) {
|
|
return c === '<' && '<' || '>';
|
|
});
|
|
},
|
|
formatters: {
|
|
t: function() {
|
|
return this.file.URL.match(/\d+\..+$/)[0];
|
|
},
|
|
T: function() {
|
|
return "<a href=" + this.file.URL + " target=_blank>" + (FileInfo.formatters.t.call(this)) + "</a>";
|
|
},
|
|
l: function() {
|
|
return "<a href=" + this.file.URL + " target=_blank>" + (FileInfo.formatters.n.call(this)) + "</a>";
|
|
},
|
|
L: function() {
|
|
return "<a href=" + this.file.URL + " target=_blank>" + (FileInfo.formatters.N.call(this)) + "</a>";
|
|
},
|
|
n: function() {
|
|
var fullname, shortname;
|
|
fullname = this.file.name;
|
|
shortname = Build.shortFilename(this.file.name, this.isReply);
|
|
if (fullname === shortname) {
|
|
return FileInfo.escape(fullname);
|
|
} else {
|
|
return "<span class=fntrunc>" + (FileInfo.escape(shortname)) + "</span><span class=fnfull>" + (FileInfo.escape(fullname)) + "</span>";
|
|
}
|
|
},
|
|
N: function() {
|
|
return FileInfo.escape(this.file.name);
|
|
},
|
|
p: function() {
|
|
if (this.file.isSpoiler) {
|
|
return 'Spoiler, ';
|
|
} else {
|
|
return '';
|
|
}
|
|
},
|
|
s: function() {
|
|
return this.file.size;
|
|
},
|
|
B: function() {
|
|
return FileInfo.convertUnit(this.file.sizeInBytes, 'B');
|
|
},
|
|
K: function() {
|
|
return FileInfo.convertUnit(this.file.sizeInBytes, 'KB');
|
|
},
|
|
M: function() {
|
|
return FileInfo.convertUnit(this.file.sizeInBytes, 'MB');
|
|
},
|
|
r: function() {
|
|
if (this.file.isImage) {
|
|
return this.file.dimensions;
|
|
} else {
|
|
return 'PDF';
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
Flash = {
|
|
init: function() {
|
|
if (g.BOARD.ID === 'f') {
|
|
return $.ready(Flash.initReady);
|
|
}
|
|
},
|
|
initReady: function() {
|
|
var nav, sauceLink, swfName;
|
|
$.globalEval('SWFEmbed.init()');
|
|
if (g.VIEW !== 'thread') {
|
|
return;
|
|
}
|
|
swfName = $('.fileText > a');
|
|
nav = $('.navLinks');
|
|
sauceLink = $.el('a', {
|
|
textContent: 'Check Sauce on SWFCHAN',
|
|
href: "http://eye.swfchan.com/search/?q=" + swfName.textContent
|
|
});
|
|
$.addClass(nav, 'swfSauce');
|
|
$.rmClass(nav, 'navLinks');
|
|
$.rmAll(nav);
|
|
return $.add(nav, [$.tn('['), sauceLink, $.tn(']')]);
|
|
}
|
|
};
|
|
|
|
Fourchan = {
|
|
init: function() {
|
|
var board;
|
|
board = g.BOARD.ID;
|
|
if (board === 'g') {
|
|
$.globalEval("window.addEventListener('prettyprint', function(e) {\n window.dispatchEvent(new CustomEvent('prettyprint:cb', {\n detail: prettyPrintOne(e.detail)\n }));\n}, false);");
|
|
Post.callbacks.push({
|
|
name: 'Parse /g/ code',
|
|
cb: this.code
|
|
});
|
|
}
|
|
if (board === 'sci') {
|
|
$.globalEval("window.addEventListener('jsmath', function(e) {\n if (jsMath.loaded) {\n // process one post\n jsMath.ProcessBeforeShowing(e.detail);\n } else {\n // load jsMath and process whole document\n jsMath.Autoload.Script.Push('ProcessBeforeShowing', [null]);\n jsMath.Autoload.LoadJsMath();\n }\n}, false);");
|
|
return Post.callbacks.push({
|
|
name: 'Parse /sci/ math',
|
|
cb: this.math
|
|
});
|
|
}
|
|
},
|
|
code: function() {
|
|
var apply, pre, _i, _len, _ref;
|
|
if (this.isClone) {
|
|
return;
|
|
}
|
|
apply = function(e) {
|
|
return pre.innerHTML = e.detail;
|
|
};
|
|
$.on(window, 'prettyprint:cb', apply);
|
|
_ref = $$('.prettyprint:not(.prettyprinted)', this.nodes.comment);
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
pre = _ref[_i];
|
|
$.event('prettyprint', pre.innerHTML, window);
|
|
}
|
|
$.off(window, 'prettyprint:cb', apply);
|
|
},
|
|
math: function() {
|
|
if (this.isClone || !$('.math', this.nodes.comment)) {
|
|
return;
|
|
}
|
|
return $.event('jsmath', this.nodes.post, window);
|
|
}
|
|
};
|
|
|
|
IDColor = {
|
|
init: function() {
|
|
if (!Conf['Color User IDs']) {
|
|
return;
|
|
}
|
|
this.ids = {};
|
|
return Post.callbacks.push({
|
|
name: 'Color User IDs',
|
|
cb: this.node
|
|
});
|
|
},
|
|
node: function() {
|
|
var rgb, span, style, uid;
|
|
if (this.isClone || !(uid = this.info.uniqueID)) {
|
|
return;
|
|
}
|
|
span = $('.hand', this.nodes.uniqueID);
|
|
if (!(span && span.nodeName === 'SPAN')) {
|
|
return;
|
|
}
|
|
rgb = IDColor.compute(uid);
|
|
style = span.style;
|
|
style.color = rgb[3];
|
|
style.backgroundColor = "rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ")";
|
|
$.addClass(span, 'painted');
|
|
return span.title = 'Highlight posts by this ID';
|
|
},
|
|
compute: function(uid) {
|
|
var hash, rgb;
|
|
if (IDColor.ids[uid]) {
|
|
return IDColor.ids[uid];
|
|
}
|
|
hash = IDColor.hash(uid);
|
|
rgb = [(hash >> 24) & 0xFF, (hash >> 16) & 0xFF, (hash >> 8) & 0xFF];
|
|
rgb[3] = (rgb[0] * 0.299 + rgb[1] * 0.587 + rgb[2] * 0.114) > 125 ? '#000' : '#fff';
|
|
return this.ids[uid] = rgb;
|
|
},
|
|
hash: function(uid) {
|
|
var i, msg;
|
|
msg = 0;
|
|
i = 0;
|
|
while (i < 8) {
|
|
msg = (msg << 5) - msg + uid.charCodeAt(i++);
|
|
}
|
|
return msg;
|
|
}
|
|
};
|
|
|
|
InfiniScroll = {
|
|
init: function() {
|
|
if (!(Conf['Infinite Scrolling'] && g.VIEW === 'index' && g.BOARD !== 'f')) {
|
|
return;
|
|
}
|
|
this.threads = g.threads;
|
|
return $.on(d, '4chanXInitFinished', this.ready);
|
|
},
|
|
ready: function() {
|
|
$.off(d, '4chanXInitFinished', InfiniScroll.ready);
|
|
$.on(d, 'scroll', InfiniScroll.scroll);
|
|
return InfiniScroll.scroll();
|
|
},
|
|
scroll: $.debounce(100, function() {
|
|
var url;
|
|
if (InfiniScroll.isFetching || ((d.body.scrollTop || doc.scrollTop) <= doc.scrollHeight - (300 + window.innerHeight))) {
|
|
return;
|
|
}
|
|
if (InfiniScroll.isDead) {
|
|
return InfiniScroll.notice();
|
|
}
|
|
if (InfiniScroll.cache && InfiniScroll.cache.time > Date.now() - $.MINUTE) {
|
|
return InfiniScroll.parse(InfiniScroll.cache);
|
|
}
|
|
new Notice('info', "Fetching next page.", 2);
|
|
InfiniScroll.isFetching = true;
|
|
url = "//api.4chan.org/" + g.BOARD + "/catalog.json";
|
|
return $.ajax(url, {
|
|
onloadend: InfiniScroll.cb.load
|
|
}, {
|
|
whenModified: true
|
|
});
|
|
}),
|
|
parse: function(response) {
|
|
var botPostForm, el, nodes, omitted_images, omitted_posts, op, post, postlink, posts, replylink, thread, threadID, threadNodes, threads, _i, _j, _len, _len1, _ref;
|
|
threads = InfiniScroll.parsePages(response);
|
|
threadNodes = [];
|
|
nodes = [];
|
|
if (!threads.length) {
|
|
InfiniScroll.notice();
|
|
return InfiniScroll.isDead = true;
|
|
}
|
|
for (_i = 0, _len = threads.length; _i < _len; _i++) {
|
|
thread = threads[_i];
|
|
posts = [];
|
|
omitted_posts = thread.omitted_posts, omitted_images = thread.omitted_images;
|
|
threadID = thread.no;
|
|
el = $.el('div', {
|
|
className: 'thread',
|
|
id: "t" + threadID
|
|
});
|
|
op = Build.postFromObject(thread, g.BOARD);
|
|
posts.push(op);
|
|
replylink = $.el('a', {
|
|
href: "res/" + threadID,
|
|
className: 'replylink',
|
|
textContent: 'Reply'
|
|
});
|
|
postlink = $.el('div', {
|
|
className: "postLink mobile",
|
|
innerHTML: "<a href=\"res/" + threadID + "\" class=\"button\">View Thread</a>"
|
|
});
|
|
if (omitted_posts) {
|
|
posts.push($.el('span', {
|
|
className: 'summary desktop',
|
|
innerHTML: "" + omitted_posts + " posts " + (omitted_images ? "and " + omitted_images + " image replies" : void 0) + " omitted. Click <a class=\"replylink\" href=\"res/" + threadID + "\">here</a> to view."
|
|
}));
|
|
$.prepend(postlink, $.el('span', {
|
|
className: 'info',
|
|
innerHTML: "<strong>" + omitted_posts + " posts omitted</strong>" + (omitted_images ? "<br><em>(" + omitted_images + " have images)</em>" : "")
|
|
}));
|
|
}
|
|
$.add($('.postInfo', op), [$.tn('\u00A0\u00A0\u00A0['), replylink, $.tn(']\u00A0')]);
|
|
$.add(op, postlink);
|
|
if (thread.last_replies) {
|
|
_ref = thread.last_replies;
|
|
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
|
|
post = _ref[_j];
|
|
posts.push(Build.postFromObject(post, g.BOARD));
|
|
}
|
|
}
|
|
$.add(el, posts);
|
|
threadNodes.push(el);
|
|
nodes.push(el);
|
|
nodes.push($.el('hr'));
|
|
}
|
|
InfiniScroll.features(threadNodes);
|
|
if (botPostForm = $('.board > .mobile.center')) {
|
|
return $.before(botPostForm, nodes);
|
|
}
|
|
},
|
|
parsePages: function(response) {
|
|
var newThreads, number, page, pages, thread, threads, _i, _len;
|
|
pages = JSON.parse(response);
|
|
newThreads = [];
|
|
for (number in pages) {
|
|
page = pages[number];
|
|
if (!(pages.hasOwnProperty(number))) {
|
|
continue;
|
|
}
|
|
threads = page.threads;
|
|
for (_i = 0, _len = threads.length; _i < _len; _i++) {
|
|
thread = threads[_i];
|
|
if (g.threads["" + g.BOARD + "." + thread.no]) {
|
|
continue;
|
|
}
|
|
newThreads.push(thread);
|
|
if (newThreads.length === 15) {
|
|
return newThreads;
|
|
}
|
|
}
|
|
}
|
|
return newThreads;
|
|
},
|
|
features: function(threadNodes) {
|
|
var err, errors, post, posts, thread, threadRoot, threads, _i, _j, _len, _len1, _ref;
|
|
posts = [];
|
|
threads = [];
|
|
for (_i = 0, _len = threadNodes.length; _i < _len; _i++) {
|
|
threadRoot = threadNodes[_i];
|
|
thread = new Thread(+threadRoot.id.slice(1), g.BOARD);
|
|
threads.push(thread);
|
|
_ref = $$('.thread > .postContainer', threadRoot);
|
|
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
|
|
post = _ref[_j];
|
|
try {
|
|
posts.push(new Post(post, thread, g.BOARD));
|
|
} catch (_error) {
|
|
err = _error;
|
|
if (!errors) {
|
|
errors = [];
|
|
}
|
|
errors.push({
|
|
message: "Parsing of Post No." + (postRoot.id.match(/\d+/)) + " failed. Post will be skipped.",
|
|
error: err
|
|
});
|
|
}
|
|
}
|
|
}
|
|
if (errors) {
|
|
Main.handleErrors(errors);
|
|
}
|
|
Main.callbackNodes(Thread, threads);
|
|
return Main.callbackNodes(Post, posts);
|
|
},
|
|
notice: (function() {
|
|
var notify, reset;
|
|
notify = false;
|
|
reset = function() {
|
|
return notify = false;
|
|
};
|
|
return function() {
|
|
if (notify) {
|
|
return;
|
|
}
|
|
notify = true;
|
|
new Notice('info', "Last page reached.", 2);
|
|
return setTimeout(reset, 3 * $.SECOND);
|
|
};
|
|
})(),
|
|
cb: {
|
|
load: function() {
|
|
InfiniScroll.isFetching = false;
|
|
if (this.status !== 200) {
|
|
return;
|
|
}
|
|
InfiniScroll.cache = new String(this.response);
|
|
InfiniScroll.cache.time = Date.now();
|
|
return InfiniScroll.parse(this.response);
|
|
}
|
|
}
|
|
};
|
|
|
|
Keybinds = {
|
|
init: function() {
|
|
var hotkey, init;
|
|
if (!Conf['Keybinds']) {
|
|
return;
|
|
}
|
|
for (hotkey in Conf.hotkeys) {
|
|
$.sync(hotkey, Keybinds.sync);
|
|
}
|
|
init = function() {
|
|
var node, _i, _len, _ref;
|
|
$.off(d, '4chanXInitFinished', init);
|
|
$.on(d, 'keydown', Keybinds.keydown);
|
|
_ref = $$('[accesskey]');
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
node = _ref[_i];
|
|
node.removeAttribute('accesskey');
|
|
}
|
|
};
|
|
return $.on(d, '4chanXInitFinished', init);
|
|
},
|
|
sync: function(key, hotkey) {
|
|
return Conf[hotkey] = key;
|
|
},
|
|
keydown: function(e) {
|
|
var key, notification, notifications, op, target, thread, threadRoot, _i, _len, _ref;
|
|
if (!(key = Keybinds.keyCode(e))) {
|
|
return;
|
|
}
|
|
target = e.target;
|
|
if ((_ref = target.nodeName) === 'INPUT' || _ref === 'TEXTAREA') {
|
|
if (!/(Esc|Alt|Ctrl|Meta|Shift\+\w{2,})/.test(key)) {
|
|
return;
|
|
}
|
|
}
|
|
threadRoot = Nav.getThread();
|
|
if (op = $('.op', threadRoot)) {
|
|
thread = Get.postFromNode(op).thread;
|
|
}
|
|
switch (key) {
|
|
case Conf['Toggle board list']:
|
|
if (Conf['Custom Board Navigation']) {
|
|
Header.toggleBoardList();
|
|
}
|
|
break;
|
|
case Conf['Toggle header']:
|
|
Header.toggleBarVisibility();
|
|
break;
|
|
case Conf['Open empty QR']:
|
|
Keybinds.qr(threadRoot);
|
|
break;
|
|
case Conf['Open QR']:
|
|
Keybinds.qr(threadRoot, true);
|
|
break;
|
|
case Conf['Open settings']:
|
|
Settings.open();
|
|
break;
|
|
case Conf['Close']:
|
|
if ($.id('fourchanx-settings')) {
|
|
Settings.close();
|
|
} else if ((notifications = $$('.notification')).length) {
|
|
for (_i = 0, _len = notifications.length; _i < _len; _i++) {
|
|
notification = notifications[_i];
|
|
$('.close', notification).click();
|
|
}
|
|
} else if (QR.nodes) {
|
|
if (Conf['Persistent QR']) {
|
|
QR.hide();
|
|
} else {
|
|
QR.close();
|
|
}
|
|
}
|
|
break;
|
|
case Conf['Spoiler tags']:
|
|
if (target.nodeName !== 'TEXTAREA') {
|
|
return;
|
|
}
|
|
Keybinds.tags('spoiler', target);
|
|
break;
|
|
case Conf['Code tags']:
|
|
if (target.nodeName !== 'TEXTAREA') {
|
|
return;
|
|
}
|
|
Keybinds.tags('code', target);
|
|
break;
|
|
case Conf['Eqn tags']:
|
|
if (target.nodeName !== 'TEXTAREA') {
|
|
return;
|
|
}
|
|
Keybinds.tags('eqn', target);
|
|
break;
|
|
case Conf['Math tags']:
|
|
if (target.nodeName !== 'TEXTAREA') {
|
|
return;
|
|
}
|
|
Keybinds.tags('math', target);
|
|
break;
|
|
case Conf['Toggle sage']:
|
|
if (QR.nodes) {
|
|
Keybinds.sage();
|
|
}
|
|
break;
|
|
case Conf['Submit QR']:
|
|
if (QR.nodes && !QR.status()) {
|
|
QR.submit();
|
|
}
|
|
break;
|
|
case Conf['Post Without Name']:
|
|
if (QR.nodes && !QR.status()) {
|
|
Keybinds.name();
|
|
QR.submit();
|
|
}
|
|
break;
|
|
case Conf['Update']:
|
|
switch (g.VIEW) {
|
|
case 'thread':
|
|
ThreadUpdater.update();
|
|
break;
|
|
case 'index':
|
|
Index.update();
|
|
}
|
|
break;
|
|
case Conf['Watch']:
|
|
ThreadWatcher.toggle(thread);
|
|
break;
|
|
case Conf['Expand image']:
|
|
Keybinds.img(threadRoot);
|
|
break;
|
|
case Conf['Expand images']:
|
|
Keybinds.img(threadRoot, true);
|
|
break;
|
|
case Conf['Open Gallery']:
|
|
Gallery.cb.toggle();
|
|
break;
|
|
case Conf['fappeTyme']:
|
|
FappeTyme.cb.toggle.call({
|
|
name: 'fappe'
|
|
});
|
|
break;
|
|
case Conf['werkTyme']:
|
|
FappeTyme.cb.toggle.call({
|
|
name: 'werk'
|
|
});
|
|
break;
|
|
case Conf['Front page']:
|
|
if (g.VIEW === 'index') {
|
|
Index.userPageNav(0);
|
|
} else {
|
|
window.location = "/" + g.BOARD + "/";
|
|
}
|
|
break;
|
|
case Conf['Open front page']:
|
|
$.open("/" + g.BOARD + "/");
|
|
break;
|
|
case Conf['Next page']:
|
|
if (!(g.VIEW === 'index' && Conf['Index Mode'] !== 'all pages')) {
|
|
return;
|
|
}
|
|
$('.next button, .next a', Index.pagelist).click();
|
|
break;
|
|
case Conf['Previous page']:
|
|
if (!(g.VIEW === 'index' && Conf['Index Mode'] !== 'all pages')) {
|
|
return;
|
|
}
|
|
$('.prev button, .prev a', Index.pagelist).click();
|
|
break;
|
|
case Conf['Search form']:
|
|
Index.searchInput.focus();
|
|
break;
|
|
case Conf['Paged mode']:
|
|
if (!(g.VIEW === 'index' && Conf['Index Mode'] !== 'paged')) {
|
|
return;
|
|
}
|
|
Index.setIndexMode('paged');
|
|
break;
|
|
case Conf['All pages mode']:
|
|
if (!(g.VIEW === 'index' && Conf['Index Mode'] !== 'all pages')) {
|
|
return;
|
|
}
|
|
Index.setIndexMode('all pages');
|
|
break;
|
|
case Conf['Catalog mode']:
|
|
if (!(g.VIEW === 'index' && Conf['Index Mode'] !== 'catalog')) {
|
|
return;
|
|
}
|
|
Index.setIndexMode('catalog');
|
|
break;
|
|
case Conf['Cycle sort type']:
|
|
if (g.VIEW !== 'index') {
|
|
return;
|
|
}
|
|
Index.cycleSortType();
|
|
break;
|
|
case Conf['Next thread']:
|
|
if (g.VIEW !== 'index') {
|
|
return;
|
|
}
|
|
Nav.scroll(+1);
|
|
break;
|
|
case Conf['Previous thread']:
|
|
if (g.VIEW !== 'index') {
|
|
return;
|
|
}
|
|
Nav.scroll(-1);
|
|
break;
|
|
case Conf['Expand thread']:
|
|
ExpandThread.toggle(thread);
|
|
break;
|
|
case Conf['Open thread']:
|
|
Keybinds.open(thread);
|
|
break;
|
|
case Conf['Open thread tab']:
|
|
Keybinds.open(thread, true);
|
|
break;
|
|
case Conf['Next reply']:
|
|
Keybinds.hl(+1, threadRoot);
|
|
break;
|
|
case Conf['Previous reply']:
|
|
Keybinds.hl(-1, threadRoot);
|
|
break;
|
|
case Conf['Deselect reply']:
|
|
Keybinds.hl(0, threadRoot);
|
|
break;
|
|
case Conf['Hide']:
|
|
PostHiding.toggle(thread.OP);
|
|
break;
|
|
case Conf['Previous Post Quoting You']:
|
|
QuoteMarkers.cb.seek('preceding');
|
|
break;
|
|
case Conf['Next Post Quoting You']:
|
|
QuoteMarkers.cb.seek('following');
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
e.preventDefault();
|
|
return e.stopPropagation();
|
|
},
|
|
keyCode: function(e) {
|
|
var kc, key;
|
|
key = (function() {
|
|
switch (kc = e.keyCode) {
|
|
case 8:
|
|
return '';
|
|
case 13:
|
|
return 'Enter';
|
|
case 27:
|
|
return 'Esc';
|
|
case 37:
|
|
return 'Left';
|
|
case 38:
|
|
return 'Up';
|
|
case 39:
|
|
return 'Right';
|
|
case 40:
|
|
return 'Down';
|
|
default:
|
|
if ((48 <= kc && kc <= 57) || (65 <= kc && kc <= 90)) {
|
|
return String.fromCharCode(kc).toLowerCase();
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
})();
|
|
if (key) {
|
|
if (e.altKey) {
|
|
key = 'Alt+' + key;
|
|
}
|
|
if (e.ctrlKey) {
|
|
key = 'Ctrl+' + key;
|
|
}
|
|
if (e.metaKey) {
|
|
key = 'Meta+' + key;
|
|
}
|
|
if (e.shiftKey) {
|
|
key = 'Shift+' + key;
|
|
}
|
|
}
|
|
return key;
|
|
},
|
|
qr: function(thread, quote) {
|
|
if (!QR.postingIsEnabled) {
|
|
return;
|
|
}
|
|
QR.open();
|
|
if (quote) {
|
|
QR.quote.call($('input', $('.post.highlight', thread) || thread));
|
|
}
|
|
QR.nodes.com.focus();
|
|
if (Conf['QR Shortcut']) {
|
|
return $.rmClass($('.qr-shortcut'), 'disabled');
|
|
}
|
|
},
|
|
tags: function(tag, ta) {
|
|
var range, selEnd, selStart, value;
|
|
value = ta.value;
|
|
selStart = ta.selectionStart;
|
|
selEnd = ta.selectionEnd;
|
|
ta.value = value.slice(0, selStart) + ("[" + tag + "]") + value.slice(selStart, selEnd) + ("[/" + tag + "]") + value.slice(selEnd);
|
|
range = ("[" + tag + "]").length + selEnd;
|
|
ta.setSelectionRange(range, range);
|
|
return $.event('input', null, ta);
|
|
},
|
|
name: function() {
|
|
return QR.nodes.name.value = '';
|
|
},
|
|
sage: function() {
|
|
var isSage;
|
|
isSage = /sage/i.test(QR.nodes.email.value);
|
|
return QR.nodes.email.value = isSage ? "" : "sage";
|
|
},
|
|
img: function(thread, all) {
|
|
var post;
|
|
if (all) {
|
|
return ImageExpand.cb.toggleAll();
|
|
} else {
|
|
post = Get.postFromNode($('.post.highlight', thread) || $('.op', thread));
|
|
return ImageExpand.toggle(post);
|
|
}
|
|
},
|
|
open: function(thread, tab) {
|
|
var url;
|
|
if (g.VIEW !== 'index') {
|
|
return;
|
|
}
|
|
url = "/" + thread.board + "/res/" + thread;
|
|
if (tab) {
|
|
return $.open(url);
|
|
} else {
|
|
return location.href = url;
|
|
}
|
|
},
|
|
hl: function(delta, thread) {
|
|
var axis, height, next, postEl, replies, reply, root, _i, _len;
|
|
postEl = $('.reply.highlight', thread);
|
|
if (!delta) {
|
|
if (postEl) {
|
|
$.rmClass(postEl, 'highlight');
|
|
}
|
|
return;
|
|
}
|
|
if (postEl) {
|
|
height = postEl.getBoundingClientRect().height;
|
|
if (Header.getTopOf(postEl) >= -height && Header.getBottomOf(postEl) >= -height) {
|
|
root = postEl.parentNode;
|
|
axis = delta === +1 ? 'following' : 'preceding';
|
|
if (!(next = $.x("" + axis + "-sibling::div[contains(@class,'replyContainer') and not(@hidden) and not(child::div[@class='stub'])][1]/child::div[contains(@class,'reply')]", root))) {
|
|
return;
|
|
}
|
|
Header.scrollToIfNeeded(next, delta === +1);
|
|
this.focus(next);
|
|
$.rmClass(postEl, 'highlight');
|
|
return;
|
|
}
|
|
$.rmClass(postEl, 'highlight');
|
|
}
|
|
replies = $$('.reply', thread);
|
|
if (delta === -1) {
|
|
replies.reverse();
|
|
}
|
|
for (_i = 0, _len = replies.length; _i < _len; _i++) {
|
|
reply = replies[_i];
|
|
if (delta === +1 && Header.getTopOf(reply) > 0 || delta === -1 && Header.getBottomOf(reply) > 0) {
|
|
this.focus(reply);
|
|
return;
|
|
}
|
|
}
|
|
},
|
|
focus: function(post) {
|
|
return $.addClass(post, 'highlight');
|
|
}
|
|
};
|
|
|
|
Nav = {
|
|
init: function() {
|
|
var next, prev;
|
|
switch (g.VIEW) {
|
|
case 'index':
|
|
if (!Conf['Index Navigation']) {
|
|
return;
|
|
}
|
|
break;
|
|
case 'thread':
|
|
if (!Conf['Reply Navigation']) {
|
|
return;
|
|
}
|
|
}
|
|
prev = $.el('a', {
|
|
href: 'javascript:;',
|
|
id: 'navPrev'
|
|
});
|
|
next = $.el('a', {
|
|
href: 'javascript:;',
|
|
id: 'navNext'
|
|
});
|
|
Header.addShortcut(prev, true);
|
|
Header.addShortcut(next, true);
|
|
$.on(prev, 'click', this.prev);
|
|
return $.on(next, 'click', this.next);
|
|
},
|
|
prev: function() {
|
|
if (g.VIEW === 'thread') {
|
|
return window.scrollTo(0, 0);
|
|
} else {
|
|
return Nav.scroll(-1);
|
|
}
|
|
},
|
|
next: function() {
|
|
if (g.VIEW === 'thread') {
|
|
return window.scrollTo(0, d.body.scrollHeight);
|
|
} else {
|
|
return Nav.scroll(+1);
|
|
}
|
|
},
|
|
getThread: function() {
|
|
var threadRoot, _i, _len, _ref;
|
|
_ref = $$('.thread');
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
threadRoot = _ref[_i];
|
|
if (Header.getTopOf(threadRoot) >= -threadRoot.getBoundingClientRect().height) {
|
|
return threadRoot;
|
|
}
|
|
}
|
|
return $('.board');
|
|
},
|
|
scroll: function(delta) {
|
|
var axis, next, thread, top;
|
|
thread = Nav.getThread();
|
|
axis = delta === +1 ? 'following' : 'preceding';
|
|
if (next = $.x("" + axis + "-sibling::div[contains(@class,'thread') and not(@hidden)][1]", thread)) {
|
|
top = Header.getTopOf(thread);
|
|
if (delta === +1 && top < 5 || delta === -1 && top > -5) {
|
|
thread = next;
|
|
}
|
|
}
|
|
return Header.scrollTo(thread);
|
|
}
|
|
};
|
|
|
|
RelativeDates = {
|
|
INTERVAL: $.MINUTE / 2,
|
|
init: function() {
|
|
switch (g.VIEW) {
|
|
case 'index':
|
|
this.flush();
|
|
$.on(d, 'visibilitychange', this.flush);
|
|
if (!Conf['Relative Post Dates']) {
|
|
return;
|
|
}
|
|
break;
|
|
case 'thread':
|
|
if (!Conf['Relative Post Dates']) {
|
|
return;
|
|
}
|
|
this.flush();
|
|
$.on(d, 'visibilitychange ThreadUpdate', this.flush);
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
return Post.callbacks.push({
|
|
name: 'Relative Post Dates',
|
|
cb: this.node
|
|
});
|
|
},
|
|
node: function() {
|
|
var dateEl;
|
|
if (this.isClone) {
|
|
return;
|
|
}
|
|
dateEl = this.nodes.date;
|
|
dateEl.title = dateEl.textContent;
|
|
return RelativeDates.update(this);
|
|
},
|
|
relative: function(diff, now, date) {
|
|
var days, months, number, rounded, unit, years;
|
|
unit = (number = diff / $.DAY) >= 1 ? (years = now.getYear() - date.getYear(), months = now.getMonth() - date.getMonth(), days = now.getDate() - date.getDate(), years > 1 ? (number = years - (months < 0 || months === 0 && days < 0), 'year') : years === 1 && (months > 0 || months === 0 && days >= 0) ? (number = years, 'year') : (months = (months + 12) % 12) > 1 ? (number = months - (days < 0), 'month') : months === 1 && days >= 0 ? (number = months, 'month') : 'day') : (number = diff / $.HOUR) >= 1 ? 'hour' : (number = diff / $.MINUTE) >= 1 ? 'minute' : (number = Math.max(0, diff) / $.SECOND, 'second');
|
|
rounded = Math.round(number);
|
|
if (rounded !== 1) {
|
|
unit += 's';
|
|
}
|
|
return "" + rounded + " " + unit + " ago";
|
|
},
|
|
stale: [],
|
|
flush: function() {
|
|
var data, now, _i, _len, _ref;
|
|
if (d.hidden) {
|
|
return;
|
|
}
|
|
now = new Date();
|
|
_ref = RelativeDates.stale;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
data = _ref[_i];
|
|
RelativeDates.update(data, now);
|
|
}
|
|
RelativeDates.stale = [];
|
|
clearTimeout(RelativeDates.timeout);
|
|
return RelativeDates.timeout = setTimeout(RelativeDates.flush, RelativeDates.INTERVAL);
|
|
},
|
|
update: function(data, now) {
|
|
var date, diff, isPost, relative, singlePost, _i, _len, _ref;
|
|
isPost = data instanceof Post;
|
|
date = isPost ? data.info.date : new Date(+data.dataset.utc);
|
|
now || (now = new Date());
|
|
diff = now - date;
|
|
relative = RelativeDates.relative(diff, now, date);
|
|
if (isPost) {
|
|
_ref = [data].concat(data.clones);
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
singlePost = _ref[_i];
|
|
singlePost.nodes.date.firstChild.textContent = relative;
|
|
}
|
|
} else {
|
|
data.firstChild.textContent = relative;
|
|
}
|
|
return RelativeDates.setOwnTimeout(diff, data);
|
|
},
|
|
setOwnTimeout: function(diff, data) {
|
|
var delay;
|
|
delay = diff < $.MINUTE ? $.SECOND - (diff + $.SECOND / 2) % $.SECOND : diff < $.HOUR ? $.MINUTE - (diff + $.MINUTE / 2) % $.MINUTE : diff < $.DAY ? $.HOUR - (diff + $.HOUR / 2) % $.HOUR : $.DAY - (diff + $.DAY / 2) % $.DAY;
|
|
return setTimeout(RelativeDates.markStale, delay, data);
|
|
},
|
|
markStale: function(data) {
|
|
if (__indexOf.call(RelativeDates.stale, data) >= 0) {
|
|
return;
|
|
}
|
|
if (data instanceof Post && !g.posts[data.fullID]) {
|
|
return;
|
|
}
|
|
return RelativeDates.stale.push(data);
|
|
}
|
|
};
|
|
|
|
RemoveSpoilers = {
|
|
init: function() {
|
|
if (Conf['Reveal Spoilers']) {
|
|
$.addClass(doc, 'reveal-spoilers');
|
|
}
|
|
if (Conf['Remove Spoilers']) {
|
|
return $.addClass(doc, 'remove-spoilers');
|
|
}
|
|
}
|
|
};
|
|
|
|
Report = {
|
|
init: function() {
|
|
if (!/report/.test(location.search)) {
|
|
return;
|
|
}
|
|
return $.asap((function() {
|
|
return $.id('recaptcha_response_field');
|
|
}), Report.ready);
|
|
},
|
|
ready: function() {
|
|
var field;
|
|
field = $.id('recaptcha_response_field');
|
|
$.on(field, 'keydown', function(e) {
|
|
if (e.keyCode === 8 && !field.value) {
|
|
return $.globalEval('Recaptcha.reload("t")');
|
|
}
|
|
});
|
|
return $.on($('form'), 'submit', function(e) {
|
|
var response;
|
|
e.preventDefault();
|
|
response = field.value.trim();
|
|
if (!/\s/.test(response)) {
|
|
field.value = "" + response + " " + response;
|
|
}
|
|
return this.submit();
|
|
});
|
|
}
|
|
};
|
|
|
|
Time = {
|
|
init: function() {
|
|
if (!Conf['Time Formatting']) {
|
|
return;
|
|
}
|
|
this.funk = this.createFunc(Conf['time']);
|
|
return Post.callbacks.push({
|
|
name: 'Time Formatting',
|
|
cb: this.node
|
|
});
|
|
},
|
|
node: function() {
|
|
if (this.isClone) {
|
|
return;
|
|
}
|
|
return this.nodes.date.textContent = Time.funk(this.info.date);
|
|
},
|
|
createFunc: function(format) {
|
|
var code;
|
|
code = format.replace(/%([A-Za-z])/g, function(s, c) {
|
|
if (c in Time.formatters) {
|
|
return "' + this.formatters." + c + ".call(date) + '";
|
|
} else {
|
|
return s;
|
|
}
|
|
});
|
|
return Function('date', "return '" + code + "'");
|
|
},
|
|
day: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
|
|
month: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
|
|
zeroPad: function(n) {
|
|
if (n < 10) {
|
|
return "0" + n;
|
|
} else {
|
|
return n;
|
|
}
|
|
},
|
|
formatters: {
|
|
a: function() {
|
|
return Time.day[this.getDay()].slice(0, 3);
|
|
},
|
|
A: function() {
|
|
return Time.day[this.getDay()];
|
|
},
|
|
b: function() {
|
|
return Time.month[this.getMonth()].slice(0, 3);
|
|
},
|
|
B: function() {
|
|
return Time.month[this.getMonth()];
|
|
},
|
|
d: function() {
|
|
return Time.zeroPad(this.getDate());
|
|
},
|
|
e: function() {
|
|
return this.getDate();
|
|
},
|
|
H: function() {
|
|
return Time.zeroPad(this.getHours());
|
|
},
|
|
I: function() {
|
|
return Time.zeroPad(this.getHours() % 12 || 12);
|
|
},
|
|
k: function() {
|
|
return this.getHours();
|
|
},
|
|
l: function() {
|
|
return this.getHours() % 12 || 12;
|
|
},
|
|
m: function() {
|
|
return Time.zeroPad(this.getMonth() + 1);
|
|
},
|
|
M: function() {
|
|
return Time.zeroPad(this.getMinutes());
|
|
},
|
|
p: function() {
|
|
if (this.getHours() < 12) {
|
|
return 'AM';
|
|
} else {
|
|
return 'PM';
|
|
}
|
|
},
|
|
P: function() {
|
|
if (this.getHours() < 12) {
|
|
return 'am';
|
|
} else {
|
|
return 'pm';
|
|
}
|
|
},
|
|
S: function() {
|
|
return Time.zeroPad(this.getSeconds());
|
|
},
|
|
y: function() {
|
|
return this.getFullYear().toString().slice(2);
|
|
},
|
|
Y: function() {
|
|
return this.getFullYear();
|
|
}
|
|
}
|
|
};
|
|
|
|
Navigate = {
|
|
path: window.location.pathname,
|
|
init: function() {
|
|
if (g.BOARD.ID === 'f' || !Conf['JSON Navigation']) {
|
|
return;
|
|
}
|
|
$.on(window, 'popstate', Navigate.popstate);
|
|
$.ready(function() {
|
|
Navigate.makeBreadCrumb(window.location, g.VIEW, g.BOARD.ID, g.THREADID);
|
|
return $.add(Index.navLinks, Navigate.el);
|
|
});
|
|
this.title = function() {};
|
|
this.el = $.el('span', {
|
|
id: 'breadCrumb'
|
|
});
|
|
Thread.callbacks.push({
|
|
name: 'Navigate',
|
|
cb: this.thread
|
|
});
|
|
return Post.callbacks.push({
|
|
name: 'Navigate',
|
|
cb: this.post
|
|
});
|
|
},
|
|
thread: function() {
|
|
var replyLink;
|
|
if (g.VIEW === 'thread') {
|
|
return;
|
|
}
|
|
replyLink = $('a.replylink', this.OP.nodes.info);
|
|
return $.on(replyLink, 'click', Navigate.navigate);
|
|
},
|
|
post: function() {
|
|
var linktype;
|
|
if (!(g.VIEW === 'thread' && this.thread.ID === g.THREADID)) {
|
|
$.on($('a[title="Highlight this post"]', this.nodes.info), 'click', Navigate.navigate);
|
|
}
|
|
if (!(linktype = Conf['Quote Inlining'] && Conf['Quote Hash Navigation'] ? '.hashlink' : !Conf['Quote Inlining'] ? '.quotelink' : null)) {
|
|
return;
|
|
}
|
|
return Navigate.quoteLink($$(linktype, this.nodes.comment));
|
|
},
|
|
quoteLink: function(links) {
|
|
var link, _i, _len;
|
|
for (_i = 0, _len = links.length; _i < _len; _i++) {
|
|
link = links[_i];
|
|
Navigate.singleQuoteLink(link);
|
|
}
|
|
},
|
|
singleQuoteLink: function(link) {
|
|
var boardID, threadID, _ref;
|
|
_ref = Get.postDataFromLink(link), boardID = _ref.boardID, threadID = _ref.threadID;
|
|
if (g.VIEW === 'index' || boardID !== g.BOARD.ID || threadID !== g.THREADID) {
|
|
return $.on(link, 'click', Navigate.navigate);
|
|
}
|
|
},
|
|
clean: function() {
|
|
g.threads.forEach(function(thread) {
|
|
return thread.collect();
|
|
});
|
|
if (Conf['Quote Backlinks']) {
|
|
QuoteBacklink.map = {};
|
|
}
|
|
return $.rmAll($('.board'));
|
|
},
|
|
features: [['Thread Excerpt', ThreadExcerpt], ['Unread Count', Unread], ['Quote Threading', QuoteThreading], ['Thread Stats', ThreadStats], ['Thread Updater', ThreadUpdater], ['Thread Expansion', ExpandThread]],
|
|
disconnect: function() {
|
|
var err, errors, feature, name, _i, _len, _ref, _ref1;
|
|
_ref = Navigate.features;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
_ref1 = _ref[_i], name = _ref1[0], feature = _ref1[1];
|
|
try {
|
|
feature.disconnect();
|
|
} catch (_error) {
|
|
err = _error;
|
|
if (!errors) {
|
|
errors = [];
|
|
}
|
|
errors.push({
|
|
message: "Failed to disconnect feature " + name + ".",
|
|
error: err
|
|
});
|
|
}
|
|
if (errors) {
|
|
Main.handleErrors(errors);
|
|
}
|
|
}
|
|
},
|
|
reconnect: function() {
|
|
var err, errors, feature, name, _i, _len, _ref, _ref1;
|
|
_ref = Navigate.features;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
_ref1 = _ref[_i], name = _ref1[0], feature = _ref1[1];
|
|
try {
|
|
feature.init();
|
|
} catch (_error) {
|
|
err = _error;
|
|
if (!errors) {
|
|
errors = [];
|
|
}
|
|
errors.push({
|
|
message: "Failed to reconnect feature " + name + ".",
|
|
error: err
|
|
});
|
|
}
|
|
}
|
|
if (errors) {
|
|
Main.handleErrors(errors);
|
|
}
|
|
},
|
|
updateContext: function(view) {
|
|
g.DEAD = false;
|
|
if (view === 'thread') {
|
|
g.THREADID = +window.location.pathname.split('/')[3];
|
|
}
|
|
if (view === g.VIEW) {
|
|
return;
|
|
}
|
|
$.rmClass(doc, g.VIEW);
|
|
$.addClass(doc, view);
|
|
({
|
|
index: function() {
|
|
delete g.THREADID;
|
|
if (Conf['Index Mode'] === 'catalog') {
|
|
return Index.cb.toggleCatalogMode();
|
|
}
|
|
},
|
|
thread: function() {
|
|
if (Conf['Index Mode'] === 'catalog') {
|
|
return $.rmClass(doc, 'catalog-mode');
|
|
}
|
|
}
|
|
})[view]();
|
|
return g.VIEW = view;
|
|
},
|
|
updateBoard: function(boardID) {
|
|
var fullBoardList;
|
|
fullBoardList = $('#full-board-list', Header.boardList);
|
|
$.rmClass($('.current', fullBoardList), 'current');
|
|
$.addClass($("a[href*='/" + boardID + "/']", fullBoardList), 'current');
|
|
Header.generateBoardList(Conf['boardnav'].replace(/(\r\n|\n|\r)/g, ' '));
|
|
Index.catalogLink.href = "//boards.4chan.org/" + boardID + "/";
|
|
QR.flagsInput();
|
|
return $.cache('//a.4cdn.org/boards.json', function() {
|
|
var aboard, board, err, _i, _len, _ref;
|
|
try {
|
|
if (this.status !== 200) {
|
|
return;
|
|
}
|
|
_ref = this.response.boards;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
aboard = _ref[_i];
|
|
if (!(aboard.board === boardID)) {
|
|
continue;
|
|
}
|
|
board = aboard;
|
|
break;
|
|
}
|
|
} catch (_error) {
|
|
err = _error;
|
|
Main.handleErrors([
|
|
{
|
|
message: "Navigation failed to update board name.",
|
|
error: err
|
|
}
|
|
]);
|
|
}
|
|
if (!board) {
|
|
return;
|
|
}
|
|
Navigate.updateTitle(board);
|
|
return Navigate.updateSFW(!!board.ws_board);
|
|
});
|
|
},
|
|
updateSFW: function(sfw) {
|
|
var theme;
|
|
Favicon.el.href = Favicon["default"] = "//s.4cdn.org/image/favicon" + (sfw ? '-ws' : '') + ".ico";
|
|
$.add(d.head, Favicon.el);
|
|
if (Favicon.SFW === sfw) {
|
|
return;
|
|
}
|
|
Favicon.SFW = sfw;
|
|
Favicon.update();
|
|
g.TYPE = sfw ? 'sfw' : 'nsfw';
|
|
if (Conf["NSFW/SFW Mascots"]) {
|
|
Main.setMascotString();
|
|
MascotTools.toggle();
|
|
}
|
|
if (Conf["NSFW/SFW Themes"]) {
|
|
Main.setThemeString();
|
|
theme = Themes[Conf[g.THEMESTRING] || (sfw ? 'Yotsuba B' : 'Yotsuba')];
|
|
return Style.setTheme(theme);
|
|
}
|
|
},
|
|
updateTitle: function(_arg) {
|
|
var board, subtitle, title;
|
|
board = _arg.board, title = _arg.title;
|
|
if (subtitle = $('.boardSubtitle')) {
|
|
$.rm(subtitle);
|
|
}
|
|
return $('.boardTitle').textContent = d.title = "/" + board + "/ - " + title;
|
|
},
|
|
setMode: function(a) {
|
|
var indexMode, indexSort, result, _ref;
|
|
_ref = a.dataset, indexMode = _ref.indexMode, indexSort = _ref.indexSort;
|
|
result = false;
|
|
if (indexMode && Conf['Index Mode'] !== indexMode) {
|
|
$.set('Index Mode', Conf['Index Mode'] = Index.selectMode.value = indexMode);
|
|
Index.cb.mode();
|
|
result = true;
|
|
}
|
|
if (indexSort && Conf['Index Sort'] !== indexSort) {
|
|
$.set('Index Sort', Conf['Index Sort'] = Index.selectSort.value = indexSort);
|
|
Index.cb.sort();
|
|
result = true;
|
|
}
|
|
return result;
|
|
},
|
|
navigate: function(e) {
|
|
var boardID, load, pageNum, path, threadID, view, _, _ref;
|
|
if (this.hostname !== 'boards.4chan.org' || window.location.hostname === 'rs.4chan.org') {
|
|
return;
|
|
}
|
|
if (e) {
|
|
if (e.shiftKey || e.ctrlKey || (e.type === 'click' && e.button !== 0)) {
|
|
if ((e != null ? e.button : void 0) !== 2) {
|
|
Navigate.setMode(this);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
if (this.pathname === Navigate.path) {
|
|
if (g.VIEW === 'thread') {
|
|
ThreadUpdater.update();
|
|
} else {
|
|
if (!Index.searchTest()) {
|
|
if (Navigate.setMode(this)) {
|
|
Index.buildIndex();
|
|
} else {
|
|
Index.update();
|
|
}
|
|
}
|
|
}
|
|
if (e != null) {
|
|
e.preventDefault();
|
|
}
|
|
return;
|
|
}
|
|
$.addClass(Index.button, 'fa-spin');
|
|
_ref = this.pathname.split('/'), _ = _ref[0], boardID = _ref[1], view = _ref[2], threadID = _ref[3];
|
|
if ('f' === boardID || 'f' === g.BOARD.ID) {
|
|
return;
|
|
}
|
|
if (e != null) {
|
|
e.preventDefault();
|
|
}
|
|
if (Index.isSearching) {
|
|
Index.clearSearch();
|
|
}
|
|
Navigate.title = function() {};
|
|
delete Index.pageNum;
|
|
$.rmAll(Header.hover);
|
|
if (threadID) {
|
|
view = 'thread';
|
|
} else {
|
|
pageNum = view;
|
|
view = 'index';
|
|
}
|
|
path = this.pathname;
|
|
if (this.hash && view === 'thread') {
|
|
path += this.hash;
|
|
}
|
|
Navigate.makeBreadCrumb(this.href, view, boardID, threadID);
|
|
if (this.id !== 'popState') {
|
|
history.pushState('internal', '', path);
|
|
}
|
|
Navigate.path = this.pathname;
|
|
Navigate.setMode(this);
|
|
if (!(view === 'index' && 'index' === g.VIEW && boardID === g.BOARD.ID)) {
|
|
Navigate.disconnect();
|
|
Navigate.updateContext(view);
|
|
Navigate.clean();
|
|
Navigate.reconnect();
|
|
}
|
|
if (boardID === g.BOARD.ID) {
|
|
Navigate.title = function() {
|
|
if (view === 'index') {
|
|
return d.title = $('.boardTitle').textContent;
|
|
}
|
|
};
|
|
} else {
|
|
g.BOARD = new Board(boardID);
|
|
Navigate.title = function() {
|
|
return Navigate.updateBoard(boardID);
|
|
};
|
|
}
|
|
Navigate.updateSFW(Favicon.SFW);
|
|
if (view === 'index') {
|
|
return Index.update(pageNum);
|
|
}
|
|
load = Navigate.load;
|
|
Navigate.req = $.ajax("//a.4cdn.org/" + boardID + "/res/" + threadID + ".json", {
|
|
onabort: load,
|
|
onloadend: load
|
|
});
|
|
return setTimeout((function() {
|
|
if (Navigate.req && !Navigate.notice) {
|
|
return Navigate.notice = new Notice('info', 'Loading thread...');
|
|
}
|
|
}), 3 * $.SECOND);
|
|
},
|
|
load: function(e) {
|
|
var err, notice, req;
|
|
$.rmClass(Index.button, 'fa-spin');
|
|
req = Navigate.req, notice = Navigate.notice;
|
|
if (notice != null) {
|
|
notice.close();
|
|
}
|
|
delete Navigate.req;
|
|
delete Navigate.notice;
|
|
if (e.type === 'abort' || req.status !== 200) {
|
|
req.onloadend = null;
|
|
new Notice('warning', "Failed to load thread." + (req.status ? " " + req.status : ''));
|
|
return;
|
|
}
|
|
Navigate.title();
|
|
try {
|
|
return Navigate.parse(req.response.posts);
|
|
} catch (_error) {
|
|
err = _error;
|
|
console.error('Navigate failure:');
|
|
console.log(err);
|
|
if (notice) {
|
|
notice.setType('error');
|
|
notice.el.lastElementChild.textContent = 'Navigation Failed.';
|
|
setTimeout(notice.close, 2 * $.SECOND);
|
|
} else {
|
|
new Notice('error', 'Navigation Failed.', 2);
|
|
}
|
|
}
|
|
},
|
|
makeBreadCrumb: function(href, view, boardID, threadID) {
|
|
var breadCrumb, el;
|
|
breadCrumb = $.el('span', {
|
|
className: 'crumb',
|
|
innerHTML: "<a href=" + href + ">/" + boardID + "/ - " + (view.charAt(0).toUpperCase()) + (view.slice(1)) + (threadID ? " No." + threadID : '') + "</a> > "
|
|
});
|
|
$.on(breadCrumb.firstElementChild, 'click', Navigate.navigate);
|
|
el = Navigate.el;
|
|
$.add(el, breadCrumb);
|
|
if (el.children.length > 5) {
|
|
return $.rm(el.firstChild);
|
|
}
|
|
},
|
|
parse: function(data) {
|
|
var OP, board, errors, i, makePost, obj, post, posts, thread, threadRoot;
|
|
posts = [];
|
|
errors = null;
|
|
board = g.BOARD;
|
|
threadRoot = Build.thread(board, OP = data[0], true);
|
|
thread = new Thread(OP.no, board);
|
|
makePost = function(postNode) {
|
|
var err;
|
|
try {
|
|
return posts.push(new Post(postNode, thread, board));
|
|
} catch (_error) {
|
|
err = _error;
|
|
if (!errors) {
|
|
errors = [];
|
|
}
|
|
return errors.push({
|
|
message: "Parsing of Post No." + postNode.ID + " failed. Post will be skipped.",
|
|
error: err
|
|
});
|
|
}
|
|
};
|
|
makePost($('.opContainer', threadRoot));
|
|
i = 0;
|
|
while (obj = data[++i]) {
|
|
post = Build.postFromObject(obj, board);
|
|
makePost(post);
|
|
$.add(threadRoot, post);
|
|
}
|
|
Thread.callbacks.execute([thread]);
|
|
Post.callbacks.execute(posts);
|
|
if (Conf['Quote Threading'] && !Conf['Unread Count']) {
|
|
QuoteThreading.force();
|
|
}
|
|
board = $('.board');
|
|
$.rmAll(board);
|
|
$.add(board, [threadRoot, $.el('hr')]);
|
|
if (Conf['Unread Count']) {
|
|
Unread.ready();
|
|
}
|
|
QR.generatePostableThreadsList();
|
|
Header.hashScroll.call(window);
|
|
if (errors) {
|
|
return Main.handleErrors(errors);
|
|
}
|
|
},
|
|
popstate: function() {
|
|
var a;
|
|
a = $.el('a', {
|
|
href: window.location,
|
|
id: 'popState'
|
|
});
|
|
return Navigate.navigate.call(a);
|
|
}
|
|
};
|
|
|
|
Settings = {
|
|
init: function() {
|
|
var addSection, arr, check, el, settings, _i, _len, _ref;
|
|
el = $.el('a', {
|
|
className: 'settings-link',
|
|
href: 'javascript:;',
|
|
textContent: 'Settings'
|
|
});
|
|
$.on(el, 'click', this.open);
|
|
$.event('AddMenuEntry', {
|
|
type: 'header',
|
|
el: el,
|
|
order: 1
|
|
});
|
|
addSection = this.addSection;
|
|
_ref = [['style', 'Style'], ['themes', 'Themes'], ['mascots', 'Mascots'], ['main', 'Script'], ['filter', 'Filter'], ['sauce', 'Sauce'], ['advanced', 'Advanced'], ['keybinds', 'Keybinds']];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
arr = _ref[_i];
|
|
addSection(arr[1], Settings[arr[0]]);
|
|
}
|
|
$.on(d, 'AddSettingsSection', this.addSection);
|
|
$.on(d, 'OpenSettings', (function(_this) {
|
|
return function(e) {
|
|
return _this.open(e.detail);
|
|
};
|
|
})(this));
|
|
settings = JSON.parse(localStorage.getItem('4chan-settings')) || {};
|
|
if (!settings.disableAll) {
|
|
settings.disableAll = true;
|
|
check = true;
|
|
}
|
|
if (settings.keyBinds) {
|
|
settings.keyBinds = false;
|
|
check = true;
|
|
}
|
|
if (check) {
|
|
return localStorage.setItem('4chan-settings', JSON.stringify(settings));
|
|
}
|
|
},
|
|
open: function(openSection) {
|
|
var dialog, link, links, overlay, section, sectionToOpen, _i, _len, _ref;
|
|
if (Conf['editMode'] === "theme") {
|
|
if (confirm("Opening the options dialog will close and discard any theme changes made with the theme editor.")) {
|
|
ThemeTools.close();
|
|
}
|
|
return;
|
|
}
|
|
if (Conf['editMode'] === "mascot") {
|
|
if (confirm("Opening the options dialog will close and discard any mascot changes made with the mascot editor.")) {
|
|
MascotTools.close();
|
|
}
|
|
return;
|
|
}
|
|
if (Settings.overlay) {
|
|
return;
|
|
}
|
|
$.event('CloseMenu');
|
|
Settings.dialog = dialog = $.el('div', {
|
|
id: 'appchanx-settings',
|
|
"class": 'dialog',
|
|
innerHTML: "<nav><div class=sections-list></div><span class='imp-exp-result warning'></span><div class=credits><a class=export>Export</a> | <a class=import>Import</a> | <a class=reset>Reset Settings</a> | <input type=file hidden><a href='http://zixaphir.github.com/appchan-x/' target=_blank>appchan x</a> | <a href='https://github.com/zixaphir/appchan-x/blob/master/CHANGELOG.md' target=_blank>" + g.VERSION + "</a> | <a href='https://github.com/zixaphir/appchan-x/blob/master/README.md#reporting-bugs-and-suggestions' target=_blank>Issues</a> | <a href=javascript:; class='close fa' title=Close>\uf00d</a></div></nav><hr><div class=section-container><section></section></div>"
|
|
});
|
|
Settings.overlay = overlay = $.el('div', {
|
|
id: 'overlay'
|
|
});
|
|
$.on($('.export', dialog), 'click', Settings["export"]);
|
|
$.on($('.import', dialog), 'click', Settings["import"]);
|
|
$.on($('.reset', dialog), 'click', Settings.reset);
|
|
$.on($('input', dialog), 'change', Settings.onImport);
|
|
links = [];
|
|
_ref = Settings.sections;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
section = _ref[_i];
|
|
link = $.el('a', {
|
|
className: "tab-" + section.hyphenatedTitle,
|
|
textContent: section.title,
|
|
href: 'javascript:;'
|
|
});
|
|
$.on(link, 'click', Settings.openSection.bind(section));
|
|
links.push(link);
|
|
if (section.title === openSection) {
|
|
sectionToOpen = link;
|
|
}
|
|
}
|
|
$.add($('.sections-list', dialog), links);
|
|
(sectionToOpen ? sectionToOpen : links[0]).click();
|
|
$.on($('.close', dialog), 'click', Settings.close);
|
|
$.on(overlay, 'click', Settings.close);
|
|
$.add(d.body, [overlay, dialog]);
|
|
return $.event('OpenSettings', null, dialog);
|
|
},
|
|
close: function() {
|
|
if (!Settings.dialog) {
|
|
return;
|
|
}
|
|
$.rm(Settings.overlay);
|
|
$.rm(Settings.dialog);
|
|
delete Settings.overlay;
|
|
return delete Settings.dialog;
|
|
},
|
|
sections: [],
|
|
addSection: function(title, open) {
|
|
var hyphenatedTitle, _ref;
|
|
if (typeof title !== 'string') {
|
|
_ref = title.detail, title = _ref.title, open = _ref.open;
|
|
}
|
|
hyphenatedTitle = title.toLowerCase().replace(/\s+/g, '-');
|
|
return Settings.sections.push({
|
|
title: title,
|
|
hyphenatedTitle: hyphenatedTitle,
|
|
open: open
|
|
});
|
|
},
|
|
openSection: function(mode) {
|
|
var section, selected;
|
|
if (selected = $('.tab-selected', Settings.dialog)) {
|
|
$.rmClass(selected, 'tab-selected');
|
|
}
|
|
$.addClass($(".tab-" + this.hyphenatedTitle, Settings.dialog), 'tab-selected');
|
|
section = $('section', Settings.dialog);
|
|
$.rmAll(section);
|
|
section.className = "section-" + this.hyphenatedTitle;
|
|
this.open(section, mode);
|
|
section.scrollTop = 0;
|
|
return $.event('OpenSettings', null, section);
|
|
},
|
|
main: function(section) {
|
|
var arr, button, description, div, fs, input, inputs, items, key, obj, _ref;
|
|
items = {};
|
|
inputs = {};
|
|
_ref = Config.main;
|
|
for (key in _ref) {
|
|
obj = _ref[key];
|
|
fs = $.el('fieldset', {
|
|
innerHTML: "<legend>" + key + "</legend>"
|
|
});
|
|
for (key in obj) {
|
|
arr = obj[key];
|
|
description = arr[1];
|
|
div = $.el('div', {
|
|
innerHTML: "<label><input type=checkbox name='" + key + "'>" + key + "</label><span class=description>" + description + "</span>"
|
|
});
|
|
input = $('input', div);
|
|
$.on($('label', div), 'mouseover', Settings.mouseover);
|
|
$.on(input, 'change', $.cb.checked);
|
|
items[key] = Conf[key];
|
|
inputs[key] = input;
|
|
$.add(fs, div);
|
|
}
|
|
Rice.nodes(fs);
|
|
$.add(section, fs);
|
|
}
|
|
$.get(items, function(items) {
|
|
var val;
|
|
for (key in items) {
|
|
val = items[key];
|
|
inputs[key].checked = val;
|
|
}
|
|
});
|
|
div = $.el('div', {
|
|
innerHTML: "<button></button><span class=description>: Clear manually-hidden threads and posts on all boards. Reload the page to apply."
|
|
});
|
|
button = $('button', div);
|
|
$.get('hiddenPosts', {}, function(_arg) {
|
|
var ID, board, hiddenNum, hiddenPosts, thread, _ref1;
|
|
hiddenPosts = _arg.hiddenPosts;
|
|
hiddenNum = 0;
|
|
_ref1 = hiddenPosts.boards;
|
|
for (ID in _ref1) {
|
|
board = _ref1[ID];
|
|
for (ID in board) {
|
|
thread = board[ID];
|
|
hiddenNum += Object.keys(thread).length;
|
|
}
|
|
}
|
|
return button.textContent = "Hidden: " + hiddenNum;
|
|
});
|
|
$.on(button, 'click', function() {
|
|
this.textContent = 'Hidden: 0';
|
|
return $["delete"]('hiddenPosts');
|
|
});
|
|
return $.after($('input[name="Recursive Hiding"]', section).parentNode.parentNode, div);
|
|
},
|
|
"export": function() {
|
|
return $.get(Conf, function(Conf) {
|
|
delete Conf['archives'];
|
|
return Settings.downloadExport('Settings', {
|
|
version: g.VERSION,
|
|
date: Date.now(),
|
|
Conf: Conf
|
|
});
|
|
});
|
|
},
|
|
downloadExport: function(title, data) {
|
|
var a;
|
|
a = $.el('a', {
|
|
download: "appchan x v" + g.VERSION + " " + title + "." + data.date + ".json",
|
|
href: "data:application/json;base64," + (btoa(unescape(encodeURIComponent(JSON.stringify(data, null, 2)))))
|
|
});
|
|
$.add(d.body, a);
|
|
a.click();
|
|
return $.rm(a);
|
|
},
|
|
"import": function() {
|
|
return $('input[type=file]', this.parentNode).click();
|
|
},
|
|
onImport: function() {
|
|
var file, reader;
|
|
if (!(file = this.files[0])) {
|
|
return;
|
|
}
|
|
if (!confirm('Your current settings will be entirely overwritten, are you sure?')) {
|
|
return;
|
|
}
|
|
reader = new FileReader();
|
|
reader.onload = function(e) {
|
|
var err;
|
|
try {
|
|
Settings.loadSettings(JSON.parse(e.target.result));
|
|
} catch (_error) {
|
|
err = _error;
|
|
alert('Import failed due to an error.');
|
|
c.error(err.stack);
|
|
return;
|
|
}
|
|
if (confirm('Import successful. Reload now?')) {
|
|
return window.location.reload();
|
|
}
|
|
};
|
|
return reader.readAsText(file);
|
|
},
|
|
loadSettings: function(data) {
|
|
if (data.Conf['WatchedThreads']) {
|
|
data.Conf['watchedThreads'] = {
|
|
boards: ThreadWatcher.convert(data.Conf['WatchedThreads'])
|
|
};
|
|
delete data.Conf['WatchedThreads'];
|
|
}
|
|
return $.clear(function() {
|
|
return $.set(data.Conf);
|
|
});
|
|
},
|
|
reset: function() {
|
|
if (confirm('Your current settings will be entirely wiped, are you sure?')) {
|
|
return $.clear(function() {
|
|
if (confirm('Reset successful. Reload now?')) {
|
|
return window.location.reload();
|
|
}
|
|
});
|
|
}
|
|
},
|
|
filter: function(section) {
|
|
var select;
|
|
section.innerHTML = "<select name=filter><option value=guide>Guide</option><option value=name>Name</option><option value=uniqueID>Unique ID</option><option value=tripcode>Tripcode</option><option value=capcode>Capcode</option><option value=email>E-mail</option><option value=subject>Subject</option><option value=comment>Comment</option><option value=flag>Flag</option><option value=filename>Filename</option><option value=dimensions>Image dimensions</option><option value=filesize>Filesize</option><option value=MD5>Image MD5</option></select><div></div>";
|
|
select = $('select', section);
|
|
$.on(select, 'change', Settings.selectFilter);
|
|
return Settings.selectFilter.call(select);
|
|
},
|
|
selectFilter: function() {
|
|
var div, name, ta;
|
|
div = this.nextElementSibling;
|
|
if ((name = this.value) !== 'guide') {
|
|
$.rmAll(div);
|
|
ta = $.el('textarea', {
|
|
name: name,
|
|
className: 'field',
|
|
spellcheck: false
|
|
});
|
|
$.get(name, Conf[name], function(item) {
|
|
return ta.value = item[name];
|
|
});
|
|
$.on(ta, 'change', $.cb.value);
|
|
$.add(div, ta);
|
|
return;
|
|
}
|
|
return div.innerHTML = "<div class=warning " + (Conf['Filter'] ? 'hidden' : '') + "><code>Filter</code> is disabled.</div><p>Use <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions\">regular expressions</a>, one per line.<br>Lines starting with a <code>#</code> will be ignored.<br>For example, <code>/weeaboo/i</code> will filter posts containing the string `<code>weeaboo</code>`, case-insensitive.<br>MD5 filtering uses exact string matching, not regular expressions.</p><ul>You can use these settings with each regular expression, separate them with semicolons:<li>Per boards, separate them with commas. It is global if not specified.<br>For example: <code>boards:a,jp;</code>.</li><li>Filter OPs only along with their threads (`only`), replies only (`no`), or both (`yes`, this is default).<br>For example: <code>op:only;</code>, <code>op:no;</code> or <code>op:yes;</code>.</li><li>Overrule the `Show Stubs` setting if specified: create a stub (`yes`) or not (`no`).<br>For example: <code>stub:yes;</code> or <code>stub:no;</code>.</li><li>Highlight instead of hiding. You can specify a class name to use with a userstyle.<br>For example: <code>highlight;</code> or <code>highlight:wallpaper;</code>.</li><li>Highlighted OPs will have their threads put on top of the board index by default.<br>For example: <code>top:yes;</code> or <code>top:no;</code>.</li></ul>";
|
|
},
|
|
sauce: function(section) {
|
|
var ta;
|
|
section.innerHTML = "<div class=warning " + (Conf['Sauce'] ? 'hidden' : '') + "><code>Sauce</code> is disabled.</div><div>Lines starting with a <code>#</code> will be ignored.</div><div>You can specify a display text by appending <code>;text:[text]</code> to the URL.</div><ul>These parameters will be replaced by their corresponding values:<li><code>%TURL</code>: Thumbnail URL.</li><li><code>%URL</code>: Full image URL.</li><li><code>%MD5</code>: MD5 hash.</li><li><code>%name</code>: Original file name.</li><li><code>%board</code>: Current board.</li></ul><textarea name=sauces class=field spellcheck=false></textarea>";
|
|
ta = $('textarea', section);
|
|
$.get('sauces', Conf['sauces'], function(item) {
|
|
return ta.value = item['sauces'].replace(/\$\d/g, function(c) {
|
|
switch (c) {
|
|
case '$1':
|
|
return '%TURL';
|
|
case '$2':
|
|
return '%URL';
|
|
case '$3':
|
|
return '%MD5';
|
|
case '$4':
|
|
return '%board';
|
|
default:
|
|
return c;
|
|
}
|
|
});
|
|
});
|
|
return $.on(ta, 'change', $.cb.value);
|
|
},
|
|
advanced: function(section) {
|
|
var archBoards, boardID, boardOptions, boardSelect, boards, data, event, files, input, inputs, item, items, name, o, row, rows, ta, table, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _ref, _ref1, _ref2, _ref3, _ref4;
|
|
section.innerHTML = "<fieldset><legend>Archiver</legend><div class=\"warning\" " + (Conf['404 Redirect'] ? 'hidden' : '') + "><code>404 Redirect</code> is disabled.</div><div><select id='archive-board-select'></select></div><table id='archive-table'><thead><th>Thread redirection</th><th>Post fetching</th><th>File redirection</th></thead><tbody></tbody></table><span class=note>Disabled selections indicate that only one archive is available for that board and redirection type.</span></fieldset><fieldset><legend>Custom Board Navigation</legend><div><textarea name=boardnav class=field spellcheck=false></textarea></div><span class=note>New lines will be converted into spaces.</span><br><br><div class=note>In the following examples for /g/, <code>g</code> can be changed to a different board ID (<code>a</code>, <code>b</code>, etc...), the current board (<code>current</code>), or the Twitter link (<code>@</code>).</div><div>Board link: <code>g</code></div><div>Title link: <code>g-title</code></div><div>Board link (Replace with title when on that board): <code>g-replace</code></div><div>Full text link: <code>g-full</code></div><div>Custom text link: <code>g-text:\"Install Gentoo\"</code></div><div>External link: <code>external-text:\"Google\",\"http://www.google.com\"</code></div><div>Index mode: <code>g-mode:\"type\"</code> where type is <code>paged</code>, <code>all threads</code> or <code>catalog</code></div><div>Index sort: <code>g-sort:\"type\"</code> where type is <code>bump order</code>, <code>last reply</code>, <code>creation date</code>, <code>reply count</code> or <code>file count</code></div<div>Combinations are possible: <code>g-text:\"VIP Catalog\"-mode:\"catalog\"-sort:\"creation date\"</code></div><div>Full board list toggle: <code>toggle-all</code></div><br><div class=note><code>[ toggle-all ] [current-title] [g-title / a-title / jp-title] [x / wsg / h-mode:\"catalog\"-sort:\"file count\"] [t-text:\"Piracy\"]</code><br>will give you<br><code>[ + ] [Technology] [Technology / Anime & Manga / Otaku Culture] [x / wsg / h] [Piracy]</code><br>if you are on /g/.</div></fieldset><fieldset><legend>Time Formatting <span class=warning " + (Conf['Time Formatting'] ? 'hidden' : '') + ">is disabled.</span></legend><div><input name=time class=field spellcheck=false>: <span class=time-preview></span></div><div>Supported <a href=//en.wikipedia.org/wiki/Date_%28Unix%29#Formatting>format specifiers</a>:</div><div>Day: <code>%a</code>, <code>%A</code>, <code>%d</code>, <code>%e</code></div><div>Month: <code>%m</code>, <code>%b</code>, <code>%B</code></div><div>Year: <code>%y</code>, <code>%Y</code></div><div>Hour: <code>%k</code>, <code>%H</code>, <code>%l</code>, <code>%I</code>, <code>%p</code>, <code>%P</code></div><div>Minute: <code>%M</code></div><div>Second: <code>%S</code></div></fieldset><fieldset><legend>Quote Backlinks formatting <span class=warning " + (Conf['Quote Backlinks'] ? 'hidden' : '') + ">is disabled.</span></legend><div><input name=backlink class=field spellcheck=false>: <span class=backlink-preview></span></div></fieldset><fieldset><legend>File Info Formatting <span class=warning " + (Conf['File Info Formatting'] ? 'hidden' : '') + ">is disabled.</span></legend><div><input name=fileInfo class=field spellcheck=false>: <span class='fileText file-info-preview'></span></div><div>Link: <code>%l</code> (truncated), <code>%L</code> (untruncated), <code>%T</code> (Unix timestamp)</div><div>Original file name: <code>%n</code> (truncated), <code>%N</code> (untruncated), <code>%t</code> (Unix timestamp)</div><div>Spoiler indicator: <code>%p</code></div><div>Size: <code>%B</code> (Bytes), <code>%K</code> (KB), <code>%M</code> (MB), <code>%s</code> (4chan default)</div><div>Resolution: <code>%r</code> (Displays 'PDF' for PDF files)</div></fieldset><fieldset><legend>Quick Reply Personas</legend><textarea class=personafield name=\"QR.personas\" class=\"field\" spellcheck=\"false\"></textarea><p>One item per line.<br>Items will be added in the relevant input's auto-completion list.<br>Password items will always be used, since there is no password input.<br>Lines starting with a <code>#</code> will be ignored.</p><ul>You can use these settings with each item, separate them with semicolons:<li>Possible items are: <code>name</code>, <code>email</code>, <code>subject</code> and <code>password</code>.</li><li>Wrap values of items with quotes, like this: <code>email:\"sage\"</code>.</li><li>Force values as defaults with the <code>always</code> keyword, for example: <code>email:\"sage\";always</code>.</li><li>Select specific boards for an item, separated with commas, for example: <code>email:\"sage\";boards:jp;always</code>.</li></ul></fieldset><fieldset><legend>Unread Favicon <span class=warning " + (Conf['Unread Favicon'] ? 'hidden' : '') + ">is disabled.</span></legend><select name=favicon><option value=ferongr>ferongr</option><option value=xat->xat-</option><option value=Mayhem>Mayhem</option><option value=4chanJS>4chanJS</option><option value=Original>Original</option><option value=Metro>Metro</option></select><span id=favicon-preview></span></fieldset><fieldset><legend>Emoji <span class=warning " + (Conf['Emoji'] ? 'hidden' : '') + ">is disabled.</span></legend><div>Sage Icon: <select name=sageEmoji><option value=\"4chan SS\">4chan SS</option><option value=\"appchan\">appchan</option></select><span class=sage-icon-preview></span></div><fieldset><legend>Thread Updater <span class=warning " + (Conf['Thread Updater'] ? 'hidden' : '') + ">is disabled.</span></legend><div>Interval: <input type=number name=Interval class=field min=1 value=" + Conf['Interval'] + "></div></fieldset><fieldset><legend><input type=checkbox name='Custom CSS' " + (Conf['Custom CSS'] ? 'checked' : '') + "> Custom CSS</legend><div><button id=apply-css>Apply CSS</button><textarea name=usercss class=field spellcheck=false " + (Conf['Custom CSS'] ? '' : 'disabled') + "></textarea></div></fieldset>";
|
|
items = {};
|
|
inputs = {};
|
|
_ref = ['boardnav', 'time', 'backlink', 'fileInfo', 'favicon', 'usercss'];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
name = _ref[_i];
|
|
input = $("[name='" + name + "']", section);
|
|
items[name] = Conf[name];
|
|
inputs[name] = input;
|
|
event = name === 'favicon' || name === 'usercss' ? 'change' : 'input';
|
|
$.on(input, event, $.cb.value);
|
|
}
|
|
ta = $('.personafield', section);
|
|
$.get('QR.personas', Conf['QR.personas'], function(item) {
|
|
return ta.value = item['QR.personas'];
|
|
});
|
|
$.on(ta, 'change', $.cb.value);
|
|
$.get(items, function(items) {
|
|
var key, val;
|
|
for (key in items) {
|
|
val = items[key];
|
|
input = inputs[key];
|
|
input.value = val;
|
|
if (key === 'usercss') {
|
|
continue;
|
|
}
|
|
$.on(input, event, Settings[key]);
|
|
Settings[key].call(input);
|
|
}
|
|
return Rice.nodes(section);
|
|
});
|
|
$.on($('input[name=Interval]', section), 'change', ThreadUpdater.cb.interval);
|
|
$.on($('input[name="Custom CSS"]', section), 'change', Settings.togglecss);
|
|
$.on($.id('apply-css'), 'click', Settings.usercss);
|
|
archBoards = {};
|
|
_ref1 = Redirect.archives;
|
|
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
|
_ref2 = _ref1[_j], name = _ref2.name, boards = _ref2.boards, files = _ref2.files, data = _ref2.data;
|
|
for (_k = 0, _len2 = boards.length; _k < _len2; _k++) {
|
|
boardID = boards[_k];
|
|
o = archBoards[boardID] || (archBoards[boardID] = {
|
|
thread: [],
|
|
post: [],
|
|
file: []
|
|
});
|
|
o.thread.push(name);
|
|
if (data.software === 'foolfuuka') {
|
|
o.post.push(name);
|
|
}
|
|
if (__indexOf.call(files, boardID) >= 0) {
|
|
o.file.push(name);
|
|
}
|
|
}
|
|
}
|
|
rows = [];
|
|
boardOptions = [];
|
|
_ref3 = Object.keys(archBoards).sort();
|
|
for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) {
|
|
boardID = _ref3[_l];
|
|
row = $.el('tr', {
|
|
className: "board-" + boardID
|
|
});
|
|
row.hidden = boardID !== g.BOARD.ID;
|
|
boardOptions.push($.el('option', {
|
|
textContent: "/" + boardID + "/",
|
|
value: "board-" + boardID,
|
|
selected: boardID === g.BOARD.ID
|
|
}));
|
|
o = archBoards[boardID];
|
|
_ref4 = ['thread', 'post', 'file'];
|
|
for (_m = 0, _len4 = _ref4.length; _m < _len4; _m++) {
|
|
item = _ref4[_m];
|
|
$.add(row, Settings.addArchiveCell(boardID, o, item));
|
|
}
|
|
rows.push(row);
|
|
}
|
|
$.add($('tbody', section), rows);
|
|
boardSelect = $('#archive-board-select', section);
|
|
$.add(boardSelect, boardOptions);
|
|
table = $.id('archive-table');
|
|
$.on(boardSelect, 'change', function() {
|
|
$('tbody > :not([hidden])', table).hidden = true;
|
|
return $("tbody > ." + this.value, table).hidden = false;
|
|
});
|
|
$.get('selectedArchives', Conf['selectedArchives'], function(_arg) {
|
|
var option, selectedArchives, type;
|
|
selectedArchives = _arg.selectedArchives;
|
|
for (boardID in selectedArchives) {
|
|
data = selectedArchives[boardID];
|
|
for (type in data) {
|
|
name = data[type];
|
|
if (option = $("select[data-boardid='" + boardID + "'][data-type='" + type + "'] > option[value='" + name + "']", section)) {
|
|
option.selected = true;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
},
|
|
addArchiveCell: function(boardID, data, type) {
|
|
var archive, i, length, options, select, td;
|
|
length = data[type].length;
|
|
td = $.el('td', {
|
|
className: 'archive-cell'
|
|
});
|
|
if (!length) {
|
|
td.textContent = '--';
|
|
return td;
|
|
}
|
|
options = [];
|
|
i = 0;
|
|
while (i < length) {
|
|
archive = data[type][i++];
|
|
options.push($.el('option', {
|
|
textContent: archive,
|
|
value: archive
|
|
}));
|
|
}
|
|
td.innerHTML = '<select></select>';
|
|
select = td.firstElementChild;
|
|
if (!(select.disabled = length === 1)) {
|
|
select.setAttribute('data-boardid', boardID);
|
|
select.setAttribute('data-type', type);
|
|
$.on(select, 'change', Settings.saveSelectedArchive);
|
|
}
|
|
$.add(select, options);
|
|
return td;
|
|
},
|
|
saveSelectedArchive: function() {
|
|
return $.get('selectedArchives', Conf['selectedArchives'], (function(_this) {
|
|
return function(_arg) {
|
|
var selectedArchives, _name;
|
|
selectedArchives = _arg.selectedArchives;
|
|
(selectedArchives[_name = _this.dataset.boardid] || (selectedArchives[_name] = {}))[_this.dataset.type] = _this.value;
|
|
return $.set('selectedArchives', selectedArchives);
|
|
};
|
|
})(this));
|
|
},
|
|
boardnav: function() {
|
|
return Header.generateBoardList(this.value);
|
|
},
|
|
time: function() {
|
|
var funk;
|
|
funk = Time.createFunc(this.value);
|
|
return this.nextElementSibling.textContent = funk(Time, new Date());
|
|
},
|
|
backlink: function() {
|
|
return this.nextElementSibling.textContent = this.value.replace(/%id/, '123456789');
|
|
},
|
|
fileInfo: function() {
|
|
var data, funk;
|
|
data = {
|
|
isReply: true,
|
|
file: {
|
|
URL: '//i.4cdn.org/g/src/1334437723720.jpg',
|
|
name: 'd9bb2efc98dd0df141a94399ff5880b7.jpg',
|
|
size: '276 KB',
|
|
sizeInBytes: 276 * 1024,
|
|
dimensions: '1280x720',
|
|
isImage: true,
|
|
isSpoiler: true
|
|
}
|
|
};
|
|
funk = FileInfo.createFunc(this.value);
|
|
return this.nextElementSibling.innerHTML = funk(FileInfo, data);
|
|
},
|
|
favicon: function() {
|
|
Favicon.init();
|
|
if (g.VIEW === 'thread' && Conf['Unread Favicon']) {
|
|
Unread.update();
|
|
}
|
|
return $.id('favicon-preview').innerHTML = "<img src=" + Favicon["default"] + ">\n<img src=" + Favicon.unreadSFW + ">\n<img src=" + Favicon.unreadNSFW + ">\n<img src=" + Favicon.unreadDead + ">";
|
|
},
|
|
togglecss: function() {
|
|
if ($('textarea', this.parentNode.parentNode).disabled = !this.checked) {
|
|
CustomCSS.rmStyle();
|
|
} else {
|
|
CustomCSS.addStyle();
|
|
}
|
|
return $.cb.checked.call(this);
|
|
},
|
|
usercss: function() {
|
|
return CustomCSS.update();
|
|
},
|
|
keybinds: function(section) {
|
|
var arr, input, inputs, items, key, tbody, tr, _ref;
|
|
section.innerHTML = "<div class=warning " + (Conf['Keybinds'] ? 'hidden' : '') + "><code>Keybinds</code> are disabled.</div><div>Allowed keys: <kbd>a-z</kbd>, <kbd>0-9</kbd>, <kbd>Ctrl</kbd>, <kbd>Shift</kbd>, <kbd>Alt</kbd>, <kbd>Meta</kbd>, <kbd>Enter</kbd>, <kbd>Esc</kbd>, <kbd>Up</kbd>, <kbd>Down</kbd>, <kbd>Right</kbd>, <kbd>Left</kbd>.</div><div>Press <kbd>Backspace</kbd> to disable a keybind.</div><table><tbody><tr><th>Actions</th><th>Keybinds</th></tr></tbody></table>";
|
|
tbody = $('tbody', section);
|
|
items = {};
|
|
inputs = {};
|
|
_ref = Config.hotkeys;
|
|
for (key in _ref) {
|
|
arr = _ref[key];
|
|
tr = $.el('tr', {
|
|
innerHTML: "<td>" + arr[1] + "</td><td><input class=field></td>"
|
|
});
|
|
input = $('input', tr);
|
|
input.name = key;
|
|
input.spellcheck = false;
|
|
items[key] = Conf[key];
|
|
inputs[key] = input;
|
|
$.on(input, 'keydown', Settings.keybind);
|
|
Rice.nodes(tr);
|
|
$.add(tbody, tr);
|
|
}
|
|
return $.get(items, function(items) {
|
|
var val;
|
|
for (key in items) {
|
|
val = items[key];
|
|
inputs[key].value = val;
|
|
}
|
|
});
|
|
},
|
|
keybind: function(e) {
|
|
var key;
|
|
if (e.keyCode === 9) {
|
|
return;
|
|
}
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
if ((key = Keybinds.keyCode(e)) == null) {
|
|
return;
|
|
}
|
|
this.value = key;
|
|
return $.cb.value.call(this);
|
|
},
|
|
style: function(section) {
|
|
var arr, description, div, fs, html, input, inputs, items, key, name, nodes, obj, type, value, _i, _len, _ref;
|
|
nodes = $.frag();
|
|
items = {};
|
|
inputs = {};
|
|
_ref = Config.style;
|
|
for (key in _ref) {
|
|
obj = _ref[key];
|
|
fs = $.el('fieldset', {
|
|
innerHTML: "<legend>" + key + "</legend>"
|
|
});
|
|
for (key in obj) {
|
|
arr = obj[key];
|
|
value = arr[0], description = arr[1], type = arr[2];
|
|
div = $.el('div', {
|
|
className: 'styleoption'
|
|
});
|
|
if (type) {
|
|
if (type === 'text') {
|
|
div.innerHTML = "<div class=option><span class=optionlabel>" + key + "</span></div><div class=description>" + description + "</div><div class=option><input name='" + key + "' style=width: 100%></div>";
|
|
input = $("input", div);
|
|
} else {
|
|
html = "<div class=option><span class=optionlabel>" + key + "</span></div><div class=description>" + description + "</div><div class=option><select name='" + key + "'>";
|
|
for (_i = 0, _len = type.length; _i < _len; _i++) {
|
|
name = type[_i];
|
|
html += "<option value='" + name + "'>" + name + "</option>";
|
|
}
|
|
html += "</select></div>";
|
|
div.innerHTML = html;
|
|
input = $("select", div);
|
|
}
|
|
} else {
|
|
div.innerHTML = "<div class=option><label><input type=checkbox name='" + key + "'>" + key + "</label></div><span style='display:none;'>" + description + "</span>";
|
|
input = $('input', div);
|
|
}
|
|
items[key] = Conf[key];
|
|
inputs[key] = input;
|
|
$.on($('.option', div), 'mouseover', Settings.mouseover);
|
|
$.add(fs, div);
|
|
}
|
|
$.add(nodes, fs);
|
|
}
|
|
return $.get(items, function(items) {
|
|
var cb, val;
|
|
cb = Settings.cb.style;
|
|
for (key in items) {
|
|
val = items[key];
|
|
input = inputs[key];
|
|
if (input.type === 'checkbox') {
|
|
input.checked = val;
|
|
$.on(input, 'change', cb.checked);
|
|
} else if (input.nodeName === 'SELECT') {
|
|
input.value = val;
|
|
$.on(input, 'change', cb.select);
|
|
} else {
|
|
input.value = val;
|
|
$.on(input, 'change', cb.value);
|
|
}
|
|
}
|
|
Rice.nodes(nodes);
|
|
return $.add(section, nodes);
|
|
});
|
|
},
|
|
themes: function(section, mode) {
|
|
var a, cb, div, keys, mouseout, mouseover, name, parentdiv, suboptions, theme, _i, _j, _k, _len, _len1, _len2, _ref;
|
|
if (typeof mode !== 'string') {
|
|
mode = 'default';
|
|
}
|
|
parentdiv = $.el('div', {
|
|
id: "themeContainer"
|
|
});
|
|
suboptions = $.el('div', {
|
|
className: "suboptions",
|
|
id: "themes"
|
|
});
|
|
keys = Object.keys(Themes);
|
|
keys.sort();
|
|
cb = Settings.cb.theme;
|
|
mouseover = function() {
|
|
return this.style.color = "" + this.dataset.hover;
|
|
};
|
|
mouseout = function() {
|
|
return this.style.color = "" + this.dataset.color;
|
|
};
|
|
if (mode === "default") {
|
|
for (_i = 0, _len = keys.length; _i < _len; _i++) {
|
|
name = keys[_i];
|
|
theme = Themes[name];
|
|
if (theme["Deleted"]) {
|
|
continue;
|
|
}
|
|
div = $.el('div', {
|
|
className: "theme " + (name === Conf[g.THEMESTRING] ? 'selectedtheme' : ''),
|
|
id: name,
|
|
innerHTML: "<div style='cursor: pointer; position: relative; margin-bottom: 2px; width: 100% ; box-shadow: none ; background:" + theme['Reply Background'] + ";border:1px solid " + theme['Reply Border'] + ";color:" + theme['Text'] + "'><div><div style='cursor: pointer; width: 9px; height: 9px; margin: 2px 3px; display: inline-block; vertical-align: bottom; background: " + theme['Checkbox Background'] + "; border: 1px solid " + theme['Checkbox Border'] + ";'></div><span style='color:" + theme['Subjects'] + "; font-weight: 600 '>\n " + name + "\n </span><span style='color:" + theme['Names'] + "; font-weight: 600 '>\n " + theme['Author'] + "\n </span><span style='color:" + theme['Sage'] + "'>\n (SAGE)\n </span><span style='color:" + theme['Tripcodes'] + "'>\n " + theme['Author Tripcode'] + "\n </span><time style='color:" + theme['Timestamps'] + "'>\n 20XX.01.01 12:00\n </time><a data-color='" + theme['Post Numbers'] + "' data-hover='" + theme['Hovered Links'] + "'>\n No.27583594\n </a><a data-color='" + theme['Backlinks'] + "' data-hover='" + theme['Hovered Links'] + "' name='" + name + "' class=edit>\n >>edit\n </a><a data-color='" + theme['Backlinks'] + "' data-hover='" + theme['Hovered Links'] + "' name='" + name + "' class=export>\n >>export\n </a><a data-color='" + theme['Backlinks'] + "' data-hover='" + theme['Hovered Links'] + "' name='" + name + "' class=delete>\n >>delete\n </a></div><blockquote style='margin: 0; padding: 12px 40px 12px 38px'><a data-color='" + theme['Quotelinks'] + "' data-hover='" + theme['Hovered Links'] + "' style='text-shadow: none;'>\n >>27582902\n </a><br>\n Post content is right here.\n</blockquote><h1 style='color: " + theme['Text'] + "'>\n Selected\n</h1></div>"
|
|
});
|
|
div.style.backgroundColor = theme['Background Color'];
|
|
_ref = $$('a[data-color]', div);
|
|
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
|
|
a = _ref[_j];
|
|
a.style.color = "" + a.dataset.color;
|
|
$.on(a, 'mouseover', mouseover);
|
|
$.on(a, 'mouseout', mouseout);
|
|
}
|
|
$.on($('a.edit', div), 'click', cb.edit);
|
|
$.on($('a.export', div), 'click', cb["export"]);
|
|
$.on($('a.delete', div), 'click', cb["delete"]);
|
|
$.on(div, 'click', cb.select);
|
|
$.add(suboptions, div);
|
|
}
|
|
div = $.el('div', {
|
|
id: 'addthemes',
|
|
innerHTML: "<a id=newtheme href='javascript:;'>New Theme</a>\n/\n<a id=import href='javascript:;' title='From Appchan X, Oneechan, or 4chan SS'>Import Theme</a><input id=importbutton type=file hidden>\n/\n<a id=tUndelete href='javascript:;'>Undelete Theme</a>"
|
|
});
|
|
$.on($("#newtheme", div), 'click', function() {
|
|
ThemeTools.init("untitled");
|
|
return Settings.close();
|
|
});
|
|
$.on($("#import", div), 'click', function() {
|
|
return this.nextSibling.click();
|
|
});
|
|
$.on($("#importbutton", div), 'change', ThemeTools.importtheme);
|
|
$.on($('#tUndelete', div), 'click', function() {
|
|
var themes;
|
|
$.rm($.id("themeContainer"));
|
|
themes = {
|
|
open: Settings.themes,
|
|
hyphenatedTitle: 'themes'
|
|
};
|
|
return Settings.openSection.apply(themes, ['undelete']);
|
|
});
|
|
} else {
|
|
for (_k = 0, _len2 = keys.length; _k < _len2; _k++) {
|
|
name = keys[_k];
|
|
theme = Themes[name];
|
|
if (!theme["Deleted"]) {
|
|
continue;
|
|
}
|
|
div = $.el('div', {
|
|
id: name,
|
|
className: theme,
|
|
innerHTML: "<div style='cursor: pointer; position: relative; margin-bottom: 2px; width: 100% ; box-shadow: none ; background:" + theme['Reply Background'] + ";border:1px solid " + theme['Reply Border'] + ";color:" + theme['Text'] + "'><div style='padding: 3px 0px 0px 8px;'><span style='color:" + theme['Subjects'] + "; font-weight: 600 '>\n " + name + "\n </span><span style='color:" + theme['Names'] + "; font-weight: 600 '>\n " + theme['Author'] + "\n </span><span style='color:" + theme['Sage'] + "'>\n (SAGE)\n </span><span style='color:" + theme['Tripcodes'] + "'>\n " + theme['Author Tripcode'] + "\n </span><time style='color:" + theme['Timestamps'] + "'>\n 20XX.01.01 12:00\n </time><a data-color='" + theme['Post Numbers'] + "' data-hover='" + theme['Hovered Links'] + "'>\n No.27583594\n </a></div><blockquote style='margin: 0; padding: 12px 40px 12px 38px'><a data-color='" + theme['Quotelinks'] + "' data-hover='" + theme['Hovered Links'] + "' style='text-shadow: none;'>\n >>27582902\n </a><br>\n I forgive you for using VLC to open me. ;__;\n</blockquote></div>"
|
|
});
|
|
$.on(div, 'click', cb.restore);
|
|
$.add(suboptions, div);
|
|
}
|
|
div = $.el('div', {
|
|
id: 'addthemes',
|
|
innerHTML: "<a href='javascript:;'>Return</a>"
|
|
});
|
|
$.on($('a', div), 'click', function() {
|
|
var themes;
|
|
themes = {
|
|
open: Settings.themes,
|
|
hyphenatedTitle: 'themes'
|
|
};
|
|
$.rm($.id("themeContainer"));
|
|
return Settings.openSection.call(themes);
|
|
});
|
|
}
|
|
$.add(parentdiv, suboptions);
|
|
$.add(parentdiv, div);
|
|
return $.add(section, parentdiv);
|
|
},
|
|
mouseover: function(e) {
|
|
var mouseover;
|
|
mouseover = $.el('div', {
|
|
id: 'mouseover',
|
|
className: 'dialog'
|
|
});
|
|
$.add(Header.hover, mouseover);
|
|
mouseover.innerHTML = this.nextElementSibling.innerHTML;
|
|
UI.hover({
|
|
root: this,
|
|
el: mouseover,
|
|
latestEvent: e,
|
|
endEvents: 'mouseout',
|
|
asapTest: function() {
|
|
return true;
|
|
},
|
|
offsetX: 15,
|
|
offsetY: -5
|
|
});
|
|
},
|
|
mascots: function(section, mode) {
|
|
var addoptions, batchmascots, categories, cb, container, div, keys, mascot, mascotEl, mascotHide, mascotoptions, menu, name, node, option, suboptions, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1;
|
|
categories = {};
|
|
cb = Settings.cb.mascot;
|
|
if (typeof mode !== 'string') {
|
|
mode = 'default';
|
|
}
|
|
suboptions = $.el("div", {
|
|
className: "suboptions"
|
|
});
|
|
mascotHide = $.el("div", {
|
|
id: "mascot_hide",
|
|
className: "reply",
|
|
innerHTML: "Hide Categories <span class=drop-marker></span><div></div>"
|
|
});
|
|
keys = Object.keys(Mascots);
|
|
keys.sort();
|
|
if (mode === 'default') {
|
|
mascotoptions = $.el('div', {
|
|
id: 'mascot-options',
|
|
innerHTML: "<a class=edit href='javascript:;'>Edit</a><a class=delete href='javascript:;'>Delete</a><a class=export href='javascript:;'>Export</a>"
|
|
});
|
|
$.on($('.edit', mascotoptions), 'click', cb.edit);
|
|
$.on($('.delete', mascotoptions), 'click', cb["delete"]);
|
|
$.on($('.export', mascotoptions), 'click', cb["export"]);
|
|
addoptions = function() {
|
|
if (mascotoptions.parentElement === this) {
|
|
return;
|
|
}
|
|
return $.add(this, mascotoptions);
|
|
};
|
|
_ref = MascotTools.categories;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
name = _ref[_i];
|
|
menu = $('div', mascotHide);
|
|
categories[name] = div = $.el("div", {
|
|
id: name,
|
|
className: "mascots-container",
|
|
innerHTML: "<h3 class=mascotHeader>" + name + "</h3>",
|
|
hidden: __indexOf.call(Conf["Hidden Categories"], name) >= 0
|
|
});
|
|
option = $.el("label", {
|
|
name: name,
|
|
innerHTML: "<input name='" + name + "' type=checkbox " + (__indexOf.call(Conf["Hidden Categories"], name) >= 0 ? 'checked' : '') + ">" + name
|
|
});
|
|
$.on($('input', option), 'change', cb.category);
|
|
$.add(suboptions, div);
|
|
$.add(menu, option);
|
|
}
|
|
for (_j = 0, _len1 = keys.length; _j < _len1; _j++) {
|
|
name = keys[_j];
|
|
if (__indexOf.call(Conf["Deleted Mascots"], name) >= 0) {
|
|
continue;
|
|
}
|
|
mascot = Mascots[name];
|
|
mascotEl = $.el('div', {
|
|
id: name,
|
|
className: __indexOf.call(Conf[g.MASCOTSTRING], name) >= 0 ? 'mascot enabled' : 'mascot',
|
|
innerHTML: "<div class='mascotname'>" + (name.replace(/_/g, " ")) + "</div> <div class='mascotcontainer " + (mascot.silhouette ? 'silhouette' : '') + "'><div class='mAlign " + mascot.category + "'><img class=mascotimg src='" + mascot.image + "'></div></div>"
|
|
});
|
|
$.on(mascotEl, 'click', cb.select);
|
|
$.on(mascotEl, 'mouseover', addoptions);
|
|
$.add(categories[mascot.category] || categories[MascotTools.categories[0]], mascotEl);
|
|
}
|
|
batchmascots = $.el('div', {
|
|
id: "mascots_batch",
|
|
innerHTML: " <a href=\"javascript:;\" id=clear>Clear All</a>\n/\n<a href=\"javascript:;\" id=selectAll>Select All</a>\n/\n<a href=\"javascript:;\" id=createNew>Add Mascot</a>\n/\n<a href=\"javascript:;\" id=importMascot>Import Mascot</a><input id=importMascotButton type=file hidden>\n/\n<a href=\"javascript:;\" id=undelete>Undelete Mascots</a>\n/\n<a href=\"http://appchan.booru.org/\" target=_blank>Get More Mascots!</a>"
|
|
});
|
|
$.on($('#clear', batchmascots), 'click', function() {
|
|
var enabledMascots, _k, _len2;
|
|
enabledMascots = JSON.parse(JSON.stringify(Conf[g.MASCOTSTRING]));
|
|
for (_k = 0, _len2 = enabledMascots.length; _k < _len2; _k++) {
|
|
name = enabledMascots[_k];
|
|
$.rmClass($.id(name), 'enabled');
|
|
}
|
|
return $.set(g.MASCOTSTRING, Conf[g.MASCOTSTRING] = []);
|
|
});
|
|
$.on($('#selectAll', batchmascots), 'click', function() {
|
|
var _ref1;
|
|
for (name in Mascots) {
|
|
mascot = Mascots[name];
|
|
if (!((_ref1 = mascot.category, __indexOf.call(Conf["Hidden Categories"], _ref1) >= 0) || __indexOf.call(Conf[g.MASCOTSTRING], name) >= 0 || __indexOf.call(Conf["Deleted Mascots"], name) >= 0)) {
|
|
$.addClass($.id(name), 'enabled');
|
|
Conf[g.MASCOTSTRING].push(name);
|
|
}
|
|
}
|
|
return $.set(g.MASCOTSTRING, Conf[g.MASCOTSTRING]);
|
|
});
|
|
$.on($('#createNew', batchmascots), 'click', function() {
|
|
MascotTools.dialog();
|
|
return Settings.close();
|
|
});
|
|
$.on($("#importMascot", batchmascots), 'click', function() {
|
|
return this.nextSibling.click();
|
|
});
|
|
$.on($("#importMascotButton", batchmascots), 'change', MascotTools.importMascot);
|
|
$.on($('#undelete', batchmascots), 'click', function() {
|
|
var mascots;
|
|
if (!(Conf["Deleted Mascots"].length > 0)) {
|
|
alert("No mascots have been deleted.");
|
|
return;
|
|
}
|
|
mascots = {
|
|
open: Settings.mascots,
|
|
hyphenatedTitle: 'mascots'
|
|
};
|
|
return Settings.openSection.apply(mascots, ['restore']);
|
|
});
|
|
} else {
|
|
container = $.el("div", {
|
|
className: "mascots"
|
|
});
|
|
for (_k = 0, _len2 = keys.length; _k < _len2; _k++) {
|
|
name = keys[_k];
|
|
if (!(__indexOf.call(Conf["Deleted Mascots"], name) >= 0)) {
|
|
continue;
|
|
}
|
|
mascot = Mascots[name];
|
|
mascotEl = $.el('div', {
|
|
className: 'mascot',
|
|
id: name,
|
|
innerHTML: "<div class='mascotname'>" + (name.replace(/_/g, " ")) + "</span> <div class='mascotcontainer " + mascot.category + " " + (mascot.silhouette ? 'silhouette' : '') + "'><img class=mascotimg src='" + mascot.image + "'></div>"
|
|
});
|
|
$.on(mascotEl, 'click', cb.restore);
|
|
$.add(container, mascotEl);
|
|
}
|
|
$.add(suboptions, container);
|
|
batchmascots = $.el('div', {
|
|
id: "mascots_batch",
|
|
innerHTML: "<a href=\"javascript:;\" id=\"return\">Return</a>"
|
|
});
|
|
$.on($('#return', batchmascots), 'click', function() {
|
|
var mascots;
|
|
mascots = {
|
|
open: Settings.mascots,
|
|
hyphenatedTitle: 'mascots'
|
|
};
|
|
return Settings.openSection.apply(mascots);
|
|
});
|
|
}
|
|
_ref1 = [suboptions, batchmascots, mascotHide];
|
|
for (_l = 0, _len3 = _ref1.length; _l < _len3; _l++) {
|
|
node = _ref1[_l];
|
|
Rice.nodes(node);
|
|
}
|
|
return $.add(section, [suboptions, batchmascots, mascotHide]);
|
|
},
|
|
cb: {
|
|
style: {
|
|
checked: function() {
|
|
var hyphenated, _ref;
|
|
$.cb.checked.call(this);
|
|
if ((_ref = this.name) === 'NSFW/SFW Themes' || _ref === 'NSFW/SFW Mascots') {
|
|
return;
|
|
}
|
|
hyphenated = this.name.toLowerCase().replace(/^4/, 'four').replace(/\s+/g, '-');
|
|
return (this.checked ? $.addClass : $.rmClass)(doc, hyphenated);
|
|
},
|
|
value: function() {
|
|
$.cb.value.call(this);
|
|
return Style.sheets.dynamicCSS.textContent = Style.dynamic();
|
|
},
|
|
select: function() {
|
|
var hyphenated, option, _i, _len, _ref;
|
|
$.cb.value.call(this);
|
|
_ref = this.options;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
option = _ref[_i];
|
|
hyphenated = ("" + this.name + " " + option.value).toLowerCase().replace(/^4/, 'four').replace(/\s+/g, '-');
|
|
(option.value === this.value ? $.addClass : $.rmClass)(doc, hyphenated);
|
|
}
|
|
}
|
|
},
|
|
mascot: {
|
|
category: function() {
|
|
var cb, i, name, setting, type, _i, _len, _ref;
|
|
if ($.id(this.name).hidden = this.checked) {
|
|
Conf["Hidden Categories"].push(this.name);
|
|
_ref = ["Enabled Mascots", "Enabled Mascots sfw", "Enabled Mascots nsfw"];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
type = _ref[_i];
|
|
setting = Conf[type];
|
|
i = setting.length;
|
|
while (i--) {
|
|
name = setting[i];
|
|
if (Mascots[name].category !== this.name) {
|
|
continue;
|
|
}
|
|
setting.splice(i, 1);
|
|
if (type !== g.MASCOTSTRING) {
|
|
continue;
|
|
}
|
|
$.rmClass($.id(name), 'enabled');
|
|
if (Conf['mascot'] === name) {
|
|
cb = MascotTools.toggle;
|
|
}
|
|
}
|
|
$.set(type, setting);
|
|
}
|
|
} else {
|
|
$.remove(Conf["Hidden Categories"], this.name);
|
|
}
|
|
$.set("Hidden Categories", Conf["Hidden Categories"]);
|
|
if (cb) {
|
|
return cb();
|
|
}
|
|
},
|
|
edit: function(e) {
|
|
e.stopPropagation();
|
|
MascotTools.dialog(this.parentElement.parentElement.id);
|
|
return Settings.close();
|
|
},
|
|
"delete": function(e) {
|
|
var name, type, _i, _len, _ref;
|
|
e.stopPropagation();
|
|
name = this.parentElement.parentElement.id;
|
|
if (confirm("Are you sure you want to delete \"" + name + "\"?")) {
|
|
if (Conf['mascot'] === name) {
|
|
MascotTools.toggle();
|
|
}
|
|
_ref = ["Enabled Mascots", "Enabled Mascots sfw", "Enabled Mascots nsfw"];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
type = _ref[_i];
|
|
$.remove(Conf[type], name);
|
|
$.set(type, Conf[type]);
|
|
}
|
|
Conf["Deleted Mascots"].push(name);
|
|
$.set("Deleted Mascots", Conf["Deleted Mascots"]);
|
|
return $.rm($.id(name));
|
|
}
|
|
},
|
|
"export": function(e) {
|
|
var a, data, name;
|
|
e.stopPropagation();
|
|
name = this.parentElement.parentElement.id;
|
|
data = Mascots[name];
|
|
data['Mascot'] = name;
|
|
a = $.el('a', {
|
|
className: 'export-button',
|
|
textContent: 'Save me!',
|
|
download: "" + name + "-" + (Date.now()) + ".json",
|
|
href: "data:application/json;base64," + (btoa(unescape(encodeURIComponent(JSON.stringify(data, null, 2))))),
|
|
target: '_blank'
|
|
});
|
|
$.on(a, 'click', function(e) {
|
|
return e.stopPropagation();
|
|
});
|
|
return $.add(this.parentElement.parentElement, a);
|
|
},
|
|
restore: function() {
|
|
if (confirm("Are you sure you want to restore \"" + this.id + "\"?")) {
|
|
$.remove(Conf["Deleted Mascots"], this.id);
|
|
$.set("Deleted Mascots", Conf["Deleted Mascots"]);
|
|
return $.rm(this);
|
|
}
|
|
},
|
|
select: function() {
|
|
var string;
|
|
string = g.MASCOTSTRING;
|
|
if ($.remove(Conf[string], this.id)) {
|
|
if (Conf['mascot'] === this.id) {
|
|
MascotTools.toggle();
|
|
}
|
|
} else {
|
|
Conf['mascot'] = this.id;
|
|
Conf[string].push(this.id);
|
|
MascotTools.change(Mascots[this.id]);
|
|
}
|
|
$.toggleClass(this, 'enabled');
|
|
$.set(string, Conf[string]);
|
|
return $.set(string, Conf[string]);
|
|
}
|
|
},
|
|
theme: {
|
|
select: function() {
|
|
var current;
|
|
if (current = $.id(Conf[g.THEMESTRING])) {
|
|
$.rmClass(current, 'selectedtheme');
|
|
}
|
|
$.set(g.THEMESTRING, Conf[g.THEMESTRING] = this.id);
|
|
$.addClass(this, 'selectedtheme');
|
|
return Style.setTheme(Themes[this.id]);
|
|
},
|
|
edit: function(e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
ThemeTools.init(this.name);
|
|
return Settings.close();
|
|
},
|
|
"export": function(e) {
|
|
var a, data;
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
data = Themes[this.name];
|
|
data['Theme'] = this.name;
|
|
a = $.el('a', {
|
|
textContent: '>>Save me!',
|
|
download: "" + this.name + "-" + (Date.now()) + ".json",
|
|
href: "data:application/json;base64," + (btoa(unescape(encodeURIComponent(JSON.stringify(data, null, 2))))),
|
|
target: '_blank'
|
|
});
|
|
$.on(a, 'click', function(e) {
|
|
return e.stopPropagation();
|
|
});
|
|
return $.replace(this, a);
|
|
},
|
|
"delete": function(e) {
|
|
var container, settheme;
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
container = $.id(this.name);
|
|
if (!(container.previousSibling || container.nextSibling)) {
|
|
alert("Cannot delete theme (No other themes available).");
|
|
return;
|
|
}
|
|
if (confirm("Are you sure you want to delete \"" + this.name + "\"?")) {
|
|
if (this.name === Conf[g.THEMESTRING]) {
|
|
if (settheme = container.previousSibling || container.nextSibling) {
|
|
Conf[g.THEMESTRING] = settheme.id;
|
|
$.addClass(settheme, 'selectedtheme');
|
|
$.set(g.THEMESTRING, Conf[g.THEMESTRING]);
|
|
}
|
|
}
|
|
Themes[this.name]["Deleted"] = true;
|
|
return $.get("userThemes", {}, (function(_this) {
|
|
return function(_arg) {
|
|
var userThemes;
|
|
userThemes = _arg.userThemes;
|
|
userThemes[_this.name] = Themes[_this.name];
|
|
$.set('userThemes', userThemes);
|
|
return $.rm(container);
|
|
};
|
|
})(this));
|
|
}
|
|
},
|
|
restore: function() {
|
|
if (confirm("Are you sure you want to restore \"" + this.id + "\"?")) {
|
|
Themes[this.id]["Deleted"] = false;
|
|
return $.get("userThemes", {}, (function(_this) {
|
|
return function(_arg) {
|
|
var userThemes;
|
|
userThemes = _arg.userThemes;
|
|
userThemes[_this.id] = Themes[_this.id];
|
|
$.set('userThemes', userThemes);
|
|
return $.rm(_this);
|
|
};
|
|
})(this));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
Main = {
|
|
init: function() {
|
|
var db, flatten, pathname, _i, _len, _ref, _ref1;
|
|
g.threads = new SimpleDict;
|
|
g.posts = new SimpleDict;
|
|
pathname = location.pathname.split('/');
|
|
g.BOARD = new Board(pathname[1]);
|
|
if ((_ref = g.BOARD.ID) === 'z' || _ref === 'fk') {
|
|
return;
|
|
}
|
|
g.VIEW = (function() {
|
|
switch (pathname[2]) {
|
|
case 'res':
|
|
return 'thread';
|
|
case 'catalog':
|
|
return 'catalog';
|
|
default:
|
|
return 'index';
|
|
}
|
|
})();
|
|
if (g.VIEW === 'catalog') {
|
|
return Index.catalogSwitch();
|
|
}
|
|
if (g.VIEW === 'thread') {
|
|
g.THREADID = +pathname[3];
|
|
}
|
|
flatten = function(parent, obj) {
|
|
var key, val;
|
|
if (obj instanceof Array) {
|
|
Conf[parent] = obj[0];
|
|
} else if (typeof obj === 'object') {
|
|
for (key in obj) {
|
|
val = obj[key];
|
|
flatten(key, val);
|
|
}
|
|
} else {
|
|
Conf[parent] = obj;
|
|
}
|
|
};
|
|
flatten(null, Config);
|
|
_ref1 = DataBoard.keys;
|
|
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
|
|
db = _ref1[_i];
|
|
Conf[db] = {
|
|
boards: {}
|
|
};
|
|
}
|
|
$.extend(Conf, {
|
|
'Enabled Mascots': [],
|
|
'Enabled Mascots sfw': [],
|
|
'Enabled Mascots nsfw': [],
|
|
'Deleted Mascots': [],
|
|
'Hidden Categories': ["Custom", "Questionable"],
|
|
'userThemes': {},
|
|
'userMascots': {},
|
|
'selectedArchives': {},
|
|
'CachedTitles': {}
|
|
});
|
|
return $.get(Conf, function(items) {
|
|
$.extend(Conf, items);
|
|
return $.asap((function() {
|
|
return Favicon.el = $('link[rel="shortcut icon"]', d.head);
|
|
}), Main.initFeatures);
|
|
});
|
|
},
|
|
initFeatures: function() {
|
|
var href, init, _ref;
|
|
Favicon.el.type = 'image/x-icon';
|
|
href = Favicon.el.href;
|
|
Favicon.SFW = /ws\.ico$/.test(href);
|
|
Favicon["default"] = href;
|
|
g.TYPE = Favicon.SFW ? 'sfw' : 'nsfw';
|
|
$.extend(Themes, Conf["userThemes"]);
|
|
$.extend(Mascots, Conf["userMascots"]);
|
|
if ((_ref = g.BOARD.ID) === 'z' || _ref === 'fk') {
|
|
return Style.init();
|
|
}
|
|
Main.setThemeString();
|
|
Main.setMascotString();
|
|
switch (location.hostname) {
|
|
case '4chan.org':
|
|
case 'www.4chan.org':
|
|
g.TYPE = 'sfw';
|
|
g.VIEW = 'home';
|
|
Main.setThemeString();
|
|
Style.init();
|
|
return;
|
|
case 'a.4cdn.org':
|
|
return;
|
|
case 'sys.4chan.org':
|
|
g.VIEW = 'report';
|
|
Style.init();
|
|
Report.init();
|
|
return;
|
|
case 'i.4cdn.org':
|
|
$.ready(function() {
|
|
var URL, pathname, _ref1;
|
|
if (Conf['404 Redirect'] && ((_ref1 = d.title) === '4chan - Temporarily Offline' || _ref1 === '4chan - 404 Not Found')) {
|
|
Redirect.init();
|
|
pathname = location.pathname.split('/');
|
|
URL = Redirect.to('file', {
|
|
boardID: g.BOARD.ID,
|
|
filename: pathname[pathname.length - 1]
|
|
});
|
|
if (URL) {
|
|
return location.replace(URL);
|
|
}
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
init = function(name, feature) {
|
|
var err;
|
|
try {
|
|
return feature.init();
|
|
} catch (_error) {
|
|
err = _error;
|
|
return Main.handleErrors({
|
|
message: "\"" + name + "\" initialization crashed.",
|
|
error: err
|
|
});
|
|
}
|
|
};
|
|
init('Emoji', Emoji);
|
|
init('Style', Style);
|
|
init('Mascots', MascotTools);
|
|
init('Rice', Rice);
|
|
init('Announcements', GlobalMessage);
|
|
init('Polyfill', Polyfill);
|
|
init('Redirect', Redirect);
|
|
init('Header', Header);
|
|
init('Catalog Links', CatalogLinks);
|
|
init('Settings', Settings);
|
|
init('Index Generator', Index);
|
|
init('Announcement Hiding', PSAHiding);
|
|
init('Fourchan thingies', Fourchan);
|
|
init('Emoji', Emoji);
|
|
init('Color User IDs', IDColor);
|
|
init('Custom CSS', CustomCSS);
|
|
init('Linkify', Linkify);
|
|
init('Reveal Spoilers', RemoveSpoilers);
|
|
init('Resurrect Quotes', Quotify);
|
|
init('Filter', Filter);
|
|
init('Reply Hiding Buttons', PostHiding);
|
|
init('Recursive', Recursive);
|
|
init('Strike-through Quotes', QuoteStrikeThrough);
|
|
init('Quick Reply', QR);
|
|
init('Menu', Menu);
|
|
init('Report Link', ReportLink);
|
|
init('Reply Hiding (Menu)', PostHiding.menu);
|
|
init('Delete Link', DeleteLink);
|
|
init('Filter (Menu)', Filter.menu);
|
|
init('Download Link', DownloadLink);
|
|
init('Archive Link', ArchiveLink);
|
|
init('Quote Inlining', QuoteInline);
|
|
init('Quote Previewing', QuotePreview);
|
|
init('Quote Backlinks', QuoteBacklink);
|
|
init('Quote Markers', QuoteMarkers);
|
|
init('Anonymize', Anonymize);
|
|
init('Time Formatting', Time);
|
|
init('Relative Post Dates', RelativeDates);
|
|
init('File Info Formatting', FileInfo);
|
|
init('Fappe Tyme', FappeTyme);
|
|
init('Gallery', Gallery);
|
|
init('Gallery (menu)', Gallery.menu);
|
|
init('Sauce', Sauce);
|
|
init('Image Expansion', ImageExpand);
|
|
init('Image Expansion (Menu)', ImageExpand.menu);
|
|
init('Reveal Spoiler Thumbnails', RevealSpoilers);
|
|
init('Image Loading', ImageLoader);
|
|
init('Image Hover', ImageHover);
|
|
init('Thread Expansion', ExpandThread);
|
|
init('Comment Expansion', ExpandComment);
|
|
init('Thread Excerpt', ThreadExcerpt);
|
|
init('Favicon', Favicon);
|
|
init('Unread', Unread);
|
|
init('Quote Threading', QuoteThreading);
|
|
init('Thread Stats', ThreadStats);
|
|
init('Thread Updater', ThreadUpdater);
|
|
init('Thread Watcher', ThreadWatcher);
|
|
init('Thread Watcher (Menu)', ThreadWatcher.menu);
|
|
init('Index Navigation', Nav);
|
|
init('Keybinds', Keybinds);
|
|
init('Show Dice Roll', Dice);
|
|
init('Banner', Banner);
|
|
init('Navigate', Navigate);
|
|
init('Flash Features', Flash);
|
|
$.on(d, 'AddCallback', Main.addCallback);
|
|
return $.ready(Main.initReady);
|
|
},
|
|
initReady: function() {
|
|
var GMver, err, href, i, passLink, styleSelector, test, v, _i, _len, _ref, _ref1;
|
|
if ((_ref = d.title) === '4chan - Temporarily Offline' || _ref === '4chan - 404 Not Found') {
|
|
if (Conf['404 Redirect'] && g.VIEW === 'thread') {
|
|
href = Redirect.to('thread', {
|
|
boardID: g.BOARD.ID,
|
|
threadID: g.THREADID,
|
|
postID: +location.hash.match(/\d+/)
|
|
});
|
|
location.replace(href || ("/" + g.BOARD + "/"));
|
|
}
|
|
return;
|
|
}
|
|
if (styleSelector = $.id('styleSelector')) {
|
|
passLink = $.el('a', {
|
|
textContent: '4chan Pass',
|
|
href: 'javascript:;'
|
|
});
|
|
$.on(passLink, 'click', function() {
|
|
return window.open('//sys.4chan.org/auth', 'This will steal your data.', 'left=0,top=0,width=500,height=255,toolbar=0,resizable=0');
|
|
});
|
|
$.before(styleSelector.previousSibling, [$.tn('['), passLink, $.tn(']\u00A0\u00A0')]);
|
|
}
|
|
if (!Conf['JSON Navigation'] || g.VIEW === 'thread') {
|
|
Main.initThread();
|
|
}
|
|
$.event('4chanXInitFinished');
|
|
test = $.el('span');
|
|
test.classList.add('a', 'b');
|
|
if (test.className !== 'a b') {
|
|
new Notice('warning', "Your version of Firefox is outdated (v26 minimum) and appchan x may not operate correctly.", 30);
|
|
}
|
|
GMver = GM_info.version.split('.');
|
|
_ref1 = "1.14".split('.');
|
|
for (i = _i = 0, _len = _ref1.length; _i < _len; i = ++_i) {
|
|
v = _ref1[i];
|
|
if (v === GMver[i]) {
|
|
continue;
|
|
}
|
|
(v < GMver[i]) || new Notice('warning', "Your version of Greasemonkey is outdated (v" + GM_info.version + " instead of v1.14 minimum) and appchan x may not operate correctly.", 30);
|
|
break;
|
|
}
|
|
try {
|
|
return localStorage.getItem('4chan-settings');
|
|
} catch (_error) {
|
|
err = _error;
|
|
return new Notice('warning', 'Cookies need to be enabled on 4chan for appchan x to operate properly.', 30);
|
|
}
|
|
},
|
|
initThread: function() {
|
|
var board, err, errors, postRoot, posts, thread, threadRoot, threads, _i, _j, _len, _len1, _ref, _ref1;
|
|
if (board = $('.board')) {
|
|
threads = [];
|
|
posts = [];
|
|
_ref = $$('.board > .thread', board);
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
threadRoot = _ref[_i];
|
|
thread = new Thread(+threadRoot.id.slice(1), g.BOARD);
|
|
threads.push(thread);
|
|
_ref1 = $$('.thread > .postContainer', threadRoot);
|
|
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
|
postRoot = _ref1[_j];
|
|
try {
|
|
posts.push(new Post(postRoot, thread, g.BOARD));
|
|
} catch (_error) {
|
|
err = _error;
|
|
if (!errors) {
|
|
errors = [];
|
|
}
|
|
errors.push({
|
|
message: "Parsing of Post No." + (postRoot.id.match(/\d+/)) + " failed. Post will be skipped.",
|
|
error: err
|
|
});
|
|
}
|
|
}
|
|
}
|
|
if (errors) {
|
|
Main.handleErrors(errors);
|
|
}
|
|
Thread.callbacks.execute(threads);
|
|
Post.callbacks.execute(posts);
|
|
}
|
|
return $.get('previousversion', null, function(_arg) {
|
|
var changelog, el, previousversion;
|
|
previousversion = _arg.previousversion;
|
|
if (previousversion === g.VERSION) {
|
|
return;
|
|
}
|
|
if (previousversion) {
|
|
changelog = 'https://github.com/zixaphir/appchan-x/blob/master/CHANGELOG.md';
|
|
el = $.el('span', {
|
|
innerHTML: "appchan x has been updated to <a href='" + changelog + "' target=_blank>version " + g.VERSION + "</a>."
|
|
});
|
|
new Notice('info', el, 15);
|
|
} else {
|
|
Settings.open();
|
|
}
|
|
return $.set('previousversion', g.VERSION);
|
|
});
|
|
},
|
|
addCallback: function(e) {
|
|
var Klass, obj;
|
|
obj = e.detail;
|
|
if (typeof obj.callback.name !== 'string') {
|
|
throw new Error("Invalid callback name: " + obj.callback.name);
|
|
}
|
|
switch (obj.type) {
|
|
case 'Post':
|
|
Klass = Post;
|
|
break;
|
|
case 'Thread':
|
|
Klass = Thread;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
obj.callback.isAddon = true;
|
|
return Klass.callbacks.push(obj.callback);
|
|
},
|
|
handleErrors: function(errors) {
|
|
var div, error, logs, _i, _len;
|
|
if (!(errors instanceof Array)) {
|
|
error = errors;
|
|
} else if (errors.length === 1) {
|
|
error = errors[0];
|
|
}
|
|
if (error) {
|
|
new Notice('error', Main.parseError(error), 15);
|
|
return;
|
|
}
|
|
div = $.el('div', {
|
|
innerHTML: "" + errors.length + " errors occurred. [<a href=javascript:;>show</a>]"
|
|
});
|
|
$.on(div.lastElementChild, 'click', function() {
|
|
var _ref;
|
|
return _ref = this.textContent === 'show' ? ['hide', false] : ['show', true], this.textContent = _ref[0], logs.hidden = _ref[1], _ref;
|
|
});
|
|
logs = $.el('div', {
|
|
hidden: true
|
|
});
|
|
for (_i = 0, _len = errors.length; _i < _len; _i++) {
|
|
error = errors[_i];
|
|
$.add(logs, Main.parseError(error));
|
|
}
|
|
return new Notice('error', [div, logs], 30);
|
|
},
|
|
parseError: function(data) {
|
|
var error, message;
|
|
c.error(data.message, data.error.stack);
|
|
message = $.el('div', {
|
|
textContent: data.message
|
|
});
|
|
error = $.el('div', {
|
|
textContent: data.error
|
|
});
|
|
return [message, error];
|
|
},
|
|
isThisPageLegit: function() {
|
|
var _ref;
|
|
if (!('thisPageIsLegit' in Main)) {
|
|
Main.thisPageIsLegit = location.hostname === 'boards.4chan.org' && !$('link[href*="favicon-status.ico"]', d.head) && ((_ref = d.title) !== '4chan - Temporarily Offline' && _ref !== '4chan - Error' && _ref !== '504 Gateway Time-out');
|
|
}
|
|
return Main.thisPageIsLegit;
|
|
},
|
|
setMascotString: function() {
|
|
var type;
|
|
type = "Enabled Mascots";
|
|
if (Conf["NSFW/SFW Mascots"]) {
|
|
type += " " + g.TYPE;
|
|
}
|
|
return g.MASCOTSTRING = type;
|
|
},
|
|
setThemeString: function() {
|
|
var type;
|
|
type = "theme";
|
|
if (Conf["NSFW/SFW Themes"]) {
|
|
type += "_" + g.TYPE;
|
|
}
|
|
return g.THEMESTRING = type;
|
|
}
|
|
};
|
|
|
|
Main.init();
|
|
|
|
}).call(this);
|