diff --git a/resources/report/js/script.js b/resources/report/js/script.js index 80a28cdc..0e112e73 100644 --- a/resources/report/js/script.js +++ b/resources/report/js/script.js @@ -31,7 +31,112 @@ var loot = { folder: '', globalMessages: [], masterlist: {}, - plugins: [] + plugins: [], + + /* Call whenever game is changed or game menu / game table are rewritten. */ + updateSelectedGame: function() { + /* Highlight game in menu. Could use fa-chevron-right instead. */ + var gameMenuItems = document.getElementById('gameMenu').children[0].children; + for (var i = 0; i < gameMenuItems.length; ++i) { + if (gameMenuItems[i].getAttribute('data-folder') == this.folder) { + gameMenuItems[i].getElementsByClassName('fa')[0].classList.toggle('fa-angle-double-right', true); + } else { + gameMenuItems[i].getElementsByClassName('fa')[0].classList.toggle('fa-angle-double-right', false); + } + } + + /* Also disable deletion of the game's row in the settings dialog. */ + var rows = document.getElementById('gameTable').getElementsByTagName('tbody')[0].getElementsByTagName('tr'); + for (var i = 0; i < rows.length; ++i) { + if (rows[i].getElementsByClassName('folder').length > 0) { + if (rows[i].getElementsByClassName('folder')[0].value == this.folder) { + document.getElementById('gameTable').setReadOnly(rows[i], ['fa-trash-o']); + } else { + document.getElementById('gameTable').setReadOnly(rows[i], ['fa-trash-o'], false); + } + } + } + }, + + /* Call whenever game is changed. */ + updateRedatePluginsButtonState: function() { + /* Also enable/disable the redate plugins option. */ + var index = undefined; + for (var i = 0; i < loot.settings.games.length; ++i) { + if (loot.settings.games[i].folder == this.folder) { + index = i; + break; + } + } + if (index != undefined && loot.settings.games[index].type == 'Skyrim') { + document.getElementById('redatePluginsButton').classList.toggle('disabled', false); + } else { + document.getElementById('redatePluginsButton').classList.toggle('disabled', true); + } + }, + + pluginsObserver: function(changes) { + changes.forEach(function(change){ + /* Need to handle plugin addition and removal. + Update plugin and message counts. */ + var totalChange = 0; + var warnChange = 0; + var errorChange = 0; + var activeChange = 0; + var dirtyChange = 0; + + if (change.addedCount > 0) { + /* Addition */ + for (var i = change.index; i < change.index + change.addedCount; ++i) { + if (change.object[i].isActive) { + ++activeChange; + } + if (change.object[i].isDirty) { + ++dirtyChange; + } + if (change.object[i].messages) { + totalChange += change.object[i].messages.length; + change.object[i].messages.forEach(function(message) { + if (message.type == 'warn') { + ++warnChange; + } else if (message.type == 'error') { + ++errorChange; + } + }); + } + } + } + if (change.removed.length > 0) { + /* Removal */ + change.removed.forEach(function(plugin){ + if (plugin.isActive) { + --activeChange; + } + if (plugin.isDirty) { + --dirtyChange; + } + if (plugin.messages) { + totalChange -= plugin.messages.length; + plugin.messages.forEach(function(message) { + if (message.type == 'warn') { + --warnChange; + } else if (message.type == 'error') { + --errorChange; + } + }); + } + }); + } + document.getElementById('filterTotalMessageNo').textContent = parseInt(document.getElementById('filterTotalMessageNo').textContent, 10) + totalChange; + document.getElementById('totalMessageNo').textContent = document.getElementById('filterTotalMessageNo').textContent; + document.getElementById('totalWarningNo').textContent = parseInt(document.getElementById('totalWarningNo').textContent, 10) + warnReduction; + document.getElementById('totalErrorNo').textContent = parseInt(document.getElementById('totalErrorNo').textContent, 10) + errorReduction; + document.getElementById('filterTotalPluginNo').textContent = parseInt(document.getElementById('filterTotalPluginNo').textContent, 10) + change.addedCount - change.removed.length; + document.getElementById('totalPluginNo').textContent = document.getElementById('filterTotalPluginNo').textContent; + document.getElementById('activePluginNo').textContent = parseInt(document.getElementById('activePluginNo').textContent, 10) + activeReduction; + document.getElementById('dirtyPluginNo').textContent = parseInt(document.getElementById('dirtyPluginNo').textContent, 10) + dirtyReduction; + }); + } }, /* Call whenever installedGames is changed or game menu is rewritten. */ @@ -49,48 +154,6 @@ var loot = { } }, - /* Call whenever game is changed or game menu / game table are rewritten. */ - updateSelectedGame: function() { - /* Highlight game in menu. Could use fa-chevron-right instead. */ - var gameMenuItems = document.getElementById('gameMenu').children[0].children; - for (var i = 0; i < gameMenuItems.length; ++i) { - if (gameMenuItems[i].getAttribute('data-folder') == this.game.folder) { - gameMenuItems[i].getElementsByClassName('fa')[0].classList.toggle('fa-angle-double-right', true); - } else { - gameMenuItems[i].getElementsByClassName('fa')[0].classList.toggle('fa-angle-double-right', false); - } - } - - /* Also disable deletion of the game's row in the settings dialog. */ - var rows = document.getElementById('gameTable').getElementsByTagName('tbody')[0].getElementsByTagName('tr'); - for (var i = 0; i < rows.length; ++i) { - if (rows[i].getElementsByClassName('folder').length > 0) { - if (rows[i].getElementsByClassName('folder')[0].value == this.game.folder) { - document.getElementById('gameTable').setReadOnly(rows[i], ['fa-trash-o']); - } else { - document.getElementById('gameTable').setReadOnly(rows[i], ['fa-trash-o'], false); - } - } - } - }, - - /* Call whenever game is changed. */ - updateRedatePluginsButtonState: function() { - /* Also enable/disable the redate plugins option. */ - var index = undefined; - for (var i = 0; i < this.settings.games.length; ++i) { - if (this.settings.games[i].folder == this.game.folder) { - index = i; - break; - } - } - if (index != undefined && this.settings.games[index].type == 'Skyrim') { - document.getElementById('redatePluginsButton').classList.toggle('disabled', false); - } else { - document.getElementById('redatePluginsButton').classList.toggle('disabled', true); - } - }, - /* Call whenever settings are changed. */ updateSettingsUI: function() { var gameSelect = document.getElementById('defaultGameSelect'); @@ -137,18 +200,139 @@ var loot = { document.getElementById('updateMasterlist').checked = this.settings.updateMasterlist; this.updateEnabledGames(); - this.updateSelectedGame(); + this.game.updateSelectedGame(); }, + /* Observer for loot members. */ observer: function(changes) { changes.forEach(function(change){ if (change.name == 'installedGames') { change.object.updateEnabledGames(); } else if (change.name == 'settings') { change.object.updateSettingsUI(); - } else if (change.name == 'game') { + } + }); + }, + + /* Observer for loot.game members. */ + gameObserver: function(changes) { + changes.forEach(function(change){ + if (change.name == 'folder') { change.object.updateSelectedGame(); change.object.updateRedatePluginsButtonState(); + } else if (change.name == 'masterlist') { + if (change.object[change.name] && change.object[change.name].revision) { + document.getElementById('masterlistRevision').textContent = change.object[change.name].revision; + } else { + document.getElementById('masterlistRevision').textContent = 'N/A'; + } + if (change.object[change.name] && change.object[change.name].date) { + document.getElementById('masterlistDate').textContent = change.object[change.name].date; + } else { + document.getElementById('masterlistDate').textContent = 'N/A'; + } + } else if (change.name == 'globalMessages') { + /* For the messages, they don't have a JS 'class' so need to everything + here. Count up the global message types that exist, then remove them + and add the new ones, counting their types, then update the message + counts. I tried using an observer for this, but it wouldn't fire for + some reason. */ + + var oldTotal = change.oldValue.length; + var newTotal = 0; + var oldWarn = 0; + var newWarn = 0; + var oldErr = 0; + var newErr = 0; + + /* Count up old warnings and errors. */ + change.oldValue.forEach(function(message){ + if (message.type == 'warn') { + ++oldWarn; + } else if (message.type == 'error') { + ++oldErr; + } + }); + + /* Remove old messages from UI. */ + var generalMessagesList = document.getElementById('generalMessages').getElementsByTagName('ul')[0]; + while (generalMessagesList.firstElementChild) { + generalMessagesList.removeChild(generalMessagesList.firstElementChild); + } + + /* Add new messages. */ + if (change.object[change.name]) { + newTotal = change.object[change.name].length; + change.object[change.name].forEach(function(message){ + var li = document.createElement('li'); + li.className = message.type; + /* Use the Marked library for Markdown formatting support. */ + li.innerHTML = marked(message.content[0].str); + generalMessagesList.appendChild(li); + + if (li.className == 'warn') { + ++newWarn; + } else if (li.className == 'error') { + ++newErr; + } + }); + } + + /* Update message counts in UI. */ + document.getElementById('filterTotalMessageNo').textContent = parseInt(document.getElementById('filterTotalMessageNo').textContent, 10) + newTotal - oldTotal; + document.getElementById('totalMessageNo').textContent = document.getElementById('filterTotalMessageNo').textContent; + document.getElementById('totalWarningNo').textContent = parseInt(document.getElementById('totalWarningNo').textContent, 10) + newWarn - oldWarn; + document.getElementById('totalErrorNo').textContent = parseInt(document.getElementById('totalErrorNo').textContent, 10) + newErr - oldErr; + } else if (change.name == 'plugins') { + /* Update plugin and message counts. Unlike for global messages + it's not worth calculating the count differences, just count + from zero. */ + var totalMessageNo = 0; + var warnMessageNo = 0; + var errorMessageNo = 0; + var activePluginNo = 0; + var dirtyPluginNo = 0; + + if (change.object.globalMessages) { + totalMessageNo = change.object.globalMessages.length; + change.object.globalMessages.forEach(function(message){ + if (message.type == 'warn') { + ++warnMessageNo; + } else if (message.type == 'error') { + ++errorMessageNo; + } + }); + } + + change.object[change.name].forEach(function(plugin) { + if (plugin.isActive) { + ++activePluginNo; + } + if (plugin.isDirty) { + ++dirtyPluginNo; + } + if (plugin.messages) { + totalMessageNo += plugin.messages.length; + plugin.messages.forEach(function(message) { + if (message.type == 'warn') { + ++warnMessageNo; + } else if (message.type == 'error') { + ++errorMessageNo; + } + }); + } + }); + document.getElementById('filterTotalMessageNo').textContent = totalMessageNo; + document.getElementById('totalMessageNo').textContent = totalMessageNo; + document.getElementById('totalWarningNo').textContent = warnMessageNo; + document.getElementById('totalErrorNo').textContent = errorMessageNo; + document.getElementById('filterTotalPluginNo').textContent = change.object[change.name].length; + document.getElementById('totalPluginNo').textContent = change.object[change.name].length; + document.getElementById('activePluginNo').textContent = activePluginNo; + document.getElementById('dirtyPluginNo').textContent = dirtyPluginNo; + + /* Register a new array observer. */ + Array.observe(change.object[change.name], change.object.pluginsObserver); } }); }, @@ -168,6 +352,8 @@ var loot = { } }; Object.observe(loot, loot.observer); +/* Register game object observer. */ +Object.observe(loot.game, loot.gameObserver); function processCefError(err) { /* Error.stack seems to be Chromium-specific. It gives a lot more useful @@ -424,10 +610,16 @@ function changeGame(evt) { } if (index == undefined) { /* Game data not cached, simply set what was sent. */ - loot.game = gameInfo; + loot.game.folder = gameInfo.folder; + loot.game.masterlist = gameInfo.masterlist; + loot.game.globalMessages = gameInfo.globalMessages; + loot.game.plugins = gameInfo.plugins; } else { /* Game data cache exists. */ - loot.game = loot.games[i]; + loot.game.folder = loot.games[i].folder; + loot.game.masterlist = loot.games[i].masterlist; + loot.game.globalMessages = loot.games[i].globalMessages; + loot.game.plugins = loot.games[i].plugins; /* Now overwrite plugin data with the newly sent data. Also update card and li vars as they were unset when the game was switched from before. */ @@ -462,9 +654,6 @@ function changeGame(evt) { }); } - /* Now update interface for new data. */ - updateInterfaceWithGameInfo(); - /* Reapply previously active filters. */ applyFilters(); }).catch(processCefError); @@ -479,8 +668,8 @@ function updateMasterlist(evt) { } /* Update JS variables. */ - loot.game.masterlist.revision = result.masterlist.revision; - loot.game.masterlist.date = result.masterlist.date; + loot.game.masterlist = result.masterlist; + loot.game.globalMessages = result.globalMessages; result.plugins.forEach(function(plugin){ for (var i = 0; i < loot.game.plugins.length; ++i) { @@ -495,53 +684,6 @@ function updateMasterlist(evt) { } } }); - - /* For the messages, they don't have a JS 'class' so need to everything - here. Count up the global message types that exist, then remove them - and add the new ones, counting their types, then update the message - counts. I tried using an observer for this, but it wouldn't fire for - some reason. */ - - var oldTotal = loot.game.globalMessages.length; - var newTotal = result.globalMessages.length; - var oldWarn = 0; - var newWarn = 0; - var oldErr = 0; - var newErr = 0; - - loot.game.globalMessages.forEach(function(message){ - if (message.type == 'warn') { - ++oldWarn; - } else if (message.type == 'error') { - ++oldErr; - } - }); - - var generalMessagesList = document.getElementById('generalMessages').getElementsByTagName('ul')[0]; - while (generalMessagesList.firstElementChild) { - generalMessagesList.removeChild(generalMessagesList.firstElementChild); - } - - result.globalMessages.forEach(function(message){ - var li = document.createElement('li'); - li.className = message.type; - /* Use the Marked library for Markdown formatting support. */ - li.innerHTML = marked(message.content[0].str); - generalMessagesList.appendChild(li); - - if (li.className == 'warn') { - ++newWarn; - } else if (li.className == 'error') { - ++newErr; - } - }); - - document.getElementById('filterTotalMessageNo').textContent = parseInt(document.getElementById('filterTotalMessageNo').textContent, 10) + newTotal - oldTotal; - document.getElementById('totalMessageNo').textContent = parseInt(document.getElementById('totalMessageNo').textContent, 10) + newTotal - oldTotal; - document.getElementById('totalWarningNo').textContent = parseInt(document.getElementById('totalWarningNo').textContent, 10) + newWarn - oldWarn; - document.getElementById('totalErrorNo').textContent = parseInt(document.getElementById('totalErrorNo').textContent, 10) + newErr - oldErr; - - loot.game.globalMessages = result.globalMessages; }).catch(processCefError); } function sortUIElements(pluginNames) { @@ -1071,12 +1213,15 @@ function initVars() { if (results.length > 3) { try { - loot.game = JSON.parse(results[3], jsonToPlugin); + var game = JSON.parse(results[3], jsonToPlugin); + loot.game.folder = game.folder; + loot.game.masterlist = game.masterlist; + loot.game.globalMessages = game.globalMessages; + loot.game.plugins = game.plugins; } catch (e) { console.log(e); console.log('getGameData response: ' + results[3]); } - updateInterfaceWithGameInfo(); } try { @@ -1095,79 +1240,6 @@ function initVars() { }).catch(processCefError); } - -function masterlistObserver(changes) { - changes.forEach(function(change){ - if (change.name == 'revision') { - document.getElementById('masterlistRevision').textContent = change.object[change.name]; - } else if (change.name == 'date') { - document.getElementById('masterlistDate').textContent = change.object[change.name]; - } - }); -} -function updateInterfaceWithGameInfo() { - - var totalMessageNo = 0; - var warnMessageNo = 0; - var errorMessageNo = 0; - var activePluginNo = 0; - var dirtyPluginNo = 0; - - /* Fill report with data. */ - document.getElementById('masterlistRevision').textContent = loot.game.masterlist.revision; - document.getElementById('masterlistDate').textContent = loot.game.masterlist.date; - - var generalMessagesList = document.getElementById('generalMessages').getElementsByTagName('ul')[0]; - loot.game.globalMessages.forEach(function(message){ - var li = document.createElement('li'); - li.className = message.type; - /* Use the Marked library for Markdown formatting support. */ - li.innerHTML = marked(message.content[0].str); - generalMessagesList.appendChild(li); - - if (li.className == 'warn') { - ++warnMessageNo; - } else if (li.className == 'error') { - ++errorMessageNo; - } - }); - totalMessageNo = loot.game.globalMessages.length; - var pluginsList = document.getElementsByTagName('main')[0]; - var pluginsNav = document.getElementById('pluginsNav'); - loot.game.plugins.forEach(function(plugin) { - - if (plugin.isActive) { - ++activePluginNo; - } - - if (plugin.isDirty) { - ++dirtyPluginNo; - } - - if (plugin.messages && plugin.messages.length != 0) { - plugin.messages.forEach(function(message) { - - if (message.type == 'warn') { - ++warnMessageNo; - } else if (message.type == 'error') { - ++errorMessageNo; - } - ++totalMessageNo; - }); - } - }); - document.getElementById('filterTotalMessageNo').textContent = totalMessageNo; - document.getElementById('totalMessageNo').textContent = totalMessageNo; - document.getElementById('totalWarningNo').textContent = warnMessageNo; - document.getElementById('totalErrorNo').textContent = errorMessageNo; - document.getElementById('filterTotalPluginNo').textContent = loot.game.plugins.length; - document.getElementById('totalPluginNo').textContent = loot.game.plugins.length; - document.getElementById('activePluginNo').textContent = activePluginNo; - document.getElementById('dirtyPluginNo').textContent = dirtyPluginNo; - - /* Observe changes to update UI as appropriate. */ - Object.observe(loot.game.masterlist, masterlistObserver); -} function onFocus() { /* Send a query for updated load order and plugin header info. */ loot.query('getGameData').then(function(result){ @@ -1232,16 +1304,6 @@ function onFocus() { /* Now sort the cards to match the load order. */ sortUIElements(pluginNames); - /* Remove the existing messages, otherwise they'll just get added again - in the UI update. */ - var globalMessages = document.getElementById('generalMessages').getElementsByTagName('ul')[0]; - while (globalMessages.firstElementChild) { - globalMessages.removeChild(globalMessages.firstElementChild); - } - - /* Now update interface for new data. */ - updateInterfaceWithGameInfo(); - /* Reapply filters. */ applyFilters(); }).catch(processCefError);