Refactored editable table code.

This commit is contained in:
WrinklyNinja
2014-07-19 13:39:45 +01:00
parent ced73b2efc
commit ec336c6895
5 changed files with 224 additions and 198 deletions
+6 -2
View File
@@ -176,12 +176,16 @@ dialog {
max-width: 40em;
}
dialog > h1 {
font-weight: normal;
text-align: center;
}
dialog[is=message-dialog] > h1 {
margin: 0;
margin-bottom: 1em;
font-weight: normal;
display: inline-block;
text-align: left;
}
dialog > span:first-child {
dialog[is=message-dialog] > span:first-child {
font-size: 4em;
position: relative;
margin-right: 0.5em;
+169 -2
View File
@@ -25,10 +25,108 @@
/* Create a <plugin-card> element type. */
var pluginCardProto = Object.create(HTMLElement.prototype, {
showEditorTable: {
value: function(evt) {
var tableClass = evt.target.getAttribute('data-for');
var tables = evt.target.parentElement.getElementsByTagName('table');
for (var i = 0; i < tables.length; ++i) {
if (tables[i].className.indexOf(tableClass) == -1) {
hideElement(tables[i]);
} else {
showElement(tables[i]);
}
}
evt.target.parentElement.getElementsByClassName('selected')[0].classList.toggle('selected');
evt.target.classList.toggle('selected');
}
},
hideEditor: {
value: function(evt) {
var isValid = true;
if (evt.target.className.indexOf('accept') != -1) {
/* First validate table inputs. */
var inputs = evt.target.parentElement.parentElement.getElementsByTagName('input');
/* If an input is readonly, it doesn't validate, so check required / value length explicitly.
*/
for (var i = 0; i < inputs.length; ++i) {
if (inputs[i].readOnly) {
if (inputs[i].required && inputs[i].value.length == 0) {
isValid = false;
console.log(inputs[i]);
inputs[i].readOnly = false;
}
} else if (!inputs[i].checkValidity()) {
isValid = false;
console.log(inputs[i]);
}
}
}
if (isValid) {
/* Remove drag 'n' drop event handlers. */
var elements = document.getElementById('pluginsNav').children;
for (var i = 0; i < elements.length; ++i) {
elements[i].removeAttribute('draggable', true);
elements[i].removeEventListener('dragstart', handlePluginDragStart, false);
}
/* Disable priority hover in plugins list. */
document.getElementById('pluginsNav').classList.toggle('editMode', false);
/* Enable header buttons. */
document.getElementsByTagName('header')[0].classList.toggle('editMode', false);
/* Hide editor. */
evt.target.parentElement.parentElement.parentElement.classList.toggle('flip');
}
}
},
showEditor: {
value: function() {
/* Set up table tab event handlers. */
var elements = this.shadowRoot.getElementsByClassName('tableTabs')[0].children;
for (var i = 0; i < elements.length; ++i) {
if (elements[i].hasAttribute('data-for')) {
elements[i].addEventListener('click', showEditorTable, false);
}
}
/* Set up button event handlers. */
editor.getElementsByClassName('accept')[0].addEventListener('click', hideEditor, false);
editor.getElementsByClassName('cancel')[0].addEventListener('click', hideEditor, false);
/* Set up drag 'n' drop event handlers. */
elements = document.getElementById('pluginsNav').children;
for (var i = 0; i < elements.length; ++i) {
elements[i].setAttribute('draggable', true);
elements[i].addEventListener('dragstart', handlePluginDragStart, false);
}
elements = this.shadowRoot.getElementsByTagName('editable-table');
for (var i = 0; i < elements.length; ++i) {
if (elements[i].className.indexOf('loadAfter') != -1 || elements[i].className.indexOf('req') != -1 || elements[i].className.indexOf('inc') != -1) {
elements[i].addEventListener('drop', handlePluginDrop, false);
elements[i].addEventListener('dragover', handlePluginDragOver, false);
}
}
/* Enable priority hover in plugins list. */
document.getElementById('pluginsNav').classList.toggle('editMode', true);
/* Disable header buttons. */
document.getElementsByTagName('header')[0].classList.toggle('editMode', true);
/* Now show editor. */
this.classList.toggle('flip');
}
},
onMenuItemClick: {
value: function(evt) {
if (evt.target.id == 'editMetadata') {
/* Show editing controls. */
evt.target.parentElement.parentElement.parentNode.host.showEditor();
} else if (evt.target.id == 'copyMetadata') {
@@ -115,8 +213,7 @@ var PluginListItem = document.registerElement('plugin-li', {
extends: 'li'
});
/* Create a <message-dialog> element type that extends from <dialog>.
Use a data-type member on the element to style its type. */
/* Create a <message-dialog> element type that extends from <dialog>. */
var messageDialogProto = Object.create(HTMLDialogElement.prototype, {
onButtonClick: {
@@ -187,3 +284,73 @@ var MessageDialog = document.registerElement('message-dialog', {
prototype: messageDialogProto,
extends: 'dialog'
});
/* Create a <editable-table> element type that extends from <table>. */
var EditableTableProto = Object.create(HTMLTableElement.prototype, {
removeRow: {
value: function(evt) {
evt.target.parentElement.parentElement.removeChild(evt.target.parentElement);
}
},
addEmptyRow: {
value: function(evt) {
/* Create new row. */
var table = evt.currentTarget.parentElement.parentElement;
var rowTemplateId = table.getAttribute('data-template');
var content = document.getElementById(rowTemplateId).content;
var row = document.importNode(content, true);
table.getElementsByTagName('tbody')[0].insertBefore(row, evt.currentTarget);
row = evt.currentTarget.previousElementSibling;
/* Enable row editing. */
var inputs = row.getElementsByTagName('input');
for (var i = 0; i < inputs.length; ++i) {
inputs[i].removeAttribute('readonly');
inputs[i].addEventListener('dblclick', toggleInputRO, false);
}
/* Add deletion listener. */
row.getElementsByClassName('fa-trash-o')[0].addEventListener('click', this.removeRow, false);
}
},
addRow: {
value: function(tableData) {
var rowTemplateId = this.getAttribute('data-template');
var content = document.getElementById(rowTemplateId).content;
var row = document.importNode(content, true);
var tbody = this.getElementsByTagName('tbody')[0];
tbody.insertBefore(row, tbody.lastElementChild);
row = tbody.lastElementChild.previousElementSibling;
/* Data is an object with keys that match element class names. */
for (var key in tableData) {
row.getElementsByClassName(key)[0].value = tableData[key];
}
/* Enable row editing. */
var inputs = row.getElementsByTagName('input');
for (var i = 0; i < inputs.length; ++i) {
inputs[i].addEventListener('dblclick', toggleInputRO, false);
}
/* Add deletion listener. */
row.getElementsByClassName('fa-trash-o')[0].addEventListener('click', this.removeRow, false);
}
},
createdCallback: {
value: function() {
/* Add new row listener. */
this.querySelector('tbody tr:last-child').addEventListener('dblclick', this.addEmptyRow, false);
}
},
});
var EditableTable = document.registerElement('editable-table', {
prototype: EditableTableProto,
extends: 'table'
});
+6
View File
@@ -130,6 +130,12 @@ function Plugin(obj) {
card.shadowRoot.querySelector('#editor .crc').textContent = this.crc;
}
/* Fill in editor table data. */
var tables = card.shadowRoot.getElementsByTagName('editable-table');
for (var i = 0; i < tables.length; ++i) {
}
document.getElementById('main').appendChild(card);
}
+2 -170
View File
@@ -230,116 +230,7 @@ function clearMetadata(evt) {
var filename = evt.target.getAttribute('data-target');
showMessageDialog('Clear Plugin Metadata', 'Are you sure you want to clear all existing user-added metadata from "' + filename + '"?');
}
function removeTableRow(evt) {
evt.target.parentElement.parentElement.removeChild(evt.target.parentElement);
}
function addNewTableRow(evt) {
/* Create new row. */
var tableBody = evt.currentTarget.parentElement;
var rowTemplateId = tableBody.getAttribute('data-template');
var content = document.getElementById(rowTemplateId).content;
var row = document.importNode(content, true);
tableBody.insertBefore(row, evt.currentTarget);
row = evt.currentTarget.previousElementSibling;
/* Enable row editing. */
var inputs = row.getElementsByTagName('input');
for (var i = 0; i < inputs.length; ++i) {
inputs[i].removeAttribute('readonly');
inputs[i].addEventListener('dblclick', toggleInputRO, false);
}
/* Add deletion listener. */
row.getElementsByClassName('fa-trash-o')[0].addEventListener('click', removeTableRow, false);
}
function addTableRow(tableBody, tableData) {
var rowTemplateId = tableBody.getAttribute('data-template');
var content = document.getElementById(rowTemplateId).content;
var row = document.importNode(content, true);
tableBody.insertBefore(row, tableBody.lastElementChild);
row = tableBody.lastElementChild.previousElementSibling;
/* Data is an object with keys that match element class names. */
for (var key in tableData) {
row.getElementsByClassName(key)[0].value = tableData[key];
}
/* Enable row editing. */
var inputs = row.getElementsByTagName('input');
for (var i = 0; i < inputs.length; ++i) {
inputs[i].addEventListener('dblclick', toggleInputRO, false);
}
/* Add deletion listener. */
row.getElementsByClassName('fa-trash-o')[0].addEventListener('click', removeTableRow, false);
}
function setupTable(tableBody) {
/* Add "add new row" row. */
var tr = document.createElement('tr');
var td = document.createElement('td');
var td2 = document.createElement('td');
td.textContent = 'Add new row...';
td.setAttribute('colspan', 4);
tr.appendChild(td);
tr.appendChild(td2);
tableBody.appendChild(tr);
/* Add new row listener. */
tr.addEventListener('dblclick', addNewTableRow, false);
}
function showEditorTable(evt) {
var tableClass = evt.target.getAttribute('data-for');
var tables = evt.target.parentElement.getElementsByTagName('table');
for (var i = 0; i < tables.length; ++i) {
if (tables[i].className.indexOf(tableClass) == -1) {
hideElement(tables[i]);
} else {
showElement(tables[i]);
}
}
evt.target.parentElement.getElementsByClassName('selected')[0].classList.toggle('selected');
evt.target.classList.toggle('selected');
}
function hideEditor(evt) {
var isValid = true;
if (evt.target.className.indexOf('accept') != -1) {
/* First validate table inputs. */
var inputs = evt.target.parentElement.parentElement.getElementsByTagName('input');
/* If an input is readonly, it doesn't validate, so check required / value length explicitly.
*/
for (var i = 0; i < inputs.length; ++i) {
if (inputs[i].readOnly) {
if (inputs[i].required && inputs[i].value.length == 0) {
isValid = false;
console.log(inputs[i]);
inputs[i].readOnly = false;
}
} else if (!inputs[i].checkValidity()) {
isValid = false;
console.log(inputs[i]);
}
}
}
if (isValid) {
/* Remove drag 'n' drop event handlers. */
var elements = document.getElementById('pluginsNav').children;
for (var i = 0; i < elements.length; ++i) {
elements[i].removeAttribute('draggable', true);
elements[i].removeEventListener('dragstart', handlePluginDragStart, false);
}
/* Disable priority hover in plugins list. */
document.getElementById('pluginsNav').classList.toggle('editMode', false);
/* Enable header buttons. */
document.getElementsByTagName('header')[0].classList.toggle('editMode', false);
/* Hide editor. */
var section = evt.target.parentElement.parentElement.parentElement;
section.classList.toggle('flip');
/* Now delete editor panel. */
section.removeChild(section.getElementsByClassName('editor')[0]);
}
}
function handlePluginDrop(evt) {
evt.stopPropagation();
@@ -360,64 +251,7 @@ function handlePluginDragOver(evt) {
evt.preventDefault();
evt.dataTransfer.dropEffect = 'copy';
}
function showEditor(evt) {
/* Editor is attached to plugins on-demand. */
var content = document.getElementById('pluginEditor').content;
var editor = document.importNode(content, true);
var sectionId = evt.target.getAttribute('data-target');
var section = document.getElementById(sectionId);
section.appendChild(editor);
editor = section.lastElementChild;
/* Fill in data. */
editor.getElementsByTagName('h1')[0].textContent = section.getElementsByTagName('h1')[0].textContent;
editor.getElementsByClassName('crc')[0].textContent = section.getElementsByClassName('crc')[0].textContent;
editor.getElementsByClassName('version')[0].textContent = section.getElementsByClassName('version')[0].textContent;
/* Initialise tables. */
var tables = editor.getElementsByTagName('table');
for (var i = 0; i < tables.length; ++i) {
setupTable(tables[i].getElementsByTagName('tbody')[0]);
}
/* Fill in table data. */
/* Set up table tab event handlers. */
var elements = editor.getElementsByClassName('tableTabs')[0].children;
for (var i = 0; i < elements.length; ++i) {
var tableClass = elements[i].getAttribute('data-for');
if (tableClass) {
elements[i].addEventListener('click', showEditorTable, false);
}
}
/* Set up button event handlers. */
editor.getElementsByClassName('accept')[0].addEventListener('click', hideEditor, false);
editor.getElementsByClassName('cancel')[0].addEventListener('click', hideEditor, false);
/* Set up drag 'n' drop event handlers. */
elements = document.getElementById('pluginsNav').children;
for (var i = 0; i < elements.length; ++i) {
elements[i].setAttribute('draggable', true);
elements[i].addEventListener('dragstart', handlePluginDragStart, false);
}
elements = editor.getElementsByTagName('table');
for (var i = 0; i < elements.length; ++i) {
if (elements[i].className.indexOf('loadAfter') != -1 || elements[i].className.indexOf('req') != -1 || elements[i].className.indexOf('inc') != -1) {
elements[i].addEventListener('drop', handlePluginDrop, false);
elements[i].addEventListener('dragover', handlePluginDragOver, false);
}
}
/* Enable priority hover in plugins list. */
document.getElementById('pluginsNav').classList.toggle('editMode', true);
/* Disable header buttons. */
document.getElementsByTagName('header')[0].classList.toggle('editMode', true);
/* Finally, show editor. */
section.classList.toggle('flip');
}
function areSettingsValid() {
/* First validate table inputs. */
var inputs = document.getElementById('settings').getElementsByTagName('input');
@@ -682,9 +516,7 @@ function initGlobalVars() {
/* Now fill game lists/table. */
var gameSelect = document.getElementById('defaultGameSelect');
var gameMenu = document.getElementById('gameMenu').firstElementChild;
var gameTableBody = document.getElementById('gameTable').getElementsByTagName('tbody')[0];
/* Add row for creating new rows. */
setupTable(gameTableBody);
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;
@@ -697,7 +529,7 @@ function initGlobalVars() {
li.textContent = loot.settings.games[i].name;
gameMenu.appendChild(li);
addTableRow(gameTableBody, loot.settings.games[i]);
gameTable.addRow(loot.settings.games[i]);
}
gameSelect.value = loot.settings.game;
+41 -24
View File
@@ -111,19 +111,21 @@
#menu span {
padding-right: 0.4em;
}
::content h1 {
::content h1, h1 {
margin: 0;
font-weight: normal;
font-size: 1.2em;
display: inline-block;
}
::content .version {
::content .version, .version {
display: inline-block;
margin-left: 1em;
color:#6394F8;
}
::content .crc {
::content .crc, .crc {
display: inline-block;
margin-left: 1em;
color:#BC8923;
}
.hidden, ::content .hidden {
display: none;
@@ -184,60 +186,74 @@
<h1></h1>
<span class="version"></span>
<span class="crc"></span>
<input type="checkbox" id="editorEnableEdits">
<label for="editorEnableEdits">Enable Edits</label><br>
<input type="checkbox" id="editorGlobalPriority">
<label for="editorGlobalPriority" title="Global priorities are compared against all other plugins. Normal priorities are compared against only conflicting plugins.">Global Priority</label><br>
<label for="editorPriorityValue">Priority Value</label>
<input id="editorPriorityValue" type="number" max="999999" min="-999999" step="1">
<div>
<input type="checkbox" id="editorEnableEdits">
<label for="editorEnableEdits">Enable Edits</label><br>
<input type="checkbox" id="editorGlobalPriority">
<label for="editorGlobalPriority" title="Global priorities are compared against all other plugins. Normal priorities are compared against only conflicting plugins.">Global Priority</label><br>
<label for="editorPriorityValue">Priority Value</label>
<input id="editorPriorityValue" type="number" max="999999" min="-999999" step="1">
</div>
<div id="tableTabs">
<span class="selected" data-for="loadAfter">Load After</span><span data-for="req">Requirements</span><span data-for="inc">Incompatibilities</span><span data-for="message">Messages</span><span data-for="tags">Bash Tags</span><span data-for="dirty">Dirty Info</span>
<table id="loadAfter" class="editable">
<span class="selected" data-for="loadAfter">Load After</span>
<span data-for="req">Requirements</span>
<span data-for="inc">Incompatibilities</span>
<span data-for="message">Messages</span>
<span data-for="tags">Bash Tags</span>
<span data-for="dirty">Dirty Info</span>
<table is="editable-table" id="loadAfter" data-template="fileRow">
<thead>
<tr><th>Filename</th><th>Display Name</th><th>Condition</th><th></th></tr>
</thead>
<tbody data-template="fileRow">
<tbody>
<!-- File rows go here. -->
<tr><td colspan="4">Add new row...</td><td></td></tr>
</tbody>
</table>
<table id="req" class="editable hidden">
<table is="editable-table" id="req" class="hidden" data-template="fileRow">
<thead>
<tr><th>Filename</th><th>Display Name</th><th>Condition</th><th></th></tr>
</thead>
<tbody data-template="fileRow">
<tbody>
<!-- File rows go here. -->
<tr><td colspan="4">Add new row...</td><td></td></tr>
</tbody>
</table>
<table id="inc" class="editable hidden">
<table is="editable-table" id="inc" class="hidden" data-template="fileRow">
<thead>
<tr><th>Filename</th><th>Display Name</th><th>Condition</th><th></th></tr>
</thead>
<tbody data-template="fileRow">
<tbody>
<!-- File rows go here. -->
<tr><td colspan="4">Add new row...</td><td></td></tr>
</tbody>
</table>
<table id="message" class="editable hidden">
<table is="editable-table" id="message" class="hidden" data-template="messageRow">
<thead>
<tr><th>Type</th><th>Content</th><th>Condition</th><th>Language</th><th></th></tr>
</thead>
<tbody data-template="messageRow">
<tbody>
<!-- Message rows go here. -->
<tr><td colspan="4">Add new row...</td><td></td></tr>
</tbody>
</table>
<table id="tags" class="editable hidden">
<table is="editable-table" id="tags" class="hidden" data-template="tagRow">
<thead>
<tr><th>Add/Remove</th><th>Bash Tag</th><th>Condition</th><th></th></tr>
</thead>
<tbody data-template="tagRow">
<tbody>
<!-- Bash Tag rows go here. -->
<tr><td colspan="4">Add new row...</td><td></td></tr>
</tbody>
</table>
<table id="dirty" class="editable hidden">
<table is="editable-table" id="dirty" class="hidden" data-template="dirtyInfoRow">
<thead>
<tr><th>CRC</th><th>ITM Count</th><th>UDR Count</th><th>Deleted Navmeshes</th><th>Cleaning Utility</th><th></th></tr>
</thead>
<tbody data-template="dirtyInfoRow">
<tbody>
<!-- Dirty info rows go here. -->
<tr><td colspan="4">Add new row...</td><td></td></tr>
</tbody>
</table>
</div>
@@ -471,11 +487,12 @@ along with LOOT. If not, see &lt;http://www.gnu.org/licenses/&gt;.
<option value="3">High</option>
</select><br>
<!-- Need to add an editable multi-column game list here. -->
<table id="gameTable" class="editable">
<table is="editable-table" id="gameTable" data-template="gameRow">
<thead>
<tr><th>Name<th>Base Game<th>LOOT Folder<th>Master File<th>Masterlist Repository URL<th>Masterlist Repository Branch<th>Install Path<th>Install Path Registry Key<th>
<tbody data-template="gameRow">
<tbody>
<!-- 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.
<hr>