diff --git a/resources/report/js/custom.js b/resources/report/js/custom.js index 9d2edd2d..7c713ffe 100644 --- a/resources/report/js/custom.js +++ b/resources/report/js/custom.js @@ -22,6 +22,77 @@ . */ 'use strict'; + +/* Create a element type. */ +var pluginMenuProto = Object.create(HTMLElement.prototype, { + + onMenuItemClick: { + value: function(evt) { + + var pluginID = evt.target.parentNode.host.getAttribute('data-for'); + var pluginCard = document.getElementById(pluginID); + + if (evt.target.id == 'editMetadata') { + /* Show editing controls. */ + pluginCard.showEditor(); + + } else if (evt.target.id == 'copyMetadata') { + + } else if (evt.target.id == 'clearMetadata') { + showMessageDialog('Clear Plugin Metadata', 'Are you sure you want to clear all existing user-added metadata from "' + pluginCard.querySelector('h1').textContent + '"?'); + } + } + }, + + onClick: { + value: function(evt) { + var menus = document.getElementsByTagName('plugin-menu'); + + for (var i = 0; i < menus.length; ++i) { + if (!evt.newMenu) { + menus[i].parentElement.removeChild(menus[i]); + } + } + } + }, + + createdCallback: { + value: function() { + + var template = document.getElementById('pluginMenu'); + var clone = document.importNode(template.content, true); + + this.createShadowRoot().appendChild(clone); + + this.id = 'activePluginMenu'; + + /* Add an event listener so that the menu gets closed. */ + main.addEventListener('click', this.onClick, false); + + /* Add event listeners for the menu items. */ + this.shadowRoot.querySelector('#editMetadata').addEventListener('click', this.onMenuItemClick, false); + this.shadowRoot.querySelector('#copyMetadata').addEventListener('click', this.onMenuItemClick, false); + this.shadowRoot.querySelector('#clearMetadata').addEventListener('click', this.onMenuItemClick, false); + } + }, + + detachedCallback: { + value: function() { + /* Remove menu close listener. */ + document.getElementById('main').removeEventListener('click', this.onClick, false); + + /* Remove event listeners for the menu items. */ + this.shadowRoot.querySelector('#editMetadata').removeEventListener('click', this.onMenuItemClick, false); + this.shadowRoot.querySelector('#copyMetadata').removeEventListener('click', this.onMenuItemClick, false); + this.shadowRoot.querySelector('#clearMetadata').removeEventListener('click', this.onMenuItemClick, false); + + } + } + + +}); +var PluginMenu = document.registerElement('plugin-menu', {prototype: pluginMenuProto}); + /* Create a element type. */ var pluginCardProto = Object.create(HTMLElement.prototype, { @@ -63,12 +134,34 @@ var pluginCardProto = Object.create(HTMLElement.prototype, { } } if (isValid) { + var card = evt.target.parentElement.parentElement.parentNode.host; + + /* Set up table tab event handlers. */ + var elements = card.shadowRoot.querySelector('#tableTabs').children; + for (var i = 0; i < elements.length; ++i) { + if (elements[i].hasAttribute('data-for')) { + elements[i].removeEventListener('click', card.showEditorTable, false); + } + } + + /* Set up button event handlers. */ + card.shadowRoot.querySelector('#accept').removeEventListener('click', card.hideEditor, false); + card.shadowRoot.querySelector('#cancel').removeEventListener('click', card.hideEditor, false); + + /* 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); } + elements = card.shadowRoot.querySelector('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].removeEventListener('drop', handlePluginDrop, false); + elements[i].removeEventListener('dragover', handlePluginDragOver, false); + } + } /* Disable priority hover in plugins list. */ document.getElementById('pluginsNav').classList.toggle('editMode', false); @@ -77,7 +170,7 @@ var pluginCardProto = Object.create(HTMLElement.prototype, { document.getElementsByTagName('header')[0].classList.toggle('editMode', false); /* Hide editor. */ - evt.target.parentElement.parentElement.parentNode.host.classList.toggle('flip'); + card.classList.toggle('flip'); } } }, @@ -121,29 +214,43 @@ var pluginCardProto = Object.create(HTMLElement.prototype, { } }, - - onMenuItemClick: { + onMenuButtonClick: { value: function(evt) { - if (evt.target.id == 'editMetadata') { - /* Show editing controls. */ - evt.target.parentElement.parentElement.parentNode.host.showEditor(); - } else if (evt.target.id == 'copyMetadata') { + /* Open a new plugin menu. */ + var menu = new PluginMenu(); + var card = evt.currentTarget.parentElement.parentElement.parentNode.host; - } else if (evt.target.id == 'clearMetadata') { - showMessageDialog('Clear Plugin Metadata', 'Are you sure you want to clear all existing user-added metadata from "' + evt.target.parentElement.parentElement.querySelector('h1').textContent + '"?'); + menu.setAttribute('data-for', card.id); + + /* To prevent the click event closing this menu just after it was + opened, attach an ID to it, then stop the current event and send + off a new one. */ + menu.id = Math.random().toString(36).substr(2) + Math.random().toString(36).substr(2); + + var main = document.getElementById('main'); + main.appendChild(menu); + + /* Set page position of menu. */ + + function getOffset( el, stopEl ) { + var _x = 0; + var _y = 0; + while( el && el != stopEl ) { + _x += el.offsetLeft; + _y += el.offsetTop; + el = el.offsetParent; + } + return { top: _y, left: _x }; } - } - }, + var offset = getOffset(evt.target, main); - onMenuClick: { - value: function(evt) { - var section = evt.currentTarget.parentElement.parentElement; - section.querySelector('#editMetadata').addEventListener('click', section.parentNode.host.onMenuItemClick, false); - section.querySelector('#copyMetadata').addEventListener('click', section.parentNode.host.onMenuItemClick, false); - section.querySelector('#clearMetadata').addEventListener('click', section.parentNode.host.onMenuItemClick, false); + menu.style.top = (offset.top + evt.target.offsetHeight + 10) + 'px'; + menu.style.right = (main.offsetWidth - offset.left - evt.target.offsetWidth - 10) + 'px'; - section.querySelector('#menu').classList.toggle('hidden'); + evt.stopPropagation(); + + menu.dispatchEvent(new CustomEvent('click', { newMenu: true })); } }, @@ -175,10 +282,16 @@ var pluginCardProto = Object.create(HTMLElement.prototype, { var messages = document.createElement('ul'); this.appendChild(messages); - this.shadowRoot.querySelector('#menuButton').addEventListener('click', this.onMenuClick, false); + this.shadowRoot.querySelector('#menuButton').addEventListener('click', this.onMenuButtonClick, false); } + }, + + detachedCallback: { + value: function() { + this.shadowRoot.querySelector('#menuButton').removeEventListener('click', this.onMenuButtonClick, false); + } } }); @@ -218,7 +331,12 @@ var messageDialogProto = Object.create(HTMLDialogElement.prototype, { onButtonClick: { value: function(evt) { - evt.currentTarget.parentElement.parentElement.close( evt.target.className == 'accept' ); + var dialog = evt.currentTarget.parentElement.parentElement; + + dialog.querySelector('.accept').removeEventListener('click', dialog.onButtonClick, false); + dialog.querySelector('.cancel').removeEventListener('click', dialog.onButtonClick, false); + + dialog.close( evt.target.className == 'accept' ); } }, @@ -270,13 +388,6 @@ var messageDialogProto = Object.create(HTMLDialogElement.prototype, { buttons.appendChild(cancel); } - }, - - detachedCallback: { - value: function() { - - this.removeEventListener('click', this.onButtonClick, false); - } } }); @@ -291,7 +402,21 @@ var EditableTableProto = Object.create(HTMLTableElement.prototype, { removeRow: { value: function(evt) { - evt.target.parentElement.parentElement.removeChild(evt.target.parentElement); + var tr = evt.target.parentElement; + var tbody = tr.parentElement + var table = tbody.parentElement; + + /* Remove row edit listeners. */ + var inputs = row.getElementsByTagName('input'); + for (var i = 0; i < inputs.length; ++i) { + inputs[i].removeEventListener('dblclick', toggleInputRO, false); + } + + /* Remove deletion listener. */ + evt.target.removeEventListener('click', table.removeRow, false); + + /* Now remove row. */ + tbody.removeChild(tr); } }, @@ -349,6 +474,30 @@ var EditableTableProto = Object.create(HTMLTableElement.prototype, { }, + detachedCallback: { + value: function() { + /* Remove event listeners. */ + var tbody = this.getElementsByTagName('tbody')[0]; + + + /* Remove row edit listeners. */ + var inputs = tbody.getElementsByTagName('input'); + for (var i = 0; i < inputs.length; ++i) { + inputs[i].removeEventListener('dblclick', toggleInputRO, false); + } + + /* Remove deletion listener. */ + var icons = tbody.getElementsByClassName('fa-trash-o'); + for (var i = 0; i < icons.length; ++i) { + icons[i].removeEventListener('click', this.removeRow, false); + } + + /* Remove new row listener. */ + this.querySelector('tbody tr:last-child').removeEventListener('dblclick', this.addEmptyRow, false); + + } + }, + }); var EditableTable = document.registerElement('editable-table', { prototype: EditableTableProto, diff --git a/resources/report/report.html b/resources/report/report.html index c191d557..21938bbb 100644 --- a/resources/report/report.html +++ b/resources/report/report.html @@ -22,7 +22,7 @@ position: relative; overflow:visible; transition: 0.6s; - transform-style: flat; + transform-style: preserve-3d; } :host([data-active=false]) #activeTick { visibility: hidden; @@ -37,28 +37,27 @@ display: none; } - :host(.flip) { - transform: rotateY(180deg); - } - #front, #editor { - backface-visibility: hidden; - transition: 0.6s; + display: block; } #editor { - transform: rotateY(180deg); + transform: rotateY(180deg) translateZ(1px); display:none; } + :host(.flip) { + transform: rotateY(180deg); + } + :host(.flip) #front { - display:none; + display: none; } :host(.flip) #editor { - backface-visibility: visible; - display:block; + display: block; } + #icons { background: transparent; margin: 0; @@ -74,7 +73,6 @@ text-align: center; display: inline-block; margin: 0.2em; - cursor: pointer; } #icons > li:hover { color: black; @@ -85,32 +83,6 @@ margin: 0.2em; cursor: pointer; } - #menu { - background: white; - box-shadow:0 0 3px 0px rgba(0,0,0,0.5); - font:10pt/1.5 Helvetica,sans-serif; - list-style-type: none; - position: absolute; - right: 0.5em; - width: 14em; - z-index: 2; - text-align: left; - opacity: 1; - padding:0; - color: black; - top: 2em; - } - #menu > li { - padding: 0.2em 0.5em; - cursor: pointer; - display: block; - } - #menu > li:hover { - background:#e3e3e3; - } - #menu span { - padding-right: 0.4em; - } ::content h1, h1 { margin: 0; font-weight: normal; @@ -176,11 +148,6 @@ - - Edit Metadata - Copy Metadata As Text - Clear User Metadata - @@ -293,6 +260,34 @@ + + + Edit Metadata + Copy Metadata As Text + Clear User Metadata + @@ -349,7 +344,7 @@ - + The LOOT Report requires Javascript to be enabled in order to function.