diff --git a/src/gui/html/js/init.js b/src/gui/html/js/init.js
index 9f192a01..72a3eab1 100644
--- a/src/gui/html/js/init.js
+++ b/src/gui/html/js/init.js
@@ -99,6 +99,7 @@
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);
+ document.addEventListener('loot-plugin-item-content-change', Plugin.onItemContentChange);
/* 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 6d3102af..ed72bcd8 100644
--- a/src/gui/html/js/plugin.js
+++ b/src/gui/html/js/plugin.js
@@ -176,10 +176,10 @@
this.loadsArchive = obj.loadsArchive || false;
this.masterlist = obj.masterlist;
- this.userlist = obj.userlist;
+ this._userlist = obj.userlist;
- this.priority = obj.priority || 0;
- this.isPriorityGlobal = obj.isPriorityGlobal || false;
+ this._priority = obj.priority || 0;
+ this._isPriorityGlobal = obj.isPriorityGlobal || false;
this._messages = obj.messages || [];
this._tags = obj.tags || [];
this._isDirty = obj.isDirty || false;
@@ -187,7 +187,7 @@
/* UI state variables */
this.id = this.name.replace(/\s+/g, '');
this.isMenuOpen = false;
- this.isEditorOpen = false;
+ this._isEditorOpen = false;
this.isConflictFilterChecked = false;
this.isSearchResult = false;
}
@@ -238,6 +238,18 @@
}));
}
+ _dispatchItemContentChangeEvent() {
+ document.dispatchEvent(new CustomEvent('loot-plugin-item-content-change', {
+ detail: {
+ pluginId: this.id,
+ priority: this.priority,
+ isPriorityGlobal: this.isPriorityGlobal,
+ isEditorOpen: this.isEditorOpen,
+ hasUserEdits: this.hasUserEdits,
+ },
+ }));
+ }
+
get messages() {
return this._messages;
}
@@ -330,7 +342,55 @@
}
get hasUserEdits() {
- return this.userlist && Object.keys(this.userlist).length > 1;
+ return this.userlist !== undefined && Object.keys(this.userlist).length > 1;
+ }
+
+ get userlist() {
+ return this._userlist;
+ }
+
+ set userlist(userlist) {
+ if (!_.isEqual(this._userlist, userlist)) {
+ this._userlist = userlist;
+
+ this._dispatchItemContentChangeEvent();
+ }
+ }
+
+ get priority() {
+ return this._priority;
+ }
+
+ set priority(priority) {
+ if (this._priority !== priority) {
+ this._priority = priority;
+
+ this._dispatchItemContentChangeEvent();
+ }
+ }
+
+ get isPriorityGlobal() {
+ return this._isPriorityGlobal;
+ }
+
+ set isPriorityGlobal(isPriorityGlobal) {
+ if (this._isPriorityGlobal !== isPriorityGlobal) {
+ this._isPriorityGlobal = isPriorityGlobal;
+
+ this._dispatchItemContentChangeEvent();
+ }
+ }
+
+ get isEditorOpen() {
+ return this._isEditorOpen;
+ }
+
+ set isEditorOpen(isEditorOpen) {
+ if (this._isEditorOpen !== isEditorOpen) {
+ this._isEditorOpen = isEditorOpen;
+
+ this._dispatchItemContentChangeEvent();
+ }
}
getCardContent(filters) {
@@ -358,5 +418,27 @@
card.updateContent();
}
}
+
+ static onItemContentChange(evt) {
+ const item = document.getElementById('cardsNav').querySelector(`[data-id="${evt.detail.pluginId}"]`);
+ if (item) {
+ item.setAttribute('priority', evt.detail.priority);
+ if (evt.detail.isPriorityGlobal) {
+ item.setAttribute('is-priority-global', '');
+ } else {
+ item.removeAttribute('is-priority-global');
+ }
+ if (evt.detail.isEditorOpen) {
+ item.setAttribute('is-editor-open', '');
+ } else {
+ item.removeAttribute('is-editor-open');
+ }
+ if (evt.detail.hasUserEdits) {
+ item.setAttribute('has-user-edits', '');
+ } else {
+ item.removeAttribute('has-user-edits');
+ }
+ }
+ }
};
}));
diff --git a/src/tests/gui/html/js/test_plugin.js b/src/tests/gui/html/js/test_plugin.js
index 6c46a6c7..ddbbcdce 100644
--- a/src/tests/gui/html/js/test_plugin.js
+++ b/src/tests/gui/html/js/test_plugin.js
@@ -646,6 +646,245 @@ describe('Plugin', () => {
});
});
+ describe('#userlist', () => {
+ let handleEvent;
+
+ afterEach(() => {
+ document.removeEventListener('loot-plugin-item-content-change', handleEvent);
+ });
+
+ it('getting value should return undefined if it has not been set in the constructor', () => {
+ const plugin = new loot.Plugin({ name: 'test' });
+
+ should(plugin.userlist).be.undefined();
+ });
+
+ it('getting value should return the value that was set', () => {
+ const plugin = new loot.Plugin({
+ name: 'test',
+ userlist: {},
+ });
+
+ plugin.userlist.should.deepEqual({});
+ });
+
+ it('setting value should store set value', () => {
+ const plugin = new loot.Plugin({ name: 'test' });
+
+ plugin.userlist = {};
+
+ plugin.userlist.should.deepEqual({});
+ });
+
+ 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-item-content-change', handleEvent);
+
+ plugin.userlist = plugin.userlist;
+
+ 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);
+ evt.detail.priority.should.equal(plugin.priority);
+ evt.detail.isPriorityGlobal.should.equal(plugin.isPriorityGlobal);
+ evt.detail.isEditorOpen.should.equal(plugin.isEditorOpen);
+ evt.detail.hasUserEdits.should.equal(plugin.hasUserEdits);
+ done();
+ };
+
+ document.addEventListener('loot-plugin-item-content-change', handleEvent);
+
+ plugin.userlist = { priority: 1 };
+ });
+ });
+
+ describe('#priority', () => {
+ let handleEvent;
+
+ afterEach(() => {
+ document.removeEventListener('loot-plugin-item-content-change', handleEvent);
+ });
+
+ it('getting value should return 0 if it has not been set in the constructor', () => {
+ const plugin = new loot.Plugin({ name: 'test' });
+
+ plugin.priority.should.equal(0);
+ });
+
+ it('getting value should return the value that was set', () => {
+ const plugin = new loot.Plugin({
+ name: 'test',
+ priority: 5,
+ });
+
+ plugin.priority.should.equal(5);
+ });
+
+ it('setting value should store set value', () => {
+ const plugin = new loot.Plugin({ name: 'test' });
+
+ plugin.priority = 5;
+
+ plugin.priority.should.equal(5);
+ });
+
+ 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-item-content-change', handleEvent);
+
+ plugin.priority = plugin.priority;
+
+ 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);
+ evt.detail.priority.should.equal(plugin.priority);
+ evt.detail.isPriorityGlobal.should.equal(plugin.isPriorityGlobal);
+ evt.detail.isEditorOpen.should.equal(plugin.isEditorOpen);
+ evt.detail.hasUserEdits.should.equal(plugin.hasUserEdits);
+ done();
+ };
+
+ document.addEventListener('loot-plugin-item-content-change', handleEvent);
+
+ plugin.priority = 5;
+ });
+ });
+
+ describe('#isPriorityGlobal', () => {
+ let handleEvent;
+
+ afterEach(() => {
+ document.removeEventListener('loot-plugin-item-content-change', handleEvent);
+ });
+
+ it('getting value should return false if it has not been set in the constructor', () => {
+ const plugin = new loot.Plugin({ name: 'test' });
+
+ plugin.isPriorityGlobal.should.be.false();
+ });
+
+ it('getting value should return the value that was set', () => {
+ const plugin = new loot.Plugin({
+ name: 'test',
+ isPriorityGlobal: true,
+ });
+
+ plugin.isPriorityGlobal.should.be.true();
+ });
+
+ it('setting value should store set value', () => {
+ const plugin = new loot.Plugin({ name: 'test' });
+
+ plugin.isPriorityGlobal = true;
+
+ plugin.isPriorityGlobal.should.be.true();
+ });
+
+ 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-item-content-change', handleEvent);
+
+ plugin.isPriorityGlobal = plugin.isPriorityGlobal;
+
+ 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);
+ evt.detail.priority.should.equal(plugin.priority);
+ evt.detail.isPriorityGlobal.should.equal(plugin.isPriorityGlobal);
+ evt.detail.isEditorOpen.should.equal(plugin.isEditorOpen);
+ evt.detail.hasUserEdits.should.equal(plugin.hasUserEdits);
+ done();
+ };
+
+ document.addEventListener('loot-plugin-item-content-change', handleEvent);
+
+ plugin.isPriorityGlobal = true;
+ });
+ });
+
+ describe('#isEditorOpen', () => {
+ let handleEvent;
+
+ afterEach(() => {
+ document.removeEventListener('loot-plugin-item-content-change', handleEvent);
+ });
+
+ it('getting value should return false if it has not been set in the constructor', () => {
+ const plugin = new loot.Plugin({ name: 'test' });
+
+ plugin.isEditorOpen.should.be.false();
+ });
+
+ it('setting value should store set value', () => {
+ const plugin = new loot.Plugin({ name: 'test' });
+
+ plugin.isEditorOpen = true;
+
+ plugin.isEditorOpen.should.be.true();
+ });
+
+ 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-item-content-change', handleEvent);
+
+ plugin.isEditorOpen = plugin.isEditorOpen;
+
+ 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);
+ evt.detail.priority.should.equal(plugin.priority);
+ evt.detail.isPriorityGlobal.should.equal(plugin.isPriorityGlobal);
+ evt.detail.isEditorOpen.should.equal(plugin.isEditorOpen);
+ evt.detail.hasUserEdits.should.equal(plugin.hasUserEdits);
+ done();
+ };
+
+ document.addEventListener('loot-plugin-item-content-change', handleEvent);
+
+ plugin.isEditorOpen = true;
+ });
+ });
+
describe('#getCardContent()', () => {
let plugin;
beforeEach(() => {