├── images ├── logo.png ├── favicon.png ├── favicon.svg └── logo.svg ├── 8chan-x.meta.js ├── LICENSE ├── LICENSE_diff ├── README.md └── 8chan-x.user.js /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pashe/8chanX/HEAD/images/logo.png -------------------------------------------------------------------------------- /images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pashe/8chanX/HEAD/images/favicon.png -------------------------------------------------------------------------------- /8chan-x.meta.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Pashe's 8chanX v2 [pure] 3 | // @version 2.0.0.1511219830 4 | // @description Small userscript to improve 8chan 5 | // @namespace https://github.com/Pashe/8chanX/tree/2-0 6 | // @updateURL https://github.com/Pashe/8chanX/raw/2-0_pure/8chan-x.meta.js 7 | // @downloadURL https://github.com/Pashe/8chanX/raw/2-0_pure/8chan-x.user.js 8 | // ==/UserScript== -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 tux3!Lev.uXFMLA 2 | 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: 3 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 4 | 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. 5 | -------------------------------------------------------------------------------- /LICENSE_diff: -------------------------------------------------------------------------------- 1 | This license applies only to changes made in this fork. The license for the original code is in "LICENSE". 2 | 3 | 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. 4 | 5 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 6 | Version 2, December 2004 7 | 8 | Copyright (C) 2004 Sam Hocevar 9 | 10 | Everyone is permitted to copy and distribute verbatim or modified 11 | copies of this license document, and changing it is allowed as long 12 | as the name is changed. 13 | 14 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 15 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 16 | 17 | 0. You just DO WHAT THE FUCK YOU WANT TO. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #![8](https://cdn.rawgit.com/Pashe/8chanX/2-0_pure/images/logo.svg)chanX 2.0 Pure 2 | #[Click here to install](https://github.com/Pashe/8chanX/raw/2-0_pure/8chan-x.user.js) 3 | 4 | This branch removes a few features in order to improve compatibility. You should not use this branch if [2.0](https://github.com/Pashe/8chanX/tree/2-0) works for you. 5 | *** 6 | 7 | This userscript adds various features and options like: 8 | * Gallery 9 | * Filters 10 | * Reverse image search 11 | * Flag preview 12 | * Mascots 13 | * Notifications 14 | * Relative post dates 15 | * Post and image counts in the menu 16 | * Many other poorly written hacks 17 | * Not as dead as tux's version 18 | 19 | This is a userscript, you will need an addon to run it properly 20 | 21 | Browser|Addon 22 | ---- |---- 23 | Firefox|[Greasemonkey](https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/) 24 | Chrome |[Tampermonkey](https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo) 25 | 26 | ####Key bindings 27 | Key | Function 28 | ---- | ---- 29 | C | Navigates to the catalog 30 | E | Expands/shrinks all images 31 | G | Toggles the gallery 32 | Q | Opens the quick reply 33 | R | Update thread/reload page 34 | Esc | Closes the quick reply, gallery, or expanded gallery image -------------------------------------------------------------------------------- /images/favicon.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml -------------------------------------------------------------------------------- /images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 16 | 17 | 19 | image/svg+xml 20 | 22 | 23 | 24 | 25 | 26 | 28 | 31 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /8chan-x.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Pashe's 8chanX v2 [pure] 3 | // @version 2.0.0.1511219830 4 | // @description Small userscript to improve 8chan 5 | // @icon https://cdn.rawgit.com/Pashe/8chanX/2-0_pure/images/logo.svg 6 | // @namespace https://github.com/Pashe/8chanX/tree/2-0 7 | // @updateURL https://github.com/Pashe/8chanX/raw/2-0_pure/8chan-x.meta.js 8 | // @downloadURL https://github.com/Pashe/8chanX/raw/2-0_pure/8chan-x.user.js 9 | // @grant none 10 | 11 | // @require https://code.jquery.com/ui/1.11.2/jquery-ui.min.js 12 | // @require https://github.com/alexei/sprintf.js/raw/master/src/sprintf.js 13 | // @require https://raw.githubusercontent.com/rmm5t/jquery-timeago/master/jquery.timeago.js 14 | // @require https://raw.githubusercontent.com/samsonjs/strftime/master/strftime.js 15 | 16 | // @match *://hatechan.co/* 17 | // @match *://8chan.co/* 18 | // @match *://h.8chan.co/* 19 | // @match *://h.8ch.net/* 20 | // @match *://jp.8chan.co/* 21 | // @match *://jp.8ch.net/* 22 | // @match *://sys.8ch.net/* 23 | // @match *://8ch.net/* 24 | // @exclude *.json 25 | // @exclude *.txt 26 | // ==/UserScript== 27 | 28 | /*Contributors 29 | ** tux3 30 | ** Zaphkiel 31 | ** varemenos 32 | ** 7185 33 | ** anonish 34 | ** Pashe 35 | */ 36 | 37 | function chxErrorHandler(e, section) { 38 | console.error(e); 39 | console.trace(); 40 | 41 | var rptObj = { //Chrome needs this 42 | name: e?(e.name||"unknown"):"VERY unknown", 43 | msg: e?(e.message||"unknown"):"VERY unknown", 44 | file: e?((e.fileName||"unknown").split("/").slice(-1).join("")):"VERY unknown", 45 | line: e?(e.lineNumber||"?"):"???", 46 | col: e?(e.columnNumber||"?"):"???", 47 | section: (section||"unknown"), 48 | scriptName: (GM_info&&GM_info.script)?(GM_info.script.name||"unknown"):"VERY unknown", 49 | scriptVersion: (GM_info&&GM_info.script)?(GM_info.script.version||"unknown"):"VERY unknown", 50 | gmVersion: (GM_info&&GM_info.version)?(GM_info.version||"unknown"):"VERY unknown", 51 | activePage: window?(window.active_page||"unknown"):"VERY unknown", 52 | browser: (window&&window.navigator)?((window.navigator.userAgent||"unknown").match(/(Chrom\S*|\S*fox\/\S*|Ice\S*)/gi)||["unknown"]).join(", "):"VERY unknown", 53 | userAgent: (window&&window.navigator)?(window.navigator.userAgent||"unknown"):"VERY unknown", 54 | location: (window&&window.location)?(window.location.href||"unknown"):"VERY unknown", 55 | stack: e?((e.stack||"unknown").replace(/file:[^ \n]*\//g, "file:").replace(/^/gm, " ")):"VERY unknown", 56 | }; 57 | 58 | console.error(sprintf( 59 | "8chanX experienced an error. Please include the following information with your report:\n"+ 60 | "[code]%s in %s/%s @ L%s C%s: %s\n\nVersion: %s (2-0_pure@%s)\nGreasemonkey: %s\nActive page: %s\nBrowser: %s\nUser agent: %s\nLocation: %s\nStack:\n%s[/code]", 61 | rptObj.name, rptObj.file, rptObj.section, rptObj.line, rptObj.col, rptObj.msg, 62 | rptObj.scriptName, rptObj.scriptVersion, 63 | rptObj.gmVersion, 64 | rptObj.activePage, 65 | rptObj.browser, 66 | rptObj.userAgent, 67 | rptObj.location, 68 | rptObj.stack 69 | )); 70 | 71 | alert("8chanX experienced an error. Check the console for details (typically F12)."); 72 | } 73 | 74 | try { 75 | //////////////// 76 | //GLOBAL VARIABLES 77 | //////////////// 78 | //Constants 79 | var bumpLimit = 300; 80 | 81 | //Initializations 82 | var thisThread; 83 | var cachedPages = null; 84 | var galleryImages; 85 | var galleryImageIndex; 86 | 87 | //Dynamic 88 | var isMod = (window.location.pathname.split("/")[1]=="mod.php"); 89 | var thisBoard = isMod?window.location.href.split("/")[4]:window.location.pathname.split("/")[1]; 90 | try {thisThread = parseInt(window.location.href.match(/([0-9]+)\.html/)[1]);} catch (e) {thisThread = -1;} 91 | var thisBoardAnonName; 92 | var thisBoardSettings; 93 | 94 | //////////////// 95 | //SETTINGS 96 | //////////////// 97 | var settingsMenu = window.document.createElement('div'); 98 | 99 | if (window.Options) { 100 | var tab = window.Options.add_tab('8chanX', 'times', '8chanX'); 101 | $(settingsMenu).appendTo(tab.content); 102 | } 103 | 104 | settingsMenu.innerHTML = sprintf('8chanX %s pure', GM_info.script.version) 105 | + '
' //General 106 | + '
' 107 | + '
' 108 | + '
' 109 | + '
' 110 | + '
' //How information is displayed 111 | + '
' 112 | + '
' 113 | + '
' 114 | + '
' 115 | + '
' 116 | + '
' 117 | + '
' 118 | + '
' //Filters 119 | + '

Filters

' 120 | + '' 121 | + '' 122 | 123 | + '' 124 | 125 | + '' 126 | 127 | + '' 128 | 129 | + '' 130 | 131 | + '' 132 | 133 | + '' 134 | 135 | + '
FieldRegexRSA
Tripcode
Name
Body
Email
Subject
Flag
' 136 | + '
' //Other shit 137 | + '' 138 | + '
'; 139 | 140 | $(settingsMenu).find(".chx_FilterField").css("text-align", "right"); 141 | $(settingsMenu).find('input').css("max-width", "100%"); 142 | 143 | 144 | var defaultSettings = { 145 | 'precisePages': true, 146 | 'failToCatalogPages': false, 147 | 'catalogLinks': true, 148 | 'revealImageSpoilers': false, 149 | 'reverseImageSearch': true, 150 | 'parseTimestampImage': true, 151 | 'localTime': true, 152 | 'dateFormat':"", 153 | 'mascotUrl':"", 154 | 'keyboardShortcutsEnabled': true, 155 | 'filterDefaultRegex': '', 156 | 'filterDefaultRecursive': true, 157 | 'filterDefaultStubs': false, 158 | 'filterDefault': false, 159 | 'hideNoFilePosts': false, 160 | }; 161 | 162 | function getSetting(key) { 163 | if (localStorage.getItem("chx_"+key)) { 164 | return JSON.parse(localStorage.getItem("chx_"+key)); 165 | } else { 166 | try { 167 | var keyMatch = key.match(/filter([A-Z][a-z]*)([A-Z][a-z]*)?/); 168 | if (!keyMatch) { 169 | return defaultSettings[key]; 170 | } else { 171 | return defaultSettings["filterDefault"+(keyMatch.hasOwnProperty(2)?keyMatch[2]:"")]; 172 | } 173 | } catch(e) {console.error(e);} 174 | } 175 | } 176 | 177 | function setSetting(key, value) { 178 | localStorage.setItem("chx_"+key, JSON.stringify(value)); 179 | } 180 | 181 | function refreshSettings() { 182 | var settingsItems = settingsMenu.getElementsByTagName("input"); 183 | for (var i in settingsItems) { 184 | if (!settingsItems.hasOwnProperty(i)) {continue;} 185 | var control = settingsItems[i]; 186 | if (!control.name) {continue;} 187 | 188 | switch (control.type) { 189 | case "checkbox": 190 | control.checked = getSetting(control.name); 191 | break; 192 | default: 193 | control.value = getSetting(control.name); 194 | break; 195 | } 196 | } 197 | } 198 | 199 | function setupControl(control) { 200 | switch (control.type) { 201 | case "checkbox": 202 | $(control).on("change", function () { 203 | setSetting(this.name, this.checked); 204 | }); 205 | break; 206 | default: 207 | $(control).on("input", function () { 208 | setSetting(this.name, this.value); 209 | }); 210 | break; 211 | } 212 | } 213 | 214 | //////////////// 215 | //GENERAL FUNCTIONS 216 | //////////////// 217 | function isOnCatalog() { 218 | return window.active_page === "catalog"; 219 | } 220 | 221 | function isOnThread() { 222 | return window.active_page === "thread"; 223 | } 224 | 225 | function printf() { //alexei et al, 3BSD 226 | var key = arguments[0], cache = sprintf.cache; 227 | if (!(cache[key] && cache.hasOwnProperty(key))) { 228 | cache[key] = sprintf.parse(key); 229 | } 230 | console.log(sprintf.format.call(null, cache[key], arguments)); 231 | } 232 | 233 | function getThreadPage(threadId, boardId, cached) { //Pashe, WTFPL 234 | if ((!cached) || (cachedPages === null)) { 235 | $.ajax({ 236 | url: "/" + boardId + "/threads.json", 237 | async: false, 238 | dataType: "json", 239 | success: function (response) {cachedPages = response;} 240 | }); 241 | } 242 | 243 | return calcThreadPage(cachedPages, threadId); 244 | } 245 | 246 | function calcThreadPage(pages, threadId) { //Pashe, WTFPL 247 | var threadPage = -1; 248 | var precisePages = getSetting("precisePages"); 249 | 250 | for (var pageIdx in pages) { 251 | if (!pages.hasOwnProperty(pageIdx)) {continue;} 252 | if (threadPage != -1) {break;} 253 | var threads = pages[pageIdx].threads; 254 | 255 | for (var threadIdx in threads) { 256 | if (!threads.hasOwnProperty(threadIdx)) {continue;} 257 | if (threadPage != -1) {break;} 258 | 259 | if (threads[threadIdx].no == threadId) { 260 | if (!precisePages) { 261 | threadPage = pages[pageIdx].page+1; 262 | } else { 263 | threadPage = ((pages[pageIdx].page+1)+(threadIdx/threads.length)).toFixed(2); 264 | } 265 | break; 266 | } 267 | } 268 | } 269 | return threadPage; 270 | } 271 | 272 | function getThreadLastModified(threadId, boardId, cached) { //Pashe, WTFPL 273 | if ((!cached) || (cachedPages === null)) { 274 | $.ajax({ 275 | url: "/" + boardId + "/threads.json", 276 | async: false, 277 | dataType: "json", 278 | success: function (response) {cachedPages = response;} 279 | }); 280 | } 281 | 282 | return calcThreadLastModified(cachedPages, threadId); 283 | } 284 | 285 | function calcThreadLastModified(pages, threadId) { //Pashe, WTFPL 286 | var threadLastModified = -1; 287 | 288 | for (var pageIdx in pages) { 289 | if (!pages.hasOwnProperty(pageIdx)) {continue;} 290 | if (threadLastModified != -1) {break;} 291 | var threads = pages[pageIdx].threads; 292 | 293 | for (var threadIdx in threads) { 294 | if (!threads.hasOwnProperty(threadIdx)) {continue;} 295 | if (threadLastModified != -1) {break;} 296 | 297 | if (threads[threadIdx].no == threadId) { 298 | threadLastModified = pages[pageIdx]["threads"][threadIdx]["last_modified"]; 299 | break; 300 | } 301 | } 302 | } 303 | return threadLastModified; 304 | } 305 | 306 | function getThreadPosts() { //Pashe, WTFPL 307 | return $(".post").length; 308 | } 309 | 310 | function getThreadImages() { //Pashe, WTFPL 311 | return $(".post-image").length; 312 | } 313 | 314 | function getFileExtension(filename) { //Pashe, WTFPL 315 | if (filename.match(/\.([a-z0-9]+)(&loop.*)?$/i) !== null) { 316 | return filename.match(/\.([a-z0-9]+)(&loop.*)?$/i)[1]; 317 | } else if (filename.match(/https?:\/\/(www\.)?youtube.com/)) { 318 | return 'Youtube'; 319 | } else { 320 | return sprintf("unknown: %s", filename); 321 | } 322 | } 323 | 324 | function isImage(fileExtension) { //Pashe, WTFPL 325 | return ($.inArray(fileExtension, ["jpg", "jpeg", "gif", "png"]) !== -1); 326 | } 327 | 328 | function isVideo(fileExtension) { //Pashe, WTFPL 329 | return ($.inArray(fileExtension, ["webm", "mp4"]) !== -1); 330 | } 331 | 332 | function updateBoardSettings(response) { //Pashe, WTFPL 333 | thisBoardSettings = response; 334 | 335 | thisBoardAnonName = thisBoardSettings.anonymous; 336 | bumpLimit = thisBoardSettings.reply_limit; 337 | } 338 | 339 | //////////////// 340 | //MENU BAR 341 | //////////////// 342 | function updateMenuStats() { //Pashe, WTFPL 343 | var nPosts = getThreadPosts(thisThread, thisBoard, false); 344 | 345 | $.ajax({ 346 | url: "/settings.php?board="+thisBoard, 347 | async: true, 348 | cache: true, 349 | dataType: "json", 350 | success: function (response) { 351 | updateBoardSettings(response); 352 | } 353 | }); 354 | 355 | if (nPosts >= bumpLimit) {nPosts = sprintf('%d', nPosts);} 356 | 357 | $("#chx_menuPosts").html(nPosts); 358 | $("#chx_menuImages").html(getThreadImages(thisThread, thisBoard, false)); 359 | 360 | $.ajax({ 361 | url: "/" + thisBoard + "/threads.json", 362 | async: true, 363 | dataType: "json", 364 | success: function (response) { 365 | cachedPages = response; 366 | 367 | var nPage = calcThreadPage(response, thisThread); 368 | if (nPage < 1) { 369 | nPage = "3+"; 370 | 371 | if (getSetting("failToCatalogPages")) { 372 | $.ajax({ 373 | url: "/" + thisBoard + "/catalog.html", 374 | async: false, 375 | dataType: "html", 376 | success: function (response) { 377 | var pageArray = []; 378 | 379 | $(response).find("div.thread").each(function() { 380 | $this = $(this); 381 | 382 | var threadId = parseInt($this.children("a").attr("href").match(/([0-9]+).html$/)[1]); 383 | var page = parseInt($this.find("strong").text().match(/P: ([0-9]+)/)[1]); 384 | 385 | pageArray[threadId] = page; 386 | }); 387 | 388 | if (pageArray.hasOwnProperty(thisThread)) {nPage = pageArray[thisThread];} 389 | } 390 | }); 391 | } 392 | } 393 | 394 | $("#chx_menuPage").html(nPage); 395 | } 396 | }); 397 | 398 | } 399 | 400 | //////////////// 401 | //KEYBOARD SHORTCUTS 402 | //////////////// 403 | function reloadPage() { //Pashe, WTFPL 404 | if (isOnThread()) { 405 | window.$('#update_thread').click(); 406 | updateMenuStats(); 407 | } else { 408 | document.location.reload(); 409 | } 410 | } 411 | 412 | function showQR() { //Pashe, WTFPL 413 | window.$(window).trigger('cite'); 414 | $("#quick-reply textarea").focus(); 415 | } 416 | 417 | function toggleExpandAll() { //Tux et al, MIT 418 | var shrink = window.$('#shrink-all-images a'); 419 | if (shrink.length) { 420 | shrink.click(); 421 | } else { 422 | window.$('#expand-all-images a').click(); 423 | } 424 | } 425 | 426 | function goToCatalog() { //Pashe, WTFPL 427 | if (isOnCatalog()) {return;} 428 | window.location = sprintf("/%s/catalog.html", thisBoard); 429 | } 430 | 431 | //////////////// 432 | //REVERSE IMAGE SEARCH 433 | //////////////// 434 | var RISProviders = { 435 | "google": { 436 | "urlFormat" : "https://www.google.com/searchbyimage?image_url=%s", 437 | "name" : "Google" 438 | }, 439 | "iqdb": { 440 | "urlFormat" : "http://iqdb.org/?url=%s", 441 | "name" : "iqdb" 442 | }, 443 | "saucenao": { 444 | "urlFormat" : "https://saucenao.com/search.php?db=999&url=%s", 445 | "name" : "SauceNAO" 446 | }, 447 | "tineye": { 448 | "urlFormat" : "https://www.tineye.com/search/?url=%s", 449 | "name" : "TinEye" 450 | }, 451 | "harrylu": { 452 | "urlFormat" : "https://iqdb.harry.lu/?url=%s", 453 | "name" : "Harry.lu (e621)", 454 | "shortName" : "E" 455 | }, 456 | "karmadecay": { 457 | "urlFormat" : "http://karmadecay.com/%s", 458 | "name" : "Karma Decay" 459 | }, 460 | }; 461 | 462 | var RISProvidersBoards = { 463 | "##ALL": ["google", "iqdb", "saucenao", "tineye", "karmadecay"], 464 | "furry": ["harrylu"], 465 | }; 466 | 467 | function addRISLinks(image) { //Pashe, 7185, WTFPL 468 | var thisBoardRISProviders = (RISProvidersBoards["##ALL"].concat(RISProvidersBoards[thisBoard]||[])); 469 | for (var providerIdx in thisBoardRISProviders) { 470 | providerIdx = thisBoardRISProviders[providerIdx]; 471 | if (!RISProviders.hasOwnProperty(providerIdx)) {continue;} 472 | var provider = RISProviders[providerIdx]; 473 | 474 | try { 475 | var RISUrl; 476 | if (!image.src.match(/\/spoiler.png$/)) { 477 | RISUrl = sprintf(provider.urlFormat, image.src); 478 | } else { 479 | RISUrl = sprintf(provider.urlFormat, image.parentNode.href); 480 | } 481 | 482 | var RISLink = $(''); 483 | RISLink.attr("href", RISUrl); 484 | RISLink.attr("title", provider.name); 485 | RISLink.attr("target", "_blank"); 486 | RISLink.css("font-size", "8pt"); 487 | RISLink.css("margin-left", "2pt"); 488 | RISLink.text(sprintf("[%s]", provider.shortName||provider.name[0].toUpperCase())); 489 | 490 | RISLink.appendTo(image.parentNode.parentNode.getElementsByClassName("fileinfo")[0]); 491 | } catch (e) {} 492 | } 493 | } 494 | 495 | //////////////// 496 | //NOTIFICATIONS 497 | //////////////// 498 | function notifyReplies() { 499 | /* 500 | * taken from https://github.com/ctrlcctrlv/8chan/blob/master/js/show-own-posts.js 501 | * 502 | * Released under the MIT license 503 | * Copyright (c) 2014 Marcin Labanowski 504 | */ 505 | 506 | var thread = $(this).parents('[id^="thread_"]').first(); 507 | if (!thread.length) {thread = $(this);} 508 | 509 | var ownPosts = JSON.parse(window.localStorage.own_posts || '{}'); 510 | 511 | $(this).find('div.body:first a:not([rel="nofollow"])').each(function() { 512 | var postID = $(this).text().match(/^>>(\d+)$/); 513 | 514 | if (postID !== null && postID.hasOwnProperty(1)) { 515 | postID = postID[1]; 516 | } else { 517 | return; 518 | } 519 | 520 | if (ownPosts[thisBoard] && ownPosts[thisBoard].indexOf(postID) !== -1) { 521 | var replyPost = $(this).closest("div.post"); 522 | var replyUser = (replyPost.find(".name").text()+replyPost.find(".trip").text()); 523 | var replyBody = replyPost.find(".body").text(); 524 | var replyImage = replyPost.find(".post-image").first().attr('src'); 525 | 526 | new Notification(replyUser+" replied to your post", {body:replyBody,icon:replyImage}); 527 | } 528 | }); 529 | } 530 | 531 | //////////////// 532 | //GALLERY 533 | //////////////// 534 | var fileExtensionStyles = { 535 | "jpg": {"background-color": "#0f0", "color": "#000"}, "jpeg": {"background-color": "#0f0", "color": "#000"}, 536 | "png": {"background-color": "#00f", "color": "#fff"}, 537 | "webm": {"background-color": "#f00", "color": "#000"}, "mp4": {"background-color": "#a00", "color": "#000"}, 538 | "gif": {"background-color": "#ff0", "color": "#000"}, 539 | }; 540 | 541 | function refreshGalleryImages() { //Pashe, 7185, WTFPL 542 | galleryImages = []; 543 | 544 | $("img.post-image").each(function() { 545 | var metadata = $(this).parent("a").siblings(".fileinfo").children(".unimportant").text().replace(/[()]/g, '').split(", "); 546 | if (!this.src.match(/\/deleted.png$/)) { 547 | galleryImages.push({ 548 | "thumbnail": this.src, 549 | "full": this.parentNode.href, 550 | "fileSize": metadata[0], 551 | "resolution": metadata[1], 552 | "aspect": metadata[2], 553 | "origName": metadata[3], 554 | }); 555 | } 556 | }); 557 | } 558 | 559 | function openGallery() { //Pashe, WTFPL 560 | refreshGalleryImages(); 561 | 562 | var galleryHolder = $(""); 563 | galleryHolder.appendTo($("body")); 564 | 565 | galleryHolder.css({ 566 | "background-color": "rgba(0,0,0,0.8)", 567 | "overflow": "auto", 568 | "z-index": "101", 569 | "position": "fixed", 570 | "left": "0", 571 | "top": "0", 572 | "width": "100%", 573 | "height": "100%" 574 | }); 575 | 576 | galleryHolder.click(function(e) { 577 | if(e.target == this) $(this).remove(); 578 | }); 579 | 580 | for (var i in galleryImages) { 581 | if (!galleryImages.hasOwnProperty(i)) {continue;} 582 | var image = galleryImages[i]; 583 | var fileExtension = getFileExtension(image.full); 584 | 585 | var thumbHolder = $('
'); 586 | var thumbLink = $(sprintf('', image.full)); 587 | var thumbImage = $(sprintf('', image.thumbnail)); 588 | var metadataSpan = $(sprintf('', fileExtension)); 589 | 590 | thumbImage.css({ 591 | "max-height": "128px", 592 | "max-width": "128px", 593 | "margin": "auto auto auto auto", 594 | "display": "block" 595 | }); 596 | 597 | thumbHolder.css({ 598 | "padding": "0pt 0pt 0pt 0pt", 599 | "height": "155px", 600 | "width": "128px", 601 | "overflow": "hidden", 602 | "float": "left", 603 | "text-align": "center", 604 | "color": "#fff" 605 | }); 606 | 607 | if (fileExtensionStyles.hasOwnProperty(fileExtension)) { 608 | metadataSpan.css(fileExtensionStyles[fileExtension]).css({"padding": "0pt 5pt 2pt 5pt", "border-radius": "2pt", "font-weight": "bolder"}); 609 | } 610 | 611 | thumbImage.appendTo(thumbLink); 612 | thumbLink.appendTo(thumbHolder); 613 | metadataSpan.appendTo(thumbHolder); 614 | thumbHolder.appendTo(galleryHolder); 615 | 616 | thumbLink.click(i, function(e) { 617 | e.preventDefault(); 618 | expandGalleryImage(parseInt(e.data)); 619 | }); 620 | } 621 | } 622 | 623 | function closeGallery() { //Pashe, WTFPL 624 | if ($("#chx_galleryExpandedImageHolder").length) { 625 | $("#chx_galleryExpandedImageHolder").remove(); 626 | } else { 627 | $("#chx_gallery").remove(); 628 | } 629 | } 630 | 631 | function toggleGallery() { //Pashe, WTFPL 632 | if ($("#chx_gallery").length) { 633 | closeGallery(); 634 | } else { 635 | openGallery(); 636 | } 637 | } 638 | 639 | function expandGalleryImage(index) { //Pashe, WTFPL 640 | galleryImageIndex = index; 641 | var expandedImage; 642 | var image = galleryImages[index].full; 643 | var imageHolder = $('
'); 644 | var fileExtension = getFileExtension(image); 645 | 646 | if (isImage(fileExtension)) { 647 | expandedImage = $(sprintf('', image)); 648 | expandedImage.css({ 649 | "max-height": "98%", 650 | "max-width": "100%", 651 | "margin": "auto auto auto auto", 652 | "display": "block" 653 | }); 654 | } else if (isVideo(fileExtension)) { 655 | image = image.match(/player\.php\?v=([^&]*[a-f0-9]+\.[a-z0-9]+).*/i)[1]; 656 | expandedImage = $(sprintf('', image)); 657 | expandedImage.css({ 658 | "max-height": "98%", 659 | "max-width": "100%", 660 | "margin": "auto auto auto auto", 661 | "display": "block" 662 | }); 663 | } else { 664 | expandedImage = $(sprintf('', image)); 665 | expandedImage.css({ 666 | "max-height": "98%", 667 | "max-width": "100%", 668 | "height": "98%", 669 | "width": "100%", 670 | "margin": "auto auto auto auto", 671 | "display": "block" 672 | }); 673 | } 674 | 675 | imageHolder.css({ 676 | "background-color": "rgba(0,0,0,0.8)", 677 | "overflow": "auto", 678 | "z-index": "102", 679 | "position": "fixed", 680 | "left": "0", 681 | "top": "0", 682 | "width": "100%", 683 | "height": "100%" 684 | }); 685 | 686 | imageHolder.appendTo($("body")); 687 | expandedImage.appendTo(imageHolder); 688 | imageHolder.click(function(e) { 689 | if(e.target == this) $(this).remove(); 690 | }); 691 | } 692 | 693 | function jogExpandedGalleryImage(steps) { 694 | if ($("#chx_galleryExpandedImageHolder").length && galleryImages.hasOwnProperty(galleryImageIndex+steps)) { 695 | $("#chx_galleryExpandedImageHolder").remove(); 696 | expandGalleryImage(galleryImageIndex+steps); 697 | } 698 | } 699 | 700 | //////////////// 701 | //FILTERS 702 | //////////////// 703 | function hidePost(post, recursive, stubs) { //Pashe, WTFPL 704 | if (!stubs) { 705 | post.jqObj.hide(); 706 | post.jqObj.next("br").remove(); 707 | } else { 708 | window.$("#reply_"+post.no).find(".post-hide-link").trigger("click"); 709 | } 710 | 711 | if (recursive && post.ment.length) { 712 | for (var i in post.ment) { 713 | if (!post.ment.hasOwnProperty(i)) {continue;} 714 | 715 | if (!stubs) { 716 | $("#reply_"+post.ment[i]).hide(); 717 | $("#reply_"+post.ment[i]).next("br").remove(); 718 | } else { 719 | window.$("#reply_"+post.ment[i]).find(".post-hide-link").trigger("click"); 720 | } 721 | } 722 | } 723 | } 724 | 725 | function runFilter() { //Pashe, WTFPL 726 | var $this = $(this); 727 | 728 | var thisPost = { 729 | trip: $this.find("span.trip").text(), 730 | name: $this.find("span.name").text(), 731 | body: $this.find("div.body").text(), 732 | email: $this.find("a.email").attr("href"), 733 | sub: $this.find("span.subject").text(), 734 | flag: $this.find("img.flag").attr("title"), 735 | 736 | cap: $this.find("span.capcode").text(), 737 | ment: $this.find(".mentioned").text().length?$this.find(".mentioned").text().replace(/>>/g, "").replace(/ $/, "").split(" "):[], 738 | 739 | // date: $this.find("time").attr("datetime"), 740 | no: $this.find("a.post_no").first().next().text(), 741 | 742 | jqObj: $this, 743 | // stdObj: this, 744 | }; 745 | 746 | if (thisPost.trip == "!!tKlE5XtNKE") { 747 | $this.find("span.trip").after($(' 8chanX')); 748 | return; 749 | } 750 | 751 | if (isMod) {return;} 752 | 753 | if (getSetting("hideNoFilePosts") && (!$this.find("div.file").length)) { 754 | hidePost(thisPost, false, false); 755 | return; 756 | } 757 | 758 | var filterTypes = { 759 | trip: "Trips", 760 | name: "Names", 761 | body: "Body", 762 | email: "Email", 763 | sub: "Subject", 764 | flag: "Flag", 765 | }; 766 | 767 | for (var i in filterTypes) { 768 | if (!filterTypes.hasOwnProperty(i) || !thisPost[i]) {continue;} 769 | 770 | var filterType = filterTypes[i]; 771 | var filterField = thisPost[i]; 772 | 773 | var filterHideAll = getSetting(sprintf("filter%s", filterType)); 774 | var filterRecursive = getSetting(sprintf("filter%sRecursive", filterType)); 775 | var filterStubs = getSetting(sprintf("filter%sStubs", filterType)); 776 | var filterRegex = getSetting(sprintf("filter%sRegex", filterType)); 777 | 778 | if ((filterHideAll && filterType !== "Names") && filterField.length) { 779 | hidePost(thisPost, filterRecursive, filterStubs); 780 | } else if ((thisBoardAnonName !== undefined) && (filterHideAll && filterType === "Names") && (filterField !== thisBoardAnonName)) { 781 | hidePost(thisPost, filterRecursive, filterStubs); 782 | } else if (filterRegex) { 783 | filterRegex = filterRegex.split('````'); 784 | for (var i in filterRegex) { 785 | var thisRegex; 786 | var thisRegexStr = filterRegex[i].split("```")[0]; 787 | 788 | if (filterRegex[i].split("```").length > 1) { 789 | var thisRegexBoards = filterRegex[i].split("```")[1].split(","); 790 | for (var i in thisRegexBoards) { 791 | if (thisBoard.match(RegExp(thisRegexBoards[i])) !== null) { 792 | thisRegex = new RegExp(thisRegexStr); 793 | if (filterField.match(thisRegex)) {hidePost(thisPost, filterRecursive, filterStubs);} 794 | } 795 | } 796 | } else { 797 | thisRegex = new RegExp(thisRegexStr); 798 | if (filterField.match(thisRegex)) {hidePost(thisPost, filterRecursive, filterStubs);} 799 | } 800 | } 801 | } 802 | } 803 | } 804 | 805 | //////////////// 806 | //INIT FUNCTIONS 807 | //////////////// 808 | function initSettings() { 809 | refreshSettings(); 810 | var settingsItems = settingsMenu.getElementsByTagName("input"); 811 | for (var i in settingsItems) { 812 | if (!settingsItems.hasOwnProperty(i)) {continue;} 813 | setupControl(settingsItems[i]); 814 | } 815 | } 816 | 817 | function initMenu() { //Pashe, WTFPL 818 | var menu = window.document.getElementsByClassName("boardlist")[0]; 819 | var $menu = $(menu); 820 | 821 | // [data-description="0"] - home, boards 822 | // [data-description="1"] - pinned boards (/b/, /meta/, /int/) 823 | // [data-description="2"] - twitter 824 | // [data-description="3"] - top boards 825 | 826 | $('[data-description="1"], [data-description="2"]').hide(); 827 | $(".boardlist.bottom").find('[data-description="0"], [data-description="2"], .favorite-boards').hide(); //Hide stuff that's at the top already 828 | $(".boardlist.bottom").find('[data-description="1"]').show(); //Show pinned boards at the bottom 829 | $(".boardlist.bottom").find('.favorite-boards').next().hide(); //Hide the watchlist link at the bottom 830 | 831 | if ((!$(".boardlist.bottom").find('[data-description="3"]').length) && ($(".boardlist.bottom").find('[data-description="1"]').length)) { 832 | var topBoardsLinks = []; 833 | 834 | $.ajax("/boards-top20.json", { 835 | async: true, 836 | cache: true, 837 | success: function(response) { 838 | for (var x in response) { 839 | topBoardsLinks.push(sprintf( 840 | '%s', 841 | response[x].uri, 842 | response[x].title, 843 | response[x].subtitle, 844 | response[x].tags.join("/"), 845 | response[x].uri 846 | )); 847 | } 848 | $(".boardlist.bottom").find('[data-description="1"]').after(sprintf(' [ %s ]', topBoardsLinks.slice(0,15).join(" / "))); 849 | } 850 | }); 851 | } 852 | 853 | if (getSetting('catalogLinks') && !isOnCatalog()) { 854 | $('.favorite-boards a').each(function () { 855 | $(this).attr("href", $(this).attr("href")+"/catalog.html"); 856 | }); 857 | } 858 | 859 | if (isOnThread()) { 860 | $('#update_secs').remove(); 861 | 862 | var updateNode = $(""); 863 | updateNode.attr("id", "update_secs"); 864 | updateNode.css("font-family", "'Source Code Pro', monospace"); 865 | updateNode.css("padding-left", "3pt"); 866 | updateNode.attr("title","Update thread"); 867 | updateNode.click(function() {$('#update_thread').click();}); 868 | updateNode.appendTo($menu); 869 | 870 | var statsNode = $(""); 871 | statsNode.html( 872 | '--- / ' 873 | +'--- / ' 874 | +'---' 875 | ); 876 | statsNode.attr("id", "menuStats"); 877 | statsNode.css("padding-left", "3pt"); 878 | statsNode.appendTo($menu); 879 | 880 | updateMenuStats(); 881 | 882 | var galleryButton = $(''); 883 | var menuButtonHolder = $('span.sub[data-description=0]').first(); 884 | 885 | menuButtonHolder.html(function() {return this.innerHTML.replace("]", " / ");}); 886 | 887 | galleryButton.appendTo(menuButtonHolder); 888 | menuButtonHolder.html(function() {return this.innerHTML + " ]";}); 889 | 890 | $(".chx_menuGalleryButton").on("click", toggleGallery); //galleryButton isn't the same as $(".chx_menuGalleryButton") after appending the ] to menuButtonHolder. 891 | } 892 | } 893 | 894 | function initRevealImageSpoilers() { //Tux et al, MIT 895 | if (!getSetting('revealImageSpoilers')) {return;} 896 | 897 | $('.post-image').each(function() { 898 | var pic; 899 | if ($(this)[0].tagName == "IMG") { 900 | pic = $(this); 901 | } else if ($(this)[0].tagName == "CANVAS") { 902 | pic = $(this).next(); 903 | } else {return;} 904 | 905 | var picUrl = pic.attr("src"); 906 | if (picUrl.indexOf('spoiler.png') >= 0) { 907 | pic.attr("src", $(this).parent().attr("href")); 908 | pic.addClass("chx_unspoileredImage"); 909 | 910 | pic.css({ 911 | "width": "auto", 912 | "height": "auto", 913 | "max-width": "255px", 914 | "max-height": "255px", 915 | }); 916 | } 917 | }); 918 | } 919 | 920 | function initKeyboardShortcuts() { //Pashe, heavily influenced by Tux et al, WTFPL 921 | if (!getSetting("keyboardShortcutsEnabled")) {return;} 922 | 923 | $(document).keydown(function(e) { 924 | if (e.keyCode == 27) { 925 | $('#quick-reply').remove(); 926 | closeGallery(); 927 | } 928 | 929 | if (e.target.nodeName == "INPUT" || e.target.nodeName == "TEXTAREA") {return;} 930 | if ((!e.ctrlKey) && (!e.metaKey)) { 931 | switch (e.keyCode) { 932 | case 82: 933 | reloadPage(); 934 | break; 935 | case 81: 936 | showQR(); 937 | e.preventDefault(); 938 | break; 939 | case 71: 940 | toggleGallery(); 941 | break; 942 | case 69: 943 | toggleExpandAll(); 944 | break; 945 | case 67: 946 | goToCatalog(); 947 | break; 948 | case 39: 949 | jogExpandedGalleryImage(+1); 950 | break; 951 | case 37: 952 | jogExpandedGalleryImage(-1); 953 | break; 954 | } 955 | } 956 | }); 957 | } 958 | 959 | function initCatalog() { //Pashe, WTFPL 960 | if (!isOnCatalog()) {return;} 961 | 962 | //addCatalogPages 963 | if (getSetting("precisePages")) { 964 | $(".thread").each(function (e, ele) { 965 | var threadId = $(ele).html().match(//)[1]; 966 | var threadPage = getThreadPage(threadId, thisBoard, true); 967 | 968 | if (threadPage < 1) {return;} 969 | 970 | $(ele).find("strong").first().html(function(e, html) { 971 | return html.replace(/P: [0-9]+/, ("P: " + threadPage)); 972 | }); 973 | }); 974 | }; 975 | 976 | //Last Modified 977 | $(".thread").each(function (e, ele) { 978 | var $this = $(this); 979 | var threadId = $this.html().match(/\/res\/([0-9]+).html?">/)[1]; 980 | var threadPage = getThreadPage(threadId, thisBoard, true); 981 | 982 | var timestamp = getThreadLastModified(threadId, thisBoard, true); 983 | if (timestamp == -1) {return;} 984 | var lmDate = new Date(timestamp * 1000); 985 | 986 | var lmTimeElement = $(''); 987 | lmTimeElement.attr("title", lmDate.toGMTString()); 988 | lmTimeElement.attr("data-timestamp", timestamp); 989 | lmTimeElement.attr("data-isotime", lmDate.toISOString()); 990 | lmTimeElement.html("
" + $.timeago(timestamp * 1000)); 991 | lmTimeElement.appendTo($this.find("strong").first()); 992 | }); 993 | 994 | //highlightCatalogAutosage 995 | $.ajax({ 996 | url: "/settings.php?board="+thisBoard, 997 | async: true, 998 | cache: true, 999 | dataType: "json", 1000 | success: function (response) { 1001 | updateBoardSettings(response); 1002 | 1003 | $(".replies").each(function (e, ele) { 1004 | var eReplies = $(ele).html().match(/R: ([0-9]+)/)[1]; 1005 | if (eReplies>bumpLimit) { 1006 | $(ele).html(function(e, html) { 1007 | return html.replace(/R: ([0-9]+)/, "R: $1"); 1008 | }); 1009 | } 1010 | }); 1011 | } 1012 | }); 1013 | 1014 | //setCatalogImageSize 1015 | var catalogStorage = JSON.parse(localStorage.catalog); 1016 | if (!catalogStorage.image_size) { 1017 | catalogStorage.image_size = "large"; 1018 | localStorage.catalog = JSON.stringify(catalogStorage); 1019 | 1020 | $(".grid-li").removeClass("grid-size-vsmall"); 1021 | $(".grid-li").removeClass("grid-size-small"); 1022 | $(".grid-li").removeClass("grid-size-large"); 1023 | $(".grid-li").addClass("grid-size-" + catalogStorage.image_size); 1024 | $("#image_size").val(catalogStorage.image_size); 1025 | } 1026 | 1027 | //addCatalogNullImagePlaceholders 1028 | $("img[src=''], img[src='/static/no-file.png']").attr("src", "data:image/svg+xml;base64,PHN2ZyB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgaGVpZ2h0PSIyMDAiIHdpZHRoPSIyMDAiIHZlcnNpb249IjEuMSI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwtODYwKSI+PHRleHQgc3R5bGU9ImxldHRlci1zcGFjaW5nOjBweDt0ZXh0LWFuY2hvcjptaWRkbGU7d29yZC1zcGFjaW5nOjBweDt0ZXh0LWFsaWduOmNlbnRlcjsiIHhtbDpzcGFjZT0icHJlc2VydmUiIGZvbnQtc2l6ZT0iNjRweCIgeT0iOTMwIiB4PSI5NSIgZm9udC1mYW1pbHk9IidBZG9iZSBDbGVhbiBVSScsIHNhbnMtc2VyaWYiIGxpbmUtaGVpZ2h0PSIxMjUlIiBmaWxsPSIjMDAwMDAwIj48dHNwYW4geD0iOTUiIHk9IjkyOSI+Tm88L3RzcGFuPjx0c3BhbiB4PSI5NSIgeT0iMTAxMCI+SW1hZ2U8L3RzcGFuPjwvdGV4dD48L2c+PC9zdmc+"); 1029 | } 1030 | 1031 | function initRISLinks() { //Pashe, 7185, WTFPL 1032 | if (!getSetting("reverseImageSearch")) {return;} 1033 | $("img.post-image").each(function() {addRISLinks(this);}); 1034 | } 1035 | 1036 | function initParseTimestampImage() { //Pashe, WTFPL 1037 | //if (!getSetting("parseTimestampImage")) {break;} 1038 | try { 1039 | var minTimestamp = new Date(1985,1).valueOf(); 1040 | var maxTimestamp = Date.now()+(24*60*60*1000); 1041 | 1042 | $("p.fileinfo > span.unimportant > a:link").each(function() { 1043 | var $this = $(this); 1044 | var filename = $this.text(); 1045 | 1046 | if (!filename.match(/^([0-9]{9,13})[^a-zA-Z0-9]?.*$/)) {return;} 1047 | var timestamp = parseInt(filename.match(/^([0-9]{9,13})[^a-zA-Z0-9]?.*$/)[1]); 1048 | 1049 | if (timestamp < minTimestamp) {timestamp *= 1000;} 1050 | if ((timestamp < minTimestamp) || (timestamp > maxTimestamp)) {return;} 1051 | 1052 | var fileDate = new Date(timestamp); 1053 | 1054 | var fileTimeElement = $(''); 1055 | fileTimeElement.attr("title", fileDate.toGMTString()); 1056 | fileTimeElement.attr("data-timestamp", timestamp); 1057 | fileTimeElement.attr("data-isotime", fileDate.toISOString()); 1058 | fileTimeElement.text(", " + $.timeago(timestamp) + ")"); 1059 | fileTimeElement.appendTo($this.parent()); 1060 | 1061 | $this.parent().html(function(e, html) { 1062 | return html.replace(")", ""); 1063 | }); 1064 | }); 1065 | } catch (e) {} 1066 | } 1067 | 1068 | function initNotifications() { 1069 | Notification.requestPermission(); 1070 | } 1071 | 1072 | function initMascot() { //Pashe, based on an anonymous contribution, WTFPL 1073 | if (!getSetting("mascotUrl")) {return;} 1074 | 1075 | var mascotUrls = getSetting("mascotUrl").split("|"); 1076 | var mascotUrl = mascotUrls[Math.floor((Math.random()*mascotUrls.length))]; 1077 | 1078 | $("head").append( 1079 | "" 1102 | ); 1103 | 1104 | var mascotHolder = $('
'); 1105 | var mascotImage = $(''); 1106 | var hostElement = $("body").first(); 1107 | 1108 | mascotImage.attr("src", mascotUrl); 1109 | 1110 | mascotImage.appendTo(mascotHolder); 1111 | mascotHolder.appendTo(hostElement); 1112 | 1113 | if (isOnCatalog()) {mascotImage.css("z-index", "-100");} 1114 | } 1115 | 1116 | function initpurgeDeadFavorites() { //Pashe, WTFPL 1117 | $("#chx_purgeDeadFavorites").click(function() { 1118 | console.log("Working..."); 1119 | var originalText = $("#chx_purgeDeadFavorites").text(); 1120 | $("#chx_purgeDeadFavorites").text("Working..."); 1121 | $("#chx_purgeDeadFavorites").prop("disabled", true); 1122 | var boards; 1123 | $.ajax({ 1124 | url: "/boards.json", 1125 | async: false, 1126 | dataType: "json", 1127 | success: function (response) {boards = response;} 1128 | }); 1129 | var boardsURIs = []; 1130 | var favorites = JSON.parse(localStorage.favorites); 1131 | 1132 | for (var x in boards) { 1133 | if (!boards.hasOwnProperty(x)) {continue;} 1134 | boardsURIs.push(boards[x].uri); 1135 | } 1136 | 1137 | if (boardsURIs.length > 0) { 1138 | for (var i=0; i').attr("rel", "shortcut icon").attr("href", faviconUrl).appendTo($("head").first()); 1173 | } 1174 | 1175 | function initFlagIcons() { //Anon from >>>/tech/60489, presumably WTFPL or similar 1176 | if (!$("#user_flag").length) {return;} 1177 | 1178 | var board = window.location.pathname.replace(/^\/([^/]+).*?$/, "$1"); 1179 | var custom_flag_url = window.location.origin + '/static/custom-flags/' + board + '/'; 1180 | var dropdown_options = document.getElementById('user_flag').childNodes; 1181 | 1182 | if (!dropdown_options || !dropdown_options.length) return; 1183 | 1184 | for (var i = 0; i < dropdown_options.length; i++) { 1185 | var opt = dropdown_options[i]; 1186 | opt.style.paddingLeft = '20px'; 1187 | if (opt.value) 1188 | opt.style.background = 'no-repeat left center url(' + custom_flag_url + opt.value + '.png)'; 1189 | } 1190 | } 1191 | 1192 | function initFormattedTime() { //Pashe, WTFPL 1193 | if (!getSetting("dateFormat")) {return;} 1194 | 1195 | $("time").text(function() { 1196 | //%Y-%m-%d %H:%M:%S is nice 1197 | 1198 | var $this = $(this); 1199 | 1200 | var thisDate = new Date($this.attr("datetime")); 1201 | 1202 | if (getSetting("localTime")) { 1203 | return strftime(getSetting("dateFormat"), thisDate); 1204 | } else { 1205 | return strftimeUTC(getSetting("dateFormat"), thisDate); 1206 | } 1207 | }); 1208 | } 1209 | 1210 | function initFilter() { //Pashe, WTFPL 1211 | $(".reply").each(runFilter); 1212 | 1213 | $.ajax({ 1214 | url: "/settings.php?board="+thisBoard, 1215 | async: true, 1216 | cache: true, 1217 | dataType: "json", 1218 | success: function (response) { 1219 | updateBoardSettings(response); 1220 | 1221 | $(".reply").each(runFilter); 1222 | } 1223 | }); 1224 | } 1225 | 1226 | //////////////// 1227 | //INIT CALLS 1228 | //////////////// 1229 | $(window.document).ready(function() { try { 1230 | initSettings(); 1231 | initDefaultSettings(); 1232 | initMenu(); 1233 | initCatalog(); 1234 | initFilter(); 1235 | initFormattedTime(); 1236 | initMascot(); 1237 | initRevealImageSpoilers(); 1238 | initRISLinks(); 1239 | initParseTimestampImage(); 1240 | initNotifications(); 1241 | initFlagIcons(); 1242 | initKeyboardShortcuts(); 1243 | initpurgeDeadFavorites(); 1244 | initFavicon(); 1245 | } catch(e) {chxErrorHandler(e, "ready");}}); 1246 | 1247 | //////////////// 1248 | //EVENT HANDLER FUNCTIONS 1249 | //////////////// 1250 | function onNewPostRISLinks(post) { //Pashe, 7185, WTFPL 1251 | $("#"+$(post).attr("id")+" img.post-image").each(function() {addRISLinks(this);}); 1252 | } 1253 | 1254 | function onNewPostNotifications(post) { 1255 | var $post = $(post); 1256 | if ($post.is('div.post.reply')) { 1257 | $post.each(notifyReplies); 1258 | } else { 1259 | $post.find('div.post.reply').each(notifyReplies); 1260 | } 1261 | } 1262 | 1263 | function onNewPostFormattedTime() { 1264 | initFormattedTime(); 1265 | } 1266 | 1267 | function onNewPostFilter(post) { //Pashe, WTFPL 1268 | $(post).each(runFilter); 1269 | } 1270 | 1271 | function intervalMenu() { 1272 | updateMenuStats(); 1273 | } 1274 | 1275 | //////////////// 1276 | //EVENT HANDLERS 1277 | //////////////// 1278 | if (window.jQuery) { 1279 | window.$(document).on('new_post', function (e, post) { try { 1280 | onNewPostRISLinks(post); 1281 | onNewPostNotifications(post); 1282 | onNewPostFormattedTime(); 1283 | onNewPostFilter(post); 1284 | } catch(e) {chxErrorHandler(e, "newpost");}}); 1285 | 1286 | setInterval(intervalMenu, (1.5*60*1000)); 1287 | } 1288 | } catch(e) {chxErrorHandler(e, "global");} 1289 | --------------------------------------------------------------------------------