summaryrefslogtreecommitdiff
path: root/crocoite/data/click.js
diff options
context:
space:
mode:
Diffstat (limited to 'crocoite/data/click.js')
-rw-r--r--crocoite/data/click.js217
1 files changed, 72 insertions, 145 deletions
diff --git a/crocoite/data/click.js b/crocoite/data/click.js
index b3e425b..ae189da 100644
--- a/crocoite/data/click.js
+++ b/crocoite/data/click.js
@@ -4,129 +4,7 @@
* like navigating to a different location. Thus whitelist known elements.
*/
-(function(){
-const selectorFlag = Object.freeze ({
- none: 0,
- multi: 1, /* click item multiple times */
-});
-const defaultClickThrottle = 50; /* in ms */
-const discoverInterval = 1000; /* 1 second */
-const sites = Object.freeze ([
- {
- hostname: /^www\.facebook\.com$/i,
- selector: [
- /* show more comments */
- {s: 'a.UFIPagerLink[role=button]', flags: selectorFlag.none},
- /* show nested comments*/
- {s: 'a.UFICommentLink[role=button]', flags: selectorFlag.none},
- /* initially show comments below a single post/video, i.e. /user/post/123 */
- {s: 'form.commentable_item a[data-comment-prelude-ref=action_link_bling][rel=ignore]', flags: selectorFlag.none},
- /* close the “register now” nag screen. for better screen shots */
- {s: 'a#expanding_cta_close_button[role=button]', flags: selectorFlag.none},
- ],
- }, {
- hostname: /^twitter\.com$/i,
- selector: [
- /* expand threads */
- {s: 'a.ThreadedConversation-moreRepliesLink', flags: selectorFlag.none},
- /* show hidden profiles */
- {s: 'button.ProfileWarningTimeline-button', flags: selectorFlag.none},
- /* show hidden/sensitive media */
- {s: 'button.Tombstone-action.js-display-this-media', flags: selectorFlag.none},
- ],
- }, {
- hostname: /^disqus\.com$/i,
- selector: [
- /* load more comments */
- {s: 'a.load-more__button', flags: selectorFlag.multi},
- ],
- }, {
- hostname: /^(www|np)\.reddit\.com$/i,
- selector: [
- /* show more comments, reddit’s javascript ignores events if too
- * frequent */
- {s: 'span.morecomments a', flags: selectorFlag.none, throttle: 500},
- ],
- }, {
- hostname: /^www\.instagram\.com$/i,
- selector: [
- /* posts may have multiple images that load dynamically, click the arrow */
- {s: 'a[role=button].coreSpriteRightChevron', flags: selectorFlag.multi, throttle: 500},
- /* load more comments */
- {s: 'article div ul li a[role=button]', flags: selectorFlag.multi},
- ],
- }, {
- hostname: /^www\.youtube\.com$/i,
- selector: [
- /* expand comment thread */
- {s: 'ytd-comment-thread-renderer div.more-button', flags: selectorFlag.none},
- ],
- }, {
- hostname: /^www\.patreon\.com$/i,
- selector: [
- /* load more content */
- {s: 'div[display=flex] div[display=block] button[color=gray][type=button]', flags: selectorFlag.multi},
- /* load more comments */
- {s: 'div.stackable[display=block] > div > div > a[color=dark][target=_self]', flags: selectorFlag.none},
- /* load more replies */
- {s: 'div > a[scale="0"][color=blue][size="1"]', flags: selectorFlag.none},
- ],
- }, {
- hostname: /^(www\.)?gab\.ai$/i,
- selector: [
- /* post comments */
- {s: 'post-detail post-comment .post-comment__replies__count a', flags: selectorFlag.none},
- /* more comments */
- {s: 'post-detail .post-comment-list__loading a', flags: selectorFlag.none},
- /* more posts */
- {s: 'post-list a.post-list__load-more', flags: selectorFlag.multi},
- ],
- }, {
- hostname: /^(www\.)?github\.com$/i,
- selector: [
- /* show hidden issue items, see https://github.com/dominictarr/event-stream/issues/116 */
- {s: 'div#discussion_bucket form.ajax-pagination-form button.ajax-pagination-btn', flags: selectorFlag.none},
- ],
- }
- ]);
-
-/* pick selectors matching current location */
-let hostname = document.location.hostname;
-let selector = [];
-for (let s of sites) {
- if (s.hostname.test (hostname)) {
- selector = selector.concat (s.selector);
- }
-}
-
-function makeClickEvent () {
- return new MouseEvent('click', {
- view: window,
- bubbles: true,
- cancelable: true
- });
-}
-
-/* throttle clicking */
-let queue = [];
-let clickTimeout = null;
-function click () {
- if (queue.length > 0) {
- const item = queue.shift ();
- const o = item.o;
- const selector = item.selector;
- o.dispatchEvent (makeClickEvent ());
-
- if (queue.length > 0) {
- const nextTimeout = 'throttle' in selector ?
- selector.throttle : defaultClickThrottle;
- clickTimeout = window.setTimeout (click, nextTimeout);
- } else {
- clickTimeout = null;
- }
- }
-}
-
+(function() {
/* Element is visible if itself and all of its parents are
*/
function isVisible (o) {
@@ -148,33 +26,82 @@ function isClickable (o) {
return !o.hasAttribute ('disabled') && isVisible (o);
}
-/* some sites don’t remove/replace the element immediately, so keep track of
- * which ones we already clicked */
-let have = new Set ();
-function discover () {
- for (let s of selector) {
- let obj = document.querySelectorAll (s.s);
- for (let o of obj) {
- if (!have.has (o) && isClickable (o)) {
- queue.push ({o: o, selector: s});
- if (!(s.flags & selectorFlag.multi)) {
- have.add (o);
- }
+const defaultClickThrottle = 50; /* in ms */
+const discoverInterval = 1000; /* 1 second */
+
+class Click {
+ constructor(options) {
+ /* pick selectors matching current location */
+ let hostname = document.location.hostname;
+ this.selector = [];
+ for (let s of options['sites']) {
+ let r = new RegExp (s.match, 'i');
+ if (r.test (hostname)) {
+ this.selector = this.selector.concat (s.selector);
}
}
+ /* throttle clicking */
+ this.queue = [];
+ this.clickTimeout = null;
+
+ /* some sites don’t remove/replace the element immediately, so keep track of
+ * which ones we already clicked */
+ this.have = new Set ();
+
+ /* XXX: can we use a mutation observer instead? */
+ this.interval = window.setInterval (this.discover.bind (this), discoverInterval);
}
- if (queue.length > 0 && clickTimeout === null) {
- /* start clicking immediately */
- clickTimeout = window.setTimeout (click, 0);
+
+ makeClickEvent () {
+ return new MouseEvent('click', {
+ view: window,
+ bubbles: true,
+ cancelable: true
+ });
+ }
+
+ click () {
+ if (this.queue.length > 0) {
+ const item = this.queue.shift ();
+ const o = item.o;
+ const selector = item.selector;
+ o.dispatchEvent (this.makeClickEvent ());
+
+ if (this.queue.length > 0) {
+ const nextTimeout = 'throttle' in selector ?
+ selector.throttle : defaultClickThrottle;
+ this.clickTimeout = window.setTimeout (this.click.bind (this), nextTimeout);
+ } else {
+ this.clickTimeout = null;
+ }
+ }
+ }
+
+ discover () {
+ for (let s of this.selector) {
+ let obj = document.querySelectorAll (s.selector);
+ for (let o of obj) {
+ if (!this.have.has (o) && isClickable (o)) {
+ this.queue.push ({o: o, selector: s});
+ if (!s.multi) {
+ this.have.add (o);
+ }
+ }
+ }
+ }
+ if (this.queue.length > 0 && this.clickTimeout === null) {
+ /* start clicking immediately */
+ this.clickTimeout = window.setTimeout (this.click.bind (this), 0);
+ }
+ return true;
}
- return true;
-}
-/* XXX: can we use a mutation observer instead? */
-let interval = window.setInterval (discover, discoverInterval);
-function stop() {
- window.clearInterval (interval);
+ stop () {
+ window.clearInterval (this.interval);
+ window.clearTimeout (this.clickTimeout);
+ }
}
-return {'stop': stop};
+
+return Click;
}())