From 8b80bce56b12c13e1400fed3566aa44e1e47f9d9 Mon Sep 17 00:00:00 2001 From: chylex Date: Fri, 27 Oct 2017 00:07:57 +0200 Subject: [PATCH] Rewrite most of the handling and fresh msg detection Closes #15 Closes #16 --- src/tracker/discord.js | 90 ++++++++++++++++++++++++++--------------- src/tracker/savefile.js | 10 ++++- src/tracker/state.js | 15 +++++++ src/tracker/Σ.js | 52 +++++++++++++----------- 4 files changed, 111 insertions(+), 56 deletions(-) diff --git a/src/tracker/discord.js b/src/tracker/discord.js index 1c867bb..0175201 100644 --- a/src/tracker/discord.js +++ b/src/tracker/discord.js @@ -1,39 +1,60 @@ var DISCORD = (function(){ var regexMessageRequest = /\/channels\/(\d+)\/messages[^a-z]/; - var lastLoadedMessage = null; - var getFirstMessage = function(){ - var props = DISCORD.getReactProps(DOM.fcls("messages")); - var array = props && props.children.find(ele => ele && ele.length); - - if (array){ - for(let obj of array){ - if (obj.props.messages && obj.props.messages.length > 0){ - return obj.props.messages[0]; - } - } - } - - return null; + var getTopMessageViewElement = function(){ + let view = DOM.fcls("messages"); + return view && view.children.length && view.children[0]; }; + var observerTimer = 0, waitingForCleanup = 0; + return { /* - * Sets up a callback hook to trigger whenever the list of messages is updated. + * Sets up a callback hook to trigger whenever the list of messages is updated. The callback is given a boolean value that is true if there are more messages to load. */ setupMessageUpdateCallback: function(callback){ - var observerInterval = window.setInterval(function(){ - var firstMsg = getFirstMessage(); - - if (firstMsg === null){ - lastLoadedMessage = null; + var onTimerFinished = function(){ + let topEle = getTopMessageViewElement(); + + if (!topEle){ + restartTimer(500); } - else if (lastLoadedMessage === null || (lastLoadedMessage !== null && lastLoadedMessage !== firstMsg.id)){ - callback(); + else if (!topEle.classList.contains("loading-more")){ + let messages = DOM.fcls("messages").children.length; + + if (messages < 100){ + waitingForCleanup = 0; + } + + if (waitingForCleanup > 0){ + --waitingForCleanup; + restartTimer(750); + } + else{ + if (messages > 300){ + waitingForCleanup = 6; + + DOM.setTimer(() => { + let view = DOM.fcls("messages"); + view.scrollTop = view.scrollHeight/2; + }, 1); + } + + callback(topEle.classList.contains("has-more")); + restartTimer(200); + } } - }, 100); + else{ + restartTimer(25); + } + }; - window.DHT_ON_UNLOAD.push(() => window.clearInterval(observerInterval)); + var restartTimer = function(delay){ + observerTimer = DOM.setTimer(onTimerFinished, delay); + }; + + onTimerFinished(); + window.DHT_ON_UNLOAD.push(() => window.clearInterval(observerTimer)); }, /* @@ -115,27 +136,32 @@ var DISCORD = (function(){ Array.prototype.push.apply(messages, obj.props.messages); } } - - lastLoadedMessage = messages.length === 0 ? null : messages[0].id; } return messages; }, /* - * Returns true if the message column is visible. + * Returns true if the message view is visible. */ - isInMessageView: (_) => DOM.cls("messages").length > 0, + isInMessageView: () => DOM.cls("messages").length > 0, /* - * Returns true if there are more messages available. + * Returns true if there are more messages available or if they're still loading. */ - hasMoreMessages: (_) => DOM.fcls("messages").children[0].classList.contains("has-more"), + hasMoreMessages: function(){ + let classes = getTopMessageViewElement().classList; + return classes.contains("has-more") || classes.contains("loading-more"); + }, /* - * Forces the message column to scroll all the way up to load older messages. + * Forces the message view to load older messages by scrolling all the way up. */ - loadOlderMessages: (_) => DOM.fcls("messages").scrollTop = 0, + loadOlderMessages: function(){ + let view = DOM.fcls("messages"); + view.scrollTop = view.scrollHeight/2; + view.scrollTop = 0; + }, /* * Selects the next text channel and returns true, otherwise returns false if there are no more channels. diff --git a/src/tracker/savefile.js b/src/tracker/savefile.js index d27f8c6..a691f49 100644 --- a/src/tracker/savefile.js +++ b/src/tracker/savefile.js @@ -91,6 +91,7 @@ var SAVEFILE = function(parsedObj){ me.tmp.userlookup = {}; me.tmp.channelkeys = new Set(); me.tmp.messagekeys = new Set(); + me.tmp.freshmsgs = new Set(); }; SAVEFILE.isValid = function(parsedObj){ @@ -184,11 +185,18 @@ SAVEFILE.prototype.convertToMessageObject = function(discordMessage){ return obj; }; +SAVEFILE.prototype.isMessageFresh = function(id){ + return this.tmp.freshmsgs.has(id); +}; + SAVEFILE.prototype.addMessagesFromDiscord = function(channelId, discordMessageArray){ var hasNewMessages = false; for(var discordMessage of discordMessageArray){ - hasNewMessages |= this.addMessage(channelId, discordMessage.id, this.convertToMessageObject(discordMessage)); + if (this.addMessage(channelId, discordMessage.id, this.convertToMessageObject(discordMessage))){ + this.tmp.freshmsgs.add(discordMessage.id); + hasNewMessages = true; + } } return hasNewMessages; diff --git a/src/tracker/state.js b/src/tracker/state.js index e237f60..60e31ed 100644 --- a/src/tracker/state.js +++ b/src/tracker/state.js @@ -57,6 +57,14 @@ var STATE = (function(){ triggerStateChanged("tracking", this._isTracking); }; + /* + * Toggles the tracking state. + */ + CLS.prototype.toggleTracking = function(){ + this._isTracking = !this._isTracking; + triggerStateChanged("tracking", this._isTracking); + }; + /* * Combines current savefile with the provided one. */ @@ -99,6 +107,13 @@ var STATE = (function(){ } }; + /* + * Returns true if the message was added during this session. + */ + CLS.prototype.isMessageFresh = function(id){ + return this.getSavefile().isMessageFresh(id); + }; + /* * Adds a listener that is called whenever the state changes. The callback is a function that takes subject (generic type) and detail (specific type or data). */ diff --git a/src/tracker/Σ.js b/src/tracker/Σ.js index 837780e..26a203d 100644 --- a/src/tracker/Σ.js +++ b/src/tracker/Σ.js @@ -14,38 +14,39 @@ window.DHT_ON_UNLOAD = []; // Execution -DISCORD.setupMessageUpdateCallback(channel => { - if (STATE.isTracking()){ - var info = DISCORD.getSelectedChannel(); +let ignoreMessageCallback = false; + +DISCORD.setupMessageUpdateCallback(hasMoreMessages => { + if (STATE.isTracking() && !ignoreMessageCallback){ + let info = DISCORD.getSelectedChannel(); STATE.addDiscordChannel(info.server, info.type, info.id, info.channel); - var hasUpdatedFile = STATE.addDiscordMessages(info.id, DISCORD.getMessages()); + let messages = DISCORD.getMessages(); + let hasUpdatedFile = STATE.addDiscordMessages(info.id, messages); if (SETTINGS.autoscroll){ - DOM.setTimer(() => { - var action = CONSTANTS.AUTOSCROLL_ACTION_NOTHING; + let action = CONSTANTS.AUTOSCROLL_ACTION_NOTHING; + + if (!hasUpdatedFile && !(messages.length && STATE.isMessageFresh(messages[0].id))){ + action = SETTINGS.afterSavedMsg; + } + else if (!hasMoreMessages){ + action = SETTINGS.afterFirstMsg; + } - if (!hasUpdatedFile){ - action = SETTINGS.afterSavedMsg; - } - else if (!DISCORD.hasMoreMessages()){ - action = SETTINGS.afterFirstMsg; - } - - if ((action === CONSTANTS.AUTOSCROLL_ACTION_SWITCH && !DISCORD.selectNextTextChannel()) || action === CONSTANTS.AUTOSCROLL_ACTION_PAUSE){ - STATE.toggleTracking(); - } - else{ - DISCORD.loadOlderMessages(); - } - }, 25); + if ((action === CONSTANTS.AUTOSCROLL_ACTION_SWITCH && !DISCORD.selectNextTextChannel()) || action === CONSTANTS.AUTOSCROLL_ACTION_PAUSE){ + STATE.toggleTracking(); + } + else{ + DISCORD.loadOlderMessages(); + } } } }); STATE.onStateChanged((type, enabled) => { if (type === "tracking" && enabled){ - var info = DISCORD.getSelectedChannel(); + let info = DISCORD.getSelectedChannel(); if (info){ STATE.addDiscordChannel(info.server, info.type, info.id, info.channel); @@ -57,10 +58,15 @@ STATE.onStateChanged((type, enabled) => { DISCORD.loadOlderMessages(); } else{ - var action = SETTINGS.afterFirstMsg; + let action = SETTINGS.afterFirstMsg; if ((action === CONSTANTS.AUTOSCROLL_ACTION_SWITCH && !DISCORD.selectNextTextChannel()) || action === CONSTANTS.AUTOSCROLL_ACTION_PAUSE){ - DOM.setTimer(() => STATE.toggleTracking(), 200); // give the user visual feedback after clicking the button before switching off + ignoreMessageCallback = true; + + DOM.setTimer(() => { + STATE.toggleTracking(); + ignoreMessageCallback = false; + }, 200); // give the user visual feedback after clicking the button before switching off } } }