diff --git a/scripts/vulcanize.js b/scripts/vulcanize.js index 0856eb6d..b5ccdf89 100755 --- a/scripts/vulcanize.js +++ b/scripts/vulcanize.js @@ -66,6 +66,7 @@ function vulcanizeTests(releasePath) { 'test_loot-custom-icons.html', 'test_loot-dropdown-menu.html', 'test_loot-message-dialog.html', + 'test_loot-plugin-card.html', 'test_loot-plugin-editor.html', 'test_loot-plugin-item.html', 'test_loot-search-toolbar.html', diff --git a/src/gui/html/elements/loot-plugin-card.html b/src/gui/html/elements/loot-plugin-card.html index 01fa3aac..74e7e39f 100644 --- a/src/gui/html/elements/loot-plugin-card.html +++ b/src/gui/html/elements/loot-plugin-card.html @@ -12,408 +12,406 @@ loot-clear-metadata --> - - - - - - - - - + + + + + + + + + + + + + - - + + Polymer({ + is: 'loot-plugin-card', + properties: { + data: { + notify: true, + observer: '_dataChanged', + }, + isActive: { + type: Boolean, + value: false, + reflectToAttribute: true, + }, + isMaster: { + type: Boolean, + value: false, + reflectToAttribute: true, + }, + isEmpty: { + type: Boolean, + value: false, + reflectToAttribute: true, + }, + loadsArchive: { + type: Boolean, + value: false, + reflectToAttribute: true, + }, + hasUserEdits: { + type: Boolean, + value: false, + reflectToAttribute: true, + }, + isSearchResult: { + type: Boolean, + value: false, + reflectToAttribute: true, + }, + }, + + attached() { + this.$.showOnlyConflicts.addEventListener('change', this._onShowOnlyConflicts); + this.$.editMetadata.addEventListener('click', this.onShowEditor); + this.$.editor.addEventListener('loot-editor-close', this._onHideEditor); + this.$.copyMetadata.addEventListener('click', this._onCopyMetadata); + this.$.clearMetadata.addEventListener('click', this._onClearMetadata); + + this.addEventListener('transitionend', this._onFlipEnd); + }, + + detached() { + this.$.showOnlyConflicts.removeEventListener('change', this._onShowOnlyConflicts); + this.$.editMetadata.removeEventListener('click', this.onShowEditor); + this.$.editor.removeEventListener('loot-editor-close', this._onHideEditor); + this.$.copyMetadata.removeEventListener('click', this._onCopyMetadata); + this.$.clearMetadata.removeEventListener('click', this._onClearMetadata); + + this.removeEventListener('transitionend', this._onFlipEnd); + }, + + _dataChanged(newValue, oldValue) { + if (newValue) { + if (newValue.isEditorOpen) { + /* Record existing data. */ + if (oldValue) { + oldValue.editor = this.readFromEditor(oldValue); + } + /* Share the data with the editor. */ + this.$.editor.setEditorData(newValue); + } + + /* Set the card flip state. */ + if (this.classList.contains('flip') !== newValue.isEditorOpen) { + /* Temporarily speed up the flip effect, as otherwise fast + scrolling lets the user see the end of it. */ + this.classList.add('fastflip'); + this.classList.toggle('flip'); + } + + /* Initialise the card content data. */ + this.updateContent(); + + /* Also set highlight if the conflict filter is active. */ + this.classList.toggle('highlight', newValue.isConflictFilterChecked); + + /* Set highlight if the plugin is a search result. */ + this.classList.toggle('search-result', newValue.isSearchResult); + } + }, + + _setTagsContent(tags) { + if (tags) { + const tagsAdded = this.getElementsByClassName('tag add')[0]; + tagsAdded.textContent = tags.added; + tagsAdded.hidden = tags.added.length === 0; + + const tagsRemoved = this.getElementsByClassName('tag remove')[0]; + tagsRemoved.textContent = tags.removed; + tagsRemoved.hidden = tags.removed.length === 0; + } + }, + + _setMessagesContent(messages) { + /* First clear any existing messages. */ + const messageList = this.getElementsByTagName('ul')[0]; + while (messageList.firstElementChild) { + messageList.removeChild(messageList.firstElementChild); + } + + if (messages) { + /* Now add new messages. */ + messages.forEach((message) => { + const messageListItem = document.createElement('li'); + messageListItem.className = message.type; + // Use the Marked library for Markdown formatting support. + messageListItem.innerHTML = window.marked(message.content); + messageList.appendChild(messageListItem); + }); + messageList.hidden = messages.length === 0; + } + }, + + updateContent() { + if (this.data) { + const cardContent = this.data.getCardContent(loot.filters); + + this.getElementsByClassName('version')[0].textContent = cardContent.version; + this.$.editor.getElementsByClassName('version')[0].textContent = cardContent.version; + + this.getElementsByClassName('crc')[0].textContent = cardContent.crc; + this.$.editor.getElementsByClassName('crc')[0].textContent = cardContent.crc; + + this._setTagsContent(cardContent.tags); + this._setMessagesContent(cardContent.messages); + + /* Update the conflict filter toggle state. */ + this.$.showOnlyConflicts.checked = this.data.isConflictFilterChecked; + + /* Notify that this card (may have) changed size. */ + this.dispatchEvent(new CustomEvent('iron-resize', { bubbles: true })); + } + }, + + getName() { + return this.getElementsByTagName('h1')[0].textContent; + }, + + _onFlipEnd() { + /* Remove fastflip class if present. This also fires when the menu is + opened or closed, but that isn't an issue. */ + this.classList.remove('fastflip'); + }, + + onShowEditor() { + let card; + if (this.tagName === 'LOOT-PLUGIN-CARD') { + card = this; + } else { + card = getMenuItemCard(this); + } + + /* If the editor hasn't already been opened, its data is not yet set, so do that now. */ + if (!card.data.isEditorOpen && !card.data.editor) { + card.$.editor.setEditorData(card.data); + } + + card.data.isEditorOpen = true; + + card.classList.toggle('flip'); + + /* Fire an open event, so that the UI can enter edit mode. */ + card.dispatchEvent(new CustomEvent('loot-editor-open', { + bubbles: true, + })); + + /* Notify that this card (may have) changed size. */ + card.dispatchEvent(new CustomEvent('iron-resize', { bubbles: true })); + }, + + _onHideEditor() { + let card; + if (this.tagName === 'LOOT-PLUGIN-CARD') { + card = this; + } else { + card = getMenuItemCard(this); + } + + /* Now hide editor. */ + card.classList.toggle('flip'); + card.data.isEditorOpen = false; + + /* Notify that this card (may have) changed size. */ + card.dispatchEvent(new CustomEvent('iron-resize', { bubbles: true })); + }, + + readFromEditor(oldData) { + return this.$.editor.readFromEditor(oldData); + }, + + _onShowOnlyConflicts(evt) { + evt.target.dispatchEvent(new CustomEvent('loot-filter-conflicts', { + detail: evt.currentTarget.checked, + bubbles: true, + })); + }, + + _onCopyMetadata(evt) { + evt.target.dispatchEvent(new CustomEvent('loot-copy-metadata', { + bubbles: true, + })); + }, + + _onClearMetadata(evt) { + evt.target.dispatchEvent(new CustomEvent('loot-clear-metadata', { + bubbles: true, + })); + }, + }); + + diff --git a/src/gui/html/js/plugin.js b/src/gui/html/js/plugin.js index 72a3f8b5..5a37d8c2 100644 --- a/src/gui/html/js/plugin.js +++ b/src/gui/html/js/plugin.js @@ -303,6 +303,10 @@ this._isDirty = dirty; } + get hasUserEdits() { + return this.userlist && Object.keys(this.userlist).length > 1; + } + getCardContent(filters) { return new PluginCardContent(this, filters); } diff --git a/src/tests/gui/html/elements/test_loot-plugin-card.html b/src/tests/gui/html/elements/test_loot-plugin-card.html new file mode 100644 index 00000000..9831c540 --- /dev/null +++ b/src/tests/gui/html/elements/test_loot-plugin-card.html @@ -0,0 +1,86 @@ + + + + test_loot-plugin-card.html + + + + + + + + + + + + + + + + + + + + +