Settings dialog improvements.

* Game name, type and folder are read-only to prevent issues identifying
a game and with desync of behaviours.
* Cancelling the dialog resets the its controls' values.
* Applying the dialog updates the JS settings vars, and sends them to
C++. It also updates the game menu contents.
* The current game can no longer be deleted.
* Added masterlist update setting control.
This commit is contained in:
WrinklyNinja
2014-08-15 16:01:47 +01:00
parent c7a479e661
commit cb2763e546
3 changed files with 133 additions and 60 deletions
+40 -9
View File
@@ -178,7 +178,7 @@ var pluginCardProto = Object.create(HTMLElement.prototype, {
var tables = this.shadowRoot.getElementsByTagName('table');
for (var j = 0; j < tables.length; ++j) {
var rowsData = tables[j].getWritableRowData();
var rowsData = tables[j].getRowsData(true);
if (rowsData.length > 0) {
if (tables[j].id == 'loadAfter') {
plugin.userlist.after = rowsData;
@@ -729,15 +729,14 @@ var MessageDialog = document.registerElement('message-dialog', {
/* Create a <editable-table> element type that extends from <table>. */
var EditableTableProto = Object.create(HTMLTableElement.prototype, {
getWritableRowData: {
value: function() {
getRowsData: {
value: function(writableOnly) {
var writableRows = [];
var rows = this.getElementsByTagName('tbody')[0].getElementsByTagName('tr');
for (var i = 0; i < rows.length; ++i) {
var trash = rows[i].getElementsByClassName('fa-trash-o');
if (trash.length > 0 && !trash[0].classList.contains('hidden')) {
if (trash.length > 0 && (!writableOnly || !trash[0].classList.contains('hidden'))) {
var rowData = {};
var inputs = rows[i].getElementsByTagName('input');
@@ -759,17 +758,49 @@ var EditableTableProto = Object.create(HTMLTableElement.prototype, {
},
setReadOnly: {
value: function(row) {
row.getElementsByClassName('fa-trash-o')[0].classList.toggle('hidden');
value: function(row, classMask, readOnly) {
if (readOnly == undefined) {
readOnly = true;
}
var trash = row.getElementsByClassName('fa-trash-o')[0];
if (classMask) {
for (var i = 0; i < classMask.length; ++i) {
if (trash.classList.contains(classMask[i])) {
trash.classList.toggle('hidden', readOnly);
break;
}
}
} else {
trash.classList.toggle('hidden', readOnly);
}
var inputs = row.getElementsByTagName('input');
for (var i = 0; i < inputs.length; ++i) {
inputs[i].setAttribute('readonly', true);
if (classMask) {
for (var j = 0; j < classMask.length; ++j) {
if (inputs[i].classList.contains(classMask[j])) {
inputs[i].setAttribute('readonly', readOnly);
break;
}
}
} else {
inputs[i].setAttribute('readonly', readOnly);
}
}
var selects = row.getElementsByTagName('select');
for (var i = 0; i < selects.length; ++i) {
selects[i].setAttribute('disabled', true);
if (classMask) {
for (var j = 0; j < classMask.length; ++j) {
if (selects[i].classList.contains(classMask[j])) {
selects[i].setAttribute('disabled', readOnly);
break;
}
}
} else {
selects[i].setAttribute('disabled', readOnly);
}
}
}
},
+91 -50
View File
@@ -230,6 +230,18 @@ function updateSelectedGame() {
} else {
document.getElementById('redatePluginsButton').classList.toggle('disabled', true);
}
/* 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 == loot.game.folder) {
document.getElementById('gameTable').setReadOnly(rows[i], ['fa-trash-o']);
} else {
document.getElementById('gameTable').setReadOnly(rows[i], ['fa-trash-o'], false);
}
}
}
}
function changeGame(evt) {
/* First store current game info in loot.games object.
@@ -501,17 +513,90 @@ function closeAboutDialog(evt) {
function showAboutDialog(evt) {
document.getElementById('about').showModal();
}
function updateSettingsUI() {
var gameSelect = document.getElementById('defaultGameSelect');
var gameMenu = document.getElementById('gameMenu').firstElementChild;
var gameTable = document.getElementById('gameTable');
/* First make sure game listing elements don't have any existing entries. */
while (gameSelect.firstElementChild) {
gameSelect.removeChild(gameSelect.firstElementChild);
}
while (gameMenu.firstElementChild) {
gameMenu.removeChild(gameMenu.firstElementChild);
}
gameTable.clear();
/* Now fill with new values. */
for (var i = 0; i < loot.settings.games.length; ++i) {
var option = document.createElement('option');
option.value = loot.settings.games[i].folder;
option.textContent = loot.settings.games[i].name;
gameSelect.appendChild(option);
var li = document.createElement('li');
li.setAttribute('data-action', 'change-game');
li.setAttribute('data-target', loot.settings.games[i].folder);
if (loot.installedGames.indexOf(loot.settings.games[i].folder) == -1) {
li.classList.toggle('disabled', true);
}
var icon = document.createElement('span');
icon.className = 'fa fa-fw';
li.appendChild(icon);
var text = document.createElement('span');
text.textContent = loot.settings.games[i].name;
li.appendChild(text);
gameMenu.appendChild(li);
var row = gameTable.addRow(loot.settings.games[i]);
gameTable.setReadOnly(row, ['name','folder','type']);
}
/* Highlight game in menu. */
updateSelectedGame();
gameSelect.value = loot.settings.game;
document.getElementById('languageSelect').value = loot.settings.language;
document.getElementById('debugVerbositySelect').value = loot.settings.debugVerbosity;
document.getElementById('updateMasterlist').checked = loot.settings.updateMasterlist;
}
function closeSettingsDialog(evt) {
if (!areSettingsValid()) {
evt.preventDefault();
return;
}
if (evt.target.returnValue == 'true') {
var dialog = evt.target.parentElement.parentElement;
if (evt.target.classList.contains('accept')) {
/* Update the JS variable values. */
var settings = {
debugVerbosity: document.getElementById('debugVerbositySelect').value,
game: document.getElementById('defaultGameSelect').value,
games: document.getElementById('gameTable').getRowsData(false),
language: document.getElementById('languageSelect').value,
lastGame: loot.game.folder,
updateMasterlist: document.getElementById('updateMasterlist').value,
};
/* Send the settings back to the C++ side. */
var request = JSON.stringify({
name: 'closeSettings',
args: [
settings
]
});
loot.query(request).catch(processCefError);
loot.settings = settings;
} else {
/* Re-apply the existing settings to the settings dialog elements. */
updateSettingsUI();
}
dialog.close();
}
function showSettingsDialog(evt) {
@@ -623,18 +708,10 @@ function setupEventHandlers() {
/* Set up event handlers for settings dialog. */
var settings = document.getElementById('settings');
settings.addEventListener('close', closeSettingsDialog, false);
settings.addEventListener('cancel', closeSettingsDialog, false);
settings.getElementsByClassName('accept')[0].addEventListener('click', function(evt){
evt.target.parentElement.parentElement.close(true);
}, false);
settings.getElementsByClassName('cancel')[0].addEventListener('click', function(evt){
evt.target.parentElement.parentElement.close(false);
}, false);
settings.getElementsByClassName('accept')[0].addEventListener('click', closeSettingsDialog, false);
settings.getElementsByClassName('cancel')[0].addEventListener('click', closeSettingsDialog, false);
/* Set up about dialog handlers. */
document.getElementById('about').getElementsByTagName('button')[0].addEventListener('click', closeAboutDialog, false);
@@ -727,43 +804,7 @@ function initVars() {
console.log('getSettings response: ' + results[3]);
}
/* Now fill game lists/table. */
var gameSelect = document.getElementById('defaultGameSelect');
var gameMenu = document.getElementById('gameMenu').firstElementChild;
var gameTable = document.getElementById('gameTable');
for (var i = 0; i < loot.settings.games.length; ++i) {
var option = document.createElement('option');
option.value = loot.settings.games[i].folder;
option.textContent = loot.settings.games[i].name;
gameSelect.appendChild(option);
var li = document.createElement('li');
li.setAttribute('data-action', 'change-game');
li.setAttribute('data-target', loot.settings.games[i].folder);
if (loot.installedGames.indexOf(loot.settings.games[i].folder) == -1) {
li.classList.toggle('disabled', true);
}
var icon = document.createElement('span');
icon.className = 'fa fa-fw';
li.appendChild(icon);
var text = document.createElement('span');
text.textContent = loot.settings.games[i].name;
li.appendChild(text);
gameMenu.appendChild(li);
gameTable.addRow(loot.settings.games[i]);
}
/* Highlight game in menu. */
updateSelectedGame();
gameSelect.value = loot.settings.game;
document.getElementById('languageSelect').value = loot.settings.language;
document.getElementById('debugVerbositySelect').value = loot.settings.debugVerbosity;
updateSettingsUI();
}).catch(processCefError);
}
+2 -1
View File
@@ -530,7 +530,8 @@ along with LOOT. If not, see &lt;http://www.gnu.org/licenses/&gt;.
<!-- Game rows go here. -->
<tr><td colspan="4">Add new row...</td><td></td></tr>
</table>
<p>Language and game changes will be applied after LOOT is restarted.
<p><input type="checkbox" id="updateMasterlist"><label for="updateMasterlist">Update masterlist before sorting</label>
<p>Language changes will be applied after LOOT is restarted.
<hr>
<div class="buttons">
<button class="accept">Apply</button>