diff --git a/chrome/content/zotero/preferences/preferences.js b/chrome/content/zotero/preferences/preferences.js index 1bd99db043..912b69c0ca 100644 --- a/chrome/content/zotero/preferences/preferences.js +++ b/chrome/content/zotero/preferences/preferences.js @@ -270,10 +270,10 @@ var Zotero_Preferences = { ? MozXULElement.parseXULToFragment(markup, dtdFiles) : this._parseXHTMLToFragment(markup, dtdFiles); contentFragment = document.importNode(contentFragment, true); + this._initImportedNodesPreInsert(contentFragment); pane.container.append(contentFragment); pane.imported = true; - - this._initImportedNodes(pane.container); + this._initImportedNodesPostInsert(pane.container); } pane.container.hidden = false; @@ -312,14 +312,41 @@ ${str} return range.extractContents(); }, - _initImportedNodes(root) { + /** + * To be called before insertion into the document tree: + * Move all processing instructions (XML ) found in the imported fragment into the document root + * so that they actually have an effect. This essentially "activates" nodes. + * + * @param {DocumentFragment} fragment + * @private + */ + _initImportedNodesPreInsert(fragment) { + let processingInstrWalker = document.createTreeWalker(fragment, NodeFilter.SHOW_PROCESSING_INSTRUCTION); + let processingInstr = processingInstrWalker.currentNode; + while (processingInstr) { + document.insertBefore(document.createProcessingInstruction(processingInstr.target, processingInstr.data), document.firstChild); + if (processingInstr.parentNode) { + processingInstr.parentNode.removeChild(processingInstr); + } + processingInstr = processingInstrWalker.nextNode(); + } + }, + + /** + * To be called after insertion into the document tree: + * Activates `preference` attributes and inline oncommand handlers and dispatches a load event at the end. + * + * @param {Element} container + * @private + */ + _initImportedNodesPostInsert(container) { // Activate `preference` attributes - for (let elem of root.querySelectorAll('[preference]')) { + for (let elem of container.querySelectorAll('[preference]')) { let preference = elem.getAttribute('preference'); - if (root.querySelector('preferences > preference#' + preference)) { + if (container.querySelector('preferences > preference#' + preference)) { Zotero.warn(' is deprecated -- `preference` attribute values ' + 'should be full preference keys, not IDs'); - preference = root.querySelector('preferences > preference#' + preference) + preference = container.querySelector('preferences > preference#' + preference) .getAttribute('name'); } @@ -356,11 +383,11 @@ ${str} // parseXULToFragment() doesn't convert oncommand attributes into actual // listeners, so we'll do it here - for (let elem of root.querySelectorAll('[oncommand]')) { + for (let elem of container.querySelectorAll('[oncommand]')) { elem.oncommand = elem.getAttribute('oncommand'); } - for (let child of root.children) { + for (let child of container.children) { child.dispatchEvent(new Event('load')); } }, diff --git a/chrome/content/zotero/xpcom/preferencePanes.js b/chrome/content/zotero/xpcom/preferencePanes.js index f1206d2302..f38f773949 100644 --- a/chrome/content/zotero/xpcom/preferencePanes.js +++ b/chrome/content/zotero/xpcom/preferencePanes.js @@ -127,7 +127,7 @@ Zotero.PreferencePanes = { src: options.src, extraDTD: options.extraDTD, scripts: options.scripts, - defaultXUL: false, + defaultXUL: true, helpURL: options.helpURL, };