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(() => {