Bug 1462798 - Create a base custom element class that shares the parseXULToFragment helper;r=Paolo

MozReview-Commit-ID: IG84xKxO9Wc

--HG--
extra : rebase_source : bc46d1f4dcfee66523a2ede8ec32ef9014cf170c
This commit is contained in:
Brian Grinstead 2018-05-19 13:56:06 -07:00
Родитель 574e1467e0
Коммит 5fa9aadc74
10 изменённых файлов: 128 добавлений и 11 удалений

Просмотреть файл

@ -84,12 +84,8 @@ MainProcessSingleton.prototype = {
const doc = subject;
if (doc.nodePrincipal.isSystemPrincipal &&
doc.contentType == "application/vnd.mozilla.xul+xml") {
for (let script of [
"chrome://global/content/elements/stringbundle.js",
"chrome://global/content/elements/general.js",
]) {
Services.scriptloader.loadSubScript(script, doc.ownerGlobal);
}
Services.scriptloader.loadSubScript(
"chrome://global/content/customElements.js", doc.ownerGlobal);
}
break;

Просмотреть файл

@ -0,0 +1,73 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// This is loaded into all XUL windows. Wrap in a block to prevent
// leaking to window scope.
{
ChromeUtils.import("resource://gre/modules/Services.jsm");
const gXULDOMParser = new DOMParser();
gXULDOMParser.forceEnableXULXBL();
class MozXULElement extends XULElement {
/**
* Allows eager deterministic construction of XUL elements with XBL attached, by
* parsing an element tree and returning a DOM fragment to be inserted in the
* document before any of the inner elements is referenced by JavaScript.
*
* This process is required instead of calling the createElement method directly
* because bindings get attached when:
*
* 1) the node gets a layout frame constructed, or
* 2) the node gets its JavaScript reflector created, if it's in the document,
*
* whichever happens first. The createElement method would return a JavaScript
* reflector, but the element wouldn't be in the document, so the node wouldn't
* get XBL attached. After that point, even if the node is inserted into a
* document, it won't get XBL attached until either the frame is constructed or
* the reflector is garbage collected and the element is touched again.
*
* @param str
* String with the XML representation of XUL elements.
*
* @return DocumentFragment containing the corresponding element tree, including
* element nodes but excluding any text node.
*/
static parseXULToFragment(str) {
let doc = gXULDOMParser.parseFromString(`
<box xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
${str}
</box>
`, "application/xml");
// The XUL/XBL parser is set to ignore all-whitespace nodes, whereas (X)HTML
// does not do this. Most XUL code assumes that the whitespace has been
// stripped out, so we simply remove all text nodes after using the parser.
let nodeIterator = doc.createNodeIterator(doc, NodeFilter.SHOW_TEXT);
let currentNode = nodeIterator.nextNode();
while (currentNode) {
currentNode.remove();
currentNode = nodeIterator.nextNode();
}
// We use a range here so that we don't access the inner DOM elements from
// JavaScript before they are imported and inserted into a document.
let range = doc.createRange();
range.selectNodeContents(doc.firstChild);
return range.extractContents();
}
}
// Attach the base class to the window so other scripts can use it:
window.MozXULElement = MozXULElement;
for (let script of [
"chrome://global/content/elements/stringbundle.js",
"chrome://global/content/elements/general.js",
]) {
Services.scriptloader.loadSubScript(script, window);
}
}

Просмотреть файл

@ -46,6 +46,7 @@ toolkit.jar:
content/global/editMenuOverlay.js
#endif
content/global/filepicker.properties
content/global/customElements.js
content/global/globalOverlay.js
content/global/mozilla.xhtml
content/global/aboutMozilla.css

Просмотреть файл

@ -101,6 +101,7 @@ skip-if = toolkit == "cocoa"
[test_closemenu_attribute.xul]
[test_colorpicker_popup.xul]
[test_contextmenu_list.xul]
[test_custom_element_base.xul]
[test_deck.xul]
[test_dialogfocus.xul]
[test_findbar.xul]

Просмотреть файл

@ -0,0 +1,45 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
<window title="Custom Element Base Class Tests"
onload="runTests();"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
<!-- test code goes here -->
<script type="application/javascript"><![CDATA[
SimpleTest.waitForExplicitFinish();
function runTests() {
ok(MozXULElement, "MozXULElement defined on the window");
testParseXULToFragment();
SimpleTest.finish();
}
function testParseXULToFragment() {
ok(MozXULElement.parseXULToFragment, "parseXULToFragment helper exists");
let frag = MozXULElement.parseXULToFragment(`<deck id='foo' />`);
ok(frag instanceof DocumentFragment);
document.documentElement.appendChild(frag);
let deck = document.documentElement.lastChild;
ok(deck instanceof MozXULElement, "instance of MozXULElement");
ok(deck instanceof XULElement, "instance of XULElement");
is(deck.id, "foo", "attribute set");
is(deck.selectedIndex, "0", "Custom Element is property attached");
deck.remove();
}
]]>
</script>
</window>

Просмотреть файл

@ -6,7 +6,7 @@
{
class MozDeck extends XULElement {
class MozDeck extends MozXULElement {
set selectedIndex(val) {
if (this.selectedIndex == val) return val;
this.setAttribute("selectedIndex", val);
@ -35,7 +35,7 @@ class MozDeck extends XULElement {
customElements.define("deck", MozDeck);
class MozDropmarker extends XULElement {
class MozDropmarker extends MozXULElement {
connectedCallback() {
// Only create the image the first time we are connected
if (!this.firstChild) {

Просмотреть файл

@ -10,7 +10,7 @@
ChromeUtils.import("resource://gre/modules/Services.jsm");
class MozStringbundle extends XULElement {
class MozStringbundle extends MozXULElement {
get stringBundle() {
if (!this._bundle) {
try {

Просмотреть файл

@ -21,7 +21,7 @@
onload="initWizard();"
style="&window.size;">
<script type="application/javascript"
src="chrome://global/content/elements/stringbundle.js"/>
src="chrome://global/content/customElements.js"/>
<stringbundle id="bundle_profileManager"
src="chrome://mozapps/locale/profile/profileSelection.properties"/>

Просмотреть файл

@ -30,7 +30,7 @@
buttonlabelcancel="&exit.label;">
<script type="application/javascript"
src="chrome://global/content/elements/stringbundle.js"/>
src="chrome://global/content/customElements.js"/>
<stringbundle id="bundle_profileManager"
src="chrome://mozapps/locale/profile/profileSelection.properties"/>

Просмотреть файл

@ -28,6 +28,7 @@ const rootDir = helpers.rootDir;
const EXTRA_SCRIPTS = [
"browser/base/content/nsContextMenu.js",
"toolkit/content/contentAreaUtils.js",
"toolkit/content/customElements.js",
"browser/components/places/content/editBookmark.js",
"browser/components/downloads/content/downloads.js",
"browser/components/downloads/content/indicator.js",