Merged <plugin-menu> into <plugin-card>.

It doesn't need to exist as a separate entity.
This commit is contained in:
Oliver Hamlet
2014-11-07 13:41:55 +00:00
parent 2c71bbbaab
commit 67bc009906
4 changed files with 180 additions and 246 deletions
+175 -43
View File
@@ -1,4 +1,7 @@
<link rel="import" href="loot://import/plugin-menu.html" />
<!--
<plugin-card> element. It fires the following custom events:
-->
<template id="pluginCard">
<style>
@@ -173,6 +176,37 @@
top:0.15em;
margin-left:0.5em;
}
#menu {
background: white;
box-shadow:0 0 3px 0px rgba(0,0,0,0.5);
font:10pt/1.5 Helvetica,sans-serif;
position: absolute;
right: 1em;
width: 14em;
text-align: left;
padding:0;
}
#menu div, #menu label {
padding: 0.2em 0.5em;
cursor: pointer;
display: block;
}
#menu div:hover, #menu label:hover {
background: #e3e3e3;
}
#menu span {
padding-right: 0.4em;
}
#menu input {
position: relative;
top: 0.15em;
margin: 0em 0.3em 0 0.1em;
}
#menu .disabled {
cursor: default;
color: #999;
}
</style>
<section id="front">
@@ -188,6 +222,12 @@
<li id="loadsBSA" class="fa fa-paperclip" title="Loads BSA"></li>
<li id="hasUserEdits" class="fa fa-user" title="Has User Metadata"></li>
<li id="menuButton" class="fa fa-ellipsis-v fa-lg" title="Click to open the plugin menu.">
<div id="menu" class="hidden">
<label><input type="checkbox" id="showOnlyConflicts" class="fa-fw">Show Only Conflicts</label>
<div id="editMetadata"><span class="fa fa-pencil fa-fw"></span>Edit Metadata</div>
<div id="copyMetadata"><span class="fa fa-copy fa-fw"></span>Copy Metadata As Text</div>
<div id="clearMetadata"><span class="fa fa-trash-o fa-fw"></span>Clear User Metadata</div>
</div>
</li>
</ol>
</section>
@@ -477,39 +517,40 @@ var pluginCardProto = Object.create(HTMLElement.prototype, {
},
showEditor: {
value: function() {
value: function(evt) {
var pluginCard = evt.target.parentElement.parentElement.parentElement.parentElement.parentNode.host;
/* Fill editor controls with values from the plugin this card corresponds to. */
/* First find the corresponding plugin. */
for (var i = 0; i < loot.game.plugins.length; ++i) {
if (loot.game.plugins[i].id == this.id) {
if (loot.game.plugins[i].id == pluginCard.id) {
this.shadowRoot.getElementById('editor').getElementsByTagName('h1')[0].textContent = loot.game.plugins[i].name;
this.shadowRoot.getElementById('editor').getElementsByClassName('version')[0].textContent = loot.game.plugins[i].version;
pluginCard.shadowRoot.getElementById('editor').getElementsByTagName('h1')[0].textContent = loot.game.plugins[i].name;
pluginCard.shadowRoot.getElementById('editor').getElementsByClassName('version')[0].textContent = loot.game.plugins[i].version;
if (loot.game.plugins[i].crc != '0') {
this.shadowRoot.getElementById('editor').getElementsByClassName('crc')[0].textContent = loot.game.plugins[i].crc.toString(16).toUpperCase();
pluginCard.shadowRoot.getElementById('editor').getElementsByClassName('crc')[0].textContent = loot.game.plugins[i].crc.toString(16).toUpperCase();
}
/* Fill in the editor input values. */
if (loot.game.plugins[i].userlist && !loot.game.plugins[i].userlist.enabled) {
this.shadowRoot.getElementById('enableEdits').checked = false;
pluginCard.shadowRoot.getElementById('enableEdits').checked = false;
} else {
this.shadowRoot.getElementById('enableEdits').checked = true;
pluginCard.shadowRoot.getElementById('enableEdits').checked = true;
}
this.shadowRoot.getElementById('globalPriority').checked = loot.game.plugins[i].isGlobalPriority;
this.shadowRoot.getElementById('priorityValue').value = loot.game.plugins[i].modPriority;
pluginCard.shadowRoot.getElementById('globalPriority').checked = loot.game.plugins[i].isGlobalPriority;
pluginCard.shadowRoot.getElementById('priorityValue').value = loot.game.plugins[i].modPriority;
/* Clear any existing editor table data. Don't remove the last row though,
that's the "add new row" one. */
var tables = this.shadowRoot.getElementsByTagName('table');
var tables = pluginCard.shadowRoot.getElementsByTagName('table');
for (var j = 0; j < tables.length; ++j) {
tables[j].clear();
}
/* Fill in editor table data. Masterlist-originated rows should have
their contents made read-only, and be unremovable. */
var tables = this.shadowRoot.getElementsByTagName('table');
var tables = pluginCard.shadowRoot.getElementsByTagName('table');
for (var j = 0; j < tables.length; ++j) {
if (tables[j].id == 'loadAfter') {
@@ -641,16 +682,16 @@ var pluginCardProto = Object.create(HTMLElement.prototype, {
}
/* Set up table tab event handlers. */
var elements = this.shadowRoot.getElementById('tableTabs').children;
var elements = pluginCard.shadowRoot.getElementById('tableTabs').children;
for (var i = 0; i < elements.length; ++i) {
if (elements[i].hasAttribute('data-for')) {
elements[i].addEventListener('click', this.showEditorTable, false);
elements[i].addEventListener('click', pluginCard.showEditorTable, false);
}
}
/* Set up button event handlers. */
this.shadowRoot.getElementById('accept').addEventListener('click', this.hideEditor, false);
this.shadowRoot.getElementById('cancel').addEventListener('click', this.hideEditor, false);
pluginCard.shadowRoot.getElementById('accept').addEventListener('click', pluginCard.hideEditor, false);
pluginCard.shadowRoot.getElementById('cancel').addEventListener('click', pluginCard.hideEditor, false);
/* Set up drag 'n' drop event handlers. */
elements = document.getElementById('pluginsNav').children;
@@ -673,42 +714,98 @@ var pluginCardProto = Object.create(HTMLElement.prototype, {
document.body.setAttribute('data-editors', numEditors);
/* Now show editor. */
this.classList.toggle('flip');
pluginCard.classList.toggle('flip');
}
},
onShowOnlyConflicts: {
value: function(evt) {
/* Depending on what was clicked, this function may be run before
the checkbox state has updated. Handle both cases. */
var activateFilter, card;
if (evt.currentTarget == evt.target) {
/* Clicked on the label, checkbox state isn't updated yet. */
activateFilter = !evt.target.firstElementChild.checked;
card = evt.target.parentElement.parentElement.parentElement.parentElement.parentNode.host;
} else {
/* Clicked on the checkbox. */
activateFilter = evt.target.checked;
card = evt.target.parentElement.parentElement.parentElement.parentElement.parentElement.parentNode.host;
}
if (activateFilter) {
/* Un-highlight any existing filter plugin. */
var cards = document.getElementsByTagName('main')[0].getElementsByTagName('plugin-card');
for (var i = 0; i < cards.length; ++i) {
cards[i].classList.toggle('highlight', false);
}
card.classList.toggle('highlight', true);
document.body.setAttribute('data-conflicts', card.getName());
} else {
card.classList.toggle('highlight', false);
document.body.removeAttribute('data-conflicts');
}
applyFilters(evt);
}
},
onCopyMetadata: {
value: function(evt) {
var card = evt.target.parentElement.parentElement.parentElement.parentElement.parentNode.host;
var request = JSON.stringify({
name: 'copyMetadata',
args: [
card.getName()
]
});
loot.query(request).catch(processCefError);
}
},
onClearMetadata: {
value: function(evt) {
var pluginCard = evt.target.parentElement.parentElement.parentElement.parentElement.parentNode.host;
showMessageDialog('Clear Plugin Metadata', 'Are you sure you want to clear all existing user-added metadata from "' + pluginCard.getName() + '"?', function(result){
if (result) {
var request = JSON.stringify({
name: 'clearPluginMetadata',
args: [
pluginCard.getName()
]
});
loot.query(request).then(JSON.parse).then(function(result){
if (result) {
/* Need to empty the UI-side user metadata. */
for (var i = 0; i < loot.game.plugins.length; ++i) {
if (loot.game.plugins[i].id == pluginCard.id) {
loot.game.plugins[i].userlist = undefined;
loot.game.plugins[i].modPriority = result.modPriority;
loot.game.plugins[i].isGlobalPriority = result.isGlobalPriority;
loot.game.plugins[i].messages = result.messages;
loot.game.plugins[i].tags = result.tags;
loot.game.plugins[i].isDirty = result.isDirty;
break;
}
}
}
}).catch(processCefError);
}
});
}
},
onMenuButtonClick: {
value: function(evt) {
/* Open a new plugin menu. */
var menu = new PluginMenu();
var card = evt.currentTarget.parentElement.parentElement.parentNode.host;
menu.setAttribute('data-for', card.id);
var main = document.getElementsByTagName('main')[0];
/* Set page position of menu. */
var rect = evt.target.getBoundingClientRect();
menu.style.right = (main.offsetWidth - (rect.right - main.offsetLeft) - 15) + 'px';
menu.style.top = (rect.bottom - document.getElementById('container').offsetTop + main.scrollTop + 5) + 'px';
main.appendChild(menu);
evt.stopPropagation();
/* To prevent the click event closing this menu just after it was
opened, stop the current event and send off a new one. */
document.body.dispatchEvent(new CustomEvent('click', {
bubbles: true,
detail: {
newMenu: menu
}
}));
/* Open the plugin menu. */
evt.currentTarget.firstElementChild.classList.toggle('hidden');
}
},
createdCallback: {
value: function() {
var template = pluginCardImportDoc.getElementById('pluginCard');
@@ -746,6 +843,33 @@ var pluginCardProto = Object.create(HTMLElement.prototype, {
hoverTargets[i].addEventListener('mouseenter', showHoverText, false);
hoverTargets[i].addEventListener('mouseleave', hideHoverText, false);
}
/* Add event listeners for the menu items. */
/* For some reason clicking on the label is processed slower
than the checkbox state, and in the time difference the menu
gets closed, so that the conflicts filter never gets applied.
To get around this, listen for a click on the label rather
than for checkbox state change. */
if (document.body.getAttribute('data-conflicts') == this.getName()) {
this.shadowRoot.getElementById('showOnlyConflicts').checked = true;
}
this.shadowRoot.getElementById('showOnlyConflicts').parentElement.addEventListener('click', this.onShowOnlyConflicts, false);
this.shadowRoot.getElementById('editMetadata').addEventListener('click', this.showEditor, false);
this.shadowRoot.getElementById('copyMetadata').addEventListener('click', this.onCopyMetadata, false);
this.shadowRoot.getElementById('clearMetadata').addEventListener('click', this.onClearMetadata, false);
/* Because of the 3D flip effect used when accessing the editor,
plugin menus get hidden underneath later plugin cards unless
those cards have a lower z-index than the card the menu is part
of. Therefore, set this card's z-index to the negative of its
position in the plugin list.
*/
var cards = this.parentElement.getElementsByTagName('plugin-card');
for (var i = 0; i < cards.length; ++i) {
if (cards[i] == this) {
this.style.zIndex = -1 * i;
}
}
}
},
@@ -758,6 +882,14 @@ var pluginCardProto = Object.create(HTMLElement.prototype, {
hoverTargets[i].removeEventListener('mouseenter', showHoverText, false);
hoverTargets[i].removeEventListener('mouseleave', hideHoverText, false);
}
/* Remove event listeners for the menu items. */
/* Nothing happens if we try to remove a listener that doesn't exist,
so don't bother checking first. */
this.shadowRoot.getElementById('showOnlyConflicts').parentElement.removeEventListener('click', this.onShowOnlyConflicts, false);
this.shadowRoot.getElementById('editMetadata').removeEventListener('click', this.showEditor, false);
this.shadowRoot.getElementById('copyMetadata').removeEventListener('click', this.onCopyMetadata, false);
this.shadowRoot.getElementById('clearMetadata').removeEventListener('click', this.onClearMetadata, false);
}
}
-195
View File
@@ -1,195 +0,0 @@
<!--
<plugin-menu> element. Intended for use inside a <plugin-card> element. Clicking on menu items fires custom events:
showConflicts:
bubbles: true,
detail: {
activate: <boolean> // true if the filter should be activated, false if it should be deactivated.
}
-->
<template id="pluginMenu">
<style>
@import 'css/font-awesome.min.css';
:host {
background: white;
box-shadow:0 0 3px 0px rgba(0,0,0,0.5);
font:10pt/1.5 Helvetica,sans-serif;
position: absolute;
z-index: 5;
width: 14em;
text-align: left;
padding:0;
}
div, label {
padding: 0.2em 0.5em;
cursor: pointer;
display: block;
}
div:hover, label:hover {
background: #e3e3e3;
}
span {
padding-right: 0.4em;
}
input {
position: relative;
top: 0.15em;
margin: 0em 0.3em 0 0.1em;
}
.disabled {
cursor: default;
color: #999;
}
</style>
<label><input type="checkbox" id="showOnlyConflicts" class="fa-fw">Show Only Conflicts</label>
<div id="editMetadata"><span class="fa fa-pencil fa-fw"></span>Edit Metadata</div>
<div id="copyMetadata"><span class="fa fa-copy fa-fw"></span>Copy Metadata As Text</div>
<div id="clearMetadata"><span class="fa fa-trash-o fa-fw"></span>Clear User Metadata</div>
</template>
<script>
'use strict';
// Record this document.
var pluginMenuImportDoc = document.currentScript.ownerDocument;
/* Create a <plugin-menu> element type. */
var pluginMenuProto = Object.create(HTMLElement.prototype, {
onShowOnlyConflicts: {
value: function(evt) {
/* Depending on what was clicked, this function may be run before
the checkbox state has updated. Handle both cases. */
var activateFilter;
if (evt.currentTarget == evt.target) {
/* Clicked on the label, checkbox state isn't updated yet. */
activateFilter = !evt.target.firstElementChild.checked;
} else {
/* Clicked on the checkbox. */
activateFilter = evt.target.checked;
}
// Fire a custom event. It will appear to originate from the <plugin-menu> element.
evt.target.dispatchEvent(new CustomEvent('showConflicts', {
bubbles: true,
detail: {
activate: activateFilter
}
}));
if (activateFilter) {
/* Un-highlight any existing filter plugin. */
var cards = document.getElementsByTagName('main')[0].getElementsByTagName('plugin-card');
for (var i = 0; i < cards.length; ++i) {
cards[i].classList.toggle('highlight', false);
}
evt.currentTarget.parentNode.host.getPluginCard().classList.toggle('highlight', true);
document.body.setAttribute('data-conflicts', evt.currentTarget.parentNode.host.getPluginCard().getName());
} else {
evt.currentTarget.parentNode.host.getPluginCard().classList.toggle('highlight', false);
document.body.removeAttribute('data-conflicts');
}
applyFilters(evt);
}
},
onEditMetadata: {
value: function(evt) {
evt.target.parentNode.host.getPluginCard().showEditor();
}
},
onCopyMetadata: {
value: function(evt) {
var request = JSON.stringify({
name: 'copyMetadata',
args: [
evt.target.parentNode.host.getPluginCard().getName()
]
});
loot.query(request).catch(processCefError);
}
},
onClearMetadata: {
value: function(evt) {
var pluginCard = evt.target.parentNode.host.getPluginCard();
showMessageDialog('Clear Plugin Metadata', 'Are you sure you want to clear all existing user-added metadata from "' + pluginCard.getName() + '"?', function(result){
if (result) {
var request = JSON.stringify({
name: 'clearPluginMetadata',
args: [
pluginCard.getName()
]
});
loot.query(request).then(JSON.parse).then(function(result){
if (result) {
/* Need to empty the UI-side user metadata. */
for (var i = 0; i < loot.game.plugins.length; ++i) {
if (loot.game.plugins[i].id == pluginCard.id) {
loot.game.plugins[i].userlist = undefined;
loot.game.plugins[i].modPriority = result.modPriority;
loot.game.plugins[i].isGlobalPriority = result.isGlobalPriority;
loot.game.plugins[i].messages = result.messages;
loot.game.plugins[i].tags = result.tags;
loot.game.plugins[i].isDirty = result.isDirty;
break;
}
}
}
}).catch(processCefError);
}
});
}
},
createdCallback: {
value: function() {
var template = pluginMenuImportDoc.querySelector('#pluginMenu');
var clone = document.importNode(template.content, true);
this.createShadowRoot().appendChild(clone);
}
},
attachedCallback: {
value: function() {
/* Add event listeners for the menu items. */
/* For some reason clicking on the label is processed slower
than the checkbox state, and in the time difference the menu
gets closed, so that the conflicts filter never gets applied.
To get around this, listen for a click on the label rather
than for checkbox state change. */
if (document.body.getAttribute('data-conflicts') == this.getPluginCard().getName()) {
this.shadowRoot.getElementById('showOnlyConflicts').checked = true;
}
this.shadowRoot.getElementById('showOnlyConflicts').parentElement.addEventListener('click', this.onShowOnlyConflicts, false);
this.shadowRoot.getElementById('editMetadata').addEventListener('click', this.onEditMetadata, false);
this.shadowRoot.getElementById('copyMetadata').addEventListener('click', this.onCopyMetadata, false);
this.shadowRoot.getElementById('clearMetadata').addEventListener('click', this.onClearMetadata, false);
}
},
detachedCallback: {
value: function() {
/* Remove event listeners for the menu items. */
/* Nothing happens if we try to remove a listener that doesn't exist,
so don't bother checking first. */
this.shadowRoot.getElementById('showOnlyConflicts').parentElement.removeEventListener('click', this.onShowOnlyConflicts, false);
this.shadowRoot.getElementById('editMetadata').removeEventListener('click', this.onEditMetadata, false);
this.shadowRoot.getElementById('copyMetadata').removeEventListener('click', this.onCopyMetadata, false);
this.shadowRoot.getElementById('clearMetadata').removeEventListener('click', this.onClearMetadata, false);
}
}
});
var PluginMenu = document.registerElement('plugin-menu', {prototype: pluginMenuProto});
</script>
+5 -7
View File
@@ -95,6 +95,11 @@
pluginCard.getElementById('accept').textContent = l10n.translate("Apply").fetch();
pluginCard.getElementById('cancel').textContent = l10n.translate("Cancel").fetch();
pluginCard.getElementById('showOnlyConflicts').nextSibling.textContent = l10n.translate("Show Only Conflicts").fetch();
pluginCard.getElementById('editMetadata').firstChild.nextSibling.textContent = l10n.translate("Edit Metadata").fetch();
pluginCard.getElementById('copyMetadata').firstChild.nextSibling.textContent = l10n.translate("Copy Metadata As Text").fetch();
pluginCard.getElementById('clearMetadata').firstChild.nextSibling.textContent = l10n.translate("Clear User Metadata").fetch();
/* Plugin List Item Template */
var pluginLI = pluginLiImportDoc.querySelector('#pluginLI').content;
pluginLI.querySelector('.dummyPlugin').title = l10n.translate("Dummy Plugin").fetch();
@@ -102,13 +107,6 @@
pluginLI.querySelector('.hasUserEdits').title = l10n.translate("Has User Metadata").fetch();
pluginLI.querySelector('.hasGlobalPriority').title = l10n.translate("Priority Is Global").fetch();
/* Plugin menu template */
var pluginMenu = pluginMenuImportDoc.querySelector('#pluginMenu').content;
pluginMenu.getElementById('showOnlyConflicts').nextSibling.textContent = l10n.translate("Show Only Conflicts").fetch();
pluginMenu.getElementById('editMetadata').firstChild.nextSibling.textContent = l10n.translate("Edit Metadata").fetch();
pluginMenu.getElementById('copyMetadata').firstChild.nextSibling.textContent = l10n.translate("Copy Metadata As Text").fetch();
pluginMenu.getElementById('clearMetadata').firstChild.nextSibling.textContent = l10n.translate("Clear User Metadata").fetch();
/* Message row template */
var messageRow = editableTableImportDoc.querySelector('#messageRow').content;
messageRow.querySelector('.type').children[0].textContent = l10n.translate("Note").fetch();
-1
View File
@@ -7,7 +7,6 @@
<link rel="import" href="loot://import/message-dialog.html">
<link rel="import" href="loot://import/plugin-li.html">
<link rel="import" href="loot://import/plugin-card.html">
<link rel="import" href="loot://import/plugin-menu.html">
<link rel="import" href="loot://import/editable-table.html">
<script src="js/require.js"></script>
</head>