fx-compat: Preferences: Manage pref observers for elements added later
This commit is contained in:
parent
e4b290a394
commit
3af5976aa2
2 changed files with 82 additions and 26 deletions
|
@ -30,8 +30,9 @@ var Zotero_Preferences = {
|
||||||
|
|
||||||
_firstPaneLoadDeferred: Zotero.Promise.defer(),
|
_firstPaneLoadDeferred: Zotero.Promise.defer(),
|
||||||
|
|
||||||
|
_observerSymbols: new Map(),
|
||||||
|
|
||||||
init: function () {
|
init: function () {
|
||||||
this._observerSymbols = [];
|
|
||||||
this.navigation = document.getElementById('prefs-navigation');
|
this.navigation = document.getElementById('prefs-navigation');
|
||||||
this.content = document.getElementById('prefs-content');
|
this.content = document.getElementById('prefs-content');
|
||||||
this.helpContainer = document.getElementById('prefs-help-container');
|
this.helpContainer = document.getElementById('prefs-help-container');
|
||||||
|
@ -96,9 +97,10 @@ var Zotero_Preferences = {
|
||||||
},
|
},
|
||||||
|
|
||||||
onUnload: function () {
|
onUnload: function () {
|
||||||
while (this._observerSymbols.length) {
|
for (let symbol of this._observerSymbols.values()) {
|
||||||
Zotero.Prefs.unregisterObserver(this._observerSymbols.shift());
|
Zotero.Prefs.unregisterObserver(symbol);
|
||||||
}
|
}
|
||||||
|
this._observerSymbols.clear();
|
||||||
},
|
},
|
||||||
|
|
||||||
waitForFirstPaneLoad: async function () {
|
waitForFirstPaneLoad: async function () {
|
||||||
|
@ -326,6 +328,49 @@ ${str}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_initImportedNodesPostInsert(container) {
|
_initImportedNodesPostInsert(container) {
|
||||||
|
let useChecked = elem => (
|
||||||
|
(elem instanceof HTMLInputElement && elem.type == 'checkbox')
|
||||||
|
|| elem.tagName == 'checkbox'
|
||||||
|
);
|
||||||
|
|
||||||
|
let syncFromPref = (elem, preference) => {
|
||||||
|
let value = Zotero.Prefs.get(preference, true);
|
||||||
|
if (useChecked(elem)) {
|
||||||
|
elem.checked = value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
elem.value = value;
|
||||||
|
}
|
||||||
|
elem.dispatchEvent(new Event('syncfrompreference'));
|
||||||
|
};
|
||||||
|
|
||||||
|
// We use a single listener function shared between all elements so we can easily detach it later
|
||||||
|
let syncToPrefOnModify = (event) => {
|
||||||
|
if (event.currentTarget.getAttribute('preference')) {
|
||||||
|
let value = useChecked(event.currentTarget) ? event.currentTarget.checked : event.currentTarget.value;
|
||||||
|
Zotero.Prefs.set(event.currentTarget.getAttribute('preference'), value, true);
|
||||||
|
event.currentTarget.dispatchEvent(new Event('synctopreference'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let attachToPreference = (elem, preference) => {
|
||||||
|
Zotero.debug(`Attaching <${elem.tagName}> element to ${preference}`);
|
||||||
|
let symbol = Zotero.Prefs.registerObserver(
|
||||||
|
preference,
|
||||||
|
() => syncFromPref(elem, preference),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
this._observerSymbols.set(elem, symbol);
|
||||||
|
};
|
||||||
|
|
||||||
|
let detachFromPreference = (elem) => {
|
||||||
|
if (this._observerSymbols.has(elem)) {
|
||||||
|
Zotero.debug(`Detaching <${elem.tagName}> element from preference`);
|
||||||
|
Zotero.Prefs.unregisterObserver(this._observerSymbols.get(elem));
|
||||||
|
this._observerSymbols.delete(elem);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Activate `preference` attributes
|
// Activate `preference` attributes
|
||||||
for (let elem of container.querySelectorAll('[preference]')) {
|
for (let elem of container.querySelectorAll('[preference]')) {
|
||||||
let preference = elem.getAttribute('preference');
|
let preference = elem.getAttribute('preference');
|
||||||
|
@ -336,30 +381,13 @@ ${str}
|
||||||
.getAttribute('name');
|
.getAttribute('name');
|
||||||
}
|
}
|
||||||
|
|
||||||
let useChecked = (elem instanceof HTMLInputElement && elem.type == 'checkbox')
|
attachToPreference(elem, preference);
|
||||||
|| elem.tagName == 'checkbox';
|
|
||||||
|
|
||||||
elem.addEventListener(elem instanceof XULElement ? 'command' : 'input', () => {
|
elem.addEventListener(elem instanceof XULElement ? 'command' : 'input', syncToPrefOnModify);
|
||||||
let value = useChecked ? elem.checked : elem.value;
|
|
||||||
Zotero.Prefs.set(preference, value, true);
|
|
||||||
elem.dispatchEvent(new Event('synctopreference'));
|
|
||||||
});
|
|
||||||
|
|
||||||
let syncFromPref = () => {
|
// Set timeout before populating the value so the pane can add listeners first
|
||||||
let value = Zotero.Prefs.get(preference, true);
|
|
||||||
if (useChecked) {
|
|
||||||
elem.checked = value;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
elem.value = value;
|
|
||||||
}
|
|
||||||
elem.dispatchEvent(new Event('syncfrompreference'));
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set timeout so pane can add listeners first
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
syncFromPref();
|
syncFromPref(elem, preference);
|
||||||
this._observerSymbols.push(Zotero.Prefs.registerObserver(preference, syncFromPref, true));
|
|
||||||
|
|
||||||
// If this is the first pane to be loaded, notify anyone waiting
|
// If this is the first pane to be loaded, notify anyone waiting
|
||||||
// (for tests)
|
// (for tests)
|
||||||
|
@ -367,6 +395,34 @@ ${str}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new MutationObserver((mutations) => {
|
||||||
|
for (let mutation of mutations) {
|
||||||
|
if (mutation.type == 'attributes') {
|
||||||
|
let target = mutation.target;
|
||||||
|
detachFromPreference(target);
|
||||||
|
if (target.hasAttribute('preference')) {
|
||||||
|
attachToPreference(target, target.getAttribute('preference'));
|
||||||
|
target.addEventListener(target instanceof XULElement ? 'command' : 'input', syncToPrefOnModify);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mutation.type == 'childList') {
|
||||||
|
for (let node of mutation.removedNodes) {
|
||||||
|
detachFromPreference(node);
|
||||||
|
}
|
||||||
|
for (let node of mutation.addedNodes) {
|
||||||
|
if (node.nodeType == Node.ELEMENT_NODE && node.hasAttribute('preference')) {
|
||||||
|
attachToPreference(node);
|
||||||
|
node.addEventListener(node instanceof XULElement ? 'command' : 'input', syncToPrefOnModify);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).observe(container, {
|
||||||
|
childList: true,
|
||||||
|
subtree: true,
|
||||||
|
attributeFilter: ['preference']
|
||||||
|
});
|
||||||
|
|
||||||
// parseXULToFragment() doesn't convert oncommand attributes into actual
|
// parseXULToFragment() doesn't convert oncommand attributes into actual
|
||||||
// listeners, so we'll do it here
|
// listeners, so we'll do it here
|
||||||
for (let elem of container.querySelectorAll('[oncommand]')) {
|
for (let elem of container.querySelectorAll('[oncommand]')) {
|
||||||
|
|
|
@ -65,12 +65,12 @@ Zotero_Preferences.Export = {
|
||||||
this.buildQuickCopyFormatDropDown(
|
this.buildQuickCopyFormatDropDown(
|
||||||
menulist, format.contentType, format, translators
|
menulist, format.contentType, format, translators
|
||||||
);
|
);
|
||||||
menulist.setAttribute('preference', "pref-quickCopy-setting");
|
menulist.setAttribute('preference', "extensions.zotero.export.quickCopy.setting");
|
||||||
|
|
||||||
// Initialize locale drop-down
|
// Initialize locale drop-down
|
||||||
var localeMenulist = document.getElementById("zotero-quickCopy-locale-menu");
|
var localeMenulist = document.getElementById("zotero-quickCopy-locale-menu");
|
||||||
Zotero.Styles.populateLocaleList(localeMenulist);
|
Zotero.Styles.populateLocaleList(localeMenulist);
|
||||||
localeMenulist.setAttribute('preference', "pref-quickCopy-locale");
|
localeMenulist.setAttribute('preference', "extensions.zotero.export.quickCopy.locale");
|
||||||
|
|
||||||
this._lastSelectedLocale = Zotero.Prefs.get("export.quickCopy.locale");
|
this._lastSelectedLocale = Zotero.Prefs.get("export.quickCopy.locale");
|
||||||
this.updateQuickCopyUI();
|
this.updateQuickCopyUI();
|
||||||
|
|
Loading…
Reference in a new issue