From 632cf1b30aa679c78f454344f931370484afde1c Mon Sep 17 00:00:00 2001 From: Oliver Hamlet Date: Tue, 9 Feb 2016 21:02:31 +0000 Subject: [PATCH] Update a plugin's card when its content changes Add new events fired when changing the CRC or tags, and update the card content if they or the plugin's messages change. Use Lodash's isEquals() to test for deep object equality. --- bower.json | 3 +- src/gui/html/index.html | 1 + src/gui/html/js/init.js | 4 +- src/gui/html/js/plugin.js | 60 ++++++++++-- src/tests/gui/html/js/test.html | 1 + src/tests/gui/html/js/test_plugin.js | 138 +++++++++++++++++++++++++-- 6 files changed, 188 insertions(+), 19 deletions(-) diff --git a/bower.json b/bower.json index 13d1fbcb..0ffbc93b 100644 --- a/bower.json +++ b/bower.json @@ -31,6 +31,7 @@ "paper-tooltip": "PolymerElements/paper-tooltip#^1.0.0", "Jed": "SlexAxton/Jed#a9d03e1bbca9211a8b29a93a298a7ee9ddb353f0", "jed-gettext-parser": "^1.0.0", - "marked": "^0.3.2" + "marked": "^0.3.2", + "lodash": "^4.3.0" } } diff --git a/src/gui/html/index.html b/src/gui/html/index.html index 57560ec4..0a1957ab 100644 --- a/src/gui/html/index.html +++ b/src/gui/html/index.html @@ -448,6 +448,7 @@ + diff --git a/src/gui/html/js/init.js b/src/gui/html/js/init.js index 4f72d5a7..9f192a01 100644 --- a/src/gui/html/js/init.js +++ b/src/gui/html/js/init.js @@ -94,9 +94,11 @@ document.getElementById('cardsNav').addEventListener('click', onSidebarClick); document.getElementById('cardsNav').addEventListener('dblclick', onSidebarClick); - /* Set up handler for plugin message and dirty info changes. */ + /* Set up handler for plugin data changes. */ document.addEventListener('loot-plugin-message-change', Plugin.onMessageChange); + document.addEventListener('loot-plugin-message-change', Plugin.onContentChange); document.addEventListener('loot-plugin-isdirty-change', Plugin.onIsDirtyChange); + document.addEventListener('loot-plugin-card-content-change', Plugin.onContentChange); /* Set up event handlers for game member variable changes. */ document.addEventListener('loot-game-folder-change', Game.onFolderChange); diff --git a/src/gui/html/js/plugin.js b/src/gui/html/js/plugin.js index 5a37d8c2..78fb2ec5 100644 --- a/src/gui/html/js/plugin.js +++ b/src/gui/html/js/plugin.js @@ -25,13 +25,13 @@ (function exportModule(root, factory) { if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. - define([], factory); + define(['bower_components/lodash/dist/lodash.core.min'], factory); } else { // Browser globals root.loot = root.loot || {}; - root.loot.Plugin = factory(); + root.loot.Plugin = factory(root._); } -}(this, () => { +}(this, (_) => { /* Messages, tags, CRCs and version strings can all be hidden by filters. Use getters with no setters for member variables as data should not be written to objects of this class. */ @@ -168,7 +168,7 @@ constructor(obj) { /* Plugin data */ this.name = obj.name; - this.crc = obj.crc || 0; + this._crc = obj.crc || 0; this.version = obj.version || ''; this.isActive = obj.isActive || false; this.isEmpty = obj.isEmpty || false; @@ -181,7 +181,7 @@ this.priority = obj.priority || 0; this.isPriorityGlobal = obj.isPriorityGlobal || false; this._messages = obj.messages || []; - this.tags = obj.tags; + this._tags = obj.tags; this._isDirty = obj.isDirty || false; /* UI state variables */ @@ -240,6 +240,12 @@ return this.priority.toString(); } + _dispatchCardContentChangeEvent() { + document.dispatchEvent(new CustomEvent('loot-plugin-card-content-change', { + detail: { pluginId: this.id }, + })); + } + get messages() { return this._messages; } @@ -273,17 +279,21 @@ } }); - if (newTotal !== oldTotal || newWarns !== oldWarns || newErrs !== oldErrs) { + if (newTotal !== oldTotal + || newWarns !== oldWarns + || newErrs !== oldErrs + || !_.isEqual(this._messages, messages)) { + this._messages = messages; + document.dispatchEvent(new CustomEvent('loot-plugin-message-change', { detail: { + pluginId: this.id, totalDiff: newTotal - oldTotal, warningDiff: newWarns - oldWarns, errorDiff: newErrs - oldErrs, }, })); } - - this._messages = messages; } get isDirty() { @@ -293,14 +303,38 @@ set isDirty(dirty) { /* Update dirty counts. */ if (dirty !== this._isDirty) { + this._isDirty = dirty; + document.dispatchEvent(new CustomEvent('loot-plugin-isdirty-change', { detail: { isDirty: dirty, }, })); } + } - this._isDirty = dirty; + get crc() { + return this._crc; + } + + set crc(crc) { + if (this._crc !== crc) { + this._crc = crc; + + this._dispatchCardContentChangeEvent(); + } + } + + get tags() { + return this._tags; + } + + set tags(tags) { + if (!_.isEqual(this._tags, tags)) { + this._tags = tags; + + this._dispatchCardContentChangeEvent(); + } } get hasUserEdits() { @@ -317,6 +351,7 @@ document.getElementById('totalWarningNo').textContent = parseInt(document.getElementById('totalWarningNo').textContent, 10) + evt.detail.warningDiff; document.getElementById('totalErrorNo').textContent = parseInt(document.getElementById('totalErrorNo').textContent, 10) + evt.detail.errorDiff; } + static onIsDirtyChange(evt) { if (evt.detail.isDirty) { document.getElementById('dirtyPluginNo').textContent = parseInt(document.getElementById('dirtyPluginNo').textContent, 10) + 1; @@ -324,5 +359,12 @@ document.getElementById('dirtyPluginNo').textContent = parseInt(document.getElementById('dirtyPluginNo').textContent, 10) - 1; } } + + static onContentChange(evt) { + const card = document.getElementById(evt.detail.pluginId); + if (card) { + card.updateContent(); + } + } }; })); diff --git a/src/tests/gui/html/js/test.html b/src/tests/gui/html/js/test.html index 44de2886..11efd275 100644 --- a/src/tests/gui/html/js/test.html +++ b/src/tests/gui/html/js/test.html @@ -9,6 +9,7 @@ + diff --git a/src/tests/gui/html/js/test_plugin.js b/src/tests/gui/html/js/test_plugin.js index 928d391e..76093c92 100644 --- a/src/tests/gui/html/js/test_plugin.js +++ b/src/tests/gui/html/js/test_plugin.js @@ -357,7 +357,7 @@ describe('Plugin', () => { }]; const plugin = new loot.Plugin({ name: 'test', - messages: messages, + messages, }); plugin.messages.should.be.deepEqual(messages); @@ -378,7 +378,7 @@ describe('Plugin', () => { plugin.messages.should.be.deepEqual(messages); }); - it('setting messages should not fire an event if no message counts were changed', (done) => { + it('setting messages should not fire an event if no messages were changed', (done) => { const plugin = new loot.Plugin({ name: 'test', messages: [{ @@ -386,10 +386,6 @@ describe('Plugin', () => { content: 'test message', }], }); - const messages = [{ - type: 'say', - content: 'another test message', - }]; handleEvent = () => { done(new Error('Should not have fired an event')); @@ -397,12 +393,12 @@ describe('Plugin', () => { document.addEventListener('loot-plugin-message-change', handleEvent); - plugin.messages = messages; + plugin.messages = plugin.messages; setTimeout(done, 100); }); - it('setting messages should fire an event if message counts were changed', (done) => { + it('setting messages should fire an event if the messages were changed', (done) => { const plugin = new loot.Plugin({ name: 'test', messages: [], @@ -413,6 +409,7 @@ describe('Plugin', () => { }]; handleEvent = (evt) => { + evt.detail.pluginId.should.equal(plugin.id); evt.detail.totalDiff.should.equal(1); evt.detail.warningDiff.should.equal(0); evt.detail.errorDiff.should.equal(1); @@ -483,6 +480,131 @@ describe('Plugin', () => { }); }); + describe('#crc', () => { + let handleEvent; + + afterEach(() => { + document.removeEventListener('loot-plugin-card-content-change', handleEvent); + }); + + it('getting value should return 0 if crc has not been set in the constructor', () => { + const plugin = new loot.Plugin({ name: 'test' }); + + plugin.isDirty.should.be.false(); + }); + + it('getting value should return 0xDEADBEEF if it was set in the constructor', () => { + const plugin = new loot.Plugin({ + name: 'test', + crc: 0xDEADBEEF, + }); + + plugin.crc.should.equal(0xDEADBEEF); + }); + + it('setting value should store set value', () => { + const plugin = new loot.Plugin({ name: 'test' }); + + plugin.crc = 0xDEADBEEF; + + plugin.crc.should.equal(0xDEADBEEF); + }); + + it('setting value to the current value should not fire an event', (done) => { + const plugin = new loot.Plugin({ name: 'test' }); + + handleEvent = () => { + done(new Error('Should not have fired an event')); + }; + + document.addEventListener('loot-plugin-card-content-change', handleEvent); + + plugin.crc = plugin.crc; + + setTimeout(done, 100); + }); + + it('setting value not equal to the current value should fire an event', (done) => { + const plugin = new loot.Plugin({ name: 'test' }); + + handleEvent = (evt) => { + evt.detail.pluginId.should.equal(plugin.id); + done(); + }; + + document.addEventListener('loot-plugin-card-content-change', handleEvent); + + plugin.crc = 0xDEADBEEF; + }); + }); + + describe('#tags', () => { + let handleEvent; + + afterEach(() => { + document.removeEventListener('loot-plugin-card-content-change', handleEvent); + }); + + it('getting value should return an empty array if tags have not been set in the constructor', () => { + const plugin = new loot.Plugin({ name: 'test' }); + + plugin.tags.length.should.equal(0); + }); + + it('getting value should return any tags that are set', () => { + const tags = [{ + name: 'Delev', + }]; + const plugin = new loot.Plugin({ + name: 'test', + tags, + }); + + plugin.tags.should.deepEqual(tags); + }); + + it('setting value should store set value', () => { + const plugin = new loot.Plugin({ name: 'test' }); + const tags = [{ + name: 'Delev', + }]; + + plugin.tags = tags; + + plugin.tags.should.deepEqual(tags); + }); + + it('setting value to the current value should not fire an event', (done) => { + const plugin = new loot.Plugin({ name: 'test' }); + + handleEvent = () => { + done(new Error('Should not have fired an event')); + }; + + document.addEventListener('loot-plugin-card-content-change', handleEvent); + + plugin.tags = plugin.tags; + + setTimeout(done, 100); + }); + + it('setting value not equal to the current value should fire an event', (done) => { + const plugin = new loot.Plugin({ name: 'test' }); + const tags = [{ + name: 'Delev', + }]; + + handleEvent = (evt) => { + evt.detail.pluginId.should.equal(plugin.id); + done(); + }; + + document.addEventListener('loot-plugin-card-content-change', handleEvent); + + plugin.tags = tags; + }); + }); + describe('#getCardContent()', () => { let plugin; beforeEach(() => {