From bf0ea30fdc985503e1bbc9d0eef8b22380e7d327 Mon Sep 17 00:00:00 2001 From: NoneGiven Date: Fri, 18 Oct 2013 01:06:50 -0500 Subject: [PATCH 001/225] New keybind: catalog search box. Close #1306, #1297. --- CHANGELOG.md | 4 +++- src/General/Config.coffee | 1 + src/Miscellaneous/Keybinds.coffee | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 639a34805..f326664c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +Added a keybind to open the catalog search form on index pages. + ### 3.11.5 - *2013-10-03* Minor Chrome 30 fix. @@ -17,7 +19,7 @@ Update posting cooldown timers to match 4chan settings: ### 3.11.2 - *2013-09-17* -Updated post and deletion cooldown timers to match 4chan changes: they are now twice longer. +Updated post and deletion cooldown timers to match 4chan changes: they are now twice as long. ### 3.11.1 - *2013-09-13* diff --git a/src/General/Config.coffee b/src/General/Config.coffee index a214386d5..1119d17d5 100644 --- a/src/General/Config.coffee +++ b/src/General/Config.coffee @@ -181,6 +181,7 @@ Config = 'Open front page': ['Shift+0', 'Open page 0 in a new tab.'] 'Next page': ['Right', 'Jump to the next page.'] 'Previous page': ['Left', 'Jump to the previous page.'] + 'Search form': ['Ctrl+Alt+s', 'Open the catalog search form.'] # Thread Navigation 'Next thread': ['Down', 'See next thread.'] 'Previous thread': ['Up', 'See previous thread.'] diff --git a/src/Miscellaneous/Keybinds.coffee b/src/Miscellaneous/Keybinds.coffee index 50177e169..36c193e97 100644 --- a/src/Miscellaneous/Keybinds.coffee +++ b/src/Miscellaneous/Keybinds.coffee @@ -73,6 +73,8 @@ Keybinds = when Conf['Previous page'] if form = $ '.prev form' window.location = form.action + when Conf['Search form'] + $.id('search-btn').click() # Thread Navigation when Conf['Next thread'] return if g.VIEW isnt 'index' From fe4c610ae3407dfca9a0deb37ae735a0d0098df5 Mon Sep 17 00:00:00 2001 From: NoneGiven Date: Tue, 22 Oct 2013 20:44:07 -0500 Subject: [PATCH 002/225] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f326664c5..bd43be2d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -Added a keybind to open the catalog search form on index pages. +Added a keybind to open the catalog search field on index pages. ### 3.11.5 - *2013-10-03* From 2bcb79625fd6c679c2e74315b9cd79ea951ab619 Mon Sep 17 00:00:00 2001 From: NoneGiven Date: Tue, 22 Oct 2013 20:46:07 -0500 Subject: [PATCH 003/225] Update Config.coffee --- src/General/Config.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/General/Config.coffee b/src/General/Config.coffee index 1119d17d5..1421ff806 100644 --- a/src/General/Config.coffee +++ b/src/General/Config.coffee @@ -181,7 +181,7 @@ Config = 'Open front page': ['Shift+0', 'Open page 0 in a new tab.'] 'Next page': ['Right', 'Jump to the next page.'] 'Previous page': ['Left', 'Jump to the previous page.'] - 'Search form': ['Ctrl+Alt+s', 'Open the catalog search form.'] + 'Search form': ['Ctrl+Alt+s', 'Open the search field on the board index.'] # Thread Navigation 'Next thread': ['Down', 'See next thread.'] 'Previous thread': ['Up', 'See previous thread.'] From cbd01e9fb922b96fb71f71baf6f05cd2bb8789b2 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Wed, 23 Oct 2013 20:21:18 +0200 Subject: [PATCH 004/225] Update deps. --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index f4ee36b15..d125f0509 100644 --- a/package.json +++ b/package.json @@ -26,8 +26,8 @@ "grunt-contrib-concat": "~0.3.0", "grunt-contrib-copy": "~0.4.1", "grunt-contrib-watch": "~0.5.3", - "grunt-shell": "~0.4.0", - "load-grunt-tasks": "~0.1.0" + "grunt-shell": "~0.5.0", + "load-grunt-tasks": "~0.2.0" }, "repository": { "type": "git", From 4ff5fd287a4950c4cf4e4774c19bc7831881ddb8 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Wed, 23 Oct 2013 21:13:10 +0200 Subject: [PATCH 005/225] Update FontAwesome. --- css/style.css | 6 +++--- html/Monitoring/ThreadWatcher.html | 2 +- package.json | 2 +- src/General/Header.coffee | 2 +- src/General/Main.coffee | 2 +- src/Images/ImageExpand.coffee | 6 +++--- src/Monitoring/ThreadWatcher.coffee | 4 ++-- src/Posting/QR.coffee | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/css/style.css b/css/style.css index dbba61fa3..a67c82043 100644 --- a/css/style.css +++ b/css/style.css @@ -842,7 +842,7 @@ a.hide-announcement { .menu-button { position: relative; } -.menu-button i:not(.icon-reorder) { +.menu-button i:not(.fa-reorder) { border-top: 6px solid; border-right: 4px solid transparent; border-left: 4px solid transparent; @@ -851,10 +851,10 @@ a.hide-announcement { vertical-align: middle; } @media screen and (resolution: 1dppx) { - .icon-reorder { + .fa-reorder { font-size: 14px; } - #shortcuts .icon-reorder { + #shortcuts .fa-reorder { vertical-align: -1px; } } diff --git a/html/Monitoring/ThreadWatcher.html b/html/Monitoring/ThreadWatcher.html index c0b5810b2..3d5b180b0 100644 --- a/html/Monitoring/ThreadWatcher.html +++ b/html/Monitoring/ThreadWatcher.html @@ -1,5 +1,5 @@
Thread Watcher - +
diff --git a/package.json b/package.json index d125f0509..a52639338 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ ] }, "devDependencies": { - "font-awesome": "git://github.com/MayhemYDG/Font-Awesome.git#df4285951124f9ca1f3907438462e5ba9e464bcb", + "font-awesome": "https://github.com/FortAwesome/Font-Awesome/archive/v4.0.0.tar.gz", "grunt": "~0.4.1", "grunt-bump": "~0.0.11", "grunt-concurrent": "~0.4.0", diff --git a/src/General/Header.coffee b/src/General/Header.coffee index 5515c70e6..e16001638 100644 --- a/src/General/Header.coffee +++ b/src/General/Header.coffee @@ -12,7 +12,7 @@ Header = @menu = new UI.Menu 'header' menuButton = $.el 'a', className: 'menu-button' - innerHTML: '' + innerHTML: '' href: 'javascript:;' $.on menuButton, 'click', @menuToggle @addShortcut menuButton, 0 diff --git a/src/General/Main.coffee b/src/General/Main.coffee index 2d7d1c3e6..b86b5c7c5 100644 --- a/src/General/Main.coffee +++ b/src/General/Main.coffee @@ -311,7 +311,7 @@ Main = css: """ @font-face { font-family: 'FontAwesome'; - src: url('data:application/font-woff;base64,<%= grunt.file.read('node_modules/font-awesome/font/fontawesome-webfont.woff', {encoding: 'base64'}) %>') format('woff'); + src: url('data:application/font-woff;base64,<%= grunt.file.read('node_modules/font-awesome/fonts/fontawesome-webfont.woff', {encoding: 'base64'}) %>') format('woff'); font-weight: normal; font-style: normal; } diff --git a/src/Images/ImageExpand.coffee b/src/Images/ImageExpand.coffee index b8e8e7b15..17b8066d3 100644 --- a/src/Images/ImageExpand.coffee +++ b/src/Images/ImageExpand.coffee @@ -3,7 +3,7 @@ ImageExpand = return if g.VIEW is 'catalog' or !Conf['Image Expansion'] @EAI = $.el 'a', - className: 'expand-all-shortcut icon-resize-full' + className: 'expand-all-shortcut fa fa-resize-full' title: 'Expand All Images' href: 'javascript:;' $.on @EAI, 'click', ImageExpand.cb.toggleAll @@ -32,11 +32,11 @@ ImageExpand = toggleAll: -> $.event 'CloseMenu' if ImageExpand.on = $.hasClass ImageExpand.EAI, 'expand-all-shortcut' - ImageExpand.EAI.className = 'contract-all-shortcut icon-resize-small' + ImageExpand.EAI.className = 'contract-all-shortcut fa fa-resize-small' ImageExpand.EAI.title = 'Contract All Images' func = ImageExpand.expand else - ImageExpand.EAI.className = 'expand-all-shortcut icon-resize-full' + ImageExpand.EAI.className = 'expand-all-shortcut fa fa-resize-full' ImageExpand.EAI.title = 'Expand All Images' func = ImageExpand.contract for ID, post of g.posts diff --git a/src/Monitoring/ThreadWatcher.coffee b/src/Monitoring/ThreadWatcher.coffee index a682d8df0..54bfb9435 100644 --- a/src/Monitoring/ThreadWatcher.coffee +++ b/src/Monitoring/ThreadWatcher.coffee @@ -149,10 +149,10 @@ ThreadWatcher = for threadID, thread of g.BOARD.threads $.extend $('.watcher-toggler', thread.OP.nodes.post), if ThreadWatcher.db.get {boardID: thread.board.ID, threadID} - className: 'watcher-toggler icon-bookmark' + className: 'watcher-toggler fa fa-bookmark' title: 'Unwatch thread' else - className: 'watcher-toggler icon-bookmark-empty' + className: 'watcher-toggler fa fa-bookmark-o' title: 'Watch thread' for refresher in ThreadWatcher.menu.refreshers diff --git a/src/Posting/QR.coffee b/src/Posting/QR.coffee index 751ac6a53..d0be4c445 100644 --- a/src/Posting/QR.coffee +++ b/src/Posting/QR.coffee @@ -19,7 +19,7 @@ QR = return unless QR.postingIsEnabled sc = $.el 'a', - className: 'qr-shortcut icon-comment-alt' + className: 'qr-shortcut fa fa-comment-o' title: 'Quick Reply' href: 'javascript:;' $.on sc, 'click', -> From 4dc8d013f3883e1bf854bd507471436068e90af7 Mon Sep 17 00:00:00 2001 From: NemDiggers Date: Wed, 23 Oct 2013 19:46:17 -0400 Subject: [PATCH 006/225] Remove WAP Needless to say, after a rather long phone call with a certain powerful agency, it's probably best I shuttered the service. At least I got to learn how to handle huge SQL databases with millions of rows and how to optimize things. --- json/archives.json | 9 --------- 1 file changed, 9 deletions(-) diff --git a/json/archives.json b/json/archives.json index 4faec708b..f783e8110 100644 --- a/json/archives.json +++ b/json/archives.json @@ -43,15 +43,6 @@ "software": "foolfuuka", "boards": ["c", "w", "wg"], "files": ["c", "w", "wg"] -}, { - "uid": 12, - "name": "FapArchive", - "domain": "fuuka.worldathleticproject.org", - "http": true, - "https": true, - "software": "foolfuuka", - "boards": ["adv", "b", "cm", "d", "e", "h", "hc", "lgbt", "pol", "r", "s", "s4s", "soc", "trv", "u", "y"], - "files": ["b", "cm", "d", "e", "h", "hc", "pol", "r", "s", "s4s", "soc", "u", "y"] }, { "uid": 7, "name": "Install Gentoo", From 5157954b09041f13cc7246714f9a4eb93eb66d3b Mon Sep 17 00:00:00 2001 From: Mayhem Date: Wed, 23 Oct 2013 23:33:31 +0200 Subject: [PATCH 007/225] Sync keybinds across tabs. --- lib/$.coffee | 8 ++++---- src/Miscellaneous/Keybinds.coffee | 6 ++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/$.coffee b/lib/$.coffee index bfea3c47f..8b2202304 100644 --- a/lib/$.coffee +++ b/lib/$.coffee @@ -211,7 +211,7 @@ $.sync = do -> chrome.storage.onChanged.addListener (changes) -> for key of changes if cb = $.syncing[key] - cb changes[key].newValue + cb changes[key].newValue, key return (key, cb) -> $.syncing[key] = cb $.localKeys = [ @@ -289,9 +289,9 @@ $.set = do -> <% } else { %> # http://wiki.greasespot.net/Main_Page $.sync = do -> - $.on window, 'storage', (e) -> - if cb = $.syncing[e.key] - cb JSON.parse e.newValue + $.on window, 'storage', ({key, newValue}) -> + if cb = $.syncing[key] + cb JSON.parse(newValue), key (key, cb) -> $.syncing[g.NAMESPACE + key] = cb $.delete = (keys) -> unless keys instanceof Array diff --git a/src/Miscellaneous/Keybinds.coffee b/src/Miscellaneous/Keybinds.coffee index 36c193e97..a06a6043b 100644 --- a/src/Miscellaneous/Keybinds.coffee +++ b/src/Miscellaneous/Keybinds.coffee @@ -2,6 +2,9 @@ Keybinds = init: -> return if g.VIEW is 'catalog' or !Conf['Keybinds'] + for hotkey of Conf.hotkeys + $.sync hotkey, Keybinds.sync + init = -> $.off d, '4chanXInitFinished', init $.on d, 'keydown', Keybinds.keydown @@ -10,6 +13,9 @@ Keybinds = return $.on d, '4chanXInitFinished', init + sync: (key, hotkey) -> + Conf[hotkey] = key + keydown: (e) -> return unless key = Keybinds.keyCode e {target} = e From f94759049d89721203d14f92c002ad45ee057d25 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Thu, 24 Oct 2013 02:41:34 +0200 Subject: [PATCH 008/225] Remove some board redirection to beta foolz since we can't default to them for non-beta users. --- json/archives.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/json/archives.json b/json/archives.json index f783e8110..ed621fa22 100644 --- a/json/archives.json +++ b/json/archives.json @@ -87,6 +87,6 @@ "https": true, "withCredentials": true, "software": "foolfuuka", - "boards": ["a", "co", "d", "gd", "h", "jp", "m", "mlp", "sp", "tg", "tv", "u", "v", "vg", "vp", "vr", "wsg"], - "files": ["a", "d", "gd", "h", "jp", "m", "tg", "u", "vg", "vp", "vr", "wsg"] + "boards": ["a", "co", "gd", "jp", "m", "mlp", "sp", "tg", "tv", "u", "v", "vg", "vp", "vr", "wsg"], + "files": ["a", "gd", "jp", "m", "tg", "u", "vg", "vp", "vr", "wsg"] }] From db296736483e5bb4b998424f8dd2c91c70fef77f Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 2 Nov 2013 16:52:22 +0100 Subject: [PATCH 009/225] Nuke 404ing boards in DataBoards again. See 667abe7480b04161ec10cf00fffad17accdf23a0 --- src/General/DataBoard.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/General/DataBoard.coffee b/src/General/DataBoard.coffee index 066b599c1..0e366ff50 100644 --- a/src/General/DataBoard.coffee +++ b/src/General/DataBoard.coffee @@ -70,7 +70,9 @@ class DataBoard @save() ajaxClean: (boardID) -> $.cache "//api.4chan.org/#{boardID}/threads.json", (e) => - return if e.target.status isnt 200 + if e.target.status isnt 200 + @delete boardID if e.target.status is 404 + return board = @data.boards[boardID] threads = {} for page in JSON.parse e.target.response From a22bce79abc00a4b009f6548a5d2309b9b76d8b6 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 2 Nov 2013 19:20:28 +0100 Subject: [PATCH 010/225] Warn users about outdated versions of Greasemonkey. --- package.json | 7 ++++++- src/General/Main.coffee | 9 +++++++++ src/Meta/manifest.json | 2 +- src/Meta/metadata.js | 4 ++-- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index a52639338..d4c4650e4 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,12 @@ "*://boards.4chan.org/*", "*://images.4chan.org/*", "*://sys.4chan.org/*" - ] + ], + "min": { + "chrome": "29", + "firefox": "22", + "greasemonkey": "1.12" + } }, "devDependencies": { "font-awesome": "https://github.com/FortAwesome/Font-Awesome/archive/v4.0.0.tar.gz", diff --git a/src/General/Main.coffee b/src/General/Main.coffee index b86b5c7c5..9410365c0 100644 --- a/src/General/Main.coffee +++ b/src/General/Main.coffee @@ -195,6 +195,15 @@ Main = Main.disableReports = true alert '4chan X v2 detected: Disable it or v3 will break.' + <% if (type === 'userscript') { %> + GMver = GM_info.version.split '.' + for v, i in "<%= meta.min.greasemonkey %>".split '.' + break if v < GMver[i] + continue if v is GMver[i] + new Notice 'warning', "Your version of Greasemonkey is outdated (v#{GM_info.version} instead of v<%= meta.min.greasemonkey %> minimum) and <%= meta.name %> may not operate correctly.", 30 + break + <% } %> + try localStorage.getItem '4chan-settings' catch err diff --git a/src/Meta/manifest.json b/src/Meta/manifest.json index b7c607807..d1c79c7a7 100644 --- a/src/Meta/manifest.json +++ b/src/Meta/manifest.json @@ -15,7 +15,7 @@ "run_at": "document_start" }], "homepage_url": "<%= meta.page %>", - "minimum_chrome_version": "29", + "minimum_chrome_version": "<%= meta.min.chrome %>", "permissions": [ "storage" ] diff --git a/src/Meta/metadata.js b/src/Meta/metadata.js index 770051fbe..6a1ff3a66 100644 --- a/src/Meta/metadata.js +++ b/src/Meta/metadata.js @@ -1,8 +1,8 @@ // ==UserScript== // @name <%= meta.name %> // @version <%= version %> -// @minGMVer 1.13 -// @minFFVer 22 +// @minGMVer <%= meta.min.greasemonkey %> +// @minFFVer <%= meta.min.firefox %> // @namespace <%= name %> // @description <%= description %> // @license MIT; <%= meta.repo %>blob/<%= meta.mainBranch %>/LICENSE From ef38269981099d888a607111ea5a00f481e54889 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Tue, 29 Oct 2013 19:13:34 +0100 Subject: [PATCH 011/225] Initial work for index navigation improvements. --- src/General/Config.coffee | 4 +-- src/General/Header.coffee | 8 +++--- src/General/Main.coffee | 1 + src/Miscellaneous/Index.coffee | 41 +++++++++++++++++++++++++++++ src/Miscellaneous/Keybinds.coffee | 10 ++++--- src/Monitoring/ThreadUpdater.coffee | 4 +-- src/Monitoring/Unread.coffee | 4 +-- 7 files changed, 59 insertions(+), 13 deletions(-) create mode 100644 src/Miscellaneous/Index.coffee diff --git a/src/General/Config.coffee b/src/General/Config.coffee index 1421ff806..4f422357e 100644 --- a/src/General/Config.coffee +++ b/src/General/Config.coffee @@ -170,9 +170,9 @@ Config = 'Eqn tags': ['Alt+e', 'Insert eqn tags.'] 'Math tags': ['Alt+m', 'Insert math tags.'] 'Submit QR': ['Alt+s', 'Submit post.'] - # Thread related + # Index/Thread related + 'Update': ['r', 'Refresh the index/thread.'] 'Watch': ['w', 'Watch thread.'] - 'Update': ['r', 'Update the thread.'] # Images 'Expand image': ['Shift+e', 'Expand selected image.'] 'Expand images': ['e', 'Expand all images.'] diff --git a/src/General/Header.coffee b/src/General/Header.coffee index e16001638..7eb6e06fe 100644 --- a/src/General/Header.coffee +++ b/src/General/Header.coffee @@ -246,8 +246,8 @@ Header = hashScroll: -> return unless (hash = @location.hash[1..]) and post = $.id hash return if (Get.postFromRoot post).isHidden - Header.scrollToPost post - scrollToPost: (post) -> + Header.scrollTo post + scrollTo: (post) -> {top} = post.getBoundingClientRect() unless Conf['Bottom header'] headRect = Header.toggle.getBoundingClientRect() @@ -268,8 +268,8 @@ Header = createNotification: (e) -> {type, content, lifetime, cb} = e.detail - notif = new Notice type, content, lifetime - cb notif if cb + notice = new Notice type, content, lifetime + cb notice if cb areNotificationsEnabled: false enableDesktopNotifications: -> diff --git a/src/General/Main.coffee b/src/General/Main.coffee index 9410365c0..2829eb208 100644 --- a/src/General/Main.coffee +++ b/src/General/Main.coffee @@ -69,6 +69,7 @@ Main = initFeature 'Polyfill', Polyfill initFeature 'Header', Header initFeature 'Settings', Settings + initFeature 'Index Pager', Index initFeature 'Announcement Hiding', PSAHiding initFeature 'Fourchan thingies', Fourchan initFeature 'Custom CSS', CustomCSS diff --git a/src/Miscellaneous/Index.coffee b/src/Miscellaneous/Index.coffee new file mode 100644 index 000000000..06aa5b329 --- /dev/null +++ b/src/Miscellaneous/Index.coffee @@ -0,0 +1,41 @@ +Index = + init: -> + return if g.VIEW isnt 'index' + + update: -> + # return unless navigator.onLine + Index.req?.abort() + Index.notice?.close() + Index.notice = new Notice 'info', 'Refreshing index...' + Index.req = $.ajax "//api.4chan.org/#{g.BOARD}/catalog.json", + onabort: Index.load + onloadend: Index.load + , + whenModified: true + load: (e) -> + {req, notice} = Index + delete Index.req + delete Index.notice + + if e.type is 'abort' + req.onloadend = null + notice.close() + return + + try + Index.parse JSON.parse req.response + catch e + # network error or non-JSON content for example. + notice.setType 'error' + notice.el.lastElementChild.textContent = 'Index refresh failed.' + setTimeout notice.close, 2 * $.SECOND + return + + notice.setType 'success' + notice.el.lastElementChild.textContent = 'Index refreshed!' + setTimeout notice.close, $.SECOND + + Header.scrollTo $.id 'delform' + parse: (pages) -> + pageNum = +window.location.pathname.split('/')[2] + threads = pages[pageNum].threads diff --git a/src/Miscellaneous/Keybinds.coffee b/src/Miscellaneous/Keybinds.coffee index a06a6043b..31a237e9c 100644 --- a/src/Miscellaneous/Keybinds.coffee +++ b/src/Miscellaneous/Keybinds.coffee @@ -58,11 +58,15 @@ Keybinds = Keybinds.tags 'math', target when Conf['Submit QR'] QR.submit() if QR.nodes and !QR.status() - # Thread related + # Index/Thread related + when Conf['Update'] + switch g.VIEW + when 'thread' + ThreadUpdater.update() + when 'index' + Index.update() when Conf['Watch'] ThreadWatcher.toggle thread - when Conf['Update'] - ThreadUpdater.update() # Images when Conf['Expand image'] Keybinds.img threadRoot diff --git a/src/Monitoring/ThreadUpdater.coffee b/src/Monitoring/ThreadUpdater.coffee index 677db825d..03c8b5053 100644 --- a/src/Monitoring/ThreadUpdater.coffee +++ b/src/Monitoring/ThreadUpdater.coffee @@ -145,7 +145,7 @@ ThreadUpdater = return unless navigator.onLine ThreadUpdater.count() ThreadUpdater.set 'timer', '...' - ThreadUpdater.req.abort() if ThreadUpdater.req + ThreadUpdater.req?.abort() url = "//api.4chan.org/#{ThreadUpdater.thread.board}/res/#{ThreadUpdater.thread}.json" ThreadUpdater.req = $.ajax url, onabort: ThreadUpdater.cb.load @@ -258,7 +258,7 @@ ThreadUpdater = if Conf['Bottom Scroll'] window.scrollTo 0, d.body.clientHeight else - Header.scrollToPost nodes[0] + Header.scrollTo nodes[0] # Enable 4chan features. threadID = ThreadUpdater.thread.ID diff --git a/src/Monitoring/Unread.coffee b/src/Monitoring/Unread.coffee index fc7e2940e..2898c6c69 100644 --- a/src/Monitoring/Unread.coffee +++ b/src/Monitoring/Unread.coffee @@ -47,7 +47,7 @@ Unread = # Scroll to the last read post. posts = Object.keys Unread.thread.posts {root} = Unread.thread.posts[posts[posts.length - 1]].nodes - onload = -> Header.scrollToPost root if checkPosition root + onload = -> Header.scrollTo root if checkPosition root checkPosition = (target) -> # Scroll to the target unless we scrolled past it. target.getBoundingClientRect().bottom > doc.clientHeight @@ -102,7 +102,7 @@ Unread = body: post.info.comment icon: Favicon.logo notif.onclick = -> - Header.scrollToPost post.nodes.root + Header.scrollTo post.nodes.root window.focus() notif.onshow = -> setTimeout -> From fecf286d26ad07a5b9641da9543594a0bd7d3232 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Tue, 29 Oct 2013 23:52:49 +0100 Subject: [PATCH 012/225] Make index page refreshing work. --- CHANGELOG.md | 2 ++ src/General/Build.coffee | 24 +++++++++++++++++++++ src/General/Main.coffee | 2 +- src/Miscellaneous/Index.coffee | 38 ++++++++++++++++++++++++++++++---- 4 files changed, 61 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd43be2d1..7f9c77613 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +Index navigation improvements: + - You can now refresh the index page you are on with the same keybind for refreshing threads. Added a keybind to open the catalog search field on index pages. ### 3.11.5 - *2013-10-03* diff --git a/src/General/Build.coffee b/src/General/Build.coffee index 783a774f5..b229c71a7 100644 --- a/src/General/Build.coffee +++ b/src/General/Build.coffee @@ -248,3 +248,27 @@ Build = quote.href = "/#{boardID}/res/#{href}" # Fix pathnames container + + thread: (board, data) -> + root = $.el 'div', + className: 'thread' + id: "t#{data.no}" + + for obj in [data].concat data.last_replies or [] + $.add root, if post = g.posts["#{board}.#{obj.no}"] + post.nodes.root + else + Build.postFromObject obj, board.ID + + # build if necessary + if data.omitted_posts + {omitted_posts, omitted_images} = data + html = [] + html.push "#{omitted_posts} post#{if omitted_posts > 1 then 's' else ''}" + html.push "and #{omitted_images} image repl#{if omitted_images > 1 then 'ies' else 'y'}" if omitted_images + html.push "omitted. Click here to view." + $.after root.firstChild, $.el 'span', + className: 'summary' + innerHTML: html.join ' ' + + root diff --git a/src/General/Main.coffee b/src/General/Main.coffee index 2829eb208..604393db8 100644 --- a/src/General/Main.coffee +++ b/src/General/Main.coffee @@ -185,7 +185,7 @@ Main = unless errors errors = [] errors.push - message: "Parsing of Post No.#{postRoot.id.match(/\d+/)} failed. Post will be skipped." + message: "Parsing of Post No.#{postRoot.id.match /\d+/} failed. Post will be skipped." error: err Main.handleErrors errors if errors diff --git a/src/Miscellaneous/Index.coffee b/src/Miscellaneous/Index.coffee index 06aa5b329..a277d76fd 100644 --- a/src/Miscellaneous/Index.coffee +++ b/src/Miscellaneous/Index.coffee @@ -3,7 +3,7 @@ Index = return if g.VIEW isnt 'index' update: -> - # return unless navigator.onLine + return unless navigator.onLine Index.req?.abort() Index.notice?.close() Index.notice = new Notice 'info', 'Refreshing index...' @@ -23,8 +23,9 @@ Index = return try - Index.parse JSON.parse req.response - catch e + Index.parse JSON.parse req.response if req.status is 200 + catch err + c.error err.stack # network error or non-JSON content for example. notice.setType 'error' notice.el.lastElementChild.textContent = 'Index refresh failed.' @@ -38,4 +39,33 @@ Index = Header.scrollTo $.id 'delform' parse: (pages) -> pageNum = +window.location.pathname.split('/')[2] - threads = pages[pageNum].threads + dataThr = pages[pageNum].threads + + nodes = [] + threads = [] + posts = [] + for data in dataThr + threadRoot = Build.thread g.BOARD, data + nodes.push threadRoot, $.el 'hr' + unless thread = g.threads["#{g.BOARD}.#{data.no}"] + thread = new Thread data.no, g.BOARD + threads.push thread + for postRoot in $$ '.thread > .postContainer', threadRoot + continue if thread.posts[postRoot.id.match /\d+/] + try + posts.push new Post postRoot, thread, g.BOARD + catch err + # Skip posts that we failed to parse. + unless errors + errors = [] + errors.push + message: "Parsing of Post No.#{postRoot.id.match /\d+/} failed. Post will be skipped." + error: err + Main.handleErrors errors if errors + + Main.callbackNodes Thread, threads + Main.callbackNodes Post, posts + + board = $ '.board' + $.rmAll board + $.add board, nodes From a5d72fe515060fbc3595bd623fcc0bc5e04828ff Mon Sep 17 00:00:00 2001 From: Mayhem Date: Wed, 30 Oct 2013 00:07:00 +0100 Subject: [PATCH 013/225] Build missing [Reply] button. --- src/General/Build.coffee | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/General/Build.coffee b/src/General/Build.coffee index b229c71a7..fb3843804 100644 --- a/src/General/Build.coffee +++ b/src/General/Build.coffee @@ -186,6 +186,11 @@ Build = else '' + replyLink = if isOP and g.VIEW is 'index' + "   [Reply]" + else + '' + container = $.el 'div', id: "pc#{postID}" className: "postContainer #{if isOP then 'op' else 'reply'}Container" @@ -233,6 +238,7 @@ Build = else "/#{boardID}/res/#{threadID}#q#{postID}" }' title='Quote this post'>#{postID}" + + replyLink + '' + '' + @@ -266,7 +272,7 @@ Build = html = [] html.push "#{omitted_posts} post#{if omitted_posts > 1 then 's' else ''}" html.push "and #{omitted_images} image repl#{if omitted_images > 1 then 'ies' else 'y'}" if omitted_images - html.push "omitted. Click here to view." + html.push "omitted. Click here to view." $.after root.firstChild, $.el 'span', className: 'summary' innerHTML: html.join ' ' From 1996fc435174951e058ecc2cd7bcc1f7a4d31531 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Wed, 30 Oct 2013 02:45:18 +0100 Subject: [PATCH 014/225] Add all-pages index navigation. Close #1133 --- CHANGELOG.md | 1 + src/General/Build.coffee | 2 +- src/General/Config.coffee | 1 + src/General/Main.coffee | 2 +- src/Miscellaneous/Index.coffee | 36 ++++++++++++++++++++++++++++++++-- 5 files changed, 38 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f9c77613..69308c0cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ Index navigation improvements: - You can now refresh the index page you are on with the same keybind for refreshing threads. + - You can now switch between single-page and all-pages navigation via the "Index Navigation" header sub-menu. Added a keybind to open the catalog search field on index pages. ### 3.11.5 - *2013-10-03* diff --git a/src/General/Build.coffee b/src/General/Build.coffee index fb3843804..b62418e13 100644 --- a/src/General/Build.coffee +++ b/src/General/Build.coffee @@ -238,7 +238,7 @@ Build = else "/#{boardID}/res/#{threadID}#q#{postID}" }' title='Quote this post'>#{postID}" + - replyLink + + replyLink + '' + '' + diff --git a/src/General/Config.coffee b/src/General/Config.coffee index 4f422357e..dd3220383 100644 --- a/src/General/Config.coffee +++ b/src/General/Config.coffee @@ -139,6 +139,7 @@ Config = #//archive.foolz.us/%board/search/image/%MD5/;text:View same on foolz /%board/ #//archive.installgentoo.net/%board/image/%MD5;text:View same on installgentoo /%board/ """ + 'Index Mode': 'paged' 'Custom CSS': false Header: 'Header auto-hide': false diff --git a/src/General/Main.coffee b/src/General/Main.coffee index 604393db8..a504f76ef 100644 --- a/src/General/Main.coffee +++ b/src/General/Main.coffee @@ -208,7 +208,7 @@ Main = try localStorage.getItem '4chan-settings' catch err - new Notice 'warning', 'Cookies need to be enabled on 4chan for <%= meta.name %> to properly function.', 30 + new Notice 'warning', 'Cookies need to be enabled on 4chan for <%= meta.name %> to operate properly.', 30 Main.disableReports = true $.event '4chanXInitFinished' diff --git a/src/Miscellaneous/Index.coffee b/src/Miscellaneous/Index.coffee index a277d76fd..dd49f4f37 100644 --- a/src/Miscellaneous/Index.coffee +++ b/src/Miscellaneous/Index.coffee @@ -2,6 +2,33 @@ Index = init: -> return if g.VIEW isnt 'index' + label = $.el 'label', + innerHTML: """ + + """ + select = label.firstChild + select.value = Conf['Index Mode'] + $.on select, 'change', $.cb.value + $.on select, 'change', @update + + $.event 'AddMenuEntry', + type: 'header' + el: $.el 'span', + textContent: 'Index Navigation' + order: 90 + subEntries: [el: label] + + $.on d, '4chanXInitFinished', @initReady + + initReady: -> + $.off d, '4chanXInitFinished', Index.initReady + return if Conf['Index Mode'] is 'paged' + Index.update() + update: -> return unless navigator.onLine Index.req?.abort() @@ -38,8 +65,13 @@ Index = Header.scrollTo $.id 'delform' parse: (pages) -> - pageNum = +window.location.pathname.split('/')[2] - dataThr = pages[pageNum].threads + if Conf['Index Mode'] is 'paged' + pageNum = +window.location.pathname.split('/')[2] + dataThr = pages[pageNum].threads + else + dataThr = [] + for page in pages + dataThr.push page.threads... nodes = [] threads = [] From e012cc4d641f9a4a29ed79b39d45cdd98a2a1e6a Mon Sep 17 00:00:00 2001 From: Mayhem Date: Wed, 30 Oct 2013 03:04:18 +0100 Subject: [PATCH 015/225] Hide the page list in non-paged mode. --- src/Miscellaneous/Index.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Miscellaneous/Index.coffee b/src/Miscellaneous/Index.coffee index dd49f4f37..bcc4c4615 100644 --- a/src/Miscellaneous/Index.coffee +++ b/src/Miscellaneous/Index.coffee @@ -101,3 +101,4 @@ Index = board = $ '.board' $.rmAll board $.add board, nodes + $('.pagelist').hidden = Conf['Index Mode'] isnt 'paged' From 6918d67d5d3079bf64a1bd8337c8ed2459262e55 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Wed, 30 Oct 2013 03:10:30 +0100 Subject: [PATCH 016/225] Disable next/previous page keybinds in non-paged mode. --- html/General/Settings-section-Filter-guide.html | 2 +- src/Miscellaneous/Keybinds.coffee | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/html/General/Settings-section-Filter-guide.html b/html/General/Settings-section-Filter-guide.html index ae73a66da..1656d0cb8 100644 --- a/html/General/Settings-section-Filter-guide.html +++ b/html/General/Settings-section-Filter-guide.html @@ -23,7 +23,7 @@ For example: highlight; or highlight:wallpaper;.
  • - Highlighted OPs will have their threads put on top of board pages by default.
    + Highlighted OPs will have their threads put on top of the board index by default.
    For example: top:yes; or top:no;.
  • diff --git a/src/Miscellaneous/Keybinds.coffee b/src/Miscellaneous/Keybinds.coffee index 31a237e9c..464bf76c2 100644 --- a/src/Miscellaneous/Keybinds.coffee +++ b/src/Miscellaneous/Keybinds.coffee @@ -78,9 +78,11 @@ Keybinds = when Conf['Open front page'] $.open "/#{g.BOARD}/#delform" when Conf['Next page'] + return if Conf['Index Mode'] isnt 'paged' if form = $ '.next form' window.location = form.action when Conf['Previous page'] + return if Conf['Index Mode'] isnt 'paged' if form = $ '.prev form' window.location = form.action when Conf['Search form'] From 43567173fc8f855b8668009a3a07d49520a295b9 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Wed, 30 Oct 2013 03:42:49 +0100 Subject: [PATCH 017/225] Use a sub-entry instead of a - - - - Paged' } + { el: $.el 'label', innerHTML: ' All threads' } + ] + for label in subEntry.subEntries + input = label.el.firstChild + input.checked = Conf['Index Mode'] is input.value + $.on input, 'change', $.cb.value + $.on input, 'change', @update + subEntries.push subEntry $.event 'AddMenuEntry', type: 'header' el: $.el 'span', textContent: 'Index Navigation' order: 90 - subEntries: [el: label] + subEntries: subEntries $.on d, '4chanXInitFinished', @initReady From 11c3b0018a87455080edbb2820ba99078b85e43a Mon Sep 17 00:00:00 2001 From: Mayhem Date: Wed, 30 Oct 2013 04:32:31 +0100 Subject: [PATCH 018/225] Fix thread watcher/expansion/hiding buttons after an index refresh. --- src/Miscellaneous/ExpandThread.coffee | 7 +++++++ src/Miscellaneous/Index.coffee | 3 ++- src/Monitoring/ThreadWatcher.coffee | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Miscellaneous/ExpandThread.coffee b/src/Miscellaneous/ExpandThread.coffee index fe2305bdc..dbe736305 100644 --- a/src/Miscellaneous/ExpandThread.coffee +++ b/src/Miscellaneous/ExpandThread.coffee @@ -2,6 +2,8 @@ ExpandThread = init: -> return if g.VIEW isnt 'index' or !Conf['Thread Expansion'] + $.on d, 'IndexRefresh', @onrefresh + Thread.callbacks.push name: 'Thread Expansion' cb: @node @@ -15,6 +17,11 @@ ExpandThread = $.on a, 'click', ExpandThread.cbToggle $.replace span, a + onrefresh: -> + for threadID, thread of g.BOARD.threads + ExpandThread.node.call thread + return + text: (status, posts, files) -> text = [status] text.push "#{posts} post#{if posts > 1 then 's' else ''}" diff --git a/src/Miscellaneous/Index.coffee b/src/Miscellaneous/Index.coffee index b1db097ec..fa717fd68 100644 --- a/src/Miscellaneous/Index.coffee +++ b/src/Miscellaneous/Index.coffee @@ -83,7 +83,7 @@ Index = nodes.push threadRoot, $.el 'hr' unless thread = g.threads["#{g.BOARD}.#{data.no}"] thread = new Thread data.no, g.BOARD - threads.push thread + threads.push thread for postRoot in $$ '.thread > .postContainer', threadRoot continue if thread.posts[postRoot.id.match /\d+/] try @@ -104,3 +104,4 @@ Index = $.rmAll board $.add board, nodes $('.pagelist').hidden = Conf['Index Mode'] isnt 'paged' + $.event 'IndexRefresh' diff --git a/src/Monitoring/ThreadWatcher.coffee b/src/Monitoring/ThreadWatcher.coffee index 54bfb9435..7697ce4cb 100644 --- a/src/Monitoring/ThreadWatcher.coffee +++ b/src/Monitoring/ThreadWatcher.coffee @@ -12,6 +12,7 @@ ThreadWatcher = $.on d, 'QRPostSuccessful', @cb.post $.on d, 'ThreadUpdate', @cb.threadUpdate if g.VIEW is 'thread' $.on d, '4chanXInitFinished', @ready + $.on d, 'IndexRefresh', @refresh now = Date.now() if (@db.data.lastChecked or 0) < now - 2 * $.HOUR From f0d19e6a5c17dbcf943f7ce27e8deba6c5185286 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Wed, 30 Oct 2013 16:49:42 +0100 Subject: [PATCH 019/225] Fix threads highlighted by the filter not being put on top. --- src/Filtering/Filter.coffee | 9 ++------- src/Miscellaneous/Index.coffee | 22 ++++++++++++++++++---- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/Filtering/Filter.coffee b/src/Filtering/Filter.coffee index 1f1387dba..eee0dfae9 100644 --- a/src/Filtering/Filter.coffee +++ b/src/Filtering/Filter.coffee @@ -110,13 +110,8 @@ Filter = # Highlight $.addClass @nodes.root, result.class - if !@isReply and result.top and g.VIEW is 'index' - # Put the highlighted OPs' thread on top of the board page... - thisThread = @nodes.root.parentNode - # ...before the first non highlighted thread. - if firstThread = $ 'div[class="postContainer opContainer"]' - unless firstThread is @nodes.root - $.before firstThread.parentNode, [thisThread, thisThread.nextElementSibling] + if !@isReply and result.top + @thread.isOnTop = true name: (post) -> if 'name' of post.info diff --git a/src/Miscellaneous/Index.coffee b/src/Miscellaneous/Index.coffee index fa717fd68..a4287e188 100644 --- a/src/Miscellaneous/Index.coffee +++ b/src/Miscellaneous/Index.coffee @@ -28,6 +28,8 @@ Index = initReady: -> $.off d, '4chanXInitFinished', Index.initReady + Index.root = $ '.board' + Index.setIndex $$ '.board > .thread, .board > hr', Index.root return if Conf['Index Mode'] is 'paged' Index.update() @@ -100,8 +102,20 @@ Index = Main.callbackNodes Thread, threads Main.callbackNodes Post, posts - board = $ '.board' - $.rmAll board - $.add board, nodes - $('.pagelist').hidden = Conf['Index Mode'] isnt 'paged' + Index.setIndex nodes $.event 'IndexRefresh' + setIndex: (nodes) -> + $.rmAll Index.root + $.add Index.root, Index.sort nodes + $('.pagelist').hidden = Conf['Index Mode'] isnt 'paged' + sort: (nodes) -> + return nodes unless Conf['Filter'] + # Put the highlighted thread on top of the index + # while keeping the original order they appear in. + tops = [] + for threadRoot in nodes by 2 when Get.threadFromRoot(threadRoot).isOnTop + tops.push threadRoot + for top, i in tops + arr = nodes.splice nodes.indexOf(top), 2 + nodes.splice i * 2, 0, arr... + nodes From df62c78ed922fc4a5a791070d003515ecf6afe6e Mon Sep 17 00:00:00 2001 From: Mayhem Date: Wed, 30 Oct 2013 17:25:22 +0100 Subject: [PATCH 020/225] After an index refresh, only scroll down if needed. --- src/General/Header.coffee | 4 ++-- src/Miscellaneous/Index.coffee | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/General/Header.coffee b/src/General/Header.coffee index 7eb6e06fe..12533ca17 100644 --- a/src/General/Header.coffee +++ b/src/General/Header.coffee @@ -247,8 +247,8 @@ Header = return unless (hash = @location.hash[1..]) and post = $.id hash return if (Get.postFromRoot post).isHidden Header.scrollTo post - scrollTo: (post) -> - {top} = post.getBoundingClientRect() + scrollTo: (root) -> + {top} = root.getBoundingClientRect() unless Conf['Bottom header'] headRect = Header.toggle.getBoundingClientRect() top -= headRect.top + headRect.height diff --git a/src/Miscellaneous/Index.coffee b/src/Miscellaneous/Index.coffee index a4287e188..44db465b6 100644 --- a/src/Miscellaneous/Index.coffee +++ b/src/Miscellaneous/Index.coffee @@ -67,7 +67,7 @@ Index = notice.el.lastElementChild.textContent = 'Index refreshed!' setTimeout notice.close, $.SECOND - Header.scrollTo $.id 'delform' + Header.scrollTo Index.root if Index.root.getBoundingClientRect().top < 0 parse: (pages) -> if Conf['Index Mode'] is 'paged' pageNum = +window.location.pathname.split('/')[2] From 66ebbd87f07cf77caf88a35a77b6b77b910af404 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Thu, 31 Oct 2013 00:21:12 +0100 Subject: [PATCH 021/225] Fix thread hiding after an index refresh. --- src/Filtering/ThreadHiding.coffee | 8 ++++++++ src/Miscellaneous/Index.coffee | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Filtering/ThreadHiding.coffee b/src/Filtering/ThreadHiding.coffee index 21bd4c211..34f9a54f2 100644 --- a/src/Filtering/ThreadHiding.coffee +++ b/src/Filtering/ThreadHiding.coffee @@ -4,6 +4,7 @@ ThreadHiding = @db = new DataBoard 'hiddenThreads' @syncCatalog() + $.on d, 'IndexRefresh', @onrefresh Thread.callbacks.push name: 'Thread Hiding' cb: @node @@ -14,6 +15,13 @@ ThreadHiding = return unless Conf['Thread Hiding'] $.prepend @OP.nodes.root, ThreadHiding.makeButton @, 'hide' + onrefresh: -> + for threadID, thread of g.BOARD.threads when thread.isHidden + hasStub = !!thread.stub + ThreadHiding.show thread + ThreadHiding.hide thread, hasStub + return + syncCatalog: -> # Sync hidden threads from the catalog into the index. hiddenThreads = ThreadHiding.db.get diff --git a/src/Miscellaneous/Index.coffee b/src/Miscellaneous/Index.coffee index 44db465b6..8045030c8 100644 --- a/src/Miscellaneous/Index.coffee +++ b/src/Miscellaneous/Index.coffee @@ -99,11 +99,13 @@ Index = error: err Main.handleErrors errors if errors + # Add the threads and
    s in a container to make sure all features work. + $.nodes nodes Main.callbackNodes Thread, threads Main.callbackNodes Post, posts + $.event 'IndexRefresh' Index.setIndex nodes - $.event 'IndexRefresh' setIndex: (nodes) -> $.rmAll Index.root $.add Index.root, Index.sort nodes From c2984275e574f8786577fbb657631d4af2f59fda Mon Sep 17 00:00:00 2001 From: Mayhem Date: Thu, 31 Oct 2013 00:55:45 +0100 Subject: [PATCH 022/225] Add index refresh shortcut in the header bar. Also fix lazy/lame implementation of Header.addShortcut() --- src/General/Header.coffee | 5 ++--- src/Images/ImageExpand.coffee | 2 +- src/Miscellaneous/Index.coffee | 7 +++++++ src/Posting/QR.coffee | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/General/Header.coffee b/src/General/Header.coffee index 12533ca17..7e401e5a9 100644 --- a/src/General/Header.coffee +++ b/src/General/Header.coffee @@ -257,11 +257,10 @@ Header = addShortcut: (el, index) -> shortcut = $.el 'span', className: 'shortcut' + shortcut.dataset.index = index $.add shortcut, el shortcuts = $ '#shortcuts', Header.bar - nodes = [shortcuts.childNodes...] - nodes.splice index, 0, shortcut - $.add shortcuts, nodes + $.add shortcuts, [shortcuts.childNodes...].concat(shortcut).sort (a, b) -> a.dataset.index - b.dataset.index menuToggle: (e) -> Header.menu.toggle e, @, g diff --git a/src/Images/ImageExpand.coffee b/src/Images/ImageExpand.coffee index 17b8066d3..c21bef490 100644 --- a/src/Images/ImageExpand.coffee +++ b/src/Images/ImageExpand.coffee @@ -7,7 +7,7 @@ ImageExpand = title: 'Expand All Images' href: 'javascript:;' $.on @EAI, 'click', ImageExpand.cb.toggleAll - Header.addShortcut @EAI, 2 + Header.addShortcut @EAI, 3 Post.callbacks.push name: 'Image Expansion' diff --git a/src/Miscellaneous/Index.coffee b/src/Miscellaneous/Index.coffee index 8045030c8..ea978a3fc 100644 --- a/src/Miscellaneous/Index.coffee +++ b/src/Miscellaneous/Index.coffee @@ -2,6 +2,13 @@ Index = init: -> return if g.VIEW isnt 'index' + button = $.el 'a', + className: 'index-refresh-shortcut fa fa-refresh' + title: 'Refresh Index' + href: 'javascript:;' + $.on button, 'click', Index.update + Header.addShortcut button, 1 + subEntries = [] subEntry = diff --git a/src/Posting/QR.coffee b/src/Posting/QR.coffee index d0be4c445..124e9a624 100644 --- a/src/Posting/QR.coffee +++ b/src/Posting/QR.coffee @@ -26,7 +26,7 @@ QR = $.event 'CloseMenu' QR.open() QR.nodes.com.focus() - Header.addShortcut sc, 1 + Header.addShortcut sc, 2 $.on d, 'QRGetSelectedPost', ({detail: cb}) -> cb QR.selected From 21e6902762ec44719c8a75c0ed149880f42f2785 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Thu, 31 Oct 2013 03:13:44 +0100 Subject: [PATCH 023/225] Dereference dead threads. I wonder if this will be enough... --- CHANGELOG.md | 2 +- src/General/Post.coffee | 7 +++++++ src/General/Thread.coffee | 6 ++++++ src/Miscellaneous/Index.coffee | 14 +++++++++++--- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69308c0cb..352ef32a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ Index navigation improvements: - - You can now refresh the index page you are on with the same keybind for refreshing threads. + - You can now refresh the index page you are on with the icon in the header bar or the same keybind for refreshing threads. - You can now switch between single-page and all-pages navigation via the "Index Navigation" header sub-menu. Added a keybind to open the catalog search field on index pages. diff --git a/src/General/Post.coffee b/src/General/Post.coffee index 27811afa5..901405495 100644 --- a/src/General/Post.coffee +++ b/src/General/Post.coffee @@ -193,6 +193,13 @@ class Post quotelink.textContent = quotelink.textContent.replace '\u00A0(Dead)', '' $.rmClass quotelink, 'deadlink' return + + collect: -> + @kill() + delete g.posts[@fullID] + delete @thread.posts[@] + delete @board.posts[@] + addClone: (context) -> new Clone @, context rmClone: (index) -> diff --git a/src/General/Thread.coffee b/src/General/Thread.coffee index 1f15bf714..97502ecd2 100644 --- a/src/General/Thread.coffee +++ b/src/General/Thread.coffee @@ -11,3 +11,9 @@ class Thread kill: -> @isDead = true @timeOfDeath = Date.now() + + collect: -> + for postID, post in @posts + post.collect() + delete g.threads[@fullID] + delete @board.threads[@] diff --git a/src/Miscellaneous/Index.coffee b/src/Miscellaneous/Index.coffee index ea978a3fc..e06236f2c 100644 --- a/src/Miscellaneous/Index.coffee +++ b/src/Miscellaneous/Index.coffee @@ -84,15 +84,17 @@ Index = for page in pages dataThr.push page.threads... - nodes = [] - threads = [] - posts = [] + nodes = [] + threads = [] + liveThreads = [] + posts = [] for data in dataThr threadRoot = Build.thread g.BOARD, data nodes.push threadRoot, $.el 'hr' unless thread = g.threads["#{g.BOARD}.#{data.no}"] thread = new Thread data.no, g.BOARD threads.push thread + liveThreads.push thread for postRoot in $$ '.thread > .postContainer', threadRoot continue if thread.posts[postRoot.id.match /\d+/] try @@ -106,6 +108,7 @@ Index = error: err Main.handleErrors errors if errors + Index.collectDeadThreads liveThreads # Add the threads and
    s in a container to make sure all features work. $.nodes nodes Main.callbackNodes Thread, threads @@ -128,3 +131,8 @@ Index = arr = nodes.splice nodes.indexOf(top), 2 nodes.splice i * 2, 0, arr... nodes + + collectDeadThreads: (liveThreads) -> + for threadID, thread of g.threads when thread not in liveThreads + thread.collect() + return From 553c4757686e6277b9fc4166a04b5746bfd6327e Mon Sep 17 00:00:00 2001 From: Mayhem Date: Thu, 31 Oct 2013 03:42:24 +0100 Subject: [PATCH 024/225] Reduce Index.sort() to 1 loop. --- src/Miscellaneous/Index.coffee | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Miscellaneous/Index.coffee b/src/Miscellaneous/Index.coffee index e06236f2c..8de6fa1de 100644 --- a/src/Miscellaneous/Index.coffee +++ b/src/Miscellaneous/Index.coffee @@ -122,14 +122,14 @@ Index = $('.pagelist').hidden = Conf['Index Mode'] isnt 'paged' sort: (nodes) -> return nodes unless Conf['Filter'] - # Put the highlighted thread on top of the index + # Put the highlighted thread &
    on top of the index # while keeping the original order they appear in. - tops = [] - for threadRoot in nodes by 2 when Get.threadFromRoot(threadRoot).isOnTop - tops.push threadRoot - for top, i in tops - arr = nodes.splice nodes.indexOf(top), 2 - nodes.splice i * 2, 0, arr... + i = offset = 0 + while threadRoot = nodes[i] + if Get.threadFromRoot(threadRoot).isOnTop + nodes.splice offset, 0, nodes.splice(i, 2)... + offset += 2 + i += 2 nodes collectDeadThreads: (liveThreads) -> From 72b38da3af8bb6773260b1478e39ae2f39986358 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Thu, 31 Oct 2013 04:13:35 +0100 Subject: [PATCH 025/225] Regenerate the QR threads list correctly after an index refresh. --- src/Posting/QR.coffee | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/src/Posting/QR.coffee b/src/Posting/QR.coffee index 124e9a624..8830b5472 100644 --- a/src/Posting/QR.coffee +++ b/src/Posting/QR.coffee @@ -39,11 +39,15 @@ QR = $.on d, 'dragover', QR.dragOver $.on d, 'drop', QR.dropFile $.on d, 'dragstart dragend', QR.drag - $.on d, 'ThreadUpdate', -> - if g.DEAD - QR.abort() - else - QR.status() + switch g.VIEW + when 'index' + $.on d, 'IndexRefresh', QR.generatePostableThreadsList + when 'thread' + $.on d, 'ThreadUpdate', -> + if g.DEAD + QR.abort() + else + QR.status() QR.persist() if Conf['Persistent QR'] @@ -796,6 +800,24 @@ QR = return e.preventDefault() + generatePostableThreadsList: -> + list = QR.nodes.thread + options = [list.firstChild] + for thread of g.BOARD.threads + options.push $.el 'option', + value: thread + textContent: "Thread No.#{thread}" + val = list.value + $.rmAll list + $.add list, options + list.value = val + return unless list.value + # Fix the value if the option disappeared. + list.value = if g.VIEW is 'thread' + g.THREADID + else + 'new' + dialog: -> dialog = UI.dialog 'qr', 'top:0;right:0;', """ <%= grunt.file.read('html/Posting/QR.html').replace(/>\s+<').trim() %> @@ -867,12 +889,6 @@ QR = nodes.flag.dataset.default = '0' $.add nodes.form, nodes.flag - # Make a list of threads. - for thread of g.BOARD.threads - $.add nodes.thread, $.el 'option', - value: thread - textContent: "Thread No.#{thread}" - <% if (type === 'userscript') { %> # XXX Firefox lacks focusin/focusout support. for elm in $$ '*', QR.nodes.el @@ -906,6 +922,7 @@ QR = $.set 'QR Size', @style.cssText <% } %> + QR.generatePostableThreadsList() QR.persona.init() new QR.post true QR.status() From 79644546cef148a67e70280275c295f0d4889358 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Thu, 31 Oct 2013 04:16:47 +0100 Subject: [PATCH 026/225] Only listen to 'IndexRefresh' events when browsing the index. --- src/Monitoring/ThreadWatcher.coffee | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Monitoring/ThreadWatcher.coffee b/src/Monitoring/ThreadWatcher.coffee index 7697ce4cb..2f2809cd4 100644 --- a/src/Monitoring/ThreadWatcher.coffee +++ b/src/Monitoring/ThreadWatcher.coffee @@ -10,9 +10,12 @@ ThreadWatcher = @list = @dialog.lastElementChild $.on d, 'QRPostSuccessful', @cb.post - $.on d, 'ThreadUpdate', @cb.threadUpdate if g.VIEW is 'thread' $.on d, '4chanXInitFinished', @ready - $.on d, 'IndexRefresh', @refresh + switch g.VIEW + when 'index' + $.on d, 'IndexRefresh', @refresh + when 'thread' + $.on d, 'ThreadUpdate', @cb.threadUpdate now = Date.now() if (@db.data.lastChecked or 0) < now - 2 * $.HOUR From 22c561b796a85a093fc2778f84a66472b0f6087f Mon Sep 17 00:00:00 2001 From: Mayhem Date: Thu, 31 Oct 2013 04:32:45 +0100 Subject: [PATCH 027/225] Take into account dead threads in the watcher after an index refresh. --- src/Monitoring/ThreadWatcher.coffee | 11 +++++++++++ src/Posting/QR.coffee | 1 + 2 files changed, 12 insertions(+) diff --git a/src/Monitoring/ThreadWatcher.coffee b/src/Monitoring/ThreadWatcher.coffee index 2f2809cd4..71abca86b 100644 --- a/src/Monitoring/ThreadWatcher.coffee +++ b/src/Monitoring/ThreadWatcher.coffee @@ -13,6 +13,7 @@ ThreadWatcher = $.on d, '4chanXInitFinished', @ready switch g.VIEW when 'index' + $.on d, 'IndexRefresh', @cb.indexUpdate $.on d, 'IndexRefresh', @refresh when 'thread' $.on d, 'ThreadUpdate', @cb.threadUpdate @@ -73,6 +74,16 @@ ThreadWatcher = $.set 'AutoWatch', threadID else if Conf['Auto Watch Reply'] ThreadWatcher.add board.threads[threadID] + indexUpdate: -> + {db} = ThreadWatcher + for threadID, data of db.data.boards[g.BOARD.ID] when threadID not in g.BOARD.threads + if Conf['Auto Prune'] + ThreadWatcher.rm g.BOARD.ID, threadID + else + data.isDead = true + db.data.lastChecked = Date.now() + db.save() + ThreadWatcher.refresh() threadUpdate: (e) -> {thread} = e.detail return unless e.detail[404] and ThreadWatcher.db.get {boardID: thread.board.ID, threadID: thread.ID} diff --git a/src/Posting/QR.coffee b/src/Posting/QR.coffee index 8830b5472..b244a984b 100644 --- a/src/Posting/QR.coffee +++ b/src/Posting/QR.coffee @@ -801,6 +801,7 @@ QR = e.preventDefault() generatePostableThreadsList: -> + return unless QR.nodes list = QR.nodes.thread options = [list.firstChild] for thread of g.BOARD.threads From 0038f1f0118ebedddaf62990fc2cde0d7ad84c38 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Thu, 31 Oct 2013 05:21:31 +0100 Subject: [PATCH 028/225] Slightly better consistency between "reload"/"refresh"/"update" usage. --- html/Monitoring/ThreadUpdater.html | 2 +- src/General/Settings.coffee | 4 ++-- src/Monitoring/ThreadWatcher.coffee | 9 ++++----- src/Posting/QR.coffee | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/html/Monitoring/ThreadUpdater.html b/html/Monitoring/ThreadUpdater.html index 04a6a17b2..32b13b497 100644 --- a/html/Monitoring/ThreadUpdater.html +++ b/html/Monitoring/ThreadUpdater.html @@ -13,5 +13,5 @@
    - +
    diff --git a/src/General/Settings.coffee b/src/General/Settings.coffee index 17cf7595d..65f2a5094 100644 --- a/src/General/Settings.coffee +++ b/src/General/Settings.coffee @@ -142,7 +142,7 @@ Settings = return div = $.el 'div', - innerHTML: ": Clear manually-hidden threads and posts on all boards. Refresh the page to apply." + innerHTML: ": Clear manually-hidden threads and posts on all boards. Reload the page to apply." button = $ 'button', div hiddenNum = 0 $.get 'hiddenThreads', boards: {}, (item) -> @@ -205,7 +205,7 @@ Settings = try data = JSON.parse e.target.result Settings.loadSettings data - if confirm 'Import successful. Refresh now?' + if confirm 'Import successful. Reload now?' window.location.reload() catch err output.textContent = 'Import failed due to an error.' diff --git a/src/Monitoring/ThreadWatcher.coffee b/src/Monitoring/ThreadWatcher.coffee index 71abca86b..b33e96e71 100644 --- a/src/Monitoring/ThreadWatcher.coffee +++ b/src/Monitoring/ThreadWatcher.coffee @@ -13,10 +13,9 @@ ThreadWatcher = $.on d, '4chanXInitFinished', @ready switch g.VIEW when 'index' - $.on d, 'IndexRefresh', @cb.indexUpdate - $.on d, 'IndexRefresh', @refresh + $.on d, 'IndexRefresh', @cb.onIndexRefresh when 'thread' - $.on d, 'ThreadUpdate', @cb.threadUpdate + $.on d, 'ThreadUpdate', @cb.onThreadRefresh now = Date.now() if (@db.data.lastChecked or 0) < now - 2 * $.HOUR @@ -74,7 +73,7 @@ ThreadWatcher = $.set 'AutoWatch', threadID else if Conf['Auto Watch Reply'] ThreadWatcher.add board.threads[threadID] - indexUpdate: -> + onIndexRefresh: -> {db} = ThreadWatcher for threadID, data of db.data.boards[g.BOARD.ID] when threadID not in g.BOARD.threads if Conf['Auto Prune'] @@ -84,7 +83,7 @@ ThreadWatcher = db.data.lastChecked = Date.now() db.save() ThreadWatcher.refresh() - threadUpdate: (e) -> + onThreadRefresh: (e) -> {thread} = e.detail return unless e.detail[404] and ThreadWatcher.db.get {boardID: thread.board.ID, threadID: thread.ID} # Update 404 status. diff --git a/src/Posting/QR.coffee b/src/Posting/QR.coffee index b244a984b..9f81f22a3 100644 --- a/src/Posting/QR.coffee +++ b/src/Posting/QR.coffee @@ -701,7 +701,7 @@ QR = imgContainer = $.el 'div', className: 'captcha-img' - title: 'Reload' + title: 'Reload reCAPTCHA' innerHTML: '' input = $.el 'input', className: 'captcha-input field' From 092d9317e0f58057d6045eafa523a2e7f14b9e39 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Thu, 31 Oct 2013 19:10:24 +0100 Subject: [PATCH 029/225] Add sorting options by bump order and creation date. --- CHANGELOG.md | 4 ++ lib/$.coffee | 2 +- src/General/Config.coffee | 4 +- src/Miscellaneous/Index.coffee | 67 +++++++++++++++++++++++----------- 4 files changed, 53 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 352ef32a5..c075422c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ Index navigation improvements: - You can now refresh the index page you are on with the icon in the header bar or the same keybind for refreshing threads. - You can now switch between single-page and all-pages navigation via the "Index Navigation" header sub-menu. + - Threads in the index can now be sorted by: + - bump order + - creation date + Added a keybind to open the catalog search field on index pages. ### 3.11.5 - *2013-10-03* diff --git a/lib/$.coffee b/lib/$.coffee index 8b2202304..711159e6c 100644 --- a/lib/$.coffee +++ b/lib/$.coffee @@ -104,7 +104,7 @@ $.rm = do -> (el) -> el.parentNode?.removeChild el $.rmAll = (root) -> # jsperf.com/emptify-element - while node = root.firstChild + for node in [root.childNodes...] # HTMLSelectElement.remove !== Element.remove root.removeChild node return diff --git a/src/General/Config.coffee b/src/General/Config.coffee index dd3220383..95f1f2a48 100644 --- a/src/General/Config.coffee +++ b/src/General/Config.coffee @@ -139,8 +139,10 @@ Config = #//archive.foolz.us/%board/search/image/%MD5/;text:View same on foolz /%board/ #//archive.installgentoo.net/%board/image/%MD5;text:View same on installgentoo /%board/ """ - 'Index Mode': 'paged' 'Custom CSS': false + Index: + 'Index Mode': 'paged' + 'Index Sort': 'bump' Header: 'Header auto-hide': false 'Bottom header': false diff --git a/src/Miscellaneous/Index.coffee b/src/Miscellaneous/Index.coffee index 8de6fa1de..51aadffc3 100644 --- a/src/Miscellaneous/Index.coffee +++ b/src/Miscellaneous/Index.coffee @@ -9,34 +9,44 @@ Index = $.on button, 'click', Index.update Header.addShortcut button, 1 - subEntries = [] - - subEntry = - el: $.el 'span', textContent: 'Index Mode' + modeEntry = + el: $.el 'span', textContent: 'Index mode' subEntries: [ { el: $.el 'label', innerHTML: ' Paged' } { el: $.el 'label', innerHTML: ' All threads' } ] - for label in subEntry.subEntries + for label in modeEntry.subEntries input = label.el.firstChild input.checked = Conf['Index Mode'] is input.value $.on input, 'change', $.cb.value $.on input, 'change', @update - subEntries.push subEntry + + sortEntry = + el: $.el 'span', textContent: 'Sort by' + subEntries: [ + { el: $.el 'label', innerHTML: ' Bump order' } + { el: $.el 'label', innerHTML: ' Creation date' } + ] + for label in sortEntry.subEntries + input = label.el.firstChild + input.checked = Conf['Index Sort'] is input.value + $.on input, 'change', $.cb.value + $.on input, 'change', @resort $.event 'AddMenuEntry', type: 'header' el: $.el 'span', textContent: 'Index Navigation' order: 90 - subEntries: subEntries + subEntries: [modeEntry, sortEntry] $.on d, '4chanXInitFinished', @initReady initReady: -> $.off d, '4chanXInitFinished', Index.initReady Index.root = $ '.board' - Index.setIndex $$ '.board > .thread, .board > hr', Index.root + Index.liveThreads = $$('.board > .thread', Index.root).map Get.threadFromRoot + Index.resort() return if Conf['Index Mode'] is 'paged' Index.update() @@ -84,17 +94,17 @@ Index = for page in pages dataThr.push page.threads... - nodes = [] - threads = [] - liveThreads = [] - posts = [] + nodes = [] + threads = [] + posts = [] + Index.liveThreads = [] for data in dataThr threadRoot = Build.thread g.BOARD, data nodes.push threadRoot, $.el 'hr' unless thread = g.threads["#{g.BOARD}.#{data.no}"] thread = new Thread data.no, g.BOARD threads.push thread - liveThreads.push thread + Index.liveThreads.push thread for postRoot in $$ '.thread > .postContainer', threadRoot continue if thread.posts[postRoot.id.match /\d+/] try @@ -108,7 +118,7 @@ Index = error: err Main.handleErrors errors if errors - Index.collectDeadThreads liveThreads + Index.collectDeadThreads() # Add the threads and
    s in a container to make sure all features work. $.nodes nodes Main.callbackNodes Thread, threads @@ -120,19 +130,32 @@ Index = $.rmAll Index.root $.add Index.root, Index.sort nodes $('.pagelist').hidden = Conf['Index Mode'] isnt 'paged' - sort: (nodes) -> + sort: (unsortedNodes) -> + nodes = [] + switch Conf['Index Sort'] + when 'bump' + for thread in Index.liveThreads + i = unsortedNodes.indexOf thread.OP.nodes.root.parentNode + nodes.push unsortedNodes[i], unsortedNodes[i + 1] + when 'birth' + dates = [] + for threadRoot, i in unsortedNodes by 2 + dates.push Get.threadFromRoot(threadRoot).OP.info.date + unsortedDates = [dates...] + for date in dates.sort((a, b) -> b - a) + i = unsortedDates.indexOf(date) * 2 + nodes.push unsortedNodes[i], unsortedNodes[i + 1] return nodes unless Conf['Filter'] # Put the highlighted thread &
    on top of the index # while keeping the original order they appear in. - i = offset = 0 - while threadRoot = nodes[i] - if Get.threadFromRoot(threadRoot).isOnTop - nodes.splice offset, 0, nodes.splice(i, 2)... - offset += 2 - i += 2 + offset = 0 + for threadRoot, i in nodes by 2 when Get.threadFromRoot(threadRoot).isOnTop + nodes.splice offset++ * 2, 0, nodes.splice(i, 2)... nodes + resort: -> + Index.setIndex $$ '.board > .thread, .board > hr', Index.root collectDeadThreads: (liveThreads) -> - for threadID, thread of g.threads when thread not in liveThreads + for threadID, thread of g.threads when thread not in Index.liveThreads thread.collect() return From d2587e4bb29b5d60499c71bada2b53828f0d5c24 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Fri, 1 Nov 2013 03:46:21 +0100 Subject: [PATCH 030/225] Refactor index generation/sorting. --- src/General/Main.coffee | 2 +- src/Miscellaneous/Index.coffee | 111 ++++++++++++++++----------------- 2 files changed, 55 insertions(+), 58 deletions(-) diff --git a/src/General/Main.coffee b/src/General/Main.coffee index a504f76ef..885b09231 100644 --- a/src/General/Main.coffee +++ b/src/General/Main.coffee @@ -170,7 +170,7 @@ Main = # Something might have gone wrong! Main.initStyle() - if board = $ '.board' + if g.VIEW is 'thread' and board = $ '.board' threads = [] posts = [] diff --git a/src/Miscellaneous/Index.coffee b/src/Miscellaneous/Index.coffee index 51aadffc3..51050bce2 100644 --- a/src/Miscellaneous/Index.coffee +++ b/src/Miscellaneous/Index.coffee @@ -19,7 +19,7 @@ Index = input = label.el.firstChild input.checked = Conf['Index Mode'] is input.value $.on input, 'change', $.cb.value - $.on input, 'change', @update + $.on input, 'change', @cb.mode sortEntry = el: $.el 'span', textContent: 'Sort by' @@ -31,7 +31,7 @@ Index = input = label.el.firstChild input.checked = Conf['Index Sort'] is input.value $.on input, 'change', $.cb.value - $.on input, 'change', @resort + $.on input, 'change', @cb.sort $.event 'AddMenuEntry', type: 'header' @@ -45,11 +45,15 @@ Index = initReady: -> $.off d, '4chanXInitFinished', Index.initReady Index.root = $ '.board' - Index.liveThreads = $$('.board > .thread', Index.root).map Get.threadFromRoot - Index.resort() - return if Conf['Index Mode'] is 'paged' Index.update() + cb: + mode: -> + Index.buildIndex() + sort: -> + Index.sort() + Index.buildIndex() + update: -> return unless navigator.onLine Index.req?.abort() @@ -86,27 +90,29 @@ Index = Header.scrollTo Index.root if Index.root.getBoundingClientRect().top < 0 parse: (pages) -> - if Conf['Index Mode'] is 'paged' - pageNum = +window.location.pathname.split('/')[2] - dataThr = pages[pageNum].threads - else - dataThr = [] - for page in pages - dataThr.push page.threads... - - nodes = [] - threads = [] - posts = [] - Index.liveThreads = [] - for data in dataThr - threadRoot = Build.thread g.BOARD, data - nodes.push threadRoot, $.el 'hr' - unless thread = g.threads["#{g.BOARD}.#{data.no}"] - thread = new Thread data.no, g.BOARD + Index.parseThreadList pages + Index.buildAll() + Index.sort() + Index.buildIndex() + parseThreadList: (pages) -> + Index.threadsNumPerPage = pages[0].threads.length + Index.liveThreadData = pages.reduce ((arr, next) -> arr.concat next.threads), [] + Index.liveThreadIDs = Index.liveThreadData.map (data) -> data.no + for threadID, thread of g.BOARD.threads when thread.ID not in Index.liveThreadIDs + thread.collect() + return + buildAll: -> + Index.nodes = [] + threads = [] + posts = [] + for threadData in Index.liveThreadData + threadRoot = Build.thread g.BOARD, threadData + Index.nodes.push threadRoot, $.el 'hr' + unless thread = g.BOARD.threads[threadData.no] + thread = new Thread threadData.no, g.BOARD threads.push thread - Index.liveThreads.push thread - for postRoot in $$ '.thread > .postContainer', threadRoot - continue if thread.posts[postRoot.id.match /\d+/] + postRoots = $$ '.thread > .postContainer', threadRoot + for postRoot in postRoots when postRoot.id.match(/\d+/)[0] not of thread.posts try posts.push new Post postRoot, thread, g.BOARD catch err @@ -118,44 +124,35 @@ Index = error: err Main.handleErrors errors if errors - Index.collectDeadThreads() # Add the threads and
    s in a container to make sure all features work. - $.nodes nodes + $.nodes Index.nodes Main.callbackNodes Thread, threads - Main.callbackNodes Post, posts - $.event 'IndexRefresh' - - Index.setIndex nodes - setIndex: (nodes) -> - $.rmAll Index.root - $.add Index.root, Index.sort nodes - $('.pagelist').hidden = Conf['Index Mode'] isnt 'paged' - sort: (unsortedNodes) -> - nodes = [] + Main.callbackNodes Post, posts + sort: -> switch Conf['Index Sort'] when 'bump' - for thread in Index.liveThreads - i = unsortedNodes.indexOf thread.OP.nodes.root.parentNode - nodes.push unsortedNodes[i], unsortedNodes[i + 1] + sortedThreadIDs = Index.liveThreadIDs when 'birth' - dates = [] - for threadRoot, i in unsortedNodes by 2 - dates.push Get.threadFromRoot(threadRoot).OP.info.date - unsortedDates = [dates...] - for date in dates.sort((a, b) -> b - a) - i = unsortedDates.indexOf(date) * 2 - nodes.push unsortedNodes[i], unsortedNodes[i + 1] - return nodes unless Conf['Filter'] + sortedThreadIDs = [Index.liveThreadIDs...].sort (a, b) -> b - a + Index.sortedNodes = [] + for threadID in sortedThreadIDs + i = Index.liveThreadIDs.indexOf(threadID) * 2 + Index.sortedNodes.push Index.nodes[i], Index.nodes[i + 1] + return unless Conf['Filter'] # Put the highlighted thread &
    on top of the index # while keeping the original order they appear in. offset = 0 - for threadRoot, i in nodes by 2 when Get.threadFromRoot(threadRoot).isOnTop - nodes.splice offset++ * 2, 0, nodes.splice(i, 2)... - nodes - resort: -> - Index.setIndex $$ '.board > .thread, .board > hr', Index.root - - collectDeadThreads: (liveThreads) -> - for threadID, thread of g.threads when thread not in Index.liveThreads - thread.collect() + for threadRoot, i in Index.sortedNodes by 2 when Get.threadFromRoot(threadRoot).isOnTop + Index.sortedNodes.splice offset++ * 2, 0, Index.sortedNodes.splice(i, 2)... return + buildIndex: -> + if Conf['Index Mode'] is 'paged' + pageNum = +window.location.pathname.split('/')[2] + nodesPerPage = Index.threadsNumPerPage * 2 + nodes = Index.sortedNodes.slice nodesPerPage * pageNum, nodesPerPage * (pageNum + 1) + else + nodes = Index.sortedNodes + $.event 'IndexRefresh' + $.rmAll Index.root + $.add Index.root, nodes + $('.pagelist').hidden = Conf['Index Mode'] isnt 'paged' From 29b96a4a07d9eca76fe7c07732ba03aff7510c72 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Fri, 1 Nov 2013 03:51:45 +0100 Subject: [PATCH 031/225] Make the index header shortcut spin while refreshing the index. --- src/Miscellaneous/Index.coffee | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Miscellaneous/Index.coffee b/src/Miscellaneous/Index.coffee index 51050bce2..edb9e17d9 100644 --- a/src/Miscellaneous/Index.coffee +++ b/src/Miscellaneous/Index.coffee @@ -2,12 +2,12 @@ Index = init: -> return if g.VIEW isnt 'index' - button = $.el 'a', + Index.button = $.el 'a', className: 'index-refresh-shortcut fa fa-refresh' title: 'Refresh Index' href: 'javascript:;' - $.on button, 'click', Index.update - Header.addShortcut button, 1 + $.on Index.button, 'click', Index.update + Header.addShortcut Index.button, 1 modeEntry = el: $.el 'span', textContent: 'Index mode' @@ -64,7 +64,9 @@ Index = onloadend: Index.load , whenModified: true + $.addClass Index.button, 'fa-spin' load: (e) -> + $.rmClass Index.button, 'fa-spin' {req, notice} = Index delete Index.req delete Index.notice From 5b6c1df0838d4fca36b80ae7da0f44c9756d216c Mon Sep 17 00:00:00 2001 From: Mayhem Date: Fri, 1 Nov 2013 04:04:34 +0100 Subject: [PATCH 032/225] Load the index asap on page load. --- css/style.css | 5 +++++ src/General/Main.coffee | 2 +- src/Miscellaneous/Index.coffee | 10 +++++----- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/css/style.css b/css/style.css index a67c82043..544b955a0 100644 --- a/css/style.css +++ b/css/style.css @@ -362,6 +362,11 @@ a[href="javascript:;"] { overflow: hidden; } +/* Index */ +:root.index-loading .board { + display: none; +} + /* Announcement Hiding */ :root.hide-announcement #globalMessage, :root.hide-announcement-enabled #toggleMsgBtn { diff --git a/src/General/Main.coffee b/src/General/Main.coffee index 885b09231..0528e4f08 100644 --- a/src/General/Main.coffee +++ b/src/General/Main.coffee @@ -69,7 +69,7 @@ Main = initFeature 'Polyfill', Polyfill initFeature 'Header', Header initFeature 'Settings', Settings - initFeature 'Index Pager', Index + initFeature 'Index Generator', Index initFeature 'Announcement Hiding', PSAHiding initFeature 'Fourchan thingies', Fourchan initFeature 'Custom CSS', CustomCSS diff --git a/src/Miscellaneous/Index.coffee b/src/Miscellaneous/Index.coffee index edb9e17d9..ed9a8cd56 100644 --- a/src/Miscellaneous/Index.coffee +++ b/src/Miscellaneous/Index.coffee @@ -40,12 +40,12 @@ Index = order: 90 subEntries: [modeEntry, sortEntry] - $.on d, '4chanXInitFinished', @initReady - - initReady: -> - $.off d, '4chanXInitFinished', Index.initReady - Index.root = $ '.board' + $.addClass doc, 'index-loading' + Index.root = $.el 'div', className: 'board' Index.update() + $.asap (-> $('.board', doc) or d.readyState isnt 'loading'), -> + $.replace $('.board'), Index.root + $.rmClass doc, 'index-loading' cb: mode: -> From 855b7f0173f8aba4828730b65dfc95eb634de552 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Fri, 1 Nov 2013 04:52:21 +0100 Subject: [PATCH 033/225] Add 3 index sorting options: reply count, file count, last reply. --- CHANGELOG.md | 3 +++ src/Miscellaneous/Index.coffee | 13 +++++++++++++ src/Miscellaneous/Keybinds.coffee | 2 +- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c075422c3..928d719eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ Index navigation improvements: - Threads in the index can now be sorted by: - bump order - creation date + - reply count + - file count + - last reply Added a keybind to open the catalog search field on index pages. diff --git a/src/Miscellaneous/Index.coffee b/src/Miscellaneous/Index.coffee index ed9a8cd56..75b8bbdd1 100644 --- a/src/Miscellaneous/Index.coffee +++ b/src/Miscellaneous/Index.coffee @@ -26,6 +26,9 @@ Index = subEntries: [ { el: $.el 'label', innerHTML: ' Bump order' } { el: $.el 'label', innerHTML: ' Creation date' } + { el: $.el 'label', innerHTML: ' Reply count' } + { el: $.el 'label', innerHTML: ' File count' } + { el: $.el 'label', innerHTML: ' Last reply' } ] for label in sortEntry.subEntries input = label.el.firstChild @@ -136,6 +139,16 @@ Index = sortedThreadIDs = Index.liveThreadIDs when 'birth' sortedThreadIDs = [Index.liveThreadIDs...].sort (a, b) -> b - a + when 'replycount' + sortedThreadIDs = [Index.liveThreadData...].sort((a, b) -> b.replies - a.replies).map (data) -> data.no + when 'filecount' + sortedThreadIDs = [Index.liveThreadData...].sort((a, b) -> b.images - a.images).map (data) -> data.no + when 'lastreply' + sortedThreadIDs = [Index.liveThreadData...].sort((a, b) -> + a = a.last_replies[a.last_replies.length - 1] if 'last_replies' of a + b = b.last_replies[b.last_replies.length - 1] if 'last_replies' of b + b.no - a.no + ).map (data) -> data.no Index.sortedNodes = [] for threadID in sortedThreadIDs i = Index.liveThreadIDs.indexOf(threadID) * 2 diff --git a/src/Miscellaneous/Keybinds.coffee b/src/Miscellaneous/Keybinds.coffee index 464bf76c2..c5fb5d59a 100644 --- a/src/Miscellaneous/Keybinds.coffee +++ b/src/Miscellaneous/Keybinds.coffee @@ -7,7 +7,7 @@ Keybinds = init = -> $.off d, '4chanXInitFinished', init - $.on d, 'keydown', Keybinds.keydown + $.on d, 'keydown', Keybinds.keydown for node in $$ '[accesskey]' node.removeAttribute 'accesskey' return From 7e8fd3173370b3d8e5b0c9bd1c70c7ab6304b6f8 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Fri, 1 Nov 2013 13:57:24 +0100 Subject: [PATCH 034/225] Toggle the pagelist visibility via CSS to avoid a crash when the index update is done before the element exists. Also only send the If-Modified-Since HTTP header when we have something significant to send. --- css/style.css | 3 ++- lib/$.coffee | 2 +- src/Miscellaneous/Index.coffee | 6 +++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/css/style.css b/css/style.css index 544b955a0..8e57b3adc 100644 --- a/css/style.css +++ b/css/style.css @@ -363,7 +363,8 @@ a[href="javascript:;"] { } /* Index */ -:root.index-loading .board { +:root.index-loading .board, +:root.index-hide-pagelist .pagelist { display: none; } diff --git a/lib/$.coffee b/lib/$.coffee index 711159e6c..53ede1802 100644 --- a/lib/$.coffee +++ b/lib/$.coffee @@ -45,7 +45,7 @@ $.ajax = do -> type or= form and 'post' or 'get' r.open type, url, !sync if whenModified - r.setRequestHeader 'If-Modified-Since', lastModified[url] or '0' + r.setRequestHeader 'If-Modified-Since', lastModified[url] if url of lastModified $.on r, 'load', -> lastModified[url] = r.getResponseHeader 'Last-Modified' $.extend r, options $.extend r.upload, upCallbacks diff --git a/src/Miscellaneous/Index.coffee b/src/Miscellaneous/Index.coffee index 75b8bbdd1..986feb182 100644 --- a/src/Miscellaneous/Index.coffee +++ b/src/Miscellaneous/Index.coffee @@ -44,6 +44,7 @@ Index = subEntries: [modeEntry, sortEntry] $.addClass doc, 'index-loading' + Index.togglePagelist() Index.root = $.el 'div', className: 'board' Index.update() $.asap (-> $('.board', doc) or d.readyState isnt 'loading'), -> @@ -52,11 +53,15 @@ Index = cb: mode: -> + Index.togglePagelist() Index.buildIndex() sort: -> Index.sort() Index.buildIndex() + togglePagelist: -> + (if Conf['Index Mode'] is 'paged' then $.rmClass else $.addClass) doc, 'index-hide-pagelist' + update: -> return unless navigator.onLine Index.req?.abort() @@ -170,4 +175,3 @@ Index = $.event 'IndexRefresh' $.rmAll Index.root $.add Index.root, nodes - $('.pagelist').hidden = Conf['Index Mode'] isnt 'paged' From c8f7eef912cd285955037467c51c80ca1bb99fb9 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Fri, 1 Nov 2013 15:59:33 +0100 Subject: [PATCH 035/225] Fix and tweak watcher updater after an index refresh. --- src/Miscellaneous/Index.coffee | 4 ++-- src/Monitoring/ThreadWatcher.coffee | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Miscellaneous/Index.coffee b/src/Miscellaneous/Index.coffee index 986feb182..f75754fcf 100644 --- a/src/Miscellaneous/Index.coffee +++ b/src/Miscellaneous/Index.coffee @@ -169,9 +169,9 @@ Index = if Conf['Index Mode'] is 'paged' pageNum = +window.location.pathname.split('/')[2] nodesPerPage = Index.threadsNumPerPage * 2 - nodes = Index.sortedNodes.slice nodesPerPage * pageNum, nodesPerPage * (pageNum + 1) + nodes = Index.sortedNodes.slice nodesPerPage * pageNum, nodesPerPage * (pageNum + 1) else - nodes = Index.sortedNodes + nodes = Index.sortedNodes $.event 'IndexRefresh' $.rmAll Index.root $.add Index.root, nodes diff --git a/src/Monitoring/ThreadWatcher.coffee b/src/Monitoring/ThreadWatcher.coffee index b33e96e71..76abbf521 100644 --- a/src/Monitoring/ThreadWatcher.coffee +++ b/src/Monitoring/ThreadWatcher.coffee @@ -74,14 +74,14 @@ ThreadWatcher = else if Conf['Auto Watch Reply'] ThreadWatcher.add board.threads[threadID] onIndexRefresh: -> - {db} = ThreadWatcher - for threadID, data of db.data.boards[g.BOARD.ID] when threadID not in g.BOARD.threads + {db} = ThreadWatcher + boardID = g.BOARD.ID + for threadID, data of db.data.boards[boardID] when not data.isDead and threadID not of g.BOARD.threads if Conf['Auto Prune'] - ThreadWatcher.rm g.BOARD.ID, threadID + ThreadWatcher.db.delete {boardID, threadID} else data.isDead = true - db.data.lastChecked = Date.now() - db.save() + ThreadWatcher.db.set {boardID, threadID, val: data} ThreadWatcher.refresh() onThreadRefresh: (e) -> {thread} = e.detail @@ -114,7 +114,7 @@ ThreadWatcher = ThreadWatcher.status.textContent = status return if @status isnt 404 if Conf['Auto Prune'] - ThreadWatcher.rm boardID, threadID + ThreadWatcher.db.delete {boardID, threadID} else data.isDead = true ThreadWatcher.db.set {boardID, threadID, val: data} From 2f9e44a7734c18efc32318acc26c3f6642198aaa Mon Sep 17 00:00:00 2001 From: Mayhem Date: Fri, 1 Nov 2013 18:27:37 +0100 Subject: [PATCH 036/225] Update the threads sticky/closed status on each index refresh. Also fix the position of the sticky/closed icon. --- src/General/Build.coffee | 4 +-- src/General/Thread.coffee | 28 +++++++++++++++++++-- src/Miscellaneous/Index.coffee | 5 +++- src/Monitoring/ThreadUpdater.coffee | 39 +++++++++++------------------ 4 files changed, 46 insertions(+), 30 deletions(-) diff --git a/src/General/Build.coffee b/src/General/Build.coffee index b62418e13..8d018b8ee 100644 --- a/src/General/Build.coffee +++ b/src/General/Build.coffee @@ -227,7 +227,7 @@ Build = "" + emailStart + "#{name or ''}" + tripcode + - capcodeStart + emailEnd + capcode + userID + flag + sticky + closed + + capcodeStart + emailEnd + capcode + userID + flag + ' ' + "#{date} " + "" + @@ -238,7 +238,7 @@ Build = else "/#{boardID}/res/#{threadID}#q#{postID}" }' title='Quote this post'>#{postID}" + - replyLink + + sticky + closed + replyLink + '' + '' + diff --git a/src/General/Thread.coffee b/src/General/Thread.coffee index 97502ecd2..e681983e5 100644 --- a/src/General/Thread.coffee +++ b/src/General/Thread.coffee @@ -3,11 +3,35 @@ class Thread toString: -> @ID constructor: (@ID, @board) -> - @fullID = "#{@board}.#{@ID}" - @posts = {} + @fullID = "#{@board}.#{@ID}" + @posts = {} + @isSticky = false + @isClosed = false + @postLimit = false + @fileLimit = false g.threads[@fullID] = board.threads[@] = @ + setStatus: (type, status) -> + name = "is#{type}" + return if @[name] is status + @[name] = status + return unless @OP + typeLC = type.toLowerCase() + unless status + $.rm $ ".#{typeLC}Icon", @OP.nodes.info + return + icon = $.el 'img', + src: "//static.4chan.org/image/#{typeLC}.gif" + alt: type + title: type + className: "#{typeLC}Icon" + root = if type is 'Closed' and @isSticky + $ '.stickyIcon', @OP.nodes.info + else + $ '[title="Quote this post"]', @OP.nodes.info + $.after root, [$.tn(' '), icon] + kill: -> @isDead = true @timeOfDeath = Date.now() diff --git a/src/Miscellaneous/Index.coffee b/src/Miscellaneous/Index.coffee index f75754fcf..cdb74fe63 100644 --- a/src/Miscellaneous/Index.coffee +++ b/src/Miscellaneous/Index.coffee @@ -118,7 +118,10 @@ Index = for threadData in Index.liveThreadData threadRoot = Build.thread g.BOARD, threadData Index.nodes.push threadRoot, $.el 'hr' - unless thread = g.BOARD.threads[threadData.no] + if thread = g.BOARD.threads[threadData.no] + thread.setStatus 'Sticky', !!threadData.sticky + thread.setStatus 'Closed', !!threadData.closed + else thread = new Thread threadData.no, g.BOARD threads.push thread postRoots = $$ '.thread > .postContainer', threadRoot diff --git a/src/Monitoring/ThreadUpdater.coffee b/src/Monitoring/ThreadUpdater.coffee index 03c8b5053..8e9c68779 100644 --- a/src/Monitoring/ThreadUpdater.coffee +++ b/src/Monitoring/ThreadUpdater.coffee @@ -155,38 +155,27 @@ ThreadUpdater = , whenModified: true - updateThreadStatus: (title, OP) -> - titleLC = title.toLowerCase() - return if ThreadUpdater.thread["is#{title}"] is !!OP[titleLC] - unless ThreadUpdater.thread["is#{title}"] = !!OP[titleLC] - message = if title is 'Sticky' - 'The thread is not a sticky anymore.' + updateThreadStatus: (type, status) -> + return unless hasChanged = ThreadUpdater.thread["is#{type}"] isnt status + ThreadUpdater.thread.setStatus type, status + change = if type is 'Sticky' + if status + 'now a sticky' else - 'The thread is not closed anymore.' - new Notice 'info', message, 30 - $.rm $ ".#{titleLC}Icon", ThreadUpdater.thread.OP.nodes.info - return - message = if title is 'Sticky' - 'The thread is now a sticky.' + 'not a sticky anymore' else - 'The thread is now closed.' - new Notice 'info', message, 30 - icon = $.el 'img', - src: "//static.4chan.org/image/#{titleLC}.gif" - alt: title - title: title - className: "#{titleLC}Icon" - root = $ '[title="Quote this post"]', ThreadUpdater.thread.OP.nodes.info - if title is 'Closed' - root = $('.stickyIcon', ThreadUpdater.thread.OP.nodes.info) or root - $.after root, [$.tn(' '), icon] + if status + 'now closed' + else + 'not closed anymore' + new Notice 'info', "The thread is #{change}.", 30 parse: (postObjects) -> OP = postObjects[0] Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler - ThreadUpdater.updateThreadStatus 'Sticky', OP - ThreadUpdater.updateThreadStatus 'Closed', OP + ThreadUpdater.updateThreadStatus 'Sticky', !!OP.sticky + ThreadUpdater.updateThreadStatus 'Closed', !!OP.closed ThreadUpdater.thread.postLimit = !!OP.bumplimit ThreadUpdater.thread.fileLimit = !!OP.imagelimit From 9c81b6e459edacdd1da1e6d771badde7a85c6442 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Fri, 1 Nov 2013 18:40:36 +0100 Subject: [PATCH 037/225] Put the stickies on top of the index. --- src/Miscellaneous/Index.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Miscellaneous/Index.coffee b/src/Miscellaneous/Index.coffee index cdb74fe63..16fef5eaa 100644 --- a/src/Miscellaneous/Index.coffee +++ b/src/Miscellaneous/Index.coffee @@ -161,6 +161,10 @@ Index = for threadID in sortedThreadIDs i = Index.liveThreadIDs.indexOf(threadID) * 2 Index.sortedNodes.push Index.nodes[i], Index.nodes[i + 1] + # Put the sticky threads on top of the index.g + offset = 0 + for threadRoot, i in Index.sortedNodes by 2 when Get.threadFromRoot(threadRoot).isSticky + Index.sortedNodes.splice offset++ * 2, 0, Index.sortedNodes.splice(i, 2)... return unless Conf['Filter'] # Put the highlighted thread &
    on top of the index # while keeping the original order they appear in. From feb8e09c5a80c57cbd1ee55acd32c3a4662e6f1f Mon Sep 17 00:00:00 2001 From: Mayhem Date: Fri, 1 Nov 2013 18:57:17 +0100 Subject: [PATCH 038/225] Support hidpi post icons. --- src/General/Build.coffee | 18 +++++++++++------- src/General/Thread.coffee | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/General/Build.coffee b/src/General/Build.coffee index 8d018b8ee..c225fa3f0 100644 --- a/src/General/Build.coffee +++ b/src/General/Build.coffee @@ -60,6 +60,10 @@ Build = isOP = postID is threadID staticPath = '//static.4chan.org/image/' + gifIcon = if window.devicePixelRatio >= 2 + '@2x.gif' + else + '.gif' if email emailStart = '' @@ -82,21 +86,21 @@ Build = capcodeClass = " capcodeAdmin" capcodeStart = " ## Admin" - capcode = " " when 'mod' capcodeClass = " capcodeMod" capcodeStart = " ## Mod" - capcode = " " when 'developer' capcodeClass = " capcodeDeveloper" capcodeStart = " ## Developer" - capcode = " " else @@ -114,11 +118,11 @@ Build = if file?.isDeleted fileHTML = if isOP "
    " + - "File deleted." + + "File deleted." + "
    " else "
    " + - "File deleted." + + "File deleted." + "
    " else if file ext = file.name[-3..] @@ -178,11 +182,11 @@ Build = '' sticky = if isSticky - " Sticky" + " Sticky" else '' closed = if isClosed - " Closed" + " Closed" else '' diff --git a/src/General/Thread.coffee b/src/General/Thread.coffee index e681983e5..a02f4bc72 100644 --- a/src/General/Thread.coffee +++ b/src/General/Thread.coffee @@ -22,7 +22,7 @@ class Thread $.rm $ ".#{typeLC}Icon", @OP.nodes.info return icon = $.el 'img', - src: "//static.4chan.org/image/#{typeLC}.gif" + src: "//static.4chan.org/image/#{typeLC}#{if window.devicePixelRatio >= 2 then '@2x' else ''}.gif" alt: type title: type className: "#{typeLC}Icon" From 47710a7c6e424f8e09afadafbb1eb3d7b644923e Mon Sep 17 00:00:00 2001 From: Mayhem Date: Fri, 1 Nov 2013 22:06:59 +0100 Subject: [PATCH 039/225] Build the pagelist dynamically. --- Gruntfile.coffee | 1 + css/style.css | 1 + html/General/Index-pagelist.html | 11 ++++ src/{Miscellaneous => General}/Index.coffee | 62 +++++++++++++++++---- 4 files changed, 64 insertions(+), 11 deletions(-) create mode 100644 html/General/Index-pagelist.html rename src/{Miscellaneous => General}/Index.coffee (81%) diff --git a/Gruntfile.coffee b/Gruntfile.coffee index e7226450a..7e0db8c07 100644 --- a/Gruntfile.coffee +++ b/Gruntfile.coffee @@ -17,6 +17,7 @@ module.exports = (grunt) -> 'src/General/Header.coffee' 'src/General/Notice.coffee' 'src/General/Settings.coffee' + 'src/General/Index.coffee' 'src/General/Get.coffee' 'src/General/Build.coffee' # Features --> diff --git a/css/style.css b/css/style.css index 8e57b3adc..31f6e7d8b 100644 --- a/css/style.css +++ b/css/style.css @@ -364,6 +364,7 @@ a[href="javascript:;"] { /* Index */ :root.index-loading .board, +:root.index-loading .pagelist, :root.index-hide-pagelist .pagelist { display: none; } diff --git a/html/General/Index-pagelist.html b/html/General/Index-pagelist.html new file mode 100644 index 000000000..d8b1d7c99 --- /dev/null +++ b/html/General/Index-pagelist.html @@ -0,0 +1,11 @@ +
    +
    + diff --git a/src/Miscellaneous/Index.coffee b/src/General/Index.coffee similarity index 81% rename from src/Miscellaneous/Index.coffee rename to src/General/Index.coffee index 16fef5eaa..0915f01c4 100644 --- a/src/Miscellaneous/Index.coffee +++ b/src/General/Index.coffee @@ -25,10 +25,10 @@ Index = el: $.el 'span', textContent: 'Sort by' subEntries: [ { el: $.el 'label', innerHTML: ' Bump order' } + { el: $.el 'label', innerHTML: ' Last reply' } { el: $.el 'label', innerHTML: ' Creation date' } { el: $.el 'label', innerHTML: ' Reply count' } { el: $.el 'label', innerHTML: ' File count' } - { el: $.el 'label', innerHTML: ' Last reply' } ] for label in sortEntry.subEntries input = label.el.firstChild @@ -44,11 +44,16 @@ Index = subEntries: [modeEntry, sortEntry] $.addClass doc, 'index-loading' - Index.togglePagelist() - Index.root = $.el 'div', className: 'board' Index.update() - $.asap (-> $('.board', doc) or d.readyState isnt 'loading'), -> - $.replace $('.board'), Index.root + Index.root = $.el 'div', className: 'board' + Index.pagelist = $.el 'div', + className: 'pagelist' + innerHTML: """ + <%= grunt.file.read('html/General/Index-pagelist.html').replace(/>\s+<').trim() %> + """ + $.asap (-> $('.pagelist', doc) or d.readyState isnt 'loading'), -> + $.replace $('.board'), Index.root + $.replace $('.pagelist'), Index.pagelist $.rmClass doc, 'index-loading' cb: @@ -61,6 +66,39 @@ Index = togglePagelist: -> (if Conf['Index Mode'] is 'paged' then $.rmClass else $.addClass) doc, 'index-hide-pagelist' + buildPagelist: -> + pagesRoot = $ '.pages', Index.pagelist + if pagesRoot.childElementCount isnt Index.pagesNum + nodes = [] + for i in [0..Index.pagesNum - 1] + a = $.el 'a', + textContent: i + href: if i then i else './' + nodes.push $.tn('['), a, $.tn '] ' + $.rmAll pagesRoot + $.add pagesRoot, nodes + Index.setPage() + setPage: -> + pageNum = +window.location.pathname.split('/')[2] + pagesRoot = $ '.pages', Index.pagelist + # Previous/Next buttons + prev = pagesRoot.previousSibling.firstChild + next = pagesRoot.nextSibling.firstChild + href = Math.max pageNum - 1, 0 + prev.href = if href is 0 then './' else href + prev.firstChild.disabled = href is pageNum + href = Math.min pageNum + 1, Index.pagesNum - 1 + next.href = if href is 0 then './' else href + next.firstChild.disabled = href is pageNum + # current page + if strong = $ 'strong', pagesRoot + return if +strong.textContent is pageNum + $.replace strong, strong.firstChild + else + strong = $.el 'strong' + a = pagesRoot.children[pageNum] + $.before a, strong + $.add strong, a update: -> return unless navigator.onLine @@ -104,7 +142,9 @@ Index = Index.buildAll() Index.sort() Index.buildIndex() + Index.buildPagelist() parseThreadList: (pages) -> + Index.pagesNum = pages.length Index.threadsNumPerPage = pages[0].threads.length Index.liveThreadData = pages.reduce ((arr, next) -> arr.concat next.threads), [] Index.liveThreadIDs = Index.liveThreadData.map (data) -> data.no @@ -145,18 +185,18 @@ Index = switch Conf['Index Sort'] when 'bump' sortedThreadIDs = Index.liveThreadIDs - when 'birth' - sortedThreadIDs = [Index.liveThreadIDs...].sort (a, b) -> b - a - when 'replycount' - sortedThreadIDs = [Index.liveThreadData...].sort((a, b) -> b.replies - a.replies).map (data) -> data.no - when 'filecount' - sortedThreadIDs = [Index.liveThreadData...].sort((a, b) -> b.images - a.images).map (data) -> data.no when 'lastreply' sortedThreadIDs = [Index.liveThreadData...].sort((a, b) -> a = a.last_replies[a.last_replies.length - 1] if 'last_replies' of a b = b.last_replies[b.last_replies.length - 1] if 'last_replies' of b b.no - a.no ).map (data) -> data.no + when 'birth' + sortedThreadIDs = [Index.liveThreadIDs...].sort (a, b) -> b - a + when 'replycount' + sortedThreadIDs = [Index.liveThreadData...].sort((a, b) -> b.replies - a.replies).map (data) -> data.no + when 'filecount' + sortedThreadIDs = [Index.liveThreadData...].sort((a, b) -> b.images - a.images).map (data) -> data.no Index.sortedNodes = [] for threadID in sortedThreadIDs i = Index.liveThreadIDs.indexOf(threadID) * 2 From bc72f0f763696f7c12a68d20b1ab68de7315823a Mon Sep 17 00:00:00 2001 From: Mayhem Date: Fri, 1 Nov 2013 23:08:31 +0100 Subject: [PATCH 040/225] Create importHTML function, and use it. --- Gruntfile.coffee | 8 ++++++- src/General/Header.coffee | 4 +--- src/General/Index.coffee | 4 +--- src/General/Settings.coffee | 36 ++++++++--------------------- src/Monitoring/Favicon.coffee | 4 ++-- src/Monitoring/ThreadStats.coffee | 4 +--- src/Monitoring/ThreadUpdater.coffee | 4 +--- src/Monitoring/ThreadWatcher.coffee | 4 +--- src/Posting/QR.coffee | 4 +--- 9 files changed, 24 insertions(+), 48 deletions(-) diff --git a/Gruntfile.coffee b/Gruntfile.coffee index 7e0db8c07..e8dcf07dd 100644 --- a/Gruntfile.coffee +++ b/Gruntfile.coffee @@ -1,11 +1,17 @@ module.exports = (grunt) -> + importHTML = (filename) -> + "\"\"\"#{grunt.file.read("html/#{filename}.html").replace(/^\s+|\s+$ grunt.config 'pkg' + get: -> + pkg = grunt.config 'pkg' + pkg.importHTML = importHTML + pkg enumerable: true ) coffee: diff --git a/src/General/Header.coffee b/src/General/Header.coffee index 7e401e5a9..c94e697ae 100644 --- a/src/General/Header.coffee +++ b/src/General/Header.coffee @@ -2,9 +2,7 @@ Header = init: -> headerEl = $.el 'div', id: 'header' - innerHTML: """ - <%= grunt.file.read('html/General/Header.html').replace(/>\s+<').trim() %> - """ + innerHTML: <%= importHTML('General/Header') %> @bar = $ '#header-bar', headerEl @toggle = $ '#toggle-header-bar', @bar diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 0915f01c4..c930bb3d0 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -48,9 +48,7 @@ Index = Index.root = $.el 'div', className: 'board' Index.pagelist = $.el 'div', className: 'pagelist' - innerHTML: """ - <%= grunt.file.read('html/General/Index-pagelist.html').replace(/>\s+<').trim() %> - """ + innerHTML: <%= importHTML('General/Index-pagelist') %> $.asap (-> $('.pagelist', doc) or d.readyState isnt 'loading'), -> $.replace $('.board'), Index.root $.replace $('.pagelist'), Index.pagelist diff --git a/src/General/Settings.coffee b/src/General/Settings.coffee index 65f2a5094..4c0499e4c 100644 --- a/src/General/Settings.coffee +++ b/src/General/Settings.coffee @@ -61,9 +61,7 @@ Settings = return if Settings.dialog $.event 'CloseMenu' - html = """ - <%= grunt.file.read('html/General/Settings.html').replace(/>\s+<').trim() %> - """ + html = <%= importHTML('General/Settings') %> Settings.dialog = overlay = $.el 'div', id: 'overlay' @@ -113,9 +111,7 @@ Settings = section.scrollTop = 0 main: (section) -> - section.innerHTML = """ - <%= grunt.file.read('html/General/Settings-section-Main.html').replace(/>\s+<').trim() %> - """ + section.innerHTML = <%= importHTML('General/Settings-section-Main') %> $.on $('.export', section), 'click', Settings.export $.on $('.import', section), 'click', Settings.import $.on $('input', section), 'change', Settings.onImport @@ -290,9 +286,7 @@ Settings = data filter: (section) -> - section.innerHTML = """ - <%= grunt.file.read('html/General/Settings-section-Filter.html').replace(/>\s+<').trim() %> - """ + section.innerHTML = <%= importHTML('General/Settings-section-Filter') %> select = $ 'select', section $.on select, 'change', Settings.selectFilter Settings.selectFilter.call select @@ -309,32 +303,24 @@ Settings = $.on ta, 'change', $.cb.value $.add div, ta return - div.innerHTML = """ - <%= grunt.file.read('html/General/Settings-section-Filter-guide.html').replace(/>\s+<').trim() %> - """ + div.innerHTML = <%= importHTML('General/Settings-section-Filter-guide') %> qr: (section) -> - section.innerHTML = """ - <%= grunt.file.read('html/General/Settings-section-QR.html').replace(/>\s+<').trim() %> - """ + section.innerHTML = <%= importHTML('General/Settings-section-QR') %> ta = $ 'textarea', section $.get 'QR.personas', Conf['QR.personas'], (item) -> ta.value = item['QR.personas'] $.on ta, 'change', $.cb.value sauce: (section) -> - section.innerHTML = """ - <%= grunt.file.read('html/General/Settings-section-Sauce.html').replace(/>\s+<').trim() %> - """ + section.innerHTML = <%= importHTML('General/Settings-section-Sauce') %> ta = $ 'textarea', section $.get 'sauces', Conf['sauces'], (item) -> ta.value = item['sauces'] $.on ta, 'change', $.cb.value rice: (section) -> - section.innerHTML = """ - <%= grunt.file.read('html/General/Settings-section-Rice.html').replace(/>\s+<').trim() %> - """ + section.innerHTML = <%= importHTML('General/Settings-section-Rice') %> items = {} inputs = {} for name in ['boardnav', 'time', 'backlink', 'fileInfo', 'favicon', 'usercss'] @@ -395,9 +381,7 @@ Settings = CustomCSS.update() archives: (section) -> - section.innerHTML = """ - <%= grunt.file.read('html/General/Settings-section-Archives.html').replace(/>\s+<').trim() %> - """ + section.innerHTML = <%= importHTML('General/Settings-section-Archives') %> showLastUpdateTime = (time) -> $('time', section).textContent = new Date(time).toLocaleString() @@ -470,9 +454,7 @@ Settings = $.set 'selectedArchives', selectedArchives keybinds: (section) -> - section.innerHTML = """ - <%= grunt.file.read('html/General/Settings-section-Keybinds.html').replace(/>\s+<').trim() %> - """ + section.innerHTML = <%= importHTML('General/Settings-section-Keybinds') %> tbody = $ 'tbody', section items = {} inputs = {} diff --git a/src/Monitoring/Favicon.coffee b/src/Monitoring/Favicon.coffee index 806134034..6085a6f2c 100644 --- a/src/Monitoring/Favicon.coffee +++ b/src/Monitoring/Favicon.coffee @@ -45,5 +45,5 @@ Favicon = Favicon.unread = Favicon.unreadNSFW Favicon.unreadY = Favicon.unreadNSFWY - dead: 'data:image/gif;base64,<%= grunt.file.read("img/favicons/dead.gif", {encoding: "base64"}) %>' - logo: 'data:image/png;base64,<%= grunt.file.read("img/icon128.png", {encoding: "base64"}) %>' + dead: 'data:image/gif;base64,<%= grunt.file.read("img/favicons/dead.gif", {encoding: "base64"}) %>' + logo: 'data:image/png;base64,<%= grunt.file.read("img/icon128.png", {encoding: "base64"}) %>' diff --git a/src/Monitoring/ThreadStats.coffee b/src/Monitoring/ThreadStats.coffee index f80154cae..89d1be0c8 100644 --- a/src/Monitoring/ThreadStats.coffee +++ b/src/Monitoring/ThreadStats.coffee @@ -1,9 +1,7 @@ ThreadStats = init: -> return if g.VIEW isnt 'thread' or !Conf['Thread Stats'] - @dialog = UI.dialog 'thread-stats', 'bottom: 0; left: 0;', """ - <%= grunt.file.read('html/Monitoring/ThreadStats.html').replace(/>\s+<').trim() %> - """ + @dialog = UI.dialog 'thread-stats', 'bottom: 0; left: 0;', <%= importHTML('Monitoring/ThreadStats') %> @postCountEl = $ '#post-count', @dialog @fileCountEl = $ '#file-count', @dialog diff --git a/src/Monitoring/ThreadUpdater.coffee b/src/Monitoring/ThreadUpdater.coffee index 8e9c68779..602f45383 100644 --- a/src/Monitoring/ThreadUpdater.coffee +++ b/src/Monitoring/ThreadUpdater.coffee @@ -7,9 +7,7 @@ ThreadUpdater = checked = if Conf[name] then 'checked' else '' html += "
    " - html = """ - <%= grunt.file.read('html/Monitoring/ThreadUpdater.html').replace(/>\s+<').trim() %> - """ + html = <%= importHTML('Monitoring/ThreadUpdater') %> @dialog = UI.dialog 'updater', 'bottom: 0; right: 0;', html @timer = $ '#update-timer', @dialog diff --git a/src/Monitoring/ThreadWatcher.coffee b/src/Monitoring/ThreadWatcher.coffee index 76abbf521..3b021d5a7 100644 --- a/src/Monitoring/ThreadWatcher.coffee +++ b/src/Monitoring/ThreadWatcher.coffee @@ -3,9 +3,7 @@ ThreadWatcher = return if !Conf['Thread Watcher'] @db = new DataBoard 'watchedThreads', @refresh, true - @dialog = UI.dialog 'thread-watcher', 'top: 50px; left: 0px;', """ - <%= grunt.file.read('html/Monitoring/ThreadWatcher.html').replace(/>\s+<').trim() %> - """ + @dialog = UI.dialog 'thread-watcher', 'top: 50px; left: 0px;', <%= importHTML('Monitoring/ThreadWatcher') %> @status = $ '#watcher-status', @dialog @list = @dialog.lastElementChild diff --git a/src/Posting/QR.coffee b/src/Posting/QR.coffee index 9f81f22a3..7a8f829ea 100644 --- a/src/Posting/QR.coffee +++ b/src/Posting/QR.coffee @@ -820,9 +820,7 @@ QR = 'new' dialog: -> - dialog = UI.dialog 'qr', 'top:0;right:0;', """ - <%= grunt.file.read('html/Posting/QR.html').replace(/>\s+<').trim() %> - """ + dialog = UI.dialog 'qr', 'top:0;right:0;', <%= importHTML('Posting/QR') %> QR.nodes = nodes = el: dialog From 0540dcf30f2d5c1b3170f6f708987b7fd0369963 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 2 Nov 2013 00:52:12 +0100 Subject: [PATCH 041/225] Instantaneous index page navigation. Also fix page navigation keybinds. --- CHANGELOG.md | 13 ++++---- css/style.css | 3 +- html/General/Index-pagelist.html | 4 +-- src/General/Index.coffee | 50 ++++++++++++++++++++++++++----- src/Miscellaneous/Keybinds.coffee | 17 ++++++----- 5 files changed, 61 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 928d719eb..bffeab527 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,13 @@ Index navigation improvements: - You can now refresh the index page you are on with the icon in the header bar or the same keybind for refreshing threads. - - You can now switch between single-page and all-pages navigation via the "Index Navigation" header sub-menu. + - You can now switch between paged and all-threads index modes via the "Index Navigation" header sub-menu. - Threads in the index can now be sorted by: - - bump order - - creation date - - reply count - - file count - - last reply + - Bump order + - Last reply + - Creation date + - Reply count + - File count + - Navigating across index pages is now instantaneous. Added a keybind to open the catalog search field on index pages. diff --git a/css/style.css b/css/style.css index 31f6e7d8b..751f3b772 100644 --- a/css/style.css +++ b/css/style.css @@ -364,8 +364,7 @@ a[href="javascript:;"] { /* Index */ :root.index-loading .board, -:root.index-loading .pagelist, -:root.index-hide-pagelist .pagelist { +:root.index-loading .pagelist { display: none; } diff --git a/html/General/Index-pagelist.html b/html/General/Index-pagelist.html index d8b1d7c99..e6923bb7a 100644 --- a/html/General/Index-pagelist.html +++ b/html/General/Index-pagelist.html @@ -1,11 +1,11 @@
    diff --git a/src/General/Index.coffee b/src/General/Index.coffee index c930bb3d0..13eb065ab 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -2,12 +2,12 @@ Index = init: -> return if g.VIEW isnt 'index' - Index.button = $.el 'a', + @button = $.el 'a', className: 'index-refresh-shortcut fa fa-refresh' title: 'Refresh Index' href: 'javascript:;' - $.on Index.button, 'click', Index.update - Header.addShortcut Index.button, 1 + $.on @button, 'click', @update + Header.addShortcut @button, 1 modeEntry = el: $.el 'span', textContent: 'Index mode' @@ -44,11 +44,15 @@ Index = subEntries: [modeEntry, sortEntry] $.addClass doc, 'index-loading' - Index.update() - Index.root = $.el 'div', className: 'board' - Index.pagelist = $.el 'div', + @update() + @root = $.el 'div', className: 'board' + @pagelist = $.el 'div', className: 'pagelist' + hidden: true innerHTML: <%= importHTML('General/Index-pagelist') %> + Index.currentPage = +window.location.pathname.split('/')[2] + $.on window, 'popstate', @cb.popstate + $.on @pagelist, 'click', @cb.pageNav $.asap (-> $('.pagelist', doc) or d.readyState isnt 'loading'), -> $.replace $('.board'), Index.root $.replace $('.pagelist'), Index.pagelist @@ -61,9 +65,38 @@ Index = sort: -> Index.sort() Index.buildIndex() + popstate: (e) -> + Index.currentPage = +window.location.pathname.split('/')[2] + Index.pageLoad() + pageNav: (e) -> + return if e.shiftKey or e.altKey or e.ctrlKey or e.metaKey or e.button isnt 0 + switch e.target.nodeName + when 'BUTTON' + a = e.target.parentNode + when 'A' + a = e.target + else + return + e.preventDefault() + Index.pageNav +a.pathname.split('/')[2] + + scrollToIndex: -> + Header.scrollTo Index.root if Index.root.getBoundingClientRect().top < 0 + + pageNav: (pageNum) -> + return if Index.currentPage is pageNum + history.pushState null, '', if pageNum is 0 then './' else pageNum + Index.currentPage = pageNum + Index.pageLoad() + pageLoad: -> + return unless 'currentPage' of Index # unnecessary popstate on page load + return if Conf['Index Mode'] isnt 'paged' + Index.buildIndex() + Index.setPage() + Index.scrollToIndex() togglePagelist: -> - (if Conf['Index Mode'] is 'paged' then $.rmClass else $.addClass) doc, 'index-hide-pagelist' + Index.pagelist.hidden = Conf['Index Mode'] isnt 'paged' buildPagelist: -> pagesRoot = $ '.pages', Index.pagelist if pagesRoot.childElementCount isnt Index.pagesNum @@ -76,6 +109,7 @@ Index = $.rmAll pagesRoot $.add pagesRoot, nodes Index.setPage() + Index.togglePagelist() setPage: -> pageNum = +window.location.pathname.split('/')[2] pagesRoot = $ '.pages', Index.pagelist @@ -134,7 +168,7 @@ Index = notice.el.lastElementChild.textContent = 'Index refreshed!' setTimeout notice.close, $.SECOND - Header.scrollTo Index.root if Index.root.getBoundingClientRect().top < 0 + Index.scrollToIndex() parse: (pages) -> Index.parseThreadList pages Index.buildAll() diff --git a/src/Miscellaneous/Keybinds.coffee b/src/Miscellaneous/Keybinds.coffee index c5fb5d59a..7ad88b273 100644 --- a/src/Miscellaneous/Keybinds.coffee +++ b/src/Miscellaneous/Keybinds.coffee @@ -74,17 +74,18 @@ Keybinds = Keybinds.img threadRoot, true # Board Navigation when Conf['Front page'] - window.location = "/#{g.BOARD}/0#delform" + if g.VIEW is 'index' + Index.pageNav 0 + else + window.location = "/#{g.BOARD}/" when Conf['Open front page'] - $.open "/#{g.BOARD}/#delform" + $.open "/#{g.BOARD}/" when Conf['Next page'] - return if Conf['Index Mode'] isnt 'paged' - if form = $ '.next form' - window.location = form.action + return unless g.VIEW is 'index' and Conf['Index Mode'] is 'paged' + $('.next a', Index.pagelist).click() when Conf['Previous page'] - return if Conf['Index Mode'] isnt 'paged' - if form = $ '.prev form' - window.location = form.action + return unless g.VIEW is 'index' and Conf['Index Mode'] is 'paged' + $('.prev a', Index.pagelist).click() when Conf['Search form'] $.id('search-btn').click() # Thread Navigation From 6dcf11db6665a7dfc67d43f7969f6190aebda415 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 2 Nov 2013 04:26:08 +0100 Subject: [PATCH 042/225] Don't break Header.hashScroll() for #top and #bottom. --- src/General/Header.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/General/Header.coffee b/src/General/Header.coffee index c94e697ae..2b8465933 100644 --- a/src/General/Header.coffee +++ b/src/General/Header.coffee @@ -242,7 +242,8 @@ Header = $('input[name=boardnav]', settings).focus() hashScroll: -> - return unless (hash = @location.hash[1..]) and post = $.id hash + hash = @location.hash[1..] + return unless /^p\d+$/.test(hash) and post = $.id hash return if (Get.postFromRoot post).isHidden Header.scrollTo post scrollTo: (root) -> From 4c00c6f9aed17e7d36a40c404395291574ecde70 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 2 Nov 2013 13:46:19 +0100 Subject: [PATCH 043/225] Add thread refresh shortcut. --- src/Monitoring/ThreadUpdater.coffee | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Monitoring/ThreadUpdater.coffee b/src/Monitoring/ThreadUpdater.coffee index 602f45383..b35f9502e 100644 --- a/src/Monitoring/ThreadUpdater.coffee +++ b/src/Monitoring/ThreadUpdater.coffee @@ -2,6 +2,13 @@ ThreadUpdater = init: -> return if g.VIEW isnt 'thread' or !Conf['Thread Updater'] + @button = $.el 'a', + className: 'thread-refresh-shortcut fa fa-refresh' + title: 'Refresh Thread' + href: 'javascript:;' + $.on @button, 'click', @update + Header.addShortcut @button, 1 + html = '' for name, conf of Config.updater.checkbox checked = if Conf[name] then 'checked' else '' @@ -79,6 +86,7 @@ ThreadUpdater = ThreadUpdater.interval = @value = val $.cb.value.call @ if e load: (e) -> + $.rmClass ThreadUpdater.button, 'fa-spin' {req} = ThreadUpdater delete ThreadUpdater.req if e.type isnt 'loadend' # timeout or abort @@ -141,6 +149,7 @@ ThreadUpdater = update: -> return unless navigator.onLine + $.addClass ThreadUpdater.button, 'fa-spin' ThreadUpdater.count() ThreadUpdater.set 'timer', '...' ThreadUpdater.req?.abort() From 7fd72676cb0b8cc7fd50cdde89dde1f8004d5118 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 2 Nov 2013 13:56:59 +0100 Subject: [PATCH 044/225] Fix spoiler thumbnails when building threads. --- src/General/Build.coffee | 2 ++ src/Miscellaneous/ExpandComment.coffee | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/General/Build.coffee b/src/General/Build.coffee index c225fa3f0..03cfaa9b1 100644 --- a/src/General/Build.coffee +++ b/src/General/Build.coffee @@ -264,6 +264,8 @@ Build = className: 'thread' id: "t#{data.no}" + Build.spoilerRange[board] = data.custom_spoiler + for obj in [data].concat data.last_replies or [] $.add root, if post = g.posts["#{board}.#{obj.no}"] post.nodes.root diff --git a/src/Miscellaneous/ExpandComment.coffee b/src/Miscellaneous/ExpandComment.coffee index 103c891e5..12fee2935 100644 --- a/src/Miscellaneous/ExpandComment.coffee +++ b/src/Miscellaneous/ExpandComment.coffee @@ -32,8 +32,7 @@ ExpandComment = return posts = JSON.parse(req.response).posts - if spoilerRange = posts[0].custom_spoiler - Build.spoilerRange[g.BOARD] = spoilerRange + Build.spoilerRange[g.BOARD] = posts[0].custom_spoiler for postObj in posts break if postObj.no is post.ID From a0d3694b61f8ed5733ea0da406d7ef3e05711e99 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 2 Nov 2013 14:32:54 +0100 Subject: [PATCH 045/225] Fix minor bugs with keybinds/pageload + index. --- src/General/Index.coffee | 19 ++++++++++--------- src/Miscellaneous/Keybinds.coffee | 4 ++-- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 13eb065ab..4b22276ae 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -50,7 +50,7 @@ Index = className: 'pagelist' hidden: true innerHTML: <%= importHTML('General/Index-pagelist') %> - Index.currentPage = +window.location.pathname.split('/')[2] + Index.currentPage = Index.getCurrentPage() $.on window, 'popstate', @cb.popstate $.on @pagelist, 'click', @cb.pageNav $.asap (-> $('.pagelist', doc) or d.readyState isnt 'loading'), -> @@ -66,8 +66,8 @@ Index = Index.sort() Index.buildIndex() popstate: (e) -> - Index.currentPage = +window.location.pathname.split('/')[2] - Index.pageLoad() + pageNum = Index.getCurrentPage() + Index.pageLoad pageNum if Index.currentPage isnt pageNum pageNav: (e) -> return if e.shiftKey or e.altKey or e.ctrlKey or e.metaKey or e.button isnt 0 switch e.target.nodeName @@ -83,13 +83,14 @@ Index = scrollToIndex: -> Header.scrollTo Index.root if Index.root.getBoundingClientRect().top < 0 + getCurrentPage: -> + +window.location.pathname.split('/')[2] pageNav: (pageNum) -> return if Index.currentPage is pageNum history.pushState null, '', if pageNum is 0 then './' else pageNum + Index.pageLoad pageNum + pageLoad: (pageNum) -> Index.currentPage = pageNum - Index.pageLoad() - pageLoad: -> - return unless 'currentPage' of Index # unnecessary popstate on page load return if Conf['Index Mode'] isnt 'paged' Index.buildIndex() Index.setPage() @@ -111,7 +112,7 @@ Index = Index.setPage() Index.togglePagelist() setPage: -> - pageNum = +window.location.pathname.split('/')[2] + pageNum = Index.getCurrentPage() pagesRoot = $ '.pages', Index.pagelist # Previous/Next buttons prev = pagesRoot.previousSibling.firstChild @@ -246,9 +247,9 @@ Index = return buildIndex: -> if Conf['Index Mode'] is 'paged' - pageNum = +window.location.pathname.split('/')[2] + pageNum = Index.getCurrentPage() nodesPerPage = Index.threadsNumPerPage * 2 - nodes = Index.sortedNodes.slice nodesPerPage * pageNum, nodesPerPage * (pageNum + 1) + nodes = Index.sortedNodes[nodesPerPage * pageNum ... nodesPerPage * (pageNum + 1)] else nodes = Index.sortedNodes $.event 'IndexRefresh' diff --git a/src/Miscellaneous/Keybinds.coffee b/src/Miscellaneous/Keybinds.coffee index 7ad88b273..d59d771e7 100644 --- a/src/Miscellaneous/Keybinds.coffee +++ b/src/Miscellaneous/Keybinds.coffee @@ -82,10 +82,10 @@ Keybinds = $.open "/#{g.BOARD}/" when Conf['Next page'] return unless g.VIEW is 'index' and Conf['Index Mode'] is 'paged' - $('.next a', Index.pagelist).click() + $('.next button', Index.pagelist).click() when Conf['Previous page'] return unless g.VIEW is 'index' and Conf['Index Mode'] is 'paged' - $('.prev a', Index.pagelist).click() + $('.prev button', Index.pagelist).click() when Conf['Search form'] $.id('search-btn').click() # Thread Navigation From 61cd553a64d949dd2a22b857b301707f5d08ba42 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 2 Nov 2013 15:23:32 +0100 Subject: [PATCH 046/225] Fix/Refactor ExpandThread.coffee --- src/Miscellaneous/ExpandThread.coffee | 139 ++++++++++++-------------- 1 file changed, 65 insertions(+), 74 deletions(-) diff --git a/src/Miscellaneous/ExpandThread.coffee b/src/Miscellaneous/ExpandThread.coffee index dbe736305..c1ca5229b 100644 --- a/src/Miscellaneous/ExpandThread.coffee +++ b/src/Miscellaneous/ExpandThread.coffee @@ -1,25 +1,29 @@ ExpandThread = init: -> return if g.VIEW isnt 'index' or !Conf['Thread Expansion'] - - $.on d, 'IndexRefresh', @onrefresh - + @statuses = {} + $.on d, 'IndexRefresh', @onIndexRefresh Thread.callbacks.push name: 'Thread Expansion' cb: @node node: -> - return unless span = $.x 'following-sibling::span[contains(@class,"summary")][1]', @OP.nodes.root - [posts, files] = span.textContent.match /\d+/g + ExpandThread.setButton @ + + setButton: (thread) -> + return unless span = $.x 'following-sibling::span[contains(@class,"summary")][1]', thread.OP.nodes.root a = $.el 'a', - textContent: ExpandThread.text '+', posts, files + textContent: ExpandThread.text '+', span.textContent.match(/\d+/g)... className: 'summary' href: 'javascript:;' $.on a, 'click', ExpandThread.cbToggle $.replace span, a - onrefresh: -> + onIndexRefresh: -> + for threadID, status of ExpandThread.statuses + status.req?.abort() + delete ExpandThread.statuses[threadID] for threadID, thread of g.BOARD.threads - ExpandThread.node.call thread + ExpandThread.setButton thread return text: (status, posts, files) -> @@ -35,89 +39,76 @@ ExpandThread = toggle: (thread) -> threadRoot = thread.OP.nodes.root.parentNode a = $ '.summary', threadRoot - - switch thread.isExpanded - when false, undefined - for post in $$ '.thread > .postContainer', threadRoot - ExpandComment.expand Get.postFromRoot post - unless a - thread.isExpanded = true - return - thread.isExpanded = 'loading' - [posts, files] = a.textContent.match /\d+/g - a.textContent = ExpandThread.text '...', posts, files - $.cache "//api.4chan.org/#{thread.board}/res/#{thread}.json", -> - ExpandThread.parse @, thread, a - - when 'loading' - thread.isExpanded = false - return unless a - [posts, files] = a.textContent.match /\d+/g - a.textContent = ExpandThread.text '+', posts, files - - when true - thread.isExpanded = false - #goddamit moot - num = if thread.isSticky - 1 - else switch g.BOARD.ID - # XXX boards config - when 'b', 'vg' then 3 - when 't' then 1 - else 5 - posts = $$ ".thread > .replyContainer", threadRoot - for post in [thread.OP.nodes.root].concat posts[-num..] - ExpandComment.contract Get.postFromRoot post - return unless a - postsCount = 0 - filesCount = 0 - for reply in posts[...-num] - if Conf['Quote Inlining'] - # rm clones - inlined.click() while inlined = $ '.inlined', reply - postsCount++ - filesCount++ if 'file' of Get.postFromRoot reply - $.rm reply - a.textContent = ExpandThread.text '+', postsCount, filesCount - return - - parse: (req, thread, a) -> - return if a.textContent[0] is '+' - if req.status not in [200, 304] - a.textContent = "Error #{req.statusText} (#{req.status})" - $.off a, 'click', ExpandThread.cbToggle + if thread.ID of ExpandThread.statuses + ExpandThread.contract thread, a, threadRoot + else + ExpandThread.expand thread, a, threadRoot + expand: (thread, a, threadRoot) -> + ExpandThread.statuses[thread] = status = {} + for post in $$ '.thread > .postContainer', threadRoot + ExpandComment.expand Get.postFromRoot post + return unless a + a.textContent = ExpandThread.text '...', a.textContent.match(/\d+/g)... + status.req = $.cache "//api.4chan.org/#{thread.board}/res/#{thread}.json", -> + delete status.req + ExpandThread.parse @, thread, a + contract: (thread, a, threadRoot) -> + status = ExpandThread.statuses[thread] + delete ExpandThread.statuses[thread] + if status.req + status.req.abort() + a.textContent = ExpandThread.text '+', a.textContent.match(/\d+/g)... if a return - thread.isExpanded = true + num = if thread.isSticky + 1 + else switch g.BOARD.ID + # XXX boards config + when 'b', 'vg' then 3 + when 't' then 1 + else 5 + posts = $$ '.thread > .replyContainer', threadRoot + for post in [thread.OP.nodes.root].concat posts[-num..] + ExpandComment.contract Get.postFromRoot post + return unless a + postsCount = 0 + filesCount = 0 + for reply in posts[...-num] + # rm clones + inlined.click() while inlined = $ '.inlined', reply if Conf['Quote Inlining'] + postsCount++ + filesCount++ if 'file' of Get.postFromRoot reply + $.rm reply + a.textContent = ExpandThread.text '+', postsCount, filesCount + parse: (req, thread, a) -> + if req.status not in [200, 304] + a.textContent = "Error #{req.statusText} (#{req.status})" + return - {posts} = JSON.parse req.response - if spoilerRange = posts.shift().custom_spoiler - Build.spoilerRange[thread.board] = spoilerRange + data = JSON.parse(req.response).posts + Build.spoilerRange[thread.board] = data.shift().custom_spoiler - postsObj = [] + posts = [] postsRoot = [] filesCount = 0 - for reply in posts - if post = thread.posts[reply.no] + for postData in data + if post = thread.posts[postData.no] filesCount++ if 'file' of post postsRoot.push post.nodes.root continue - root = Build.postFromObject reply, thread.board.ID + root = Build.postFromObject postData, thread.board.ID post = new Post root, thread, thread.board - link = $ 'a[title="Highlight this post"]', root - link.href = "res/#{thread}#p#{post}" - link.nextSibling.href = "res/#{thread}#q#{post}" filesCount++ if 'file' of post - postsObj.push post + posts.push post postsRoot.push root - Main.callbackNodes Post, postsObj + Main.callbackNodes Post, posts $.after a, postsRoot - postsCount = postsRoot.length + postsCount = postsRoot.length a.textContent = ExpandThread.text '-', postsCount, filesCount # Enable 4chan features. if Conf['Enable 4chan\'s Extension'] - $.globalEval "Parser.parseThread(#{thread.ID}, 1, #{postsCount})" + $.globalEval "Parser.parseThread(#{thread}, 1, #{postsCount})" else Fourchan.parseThread thread.ID, 1, postsCount From 6460d5e0c18e54a7ed4fcea11c0a4f0cb35bbd84 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 2 Nov 2013 15:55:50 +0100 Subject: [PATCH 047/225] Fix early notices. --- src/General/Header.coffee | 1 + src/General/Notice.coffee | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/General/Header.coffee b/src/General/Header.coffee index 2b8465933..f76da0383 100644 --- a/src/General/Header.coffee +++ b/src/General/Header.coffee @@ -6,6 +6,7 @@ Header = @bar = $ '#header-bar', headerEl @toggle = $ '#toggle-header-bar', @bar + @noticesRoot = $ '#notifications', headerEl @menu = new UI.Menu 'header' menuButton = $.el 'a', diff --git a/src/General/Notice.coffee b/src/General/Notice.coffee index 60b46ff77..90c2e504b 100644 --- a/src/General/Notice.coffee +++ b/src/General/Notice.coffee @@ -19,7 +19,7 @@ class Notice $.on d, 'visibilitychange', @add return $.off d, 'visibilitychange', @add - $.add $.id('notifications'), @el + $.add Header.noticesRoot, @el @el.clientHeight # force reflow @el.style.opacity = 1 setTimeout @close, @timeout * $.SECOND if @timeout From a22356893727c9872bf4908740e481bc46ef7b10 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 2 Nov 2013 16:46:56 +0100 Subject: [PATCH 048/225] Fix pretty-printing on Chrome. --- src/Miscellaneous/Fourchan.coffee | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/Miscellaneous/Fourchan.coffee b/src/Miscellaneous/Fourchan.coffee index 64b1f4562..1b78c17de 100644 --- a/src/Miscellaneous/Fourchan.coffee +++ b/src/Miscellaneous/Fourchan.coffee @@ -6,8 +6,9 @@ Fourchan = if board is 'g' $.globalEval """ window.addEventListener('prettyprint', function(e) { - var pre = e.detail; - pre.innerHTML = prettyPrintOne(pre.innerHTML); + window.dispatchEvent(new CustomEvent('prettyprint:cb', { + detail: prettyPrintOne(e.detail) + })); }, false); """ Post.callbacks.push @@ -32,9 +33,11 @@ Fourchan = cb: @math code: -> return if @isClone - for pre in $$ '.prettyprint:not(.prettyprinted)', @nodes.comment - $.event 'prettyprint', pre, window - $.addClass pre, 'prettyprinted' + apply = (e) -> pre.innerHTML = e.detail + $.on window, 'prettyprint:cb', apply + for pre in $$ '.prettyprint', @nodes.comment + $.event 'prettyprint', pre.innerHTML, window + $.off window, 'prettyprint:cb', apply return math: -> return if @isClone or !$ '.math', @nodes.comment From d00597f53d6d9740c79433dfd33623373480969d Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 2 Nov 2013 17:33:39 +0100 Subject: [PATCH 049/225] Remove comment expansion-related code. --- src/General/Config.coffee | 1 - src/General/Main.coffee | 1 - src/Miscellaneous/ExpandComment.coffee | 70 -------------------------- src/Miscellaneous/ExpandThread.coffee | 11 +--- 4 files changed, 2 insertions(+), 81 deletions(-) delete mode 100644 src/Miscellaneous/ExpandComment.coffee diff --git a/src/General/Config.coffee b/src/General/Config.coffee index 95f1f2a48..715822858 100644 --- a/src/General/Config.coffee +++ b/src/General/Config.coffee @@ -9,7 +9,6 @@ Config = 'Time Formatting': [true, 'Localize and format timestamps.'] 'Relative Post Dates': [false, 'Display dates like "3 minutes ago". Tooltip shows the timestamp.'] 'File Info Formatting': [true, 'Reformat the file information.'] - 'Comment Expansion': [true, 'Add buttons to expand too long comments.'] 'Thread Expansion': [true, 'Add buttons to expand threads.'] 'Index Navigation': [false, 'Add buttons to navigate between threads.'] 'Reply Navigation': [false, 'Add buttons to navigate to top / bottom of thread.'] diff --git a/src/General/Main.coffee b/src/General/Main.coffee index 0528e4f08..9756b15e2 100644 --- a/src/General/Main.coffee +++ b/src/General/Main.coffee @@ -106,7 +106,6 @@ Main = initFeature 'Reveal Spoilers', RevealSpoilers initFeature 'Auto-GIF', AutoGIF initFeature 'Image Hover', ImageHover - initFeature 'Comment Expansion', ExpandComment initFeature 'Thread Expansion', ExpandThread initFeature 'Thread Excerpt', ThreadExcerpt initFeature 'Favicon', Favicon diff --git a/src/Miscellaneous/ExpandComment.coffee b/src/Miscellaneous/ExpandComment.coffee deleted file mode 100644 index 12fee2935..000000000 --- a/src/Miscellaneous/ExpandComment.coffee +++ /dev/null @@ -1,70 +0,0 @@ -ExpandComment = - init: -> - return if g.VIEW isnt 'index' or !Conf['Comment Expansion'] - - Post.callbacks.push - name: 'Comment Expansion' - cb: @node - node: -> - if a = $ '.abbr > a:not([onclick])', @nodes.comment - $.on a, 'click', ExpandComment.cb - cb: (e) -> - e.preventDefault() - ExpandComment.expand Get.postFromNode @ - expand: (post) -> - if post.nodes.longComment and !post.nodes.longComment.parentNode - $.replace post.nodes.shortComment, post.nodes.longComment - post.nodes.comment = post.nodes.longComment - return - return unless a = $ '.abbr > a', post.nodes.comment - a.textContent = "Post No.#{post} Loading..." - $.cache "//api.4chan.org#{a.pathname}.json", -> ExpandComment.parse @, a, post - contract: (post) -> - return unless post.nodes.shortComment - a = $ '.abbr > a', post.nodes.shortComment - a.textContent = 'here' - $.replace post.nodes.longComment, post.nodes.shortComment - post.nodes.comment = post.nodes.shortComment - parse: (req, a, post) -> - {status} = req - if status not in [200, 304] - a.textContent = "Error #{req.statusText} (#{status})" - return - - posts = JSON.parse(req.response).posts - Build.spoilerRange[g.BOARD] = posts[0].custom_spoiler - - for postObj in posts - break if postObj.no is post.ID - if postObj.no isnt post.ID - a.textContent = "Post No.#{post} not found." - return - - {comment} = post.nodes - clone = comment.cloneNode false - clone.innerHTML = postObj.com - for quote in $$ '.quotelink', clone - href = quote.getAttribute 'href' - continue if href[0] is '/' # Cross-board quote, or board link - quote.href = "/#{post.board}/res/#{href}" # Fix pathnames - post.nodes.shortComment = comment - $.replace comment, clone - post.nodes.comment = post.nodes.longComment = clone - post.parseComment() - post.parseQuotes() - if Conf['Resurrect Quotes'] - Quotify.node.call post - if Conf['Quote Previewing'] - QuotePreview.node.call post - if Conf['Quote Inlining'] - QuoteInline.node.call post - if Conf['Mark OP Quotes'] - QuoteOP.node.call post - if Conf['Mark Cross-thread Quotes'] - QuoteCT.node.call post - if g.BOARD.ID is 'g' - Fourchan.code.call post - if g.BOARD.ID is 'sci' - Fourchan.math.call post - if Conf['Linkify'] - Linkify.node.call post diff --git a/src/Miscellaneous/ExpandThread.coffee b/src/Miscellaneous/ExpandThread.coffee index c1ca5229b..fb3a24699 100644 --- a/src/Miscellaneous/ExpandThread.coffee +++ b/src/Miscellaneous/ExpandThread.coffee @@ -38,16 +38,13 @@ ExpandThread = toggle: (thread) -> threadRoot = thread.OP.nodes.root.parentNode - a = $ '.summary', threadRoot + return unless a = $ '.summary', threadRoot if thread.ID of ExpandThread.statuses ExpandThread.contract thread, a, threadRoot else ExpandThread.expand thread, a, threadRoot expand: (thread, a, threadRoot) -> ExpandThread.statuses[thread] = status = {} - for post in $$ '.thread > .postContainer', threadRoot - ExpandComment.expand Get.postFromRoot post - return unless a a.textContent = ExpandThread.text '...', a.textContent.match(/\d+/g)... status.req = $.cache "//api.4chan.org/#{thread.board}/res/#{thread}.json", -> delete status.req @@ -67,13 +64,9 @@ ExpandThread = when 'b', 'vg' then 3 when 't' then 1 else 5 - posts = $$ '.thread > .replyContainer', threadRoot - for post in [thread.OP.nodes.root].concat posts[-num..] - ExpandComment.contract Get.postFromRoot post - return unless a postsCount = 0 filesCount = 0 - for reply in posts[...-num] + for reply in $$('.thread > .replyContainer', threadRoot)[...-num] # rm clones inlined.click() while inlined = $ '.inlined', reply if Conf['Quote Inlining'] postsCount++ From 0eb224e07726c15d86c046540adfe85bd233f5f2 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 2 Nov 2013 18:37:40 +0100 Subject: [PATCH 050/225] Simpler summary creation, tiny Build.thread() optimization. --- css/style.css | 3 +++ src/General/Build.coffee | 29 +++++++++++++++------------ src/General/Index.coffee | 1 - src/Miscellaneous/ExpandThread.coffee | 14 ++++++------- 4 files changed, 25 insertions(+), 22 deletions(-) diff --git a/css/style.css b/css/style.css index 751f3b772..4bebe551d 100644 --- a/css/style.css +++ b/css/style.css @@ -367,6 +367,9 @@ a[href="javascript:;"] { :root.index-loading .pagelist { display: none; } +.summary { + text-decoration: none; +} /* Announcement Hiding */ :root.hide-announcement #globalMessage, diff --git a/src/General/Build.coffee b/src/General/Build.coffee index 03cfaa9b1..5c75dff8e 100644 --- a/src/General/Build.coffee +++ b/src/General/Build.coffee @@ -259,28 +259,31 @@ Build = container + summary: (boardID, threadID, posts, files) -> + text = [] + text.push "#{posts} post#{if posts > 1 then 's' else ''}" + text.push "and #{files} image repl#{if files > 1 then 'ies' else 'y'}" if files + text.push 'omitted.' + $.el 'a', + className: 'summary' + textContent: text.join ' ' + href: "/#{boardID}/res/#{threadID}" thread: (board, data) -> - root = $.el 'div', - className: 'thread' - id: "t#{data.no}" - Build.spoilerRange[board] = data.custom_spoiler + nodes = [] for obj in [data].concat data.last_replies or [] - $.add root, if post = g.posts["#{board}.#{obj.no}"] + nodes.push if post = board.posts[obj.no] post.nodes.root else Build.postFromObject obj, board.ID # build if necessary if data.omitted_posts - {omitted_posts, omitted_images} = data - html = [] - html.push "#{omitted_posts} post#{if omitted_posts > 1 then 's' else ''}" - html.push "and #{omitted_images} image repl#{if omitted_images > 1 then 'ies' else 'y'}" if omitted_images - html.push "omitted. Click here to view." - $.after root.firstChild, $.el 'span', - className: 'summary' - innerHTML: html.join ' ' + nodes.splice 1, 0, Build.summary board.ID, data.no, data.omitted_posts, data.omitted_images + root = $.el 'div', + className: 'thread' + id: "t#{data.no}" + $.add root, nodes root diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 4b22276ae..5b331337a 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -158,7 +158,6 @@ Index = try Index.parse JSON.parse req.response if req.status is 200 catch err - c.error err.stack # network error or non-JSON content for example. notice.setType 'error' notice.el.lastElementChild.textContent = 'Index refresh failed.' diff --git a/src/Miscellaneous/ExpandThread.coffee b/src/Miscellaneous/ExpandThread.coffee index fb3a24699..d9efaa2b0 100644 --- a/src/Miscellaneous/ExpandThread.coffee +++ b/src/Miscellaneous/ExpandThread.coffee @@ -10,13 +10,9 @@ ExpandThread = ExpandThread.setButton @ setButton: (thread) -> - return unless span = $.x 'following-sibling::span[contains(@class,"summary")][1]', thread.OP.nodes.root - a = $.el 'a', - textContent: ExpandThread.text '+', span.textContent.match(/\d+/g)... - className: 'summary' - href: 'javascript:;' + return unless a = $.x 'following-sibling::a[contains(@class,"summary")][1]', thread.OP.nodes.root + a.textContent = ExpandThread.text '+', a.textContent.match(/\d+/g)... $.on a, 'click', ExpandThread.cbToggle - $.replace span, a onIndexRefresh: -> for threadID, status of ExpandThread.statuses @@ -33,7 +29,9 @@ ExpandThread = text.push if status is '-' then 'shown' else 'omitted' text.join(' ') + '.' - cbToggle: -> + cbToggle: (e) -> + return if e.shiftKey or e.altKey or e.ctrlKey or e.metaKey or e.button isnt 0 + e.preventDefault() ExpandThread.toggle Get.threadFromNode @ toggle: (thread) -> @@ -92,7 +90,7 @@ ExpandThread = root = Build.postFromObject postData, thread.board.ID post = new Post root, thread, thread.board filesCount++ if 'file' of post - posts.push post + posts.push post postsRoot.push root Main.callbackNodes Post, posts $.after a, postsRoot From 54eaa9adea317c0547966646008f9175fefa9693 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 2 Nov 2013 20:29:06 +0100 Subject: [PATCH 051/225] Disable enhanced index on /f/. --- src/General/Index.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 5b331337a..336e2c3f9 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -1,6 +1,6 @@ Index = init: -> - return if g.VIEW isnt 'index' + return if g.VIEW isnt 'index' or g.BOARD.ID is 'f' @button = $.el 'a', className: 'index-refresh-shortcut fa fa-refresh' From 44c65671e70a4a1c0ea017101d4be323f7e1448e Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 2 Nov 2013 20:56:42 +0100 Subject: [PATCH 052/225] Fix #1319. --- json/archives.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json/archives.json b/json/archives.json index ed621fa22..a3079bbd0 100644 --- a/json/archives.json +++ b/json/archives.json @@ -87,6 +87,6 @@ "https": true, "withCredentials": true, "software": "foolfuuka", - "boards": ["a", "co", "gd", "jp", "m", "mlp", "sp", "tg", "tv", "u", "v", "vg", "vp", "vr", "wsg"], + "boards": ["a", "co", "gd", "jp", "m", "sp", "tg", "tv", "u", "v", "vg", "vp", "vr", "wsg"], "files": ["a", "gd", "jp", "m", "tg", "u", "vg", "vp", "vr", "wsg"] }] From 81a2b096a1b54954916f11442b146290b9bb36e5 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sun, 3 Nov 2013 01:27:23 +0100 Subject: [PATCH 053/225] Introduce Header.{scrollToIfNeeded,getTopOf,getBottomOf}() and use them. 4chan X - now with proper bottom header support. --- src/General/Header.coffee | 22 +++++++++++++--- src/General/Index.coffee | 4 +-- src/Images/ImageExpand.coffee | 20 ++++++-------- src/Miscellaneous/Keybinds.coffee | 36 +++++++++---------------- src/Miscellaneous/Nav.coffee | 41 +++++++++++++---------------- src/Monitoring/ThreadUpdater.coffee | 3 +-- src/Monitoring/Unread.coffee | 15 +++++------ 7 files changed, 66 insertions(+), 75 deletions(-) diff --git a/src/General/Header.coffee b/src/General/Header.coffee index f76da0383..10359d471 100644 --- a/src/General/Header.coffee +++ b/src/General/Header.coffee @@ -247,12 +247,28 @@ Header = return unless /^p\d+$/.test(hash) and post = $.id hash return if (Get.postFromRoot post).isHidden Header.scrollTo post - scrollTo: (root) -> + scrollTo: (root, down, needed) -> + if down + x = Header.getBottomOf root + window.scrollBy 0, -x unless needed and x >= 0 + else + x = Header.getTopOf root + window.scrollBy 0, x unless needed and x >= 0 + scrollToIfNeeded: (root, down) -> + Header.scrollTo root, down, true + getTopOf: (root) -> {top} = root.getBoundingClientRect() unless Conf['Bottom header'] headRect = Header.toggle.getBoundingClientRect() - top -= headRect.top + headRect.height - window.scrollBy 0, top + top -= headRect.top + headRect.height + top + getBottomOf: (root) -> + {clientHeight} = doc + bottom = clientHeight - root.getBoundingClientRect().bottom + if Conf['Bottom header'] + headRect = Header.toggle.getBoundingClientRect() + bottom -= clientHeight - headRect.bottom + headRect.height + bottom addShortcut: (el, index) -> shortcut = $.el 'span', diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 336e2c3f9..c9a8b5134 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -50,7 +50,7 @@ Index = className: 'pagelist' hidden: true innerHTML: <%= importHTML('General/Index-pagelist') %> - Index.currentPage = Index.getCurrentPage() + @currentPage = @getCurrentPage() $.on window, 'popstate', @cb.popstate $.on @pagelist, 'click', @cb.pageNav $.asap (-> $('.pagelist', doc) or d.readyState isnt 'loading'), -> @@ -81,7 +81,7 @@ Index = Index.pageNav +a.pathname.split('/')[2] scrollToIndex: -> - Header.scrollTo Index.root if Index.root.getBoundingClientRect().top < 0 + Header.scrollToIfNeeded Index.root getCurrentPage: -> +window.location.pathname.split('/')[2] diff --git a/src/Images/ImageExpand.coffee b/src/Images/ImageExpand.coffee index c21bef490..60382bb73 100644 --- a/src/Images/ImageExpand.coffee +++ b/src/Images/ImageExpand.coffee @@ -45,7 +45,7 @@ ImageExpand = continue unless file and file.isImage and doc.contains post.nodes.root if ImageExpand.on and (!Conf['Expand spoilers'] and file.isSpoiler or - Conf['Expand from here'] and file.thumb.getBoundingClientRect().top < 0) + Conf['Expand from here'] and Header.getTopOf(file.thumb) < 0) continue $.queueTask func, post return @@ -60,13 +60,10 @@ ImageExpand = # Scroll back to the thumbnail when contracting the image # to avoid being left miles away from the relevant post. - rect = post.nodes.root.getBoundingClientRect() - if rect.top < 0 - y = rect.top - unless Conf['Bottom header'] - headRect = Header.toggle.getBoundingClientRect() - y -= headRect.top + headRect.height - if rect.left < 0 + top = Header.getTopOf post.nodes.root + if top < 0 + y = top + if post.nodes.root.getBoundingClientRect().left < 0 x = -window.scrollX window.scrollBy x, y if x or y ImageExpand.contract post @@ -104,13 +101,12 @@ ImageExpand = $.addClass post.nodes.root, 'expanded-image' $.rmClass post.file.thumb, 'expanding' return - prev = post.nodes.root.getBoundingClientRect() + {bottom} = post.nodes.root.getBoundingClientRect() $.queueTask -> $.addClass post.nodes.root, 'expanded-image' $.rmClass post.file.thumb, 'expanding' - return unless prev.top + prev.height <= 0 - curr = post.nodes.root.getBoundingClientRect() - window.scrollBy 0, curr.height - prev.height + curr.top - prev.top + return unless bottom <= 0 + window.scrollBy 0, post.nodes.root.getBoundingClientRect().bottom - bottom error: -> post = Get.postFromNode @ diff --git a/src/Miscellaneous/Keybinds.coffee b/src/Miscellaneous/Keybinds.coffee index d59d771e7..00ee147cd 100644 --- a/src/Miscellaneous/Keybinds.coffee +++ b/src/Miscellaneous/Keybinds.coffee @@ -183,43 +183,31 @@ Keybinds = location.href = url hl: (delta, thread) -> + postEl = $ '.reply.highlight', thread + unless delta - if postEl = $ '.reply.highlight', thread - $.rmClass postEl, 'highlight' + $.rmClass postEl, 'highlight' if postEl return - if Conf['Bottom header'] - topMargin = 0 - else - headRect = Header.toggle.getBoundingClientRect() - topMargin = headRect.top + headRect.height - if postEl = $ '.reply.highlight', thread - $.rmClass postEl, 'highlight' - rect = postEl.getBoundingClientRect() - if rect.bottom >= topMargin and rect.top <= doc.clientHeight # We're at least partially visible + + if postEl + {height} = postEl.getBoundingClientRect() + if Header.getTopOf(postEl) >= -height and Header.getBottomOf(postEl) >= -height # We're at least partially visible root = postEl.parentNode axe = if delta is +1 'following' else 'preceding' - next = $.x "#{axe}-sibling::div[contains(@class,'replyContainer')][1]/child::div[contains(@class,'reply')]", root - unless next - @focus postEl - return - return unless g.VIEW is 'thread' or $.x('ancestor::div[parent::div[@class="board"]]', next) is thread - rect = next.getBoundingClientRect() - if rect.top < 0 or rect.bottom > doc.clientHeight - if delta is -1 - window.scrollBy 0, rect.top - topMargin - else - next.scrollIntoView false + return unless next = $.x "#{axe}-sibling::div[contains(@class,'replyContainer')][1]/child::div[contains(@class,'reply')]", root + Header.scrollToIfNeeded next, delta is +1 @focus next + $.rmClass postEl, 'highlight' return + $.rmClass postEl, 'highlight' replies = $$ '.reply', thread replies.reverse() if delta is -1 for reply in replies - rect = reply.getBoundingClientRect() - if delta is +1 and rect.top >= topMargin or delta is -1 and rect.bottom <= doc.clientHeight + if delta is +1 and Header.getTopOf(reply) > 0 or delta is -1 and Header.getBottomOf(reply) > 0 @focus reply return diff --git a/src/Miscellaneous/Nav.coffee b/src/Miscellaneous/Nav.coffee index 2b7e23354..3620080f0 100644 --- a/src/Miscellaneous/Nav.coffee +++ b/src/Miscellaneous/Nav.coffee @@ -38,29 +38,24 @@ Nav = else Nav.scroll +1 - getThread: (full) -> - if Conf['Bottom header'] - topMargin = 0 - else - headRect = Header.toggle.getBoundingClientRect() - topMargin = headRect.top + headRect.height - threads = $$('.thread').filter (thread) -> - thread = Get.threadFromRoot thread - !(thread.isHidden and !thread.stub) - for thread, i in threads - rect = thread.getBoundingClientRect() - if rect.bottom > topMargin # not scrolled past - return if full then [threads, thread, i, rect, topMargin] else thread + getThread: -> + for threadRoot in $$ '.thread' + thread = Get.threadFromRoot threadRoot + continue if thread.isHidden and !thread.stub + if Header.getTopOf(threadRoot) >= -threadRoot.getBoundingClientRect().height # not scrolled past + return threadRoot return $ '.board' scroll: (delta) -> - [threads, thread, i, rect, topMargin] = Nav.getThread true - top = rect.top - topMargin - - # unless we're not at the beginning of the current thread - # (and thus wanting to move to beginning) - # or we're above the first thread and don't want to skip it - if (delta is -1 and top > -5) or (delta is +1 and top < 5) - top = threads[i + delta]?.getBoundingClientRect().top - topMargin - - window.scrollBy 0, top + thread = Nav.getThread() + axe = if delta is +1 + 'following' + else + 'preceding' + if next = $.x "#{axe}-sibling::div[contains(@class,'thread')][1]", thread + # Unless we're not at the beginning of the current thread, + # and thus wanting to move to beginning, + # or we're above the first thread and don't want to skip it. + top = Header.getTopOf thread + thread = next if delta is +1 and top < 5 or delta is -1 and top > -5 + Header.scrollTo thread diff --git a/src/Monitoring/ThreadUpdater.coffee b/src/Monitoring/ThreadUpdater.coffee index b35f9502e..0ef1d04bf 100644 --- a/src/Monitoring/ThreadUpdater.coffee +++ b/src/Monitoring/ThreadUpdater.coffee @@ -246,8 +246,7 @@ ThreadUpdater = ThreadUpdater.lastPost = posts[count - 1].ID Main.callbackNodes Post, posts - scroll = Conf['Auto Scroll'] and ThreadUpdater.scrollBG() and - ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25 + scroll = Conf['Auto Scroll'] and ThreadUpdater.scrollBG() and Header.getBottomOf(ThreadUpdater.root) > -25 $.add ThreadUpdater.root, nodes sendEvent() if scroll diff --git a/src/Monitoring/Unread.coffee b/src/Monitoring/Unread.coffee index 2898c6c69..9ca6ce402 100644 --- a/src/Monitoring/Unread.coffee +++ b/src/Monitoring/Unread.coffee @@ -42,18 +42,16 @@ Unread = while root = $.x 'preceding-sibling::div[contains(@class,"replyContainer")][1]', post.nodes.root break unless (post = Get.postFromRoot root).isHidden return unless root - onload = -> root.scrollIntoView false if checkPosition root + down = true else # Scroll to the last read post. posts = Object.keys Unread.thread.posts {root} = Unread.thread.posts[posts[posts.length - 1]].nodes - onload = -> Header.scrollTo root if checkPosition root - checkPosition = (target) -> - # Scroll to the target unless we scrolled past it. - target.getBoundingClientRect().bottom > doc.clientHeight # Prevent the browser to scroll back to # the previous scroll location on page load. - $.on window, 'load', onload + $.on window, 'load', -> + # Scroll to the target unless we scrolled past it. + Header.scrollTo root, down if Header.getBottomOf(root) < 0 sync: -> lastReadPost = Unread.db.get @@ -102,7 +100,7 @@ Unread = body: post.info.comment icon: Favicon.logo notif.onclick = -> - Header.scrollTo post.nodes.root + Header.scrollToIfNeeded post.nodes.root, true window.focus() notif.onshow = -> setTimeout -> @@ -132,9 +130,8 @@ Unread = read: (e) -> return if d.hidden or !Unread.posts.length - height = doc.clientHeight for post, i in Unread.posts - break if post.nodes.root.getBoundingClientRect().bottom > height # post is not completely read + break if Header.getBottomOf(post.nodes.root) <= 0 # post is not completely read return unless i Unread.lastReadPost = Unread.posts.splice(0, i)[i - 1].ID From a1a12aaf232be8428ed3987c174a31cbf0a5b02b Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sun, 3 Nov 2013 13:57:55 +0100 Subject: [PATCH 054/225] Make sure posts are read when scrolling via next reply keybind. --- CHANGELOG.md | 2 +- src/Monitoring/Unread.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bffeab527..125b5b3bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ Index navigation improvements: - - You can now refresh the index page you are on with the icon in the header bar or the same keybind for refreshing threads. + - You can now refresh the index page you are on with the refresh shortcut in the header bar or the same keybind for refreshing threads. - You can now switch between paged and all-threads index modes via the "Index Navigation" header sub-menu. - Threads in the index can now be sorted by: - Bump order diff --git a/src/Monitoring/Unread.coffee b/src/Monitoring/Unread.coffee index 9ca6ce402..8e13c463e 100644 --- a/src/Monitoring/Unread.coffee +++ b/src/Monitoring/Unread.coffee @@ -131,7 +131,7 @@ Unread = read: (e) -> return if d.hidden or !Unread.posts.length for post, i in Unread.posts - break if Header.getBottomOf(post.nodes.root) <= 0 # post is not completely read + break if Header.getBottomOf(post.nodes.root) < -1 # post is not completely read return unless i Unread.lastReadPost = Unread.posts.splice(0, i)[i - 1].ID From b8dac7145676908ec1755e6afeadfca4490a86e3 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sun, 3 Nov 2013 13:58:52 +0100 Subject: [PATCH 055/225] Bumping should checkout the main branch before anything else. --- Gruntfile.coffee | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Gruntfile.coffee b/Gruntfile.coffee index e8dcf07dd..9f48729d7 100644 --- a/Gruntfile.coffee +++ b/Gruntfile.coffee @@ -85,9 +85,10 @@ module.exports = (grunt) -> stdout: true stderr: true failOnError: true + checkout: + command: 'git checkout <%= pkg.meta.mainBranch %>' commit: command: """ - git checkout <%= pkg.meta.mainBranch %> git commit -am "Release <%= pkg.meta.name %> v<%= pkg.version %>." git tag -a <%= pkg.version %> -m "<%= pkg.meta.name %> v<%= pkg.version %>." git tag -af stable-v3 -m "<%= pkg.meta.name %> v<%= pkg.version %>." @@ -151,9 +152,9 @@ module.exports = (grunt) -> ] grunt.registerTask 'release', ['shell:commit', 'shell:push', 'build-crx', 'compress:crx'] - grunt.registerTask 'patch', ['bump', 'updcl:3', 'release'] - grunt.registerTask 'minor', ['bump:minor', 'updcl:2', 'release'] - grunt.registerTask 'major', ['bump:major', 'updcl:1', 'release'] + grunt.registerTask 'patch', ['shell:checkout', 'bump', 'updcl:3', 'release'] + grunt.registerTask 'minor', ['shell:checkout', 'bump:minor', 'updcl:2', 'release'] + grunt.registerTask 'major', ['shell:checkout', 'bump:major', 'updcl:1', 'release'] grunt.registerTask 'updcl', 'Update the changelog', (headerLevel) -> headerPrefix = new Array(+headerLevel + 1).join '#' From bddb032dac47663cfd7a759aac8b8ca7d810f028 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sun, 3 Nov 2013 16:47:22 +0100 Subject: [PATCH 056/225] We only have to look for one thread when visiting thread pages. --- src/General/Index.coffee | 3 +-- src/General/Main.coffee | 31 +++++++++++++------------------ 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/src/General/Index.coffee b/src/General/Index.coffee index c9a8b5134..5946e0e5f 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -202,8 +202,7 @@ Index = posts.push new Post postRoot, thread, g.BOARD catch err # Skip posts that we failed to parse. - unless errors - errors = [] + errors = [] unless errors errors.push message: "Parsing of Post No.#{postRoot.id.match /\d+/} failed. Post will be skipped." error: err diff --git a/src/General/Main.coffee b/src/General/Main.coffee index 9756b15e2..e0b9abc8b 100644 --- a/src/General/Main.coffee +++ b/src/General/Main.coffee @@ -169,26 +169,21 @@ Main = # Something might have gone wrong! Main.initStyle() - if g.VIEW is 'thread' and board = $ '.board' - threads = [] - posts = [] - - for threadRoot in $$ '.board > .thread', board - thread = new Thread +threadRoot.id[1..], g.BOARD - threads.push thread - for postRoot in $$ '.thread > .postContainer', threadRoot - try - posts.push new Post postRoot, thread, g.BOARD - catch err - # Skip posts that we failed to parse. - unless errors - errors = [] - errors.push - message: "Parsing of Post No.#{postRoot.id.match /\d+/} failed. Post will be skipped." - error: err + if g.VIEW is 'thread' and threadRoot = $ '.thread' + thread = new Thread +threadRoot.id[1..], g.BOARD + posts = [] + for postRoot in $$ '.thread > .postContainer', threadRoot + try + posts.push new Post postRoot, thread, g.BOARD + catch err + # Skip posts that we failed to parse. + errors = [] unless errors + errors.push + message: "Parsing of Post No.#{postRoot.id.match /\d+/} failed. Post will be skipped." + error: err Main.handleErrors errors if errors - Main.callbackNodes Thread, threads + Main.callbackNodes Thread, [thread] Main.callbackNodes Post, posts if $.hasClass d.body, 'fourchan_x' From aeea95564cdda3cdbd2555ab7e621b6bca1e6a3c Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sun, 3 Nov 2013 16:58:50 +0100 Subject: [PATCH 057/225] Don't need to reprettyprint inside of threads. --- src/Miscellaneous/Fourchan.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miscellaneous/Fourchan.coffee b/src/Miscellaneous/Fourchan.coffee index 1b78c17de..6f290d662 100644 --- a/src/Miscellaneous/Fourchan.coffee +++ b/src/Miscellaneous/Fourchan.coffee @@ -35,7 +35,7 @@ Fourchan = return if @isClone apply = (e) -> pre.innerHTML = e.detail $.on window, 'prettyprint:cb', apply - for pre in $$ '.prettyprint', @nodes.comment + for pre in $$ '.prettyprint:not(.prettyprinted)', @nodes.comment $.event 'prettyprint', pre.innerHTML, window $.off window, 'prettyprint:cb', apply return From bc0f5fcc3b59558bb382aea0381eb49e78355c1a Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sun, 3 Nov 2013 17:14:01 +0100 Subject: [PATCH 058/225] Avoid creating new thread root+
    when they already exist. --- src/Filtering/ThreadHiding.coffee | 6 ++---- src/General/Build.coffee | 15 +++++++++++---- src/General/Index.coffee | 6 +++--- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/Filtering/ThreadHiding.coffee b/src/Filtering/ThreadHiding.coffee index 34f9a54f2..55fd4dd77 100644 --- a/src/Filtering/ThreadHiding.coffee +++ b/src/Filtering/ThreadHiding.coffee @@ -16,10 +16,8 @@ ThreadHiding = $.prepend @OP.nodes.root, ThreadHiding.makeButton @, 'hide' onrefresh: -> - for threadID, thread of g.BOARD.threads when thread.isHidden - hasStub = !!thread.stub - ThreadHiding.show thread - ThreadHiding.hide thread, hasStub + for threadID, thread of g.BOARD.threads when thread.isHidden and thread.stub + $.prepend thread.OP.nodes.root.parentNode, thread.stub return syncCatalog: -> diff --git a/src/General/Build.coffee b/src/General/Build.coffee index 5c75dff8e..74b40338b 100644 --- a/src/General/Build.coffee +++ b/src/General/Build.coffee @@ -271,6 +271,16 @@ Build = thread: (board, data) -> Build.spoilerRange[board] = data.custom_spoiler + if (OP = board.posts[data.no]) and parent = OP.nodes.root.parentNode + root = parent + hr = parent.nextElementSibling + $.rmAll root + else + root = $.el 'div', + className: 'thread' + id: "t#{data.no}" + hr = $.el 'hr' + nodes = [] for obj in [data].concat data.last_replies or [] nodes.push if post = board.posts[obj.no] @@ -282,8 +292,5 @@ Build = if data.omitted_posts nodes.splice 1, 0, Build.summary board.ID, data.no, data.omitted_posts, data.omitted_images - root = $.el 'div', - className: 'thread' - id: "t#{data.no}" $.add root, nodes - root + [root, hr] diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 5946e0e5f..5f66c0f40 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -188,8 +188,8 @@ Index = threads = [] posts = [] for threadData in Index.liveThreadData - threadRoot = Build.thread g.BOARD, threadData - Index.nodes.push threadRoot, $.el 'hr' + [threadRoot, hr] = Build.thread g.BOARD, threadData + Index.nodes.push threadRoot, hr if thread = g.BOARD.threads[threadData.no] thread.setStatus 'Sticky', !!threadData.sticky thread.setStatus 'Closed', !!threadData.closed @@ -250,6 +250,6 @@ Index = nodes = Index.sortedNodes[nodesPerPage * pageNum ... nodesPerPage * (pageNum + 1)] else nodes = Index.sortedNodes - $.event 'IndexRefresh' $.rmAll Index.root + $.event 'IndexRefresh' $.add Index.root, nodes From 11371f1f40a6670c0496bb67da1b73e356bd3cdc Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sun, 3 Nov 2013 17:59:25 +0100 Subject: [PATCH 059/225] Add sub-menu preview in the changelog. --- CHANGELOG.md | 3 ++- img/changelog/3.12.0/0.png | Bin 0 -> 18853 bytes 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 img/changelog/3.12.0/0.png diff --git a/CHANGELOG.md b/CHANGELOG.md index 125b5b3bd..733165a61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ Index navigation improvements: - You can now refresh the index page you are on with the refresh shortcut in the header bar or the same keybind for refreshing threads. - - You can now switch between paged and all-threads index modes via the "Index Navigation" header sub-menu. + - You can now switch between paged and all-threads index modes via the "Index Navigation" header sub-menu:
    + ![index navigation](img/changelog/3.12.0/0.png) - Threads in the index can now be sorted by: - Bump order - Last reply diff --git a/img/changelog/3.12.0/0.png b/img/changelog/3.12.0/0.png new file mode 100644 index 0000000000000000000000000000000000000000..cb17e29c0a44ec4b4692eac9843ccad2fed1ec97 GIT binary patch literal 18853 zcmZs@1yqz>*Z7Sf-O?ZoDI(G(HI$U3bhpwa-O}CCAQIAzbT>$M_s~7$5W_ck-#+j2 zzW;A67i)l-bM3SDK0AJAW2mCMBqkau8XO!PrnJ<1B{(?vDLA-iNGR~IpZxxqKmi9Q zZ6*C)M8);l;qsybzAAj*ncJ!1wRzp|g{0Cdi&bYptp$Kk{46Z|z|T*caixc`v+N6z z#hIVFO14?VdwgTrIh^WkKj~Mj(m?}WuLfvMKC?@|LVbox$|~G0WayJun3IsgIV{UA z6I6c5V9CzAoS&bfypwe7Am4NwJTlmRiVc&*T=)j|H30VV&kIUV*ms@CurKQfaBw)l ze_wn(#XSN<_ofrtSO}&zEk1P0WC}sMuePpRD$XEF=}Sc)Tog{)-|yFqW}V}(O!!fM5#f^91 zJ3fx1({GucNXg!4RGEm~r_A3P>1BiQj;r<$Tei^^bytAECjIxY{p8eIJw~@=e0(8W zf7WkX&b$AG&eZI{`KV*&z1vxIO`Gp9oc1|+7SS_S8x@W;exYQ<4 zUauF-b)+3>5Ht){2YRmbb{6&CXMcg&k#cz5xNX)sy<=Sefp71Wt=YNwAy$0RYliJ* zg#6=d^W&~Qp`c}>lGFLV{$*>{I0gU8!+sFicSmC2%UK(na#<_LHT?`Qfdeg^)CuAB zx-Qkj2gH)Nh4*Bst9jnE^3VO~@dugr1l~XBJw0uCJ!hu2D;&~U*<3}7L8ylHzO7D( zU0-}Fx-Z6-XUuST0b5S!c1>)tv5Ov$@XqLjYA2)Ye4)$BRIPMmV#P7E$7?Krg8xlk zC+rCp4(F}sG}3}@yYewF(&Ep@CO^P@^?tQe@-~uS`vC4kHDmT9R@dR}Oa!YJXnYn+ zGB1yWqw``$JJX&Rm_Ey##_dz0yGN){fAZ@*`p=TUwofkmJ5-^dtd8258*G@!Ur*0C z#@9v$Y|344-3S{qjrgX55@}Ee1F|6C68!QQK~xV{|kwL)%y_xd8kn8}*SfL$L+s%IR{5BabK&~tPwPqf9}gEC(QYeY zc>}q6O;$cl8XisOBQ;LJw?`j(nH0V}BCwcu@zkEAb(~jNTsD;+t#;EtIRj-*XWv?D zYKOI^G_m{9gKt!9H@RN*^t$S;k%jmz2WQn3BdsLa<+c^s#;cn&7M|7S zFZ$Bq@mqr6)>G)^h|`QH&GxU+DL2;Q{xp!t4cym=E~_N{dv-`+Z80~k9^7W}K+$#W z```@c#-Jd(eY9Xr6W!DWiK*c<_-y#?y22@&!`r#itPF0CnZ4=m_>$`nrGqb0*R$!D zdWmEn1ZZOgPyldnc?(e>xhv-efkNglui*qQP8rkc4w-MO8uDkoLoYz1{)W9i?}h+RMnjPA(^|-By;=|P z?>yk~HqjkmJqStbtM7K{O-*O7t|430V^Sm-ErkfhAaXGxF$ z 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 Date: Sun, 3 Nov 2013 18:55:58 +0100 Subject: [PATCH 060/225] Index optimization: only build/load last replies of visible threads. --- src/Filtering/ThreadHiding.coffee | 8 +++-- src/General/Build.coffee | 18 +++-------- src/General/Index.coffee | 52 +++++++++++++++++++++++-------- 3 files changed, 49 insertions(+), 29 deletions(-) diff --git a/src/Filtering/ThreadHiding.coffee b/src/Filtering/ThreadHiding.coffee index 55fd4dd77..80c11b1d2 100644 --- a/src/Filtering/ThreadHiding.coffee +++ b/src/Filtering/ThreadHiding.coffee @@ -16,8 +16,12 @@ ThreadHiding = $.prepend @OP.nodes.root, ThreadHiding.makeButton @, 'hide' onrefresh: -> - for threadID, thread of g.BOARD.threads when thread.isHidden and thread.stub - $.prepend thread.OP.nodes.root.parentNode, thread.stub + for threadID, thread of g.BOARD.threads when thread.isHidden + root = thread.OP.nodes.root.parentNode + if thread.stub + $.prepend root, thread.stub + else + threadRoot.nextElementSibling.hidden = true return syncCatalog: -> diff --git a/src/General/Build.coffee b/src/General/Build.coffee index 74b40338b..c621afa3c 100644 --- a/src/General/Build.coffee +++ b/src/General/Build.coffee @@ -271,26 +271,16 @@ Build = thread: (board, data) -> Build.spoilerRange[board] = data.custom_spoiler - if (OP = board.posts[data.no]) and parent = OP.nodes.root.parentNode - root = parent - hr = parent.nextElementSibling + if (OP = board.posts[data.no]) and root = OP.nodes.root.parentNode $.rmAll root else root = $.el 'div', className: 'thread' id: "t#{data.no}" - hr = $.el 'hr' - nodes = [] - for obj in [data].concat data.last_replies or [] - nodes.push if post = board.posts[obj.no] - post.nodes.root - else - Build.postFromObject obj, board.ID - - # build if necessary + nodes = [if OP then OP.nodes.root else Build.postFromObject data, board.ID] if data.omitted_posts - nodes.splice 1, 0, Build.summary board.ID, data.no, data.omitted_posts, data.omitted_images + nodes.push Build.summary board.ID, data.no, data.omitted_posts, data.omitted_images $.add root, nodes - [root, hr] + root diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 5f66c0f40..5e0713f62 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -158,6 +158,7 @@ Index = try Index.parse JSON.parse req.response if req.status is 200 catch err + c.error 'Index failure:', err.stack # network error or non-JSON content for example. notice.setType 'error' notice.el.lastElementChild.textContent = 'Index refresh failed.' @@ -171,7 +172,7 @@ Index = Index.scrollToIndex() parse: (pages) -> Index.parseThreadList pages - Index.buildAll() + Index.buildThreads() Index.sort() Index.buildIndex() Index.buildPagelist() @@ -183,35 +184,59 @@ Index = for threadID, thread of g.BOARD.threads when thread.ID not in Index.liveThreadIDs thread.collect() return - buildAll: -> + buildThreads: -> Index.nodes = [] threads = [] posts = [] for threadData in Index.liveThreadData - [threadRoot, hr] = Build.thread g.BOARD, threadData - Index.nodes.push threadRoot, hr + threadRoot = Build.thread g.BOARD, threadData + Index.nodes.push threadRoot, $.el 'hr' if thread = g.BOARD.threads[threadData.no] thread.setStatus 'Sticky', !!threadData.sticky thread.setStatus 'Closed', !!threadData.closed else thread = new Thread threadData.no, g.BOARD threads.push thread - postRoots = $$ '.thread > .postContainer', threadRoot - for postRoot in postRoots when postRoot.id.match(/\d+/)[0] not of thread.posts + # postRoots = $$ '.thread > .postContainer', threadRoot + # for postRoot in postRoots when postRoot.id.match(/\d+/)[0] not of thread.posts + OPRoot = $ '.opContainer', threadRoot + continue if OPRoot.id.match(/\d+/)[0] of thread.posts + try + posts.push new Post OPRoot, thread, g.BOARD + catch err + # Skip posts that we failed to parse. + Main.handleErrors + message: "Parsing of Post No.#{postRoot.id.match /\d+/} failed. Post will be skipped." + error: err + + # Add the threads and
    s in a container to make sure all features work. + $.nodes Index.nodes + Main.callbackNodes Thread, threads + Main.callbackNodes Post, posts + buildReplies: (threadRoots) -> + posts = [] + for threadRoot in threadRoots by 2 + thread = Get.threadFromRoot threadRoot + i = Index.liveThreadIDs.indexOf thread.ID + continue unless lastReplies = Index.liveThreadData[i].last_replies + nodes = [] + for data in lastReplies + 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 postRoot, thread, g.BOARD + posts.push new Post node, thread, thread.board catch err # Skip posts that we failed to parse. errors = [] unless errors errors.push message: "Parsing of Post No.#{postRoot.id.match /\d+/} failed. Post will be skipped." error: err - Main.handleErrors errors if errors + $.add threadRoot, nodes - # Add the threads and
    s in a container to make sure all features work. - $.nodes Index.nodes - Main.callbackNodes Thread, threads - Main.callbackNodes Post, posts + Main.handleErrors errors if errors + Main.callbackNodes Post, posts sort: -> switch Conf['Index Sort'] when 'bump' @@ -232,7 +257,7 @@ Index = for threadID in sortedThreadIDs i = Index.liveThreadIDs.indexOf(threadID) * 2 Index.sortedNodes.push Index.nodes[i], Index.nodes[i + 1] - # Put the sticky threads on top of the index.g + # Put the sticky threads on top of the index. offset = 0 for threadRoot, i in Index.sortedNodes by 2 when Get.threadFromRoot(threadRoot).isSticky Index.sortedNodes.splice offset++ * 2, 0, Index.sortedNodes.splice(i, 2)... @@ -251,5 +276,6 @@ Index = else nodes = Index.sortedNodes $.rmAll Index.root + Index.buildReplies nodes $.event 'IndexRefresh' $.add Index.root, nodes From b94a6327ab18729e3e9658d6b7b537dc56b08c74 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sun, 3 Nov 2013 21:15:15 +0100 Subject: [PATCH 061/225] Release 4chan X v3.12.0. --- CHANGELOG.md | 2 ++ package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 733165a61..15eed9c10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## 3.12.0 - *2013-11-03* + Index navigation improvements: - You can now refresh the index page you are on with the refresh shortcut in the header bar or the same keybind for refreshing threads. - You can now switch between paged and all-threads index modes via the "Index Navigation" header sub-menu:
    diff --git a/package.json b/package.json index d4c4650e4..261243e4b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "4chan-X", - "version": "3.11.5", + "version": "3.12.0", "description": "Cross-browser extension for productive lurking on 4chan.", "meta": { "name": "4chan X", From 301d5d8a7a5041ef4da4fcd04f46bab547e032ae Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sun, 3 Nov 2013 23:58:06 +0100 Subject: [PATCH 062/225] Typo. --- src/Filtering/ThreadHiding.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Filtering/ThreadHiding.coffee b/src/Filtering/ThreadHiding.coffee index 80c11b1d2..d728504bd 100644 --- a/src/Filtering/ThreadHiding.coffee +++ b/src/Filtering/ThreadHiding.coffee @@ -21,7 +21,7 @@ ThreadHiding = if thread.stub $.prepend root, thread.stub else - threadRoot.nextElementSibling.hidden = true + root.nextElementSibling.hidden = true return syncCatalog: -> From b56a987600dc93b274a2d1f3d39d7b7ee17608fd Mon Sep 17 00:00:00 2001 From: Mayhem Date: Mon, 4 Nov 2013 00:05:59 +0100 Subject: [PATCH 063/225] Fix next/prev thread keybinds when encountering hidden threads with no stubs. --- src/Miscellaneous/Nav.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miscellaneous/Nav.coffee b/src/Miscellaneous/Nav.coffee index 3620080f0..59c532ec1 100644 --- a/src/Miscellaneous/Nav.coffee +++ b/src/Miscellaneous/Nav.coffee @@ -52,7 +52,7 @@ Nav = 'following' else 'preceding' - if next = $.x "#{axe}-sibling::div[contains(@class,'thread')][1]", thread + if next = $.x "#{axe}-sibling::div[contains(@class,'thread') and not(@hidden)][1]", thread # Unless we're not at the beginning of the current thread, # and thus wanting to move to beginning, # or we're above the first thread and don't want to skip it. From 09daa29220907a023e090ccef813b52a3e3b476e Mon Sep 17 00:00:00 2001 From: Mayhem Date: Mon, 4 Nov 2013 01:21:04 +0100 Subject: [PATCH 064/225] Fix some hasty copy-paste gone wrong. --- src/General/Index.coffee | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 5e0713f62..31c2abea1 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -197,17 +197,16 @@ Index = else thread = new Thread threadData.no, g.BOARD threads.push thread - # postRoots = $$ '.thread > .postContainer', threadRoot - # for postRoot in postRoots when postRoot.id.match(/\d+/)[0] not of thread.posts - OPRoot = $ '.opContainer', threadRoot - continue if OPRoot.id.match(/\d+/)[0] of thread.posts + continue if thread.ID of thread.posts try - posts.push new Post OPRoot, thread, g.BOARD + posts.push new Post $('.opContainer', threadRoot), thread, g.BOARD catch err # Skip posts that we failed to parse. - Main.handleErrors - message: "Parsing of Post No.#{postRoot.id.match /\d+/} failed. Post will be skipped." + errors = [] unless errors + errors.push + message: "Parsing of Post No.#{thread} failed. Post will be skipped." error: err + Main.handleErrors errors if errors # Add the threads and
    s in a container to make sure all features work. $.nodes Index.nodes @@ -231,7 +230,7 @@ Index = # Skip posts that we failed to parse. errors = [] unless errors errors.push - message: "Parsing of Post No.#{postRoot.id.match /\d+/} failed. Post will be skipped." + message: "Parsing of Post No.#{data.no} failed. Post will be skipped." error: err $.add threadRoot, nodes From 451661077d802233c570434457da4390fa65b18c Mon Sep 17 00:00:00 2001 From: Mayhem Date: Mon, 4 Nov 2013 10:48:35 +0100 Subject: [PATCH 065/225] Remove outdated temporary workarounds. --- src/Posting/QR.coffee | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Posting/QR.coffee b/src/Posting/QR.coffee index 7a8f829ea..6f71abb2f 100644 --- a/src/Posting/QR.coffee +++ b/src/Posting/QR.coffee @@ -234,7 +234,6 @@ QR = setTimers = (e) => QR.cooldown.types = e.detail $.on window, 'cooldown:timers', setTimers $.globalEval 'window.dispatchEvent(new CustomEvent("cooldown:timers", {detail: cooldowns}))' - QR.cooldown.types or= {} # XXX tmp workaround until all pages and the catalogs get the cooldowns var. $.off window, 'cooldown:timers', setTimers for type of QR.cooldown.types QR.cooldown.types[type] = +QR.cooldown.types[type] @@ -304,11 +303,6 @@ QR = QR.cooldown.unset start continue - if 'timeout' of cooldown - # XXX tmp conversion from previous cooldowns - QR.cooldown.unset start - continue - if isReply is cooldown.isReply # Only cooldowns relevant to this post can set the seconds variable: # reply cooldown with a reply, thread cooldown with a thread From 66189e449cc528ed0e2fcb3b54bdcb4a494f7669 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Mon, 4 Nov 2013 11:22:49 +0100 Subject: [PATCH 066/225] Update the number of replies in thread stubs after an index refresh. --- src/Filtering/ThreadHiding.coffee | 37 ++++++++++++++++--------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/Filtering/ThreadHiding.coffee b/src/Filtering/ThreadHiding.coffee index d728504bd..11c5015b3 100644 --- a/src/Filtering/ThreadHiding.coffee +++ b/src/Filtering/ThreadHiding.coffee @@ -19,6 +19,7 @@ ThreadHiding = for threadID, thread of g.BOARD.threads when thread.isHidden root = thread.OP.nodes.root.parentNode if thread.stub + thread.stub = ThreadHiding.makeStub thread, root $.prepend root, thread.stub else root.nextElementSibling.hidden = true @@ -109,6 +110,23 @@ ThreadHiding = a.dataset.fullID = thread.fullID $.on a, 'click', ThreadHiding.toggle a + makeStub: (thread, root) -> + numReplies = $$('.thread > .replyContainer', root).length + numReplies += +summary.textContent.match /\d+/ if summary = $ '.summary', root + opInfo = if Conf['Anonymize'] + 'Anonymous' + else + $('.nameBlock', thread.OP.nodes.info).textContent + + a = ThreadHiding.makeButton thread, 'show' + $.add a, $.tn " #{opInfo} (#{if numReplies is 1 then '1 reply' else "#{numReplies} replies"})" + stub = $.el 'div', + className: 'stub' + if Conf['Menu'] + $.add stub, [a, $.tn(' '), Menu.makeButton()] + else + $.add stub, a + stub saveHiddenState: (thread, makeStub) -> hiddenThreadsOnCatalog = JSON.parse(localStorage.getItem "4chan-hide-t-#{g.BOARD}") or {} @@ -144,24 +162,7 @@ ThreadHiding = threadRoot.hidden = threadRoot.nextElementSibling.hidden = true #
    return - numReplies = 0 - if span = $ '.summary', threadRoot - numReplies = +span.textContent.match /\d+/ - numReplies += $$('.opContainer ~ .replyContainer', threadRoot).length - numReplies = if numReplies is 1 then '1 reply' else "#{numReplies} replies" - opInfo = - if Conf['Anonymize'] - 'Anonymous' - else - $('.nameBlock', OP.nodes.info).textContent - - a = ThreadHiding.makeButton thread, 'show' - $.add a, $.tn " #{opInfo} (#{numReplies})" - thread.stub = $.el 'div', - className: 'stub' - $.add thread.stub, a - if Conf['Menu'] - $.add thread.stub, [$.tn(' '), Menu.makeButton()] + thread.stub = ThreadHiding.makeStub thread, threadRoot $.prepend threadRoot, thread.stub show: (thread) -> From 1c66c6a60466ecc4f47213f4c0e7734bcc9a5e3d Mon Sep 17 00:00:00 2001 From: Mayhem Date: Mon, 4 Nov 2013 12:06:10 +0100 Subject: [PATCH 067/225] Don't display the index refreshing notice on intial page load for fast connections. #1322 --- src/General/Index.coffee | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 31c2abea1..9d278f6d7 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -137,7 +137,17 @@ Index = return unless navigator.onLine Index.req?.abort() Index.notice?.close() - Index.notice = new Notice 'info', 'Refreshing index...' + if d.readyState isnt 'loading' + Index.notice = new Notice 'info', 'Refreshing index...' + else + # Delay the notice on initial page load + # and only display it for slow connections. + now = Date.now() + $.ready -> + setTimeout (-> + return unless Index.req and !Index.notice + Index.notice = new Notice 'info', 'Refreshing index...' + ), $.SECOND - (Date.now() - now) Index.req = $.ajax "//api.4chan.org/#{g.BOARD}/catalog.json", onabort: Index.load onloadend: Index.load @@ -160,14 +170,18 @@ Index = catch err c.error 'Index failure:', err.stack # network error or non-JSON content for example. - notice.setType 'error' - notice.el.lastElementChild.textContent = 'Index refresh failed.' - setTimeout notice.close, 2 * $.SECOND + if notice + notice.setType 'error' + notice.el.lastElementChild.textContent = 'Index refresh failed.' + setTimeout notice.close, 2 * $.SECOND + else + new Notice 'error', 'Index refresh failed.', 2 return - notice.setType 'success' - notice.el.lastElementChild.textContent = 'Index refreshed!' - setTimeout notice.close, $.SECOND + if notice + notice.setType 'success' + notice.el.lastElementChild.textContent = 'Index refreshed!' + setTimeout notice.close, $.SECOND Index.scrollToIndex() parse: (pages) -> From 293bf70aeef08691aebf7c656ec60604e4a98e39 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Mon, 4 Nov 2013 18:41:23 +0100 Subject: [PATCH 068/225] Bring back `Catalog` link in the pagelist. --- html/General/Index-pagelist.html | 3 +++ src/General/Index.coffee | 1 + 2 files changed, 4 insertions(+) diff --git a/html/General/Index-pagelist.html b/html/General/Index-pagelist.html index e6923bb7a..fd5f4020b 100644 --- a/html/General/Index-pagelist.html +++ b/html/General/Index-pagelist.html @@ -9,3 +9,6 @@ + diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 9d278f6d7..f8ba049a9 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -77,6 +77,7 @@ Index = a = e.target else return + return if a.textContent is 'Catalog' e.preventDefault() Index.pageNav +a.pathname.split('/')[2] From 5f1ce2d9ec94ce2285db4a5e56a1beae38bd4e75 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Mon, 4 Nov 2013 18:47:42 +0100 Subject: [PATCH 069/225] Adjust initial index refresh notice delay, changelog. --- CHANGELOG.md | 3 +++ src/General/Index.coffee | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15eed9c10..dc9791ed8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +- The index refreshing notification will now only appear on initial page load with slow connections. +- Minor fixes. + ## 3.12.0 - *2013-11-03* Index navigation improvements: diff --git a/src/General/Index.coffee b/src/General/Index.coffee index f8ba049a9..c5df4b32c 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -148,7 +148,7 @@ Index = setTimeout (-> return unless Index.req and !Index.notice Index.notice = new Notice 'info', 'Refreshing index...' - ), $.SECOND - (Date.now() - now) + ), 5 * $.SECOND - (Date.now() - now) Index.req = $.ajax "//api.4chan.org/#{g.BOARD}/catalog.json", onabort: Index.load onloadend: Index.load From 5db85bc4541cf48a7faea9dd3b83e8fbbe661f7f Mon Sep 17 00:00:00 2001 From: Mayhem Date: Mon, 4 Nov 2013 19:51:51 +0100 Subject: [PATCH 070/225] Release 4chan X v3.12.1. --- CHANGELOG.md | 2 ++ package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc9791ed8..e4e26d6cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +### 3.12.1 - *2013-11-04* + - The index refreshing notification will now only appear on initial page load with slow connections. - Minor fixes. diff --git a/package.json b/package.json index 261243e4b..2a9b2dfa0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "4chan-X", - "version": "3.12.0", + "version": "3.12.1", "description": "Cross-browser extension for productive lurking on 4chan.", "meta": { "name": "4chan X", From 8f56d3e4155afead231416f63f2e77195babf9b6 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Mon, 4 Nov 2013 21:32:58 +0100 Subject: [PATCH 071/225] Remove some now useless code in ExpandThread and small cleanup in ThreadHiding. --- src/Filtering/ThreadHiding.coffee | 17 +++++++---------- src/Miscellaneous/ExpandThread.coffee | 5 ----- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/Filtering/ThreadHiding.coffee b/src/Filtering/ThreadHiding.coffee index 11c5015b3..c225c0056 100644 --- a/src/Filtering/ThreadHiding.coffee +++ b/src/Filtering/ThreadHiding.coffee @@ -19,8 +19,7 @@ ThreadHiding = for threadID, thread of g.BOARD.threads when thread.isHidden root = thread.OP.nodes.root.parentNode if thread.stub - thread.stub = ThreadHiding.makeStub thread, root - $.prepend root, thread.stub + ThreadHiding.makeStub thread, root else root.nextElementSibling.hidden = true return @@ -120,13 +119,13 @@ ThreadHiding = a = ThreadHiding.makeButton thread, 'show' $.add a, $.tn " #{opInfo} (#{if numReplies is 1 then '1 reply' else "#{numReplies} replies"})" - stub = $.el 'div', + thread.stub = $.el 'div', className: 'stub' if Conf['Menu'] - $.add stub, [a, $.tn(' '), Menu.makeButton()] + $.add thread.stub, [a, $.tn(' '), Menu.makeButton()] else - $.add stub, a - stub + $.add thread.stub, a + $.prepend root, thread.stub saveHiddenState: (thread, makeStub) -> hiddenThreadsOnCatalog = JSON.parse(localStorage.getItem "4chan-hide-t-#{g.BOARD}") or {} @@ -154,16 +153,14 @@ ThreadHiding = hide: (thread, makeStub=Conf['Stubs']) -> return if thread.isHidden - {OP} = thread - threadRoot = OP.nodes.root.parentNode + threadRoot = thread.OP.nodes.root.parentNode thread.isHidden = true unless makeStub threadRoot.hidden = threadRoot.nextElementSibling.hidden = true #
    return - thread.stub = ThreadHiding.makeStub thread, threadRoot - $.prepend threadRoot, thread.stub + ThreadHiding.makeStub thread, threadRoot show: (thread) -> if thread.stub diff --git a/src/Miscellaneous/ExpandThread.coffee b/src/Miscellaneous/ExpandThread.coffee index d9efaa2b0..608572cf7 100644 --- a/src/Miscellaneous/ExpandThread.coffee +++ b/src/Miscellaneous/ExpandThread.coffee @@ -3,11 +3,6 @@ ExpandThread = return if g.VIEW isnt 'index' or !Conf['Thread Expansion'] @statuses = {} $.on d, 'IndexRefresh', @onIndexRefresh - Thread.callbacks.push - name: 'Thread Expansion' - cb: @node - node: -> - ExpandThread.setButton @ setButton: (thread) -> return unless a = $.x 'following-sibling::a[contains(@class,"summary")][1]', thread.OP.nodes.root From f09121ab2eb88cd7671ab0559d9898865251c8ca Mon Sep 17 00:00:00 2001 From: Mayhem Date: Tue, 5 Nov 2013 01:03:09 +0100 Subject: [PATCH 072/225] More index tweaking/optimization and small thread hiding fix. Most feature that need to be called on each index refresh don't need to be called on every single page build, but only after building the threads. ThreadHiding needs to be fired on each page build to ensure that the stub summaries fit with the number of replies, so it has to wait for the last replies to be added. This also fixes the bug where ThreadHiding was creating one extra stub on each IndexRefresh event. --- src/Filtering/ThreadHiding.coffee | 16 +++++++++------- src/General/Index.coffee | 3 ++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/Filtering/ThreadHiding.coffee b/src/Filtering/ThreadHiding.coffee index c225c0056..920bfe4f2 100644 --- a/src/Filtering/ThreadHiding.coffee +++ b/src/Filtering/ThreadHiding.coffee @@ -4,7 +4,7 @@ ThreadHiding = @db = new DataBoard 'hiddenThreads' @syncCatalog() - $.on d, 'IndexRefresh', @onrefresh + $.on d, 'IndexBuild', @onIndexBuild Thread.callbacks.push name: 'Thread Hiding' cb: @node @@ -15,13 +15,15 @@ ThreadHiding = return unless Conf['Thread Hiding'] $.prepend @OP.nodes.root, ThreadHiding.makeButton @, 'hide' - onrefresh: -> - for threadID, thread of g.BOARD.threads when thread.isHidden - root = thread.OP.nodes.root.parentNode - if thread.stub + onIndexBuild: ({detail: nodes}) -> + for root, i in nodes by 2 + thread = Get.threadFromRoot root + continue unless thread.isHidden + unless thread.stub + nodes[i + 1].hidden = true + else unless root.contains thread.stub + # When we come back to a page, the stub is already there. ThreadHiding.makeStub thread, root - else - root.nextElementSibling.hidden = true return syncCatalog: -> diff --git a/src/General/Index.coffee b/src/General/Index.coffee index c5df4b32c..60dfed9e9 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -227,6 +227,7 @@ Index = $.nodes Index.nodes Main.callbackNodes Thread, threads Main.callbackNodes Post, posts + $.event 'IndexRefresh' buildReplies: (threadRoots) -> posts = [] for threadRoot in threadRoots by 2 @@ -291,5 +292,5 @@ Index = nodes = Index.sortedNodes $.rmAll Index.root Index.buildReplies nodes - $.event 'IndexRefresh' + $.event 'IndexBuild', nodes $.add Index.root, nodes From ab83d61171e764224353445cbb449e7e46a837fe Mon Sep 17 00:00:00 2001 From: Mayhem Date: Tue, 5 Nov 2013 10:49:09 +0100 Subject: [PATCH 073/225] Allow "Shift+[not a letter or number]" keybinds to work in inputs. --- src/Miscellaneous/Keybinds.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miscellaneous/Keybinds.coffee b/src/Miscellaneous/Keybinds.coffee index 00ee147cd..5388ebc89 100644 --- a/src/Miscellaneous/Keybinds.coffee +++ b/src/Miscellaneous/Keybinds.coffee @@ -20,7 +20,7 @@ Keybinds = return unless key = Keybinds.keyCode e {target} = e if target.nodeName in ['INPUT', 'TEXTAREA'] - return unless /(Esc|Alt|Ctrl|Meta)/.test key + return unless /(Esc|Alt|Ctrl|Meta|Shift\+\w{2,})/.test key threadRoot = Nav.getThread() if op = $ '.op', threadRoot From 4b7bc3e3dcb43f3bcdf04f9a2756308e4e6a0760 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Tue, 5 Nov 2013 12:04:35 +0100 Subject: [PATCH 074/225] Use lists consistently in the changelog. --- CHANGELOG.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4e26d6cd..ba2930ee9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,32 +5,33 @@ ## 3.12.0 - *2013-11-03* -Index navigation improvements: +- Index navigation improvements: - You can now refresh the index page you are on with the refresh shortcut in the header bar or the same keybind for refreshing threads. - You can now switch between paged and all-threads index modes via the "Index Navigation" header sub-menu:
    ![index navigation](img/changelog/3.12.0/0.png) - Threads in the index can now be sorted by: - - Bump order - - Last reply - - Creation date - - Reply count - - File count +
      +
    • Bump order +
    • Last reply +
    • Creation date +
    • Reply count +
    • File count +
    - Navigating across index pages is now instantaneous. - -Added a keybind to open the catalog search field on index pages. +- Added a keybind to open the catalog search field on index pages. ### 3.11.5 - *2013-10-03* -Minor Chrome 30 fix. +- Minor Chrome 30 fix. ### 3.11.4 - *2013-09-23* -Tiny posting cooldown adjustment: +- Tiny posting cooldown adjustment: - You can post an image reply immediately after a non-image reply. ### 3.11.3 - *2013-09-19* -Update posting cooldown timers to match 4chan settings: +- Update posting cooldown timers to match 4chan settings: - Cooldown may vary between inter-thread and intra-thread replies. - Cooldown may vary when posting a file or not. - Cooldown does not take sageing into account anymore. @@ -38,7 +39,7 @@ Update posting cooldown timers to match 4chan settings: ### 3.11.2 - *2013-09-17* -Updated post and deletion cooldown timers to match 4chan changes: they are now twice as long. +- Updated post and deletion cooldown timers to match 4chan changes: they are now twice as long. ### 3.11.1 - *2013-09-13* @@ -149,7 +150,7 @@ Updated post and deletion cooldown timers to match 4chan changes: they are now t - **New feature**: `Archive selection` - Select which archive you want for specific boards and redirection type. - Access it in the `Archives` tab of the Settings window. -- The list of archived boards will now update automatically, separately from 4chan X updates. +- The list of archived boards will now update automatically, independently from 4chan X updates. - If you're an archiver and want [data](https://github.com/MayhemYDG/4chan-x/blob/v3/json/archives.json) about your archive to be updated, added or removed: send a PR or open an issue. - Fix quote previews getting 'stuck' in Opera. From 6d7ce32b947b66b60e10d58b4b692e5a137496d0 Mon Sep 17 00:00:00 2001 From: noface Date: Thu, 7 Nov 2013 13:33:47 +0100 Subject: [PATCH 075/225] Add FoolFrame. --- json/archives.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/json/archives.json b/json/archives.json index a3079bbd0..16c20be76 100644 --- a/json/archives.json +++ b/json/archives.json @@ -89,4 +89,13 @@ "software": "foolfuuka", "boards": ["a", "co", "gd", "jp", "m", "sp", "tg", "tv", "u", "v", "vg", "vp", "vr", "wsg"], "files": ["a", "gd", "jp", "m", "tg", "u", "vg", "vp", "vr", "wsg"] +}, { + "uid": 14, + "name": "FoolFrame", + "domain": "archive.bui.pm", + "http": true, + "https": false, + "software": "foolfuuka", + "boards": ["an", "b"], + "files": ["an", "b"] }] From 6975a766b9ab09f1aec7c6bc68e91826084a4363 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Thu, 7 Nov 2013 22:34:41 +0100 Subject: [PATCH 076/225] Update font-awesome. --- css/style.css | 6 +++--- html/Monitoring/ThreadWatcher.html | 2 +- package.json | 2 +- src/General/Header.coffee | 2 +- src/Images/ImageExpand.coffee | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/css/style.css b/css/style.css index 4bebe551d..7968c10b4 100644 --- a/css/style.css +++ b/css/style.css @@ -851,7 +851,7 @@ a.hide-announcement { .menu-button { position: relative; } -.menu-button i:not(.fa-reorder) { +.menu-button i:not(.fa-bars) { border-top: 6px solid; border-right: 4px solid transparent; border-left: 4px solid transparent; @@ -860,10 +860,10 @@ a.hide-announcement { vertical-align: middle; } @media screen and (resolution: 1dppx) { - .fa-reorder { + .fa-bars { font-size: 14px; } - #shortcuts .fa-reorder { + #shortcuts .fa-bars { vertical-align: -1px; } } diff --git a/html/Monitoring/ThreadWatcher.html b/html/Monitoring/ThreadWatcher.html index 3d5b180b0..38374dd0a 100644 --- a/html/Monitoring/ThreadWatcher.html +++ b/html/Monitoring/ThreadWatcher.html @@ -1,5 +1,5 @@
    Thread Watcher - +
    diff --git a/package.json b/package.json index 2a9b2dfa0..ffe746202 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ } }, "devDependencies": { - "font-awesome": "https://github.com/FortAwesome/Font-Awesome/archive/v4.0.0.tar.gz", + "font-awesome": "https://github.com/FortAwesome/Font-Awesome/archive/v4.0.3.tar.gz", "grunt": "~0.4.1", "grunt-bump": "~0.0.11", "grunt-concurrent": "~0.4.0", diff --git a/src/General/Header.coffee b/src/General/Header.coffee index 10359d471..849e9ba24 100644 --- a/src/General/Header.coffee +++ b/src/General/Header.coffee @@ -11,7 +11,7 @@ Header = @menu = new UI.Menu 'header' menuButton = $.el 'a', className: 'menu-button' - innerHTML: '' + innerHTML: '' href: 'javascript:;' $.on menuButton, 'click', @menuToggle @addShortcut menuButton, 0 diff --git a/src/Images/ImageExpand.coffee b/src/Images/ImageExpand.coffee index 60382bb73..8d20eb4bb 100644 --- a/src/Images/ImageExpand.coffee +++ b/src/Images/ImageExpand.coffee @@ -3,7 +3,7 @@ ImageExpand = return if g.VIEW is 'catalog' or !Conf['Image Expansion'] @EAI = $.el 'a', - className: 'expand-all-shortcut fa fa-resize-full' + className: 'expand-all-shortcut fa fa-expand' title: 'Expand All Images' href: 'javascript:;' $.on @EAI, 'click', ImageExpand.cb.toggleAll @@ -32,11 +32,11 @@ ImageExpand = toggleAll: -> $.event 'CloseMenu' if ImageExpand.on = $.hasClass ImageExpand.EAI, 'expand-all-shortcut' - ImageExpand.EAI.className = 'contract-all-shortcut fa fa-resize-small' + ImageExpand.EAI.className = 'contract-all-shortcut fa fa-compress' ImageExpand.EAI.title = 'Contract All Images' func = ImageExpand.expand else - ImageExpand.EAI.className = 'expand-all-shortcut fa fa-resize-full' + ImageExpand.EAI.className = 'expand-all-shortcut fa fa-expand' ImageExpand.EAI.title = 'Expand All Images' func = ImageExpand.contract for ID, post of g.posts From 4d27a818885b051e3790182dbb9f7648dae7d18b Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 9 Nov 2013 18:37:09 +0100 Subject: [PATCH 077/225] Extra return to clean up transpiled code. --- src/Monitoring/ThreadWatcher.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Monitoring/ThreadWatcher.coffee b/src/Monitoring/ThreadWatcher.coffee index 3b021d5a7..680d61c6a 100644 --- a/src/Monitoring/ThreadWatcher.coffee +++ b/src/Monitoring/ThreadWatcher.coffee @@ -275,6 +275,7 @@ ThreadWatcher = $.on entry.el, 'click', cb if cb @refreshers.push refresh.bind entry if refresh $.event 'AddMenuEntry', entry + return createSubEntry: (name, desc) -> entry = type: 'thread watcher' From 61d55c2cbab7c984f6b62c374c6b7adf331cc8db Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sun, 10 Nov 2013 01:37:21 +0100 Subject: [PATCH 078/225] Thank feedbackers. --- src/Meta/banner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Meta/banner.js b/src/Meta/banner.js index 10140c5d6..abcfe5398 100644 --- a/src/Meta/banner.js +++ b/src/Meta/banner.js @@ -12,7 +12,7 @@ * herpaderpderp - recaptcha fixes * WakiMiko - recaptcha tab order http://userscripts.org/scripts/show/82657 * - * All the people who've taken the time to write bug reports. + * All the people who've taken the time to write bug reports and provide feedback. * * Thank you. */ From 9eaf16576c46c3fcd422fd687a8a66484be1e724 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sun, 10 Nov 2013 04:20:00 +0100 Subject: [PATCH 079/225] Better return guard for the page visibility polyfill. --- lib/polyfill.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/polyfill.coffee b/lib/polyfill.coffee index 0ad7c1fe8..8298d63ae 100644 --- a/lib/polyfill.coffee +++ b/lib/polyfill.coffee @@ -27,7 +27,7 @@ Polyfill = cb new Blob [ui8a], type: 'image/png' visibility: -> # page visibility API - return unless 'webkitHidden' of document + return if 'visibilityState' of d Object.defineProperties HTMLDocument.prototype, visibilityState: get: -> @webkitVisibilityState From 301c9930a704b04e22a79478bfb567cc74d6f73b Mon Sep 17 00:00:00 2001 From: Bui Date: Thu, 14 Nov 2013 08:07:50 +0000 Subject: [PATCH 080/225] Update archive.bui.pm Enabled SSL, removed /an/, added unimaginative name --- json/archives.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/json/archives.json b/json/archives.json index 16c20be76..1c27427ee 100644 --- a/json/archives.json +++ b/json/archives.json @@ -91,11 +91,11 @@ "files": ["a", "gd", "jp", "m", "tg", "u", "vg", "vp", "vr", "wsg"] }, { "uid": 14, - "name": "FoolFrame", + "name": "Bui's Archive", "domain": "archive.bui.pm", "http": true, - "https": false, + "https": true, "software": "foolfuuka", - "boards": ["an", "b"], - "files": ["an", "b"] + "boards": ["b"], + "files": ["b"] }] From c762a7c1a154f4b3807c5b577cedbe58a7d8ea1e Mon Sep 17 00:00:00 2001 From: Mayhem Date: Fri, 15 Nov 2013 02:08:51 +0100 Subject: [PATCH 081/225] Fix file deleted icons for OPs. Class attribute was wrong. --- src/General/Build.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/General/Build.coffee b/src/General/Build.coffee index c621afa3c..6fe60021b 100644 --- a/src/General/Build.coffee +++ b/src/General/Build.coffee @@ -118,7 +118,7 @@ Build = if file?.isDeleted fileHTML = if isOP "
    " + - "File deleted." + + "File deleted." + "
    " else "
    " + From d20e62dda20e476b2cb86a1483b9d1dc6337b664 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Fri, 15 Nov 2013 21:11:32 +0100 Subject: [PATCH 082/225] Remove sending error logs. I don't have the time to look into them actively, and the majority of logs were not useful. --- src/General/Main.coffee | 37 +------------------------------------ 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/src/General/Main.coffee b/src/General/Main.coffee index e0b9abc8b..56dc4d618 100644 --- a/src/General/Main.coffee +++ b/src/General/Main.coffee @@ -187,7 +187,6 @@ Main = Main.callbackNodes Post, posts if $.hasClass d.body, 'fourchan_x' - Main.disableReports = true alert '4chan X v2 detected: Disable it or v3 will break.' <% if (type === 'userscript') { %> @@ -203,7 +202,6 @@ Main = localStorage.getItem '4chan-settings' catch err new Notice 'warning', 'Cookies need to be enabled on 4chan for <%= meta.name %> to operate properly.', 30 - Main.disableReports = true $.event '4chanXInitFinished' @@ -264,46 +262,13 @@ Main = new Notice 'error', [div, logs], 30 parseError: (data) -> - Main.logError data + c.error data.message, data.error.stack message = $.el 'div', textContent: data.message error = $.el 'div', textContent: data.error [message, error] - errors: [] - logError: (data) -> - unless Main.errors.length - $.on window, 'unload', Main.postErrors - c.error data.message, data.error.stack - Main.errors.push data - - postErrors: -> - return if Main.disableReports - errors = Main.errors.filter((d) -> !!d.error.stack).map((d) -> - <% if (type === 'userscript') { %> - # Before: - # someFn@file:///C:/Users//AppData/Roaming/Mozilla/Firefox/Profiles/.default/gm_scripts/4chan_X/4chan-X.user.js:line_number - # someFn@file:///home//.mozilla/firefox/.default/gm_scripts/4chan_X/4chan-X.user.js:line_number - # After: - # someFn@4chan-X.user.js:line_number - {name, message, stack} = d.error - stack = stack.replace /file:\/{3}.+\//g, '' - "#{d.message} #{name}: #{message} #{stack}" - <% } else { %> - "#{d.message} #{d.error.stack}" - <% } %> - ).join '\n' - return unless errors - $.ajax '<%= meta.page %>errors', null, - sync: true - form: $.formData - n: "<%= meta.name %> v#{g.VERSION}" - t: '<%= type %>' - ua: window.navigator.userAgent - url: window.location.href - e: errors - isThisPageLegit: -> # 404 error page or similar. unless 'thisPageIsLegit' of Main From 30e3a276a24e4a7545aa3cc8a358c108ab51db7f Mon Sep 17 00:00:00 2001 From: Mayhem Date: Fri, 15 Nov 2013 21:41:48 +0100 Subject: [PATCH 083/225] Trim old changelog. --- changelog-old | 2 -- 1 file changed, 2 deletions(-) diff --git a/changelog-old b/changelog-old index 598fa09a1..2fe316f93 100644 --- a/changelog-old +++ b/changelog-old @@ -1,5 +1,3 @@ -master - 2.39.7 - Mayhem Update archive redirection for /pol/ and /vg/. From c318fb37b9399958a60b579629c7bb70d0a7a9ec Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 16 Nov 2013 15:51:07 +0100 Subject: [PATCH 084/225] Update deps. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ffe746202..4deb4f96b 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "grunt-contrib-concat": "~0.3.0", "grunt-contrib-copy": "~0.4.1", "grunt-contrib-watch": "~0.5.3", - "grunt-shell": "~0.5.0", + "grunt-shell": "~0.6.0", "load-grunt-tasks": "~0.2.0" }, "repository": { From a8209eaa89857be9eec27820a13c6e262cd6c162 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 9 Nov 2013 21:59:01 +0100 Subject: [PATCH 085/225] Add index searching. Close #1318 --- CHANGELOG.md | 8 +++++ css/style.css | 1 + html/General/Index-navlinks.html | 2 ++ src/General/Config.coffee | 56 +++++++++++++++---------------- src/General/Index.coffee | 44 ++++++++++++++++++++---- src/General/Post.coffee | 2 +- src/Miscellaneous/Keybinds.coffee | 2 +- 7 files changed, 78 insertions(+), 37 deletions(-) create mode 100644 html/General/Index-navlinks.html diff --git a/CHANGELOG.md b/CHANGELOG.md index ba2930ee9..fcc3a9335 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +- Searching in the index will now show matched OPs by: + - comment + - subject + - filename + - name + - tripcode + - e-mail + ### 3.12.1 - *2013-11-04* - The index refreshing notification will now only appear on initial page load with slow connections. diff --git a/css/style.css b/css/style.css index 7968c10b4..07d983a9d 100644 --- a/css/style.css +++ b/css/style.css @@ -363,6 +363,7 @@ a[href="javascript:;"] { } /* Index */ +:root.index-loading .navLinks, :root.index-loading .board, :root.index-loading .pagelist { display: none; diff --git a/html/General/Index-navlinks.html b/html/General/Index-navlinks.html new file mode 100644 index 000000000..3ac6b2437 --- /dev/null +++ b/html/General/Index-navlinks.html @@ -0,0 +1,2 @@ +[Catalog]  + diff --git a/src/General/Config.coffee b/src/General/Config.coffee index 715822858..e1818ec89 100644 --- a/src/General/Config.coffee +++ b/src/General/Config.coffee @@ -162,39 +162,39 @@ Config = usercss: '' hotkeys: # Header, QR & Options - 'Toggle board list': ['Ctrl+b', 'Toggle the full board list.'] - 'Open empty QR': ['q', 'Open QR without post number inserted.'] - 'Open QR': ['Shift+q', '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.'] - 'Submit QR': ['Alt+s', 'Submit post.'] + 'Toggle board list': ['Ctrl+b', 'Toggle the full board list.'] + 'Open empty QR': ['q', 'Open QR without post number inserted.'] + 'Open QR': ['Shift+q', '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.'] + 'Submit QR': ['Alt+s', 'Submit post.'] # Index/Thread related - 'Update': ['r', 'Refresh the index/thread.'] - 'Watch': ['w', 'Watch thread.'] + 'Update': ['r', 'Refresh the index/thread.'] + 'Watch': ['w', 'Watch thread.'] # Images - 'Expand image': ['Shift+e', 'Expand selected image.'] - 'Expand images': ['e', 'Expand all images.'] + 'Expand image': ['Shift+e', 'Expand selected image.'] + 'Expand images': ['e', 'Expand all images.'] # Board Navigation - 'Front page': ['0', 'Jump to page 0.'] - 'Open front page': ['Shift+0', 'Open page 0 in a new tab.'] - 'Next page': ['Right', 'Jump to the next page.'] - 'Previous page': ['Left', 'Jump to the previous page.'] - 'Search form': ['Ctrl+Alt+s', 'Open the search field on the board index.'] + 'Front page': ['0', 'Jump to page 0.'] + 'Open front page': ['Shift+0', 'Open page 0 in a new tab.'] + 'Next page': ['Right', 'Jump to the next page.'] + 'Previous page': ['Left', 'Jump to the previous page.'] + 'Search form': ['Ctrl+Alt+s', 'Focus the search field on the board index.'] # Thread Navigation - 'Next thread': ['Down', 'See next thread.'] - 'Previous thread': ['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 thread': ['Down', 'See next thread.'] + 'Previous thread': ['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.'] # Reply Navigation - 'Next reply': ['j', 'Select next reply.'] - 'Previous reply': ['k', 'Select previous reply.'] - 'Deselect reply': ['Shift+d', 'Deselect reply.'] - 'Hide': ['x', 'Hide thread.'] + 'Next reply': ['j', 'Select next reply.'] + 'Previous reply': ['k', 'Select previous reply.'] + 'Deselect reply': ['Shift+d', 'Deselect reply.'] + 'Hide': ['x', 'Hide thread.'] updater: checkbox: 'Beep': [false, 'Beep on new post to completely read thread.'] diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 60dfed9e9..4591ee706 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -50,13 +50,21 @@ Index = className: 'pagelist' hidden: true innerHTML: <%= importHTML('General/Index-pagelist') %> + @navLinks = $.el 'div', + className: 'navLinks' + innerHTML: <%= importHTML('General/Index-navlinks') %> + @searchInput = $ '#index-search', @navLinks @currentPage = @getCurrentPage() $.on window, 'popstate', @cb.popstate $.on @pagelist, 'click', @cb.pageNav + $.on @searchInput, 'input', @onSearchInput $.asap (-> $('.pagelist', doc) or d.readyState isnt 'loading'), -> $.replace $('.board'), Index.root $.replace $('.pagelist'), Index.pagelist $.rmClass doc, 'index-loading' + for navLink in $$ '.navLinks' + $.rm navLink + $.after $.x('child::form/preceding-sibling::hr'), Index.navLinks cb: mode: -> @@ -276,13 +284,14 @@ Index = offset = 0 for threadRoot, i in Index.sortedNodes by 2 when Get.threadFromRoot(threadRoot).isSticky Index.sortedNodes.splice offset++ * 2, 0, Index.sortedNodes.splice(i, 2)... - return unless Conf['Filter'] - # Put the highlighted thread &
    on top of the index - # while keeping the original order they appear in. - offset = 0 - for threadRoot, i in Index.sortedNodes by 2 when Get.threadFromRoot(threadRoot).isOnTop - Index.sortedNodes.splice offset++ * 2, 0, Index.sortedNodes.splice(i, 2)... - return + if Conf['Filter'] + # Put the highlighted thread &
    on top of the index + # while keeping the original order they appear in. + offset = 0 + for threadRoot, i in Index.sortedNodes by 2 when Get.threadFromRoot(threadRoot).isOnTop + Index.sortedNodes.splice offset++ * 2, 0, Index.sortedNodes.splice(i, 2)... + if Index.searchInput.value + Index.sortedNodes = Index.querySearch(Index.searchInput.value) or Index.sortedNodes buildIndex: -> if Conf['Index Mode'] is 'paged' pageNum = Index.getCurrentPage() @@ -294,3 +303,24 @@ Index = Index.buildReplies nodes $.event 'IndexBuild', nodes $.add Index.root, nodes + + onSearchInput: -> + Index.sort() + Index.buildIndex() + querySearch: (query) -> + return unless keywords = query.toLowerCase().match /\S+/g + Index.search keywords + search: (keywords) -> + found = [] + for threadRoot, i in Index.sortedNodes by 2 + {OP} = Get.threadFromRoot threadRoot + text = [] + for key in ['comment', 'subject', 'name', 'tripcode', 'email'] + text.push OP.info[key] if key of OP.info + text.push OP.file.name if 'file' of OP + text = text.join(' ').toLowerCase() + for keyword in keywords + continue if -1 is text.indexOf keyword + found.push Index.sortedNodes[i], Index.sortedNodes[i + 1] + break + found diff --git a/src/General/Post.coffee b/src/General/Post.coffee index 901405495..5cb484309 100644 --- a/src/General/Post.coffee +++ b/src/General/Post.coffee @@ -49,7 +49,7 @@ class Post @parseComment() @parseQuotes() - @parseFile(that) + @parseFile that @clones = [] g.posts[@fullID] = thread.posts[@] = board.posts[@] = @ diff --git a/src/Miscellaneous/Keybinds.coffee b/src/Miscellaneous/Keybinds.coffee index 5388ebc89..76d817825 100644 --- a/src/Miscellaneous/Keybinds.coffee +++ b/src/Miscellaneous/Keybinds.coffee @@ -87,7 +87,7 @@ Keybinds = return unless g.VIEW is 'index' and Conf['Index Mode'] is 'paged' $('.prev button', Index.pagelist).click() when Conf['Search form'] - $.id('search-btn').click() + Index.searchInput.focus() # Thread Navigation when Conf['Next thread'] return if g.VIEW isnt 'index' From dcdb530d1969eb8bf2c1e35d962aefa9380737e9 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sun, 10 Nov 2013 00:58:18 +0100 Subject: [PATCH 086/225] Searches should match all keywords. --- src/General/Index.coffee | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 4591ee706..53b9b8b54 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -313,14 +313,16 @@ Index = search: (keywords) -> found = [] for threadRoot, i in Index.sortedNodes by 2 - {OP} = Get.threadFromRoot threadRoot - text = [] - for key in ['comment', 'subject', 'name', 'tripcode', 'email'] - text.push OP.info[key] if key of OP.info - text.push OP.file.name if 'file' of OP - text = text.join(' ').toLowerCase() - for keyword in keywords - continue if -1 is text.indexOf keyword + if Index.searchMatch Get.threadFromRoot(threadRoot), keywords found.push Index.sortedNodes[i], Index.sortedNodes[i + 1] - break found + searchMatch: (thread, keywords) -> + {info, file} = thread.OP + text = [] + for key in ['comment', 'subject', 'name', 'tripcode', 'email'] + text.push info[key] if key of info + text.push file.name if file + text = text.join(' ').toLowerCase() + for keyword in keywords + return false if -1 is text.indexOf keyword + return true From bd2fe915eb9f39f53118ab62f44a08bcae4dcdd8 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sun, 10 Nov 2013 21:01:23 +0100 Subject: [PATCH 087/225] Fix position of navlinks on Firefox. --- src/General/Index.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 53b9b8b54..f00b50fd5 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -64,7 +64,7 @@ Index = $.rmClass doc, 'index-loading' for navLink in $$ '.navLinks' $.rm navLink - $.after $.x('child::form/preceding-sibling::hr'), Index.navLinks + $.after $.x('child::form/preceding-sibling::hr[1]'), Index.navLinks cb: mode: -> From 564e799d31f77756376ddf458f47926801a3f6c7 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Mon, 11 Nov 2013 18:50:25 +0100 Subject: [PATCH 088/225] Indicate the elapsed time since the last index refresh at the top of the index. --- CHANGELOG.md | 3 ++- html/General/Index-navlinks.html | 1 + src/General/Index.coffee | 7 ++++++ src/Miscellaneous/RelativeDates.coffee | 34 +++++++++++++++++--------- 4 files changed, 32 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fcc3a9335..3c64ceeaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,11 @@ -- Searching in the index will now show matched OPs by: +- Searching in the index is now possible and will show matched OPs by: - comment - subject - filename - name - tripcode - e-mail +- The elapsed time since the last index refresh is now indicated at the top of the index. ### 3.12.1 - *2013-11-04* diff --git a/html/General/Index-navlinks.html b/html/General/Index-navlinks.html index 3ac6b2437..dc185f087 100644 --- a/html/General/Index-navlinks.html +++ b/html/General/Index-navlinks.html @@ -1,2 +1,3 @@ +[]  [Catalog diff --git a/src/General/Index.coffee b/src/General/Index.coffee index f00b50fd5..77b10aa5f 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -192,6 +192,13 @@ Index = notice.el.lastElementChild.textContent = 'Index refreshed!' setTimeout notice.close, $.SECOND + timeEl = $ '#index-last-refresh', Index.navLinks + timeEl.dataset.utc = e.timeStamp + if timeEl.dataset.init + RelativeDates.setUpdate el: timeEl + delete timeEl.dataset.init + else + RelativeDates.flush() Index.scrollToIndex() parse: (pages) -> Index.parseThreadList pages diff --git a/src/Miscellaneous/RelativeDates.coffee b/src/Miscellaneous/RelativeDates.coffee index d678ecb23..b856a19fd 100644 --- a/src/Miscellaneous/RelativeDates.coffee +++ b/src/Miscellaneous/RelativeDates.coffee @@ -1,13 +1,17 @@ RelativeDates = INTERVAL: $.MINUTE / 2 init: -> - return if g.VIEW is 'catalog' or !Conf['Relative Post Dates'] - - # Flush when page becomes visible again or when the thread updates. - $.on d, 'visibilitychange ThreadUpdate', @flush - - # Start the timeout. - @flush() + switch g.VIEW + when 'index' + @flush() + $.on d, 'visibilitychange', @flush + return unless Conf['Relative Post Dates'] + when 'thread' + return unless Conf['Relative Post Dates'] + @flush() + $.on d, 'visibilitychange ThreadUpdate', @flush if g.VIEW is 'thread' + else + return Post.callbacks.push name: 'Relative Post Dates' @@ -21,7 +25,7 @@ RelativeDates = dateEl = @nodes.date dateEl.title = dateEl.textContent - RelativeDates.setUpdate @ + RelativeDates.setUpdate post: @ # diff is milliseconds from now. relative: (diff, now, date) -> @@ -81,7 +85,7 @@ RelativeDates = # Create function `update()`, closed over post, that, when called # from `flush()`, updates the elements, and re-calls `setOwnTimeout()` to # re-add `update()` to the stale list later. - setUpdate: (post) -> + setUpdate: ({post, el}) -> setOwnTimeout = (diff) -> delay = if diff < $.MINUTE $.SECOND - (diff + $.SECOND / 2) % $.SECOND @@ -94,11 +98,17 @@ RelativeDates = setTimeout markStale, delay update = (now) -> - {date} = post.info + date = if post + post.info.date + else + new Date +el.dataset.utc diff = now - date relative = RelativeDates.relative diff, now, date - for singlePost in [post].concat post.clones - singlePost.nodes.date.firstChild.textContent = relative + if post + for singlePost in [post].concat post.clones + singlePost.nodes.date.firstChild.textContent = relative + else + el.firstChild.textContent = RelativeDates.relative diff, now, date setOwnTimeout diff markStale = -> RelativeDates.stale.push update From 86a46f35fb10daec3dc8f23855317857d586dc5a Mon Sep 17 00:00:00 2001 From: Mayhem Date: Mon, 11 Nov 2013 21:05:35 +0100 Subject: [PATCH 089/225] Move the last refresh timer, give the "field" class to the search input. --- css/style.css | 3 +++ html/General/Index-navlinks.html | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/css/style.css b/css/style.css index 07d983a9d..6ee0d31b1 100644 --- a/css/style.css +++ b/css/style.css @@ -32,6 +32,9 @@ background-color: #F2F2F2; color: #888; } +.field::-webkit-search-decoration { + display: none; +} .move { cursor: move; } diff --git a/html/General/Index-navlinks.html b/html/General/Index-navlinks.html index dc185f087..7d3b04da7 100644 --- a/html/General/Index-navlinks.html +++ b/html/General/Index-navlinks.html @@ -1,3 +1,3 @@ -[]  [Catalog]  - +[]  + From 547e9db6a2488dfacd57b2b081f178d8c2c59a30 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Mon, 11 Nov 2013 22:32:47 +0100 Subject: [PATCH 090/225] Smaller search input by default. Hidamarize on hover/focus. --- css/style.css | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/css/style.css b/css/style.css index 6ee0d31b1..89639943b 100644 --- a/css/style.css +++ b/css/style.css @@ -371,6 +371,14 @@ a[href="javascript:;"] { :root.index-loading .pagelist { display: none; } +#index-search { + width: 100px; + transition: color .25s, border-color .25s, width .25s; +} +#index-search:hover, +#index-search:focus { + width: 200px; +} .summary { text-decoration: none; } From 46e3414ec9cf83a5818f18f5e3af5c9f86127605 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Wed, 13 Nov 2013 12:35:45 +0100 Subject: [PATCH 091/225] Fix spacing issue for the top right link of the settings. --- html/General/Settings.html | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/html/General/Settings.html b/html/General/Settings.html index 8ee5f006b..9a94ccc59 100644 --- a/html/General/Settings.html +++ b/html/General/Settings.html @@ -2,9 +2,12 @@ From e9a128da704726397f2c15853c6494cbc1128528 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Fri, 15 Nov 2013 01:31:01 +0100 Subject: [PATCH 092/225] Add search-clearing button. --- css/style.css | 12 ++++++++++-- html/General/Index-navlinks.html | 1 + src/General/Index.coffee | 11 ++++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/css/style.css b/css/style.css index 89639943b..56a6a5d31 100644 --- a/css/style.css +++ b/css/style.css @@ -372,13 +372,21 @@ a[href="javascript:;"] { display: none; } #index-search { + padding-right: 1.5em; width: 100px; transition: color .25s, border-color .25s, width .25s; } -#index-search:hover, -#index-search:focus { +#index-search[data-searching] { width: 200px; } +#index-search-clear { + color: gray; + margin-left: -1.25em; +} +#index-search::-webkit-search-cancel-button, +#index-search:not([data-searching]) + #index-search-clear { + display: none; +} .summary { text-decoration: none; } diff --git a/html/General/Index-navlinks.html b/html/General/Index-navlinks.html index 7d3b04da7..cb69adae9 100644 --- a/html/General/Index-navlinks.html +++ b/html/General/Index-navlinks.html @@ -1,3 +1,4 @@ [Catalog]  [ + diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 77b10aa5f..5a492f7fe 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -58,6 +58,7 @@ Index = $.on window, 'popstate', @cb.popstate $.on @pagelist, 'click', @cb.pageNav $.on @searchInput, 'input', @onSearchInput + $.on $('#index-search-clear', @navLinks), 'click', @clearSearch $.asap (-> $('.pagelist', doc) or d.readyState isnt 'loading'), -> $.replace $('.board'), Index.root $.replace $('.pagelist'), Index.pagelist @@ -297,7 +298,7 @@ Index = offset = 0 for threadRoot, i in Index.sortedNodes by 2 when Get.threadFromRoot(threadRoot).isOnTop Index.sortedNodes.splice offset++ * 2, 0, Index.sortedNodes.splice(i, 2)... - if Index.searchInput.value + if Index.isSearching Index.sortedNodes = Index.querySearch(Index.searchInput.value) or Index.sortedNodes buildIndex: -> if Conf['Index Mode'] is 'paged' @@ -311,7 +312,15 @@ Index = $.event 'IndexBuild', nodes $.add Index.root, nodes + isSearching: false + clearSearch: -> + Index.searchInput.value = null + Index.onSearchInput() onSearchInput: -> + if Index.isSearching = !!Index.searchInput.value.trim() + Index.searchInput.dataset.searching = 1 + else + delete Index.searchInput.dataset.searching Index.sort() Index.buildIndex() querySearch: (query) -> From 91dd12213e360cbc9bad4fe6f30a23bc7dbc3dad Mon Sep 17 00:00:00 2001 From: Mayhem Date: Fri, 15 Nov 2013 02:34:13 +0100 Subject: [PATCH 093/225] Focus the index search input after clearing it. --- src/General/Index.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 5a492f7fe..eb19cd87b 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -316,6 +316,7 @@ Index = clearSearch: -> Index.searchInput.value = null Index.onSearchInput() + Index.searchInput.focus() onSearchInput: -> if Index.isSearching = !!Index.searchInput.value.trim() Index.searchInput.dataset.searching = 1 From 67e75bd2fb78eeb8819bba0d24916852b67bcb29 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Fri, 15 Nov 2013 17:18:36 +0100 Subject: [PATCH 094/225] Prevent content inside of .board from being downloaded on intial page load. See comments in the code. --- src/General/Index.coffee | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/General/Index.coffee b/src/General/Index.coffee index eb19cd87b..070671247 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -59,13 +59,24 @@ Index = $.on @pagelist, 'click', @cb.pageNav $.on @searchInput, 'input', @onSearchInput $.on $('#index-search-clear', @navLinks), 'click', @clearSearch - $.asap (-> $('.pagelist', doc) or d.readyState isnt 'loading'), -> - $.replace $('.board'), Index.root - $.replace $('.pagelist'), Index.pagelist - $.rmClass doc, 'index-loading' + $.asap (-> $('.board', doc) or d.readyState isnt 'loading'), -> + board = $ '.board' + $.replace board, Index.root + # Hacks: + # - When removing an element from the document during page load, + # its ancestors will still be correctly created inside of it. + # - Creating loadable elements inside of an origin-less document + # will not download them. + # - Combine the two and you get a download canceller! + # Does not work on Firefox unfortunately. + d.implementation.createDocument(null, null, null).appendChild board + for navLink in $$ '.navLinks' $.rm navLink $.after $.x('child::form/preceding-sibling::hr[1]'), Index.navLinks + $.rmClass doc, 'index-loading' + $.asap (-> $('.pagelist') or d.readyState isnt 'loading'), -> + $.replace $('.pagelist'), Index.pagelist cb: mode: -> From 2248e4de165e5cb43ca7b518c813d39e83d399e6 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Fri, 15 Nov 2013 18:07:38 +0100 Subject: [PATCH 095/225] Fix the index search clear button appearance on Firefox. --- css/style.css | 3 +++ src/General/Index.coffee | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/css/style.css b/css/style.css index 56a6a5d31..0718196fd 100644 --- a/css/style.css +++ b/css/style.css @@ -383,7 +383,10 @@ a[href="javascript:;"] { color: gray; margin-left: -1.25em; } +<% if (type === 'crx') { %> +/* ``::-webkit-*'' selectors break selector lists on Firefox. */ #index-search::-webkit-search-cancel-button, +<% } %> #index-search:not([data-searching]) + #index-search-clear { display: none; } diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 070671247..866067d0d 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -332,7 +332,12 @@ Index = if Index.isSearching = !!Index.searchInput.value.trim() Index.searchInput.dataset.searching = 1 else + <% if (type === 'userscript') { %> + # XXX https://github.com/greasemonkey/greasemonkey/issues/1571 + Index.searchInput.removeAttribute 'data-searching' + <% } else { %> delete Index.searchInput.dataset.searching + <% } %> Index.sort() Index.buildIndex() querySearch: (query) -> From ac7b7661ca459e5e3b2a76b48037a9bb38421e3f Mon Sep 17 00:00:00 2001 From: Mayhem Date: Fri, 15 Nov 2013 18:47:46 +0100 Subject: [PATCH 096/225] Jump to page zero when starting to search. Jump back to the previous page when clearing the search. --- src/General/Index.coffee | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 866067d0d..2545b9ad3 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -330,8 +330,13 @@ Index = Index.searchInput.focus() onSearchInput: -> if Index.isSearching = !!Index.searchInput.value.trim() - Index.searchInput.dataset.searching = 1 + unless Index.searchInput.dataset.searching + Index.searchInput.dataset.searching = 1 + Index.pageBeforeSearch = Index.getCurrentPage() + pageNum = 0 else + pageNum = Index.pageBeforeSearch + delete Index.pageBeforeSearch <% if (type === 'userscript') { %> # XXX https://github.com/greasemonkey/greasemonkey/issues/1571 Index.searchInput.removeAttribute 'data-searching' @@ -339,7 +344,10 @@ Index = delete Index.searchInput.dataset.searching <% } %> Index.sort() - Index.buildIndex() + if Index.currentPage is pageNum + Index.buildIndex() + else + Index.pageNav pageNum querySearch: (query) -> return unless keywords = query.toLowerCase().match /\S+/g Index.search keywords From 07bca42d637de58c0434e810445250c81b65e7cf Mon Sep 17 00:00:00 2001 From: Mayhem Date: Fri, 15 Nov 2013 21:04:49 +0100 Subject: [PATCH 097/225] Rebuild the pagelist when searching. --- src/General/Index.coffee | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 2545b9ad3..437103501 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -117,31 +117,39 @@ Index = Index.setPage() Index.scrollToIndex() + getPagesNum: -> + if Index.isSearching + Math.ceil (Index.sortedNodes.length / 2) / Index.threadsNumPerPage + else + Index.pagesNum + getMaxPageNum: -> + Math.max 0, Index.getPagesNum() - 1 togglePagelist: -> Index.pagelist.hidden = Conf['Index Mode'] isnt 'paged' buildPagelist: -> pagesRoot = $ '.pages', Index.pagelist - if pagesRoot.childElementCount isnt Index.pagesNum + maxPageNum = Index.getMaxPageNum() + if pagesRoot.childElementCount isnt maxPageNum + 1 nodes = [] - for i in [0..Index.pagesNum - 1] + for i in [0..maxPageNum] by 1 a = $.el 'a', textContent: i href: if i then i else './' nodes.push $.tn('['), a, $.tn '] ' $.rmAll pagesRoot $.add pagesRoot, nodes - Index.setPage() Index.togglePagelist() setPage: -> - pageNum = Index.getCurrentPage() - pagesRoot = $ '.pages', Index.pagelist + pageNum = Index.getCurrentPage() + maxPageNum = Index.getMaxPageNum() + pagesRoot = $ '.pages', Index.pagelist # Previous/Next buttons prev = pagesRoot.previousSibling.firstChild next = pagesRoot.nextSibling.firstChild href = Math.max pageNum - 1, 0 prev.href = if href is 0 then './' else href prev.firstChild.disabled = href is pageNum - href = Math.min pageNum + 1, Index.pagesNum - 1 + href = Math.min pageNum + 1, maxPageNum next.href = if href is 0 then './' else href next.firstChild.disabled = href is pageNum # current page @@ -218,6 +226,7 @@ Index = Index.sort() Index.buildIndex() Index.buildPagelist() + Index.setPage() parseThreadList: (pages) -> Index.pagesNum = pages.length Index.threadsNumPerPage = pages[0].threads.length @@ -334,6 +343,8 @@ Index = Index.searchInput.dataset.searching = 1 Index.pageBeforeSearch = Index.getCurrentPage() pageNum = 0 + else + pageNum = Index.getCurrentPage() else pageNum = Index.pageBeforeSearch delete Index.pageBeforeSearch @@ -344,8 +355,12 @@ Index = delete Index.searchInput.dataset.searching <% } %> Index.sort() + # Go to the last available page if we were past the limit. + pageNum = Math.min pageNum, Index.getMaxPageNum() if Conf['Index Mode'] is 'paged' + Index.buildPagelist() if Index.currentPage is pageNum Index.buildIndex() + Index.setPage() else Index.pageNav pageNum querySearch: (query) -> From 8afcac8d6fb0b04027901678c89afc0a565915c6 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 16 Nov 2013 00:09:08 +0100 Subject: [PATCH 098/225] Add the `Show replies` index setting. --- CHANGELOG.md | 20 ++++++++++++-------- src/General/Build.coffee | 9 +++++++-- src/General/Config.coffee | 1 + src/General/Index.coffee | 15 +++++++++++++-- src/Miscellaneous/ExpandThread.coffee | 19 +++++++++++-------- 5 files changed, 44 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c64ceeaa..f5e83939d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,15 @@ -- Searching in the index is now possible and will show matched OPs by: - - comment - - subject - - filename - - name - - tripcode - - e-mail -- The elapsed time since the last index refresh is now indicated at the top of the index. +- More index navigation improvements: + - Searching in the index is now possible and will show matched OPs by: +
      +
    • comment +
    • subject +
    • filename +
    • name +
    • tripcode +
    • e-mail +
    + - The elapsed time since the last index refresh is now indicated at the top of the index. + - New setting: `Show replies`, enabled by default. Disable it to only show OPs in the index. ### 3.12.1 - *2013-11-04* diff --git a/src/General/Build.coffee b/src/General/Build.coffee index 6fe60021b..31fbea6a9 100644 --- a/src/General/Build.coffee +++ b/src/General/Build.coffee @@ -279,8 +279,13 @@ Build = id: "t#{data.no}" nodes = [if OP then OP.nodes.root else Build.postFromObject data, board.ID] - if data.omitted_posts - nodes.push Build.summary board.ID, data.no, data.omitted_posts, data.omitted_images + if data.omitted_posts or !Conf['Show Replies'] and data.replies + [posts, files] = if Conf['Show Replies'] + [data.omitted_posts, data.omitted_images] + else + # XXX data.images is not accurate. + [data.replies, data.omitted_images + data.last_replies.filter((data) -> !!data.ext).length] + nodes.push Build.summary board.ID, data.no, posts, files $.add root, nodes root diff --git a/src/General/Config.coffee b/src/General/Config.coffee index e1818ec89..de55119ff 100644 --- a/src/General/Config.coffee +++ b/src/General/Config.coffee @@ -142,6 +142,7 @@ Config = Index: 'Index Mode': 'paged' 'Index Sort': 'bump' + 'Show Replies': true Header: 'Header auto-hide': false 'Bottom header': false diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 437103501..251d6efe8 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -36,12 +36,19 @@ Index = $.on input, 'change', $.cb.value $.on input, 'change', @cb.sort + repliesEntry = + el: $.el 'label', innerHTML: ' Show replies' + input = repliesEntry.el.firstChild + input.checked = Conf['Show Replies'] + $.on input, 'change', $.cb.checked + $.on input, 'change', @cb.replies + $.event 'AddMenuEntry', type: 'header' el: $.el 'span', textContent: 'Index Navigation' order: 90 - subEntries: [modeEntry, sortEntry] + subEntries: [modeEntry, sortEntry, repliesEntry] $.addClass doc, 'index-loading' @update() @@ -85,6 +92,10 @@ Index = sort: -> Index.sort() Index.buildIndex() + replies: -> + Index.buildThreads() + Index.sort() + Index.buildIndex() popstate: (e) -> pageNum = Index.getCurrentPage() Index.pageLoad pageNum if Index.currentPage isnt pageNum @@ -328,7 +339,7 @@ Index = else nodes = Index.sortedNodes $.rmAll Index.root - Index.buildReplies nodes + Index.buildReplies nodes if Conf['Show Replies'] $.event 'IndexBuild', nodes $.add Index.root, nodes diff --git a/src/Miscellaneous/ExpandThread.coffee b/src/Miscellaneous/ExpandThread.coffee index 608572cf7..086f76d8d 100644 --- a/src/Miscellaneous/ExpandThread.coffee +++ b/src/Miscellaneous/ExpandThread.coffee @@ -50,16 +50,19 @@ ExpandThread = a.textContent = ExpandThread.text '+', a.textContent.match(/\d+/g)... if a return - num = if thread.isSticky - 1 - else switch g.BOARD.ID - # XXX boards config - when 'b', 'vg' then 3 - when 't' then 1 - else 5 + replies = $$ '.thread > .replyContainer', threadRoot + if Conf['Show Replies'] + num = if thread.isSticky + 1 + else switch g.BOARD.ID + # XXX boards config + when 'b', 'vg' then 3 + when 't' then 1 + else 5 + replies = replies[...-num] postsCount = 0 filesCount = 0 - for reply in $$('.thread > .replyContainer', threadRoot)[...-num] + for reply in replies # rm clones inlined.click() while inlined = $ '.inlined', reply if Conf['Quote Inlining'] postsCount++ From e7dfbf776baa28072b1edd5ed12119e3b0bcf70d Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 16 Nov 2013 01:10:24 +0100 Subject: [PATCH 099/225] Add a page indicator on OPs in the index. --- CHANGELOG.md | 6 ++++++ src/General/Build.coffee | 9 ++++++--- src/General/Index.coffee | 3 ++- src/General/Thread.coffee | 5 +++++ 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5e83939d..39c35a577 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,12 @@
  • tripcode
  • e-mail + - The page number on which threads are will now be displayed in OPs, to easily identify where threads are located when: +
      +
    • searching through the index. +
    • using different index sorting types. +
    • threads highlighted by the filter are moved to the top and move other threads down. +
        - The elapsed time since the last index refresh is now indicated at the top of the index. - New setting: `Show replies`, enabled by default. Disable it to only show OPs in the index. diff --git a/src/General/Build.coffee b/src/General/Build.coffee index 31fbea6a9..9fbcf6315 100644 --- a/src/General/Build.coffee +++ b/src/General/Build.coffee @@ -190,10 +190,12 @@ Build = else '' - replyLink = if isOP and g.VIEW is 'index' - "   [Reply]" + if isOP and g.VIEW is 'index' + pageNum = Math.floor Index.liveThreadIDs.indexOf(postID) / Index.threadsNumPerPage + pageIcon = " #{pageNum} " + replyLink = "   [Reply]" else - '' + pageIcon = replyLink = '' container = $.el 'div', id: "pc#{postID}" @@ -226,6 +228,7 @@ Build = (if isOP then fileHTML else '') + "
        diff --git a/html/Posting/QR.html b/html/Posting/QR.html index 9b9786933..c172cb848 100644 --- a/html/Posting/QR.html +++ b/html/Posting/QR.html @@ -4,7 +4,7 @@ - × +
  • @@ -29,7 +29,7 @@ No selected file - × +
    diff --git a/src/General/Notice.coffee b/src/General/Notice.coffee index 90c2e504b..ea5f6f360 100644 --- a/src/General/Notice.coffee +++ b/src/General/Notice.coffee @@ -1,7 +1,7 @@ class Notice constructor: (type, content, @timeout) -> @el = $.el 'div', - innerHTML: '×
    ' + innerHTML: '
    ' @el.style.opacity = 0 @setType type $.on @el.firstElementChild, 'click', @close diff --git a/src/Monitoring/ThreadWatcher.coffee b/src/Monitoring/ThreadWatcher.coffee index 680d61c6a..ad9e710ee 100644 --- a/src/Monitoring/ThreadWatcher.coffee +++ b/src/Monitoring/ThreadWatcher.coffee @@ -131,7 +131,7 @@ ThreadWatcher = makeLine: (boardID, threadID, data) -> x = $.el 'a', - textContent: '×' + className: 'fa fa-times' href: 'javascript:;' $.on x, 'click', ThreadWatcher.cb.rm diff --git a/src/Posting/QR.coffee b/src/Posting/QR.coffee index 6f71abb2f..b3e41a838 100644 --- a/src/Posting/QR.coffee +++ b/src/Posting/QR.coffee @@ -438,7 +438,7 @@ QR = className: 'qr-preview' draggable: true href: 'javascript:;' - innerHTML: '×' + innerHTML: '' @nodes = el: el From 20b4087f1d0be4de7750e744bba44de1a46d9d08 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 16 Nov 2013 03:45:51 +0100 Subject: [PATCH 101/225] Use fa-plus for the #add-post in the QR. #1338 --- css/style.css | 8 +++----- html/Posting/QR.html | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/css/style.css b/css/style.css index 63b807874..354677865 100644 --- a/css/style.css +++ b/css/style.css @@ -764,11 +764,9 @@ a.remove { vertical-align: bottom; } #add-post { - display: inline-block; - font-size: 30px; - height: 30px; - width: 30px; - line-height: 1; + font-size: 20px; + height: 20px; + width: 20px; text-align: center; position: absolute; right: 0; diff --git a/html/Posting/QR.html b/html/Posting/QR.html index c172cb848..1458303cf 100644 --- a/html/Posting/QR.html +++ b/html/Posting/QR.html @@ -15,7 +15,7 @@
    - + +
    From b72b69d9a3fcfd5611c456ced4dddb00f0503dab Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 16 Nov 2013 03:51:54 +0100 Subject: [PATCH 102/225] Hidamarize the index search input on focus. --- css/style.css | 1 + 1 file changed, 1 insertion(+) diff --git a/css/style.css b/css/style.css index 354677865..cbb57f87a 100644 --- a/css/style.css +++ b/css/style.css @@ -376,6 +376,7 @@ a[href="javascript:;"] { width: 100px; transition: color .25s, border-color .25s, width .25s; } +#index-search:focus, #index-search[data-searching] { width: 200px; } From 752e6a87478445252217ae44349d9cc15df5b8cb Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 16 Nov 2013 15:27:39 +0100 Subject: [PATCH 103/225] Fix font-family of the page num indicators. --- css/style.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/css/style.css b/css/style.css index cbb57f87a..6f6f596cf 100644 --- a/css/style.css +++ b/css/style.css @@ -391,6 +391,12 @@ a[href="javascript:;"] { #index-search:not([data-searching]) + #index-search-clear { display: none; } +.page-num { + font-family: inherit; +} +.page-num::before { + font-family: FontAwesome; +} .summary { text-decoration: none; } From 06e83cc5f6bb64fcf74aa8eb975c43c95cb9baa4 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 16 Nov 2013 15:42:11 +0100 Subject: [PATCH 104/225] Fix relative index refresh date on Firefox. --- src/General/Index.coffee | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 0df36998e..ca4ec0c0b 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -224,10 +224,15 @@ Index = setTimeout notice.close, $.SECOND timeEl = $ '#index-last-refresh', Index.navLinks - timeEl.dataset.utc = e.timeStamp + timeEl.dataset.utc = e.timeStamp <% if (type === 'userscript') { %>/ 1000<% } %> if timeEl.dataset.init RelativeDates.setUpdate el: timeEl + <% if (type === 'userscript') { %> + # XXX https://github.com/greasemonkey/greasemonkey/issues/1571 + timeEl.removeAttribute 'data-init' + <% } else { %> delete timeEl.dataset.init + <% } %> else RelativeDates.flush() Index.scrollToIndex() From 1b8e55f0b49c92013c016dd44a257bb9d0db72af Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 16 Nov 2013 20:07:19 +0100 Subject: [PATCH 105/225] Use fa-times-circle instead of fa-times for clearing actions. --- html/Posting/QR.html | 2 +- src/Posting/QR.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/html/Posting/QR.html b/html/Posting/QR.html index 1458303cf..6593cb38b 100644 --- a/html/Posting/QR.html +++ b/html/Posting/QR.html @@ -29,7 +29,7 @@ No selected file - +
    diff --git a/src/Posting/QR.coffee b/src/Posting/QR.coffee index b3e41a838..bd3634e1d 100644 --- a/src/Posting/QR.coffee +++ b/src/Posting/QR.coffee @@ -438,7 +438,7 @@ QR = className: 'qr-preview' draggable: true href: 'javascript:;' - innerHTML: '' + innerHTML: '' @nodes = el: el From b2b4197249e987efc0684e866d5c132a3af22c3e Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sat, 16 Nov 2013 20:19:17 +0100 Subject: [PATCH 106/225] Change the OP page indicator. --- CHANGELOG.md | 2 +- css/style.css | 6 ------ src/General/Build.coffee | 5 ++--- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 39c35a577..487f93a61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ - The page number on which threads are will now be displayed in OPs, to easily identify where threads are located when: