diff --git a/src/renderer/index.html b/src/renderer/index.html index 6dd5e42..f3b7210 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -31,12 +31,6 @@ - -
- -
+
+ +
+ +
+ +
+ +
+
diff --git a/src/renderer/scr.exec.js b/src/renderer/scr.exec.js index a8f3738..a2eb858 100644 --- a/src/renderer/scr.exec.js +++ b/src/renderer/scr.exec.js @@ -26,14 +26,18 @@ document.addEventListener("DOMContentLoaded", () => { STATE.setMessagesPerPage(GUI.getOptionMessagesPerPage()); - GUI.onOptionMessagesByUserChanged(() => { - STATE.setMessagesByUser(GUI.getOptionMessagesByUser()); + GUI.onOptMessageFilterChanged(filter => { + STATE.setActiveFilter(filter); }); - + GUI.onNavigationButtonClicked(action => { STATE.updateCurrentPage(action); }); + STATE.onUsersRefreshed(users => { + GUI.updateUserList(users); + }); + STATE.onChannelsRefreshed(channels => { GUI.updateChannelList(channels, STATE.selectChannel); }); @@ -43,8 +47,4 @@ document.addEventListener("DOMContentLoaded", () => { GUI.updateMessageList(messages); GUI.scrollMessagesToTop(); }); - - STATE.onUsersRefreshed(users => { - GUI.updateUserFilter(users); - }); }); diff --git a/src/renderer/scr.gui.js b/src/renderer/scr.gui.js index fa4548e..5674c18 100644 --- a/src/renderer/scr.gui.js +++ b/src/renderer/scr.gui.js @@ -1,9 +1,22 @@ var GUI = (function(){ var eventOnFileUploaded; var eventOnOptMessagesPerPageChanged; - var eventOnOptMessagesByUserChanged; + var eventOnOptMessageFilterChanged; var eventOnNavButtonClicked; + var getActiveFilter = function(){ + var active = DOM.fcls("active", DOM.id("opt-filter-list")); + + return active && active.value !== "" ? { + "type": active.getAttribute("data-filter-type"), + "value": active.value + } : null; + }; + + var triggerFilterChanged = function(){ + eventOnOptMessageFilterChanged && eventOnOptMessageFilterChanged(getActiveFilter()); + }; + var showModal = function(width, html){ var dialog = DOM.id("dialog"); dialog.innerHTML = html; @@ -59,6 +72,8 @@ var GUI = (function(){ */ setup: function(){ var inputUploadedFile = DOM.id("uploaded-file"); + var inputMessageFilter = DOM.id("opt-messages-filter"); + var containerFilterList = DOM.id("opt-filter-list"); DOM.id("btn-upload-file").addEventListener("click", () => { inputUploadedFile.click(); @@ -67,16 +82,31 @@ var GUI = (function(){ inputUploadedFile.addEventListener("change", () => { if (eventOnFileUploaded && eventOnFileUploaded(inputUploadedFile.files)){ inputUploadedFile.value = null; + + inputMessageFilter.value = ""; + inputMessageFilter.dispatchEvent(new Event("change")); } }); + inputMessageFilter.value = ""; // required to prevent browsers from remembering old value + + inputMessageFilter.addEventListener("change", () => { + DOM.cls("active", containerFilterList).forEach(ele => ele.classList.remove("active")); + + if (inputMessageFilter.value){ + containerFilterList.querySelector("[data-filter-type='"+inputMessageFilter.value+"']").classList.add("active"); + } + + triggerFilterChanged(); + }); + + Array.prototype.forEach.call(containerFilterList.children, ele => { + ele.addEventListener("change", e => triggerFilterChanged()); + }); + DOM.id("opt-messages-per-page").addEventListener("change", () => { eventOnOptMessagesPerPageChanged && eventOnOptMessagesPerPageChanged(); }); - - DOM.id("opt-messages-by-user").addEventListener("change", () => { - eventOnOptMessagesByUserChanged && eventOnOptMessagesByUserChanged(); - }); DOM.tag("button", DOM.fcls("nav")).forEach(button => { button.disabled = true; @@ -119,10 +149,10 @@ var GUI = (function(){ }, /* - * Sets a callback for when the user changes the messages by user option. The callback is not passed any arguments. + * Sets a callback for when the user changes the active filter. The callback is passed either null or an object such as { type: , value: }. */ - onOptionMessagesByUserChanged: function(callback){ - eventOnOptMessagesByUserChanged = callback; + onOptMessageFilterChanged: function(callback){ + eventOnOptMessageFilterChanged = callback; }, /* @@ -142,13 +172,6 @@ var GUI = (function(){ getOptionMessagesPerPage: function(){ return parseInt(DOM.id("opt-messages-per-page").value, 10); }, - - /* - * Returns the user which to filter messages by. - */ - getOptionMessagesByUser: function(){ - return DOM.id("opt-messages-by-user").value; - }, /* * Updates the navigation text and buttons. @@ -163,9 +186,9 @@ var GUI = (function(){ DOM.id("nav-last").disabled = currentPage === (totalPages || 1); }, - // ------------ - // Channel list - // ------------ + // -------------- + // Updating lists + // -------------- /* * Updates the channel list and sets up their click events. The callback is triggered whenever a channel is selected, and takes the channel ID as its argument. @@ -177,7 +200,11 @@ var GUI = (function(){ eleChannels.innerHTML = ""; } else{ - eleChannels.innerHTML = channels.filter(channel => channel.msgcount > 0).map(channel => DISCORD.getChannelHTML(channel)).join(""); + if (getActiveFilter() != null){ + channels = channels.filter(channel => channel.msgcount > 0); + } + + eleChannels.innerHTML = channels.map(channel => DISCORD.getChannelHTML(channel)).join(""); Array.prototype.forEach.call(eleChannels.children, ele => { ele.addEventListener("click", e => { @@ -206,31 +233,26 @@ var GUI = (function(){ }, /* - * Updates the select box with all possibly user names. + * Updates the user filter list. */ - updateUserFilter: function(users){ - var select = DOM.id("opt-messages-by-user"); - - // Remove all but first option - for (var i = select.length; i > 0; i--) { - select.remove(i); + updateUserList: function(users){ + var eleSelect = DOM.id("opt-filter-user"); + + while(eleSelect.length > 1){ + eleSelect.remove(1); } - + var options = []; - for (var key in users) { - // Skip loop if the property is from prototype - if (!users.hasOwnProperty(key)) continue; - + + for(var key of Object.keys(users)){ var option = document.createElement("option"); option.value = key; option.text = users[key].name; options.push(option); } - options.sort((a, b) => { - return a.text.toLowerCase().localeCompare(b.text.toLowerCase()); - }).forEach(option => { - select.add(option); - }); + + options.sort((a, b) => a.text.toLocaleLowerCase().localeCompare(b.text.toLocaleLowerCase())); + options.forEach(option => eleSelect.add(option)); }, /* diff --git a/src/renderer/scr.savefile.js b/src/renderer/scr.savefile.js index e4e85da..9165d0b 100644 --- a/src/renderer/scr.savefile.js +++ b/src/renderer/scr.savefile.js @@ -26,6 +26,10 @@ SAVEFILE.prototype.getChannelById = function(channel){ return this.meta.channels[channel] || { "id": channel, "name": channel }; }; +SAVEFILE.prototype.getUsers = function(){ + return this.meta.users; +}; + SAVEFILE.prototype.getUser = function(index){ return this.meta.users[this.meta.userindex[index]] || { "name": "<unknown>" }; }; @@ -34,20 +38,6 @@ SAVEFILE.prototype.getUserById = function(user){ return this.meta.users[user] || { "name": user }; }; -SAVEFILE.prototype.getMessageCount = function(channel){ - return Object.keys(this.getMessages(channel)).length; -}; - -SAVEFILE.prototype.getFilteredMessageCount = function(channel, userindex){ - if (userindex === -1) return this.getMessageCount(channel); - - var count = 0; - UTILS.forEachValue(this.getMessages(channel), messageObject => { - if (messageObject.u === userindex) count++; - }); - return count; -}; - SAVEFILE.prototype.getAllMessages = function(){ var messages = {}; @@ -56,6 +46,8 @@ SAVEFILE.prototype.getAllMessages = function(){ }); return messages; +SAVEFILE.prototype.getUserIndex = function(user){ + return this.meta.userindex.indexOf(user); }; SAVEFILE.prototype.getMessages = function(channel){ diff --git a/src/renderer/scr.state.js b/src/renderer/scr.state.js index a118135..523fbe3 100644 --- a/src/renderer/scr.state.js +++ b/src/renderer/scr.state.js @@ -11,7 +11,7 @@ var STATE = (function(){ var selectedChannel; var currentPage; var messagesPerPage; - var messagesByUser; + var filterFunction; // ---------------------------------- // Channel and message refresh events @@ -53,10 +53,10 @@ var STATE = (function(){ FILE = file; MSGS = null; currentPage = 1; - + + triggerUsersRefreshed(); triggerChannelsRefreshed(); triggerMessagesRefreshed(); - triggerUsersRefreshed(); }; ROOT.getChannelName = function(channel){ @@ -74,24 +74,34 @@ var STATE = (function(){ // -------------------------- // Channel list and selection // -------------------------- + + var getFilteredMessageKeys = function(channel){ + var messages = FILE.getMessages(channel); + var keys = Object.keys(messages); + + if (filterFunction){ + keys = keys.filter(key => filterFunction(messages[key])); + } + + return keys; + }; ROOT.getChannelList = function(){ var channels = FILE.getChannels(); - var userindex = messagesByUser ? FILE.meta.userindex.indexOf(messagesByUser) : -1; return Object.keys(channels).map(key => ({ "id": key, "name": channels[key].name, "server": FILE.getServer(channels[key].server), - "msgcount": FILE.getFilteredMessageCount(key, userindex) + "msgcount": getFilteredMessageKeys(key).length })); }; ROOT.selectChannel = function(channel){ currentPage = 1; selectedChannel = channel; - MSGS = Object.keys(FILE.getMessages(channel)).sort(PROCESSOR.SORTER.oldestToNewest); - + + MSGS = getFilteredMessageKeys(channel).sort(PROCESSOR.SORTER.oldestToNewest); triggerMessagesRefreshed(); }; @@ -102,19 +112,6 @@ var STATE = (function(){ // ------------ // Message list // ------------ - ROOT.getFilteredMessageList = function(){ - if (!messagesByUser) { - return MSGS; - } - - var pos = FILE.meta.userindex.indexOf(messagesByUser); - var messages = FILE.getMessages(selectedChannel); - return MSGS.filter(key => { - var message = messages[key]; - return message.u == pos; - }); - }; - ROOT.getMessageList = function(){ if (!MSGS){ @@ -124,7 +121,7 @@ var STATE = (function(){ var messages = FILE.getMessages(selectedChannel); var startIndex = messagesPerPage*(ROOT.getCurrentPage()-1); - return ROOT.getFilteredMessageList().slice(startIndex, !messagesPerPage ? undefined : startIndex+messagesPerPage).map(key => { + return MSGS.slice(startIndex, !messagesPerPage ? undefined : startIndex+messagesPerPage).map(key => { var message = messages[key]; return { @@ -137,24 +134,32 @@ var STATE = (function(){ }; }); }; - - ROOT.getUserList = function(){ - if (!FILE){ - return []; - } - - return FILE.meta.users; - }; // ---------- // Filtering // ---------- + + ROOT.setActiveFilter = function(filter){ + switch(filter ? filter.type : ""){ + case "user": + filterFunction = PROCESSOR.FILTER.byUser(FILE.getUserIndex(filter.value)); + break; - ROOT.setMessagesByUser = function(key){ - currentPage = 1; - messagesByUser = key; + default: + filterFunction = null; + break; + } + triggerChannelsRefreshed(); - triggerMessagesRefreshed(); + ROOT.selectChannel(selectedChannel); // resets current page and updates messages + }; + + // ----- + // Users + // ----- + + ROOT.getUserList = function(){ + return FILE ? FILE.getUsers() : []; }; // ---------- @@ -188,7 +193,7 @@ var STATE = (function(){ }; ROOT.getPageCount = function(){ - return !MSGS ? 0 : (!messagesPerPage ? 1 : Math.ceil(ROOT.getFilteredMessageList().length/messagesPerPage)); + return !MSGS ? 0 : (!messagesPerPage ? 1 : Math.ceil(MSGS.length/messagesPerPage)); }; // -------- diff --git a/src/renderer/stl.menu.css b/src/renderer/stl.menu.css index 7904667..09816c8 100644 --- a/src/renderer/stl.menu.css +++ b/src/renderer/stl.menu.css @@ -60,3 +60,11 @@ #menu .nav > button, #menu .nav > p { margin: 8px 1px; } + +#opt-filter-list > select, #opt-filter-list > input { + display: none; +} + +#opt-filter-list > .active { + display: block; +}