From d1cb689b2471f7ff9d6a35f01176b475892d2204 Mon Sep 17 00:00:00 2001 From: Oliver Hamlet Date: Sun, 20 Dec 2015 14:01:05 +0000 Subject: [PATCH] Reimplement dialog helpers In a Dialog class with static members. No tests for these yet as I'm still trying to work out how best to test code that relies on the DOM and custom elements and their APIs. --- src/gui/handler.cpp | 2 +- src/gui/html/css/style.css | 2 +- .../html/elements/loot-message-dialog.html | 52 +++++++------------ src/gui/html/index.html | 1 + src/gui/html/js/dialog.js | 48 +++++++++++++++++ src/gui/html/js/events.js | 38 +++++++------- src/gui/html/js/helpers.js | 45 +++------------- src/gui/html/js/init.js | 6 +-- src/gui/html/js/l10n.js | 13 +++++ 9 files changed, 112 insertions(+), 95 deletions(-) create mode 100644 src/gui/html/js/dialog.js diff --git a/src/gui/handler.cpp b/src/gui/handler.cpp index c1bbf9b8..f62eb811 100644 --- a/src/gui/handler.cpp +++ b/src/gui/handler.cpp @@ -1108,6 +1108,6 @@ namespace loot { void Handler::SendProgressUpdate(CefRefPtr frame, const std::string& message) { BOOST_LOG_TRIVIAL(trace) << "Sending progress update: " << message; - frame->ExecuteJavaScript("showProgress('" + message + "');", frame->GetURL(), 0); + frame->ExecuteJavaScript("loot.Dialog.showProgress('" + message + "');", frame->GetURL(), 0); } } diff --git a/src/gui/html/css/style.css b/src/gui/html/css/style.css index b2875018..65380f33 100644 --- a/src/gui/html/css/style.css +++ b/src/gui/html/css/style.css @@ -35,7 +35,7 @@ html /deep/ ::-webkit-scrollbar-track { html /deep/ ::-webkit-scrollbar-thumb { background: rgba(0, 0, 0, 0.26); } -paper-button[autofocus] { +html /deep/ paper-button[autofocus] { color: #64B5F6; } .hidden { diff --git a/src/gui/html/elements/loot-message-dialog.html b/src/gui/html/elements/loot-message-dialog.html index afe1ecf5..e606a2cb 100644 --- a/src/gui/html/elements/loot-message-dialog.html +++ b/src/gui/html/elements/loot-message-dialog.html @@ -16,74 +16,62 @@ was pressed. - + + diff --git a/src/gui/html/js/dialog.js b/src/gui/html/js/dialog.js new file mode 100644 index 00000000..e83f2243 --- /dev/null +++ b/src/gui/html/js/dialog.js @@ -0,0 +1,48 @@ +'use strict'; +(function exportModule(root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define([], factory); + } else { + // Browser globals + root.loot = root.loot || {}; + root.loot.Dialog = factory(); + } +}(this, () => { + return class Dialog { + static showProgress(text) { + const progressDialog = document.getElementById('progressDialog'); + progressDialog.getElementsByTagName('p')[0].textContent = text; + if (!progressDialog.opened) { + progressDialog.showModal(); + } + } + + static closeProgress() { + const progressDialog = document.getElementById('progressDialog'); + if (progressDialog.opened) { + progressDialog.close(); + } + } + + static showMessage(title, text) { + const dialog = document.createElement('loot-message-dialog'); + dialog.setDismissable(false); + dialog.showModal(title, text); + document.body.appendChild(dialog); + } + + static askQuestion(title, text, confirmText, closeCallback) { + const dialog = document.createElement('loot-message-dialog'); + dialog.setConfirmText(confirmText); + dialog.showModal(title, text, closeCallback); + document.body.appendChild(dialog); + } + + static showNotification(text) { + const toast = document.getElementById('toast'); + toast.text = text; + toast.show(); + } + }; +})); diff --git a/src/gui/html/js/events.js b/src/gui/html/js/events.js index a064f59f..5e056f22 100644 --- a/src/gui/html/js/events.js +++ b/src/gui/html/js/events.js @@ -110,7 +110,7 @@ function onChangeGame(evt) { } /* Send off a CEF query with the folder name of the new game. */ - showProgress(loot.l10n.translate('Loading game data...')); + loot.Dialog.showProgress(loot.l10n.translate('Loading game data...')); loot.query('changeGame', evt.currentTarget.getAttribute('value')).then(function(result){ /* Filters should be re-applied on game change, except the conflicts filter. Don't need to deactivate the others beforehand. Strictly not @@ -144,7 +144,7 @@ function onChangeGame(evt) { console.log('changeGame response: ' + result); } - closeProgressDialog(); + loot.Dialog.closeProgress(); }).catch(processCefError); } function onOpenReadme(evt) { @@ -174,16 +174,16 @@ function updateMasterlistNoProgress() { /* Hack to stop cards overlapping. */ document.getElementById('main').lastElementChild.updateSize(); - toast(loot.l10n.translate('Masterlist updated to revision %s.', loot.game.masterlist.revision)); + loot.Dialog.showNotification(loot.l10n.translate('Masterlist updated to revision %s.', loot.game.masterlist.revision)); } else { - toast(loot.l10n.translate('No masterlist update was necessary.')); + loot.Dialog.showNotification(loot.l10n.translate('No masterlist update was necessary.')); } }).catch(processCefError); } function onUpdateMasterlist(evt) { - showProgress(loot.l10n.translate('Updating masterlist...')); + loot.Dialog.showProgress(loot.l10n.translate('Updating masterlist...')); updateMasterlistNoProgress().then(function(result){ - closeProgressDialog(); + loot.Dialog.closeProgress(); }).catch(processCefError); } function onSortPlugins(evt) { @@ -205,7 +205,7 @@ function onSortPlugins(evt) { promise = promise.then(updateMasterlistNoProgress()); } promise.then(function(){ - showProgress(loot.l10n.translate('Sorting plugins...')); + loot.Dialog.showProgress(loot.l10n.translate('Sorting plugins...')); loot.query('sortPlugins').then(JSON.parse).then(function(result){ if (result) { loot.game.oldLoadOrder = loot.game.plugins; @@ -251,7 +251,7 @@ function onSortPlugins(evt) { /* Disable changing game. */ document.getElementById('gameMenu').setAttribute('disabled', ''); - closeProgressDialog(); + loot.Dialog.closeProgress(); } }).catch(processCefError); }).catch(processCefError); @@ -301,16 +301,16 @@ function onRedatePlugins(evt) { return; } - showMessageDialog(loot.l10n.translate('Redate Plugins?'), loot.l10n.translate('This feature is provided so that modders using the Creation Kit may set the load order it uses. A side-effect is that any subscribed Steam Workshop mods will be re-downloaded by Steam. Do you wish to continue?'), loot.l10n.translate('Redate'), function(result){ + loot.Dialog.askQuestion(loot.l10n.translate('Redate Plugins?'), loot.l10n.translate('This feature is provided so that modders using the Creation Kit may set the load order it uses. A side-effect is that any subscribed Steam Workshop mods will be re-downloaded by Steam. Do you wish to continue?'), loot.l10n.translate('Redate'), function(result){ if (result) { loot.query('redatePlugins').then(function(response){ - toast('Plugins were successfully redated.'); + loot.Dialog.showNotification('Plugins were successfully redated.'); }).catch(processCefError); } }); } function onClearAllMetadata(evt) { - showMessageDialog('', loot.l10n.translate('Are you sure you want to clear all existing user-added metadata from all plugins?'), loot.l10n.translate('Clear'), function(result){ + loot.Dialog.askQuestion('', loot.l10n.translate('Are you sure you want to clear all existing user-added metadata from all plugins?'), loot.l10n.translate('Clear'), function(result){ if (result) { loot.query('clearAllMetadata').then(JSON.parse).then(function(result){ if (result) { @@ -332,7 +332,7 @@ function onClearAllMetadata(evt) { } }); - toast(loot.l10n.translate('All user-added metadata has been cleared.')); + loot.Dialog.showNotification(loot.l10n.translate('All user-added metadata has been cleared.')); } }).catch(processCefError); } @@ -384,7 +384,7 @@ function onCopyContent(evt) { messages: messages, plugins: plugins }).then(function(){ - toast(loot.l10n.translate("LOOT's content has been copied to the clipboard.")); + loot.Dialog.showNotification(loot.l10n.translate("LOOT's content has been copied to the clipboard.")); }).catch(processCefError); } function onCopyLoadOrder(evt) { @@ -399,7 +399,7 @@ function onCopyLoadOrder(evt) { } loot.query('copyLoadOrder', plugins).then(function(){ - toast(loot.l10n.translate("The load order has been copied to the clipboard.")); + loot.Dialog.showNotification(loot.l10n.translate("The load order has been copied to the clipboard.")); }).catch(processCefError); } function onSwitchSidebarTab(evt) { @@ -590,11 +590,11 @@ function onConflictsFilter(evt) { } function onCopyMetadata(evt) { loot.query('copyMetadata', evt.target.getName()).then(function(){ - toast(loot.l10n.translate('The metadata for "%s" has been copied to the clipboard.', evt.target.getName())); + loot.Dialog.showNotification(loot.l10n.translate('The metadata for "%s" has been copied to the clipboard.', evt.target.getName())); }).catch(processCefError); } function onClearMetadata(evt) { - showMessageDialog('', loot.l10n.translate('Are you sure you want to clear all existing user-added metadata from "%s"?', evt.target.getName()), loot.l10n.translate('Clear'), function(result){ + loot.Dialog.askQuestion('', loot.l10n.translate('Are you sure you want to clear all existing user-added metadata from "%s"?', evt.target.getName()), loot.l10n.translate('Clear'), function(result){ if (result) { loot.query('clearPluginMetadata', evt.target.getName()).then(JSON.parse).then(function(result){ if (result) { @@ -613,7 +613,7 @@ function onClearMetadata(evt) { break; } } - toast(loot.l10n.translate('The user-added metadata for "%s" has been cleared.', evt.target.getName())); + loot.Dialog.showNotification(loot.l10n.translate('The user-added metadata for "%s" has been cleared.', evt.target.getName())); /* Now perform search again. If there is no current search, this won't do anything. */ document.getElementById('searchBar').search(); @@ -649,7 +649,7 @@ function onJumpToGeneralInfo(evt) { } function onContentRefresh(evt) { /* Send a query for updated load order and plugin header info. */ - showProgress(loot.l10n.translate('Refreshing data...')); + loot.Dialog.showProgress(loot.l10n.translate('Refreshing data...')); loot.query('getGameData').then(function(result){ /* Parse the data sent from C++. */ try { @@ -711,7 +711,7 @@ function onContentRefresh(evt) { /* Reapply filters. */ setFilteredUIData(); - closeProgressDialog(); + loot.Dialog.closeProgress(); }).catch(processCefError); } function onSearchOpen(evt) { diff --git a/src/gui/html/js/helpers.js b/src/gui/html/js/helpers.js index 23bec811..398492a0 100644 --- a/src/gui/html/js/helpers.js +++ b/src/gui/html/js/helpers.js @@ -4,8 +4,8 @@ function processCefError(err) { info than just the error message. Also, this can be used to catch any promise errors, not just CEF errors. */ console.log(err.stack); - closeProgressDialog(); - showMessageBox(loot.l10n.translate('Error'), err.message); + loot.Dialog.closeProgress(); + loot.Dialog.showMessage(loot.l10n.translate('Error'), err.message); } function showElement(element) { @@ -18,41 +18,8 @@ function hideElement(element) { element.classList.toggle('hidden', true); } } -function toast(text) { - var toast = document.getElementById('toast'); - toast.text = text; - toast.show(); -} -function showMessageDialog(title, text, positiveText, closeCallback) { - var dialog = document.createElement('loot-message-dialog'); - dialog.setButtonText(positiveText, loot.l10n.translate('Cancel')); - dialog.showModal(title, text, closeCallback); - document.body.appendChild(dialog); -} -function showMessageBox(title, text) { - var dialog = document.createElement('loot-message-dialog'); - dialog.setButtonText(loot.l10n.translate('OK')); - dialog.showModal(title, text); - document.body.appendChild(dialog); -} - -function showProgress(message) { - var progressDialog = document.getElementById('progressDialog'); - if (message) { - progressDialog.getElementsByTagName('p')[0].textContent = message; - } - if (!progressDialog.opened) { - progressDialog.showModal(); - } -} -function closeProgressDialog() { - var progressDialog = document.getElementById('progressDialog'); - if (progressDialog.opened) { - progressDialog.close(); - } -} function handleUnappliedChangesClose(change) { - showMessageDialog('', loot.l10n.translate('You have not yet applied or cancelled your %s. Are you sure you want to quit?', change), loot.l10n.translate('Quit'), function(result){ + loot.Dialog.askQuestion('', loot.l10n.translate('You have not yet applied or cancelled your %s. Are you sure you want to quit?', change), loot.l10n.translate('Quit'), function(result){ if (result) { /* Cancel any sorting and close any editors. Cheat by sending a cancelSort query for as many times as necessary. */ @@ -77,7 +44,7 @@ function getConflictingPlugins(pluginName) { } /* Now get conflicts for the plugin. */ - showProgress(loot.l10n.translate('Checking if plugins have been loaded...')); + loot.Dialog.showProgress(loot.l10n.translate('Checking if plugins have been loaded...')); return loot.query('getConflictingPlugins', pluginName).then(JSON.parse).then((result) => { if (result) { @@ -100,10 +67,10 @@ function getConflictingPlugins(pluginName) { } } } - closeProgressDialog(); + loot.Dialog.closeProgress(); return conflicts; } - closeProgressDialog(); + loot.Dialog.closeProgress(); return [pluginName]; }).catch(processCefError); } diff --git a/src/gui/html/js/init.js b/src/gui/html/js/init.js index 8d02243f..f55eb924 100644 --- a/src/gui/html/js/init.js +++ b/src/gui/html/js/init.js @@ -146,7 +146,7 @@ function initVars() { loot.query('getSettings'), ]; - showProgress('Initialising user interface...'); + loot.Dialog.showProgress('Initialising user interface...'); Promise.all(parallelPromises).then(function(results) { try { loot.gameTypes = JSON.parse(results[0]); @@ -197,7 +197,7 @@ function initVars() { }).then(function(){ if (result) { return new Promise(function(resolve, reject){ - closeProgressDialog(); + loot.Dialog.closeProgress(); document.getElementById('settingsButton').click(); resolve(''); }); @@ -214,7 +214,7 @@ function initVars() { setTimeout(function() { document.getElementById('cardsNav').updateSize(); - closeProgressDialog(); + loot.Dialog.closeProgress(); }, 100); return ''; diff --git a/src/gui/html/js/l10n.js b/src/gui/html/js/l10n.js index 80eeebb7..ca3ff8f2 100644 --- a/src/gui/html/js/l10n.js +++ b/src/gui/html/js/l10n.js @@ -106,6 +106,18 @@ pluginItem.getElementById('editorIsOpenTooltip').textContent = l10n.translate('Editor Is Open'); } + function translateMessageDialogTemplate(l10n) { + /* Plugin List Item Template */ + let messageDialog = document.querySelector('link[rel="import"][href$="loot-message-dialog.html"]'); + if (messageDialog) { + messageDialog = messageDialog.import.querySelector('template').content; + } else { + messageDialog = document.querySelector('polymer-element[name="loot-message-dialog"]').querySelector('template').content; + } + messageDialog.getElementById('confirm').textContent = l10n.translate('OK'); + messageDialog.getElementById('dismiss').textContent = l10n.translate('Cancel'); + } + function translateFileRowTemplate(l10n) { /* File row template */ let fileRow = document.querySelector('link[rel="import"][href$="editable-table.html"]'); @@ -312,6 +324,7 @@ translatePluginCardTemplate(l10n); translatePluginEditorTemplate(l10n); translatePluginListItemTemplate(l10n); + translateMessageDialogTemplate(l10n); translateFileRowTemplate(l10n); translateMessageRowTemplate(l10n);