diff --git a/packages/docs/src/routes/api/qwik-testing/api.json b/packages/docs/src/routes/api/qwik-testing/api.json index 6655a5bf60d..61612a19941 100644 --- a/packages/docs/src/routes/api/qwik-testing/api.json +++ b/packages/docs/src/routes/api/qwik-testing/api.json @@ -61,7 +61,7 @@ } ], "kind": "Property", - "content": "```typescript\ndocument: MockDocument;\n```", + "content": "```typescript\ndocument: Document;\n```", "mdFile": "core.elementfixture.document.md" }, { @@ -88,7 +88,7 @@ } ], "kind": "Class", - "content": "Creates a simple DOM structure for testing components.\n\nBy default `EntityFixture` creates:\n\n```html\n\n \n\n```\n\n\n```typescript\nexport declare class ElementFixture \n```\n\n\n\n\n
\n\nConstructor\n\n\n\n\nModifiers\n\n\n\n\nDescription\n\n\n
\n\n[(constructor)(options)](#)\n\n\n\n\n\n\n\nConstructs a new instance of the `ElementFixture` class\n\n\n
\n\n\n\n\n\n\n\n\n\n
\n\nProperty\n\n\n\n\nModifiers\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\n[child](#elementfixture-child)\n\n\n\n\n\n\n\nHTMLElement\n\n\n\n\n\n
\n\n[document](#elementfixture-document)\n\n\n\n\n\n\n\nMockDocument\n\n\n\n\n\n
\n\n[host](#elementfixture-host)\n\n\n\n\n\n\n\nHTMLElement\n\n\n\n\n\n
\n\n[parent](#elementfixture-parent)\n\n\n\n\n\n\n\nHTMLElement\n\n\n\n\n\n
\n\n[superParent](#elementfixture-superparent)\n\n\n\n\n\n\n\nHTMLElement\n\n\n\n\n\n
\n\n[window](#elementfixture-window)\n\n\n\n\n\n\n\nMockWindow\n\n\n\n\n\n
", + "content": "Creates a simple DOM structure for testing components.\n\nBy default `EntityFixture` creates:\n\n```html\n\n \n\n```\n\n\n```typescript\nexport declare class ElementFixture \n```\n\n\n\n\n
\n\nConstructor\n\n\n\n\nModifiers\n\n\n\n\nDescription\n\n\n
\n\n[(constructor)(options)](#)\n\n\n\n\n\n\n\nConstructs a new instance of the `ElementFixture` class\n\n\n
\n\n\n\n\n\n\n\n\n\n
\n\nProperty\n\n\n\n\nModifiers\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\n[child](#elementfixture-child)\n\n\n\n\n\n\n\nHTMLElement\n\n\n\n\n\n
\n\n[document](#elementfixture-document)\n\n\n\n\n\n\n\nDocument\n\n\n\n\n\n
\n\n[host](#elementfixture-host)\n\n\n\n\n\n\n\nHTMLElement\n\n\n\n\n\n
\n\n[parent](#elementfixture-parent)\n\n\n\n\n\n\n\nHTMLElement\n\n\n\n\n\n
\n\n[superParent](#elementfixture-superparent)\n\n\n\n\n\n\n\nHTMLElement\n\n\n\n\n\n
\n\n[window](#elementfixture-window)\n\n\n\n\n\n\n\nReturnType<typeof createWindow>\n\n\n\n\n\n
", "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/testing/element-fixture.ts", "mdFile": "core.elementfixture.md" }, @@ -255,7 +255,7 @@ } ], "kind": "Property", - "content": "```typescript\nwindow: MockWindow;\n```", + "content": "```typescript\nwindow: ReturnType;\n```", "mdFile": "core.elementfixture.window.md" } ] diff --git a/packages/docs/src/routes/api/qwik-testing/index.md b/packages/docs/src/routes/api/qwik-testing/index.md index b8b4645fa0f..e283a609ef8 100644 --- a/packages/docs/src/routes/api/qwik-testing/index.md +++ b/packages/docs/src/routes/api/qwik-testing/index.md @@ -106,7 +106,7 @@ Promise<{ render: (jsxElement: JSXOutput) => Promise<import("@qwik.dev/ ## document ```typescript -document: MockDocument; +document: Document; ``` ## domRender @@ -249,7 +249,7 @@ HTMLElement -MockDocument +Document @@ -301,7 +301,7 @@ HTMLElement -MockWindow +ReturnType<typeof createWindow> @@ -669,5 +669,5 @@ void ## window ```typescript -window: MockWindow; +window: ReturnType; ``` diff --git a/packages/qwik-dom/CHANGELOG.md b/packages/qwik-dom/CHANGELOG.md deleted file mode 100644 index 7c89b152721..00000000000 --- a/packages/qwik-dom/CHANGELOG.md +++ /dev/null @@ -1,331 +0,0 @@ -# domino x.x.x (not yet released) - -# domino 2.1.6 (16 Jul 2020) - -- Bumped version of lodash (#169) -- Performance improvement to DOMTokenList (#166) -- `mocha` dependency has been updated to 6.x. As a result, we are - no longer testing on node 4. - -# domino 2.1.5 (30 Apr 2020) - -- Bumped version of jquery dev dependency (#163) -- Omit tests/ directory from NPM package (#161) - -# domino 2.1.4 (16 Dec 2019) - -- Bug fix for `Element#closest` when selector doesn't match (#154) - -# domino 2.1.3 (6 Mar 2019) - -- Bug fix for CSS `$=` selector and for matches on root `` element. -- Renamed CSS `:matches` to `:is` - ( https://github.com/w3c/csswg-drafts/issues/3258 ) -- Bug fix for CSS matches with escape characters in tag name. - -# domino 2.1.2 (14 Feb 2019) - -- Allow writable Element constructors unless **domino_frozen** is set to true (#138) -- Bug fix for CSS `$=` selector. (#135) -- Move `Node#_serializeOne()` to `NodeUtils.serializeOne()` to reduce pressure - on the megamorphic stub cache in V8, and thereby improve throughput (#142). -- Implemented `HTMLOptionElement#text` and `HTMLOptionElement#value` (#136) - -# domino 2.1.1 (30 Nov 2018) - -- Add `domino.createIncrementalHTMLParser` interface. - -# domino 2.1.0 (13 Aug 2018) - -- Fix `ContainerNode#removeChildren()` when there is more than one child (#129) -- Implement `Document#scrollingElement` (#107) -- Implement setter for `Element#outerHTML` (#102) -- Handle null/undefined in setter for `Node#textContent` -- Handle null/undefined/negative values in `CharacterData` interface methods -- Spec-correctness fixes for `DOMTokenList`, including handling of duplicate - keys. -- Fix `[src=...]` selectors in `Document#querySelector()` and similar -- Spec-correctness fixes for `Document#createElement()` and - `Document#createElementNS()`, including proper exception type and type - coercion. -- Implement `Attr#cloneNode()`, `Element#getAttributeNode()`, - `Element#getAttributeNodeNS()`, `Element#setAttributeNode()`, - `Element#setAttributeNodeNS()`, and `Element#removeAttributeNode()` - (DOM3 compatibility) -- Implement `Document#createAttribute()` and `Document#createAttributeNS()` -- Implement `Element#hasAttributes()`, `Element#toggleAttribute()`, and - `Element#getAttributeNames()` -- Implement `Text#wholeText` -- Implement `Document#cloneNode()` and `DocumentType#cloneNode()` -- Spec-correctness fixes for `Node#lookupPrefix()`, - `Node#lookupNamespaceURI()`, and `Node#isDefaultNamespace`, including - proper type coercion and reconciling DOM 3 and DOM 4 specifications. -- Ensure `Document#title` continues to use correct whitespace stripping - for node > 4, and properly set `` when `undefined` is passed to - `DOMImplementation#createHTMLDocument()` -- Ensure `Element#attributes` implements `NamedNodeMap` and that indexed - properties of `Element#attributes` work (previously you needed to use - the `item()` accessor method) -- Improve stubs for `HTMLElement#style`, `Document#documentURI`, and - `Document#contentType` -- Implement proper accessors for `HTMLSelectElement#autocomplete`, - `HTMLTextAreaElement#type/value/defaultValue/textLength`, and - `HTMLInputElement#width/height/minLength` -- Implement `Element#insertAdjacentElement()`, `Element#insertAdjacentText()`, - and `Element#insertAdjacentHTML()` (#102) -- Spec-correctness fixes for `TreeWalker` and `NodeIterator`: read-only - properties, proper exception types, type coercion of `NodeFilter` results. -- Implement `NodeIterator` pre-removal steps. Note that in the absence - of weak references, be cautious about the number of `NodeIterator`s you - create on any single document, since domino does not artificially limit - these. - See https://github.com/tc39/proposal-weakrefs/issues/17 for details. -- Preserve prefix of SVG elements during parsing. (#102) - -# domino 2.0.3 (12 Jul 2018) - -- Define `blur()`, `focus()` and `forceSpellCheck()` on `HTMLElement` (#125) -- Stringify argument tokens for DOMTokenList methods (#126) -- Fix `HTMLAnchorElement#hash` when `href` attribute contains bare - fragment (#127) -- Implement case-insensitive CSS attribute matching (#128) -- Implement `DOMTokenList#replace()`, `DOMTokenList#toggle(token, force)`, - and `DOMTokenList#value`. Fix handling of non-space whitespace. (#111) - -# domino 2.0.2 (28 Mar 2018) - -- Add TypeScript definitions (#103) -- Add `flex` CSS styles (#119, #120) -- Fix Element#matches with ~= selectors (#121) - -# domino 2.0.1 (14 Feb 2018) - -- Allow attributes named 'xmlns' (#112) -- Make DOMTokenList add/remove variadic (#109) -- Make `Array.from` and for-of loops work on `Node#attributes`. - -# domino 2.0.0 ( 8 Nov 2017) - -- Fix potential O(N^2) slowdown in FilteredElementList#item. -- `mocha` dependency has been updated to 4.0.x. As a result, we are - no longer testing on node pre-v4.0.0; see: - https://boneskull.com/mocha-v4-nears-release/ -- Domino now uses a linked list representation for children of Node, - unless/until the Node#childNodes accessor is used (which requires - an indexed array to be built). Inserting a removing nodes can be - much quicker using the linked list representation if care is - taken not to deoptimize the tree by using the #childNodes accessor. - This implementation strategy matches the one used by webkit and - other browser-based implementations, and thus ought to match - performance expectations of folks used to writing browser-based - DOM manipulation code. - -# domino 1.0.30 (24 Oct 2017) - -- Fix regexp capitalization in URLUtils (#101) -- Fix O(N^2) slowdown in initial tree traversal using nextSibling/prevSibling -- Update `mocha` dependency to 3.5.x and `should` to 13.1.x. - -# domino 1.0.29 ( 7 Aug 2017) - -- Fix "#id" optimization in querySelectorAll() when 0 or 2 matches for - `id`. (#99) -- Correct return value of CSSStyleDeclaration#getPropertyValue() when - style is not set. (#98) - -# domino 1.0.28 (27 Jan 2017) - -- Fix unescape mechanism in attribute values. (#95) -- Disable nonstandard "ignore case" version of attribute matching. -- Add `dom/nodes` tests from w3c/web-platform-tests. (#92, @pimterry) -- Make selected API methods writable to support polyfills. (#89, @pimterry) -- Fix `Element#hasAttribute`/`Element#hasAttributeNS` after - `Element#removeAttribute`/`Element#removeAttributeNS`. (#90, @clint-tseng) -- Fix deep `Document#importNode`. (#93) -- Ensure that `Node#parentNode` is `null` (not `undefined`) when removed. -- Add an optional second argument to `domino.createWindow` to specify - the document's address. -- Tweak JavaScript properties which are DOM reflections of element - attributes in order to more closely match the DOM 4 spec. -- Implement `ChildNode#before()`, `ChildNode#after()`, and - `ChildNode#replaceWith()`. - -# domino 1.0.27 (17 Oct 2016) - -- Fix bug in AFE list replacement over existing bookmark. -- Update htmlwg test suite to latest w3c/web-platform-tests. -- Update html5lib test suite to latest. -- HTML5 spec update: <menuitem> is no longer an empty element. -- HTML5 spec update: tweaked HTML entity parsing in attributes. -- HTML5 spec update: dashes are allowed in HTML comments. -- HTML5 spec update: remove special handling of <isindex>. -- Improve handling of legacy elements: `<xmp>`, `<listing>`, `acronym`, - `basefont`, `big`, `center`, `nobr`, `noembed`, `noframes`, `plaintext`, - `rb`, `rtc`, `strike`, and `tt`. -- HTML5 spec update: Remove extra newline in serialization of `<pre>`, - `<listing>`, `<textarea>`. (#88) -- HTML5 spec update: Remove case normalization for defunct SVG attributes. -- Implement HTMLMenuItemElement#label. -- Basic SVG support. (#81, #82) - -# domino 1.0.26 (15 Oct 2016) - -- Implement Document#dir. -- Minor spec-compliance fixes to Document#title and classList#contains. -- Implement Element#closest(). (#84) -- Actually run the HTMLWG tests (#83) -- Expose the HTML5 tree builder implementation. (#87) -- Add workaround to W3C test harness for node >= 0.11.7. -- Update the form-associated element list to match HTML5. - -# domino 1.0.25 (19 May 2016) - -- Fix broken stopping of immediate propagation of Events. (#78) -- Properly set "scripting enabled" flag when parsing fragments. -- Fix handling of escaped or invalid CSS identifiers in - `querySelector` and friends. (#79) - -# domino 1.0.24 (05 Apr 2016) - -- Implement WindowTimers interface on Window. (#72) -- Factor out the NavigatorID interface and make more spec-compliant. -- Implement `HTMLTemplateElement` and parse `<template>` tags. -- Properly parse the `<main>` tag. -- Remove support for the non-standard `<command>` tag. -- Create `HTMLCanvasElement` when parsing `<canvas>` tags. -- Create `HTMLDialogElement` when parsing `<dialog>` tags. -- Fix parsing of `<ruby>` tags, especially `<rb>` and `<rtc>`. -- Create `HTMLMenuItemElement` when parsing `<menuitem>` tags. -- Create `HTMLSourceElement` when parsing `<source>` tags. -- Create `HTMLTrackElement` when parsing `<track>` tags. -- Improve parsing of `<svg>` elements. -- Fix parsing of `<isindex>` element in unusual contexts. -- Serialize `<!DOCTYPE>` according to latest HTML5 spec. -- Update adoption agency algorithm to match latest HTML5 spec. -- Add additional parameter to `domino.createDocument` to - allow creating a document from an empty string if desired. -- Add tree builder test cases from `html5lib-tests`. -- Implement `Document#location`. (#75) -- Stub out additional properties of `HTMLIFrameElement`. (#76) - -# domino 1.0.23 (30 Jan 2016) - -- Fix `CSSStyleDeclaration#setProperty`. (#71) -- Update bundled CSS parser to 0.2.5+domino1. - -# domino 1.0.22 (27 Jan 2016) - -- Prevent TypeError due to undefined property when parsing styles. (#68) -- Support legacy `Attr#nodeValue` and `Attr#textContent` aliases. (#70) - -# domino 1.0.21 (23 Dec 2015) - -- Improve performance when adding nodes with duplicate IDs. (#60) -- Be more careful about setting prototype to `null` when using - Objects as a Map. (#61) -- Fix a global leak in NodeIterator. -- Improve efficiency of `Node#replaceChild` and `Node#insert`. (#62) -- Bug fix for `Node#normalize` which could cause deletion of empty - `Comment` or `ProcessingInstruction` nodes. (#63) -- Don't lowercase non-ASCII tag and attribute names. (#65) -- Fix a number of minor bugs in rarely used code, discovered - during delinting. (#66) -- Implement `Node.contains`. (#67) - -# domino 1.0.20 (20 Nov 2015) - -- CharacterData implements the NonDocumentTypeChildNode - interface. (#57, #58) -- Fix CSS `[style]` selector. (#59) - -# domino 1.0.19 (29 Jul 2015) - -- Bug fixes for `TreeWalker` / `document.createTreeWalker` (filter - argument was ignored; various traversal issues) -- Implement `NodeIterator` / `document.createNodeIterator` (#54) -- Update `mocha` dependency to 2.2.x and `should` to 7.0.x. - -# domino 1.0.18 (25 Sep 2014) - -- HTMLAnchorElement now implements URLUtils. (#47) -- Be consistent with our handling of null/empty namespaces. (#48) -- Update `mocha` dependency to 1.21.x and `should` to 4.0.x. - -# domino 1.0.17 (14 May 2014) - -- Brown paper bag bug fix for an HTML parsing regression introduced in - domino 1.0.16. (#45) -- Update `mocha` dependency to 1.18.x and `should` to 3.3.x. - -# domino 1.0.16 (13 May 2014) - -**DO NOT USE:** contains parser regression, fixed in 1.0.17. - -- Various performance improvements to the HTML5 parser. (#43, #44) -- Fix `Element#isHTML` for non-HTML elements. (#41) - -# domino 1.0.15 (21 Jan 2014) - -- Implement `Element#matches()`. -- Fix CSS `[lang]`, `[dir]`, etc selectors. -- Update `mocha` dependency to 1.17.x. - -# domino 1.0.14 (21 Dec 2013) - -- `Element#classList.length` should be 0 if there's no `class` - attribute. -- Add `height`/`width` attributes to `HTMLImageElement`. -- Fix node 0.11 incompatibility in the w3c test harness. -- Update `mocha` dependency to 1.16.x; update `should` dependency to 2.1.x. - -# domino 1.0.13 (8 Oct 2013) - -- Include `<th>` elements in `HTMLTableRowElement#cells`. (#38, #39) -- Fix old call to `toLowerCase()` function. (#37) -- Update `mocha` and `should` dependencies. - -# domino 1.0.12 (9 Jul 2013) - -- Fix bug in formatting element adoption agency algorithm. (#36) -- Coerce `document.createTextNode` argument to a string. (#34, #35) -- Work around performance regression in node <= 0.6. - -# domino 1.0.11 (1 May 2013) - -- Fix rooted element traversal (`Element#nextElement`, - `Element#getElementsByTagName`). (#31, #32) -- Update zest to fix bugs in `+` and `>` combinators. -- Don't overflow the stack if attribute values are very large (>64k). - -# domino 1.0.10 (12 Apr 2013) - -- Document issues with `Element#attributes`. (#27) -- Fix `Document#title` to match DOM spec. (#29) -- Add missing `require('utils')` for `handleErrors`. (#28) -- Implement `DocumentFragment#querySelector` and - `DocumentFragment#querySelectorAll`. (#20, #26) -- Fix `querySelectorAll` on unparented `Element`s. (#23) -- Move `outerHTML`/`innerHTML` properties from `HTMLElement` to - `Element` to match dom parsing spec. (#21) -- Update zest selector library to 0.0.4. (#25) -- Fix regression in node 0.10. (#22, #24) -- Update `mocha` and `should` dependencies. - -# domino 1.0.9 (11 Mar 2013) - -- Support jQuery 1.9.x by allowing `Element#attributes[qname]`. -- Implement `HTMLElement#outerHTML`. (#18) -- Only add newlines after `<pre>`/`<textarea>`/`<listing>` if - necessary, to match HTML5 serialization spec. (#16, #17) -- Mirror node type properties (`ELEMENT_NODE`, etc) into - `Node.prototype`. (#14, #15) - -# domino 1.0.8 - -**DO NOT USE:** was inadvertently published identical to domino 1.0.7. - -# domino 1.0.7 (16 Jan 2013) - -- Throw `SyntaxError` upon invocation rather than build-time. (#10) -- Return nodes in document order. (#11) -- Added a TreeWalker implementation. diff --git a/packages/qwik-dom/LICENSE b/packages/qwik-dom/LICENSE deleted file mode 100644 index 9e1807f8e76..00000000000 --- a/packages/qwik-dom/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2011 The Mozilla Foundation. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/qwik-dom/lib/CSSStyleDeclaration.js b/packages/qwik-dom/lib/CSSStyleDeclaration.js deleted file mode 100644 index fb330253f56..00000000000 --- a/packages/qwik-dom/lib/CSSStyleDeclaration.js +++ /dev/null @@ -1,822 +0,0 @@ -'use strict'; -var parserlib = require('./cssparser'); - -module.exports = CSSStyleDeclaration; - -function CSSStyleDeclaration(elt) { - this._element = elt; -} - -// Utility function for parsing style declarations -// Pass in a string like "margin-left: 5px; border-style: solid" -// and this function returns an object like -// {"margin-left":"5px", "border-style":"solid"} -function parseStyles(s) { - var parser = new parserlib.css.Parser(); - var result = { property: Object.create(null), priority: Object.create(null) }; - parser.addListener('property', function (e) { - if (e.invalid) return; // Skip errors - result.property[e.property.text] = e.value.text; - if (e.important) result.priority[e.property.text] = 'important'; - }); - s = ('' + s).replace(/^;/, ''); - parser.parseStyleAttribute(s); - return result; -} - -var NO_CHANGE = {}; // Private marker object - -CSSStyleDeclaration.prototype = Object.create(Object.prototype, { - // Return the parsed form of the element's style attribute. - // If the element's style attribute has never been parsed - // or if it has changed since the last parse, then reparse it - // Note that the styles don't get parsed until they're actually needed - _parsed: { - get: function () { - if (!this._parsedStyles || this.cssText !== this._lastParsedText) { - var text = this.cssText; - this._parsedStyles = parseStyles(text); - this._lastParsedText = text; - delete this._names; - } - return this._parsedStyles; - }, - }, - - // Call this method any time the parsed representation of the - // style changes. It converts the style properties to a string and - // sets cssText and the element's style attribute - _serialize: { - value: function () { - var styles = this._parsed; - var s = ''; - - for (var name in styles.property) { - if (s) s += ' '; - s += name + ': ' + styles.property[name]; - if (styles.priority[name]) { - s += ' !' + styles.priority[name]; - } - s += ';'; - } - - this.cssText = s; // also sets the style attribute - this._lastParsedText = s; // so we don't reparse - delete this._names; - }, - }, - - cssText: { - get: function () { - // XXX: this is a CSSStyleDeclaration for an element. - // A different impl might be necessary for a set of styles - // associated returned by getComputedStyle(), e.g. - return this._element.getAttribute('style'); - }, - set: function (value) { - // XXX: I should parse and serialize the value to - // normalize it and remove errors. FF and chrome do that. - this._element.setAttribute('style', value); - }, - }, - - length: { - get: function () { - if (!this._names) this._names = Object.getOwnPropertyNames(this._parsed.property); - return this._names.length; - }, - }, - - item: { - value: function (n) { - if (!this._names) this._names = Object.getOwnPropertyNames(this._parsed.property); - return this._names[n]; - }, - }, - - getPropertyValue: { - value: function (property) { - property = property.toLowerCase(); - return this._parsed.property[property] || ''; - }, - }, - - getPropertyPriority: { - value: function (property) { - property = property.toLowerCase(); - return this._parsed.priority[property] || ''; - }, - }, - - setProperty: { - value: function (property, value, priority) { - property = property.toLowerCase(); - if (value === null || value === undefined) { - value = ''; - } - if (priority === null || priority === undefined) { - priority = ''; - } - - // String coercion - if (value !== NO_CHANGE) { - value = '' + value; - } - - if (value === '') { - this.removeProperty(property); - return; - } - - if (priority !== '' && priority !== NO_CHANGE && !/^important$/i.test(priority)) { - return; - } - - var styles = this._parsed; - if (value === NO_CHANGE) { - if (!styles.property[property]) { - return; // Not a valid property name. - } - if (priority !== '') { - styles.priority[property] = 'important'; - } else { - delete styles.priority[property]; - } - } else { - // We don't just accept the property value. Instead - // we parse it to ensure that it is something valid. - // If it contains a semicolon it is invalid - if (value.indexOf(';') !== -1) return; - - var newprops = parseStyles(property + ':' + value); - if (Object.getOwnPropertyNames(newprops.property).length === 0) { - return; // no valid property found - } - if (Object.getOwnPropertyNames(newprops.priority).length !== 0) { - return; // if the value included '!important' it wasn't valid. - } - - // XXX handle shorthand properties - - for (var p in newprops.property) { - styles.property[p] = newprops.property[p]; - if (priority === NO_CHANGE) { - continue; - } else if (priority !== '') { - styles.priority[p] = 'important'; - } else if (styles.priority[p]) { - delete styles.priority[p]; - } - } - } - - // Serialize and update cssText and element.style! - this._serialize(); - }, - }, - - setPropertyValue: { - value: function (property, value) { - return this.setProperty(property, value, NO_CHANGE); - }, - }, - - setPropertyPriority: { - value: function (property, priority) { - return this.setProperty(property, NO_CHANGE, priority); - }, - }, - - removeProperty: { - value: function (property) { - property = property.toLowerCase(); - var styles = this._parsed; - if (property in styles.property) { - delete styles.property[property]; - delete styles.priority[property]; - - // Serialize and update cssText and element.style! - this._serialize(); - } - }, - }, -}); - -const cssProperties = { - accentColor: 'accent-color', - additiveSymbols: 'additive-symbols', - alignContent: 'align-content', - alignItems: 'align-items', - alignSelf: 'align-self', - alignmentBaseline: 'alignment-baseline', - all: 'all', - animation: 'animation', - animationDelay: 'animation-delay', - animationDirection: 'animation-direction', - animationDuration: 'animation-duration', - animationFillMode: 'animation-fill-mode', - animationIterationCount: 'animation-iteration-count', - animationName: 'animation-name', - animationPlayState: 'animation-play-state', - animationTimingFunction: 'animation-timing-function', - appRegion: 'app-region', - appearance: 'appearance', - ascentOverride: 'ascent-override', - aspectRatio: 'aspect-ratio', - backdropFilter: 'backdrop-filter', - backfaceVisibility: 'backface-visibility', - background: 'background', - backgroundAttachment: 'background-attachment', - backgroundBlendMode: 'background-blend-mode', - backgroundClip: 'background-clip', - backgroundColor: 'background-color', - backgroundImage: 'background-image', - backgroundOrigin: 'background-origin', - backgroundPosition: 'background-position', - backgroundPositionX: 'background-position-x', - backgroundPositionY: 'background-position-y', - backgroundRepeat: 'background-repeat', - backgroundRepeatX: 'background-repeat-x', - backgroundRepeatY: 'background-repeat-y', - backgroundSize: 'background-size', - basePalette: 'base-palette', - baselineShift: 'baseline-shift', - blockSize: 'block-size', - border: 'border', - borderBlock: 'border-block', - borderBlockColor: 'border-block-color', - borderBlockEnd: 'border-block-end', - borderBlockEndColor: 'border-block-end-color', - borderBlockEndStyle: 'border-block-end-style', - borderBlockEndWidth: 'border-block-end-width', - borderBlockStart: 'border-block-start', - borderBlockStartColor: 'border-block-start-color', - borderBlockStartStyle: 'border-block-start-style', - borderBlockStartWidth: 'border-block-start-width', - borderBlockStyle: 'border-block-style', - borderBlockWidth: 'border-block-width', - borderBottom: 'border-bottom', - borderBottomColor: 'border-bottom-color', - borderBottomLeftRadius: 'border-bottom-left-radius', - borderBottomRightRadius: 'border-bottom-right-radius', - borderBottomStyle: 'border-bottom-style', - borderBottomWidth: 'border-bottom-width', - borderCollapse: 'border-collapse', - borderColor: 'border-color', - borderEndEndRadius: 'border-end-end-radius', - borderEndStartRadius: 'border-end-start-radius', - borderImage: 'border-image', - borderImageOutset: 'border-image-outset', - borderImageRepeat: 'border-image-repeat', - borderImageSlice: 'border-image-slice', - borderImageSource: 'border-image-source', - borderImageWidth: 'border-image-width', - borderInline: 'border-inline', - borderInlineColor: 'border-inline-color', - borderInlineEnd: 'border-inline-end', - borderInlineEndColor: 'border-inline-end-color', - borderInlineEndStyle: 'border-inline-end-style', - borderInlineEndWidth: 'border-inline-end-width', - borderInlineStart: 'border-inline-start', - borderInlineStartColor: 'border-inline-start-color', - borderInlineStartStyle: 'border-inline-start-style', - borderInlineStartWidth: 'border-inline-start-width', - borderInlineStyle: 'border-inline-style', - borderInlineWidth: 'border-inline-width', - borderLeft: 'border-left', - borderLeftColor: 'border-left-color', - borderLeftStyle: 'border-left-style', - borderLeftWidth: 'border-left-width', - borderRadius: 'border-radius', - borderRight: 'border-right', - borderRightColor: 'border-right-color', - borderRightStyle: 'border-right-style', - borderRightWidth: 'border-right-width', - borderSpacing: 'border-spacing', - borderStartEndRadius: 'border-start-end-radius', - borderStartStartRadius: 'border-start-start-radius', - borderStyle: 'border-style', - borderTop: 'border-top', - borderTopColor: 'border-top-color', - borderTopLeftRadius: 'border-top-left-radius', - borderTopRightRadius: 'border-top-right-radius', - borderTopStyle: 'border-top-style', - borderTopWidth: 'border-top-width', - borderWidth: 'border-width', - bottom: 'bottom', - boxShadow: 'box-shadow', - boxSizing: 'box-sizing', - breakAfter: 'break-after', - breakBefore: 'break-before', - breakInside: 'break-inside', - bufferedRendering: 'buffered-rendering', - captionSide: 'caption-side', - caretColor: 'caret-color', - clear: 'clear', - clip: 'clip', - clipPath: 'clip-path', - clipRule: 'clip-rule', - color: 'color', - colorInterpolation: 'color-interpolation', - colorInterpolationFilters: 'color-interpolation-filters', - colorRendering: 'color-rendering', - colorScheme: 'color-scheme', - columnCount: 'column-count', - columnFill: 'column-fill', - columnGap: 'column-gap', - columnRule: 'column-rule', - columnRuleColor: 'column-rule-color', - columnRuleStyle: 'column-rule-style', - columnRuleWidth: 'column-rule-width', - columnSpan: 'column-span', - columnWidth: 'column-width', - columns: 'columns', - contain: 'contain', - containIntrinsicBlockSize: 'contain-intrinsic-block-size', - containIntrinsicHeight: 'contain-intrinsic-height', - containIntrinsicInlineSize: 'contain-intrinsic-inline-size', - containIntrinsicSize: 'contain-intrinsic-size', - containIntrinsicWidth: 'contain-intrinsic-width', - container: 'container', - containerName: 'container-name', - containerType: 'container-type', - content: 'content', - contentVisibility: 'content-visibility', - counterIncrement: 'counter-increment', - counterReset: 'counter-reset', - counterSet: 'counter-set', - cursor: 'cursor', - cx: 'cx', - cy: 'cy', - d: 'd', - descentOverride: 'descent-override', - direction: 'direction', - display: 'display', - dominantBaseline: 'dominant-baseline', - emptyCells: 'empty-cells', - fallback: 'fallback', - fill: 'fill', - fillOpacity: 'fill-opacity', - fillRule: 'fill-rule', - filter: 'filter', - flex: 'flex', - flexBasis: 'flex-basis', - flexDirection: 'flex-direction', - flexFlow: 'flex-flow', - flexGrow: 'flex-grow', - flexShrink: 'flex-shrink', - flexWrap: 'flex-wrap', - float: 'float', - floodColor: 'flood-color', - floodOpacity: 'flood-opacity', - font: 'font', - fontDisplay: 'font-display', - fontFamily: 'font-family', - fontFeatureSettings: 'font-feature-settings', - fontKerning: 'font-kerning', - fontOpticalSizing: 'font-optical-sizing', - fontPalette: 'font-palette', - fontSize: 'font-size', - fontStretch: 'font-stretch', - fontStyle: 'font-style', - fontSynthesis: 'font-synthesis', - fontSynthesisSmallCaps: 'font-synthesis-small-caps', - fontSynthesisStyle: 'font-synthesis-style', - fontSynthesisWeight: 'font-synthesis-weight', - fontVariant: 'font-variant', - fontVariantCaps: 'font-variant-caps', - fontVariantEastAsian: 'font-variant-east-asian', - fontVariantLigatures: 'font-variant-ligatures', - fontVariantNumeric: 'font-variant-numeric', - fontVariationSettings: 'font-variation-settings', - fontWeight: 'font-weight', - forcedColorAdjust: 'forced-color-adjust', - gap: 'gap', - grid: 'grid', - gridArea: 'grid-area', - gridAutoColumns: 'grid-auto-columns', - gridAutoFlow: 'grid-auto-flow', - gridAutoRows: 'grid-auto-rows', - gridColumn: 'grid-column', - gridColumnEnd: 'grid-column-end', - gridColumnGap: 'grid-column-gap', - gridColumnStart: 'grid-column-start', - gridGap: 'grid-gap', - gridRow: 'grid-row', - gridRowEnd: 'grid-row-end', - gridRowGap: 'grid-row-gap', - gridRowStart: 'grid-row-start', - gridTemplate: 'grid-template', - gridTemplateAreas: 'grid-template-areas', - gridTemplateColumns: 'grid-template-columns', - gridTemplateRows: 'grid-template-rows', - height: 'height', - hyphenateCharacter: 'hyphenate-character', - hyphenateLimitChars: 'hyphenate-limit-chars', - hyphens: 'hyphens', - imageOrientation: 'image-orientation', - imageRendering: 'image-rendering', - inherits: 'inherits', - initialLetter: 'initial-letter', - initialValue: 'initial-value', - inlineSize: 'inline-size', - inset: 'inset', - insetBlock: 'inset-block', - insetBlockEnd: 'inset-block-end', - insetBlockStart: 'inset-block-start', - insetInline: 'inset-inline', - insetInlineEnd: 'inset-inline-end', - insetInlineStart: 'inset-inline-start', - isolation: 'isolation', - justifyContent: 'justify-content', - justifyItems: 'justify-items', - justifySelf: 'justify-self', - left: 'left', - letterSpacing: 'letter-spacing', - lightingColor: 'lighting-color', - lineBreak: 'line-break', - lineGapOverride: 'line-gap-override', - lineHeight: 'line-height', - listStyle: 'list-style', - listStyleImage: 'list-style-image', - listStylePosition: 'list-style-position', - listStyleType: 'list-style-type', - margin: 'margin', - marginBlock: 'margin-block', - marginBlockEnd: 'margin-block-end', - marginBlockStart: 'margin-block-start', - marginBottom: 'margin-bottom', - marginInline: 'margin-inline', - marginInlineEnd: 'margin-inline-end', - marginInlineStart: 'margin-inline-start', - marginLeft: 'margin-left', - marginRight: 'margin-right', - marginTop: 'margin-top', - marker: 'marker', - markerEnd: 'marker-end', - markerMid: 'marker-mid', - markerStart: 'marker-start', - mask: 'mask', - maskType: 'mask-type', - mathDepth: 'math-depth', - mathShift: 'math-shift', - mathStyle: 'math-style', - maxBlockSize: 'max-block-size', - maxHeight: 'max-height', - maxInlineSize: 'max-inline-size', - maxWidth: 'max-width', - minBlockSize: 'min-block-size', - minHeight: 'min-height', - minInlineSize: 'min-inline-size', - minWidth: 'min-width', - mixBlendMode: 'mix-blend-mode', - negative: 'negative', - objectFit: 'object-fit', - objectPosition: 'object-position', - objectViewBox: 'object-view-box', - offset: 'offset', - offsetDistance: 'offset-distance', - offsetPath: 'offset-path', - offsetRotate: 'offset-rotate', - opacity: 'opacity', - order: 'order', - orphans: 'orphans', - outline: 'outline', - outlineColor: 'outline-color', - outlineOffset: 'outline-offset', - outlineStyle: 'outline-style', - outlineWidth: 'outline-width', - overflow: 'overflow', - overflowAnchor: 'overflow-anchor', - overflowClipMargin: 'overflow-clip-margin', - overflowWrap: 'overflow-wrap', - overflowX: 'overflow-x', - overflowY: 'overflow-y', - overrideColors: 'override-colors', - overscrollBehavior: 'overscroll-behavior', - overscrollBehaviorBlock: 'overscroll-behavior-block', - overscrollBehaviorInline: 'overscroll-behavior-inline', - overscrollBehaviorX: 'overscroll-behavior-x', - overscrollBehaviorY: 'overscroll-behavior-y', - pad: 'pad', - padding: 'padding', - paddingBlock: 'padding-block', - paddingBlockEnd: 'padding-block-end', - paddingBlockStart: 'padding-block-start', - paddingBottom: 'padding-bottom', - paddingInline: 'padding-inline', - paddingInlineEnd: 'padding-inline-end', - paddingInlineStart: 'padding-inline-start', - paddingLeft: 'padding-left', - paddingRight: 'padding-right', - paddingTop: 'padding-top', - page: 'page', - pageBreakAfter: 'page-break-after', - pageBreakBefore: 'page-break-before', - pageBreakInside: 'page-break-inside', - pageOrientation: 'page-orientation', - paintOrder: 'paint-order', - perspective: 'perspective', - perspectiveOrigin: 'perspective-origin', - placeContent: 'place-content', - placeItems: 'place-items', - placeSelf: 'place-self', - pointerEvents: 'pointer-events', - position: 'position', - prefix: 'prefix', - quotes: 'quotes', - r: 'r', - range: 'range', - resize: 'resize', - right: 'right', - rotate: 'rotate', - rowGap: 'row-gap', - rubyPosition: 'ruby-position', - rx: 'rx', - ry: 'ry', - scale: 'scale', - scrollBehavior: 'scroll-behavior', - scrollMargin: 'scroll-margin', - scrollMarginBlock: 'scroll-margin-block', - scrollMarginBlockEnd: 'scroll-margin-block-end', - scrollMarginBlockStart: 'scroll-margin-block-start', - scrollMarginBottom: 'scroll-margin-bottom', - scrollMarginInline: 'scroll-margin-inline', - scrollMarginInlineEnd: 'scroll-margin-inline-end', - scrollMarginInlineStart: 'scroll-margin-inline-start', - scrollMarginLeft: 'scroll-margin-left', - scrollMarginRight: 'scroll-margin-right', - scrollMarginTop: 'scroll-margin-top', - scrollPadding: 'scroll-padding', - scrollPaddingBlock: 'scroll-padding-block', - scrollPaddingBlockEnd: 'scroll-padding-block-end', - scrollPaddingBlockStart: 'scroll-padding-block-start', - scrollPaddingBottom: 'scroll-padding-bottom', - scrollPaddingInline: 'scroll-padding-inline', - scrollPaddingInlineEnd: 'scroll-padding-inline-end', - scrollPaddingInlineStart: 'scroll-padding-inline-start', - scrollPaddingLeft: 'scroll-padding-left', - scrollPaddingRight: 'scroll-padding-right', - scrollPaddingTop: 'scroll-padding-top', - scrollSnapAlign: 'scroll-snap-align', - scrollSnapStop: 'scroll-snap-stop', - scrollSnapType: 'scroll-snap-type', - scrollbarGutter: 'scrollbar-gutter', - shapeImageThreshold: 'shape-image-threshold', - shapeMargin: 'shape-margin', - shapeOutside: 'shape-outside', - shapeRendering: 'shape-rendering', - size: 'size', - sizeAdjust: 'size-adjust', - speak: 'speak', - speakAs: 'speak-as', - src: 'src', - stopColor: 'stop-color', - stopOpacity: 'stop-opacity', - stroke: 'stroke', - strokeDasharray: 'stroke-dasharray', - strokeDashoffset: 'stroke-dashoffset', - strokeLinecap: 'stroke-linecap', - strokeLinejoin: 'stroke-linejoin', - strokeMiterlimit: 'stroke-miterlimit', - strokeOpacity: 'stroke-opacity', - strokeWidth: 'stroke-width', - suffix: 'suffix', - symbols: 'symbols', - syntax: 'syntax', - system: 'system', - tabSize: 'tab-size', - tableLayout: 'table-layout', - textAlign: 'text-align', - textAlignLast: 'text-align-last', - textAnchor: 'text-anchor', - textCombineUpright: 'text-combine-upright', - textDecoration: 'text-decoration', - textDecorationColor: 'text-decoration-color', - textDecorationLine: 'text-decoration-line', - textDecorationSkipInk: 'text-decoration-skip-ink', - textDecorationStyle: 'text-decoration-style', - textDecorationThickness: 'text-decoration-thickness', - textEmphasis: 'text-emphasis', - textEmphasisColor: 'text-emphasis-color', - textEmphasisPosition: 'text-emphasis-position', - textEmphasisStyle: 'text-emphasis-style', - textIndent: 'text-indent', - textOrientation: 'text-orientation', - textOverflow: 'text-overflow', - textRendering: 'text-rendering', - textShadow: 'text-shadow', - textSizeAdjust: 'text-size-adjust', - textTransform: 'text-transform', - textUnderlineOffset: 'text-underline-offset', - textUnderlinePosition: 'text-underline-position', - top: 'top', - touchAction: 'touch-action', - transform: 'transform', - transformBox: 'transform-box', - transformOrigin: 'transform-origin', - transformStyle: 'transform-style', - transition: 'transition', - transitionDelay: 'transition-delay', - transitionDuration: 'transition-duration', - transitionProperty: 'transition-property', - transitionTimingFunction: 'transition-timing-function', - translate: 'translate', - unicodeBidi: 'unicode-bidi', - unicodeRange: 'unicode-range', - userSelect: 'user-select', - vectorEffect: 'vector-effect', - verticalAlign: 'vertical-align', - visibility: 'visibility', - webkitAlignContent: '-webkit-align-content', - webkitAlignItems: '-webkit-align-items', - webkitAlignSelf: '-webkit-align-self', - webkitAnimation: '-webkit-animation', - webkitAnimationDelay: '-webkit-animation-delay', - webkitAnimationDirection: '-webkit-animation-direction', - webkitAnimationDuration: '-webkit-animation-duration', - webkitAnimationFillMode: '-webkit-animation-fill-mode', - webkitAnimationIterationCount: '-webkit-animation-iteration-count', - webkitAnimationName: '-webkit-animation-name', - webkitAnimationPlayState: '-webkit-animation-play-state', - webkitAnimationTimingFunction: '-webkit-animation-timing-function', - webkitAppRegion: '-webkit-app-region', - webkitAppearance: '-webkit-appearance', - webkitBackfaceVisibility: '-webkit-backface-visibility', - webkitBackgroundClip: '-webkit-background-clip', - webkitBackgroundOrigin: '-webkit-background-origin', - webkitBackgroundSize: '-webkit-background-size', - webkitBorderAfter: '-webkit-border-after', - webkitBorderAfterColor: '-webkit-border-after-color', - webkitBorderAfterStyle: '-webkit-border-after-style', - webkitBorderAfterWidth: '-webkit-border-after-width', - webkitBorderBefore: '-webkit-border-before', - webkitBorderBeforeColor: '-webkit-border-before-color', - webkitBorderBeforeStyle: '-webkit-border-before-style', - webkitBorderBeforeWidth: '-webkit-border-before-width', - webkitBorderBottomLeftRadius: '-webkit-border-bottom-left-radius', - webkitBorderBottomRightRadius: '-webkit-border-bottom-right-radius', - webkitBorderEnd: '-webkit-border-end', - webkitBorderEndColor: '-webkit-border-end-color', - webkitBorderEndStyle: '-webkit-border-end-style', - webkitBorderEndWidth: '-webkit-border-end-width', - webkitBorderHorizontalSpacing: '-webkit-border-horizontal-spacing', - webkitBorderImage: '-webkit-border-image', - webkitBorderRadius: '-webkit-border-radius', - webkitBorderStart: '-webkit-border-start', - webkitBorderStartColor: '-webkit-border-start-color', - webkitBorderStartStyle: '-webkit-border-start-style', - webkitBorderStartWidth: '-webkit-border-start-width', - webkitBorderTopLeftRadius: '-webkit-border-top-left-radius', - webkitBorderTopRightRadius: '-webkit-border-top-right-radius', - webkitBorderVerticalSpacing: '-webkit-border-vertical-spacing', - webkitBoxAlign: '-webkit-box-align', - webkitBoxDecorationBreak: '-webkit-box-decoration-break', - webkitBoxDirection: '-webkit-box-direction', - webkitBoxFlex: '-webkit-box-flex', - webkitBoxOrdinalGroup: '-webkit-box-ordinal-group', - webkitBoxOrient: '-webkit-box-orient', - webkitBoxPack: '-webkit-box-pack', - webkitBoxReflect: '-webkit-box-reflect', - webkitBoxShadow: '-webkit-box-shadow', - webkitBoxSizing: '-webkit-box-sizing', - webkitClipPath: '-webkit-clip-path', - webkitColumnBreakAfter: '-webkit-column-break-after', - webkitColumnBreakBefore: '-webkit-column-break-before', - webkitColumnBreakInside: '-webkit-column-break-inside', - webkitColumnCount: '-webkit-column-count', - webkitColumnGap: '-webkit-column-gap', - webkitColumnRule: '-webkit-column-rule', - webkitColumnRuleColor: '-webkit-column-rule-color', - webkitColumnRuleStyle: '-webkit-column-rule-style', - webkitColumnRuleWidth: '-webkit-column-rule-width', - webkitColumnSpan: '-webkit-column-span', - webkitColumnWidth: '-webkit-column-width', - webkitColumns: '-webkit-columns', - webkitFilter: '-webkit-filter', - webkitFlex: '-webkit-flex', - webkitFlexBasis: '-webkit-flex-basis', - webkitFlexDirection: '-webkit-flex-direction', - webkitFlexFlow: '-webkit-flex-flow', - webkitFlexGrow: '-webkit-flex-grow', - webkitFlexShrink: '-webkit-flex-shrink', - webkitFlexWrap: '-webkit-flex-wrap', - webkitFontFeatureSettings: '-webkit-font-feature-settings', - webkitFontSmoothing: '-webkit-font-smoothing', - webkitHighlight: '-webkit-highlight', - webkitHyphenateCharacter: '-webkit-hyphenate-character', - webkitJustifyContent: '-webkit-justify-content', - webkitLineBreak: '-webkit-line-break', - webkitLineClamp: '-webkit-line-clamp', - webkitLocale: '-webkit-locale', - webkitLogicalHeight: '-webkit-logical-height', - webkitLogicalWidth: '-webkit-logical-width', - webkitMarginAfter: '-webkit-margin-after', - webkitMarginBefore: '-webkit-margin-before', - webkitMarginEnd: '-webkit-margin-end', - webkitMarginStart: '-webkit-margin-start', - webkitMask: '-webkit-mask', - webkitMaskBoxImage: '-webkit-mask-box-image', - webkitMaskBoxImageOutset: '-webkit-mask-box-image-outset', - webkitMaskBoxImageRepeat: '-webkit-mask-box-image-repeat', - webkitMaskBoxImageSlice: '-webkit-mask-box-image-slice', - webkitMaskBoxImageSource: '-webkit-mask-box-image-source', - webkitMaskBoxImageWidth: '-webkit-mask-box-image-width', - webkitMaskClip: '-webkit-mask-clip', - webkitMaskComposite: '-webkit-mask-composite', - webkitMaskImage: '-webkit-mask-image', - webkitMaskOrigin: '-webkit-mask-origin', - webkitMaskPosition: '-webkit-mask-position', - webkitMaskPositionX: '-webkit-mask-position-x', - webkitMaskPositionY: '-webkit-mask-position-y', - webkitMaskRepeat: '-webkit-mask-repeat', - webkitMaskRepeatX: '-webkit-mask-repeat-x', - webkitMaskRepeatY: '-webkit-mask-repeat-y', - webkitMaskSize: '-webkit-mask-size', - webkitMaxLogicalHeight: '-webkit-max-logical-height', - webkitMaxLogicalWidth: '-webkit-max-logical-width', - webkitMinLogicalHeight: '-webkit-min-logical-height', - webkitMinLogicalWidth: '-webkit-min-logical-width', - webkitOpacity: '-webkit-opacity', - webkitOrder: '-webkit-order', - webkitPaddingAfter: '-webkit-padding-after', - webkitPaddingBefore: '-webkit-padding-before', - webkitPaddingEnd: '-webkit-padding-end', - webkitPaddingStart: '-webkit-padding-start', - webkitPerspective: '-webkit-perspective', - webkitPerspectiveOrigin: '-webkit-perspective-origin', - webkitPerspectiveOriginX: '-webkit-perspective-origin-x', - webkitPerspectiveOriginY: '-webkit-perspective-origin-y', - webkitPrintColorAdjust: '-webkit-print-color-adjust', - webkitRtlOrdering: '-webkit-rtl-ordering', - webkitRubyPosition: '-webkit-ruby-position', - webkitShapeImageThreshold: '-webkit-shape-image-threshold', - webkitShapeMargin: '-webkit-shape-margin', - webkitShapeOutside: '-webkit-shape-outside', - webkitTapHighlightColor: '-webkit-tap-highlight-color', - webkitTextCombine: '-webkit-text-combine', - webkitTextDecorationsInEffect: '-webkit-text-decorations-in-effect', - webkitTextEmphasis: '-webkit-text-emphasis', - webkitTextEmphasisColor: '-webkit-text-emphasis-color', - webkitTextEmphasisPosition: '-webkit-text-emphasis-position', - webkitTextEmphasisStyle: '-webkit-text-emphasis-style', - webkitTextFillColor: '-webkit-text-fill-color', - webkitTextOrientation: '-webkit-text-orientation', - webkitTextSecurity: '-webkit-text-security', - webkitTextSizeAdjust: '-webkit-text-size-adjust', - webkitTextStroke: '-webkit-text-stroke', - webkitTextStrokeColor: '-webkit-text-stroke-color', - webkitTextStrokeWidth: '-webkit-text-stroke-width', - webkitTransform: '-webkit-transform', - webkitTransformOrigin: '-webkit-transform-origin', - webkitTransformOriginX: '-webkit-transform-origin-x', - webkitTransformOriginY: '-webkit-transform-origin-y', - webkitTransformOriginZ: '-webkit-transform-origin-z', - webkitTransformStyle: '-webkit-transform-style', - webkitTransition: '-webkit-transition', - webkitTransitionDelay: '-webkit-transition-delay', - webkitTransitionDuration: '-webkit-transition-duration', - webkitTransitionProperty: '-webkit-transition-property', - webkitTransitionTimingFunction: '-webkit-transition-timing-function', - webkitUserDrag: '-webkit-user-drag', - webkitUserModify: '-webkit-user-modify', - webkitUserSelect: '-webkit-user-select', - webkitWritingMode: '-webkit-writing-mode', - whiteSpace: 'white-space', - widows: 'widows', - width: 'width', - willChange: 'will-change', - wordBreak: 'word-break', - wordSpacing: 'word-spacing', - wordWrap: 'word-wrap', - writingMode: 'writing-mode', - x: 'x', - y: 'y', - zIndex: 'z-index', - zoom: 'zoom', -}; - -for (var prop in cssProperties) defineStyleProperty(prop); - -function defineStyleProperty(jsname) { - var cssname = cssProperties[jsname]; - Object.defineProperty(CSSStyleDeclaration.prototype, jsname, { - get: function () { - return this.getPropertyValue(cssname); - }, - set: function (value) { - this.setProperty(cssname, value); - }, - }); - - if (!CSSStyleDeclaration.prototype.hasOwnProperty(cssname)) { - Object.defineProperty(CSSStyleDeclaration.prototype, cssname, { - get: function () { - return this.getPropertyValue(cssname); - }, - set: function (value) { - this.setProperty(cssname, value); - }, - }); - } -} diff --git a/packages/qwik-dom/lib/CharacterData.js b/packages/qwik-dom/lib/CharacterData.js deleted file mode 100644 index 4f974e52fa1..00000000000 --- a/packages/qwik-dom/lib/CharacterData.js +++ /dev/null @@ -1,137 +0,0 @@ -/* jshint bitwise: false */ -'use strict'; -module.exports = CharacterData; - -var Leaf = require('./Leaf'); -var utils = require('./utils'); -var ChildNode = require('./ChildNode'); -var NonDocumentTypeChildNode = require('./NonDocumentTypeChildNode'); - -function CharacterData() { - Leaf.call(this); -} - -CharacterData.prototype = Object.create(Leaf.prototype, { - // DOMString substringData(unsigned long offset, - // unsigned long count); - // The substringData(offset, count) method must run these steps: - // - // If offset is greater than the context object's - // length, throw an INDEX_SIZE_ERR exception and - // terminate these steps. - // - // If offset+count is greater than the context - // object's length, return a DOMString whose value is - // the UTF-16 code units from the offsetth UTF-16 code - // unit to the end of data. - // - // Return a DOMString whose value is the UTF-16 code - // units from the offsetth UTF-16 code unit to the - // offset+countth UTF-16 code unit in data. - substringData: { - value: function substringData(offset, count) { - if (arguments.length < 2) { - throw new TypeError('Not enough arguments'); - } - // Convert arguments to WebIDL "unsigned long" - offset = offset >>> 0; - count = count >>> 0; - if (offset > this.data.length || offset < 0 || count < 0) { - utils.IndexSizeError(); - } - return this.data.substring(offset, offset + count); - }, - }, - - // void appendData(DOMString data); - // The appendData(data) method must append data to the context - // object's data. - appendData: { - value: function appendData(data) { - if (arguments.length < 1) { - throw new TypeError('Not enough arguments'); - } - this.data += String(data); - }, - }, - - // void insertData(unsigned long offset, DOMString data); - // The insertData(offset, data) method must run these steps: - // - // If offset is greater than the context object's - // length, throw an INDEX_SIZE_ERR exception and - // terminate these steps. - // - // Insert data into the context object's data after - // offset UTF-16 code units. - // - insertData: { - value: function insertData(offset, data) { - return this.replaceData(offset, 0, data); - }, - }, - - // void deleteData(unsigned long offset, unsigned long count); - // The deleteData(offset, count) method must run these steps: - // - // If offset is greater than the context object's - // length, throw an INDEX_SIZE_ERR exception and - // terminate these steps. - // - // If offset+count is greater than the context - // object's length var count be length-offset. - // - // Starting from offset UTF-16 code units remove count - // UTF-16 code units from the context object's data. - deleteData: { - value: function deleteData(offset, count) { - return this.replaceData(offset, count, ''); - }, - }, - - // void replaceData(unsigned long offset, unsigned long count, - // DOMString data); - // - // The replaceData(offset, count, data) method must act as - // if the deleteData() method is invoked with offset and - // count as arguments followed by the insertData() method - // with offset and data as arguments and re-throw any - // exceptions these methods might have thrown. - replaceData: { - value: function replaceData(offset, count, data) { - var curtext = this.data, - len = curtext.length; - // Convert arguments to correct WebIDL type - offset = offset >>> 0; - count = count >>> 0; - data = String(data); - - if (offset > len || offset < 0) utils.IndexSizeError(); - - if (offset + count > len) count = len - offset; - - var prefix = curtext.substring(0, offset), - suffix = curtext.substring(offset + count); - - this.data = prefix + data + suffix; - }, - }, - - // Utility method that Node.isEqualNode() calls to test Text and - // Comment nodes for equality. It is okay to put it here, since - // Node will have already verified that nodeType is equal - isEqual: { - value: function isEqual(n) { - return this._data === n._data; - }, - }, - - length: { - get: function () { - return this.data.length; - }, - }, -}); - -Object.defineProperties(CharacterData.prototype, ChildNode); -Object.defineProperties(CharacterData.prototype, NonDocumentTypeChildNode); diff --git a/packages/qwik-dom/lib/ChildNode.js b/packages/qwik-dom/lib/ChildNode.js deleted file mode 100644 index 5e2c57d9758..00000000000 --- a/packages/qwik-dom/lib/ChildNode.js +++ /dev/null @@ -1,149 +0,0 @@ -'use strict'; - -var Node = require('./Node'); -var LinkedList = require('./LinkedList'); - -var createDocumentFragmentFromArguments = function (document, args) { - var docFrag = document.createDocumentFragment(); - - for (var i = 0; i < args.length; i++) { - var argItem = args[i]; - var isNode = argItem instanceof Node; - docFrag.appendChild(isNode ? argItem : document.createTextNode(String(argItem))); - } - - return docFrag; -}; - -// The ChildNode interface contains methods that are particular to `Node` -// objects that can have a parent. It is implemented by `Element`, -// `DocumentType`, and `CharacterData` objects. -var ChildNode = { - // Inserts a set of Node or String objects in the children list of this - // ChildNode's parent, just after this ChildNode. String objects are - // inserted as the equivalent Text nodes. - after: { - value: function after() { - var argArr = Array.prototype.slice.call(arguments); - var parentNode = this.parentNode, - nextSibling = this.nextSibling; - if (parentNode === null) { - return; - } - // Find "viable next sibling"; that is, next one not in argArr - while ( - nextSibling && - argArr.some(function (v) { - return v === nextSibling; - }) - ) - nextSibling = nextSibling.nextSibling; - // ok, parent and sibling are saved away since this node could itself - // appear in argArr and we're about to move argArr to a document fragment. - var docFrag = createDocumentFragmentFromArguments(this.doc, argArr); - - parentNode.insertBefore(docFrag, nextSibling); - }, - }, - - // Inserts a set of Node or String objects in the children list of this - // ChildNode's parent, just before this ChildNode. String objects are - // inserted as the equivalent Text nodes. - before: { - value: function before() { - var argArr = Array.prototype.slice.call(arguments); - var parentNode = this.parentNode, - prevSibling = this.previousSibling; - if (parentNode === null) { - return; - } - // Find "viable prev sibling"; that is, prev one not in argArr - while ( - prevSibling && - argArr.some(function (v) { - return v === prevSibling; - }) - ) - prevSibling = prevSibling.previousSibling; - // ok, parent and sibling are saved away since this node could itself - // appear in argArr and we're about to move argArr to a document fragment. - var docFrag = createDocumentFragmentFromArguments(this.doc, argArr); - - var nextSibling = prevSibling ? prevSibling.nextSibling : parentNode.firstChild; - parentNode.insertBefore(docFrag, nextSibling); - }, - }, - - // Remove this node from its parent - remove: { - value: function remove() { - if (this.parentNode === null) return; - - // Send mutation events if necessary - if (this.doc) { - this.doc._preremoveNodeIterators(this); - if (this.rooted) { - this.doc.mutateRemove(this); - } - } - - // Remove this node from its parents array of children - // and update the structure id for all ancestors - this._remove(); - - // Forget this node's parent - this.parentNode = null; - }, - }, - - // Remove this node w/o uprooting or sending mutation events - // (But do update the structure id for all ancestors) - _remove: { - value: function _remove() { - var parent = this.parentNode; - if (parent === null) return; - if (parent._childNodes) { - parent._childNodes.splice(this.index, 1); - } else if (parent._firstChild === this) { - if (this._nextSibling === this) { - parent._firstChild = null; - } else { - parent._firstChild = this._nextSibling; - } - } - LinkedList.remove(this); - parent.modify(); - }, - }, - - // Replace this node with the nodes or strings provided as arguments. - replaceWith: { - value: function replaceWith() { - var argArr = Array.prototype.slice.call(arguments); - var parentNode = this.parentNode, - nextSibling = this.nextSibling; - if (parentNode === null) { - return; - } - // Find "viable next sibling"; that is, next one not in argArr - while ( - nextSibling && - argArr.some(function (v) { - return v === nextSibling; - }) - ) - nextSibling = nextSibling.nextSibling; - // ok, parent and sibling are saved away since this node could itself - // appear in argArr and we're about to move argArr to a document fragment. - var docFrag = createDocumentFragmentFromArguments(this.doc, argArr); - if (this.parentNode === parentNode) { - parentNode.replaceChild(docFrag, this); - } else { - // `this` was inserted into docFrag - parentNode.insertBefore(docFrag, nextSibling); - } - }, - }, -}; - -module.exports = ChildNode; diff --git a/packages/qwik-dom/lib/Comment.js b/packages/qwik-dom/lib/Comment.js deleted file mode 100644 index 25d473fcfb2..00000000000 --- a/packages/qwik-dom/lib/Comment.js +++ /dev/null @@ -1,48 +0,0 @@ -'use strict'; -module.exports = Comment; - -var Node = require('./Node'); -var utils = require('./utils'); - -var CharacterData = require('./CharacterData'); - -function Comment(doc, data) { - CharacterData.call(this); - this.nodeType = Node.COMMENT_NODE; - this.ownerDocument = doc; - this._data = utils.escapeText(data); -} - -var nodeValue = { - get: function () { - return this._data; - }, - set: function (v) { - if (v === null || v === undefined) { - v = ''; - } else { - v = String(v); - } - this._data = utils.escapeText(v); - if (this.rooted) this.ownerDocument.mutateValue(this); - }, -}; - -Comment.prototype = Object.create(CharacterData.prototype, { - nodeName: { value: '#comment' }, - nodeValue: nodeValue, - textContent: nodeValue, - data: { - get: nodeValue.get, - set: function (v) { - nodeValue.set.call(this, v === null ? '' : String(v)); - }, - }, - - // Utility methods - clone: { - value: function clone() { - return new Comment(this.ownerDocument, this._data); - }, - }, -}); diff --git a/packages/qwik-dom/lib/ContainerNode.js b/packages/qwik-dom/lib/ContainerNode.js deleted file mode 100644 index 11da347c6f9..00000000000 --- a/packages/qwik-dom/lib/ContainerNode.js +++ /dev/null @@ -1,105 +0,0 @@ -'use strict'; -module.exports = ContainerNode; - -var Node = require('./Node'); -var NodeList = require('./NodeList'); - -// This class defines common functionality for node subtypes that -// can have children - -function ContainerNode() { - Node.call(this); - this._firstChild = this._childNodes = null; -} - -// Primary representation is a circular linked list of siblings -ContainerNode.prototype = Object.create(Node.prototype, { - hasChildNodes: { - value: function () { - if (this._childNodes) { - return this._childNodes.length > 0; - } - return this._firstChild !== null; - }, - }, - - childNodes: { - get: function () { - this._ensureChildNodes(); - return this._childNodes; - }, - }, - - firstChild: { - get: function () { - if (this._childNodes) { - return this._childNodes.length === 0 ? null : this._childNodes[0]; - } - return this._firstChild; - }, - }, - - lastChild: { - get: function () { - var kids = this._childNodes, - first; - if (kids) { - return kids.length === 0 ? null : kids[kids.length - 1]; - } - first = this._firstChild; - if (first === null) { - return null; - } - return first._previousSibling; // circular linked list - }, - }, - - _ensureChildNodes: { - value: function () { - if (this._childNodes) { - return; - } - var first = this._firstChild, - kid = first, - childNodes = (this._childNodes = new NodeList()); - if (first) - do { - childNodes.push(kid); - kid = kid._nextSibling; - } while (kid !== first); // circular linked list - this._firstChild = null; // free memory - }, - }, - - replaceChildren: { - value: function replaceChildren() { - this.removeChildren(); - - // Should probably implement here the replace logic as well - // but for now we just need the "children" removal ability - } - }, - - // Remove all of this node's children. This is a minor - // optimization that only calls modify() once. - removeChildren: { - value: function removeChildren() { - var root = this.rooted ? this.ownerDocument : null, - next = this.firstChild, - kid; - while (next !== null) { - kid = next; - next = kid.nextSibling; - - if (root) root.mutateRemove(kid); - kid.parentNode = null; - } - if (this._childNodes) { - this._childNodes.length = 0; - } else { - this._firstChild = null; - } - this.modify(); // Update last modified type once only - }, - }, -}); diff --git a/packages/qwik-dom/lib/CustomEvent.js b/packages/qwik-dom/lib/CustomEvent.js deleted file mode 100644 index 04dbe6fd5d4..00000000000 --- a/packages/qwik-dom/lib/CustomEvent.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict'; -module.exports = CustomEvent; - -var Event = require('./Event'); - -function CustomEvent(type, dictionary) { - // Just use the superclass constructor to initialize - Event.call(this, type, dictionary); -} -CustomEvent.prototype = Object.create(Event.prototype, { - constructor: { value: CustomEvent }, -}); diff --git a/packages/qwik-dom/lib/DOMException.js b/packages/qwik-dom/lib/DOMException.js deleted file mode 100644 index ce7d3f6008a..00000000000 --- a/packages/qwik-dom/lib/DOMException.js +++ /dev/null @@ -1,134 +0,0 @@ -'use strict'; -module.exports = DOMException; - -var INDEX_SIZE_ERR = 1; -var HIERARCHY_REQUEST_ERR = 3; -var WRONG_DOCUMENT_ERR = 4; -var INVALID_CHARACTER_ERR = 5; -var NO_MODIFICATION_ALLOWED_ERR = 7; -var NOT_FOUND_ERR = 8; -var NOT_SUPPORTED_ERR = 9; -var INVALID_STATE_ERR = 11; -var SYNTAX_ERR = 12; -var INVALID_MODIFICATION_ERR = 13; -var NAMESPACE_ERR = 14; -var INVALID_ACCESS_ERR = 15; -var TYPE_MISMATCH_ERR = 17; -var SECURITY_ERR = 18; -var NETWORK_ERR = 19; -var ABORT_ERR = 20; -var URL_MISMATCH_ERR = 21; -var QUOTA_EXCEEDED_ERR = 22; -var TIMEOUT_ERR = 23; -var INVALID_NODE_TYPE_ERR = 24; -var DATA_CLONE_ERR = 25; - -// Code to name -var names = [ - null, // No error with code 0 - 'INDEX_SIZE_ERR', - null, // historical - 'HIERARCHY_REQUEST_ERR', - 'WRONG_DOCUMENT_ERR', - 'INVALID_CHARACTER_ERR', - null, // historical - 'NO_MODIFICATION_ALLOWED_ERR', - 'NOT_FOUND_ERR', - 'NOT_SUPPORTED_ERR', - 'INUSE_ATTRIBUTE_ERR', // historical - 'INVALID_STATE_ERR', - 'SYNTAX_ERR', - 'INVALID_MODIFICATION_ERR', - 'NAMESPACE_ERR', - 'INVALID_ACCESS_ERR', - null, // historical - 'TYPE_MISMATCH_ERR', - 'SECURITY_ERR', - 'NETWORK_ERR', - 'ABORT_ERR', - 'URL_MISMATCH_ERR', - 'QUOTA_EXCEEDED_ERR', - 'TIMEOUT_ERR', - 'INVALID_NODE_TYPE_ERR', - 'DATA_CLONE_ERR', -]; - -// Code to message -// These strings are from the 13 May 2011 Editor's Draft of DOM Core. -// http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html -// Copyright Ā© 2011 W3CĀ® (MIT, ERCIM, Keio), All Rights Reserved. -// Used under the terms of the W3C Document License: -// http://www.w3.org/Consortium/Legal/2002/copyright-documents-20021231 -var messages = [ - null, // No error with code 0 - 'INDEX_SIZE_ERR (1): the index is not in the allowed range', - null, - 'HIERARCHY_REQUEST_ERR (3): the operation would yield an incorrect nodes model', - 'WRONG_DOCUMENT_ERR (4): the object is in the wrong Document, a call to importNode is required', - 'INVALID_CHARACTER_ERR (5): the string contains invalid characters', - null, - 'NO_MODIFICATION_ALLOWED_ERR (7): the object can not be modified', - 'NOT_FOUND_ERR (8): the object can not be found here', - 'NOT_SUPPORTED_ERR (9): this operation is not supported', - 'INUSE_ATTRIBUTE_ERR (10): setAttributeNode called on owned Attribute', - 'INVALID_STATE_ERR (11): the object is in an invalid state', - 'SYNTAX_ERR (12): the string did not match the expected pattern', - 'INVALID_MODIFICATION_ERR (13): the object can not be modified in this way', - 'NAMESPACE_ERR (14): the operation is not allowed by Namespaces in XML', - 'INVALID_ACCESS_ERR (15): the object does not support the operation or argument', - null, - 'TYPE_MISMATCH_ERR (17): the type of the object does not match the expected type', - 'SECURITY_ERR (18): the operation is insecure', - 'NETWORK_ERR (19): a network error occurred', - 'ABORT_ERR (20): the user aborted an operation', - 'URL_MISMATCH_ERR (21): the given URL does not match another URL', - 'QUOTA_EXCEEDED_ERR (22): the quota has been exceeded', - 'TIMEOUT_ERR (23): a timeout occurred', - 'INVALID_NODE_TYPE_ERR (24): the supplied node is invalid or has an invalid ancestor for this operation', - 'DATA_CLONE_ERR (25): the object can not be cloned.', -]; - -// Name to code -var constants = { - INDEX_SIZE_ERR: INDEX_SIZE_ERR, - DOMSTRING_SIZE_ERR: 2, // historical - HIERARCHY_REQUEST_ERR: HIERARCHY_REQUEST_ERR, - WRONG_DOCUMENT_ERR: WRONG_DOCUMENT_ERR, - INVALID_CHARACTER_ERR: INVALID_CHARACTER_ERR, - NO_DATA_ALLOWED_ERR: 6, // historical - NO_MODIFICATION_ALLOWED_ERR: NO_MODIFICATION_ALLOWED_ERR, - NOT_FOUND_ERR: NOT_FOUND_ERR, - NOT_SUPPORTED_ERR: NOT_SUPPORTED_ERR, - INUSE_ATTRIBUTE_ERR: 10, // historical - INVALID_STATE_ERR: INVALID_STATE_ERR, - SYNTAX_ERR: SYNTAX_ERR, - INVALID_MODIFICATION_ERR: INVALID_MODIFICATION_ERR, - NAMESPACE_ERR: NAMESPACE_ERR, - INVALID_ACCESS_ERR: INVALID_ACCESS_ERR, - VALIDATION_ERR: 16, // historical - TYPE_MISMATCH_ERR: TYPE_MISMATCH_ERR, - SECURITY_ERR: SECURITY_ERR, - NETWORK_ERR: NETWORK_ERR, - ABORT_ERR: ABORT_ERR, - URL_MISMATCH_ERR: URL_MISMATCH_ERR, - QUOTA_EXCEEDED_ERR: QUOTA_EXCEEDED_ERR, - TIMEOUT_ERR: TIMEOUT_ERR, - INVALID_NODE_TYPE_ERR: INVALID_NODE_TYPE_ERR, - DATA_CLONE_ERR: DATA_CLONE_ERR, -}; - -function DOMException(code) { - Error.call(this); - Error.captureStackTrace(this, this.constructor); - this.code = code; - this.message = messages[code]; - this.name = names[code]; -} -DOMException.prototype.__proto__ = Error.prototype; - -// Initialize the constants on DOMException and DOMException.prototype -for (var c in constants) { - var v = { value: constants[c] }; - Object.defineProperty(DOMException, c, v); - Object.defineProperty(DOMException.prototype, c, v); -} diff --git a/packages/qwik-dom/lib/DOMImplementation.js b/packages/qwik-dom/lib/DOMImplementation.js deleted file mode 100644 index c2a89e52a0c..00000000000 --- a/packages/qwik-dom/lib/DOMImplementation.js +++ /dev/null @@ -1,91 +0,0 @@ -'use strict'; -module.exports = DOMImplementation; - -var Document = require('./Document'); -var DocumentType = require('./DocumentType'); -var HTMLParser = require('./HTMLParser'); -var utils = require('./utils'); -var xml = require('./xmlnames'); - -// Each document must have its own instance of the domimplementation object -function DOMImplementation(contextObject) { - this.contextObject = contextObject; -} - -// Feature/version pairs that DOMImplementation.hasFeature() returns -// true for. It returns false for anything else. -var supportedFeatures = { - xml: { '': true, '1.0': true, '2.0': true }, // DOM Core - core: { '': true, '2.0': true }, // DOM Core - html: { '': true, '1.0': true, '2.0': true }, // HTML - xhtml: { '': true, '1.0': true, '2.0': true }, // HTML -}; - -DOMImplementation.prototype = { - hasFeature: function hasFeature(feature, version) { - var f = supportedFeatures[(feature || '').toLowerCase()]; - return (f && f[version || '']) || false; - }, - - createDocumentType: function createDocumentType(qualifiedName, publicId, systemId) { - if (!xml.isValidQName(qualifiedName)) utils.InvalidCharacterError(); - - return new DocumentType(this.contextObject, qualifiedName, publicId, systemId); - }, - - createDocument: function createDocument(namespace, qualifiedName, doctype) { - // - // Note that the current DOMCore spec makes it impossible to - // create an HTML document with this function, even if the - // namespace and doctype are properly set. See this thread: - // http://lists.w3.org/Archives/Public/www-dom/2011AprJun/0132.html - // - var d = new Document(false, null); - var e; - - if (qualifiedName) e = d.createElementNS(namespace, qualifiedName); - else e = null; - - if (doctype) { - d.appendChild(doctype); - } - - if (e) d.appendChild(e); - if (namespace === utils.NAMESPACE.HTML) { - d._contentType = 'application/xhtml+xml'; - } else if (namespace === utils.NAMESPACE.SVG) { - d._contentType = 'image/svg+xml'; - } else { - d._contentType = 'application/xml'; - } - - return d; - }, - - createHTMLDocument: function createHTMLDocument(titleText) { - var d = new Document(true, null); - d.appendChild(new DocumentType(d, 'html')); - var html = d.createElement('html'); - d.appendChild(html); - var head = d.createElement('head'); - html.appendChild(head); - if (titleText !== undefined) { - var title = d.createElement('title'); - head.appendChild(title); - title.appendChild(d.createTextNode(titleText)); - } - html.appendChild(d.createElement('body')); - d.modclock = 1; // Start tracking modifications - return d; - }, - - mozSetOutputMutationHandler: function (doc, handler) { - doc.mutationHandler = handler; - }, - - mozGetInputMutationHandler: function (doc) { - utils.nyi(); - }, - - mozHTMLParser: HTMLParser, -}; diff --git a/packages/qwik-dom/lib/DOMTokenList.js b/packages/qwik-dom/lib/DOMTokenList.js deleted file mode 100644 index 8acf4b357cd..00000000000 --- a/packages/qwik-dom/lib/DOMTokenList.js +++ /dev/null @@ -1,210 +0,0 @@ -'use strict'; -// DOMTokenList implementation based on https://github.com/Raynos/DOM-shim -var utils = require('./utils'); - -module.exports = DOMTokenList; - -function DOMTokenList(getter, setter) { - this._getString = getter; - this._setString = setter; - this._length = 0; - this._lastStringValue = ''; - this._update(); -} - -Object.defineProperties(DOMTokenList.prototype, { - length: { - get: function () { - return this._length; - }, - }, - item: { - value: function (index) { - var list = getList(this); - if (index < 0 || index >= list.length) { - return null; - } - return list[index]; - }, - }, - - contains: { - value: function (token) { - token = String(token); // no error checking for contains() - var list = getList(this); - return list.indexOf(token) > -1; - }, - }, - - add: { - value: function () { - var list = getList(this); - for (var i = 0, len = arguments.length; i < len; i++) { - var token = handleErrors(arguments[i]); - if (list.indexOf(token) < 0) { - list.push(token); - } - } - // Note: as per spec, if handleErrors() throws any errors, we never - // make it here and none of the changes take effect. - // Also per spec: we run the "update steps" even if no change was - // made (ie, if the token already existed) - this._update(list); - }, - }, - - remove: { - value: function () { - var list = getList(this); - for (var i = 0, len = arguments.length; i < len; i++) { - var token = handleErrors(arguments[i]); - var index = list.indexOf(token); - if (index > -1) { - list.splice(index, 1); - } - } - // Note: as per spec, if handleErrors() throws any errors, we never - // make it here and none of the changes take effect. - // Also per spec: we run the "update steps" even if no change was - // made (ie, if the token wasn't previously present) - this._update(list); - }, - }, - - toggle: { - value: function toggle(token, force) { - token = handleErrors(token); - if (this.contains(token)) { - if (force === undefined || force === false) { - this.remove(token); - return false; - } - return true; - } else { - if (force === undefined || force === true) { - this.add(token); - return true; - } - return false; - } - }, - }, - - replace: { - value: function replace(token, newToken) { - // weird corner case of spec: if `token` contains whitespace, but - // `newToken` is the empty string, we must throw SyntaxError not - // InvalidCharacterError (sigh) - if (String(newToken) === '') { - utils.SyntaxError(); - } - token = handleErrors(token); - newToken = handleErrors(newToken); - var list = getList(this); - var idx = list.indexOf(token); - if (idx < 0) { - // Note that, per spec, we do not run the update steps on this path. - return false; - } - var idx2 = list.indexOf(newToken); - if (idx2 < 0) { - list[idx] = newToken; - } else { - // "replace the first instance of either `token` or `newToken` with - // `newToken` and remove all other instances" - if (idx < idx2) { - list[idx] = newToken; - list.splice(idx2, 1); - } else { - // idx2 is already `newToken` - list.splice(idx, 1); - } - } - this._update(list); - return true; - }, - }, - - toString: { - value: function () { - return this._getString(); - }, - }, - - value: { - get: function () { - return this._getString(); - }, - set: function (v) { - this._setString(v); - this._update(); - }, - }, - - // Called when the setter is called from outside this interface. - _update: { - value: function (list) { - if (list) { - fixIndex(this, list); - this._setString(list.join(' ').trim()); - } else { - fixIndex(this, getList(this)); - } - this._lastStringValue = this._getString(); - }, - }, -}); - -function fixIndex(clist, list) { - var oldLength = clist._length; - var i; - clist._length = list.length; - for (i = 0; i < list.length; i++) { - clist[i] = list[i]; - } - // Clear/free old entries. - for (; i < oldLength; i++) { - clist[i] = undefined; - } -} - -function handleErrors(token) { - token = String(token); - if (token === '') { - utils.SyntaxError(); - } - if (/[ \t\r\n\f]/.test(token)) { - utils.InvalidCharacterError(); - } - return token; -} - -function toArray(clist) { - var length = clist._length; - var arr = Array(length); - for (var i = 0; i < length; i++) { - arr[i] = clist[i]; - } - return arr; -} - -function getList(clist) { - var strProp = clist._getString(); - if (strProp === clist._lastStringValue) { - return toArray(clist); - } - var str = strProp.replace(/(^[ \t\r\n\f]+)|([ \t\r\n\f]+$)/g, ''); - if (str === '') { - return []; - } else { - var seen = Object.create(null); - return str.split(/[ \t\r\n\f]+/g).filter(function (n) { - var key = '$' + n; - if (seen[key]) { - return false; - } - seen[key] = true; - return true; - }); - } -} diff --git a/packages/qwik-dom/lib/Document.js b/packages/qwik-dom/lib/Document.js deleted file mode 100644 index 13255980aa2..00000000000 --- a/packages/qwik-dom/lib/Document.js +++ /dev/null @@ -1,1116 +0,0 @@ -'use strict'; -module.exports = Document; - -var Node = require('./Node'); -var NodeList = require('./NodeList'); -var ContainerNode = require('./ContainerNode'); -var Element = require('./Element'); -var Text = require('./Text'); -var Comment = require('./Comment'); -var Event = require('./Event'); -var DocumentFragment = require('./DocumentFragment'); -var ProcessingInstruction = require('./ProcessingInstruction'); -var DOMImplementation = require('./DOMImplementation'); -var TreeWalker = require('./TreeWalker'); -var NodeIterator = require('./NodeIterator'); -var NodeFilter = require('./NodeFilter'); -var URL = require('./URL'); -var select = require('./select'); -var events = require('./events'); -var xml = require('./xmlnames'); -var html = require('./htmlelts'); -var svg = require('./svg'); -var utils = require('./utils'); -var MUTATE = require('./MutationConstants'); -var NAMESPACE = utils.NAMESPACE; -var isApiWritable = require('./config').isApiWritable; - -function Document(isHTML, address) { - ContainerNode.call(this); - this.nodeType = Node.DOCUMENT_NODE; - this.isHTML = isHTML; - this._address = address || 'about:blank'; - this.readyState = 'loading'; - this.implementation = new DOMImplementation(this); - - // DOMCore says that documents are always associated with themselves - this.ownerDocument = null; // ... but W3C tests expect null - this._contentType = isHTML ? 'text/html' : 'application/xml'; - - // These will be initialized by our custom versions of - // appendChild and insertBefore that override the inherited - // Node methods. - // XXX: override those methods! - this.doctype = null; - this.documentElement = null; - - // "Associated inert template document" - this._templateDocCache = null; - // List of active NodeIterators, see NodeIterator#_preremove() - this._nodeIterators = null; - - // Documents are always rooted, by definition - this._nid = 1; - this._nextnid = 2; // For numbering children of the document - this._nodes = [null, this]; // nid to node map - - // This maintains the mapping from element ids to element nodes. - // We may need to update this mapping every time a node is rooted - // or uprooted, and any time an attribute is added, removed or changed - // on a rooted element. - this.byId = Object.create(null); - - // This property holds a monotonically increasing value akin to - // a timestamp used to record the last modification time of nodes - // and their subtrees. See the lastModTime attribute and modify() - // method of the Node class. And see FilteredElementList for an example - // of the use of lastModTime - this.modclock = 0; -} - -// Map from lowercase event category names (used as arguments to -// createEvent()) to the property name in the impl object of the -// event constructor. -var supportedEvents = { - event: 'Event', - customevent: 'CustomEvent', - uievent: 'UIEvent', - mouseevent: 'MouseEvent', -}; - -// Certain arguments to document.createEvent() must be treated specially -var replacementEvent = { - events: 'event', - htmlevents: 'event', - mouseevents: 'mouseevent', - mutationevents: 'mutationevent', - uievents: 'uievent', -}; - -var mirrorAttr = function (f, name, defaultValue) { - return { - get: function () { - var o = f.call(this); - if (o) { - return o[name]; - } - return defaultValue; - }, - set: function (value) { - var o = f.call(this); - if (o) { - o[name] = value; - } - }, - }; -}; - -/** @spec https://dom.spec.whatwg.org/#validate-and-extract */ -function validateAndExtract(namespace, qualifiedName) { - var prefix, localName, pos; - if (namespace === '') { - namespace = null; - } - // See https://github.com/whatwg/dom/issues/671 - // and https://github.com/whatwg/dom/issues/319 - if (!xml.isValidQName(qualifiedName)) { - utils.InvalidCharacterError(); - } - prefix = null; - localName = qualifiedName; - - pos = qualifiedName.indexOf(':'); - if (pos >= 0) { - prefix = qualifiedName.substring(0, pos); - localName = qualifiedName.substring(pos + 1); - } - if (prefix !== null && namespace === null) { - utils.NamespaceError(); - } - if (prefix === 'xml' && namespace !== NAMESPACE.XML) { - utils.NamespaceError(); - } - if ((prefix === 'xmlns' || qualifiedName === 'xmlns') && namespace !== NAMESPACE.XMLNS) { - utils.NamespaceError(); - } - if (namespace === NAMESPACE.XMLNS && !(prefix === 'xmlns' || qualifiedName === 'xmlns')) { - utils.NamespaceError(); - } - return { namespace: namespace, prefix: prefix, localName: localName }; -} - -Document.prototype = Object.create(ContainerNode.prototype, { - // This method allows dom.js to communicate with a renderer - // that displays the document in some way - // XXX: I should probably move this to the window object - _setMutationHandler: { - value: function (handler) { - this.mutationHandler = handler; - }, - }, - - // This method allows dom.js to receive event notifications - // from the renderer. - // XXX: I should probably move this to the window object - _dispatchRendererEvent: { - value: function (targetNid, type, details) { - var target = this._nodes[targetNid]; - if (!target) return; - target._dispatchEvent(new Event(type, details), true); - }, - }, - - nodeName: { value: '#document' }, - nodeValue: { - get: function () { - return null; - }, - set: function () {}, - }, - - // XXX: DOMCore may remove documentURI, so it is NYI for now - documentURI: { - get: function () { - return this._address; - }, - set: utils.nyi, - }, - compatMode: { - get: function () { - // The _quirks property is set by the HTML parser - return this._quirks ? 'BackCompat' : 'CSS1Compat'; - }, - }, - - createTextNode: { - value: function (data) { - return new Text(this, String(data)); - }, - }, - createComment: { - value: function (data) { - return new Comment(this, data); - }, - }, - createDocumentFragment: { - value: function () { - return new DocumentFragment(this); - }, - }, - createProcessingInstruction: { - value: function (target, data) { - if (!xml.isValidName(target) || data.indexOf('?>') !== -1) utils.InvalidCharacterError(); - return new ProcessingInstruction(this, target, data); - }, - }, - - createAttribute: { - value: function (localName) { - localName = String(localName); - if (!xml.isValidName(localName)) utils.InvalidCharacterError(); - if (this.isHTML) { - localName = utils.toASCIILowerCase(localName); - } - return new Element._Attr(null, localName, null, null, ''); - }, - }, - createAttributeNS: { - value: function (namespace, qualifiedName) { - // Convert parameter types according to WebIDL - namespace = - namespace === null || namespace === undefined || namespace === '' - ? null - : String(namespace); - qualifiedName = String(qualifiedName); - var ve = validateAndExtract(namespace, qualifiedName); - return new Element._Attr(null, ve.localName, ve.prefix, ve.namespace, ''); - }, - }, - - createElement: { - value: function (localName) { - localName = String(localName); - if (!xml.isValidName(localName)) utils.InvalidCharacterError(); - // Per spec, namespace should be HTML namespace if "context object is - // an HTML document or context object's content type is - // "application/xhtml+xml", and null otherwise. - if (this.isHTML) { - if (/[A-Z]/.test(localName)) localName = utils.toASCIILowerCase(localName); - return html.createElement(this, localName, null); - } else if (this.contentType === 'application/xhtml+xml') { - return html.createElement(this, localName, null); - } else { - return new Element(this, localName, null, null); - } - }, - writable: isApiWritable, - }, - - createElementNS: { - value: function (namespace, qualifiedName) { - // Convert parameter types according to WebIDL - namespace = - namespace === null || namespace === undefined || namespace === '' - ? null - : String(namespace); - qualifiedName = String(qualifiedName); - var ve = validateAndExtract(namespace, qualifiedName); - return this._createElementNS(ve.localName, ve.namespace, ve.prefix); - }, - writable: isApiWritable, - }, - - // This is used directly by HTML parser, which allows it to create - // elements with localNames containing ':' and non-default namespaces - _createElementNS: { - value: function (localName, namespace, prefix) { - if (namespace === NAMESPACE.HTML) { - return html.createElement(this, localName, prefix); - } else if (namespace === NAMESPACE.SVG) { - return svg.createElement(this, localName, prefix); - } - - return new Element(this, localName, namespace, prefix); - }, - }, - - createEvent: { - value: function createEvent(interfaceName) { - interfaceName = interfaceName.toLowerCase(); - var name = replacementEvent[interfaceName] || interfaceName; - var constructor = events[supportedEvents[name]]; - - if (constructor) { - var e = new constructor(); - e._initialized = false; - return e; - } else { - utils.NotSupportedError(); - } - }, - }, - - // See: http://www.w3.org/TR/dom/#dom-document-createtreewalker - createTreeWalker: { - value: function (root, whatToShow, filter) { - if (!root) { - throw new TypeError('root argument is required'); - } - if (!(root instanceof Node)) { - throw new TypeError('root not a node'); - } - whatToShow = whatToShow === undefined ? NodeFilter.SHOW_ALL : +whatToShow; - filter = filter === undefined ? null : filter; - - return new TreeWalker(root, whatToShow, filter); - }, - }, - - // See: http://www.w3.org/TR/dom/#dom-document-createnodeiterator - createNodeIterator: { - value: function (root, whatToShow, filter) { - if (!root) { - throw new TypeError('root argument is required'); - } - if (!(root instanceof Node)) { - throw new TypeError('root not a node'); - } - whatToShow = whatToShow === undefined ? NodeFilter.SHOW_ALL : +whatToShow; - filter = filter === undefined ? null : filter; - - return new NodeIterator(root, whatToShow, filter); - }, - }, - - _attachNodeIterator: { - value: function (ni) { - // XXX ideally this should be a weak reference from Document to NodeIterator - if (!this._nodeIterators) { - this._nodeIterators = []; - } - this._nodeIterators.push(ni); - }, - }, - - _detachNodeIterator: { - value: function (ni) { - // ni should always be in list of node iterators - var idx = this._nodeIterators.indexOf(ni); - this._nodeIterators.splice(idx, 1); - }, - }, - - _preremoveNodeIterators: { - value: function (toBeRemoved) { - if (this._nodeIterators) { - this._nodeIterators.forEach(function (ni) { - ni._preremove(toBeRemoved); - }); - } - }, - }, - - // Maintain the documentElement and - // doctype properties of the document. Each of the following - // methods chains to the Node implementation of the method - // to do the actual inserting, removal or replacement. - - _updateDocTypeElement: { - value: function _updateDocTypeElement() { - this.doctype = this.documentElement = null; - for (var kid = this.firstChild; kid !== null; kid = kid.nextSibling) { - if (kid.nodeType === Node.DOCUMENT_TYPE_NODE) this.doctype = kid; - else if (kid.nodeType === Node.ELEMENT_NODE) this.documentElement = kid; - } - }, - }, - - insertBefore: { - value: function insertBefore(child, refChild) { - Node.prototype.insertBefore.call(this, child, refChild); - this._updateDocTypeElement(); - return child; - }, - }, - - replaceChild: { - value: function replaceChild(node, child) { - Node.prototype.replaceChild.call(this, node, child); - this._updateDocTypeElement(); - return child; - }, - }, - - removeChild: { - value: function removeChild(child) { - Node.prototype.removeChild.call(this, child); - this._updateDocTypeElement(); - return child; - }, - }, - - getElementById: { - value: function (id) { - var n = this.byId[id]; - if (!n) return null; - if (n instanceof MultiId) { - // there was more than one element with this id - return n.getFirst(); - } - return n; - }, - }, - - _hasMultipleElementsWithId: { - value: function (id) { - // Used internally by querySelectorAll optimization - return this.byId[id] instanceof MultiId; - }, - }, - - // Just copy this method from the Element prototype - getElementsByName: { value: Element.prototype.getElementsByName }, - getElementsByTagName: { value: Element.prototype.getElementsByTagName }, - getElementsByTagNameNS: { value: Element.prototype.getElementsByTagNameNS }, - getElementsByClassName: { value: Element.prototype.getElementsByClassName }, - - adoptNode: { - value: function adoptNode(node) { - if (node.nodeType === Node.DOCUMENT_NODE) utils.NotSupportedError(); - if (node.nodeType === Node.ATTRIBUTE_NODE) { - return node; - } - - if (node.parentNode) node.parentNode.removeChild(node); - - if (node.ownerDocument !== this) recursivelySetOwner(node, this); - - return node; - }, - }, - - importNode: { - value: function importNode(node, deep) { - return this.adoptNode(node.cloneNode(deep)); - }, - writable: isApiWritable, - }, - - // The following attributes and methods are from the HTML spec - origin: { - get: function origin() { - return null; - }, - }, - characterSet: { - get: function characterSet() { - return 'UTF-8'; - }, - }, - contentType: { - get: function contentType() { - return this._contentType; - }, - }, - URL: { - get: function URL() { - return this._address; - }, - }, - domain: { get: utils.nyi, set: utils.nyi }, - referrer: { get: utils.nyi }, - cookie: { get: utils.nyi, set: utils.nyi }, - lastModified: { get: utils.nyi }, - location: { - get: function () { - return this.defaultView ? this.defaultView.location : null; // gh #75 - }, - set: utils.nyi, - }, - _titleElement: { - get: function () { - // The title element of a document is the first title element in the - // document in tree order, if there is one, or null otherwise. - return this.getElementsByTagName('title').item(0) || null; - }, - }, - title: { - get: function () { - var elt = this._titleElement; - // The child text content of the title element, or '' if null. - var value = elt ? elt.textContent : ''; - // Strip and collapse whitespace in value - return value.replace(/[ \t\n\r\f]+/g, ' ').replace(/(^ )|( $)/g, ''); - }, - set: function (value) { - var elt = this._titleElement; - var head = this.head; - if (!elt && !head) { - return; /* according to spec */ - } - if (!elt) { - elt = this.createElement('title'); - head.appendChild(elt); - } - elt.textContent = value; - }, - }, - dir: mirrorAttr( - function () { - var htmlElement = this.documentElement; - if (htmlElement && htmlElement.tagName === 'HTML') { - return htmlElement; - } - }, - 'dir', - '' - ), - fgColor: mirrorAttr( - function () { - return this.body; - }, - 'text', - '' - ), - linkColor: mirrorAttr( - function () { - return this.body; - }, - 'link', - '' - ), - vlinkColor: mirrorAttr( - function () { - return this.body; - }, - 'vLink', - '' - ), - alinkColor: mirrorAttr( - function () { - return this.body; - }, - 'aLink', - '' - ), - bgColor: mirrorAttr( - function () { - return this.body; - }, - 'bgColor', - '' - ), - - // Historical aliases of Document#characterSet - charset: { - get: function () { - return this.characterSet; - }, - }, - inputEncoding: { - get: function () { - return this.characterSet; - }, - }, - - scrollingElement: { - get: function () { - return this._quirks ? this.body : this.documentElement; - }, - }, - - // Return the first <body> child of the document element. - // XXX For now, setting this attribute is not implemented. - body: { - get: function () { - return namedHTMLChild(this.documentElement, 'body'); - }, - set: utils.nyi, - }, - // Return the first <head> child of the document element. - head: { - get: function () { - return namedHTMLChild(this.documentElement, 'head'); - }, - }, - images: { get: utils.nyi }, - embeds: { get: utils.nyi }, - plugins: { get: utils.nyi }, - links: { get: utils.nyi }, - forms: { get: utils.nyi }, - scripts: { get: utils.nyi }, - applets: { - get: function () { - return []; - }, - }, - activeElement: { - get: function () { - return null; - }, - }, - innerHTML: { - get: function () { - return this.serialize(); - }, - set: utils.nyi, - }, - outerHTML: { - get: function () { - return this.serialize(); - }, - set: utils.nyi, - }, - - write: { - value: function (args) { - if (!this.isHTML) utils.InvalidStateError(); - - // XXX: still have to implement the ignore part - if (!this._parser /* && this._ignore_destructive_writes > 0 */) return; - - if (!this._parser) { - // XXX call document.open, etc. - } - - var s = arguments.join(''); - - // If the Document object's reload override flag is set, then - // append the string consisting of the concatenation of all the - // arguments to the method to the Document's reload override - // buffer. - // XXX: don't know what this is about. Still have to do it - - // If there is no pending parsing-blocking script, have the - // tokenizer process the characters that were inserted, one at a - // time, processing resulting tokens as they are emitted, and - // stopping when the tokenizer reaches the insertion point or when - // the processing of the tokenizer is aborted by the tree - // construction stage (this can happen if a script end tag token is - // emitted by the tokenizer). - - // XXX: still have to do the above. Sounds as if we don't - // always call parse() here. If we're blocked, then we just - // insert the text into the stream but don't parse it reentrantly... - - // Invoke the parser reentrantly - this._parser.parse(s); - }, - }, - - writeln: { - value: function writeln(args) { - this.write(Array.prototype.join.call(arguments, '') + '\n'); - }, - }, - - open: { - value: function () { - this.documentElement = null; - }, - }, - - close: { - value: function () { - this.readyState = 'interactive'; - this._dispatchEvent(new Event('readystatechange'), true); - this._dispatchEvent(new Event('DOMContentLoaded'), true); - this.readyState = 'complete'; - this._dispatchEvent(new Event('readystatechange'), true); - if (this.defaultView) { - this.defaultView._dispatchEvent(new Event('load'), true); - } - }, - }, - - // Utility methods - clone: { - value: function clone() { - var d = new Document(this.isHTML, this._address); - d._quirks = this._quirks; - d._contentType = this._contentType; - return d; - }, - }, - - // We need to adopt the nodes if we do a deep clone - cloneNode: { - value: function cloneNode(deep) { - var clone = Node.prototype.cloneNode.call(this, false); - if (deep) { - for (var kid = this.firstChild; kid !== null; kid = kid.nextSibling) { - clone._appendChild(clone.importNode(kid, true)); - } - } - clone._updateDocTypeElement(); - return clone; - }, - }, - - isEqual: { - value: function isEqual(n) { - // Any two documents are shallowly equal. - // Node.isEqualNode will also test the children - return true; - }, - }, - - // Implementation-specific function. Called when a text, comment, - // or pi value changes. - mutateValue: { - value: function (node) { - if (this.mutationHandler) { - this.mutationHandler({ - type: MUTATE.VALUE, - target: node, - data: node.data, - }); - } - }, - }, - - // Invoked when an attribute's value changes. Attr holds the new - // value. oldval is the old value. Attribute mutations can also - // involve changes to the prefix (and therefore the qualified name) - mutateAttr: { - value: function (attr, oldval) { - // Manage id->element mapping for getElementsById() - // XXX: this special case id handling should not go here, - // but in the attribute declaration for the id attribute - /* - if (attr.localName === 'id' && attr.namespaceURI === null) { - if (oldval) delId(oldval, attr.ownerElement); - addId(attr.value, attr.ownerElement); - } - */ - if (this.mutationHandler) { - this.mutationHandler({ - type: MUTATE.ATTR, - target: attr.ownerElement, - attr: attr, - }); - } - }, - }, - - // Used by removeAttribute and removeAttributeNS for attributes. - mutateRemoveAttr: { - value: function (attr) { - /* -* This is now handled in Attributes.js - // Manage id to element mapping - if (attr.localName === 'id' && attr.namespaceURI === null) { - this.delId(attr.value, attr.ownerElement); - } -*/ - if (this.mutationHandler) { - this.mutationHandler({ - type: MUTATE.REMOVE_ATTR, - target: attr.ownerElement, - attr: attr, - }); - } - }, - }, - - // Called by Node.removeChild, etc. to remove a rooted element from - // the tree. Only needs to generate a single mutation event when a - // node is removed, but must recursively mark all descendants as not - // rooted. - mutateRemove: { - value: function (node) { - // Send a single mutation event - if (this.mutationHandler) { - this.mutationHandler({ - type: MUTATE.REMOVE, - target: node.parentNode, - node: node, - }); - } - - // Mark this and all descendants as not rooted - recursivelyUproot(node); - }, - }, - - // Called when a new element becomes rooted. It must recursively - // generate mutation events for each of the children, and mark them all - // as rooted. - mutateInsert: { - value: function (node) { - // Mark node and its descendants as rooted - recursivelyRoot(node); - - // Send a single mutation event - if (this.mutationHandler) { - this.mutationHandler({ - type: MUTATE.INSERT, - target: node.parentNode, - node: node, - }); - } - }, - }, - - // Called when a rooted element is moved within the document - mutateMove: { - value: function (node) { - if (this.mutationHandler) { - this.mutationHandler({ - type: MUTATE.MOVE, - target: node, - }); - } - }, - }, - - // Add a mapping from id to n for n.ownerDocument - addId: { - value: function addId(id, n) { - var val = this.byId[id]; - if (!val) { - this.byId[id] = n; - } else { - // TODO: Add a way to opt-out console warnings - //console.warn('Duplicate element id ' + id); - if (!(val instanceof MultiId)) { - val = new MultiId(val); - this.byId[id] = val; - } - val.add(n); - } - }, - }, - - // Delete the mapping from id to n for n.ownerDocument - delId: { - value: function delId(id, n) { - var val = this.byId[id]; - utils.assert(val); - - if (val instanceof MultiId) { - val.del(n); - if (val.length === 1) { - // convert back to a single node - this.byId[id] = val.downgrade(); - } - } else { - this.byId[id] = undefined; - } - }, - }, - - _resolve: { - value: function (href) { - //XXX: Cache the URL - return new URL(this._documentBaseURL).resolve(href); - }, - }, - - _documentBaseURL: { - get: function () { - // XXX: This is not implemented correctly yet - var url = this._address; - if (url === 'about:blank') url = '/'; - - var base = this.querySelector('base[href]'); - if (base) { - return new URL(url).resolve(base.getAttribute('href')); - } - return url; - - // The document base URL of a Document object is the - // absolute URL obtained by running these substeps: - - // Let fallback base url be the document's address. - - // If fallback base url is about:blank, and the - // Document's browsing context has a creator browsing - // context, then let fallback base url be the document - // base URL of the creator Document instead. - - // If the Document is an iframe srcdoc document, then - // let fallback base url be the document base URL of - // the Document's browsing context's browsing context - // container's Document instead. - - // If there is no base element that has an href - // attribute, then the document base URL is fallback - // base url; abort these steps. Otherwise, let url be - // the value of the href attribute of the first such - // element. - - // Resolve url relative to fallback base url (thus, - // the base href attribute isn't affected by xml:base - // attributes). - - // The document base URL is the result of the previous - // step if it was successful; otherwise it is fallback - // base url. - }, - }, - - _templateDoc: { - get: function () { - if (!this._templateDocCache) { - // "associated inert template document" - var newDoc = new Document(this.isHTML, this._address); - this._templateDocCache = newDoc._templateDocCache = newDoc; - } - return this._templateDocCache; - }, - }, - - querySelector: { - value: function (selector) { - return select(selector, this)[0]; - }, - }, - - querySelectorAll: { - value: function (selector) { - var nodes = select(selector, this); - return nodes.item ? nodes : new NodeList(nodes); - }, - }, -}); - -var eventHandlerTypes = [ - 'abort', - 'canplay', - 'canplaythrough', - 'change', - 'click', - 'contextmenu', - 'cuechange', - 'dblclick', - 'drag', - 'dragend', - 'dragenter', - 'dragleave', - 'dragover', - 'dragstart', - 'drop', - 'durationchange', - 'emptied', - 'ended', - 'input', - 'invalid', - 'keydown', - 'keypress', - 'keyup', - 'loadeddata', - 'loadedmetadata', - 'loadstart', - 'mousedown', - 'mousemove', - 'mouseout', - 'mouseover', - 'mouseup', - 'mousewheel', - 'pause', - 'play', - 'playing', - 'progress', - 'ratechange', - 'readystatechange', - 'reset', - 'seeked', - 'seeking', - 'select', - 'show', - 'stalled', - 'submit', - 'suspend', - 'timeupdate', - 'volumechange', - 'waiting', - - 'blur', - 'error', - 'focus', - 'load', - 'scroll', -]; - -// Add event handler idl attribute getters and setters to Document -eventHandlerTypes.forEach(function (type) { - // Define the event handler registration IDL attribute for this type - Object.defineProperty(Document.prototype, 'on' + type, { - get: function () { - return this._getEventHandler(type); - }, - set: function (v) { - this._setEventHandler(type, v); - }, - }); -}); - -function namedHTMLChild(parent, name) { - if (parent && parent.isHTML) { - for (var kid = parent.firstChild; kid !== null; kid = kid.nextSibling) { - if ( - kid.nodeType === Node.ELEMENT_NODE && - kid.localName === name && - kid.namespaceURI === NAMESPACE.HTML - ) { - return kid; - } - } - } - return null; -} - -function root(n) { - n._nid = n.ownerDocument._nextnid++; - n.ownerDocument._nodes[n._nid] = n; - // Manage id to element mapping - if (n.nodeType === Node.ELEMENT_NODE) { - var id = n.getAttribute('id'); - if (id) n.ownerDocument.addId(id, n); - - // Script elements need to know when they're inserted - // into the document - if (n._roothook) n._roothook(); - } -} - -function uproot(n) { - // Manage id to element mapping - if (n.nodeType === Node.ELEMENT_NODE) { - var id = n.getAttribute('id'); - if (id) n.ownerDocument.delId(id, n); - } - n.ownerDocument._nodes[n._nid] = undefined; - n._nid = undefined; -} - -function recursivelyRoot(node) { - root(node); - // XXX: - // accessing childNodes on a leaf node creates a new array the - // first time, so be careful to write this loop so that it - // doesn't do that. node is polymorphic, so maybe this is hard to - // optimize? Try switching on nodeType? - /* - if (node.hasChildNodes()) { - var kids = node.childNodes; - for(var i = 0, n = kids.length; i < n; i++) - recursivelyRoot(kids[i]); - } -*/ - if (node.nodeType === Node.ELEMENT_NODE) { - for (var kid = node.firstChild; kid !== null; kid = kid.nextSibling) recursivelyRoot(kid); - } -} - -function recursivelyUproot(node) { - uproot(node); - for (var kid = node.firstChild; kid !== null; kid = kid.nextSibling) recursivelyUproot(kid); -} - -function recursivelySetOwner(node, owner) { - node.ownerDocument = owner; - node._lastModTime = undefined; // mod times are document-based - if (Object.prototype.hasOwnProperty.call(node, '_tagName')) { - node._tagName = undefined; // Element subclasses might need to change case - } - for (var kid = node.firstChild; kid !== null; kid = kid.nextSibling) - recursivelySetOwner(kid, owner); -} - -// A class for storing multiple nodes with the same ID -function MultiId(node) { - this.nodes = Object.create(null); - this.nodes[node._nid] = node; - this.length = 1; - this.firstNode = undefined; -} - -// Add a node to the list, with O(1) time -MultiId.prototype.add = function (node) { - if (!this.nodes[node._nid]) { - this.nodes[node._nid] = node; - this.length++; - this.firstNode = undefined; - } -}; - -// Remove a node from the list, with O(1) time -MultiId.prototype.del = function (node) { - if (this.nodes[node._nid]) { - delete this.nodes[node._nid]; - this.length--; - this.firstNode = undefined; - } -}; - -// Get the first node from the list, in the document order -// Takes O(N) time in the size of the list, with a cache that is invalidated -// when the list is modified. -MultiId.prototype.getFirst = function () { - /* jshint bitwise: false */ - if (!this.firstNode) { - var nid; - for (nid in this.nodes) { - if ( - this.firstNode === undefined || - this.firstNode.compareDocumentPosition(this.nodes[nid]) & Node.DOCUMENT_POSITION_PRECEDING - ) { - this.firstNode = this.nodes[nid]; - } - } - } - return this.firstNode; -}; - -// If there is only one node left, return it. Otherwise return "this". -MultiId.prototype.downgrade = function () { - if (this.length === 1) { - var nid; - for (nid in this.nodes) { - return this.nodes[nid]; - } - } - return this; -}; diff --git a/packages/qwik-dom/lib/DocumentFragment.js b/packages/qwik-dom/lib/DocumentFragment.js deleted file mode 100644 index 4eef4e0a967..00000000000 --- a/packages/qwik-dom/lib/DocumentFragment.js +++ /dev/null @@ -1,80 +0,0 @@ -'use strict'; -module.exports = DocumentFragment; - -var Node = require('./Node'); -var NodeList = require('./NodeList'); -var ContainerNode = require('./ContainerNode'); -var Element = require('./Element'); -var select = require('./select'); -var utils = require('./utils'); - -function DocumentFragment(doc) { - ContainerNode.call(this); - this.nodeType = Node.DOCUMENT_FRAGMENT_NODE; - this.ownerDocument = doc; -} - -DocumentFragment.prototype = Object.create(ContainerNode.prototype, { - nodeName: { value: '#document-fragment' }, - nodeValue: { - get: function () { - return null; - }, - set: function () {}, - }, - // Copy the text content getter/setter from Element - textContent: Object.getOwnPropertyDescriptor(Element.prototype, 'textContent'), - - querySelector: { - value: function (selector) { - // implement in terms of querySelectorAll - var nodes = this.querySelectorAll(selector); - return nodes.length ? nodes[0] : null; - }, - }, - querySelectorAll: { - value: function (selector) { - // create a context - var context = Object.create(this); - // add some methods to the context for zest implementation, without - // adding them to the public DocumentFragment API - context.isHTML = true; // in HTML namespace (case-insensitive match) - context.getElementsByTagName = Element.prototype.getElementsByTagName; - context.nextElement = Object.getOwnPropertyDescriptor( - Element.prototype, - 'firstElementChild' - ).get; - // invoke zest - var nodes = select(selector, context); - return nodes.item ? nodes : new NodeList(nodes); - }, - }, - - // Utility methods - clone: { - value: function clone() { - return new DocumentFragment(this.ownerDocument); - }, - }, - isEqual: { - value: function isEqual(n) { - // Any two document fragments are shallowly equal. - // Node.isEqualNode() will test their children for equality - return true; - }, - }, - - // Non-standard, but useful (github issue #73) - innerHTML: { - get: function () { - return this.serialize(); - }, - set: utils.nyi, - }, - outerHTML: { - get: function () { - return this.serialize(); - }, - set: utils.nyi, - }, -}); diff --git a/packages/qwik-dom/lib/DocumentType.js b/packages/qwik-dom/lib/DocumentType.js deleted file mode 100644 index 442e0b8f14f..00000000000 --- a/packages/qwik-dom/lib/DocumentType.js +++ /dev/null @@ -1,44 +0,0 @@ -'use strict'; -module.exports = DocumentType; - -var Node = require('./Node'); -var Leaf = require('./Leaf'); -var ChildNode = require('./ChildNode'); - -function DocumentType(ownerDocument, name, publicId, systemId) { - Leaf.call(this); - this.nodeType = Node.DOCUMENT_TYPE_NODE; - this.ownerDocument = ownerDocument || null; - this.name = name; - this.publicId = publicId || ''; - this.systemId = systemId || ''; -} - -DocumentType.prototype = Object.create(Leaf.prototype, { - nodeName: { - get: function () { - return this.name; - }, - }, - nodeValue: { - get: function () { - return null; - }, - set: function () {}, - }, - - // Utility methods - clone: { - value: function clone() { - return new DocumentType(this.ownerDocument, this.name, this.publicId, this.systemId); - }, - }, - - isEqual: { - value: function isEqual(n) { - return this.name === n.name && this.publicId === n.publicId && this.systemId === n.systemId; - }, - }, -}); - -Object.defineProperties(DocumentType.prototype, ChildNode); diff --git a/packages/qwik-dom/lib/Element.js b/packages/qwik-dom/lib/Element.js deleted file mode 100644 index 3efe91618f0..00000000000 --- a/packages/qwik-dom/lib/Element.js +++ /dev/null @@ -1,1371 +0,0 @@ -'use strict'; -module.exports = Element; - -var xml = require('./xmlnames'); -var utils = require('./utils'); -var NAMESPACE = utils.NAMESPACE; -var attributes = require('./attributes'); -var Node = require('./Node'); -var NodeList = require('./NodeList'); -var NodeUtils = require('./NodeUtils'); -var FilteredElementList = require('./FilteredElementList'); -var DOMException = require('./DOMException'); -var DOMTokenList = require('./DOMTokenList'); -var select = require('./select'); -var ContainerNode = require('./ContainerNode'); -var ChildNode = require('./ChildNode'); -var NonDocumentTypeChildNode = require('./NonDocumentTypeChildNode'); -var NamedNodeMap = require('./NamedNodeMap'); - -var uppercaseCache = Object.create(null); - -function Element(doc, localName, namespaceURI, prefix) { - ContainerNode.call(this); - this.nodeType = Node.ELEMENT_NODE; - this.ownerDocument = doc; - this.localName = localName; - this.namespaceURI = namespaceURI; - this.prefix = prefix; - this._tagName = undefined; - - // These properties maintain the set of attributes - this._attrsByQName = Object.create(null); // The qname->Attr map - this._attrsByLName = Object.create(null); // The ns|lname->Attr map - this._attrKeys = []; // attr index -> ns|lname -} - -function recursiveGetText(node, a) { - if (node.nodeType === Node.TEXT_NODE) { - a.push(node._data); - } else { - for (var i = 0, n = node.childNodes.length; i < n; i++) recursiveGetText(node.childNodes[i], a); - } -} - -Element.prototype = Object.create(ContainerNode.prototype, { - isHTML: { - get: function isHTML() { - return this.namespaceURI === NAMESPACE.HTML && this.ownerDocument.isHTML; - }, - }, - tagName: { - get: function tagName() { - if (this._tagName === undefined) { - var tn; - if (this.prefix === null) { - tn = this.localName; - } else { - tn = this.prefix + ':' + this.localName; - } - if (this.isHTML) { - var up = uppercaseCache[tn]; - if (!up) { - // Converting to uppercase can be slow, so cache the conversion. - uppercaseCache[tn] = up = utils.toASCIIUpperCase(tn); - } - tn = up; - } - this._tagName = tn; - } - return this._tagName; - }, - }, - nodeName: { - get: function () { - return this.tagName; - }, - }, - nodeValue: { - get: function () { - return null; - }, - set: function () {}, - }, - textContent: { - get: function () { - var strings = []; - recursiveGetText(this, strings); - return strings.join(''); - }, - set: function (newtext) { - this.removeChildren(); - if (newtext !== null && newtext !== undefined && newtext !== '') { - this._appendChild(this.ownerDocument.createTextNode(newtext)); - } - }, - }, - innerHTML: { - get: function () { - return this.serialize(); - }, - set: function(v) { - var parser = this.ownerDocument.implementation.mozHTMLParser( - this.ownerDocument._address, - this); - parser.parse(v===null ? '' : String(v), true); - - // Remove any existing children of this node - var target = this; - while(target.hasChildNodes()) - target.removeChild(target.firstChild); - - // Now copy newly parsed children to this node - target.appendChild(parser._asDocumentFragment()); - - }, - }, - outerHTML: { - get: function () { - // "the attribute must return the result of running the HTML fragment - // serialization algorithm on a fictional node whose only child is - // the context object" - // - // The serialization logic is intentionally implemented in a separate - // `NodeUtils` helper instead of the more obvious choice of a private - // `_serializeOne()` method on the `Node.prototype` in order to avoid - // the megamorphic `this._serializeOne` property access, which reduces - // performance unnecessarily. If you need specialized behavior for a - // certain subclass, you'll need to implement that in `NodeUtils`. - // See https://github.com/fgnass/domino/pull/142 for more information. - return NodeUtils.serializeOne(this, { nodeType: 0 }); - }, - set: function (v) { - var document = this.ownerDocument; - var parent = this.parentNode; - if (parent === null) { - return; - } - if (parent.nodeType === Node.DOCUMENT_NODE) { - utils.NoModificationAllowedError(); - } - if (parent.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { - parent = parent.ownerDocument.createElement('body'); - } - var parser = document.implementation.mozHTMLParser(document._address, parent); - parser.parse(v === null ? '' : String(v), true); - this.replaceWith(parser._asDocumentFragment()); - }, - }, - - _insertAdjacent: { - value: function _insertAdjacent(position, node) { - var first = false; - switch (position) { - case 'beforebegin': - first = true; - /* falls through */ - case 'afterend': - var parent = this.parentNode; - if (parent === null) { - return null; - } - return parent.insertBefore(node, first ? this : this.nextSibling); - case 'afterbegin': - first = true; - /* falls through */ - case 'beforeend': - return this.insertBefore(node, first ? this.firstChild : null); - default: - return utils.SyntaxError(); - } - }, - }, - - insertAdjacentElement: { - value: function insertAdjacentElement(position, element) { - if (element.nodeType !== Node.ELEMENT_NODE) { - throw new TypeError('not an element'); - } - position = utils.toASCIILowerCase(String(position)); - return this._insertAdjacent(position, element); - }, - }, - - insertAdjacentText: { - value: function insertAdjacentText(position, data) { - var textNode = this.ownerDocument.createTextNode(data); - position = utils.toASCIILowerCase(String(position)); - this._insertAdjacent(position, textNode); - // "This method returns nothing because it existed before we had a chance - // to design it." - }, - }, - - insertAdjacentHTML: { - value: function insertAdjacentHTML(position, text) { - position = utils.toASCIILowerCase(String(position)); - text = String(text); - var context; - switch (position) { - case 'beforebegin': - case 'afterend': - context = this.parentNode; - if (context === null || context.nodeType === Node.DOCUMENT_NODE) { - utils.NoModificationAllowedError(); - } - break; - case 'afterbegin': - case 'beforeend': - context = this; - break; - default: - utils.SyntaxError(); - } - if ( - !(context instanceof Element) || - (context.ownerDocument.isHTML && - context.localName === 'html' && - context.namespaceURI === NAMESPACE.HTML) - ) { - context = context.ownerDocument.createElementNS(NAMESPACE.HTML, 'body'); - } - var parser = this.ownerDocument.implementation.mozHTMLParser( - this.ownerDocument._address, - context - ); - parser.parse(text, true); - this._insertAdjacent(position, parser._asDocumentFragment()); - }, - }, - - children: { - get: function () { - if (!this._children) { - this._children = new ChildrenCollection(this); - } - return this._children; - }, - }, - - attributes: { - get: function () { - if (!this._attributes) { - this._attributes = new AttributesArray(this); - } - return this._attributes; - }, - }, - - firstElementChild: { - get: function () { - for (var kid = this.firstChild; kid !== null; kid = kid.nextSibling) { - if (kid.nodeType === Node.ELEMENT_NODE) return kid; - } - return null; - }, - }, - - lastElementChild: { - get: function () { - for (var kid = this.lastChild; kid !== null; kid = kid.previousSibling) { - if (kid.nodeType === Node.ELEMENT_NODE) return kid; - } - return null; - }, - }, - - childElementCount: { - get: function () { - return this.children.length; - }, - }, - - // Return the next element, in source order, after this one or - // null if there are no more. If root element is specified, - // then don't traverse beyond its subtree. - // - // This is not a DOM method, but is convenient for - // lazy traversals of the tree. - nextElement: { - value: function (root) { - if (!root) root = this.ownerDocument.documentElement; - var next = this.firstElementChild; - if (!next) { - // don't use sibling if we're at root - if (this === root) return null; - next = this.nextElementSibling; - } - if (next) return next; - - // If we can't go down or across, then we have to go up - // and across to the parent sibling or another ancestor's - // sibling. Be careful, though: if we reach the root - // element, or if we reach the documentElement, then - // the traversal ends. - for ( - var parent = this.parentElement; - parent && parent !== root; - parent = parent.parentElement - ) { - next = parent.nextElementSibling; - if (next) return next; - } - - return null; - }, - }, - - // XXX: - // Tests are currently failing for this function. - // Awaiting resolution of: - // http://lists.w3.org/Archives/Public/www-dom/2011JulSep/0016.html - getElementsByTagName: { - value: function getElementsByTagName(lname) { - var filter; - if (!lname) return new NodeList(); - if (lname === '*') - filter = function () { - return true; - }; - else if (this.isHTML) filter = htmlLocalNameElementFilter(lname); - else filter = localNameElementFilter(lname); - - return new FilteredElementList(this, filter); - }, - }, - - getElementsByTagNameNS: { - value: function getElementsByTagNameNS(ns, lname) { - var filter; - if (ns === '*' && lname === '*') - filter = function () { - return true; - }; - else if (ns === '*') filter = localNameElementFilter(lname); - else if (lname === '*') filter = namespaceElementFilter(ns); - else filter = namespaceLocalNameElementFilter(ns, lname); - - return new FilteredElementList(this, filter); - }, - }, - - getElementsByClassName: { - value: function getElementsByClassName(names) { - names = String(names).trim(); - if (names === '') { - var result = new NodeList(); // Empty node list - return result; - } - names = names.split(/[ \t\r\n\f]+/); // Split on ASCII whitespace - return new FilteredElementList(this, classNamesElementFilter(names)); - }, - }, - - getElementsByName: { - value: function getElementsByName(name) { - return new FilteredElementList(this, elementNameFilter(String(name))); - }, - }, - - // Utility methods used by the public API methods above - clone: { - value: function clone() { - var e; - - // XXX: - // Modify this to use the constructor directly or - // avoid error checking in some other way. In case we try - // to clone an invalid node that the parser inserted. - // - if (this.namespaceURI !== NAMESPACE.HTML || this.prefix || !this.ownerDocument.isHTML) { - e = this.ownerDocument.createElementNS( - this.namespaceURI, - this.prefix !== null ? this.prefix + ':' + this.localName : this.localName - ); - } else { - e = this.ownerDocument.createElement(this.localName); - } - - for (var i = 0, n = this._attrKeys.length; i < n; i++) { - var lname = this._attrKeys[i]; - var a = this._attrsByLName[lname]; - var b = a.cloneNode(); - b._setOwnerElement(e); - e._attrsByLName[lname] = b; - e._addQName(b); - } - e._attrKeys = this._attrKeys.concat(); - - return e; - }, - }, - - isEqual: { - value: function isEqual(that) { - if ( - this.localName !== that.localName || - this.namespaceURI !== that.namespaceURI || - this.prefix !== that.prefix || - this._numattrs !== that._numattrs - ) - return false; - - // Compare the sets of attributes, ignoring order - // and ignoring attribute prefixes. - for (var i = 0, n = this._numattrs; i < n; i++) { - var a = this._attr(i); - if (!that.hasAttributeNS(a.namespaceURI, a.localName)) return false; - if (that.getAttributeNS(a.namespaceURI, a.localName) !== a.value) return false; - } - - return true; - }, - }, - - // This is the 'locate a namespace prefix' algorithm from the - // DOM specification. It is used by Node.lookupPrefix() - // (Be sure to compare DOM3 and DOM4 versions of spec.) - _lookupNamespacePrefix: { - value: function _lookupNamespacePrefix(ns, originalElement) { - if ( - this.namespaceURI && - this.namespaceURI === ns && - this.prefix !== null && - originalElement.lookupNamespaceURI(this.prefix) === ns - ) { - return this.prefix; - } - - for (var i = 0, n = this._numattrs; i < n; i++) { - var a = this._attr(i); - if ( - a.prefix === 'xmlns' && - a.value === ns && - originalElement.lookupNamespaceURI(a.localName) === ns - ) { - return a.localName; - } - } - - var parent = this.parentElement; - return parent ? parent._lookupNamespacePrefix(ns, originalElement) : null; - }, - }, - - // This is the 'locate a namespace' algorithm for Element nodes - // from the DOM Core spec. It is used by Node#lookupNamespaceURI() - lookupNamespaceURI: { - value: function lookupNamespaceURI(prefix) { - if (prefix === '' || prefix === undefined) { - prefix = null; - } - if (this.namespaceURI !== null && this.prefix === prefix) return this.namespaceURI; - - for (var i = 0, n = this._numattrs; i < n; i++) { - var a = this._attr(i); - if (a.namespaceURI === NAMESPACE.XMLNS) { - if ( - (a.prefix === 'xmlns' && a.localName === prefix) || - (prefix === null && a.prefix === null && a.localName === 'xmlns') - ) { - return a.value || null; - } - } - } - - var parent = this.parentElement; - return parent ? parent.lookupNamespaceURI(prefix) : null; - }, - }, - - // - // Attribute handling methods and utilities - // - - /* - * Attributes in the DOM are tricky: - * - * - there are the 8 basic get/set/has/removeAttribute{NS} methods - * - * - but many HTML attributes are also 'reflected' through IDL - * attributes which means that they can be queried and set through - * regular properties of the element. There is just one attribute - * value, but two ways to get and set it. - * - * - Different HTML element types have different sets of reflected - attributes. - * - * - attributes can also be queried and set through the .attributes - * property of an element. This property behaves like an array of - * Attr objects. The value property of each Attr is writeable, so - * this is a third way to read and write attributes. - * - * - for efficiency, we really want to store attributes in some kind - * of name->attr map. But the attributes[] array is an array, not a - * map, which is kind of unnatural. - * - * - When using namespaces and prefixes, and mixing the NS methods - * with the non-NS methods, it is apparently actually possible for - * an attributes[] array to have more than one attribute with the - * same qualified name. And certain methods must operate on only - * the first attribute with such a name. So for these methods, an - * inefficient array-like data structure would be easier to - * implement. - * - * - The attributes[] array is live, not a snapshot, so changes to the - * attributes must be immediately visible through existing arrays. - * - * - When attributes are queried and set through IDL properties - * (instead of the get/setAttributes() method or the attributes[] - * array) they may be subject to type conversions, URL - * normalization, etc., so some extra processing is required in that - * case. - * - * - But access through IDL properties is probably the most common - * case, so we'd like that to be as fast as possible. - * - * - We can't just store attribute values in their parsed idl form, - * because setAttribute() has to return whatever string is passed to - * getAttribute even if it is not a legal, parseable value. So - * attribute values must be stored in unparsed string form. - * - * - We need to be able to send change notifications or mutation - * events of some sort to the renderer whenever an attribute value - * changes, regardless of the way in which it changes. - * - * - Some attributes, such as id and class affect other parts of the - * DOM API, like getElementById and getElementsByClassName and so - * for efficiency, we need to specially track changes to these - * special attributes. - * - * - Some attributes like class have different names (className) when - * reflected. - * - * - Attributes whose names begin with the string 'data-' are treated - specially. - * - * - Reflected attributes that have a boolean type in IDL have special - * behavior: setting them to false (in IDL) is the same as removing - * them with removeAttribute() - * - * - numeric attributes (like HTMLElement.tabIndex) can have default - * values that must be returned by the idl getter even if the - * content attribute does not exist. (The default tabIndex value - * actually varies based on the type of the element, so that is a - * tricky one). - * - * See - * http://www.whatwg.org/specs/web-apps/current-work/multipage/urls.html#reflect - * for rules on how attributes are reflected. - * - */ - - getAttribute: { - value: function getAttribute(qname) { - var attr = this.getAttributeNode(qname); - return attr ? attr.value : null; - }, - }, - - getAttributeNS: { - value: function getAttributeNS(ns, lname) { - var attr = this.getAttributeNodeNS(ns, lname); - return attr ? attr.value : null; - }, - }, - - getAttributeNode: { - value: function getAttributeNode(qname) { - qname = String(qname); - if (/[A-Z]/.test(qname) && this.isHTML) qname = utils.toASCIILowerCase(qname); - var attr = this._attrsByQName[qname]; - if (!attr) return null; - - if (Array.isArray(attr)) - // If there is more than one - attr = attr[0]; // use the first - - return attr; - }, - }, - - getAttributeNodeNS: { - value: function getAttributeNodeNS(ns, lname) { - ns = ns === undefined || ns === null ? '' : String(ns); - lname = String(lname); - var attr = this._attrsByLName[ns + '|' + lname]; - return attr ? attr : null; - }, - }, - - hasAttribute: { - value: function hasAttribute(qname) { - qname = String(qname); - if (/[A-Z]/.test(qname) && this.isHTML) qname = utils.toASCIILowerCase(qname); - return this._attrsByQName[qname] !== undefined; - }, - }, - - hasAttributeNS: { - value: function hasAttributeNS(ns, lname) { - ns = ns === undefined || ns === null ? '' : String(ns); - lname = String(lname); - var key = ns + '|' + lname; - return this._attrsByLName[key] !== undefined; - }, - }, - - hasAttributes: { - value: function hasAttributes() { - return this._numattrs > 0; - }, - }, - - toggleAttribute: { - value: function toggleAttribute(qname, force) { - qname = String(qname); - if (!xml.isValidName(qname)) utils.InvalidCharacterError(); - if (/[A-Z]/.test(qname) && this.isHTML) qname = utils.toASCIILowerCase(qname); - var a = this._attrsByQName[qname]; - if (a === undefined) { - if (force === undefined || force === true) { - this._setAttribute(qname, ''); - return true; - } - return false; - } else { - if (force === undefined || force === false) { - this.removeAttribute(qname); - return false; - } - return true; - } - }, - }, - - // Set the attribute without error checking. The parser uses this. - _setAttribute: { - value: function _setAttribute(qname, value) { - // XXX: the spec says that this next search should be done - // on the local name, but I think that is an error. - // email pending on www-dom about it. - var attr = this._attrsByQName[qname]; - var isnew; - if (!attr) { - attr = this._newattr(qname); - isnew = true; - } else { - if (Array.isArray(attr)) attr = attr[0]; - } - - // Now set the attribute value on the new or existing Attr object. - // The Attr.value setter method handles mutation events, etc. - attr.value = value; - if (this._attributes) this._attributes[qname] = attr; - if (isnew && this._newattrhook) this._newattrhook(qname, value); - }, - }, - - // Check for errors, and then set the attribute - setAttribute: { - value: function setAttribute(qname, value) { - qname = String(qname); - if (!xml.isValidName(qname)) utils.InvalidCharacterError(); - if (/[A-Z]/.test(qname) && this.isHTML) qname = utils.toASCIILowerCase(qname); - this._setAttribute(qname, String(value)); - }, - }, - - // The version with no error checking used by the parser - _setAttributeNS: { - value: function _setAttributeNS(ns, qname, value) { - var pos = qname.indexOf(':'), - prefix, - lname; - if (pos < 0) { - prefix = null; - lname = qname; - } else { - prefix = qname.substring(0, pos); - lname = qname.substring(pos + 1); - } - - if (ns === '' || ns === undefined) ns = null; - var key = (ns === null ? '' : ns) + '|' + lname; - - var attr = this._attrsByLName[key]; - var isnew; - if (!attr) { - attr = new Attr(this, lname, prefix, ns); - isnew = true; - this._attrsByLName[key] = attr; - if (this._attributes) { - this._attributes[this._attrKeys.length] = attr; - } - this._attrKeys.push(key); - - // We also have to make the attr searchable by qname. - // But we have to be careful because there may already - // be an attr with this qname. - this._addQName(attr); - } else if (false /* changed in DOM 4 */) { - // Calling setAttributeNS() can change the prefix of an - // existing attribute in DOM 2/3. - if (attr.prefix !== prefix) { - // Unbind the old qname - this._removeQName(attr); - // Update the prefix - attr.prefix = prefix; - // Bind the new qname - this._addQName(attr); - } - } - attr.value = value; // Automatically sends mutation event - if (isnew && this._newattrhook) this._newattrhook(qname, value); - }, - }, - - // Do error checking then call _setAttributeNS - setAttributeNS: { - value: function setAttributeNS(ns, qname, value) { - // Convert parameter types according to WebIDL - ns = ns === null || ns === undefined || ns === '' ? null : String(ns); - qname = String(qname); - if (!xml.isValidQName(qname)) utils.InvalidCharacterError(); - - var pos = qname.indexOf(':'); - var prefix = pos < 0 ? null : qname.substring(0, pos); - - if ( - (prefix !== null && ns === null) || - (prefix === 'xml' && ns !== NAMESPACE.XML) || - ((qname === 'xmlns' || prefix === 'xmlns') && ns !== NAMESPACE.XMLNS) || - (ns === NAMESPACE.XMLNS && !(qname === 'xmlns' || prefix === 'xmlns')) - ) - utils.NamespaceError(); - - this._setAttributeNS(ns, qname, String(value)); - }, - }, - - setAttributeNode: { - value: function setAttributeNode(attr) { - if (attr.ownerElement !== null && attr.ownerElement !== this) { - throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR); - } - var result = null; - var oldAttrs = this._attrsByQName[attr.name]; - if (oldAttrs) { - if (!Array.isArray(oldAttrs)) { - oldAttrs = [oldAttrs]; - } - if ( - oldAttrs.some(function (a) { - return a === attr; - }) - ) { - return attr; - } else if (attr.ownerElement !== null) { - throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR); - } - oldAttrs.forEach(function (a) { - this.removeAttributeNode(a); - }, this); - result = oldAttrs[0]; - } - this.setAttributeNodeNS(attr); - return result; - }, - }, - - setAttributeNodeNS: { - value: function setAttributeNodeNS(attr) { - if (attr.ownerElement !== null) { - throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR); - } - var ns = attr.namespaceURI; - var key = (ns === null ? '' : ns) + '|' + attr.localName; - var oldAttr = this._attrsByLName[key]; - if (oldAttr) { - this.removeAttributeNode(oldAttr); - } - attr._setOwnerElement(this); - this._attrsByLName[key] = attr; - if (this._attributes) { - this._attributes[this._attrKeys.length] = attr; - } - this._attrKeys.push(key); - this._addQName(attr); - if (this._newattrhook) this._newattrhook(attr.name, attr.value); - return oldAttr || null; - }, - }, - - removeAttribute: { - value: function removeAttribute(qname) { - qname = String(qname); - if (/[A-Z]/.test(qname) && this.isHTML) qname = utils.toASCIILowerCase(qname); - - var attr = this._attrsByQName[qname]; - if (!attr) return; - - // If there is more than one match for this qname - // so don't delete the qname mapping, just remove the first - // element from it. - if (Array.isArray(attr)) { - if (attr.length > 2) { - attr = attr.shift(); // remove it from the array - } else { - this._attrsByQName[qname] = attr[1]; - attr = attr[0]; - } - } else { - // only a single match, so remove the qname mapping - this._attrsByQName[qname] = undefined; - } - - var ns = attr.namespaceURI; - // Now attr is the removed attribute. Figure out its - // ns+lname key and remove it from the other mapping as well. - var key = (ns === null ? '' : ns) + '|' + attr.localName; - this._attrsByLName[key] = undefined; - - var i = this._attrKeys.indexOf(key); - if (this._attributes) { - Array.prototype.splice.call(this._attributes, i, 1); - this._attributes[qname] = undefined; - } - this._attrKeys.splice(i, 1); - - // Onchange handler for the attribute - var onchange = attr.onchange; - attr._setOwnerElement(null); - if (onchange) { - onchange.call(attr, this, attr.localName, attr.value, null); - } - // Mutation event - if (this.rooted) this.ownerDocument.mutateRemoveAttr(attr); - }, - }, - - removeAttributeNS: { - value: function removeAttributeNS(ns, lname) { - ns = ns === undefined || ns === null ? '' : String(ns); - lname = String(lname); - var key = ns + '|' + lname; - var attr = this._attrsByLName[key]; - if (!attr) return; - - this._attrsByLName[key] = undefined; - - var i = this._attrKeys.indexOf(key); - if (this._attributes) { - Array.prototype.splice.call(this._attributes, i, 1); - } - this._attrKeys.splice(i, 1); - - // Now find the same Attr object in the qname mapping and remove it - // But be careful because there may be more than one match. - this._removeQName(attr); - - // Onchange handler for the attribute - var onchange = attr.onchange; - attr._setOwnerElement(null); - if (onchange) { - onchange.call(attr, this, attr.localName, attr.value, null); - } - // Mutation event - if (this.rooted) this.ownerDocument.mutateRemoveAttr(attr); - }, - }, - - removeAttributeNode: { - value: function removeAttributeNode(attr) { - var ns = attr.namespaceURI; - var key = (ns === null ? '' : ns) + '|' + attr.localName; - if (this._attrsByLName[key] !== attr) { - utils.NotFoundError(); - } - this.removeAttributeNS(ns, attr.localName); - return attr; - }, - }, - - getAttributeNames: { - value: function getAttributeNames() { - var elt = this; - return this._attrKeys.map(function (key) { - return elt._attrsByLName[key].name; - }); - }, - }, - - // This 'raw' version of getAttribute is used by the getter functions - // of reflected attributes. It skips some error checking and - // namespace steps - _getattr: { - value: function _getattr(qname) { - // Assume that qname is already lowercased, so don't do it here. - // Also don't check whether attr is an array: a qname with no - // prefix will never have two matching Attr objects (because - // setAttributeNS doesn't allow a non-null namespace with a - // null prefix. - var attr = this._attrsByQName[qname]; - return attr ? attr.value : null; - }, - }, - - // The raw version of setAttribute for reflected idl attributes. - _setattr: { - value: function _setattr(qname, value) { - var attr = this._attrsByQName[qname]; - var isnew; - if (!attr) { - attr = this._newattr(qname); - isnew = true; - } - attr.value = String(value); - if (this._attributes) this._attributes[qname] = attr; - if (isnew && this._newattrhook) this._newattrhook(qname, value); - }, - }, - - // Create a new Attr object, insert it, and return it. - // Used by setAttribute() and by set() - _newattr: { - value: function _newattr(qname) { - var attr = new Attr(this, qname, null, null); - var key = '|' + qname; - this._attrsByQName[qname] = attr; - this._attrsByLName[key] = attr; - if (this._attributes) { - this._attributes[this._attrKeys.length] = attr; - } - this._attrKeys.push(key); - return attr; - }, - }, - - // Add a qname->Attr mapping to the _attrsByQName object, taking into - // account that there may be more than one attr object with the - // same qname - _addQName: { - value: function (attr) { - var qname = attr.name; - var existing = this._attrsByQName[qname]; - if (!existing) { - this._attrsByQName[qname] = attr; - } else if (Array.isArray(existing)) { - existing.push(attr); - } else { - this._attrsByQName[qname] = [existing, attr]; - } - if (this._attributes) this._attributes[qname] = attr; - }, - }, - - // Remove a qname->Attr mapping to the _attrsByQName object, taking into - // account that there may be more than one attr object with the - // same qname - _removeQName: { - value: function (attr) { - var qname = attr.name; - var target = this._attrsByQName[qname]; - - if (Array.isArray(target)) { - var idx = target.indexOf(attr); - utils.assert(idx !== -1); // It must be here somewhere - if (target.length === 2) { - this._attrsByQName[qname] = target[1 - idx]; - if (this._attributes) { - this._attributes[qname] = this._attrsByQName[qname]; - } - } else { - target.splice(idx, 1); - if (this._attributes && this._attributes[qname] === attr) { - this._attributes[qname] = target[0]; - } - } - } else { - utils.assert(target === attr); // If only one, it must match - this._attrsByQName[qname] = undefined; - if (this._attributes) { - this._attributes[qname] = undefined; - } - } - }, - }, - - // Return the number of attributes - _numattrs: { - get: function () { - return this._attrKeys.length; - }, - }, - // Return the nth Attr object - _attr: { - value: function (n) { - return this._attrsByLName[this._attrKeys[n]]; - }, - }, - - // Define getters and setters for an 'id' property that reflects - // the content attribute 'id'. - id: attributes.property({ name: 'id' }), - - // Define getters and setters for a 'className' property that reflects - // the content attribute 'class'. - className: attributes.property({ name: 'class' }), - - classList: { - get: function () { - var self = this; - if (this._classList) { - return this._classList; - } - var dtlist = new DOMTokenList( - function () { - return self.className || ''; - }, - function (v) { - self.className = v; - } - ); - this._classList = dtlist; - return dtlist; - }, - set: function (v) { - this.className = v; - }, - }, - - matches: { - value: function (selector) { - return select.matches(this, selector); - }, - }, - - closest: { - value: function (selector) { - var el = this; - do { - if (el.matches && el.matches(selector)) { - return el; - } - el = el.parentElement || el.parentNode; - } while (el !== null && el.nodeType === Node.ELEMENT_NODE); - return null; - }, - }, - - querySelector: { - value: function (selector) { - return select(selector, this)[0]; - }, - }, - - querySelectorAll: { - value: function (selector) { - var nodes = select(selector, this); - return nodes.item ? nodes : new NodeList(nodes); - }, - }, -}); - -Object.defineProperties(Element.prototype, ChildNode); -Object.defineProperties(Element.prototype, NonDocumentTypeChildNode); - -// Register special handling for the id attribute -attributes.registerChangeHandler(Element, 'id', function (element, lname, oldval, newval) { - if (element.rooted) { - if (oldval) { - element.ownerDocument.delId(oldval, element); - } - if (newval) { - element.ownerDocument.addId(newval, element); - } - } -}); -attributes.registerChangeHandler(Element, 'class', function (element, lname, oldval, newval) { - if (element._classList) { - element._classList._update(); - } -}); - -// The Attr class represents a single attribute. The values in -// _attrsByQName and _attrsByLName are instances of this class. -function Attr(elt, lname, prefix, namespace, value) { - // localName and namespace are constant for any attr object. - // But value may change. And so can prefix, and so, therefore can name. - this.localName = lname; - this.prefix = prefix === null || prefix === '' ? null : '' + prefix; - this.namespaceURI = namespace === null || namespace === '' ? null : '' + namespace; - this.data = value; - // Set ownerElement last to ensure it is hooked up to onchange handler - this._setOwnerElement(elt); -} - -// In DOM 3 Attr was supposed to extend Node; in DOM 4 that was abandoned. -Attr.prototype = Object.create(Object.prototype, { - ownerElement: { - get: function () { - return this._ownerElement; - }, - }, - _setOwnerElement: { - value: function _setOwnerElement(elt) { - this._ownerElement = elt; - if (this.prefix === null && this.namespaceURI === null && elt) { - this.onchange = elt._attributeChangeHandlers[this.localName]; - } else { - this.onchange = null; - } - }, - }, - - name: { - get: function () { - return this.prefix ? this.prefix + ':' + this.localName : this.localName; - }, - }, - - specified: { - get: function () { - // Deprecated - return true; - }, - }, - - value: { - get: function () { - return this.data; - }, - set: function (value) { - var oldval = this.data; - value = value === undefined ? '' : value + ''; - if (value === oldval) return; - - this.data = value; - - // Run the onchange hook for the attribute - // if there is one. - if (this.ownerElement) { - if (this.onchange) this.onchange(this.ownerElement, this.localName, oldval, value); - - // Generate a mutation event if the element is rooted - if (this.ownerElement.rooted) this.ownerElement.ownerDocument.mutateAttr(this, oldval); - } - }, - }, - - cloneNode: { - value: function cloneNode(deep) { - // Both this method and Document#createAttribute*() create unowned Attrs - return new Attr(null, this.localName, this.prefix, this.namespaceURI, this.data); - }, - }, - - // Legacy aliases (see gh#70 and https://dom.spec.whatwg.org/#interface-attr) - nodeType: { - get: function () { - return Node.ATTRIBUTE_NODE; - }, - }, - nodeName: { - get: function () { - return this.name; - }, - }, - nodeValue: { - get: function () { - return this.value; - }, - set: function (v) { - this.value = v; - }, - }, - textContent: { - get: function () { - return this.value; - }, - set: function (v) { - if (v === null || v === undefined) { - v = ''; - } - this.value = v; - }, - }, -}); -// Sneakily export this class for use by Document.createAttribute() -Element._Attr = Attr; - -// The attributes property of an Element will be an instance of this class. -// This class is really just a dummy, though. It only defines a length -// property and an item() method. The AttrArrayProxy that -// defines the public API just uses the Element object itself. -function AttributesArray(elt) { - NamedNodeMap.call(this, elt); - for (var name in elt._attrsByQName) { - this[name] = elt._attrsByQName[name]; - } - for (var i = 0; i < elt._attrKeys.length; i++) { - this[i] = elt._attrsByLName[elt._attrKeys[i]]; - } -} -AttributesArray.prototype = Object.create(NamedNodeMap.prototype, { - length: { - get: function () { - return this.element._attrKeys.length; - }, - set: function () { - /* ignore */ - }, - }, - item: { - value: function (n) { - /* jshint bitwise: false */ - n = n >>> 0; - if (n >= this.length) { - return null; - } - return this.element._attrsByLName[this.element._attrKeys[n]]; - /* jshint bitwise: true */ - }, - }, -}); - -// We can't make direct array access work (without Proxies, node >=6) -// but we can make `Array.from(node.attributes)` and for-of loops work. -if (global.Symbol && global.Symbol.iterator) { - AttributesArray.prototype[global.Symbol.iterator] = function () { - var i = 0, - n = this.length, - self = this; - return { - next: function () { - if (i < n) return { value: self.item(i++) }; - return { done: true }; - }, - }; - }; -} - -// The children property of an Element will be an instance of this class. -// It defines length, item() and namedItem() and will be wrapped by an -// HTMLCollection when exposed through the DOM. -function ChildrenCollection(e) { - this.element = e; - this.updateCache(); -} - -ChildrenCollection.prototype = Object.create(Object.prototype, { - length: { - get: function () { - this.updateCache(); - return this.childrenByNumber.length; - }, - }, - item: { - value: function item(n) { - this.updateCache(); - return this.childrenByNumber[n] || null; - }, - }, - - namedItem: { - value: function namedItem(name) { - this.updateCache(); - return this.childrenByName[name] || null; - }, - }, - - // This attribute returns the entire name->element map. - // It is not part of the HTMLCollection API, but we need it in - // src/HTMLCollectionProxy - namedItems: { - get: function () { - this.updateCache(); - return this.childrenByName; - }, - }, - - updateCache: { - value: function updateCache() { - var namedElts = /^(a|applet|area|embed|form|frame|frameset|iframe|img|object)$/; - if (this.lastModTime !== this.element.lastModTime) { - this.lastModTime = this.element.lastModTime; - - var n = (this.childrenByNumber && this.childrenByNumber.length) || 0; - for (var i = 0; i < n; i++) { - this[i] = undefined; - } - - this.childrenByNumber = []; - this.childrenByName = Object.create(null); - - for (var c = this.element.firstChild; c !== null; c = c.nextSibling) { - if (c.nodeType === Node.ELEMENT_NODE) { - this[this.childrenByNumber.length] = c; - this.childrenByNumber.push(c); - - // XXX Are there any requirements about the namespace - // of the id property? - var id = c.getAttribute('id'); - - // If there is an id that is not already in use... - if (id && !this.childrenByName[id]) this.childrenByName[id] = c; - - // For certain HTML elements we check the name attribute - var name = c.getAttribute('name'); - if ( - name && - this.element.namespaceURI === NAMESPACE.HTML && - namedElts.test(this.element.localName) && - !this.childrenByName[name] - ) - this.childrenByName[id] = c; - } - } - } - }, - }, -}); - -// These functions return predicates for filtering elements. -// They're used by the Document and Element classes for methods like -// getElementsByTagName and getElementsByClassName - -function localNameElementFilter(lname) { - return function (e) { - return e.localName === lname; - }; -} - -function htmlLocalNameElementFilter(lname) { - var lclname = utils.toASCIILowerCase(lname); - if (lclname === lname) return localNameElementFilter(lname); - - return function (e) { - return e.isHTML ? e.localName === lclname : e.localName === lname; - }; -} - -function namespaceElementFilter(ns) { - return function (e) { - return e.namespaceURI === ns; - }; -} - -function namespaceLocalNameElementFilter(ns, lname) { - return function (e) { - return e.namespaceURI === ns && e.localName === lname; - }; -} - -function classNamesElementFilter(names) { - return function (e) { - return names.every(function (n) { - return e.classList.contains(n); - }); - }; -} - -function elementNameFilter(name) { - return function (e) { - // All the *HTML elements* in the document with the given name attribute - if (e.namespaceURI !== NAMESPACE.HTML) { - return false; - } - return e.getAttribute('name') === name; - }; -} diff --git a/packages/qwik-dom/lib/Event.js b/packages/qwik-dom/lib/Event.js deleted file mode 100644 index 89f7431d2ea..00000000000 --- a/packages/qwik-dom/lib/Event.js +++ /dev/null @@ -1,73 +0,0 @@ -'use strict'; -module.exports = Event; - -Event.CAPTURING_PHASE = 1; -Event.AT_TARGET = 2; -Event.BUBBLING_PHASE = 3; - -function Event(type, dictionary) { - // Initialize basic event properties - this.type = ''; - this.target = null; - this.currentTarget = null; - this.eventPhase = Event.AT_TARGET; - this.bubbles = false; - this.cancelable = false; - this.isTrusted = false; - this.defaultPrevented = false; - this.timeStamp = Date.now(); - - // Initialize internal flags - // XXX: Would it be better to inherit these defaults from the prototype? - this._propagationStopped = false; - this._immediatePropagationStopped = false; - this._initialized = true; - this._dispatching = false; - - // Now initialize based on the constructor arguments (if any) - if (type) this.type = type; - if (dictionary) { - for (var p in dictionary) { - this[p] = dictionary[p]; - } - } -} - -Event.prototype = Object.create(Object.prototype, { - constructor: { value: Event }, - stopPropagation: { - value: function stopPropagation() { - this._propagationStopped = true; - }, - }, - - stopImmediatePropagation: { - value: function stopImmediatePropagation() { - this._propagationStopped = true; - this._immediatePropagationStopped = true; - }, - }, - - preventDefault: { - value: function preventDefault() { - if (this.cancelable) this.defaultPrevented = true; - }, - }, - - initEvent: { - value: function initEvent(type, bubbles, cancelable) { - this._initialized = true; - if (this._dispatching) return; - - this._propagationStopped = false; - this._immediatePropagationStopped = false; - this.defaultPrevented = false; - this.isTrusted = false; - - this.target = null; - this.type = type; - this.bubbles = bubbles; - this.cancelable = cancelable; - }, - }, -}); diff --git a/packages/qwik-dom/lib/EventTarget.js b/packages/qwik-dom/lib/EventTarget.js deleted file mode 100644 index 6f9386aa455..00000000000 --- a/packages/qwik-dom/lib/EventTarget.js +++ /dev/null @@ -1,297 +0,0 @@ -'use strict'; -var Event = require('./Event'); -var MouseEvent = require('./MouseEvent'); -var utils = require('./utils'); - -module.exports = EventTarget; - -function EventTarget() {} - -EventTarget.prototype = { - // XXX - // See WebIDL Ā§4.8 for details on object event handlers - // and how they should behave. We actually have to accept - // any object to addEventListener... Can't type check it. - // on registration. - - // XXX: - // Capturing event listeners are sort of rare. I think I can optimize - // them so that dispatchEvent can skip the capturing phase (or much of - // it). Each time a capturing listener is added, increment a flag on - // the target node and each of its ancestors. Decrement when removed. - // And update the counter when nodes are added and removed from the - // tree as well. Then, in dispatch event, the capturing phase can - // abort if it sees any node with a zero count. - addEventListener: function addEventListener(type, listener, capture) { - if (!listener) return; - if (capture === undefined) capture = false; - if (!this._listeners) this._listeners = Object.create(null); - if (!this._listeners[type]) this._listeners[type] = []; - var list = this._listeners[type]; - - // If this listener has already been registered, just return - for (var i = 0, n = list.length; i < n; i++) { - var l = list[i]; - if (l.listener === listener && l.capture === capture) return; - } - - // Add an object to the list of listeners - var obj = { listener: listener, capture: capture }; - if (typeof listener === 'function') obj.f = listener; - list.push(obj); - }, - - removeEventListener: function removeEventListener(type, listener, capture) { - if (capture === undefined) capture = false; - if (this._listeners) { - var list = this._listeners[type]; - if (list) { - // Find the listener in the list and remove it - for (var i = 0, n = list.length; i < n; i++) { - var l = list[i]; - if (l.listener === listener && l.capture === capture) { - if (list.length === 1) { - this._listeners[type] = undefined; - } else { - list.splice(i, 1); - } - return; - } - } - } - } - }, - - // This is the public API for dispatching untrusted public events. - // See _dispatchEvent for the implementation - dispatchEvent: function dispatchEvent(event) { - // Dispatch an untrusted event - return this._dispatchEvent(event, false); - }, - - // - // See DOMCore Ā§4.4 - // XXX: I'll probably need another version of this method for - // internal use, one that does not set isTrusted to false. - // XXX: see Document._dispatchEvent: perhaps that and this could - // call a common internal function with different settings of - // a trusted boolean argument - // - // XXX: - // The spec has changed in how to deal with handlers registered - // on idl or content attributes rather than with addEventListener. - // Used to say that they always ran first. That's how webkit does it - // Spec now says that they run in a position determined by - // when they were first set. FF does it that way. See: - // http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#event-handlers - // - _dispatchEvent: function _dispatchEvent(event, trusted) { - if (typeof trusted !== 'boolean') trusted = false; - function invoke(target, event) { - var type = event.type, - phase = event.eventPhase; - event.currentTarget = target; - - // If there was an individual handler defined, invoke it first - // XXX: see comment above: this shouldn't always be first. - if (phase !== Event.CAPTURING_PHASE && target._handlers && target._handlers[type]) { - var handler = target._handlers[type]; - var rv; - if (typeof handler === 'function') { - rv = handler.call(event.currentTarget, event); - } else { - var f = handler.handleEvent; - if (typeof f !== 'function') - throw new TypeError( - 'handleEvent property of ' + 'event handler object is' + 'not a function.' - ); - rv = f.call(handler, event); - } - - switch (event.type) { - case 'mouseover': - if (rv === true) - // Historical baggage - event.preventDefault(); - break; - case 'beforeunload': - // XXX: eventually we need a special case here - /* falls through */ - default: - if (rv === false) event.preventDefault(); - break; - } - } - - // Now invoke list list of listeners for this target and type - var list = target._listeners && target._listeners[type]; - if (!list) return; - list = list.slice(); - for (var i = 0, n = list.length; i < n; i++) { - if (event._immediatePropagationStopped) return; - var l = list[i]; - if ( - (phase === Event.CAPTURING_PHASE && !l.capture) || - (phase === Event.BUBBLING_PHASE && l.capture) - ) - continue; - if (l.f) { - l.f.call(event.currentTarget, event); - } else { - var fn = l.listener.handleEvent; - if (typeof fn !== 'function') - throw new TypeError('handleEvent property of event listener object is not a function.'); - fn.call(l.listener, event); - } - } - } - - if (!event._initialized || event._dispatching) utils.InvalidStateError(); - event.isTrusted = trusted; - - // Begin dispatching the event now - event._dispatching = true; - event.target = this; - - // Build the list of targets for the capturing and bubbling phases - // XXX: we'll eventually have to add Window to this list. - var ancestors = []; - for (var n = this.parentNode; n; n = n.parentNode) ancestors.push(n); - - // Capturing phase - event.eventPhase = Event.CAPTURING_PHASE; - for (var i = ancestors.length - 1; i >= 0; i--) { - invoke(ancestors[i], event); - if (event._propagationStopped) break; - } - - // At target phase - if (!event._propagationStopped) { - event.eventPhase = Event.AT_TARGET; - invoke(this, event); - } - - // Bubbling phase - if (event.bubbles && !event._propagationStopped) { - event.eventPhase = Event.BUBBLING_PHASE; - for (var ii = 0, nn = ancestors.length; ii < nn; ii++) { - invoke(ancestors[ii], event); - if (event._propagationStopped) break; - } - } - - event._dispatching = false; - event.eventPhase = Event.AT_TARGET; - event.currentTarget = null; - - // Deal with mouse events and figure out when - // a click has happened - if (trusted && !event.defaultPrevented && event instanceof MouseEvent) { - switch (event.type) { - case 'mousedown': - this._armed = { - x: event.clientX, - y: event.clientY, - t: event.timeStamp, - }; - break; - case 'mouseout': - case 'mouseover': - this._armed = null; - break; - case 'mouseup': - if (this._isClick(event)) this._doClick(event); - this._armed = null; - break; - } - } - - return !event.defaultPrevented; - }, - - // Determine whether a click occurred - // XXX We don't support double clicks for now - _isClick: function (event) { - return ( - this._armed !== null && - event.type === 'mouseup' && - event.isTrusted && - event.button === 0 && - event.timeStamp - this._armed.t < 1000 && - Math.abs(event.clientX - this._armed.x) < 10 && - Math.abs(event.clientY - this._armed.Y) < 10 - ); - }, - - // Clicks are handled like this: - // http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html#interactive-content-0 - // - // Note that this method is similar to the HTMLElement.click() method - // The event argument must be the trusted mouseup event - _doClick: function (event) { - if (this._click_in_progress) return; - this._click_in_progress = true; - - // Find the nearest enclosing element that is activatable - // An element is activatable if it has a - // _post_click_activation_steps hook - var activated = this; - while (activated && !activated._post_click_activation_steps) activated = activated.parentNode; - - if (activated && activated._pre_click_activation_steps) { - activated._pre_click_activation_steps(); - } - - var click = this.ownerDocument.createEvent('MouseEvent'); - click.initMouseEvent( - 'click', - true, - true, - this.ownerDocument.defaultView, - 1, - event.screenX, - event.screenY, - event.clientX, - event.clientY, - event.ctrlKey, - event.altKey, - event.shiftKey, - event.metaKey, - event.button, - null - ); - - var result = this._dispatchEvent(click, true); - - if (activated) { - if (result) { - // This is where hyperlinks get followed, for example. - if (activated._post_click_activation_steps) activated._post_click_activation_steps(click); - } else { - if (activated._cancelled_activation_steps) activated._cancelled_activation_steps(); - } - } - }, - - // - // An event handler is like an event listener, but it registered - // by setting an IDL or content attribute like onload or onclick. - // There can only be one of these at a time for any event type. - // This is an internal method for the attribute accessors and - // content attribute handlers that need to register events handlers. - // The type argument is the same as in addEventListener(). - // The handler argument is the same as listeners in addEventListener: - // it can be a function or an object. Pass null to remove any existing - // handler. Handlers are always invoked before any listeners of - // the same type. They are not invoked during the capturing phase - // of event dispatch. - // - _setEventHandler: function _setEventHandler(type, handler) { - if (!this._handlers) this._handlers = Object.create(null); - this._handlers[type] = handler; - }, - - _getEventHandler: function _getEventHandler(type) { - return (this._handlers && this._handlers[type]) || null; - }, -}; diff --git a/packages/qwik-dom/lib/FilteredElementList.js b/packages/qwik-dom/lib/FilteredElementList.js deleted file mode 100644 index c0152c80a55..00000000000 --- a/packages/qwik-dom/lib/FilteredElementList.js +++ /dev/null @@ -1,102 +0,0 @@ -'use strict'; -module.exports = FilteredElementList; - -var Node = require('./Node'); - -// -// This file defines node list implementation that lazily traverses -// the document tree (or a subtree rooted at any element) and includes -// only those elements for which a specified filter function returns true. -// It is used to implement the -// {Document,Element}.getElementsBy{TagName,ClassName}{,NS} methods. -// -// XXX this should inherit from NodeList - -function FilteredElementList(root, filter) { - this.root = root; - this.filter = filter; - this.lastModTime = root.lastModTime; - this.done = false; - this.cache = []; - this.traverse(); -} - -FilteredElementList.prototype = Object.create(Object.prototype, { - length: { - get: function () { - this.checkcache(); - if (!this.done) this.traverse(); - return this.cache.length; - }, - }, - - item: { - value: function (n) { - this.checkcache(); - if (!this.done && n >= this.cache.length) { - // This can lead to O(N^2) behavior if we stop when we get to n - // and the caller is iterating through the items in order; so - // be sure to do the full traverse here. - this.traverse(/*n*/); - } - return this.cache[n]; - }, - }, - - checkcache: { - value: function () { - if (this.lastModTime !== this.root.lastModTime) { - // subtree has changed, so invalidate cache - for (var i = this.cache.length - 1; i >= 0; i--) { - this[i] = undefined; - } - this.cache.length = 0; - this.done = false; - this.lastModTime = this.root.lastModTime; - } - }, - }, - - // If n is specified, then traverse the tree until we've found the nth - // item (or until we've found all items). If n is not specified, - // traverse until we've found all items. - traverse: { - value: function (n) { - // increment n so we can compare to length, and so it is never falsy - if (n !== undefined) n++; - - var elt; - while ((elt = this.next()) !== null) { - this[this.cache.length] = elt; //XXX Use proxy instead - this.cache.push(elt); - if (n && this.cache.length === n) return; - } - - // no next element, so we've found everything - this.done = true; - }, - }, - - // Return the next element under root that matches filter - next: { - value: function () { - var start = - this.cache.length === 0 - ? this.root // Start at the root or at - : this.cache[this.cache.length - 1]; // the last element we found - - var elt; - if (start.nodeType === Node.DOCUMENT_NODE) elt = start.documentElement; - else elt = start.nextElement(this.root); - - while (elt) { - if (this.filter(elt)) { - return elt; - } - - elt = elt.nextElement(this.root); - } - return null; - }, - }, -}); diff --git a/packages/qwik-dom/lib/HTMLParser.js b/packages/qwik-dom/lib/HTMLParser.js deleted file mode 100644 index 64871f4cef9..00000000000 --- a/packages/qwik-dom/lib/HTMLParser.js +++ /dev/null @@ -1,9183 +0,0 @@ -'use strict'; -module.exports = HTMLParser; - -var Document = require('./Document'); -var DocumentType = require('./DocumentType'); -var Node = require('./Node'); -var NAMESPACE = require('./utils').NAMESPACE; -var html = require('./htmlelts'); -var impl = html.elements; - -var pushAll = Function.prototype.apply.bind(Array.prototype.push); - -/* - * This file contains an implementation of the HTML parsing algorithm. - * The algorithm and the implementation are complex because HTML - * explicitly defines how the parser should behave for all possible - * valid and invalid inputs. - * - * Usage: - * - * The file defines a single HTMLParser() function, which dom.js exposes - * publicly as document.implementation.mozHTMLParser(). This is a - * factory function, not a constructor. - * - * When you call document.implementation.mozHTMLParser(), it returns - * an object that has parse() and document() methods. To parse HTML text, - * pass the text (in one or more chunks) to the parse() method. When - * you've passed all the text (on the last chunk, or afterward) pass - * true as the second argument to parse() to tell the parser that there - * is no more coming. Call document() to get the document object that - * the parser is parsing into. You can call this at any time, before - * or after calling parse(). - * - * The first argument to mozHTMLParser is the absolute URL of the document. - * - * The second argument is optional and is for internal use only. Pass an - * element as the fragmentContext to do innerHTML parsing for the - * element. To do innerHTML parsing on a document, pass null. Otherwise, - * omit the 2nd argument. See HTMLElement.innerHTML for an example. Note - * that if you pass a context element, the end() method will return an - * unwrapped document instead of a wrapped one. - * - * Implementation details: - * - * This is a long file of almost 7000 lines. It is structured as one - * big function nested within another big function. The outer - * function defines a bunch of constant data, utility functions - * that use that data, and a couple of classes used by the parser. - * The outer function also defines and returns the - * inner function. This inner function is the HTMLParser factory - * function that implements the parser and holds all the parser state - * as local variables. The HTMLParser function is quite big because - * it defines many nested functions that use those local variables. - * - * There are three tightly coupled parser stages: a scanner, a - * tokenizer and a tree builder. In a (possibly misguided) attempt at - * efficiency, the stages are not implemented as separate classes: - * everything shares state and is (mostly) implemented in imperative - * (rather than OO) style. - * - * The stages of the parser work like this: When the client code calls - * the parser's parse() method, the specified string is passed to - * scanChars(). The scanner loops through that string and passes characters - * (sometimes one at a time, sometimes in chunks) to the tokenizer stage. - * The tokenizer groups the characters into tokens: tags, endtags, runs - * of text, comments, doctype declarations, and the end-of-file (EOF) - * token. These tokens are then passed to the tree building stage via - * the insertToken() function. The tree building stage builds up the - * document tree. - * - * The tokenizer stage is a finite state machine. Each state is - * implemented as a function with a name that ends in "_state". The - * initial state is data_state(). The current tokenizer state is stored - * in the variable 'tokenizer'. Most state functions expect a single - * integer argument which represents a single UTF-16 codepoint. Some - * states want more characters and set a lookahead property on - * themselves. The scanChars() function in the scanner checks for this - * lookahead property. If it doesn't exist, then scanChars() just passes - * the next input character to the current tokenizer state function. - * Otherwise, scanChars() looks ahead (a given # of characters, or for a - * matching string, or for a matching regexp) and passes a string of - * characters to the current tokenizer state function. - * - * As a shortcut, certain states of the tokenizer use regular expressions - * to look ahead in the scanner's input buffer for runs of text, simple - * tags and attributes. For well-formed input, these shortcuts skip a - * lot of state transitions and speed things up a bit. - * - * When a tokenizer state function has consumed a complete token, it - * emits that token, by calling insertToken(), or by calling a utility - * function that itself calls insertToken(). These tokens are passed to - * the tree building stage, which is also a state machine. Like the - * tokenizer, the tree building states are implemented as functions, and - * these functions have names that end with _mode (because the HTML spec - * refers to them as insertion modes). The current insertion mode is held - * by the 'parser' variable. Each insertion mode function takes up to 4 - * arguments. The first is a token type, represented by the constants - * TAG, ENDTAG, TEXT, COMMENT, DOCTYPE and EOF. The second argument is - * the value of the token: the text or comment data, or tagname or - * doctype. For tags, the 3rd argument is an array of attributes. For - * DOCTYPES it is the optional public id. For tags, the 4th argument is - * true if the tag is self-closing. For doctypes, the 4th argument is the - * optional system id. - * - * Search for "***" to find the major sub-divisions in the code. - */ - -/*** - * Data prolog. Lots of constants declared here, including some - * very large objects. They're used throughout the code that follows - */ -// Token types for the tree builder. -var EOF = -1; -var TEXT = 1; -var TAG = 2; -var ENDTAG = 3; -var COMMENT = 4; -var DOCTYPE = 5; - -// A re-usable empty array -var NOATTRS = []; - -// These DTD public ids put the browser in quirks mode -var quirkyPublicIds = - /^HTML$|^-\/\/W3O\/\/DTD W3 HTML Strict 3\.0\/\/EN\/\/$|^-\/W3C\/DTD HTML 4\.0 Transitional\/EN$|^\+\/\/Silmaril\/\/dtd html Pro v0r11 19970101\/\/|^-\/\/AdvaSoft Ltd\/\/DTD HTML 3\.0 asWedit \+ extensions\/\/|^-\/\/AS\/\/DTD HTML 3\.0 asWedit \+ extensions\/\/|^-\/\/IETF\/\/DTD HTML 2\.0 Level 1\/\/|^-\/\/IETF\/\/DTD HTML 2\.0 Level 2\/\/|^-\/\/IETF\/\/DTD HTML 2\.0 Strict Level 1\/\/|^-\/\/IETF\/\/DTD HTML 2\.0 Strict Level 2\/\/|^-\/\/IETF\/\/DTD HTML 2\.0 Strict\/\/|^-\/\/IETF\/\/DTD HTML 2\.0\/\/|^-\/\/IETF\/\/DTD HTML 2\.1E\/\/|^-\/\/IETF\/\/DTD HTML 3\.0\/\/|^-\/\/IETF\/\/DTD HTML 3\.2 Final\/\/|^-\/\/IETF\/\/DTD HTML 3\.2\/\/|^-\/\/IETF\/\/DTD HTML 3\/\/|^-\/\/IETF\/\/DTD HTML Level 0\/\/|^-\/\/IETF\/\/DTD HTML Level 1\/\/|^-\/\/IETF\/\/DTD HTML Level 2\/\/|^-\/\/IETF\/\/DTD HTML Level 3\/\/|^-\/\/IETF\/\/DTD HTML Strict Level 0\/\/|^-\/\/IETF\/\/DTD HTML Strict Level 1\/\/|^-\/\/IETF\/\/DTD HTML Strict Level 2\/\/|^-\/\/IETF\/\/DTD HTML Strict Level 3\/\/|^-\/\/IETF\/\/DTD HTML Strict\/\/|^-\/\/IETF\/\/DTD HTML\/\/|^-\/\/Metrius\/\/DTD Metrius Presentational\/\/|^-\/\/Microsoft\/\/DTD Internet Explorer 2\.0 HTML Strict\/\/|^-\/\/Microsoft\/\/DTD Internet Explorer 2\.0 HTML\/\/|^-\/\/Microsoft\/\/DTD Internet Explorer 2\.0 Tables\/\/|^-\/\/Microsoft\/\/DTD Internet Explorer 3\.0 HTML Strict\/\/|^-\/\/Microsoft\/\/DTD Internet Explorer 3\.0 HTML\/\/|^-\/\/Microsoft\/\/DTD Internet Explorer 3\.0 Tables\/\/|^-\/\/Netscape Comm\. Corp\.\/\/DTD HTML\/\/|^-\/\/Netscape Comm\. Corp\.\/\/DTD Strict HTML\/\/|^-\/\/O'Reilly and Associates\/\/DTD HTML 2\.0\/\/|^-\/\/O'Reilly and Associates\/\/DTD HTML Extended 1\.0\/\/|^-\/\/O'Reilly and Associates\/\/DTD HTML Extended Relaxed 1\.0\/\/|^-\/\/SoftQuad Software\/\/DTD HoTMetaL PRO 6\.0::19990601::extensions to HTML 4\.0\/\/|^-\/\/SoftQuad\/\/DTD HoTMetaL PRO 4\.0::19971010::extensions to HTML 4\.0\/\/|^-\/\/Spyglass\/\/DTD HTML 2\.0 Extended\/\/|^-\/\/SQ\/\/DTD HTML 2\.0 HoTMetaL \+ extensions\/\/|^-\/\/Sun Microsystems Corp\.\/\/DTD HotJava HTML\/\/|^-\/\/Sun Microsystems Corp\.\/\/DTD HotJava Strict HTML\/\/|^-\/\/W3C\/\/DTD HTML 3 1995-03-24\/\/|^-\/\/W3C\/\/DTD HTML 3\.2 Draft\/\/|^-\/\/W3C\/\/DTD HTML 3\.2 Final\/\/|^-\/\/W3C\/\/DTD HTML 3\.2\/\/|^-\/\/W3C\/\/DTD HTML 3\.2S Draft\/\/|^-\/\/W3C\/\/DTD HTML 4\.0 Frameset\/\/|^-\/\/W3C\/\/DTD HTML 4\.0 Transitional\/\/|^-\/\/W3C\/\/DTD HTML Experimental 19960712\/\/|^-\/\/W3C\/\/DTD HTML Experimental 970421\/\/|^-\/\/W3C\/\/DTD W3 HTML\/\/|^-\/\/W3O\/\/DTD W3 HTML 3\.0\/\/|^-\/\/WebTechs\/\/DTD Mozilla HTML 2\.0\/\/|^-\/\/WebTechs\/\/DTD Mozilla HTML\/\//i; - -var quirkySystemId = 'http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd'; - -var conditionallyQuirkyPublicIds = - /^-\/\/W3C\/\/DTD HTML 4\.01 Frameset\/\/|^-\/\/W3C\/\/DTD HTML 4\.01 Transitional\/\//i; - -// These DTD public ids put the browser in limited quirks mode -var limitedQuirkyPublicIds = - /^-\/\/W3C\/\/DTD XHTML 1\.0 Frameset\/\/|^-\/\/W3C\/\/DTD XHTML 1\.0 Transitional\/\//i; - -// Element sets below. See the isA() function for a way to test -// whether an element is a member of a set -var specialSet = Object.create(null); -specialSet[NAMESPACE.HTML] = { - __proto__: null, - address: true, - applet: true, - area: true, - article: true, - aside: true, - base: true, - basefont: true, - bgsound: true, - blockquote: true, - body: true, - br: true, - button: true, - caption: true, - center: true, - col: true, - colgroup: true, - dd: true, - details: true, - dir: true, - div: true, - dl: true, - dt: true, - embed: true, - fieldset: true, - figcaption: true, - figure: true, - footer: true, - form: true, - frame: true, - frameset: true, - h1: true, - h2: true, - h3: true, - h4: true, - h5: true, - h6: true, - head: true, - header: true, - hgroup: true, - hr: true, - html: true, - iframe: true, - img: true, - input: true, - li: true, - link: true, - listing: true, - main: true, - marquee: true, - menu: true, - meta: true, - nav: true, - noembed: true, - noframes: true, - noscript: true, - object: true, - ol: true, - p: true, - param: true, - plaintext: true, - pre: true, - script: true, - section: true, - select: true, - source: true, - style: true, - summary: true, - table: true, - tbody: true, - td: true, - template: true, - textarea: true, - tfoot: true, - th: true, - thead: true, - title: true, - tr: true, - track: true, - // Note that "xmp" was removed from the "special" set in the latest - // spec, apparently by accident; see - // https://github.com/whatwg/html/pull/1919 - ul: true, - wbr: true, - xmp: true, -}; -specialSet[NAMESPACE.SVG] = { - __proto__: null, - foreignObject: true, - desc: true, - title: true, -}; -specialSet[NAMESPACE.MATHML] = { - __proto__: null, - mi: true, - mo: true, - mn: true, - ms: true, - mtext: true, - 'annotation-xml': true, -}; - -// The set of address, div, and p HTML tags -var addressdivpSet = Object.create(null); -addressdivpSet[NAMESPACE.HTML] = { - __proto__: null, - address: true, - div: true, - p: true, -}; - -var dddtSet = Object.create(null); -dddtSet[NAMESPACE.HTML] = { - __proto__: null, - dd: true, - dt: true, -}; - -var tablesectionrowSet = Object.create(null); -tablesectionrowSet[NAMESPACE.HTML] = { - __proto__: null, - table: true, - thead: true, - tbody: true, - tfoot: true, - tr: true, -}; - -var impliedEndTagsSet = Object.create(null); -impliedEndTagsSet[NAMESPACE.HTML] = { - __proto__: null, - dd: true, - dt: true, - li: true, - menuitem: true, - optgroup: true, - option: true, - p: true, - rb: true, - rp: true, - rt: true, - rtc: true, -}; - -var thoroughImpliedEndTagsSet = Object.create(null); -thoroughImpliedEndTagsSet[NAMESPACE.HTML] = { - __proto__: null, - caption: true, - colgroup: true, - dd: true, - dt: true, - li: true, - optgroup: true, - option: true, - p: true, - rb: true, - rp: true, - rt: true, - rtc: true, - tbody: true, - td: true, - tfoot: true, - th: true, - thead: true, - tr: true, -}; - -var tableContextSet = Object.create(null); -tableContextSet[NAMESPACE.HTML] = { - __proto__: null, - table: true, - template: true, - html: true, -}; - -var tableBodyContextSet = Object.create(null); -tableBodyContextSet[NAMESPACE.HTML] = { - __proto__: null, - tbody: true, - tfoot: true, - thead: true, - template: true, - html: true, -}; - -var tableRowContextSet = Object.create(null); -tableRowContextSet[NAMESPACE.HTML] = { - __proto__: null, - tr: true, - template: true, - html: true, -}; - -// See http://www.w3.org/TR/html5/forms.html#form-associated-element -var formassociatedSet = Object.create(null); -formassociatedSet[NAMESPACE.HTML] = { - __proto__: null, - button: true, - fieldset: true, - input: true, - keygen: true, - object: true, - output: true, - select: true, - textarea: true, - img: true, -}; - -var inScopeSet = Object.create(null); -inScopeSet[NAMESPACE.HTML] = { - __proto__: null, - applet: true, - caption: true, - html: true, - table: true, - td: true, - th: true, - marquee: true, - object: true, - template: true, -}; -inScopeSet[NAMESPACE.MATHML] = { - __proto__: null, - mi: true, - mo: true, - mn: true, - ms: true, - mtext: true, - 'annotation-xml': true, -}; -inScopeSet[NAMESPACE.SVG] = { - __proto__: null, - foreignObject: true, - desc: true, - title: true, -}; - -var inListItemScopeSet = Object.create(inScopeSet); -inListItemScopeSet[NAMESPACE.HTML] = Object.create(inScopeSet[NAMESPACE.HTML]); -inListItemScopeSet[NAMESPACE.HTML].ol = true; -inListItemScopeSet[NAMESPACE.HTML].ul = true; - -var inButtonScopeSet = Object.create(inScopeSet); -inButtonScopeSet[NAMESPACE.HTML] = Object.create(inScopeSet[NAMESPACE.HTML]); -inButtonScopeSet[NAMESPACE.HTML].button = true; - -var inTableScopeSet = Object.create(null); -inTableScopeSet[NAMESPACE.HTML] = { - __proto__: null, - html: true, - table: true, - template: true, -}; - -// The set of elements for select scope is the everything *except* these -var invertedSelectScopeSet = Object.create(null); -invertedSelectScopeSet[NAMESPACE.HTML] = { - __proto__: null, - optgroup: true, - option: true, -}; - -var mathmlTextIntegrationPointSet = Object.create(null); -mathmlTextIntegrationPointSet[NAMESPACE.MATHML] = { - __proto__: null, - mi: true, - mo: true, - mn: true, - ms: true, - mtext: true, -}; - -var htmlIntegrationPointSet = Object.create(null); -htmlIntegrationPointSet[NAMESPACE.SVG] = { - __proto__: null, - foreignObject: true, - desc: true, - title: true, -}; - -var foreignAttributes = { - __proto__: null, - 'xlink:actuate': NAMESPACE.XLINK, - 'xlink:arcrole': NAMESPACE.XLINK, - 'xlink:href': NAMESPACE.XLINK, - 'xlink:role': NAMESPACE.XLINK, - 'xlink:show': NAMESPACE.XLINK, - 'xlink:title': NAMESPACE.XLINK, - 'xlink:type': NAMESPACE.XLINK, - 'xml:base': NAMESPACE.XML, - 'xml:lang': NAMESPACE.XML, - 'xml:space': NAMESPACE.XML, - xmlns: NAMESPACE.XMLNS, - 'xmlns:xlink': NAMESPACE.XMLNS, -}; - -// Lowercase to mixed case mapping for SVG attributes and tagnames -var svgAttrAdjustments = { - __proto__: null, - attributename: 'attributeName', - attributetype: 'attributeType', - basefrequency: 'baseFrequency', - baseprofile: 'baseProfile', - calcmode: 'calcMode', - clippathunits: 'clipPathUnits', - diffuseconstant: 'diffuseConstant', - edgemode: 'edgeMode', - filterunits: 'filterUnits', - glyphref: 'glyphRef', - gradienttransform: 'gradientTransform', - gradientunits: 'gradientUnits', - kernelmatrix: 'kernelMatrix', - kernelunitlength: 'kernelUnitLength', - keypoints: 'keyPoints', - keysplines: 'keySplines', - keytimes: 'keyTimes', - lengthadjust: 'lengthAdjust', - limitingconeangle: 'limitingConeAngle', - markerheight: 'markerHeight', - markerunits: 'markerUnits', - markerwidth: 'markerWidth', - maskcontentunits: 'maskContentUnits', - maskunits: 'maskUnits', - numoctaves: 'numOctaves', - pathlength: 'pathLength', - patterncontentunits: 'patternContentUnits', - patterntransform: 'patternTransform', - patternunits: 'patternUnits', - pointsatx: 'pointsAtX', - pointsaty: 'pointsAtY', - pointsatz: 'pointsAtZ', - preservealpha: 'preserveAlpha', - preserveaspectratio: 'preserveAspectRatio', - primitiveunits: 'primitiveUnits', - refx: 'refX', - refy: 'refY', - repeatcount: 'repeatCount', - repeatdur: 'repeatDur', - requiredextensions: 'requiredExtensions', - requiredfeatures: 'requiredFeatures', - specularconstant: 'specularConstant', - specularexponent: 'specularExponent', - spreadmethod: 'spreadMethod', - startoffset: 'startOffset', - stddeviation: 'stdDeviation', - stitchtiles: 'stitchTiles', - surfacescale: 'surfaceScale', - systemlanguage: 'systemLanguage', - tablevalues: 'tableValues', - targetx: 'targetX', - targety: 'targetY', - textlength: 'textLength', - viewbox: 'viewBox', - viewtarget: 'viewTarget', - xchannelselector: 'xChannelSelector', - ychannelselector: 'yChannelSelector', - zoomandpan: 'zoomAndPan', -}; - -var svgTagNameAdjustments = { - __proto__: null, - altglyph: 'altGlyph', - altglyphdef: 'altGlyphDef', - altglyphitem: 'altGlyphItem', - animatecolor: 'animateColor', - animatemotion: 'animateMotion', - animatetransform: 'animateTransform', - clippath: 'clipPath', - feblend: 'feBlend', - fecolormatrix: 'feColorMatrix', - fecomponenttransfer: 'feComponentTransfer', - fecomposite: 'feComposite', - feconvolvematrix: 'feConvolveMatrix', - fediffuselighting: 'feDiffuseLighting', - fedisplacementmap: 'feDisplacementMap', - fedistantlight: 'feDistantLight', - feflood: 'feFlood', - fefunca: 'feFuncA', - fefuncb: 'feFuncB', - fefuncg: 'feFuncG', - fefuncr: 'feFuncR', - fegaussianblur: 'feGaussianBlur', - feimage: 'feImage', - femerge: 'feMerge', - femergenode: 'feMergeNode', - femorphology: 'feMorphology', - feoffset: 'feOffset', - fepointlight: 'fePointLight', - fespecularlighting: 'feSpecularLighting', - fespotlight: 'feSpotLight', - fetile: 'feTile', - feturbulence: 'feTurbulence', - foreignobject: 'foreignObject', - glyphref: 'glyphRef', - lineargradient: 'linearGradient', - radialgradient: 'radialGradient', - textpath: 'textPath', -}; - -// Data for parsing numeric and named character references -// These next 3 objects are direct translations of tables -// in the HTML spec into JavaScript object format -var numericCharRefReplacements = { - __proto__: null, - 0x00: 0xfffd, - 0x80: 0x20ac, - 0x82: 0x201a, - 0x83: 0x0192, - 0x84: 0x201e, - 0x85: 0x2026, - 0x86: 0x2020, - 0x87: 0x2021, - 0x88: 0x02c6, - 0x89: 0x2030, - 0x8a: 0x0160, - 0x8b: 0x2039, - 0x8c: 0x0152, - 0x8e: 0x017d, - 0x91: 0x2018, - 0x92: 0x2019, - 0x93: 0x201c, - 0x94: 0x201d, - 0x95: 0x2022, - 0x96: 0x2013, - 0x97: 0x2014, - 0x98: 0x02dc, - 0x99: 0x2122, - 0x9a: 0x0161, - 0x9b: 0x203a, - 0x9c: 0x0153, - 0x9e: 0x017e, - 0x9f: 0x0178, -}; - -/* - * This table is generated with test/tools/update-entities.js - */ -var namedCharRefs = { - __proto__: null, - AElig: 0xc6, - 'AElig;': 0xc6, - AMP: 0x26, - 'AMP;': 0x26, - Aacute: 0xc1, - 'Aacute;': 0xc1, - 'Abreve;': 0x102, - Acirc: 0xc2, - 'Acirc;': 0xc2, - 'Acy;': 0x410, - 'Afr;': [0xd835, 0xdd04], - Agrave: 0xc0, - 'Agrave;': 0xc0, - 'Alpha;': 0x391, - 'Amacr;': 0x100, - 'And;': 0x2a53, - 'Aogon;': 0x104, - 'Aopf;': [0xd835, 0xdd38], - 'ApplyFunction;': 0x2061, - Aring: 0xc5, - 'Aring;': 0xc5, - 'Ascr;': [0xd835, 0xdc9c], - 'Assign;': 0x2254, - Atilde: 0xc3, - 'Atilde;': 0xc3, - Auml: 0xc4, - 'Auml;': 0xc4, - 'Backslash;': 0x2216, - 'Barv;': 0x2ae7, - 'Barwed;': 0x2306, - 'Bcy;': 0x411, - 'Because;': 0x2235, - 'Bernoullis;': 0x212c, - 'Beta;': 0x392, - 'Bfr;': [0xd835, 0xdd05], - 'Bopf;': [0xd835, 0xdd39], - 'Breve;': 0x2d8, - 'Bscr;': 0x212c, - 'Bumpeq;': 0x224e, - 'CHcy;': 0x427, - COPY: 0xa9, - 'COPY;': 0xa9, - 'Cacute;': 0x106, - 'Cap;': 0x22d2, - 'CapitalDifferentialD;': 0x2145, - 'Cayleys;': 0x212d, - 'Ccaron;': 0x10c, - Ccedil: 0xc7, - 'Ccedil;': 0xc7, - 'Ccirc;': 0x108, - 'Cconint;': 0x2230, - 'Cdot;': 0x10a, - 'Cedilla;': 0xb8, - 'CenterDot;': 0xb7, - 'Cfr;': 0x212d, - 'Chi;': 0x3a7, - 'CircleDot;': 0x2299, - 'CircleMinus;': 0x2296, - 'CirclePlus;': 0x2295, - 'CircleTimes;': 0x2297, - 'ClockwiseContourIntegral;': 0x2232, - 'CloseCurlyDoubleQuote;': 0x201d, - 'CloseCurlyQuote;': 0x2019, - 'Colon;': 0x2237, - 'Colone;': 0x2a74, - 'Congruent;': 0x2261, - 'Conint;': 0x222f, - 'ContourIntegral;': 0x222e, - 'Copf;': 0x2102, - 'Coproduct;': 0x2210, - 'CounterClockwiseContourIntegral;': 0x2233, - 'Cross;': 0x2a2f, - 'Cscr;': [0xd835, 0xdc9e], - 'Cup;': 0x22d3, - 'CupCap;': 0x224d, - 'DD;': 0x2145, - 'DDotrahd;': 0x2911, - 'DJcy;': 0x402, - 'DScy;': 0x405, - 'DZcy;': 0x40f, - 'Dagger;': 0x2021, - 'Darr;': 0x21a1, - 'Dashv;': 0x2ae4, - 'Dcaron;': 0x10e, - 'Dcy;': 0x414, - 'Del;': 0x2207, - 'Delta;': 0x394, - 'Dfr;': [0xd835, 0xdd07], - 'DiacriticalAcute;': 0xb4, - 'DiacriticalDot;': 0x2d9, - 'DiacriticalDoubleAcute;': 0x2dd, - 'DiacriticalGrave;': 0x60, - 'DiacriticalTilde;': 0x2dc, - 'Diamond;': 0x22c4, - 'DifferentialD;': 0x2146, - 'Dopf;': [0xd835, 0xdd3b], - 'Dot;': 0xa8, - 'DotDot;': 0x20dc, - 'DotEqual;': 0x2250, - 'DoubleContourIntegral;': 0x222f, - 'DoubleDot;': 0xa8, - 'DoubleDownArrow;': 0x21d3, - 'DoubleLeftArrow;': 0x21d0, - 'DoubleLeftRightArrow;': 0x21d4, - 'DoubleLeftTee;': 0x2ae4, - 'DoubleLongLeftArrow;': 0x27f8, - 'DoubleLongLeftRightArrow;': 0x27fa, - 'DoubleLongRightArrow;': 0x27f9, - 'DoubleRightArrow;': 0x21d2, - 'DoubleRightTee;': 0x22a8, - 'DoubleUpArrow;': 0x21d1, - 'DoubleUpDownArrow;': 0x21d5, - 'DoubleVerticalBar;': 0x2225, - 'DownArrow;': 0x2193, - 'DownArrowBar;': 0x2913, - 'DownArrowUpArrow;': 0x21f5, - 'DownBreve;': 0x311, - 'DownLeftRightVector;': 0x2950, - 'DownLeftTeeVector;': 0x295e, - 'DownLeftVector;': 0x21bd, - 'DownLeftVectorBar;': 0x2956, - 'DownRightTeeVector;': 0x295f, - 'DownRightVector;': 0x21c1, - 'DownRightVectorBar;': 0x2957, - 'DownTee;': 0x22a4, - 'DownTeeArrow;': 0x21a7, - 'Downarrow;': 0x21d3, - 'Dscr;': [0xd835, 0xdc9f], - 'Dstrok;': 0x110, - 'ENG;': 0x14a, - ETH: 0xd0, - 'ETH;': 0xd0, - Eacute: 0xc9, - 'Eacute;': 0xc9, - 'Ecaron;': 0x11a, - Ecirc: 0xca, - 'Ecirc;': 0xca, - 'Ecy;': 0x42d, - 'Edot;': 0x116, - 'Efr;': [0xd835, 0xdd08], - Egrave: 0xc8, - 'Egrave;': 0xc8, - 'Element;': 0x2208, - 'Emacr;': 0x112, - 'EmptySmallSquare;': 0x25fb, - 'EmptyVerySmallSquare;': 0x25ab, - 'Eogon;': 0x118, - 'Eopf;': [0xd835, 0xdd3c], - 'Epsilon;': 0x395, - 'Equal;': 0x2a75, - 'EqualTilde;': 0x2242, - 'Equilibrium;': 0x21cc, - 'Escr;': 0x2130, - 'Esim;': 0x2a73, - 'Eta;': 0x397, - Euml: 0xcb, - 'Euml;': 0xcb, - 'Exists;': 0x2203, - 'ExponentialE;': 0x2147, - 'Fcy;': 0x424, - 'Ffr;': [0xd835, 0xdd09], - 'FilledSmallSquare;': 0x25fc, - 'FilledVerySmallSquare;': 0x25aa, - 'Fopf;': [0xd835, 0xdd3d], - 'ForAll;': 0x2200, - 'Fouriertrf;': 0x2131, - 'Fscr;': 0x2131, - 'GJcy;': 0x403, - GT: 0x3e, - 'GT;': 0x3e, - 'Gamma;': 0x393, - 'Gammad;': 0x3dc, - 'Gbreve;': 0x11e, - 'Gcedil;': 0x122, - 'Gcirc;': 0x11c, - 'Gcy;': 0x413, - 'Gdot;': 0x120, - 'Gfr;': [0xd835, 0xdd0a], - 'Gg;': 0x22d9, - 'Gopf;': [0xd835, 0xdd3e], - 'GreaterEqual;': 0x2265, - 'GreaterEqualLess;': 0x22db, - 'GreaterFullEqual;': 0x2267, - 'GreaterGreater;': 0x2aa2, - 'GreaterLess;': 0x2277, - 'GreaterSlantEqual;': 0x2a7e, - 'GreaterTilde;': 0x2273, - 'Gscr;': [0xd835, 0xdca2], - 'Gt;': 0x226b, - 'HARDcy;': 0x42a, - 'Hacek;': 0x2c7, - 'Hat;': 0x5e, - 'Hcirc;': 0x124, - 'Hfr;': 0x210c, - 'HilbertSpace;': 0x210b, - 'Hopf;': 0x210d, - 'HorizontalLine;': 0x2500, - 'Hscr;': 0x210b, - 'Hstrok;': 0x126, - 'HumpDownHump;': 0x224e, - 'HumpEqual;': 0x224f, - 'IEcy;': 0x415, - 'IJlig;': 0x132, - 'IOcy;': 0x401, - Iacute: 0xcd, - 'Iacute;': 0xcd, - Icirc: 0xce, - 'Icirc;': 0xce, - 'Icy;': 0x418, - 'Idot;': 0x130, - 'Ifr;': 0x2111, - Igrave: 0xcc, - 'Igrave;': 0xcc, - 'Im;': 0x2111, - 'Imacr;': 0x12a, - 'ImaginaryI;': 0x2148, - 'Implies;': 0x21d2, - 'Int;': 0x222c, - 'Integral;': 0x222b, - 'Intersection;': 0x22c2, - 'InvisibleComma;': 0x2063, - 'InvisibleTimes;': 0x2062, - 'Iogon;': 0x12e, - 'Iopf;': [0xd835, 0xdd40], - 'Iota;': 0x399, - 'Iscr;': 0x2110, - 'Itilde;': 0x128, - 'Iukcy;': 0x406, - Iuml: 0xcf, - 'Iuml;': 0xcf, - 'Jcirc;': 0x134, - 'Jcy;': 0x419, - 'Jfr;': [0xd835, 0xdd0d], - 'Jopf;': [0xd835, 0xdd41], - 'Jscr;': [0xd835, 0xdca5], - 'Jsercy;': 0x408, - 'Jukcy;': 0x404, - 'KHcy;': 0x425, - 'KJcy;': 0x40c, - 'Kappa;': 0x39a, - 'Kcedil;': 0x136, - 'Kcy;': 0x41a, - 'Kfr;': [0xd835, 0xdd0e], - 'Kopf;': [0xd835, 0xdd42], - 'Kscr;': [0xd835, 0xdca6], - 'LJcy;': 0x409, - LT: 0x3c, - 'LT;': 0x3c, - 'Lacute;': 0x139, - 'Lambda;': 0x39b, - 'Lang;': 0x27ea, - 'Laplacetrf;': 0x2112, - 'Larr;': 0x219e, - 'Lcaron;': 0x13d, - 'Lcedil;': 0x13b, - 'Lcy;': 0x41b, - 'LeftAngleBracket;': 0x27e8, - 'LeftArrow;': 0x2190, - 'LeftArrowBar;': 0x21e4, - 'LeftArrowRightArrow;': 0x21c6, - 'LeftCeiling;': 0x2308, - 'LeftDoubleBracket;': 0x27e6, - 'LeftDownTeeVector;': 0x2961, - 'LeftDownVector;': 0x21c3, - 'LeftDownVectorBar;': 0x2959, - 'LeftFloor;': 0x230a, - 'LeftRightArrow;': 0x2194, - 'LeftRightVector;': 0x294e, - 'LeftTee;': 0x22a3, - 'LeftTeeArrow;': 0x21a4, - 'LeftTeeVector;': 0x295a, - 'LeftTriangle;': 0x22b2, - 'LeftTriangleBar;': 0x29cf, - 'LeftTriangleEqual;': 0x22b4, - 'LeftUpDownVector;': 0x2951, - 'LeftUpTeeVector;': 0x2960, - 'LeftUpVector;': 0x21bf, - 'LeftUpVectorBar;': 0x2958, - 'LeftVector;': 0x21bc, - 'LeftVectorBar;': 0x2952, - 'Leftarrow;': 0x21d0, - 'Leftrightarrow;': 0x21d4, - 'LessEqualGreater;': 0x22da, - 'LessFullEqual;': 0x2266, - 'LessGreater;': 0x2276, - 'LessLess;': 0x2aa1, - 'LessSlantEqual;': 0x2a7d, - 'LessTilde;': 0x2272, - 'Lfr;': [0xd835, 0xdd0f], - 'Ll;': 0x22d8, - 'Lleftarrow;': 0x21da, - 'Lmidot;': 0x13f, - 'LongLeftArrow;': 0x27f5, - 'LongLeftRightArrow;': 0x27f7, - 'LongRightArrow;': 0x27f6, - 'Longleftarrow;': 0x27f8, - 'Longleftrightarrow;': 0x27fa, - 'Longrightarrow;': 0x27f9, - 'Lopf;': [0xd835, 0xdd43], - 'LowerLeftArrow;': 0x2199, - 'LowerRightArrow;': 0x2198, - 'Lscr;': 0x2112, - 'Lsh;': 0x21b0, - 'Lstrok;': 0x141, - 'Lt;': 0x226a, - 'Map;': 0x2905, - 'Mcy;': 0x41c, - 'MediumSpace;': 0x205f, - 'Mellintrf;': 0x2133, - 'Mfr;': [0xd835, 0xdd10], - 'MinusPlus;': 0x2213, - 'Mopf;': [0xd835, 0xdd44], - 'Mscr;': 0x2133, - 'Mu;': 0x39c, - 'NJcy;': 0x40a, - 'Nacute;': 0x143, - 'Ncaron;': 0x147, - 'Ncedil;': 0x145, - 'Ncy;': 0x41d, - 'NegativeMediumSpace;': 0x200b, - 'NegativeThickSpace;': 0x200b, - 'NegativeThinSpace;': 0x200b, - 'NegativeVeryThinSpace;': 0x200b, - 'NestedGreaterGreater;': 0x226b, - 'NestedLessLess;': 0x226a, - 'NewLine;': 0xa, - 'Nfr;': [0xd835, 0xdd11], - 'NoBreak;': 0x2060, - 'NonBreakingSpace;': 0xa0, - 'Nopf;': 0x2115, - 'Not;': 0x2aec, - 'NotCongruent;': 0x2262, - 'NotCupCap;': 0x226d, - 'NotDoubleVerticalBar;': 0x2226, - 'NotElement;': 0x2209, - 'NotEqual;': 0x2260, - 'NotEqualTilde;': [0x2242, 0x338], - 'NotExists;': 0x2204, - 'NotGreater;': 0x226f, - 'NotGreaterEqual;': 0x2271, - 'NotGreaterFullEqual;': [0x2267, 0x338], - 'NotGreaterGreater;': [0x226b, 0x338], - 'NotGreaterLess;': 0x2279, - 'NotGreaterSlantEqual;': [0x2a7e, 0x338], - 'NotGreaterTilde;': 0x2275, - 'NotHumpDownHump;': [0x224e, 0x338], - 'NotHumpEqual;': [0x224f, 0x338], - 'NotLeftTriangle;': 0x22ea, - 'NotLeftTriangleBar;': [0x29cf, 0x338], - 'NotLeftTriangleEqual;': 0x22ec, - 'NotLess;': 0x226e, - 'NotLessEqual;': 0x2270, - 'NotLessGreater;': 0x2278, - 'NotLessLess;': [0x226a, 0x338], - 'NotLessSlantEqual;': [0x2a7d, 0x338], - 'NotLessTilde;': 0x2274, - 'NotNestedGreaterGreater;': [0x2aa2, 0x338], - 'NotNestedLessLess;': [0x2aa1, 0x338], - 'NotPrecedes;': 0x2280, - 'NotPrecedesEqual;': [0x2aaf, 0x338], - 'NotPrecedesSlantEqual;': 0x22e0, - 'NotReverseElement;': 0x220c, - 'NotRightTriangle;': 0x22eb, - 'NotRightTriangleBar;': [0x29d0, 0x338], - 'NotRightTriangleEqual;': 0x22ed, - 'NotSquareSubset;': [0x228f, 0x338], - 'NotSquareSubsetEqual;': 0x22e2, - 'NotSquareSuperset;': [0x2290, 0x338], - 'NotSquareSupersetEqual;': 0x22e3, - 'NotSubset;': [0x2282, 0x20d2], - 'NotSubsetEqual;': 0x2288, - 'NotSucceeds;': 0x2281, - 'NotSucceedsEqual;': [0x2ab0, 0x338], - 'NotSucceedsSlantEqual;': 0x22e1, - 'NotSucceedsTilde;': [0x227f, 0x338], - 'NotSuperset;': [0x2283, 0x20d2], - 'NotSupersetEqual;': 0x2289, - 'NotTilde;': 0x2241, - 'NotTildeEqual;': 0x2244, - 'NotTildeFullEqual;': 0x2247, - 'NotTildeTilde;': 0x2249, - 'NotVerticalBar;': 0x2224, - 'Nscr;': [0xd835, 0xdca9], - Ntilde: 0xd1, - 'Ntilde;': 0xd1, - 'Nu;': 0x39d, - 'OElig;': 0x152, - Oacute: 0xd3, - 'Oacute;': 0xd3, - Ocirc: 0xd4, - 'Ocirc;': 0xd4, - 'Ocy;': 0x41e, - 'Odblac;': 0x150, - 'Ofr;': [0xd835, 0xdd12], - Ograve: 0xd2, - 'Ograve;': 0xd2, - 'Omacr;': 0x14c, - 'Omega;': 0x3a9, - 'Omicron;': 0x39f, - 'Oopf;': [0xd835, 0xdd46], - 'OpenCurlyDoubleQuote;': 0x201c, - 'OpenCurlyQuote;': 0x2018, - 'Or;': 0x2a54, - 'Oscr;': [0xd835, 0xdcaa], - Oslash: 0xd8, - 'Oslash;': 0xd8, - Otilde: 0xd5, - 'Otilde;': 0xd5, - 'Otimes;': 0x2a37, - Ouml: 0xd6, - 'Ouml;': 0xd6, - 'OverBar;': 0x203e, - 'OverBrace;': 0x23de, - 'OverBracket;': 0x23b4, - 'OverParenthesis;': 0x23dc, - 'PartialD;': 0x2202, - 'Pcy;': 0x41f, - 'Pfr;': [0xd835, 0xdd13], - 'Phi;': 0x3a6, - 'Pi;': 0x3a0, - 'PlusMinus;': 0xb1, - 'Poincareplane;': 0x210c, - 'Popf;': 0x2119, - 'Pr;': 0x2abb, - 'Precedes;': 0x227a, - 'PrecedesEqual;': 0x2aaf, - 'PrecedesSlantEqual;': 0x227c, - 'PrecedesTilde;': 0x227e, - 'Prime;': 0x2033, - 'Product;': 0x220f, - 'Proportion;': 0x2237, - 'Proportional;': 0x221d, - 'Pscr;': [0xd835, 0xdcab], - 'Psi;': 0x3a8, - QUOT: 0x22, - 'QUOT;': 0x22, - 'Qfr;': [0xd835, 0xdd14], - 'Qopf;': 0x211a, - 'Qscr;': [0xd835, 0xdcac], - 'RBarr;': 0x2910, - REG: 0xae, - 'REG;': 0xae, - 'Racute;': 0x154, - 'Rang;': 0x27eb, - 'Rarr;': 0x21a0, - 'Rarrtl;': 0x2916, - 'Rcaron;': 0x158, - 'Rcedil;': 0x156, - 'Rcy;': 0x420, - 'Re;': 0x211c, - 'ReverseElement;': 0x220b, - 'ReverseEquilibrium;': 0x21cb, - 'ReverseUpEquilibrium;': 0x296f, - 'Rfr;': 0x211c, - 'Rho;': 0x3a1, - 'RightAngleBracket;': 0x27e9, - 'RightArrow;': 0x2192, - 'RightArrowBar;': 0x21e5, - 'RightArrowLeftArrow;': 0x21c4, - 'RightCeiling;': 0x2309, - 'RightDoubleBracket;': 0x27e7, - 'RightDownTeeVector;': 0x295d, - 'RightDownVector;': 0x21c2, - 'RightDownVectorBar;': 0x2955, - 'RightFloor;': 0x230b, - 'RightTee;': 0x22a2, - 'RightTeeArrow;': 0x21a6, - 'RightTeeVector;': 0x295b, - 'RightTriangle;': 0x22b3, - 'RightTriangleBar;': 0x29d0, - 'RightTriangleEqual;': 0x22b5, - 'RightUpDownVector;': 0x294f, - 'RightUpTeeVector;': 0x295c, - 'RightUpVector;': 0x21be, - 'RightUpVectorBar;': 0x2954, - 'RightVector;': 0x21c0, - 'RightVectorBar;': 0x2953, - 'Rightarrow;': 0x21d2, - 'Ropf;': 0x211d, - 'RoundImplies;': 0x2970, - 'Rrightarrow;': 0x21db, - 'Rscr;': 0x211b, - 'Rsh;': 0x21b1, - 'RuleDelayed;': 0x29f4, - 'SHCHcy;': 0x429, - 'SHcy;': 0x428, - 'SOFTcy;': 0x42c, - 'Sacute;': 0x15a, - 'Sc;': 0x2abc, - 'Scaron;': 0x160, - 'Scedil;': 0x15e, - 'Scirc;': 0x15c, - 'Scy;': 0x421, - 'Sfr;': [0xd835, 0xdd16], - 'ShortDownArrow;': 0x2193, - 'ShortLeftArrow;': 0x2190, - 'ShortRightArrow;': 0x2192, - 'ShortUpArrow;': 0x2191, - 'Sigma;': 0x3a3, - 'SmallCircle;': 0x2218, - 'Sopf;': [0xd835, 0xdd4a], - 'Sqrt;': 0x221a, - 'Square;': 0x25a1, - 'SquareIntersection;': 0x2293, - 'SquareSubset;': 0x228f, - 'SquareSubsetEqual;': 0x2291, - 'SquareSuperset;': 0x2290, - 'SquareSupersetEqual;': 0x2292, - 'SquareUnion;': 0x2294, - 'Sscr;': [0xd835, 0xdcae], - 'Star;': 0x22c6, - 'Sub;': 0x22d0, - 'Subset;': 0x22d0, - 'SubsetEqual;': 0x2286, - 'Succeeds;': 0x227b, - 'SucceedsEqual;': 0x2ab0, - 'SucceedsSlantEqual;': 0x227d, - 'SucceedsTilde;': 0x227f, - 'SuchThat;': 0x220b, - 'Sum;': 0x2211, - 'Sup;': 0x22d1, - 'Superset;': 0x2283, - 'SupersetEqual;': 0x2287, - 'Supset;': 0x22d1, - THORN: 0xde, - 'THORN;': 0xde, - 'TRADE;': 0x2122, - 'TSHcy;': 0x40b, - 'TScy;': 0x426, - 'Tab;': 0x9, - 'Tau;': 0x3a4, - 'Tcaron;': 0x164, - 'Tcedil;': 0x162, - 'Tcy;': 0x422, - 'Tfr;': [0xd835, 0xdd17], - 'Therefore;': 0x2234, - 'Theta;': 0x398, - 'ThickSpace;': [0x205f, 0x200a], - 'ThinSpace;': 0x2009, - 'Tilde;': 0x223c, - 'TildeEqual;': 0x2243, - 'TildeFullEqual;': 0x2245, - 'TildeTilde;': 0x2248, - 'Topf;': [0xd835, 0xdd4b], - 'TripleDot;': 0x20db, - 'Tscr;': [0xd835, 0xdcaf], - 'Tstrok;': 0x166, - Uacute: 0xda, - 'Uacute;': 0xda, - 'Uarr;': 0x219f, - 'Uarrocir;': 0x2949, - 'Ubrcy;': 0x40e, - 'Ubreve;': 0x16c, - Ucirc: 0xdb, - 'Ucirc;': 0xdb, - 'Ucy;': 0x423, - 'Udblac;': 0x170, - 'Ufr;': [0xd835, 0xdd18], - Ugrave: 0xd9, - 'Ugrave;': 0xd9, - 'Umacr;': 0x16a, - 'UnderBar;': 0x5f, - 'UnderBrace;': 0x23df, - 'UnderBracket;': 0x23b5, - 'UnderParenthesis;': 0x23dd, - 'Union;': 0x22c3, - 'UnionPlus;': 0x228e, - 'Uogon;': 0x172, - 'Uopf;': [0xd835, 0xdd4c], - 'UpArrow;': 0x2191, - 'UpArrowBar;': 0x2912, - 'UpArrowDownArrow;': 0x21c5, - 'UpDownArrow;': 0x2195, - 'UpEquilibrium;': 0x296e, - 'UpTee;': 0x22a5, - 'UpTeeArrow;': 0x21a5, - 'Uparrow;': 0x21d1, - 'Updownarrow;': 0x21d5, - 'UpperLeftArrow;': 0x2196, - 'UpperRightArrow;': 0x2197, - 'Upsi;': 0x3d2, - 'Upsilon;': 0x3a5, - 'Uring;': 0x16e, - 'Uscr;': [0xd835, 0xdcb0], - 'Utilde;': 0x168, - Uuml: 0xdc, - 'Uuml;': 0xdc, - 'VDash;': 0x22ab, - 'Vbar;': 0x2aeb, - 'Vcy;': 0x412, - 'Vdash;': 0x22a9, - 'Vdashl;': 0x2ae6, - 'Vee;': 0x22c1, - 'Verbar;': 0x2016, - 'Vert;': 0x2016, - 'VerticalBar;': 0x2223, - 'VerticalLine;': 0x7c, - 'VerticalSeparator;': 0x2758, - 'VerticalTilde;': 0x2240, - 'VeryThinSpace;': 0x200a, - 'Vfr;': [0xd835, 0xdd19], - 'Vopf;': [0xd835, 0xdd4d], - 'Vscr;': [0xd835, 0xdcb1], - 'Vvdash;': 0x22aa, - 'Wcirc;': 0x174, - 'Wedge;': 0x22c0, - 'Wfr;': [0xd835, 0xdd1a], - 'Wopf;': [0xd835, 0xdd4e], - 'Wscr;': [0xd835, 0xdcb2], - 'Xfr;': [0xd835, 0xdd1b], - 'Xi;': 0x39e, - 'Xopf;': [0xd835, 0xdd4f], - 'Xscr;': [0xd835, 0xdcb3], - 'YAcy;': 0x42f, - 'YIcy;': 0x407, - 'YUcy;': 0x42e, - Yacute: 0xdd, - 'Yacute;': 0xdd, - 'Ycirc;': 0x176, - 'Ycy;': 0x42b, - 'Yfr;': [0xd835, 0xdd1c], - 'Yopf;': [0xd835, 0xdd50], - 'Yscr;': [0xd835, 0xdcb4], - 'Yuml;': 0x178, - 'ZHcy;': 0x416, - 'Zacute;': 0x179, - 'Zcaron;': 0x17d, - 'Zcy;': 0x417, - 'Zdot;': 0x17b, - 'ZeroWidthSpace;': 0x200b, - 'Zeta;': 0x396, - 'Zfr;': 0x2128, - 'Zopf;': 0x2124, - 'Zscr;': [0xd835, 0xdcb5], - aacute: 0xe1, - 'aacute;': 0xe1, - 'abreve;': 0x103, - 'ac;': 0x223e, - 'acE;': [0x223e, 0x333], - 'acd;': 0x223f, - acirc: 0xe2, - 'acirc;': 0xe2, - acute: 0xb4, - 'acute;': 0xb4, - 'acy;': 0x430, - aelig: 0xe6, - 'aelig;': 0xe6, - 'af;': 0x2061, - 'afr;': [0xd835, 0xdd1e], - agrave: 0xe0, - 'agrave;': 0xe0, - 'alefsym;': 0x2135, - 'aleph;': 0x2135, - 'alpha;': 0x3b1, - 'amacr;': 0x101, - 'amalg;': 0x2a3f, - amp: 0x26, - 'amp;': 0x26, - 'and;': 0x2227, - 'andand;': 0x2a55, - 'andd;': 0x2a5c, - 'andslope;': 0x2a58, - 'andv;': 0x2a5a, - 'ang;': 0x2220, - 'ange;': 0x29a4, - 'angle;': 0x2220, - 'angmsd;': 0x2221, - 'angmsdaa;': 0x29a8, - 'angmsdab;': 0x29a9, - 'angmsdac;': 0x29aa, - 'angmsdad;': 0x29ab, - 'angmsdae;': 0x29ac, - 'angmsdaf;': 0x29ad, - 'angmsdag;': 0x29ae, - 'angmsdah;': 0x29af, - 'angrt;': 0x221f, - 'angrtvb;': 0x22be, - 'angrtvbd;': 0x299d, - 'angsph;': 0x2222, - 'angst;': 0xc5, - 'angzarr;': 0x237c, - 'aogon;': 0x105, - 'aopf;': [0xd835, 0xdd52], - 'ap;': 0x2248, - 'apE;': 0x2a70, - 'apacir;': 0x2a6f, - 'ape;': 0x224a, - 'apid;': 0x224b, - 'apos;': 0x27, - 'approx;': 0x2248, - 'approxeq;': 0x224a, - aring: 0xe5, - 'aring;': 0xe5, - 'ascr;': [0xd835, 0xdcb6], - 'ast;': 0x2a, - 'asymp;': 0x2248, - 'asympeq;': 0x224d, - atilde: 0xe3, - 'atilde;': 0xe3, - auml: 0xe4, - 'auml;': 0xe4, - 'awconint;': 0x2233, - 'awint;': 0x2a11, - 'bNot;': 0x2aed, - 'backcong;': 0x224c, - 'backepsilon;': 0x3f6, - 'backprime;': 0x2035, - 'backsim;': 0x223d, - 'backsimeq;': 0x22cd, - 'barvee;': 0x22bd, - 'barwed;': 0x2305, - 'barwedge;': 0x2305, - 'bbrk;': 0x23b5, - 'bbrktbrk;': 0x23b6, - 'bcong;': 0x224c, - 'bcy;': 0x431, - 'bdquo;': 0x201e, - 'becaus;': 0x2235, - 'because;': 0x2235, - 'bemptyv;': 0x29b0, - 'bepsi;': 0x3f6, - 'bernou;': 0x212c, - 'beta;': 0x3b2, - 'beth;': 0x2136, - 'between;': 0x226c, - 'bfr;': [0xd835, 0xdd1f], - 'bigcap;': 0x22c2, - 'bigcirc;': 0x25ef, - 'bigcup;': 0x22c3, - 'bigodot;': 0x2a00, - 'bigoplus;': 0x2a01, - 'bigotimes;': 0x2a02, - 'bigsqcup;': 0x2a06, - 'bigstar;': 0x2605, - 'bigtriangledown;': 0x25bd, - 'bigtriangleup;': 0x25b3, - 'biguplus;': 0x2a04, - 'bigvee;': 0x22c1, - 'bigwedge;': 0x22c0, - 'bkarow;': 0x290d, - 'blacklozenge;': 0x29eb, - 'blacksquare;': 0x25aa, - 'blacktriangle;': 0x25b4, - 'blacktriangledown;': 0x25be, - 'blacktriangleleft;': 0x25c2, - 'blacktriangleright;': 0x25b8, - 'blank;': 0x2423, - 'blk12;': 0x2592, - 'blk14;': 0x2591, - 'blk34;': 0x2593, - 'block;': 0x2588, - 'bne;': [0x3d, 0x20e5], - 'bnequiv;': [0x2261, 0x20e5], - 'bnot;': 0x2310, - 'bopf;': [0xd835, 0xdd53], - 'bot;': 0x22a5, - 'bottom;': 0x22a5, - 'bowtie;': 0x22c8, - 'boxDL;': 0x2557, - 'boxDR;': 0x2554, - 'boxDl;': 0x2556, - 'boxDr;': 0x2553, - 'boxH;': 0x2550, - 'boxHD;': 0x2566, - 'boxHU;': 0x2569, - 'boxHd;': 0x2564, - 'boxHu;': 0x2567, - 'boxUL;': 0x255d, - 'boxUR;': 0x255a, - 'boxUl;': 0x255c, - 'boxUr;': 0x2559, - 'boxV;': 0x2551, - 'boxVH;': 0x256c, - 'boxVL;': 0x2563, - 'boxVR;': 0x2560, - 'boxVh;': 0x256b, - 'boxVl;': 0x2562, - 'boxVr;': 0x255f, - 'boxbox;': 0x29c9, - 'boxdL;': 0x2555, - 'boxdR;': 0x2552, - 'boxdl;': 0x2510, - 'boxdr;': 0x250c, - 'boxh;': 0x2500, - 'boxhD;': 0x2565, - 'boxhU;': 0x2568, - 'boxhd;': 0x252c, - 'boxhu;': 0x2534, - 'boxminus;': 0x229f, - 'boxplus;': 0x229e, - 'boxtimes;': 0x22a0, - 'boxuL;': 0x255b, - 'boxuR;': 0x2558, - 'boxul;': 0x2518, - 'boxur;': 0x2514, - 'boxv;': 0x2502, - 'boxvH;': 0x256a, - 'boxvL;': 0x2561, - 'boxvR;': 0x255e, - 'boxvh;': 0x253c, - 'boxvl;': 0x2524, - 'boxvr;': 0x251c, - 'bprime;': 0x2035, - 'breve;': 0x2d8, - brvbar: 0xa6, - 'brvbar;': 0xa6, - 'bscr;': [0xd835, 0xdcb7], - 'bsemi;': 0x204f, - 'bsim;': 0x223d, - 'bsime;': 0x22cd, - 'bsol;': 0x5c, - 'bsolb;': 0x29c5, - 'bsolhsub;': 0x27c8, - 'bull;': 0x2022, - 'bullet;': 0x2022, - 'bump;': 0x224e, - 'bumpE;': 0x2aae, - 'bumpe;': 0x224f, - 'bumpeq;': 0x224f, - 'cacute;': 0x107, - 'cap;': 0x2229, - 'capand;': 0x2a44, - 'capbrcup;': 0x2a49, - 'capcap;': 0x2a4b, - 'capcup;': 0x2a47, - 'capdot;': 0x2a40, - 'caps;': [0x2229, 0xfe00], - 'caret;': 0x2041, - 'caron;': 0x2c7, - 'ccaps;': 0x2a4d, - 'ccaron;': 0x10d, - ccedil: 0xe7, - 'ccedil;': 0xe7, - 'ccirc;': 0x109, - 'ccups;': 0x2a4c, - 'ccupssm;': 0x2a50, - 'cdot;': 0x10b, - cedil: 0xb8, - 'cedil;': 0xb8, - 'cemptyv;': 0x29b2, - cent: 0xa2, - 'cent;': 0xa2, - 'centerdot;': 0xb7, - 'cfr;': [0xd835, 0xdd20], - 'chcy;': 0x447, - 'check;': 0x2713, - 'checkmark;': 0x2713, - 'chi;': 0x3c7, - 'cir;': 0x25cb, - 'cirE;': 0x29c3, - 'circ;': 0x2c6, - 'circeq;': 0x2257, - 'circlearrowleft;': 0x21ba, - 'circlearrowright;': 0x21bb, - 'circledR;': 0xae, - 'circledS;': 0x24c8, - 'circledast;': 0x229b, - 'circledcirc;': 0x229a, - 'circleddash;': 0x229d, - 'cire;': 0x2257, - 'cirfnint;': 0x2a10, - 'cirmid;': 0x2aef, - 'cirscir;': 0x29c2, - 'clubs;': 0x2663, - 'clubsuit;': 0x2663, - 'colon;': 0x3a, - 'colone;': 0x2254, - 'coloneq;': 0x2254, - 'comma;': 0x2c, - 'commat;': 0x40, - 'comp;': 0x2201, - 'compfn;': 0x2218, - 'complement;': 0x2201, - 'complexes;': 0x2102, - 'cong;': 0x2245, - 'congdot;': 0x2a6d, - 'conint;': 0x222e, - 'copf;': [0xd835, 0xdd54], - 'coprod;': 0x2210, - copy: 0xa9, - 'copy;': 0xa9, - 'copysr;': 0x2117, - 'crarr;': 0x21b5, - 'cross;': 0x2717, - 'cscr;': [0xd835, 0xdcb8], - 'csub;': 0x2acf, - 'csube;': 0x2ad1, - 'csup;': 0x2ad0, - 'csupe;': 0x2ad2, - 'ctdot;': 0x22ef, - 'cudarrl;': 0x2938, - 'cudarrr;': 0x2935, - 'cuepr;': 0x22de, - 'cuesc;': 0x22df, - 'cularr;': 0x21b6, - 'cularrp;': 0x293d, - 'cup;': 0x222a, - 'cupbrcap;': 0x2a48, - 'cupcap;': 0x2a46, - 'cupcup;': 0x2a4a, - 'cupdot;': 0x228d, - 'cupor;': 0x2a45, - 'cups;': [0x222a, 0xfe00], - 'curarr;': 0x21b7, - 'curarrm;': 0x293c, - 'curlyeqprec;': 0x22de, - 'curlyeqsucc;': 0x22df, - 'curlyvee;': 0x22ce, - 'curlywedge;': 0x22cf, - curren: 0xa4, - 'curren;': 0xa4, - 'curvearrowleft;': 0x21b6, - 'curvearrowright;': 0x21b7, - 'cuvee;': 0x22ce, - 'cuwed;': 0x22cf, - 'cwconint;': 0x2232, - 'cwint;': 0x2231, - 'cylcty;': 0x232d, - 'dArr;': 0x21d3, - 'dHar;': 0x2965, - 'dagger;': 0x2020, - 'daleth;': 0x2138, - 'darr;': 0x2193, - 'dash;': 0x2010, - 'dashv;': 0x22a3, - 'dbkarow;': 0x290f, - 'dblac;': 0x2dd, - 'dcaron;': 0x10f, - 'dcy;': 0x434, - 'dd;': 0x2146, - 'ddagger;': 0x2021, - 'ddarr;': 0x21ca, - 'ddotseq;': 0x2a77, - deg: 0xb0, - 'deg;': 0xb0, - 'delta;': 0x3b4, - 'demptyv;': 0x29b1, - 'dfisht;': 0x297f, - 'dfr;': [0xd835, 0xdd21], - 'dharl;': 0x21c3, - 'dharr;': 0x21c2, - 'diam;': 0x22c4, - 'diamond;': 0x22c4, - 'diamondsuit;': 0x2666, - 'diams;': 0x2666, - 'die;': 0xa8, - 'digamma;': 0x3dd, - 'disin;': 0x22f2, - 'div;': 0xf7, - divide: 0xf7, - 'divide;': 0xf7, - 'divideontimes;': 0x22c7, - 'divonx;': 0x22c7, - 'djcy;': 0x452, - 'dlcorn;': 0x231e, - 'dlcrop;': 0x230d, - 'dollar;': 0x24, - 'dopf;': [0xd835, 0xdd55], - 'dot;': 0x2d9, - 'doteq;': 0x2250, - 'doteqdot;': 0x2251, - 'dotminus;': 0x2238, - 'dotplus;': 0x2214, - 'dotsquare;': 0x22a1, - 'doublebarwedge;': 0x2306, - 'downarrow;': 0x2193, - 'downdownarrows;': 0x21ca, - 'downharpoonleft;': 0x21c3, - 'downharpoonright;': 0x21c2, - 'drbkarow;': 0x2910, - 'drcorn;': 0x231f, - 'drcrop;': 0x230c, - 'dscr;': [0xd835, 0xdcb9], - 'dscy;': 0x455, - 'dsol;': 0x29f6, - 'dstrok;': 0x111, - 'dtdot;': 0x22f1, - 'dtri;': 0x25bf, - 'dtrif;': 0x25be, - 'duarr;': 0x21f5, - 'duhar;': 0x296f, - 'dwangle;': 0x29a6, - 'dzcy;': 0x45f, - 'dzigrarr;': 0x27ff, - 'eDDot;': 0x2a77, - 'eDot;': 0x2251, - eacute: 0xe9, - 'eacute;': 0xe9, - 'easter;': 0x2a6e, - 'ecaron;': 0x11b, - 'ecir;': 0x2256, - ecirc: 0xea, - 'ecirc;': 0xea, - 'ecolon;': 0x2255, - 'ecy;': 0x44d, - 'edot;': 0x117, - 'ee;': 0x2147, - 'efDot;': 0x2252, - 'efr;': [0xd835, 0xdd22], - 'eg;': 0x2a9a, - egrave: 0xe8, - 'egrave;': 0xe8, - 'egs;': 0x2a96, - 'egsdot;': 0x2a98, - 'el;': 0x2a99, - 'elinters;': 0x23e7, - 'ell;': 0x2113, - 'els;': 0x2a95, - 'elsdot;': 0x2a97, - 'emacr;': 0x113, - 'empty;': 0x2205, - 'emptyset;': 0x2205, - 'emptyv;': 0x2205, - 'emsp13;': 0x2004, - 'emsp14;': 0x2005, - 'emsp;': 0x2003, - 'eng;': 0x14b, - 'ensp;': 0x2002, - 'eogon;': 0x119, - 'eopf;': [0xd835, 0xdd56], - 'epar;': 0x22d5, - 'eparsl;': 0x29e3, - 'eplus;': 0x2a71, - 'epsi;': 0x3b5, - 'epsilon;': 0x3b5, - 'epsiv;': 0x3f5, - 'eqcirc;': 0x2256, - 'eqcolon;': 0x2255, - 'eqsim;': 0x2242, - 'eqslantgtr;': 0x2a96, - 'eqslantless;': 0x2a95, - 'equals;': 0x3d, - 'equest;': 0x225f, - 'equiv;': 0x2261, - 'equivDD;': 0x2a78, - 'eqvparsl;': 0x29e5, - 'erDot;': 0x2253, - 'erarr;': 0x2971, - 'escr;': 0x212f, - 'esdot;': 0x2250, - 'esim;': 0x2242, - 'eta;': 0x3b7, - eth: 0xf0, - 'eth;': 0xf0, - euml: 0xeb, - 'euml;': 0xeb, - 'euro;': 0x20ac, - 'excl;': 0x21, - 'exist;': 0x2203, - 'expectation;': 0x2130, - 'exponentiale;': 0x2147, - 'fallingdotseq;': 0x2252, - 'fcy;': 0x444, - 'female;': 0x2640, - 'ffilig;': 0xfb03, - 'fflig;': 0xfb00, - 'ffllig;': 0xfb04, - 'ffr;': [0xd835, 0xdd23], - 'filig;': 0xfb01, - 'fjlig;': [0x66, 0x6a], - 'flat;': 0x266d, - 'fllig;': 0xfb02, - 'fltns;': 0x25b1, - 'fnof;': 0x192, - 'fopf;': [0xd835, 0xdd57], - 'forall;': 0x2200, - 'fork;': 0x22d4, - 'forkv;': 0x2ad9, - 'fpartint;': 0x2a0d, - frac12: 0xbd, - 'frac12;': 0xbd, - 'frac13;': 0x2153, - frac14: 0xbc, - 'frac14;': 0xbc, - 'frac15;': 0x2155, - 'frac16;': 0x2159, - 'frac18;': 0x215b, - 'frac23;': 0x2154, - 'frac25;': 0x2156, - frac34: 0xbe, - 'frac34;': 0xbe, - 'frac35;': 0x2157, - 'frac38;': 0x215c, - 'frac45;': 0x2158, - 'frac56;': 0x215a, - 'frac58;': 0x215d, - 'frac78;': 0x215e, - 'frasl;': 0x2044, - 'frown;': 0x2322, - 'fscr;': [0xd835, 0xdcbb], - 'gE;': 0x2267, - 'gEl;': 0x2a8c, - 'gacute;': 0x1f5, - 'gamma;': 0x3b3, - 'gammad;': 0x3dd, - 'gap;': 0x2a86, - 'gbreve;': 0x11f, - 'gcirc;': 0x11d, - 'gcy;': 0x433, - 'gdot;': 0x121, - 'ge;': 0x2265, - 'gel;': 0x22db, - 'geq;': 0x2265, - 'geqq;': 0x2267, - 'geqslant;': 0x2a7e, - 'ges;': 0x2a7e, - 'gescc;': 0x2aa9, - 'gesdot;': 0x2a80, - 'gesdoto;': 0x2a82, - 'gesdotol;': 0x2a84, - 'gesl;': [0x22db, 0xfe00], - 'gesles;': 0x2a94, - 'gfr;': [0xd835, 0xdd24], - 'gg;': 0x226b, - 'ggg;': 0x22d9, - 'gimel;': 0x2137, - 'gjcy;': 0x453, - 'gl;': 0x2277, - 'glE;': 0x2a92, - 'gla;': 0x2aa5, - 'glj;': 0x2aa4, - 'gnE;': 0x2269, - 'gnap;': 0x2a8a, - 'gnapprox;': 0x2a8a, - 'gne;': 0x2a88, - 'gneq;': 0x2a88, - 'gneqq;': 0x2269, - 'gnsim;': 0x22e7, - 'gopf;': [0xd835, 0xdd58], - 'grave;': 0x60, - 'gscr;': 0x210a, - 'gsim;': 0x2273, - 'gsime;': 0x2a8e, - 'gsiml;': 0x2a90, - gt: 0x3e, - 'gt;': 0x3e, - 'gtcc;': 0x2aa7, - 'gtcir;': 0x2a7a, - 'gtdot;': 0x22d7, - 'gtlPar;': 0x2995, - 'gtquest;': 0x2a7c, - 'gtrapprox;': 0x2a86, - 'gtrarr;': 0x2978, - 'gtrdot;': 0x22d7, - 'gtreqless;': 0x22db, - 'gtreqqless;': 0x2a8c, - 'gtrless;': 0x2277, - 'gtrsim;': 0x2273, - 'gvertneqq;': [0x2269, 0xfe00], - 'gvnE;': [0x2269, 0xfe00], - 'hArr;': 0x21d4, - 'hairsp;': 0x200a, - 'half;': 0xbd, - 'hamilt;': 0x210b, - 'hardcy;': 0x44a, - 'harr;': 0x2194, - 'harrcir;': 0x2948, - 'harrw;': 0x21ad, - 'hbar;': 0x210f, - 'hcirc;': 0x125, - 'hearts;': 0x2665, - 'heartsuit;': 0x2665, - 'hellip;': 0x2026, - 'hercon;': 0x22b9, - 'hfr;': [0xd835, 0xdd25], - 'hksearow;': 0x2925, - 'hkswarow;': 0x2926, - 'hoarr;': 0x21ff, - 'homtht;': 0x223b, - 'hookleftarrow;': 0x21a9, - 'hookrightarrow;': 0x21aa, - 'hopf;': [0xd835, 0xdd59], - 'horbar;': 0x2015, - 'hscr;': [0xd835, 0xdcbd], - 'hslash;': 0x210f, - 'hstrok;': 0x127, - 'hybull;': 0x2043, - 'hyphen;': 0x2010, - iacute: 0xed, - 'iacute;': 0xed, - 'ic;': 0x2063, - icirc: 0xee, - 'icirc;': 0xee, - 'icy;': 0x438, - 'iecy;': 0x435, - iexcl: 0xa1, - 'iexcl;': 0xa1, - 'iff;': 0x21d4, - 'ifr;': [0xd835, 0xdd26], - igrave: 0xec, - 'igrave;': 0xec, - 'ii;': 0x2148, - 'iiiint;': 0x2a0c, - 'iiint;': 0x222d, - 'iinfin;': 0x29dc, - 'iiota;': 0x2129, - 'ijlig;': 0x133, - 'imacr;': 0x12b, - 'image;': 0x2111, - 'imagline;': 0x2110, - 'imagpart;': 0x2111, - 'imath;': 0x131, - 'imof;': 0x22b7, - 'imped;': 0x1b5, - 'in;': 0x2208, - 'incare;': 0x2105, - 'infin;': 0x221e, - 'infintie;': 0x29dd, - 'inodot;': 0x131, - 'int;': 0x222b, - 'intcal;': 0x22ba, - 'integers;': 0x2124, - 'intercal;': 0x22ba, - 'intlarhk;': 0x2a17, - 'intprod;': 0x2a3c, - 'iocy;': 0x451, - 'iogon;': 0x12f, - 'iopf;': [0xd835, 0xdd5a], - 'iota;': 0x3b9, - 'iprod;': 0x2a3c, - iquest: 0xbf, - 'iquest;': 0xbf, - 'iscr;': [0xd835, 0xdcbe], - 'isin;': 0x2208, - 'isinE;': 0x22f9, - 'isindot;': 0x22f5, - 'isins;': 0x22f4, - 'isinsv;': 0x22f3, - 'isinv;': 0x2208, - 'it;': 0x2062, - 'itilde;': 0x129, - 'iukcy;': 0x456, - iuml: 0xef, - 'iuml;': 0xef, - 'jcirc;': 0x135, - 'jcy;': 0x439, - 'jfr;': [0xd835, 0xdd27], - 'jmath;': 0x237, - 'jopf;': [0xd835, 0xdd5b], - 'jscr;': [0xd835, 0xdcbf], - 'jsercy;': 0x458, - 'jukcy;': 0x454, - 'kappa;': 0x3ba, - 'kappav;': 0x3f0, - 'kcedil;': 0x137, - 'kcy;': 0x43a, - 'kfr;': [0xd835, 0xdd28], - 'kgreen;': 0x138, - 'khcy;': 0x445, - 'kjcy;': 0x45c, - 'kopf;': [0xd835, 0xdd5c], - 'kscr;': [0xd835, 0xdcc0], - 'lAarr;': 0x21da, - 'lArr;': 0x21d0, - 'lAtail;': 0x291b, - 'lBarr;': 0x290e, - 'lE;': 0x2266, - 'lEg;': 0x2a8b, - 'lHar;': 0x2962, - 'lacute;': 0x13a, - 'laemptyv;': 0x29b4, - 'lagran;': 0x2112, - 'lambda;': 0x3bb, - 'lang;': 0x27e8, - 'langd;': 0x2991, - 'langle;': 0x27e8, - 'lap;': 0x2a85, - laquo: 0xab, - 'laquo;': 0xab, - 'larr;': 0x2190, - 'larrb;': 0x21e4, - 'larrbfs;': 0x291f, - 'larrfs;': 0x291d, - 'larrhk;': 0x21a9, - 'larrlp;': 0x21ab, - 'larrpl;': 0x2939, - 'larrsim;': 0x2973, - 'larrtl;': 0x21a2, - 'lat;': 0x2aab, - 'latail;': 0x2919, - 'late;': 0x2aad, - 'lates;': [0x2aad, 0xfe00], - 'lbarr;': 0x290c, - 'lbbrk;': 0x2772, - 'lbrace;': 0x7b, - 'lbrack;': 0x5b, - 'lbrke;': 0x298b, - 'lbrksld;': 0x298f, - 'lbrkslu;': 0x298d, - 'lcaron;': 0x13e, - 'lcedil;': 0x13c, - 'lceil;': 0x2308, - 'lcub;': 0x7b, - 'lcy;': 0x43b, - 'ldca;': 0x2936, - 'ldquo;': 0x201c, - 'ldquor;': 0x201e, - 'ldrdhar;': 0x2967, - 'ldrushar;': 0x294b, - 'ldsh;': 0x21b2, - 'le;': 0x2264, - 'leftarrow;': 0x2190, - 'leftarrowtail;': 0x21a2, - 'leftharpoondown;': 0x21bd, - 'leftharpoonup;': 0x21bc, - 'leftleftarrows;': 0x21c7, - 'leftrightarrow;': 0x2194, - 'leftrightarrows;': 0x21c6, - 'leftrightharpoons;': 0x21cb, - 'leftrightsquigarrow;': 0x21ad, - 'leftthreetimes;': 0x22cb, - 'leg;': 0x22da, - 'leq;': 0x2264, - 'leqq;': 0x2266, - 'leqslant;': 0x2a7d, - 'les;': 0x2a7d, - 'lescc;': 0x2aa8, - 'lesdot;': 0x2a7f, - 'lesdoto;': 0x2a81, - 'lesdotor;': 0x2a83, - 'lesg;': [0x22da, 0xfe00], - 'lesges;': 0x2a93, - 'lessapprox;': 0x2a85, - 'lessdot;': 0x22d6, - 'lesseqgtr;': 0x22da, - 'lesseqqgtr;': 0x2a8b, - 'lessgtr;': 0x2276, - 'lesssim;': 0x2272, - 'lfisht;': 0x297c, - 'lfloor;': 0x230a, - 'lfr;': [0xd835, 0xdd29], - 'lg;': 0x2276, - 'lgE;': 0x2a91, - 'lhard;': 0x21bd, - 'lharu;': 0x21bc, - 'lharul;': 0x296a, - 'lhblk;': 0x2584, - 'ljcy;': 0x459, - 'll;': 0x226a, - 'llarr;': 0x21c7, - 'llcorner;': 0x231e, - 'llhard;': 0x296b, - 'lltri;': 0x25fa, - 'lmidot;': 0x140, - 'lmoust;': 0x23b0, - 'lmoustache;': 0x23b0, - 'lnE;': 0x2268, - 'lnap;': 0x2a89, - 'lnapprox;': 0x2a89, - 'lne;': 0x2a87, - 'lneq;': 0x2a87, - 'lneqq;': 0x2268, - 'lnsim;': 0x22e6, - 'loang;': 0x27ec, - 'loarr;': 0x21fd, - 'lobrk;': 0x27e6, - 'longleftarrow;': 0x27f5, - 'longleftrightarrow;': 0x27f7, - 'longmapsto;': 0x27fc, - 'longrightarrow;': 0x27f6, - 'looparrowleft;': 0x21ab, - 'looparrowright;': 0x21ac, - 'lopar;': 0x2985, - 'lopf;': [0xd835, 0xdd5d], - 'loplus;': 0x2a2d, - 'lotimes;': 0x2a34, - 'lowast;': 0x2217, - 'lowbar;': 0x5f, - 'loz;': 0x25ca, - 'lozenge;': 0x25ca, - 'lozf;': 0x29eb, - 'lpar;': 0x28, - 'lparlt;': 0x2993, - 'lrarr;': 0x21c6, - 'lrcorner;': 0x231f, - 'lrhar;': 0x21cb, - 'lrhard;': 0x296d, - 'lrm;': 0x200e, - 'lrtri;': 0x22bf, - 'lsaquo;': 0x2039, - 'lscr;': [0xd835, 0xdcc1], - 'lsh;': 0x21b0, - 'lsim;': 0x2272, - 'lsime;': 0x2a8d, - 'lsimg;': 0x2a8f, - 'lsqb;': 0x5b, - 'lsquo;': 0x2018, - 'lsquor;': 0x201a, - 'lstrok;': 0x142, - lt: 0x3c, - 'lt;': 0x3c, - 'ltcc;': 0x2aa6, - 'ltcir;': 0x2a79, - 'ltdot;': 0x22d6, - 'lthree;': 0x22cb, - 'ltimes;': 0x22c9, - 'ltlarr;': 0x2976, - 'ltquest;': 0x2a7b, - 'ltrPar;': 0x2996, - 'ltri;': 0x25c3, - 'ltrie;': 0x22b4, - 'ltrif;': 0x25c2, - 'lurdshar;': 0x294a, - 'luruhar;': 0x2966, - 'lvertneqq;': [0x2268, 0xfe00], - 'lvnE;': [0x2268, 0xfe00], - 'mDDot;': 0x223a, - macr: 0xaf, - 'macr;': 0xaf, - 'male;': 0x2642, - 'malt;': 0x2720, - 'maltese;': 0x2720, - 'map;': 0x21a6, - 'mapsto;': 0x21a6, - 'mapstodown;': 0x21a7, - 'mapstoleft;': 0x21a4, - 'mapstoup;': 0x21a5, - 'marker;': 0x25ae, - 'mcomma;': 0x2a29, - 'mcy;': 0x43c, - 'mdash;': 0x2014, - 'measuredangle;': 0x2221, - 'mfr;': [0xd835, 0xdd2a], - 'mho;': 0x2127, - micro: 0xb5, - 'micro;': 0xb5, - 'mid;': 0x2223, - 'midast;': 0x2a, - 'midcir;': 0x2af0, - middot: 0xb7, - 'middot;': 0xb7, - 'minus;': 0x2212, - 'minusb;': 0x229f, - 'minusd;': 0x2238, - 'minusdu;': 0x2a2a, - 'mlcp;': 0x2adb, - 'mldr;': 0x2026, - 'mnplus;': 0x2213, - 'models;': 0x22a7, - 'mopf;': [0xd835, 0xdd5e], - 'mp;': 0x2213, - 'mscr;': [0xd835, 0xdcc2], - 'mstpos;': 0x223e, - 'mu;': 0x3bc, - 'multimap;': 0x22b8, - 'mumap;': 0x22b8, - 'nGg;': [0x22d9, 0x338], - 'nGt;': [0x226b, 0x20d2], - 'nGtv;': [0x226b, 0x338], - 'nLeftarrow;': 0x21cd, - 'nLeftrightarrow;': 0x21ce, - 'nLl;': [0x22d8, 0x338], - 'nLt;': [0x226a, 0x20d2], - 'nLtv;': [0x226a, 0x338], - 'nRightarrow;': 0x21cf, - 'nVDash;': 0x22af, - 'nVdash;': 0x22ae, - 'nabla;': 0x2207, - 'nacute;': 0x144, - 'nang;': [0x2220, 0x20d2], - 'nap;': 0x2249, - 'napE;': [0x2a70, 0x338], - 'napid;': [0x224b, 0x338], - 'napos;': 0x149, - 'napprox;': 0x2249, - 'natur;': 0x266e, - 'natural;': 0x266e, - 'naturals;': 0x2115, - nbsp: 0xa0, - 'nbsp;': 0xa0, - 'nbump;': [0x224e, 0x338], - 'nbumpe;': [0x224f, 0x338], - 'ncap;': 0x2a43, - 'ncaron;': 0x148, - 'ncedil;': 0x146, - 'ncong;': 0x2247, - 'ncongdot;': [0x2a6d, 0x338], - 'ncup;': 0x2a42, - 'ncy;': 0x43d, - 'ndash;': 0x2013, - 'ne;': 0x2260, - 'neArr;': 0x21d7, - 'nearhk;': 0x2924, - 'nearr;': 0x2197, - 'nearrow;': 0x2197, - 'nedot;': [0x2250, 0x338], - 'nequiv;': 0x2262, - 'nesear;': 0x2928, - 'nesim;': [0x2242, 0x338], - 'nexist;': 0x2204, - 'nexists;': 0x2204, - 'nfr;': [0xd835, 0xdd2b], - 'ngE;': [0x2267, 0x338], - 'nge;': 0x2271, - 'ngeq;': 0x2271, - 'ngeqq;': [0x2267, 0x338], - 'ngeqslant;': [0x2a7e, 0x338], - 'nges;': [0x2a7e, 0x338], - 'ngsim;': 0x2275, - 'ngt;': 0x226f, - 'ngtr;': 0x226f, - 'nhArr;': 0x21ce, - 'nharr;': 0x21ae, - 'nhpar;': 0x2af2, - 'ni;': 0x220b, - 'nis;': 0x22fc, - 'nisd;': 0x22fa, - 'niv;': 0x220b, - 'njcy;': 0x45a, - 'nlArr;': 0x21cd, - 'nlE;': [0x2266, 0x338], - 'nlarr;': 0x219a, - 'nldr;': 0x2025, - 'nle;': 0x2270, - 'nleftarrow;': 0x219a, - 'nleftrightarrow;': 0x21ae, - 'nleq;': 0x2270, - 'nleqq;': [0x2266, 0x338], - 'nleqslant;': [0x2a7d, 0x338], - 'nles;': [0x2a7d, 0x338], - 'nless;': 0x226e, - 'nlsim;': 0x2274, - 'nlt;': 0x226e, - 'nltri;': 0x22ea, - 'nltrie;': 0x22ec, - 'nmid;': 0x2224, - 'nopf;': [0xd835, 0xdd5f], - not: 0xac, - 'not;': 0xac, - 'notin;': 0x2209, - 'notinE;': [0x22f9, 0x338], - 'notindot;': [0x22f5, 0x338], - 'notinva;': 0x2209, - 'notinvb;': 0x22f7, - 'notinvc;': 0x22f6, - 'notni;': 0x220c, - 'notniva;': 0x220c, - 'notnivb;': 0x22fe, - 'notnivc;': 0x22fd, - 'npar;': 0x2226, - 'nparallel;': 0x2226, - 'nparsl;': [0x2afd, 0x20e5], - 'npart;': [0x2202, 0x338], - 'npolint;': 0x2a14, - 'npr;': 0x2280, - 'nprcue;': 0x22e0, - 'npre;': [0x2aaf, 0x338], - 'nprec;': 0x2280, - 'npreceq;': [0x2aaf, 0x338], - 'nrArr;': 0x21cf, - 'nrarr;': 0x219b, - 'nrarrc;': [0x2933, 0x338], - 'nrarrw;': [0x219d, 0x338], - 'nrightarrow;': 0x219b, - 'nrtri;': 0x22eb, - 'nrtrie;': 0x22ed, - 'nsc;': 0x2281, - 'nsccue;': 0x22e1, - 'nsce;': [0x2ab0, 0x338], - 'nscr;': [0xd835, 0xdcc3], - 'nshortmid;': 0x2224, - 'nshortparallel;': 0x2226, - 'nsim;': 0x2241, - 'nsime;': 0x2244, - 'nsimeq;': 0x2244, - 'nsmid;': 0x2224, - 'nspar;': 0x2226, - 'nsqsube;': 0x22e2, - 'nsqsupe;': 0x22e3, - 'nsub;': 0x2284, - 'nsubE;': [0x2ac5, 0x338], - 'nsube;': 0x2288, - 'nsubset;': [0x2282, 0x20d2], - 'nsubseteq;': 0x2288, - 'nsubseteqq;': [0x2ac5, 0x338], - 'nsucc;': 0x2281, - 'nsucceq;': [0x2ab0, 0x338], - 'nsup;': 0x2285, - 'nsupE;': [0x2ac6, 0x338], - 'nsupe;': 0x2289, - 'nsupset;': [0x2283, 0x20d2], - 'nsupseteq;': 0x2289, - 'nsupseteqq;': [0x2ac6, 0x338], - 'ntgl;': 0x2279, - ntilde: 0xf1, - 'ntilde;': 0xf1, - 'ntlg;': 0x2278, - 'ntriangleleft;': 0x22ea, - 'ntrianglelefteq;': 0x22ec, - 'ntriangleright;': 0x22eb, - 'ntrianglerighteq;': 0x22ed, - 'nu;': 0x3bd, - 'num;': 0x23, - 'numero;': 0x2116, - 'numsp;': 0x2007, - 'nvDash;': 0x22ad, - 'nvHarr;': 0x2904, - 'nvap;': [0x224d, 0x20d2], - 'nvdash;': 0x22ac, - 'nvge;': [0x2265, 0x20d2], - 'nvgt;': [0x3e, 0x20d2], - 'nvinfin;': 0x29de, - 'nvlArr;': 0x2902, - 'nvle;': [0x2264, 0x20d2], - 'nvlt;': [0x3c, 0x20d2], - 'nvltrie;': [0x22b4, 0x20d2], - 'nvrArr;': 0x2903, - 'nvrtrie;': [0x22b5, 0x20d2], - 'nvsim;': [0x223c, 0x20d2], - 'nwArr;': 0x21d6, - 'nwarhk;': 0x2923, - 'nwarr;': 0x2196, - 'nwarrow;': 0x2196, - 'nwnear;': 0x2927, - 'oS;': 0x24c8, - oacute: 0xf3, - 'oacute;': 0xf3, - 'oast;': 0x229b, - 'ocir;': 0x229a, - ocirc: 0xf4, - 'ocirc;': 0xf4, - 'ocy;': 0x43e, - 'odash;': 0x229d, - 'odblac;': 0x151, - 'odiv;': 0x2a38, - 'odot;': 0x2299, - 'odsold;': 0x29bc, - 'oelig;': 0x153, - 'ofcir;': 0x29bf, - 'ofr;': [0xd835, 0xdd2c], - 'ogon;': 0x2db, - ograve: 0xf2, - 'ograve;': 0xf2, - 'ogt;': 0x29c1, - 'ohbar;': 0x29b5, - 'ohm;': 0x3a9, - 'oint;': 0x222e, - 'olarr;': 0x21ba, - 'olcir;': 0x29be, - 'olcross;': 0x29bb, - 'oline;': 0x203e, - 'olt;': 0x29c0, - 'omacr;': 0x14d, - 'omega;': 0x3c9, - 'omicron;': 0x3bf, - 'omid;': 0x29b6, - 'ominus;': 0x2296, - 'oopf;': [0xd835, 0xdd60], - 'opar;': 0x29b7, - 'operp;': 0x29b9, - 'oplus;': 0x2295, - 'or;': 0x2228, - 'orarr;': 0x21bb, - 'ord;': 0x2a5d, - 'order;': 0x2134, - 'orderof;': 0x2134, - ordf: 0xaa, - 'ordf;': 0xaa, - ordm: 0xba, - 'ordm;': 0xba, - 'origof;': 0x22b6, - 'oror;': 0x2a56, - 'orslope;': 0x2a57, - 'orv;': 0x2a5b, - 'oscr;': 0x2134, - oslash: 0xf8, - 'oslash;': 0xf8, - 'osol;': 0x2298, - otilde: 0xf5, - 'otilde;': 0xf5, - 'otimes;': 0x2297, - 'otimesas;': 0x2a36, - ouml: 0xf6, - 'ouml;': 0xf6, - 'ovbar;': 0x233d, - 'par;': 0x2225, - para: 0xb6, - 'para;': 0xb6, - 'parallel;': 0x2225, - 'parsim;': 0x2af3, - 'parsl;': 0x2afd, - 'part;': 0x2202, - 'pcy;': 0x43f, - 'percnt;': 0x25, - 'period;': 0x2e, - 'permil;': 0x2030, - 'perp;': 0x22a5, - 'pertenk;': 0x2031, - 'pfr;': [0xd835, 0xdd2d], - 'phi;': 0x3c6, - 'phiv;': 0x3d5, - 'phmmat;': 0x2133, - 'phone;': 0x260e, - 'pi;': 0x3c0, - 'pitchfork;': 0x22d4, - 'piv;': 0x3d6, - 'planck;': 0x210f, - 'planckh;': 0x210e, - 'plankv;': 0x210f, - 'plus;': 0x2b, - 'plusacir;': 0x2a23, - 'plusb;': 0x229e, - 'pluscir;': 0x2a22, - 'plusdo;': 0x2214, - 'plusdu;': 0x2a25, - 'pluse;': 0x2a72, - plusmn: 0xb1, - 'plusmn;': 0xb1, - 'plussim;': 0x2a26, - 'plustwo;': 0x2a27, - 'pm;': 0xb1, - 'pointint;': 0x2a15, - 'popf;': [0xd835, 0xdd61], - pound: 0xa3, - 'pound;': 0xa3, - 'pr;': 0x227a, - 'prE;': 0x2ab3, - 'prap;': 0x2ab7, - 'prcue;': 0x227c, - 'pre;': 0x2aaf, - 'prec;': 0x227a, - 'precapprox;': 0x2ab7, - 'preccurlyeq;': 0x227c, - 'preceq;': 0x2aaf, - 'precnapprox;': 0x2ab9, - 'precneqq;': 0x2ab5, - 'precnsim;': 0x22e8, - 'precsim;': 0x227e, - 'prime;': 0x2032, - 'primes;': 0x2119, - 'prnE;': 0x2ab5, - 'prnap;': 0x2ab9, - 'prnsim;': 0x22e8, - 'prod;': 0x220f, - 'profalar;': 0x232e, - 'profline;': 0x2312, - 'profsurf;': 0x2313, - 'prop;': 0x221d, - 'propto;': 0x221d, - 'prsim;': 0x227e, - 'prurel;': 0x22b0, - 'pscr;': [0xd835, 0xdcc5], - 'psi;': 0x3c8, - 'puncsp;': 0x2008, - 'qfr;': [0xd835, 0xdd2e], - 'qint;': 0x2a0c, - 'qopf;': [0xd835, 0xdd62], - 'qprime;': 0x2057, - 'qscr;': [0xd835, 0xdcc6], - 'quaternions;': 0x210d, - 'quatint;': 0x2a16, - 'quest;': 0x3f, - 'questeq;': 0x225f, - quot: 0x22, - 'quot;': 0x22, - 'rAarr;': 0x21db, - 'rArr;': 0x21d2, - 'rAtail;': 0x291c, - 'rBarr;': 0x290f, - 'rHar;': 0x2964, - 'race;': [0x223d, 0x331], - 'racute;': 0x155, - 'radic;': 0x221a, - 'raemptyv;': 0x29b3, - 'rang;': 0x27e9, - 'rangd;': 0x2992, - 'range;': 0x29a5, - 'rangle;': 0x27e9, - raquo: 0xbb, - 'raquo;': 0xbb, - 'rarr;': 0x2192, - 'rarrap;': 0x2975, - 'rarrb;': 0x21e5, - 'rarrbfs;': 0x2920, - 'rarrc;': 0x2933, - 'rarrfs;': 0x291e, - 'rarrhk;': 0x21aa, - 'rarrlp;': 0x21ac, - 'rarrpl;': 0x2945, - 'rarrsim;': 0x2974, - 'rarrtl;': 0x21a3, - 'rarrw;': 0x219d, - 'ratail;': 0x291a, - 'ratio;': 0x2236, - 'rationals;': 0x211a, - 'rbarr;': 0x290d, - 'rbbrk;': 0x2773, - 'rbrace;': 0x7d, - 'rbrack;': 0x5d, - 'rbrke;': 0x298c, - 'rbrksld;': 0x298e, - 'rbrkslu;': 0x2990, - 'rcaron;': 0x159, - 'rcedil;': 0x157, - 'rceil;': 0x2309, - 'rcub;': 0x7d, - 'rcy;': 0x440, - 'rdca;': 0x2937, - 'rdldhar;': 0x2969, - 'rdquo;': 0x201d, - 'rdquor;': 0x201d, - 'rdsh;': 0x21b3, - 'real;': 0x211c, - 'realine;': 0x211b, - 'realpart;': 0x211c, - 'reals;': 0x211d, - 'rect;': 0x25ad, - reg: 0xae, - 'reg;': 0xae, - 'rfisht;': 0x297d, - 'rfloor;': 0x230b, - 'rfr;': [0xd835, 0xdd2f], - 'rhard;': 0x21c1, - 'rharu;': 0x21c0, - 'rharul;': 0x296c, - 'rho;': 0x3c1, - 'rhov;': 0x3f1, - 'rightarrow;': 0x2192, - 'rightarrowtail;': 0x21a3, - 'rightharpoondown;': 0x21c1, - 'rightharpoonup;': 0x21c0, - 'rightleftarrows;': 0x21c4, - 'rightleftharpoons;': 0x21cc, - 'rightrightarrows;': 0x21c9, - 'rightsquigarrow;': 0x219d, - 'rightthreetimes;': 0x22cc, - 'ring;': 0x2da, - 'risingdotseq;': 0x2253, - 'rlarr;': 0x21c4, - 'rlhar;': 0x21cc, - 'rlm;': 0x200f, - 'rmoust;': 0x23b1, - 'rmoustache;': 0x23b1, - 'rnmid;': 0x2aee, - 'roang;': 0x27ed, - 'roarr;': 0x21fe, - 'robrk;': 0x27e7, - 'ropar;': 0x2986, - 'ropf;': [0xd835, 0xdd63], - 'roplus;': 0x2a2e, - 'rotimes;': 0x2a35, - 'rpar;': 0x29, - 'rpargt;': 0x2994, - 'rppolint;': 0x2a12, - 'rrarr;': 0x21c9, - 'rsaquo;': 0x203a, - 'rscr;': [0xd835, 0xdcc7], - 'rsh;': 0x21b1, - 'rsqb;': 0x5d, - 'rsquo;': 0x2019, - 'rsquor;': 0x2019, - 'rthree;': 0x22cc, - 'rtimes;': 0x22ca, - 'rtri;': 0x25b9, - 'rtrie;': 0x22b5, - 'rtrif;': 0x25b8, - 'rtriltri;': 0x29ce, - 'ruluhar;': 0x2968, - 'rx;': 0x211e, - 'sacute;': 0x15b, - 'sbquo;': 0x201a, - 'sc;': 0x227b, - 'scE;': 0x2ab4, - 'scap;': 0x2ab8, - 'scaron;': 0x161, - 'sccue;': 0x227d, - 'sce;': 0x2ab0, - 'scedil;': 0x15f, - 'scirc;': 0x15d, - 'scnE;': 0x2ab6, - 'scnap;': 0x2aba, - 'scnsim;': 0x22e9, - 'scpolint;': 0x2a13, - 'scsim;': 0x227f, - 'scy;': 0x441, - 'sdot;': 0x22c5, - 'sdotb;': 0x22a1, - 'sdote;': 0x2a66, - 'seArr;': 0x21d8, - 'searhk;': 0x2925, - 'searr;': 0x2198, - 'searrow;': 0x2198, - sect: 0xa7, - 'sect;': 0xa7, - 'semi;': 0x3b, - 'seswar;': 0x2929, - 'setminus;': 0x2216, - 'setmn;': 0x2216, - 'sext;': 0x2736, - 'sfr;': [0xd835, 0xdd30], - 'sfrown;': 0x2322, - 'sharp;': 0x266f, - 'shchcy;': 0x449, - 'shcy;': 0x448, - 'shortmid;': 0x2223, - 'shortparallel;': 0x2225, - shy: 0xad, - 'shy;': 0xad, - 'sigma;': 0x3c3, - 'sigmaf;': 0x3c2, - 'sigmav;': 0x3c2, - 'sim;': 0x223c, - 'simdot;': 0x2a6a, - 'sime;': 0x2243, - 'simeq;': 0x2243, - 'simg;': 0x2a9e, - 'simgE;': 0x2aa0, - 'siml;': 0x2a9d, - 'simlE;': 0x2a9f, - 'simne;': 0x2246, - 'simplus;': 0x2a24, - 'simrarr;': 0x2972, - 'slarr;': 0x2190, - 'smallsetminus;': 0x2216, - 'smashp;': 0x2a33, - 'smeparsl;': 0x29e4, - 'smid;': 0x2223, - 'smile;': 0x2323, - 'smt;': 0x2aaa, - 'smte;': 0x2aac, - 'smtes;': [0x2aac, 0xfe00], - 'softcy;': 0x44c, - 'sol;': 0x2f, - 'solb;': 0x29c4, - 'solbar;': 0x233f, - 'sopf;': [0xd835, 0xdd64], - 'spades;': 0x2660, - 'spadesuit;': 0x2660, - 'spar;': 0x2225, - 'sqcap;': 0x2293, - 'sqcaps;': [0x2293, 0xfe00], - 'sqcup;': 0x2294, - 'sqcups;': [0x2294, 0xfe00], - 'sqsub;': 0x228f, - 'sqsube;': 0x2291, - 'sqsubset;': 0x228f, - 'sqsubseteq;': 0x2291, - 'sqsup;': 0x2290, - 'sqsupe;': 0x2292, - 'sqsupset;': 0x2290, - 'sqsupseteq;': 0x2292, - 'squ;': 0x25a1, - 'square;': 0x25a1, - 'squarf;': 0x25aa, - 'squf;': 0x25aa, - 'srarr;': 0x2192, - 'sscr;': [0xd835, 0xdcc8], - 'ssetmn;': 0x2216, - 'ssmile;': 0x2323, - 'sstarf;': 0x22c6, - 'star;': 0x2606, - 'starf;': 0x2605, - 'straightepsilon;': 0x3f5, - 'straightphi;': 0x3d5, - 'strns;': 0xaf, - 'sub;': 0x2282, - 'subE;': 0x2ac5, - 'subdot;': 0x2abd, - 'sube;': 0x2286, - 'subedot;': 0x2ac3, - 'submult;': 0x2ac1, - 'subnE;': 0x2acb, - 'subne;': 0x228a, - 'subplus;': 0x2abf, - 'subrarr;': 0x2979, - 'subset;': 0x2282, - 'subseteq;': 0x2286, - 'subseteqq;': 0x2ac5, - 'subsetneq;': 0x228a, - 'subsetneqq;': 0x2acb, - 'subsim;': 0x2ac7, - 'subsub;': 0x2ad5, - 'subsup;': 0x2ad3, - 'succ;': 0x227b, - 'succapprox;': 0x2ab8, - 'succcurlyeq;': 0x227d, - 'succeq;': 0x2ab0, - 'succnapprox;': 0x2aba, - 'succneqq;': 0x2ab6, - 'succnsim;': 0x22e9, - 'succsim;': 0x227f, - 'sum;': 0x2211, - 'sung;': 0x266a, - sup1: 0xb9, - 'sup1;': 0xb9, - sup2: 0xb2, - 'sup2;': 0xb2, - sup3: 0xb3, - 'sup3;': 0xb3, - 'sup;': 0x2283, - 'supE;': 0x2ac6, - 'supdot;': 0x2abe, - 'supdsub;': 0x2ad8, - 'supe;': 0x2287, - 'supedot;': 0x2ac4, - 'suphsol;': 0x27c9, - 'suphsub;': 0x2ad7, - 'suplarr;': 0x297b, - 'supmult;': 0x2ac2, - 'supnE;': 0x2acc, - 'supne;': 0x228b, - 'supplus;': 0x2ac0, - 'supset;': 0x2283, - 'supseteq;': 0x2287, - 'supseteqq;': 0x2ac6, - 'supsetneq;': 0x228b, - 'supsetneqq;': 0x2acc, - 'supsim;': 0x2ac8, - 'supsub;': 0x2ad4, - 'supsup;': 0x2ad6, - 'swArr;': 0x21d9, - 'swarhk;': 0x2926, - 'swarr;': 0x2199, - 'swarrow;': 0x2199, - 'swnwar;': 0x292a, - szlig: 0xdf, - 'szlig;': 0xdf, - 'target;': 0x2316, - 'tau;': 0x3c4, - 'tbrk;': 0x23b4, - 'tcaron;': 0x165, - 'tcedil;': 0x163, - 'tcy;': 0x442, - 'tdot;': 0x20db, - 'telrec;': 0x2315, - 'tfr;': [0xd835, 0xdd31], - 'there4;': 0x2234, - 'therefore;': 0x2234, - 'theta;': 0x3b8, - 'thetasym;': 0x3d1, - 'thetav;': 0x3d1, - 'thickapprox;': 0x2248, - 'thicksim;': 0x223c, - 'thinsp;': 0x2009, - 'thkap;': 0x2248, - 'thksim;': 0x223c, - thorn: 0xfe, - 'thorn;': 0xfe, - 'tilde;': 0x2dc, - times: 0xd7, - 'times;': 0xd7, - 'timesb;': 0x22a0, - 'timesbar;': 0x2a31, - 'timesd;': 0x2a30, - 'tint;': 0x222d, - 'toea;': 0x2928, - 'top;': 0x22a4, - 'topbot;': 0x2336, - 'topcir;': 0x2af1, - 'topf;': [0xd835, 0xdd65], - 'topfork;': 0x2ada, - 'tosa;': 0x2929, - 'tprime;': 0x2034, - 'trade;': 0x2122, - 'triangle;': 0x25b5, - 'triangledown;': 0x25bf, - 'triangleleft;': 0x25c3, - 'trianglelefteq;': 0x22b4, - 'triangleq;': 0x225c, - 'triangleright;': 0x25b9, - 'trianglerighteq;': 0x22b5, - 'tridot;': 0x25ec, - 'trie;': 0x225c, - 'triminus;': 0x2a3a, - 'triplus;': 0x2a39, - 'trisb;': 0x29cd, - 'tritime;': 0x2a3b, - 'trpezium;': 0x23e2, - 'tscr;': [0xd835, 0xdcc9], - 'tscy;': 0x446, - 'tshcy;': 0x45b, - 'tstrok;': 0x167, - 'twixt;': 0x226c, - 'twoheadleftarrow;': 0x219e, - 'twoheadrightarrow;': 0x21a0, - 'uArr;': 0x21d1, - 'uHar;': 0x2963, - uacute: 0xfa, - 'uacute;': 0xfa, - 'uarr;': 0x2191, - 'ubrcy;': 0x45e, - 'ubreve;': 0x16d, - ucirc: 0xfb, - 'ucirc;': 0xfb, - 'ucy;': 0x443, - 'udarr;': 0x21c5, - 'udblac;': 0x171, - 'udhar;': 0x296e, - 'ufisht;': 0x297e, - 'ufr;': [0xd835, 0xdd32], - ugrave: 0xf9, - 'ugrave;': 0xf9, - 'uharl;': 0x21bf, - 'uharr;': 0x21be, - 'uhblk;': 0x2580, - 'ulcorn;': 0x231c, - 'ulcorner;': 0x231c, - 'ulcrop;': 0x230f, - 'ultri;': 0x25f8, - 'umacr;': 0x16b, - uml: 0xa8, - 'uml;': 0xa8, - 'uogon;': 0x173, - 'uopf;': [0xd835, 0xdd66], - 'uparrow;': 0x2191, - 'updownarrow;': 0x2195, - 'upharpoonleft;': 0x21bf, - 'upharpoonright;': 0x21be, - 'uplus;': 0x228e, - 'upsi;': 0x3c5, - 'upsih;': 0x3d2, - 'upsilon;': 0x3c5, - 'upuparrows;': 0x21c8, - 'urcorn;': 0x231d, - 'urcorner;': 0x231d, - 'urcrop;': 0x230e, - 'uring;': 0x16f, - 'urtri;': 0x25f9, - 'uscr;': [0xd835, 0xdcca], - 'utdot;': 0x22f0, - 'utilde;': 0x169, - 'utri;': 0x25b5, - 'utrif;': 0x25b4, - 'uuarr;': 0x21c8, - uuml: 0xfc, - 'uuml;': 0xfc, - 'uwangle;': 0x29a7, - 'vArr;': 0x21d5, - 'vBar;': 0x2ae8, - 'vBarv;': 0x2ae9, - 'vDash;': 0x22a8, - 'vangrt;': 0x299c, - 'varepsilon;': 0x3f5, - 'varkappa;': 0x3f0, - 'varnothing;': 0x2205, - 'varphi;': 0x3d5, - 'varpi;': 0x3d6, - 'varpropto;': 0x221d, - 'varr;': 0x2195, - 'varrho;': 0x3f1, - 'varsigma;': 0x3c2, - 'varsubsetneq;': [0x228a, 0xfe00], - 'varsubsetneqq;': [0x2acb, 0xfe00], - 'varsupsetneq;': [0x228b, 0xfe00], - 'varsupsetneqq;': [0x2acc, 0xfe00], - 'vartheta;': 0x3d1, - 'vartriangleleft;': 0x22b2, - 'vartriangleright;': 0x22b3, - 'vcy;': 0x432, - 'vdash;': 0x22a2, - 'vee;': 0x2228, - 'veebar;': 0x22bb, - 'veeeq;': 0x225a, - 'vellip;': 0x22ee, - 'verbar;': 0x7c, - 'vert;': 0x7c, - 'vfr;': [0xd835, 0xdd33], - 'vltri;': 0x22b2, - 'vnsub;': [0x2282, 0x20d2], - 'vnsup;': [0x2283, 0x20d2], - 'vopf;': [0xd835, 0xdd67], - 'vprop;': 0x221d, - 'vrtri;': 0x22b3, - 'vscr;': [0xd835, 0xdccb], - 'vsubnE;': [0x2acb, 0xfe00], - 'vsubne;': [0x228a, 0xfe00], - 'vsupnE;': [0x2acc, 0xfe00], - 'vsupne;': [0x228b, 0xfe00], - 'vzigzag;': 0x299a, - 'wcirc;': 0x175, - 'wedbar;': 0x2a5f, - 'wedge;': 0x2227, - 'wedgeq;': 0x2259, - 'weierp;': 0x2118, - 'wfr;': [0xd835, 0xdd34], - 'wopf;': [0xd835, 0xdd68], - 'wp;': 0x2118, - 'wr;': 0x2240, - 'wreath;': 0x2240, - 'wscr;': [0xd835, 0xdccc], - 'xcap;': 0x22c2, - 'xcirc;': 0x25ef, - 'xcup;': 0x22c3, - 'xdtri;': 0x25bd, - 'xfr;': [0xd835, 0xdd35], - 'xhArr;': 0x27fa, - 'xharr;': 0x27f7, - 'xi;': 0x3be, - 'xlArr;': 0x27f8, - 'xlarr;': 0x27f5, - 'xmap;': 0x27fc, - 'xnis;': 0x22fb, - 'xodot;': 0x2a00, - 'xopf;': [0xd835, 0xdd69], - 'xoplus;': 0x2a01, - 'xotime;': 0x2a02, - 'xrArr;': 0x27f9, - 'xrarr;': 0x27f6, - 'xscr;': [0xd835, 0xdccd], - 'xsqcup;': 0x2a06, - 'xuplus;': 0x2a04, - 'xutri;': 0x25b3, - 'xvee;': 0x22c1, - 'xwedge;': 0x22c0, - yacute: 0xfd, - 'yacute;': 0xfd, - 'yacy;': 0x44f, - 'ycirc;': 0x177, - 'ycy;': 0x44b, - yen: 0xa5, - 'yen;': 0xa5, - 'yfr;': [0xd835, 0xdd36], - 'yicy;': 0x457, - 'yopf;': [0xd835, 0xdd6a], - 'yscr;': [0xd835, 0xdcce], - 'yucy;': 0x44e, - yuml: 0xff, - 'yuml;': 0xff, - 'zacute;': 0x17a, - 'zcaron;': 0x17e, - 'zcy;': 0x437, - 'zdot;': 0x17c, - 'zeetrf;': 0x2128, - 'zeta;': 0x3b6, - 'zfr;': [0xd835, 0xdd37], - 'zhcy;': 0x436, - 'zigrarr;': 0x21dd, - 'zopf;': [0xd835, 0xdd6b], - 'zscr;': [0xd835, 0xdccf], - 'zwj;': 0x200d, - 'zwnj;': 0x200c, -}; -/* - * This regexp is generated with test/tools/update-entities.js - * It will always match at least one character -- but note that there - * are no entities whose names are a single character long. - */ -var NAMEDCHARREF = - /(A(?:Elig;?|MP;?|acute;?|breve;|c(?:irc;?|y;)|fr;|grave;?|lpha;|macr;|nd;|o(?:gon;|pf;)|pplyFunction;|ring;?|s(?:cr;|sign;)|tilde;?|uml;?)|B(?:a(?:ckslash;|r(?:v;|wed;))|cy;|e(?:cause;|rnoullis;|ta;)|fr;|opf;|reve;|scr;|umpeq;)|C(?:Hcy;|OPY;?|a(?:cute;|p(?:;|italDifferentialD;)|yleys;)|c(?:aron;|edil;?|irc;|onint;)|dot;|e(?:dilla;|nterDot;)|fr;|hi;|ircle(?:Dot;|Minus;|Plus;|Times;)|lo(?:ckwiseContourIntegral;|seCurly(?:DoubleQuote;|Quote;))|o(?:lon(?:;|e;)|n(?:gruent;|int;|tourIntegral;)|p(?:f;|roduct;)|unterClockwiseContourIntegral;)|ross;|scr;|up(?:;|Cap;))|D(?:D(?:;|otrahd;)|Jcy;|Scy;|Zcy;|a(?:gger;|rr;|shv;)|c(?:aron;|y;)|el(?:;|ta;)|fr;|i(?:a(?:critical(?:Acute;|Do(?:t;|ubleAcute;)|Grave;|Tilde;)|mond;)|fferentialD;)|o(?:pf;|t(?:;|Dot;|Equal;)|uble(?:ContourIntegral;|Do(?:t;|wnArrow;)|L(?:eft(?:Arrow;|RightArrow;|Tee;)|ong(?:Left(?:Arrow;|RightArrow;)|RightArrow;))|Right(?:Arrow;|Tee;)|Up(?:Arrow;|DownArrow;)|VerticalBar;)|wn(?:Arrow(?:;|Bar;|UpArrow;)|Breve;|Left(?:RightVector;|TeeVector;|Vector(?:;|Bar;))|Right(?:TeeVector;|Vector(?:;|Bar;))|Tee(?:;|Arrow;)|arrow;))|s(?:cr;|trok;))|E(?:NG;|TH;?|acute;?|c(?:aron;|irc;?|y;)|dot;|fr;|grave;?|lement;|m(?:acr;|pty(?:SmallSquare;|VerySmallSquare;))|o(?:gon;|pf;)|psilon;|qu(?:al(?:;|Tilde;)|ilibrium;)|s(?:cr;|im;)|ta;|uml;?|x(?:ists;|ponentialE;))|F(?:cy;|fr;|illed(?:SmallSquare;|VerySmallSquare;)|o(?:pf;|rAll;|uriertrf;)|scr;)|G(?:Jcy;|T;?|amma(?:;|d;)|breve;|c(?:edil;|irc;|y;)|dot;|fr;|g;|opf;|reater(?:Equal(?:;|Less;)|FullEqual;|Greater;|Less;|SlantEqual;|Tilde;)|scr;|t;)|H(?:ARDcy;|a(?:cek;|t;)|circ;|fr;|ilbertSpace;|o(?:pf;|rizontalLine;)|s(?:cr;|trok;)|ump(?:DownHump;|Equal;))|I(?:Ecy;|Jlig;|Ocy;|acute;?|c(?:irc;?|y;)|dot;|fr;|grave;?|m(?:;|a(?:cr;|ginaryI;)|plies;)|n(?:t(?:;|e(?:gral;|rsection;))|visible(?:Comma;|Times;))|o(?:gon;|pf;|ta;)|scr;|tilde;|u(?:kcy;|ml;?))|J(?:c(?:irc;|y;)|fr;|opf;|s(?:cr;|ercy;)|ukcy;)|K(?:Hcy;|Jcy;|appa;|c(?:edil;|y;)|fr;|opf;|scr;)|L(?:Jcy;|T;?|a(?:cute;|mbda;|ng;|placetrf;|rr;)|c(?:aron;|edil;|y;)|e(?:ft(?:A(?:ngleBracket;|rrow(?:;|Bar;|RightArrow;))|Ceiling;|Do(?:ubleBracket;|wn(?:TeeVector;|Vector(?:;|Bar;)))|Floor;|Right(?:Arrow;|Vector;)|T(?:ee(?:;|Arrow;|Vector;)|riangle(?:;|Bar;|Equal;))|Up(?:DownVector;|TeeVector;|Vector(?:;|Bar;))|Vector(?:;|Bar;)|arrow;|rightarrow;)|ss(?:EqualGreater;|FullEqual;|Greater;|Less;|SlantEqual;|Tilde;))|fr;|l(?:;|eftarrow;)|midot;|o(?:ng(?:Left(?:Arrow;|RightArrow;)|RightArrow;|left(?:arrow;|rightarrow;)|rightarrow;)|pf;|wer(?:LeftArrow;|RightArrow;))|s(?:cr;|h;|trok;)|t;)|M(?:ap;|cy;|e(?:diumSpace;|llintrf;)|fr;|inusPlus;|opf;|scr;|u;)|N(?:Jcy;|acute;|c(?:aron;|edil;|y;)|e(?:gative(?:MediumSpace;|Thi(?:ckSpace;|nSpace;)|VeryThinSpace;)|sted(?:GreaterGreater;|LessLess;)|wLine;)|fr;|o(?:Break;|nBreakingSpace;|pf;|t(?:;|C(?:ongruent;|upCap;)|DoubleVerticalBar;|E(?:lement;|qual(?:;|Tilde;)|xists;)|Greater(?:;|Equal;|FullEqual;|Greater;|Less;|SlantEqual;|Tilde;)|Hump(?:DownHump;|Equal;)|Le(?:ftTriangle(?:;|Bar;|Equal;)|ss(?:;|Equal;|Greater;|Less;|SlantEqual;|Tilde;))|Nested(?:GreaterGreater;|LessLess;)|Precedes(?:;|Equal;|SlantEqual;)|R(?:everseElement;|ightTriangle(?:;|Bar;|Equal;))|S(?:quareSu(?:bset(?:;|Equal;)|perset(?:;|Equal;))|u(?:bset(?:;|Equal;)|cceeds(?:;|Equal;|SlantEqual;|Tilde;)|perset(?:;|Equal;)))|Tilde(?:;|Equal;|FullEqual;|Tilde;)|VerticalBar;))|scr;|tilde;?|u;)|O(?:Elig;|acute;?|c(?:irc;?|y;)|dblac;|fr;|grave;?|m(?:acr;|ega;|icron;)|opf;|penCurly(?:DoubleQuote;|Quote;)|r;|s(?:cr;|lash;?)|ti(?:lde;?|mes;)|uml;?|ver(?:B(?:ar;|rac(?:e;|ket;))|Parenthesis;))|P(?:artialD;|cy;|fr;|hi;|i;|lusMinus;|o(?:incareplane;|pf;)|r(?:;|ecedes(?:;|Equal;|SlantEqual;|Tilde;)|ime;|o(?:duct;|portion(?:;|al;)))|s(?:cr;|i;))|Q(?:UOT;?|fr;|opf;|scr;)|R(?:Barr;|EG;?|a(?:cute;|ng;|rr(?:;|tl;))|c(?:aron;|edil;|y;)|e(?:;|verse(?:E(?:lement;|quilibrium;)|UpEquilibrium;))|fr;|ho;|ight(?:A(?:ngleBracket;|rrow(?:;|Bar;|LeftArrow;))|Ceiling;|Do(?:ubleBracket;|wn(?:TeeVector;|Vector(?:;|Bar;)))|Floor;|T(?:ee(?:;|Arrow;|Vector;)|riangle(?:;|Bar;|Equal;))|Up(?:DownVector;|TeeVector;|Vector(?:;|Bar;))|Vector(?:;|Bar;)|arrow;)|o(?:pf;|undImplies;)|rightarrow;|s(?:cr;|h;)|uleDelayed;)|S(?:H(?:CHcy;|cy;)|OFTcy;|acute;|c(?:;|aron;|edil;|irc;|y;)|fr;|hort(?:DownArrow;|LeftArrow;|RightArrow;|UpArrow;)|igma;|mallCircle;|opf;|q(?:rt;|uare(?:;|Intersection;|Su(?:bset(?:;|Equal;)|perset(?:;|Equal;))|Union;))|scr;|tar;|u(?:b(?:;|set(?:;|Equal;))|c(?:ceeds(?:;|Equal;|SlantEqual;|Tilde;)|hThat;)|m;|p(?:;|erset(?:;|Equal;)|set;)))|T(?:HORN;?|RADE;|S(?:Hcy;|cy;)|a(?:b;|u;)|c(?:aron;|edil;|y;)|fr;|h(?:e(?:refore;|ta;)|i(?:ckSpace;|nSpace;))|ilde(?:;|Equal;|FullEqual;|Tilde;)|opf;|ripleDot;|s(?:cr;|trok;))|U(?:a(?:cute;?|rr(?:;|ocir;))|br(?:cy;|eve;)|c(?:irc;?|y;)|dblac;|fr;|grave;?|macr;|n(?:der(?:B(?:ar;|rac(?:e;|ket;))|Parenthesis;)|ion(?:;|Plus;))|o(?:gon;|pf;)|p(?:Arrow(?:;|Bar;|DownArrow;)|DownArrow;|Equilibrium;|Tee(?:;|Arrow;)|arrow;|downarrow;|per(?:LeftArrow;|RightArrow;)|si(?:;|lon;))|ring;|scr;|tilde;|uml;?)|V(?:Dash;|bar;|cy;|dash(?:;|l;)|e(?:e;|r(?:bar;|t(?:;|ical(?:Bar;|Line;|Separator;|Tilde;))|yThinSpace;))|fr;|opf;|scr;|vdash;)|W(?:circ;|edge;|fr;|opf;|scr;)|X(?:fr;|i;|opf;|scr;)|Y(?:Acy;|Icy;|Ucy;|acute;?|c(?:irc;|y;)|fr;|opf;|scr;|uml;)|Z(?:Hcy;|acute;|c(?:aron;|y;)|dot;|e(?:roWidthSpace;|ta;)|fr;|opf;|scr;)|a(?:acute;?|breve;|c(?:;|E;|d;|irc;?|ute;?|y;)|elig;?|f(?:;|r;)|grave;?|l(?:e(?:fsym;|ph;)|pha;)|m(?:a(?:cr;|lg;)|p;?)|n(?:d(?:;|and;|d;|slope;|v;)|g(?:;|e;|le;|msd(?:;|a(?:a;|b;|c;|d;|e;|f;|g;|h;))|rt(?:;|vb(?:;|d;))|s(?:ph;|t;)|zarr;))|o(?:gon;|pf;)|p(?:;|E;|acir;|e;|id;|os;|prox(?:;|eq;))|ring;?|s(?:cr;|t;|ymp(?:;|eq;))|tilde;?|uml;?|w(?:conint;|int;))|b(?:Not;|a(?:ck(?:cong;|epsilon;|prime;|sim(?:;|eq;))|r(?:vee;|wed(?:;|ge;)))|brk(?:;|tbrk;)|c(?:ong;|y;)|dquo;|e(?:caus(?:;|e;)|mptyv;|psi;|rnou;|t(?:a;|h;|ween;))|fr;|ig(?:c(?:ap;|irc;|up;)|o(?:dot;|plus;|times;)|s(?:qcup;|tar;)|triangle(?:down;|up;)|uplus;|vee;|wedge;)|karow;|l(?:a(?:ck(?:lozenge;|square;|triangle(?:;|down;|left;|right;))|nk;)|k(?:1(?:2;|4;)|34;)|ock;)|n(?:e(?:;|quiv;)|ot;)|o(?:pf;|t(?:;|tom;)|wtie;|x(?:D(?:L;|R;|l;|r;)|H(?:;|D;|U;|d;|u;)|U(?:L;|R;|l;|r;)|V(?:;|H;|L;|R;|h;|l;|r;)|box;|d(?:L;|R;|l;|r;)|h(?:;|D;|U;|d;|u;)|minus;|plus;|times;|u(?:L;|R;|l;|r;)|v(?:;|H;|L;|R;|h;|l;|r;)))|prime;|r(?:eve;|vbar;?)|s(?:cr;|emi;|im(?:;|e;)|ol(?:;|b;|hsub;))|u(?:ll(?:;|et;)|mp(?:;|E;|e(?:;|q;))))|c(?:a(?:cute;|p(?:;|and;|brcup;|c(?:ap;|up;)|dot;|s;)|r(?:et;|on;))|c(?:a(?:ps;|ron;)|edil;?|irc;|ups(?:;|sm;))|dot;|e(?:dil;?|mptyv;|nt(?:;|erdot;|))|fr;|h(?:cy;|eck(?:;|mark;)|i;)|ir(?:;|E;|c(?:;|eq;|le(?:arrow(?:left;|right;)|d(?:R;|S;|ast;|circ;|dash;)))|e;|fnint;|mid;|scir;)|lubs(?:;|uit;)|o(?:lon(?:;|e(?:;|q;))|m(?:ma(?:;|t;)|p(?:;|fn;|le(?:ment;|xes;)))|n(?:g(?:;|dot;)|int;)|p(?:f;|rod;|y(?:;|sr;|)))|r(?:arr;|oss;)|s(?:cr;|u(?:b(?:;|e;)|p(?:;|e;)))|tdot;|u(?:darr(?:l;|r;)|e(?:pr;|sc;)|larr(?:;|p;)|p(?:;|brcap;|c(?:ap;|up;)|dot;|or;|s;)|r(?:arr(?:;|m;)|ly(?:eq(?:prec;|succ;)|vee;|wedge;)|ren;?|vearrow(?:left;|right;))|vee;|wed;)|w(?:conint;|int;)|ylcty;)|d(?:Arr;|Har;|a(?:gger;|leth;|rr;|sh(?:;|v;))|b(?:karow;|lac;)|c(?:aron;|y;)|d(?:;|a(?:gger;|rr;)|otseq;)|e(?:g;?|lta;|mptyv;)|f(?:isht;|r;)|har(?:l;|r;)|i(?:am(?:;|ond(?:;|suit;)|s;)|e;|gamma;|sin;|v(?:;|ide(?:;|ontimes;|)|onx;))|jcy;|lc(?:orn;|rop;)|o(?:llar;|pf;|t(?:;|eq(?:;|dot;)|minus;|plus;|square;)|ublebarwedge;|wn(?:arrow;|downarrows;|harpoon(?:left;|right;)))|r(?:bkarow;|c(?:orn;|rop;))|s(?:c(?:r;|y;)|ol;|trok;)|t(?:dot;|ri(?:;|f;))|u(?:arr;|har;)|wangle;|z(?:cy;|igrarr;))|e(?:D(?:Dot;|ot;)|a(?:cute;?|ster;)|c(?:aron;|ir(?:;|c;?)|olon;|y;)|dot;|e;|f(?:Dot;|r;)|g(?:;|rave;?|s(?:;|dot;))|l(?:;|inters;|l;|s(?:;|dot;))|m(?:acr;|pty(?:;|set;|v;)|sp(?:1(?:3;|4;)|;))|n(?:g;|sp;)|o(?:gon;|pf;)|p(?:ar(?:;|sl;)|lus;|si(?:;|lon;|v;))|q(?:c(?:irc;|olon;)|s(?:im;|lant(?:gtr;|less;))|u(?:als;|est;|iv(?:;|DD;))|vparsl;)|r(?:Dot;|arr;)|s(?:cr;|dot;|im;)|t(?:a;|h;?)|u(?:ml;?|ro;)|x(?:cl;|ist;|p(?:ectation;|onentiale;)))|f(?:allingdotseq;|cy;|emale;|f(?:ilig;|l(?:ig;|lig;)|r;)|ilig;|jlig;|l(?:at;|lig;|tns;)|nof;|o(?:pf;|r(?:all;|k(?:;|v;)))|partint;|r(?:a(?:c(?:1(?:2;?|3;|4;?|5;|6;|8;)|2(?:3;|5;)|3(?:4;?|5;|8;)|45;|5(?:6;|8;)|78;)|sl;)|own;)|scr;)|g(?:E(?:;|l;)|a(?:cute;|mma(?:;|d;)|p;)|breve;|c(?:irc;|y;)|dot;|e(?:;|l;|q(?:;|q;|slant;)|s(?:;|cc;|dot(?:;|o(?:;|l;))|l(?:;|es;)))|fr;|g(?:;|g;)|imel;|jcy;|l(?:;|E;|a;|j;)|n(?:E;|ap(?:;|prox;)|e(?:;|q(?:;|q;))|sim;)|opf;|rave;|s(?:cr;|im(?:;|e;|l;))|t(?:;|c(?:c;|ir;)|dot;|lPar;|quest;|r(?:a(?:pprox;|rr;)|dot;|eq(?:less;|qless;)|less;|sim;)|)|v(?:ertneqq;|nE;))|h(?:Arr;|a(?:irsp;|lf;|milt;|r(?:dcy;|r(?:;|cir;|w;)))|bar;|circ;|e(?:arts(?:;|uit;)|llip;|rcon;)|fr;|ks(?:earow;|warow;)|o(?:arr;|mtht;|ok(?:leftarrow;|rightarrow;)|pf;|rbar;)|s(?:cr;|lash;|trok;)|y(?:bull;|phen;))|i(?:acute;?|c(?:;|irc;?|y;)|e(?:cy;|xcl;?)|f(?:f;|r;)|grave;?|i(?:;|i(?:int;|nt;)|nfin;|ota;)|jlig;|m(?:a(?:cr;|g(?:e;|line;|part;)|th;)|of;|ped;)|n(?:;|care;|fin(?:;|tie;)|odot;|t(?:;|cal;|e(?:gers;|rcal;)|larhk;|prod;))|o(?:cy;|gon;|pf;|ta;)|prod;|quest;?|s(?:cr;|in(?:;|E;|dot;|s(?:;|v;)|v;))|t(?:;|ilde;)|u(?:kcy;|ml;?))|j(?:c(?:irc;|y;)|fr;|math;|opf;|s(?:cr;|ercy;)|ukcy;)|k(?:appa(?:;|v;)|c(?:edil;|y;)|fr;|green;|hcy;|jcy;|opf;|scr;)|l(?:A(?:arr;|rr;|tail;)|Barr;|E(?:;|g;)|Har;|a(?:cute;|emptyv;|gran;|mbda;|ng(?:;|d;|le;)|p;|quo;?|rr(?:;|b(?:;|fs;)|fs;|hk;|lp;|pl;|sim;|tl;)|t(?:;|ail;|e(?:;|s;)))|b(?:arr;|brk;|r(?:ac(?:e;|k;)|k(?:e;|sl(?:d;|u;))))|c(?:aron;|e(?:dil;|il;)|ub;|y;)|d(?:ca;|quo(?:;|r;)|r(?:dhar;|ushar;)|sh;)|e(?:;|ft(?:arrow(?:;|tail;)|harpoon(?:down;|up;)|leftarrows;|right(?:arrow(?:;|s;)|harpoons;|squigarrow;)|threetimes;)|g;|q(?:;|q;|slant;)|s(?:;|cc;|dot(?:;|o(?:;|r;))|g(?:;|es;)|s(?:approx;|dot;|eq(?:gtr;|qgtr;)|gtr;|sim;)))|f(?:isht;|loor;|r;)|g(?:;|E;)|h(?:ar(?:d;|u(?:;|l;))|blk;)|jcy;|l(?:;|arr;|corner;|hard;|tri;)|m(?:idot;|oust(?:;|ache;))|n(?:E;|ap(?:;|prox;)|e(?:;|q(?:;|q;))|sim;)|o(?:a(?:ng;|rr;)|brk;|ng(?:left(?:arrow;|rightarrow;)|mapsto;|rightarrow;)|oparrow(?:left;|right;)|p(?:ar;|f;|lus;)|times;|w(?:ast;|bar;)|z(?:;|enge;|f;))|par(?:;|lt;)|r(?:arr;|corner;|har(?:;|d;)|m;|tri;)|s(?:aquo;|cr;|h;|im(?:;|e;|g;)|q(?:b;|uo(?:;|r;))|trok;)|t(?:;|c(?:c;|ir;)|dot;|hree;|imes;|larr;|quest;|r(?:Par;|i(?:;|e;|f;))|)|ur(?:dshar;|uhar;)|v(?:ertneqq;|nE;))|m(?:DDot;|a(?:cr;?|l(?:e;|t(?:;|ese;))|p(?:;|sto(?:;|down;|left;|up;))|rker;)|c(?:omma;|y;)|dash;|easuredangle;|fr;|ho;|i(?:cro;?|d(?:;|ast;|cir;|dot;?)|nus(?:;|b;|d(?:;|u;)))|l(?:cp;|dr;)|nplus;|o(?:dels;|pf;)|p;|s(?:cr;|tpos;)|u(?:;|ltimap;|map;))|n(?:G(?:g;|t(?:;|v;))|L(?:eft(?:arrow;|rightarrow;)|l;|t(?:;|v;))|Rightarrow;|V(?:Dash;|dash;)|a(?:bla;|cute;|ng;|p(?:;|E;|id;|os;|prox;)|tur(?:;|al(?:;|s;)))|b(?:sp;?|ump(?:;|e;))|c(?:a(?:p;|ron;)|edil;|ong(?:;|dot;)|up;|y;)|dash;|e(?:;|Arr;|ar(?:hk;|r(?:;|ow;))|dot;|quiv;|s(?:ear;|im;)|xist(?:;|s;))|fr;|g(?:E;|e(?:;|q(?:;|q;|slant;)|s;)|sim;|t(?:;|r;))|h(?:Arr;|arr;|par;)|i(?:;|s(?:;|d;)|v;)|jcy;|l(?:Arr;|E;|arr;|dr;|e(?:;|ft(?:arrow;|rightarrow;)|q(?:;|q;|slant;)|s(?:;|s;))|sim;|t(?:;|ri(?:;|e;)))|mid;|o(?:pf;|t(?:;|in(?:;|E;|dot;|v(?:a;|b;|c;))|ni(?:;|v(?:a;|b;|c;))|))|p(?:ar(?:;|allel;|sl;|t;)|olint;|r(?:;|cue;|e(?:;|c(?:;|eq;))))|r(?:Arr;|arr(?:;|c;|w;)|ightarrow;|tri(?:;|e;))|s(?:c(?:;|cue;|e;|r;)|hort(?:mid;|parallel;)|im(?:;|e(?:;|q;))|mid;|par;|qsu(?:be;|pe;)|u(?:b(?:;|E;|e;|set(?:;|eq(?:;|q;)))|cc(?:;|eq;)|p(?:;|E;|e;|set(?:;|eq(?:;|q;)))))|t(?:gl;|ilde;?|lg;|riangle(?:left(?:;|eq;)|right(?:;|eq;)))|u(?:;|m(?:;|ero;|sp;))|v(?:Dash;|Harr;|ap;|dash;|g(?:e;|t;)|infin;|l(?:Arr;|e;|t(?:;|rie;))|r(?:Arr;|trie;)|sim;)|w(?:Arr;|ar(?:hk;|r(?:;|ow;))|near;))|o(?:S;|a(?:cute;?|st;)|c(?:ir(?:;|c;?)|y;)|d(?:ash;|blac;|iv;|ot;|sold;)|elig;|f(?:cir;|r;)|g(?:on;|rave;?|t;)|h(?:bar;|m;)|int;|l(?:arr;|c(?:ir;|ross;)|ine;|t;)|m(?:acr;|ega;|i(?:cron;|d;|nus;))|opf;|p(?:ar;|erp;|lus;)|r(?:;|arr;|d(?:;|er(?:;|of;)|f;?|m;?)|igof;|or;|slope;|v;)|s(?:cr;|lash;?|ol;)|ti(?:lde;?|mes(?:;|as;))|uml;?|vbar;)|p(?:ar(?:;|a(?:;|llel;|)|s(?:im;|l;)|t;)|cy;|er(?:cnt;|iod;|mil;|p;|tenk;)|fr;|h(?:i(?:;|v;)|mmat;|one;)|i(?:;|tchfork;|v;)|l(?:an(?:ck(?:;|h;)|kv;)|us(?:;|acir;|b;|cir;|d(?:o;|u;)|e;|mn;?|sim;|two;))|m;|o(?:intint;|pf;|und;?)|r(?:;|E;|ap;|cue;|e(?:;|c(?:;|approx;|curlyeq;|eq;|n(?:approx;|eqq;|sim;)|sim;))|ime(?:;|s;)|n(?:E;|ap;|sim;)|o(?:d;|f(?:alar;|line;|surf;)|p(?:;|to;))|sim;|urel;)|s(?:cr;|i;)|uncsp;)|q(?:fr;|int;|opf;|prime;|scr;|u(?:at(?:ernions;|int;)|est(?:;|eq;)|ot;?))|r(?:A(?:arr;|rr;|tail;)|Barr;|Har;|a(?:c(?:e;|ute;)|dic;|emptyv;|ng(?:;|d;|e;|le;)|quo;?|rr(?:;|ap;|b(?:;|fs;)|c;|fs;|hk;|lp;|pl;|sim;|tl;|w;)|t(?:ail;|io(?:;|nals;)))|b(?:arr;|brk;|r(?:ac(?:e;|k;)|k(?:e;|sl(?:d;|u;))))|c(?:aron;|e(?:dil;|il;)|ub;|y;)|d(?:ca;|ldhar;|quo(?:;|r;)|sh;)|e(?:al(?:;|ine;|part;|s;)|ct;|g;?)|f(?:isht;|loor;|r;)|h(?:ar(?:d;|u(?:;|l;))|o(?:;|v;))|i(?:ght(?:arrow(?:;|tail;)|harpoon(?:down;|up;)|left(?:arrows;|harpoons;)|rightarrows;|squigarrow;|threetimes;)|ng;|singdotseq;)|l(?:arr;|har;|m;)|moust(?:;|ache;)|nmid;|o(?:a(?:ng;|rr;)|brk;|p(?:ar;|f;|lus;)|times;)|p(?:ar(?:;|gt;)|polint;)|rarr;|s(?:aquo;|cr;|h;|q(?:b;|uo(?:;|r;)))|t(?:hree;|imes;|ri(?:;|e;|f;|ltri;))|uluhar;|x;)|s(?:acute;|bquo;|c(?:;|E;|a(?:p;|ron;)|cue;|e(?:;|dil;)|irc;|n(?:E;|ap;|sim;)|polint;|sim;|y;)|dot(?:;|b;|e;)|e(?:Arr;|ar(?:hk;|r(?:;|ow;))|ct;?|mi;|swar;|tm(?:inus;|n;)|xt;)|fr(?:;|own;)|h(?:arp;|c(?:hcy;|y;)|ort(?:mid;|parallel;)|y;?)|i(?:gma(?:;|f;|v;)|m(?:;|dot;|e(?:;|q;)|g(?:;|E;)|l(?:;|E;)|ne;|plus;|rarr;))|larr;|m(?:a(?:llsetminus;|shp;)|eparsl;|i(?:d;|le;)|t(?:;|e(?:;|s;)))|o(?:ftcy;|l(?:;|b(?:;|ar;))|pf;)|pa(?:des(?:;|uit;)|r;)|q(?:c(?:ap(?:;|s;)|up(?:;|s;))|su(?:b(?:;|e;|set(?:;|eq;))|p(?:;|e;|set(?:;|eq;)))|u(?:;|ar(?:e;|f;)|f;))|rarr;|s(?:cr;|etmn;|mile;|tarf;)|t(?:ar(?:;|f;)|r(?:aight(?:epsilon;|phi;)|ns;))|u(?:b(?:;|E;|dot;|e(?:;|dot;)|mult;|n(?:E;|e;)|plus;|rarr;|s(?:et(?:;|eq(?:;|q;)|neq(?:;|q;))|im;|u(?:b;|p;)))|cc(?:;|approx;|curlyeq;|eq;|n(?:approx;|eqq;|sim;)|sim;)|m;|ng;|p(?:1;?|2;?|3;?|;|E;|d(?:ot;|sub;)|e(?:;|dot;)|hs(?:ol;|ub;)|larr;|mult;|n(?:E;|e;)|plus;|s(?:et(?:;|eq(?:;|q;)|neq(?:;|q;))|im;|u(?:b;|p;))))|w(?:Arr;|ar(?:hk;|r(?:;|ow;))|nwar;)|zlig;?)|t(?:a(?:rget;|u;)|brk;|c(?:aron;|edil;|y;)|dot;|elrec;|fr;|h(?:e(?:re(?:4;|fore;)|ta(?:;|sym;|v;))|i(?:ck(?:approx;|sim;)|nsp;)|k(?:ap;|sim;)|orn;?)|i(?:lde;|mes(?:;|b(?:;|ar;)|d;|)|nt;)|o(?:ea;|p(?:;|bot;|cir;|f(?:;|ork;))|sa;)|prime;|r(?:ade;|i(?:angle(?:;|down;|left(?:;|eq;)|q;|right(?:;|eq;))|dot;|e;|minus;|plus;|sb;|time;)|pezium;)|s(?:c(?:r;|y;)|hcy;|trok;)|w(?:ixt;|ohead(?:leftarrow;|rightarrow;)))|u(?:Arr;|Har;|a(?:cute;?|rr;)|br(?:cy;|eve;)|c(?:irc;?|y;)|d(?:arr;|blac;|har;)|f(?:isht;|r;)|grave;?|h(?:ar(?:l;|r;)|blk;)|l(?:c(?:orn(?:;|er;)|rop;)|tri;)|m(?:acr;|l;?)|o(?:gon;|pf;)|p(?:arrow;|downarrow;|harpoon(?:left;|right;)|lus;|si(?:;|h;|lon;)|uparrows;)|r(?:c(?:orn(?:;|er;)|rop;)|ing;|tri;)|scr;|t(?:dot;|ilde;|ri(?:;|f;))|u(?:arr;|ml;?)|wangle;)|v(?:Arr;|Bar(?:;|v;)|Dash;|a(?:ngrt;|r(?:epsilon;|kappa;|nothing;|p(?:hi;|i;|ropto;)|r(?:;|ho;)|s(?:igma;|u(?:bsetneq(?:;|q;)|psetneq(?:;|q;)))|t(?:heta;|riangle(?:left;|right;))))|cy;|dash;|e(?:e(?:;|bar;|eq;)|llip;|r(?:bar;|t;))|fr;|ltri;|nsu(?:b;|p;)|opf;|prop;|rtri;|s(?:cr;|u(?:bn(?:E;|e;)|pn(?:E;|e;)))|zigzag;)|w(?:circ;|e(?:d(?:bar;|ge(?:;|q;))|ierp;)|fr;|opf;|p;|r(?:;|eath;)|scr;)|x(?:c(?:ap;|irc;|up;)|dtri;|fr;|h(?:Arr;|arr;)|i;|l(?:Arr;|arr;)|map;|nis;|o(?:dot;|p(?:f;|lus;)|time;)|r(?:Arr;|arr;)|s(?:cr;|qcup;)|u(?:plus;|tri;)|vee;|wedge;)|y(?:ac(?:ute;?|y;)|c(?:irc;|y;)|en;?|fr;|icy;|opf;|scr;|u(?:cy;|ml;?))|z(?:acute;|c(?:aron;|y;)|dot;|e(?:etrf;|ta;)|fr;|hcy;|igrarr;|opf;|scr;|w(?:j;|nj;)))|[\s\S]/g; - -var NAMEDCHARREF_MAXLEN = 32; - -// Regular expression constants used by the tokenizer and parser - -// Note that \r is included in all of these regexps because it will need -// to be converted to LF by the scanChars() function. -var DBLQUOTEATTRVAL = /[^\r"&\u0000]+/g; -var SINGLEQUOTEATTRVAL = /[^\r'&\u0000]+/g; -var UNQUOTEDATTRVAL = /[^\r\t\n\f &>\u0000]+/g; -var TAGNAME = /[^\r\t\n\f \/>A-Z\u0000]+/g; -var ATTRNAME = /[^\r\t\n\f \/=>A-Z\u0000]+/g; - -var CDATATEXT = /[^\]\r\u0000\uffff]*/g; -var DATATEXT = /[^&<\r\u0000\uffff]*/g; -var RAWTEXT = /[^<\r\u0000\uffff]*/g; -var PLAINTEXT = /[^\r\u0000\uffff]*/g; -// Since we don't have the 'sticky tag', add '|.' to the end of SIMPLETAG -// and SIMPLEATTR so that we are guaranteed to always match. This prevents -// us from scanning past the lastIndex set. (Note that the desired matches -// are always greater than 1 char long, so longest-match will ensure that . -// is not matched unless the desired match fails.) -var SIMPLETAG = /(?:(\/)?([a-z]+)>)|[\s\S]/g; -var SIMPLEATTR = - /(?:([-a-z]+)[ \t\n\f]*=[ \t\n\f]*('[^'&\r\u0000]*'|"[^"&\r\u0000]*"|[^\t\n\r\f "&'\u0000>][^&> \t\n\r\f\u0000]*[ \t\n\f]))|[\s\S]/g; - -var NONWS = /[^\x09\x0A\x0C\x0D\x20]/; -var ALLNONWS = /[^\x09\x0A\x0C\x0D\x20]/g; // like above, with g flag -var NONWSNONNUL = /[^\x00\x09\x0A\x0C\x0D\x20]/; // don't allow NUL either -var LEADINGWS = /^[\x09\x0A\x0C\x0D\x20]+/; -var NULCHARS = /\x00/g; - -/*** - * These are utility functions that don't use any of the parser's - * internal state. - */ -function buf2str(buf) { - var CHUNKSIZE = 16384; - if (buf.length < CHUNKSIZE) { - return String.fromCharCode.apply(String, buf); - } - // special case for large strings, to avoid busting the stack. - var result = ''; - for (var i = 0; i < buf.length; i += CHUNKSIZE) { - result += String.fromCharCode.apply(String, buf.slice(i, i + CHUNKSIZE)); - } - return result; -} - -function str2buf(s) { - var result = []; - for (var i = 0; i < s.length; i++) { - result[i] = s.charCodeAt(i); - } - return result; -} - -// Determine whether the element is a member of the set. -// The set is an object that maps namespaces to objects. The objects -// then map local tagnames to the value true if that tag is part of the set -function isA(elt, set) { - if (typeof set === 'string') { - // convenience case for testing a particular HTML element - return elt.namespaceURI === NAMESPACE.HTML && elt.localName === set; - } - var tagnames = set[elt.namespaceURI]; - return tagnames && tagnames[elt.localName]; -} - -function isMathmlTextIntegrationPoint(n) { - return isA(n, mathmlTextIntegrationPointSet); -} - -function isHTMLIntegrationPoint(n) { - if (isA(n, htmlIntegrationPointSet)) return true; - if (n.namespaceURI === NAMESPACE.MATHML && n.localName === 'annotation-xml') { - var encoding = n.getAttribute('encoding'); - if (encoding) encoding = encoding.toLowerCase(); - if (encoding === 'text/html' || encoding === 'application/xhtml+xml') return true; - } - return false; -} - -function adjustSVGTagName(name) { - if (name in svgTagNameAdjustments) return svgTagNameAdjustments[name]; - else return name; -} - -function adjustSVGAttributes(attrs) { - for (var i = 0, n = attrs.length; i < n; i++) { - if (attrs[i][0] in svgAttrAdjustments) { - attrs[i][0] = svgAttrAdjustments[attrs[i][0]]; - } - } -} - -function adjustMathMLAttributes(attrs) { - for (var i = 0, n = attrs.length; i < n; i++) { - if (attrs[i][0] === 'definitionurl') { - attrs[i][0] = 'definitionURL'; - break; - } - } -} - -function adjustForeignAttributes(attrs) { - for (var i = 0, n = attrs.length; i < n; i++) { - if (attrs[i][0] in foreignAttributes) { - // Attributes with namespaces get a 3rd element: - // [Qname, value, namespace] - attrs[i].push(foreignAttributes[attrs[i][0]]); - } - } -} - -// For each attribute in attrs, if elt doesn't have an attribute -// by that name, add the attribute to elt -// XXX: I'm ignoring namespaces for now -function transferAttributes(attrs, elt) { - for (var i = 0, n = attrs.length; i < n; i++) { - var name = attrs[i][0], - value = attrs[i][1]; - if (elt.hasAttribute(name)) continue; - elt._setAttribute(name, value); - } -} - -/*** - * The ElementStack class - */ -HTMLParser.ElementStack = function ElementStack() { - this.elements = []; - this.top = null; // stack.top is the "current node" in the spec -}; - -/* -// This is for debugging only -HTMLParser.ElementStack.prototype.toString = function(e) { - return "STACK: " + - this.elements.map(function(e) {return e.localName;}).join("-"); -} -*/ - -HTMLParser.ElementStack.prototype.push = function (e) { - this.elements.push(e); - this.top = e; -}; - -HTMLParser.ElementStack.prototype.pop = function (e) { - this.elements.pop(); - this.top = this.elements[this.elements.length - 1]; -}; - -// Pop elements off the stack up to and including the first -// element with the specified (HTML) tagname -HTMLParser.ElementStack.prototype.popTag = function (tag) { - for (var i = this.elements.length - 1; i > 0; i--) { - var e = this.elements[i]; - if (isA(e, tag)) break; - } - this.elements.length = i; - this.top = this.elements[i - 1]; -}; - -// Pop elements off the stack up to and including the first -// element that is an instance of the specified type -HTMLParser.ElementStack.prototype.popElementType = function (type) { - for (var i = this.elements.length - 1; i > 0; i--) { - if (this.elements[i] instanceof type) break; - } - this.elements.length = i; - this.top = this.elements[i - 1]; -}; - -// Pop elements off the stack up to and including the element e. -// Note that this is very different from removeElement() -// This requires that e is on the stack. -HTMLParser.ElementStack.prototype.popElement = function (e) { - for (var i = this.elements.length - 1; i > 0; i--) { - if (this.elements[i] === e) break; - } - this.elements.length = i; - this.top = this.elements[i - 1]; -}; - -// Remove a specific element from the stack. -// Do nothing if the element is not on the stack -HTMLParser.ElementStack.prototype.removeElement = function (e) { - if (this.top === e) this.pop(); - else { - var idx = this.elements.lastIndexOf(e); - if (idx !== -1) this.elements.splice(idx, 1); - } -}; - -HTMLParser.ElementStack.prototype.clearToContext = function (set) { - // Note that we don't loop to 0. Never pop the <html> elt off. - for (var i = this.elements.length - 1; i > 0; i--) { - if (isA(this.elements[i], set)) break; - } - this.elements.length = i + 1; - this.top = this.elements[i]; -}; - -HTMLParser.ElementStack.prototype.contains = function (tag) { - return this.inSpecificScope(tag, Object.create(null)); -}; - -HTMLParser.ElementStack.prototype.inSpecificScope = function (tag, set) { - for (var i = this.elements.length - 1; i >= 0; i--) { - var elt = this.elements[i]; - if (isA(elt, tag)) return true; - if (isA(elt, set)) return false; - } - return false; -}; - -// Like the above, but for a specific element, not a tagname -HTMLParser.ElementStack.prototype.elementInSpecificScope = function (target, set) { - for (var i = this.elements.length - 1; i >= 0; i--) { - var elt = this.elements[i]; - if (elt === target) return true; - if (isA(elt, set)) return false; - } - return false; -}; - -// Like the above, but for an element interface, not a tagname -HTMLParser.ElementStack.prototype.elementTypeInSpecificScope = function (target, set) { - for (var i = this.elements.length - 1; i >= 0; i--) { - var elt = this.elements[i]; - if (elt instanceof target) return true; - if (isA(elt, set)) return false; - } - return false; -}; - -HTMLParser.ElementStack.prototype.inScope = function (tag) { - return this.inSpecificScope(tag, inScopeSet); -}; - -HTMLParser.ElementStack.prototype.elementInScope = function (e) { - return this.elementInSpecificScope(e, inScopeSet); -}; - -HTMLParser.ElementStack.prototype.elementTypeInScope = function (type) { - return this.elementTypeInSpecificScope(type, inScopeSet); -}; - -HTMLParser.ElementStack.prototype.inButtonScope = function (tag) { - return this.inSpecificScope(tag, inButtonScopeSet); -}; - -HTMLParser.ElementStack.prototype.inListItemScope = function (tag) { - return this.inSpecificScope(tag, inListItemScopeSet); -}; - -HTMLParser.ElementStack.prototype.inTableScope = function (tag) { - return this.inSpecificScope(tag, inTableScopeSet); -}; - -HTMLParser.ElementStack.prototype.inSelectScope = function (tag) { - // Can't implement this one with inSpecificScope, since it involves - // a set defined by inverting another set. So implement manually. - for (var i = this.elements.length - 1; i >= 0; i--) { - var elt = this.elements[i]; - if (elt.namespaceURI !== NAMESPACE.HTML) return false; - var localname = elt.localName; - if (localname === tag) return true; - if (localname !== 'optgroup' && localname !== 'option') return false; - } - return false; -}; - -HTMLParser.ElementStack.prototype.generateImpliedEndTags = function (butnot, thorough) { - var endTagSet = thorough ? thoroughImpliedEndTagsSet : impliedEndTagsSet; - for (var i = this.elements.length - 1; i >= 0; i--) { - var e = this.elements[i]; - if (butnot && isA(e, butnot)) break; - if (!isA(this.elements[i], endTagSet)) break; - } - - this.elements.length = i + 1; - this.top = this.elements[i]; -}; - -/*** - * The ActiveFormattingElements class - */ -HTMLParser.ActiveFormattingElements = function AFE() { - this.list = []; // elements - this.attrs = []; // attribute tokens for cloning -}; - -HTMLParser.ActiveFormattingElements.prototype.MARKER = { localName: '|' }; - -/* -// For debugging -HTMLParser.ActiveFormattingElements.prototype.toString = function() { - return "AFE: " + - this.list.map(function(e) { return e.localName; }).join("-"); -} -*/ - -HTMLParser.ActiveFormattingElements.prototype.insertMarker = function () { - this.list.push(this.MARKER); - this.attrs.push(this.MARKER); -}; - -HTMLParser.ActiveFormattingElements.prototype.push = function (elt, attrs) { - // Scan backwards: if there are already 3 copies of this element - // before we encounter a marker, then drop the last one - var count = 0; - for (var i = this.list.length - 1; i >= 0; i--) { - if (this.list[i] === this.MARKER) break; - // equal() is defined below - if (equal(elt, this.list[i], this.attrs[i])) { - count++; - if (count === 3) { - this.list.splice(i, 1); - this.attrs.splice(i, 1); - break; - } - } - } - - // Now push the element onto the list - this.list.push(elt); - - // Copy the attributes and push those on, too - var attrcopy = []; - for (var ii = 0; ii < attrs.length; ii++) { - attrcopy[ii] = attrs[ii]; - } - - this.attrs.push(attrcopy); - - // This function defines equality of two elements for the purposes - // of the AFE list. Note that it compares the new elements - // attributes to the saved array of attributes associated with - // the old element because a script could have changed the - // old element's set of attributes - function equal(newelt, oldelt, oldattrs) { - if (newelt.localName !== oldelt.localName) return false; - if (newelt._numattrs !== oldattrs.length) return false; - for (var i = 0, n = oldattrs.length; i < n; i++) { - var oldname = oldattrs[i][0]; - var oldval = oldattrs[i][1]; - if (!newelt.hasAttribute(oldname)) return false; - if (newelt.getAttribute(oldname) !== oldval) return false; - } - return true; - } -}; - -HTMLParser.ActiveFormattingElements.prototype.clearToMarker = function () { - for (var i = this.list.length - 1; i >= 0; i--) { - if (this.list[i] === this.MARKER) break; - } - if (i < 0) i = 0; - this.list.length = i; - this.attrs.length = i; -}; - -// Find and return the last element with the specified tag between the -// end of the list and the last marker on the list. -// Used when parsing <a> in_body_mode() -HTMLParser.ActiveFormattingElements.prototype.findElementByTag = function (tag) { - for (var i = this.list.length - 1; i >= 0; i--) { - var elt = this.list[i]; - if (elt === this.MARKER) break; - if (elt.localName === tag) return elt; - } - return null; -}; - -HTMLParser.ActiveFormattingElements.prototype.indexOf = function (e) { - return this.list.lastIndexOf(e); -}; - -// Find the element e in the list and remove it -// Used when parsing <a> in_body() -HTMLParser.ActiveFormattingElements.prototype.remove = function (e) { - var idx = this.list.lastIndexOf(e); - if (idx !== -1) { - this.list.splice(idx, 1); - this.attrs.splice(idx, 1); - } -}; - -// Find element a in the list and replace it with element b -// XXX: Do I need to handle attributes here? -HTMLParser.ActiveFormattingElements.prototype.replace = function (a, b, attrs) { - var idx = this.list.lastIndexOf(a); - if (idx !== -1) { - this.list[idx] = b; - this.attrs[idx] = attrs; - } -}; - -// Find a in the list and insert b after it -// This is only used for insert a bookmark object, so the -// attrs array doesn't really matter -HTMLParser.ActiveFormattingElements.prototype.insertAfter = function (a, b) { - var idx = this.list.lastIndexOf(a); - if (idx !== -1) { - this.list.splice(idx, 0, b); - this.attrs.splice(idx, 0, b); - } -}; - -/*** - * This is the parser factory function. It is the return value of - * the outer closure that it is defined within. Most of the parser - * implementation details are inside this function. - */ -function HTMLParser(address, fragmentContext, options) { - /*** - * These are the parser's state variables - */ - // Scanner state - var chars = null; - var numchars = 0; // Length of chars - var nextchar = 0; // Index of next char - var input_complete = false; // Becomes true when end() called. - var scanner_skip_newline = false; // If previous char was CR - var reentrant_invocations = 0; - var saved_scanner_state = []; - var leftovers = ''; - var first_batch = true; - var paused = 0; // Becomes non-zero while loading scripts - - // Tokenizer state - var tokenizer = data_state; // Current tokenizer state - var return_state; - var character_reference_code; - var tagnamebuf = ''; - var lasttagname = ''; // holds the target end tag for text states - var tempbuf = []; - var attrnamebuf = ''; - var attrvaluebuf = ''; - var commentbuf = []; - var doctypenamebuf = []; - var doctypepublicbuf = []; - var doctypesystembuf = []; - var attributes = []; - var is_end_tag = false; - - // Tree builder state - var parser = initial_mode; // Current insertion mode - var originalInsertionMode = null; // A saved insertion mode - var templateInsertionModes = []; // Stack of template insertion modes. - var stack = new HTMLParser.ElementStack(); // Stack of open elements - var afe = new HTMLParser.ActiveFormattingElements(); // mis-nested tags - var fragment = fragmentContext !== undefined; // For innerHTML, etc. - var head_element_pointer = null; - var form_element_pointer = null; - var scripting_enabled = true; - if (fragmentContext) { - scripting_enabled = fragmentContext.ownerDocument._scripting_enabled; - } - if (options && options.scripting_enabled === false) scripting_enabled = false; - var frameset_ok = true; - var force_quirks = false; - var pending_table_text; - var text_integration_mode; // XXX a spec bug workaround? - - // A single run of characters, buffered up to be sent to - // the parser as a single string. - var textrun = []; - var textIncludesNUL = false; - var ignore_linefeed = false; - - /*** - * This is the parser object that will be the return value of this - * factory function, which is some 5000 lines below. - * Note that the variable "parser" is the current state of the - * parser's state machine. This variable "htmlparser" is the - * return value and defines the public API of the parser - */ - var htmlparser = { - document: function () { - return doc; - }, - - // Convenience function for internal use. Can only be called once, - // as it removes the nodes from `doc` to add them to fragment. - _asDocumentFragment: function () { - var frag = doc.createDocumentFragment(); - var root = doc.firstChild; - while (root.hasChildNodes()) { - frag.appendChild(root.firstChild); - } - return frag; - }, - - // Internal function used from HTMLScriptElement to pause the - // parser while a script is being loaded from the network - pause: function () { - // print("pausing parser"); - paused++; - }, - - // Called when a script finishes loading - resume: function () { - // print("resuming parser"); - paused--; - // XXX: added this to force a resumption. - // Is this the right thing to do? - this.parse(''); - }, - - // Parse the HTML text s. - // The second argument should be true if there is no more - // text to be parsed, and should be false or omitted otherwise. - // The second argument must not be set for recursive invocations - // from document.write() - parse: function (s, end, shouldPauseFunc) { - var moreToDo; - - // If we're paused, remember the text to parse, but - // don't parse it now. - // (Don't invoke shouldPauseFunc because we haven't handled 'end' yet.) - if (paused > 0) { - leftovers += s; - return true; // more to do - } - - if (reentrant_invocations === 0) { - // A normal, top-level invocation - if (leftovers) { - s = leftovers + s; - leftovers = ''; - } - - // Add a special marker character to the end of - // the buffer. If the scanner is at the end of - // the buffer and input_complete is set, then this - // character will transform into an EOF token. - // Having an actual character that represents EOF - // in the character buffer makes lookahead regexp - // matching work more easily, and this is - // important for character references. - if (end) { - s += '\uFFFF'; - input_complete = true; // Makes scanChars() send EOF - } - - chars = s; - numchars = s.length; - nextchar = 0; - - if (first_batch) { - // We skip a leading Byte Order Mark (\uFEFF) - // on first batch of text we're given - first_batch = false; - if (chars.charCodeAt(0) === 0xfeff) nextchar = 1; - } - - reentrant_invocations++; - moreToDo = scanChars(shouldPauseFunc); - leftovers = chars.substring(nextchar, numchars); - reentrant_invocations--; - } else { - // This is the re-entrant case, which we have to - // handle a little differently. - reentrant_invocations++; - - // Save current scanner state - saved_scanner_state.push(chars, numchars, nextchar); - - // Set new scanner state - chars = s; - numchars = s.length; - nextchar = 0; - - // Now scan as many of these new chars as we can - scanChars(); - moreToDo = false; - - leftovers = chars.substring(nextchar, numchars); - - // restore old scanner state - nextchar = saved_scanner_state.pop(); - numchars = saved_scanner_state.pop(); - chars = saved_scanner_state.pop(); - - // If there were leftover chars from this invocation - // insert them into the pending invocation's buffer - // and trim already processed chars at the same time - if (leftovers) { - chars = leftovers + chars.substring(nextchar); - numchars = chars.length; - nextchar = 0; - leftovers = ''; - } - - // Decrement the counter - reentrant_invocations--; - } - return moreToDo; - }, - }; - - // This is the document we'll be building up - var doc = new Document(true, address); - - // The document needs to know about the parser, for document.write(). - // This _parser property will be deleted when we're done parsing. - doc._parser = htmlparser; - - // XXX I think that any document we use this parser on should support - // scripts. But I may need to configure that through a parser parameter - // Only documents with windows ("browsing contexts" to be precise) - // allow scripting. - doc._scripting_enabled = scripting_enabled; - - /*** - * The actual code of the HTMLParser() factory function begins here. - */ - - if (fragmentContext) { - // for innerHTML parsing - if (fragmentContext.ownerDocument._quirks) doc._quirks = true; - if (fragmentContext.ownerDocument._limitedQuirks) doc._limitedQuirks = true; - - // Set the initial tokenizer state - if (fragmentContext.namespaceURI === NAMESPACE.HTML) { - switch (fragmentContext.localName) { - case 'title': - case 'textarea': - tokenizer = rcdata_state; - break; - case 'style': - case 'xmp': - case 'iframe': - case 'noembed': - case 'noframes': - case 'script': - case 'plaintext': - tokenizer = plaintext_state; - break; - case 'noscript': - if (scripting_enabled) tokenizer = plaintext_state; - } - } - - var root = doc.createElement('html'); - doc._appendChild(root); - stack.push(root); - if (fragmentContext instanceof impl.HTMLTemplateElement) { - templateInsertionModes.push(in_template_mode); - } - resetInsertionMode(); - - for (var e = fragmentContext; e !== null; e = e.parentElement) { - if (e instanceof impl.HTMLFormElement) { - form_element_pointer = e; - break; - } - } - } - - /*** - * Scanner functions - */ - // Loop through the characters in chars, and pass them one at a time - // to the tokenizer FSM. Return when no more characters can be processed - // (This may leave 1 or more characters in the buffer: like a CR - // waiting to see if the next char is LF, or for states that require - // lookahead...) - function scanChars(shouldPauseFunc) { - var codepoint, s, pattern, eof; - - while (nextchar < numchars) { - // If we just tokenized a </script> tag, then the paused flag - // may have been set to tell us to stop tokenizing while - // the script is loading - if (paused > 0 || (shouldPauseFunc && shouldPauseFunc())) { - return true; - } - - switch (typeof tokenizer.lookahead) { - case 'undefined': - codepoint = chars.charCodeAt(nextchar++); - if (scanner_skip_newline) { - scanner_skip_newline = false; - if (codepoint === 0x000a) { - nextchar++; - continue; - } - } - switch (codepoint) { - case 0x000d: - // CR always turns into LF, but if the next character - // is LF, then that second LF is skipped. - if (nextchar < numchars) { - if (chars.charCodeAt(nextchar) === 0x000a) nextchar++; - } else { - // We don't know the next char right now, so we - // can't check if it is a LF. So set a flag - scanner_skip_newline = true; - } - - // In either case, emit a LF - tokenizer(0x000a); - - break; - case 0xffff: - if (input_complete && nextchar === numchars) { - tokenizer(EOF); // codepoint will be 0xFFFF here - break; - } - /* falls through */ - default: - tokenizer(codepoint); - break; - } - break; - - case 'number': - codepoint = chars.charCodeAt(nextchar); - - // The only tokenizer states that require fixed lookahead - // only consume alphanum characters, so we don't have - // to worry about CR and LF in this case - - // tokenizer wants n chars of lookahead - var n = tokenizer.lookahead; - var needsString = true; - if (n < 0) { - needsString = false; - n = -n; - } - - if (n < numchars - nextchar) { - // If we can look ahead that far - s = needsString ? chars.substring(nextchar, nextchar + n) : null; - eof = false; - } else { - // if we don't have that many characters - if (input_complete) { - // If no more are coming - // Just return what we have - s = needsString ? chars.substring(nextchar, numchars) : null; - eof = true; - if (codepoint === 0xffff && nextchar === numchars - 1) codepoint = EOF; - } else { - // Return now and wait for more chars later - return true; - } - } - tokenizer(codepoint, s, eof); - break; - case 'string': - codepoint = chars.charCodeAt(nextchar); - - // tokenizer wants characters up to a matching string - pattern = tokenizer.lookahead; - var pos = chars.indexOf(pattern, nextchar); - if (pos !== -1) { - s = chars.substring(nextchar, pos + pattern.length); - eof = false; - } else { - // No match - // If more characters coming, wait for them - if (!input_complete) return true; - - // Otherwise, we've got to return what we've got - s = chars.substring(nextchar, numchars); - if (codepoint === 0xffff && nextchar === numchars - 1) codepoint = EOF; - eof = true; - } - - // The tokenizer states that require this kind of - // lookahead have to be careful to handle CR characters - // correctly - tokenizer(codepoint, s, eof); - break; - } - } - return false; // no more characters to scan! - } - - /*** - * Tokenizer utility functions - */ - function addAttribute(name, value) { - // Make sure there isn't already an attribute with this name - // If there is, ignore this one. - for (var i = 0; i < attributes.length; i++) { - if (attributes[i][0] === name) return; - } - - if (value !== undefined) { - attributes.push([name, value]); - } else { - attributes.push([name]); - } - } - - // Shortcut for simple attributes - function handleSimpleAttribute() { - SIMPLEATTR.lastIndex = nextchar - 1; - var matched = SIMPLEATTR.exec(chars); - if (!matched) throw new Error('should never happen'); - var name = matched[1]; - if (!name) return false; - var value = matched[2]; - var len = value.length; - switch (value[0]) { - case '"': - case "'": - value = value.substring(1, len - 1); - nextchar += matched[0].length - 1; - tokenizer = after_attribute_value_quoted_state; - break; - default: - tokenizer = before_attribute_name_state; - nextchar += matched[0].length - 1; - value = value.substring(0, len - 1); - break; - } - - // Make sure there isn't already an attribute with this name - // If there is, ignore this one. - for (var i = 0; i < attributes.length; i++) { - if (attributes[i][0] === name) return true; - } - - attributes.push([name, value]); - return true; - } - - function beginTagName() { - is_end_tag = false; - tagnamebuf = ''; - attributes.length = 0; - } - function beginEndTagName() { - is_end_tag = true; - tagnamebuf = ''; - attributes.length = 0; - } - - function beginTempBuf() { - tempbuf.length = 0; - } - function beginAttrName() { - attrnamebuf = ''; - } - function beginAttrValue() { - attrvaluebuf = ''; - } - function beginComment() { - commentbuf.length = 0; - } - function beginDoctype() { - doctypenamebuf.length = 0; - doctypepublicbuf = null; - doctypesystembuf = null; - } - function beginDoctypePublicId() { - doctypepublicbuf = []; - } - function beginDoctypeSystemId() { - doctypesystembuf = []; - } - function forcequirks() { - force_quirks = true; - } - function cdataAllowed() { - return stack.top && stack.top.namespaceURI !== 'http://www.w3.org/1999/xhtml'; - } - - // Return true if the codepoints in the specified buffer match the - // characters of lasttagname - function appropriateEndTag(buf) { - return lasttagname === buf; - } - - function flushText() { - if (textrun.length > 0) { - var s = buf2str(textrun); - textrun.length = 0; - - if (ignore_linefeed) { - ignore_linefeed = false; - if (s[0] === '\n') s = s.substring(1); - if (s.length === 0) return; - } - - insertToken(TEXT, s); - textIncludesNUL = false; - } - ignore_linefeed = false; - } - - // Consume chars matched by the pattern and return them as a string. Starts - // matching at the current position, so users should drop the current char - // otherwise. - function getMatchingChars(pattern) { - pattern.lastIndex = nextchar - 1; - var match = pattern.exec(chars); - if (match && match.index === nextchar - 1) { - match = match[0]; - nextchar += match.length - 1; - /* Careful! Make sure we haven't matched the EOF character! */ - if (input_complete && nextchar === numchars) { - // Oops, backup one. - match = match.slice(0, -1); - nextchar--; - } - return match; - } else { - throw new Error('should never happen'); - } - } - - // emit a string of chars that match a regexp - // Returns false if no chars matched. - function emitCharsWhile(pattern) { - pattern.lastIndex = nextchar - 1; - var match = pattern.exec(chars)[0]; - if (!match) return false; - emitCharString(match); - nextchar += match.length - 1; - return true; - } - - // This is used by CDATA sections - function emitCharString(s) { - if (textrun.length > 0) flushText(); - - if (ignore_linefeed) { - ignore_linefeed = false; - if (s[0] === '\n') s = s.substring(1); - if (s.length === 0) return; - } - - insertToken(TEXT, s); - } - - function emitTag() { - if (is_end_tag) insertToken(ENDTAG, tagnamebuf); - else { - // Remember the last open tag we emitted - var tagname = tagnamebuf; - tagnamebuf = ''; - lasttagname = tagname; - insertToken(TAG, tagname, attributes); - } - } - - // A shortcut: look ahead and if this is a open or close tag - // in lowercase with no spaces and no attributes, just emit it now. - function emitSimpleTag() { - if (nextchar === numchars) { - return false; /* not even 1 char left */ - } - SIMPLETAG.lastIndex = nextchar; - var matched = SIMPLETAG.exec(chars); - if (!matched) throw new Error('should never happen'); - var tagname = matched[2]; - if (!tagname) return false; - var endtag = matched[1]; - if (endtag) { - nextchar += tagname.length + 2; - insertToken(ENDTAG, tagname); - } else { - nextchar += tagname.length + 1; - lasttagname = tagname; - insertToken(TAG, tagname, NOATTRS); - } - return true; - } - - function emitSelfClosingTag() { - if (is_end_tag) insertToken(ENDTAG, tagnamebuf, null, true); - else { - insertToken(TAG, tagnamebuf, attributes, true); - } - } - - function emitDoctype() { - insertToken( - DOCTYPE, - buf2str(doctypenamebuf), - doctypepublicbuf ? buf2str(doctypepublicbuf) : undefined, - doctypesystembuf ? buf2str(doctypesystembuf) : undefined - ); - } - - function emitEOF() { - flushText(); - parser(EOF); // EOF never goes to insertForeignContent() - doc.modclock = 1; // Start tracking modifications - } - - // Insert a token, either using the current parser insertion mode - // (for HTML stuff) or using the insertForeignToken() method. - var insertToken = (htmlparser.insertToken = function insertToken(t, value, arg3, arg4) { - flushText(); - var current = stack.top; - - if (!current || current.namespaceURI === NAMESPACE.HTML) { - // This is the common case - parser(t, value, arg3, arg4); - } else { - // Otherwise we may need to insert this token as foreign content - if (t !== TAG && t !== TEXT) { - insertForeignToken(t, value, arg3, arg4); - } else { - // But in some cases we treat it as regular content - if ( - (isMathmlTextIntegrationPoint(current) && - (t === TEXT || (t === TAG && value !== 'mglyph' && value !== 'malignmark'))) || - (t === TAG && - value === 'svg' && - current.namespaceURI === NAMESPACE.MATHML && - current.localName === 'annotation-xml') || - isHTMLIntegrationPoint(current) - ) { - // XXX: the text_integration_mode stuff is an - // attempted bug workaround of mine - text_integration_mode = true; - parser(t, value, arg3, arg4); - text_integration_mode = false; - } - // Otherwise it is foreign content - else { - insertForeignToken(t, value, arg3, arg4); - } - } - } - }); - - /*** - * Tree building utility functions - */ - function insertComment(data) { - var parent = stack.top; - if (foster_parent_mode && isA(parent, tablesectionrowSet)) { - fosterParent(function (doc) { - return doc.createComment(data); - }); - } else { - // "If the adjusted insertion location is inside a template element, - // let it instead be inside the template element's template contents" - if (parent instanceof impl.HTMLTemplateElement) { - parent = parent.content; - } - parent._appendChild(parent.ownerDocument.createComment(data)); - } - } - - function insertText(s) { - var parent = stack.top; - if (foster_parent_mode && isA(parent, tablesectionrowSet)) { - fosterParent(function (doc) { - return doc.createTextNode(s); - }); - } else { - // "If the adjusted insertion location is inside a template element, - // let it instead be inside the template element's template contents" - if (parent instanceof impl.HTMLTemplateElement) { - parent = parent.content; - } - // "If there is a Text node immediately before the adjusted insertion - // location, then append data to that Text node's data." - var lastChild = parent.lastChild; - if (lastChild && lastChild.nodeType === Node.TEXT_NODE) { - lastChild.appendData(s); - } else { - parent._appendChild(parent.ownerDocument.createTextNode(s)); - } - } - } - - function createHTMLElt(doc, name, attrs) { - // Create the element this way, rather than with - // doc.createElement because createElement() does error - // checking on the element name that we need to avoid here. - var elt = html.createElement(doc, name, null); - - if (attrs) { - for (var i = 0, n = attrs.length; i < n; i++) { - // Use the _ version to avoid testing the validity - // of the attribute name - elt._setAttribute(attrs[i][0], attrs[i][1]); - } - } - // XXX - // If the element is a resettable form element, - // run its reset algorithm now - // XXX - // handle case where form-element-pointer is not null - return elt; - } - - // The in_table insertion mode turns on this flag, and that makes - // insertHTMLElement use the foster parenting algorithm for elements - // tags inside a table - var foster_parent_mode = false; - - function insertHTMLElement(name, attrs) { - var elt = insertElement(function (doc) { - return createHTMLElt(doc, name, attrs); - }); - - // XXX - // If this is a form element, set its form attribute property here - if (isA(elt, formassociatedSet)) { - elt._form = form_element_pointer; - } - - return elt; - } - - // Insert the element into the open element or foster parent it - function insertElement(eltFunc) { - var elt; - if (foster_parent_mode && isA(stack.top, tablesectionrowSet)) { - elt = fosterParent(eltFunc); - } else if (stack.top instanceof impl.HTMLTemplateElement) { - // "If the adjusted insertion location is inside a template element, - // let it instead be inside the template element's template contents" - elt = eltFunc(stack.top.content.ownerDocument); - stack.top.content._appendChild(elt); - } else { - elt = eltFunc(stack.top.ownerDocument); - stack.top._appendChild(elt); - } - - stack.push(elt); - return elt; - } - - function insertForeignElement(name, attrs, ns) { - return insertElement(function (doc) { - // We need to prevent createElementNS from trying to parse `name` as a - // `qname`, so use an internal Document#_createElementNS() interface. - var elt = doc._createElementNS(name, ns, null); - if (attrs) { - for (var i = 0, n = attrs.length; i < n; i++) { - var attr = attrs[i]; - if (attr.length === 2) elt._setAttribute(attr[0], attr[1]); - else { - elt._setAttributeNS(attr[2], attr[0], attr[1]); - } - } - } - return elt; - }); - } - - function lastElementOfType(type) { - for (var i = stack.elements.length - 1; i >= 0; i--) { - if (stack.elements[i] instanceof type) { - return i; - } - } - return -1; - } - - function fosterParent(eltFunc) { - var parent, - before, - lastTable = -1, - lastTemplate = -1, - elt; - - lastTable = lastElementOfType(impl.HTMLTableElement); - lastTemplate = lastElementOfType(impl.HTMLTemplateElement); - - if (lastTemplate >= 0 && (lastTable < 0 || lastTemplate > lastTable)) { - parent = stack.elements[lastTemplate]; - } else if (lastTable >= 0) { - parent = stack.elements[lastTable].parentNode; - if (parent) { - before = stack.elements[lastTable]; - } else { - parent = stack.elements[lastTable - 1]; - } - } - if (!parent) parent = stack.elements[0]; // the `html` element. - - // "If the adjusted insertion location is inside a template element, - // let it instead be inside the template element's template contents" - if (parent instanceof impl.HTMLTemplateElement) { - parent = parent.content; - } - // Create element in the appropriate document. - elt = eltFunc(parent.ownerDocument); - - if (elt.nodeType === Node.TEXT_NODE) { - var prev; - if (before) prev = before.previousSibling; - else prev = parent.lastChild; - if (prev && prev.nodeType === Node.TEXT_NODE) { - prev.appendData(elt.data); - return elt; - } - } - if (before) parent.insertBefore(elt, before); - else parent._appendChild(elt); - return elt; - } - - function resetInsertionMode() { - var last = false; - for (var i = stack.elements.length - 1; i >= 0; i--) { - var node = stack.elements[i]; - if (i === 0) { - last = true; - if (fragment) { - node = fragmentContext; - } - } - if (node.namespaceURI === NAMESPACE.HTML) { - var tag = node.localName; - switch (tag) { - case 'select': - for (var j = i; j > 0; ) { - var ancestor = stack.elements[--j]; - if (ancestor instanceof impl.HTMLTemplateElement) { - break; - } else if (ancestor instanceof impl.HTMLTableElement) { - parser = in_select_in_table_mode; - return; - } - } - parser = in_select_mode; - return; - case 'tr': - parser = in_row_mode; - return; - case 'tbody': - case 'tfoot': - case 'thead': - parser = in_table_body_mode; - return; - case 'caption': - parser = in_caption_mode; - return; - case 'colgroup': - parser = in_column_group_mode; - return; - case 'table': - parser = in_table_mode; - return; - case 'template': - parser = templateInsertionModes[templateInsertionModes.length - 1]; - return; - case 'body': - parser = in_body_mode; - return; - case 'frameset': - parser = in_frameset_mode; - return; - case 'html': - if (head_element_pointer === null) { - parser = before_head_mode; - } else { - parser = after_head_mode; - } - return; - default: - if (!last) { - if (tag === 'head') { - parser = in_head_mode; - return; - } - if (tag === 'td' || tag === 'th') { - parser = in_cell_mode; - return; - } - } - } - } - if (last) { - parser = in_body_mode; - return; - } - } - } - - function parseRawText(name, attrs) { - insertHTMLElement(name, attrs); - tokenizer = rawtext_state; - originalInsertionMode = parser; - parser = text_mode; - } - - function parseRCDATA(name, attrs) { - insertHTMLElement(name, attrs); - tokenizer = rcdata_state; - originalInsertionMode = parser; - parser = text_mode; - } - - // Make a copy of element i on the list of active formatting - // elements, using its original attributes, not current - // attributes (which may have been modified by a script) - function afeclone(doc, i) { - return { - elt: createHTMLElt(doc, afe.list[i].localName, afe.attrs[i]), - attrs: afe.attrs[i], - }; - } - - function afereconstruct() { - if (afe.list.length === 0) return; - var entry = afe.list[afe.list.length - 1]; - // If the last is a marker , do nothing - if (entry === afe.MARKER) return; - // Or if it is an open element, do nothing - if (stack.elements.lastIndexOf(entry) !== -1) return; - - // Loop backward through the list until we find a marker or an - // open element, and then move forward one from there. - for (var i = afe.list.length - 2; i >= 0; i--) { - entry = afe.list[i]; - if (entry === afe.MARKER) break; - if (stack.elements.lastIndexOf(entry) !== -1) break; - } - - // Now loop forward, starting from the element after the current - // one, recreating formatting elements and pushing them back onto - // the list of open elements - for (i = i + 1; i < afe.list.length; i++) { - var newelt = insertElement(function (doc) { - return afeclone(doc, i).elt; - }); - afe.list[i] = newelt; - } - } - - // Used by the adoptionAgency() function - var BOOKMARK = { localName: 'BM' }; - - function adoptionAgency(tag) { - // If the current node is an HTML element whose tag name is subject, - // and the current node is not in the list of active formatting - // elements, then pop the current node off the stack of open - // elements and abort these steps. - if (isA(stack.top, tag) && afe.indexOf(stack.top) === -1) { - stack.pop(); - return true; // no more handling required - } - - // Let outer loop counter be zero. - var outer = 0; - - // Outer loop: If outer loop counter is greater than or - // equal to eight, then abort these steps. - while (outer < 8) { - // Increment outer loop counter by one. - outer++; - - // Let the formatting element be the last element in the list - // of active formatting elements that: is between the end of - // the list and the last scope marker in the list, if any, or - // the start of the list otherwise, and has the same tag name - // as the token. - var fmtelt = afe.findElementByTag(tag); - - // If there is no such node, then abort these steps and instead - // act as described in the "any other end tag" entry below. - if (!fmtelt) { - return false; // false means handle by the default case - } - - // Otherwise, if there is such a node, but that node is not in - // the stack of open elements, then this is a parse error; - // remove the element from the list, and abort these steps. - var index = stack.elements.lastIndexOf(fmtelt); - if (index === -1) { - afe.remove(fmtelt); - return true; // true means no more handling required - } - - // Otherwise, if there is such a node, and that node is also in - // the stack of open elements, but the element is not in scope, - // then this is a parse error; ignore the token, and abort - // these steps. - if (!stack.elementInScope(fmtelt)) { - return true; - } - - // Let the furthest block be the topmost node in the stack of - // open elements that is lower in the stack than the formatting - // element, and is an element in the special category. There - // might not be one. - var furthestblock = null, - furthestblockindex; - for (var i = index + 1; i < stack.elements.length; i++) { - if (isA(stack.elements[i], specialSet)) { - furthestblock = stack.elements[i]; - furthestblockindex = i; - break; - } - } - - // If there is no furthest block, then the UA must skip the - // subsequent steps and instead just pop all the nodes from the - // bottom of the stack of open elements, from the current node - // up to and including the formatting element, and remove the - // formatting element from the list of active formatting - // elements. - if (!furthestblock) { - stack.popElement(fmtelt); - afe.remove(fmtelt); - return true; - } else { - // Let the common ancestor be the element immediately above - // the formatting element in the stack of open elements. - var ancestor = stack.elements[index - 1]; - - // Let a bookmark note the position of the formatting - // element in the list of active formatting elements - // relative to the elements on either side of it in the - // list. - afe.insertAfter(fmtelt, BOOKMARK); - - // Let node and last node be the furthest block. - var node = furthestblock; - var lastnode = furthestblock; - var nodeindex = furthestblockindex; - var nodeafeindex; - - // Let inner loop counter be zero. - var inner = 0; - - while (true) { - // Increment inner loop counter by one. - inner++; - - // Let node be the element immediately above node in - // the stack of open elements, or if node is no longer - // in the stack of open elements (e.g. because it got - // removed by this algorithm), the element that was - // immediately above node in the stack of open elements - // before node was removed. - node = stack.elements[--nodeindex]; - - // If node is the formatting element, then go - // to the next step in the overall algorithm. - if (node === fmtelt) break; - - // If the inner loop counter is greater than three and node - // is in the list of active formatting elements, then remove - // node from the list of active formatting elements. - nodeafeindex = afe.indexOf(node); - if (inner > 3 && nodeafeindex !== -1) { - afe.remove(node); - nodeafeindex = -1; - } - - // If node is not in the list of active formatting - // elements, then remove node from the stack of open - // elements and then go back to the step labeled inner - // loop. - if (nodeafeindex === -1) { - stack.removeElement(node); - continue; - } - - // Create an element for the token for which the - // element node was created with common ancestor as - // the intended parent, replace the entry for node - // in the list of active formatting elements with an - // entry for the new element, replace the entry for - // node in the stack of open elements with an entry for - // the new element, and let node be the new element. - var newelt = afeclone(ancestor.ownerDocument, nodeafeindex); - afe.replace(node, newelt.elt, newelt.attrs); - stack.elements[nodeindex] = newelt.elt; - node = newelt.elt; - - // If last node is the furthest block, then move the - // aforementioned bookmark to be immediately after the - // new node in the list of active formatting elements. - if (lastnode === furthestblock) { - afe.remove(BOOKMARK); - afe.insertAfter(newelt.elt, BOOKMARK); - } - - // Insert last node into node, first removing it from - // its previous parent node if any. - node._appendChild(lastnode); - - // Let last node be node. - lastnode = node; - } - - // If the common ancestor node is a table, tbody, tfoot, - // thead, or tr element, then, foster parent whatever last - // node ended up being in the previous step, first removing - // it from its previous parent node if any. - if (foster_parent_mode && isA(ancestor, tablesectionrowSet)) { - fosterParent(function () { - return lastnode; - }); - } - // Otherwise, append whatever last node ended up being in - // the previous step to the common ancestor node, first - // removing it from its previous parent node if any. - else if (ancestor instanceof impl.HTMLTemplateElement) { - ancestor.content._appendChild(lastnode); - } else { - ancestor._appendChild(lastnode); - } - - // Create an element for the token for which the - // formatting element was created, with furthest block - // as the intended parent. - var newelt2 = afeclone(furthestblock.ownerDocument, afe.indexOf(fmtelt)); - - // Take all of the child nodes of the furthest block and - // append them to the element created in the last step. - while (furthestblock.hasChildNodes()) { - newelt2.elt._appendChild(furthestblock.firstChild); - } - - // Append that new element to the furthest block. - furthestblock._appendChild(newelt2.elt); - - // Remove the formatting element from the list of active - // formatting elements, and insert the new element into the - // list of active formatting elements at the position of - // the aforementioned bookmark. - afe.remove(fmtelt); - afe.replace(BOOKMARK, newelt2.elt, newelt2.attrs); - - // Remove the formatting element from the stack of open - // elements, and insert the new element into the stack of - // open elements immediately below the position of the - // furthest block in that stack. - stack.removeElement(fmtelt); - var pos = stack.elements.lastIndexOf(furthestblock); - stack.elements.splice(pos + 1, 0, newelt2.elt); - } - } - - return true; - } - - // We do this when we get /script in in_text_mode - function handleScriptEnd() { - // XXX: - // This is just a stub implementation right now and doesn't run scripts. - // Getting this method right involves the event loop, URL resolution - // script fetching etc. For now I just want to be able to parse - // documents and test the parser. - - //var script = stack.top; - stack.pop(); - parser = originalInsertionMode; - //script._prepare(); - return; - - // XXX: here is what this method is supposed to do - - // Provide a stable state. - - // Let script be the current node (which will be a script - // element). - - // Pop the current node off the stack of open elements. - - // Switch the insertion mode to the original insertion mode. - - // Let the old insertion point have the same value as the current - // insertion point. Let the insertion point be just before the - // next input character. - - // Increment the parser's script nesting level by one. - - // Prepare the script. This might cause some script to execute, - // which might cause new characters to be inserted into the - // tokenizer, and might cause the tokenizer to output more tokens, - // resulting in a reentrant invocation of the parser. - - // Decrement the parser's script nesting level by one. If the - // parser's script nesting level is zero, then set the parser - // pause flag to false. - - // Let the insertion point have the value of the old insertion - // point. (In other words, restore the insertion point to its - // previous value. This value might be the "undefined" value.) - - // At this stage, if there is a pending parsing-blocking script, - // then: - - // If the script nesting level is not zero: - - // Set the parser pause flag to true, and abort the processing - // of any nested invocations of the tokenizer, yielding - // control back to the caller. (Tokenization will resume when - // the caller returns to the "outer" tree construction stage.) - - // The tree construction stage of this particular parser is - // being called reentrantly, say from a call to - // document.write(). - - // Otherwise: - - // Run these steps: - - // Let the script be the pending parsing-blocking - // script. There is no longer a pending - // parsing-blocking script. - - // Block the tokenizer for this instance of the HTML - // parser, such that the event loop will not run tasks - // that invoke the tokenizer. - - // If the parser's Document has a style sheet that is - // blocking scripts or the script's "ready to be - // parser-executed" flag is not set: spin the event - // loop until the parser's Document has no style sheet - // that is blocking scripts and the script's "ready to - // be parser-executed" flag is set. - - // Unblock the tokenizer for this instance of the HTML - // parser, such that tasks that invoke the tokenizer - // can again be run. - - // Let the insertion point be just before the next - // input character. - - // Increment the parser's script nesting level by one - // (it should be zero before this step, so this sets - // it to one). - - // Execute the script. - - // Decrement the parser's script nesting level by - // one. If the parser's script nesting level is zero - // (which it always should be at this point), then set - // the parser pause flag to false. - - // Let the insertion point be undefined again. - - // If there is once again a pending parsing-blocking - // script, then repeat these steps from step 1. - } - - function stopParsing() { - // XXX This is just a temporary implementation to get the parser working. - // A full implementation involves scripts and events and the event loop. - - // Remove the link from document to parser. - // This is instead of "set the insertion point to undefined". - // It means that document.write() can't write into the doc anymore. - delete doc._parser; - - stack.elements.length = 0; // pop everything off - - // If there is a window object associated with the document - // then trigger an load event on it - if (doc.defaultView) { - doc.defaultView.dispatchEvent(new impl.Event('load', {})); - } - } - - /**** - * Tokenizer states - */ - - /** - * This file was partially mechanically generated from - * http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html - * - * After mechanical conversion, it was further converted from - * prose to JS by hand, but the intent is that it is a very - * faithful rendering of the HTML tokenization spec in - * JavaScript. - * - * It is not a goal of this tokenizer to detect or report - * parse errors. - * - * XXX The tokenizer is supposed to work with straight UTF32 - * codepoints. But I don't think it has any dependencies on - * any character outside of the BMP so I think it is safe to - * pass it UTF16 characters. I don't think it will ever change - * state in the middle of a surrogate pair. - */ - - /* - * Each state is represented by a function. For most states, the - * scanner simply passes the next character (as an integer - * codepoint) to the current state function and automatically - * consumes the character. If the state function can't process - * the character it can call pushback() to push it back to the - * scanner. - * - * Some states require lookahead, though. If a state function has - * a lookahead property, then it is invoked differently. In this - * case, the scanner invokes the function with 3 arguments: 1) the - * next codepoint 2) a string of lookahead text 3) a boolean that - * is true if the lookahead goes all the way to the EOF. (XXX - * actually maybe this third is not necessary... the lookahead - * could just include \uFFFF?) - * - * If the lookahead property of a state function is an integer, it - * specifies the number of characters required. If it is a string, - * then the scanner will scan for that string and return all - * characters up to and including that sequence, or up to EOF. If - * the lookahead property is a regexp, then the scanner will match - * the regexp at the current point and return the matching string. - * - * States that require lookahead are responsible for explicitly - * consuming the characters they process. They do this by - * incrementing nextchar by the number of processed characters. - */ - function reconsume(c, new_state) { - tokenizer = new_state; - nextchar--; // pushback - } - - function data_state(c) { - switch (c) { - case 0x0026: // AMPERSAND - return_state = data_state; - tokenizer = character_reference_state; - break; - case 0x003c: // LESS-THAN SIGN - if (emitSimpleTag()) - // Shortcut for <p>, <dl>, </div> etc. - break; - tokenizer = tag_open_state; - break; - case 0x0000: // NULL - // Usually null characters emitted by the tokenizer will be - // ignored by the tree builder, but sometimes they'll be - // converted to \uFFFD. I don't want to have the search every - // string emitted to replace NULs, so I'll set a flag - // if I've emitted a NUL. - textrun.push(c); - textIncludesNUL = true; - break; - case -1: // EOF - emitEOF(); - break; - default: - // Instead of just pushing a single character and then - // coming back to the very same place, lookahead and - // emit everything we can at once. - /*jshint -W030 */ - emitCharsWhile(DATATEXT) || textrun.push(c); - break; - } - } - - function rcdata_state(c) { - // Save the open tag so we can find a matching close tag - switch (c) { - case 0x0026: // AMPERSAND - return_state = rcdata_state; - tokenizer = character_reference_state; - break; - case 0x003c: // LESS-THAN SIGN - tokenizer = rcdata_less_than_sign_state; - break; - case 0x0000: // NULL - textrun.push(0xfffd); // REPLACEMENT CHARACTER - textIncludesNUL = true; - break; - case -1: // EOF - emitEOF(); - break; - default: - textrun.push(c); - break; - } - } - - function rawtext_state(c) { - switch (c) { - case 0x003c: // LESS-THAN SIGN - tokenizer = rawtext_less_than_sign_state; - break; - case 0x0000: // NULL - textrun.push(0xfffd); // REPLACEMENT CHARACTER - break; - case -1: // EOF - emitEOF(); - break; - default: - /*jshint -W030 */ - emitCharsWhile(RAWTEXT) || textrun.push(c); - break; - } - } - - function script_data_state(c) { - switch (c) { - case 0x003c: // LESS-THAN SIGN - tokenizer = script_data_less_than_sign_state; - break; - case 0x0000: // NULL - textrun.push(0xfffd); // REPLACEMENT CHARACTER - break; - case -1: // EOF - emitEOF(); - break; - default: - /*jshint -W030 */ - emitCharsWhile(RAWTEXT) || textrun.push(c); - break; - } - } - - function plaintext_state(c) { - switch (c) { - case 0x0000: // NULL - textrun.push(0xfffd); // REPLACEMENT CHARACTER - break; - case -1: // EOF - emitEOF(); - break; - default: - /*jshint -W030 */ - emitCharsWhile(PLAINTEXT) || textrun.push(c); - break; - } - } - - function tag_open_state(c) { - switch (c) { - case 0x0021: // EXCLAMATION MARK - tokenizer = markup_declaration_open_state; - break; - case 0x002f: // SOLIDUS - tokenizer = end_tag_open_state; - break; - case 0x0041: // [A-Z] - case 0x0042: - case 0x0043: - case 0x0044: - case 0x0045: - case 0x0046: - case 0x0047: - case 0x0048: - case 0x0049: - case 0x004a: - case 0x004b: - case 0x004c: - case 0x004d: - case 0x004e: - case 0x004f: - case 0x0050: - case 0x0051: - case 0x0052: - case 0x0053: - case 0x0054: - case 0x0055: - case 0x0056: - case 0x0057: - case 0x0058: - case 0x0059: - case 0x005a: - case 0x0061: // [a-z] - case 0x0062: - case 0x0063: - case 0x0064: - case 0x0065: - case 0x0066: - case 0x0067: - case 0x0068: - case 0x0069: - case 0x006a: - case 0x006b: - case 0x006c: - case 0x006d: - case 0x006e: - case 0x006f: - case 0x0070: - case 0x0071: - case 0x0072: - case 0x0073: - case 0x0074: - case 0x0075: - case 0x0076: - case 0x0077: - case 0x0078: - case 0x0079: - case 0x007a: - beginTagName(); - reconsume(c, tag_name_state); - break; - case 0x003f: // QUESTION MARK - reconsume(c, bogus_comment_state); - break; - default: // LESS-THAN SIGN - textrun.push(0x003c); - reconsume(c, data_state); - break; - } - } - - function end_tag_open_state(c) { - switch (c) { - case 0x0041: // [A-Z] - case 0x0042: - case 0x0043: - case 0x0044: - case 0x0045: - case 0x0046: - case 0x0047: - case 0x0048: - case 0x0049: - case 0x004a: - case 0x004b: - case 0x004c: - case 0x004d: - case 0x004e: - case 0x004f: - case 0x0050: - case 0x0051: - case 0x0052: - case 0x0053: - case 0x0054: - case 0x0055: - case 0x0056: - case 0x0057: - case 0x0058: - case 0x0059: - case 0x005a: - case 0x0061: // [a-z] - case 0x0062: - case 0x0063: - case 0x0064: - case 0x0065: - case 0x0066: - case 0x0067: - case 0x0068: - case 0x0069: - case 0x006a: - case 0x006b: - case 0x006c: - case 0x006d: - case 0x006e: - case 0x006f: - case 0x0070: - case 0x0071: - case 0x0072: - case 0x0073: - case 0x0074: - case 0x0075: - case 0x0076: - case 0x0077: - case 0x0078: - case 0x0079: - case 0x007a: - beginEndTagName(); - reconsume(c, tag_name_state); - break; - case 0x003e: // GREATER-THAN SIGN - tokenizer = data_state; - break; - case -1: // EOF - textrun.push(0x003c); // LESS-THAN SIGN - textrun.push(0x002f); // SOLIDUS - emitEOF(); - break; - default: - reconsume(c, bogus_comment_state); - break; - } - } - - function tag_name_state(c) { - switch (c) { - case 0x0009: // CHARACTER TABULATION (tab) - case 0x000a: // LINE FEED (LF) - case 0x000c: // FORM FEED (FF) - case 0x0020: // SPACE - tokenizer = before_attribute_name_state; - break; - case 0x002f: // SOLIDUS - tokenizer = self_closing_start_tag_state; - break; - case 0x003e: // GREATER-THAN SIGN - tokenizer = data_state; - emitTag(); - break; - case 0x0041: // [A-Z] - case 0x0042: - case 0x0043: - case 0x0044: - case 0x0045: - case 0x0046: - case 0x0047: - case 0x0048: - case 0x0049: - case 0x004a: - case 0x004b: - case 0x004c: - case 0x004d: - case 0x004e: - case 0x004f: - case 0x0050: - case 0x0051: - case 0x0052: - case 0x0053: - case 0x0054: - case 0x0055: - case 0x0056: - case 0x0057: - case 0x0058: - case 0x0059: - case 0x005a: - tagnamebuf += String.fromCharCode(c + 0x0020); - break; - case 0x0000: // NULL - tagnamebuf += String.fromCharCode(0xfffd /* REPLACEMENT CHARACTER */); - break; - case -1: // EOF - emitEOF(); - break; - default: - tagnamebuf += getMatchingChars(TAGNAME); - break; - } - } - - function rcdata_less_than_sign_state(c) { - /* identical to the RAWTEXT less-than sign state, except s/RAWTEXT/RCDATA/g */ - if (c === 0x002f) { - // SOLIDUS - beginTempBuf(); - tokenizer = rcdata_end_tag_open_state; - } else { - textrun.push(0x003c); // LESS-THAN SIGN - reconsume(c, rcdata_state); - } - } - - function rcdata_end_tag_open_state(c) { - /* identical to the RAWTEXT (and Script data) end tag open state, except s/RAWTEXT/RCDATA/g */ - switch (c) { - case 0x0041: // [A-Z] - case 0x0042: - case 0x0043: - case 0x0044: - case 0x0045: - case 0x0046: - case 0x0047: - case 0x0048: - case 0x0049: - case 0x004a: - case 0x004b: - case 0x004c: - case 0x004d: - case 0x004e: - case 0x004f: - case 0x0050: - case 0x0051: - case 0x0052: - case 0x0053: - case 0x0054: - case 0x0055: - case 0x0056: - case 0x0057: - case 0x0058: - case 0x0059: - case 0x005a: - case 0x0061: // [a-z] - case 0x0062: - case 0x0063: - case 0x0064: - case 0x0065: - case 0x0066: - case 0x0067: - case 0x0068: - case 0x0069: - case 0x006a: - case 0x006b: - case 0x006c: - case 0x006d: - case 0x006e: - case 0x006f: - case 0x0070: - case 0x0071: - case 0x0072: - case 0x0073: - case 0x0074: - case 0x0075: - case 0x0076: - case 0x0077: - case 0x0078: - case 0x0079: - case 0x007a: - beginEndTagName(); - reconsume(c, rcdata_end_tag_name_state); - break; - default: // LESS-THAN SIGN - // SOLIDUS - textrun.push(0x003c); - textrun.push(0x002f); - reconsume(c, rcdata_state); - break; - } - } - - function rcdata_end_tag_name_state(c) { - /* identical to the RAWTEXT (and Script data) end tag name state, except s/RAWTEXT/RCDATA/g */ - switch (c) { - case 0x0009: // CHARACTER TABULATION (tab) - case 0x000a: // LINE FEED (LF) - case 0x000c: // FORM FEED (FF) - case 0x0020: // SPACE - if (appropriateEndTag(tagnamebuf)) { - tokenizer = before_attribute_name_state; - return; - } - break; - case 0x002f: // SOLIDUS - if (appropriateEndTag(tagnamebuf)) { - tokenizer = self_closing_start_tag_state; - return; - } - break; - case 0x003e: // GREATER-THAN SIGN - if (appropriateEndTag(tagnamebuf)) { - tokenizer = data_state; - emitTag(); - return; - } - break; - case 0x0041: // [A-Z] - case 0x0042: - case 0x0043: - case 0x0044: - case 0x0045: - case 0x0046: - case 0x0047: - case 0x0048: - case 0x0049: - case 0x004a: - case 0x004b: - case 0x004c: - case 0x004d: - case 0x004e: - case 0x004f: - case 0x0050: - case 0x0051: - case 0x0052: - case 0x0053: - case 0x0054: - case 0x0055: - case 0x0056: - case 0x0057: - case 0x0058: - case 0x0059: - case 0x005a: - tagnamebuf += String.fromCharCode(c + 0x0020); - tempbuf.push(c); - return; - case 0x0061: // [a-z] - case 0x0062: - case 0x0063: - case 0x0064: - case 0x0065: - case 0x0066: - case 0x0067: - case 0x0068: - case 0x0069: - case 0x006a: - case 0x006b: - case 0x006c: - case 0x006d: - case 0x006e: - case 0x006f: - case 0x0070: - case 0x0071: - case 0x0072: - case 0x0073: - case 0x0074: - case 0x0075: - case 0x0076: - case 0x0077: - case 0x0078: - case 0x0079: - case 0x007a: - tagnamebuf += String.fromCharCode(c); - tempbuf.push(c); - return; - default: - break; - } - - // If we don't return in one of the cases above, then this was not - // an appropriately matching close tag, so back out by emitting all - // the characters as text - textrun.push(0x003c); // LESS-THAN SIGN - textrun.push(0x002f); // SOLIDUS - pushAll(textrun, tempbuf); - reconsume(c, rcdata_state); - } - - function rawtext_less_than_sign_state(c) { - /* identical to the RCDATA less-than sign state, except s/RCDATA/RAWTEXT/g - */ - if (c === 0x002f) { - // SOLIDUS - beginTempBuf(); - tokenizer = rawtext_end_tag_open_state; - } else { - textrun.push(0x003c); // LESS-THAN SIGN - reconsume(c, rawtext_state); - } - } - - function rawtext_end_tag_open_state(c) { - /* identical to the RCDATA (and Script data) end tag open state, except s/RCDATA/RAWTEXT/g */ - switch (c) { - case 0x0041: // [A-Z] - case 0x0042: - case 0x0043: - case 0x0044: - case 0x0045: - case 0x0046: - case 0x0047: - case 0x0048: - case 0x0049: - case 0x004a: - case 0x004b: - case 0x004c: - case 0x004d: - case 0x004e: - case 0x004f: - case 0x0050: - case 0x0051: - case 0x0052: - case 0x0053: - case 0x0054: - case 0x0055: - case 0x0056: - case 0x0057: - case 0x0058: - case 0x0059: - case 0x005a: - case 0x0061: // [a-z] - case 0x0062: - case 0x0063: - case 0x0064: - case 0x0065: - case 0x0066: - case 0x0067: - case 0x0068: - case 0x0069: - case 0x006a: - case 0x006b: - case 0x006c: - case 0x006d: - case 0x006e: - case 0x006f: - case 0x0070: - case 0x0071: - case 0x0072: - case 0x0073: - case 0x0074: - case 0x0075: - case 0x0076: - case 0x0077: - case 0x0078: - case 0x0079: - case 0x007a: - beginEndTagName(); - reconsume(c, rawtext_end_tag_name_state); - break; - default: // LESS-THAN SIGN - // SOLIDUS - textrun.push(0x003c); - textrun.push(0x002f); - reconsume(c, rawtext_state); - break; - } - } - - function rawtext_end_tag_name_state(c) { - /* identical to the RCDATA (and Script data) end tag name state, except s/RCDATA/RAWTEXT/g */ - switch (c) { - case 0x0009: // CHARACTER TABULATION (tab) - case 0x000a: // LINE FEED (LF) - case 0x000c: // FORM FEED (FF) - case 0x0020: // SPACE - if (appropriateEndTag(tagnamebuf)) { - tokenizer = before_attribute_name_state; - return; - } - break; - case 0x002f: // SOLIDUS - if (appropriateEndTag(tagnamebuf)) { - tokenizer = self_closing_start_tag_state; - return; - } - break; - case 0x003e: // GREATER-THAN SIGN - if (appropriateEndTag(tagnamebuf)) { - tokenizer = data_state; - emitTag(); - return; - } - break; - case 0x0041: // [A-Z] - case 0x0042: - case 0x0043: - case 0x0044: - case 0x0045: - case 0x0046: - case 0x0047: - case 0x0048: - case 0x0049: - case 0x004a: - case 0x004b: - case 0x004c: - case 0x004d: - case 0x004e: - case 0x004f: - case 0x0050: - case 0x0051: - case 0x0052: - case 0x0053: - case 0x0054: - case 0x0055: - case 0x0056: - case 0x0057: - case 0x0058: - case 0x0059: - case 0x005a: - tagnamebuf += String.fromCharCode(c + 0x0020); - tempbuf.push(c); - return; - case 0x0061: // [a-z] - case 0x0062: - case 0x0063: - case 0x0064: - case 0x0065: - case 0x0066: - case 0x0067: - case 0x0068: - case 0x0069: - case 0x006a: - case 0x006b: - case 0x006c: - case 0x006d: - case 0x006e: - case 0x006f: - case 0x0070: - case 0x0071: - case 0x0072: - case 0x0073: - case 0x0074: - case 0x0075: - case 0x0076: - case 0x0077: - case 0x0078: - case 0x0079: - case 0x007a: - tagnamebuf += String.fromCharCode(c); - tempbuf.push(c); - return; - default: - break; - } - - // If we don't return in one of the cases above, then this was not - // an appropriately matching close tag, so back out by emitting all - // the characters as text - textrun.push(0x003c); // LESS-THAN SIGN - textrun.push(0x002f); // SOLIDUS - pushAll(textrun, tempbuf); - reconsume(c, rawtext_state); - } - - function script_data_less_than_sign_state(c) { - switch (c) { - case 0x002f: // SOLIDUS - beginTempBuf(); - tokenizer = script_data_end_tag_open_state; - break; - case 0x0021: // EXCLAMATION MARK - tokenizer = script_data_escape_start_state; - textrun.push(0x003c); // LESS-THAN SIGN - textrun.push(0x0021); // EXCLAMATION MARK - break; - default: // LESS-THAN SIGN - textrun.push(0x003c); - reconsume(c, script_data_state); - break; - } - } - - function script_data_end_tag_open_state(c) { - /* identical to the RCDATA (and RAWTEXT) end tag open state, except s/RCDATA/Script data/g */ - switch (c) { - case 0x0041: // [A-Z] - case 0x0042: - case 0x0043: - case 0x0044: - case 0x0045: - case 0x0046: - case 0x0047: - case 0x0048: - case 0x0049: - case 0x004a: - case 0x004b: - case 0x004c: - case 0x004d: - case 0x004e: - case 0x004f: - case 0x0050: - case 0x0051: - case 0x0052: - case 0x0053: - case 0x0054: - case 0x0055: - case 0x0056: - case 0x0057: - case 0x0058: - case 0x0059: - case 0x005a: - case 0x0061: // [a-z] - case 0x0062: - case 0x0063: - case 0x0064: - case 0x0065: - case 0x0066: - case 0x0067: - case 0x0068: - case 0x0069: - case 0x006a: - case 0x006b: - case 0x006c: - case 0x006d: - case 0x006e: - case 0x006f: - case 0x0070: - case 0x0071: - case 0x0072: - case 0x0073: - case 0x0074: - case 0x0075: - case 0x0076: - case 0x0077: - case 0x0078: - case 0x0079: - case 0x007a: - beginEndTagName(); - reconsume(c, script_data_end_tag_name_state); - break; - default: // LESS-THAN SIGN - // SOLIDUS - textrun.push(0x003c); - textrun.push(0x002f); - reconsume(c, script_data_state); - break; - } - } - - function script_data_end_tag_name_state(c) { - /* identical to the RCDATA (and RAWTEXT) end tag name state, except s/RCDATA/Script data/g */ - switch (c) { - case 0x0009: // CHARACTER TABULATION (tab) - case 0x000a: // LINE FEED (LF) - case 0x000c: // FORM FEED (FF) - case 0x0020: // SPACE - if (appropriateEndTag(tagnamebuf)) { - tokenizer = before_attribute_name_state; - return; - } - break; - case 0x002f: // SOLIDUS - if (appropriateEndTag(tagnamebuf)) { - tokenizer = self_closing_start_tag_state; - return; - } - break; - case 0x003e: // GREATER-THAN SIGN - if (appropriateEndTag(tagnamebuf)) { - tokenizer = data_state; - emitTag(); - return; - } - break; - case 0x0041: // [A-Z] - case 0x0042: - case 0x0043: - case 0x0044: - case 0x0045: - case 0x0046: - case 0x0047: - case 0x0048: - case 0x0049: - case 0x004a: - case 0x004b: - case 0x004c: - case 0x004d: - case 0x004e: - case 0x004f: - case 0x0050: - case 0x0051: - case 0x0052: - case 0x0053: - case 0x0054: - case 0x0055: - case 0x0056: - case 0x0057: - case 0x0058: - case 0x0059: - case 0x005a: - tagnamebuf += String.fromCharCode(c + 0x0020); - tempbuf.push(c); - return; - case 0x0061: // [a-z] - case 0x0062: - case 0x0063: - case 0x0064: - case 0x0065: - case 0x0066: - case 0x0067: - case 0x0068: - case 0x0069: - case 0x006a: - case 0x006b: - case 0x006c: - case 0x006d: - case 0x006e: - case 0x006f: - case 0x0070: - case 0x0071: - case 0x0072: - case 0x0073: - case 0x0074: - case 0x0075: - case 0x0076: - case 0x0077: - case 0x0078: - case 0x0079: - case 0x007a: - tagnamebuf += String.fromCharCode(c); - tempbuf.push(c); - return; - default: - break; - } - - // If we don't return in one of the cases above, then this was not - // an appropriately matching close tag, so back out by emitting all - // the characters as text - textrun.push(0x003c); // LESS-THAN SIGN - textrun.push(0x002f); // SOLIDUS - pushAll(textrun, tempbuf); - reconsume(c, script_data_state); - } - - function script_data_escape_start_state(c) { - if (c === 0x002d) { - // HYPHEN-MINUS - tokenizer = script_data_escape_start_dash_state; - textrun.push(0x002d); // HYPHEN-MINUS - } else { - reconsume(c, script_data_state); - } - } - - function script_data_escape_start_dash_state(c) { - if (c === 0x002d) { - // HYPHEN-MINUS - tokenizer = script_data_escaped_dash_dash_state; - textrun.push(0x002d); // HYPHEN-MINUS - } else { - reconsume(c, script_data_state); - } - } - - function script_data_escaped_state(c) { - switch (c) { - case 0x002d: // HYPHEN-MINUS - tokenizer = script_data_escaped_dash_state; - textrun.push(0x002d); // HYPHEN-MINUS - break; - case 0x003c: // LESS-THAN SIGN - tokenizer = script_data_escaped_less_than_sign_state; - break; - case 0x0000: // NULL - textrun.push(0xfffd); // REPLACEMENT CHARACTER - break; - case -1: // EOF - emitEOF(); - break; - default: - textrun.push(c); - break; - } - } - - function script_data_escaped_dash_state(c) { - switch (c) { - case 0x002d: // HYPHEN-MINUS - tokenizer = script_data_escaped_dash_dash_state; - textrun.push(0x002d); // HYPHEN-MINUS - break; - case 0x003c: // LESS-THAN SIGN - tokenizer = script_data_escaped_less_than_sign_state; - break; - case 0x0000: // NULL - tokenizer = script_data_escaped_state; - textrun.push(0xfffd); // REPLACEMENT CHARACTER - break; - case -1: // EOF - emitEOF(); - break; - default: - tokenizer = script_data_escaped_state; - textrun.push(c); - break; - } - } - - function script_data_escaped_dash_dash_state(c) { - switch (c) { - case 0x002d: // HYPHEN-MINUS - textrun.push(0x002d); // HYPHEN-MINUS - break; - case 0x003c: // LESS-THAN SIGN - tokenizer = script_data_escaped_less_than_sign_state; - break; - case 0x003e: // GREATER-THAN SIGN - tokenizer = script_data_state; - textrun.push(0x003e); // GREATER-THAN SIGN - break; - case 0x0000: // NULL - tokenizer = script_data_escaped_state; - textrun.push(0xfffd); // REPLACEMENT CHARACTER - break; - case -1: // EOF - emitEOF(); - break; - default: - tokenizer = script_data_escaped_state; - textrun.push(c); - break; - } - } - - function script_data_escaped_less_than_sign_state(c) { - switch (c) { - case 0x002f: // SOLIDUS - beginTempBuf(); - tokenizer = script_data_escaped_end_tag_open_state; - break; - case 0x0041: // [A-Z] - case 0x0042: - case 0x0043: - case 0x0044: - case 0x0045: - case 0x0046: - case 0x0047: - case 0x0048: - case 0x0049: - case 0x004a: - case 0x004b: - case 0x004c: - case 0x004d: - case 0x004e: - case 0x004f: - case 0x0050: - case 0x0051: - case 0x0052: - case 0x0053: - case 0x0054: - case 0x0055: - case 0x0056: - case 0x0057: - case 0x0058: - case 0x0059: - case 0x005a: - case 0x0061: // [a-z] - case 0x0062: - case 0x0063: - case 0x0064: - case 0x0065: - case 0x0066: - case 0x0067: - case 0x0068: - case 0x0069: - case 0x006a: - case 0x006b: - case 0x006c: - case 0x006d: - case 0x006e: - case 0x006f: - case 0x0070: - case 0x0071: - case 0x0072: - case 0x0073: - case 0x0074: - case 0x0075: - case 0x0076: - case 0x0077: - case 0x0078: - case 0x0079: - case 0x007a: - beginTempBuf(); - textrun.push(0x003c); // LESS-THAN SIGN - reconsume(c, script_data_double_escape_start_state); - break; - default: // LESS-THAN SIGN - textrun.push(0x003c); - reconsume(c, script_data_escaped_state); - break; - } - } - - function script_data_escaped_end_tag_open_state(c) { - switch (c) { - case 0x0041: // [A-Z] - case 0x0042: - case 0x0043: - case 0x0044: - case 0x0045: - case 0x0046: - case 0x0047: - case 0x0048: - case 0x0049: - case 0x004a: - case 0x004b: - case 0x004c: - case 0x004d: - case 0x004e: - case 0x004f: - case 0x0050: - case 0x0051: - case 0x0052: - case 0x0053: - case 0x0054: - case 0x0055: - case 0x0056: - case 0x0057: - case 0x0058: - case 0x0059: - case 0x005a: - case 0x0061: // [a-z] - case 0x0062: - case 0x0063: - case 0x0064: - case 0x0065: - case 0x0066: - case 0x0067: - case 0x0068: - case 0x0069: - case 0x006a: - case 0x006b: - case 0x006c: - case 0x006d: - case 0x006e: - case 0x006f: - case 0x0070: - case 0x0071: - case 0x0072: - case 0x0073: - case 0x0074: - case 0x0075: - case 0x0076: - case 0x0077: - case 0x0078: - case 0x0079: - case 0x007a: - beginEndTagName(); - reconsume(c, script_data_escaped_end_tag_name_state); - break; - default: // LESS-THAN SIGN - // SOLIDUS - textrun.push(0x003c); - textrun.push(0x002f); - reconsume(c, script_data_escaped_state); - break; - } - } - - function script_data_escaped_end_tag_name_state(c) { - switch (c) { - case 0x0009: // CHARACTER TABULATION (tab) - case 0x000a: // LINE FEED (LF) - case 0x000c: // FORM FEED (FF) - case 0x0020: // SPACE - if (appropriateEndTag(tagnamebuf)) { - tokenizer = before_attribute_name_state; - return; - } - break; - case 0x002f: // SOLIDUS - if (appropriateEndTag(tagnamebuf)) { - tokenizer = self_closing_start_tag_state; - return; - } - break; - case 0x003e: // GREATER-THAN SIGN - if (appropriateEndTag(tagnamebuf)) { - tokenizer = data_state; - emitTag(); - return; - } - break; - case 0x0041: // [A-Z] - case 0x0042: - case 0x0043: - case 0x0044: - case 0x0045: - case 0x0046: - case 0x0047: - case 0x0048: - case 0x0049: - case 0x004a: - case 0x004b: - case 0x004c: - case 0x004d: - case 0x004e: - case 0x004f: - case 0x0050: - case 0x0051: - case 0x0052: - case 0x0053: - case 0x0054: - case 0x0055: - case 0x0056: - case 0x0057: - case 0x0058: - case 0x0059: - case 0x005a: - tagnamebuf += String.fromCharCode(c + 0x0020); - tempbuf.push(c); - return; - case 0x0061: // [a-z] - case 0x0062: - case 0x0063: - case 0x0064: - case 0x0065: - case 0x0066: - case 0x0067: - case 0x0068: - case 0x0069: - case 0x006a: - case 0x006b: - case 0x006c: - case 0x006d: - case 0x006e: - case 0x006f: - case 0x0070: - case 0x0071: - case 0x0072: - case 0x0073: - case 0x0074: - case 0x0075: - case 0x0076: - case 0x0077: - case 0x0078: - case 0x0079: - case 0x007a: - tagnamebuf += String.fromCharCode(c); - tempbuf.push(c); - return; - default: - break; - } - - // We get here in the default case, and if the closing tagname - // is not an appropriate tagname. - textrun.push(0x003c); // LESS-THAN SIGN - textrun.push(0x002f); // SOLIDUS - pushAll(textrun, tempbuf); - reconsume(c, script_data_escaped_state); - } - - function script_data_double_escape_start_state(c) { - switch (c) { - case 0x0009: // CHARACTER TABULATION (tab) - case 0x000a: // LINE FEED (LF) - case 0x000c: // FORM FEED (FF) - case 0x0020: // SPACE - case 0x002f: // SOLIDUS - case 0x003e: // GREATER-THAN SIGN - if (buf2str(tempbuf) === 'script') { - tokenizer = script_data_double_escaped_state; - } else { - tokenizer = script_data_escaped_state; - } - textrun.push(c); - break; - case 0x0041: // [A-Z] - case 0x0042: - case 0x0043: - case 0x0044: - case 0x0045: - case 0x0046: - case 0x0047: - case 0x0048: - case 0x0049: - case 0x004a: - case 0x004b: - case 0x004c: - case 0x004d: - case 0x004e: - case 0x004f: - case 0x0050: - case 0x0051: - case 0x0052: - case 0x0053: - case 0x0054: - case 0x0055: - case 0x0056: - case 0x0057: - case 0x0058: - case 0x0059: - case 0x005a: - tempbuf.push(c + 0x0020); - textrun.push(c); - break; - case 0x0061: // [a-z] - case 0x0062: - case 0x0063: - case 0x0064: - case 0x0065: - case 0x0066: - case 0x0067: - case 0x0068: - case 0x0069: - case 0x006a: - case 0x006b: - case 0x006c: - case 0x006d: - case 0x006e: - case 0x006f: - case 0x0070: - case 0x0071: - case 0x0072: - case 0x0073: - case 0x0074: - case 0x0075: - case 0x0076: - case 0x0077: - case 0x0078: - case 0x0079: - case 0x007a: - tempbuf.push(c); - textrun.push(c); - break; - default: - reconsume(c, script_data_escaped_state); - break; - } - } - - function script_data_double_escaped_state(c) { - switch (c) { - case 0x002d: // HYPHEN-MINUS - tokenizer = script_data_double_escaped_dash_state; - textrun.push(0x002d); // HYPHEN-MINUS - break; - case 0x003c: // LESS-THAN SIGN - tokenizer = script_data_double_escaped_less_than_sign_state; - textrun.push(0x003c); // LESS-THAN SIGN - break; - case 0x0000: // NULL - textrun.push(0xfffd); // REPLACEMENT CHARACTER - break; - case -1: // EOF - emitEOF(); - break; - default: - textrun.push(c); - break; - } - } - - function script_data_double_escaped_dash_state(c) { - switch (c) { - case 0x002d: // HYPHEN-MINUS - tokenizer = script_data_double_escaped_dash_dash_state; - textrun.push(0x002d); // HYPHEN-MINUS - break; - case 0x003c: // LESS-THAN SIGN - tokenizer = script_data_double_escaped_less_than_sign_state; - textrun.push(0x003c); // LESS-THAN SIGN - break; - case 0x0000: // NULL - tokenizer = script_data_double_escaped_state; - textrun.push(0xfffd); // REPLACEMENT CHARACTER - break; - case -1: // EOF - emitEOF(); - break; - default: - tokenizer = script_data_double_escaped_state; - textrun.push(c); - break; - } - } - - function script_data_double_escaped_dash_dash_state(c) { - switch (c) { - case 0x002d: // HYPHEN-MINUS - textrun.push(0x002d); // HYPHEN-MINUS - break; - case 0x003c: // LESS-THAN SIGN - tokenizer = script_data_double_escaped_less_than_sign_state; - textrun.push(0x003c); // LESS-THAN SIGN - break; - case 0x003e: // GREATER-THAN SIGN - tokenizer = script_data_state; - textrun.push(0x003e); // GREATER-THAN SIGN - break; - case 0x0000: // NULL - tokenizer = script_data_double_escaped_state; - textrun.push(0xfffd); // REPLACEMENT CHARACTER - break; - case -1: // EOF - emitEOF(); - break; - default: - tokenizer = script_data_double_escaped_state; - textrun.push(c); - break; - } - } - - function script_data_double_escaped_less_than_sign_state(c) { - if (c === 0x002f) { - // SOLIDUS - beginTempBuf(); - tokenizer = script_data_double_escape_end_state; - textrun.push(0x002f); // SOLIDUS - } else { - reconsume(c, script_data_double_escaped_state); - } - } - - function script_data_double_escape_end_state(c) { - switch (c) { - case 0x0009: // CHARACTER TABULATION (tab) - case 0x000a: // LINE FEED (LF) - case 0x000c: // FORM FEED (FF) - case 0x0020: // SPACE - case 0x002f: // SOLIDUS - case 0x003e: // GREATER-THAN SIGN - if (buf2str(tempbuf) === 'script') { - tokenizer = script_data_escaped_state; - } else { - tokenizer = script_data_double_escaped_state; - } - textrun.push(c); - break; - case 0x0041: // [A-Z] - case 0x0042: - case 0x0043: - case 0x0044: - case 0x0045: - case 0x0046: - case 0x0047: - case 0x0048: - case 0x0049: - case 0x004a: - case 0x004b: - case 0x004c: - case 0x004d: - case 0x004e: - case 0x004f: - case 0x0050: - case 0x0051: - case 0x0052: - case 0x0053: - case 0x0054: - case 0x0055: - case 0x0056: - case 0x0057: - case 0x0058: - case 0x0059: - case 0x005a: - tempbuf.push(c + 0x0020); - textrun.push(c); - break; - case 0x0061: // [a-z] - case 0x0062: - case 0x0063: - case 0x0064: - case 0x0065: - case 0x0066: - case 0x0067: - case 0x0068: - case 0x0069: - case 0x006a: - case 0x006b: - case 0x006c: - case 0x006d: - case 0x006e: - case 0x006f: - case 0x0070: - case 0x0071: - case 0x0072: - case 0x0073: - case 0x0074: - case 0x0075: - case 0x0076: - case 0x0077: - case 0x0078: - case 0x0079: - case 0x007a: - tempbuf.push(c); - textrun.push(c); - break; - default: - reconsume(c, script_data_double_escaped_state); - break; - } - } - - function before_attribute_name_state(c) { - switch (c) { - case 0x0009: // CHARACTER TABULATION (tab) - case 0x000a: // LINE FEED (LF) - case 0x000c: // FORM FEED (FF) - case 0x0020: // SPACE - /* Ignore the character. */ - break; - // For SOLIDUS, GREATER-THAN SIGN, and EOF, spec says "reconsume in - // the after attribute name state", but in our implementation that - // state always has an active attribute in attrnamebuf. Just clone - // the rules here, without the addAttribute business. - case 0x002f: // SOLIDUS - tokenizer = self_closing_start_tag_state; - break; - case 0x003e: // GREATER-THAN SIGN - tokenizer = data_state; - emitTag(); - break; - case -1: // EOF - emitEOF(); - break; - case 0x003d: // EQUALS SIGN - beginAttrName(); - attrnamebuf += String.fromCharCode(c); - tokenizer = attribute_name_state; - break; - default: - if (handleSimpleAttribute()) break; - beginAttrName(); - reconsume(c, attribute_name_state); - break; - } - } - - // beginAttrName() must have been called before this point - // There is an active attribute in attrnamebuf (but not attrvaluebuf) - function attribute_name_state(c) { - switch (c) { - case 0x0009: // CHARACTER TABULATION (tab) - case 0x000a: // LINE FEED (LF) - case 0x000c: // FORM FEED (FF) - case 0x0020: // SPACE - case 0x002f: // SOLIDUS - case 0x003e: // GREATER-THAN SIGN - case -1: // EOF - reconsume(c, after_attribute_name_state); - break; - case 0x003d: // EQUALS SIGN - tokenizer = before_attribute_value_state; - break; - case 0x0041: // [A-Z] - case 0x0042: - case 0x0043: - case 0x0044: - case 0x0045: - case 0x0046: - case 0x0047: - case 0x0048: - case 0x0049: - case 0x004a: - case 0x004b: - case 0x004c: - case 0x004d: - case 0x004e: - case 0x004f: - case 0x0050: - case 0x0051: - case 0x0052: - case 0x0053: - case 0x0054: - case 0x0055: - case 0x0056: - case 0x0057: - case 0x0058: - case 0x0059: - case 0x005a: - attrnamebuf += String.fromCharCode(c + 0x0020); - break; - case 0x0000: // NULL - attrnamebuf += String.fromCharCode(0xfffd /* REPLACEMENT CHARACTER */); - break; - case 0x0022: // QUOTATION MARK - case 0x0027: // APOSTROPHE - case 0x003c: // LESS-THAN SIGN - /* falls through */ - default: - attrnamebuf += getMatchingChars(ATTRNAME); - break; - } - } - - // There is an active attribute in attrnamebuf, but not yet in attrvaluebuf. - function after_attribute_name_state(c) { - switch (c) { - case 0x0009: // CHARACTER TABULATION (tab) - case 0x000a: // LINE FEED (LF) - case 0x000c: // FORM FEED (FF) - case 0x0020: // SPACE - /* Ignore the character. */ - break; - case 0x002f: // SOLIDUS - // Keep in sync with before_attribute_name_state. - addAttribute(attrnamebuf); - tokenizer = self_closing_start_tag_state; - break; - case 0x003d: // EQUALS SIGN - tokenizer = before_attribute_value_state; - break; - case 0x003e: // GREATER-THAN SIGN - // Keep in sync with before_attribute_name_state. - tokenizer = data_state; - addAttribute(attrnamebuf); - emitTag(); - break; - case -1: // EOF - // Keep in sync with before_attribute_name_state. - addAttribute(attrnamebuf); - emitEOF(); - break; - default: - addAttribute(attrnamebuf); - beginAttrName(); - reconsume(c, attribute_name_state); - break; - } - } - - function before_attribute_value_state(c) { - switch (c) { - case 0x0009: // CHARACTER TABULATION (tab) - case 0x000a: // LINE FEED (LF) - case 0x000c: // FORM FEED (FF) - case 0x0020: // SPACE - /* Ignore the character. */ - break; - case 0x0022: // QUOTATION MARK - beginAttrValue(); - tokenizer = attribute_value_double_quoted_state; - break; - case 0x0027: // APOSTROPHE - beginAttrValue(); - tokenizer = attribute_value_single_quoted_state; - break; - case 0x003e: // GREATER-THAN SIGN - /* falls through */ - default: - beginAttrValue(); - reconsume(c, attribute_value_unquoted_state); - break; - } - } - - function attribute_value_double_quoted_state(c) { - switch (c) { - case 0x0022: // QUOTATION MARK - addAttribute(attrnamebuf, attrvaluebuf); - tokenizer = after_attribute_value_quoted_state; - break; - case 0x0026: // AMPERSAND - return_state = attribute_value_double_quoted_state; - tokenizer = character_reference_state; - break; - case 0x0000: // NULL - attrvaluebuf += String.fromCharCode(0xfffd /* REPLACEMENT CHARACTER */); - break; - case -1: // EOF - emitEOF(); - break; - case 0x000a: // LF - // this could be a converted \r, so don't use getMatchingChars - attrvaluebuf += String.fromCharCode(c); - break; - default: - attrvaluebuf += getMatchingChars(DBLQUOTEATTRVAL); - break; - } - } - - function attribute_value_single_quoted_state(c) { - switch (c) { - case 0x0027: // APOSTROPHE - addAttribute(attrnamebuf, attrvaluebuf); - tokenizer = after_attribute_value_quoted_state; - break; - case 0x0026: // AMPERSAND - return_state = attribute_value_single_quoted_state; - tokenizer = character_reference_state; - break; - case 0x0000: // NULL - attrvaluebuf += String.fromCharCode(0xfffd /* REPLACEMENT CHARACTER */); - break; - case -1: // EOF - emitEOF(); - break; - case 0x000a: // LF - // this could be a converted \r, so don't use getMatchingChars - attrvaluebuf += String.fromCharCode(c); - break; - default: - attrvaluebuf += getMatchingChars(SINGLEQUOTEATTRVAL); - break; - } - } - - function attribute_value_unquoted_state(c) { - switch (c) { - case 0x0009: // CHARACTER TABULATION (tab) - case 0x000a: // LINE FEED (LF) - case 0x000c: // FORM FEED (FF) - case 0x0020: // SPACE - addAttribute(attrnamebuf, attrvaluebuf); - tokenizer = before_attribute_name_state; - break; - case 0x0026: // AMPERSAND - return_state = attribute_value_unquoted_state; - tokenizer = character_reference_state; - break; - case 0x003e: // GREATER-THAN SIGN - addAttribute(attrnamebuf, attrvaluebuf); - tokenizer = data_state; - emitTag(); - break; - case 0x0000: // NULL - attrvaluebuf += String.fromCharCode(0xfffd /* REPLACEMENT CHARACTER */); - break; - case -1: // EOF - nextchar--; // pushback - tokenizer = data_state; - break; - case 0x0022: // QUOTATION MARK - case 0x0027: // APOSTROPHE - case 0x003c: // LESS-THAN SIGN - case 0x003d: // EQUALS SIGN - case 0x0060: // GRAVE ACCENT - /* falls through */ - default: - attrvaluebuf += getMatchingChars(UNQUOTEDATTRVAL); - break; - } - } - - function after_attribute_value_quoted_state(c) { - switch (c) { - case 0x0009: // CHARACTER TABULATION (tab) - case 0x000a: // LINE FEED (LF) - case 0x000c: // FORM FEED (FF) - case 0x0020: // SPACE - tokenizer = before_attribute_name_state; - break; - case 0x002f: // SOLIDUS - tokenizer = self_closing_start_tag_state; - break; - case 0x003e: // GREATER-THAN SIGN - tokenizer = data_state; - emitTag(); - break; - case -1: // EOF - emitEOF(); - break; - default: - reconsume(c, before_attribute_name_state); - break; - } - } - - function self_closing_start_tag_state(c) { - switch (c) { - case 0x003e: // GREATER-THAN SIGN - // Set the <i>self-closing flag</i> of the current tag token. - tokenizer = data_state; - emitSelfClosingTag(true); - break; - case -1: // EOF - emitEOF(); - break; - default: - reconsume(c, before_attribute_name_state); - break; - } - } - - function bogus_comment_state(c, lookahead, eof) { - var len = lookahead.length; - - if (eof) { - nextchar += len - 1; // don't consume the eof - } else { - nextchar += len; - } - - var comment = lookahead.substring(0, len - 1); - - comment = comment.replace(/\u0000/g, '\uFFFD'); - comment = comment.replace(/\u000D\u000A/g, '\u000A'); - comment = comment.replace(/\u000D/g, '\u000A'); - - insertToken(COMMENT, comment); - tokenizer = data_state; - } - bogus_comment_state.lookahead = '>'; - - function markup_declaration_open_state(c, lookahead, eof) { - if (lookahead[0] === '-' && lookahead[1] === '-') { - nextchar += 2; - beginComment(); - tokenizer = comment_start_state; - return; - } - - if (lookahead.toUpperCase() === 'DOCTYPE') { - nextchar += 7; - tokenizer = doctype_state; - } else if (lookahead === '[CDATA[' && cdataAllowed()) { - nextchar += 7; - tokenizer = cdata_section_state; - } else { - tokenizer = bogus_comment_state; - } - } - markup_declaration_open_state.lookahead = 7; - - function comment_start_state(c) { - beginComment(); - switch (c) { - case 0x002d: // HYPHEN-MINUS - tokenizer = comment_start_dash_state; - break; - case 0x003e: // GREATER-THAN SIGN - tokenizer = data_state; - insertToken(COMMENT, buf2str(commentbuf)); - break; /* see comment in comment end state */ - default: - reconsume(c, comment_state); - break; - } - } - - function comment_start_dash_state(c) { - switch (c) { - case 0x002d: // HYPHEN-MINUS - tokenizer = comment_end_state; - break; - case 0x003e: // GREATER-THAN SIGN - tokenizer = data_state; - insertToken(COMMENT, buf2str(commentbuf)); - break; - case -1: // EOF - insertToken(COMMENT, buf2str(commentbuf)); - emitEOF(); - break; /* see comment in comment end state */ - default: - commentbuf.push(0x002d /* HYPHEN-MINUS */); - reconsume(c, comment_state); - break; - } - } - - function comment_state(c) { - switch (c) { - case 0x003c: // LESS-THAN SIGN - commentbuf.push(c); - tokenizer = comment_less_than_sign_state; - break; - case 0x002d: // HYPHEN-MINUS - tokenizer = comment_end_dash_state; - break; - case 0x0000: // NULL - commentbuf.push(0xfffd /* REPLACEMENT CHARACTER */); - break; - case -1: // EOF - insertToken(COMMENT, buf2str(commentbuf)); - emitEOF(); - break; /* see comment in comment end state */ - default: - commentbuf.push(c); - break; - } - } - - function comment_less_than_sign_state(c) { - switch (c) { - case 0x0021: // EXCLAMATION MARK - commentbuf.push(c); - tokenizer = comment_less_than_sign_bang_state; - break; - case 0x003c: // LESS-THAN SIGN - commentbuf.push(c); - break; - default: - reconsume(c, comment_state); - break; - } - } - - function comment_less_than_sign_bang_state(c) { - switch (c) { - case 0x002d: // HYPHEN-MINUS - tokenizer = comment_less_than_sign_bang_dash_state; - break; - default: - reconsume(c, comment_state); - break; - } - } - - function comment_less_than_sign_bang_dash_state(c) { - switch (c) { - case 0x002d: // HYPHEN-MINUS - tokenizer = comment_less_than_sign_bang_dash_dash_state; - break; - default: - reconsume(c, comment_end_dash_state); - break; - } - } - - function comment_less_than_sign_bang_dash_dash_state(c) { - switch (c) { - case 0x003e: // GREATER-THAN SIGN - case -1: // EOF - reconsume(c, comment_end_state); - break; - default: - // parse error - reconsume(c, comment_end_state); - break; - } - } - - function comment_end_dash_state(c) { - switch (c) { - case 0x002d: // HYPHEN-MINUS - tokenizer = comment_end_state; - break; - case -1: // EOF - insertToken(COMMENT, buf2str(commentbuf)); - emitEOF(); - break; /* see comment in comment end state */ - default: - commentbuf.push(0x002d /* HYPHEN-MINUS */); - reconsume(c, comment_state); - break; - } - } - - function comment_end_state(c) { - switch (c) { - case 0x003e: // GREATER-THAN SIGN - tokenizer = data_state; - insertToken(COMMENT, buf2str(commentbuf)); - break; - case 0x0021: // EXCLAMATION MARK - tokenizer = comment_end_bang_state; - break; - case 0x002d: // HYPHEN-MINUS - commentbuf.push(0x002d); - break; - case -1: // EOF - insertToken(COMMENT, buf2str(commentbuf)); - emitEOF(); - break; /* For security reasons: otherwise, hostile user could put a script in a comment e.g. in a blog comment and then DOS the server so that the end tag isn't read, and then the commented script tag would be treated as live code */ - default: - commentbuf.push(0x002d); - commentbuf.push(0x002d); - reconsume(c, comment_state); - break; - } - } - - function comment_end_bang_state(c) { - switch (c) { - case 0x002d: // HYPHEN-MINUS - commentbuf.push(0x002d); - commentbuf.push(0x002d); - commentbuf.push(0x0021); - tokenizer = comment_end_dash_state; - break; - case 0x003e: // GREATER-THAN SIGN - tokenizer = data_state; - insertToken(COMMENT, buf2str(commentbuf)); - break; - case -1: // EOF - insertToken(COMMENT, buf2str(commentbuf)); - emitEOF(); - break; /* see comment in comment end state */ - default: - commentbuf.push(0x002d); - commentbuf.push(0x002d); - commentbuf.push(0x0021); - reconsume(c, comment_state); - break; - } - } - - function doctype_state(c) { - switch (c) { - case 0x0009: // CHARACTER TABULATION (tab) - case 0x000a: // LINE FEED (LF) - case 0x000c: // FORM FEED (FF) - case 0x0020: // SPACE - tokenizer = before_doctype_name_state; - break; - case -1: // EOF - beginDoctype(); - forcequirks(); - emitDoctype(); - emitEOF(); - break; - default: - reconsume(c, before_doctype_name_state); - break; - } - } - - function before_doctype_name_state(c) { - switch (c) { - case 0x0009: // CHARACTER TABULATION (tab) - case 0x000a: // LINE FEED (LF) - case 0x000c: // FORM FEED (FF) - case 0x0020: // SPACE - /* Ignore the character. */ - break; - case 0x0041: // [A-Z] - case 0x0042: - case 0x0043: - case 0x0044: - case 0x0045: - case 0x0046: - case 0x0047: - case 0x0048: - case 0x0049: - case 0x004a: - case 0x004b: - case 0x004c: - case 0x004d: - case 0x004e: - case 0x004f: - case 0x0050: - case 0x0051: - case 0x0052: - case 0x0053: - case 0x0054: - case 0x0055: - case 0x0056: - case 0x0057: - case 0x0058: - case 0x0059: - case 0x005a: - beginDoctype(); - doctypenamebuf.push(c + 0x0020); - tokenizer = doctype_name_state; - break; - case 0x0000: // NULL - beginDoctype(); - doctypenamebuf.push(0xfffd); - tokenizer = doctype_name_state; - break; - case 0x003e: // GREATER-THAN SIGN - beginDoctype(); - forcequirks(); - tokenizer = data_state; - emitDoctype(); - break; - case -1: // EOF - beginDoctype(); - forcequirks(); - emitDoctype(); - emitEOF(); - break; - default: - beginDoctype(); - doctypenamebuf.push(c); - tokenizer = doctype_name_state; - break; - } - } - - function doctype_name_state(c) { - switch (c) { - case 0x0009: // CHARACTER TABULATION (tab) - case 0x000a: // LINE FEED (LF) - case 0x000c: // FORM FEED (FF) - case 0x0020: // SPACE - tokenizer = after_doctype_name_state; - break; - case 0x003e: // GREATER-THAN SIGN - tokenizer = data_state; - emitDoctype(); - break; - case 0x0041: // [A-Z] - case 0x0042: - case 0x0043: - case 0x0044: - case 0x0045: - case 0x0046: - case 0x0047: - case 0x0048: - case 0x0049: - case 0x004a: - case 0x004b: - case 0x004c: - case 0x004d: - case 0x004e: - case 0x004f: - case 0x0050: - case 0x0051: - case 0x0052: - case 0x0053: - case 0x0054: - case 0x0055: - case 0x0056: - case 0x0057: - case 0x0058: - case 0x0059: - case 0x005a: - doctypenamebuf.push(c + 0x0020); - break; - case 0x0000: // NULL - doctypenamebuf.push(0xfffd /* REPLACEMENT CHARACTER */); - break; - case -1: // EOF - forcequirks(); - emitDoctype(); - emitEOF(); - break; - default: - doctypenamebuf.push(c); - break; - } - } - - function after_doctype_name_state(c, lookahead, eof) { - switch (c) { - case 0x0009: // CHARACTER TABULATION (tab) - case 0x000a: // LINE FEED (LF) - case 0x000c: // FORM FEED (FF) - case 0x0020: // SPACE - /* Ignore the character. */ - nextchar += 1; - break; - case 0x003e: // GREATER-THAN SIGN - tokenizer = data_state; - nextchar += 1; - emitDoctype(); - break; - case -1: // EOF - forcequirks(); - emitDoctype(); - emitEOF(); - break; - default: - lookahead = lookahead.toUpperCase(); - if (lookahead === 'PUBLIC') { - nextchar += 6; - tokenizer = after_doctype_public_keyword_state; - } else if (lookahead === 'SYSTEM') { - nextchar += 6; - tokenizer = after_doctype_system_keyword_state; - } else { - forcequirks(); - tokenizer = bogus_doctype_state; - } - break; - } - } - after_doctype_name_state.lookahead = 6; - - function after_doctype_public_keyword_state(c) { - switch (c) { - case 0x0009: // CHARACTER TABULATION (tab) - case 0x000a: // LINE FEED (LF) - case 0x000c: // FORM FEED (FF) - case 0x0020: // SPACE - tokenizer = before_doctype_public_identifier_state; - break; - case 0x0022: // QUOTATION MARK - beginDoctypePublicId(); - tokenizer = doctype_public_identifier_double_quoted_state; - break; - case 0x0027: // APOSTROPHE - beginDoctypePublicId(); - tokenizer = doctype_public_identifier_single_quoted_state; - break; - case 0x003e: // GREATER-THAN SIGN - forcequirks(); - tokenizer = data_state; - emitDoctype(); - break; - case -1: // EOF - forcequirks(); - emitDoctype(); - emitEOF(); - break; - default: - forcequirks(); - tokenizer = bogus_doctype_state; - break; - } - } - - function before_doctype_public_identifier_state(c) { - switch (c) { - case 0x0009: // CHARACTER TABULATION (tab) - case 0x000a: // LINE FEED (LF) - case 0x000c: // FORM FEED (FF) - case 0x0020: // SPACE - /* Ignore the character. */ - break; - case 0x0022: // QUOTATION MARK - beginDoctypePublicId(); - tokenizer = doctype_public_identifier_double_quoted_state; - break; - case 0x0027: // APOSTROPHE - beginDoctypePublicId(); - tokenizer = doctype_public_identifier_single_quoted_state; - break; - case 0x003e: // GREATER-THAN SIGN - forcequirks(); - tokenizer = data_state; - emitDoctype(); - break; - case -1: // EOF - forcequirks(); - emitDoctype(); - emitEOF(); - break; - default: - forcequirks(); - tokenizer = bogus_doctype_state; - break; - } - } - - function doctype_public_identifier_double_quoted_state(c) { - switch (c) { - case 0x0022: // QUOTATION MARK - tokenizer = after_doctype_public_identifier_state; - break; - case 0x0000: // NULL - doctypepublicbuf.push(0xfffd /* REPLACEMENT CHARACTER */); - break; - case 0x003e: // GREATER-THAN SIGN - forcequirks(); - tokenizer = data_state; - emitDoctype(); - break; - case -1: // EOF - forcequirks(); - emitDoctype(); - emitEOF(); - break; - default: - doctypepublicbuf.push(c); - break; - } - } - - function doctype_public_identifier_single_quoted_state(c) { - switch (c) { - case 0x0027: // APOSTROPHE - tokenizer = after_doctype_public_identifier_state; - break; - case 0x0000: // NULL - doctypepublicbuf.push(0xfffd /* REPLACEMENT CHARACTER */); - break; - case 0x003e: // GREATER-THAN SIGN - forcequirks(); - tokenizer = data_state; - emitDoctype(); - break; - case -1: // EOF - forcequirks(); - emitDoctype(); - emitEOF(); - break; - default: - doctypepublicbuf.push(c); - break; - } - } - - function after_doctype_public_identifier_state(c) { - switch (c) { - case 0x0009: // CHARACTER TABULATION (tab) - case 0x000a: // LINE FEED (LF) - case 0x000c: // FORM FEED (FF) - case 0x0020: // SPACE - tokenizer = between_doctype_public_and_system_identifiers_state; - break; - case 0x003e: // GREATER-THAN SIGN - tokenizer = data_state; - emitDoctype(); - break; - case 0x0022: // QUOTATION MARK - beginDoctypeSystemId(); - tokenizer = doctype_system_identifier_double_quoted_state; - break; - case 0x0027: // APOSTROPHE - beginDoctypeSystemId(); - tokenizer = doctype_system_identifier_single_quoted_state; - break; - case -1: // EOF - forcequirks(); - emitDoctype(); - emitEOF(); - break; - default: - forcequirks(); - tokenizer = bogus_doctype_state; - break; - } - } - - function between_doctype_public_and_system_identifiers_state(c) { - switch (c) { - case 0x0009: // CHARACTER TABULATION (tab) - case 0x000a: // LINE FEED (LF) - case 0x000c: // FORM FEED (FF) - case 0x0020: // SPACE Ignore the character. - break; - case 0x003e: // GREATER-THAN SIGN - tokenizer = data_state; - emitDoctype(); - break; - case 0x0022: // QUOTATION MARK - beginDoctypeSystemId(); - tokenizer = doctype_system_identifier_double_quoted_state; - break; - case 0x0027: // APOSTROPHE - beginDoctypeSystemId(); - tokenizer = doctype_system_identifier_single_quoted_state; - break; - case -1: // EOF - forcequirks(); - emitDoctype(); - emitEOF(); - break; - default: - forcequirks(); - tokenizer = bogus_doctype_state; - break; - } - } - - function after_doctype_system_keyword_state(c) { - switch (c) { - case 0x0009: // CHARACTER TABULATION (tab) - case 0x000a: // LINE FEED (LF) - case 0x000c: // FORM FEED (FF) - case 0x0020: // SPACE - tokenizer = before_doctype_system_identifier_state; - break; - case 0x0022: // QUOTATION MARK - beginDoctypeSystemId(); - tokenizer = doctype_system_identifier_double_quoted_state; - break; - case 0x0027: // APOSTROPHE - beginDoctypeSystemId(); - tokenizer = doctype_system_identifier_single_quoted_state; - break; - case 0x003e: // GREATER-THAN SIGN - forcequirks(); - tokenizer = data_state; - emitDoctype(); - break; - case -1: // EOF - forcequirks(); - emitDoctype(); - emitEOF(); - break; - default: - forcequirks(); - tokenizer = bogus_doctype_state; - break; - } - } - - function before_doctype_system_identifier_state(c) { - switch (c) { - case 0x0009: // CHARACTER TABULATION (tab) - case 0x000a: // LINE FEED (LF) - case 0x000c: // FORM FEED (FF) - case 0x0020: // SPACE Ignore the character. - break; - case 0x0022: // QUOTATION MARK - beginDoctypeSystemId(); - tokenizer = doctype_system_identifier_double_quoted_state; - break; - case 0x0027: // APOSTROPHE - beginDoctypeSystemId(); - tokenizer = doctype_system_identifier_single_quoted_state; - break; - case 0x003e: // GREATER-THAN SIGN - forcequirks(); - tokenizer = data_state; - emitDoctype(); - break; - case -1: // EOF - forcequirks(); - emitDoctype(); - emitEOF(); - break; - default: - forcequirks(); - tokenizer = bogus_doctype_state; - break; - } - } - - function doctype_system_identifier_double_quoted_state(c) { - switch (c) { - case 0x0022: // QUOTATION MARK - tokenizer = after_doctype_system_identifier_state; - break; - case 0x0000: // NULL - doctypesystembuf.push(0xfffd /* REPLACEMENT CHARACTER */); - break; - case 0x003e: // GREATER-THAN SIGN - forcequirks(); - tokenizer = data_state; - emitDoctype(); - break; - case -1: // EOF - forcequirks(); - emitDoctype(); - emitEOF(); - break; - default: - doctypesystembuf.push(c); - break; - } - } - - function doctype_system_identifier_single_quoted_state(c) { - switch (c) { - case 0x0027: // APOSTROPHE - tokenizer = after_doctype_system_identifier_state; - break; - case 0x0000: // NULL - doctypesystembuf.push(0xfffd /* REPLACEMENT CHARACTER */); - break; - case 0x003e: // GREATER-THAN SIGN - forcequirks(); - tokenizer = data_state; - emitDoctype(); - break; - case -1: // EOF - forcequirks(); - emitDoctype(); - emitEOF(); - break; - default: - doctypesystembuf.push(c); - break; - } - } - - function after_doctype_system_identifier_state(c) { - switch (c) { - case 0x0009: // CHARACTER TABULATION (tab) - case 0x000a: // LINE FEED (LF) - case 0x000c: // FORM FEED (FF) - case 0x0020: // SPACE - /* Ignore the character. */ - break; - case 0x003e: // GREATER-THAN SIGN - tokenizer = data_state; - emitDoctype(); - break; - case -1: // EOF - forcequirks(); - emitDoctype(); - emitEOF(); - break; - default: - tokenizer = bogus_doctype_state; - /* This does *not* set the DOCTYPE token's force-quirks flag. */ - break; - } - } - - function bogus_doctype_state(c) { - switch (c) { - case 0x003e: // GREATER-THAN SIGN - tokenizer = data_state; - emitDoctype(); - break; - case -1: // EOF - emitDoctype(); - emitEOF(); - break; - default: - /* Ignore the character. */ - break; - } - } - - function cdata_section_state(c) { - switch (c) { - case 0x005d: // RIGHT SQUARE BRACKET - tokenizer = cdata_section_bracket_state; - break; - case -1: // EOF - emitEOF(); - break; - case 0x0000: // NULL - textIncludesNUL = true; - /* fall through */ - default: - // Instead of just pushing a single character and then - // coming back to the very same place, lookahead and - // emit everything we can at once. - /*jshint -W030 */ - emitCharsWhile(CDATATEXT) || textrun.push(c); - break; - } - } - - function cdata_section_bracket_state(c) { - switch (c) { - case 0x005d: // RIGHT SQUARE BRACKET - tokenizer = cdata_section_end_state; - break; - default: - textrun.push(0x005d); - reconsume(c, cdata_section_state); - break; - } - } - - function cdata_section_end_state(c) { - switch (c) { - case 0x005d: // RIGHT SQUARE BRACKET - textrun.push(0x005d); - break; - case 0x003e: // GREATER-THAN SIGN - flushText(); - tokenizer = data_state; - break; - default: - textrun.push(0x005d); - textrun.push(0x005d); - reconsume(c, cdata_section_state); - break; - } - } - - function character_reference_state(c) { - beginTempBuf(); - tempbuf.push(0x0026); - switch (c) { - case 0x0009: // TAB - case 0x000a: // LINE FEED - case 0x000c: // FORM FEED - case 0x0020: // SPACE - case 0x003c: // LESS-THAN SIGN - case 0x0026: // AMPERSAND - case -1: // EOF - reconsume(c, character_reference_end_state); - break; - case 0x0023: // NUMBER SIGN - tempbuf.push(c); - tokenizer = numeric_character_reference_state; - break; - default: - reconsume(c, named_character_reference_state); - break; - } - } - - function named_character_reference_state(c) { - NAMEDCHARREF.lastIndex = nextchar; // w/ lookahead no char has been consumed - var matched = NAMEDCHARREF.exec(chars); - if (!matched) throw new Error('should never happen'); - var name = matched[1]; - if (!name) { - // If no match can be made, switch to the character reference end state - tokenizer = character_reference_end_state; - return; - } - - // Consume the matched characters and append them to temporary buffer - nextchar += name.length; - pushAll(tempbuf, str2buf(name)); - - switch (return_state) { - case attribute_value_double_quoted_state: - case attribute_value_single_quoted_state: - case attribute_value_unquoted_state: - // If the character reference was consumed as part of an attribute... - if (name[name.length - 1] !== ';') { - // ...and the last char is not ; - if (/[=A-Za-z0-9]/.test(chars[nextchar])) { - tokenizer = character_reference_end_state; - return; - } - } - break; - default: - break; - } - - beginTempBuf(); - var rv = namedCharRefs[name]; - if (typeof rv === 'number') { - tempbuf.push(rv); - } else { - pushAll(tempbuf, rv); - } - tokenizer = character_reference_end_state; - } - // We might need to pause tokenization until we have enough characters - // in the buffer for longest possible character reference. - named_character_reference_state.lookahead = -NAMEDCHARREF_MAXLEN; - - function numeric_character_reference_state(c) { - character_reference_code = 0; - switch (c) { - case 0x0078: // x - case 0x0058: // X - tempbuf.push(c); - tokenizer = hexadecimal_character_reference_start_state; - break; - default: - reconsume(c, decimal_character_reference_start_state); - break; - } - } - - function hexadecimal_character_reference_start_state(c) { - switch (c) { - case 0x0030: - case 0x0031: - case 0x0032: - case 0x0033: - case 0x0034: - case 0x0035: - case 0x0036: - case 0x0037: - case 0x0038: - case 0x0039: // [0-9] - case 0x0041: - case 0x0042: - case 0x0043: - case 0x0044: - case 0x0045: - case 0x0046: // [A-F] - case 0x0061: - case 0x0062: - case 0x0063: - case 0x0064: - case 0x0065: - case 0x0066: // [a-f] - reconsume(c, hexadecimal_character_reference_state); - break; - default: - reconsume(c, character_reference_end_state); - break; - } - } - - function decimal_character_reference_start_state(c) { - switch (c) { - case 0x0030: - case 0x0031: - case 0x0032: - case 0x0033: - case 0x0034: - case 0x0035: - case 0x0036: - case 0x0037: - case 0x0038: - case 0x0039: // [0-9] - reconsume(c, decimal_character_reference_state); - break; - default: - reconsume(c, character_reference_end_state); - break; - } - } - - function hexadecimal_character_reference_state(c) { - switch (c) { - case 0x0041: - case 0x0042: - case 0x0043: - case 0x0044: - case 0x0045: - case 0x0046: // [A-F] - character_reference_code *= 16; - character_reference_code += c - 0x0037; - break; - case 0x0061: - case 0x0062: - case 0x0063: - case 0x0064: - case 0x0065: - case 0x0066: // [a-f] - character_reference_code *= 16; - character_reference_code += c - 0x0057; - break; - case 0x0030: - case 0x0031: - case 0x0032: - case 0x0033: - case 0x0034: - case 0x0035: - case 0x0036: - case 0x0037: - case 0x0038: - case 0x0039: // [0-9] - character_reference_code *= 16; - character_reference_code += c - 0x0030; - break; - case 0x003b: // SEMICOLON - tokenizer = numeric_character_reference_end_state; - break; - default: - reconsume(c, numeric_character_reference_end_state); - break; - } - } - - function decimal_character_reference_state(c) { - switch (c) { - case 0x0030: - case 0x0031: - case 0x0032: - case 0x0033: - case 0x0034: - case 0x0035: - case 0x0036: - case 0x0037: - case 0x0038: - case 0x0039: // [0-9] - character_reference_code *= 10; - character_reference_code += c - 0x0030; - break; - case 0x003b: // SEMICOLON - tokenizer = numeric_character_reference_end_state; - break; - default: - reconsume(c, numeric_character_reference_end_state); - break; - } - } - - function numeric_character_reference_end_state(c) { - if (character_reference_code in numericCharRefReplacements) { - character_reference_code = numericCharRefReplacements[character_reference_code]; - } else if ( - character_reference_code > 0x10ffff || - (character_reference_code >= 0xd800 && character_reference_code < 0xe000) - ) { - character_reference_code = 0xfffd; - } - - beginTempBuf(); - if (character_reference_code <= 0xffff) { - tempbuf.push(character_reference_code); - } else { - character_reference_code = character_reference_code - 0x10000; - /* jshint bitwise: false */ - tempbuf.push(0xd800 + (character_reference_code >> 10)); - tempbuf.push(0xdc00 + (character_reference_code & 0x03ff)); - } - reconsume(c, character_reference_end_state); - } - - function character_reference_end_state(c) { - switch (return_state) { - case attribute_value_double_quoted_state: - case attribute_value_single_quoted_state: - case attribute_value_unquoted_state: - // append each character to the current attribute's value - attrvaluebuf += buf2str(tempbuf); - break; - default: - pushAll(textrun, tempbuf); - break; - } - reconsume(c, return_state); - } - - /*** - * The tree builder insertion modes - */ - - // 11.2.5.4.1 The "initial" insertion mode - function initial_mode(t, value, arg3, arg4) { - switch (t) { - case 1: // TEXT - value = value.replace(LEADINGWS, ''); // Ignore spaces - if (value.length === 0) return; // Are we done? - break; // Handle anything non-space text below - case 4: // COMMENT - doc._appendChild(doc.createComment(value)); - return; - case 5: // DOCTYPE - var name = value; - var publicid = arg3; - var systemid = arg4; - // Use the constructor directly instead of - // implementation.createDocumentType because the create - // function throws errors on invalid characters, and - // we don't want the parser to throw them. - doc.appendChild(new DocumentType(doc, name, publicid, systemid)); - - // Note that there is no public API for setting quirks mode We can - // do this here because we have access to implementation details - if ( - force_quirks || - name.toLowerCase() !== 'html' || - quirkyPublicIds.test(publicid) || - (systemid && systemid.toLowerCase() === quirkySystemId) || - (systemid === undefined && conditionallyQuirkyPublicIds.test(publicid)) - ) - doc._quirks = true; - else if ( - limitedQuirkyPublicIds.test(publicid) || - (systemid !== undefined && conditionallyQuirkyPublicIds.test(publicid)) - ) - doc._limitedQuirks = true; - parser = before_html_mode; - return; - } - - // tags or non-whitespace text - doc._quirks = true; - parser = before_html_mode; - parser(t, value, arg3, arg4); - } - - // 11.2.5.4.2 The "before html" insertion mode - function before_html_mode(t, value, arg3, arg4) { - var elt; - switch (t) { - case 1: // TEXT - value = value.replace(LEADINGWS, ''); // Ignore spaces - if (value.length === 0) return; // Are we done? - break; // Handle anything non-space text below - case 5: // DOCTYPE - /* ignore the token */ - return; - case 4: // COMMENT - doc._appendChild(doc.createComment(value)); - return; - case 2: // TAG - if (value === 'html') { - elt = createHTMLElt(doc, value, arg3); - stack.push(elt); - doc.appendChild(elt); - // XXX: handle application cache here - parser = before_head_mode; - return; - } - break; - case 3: // ENDTAG - switch (value) { - case 'html': - case 'head': - case 'body': - case 'br': - break; // fall through on these - default: - return; // ignore most end tags - } - } - - // Anything that didn't get handled above is handled like this: - elt = createHTMLElt(doc, 'html', null); - stack.push(elt); - doc.appendChild(elt); - // XXX: handle application cache here - parser = before_head_mode; - parser(t, value, arg3, arg4); - } - - // 11.2.5.4.3 The "before head" insertion mode - function before_head_mode(t, value, arg3, arg4) { - switch (t) { - case 1: // TEXT - value = value.replace(LEADINGWS, ''); // Ignore spaces - if (value.length === 0) return; // Are we done? - break; // Handle anything non-space text below - case 5: // DOCTYPE - /* ignore the token */ - return; - case 4: // COMMENT - insertComment(value); - return; - case 2: // TAG - switch (value) { - case 'html': - in_body_mode(t, value, arg3, arg4); - return; - case 'head': - var elt = insertHTMLElement(value, arg3); - head_element_pointer = elt; - parser = in_head_mode; - return; - } - break; - case 3: // ENDTAG - switch (value) { - case 'html': - case 'head': - case 'body': - case 'br': - break; - default: - return; // ignore most end tags - } - } - - // If not handled explicitly above - before_head_mode(TAG, 'head', null); // create a head tag - parser(t, value, arg3, arg4); // then try again with this token - } - - function in_head_mode(t, value, arg3, arg4) { - switch (t) { - case 1: // TEXT - var ws = value.match(LEADINGWS); - if (ws) { - insertText(ws[0]); - value = value.substring(ws[0].length); - } - if (value.length === 0) return; - break; // Handle non-whitespace below - case 4: // COMMENT - insertComment(value); - return; - case 5: // DOCTYPE - return; - case 2: // TAG - switch (value) { - case 'html': - in_body_mode(t, value, arg3, arg4); - return; - case 'meta': - // XXX: - // May need to change the encoding based on this tag - /* falls through */ - case 'base': - case 'basefont': - case 'bgsound': - case 'link': - insertHTMLElement(value, arg3); - stack.pop(); - return; - case 'title': - parseRCDATA(value, arg3); - return; - case 'noscript': - if (!scripting_enabled) { - insertHTMLElement(value, arg3); - parser = in_head_noscript_mode; - return; - } - // Otherwise, if scripting is enabled... - /* falls through */ - case 'noframes': - case 'style': - parseRawText(value, arg3); - return; - case 'script': - insertElement(function (doc) { - var elt = createHTMLElt(doc, value, arg3); - elt._parser_inserted = true; - elt._force_async = false; - if (fragment) elt._already_started = true; - flushText(); - return elt; - }); - tokenizer = script_data_state; - originalInsertionMode = parser; - parser = text_mode; - return; - case 'template': - insertHTMLElement(value, arg3); - afe.insertMarker(); - frameset_ok = false; - parser = in_template_mode; - templateInsertionModes.push(parser); - return; - case 'head': - return; // ignore it - } - break; - case 3: // ENDTAG - switch (value) { - case 'head': - stack.pop(); - parser = after_head_mode; - return; - case 'body': - case 'html': - case 'br': - break; // handle these at the bottom of the function - case 'template': - if (!stack.contains('template')) { - return; - } - stack.generateImpliedEndTags(null, 'thorough'); - stack.popTag('template'); - afe.clearToMarker(); - templateInsertionModes.pop(); - resetInsertionMode(); - return; - default: - // ignore any other end tag - return; - } - break; - } - - // If not handled above - in_head_mode(ENDTAG, 'head', null); // synthetic </head> - parser(t, value, arg3, arg4); // Then redo this one - } - - // 13.2.5.4.5 The "in head noscript" insertion mode - function in_head_noscript_mode(t, value, arg3, arg4) { - switch (t) { - case 5: // DOCTYPE - return; - case 4: // COMMENT - in_head_mode(t, value); - return; - case 1: // TEXT - var ws = value.match(LEADINGWS); - if (ws) { - in_head_mode(t, ws[0]); - value = value.substring(ws[0].length); - } - if (value.length === 0) return; // no more text - break; // Handle non-whitespace below - case 2: // TAG - switch (value) { - case 'html': - in_body_mode(t, value, arg3, arg4); - return; - case 'basefont': - case 'bgsound': - case 'link': - case 'meta': - case 'noframes': - case 'style': - in_head_mode(t, value, arg3); - return; - case 'head': - case 'noscript': - return; - } - break; - case 3: // ENDTAG - switch (value) { - case 'noscript': - stack.pop(); - parser = in_head_mode; - return; - case 'br': - break; // goes to the outer default - default: - return; // ignore other end tags - } - break; - } - - // If not handled above - in_head_noscript_mode(ENDTAG, 'noscript', null); - parser(t, value, arg3, arg4); - } - - function after_head_mode(t, value, arg3, arg4) { - switch (t) { - case 1: // TEXT - var ws = value.match(LEADINGWS); - if (ws) { - insertText(ws[0]); - value = value.substring(ws[0].length); - } - if (value.length === 0) return; - break; // Handle non-whitespace below - case 4: // COMMENT - insertComment(value); - return; - case 5: // DOCTYPE - return; - case 2: // TAG - switch (value) { - case 'html': - in_body_mode(t, value, arg3, arg4); - return; - case 'body': - insertHTMLElement(value, arg3); - frameset_ok = false; - parser = in_body_mode; - return; - case 'frameset': - insertHTMLElement(value, arg3); - parser = in_frameset_mode; - return; - case 'base': - case 'basefont': - case 'bgsound': - case 'link': - case 'meta': - case 'noframes': - case 'script': - case 'style': - case 'template': - case 'title': - stack.push(head_element_pointer); - in_head_mode(TAG, value, arg3); - stack.removeElement(head_element_pointer); - return; - case 'head': - return; - } - break; - case 3: // ENDTAG - switch (value) { - case 'template': - return in_head_mode(t, value, arg3, arg4); - case 'body': - case 'html': - case 'br': - break; - default: - return; // ignore any other end tag - } - break; - } - - after_head_mode(TAG, 'body', null); - frameset_ok = true; - parser(t, value, arg3, arg4); - } - - // 13.2.5.4.7 The "in body" insertion mode - function in_body_mode(t, value, arg3, arg4) { - var body, i, node, elt; - switch (t) { - case 1: // TEXT - if (textIncludesNUL) { - value = value.replace(NULCHARS, ''); - if (value.length === 0) return; - } - // If any non-space characters - if (frameset_ok && NONWS.test(value)) frameset_ok = false; - afereconstruct(); - insertText(value); - return; - case 5: // DOCTYPE - return; - case 4: // COMMENT - insertComment(value); - return; - case -1: // EOF - if (templateInsertionModes.length) { - return in_template_mode(t); - } - stopParsing(); - return; - case 2: // TAG - switch (value) { - case 'html': - if (stack.contains('template')) { - return; - } - transferAttributes(arg3, stack.elements[0]); - return; - case 'base': - case 'basefont': - case 'bgsound': - case 'link': - case 'meta': - case 'noframes': - case 'script': - case 'style': - case 'template': - case 'title': - in_head_mode(TAG, value, arg3); - return; - case 'body': - body = stack.elements[1]; - if (!body || !(body instanceof impl.HTMLBodyElement) || stack.contains('template')) - return; - frameset_ok = false; - transferAttributes(arg3, body); - return; - case 'frameset': - if (!frameset_ok) return; - body = stack.elements[1]; - if (!body || !(body instanceof impl.HTMLBodyElement)) return; - if (body.parentNode) body.parentNode.removeChild(body); - while (!(stack.top instanceof impl.HTMLHtmlElement)) stack.pop(); - insertHTMLElement(value, arg3); - parser = in_frameset_mode; - return; - - case 'address': - case 'article': - case 'aside': - case 'blockquote': - case 'center': - case 'details': - case 'dialog': - case 'dir': - case 'div': - case 'dl': - case 'fieldset': - case 'figcaption': - case 'figure': - case 'footer': - case 'header': - case 'hgroup': - case 'main': - case 'nav': - case 'ol': - case 'p': - case 'section': - case 'summary': - case 'ul': - if (stack.inButtonScope('p')) in_body_mode(ENDTAG, 'p'); - insertHTMLElement(value, arg3); - return; - - case 'menu': - if (stack.inButtonScope('p')) in_body_mode(ENDTAG, 'p'); - if (isA(stack.top, 'menuitem')) { - stack.pop(); - } - insertHTMLElement(value, arg3); - return; - - case 'h1': - case 'h2': - case 'h3': - case 'h4': - case 'h5': - case 'h6': - if (stack.inButtonScope('p')) in_body_mode(ENDTAG, 'p'); - if (stack.top instanceof impl.HTMLHeadingElement) stack.pop(); - insertHTMLElement(value, arg3); - return; - - case 'pre': - case 'listing': - if (stack.inButtonScope('p')) in_body_mode(ENDTAG, 'p'); - insertHTMLElement(value, arg3); - ignore_linefeed = true; - frameset_ok = false; - return; - - case 'form': - if (form_element_pointer && !stack.contains('template')) return; - if (stack.inButtonScope('p')) in_body_mode(ENDTAG, 'p'); - elt = insertHTMLElement(value, arg3); - if (!stack.contains('template')) form_element_pointer = elt; - return; - - case 'li': - frameset_ok = false; - for (i = stack.elements.length - 1; i >= 0; i--) { - node = stack.elements[i]; - if (node instanceof impl.HTMLLIElement) { - in_body_mode(ENDTAG, 'li'); - break; - } - if (isA(node, specialSet) && !isA(node, addressdivpSet)) break; - } - if (stack.inButtonScope('p')) in_body_mode(ENDTAG, 'p'); - insertHTMLElement(value, arg3); - return; - - case 'dd': - case 'dt': - frameset_ok = false; - for (i = stack.elements.length - 1; i >= 0; i--) { - node = stack.elements[i]; - if (isA(node, dddtSet)) { - in_body_mode(ENDTAG, node.localName); - break; - } - if (isA(node, specialSet) && !isA(node, addressdivpSet)) break; - } - if (stack.inButtonScope('p')) in_body_mode(ENDTAG, 'p'); - insertHTMLElement(value, arg3); - return; - - case 'plaintext': - if (stack.inButtonScope('p')) in_body_mode(ENDTAG, 'p'); - insertHTMLElement(value, arg3); - tokenizer = plaintext_state; - return; - - case 'button': - if (stack.inScope('button')) { - in_body_mode(ENDTAG, 'button'); - parser(t, value, arg3, arg4); - } else { - afereconstruct(); - insertHTMLElement(value, arg3); - frameset_ok = false; - } - return; - - case 'a': - var activeElement = afe.findElementByTag('a'); - if (activeElement) { - in_body_mode(ENDTAG, value); - afe.remove(activeElement); - stack.removeElement(activeElement); - } - /* falls through */ - case 'b': - case 'big': - case 'code': - case 'em': - case 'font': - case 'i': - case 's': - case 'small': - case 'strike': - case 'strong': - case 'tt': - case 'u': - afereconstruct(); - afe.push(insertHTMLElement(value, arg3), arg3); - return; - - case 'nobr': - afereconstruct(); - - if (stack.inScope(value)) { - in_body_mode(ENDTAG, value); - afereconstruct(); - } - afe.push(insertHTMLElement(value, arg3), arg3); - return; - - case 'applet': - case 'marquee': - case 'object': - afereconstruct(); - insertHTMLElement(value, arg3); - afe.insertMarker(); - frameset_ok = false; - return; - - case 'table': - if (!doc._quirks && stack.inButtonScope('p')) { - in_body_mode(ENDTAG, 'p'); - } - insertHTMLElement(value, arg3); - frameset_ok = false; - parser = in_table_mode; - return; - - case 'area': - case 'br': - case 'embed': - case 'img': - case 'keygen': - case 'wbr': - afereconstruct(); - insertHTMLElement(value, arg3); - stack.pop(); - frameset_ok = false; - return; - - case 'input': - afereconstruct(); - elt = insertHTMLElement(value, arg3); - stack.pop(); - var type = elt.getAttribute('type'); - if (!type || type.toLowerCase() !== 'hidden') frameset_ok = false; - return; - - case 'param': - case 'source': - case 'track': - insertHTMLElement(value, arg3); - stack.pop(); - return; - - case 'hr': - if (stack.inButtonScope('p')) in_body_mode(ENDTAG, 'p'); - if (isA(stack.top, 'menuitem')) { - stack.pop(); - } - insertHTMLElement(value, arg3); - stack.pop(); - frameset_ok = false; - return; - - case 'image': - in_body_mode(TAG, 'img', arg3, arg4); - return; - - case 'textarea': - insertHTMLElement(value, arg3); - ignore_linefeed = true; - frameset_ok = false; - tokenizer = rcdata_state; - originalInsertionMode = parser; - parser = text_mode; - return; - - case 'xmp': - if (stack.inButtonScope('p')) in_body_mode(ENDTAG, 'p'); - afereconstruct(); - frameset_ok = false; - parseRawText(value, arg3); - return; - - case 'iframe': - frameset_ok = false; - parseRawText(value, arg3); - return; - - case 'noembed': - parseRawText(value, arg3); - return; - - case 'noscript': - if (scripting_enabled) { - parseRawText(value, arg3); - return; - } - break; // XXX Otherwise treat it as any other open tag? - - case 'select': - afereconstruct(); - insertHTMLElement(value, arg3); - frameset_ok = false; - if ( - parser === in_table_mode || - parser === in_caption_mode || - parser === in_table_body_mode || - parser === in_row_mode || - parser === in_cell_mode - ) - parser = in_select_in_table_mode; - else parser = in_select_mode; - return; - - case 'optgroup': - case 'option': - if (stack.top instanceof impl.HTMLOptionElement) { - in_body_mode(ENDTAG, 'option'); - } - afereconstruct(); - insertHTMLElement(value, arg3); - return; - - case 'menuitem': - if (isA(stack.top, 'menuitem')) { - stack.pop(); - } - afereconstruct(); - insertHTMLElement(value, arg3); - return; - - case 'rb': - case 'rtc': - if (stack.inScope('ruby')) { - stack.generateImpliedEndTags(); - } - insertHTMLElement(value, arg3); - return; - - case 'rp': - case 'rt': - if (stack.inScope('ruby')) { - stack.generateImpliedEndTags('rtc'); - } - insertHTMLElement(value, arg3); - return; - - case 'math': - afereconstruct(); - adjustMathMLAttributes(arg3); - adjustForeignAttributes(arg3); - insertForeignElement(value, arg3, NAMESPACE.MATHML); - if (arg4) - // self-closing flag - stack.pop(); - return; - - case 'svg': - afereconstruct(); - adjustSVGAttributes(arg3); - adjustForeignAttributes(arg3); - insertForeignElement(value, arg3, NAMESPACE.SVG); - if (arg4) - // self-closing flag - stack.pop(); - return; - - case 'caption': - case 'col': - case 'colgroup': - case 'frame': - case 'head': - case 'tbody': - case 'td': - case 'tfoot': - case 'th': - case 'thead': - case 'tr': - // Ignore table tags if we're not in_table mode - return; - } - - // Handle any other start tag here - // (and also noscript tags when scripting is disabled) - afereconstruct(); - insertHTMLElement(value, arg3); - return; - - case 3: // ENDTAG - switch (value) { - case 'template': - in_head_mode(ENDTAG, value, arg3); - return; - case 'body': - if (!stack.inScope('body')) return; - parser = after_body_mode; - return; - case 'html': - if (!stack.inScope('body')) return; - parser = after_body_mode; - parser(t, value, arg3); - return; - - case 'address': - case 'article': - case 'aside': - case 'blockquote': - case 'button': - case 'center': - case 'details': - case 'dialog': - case 'dir': - case 'div': - case 'dl': - case 'fieldset': - case 'figcaption': - case 'figure': - case 'footer': - case 'header': - case 'hgroup': - case 'listing': - case 'main': - case 'menu': - case 'nav': - case 'ol': - case 'pre': - case 'section': - case 'summary': - case 'ul': - // Ignore if there is not a matching open tag - if (!stack.inScope(value)) return; - stack.generateImpliedEndTags(); - stack.popTag(value); - return; - - case 'form': - if (!stack.contains('template')) { - var openform = form_element_pointer; - form_element_pointer = null; - if (!openform || !stack.elementInScope(openform)) return; - stack.generateImpliedEndTags(); - stack.removeElement(openform); - } else { - if (!stack.inScope('form')) return; - stack.generateImpliedEndTags(); - stack.popTag('form'); - } - return; - - case 'p': - if (!stack.inButtonScope(value)) { - in_body_mode(TAG, value, null); - parser(t, value, arg3, arg4); - } else { - stack.generateImpliedEndTags(value); - stack.popTag(value); - } - return; - - case 'li': - if (!stack.inListItemScope(value)) return; - stack.generateImpliedEndTags(value); - stack.popTag(value); - return; - - case 'dd': - case 'dt': - if (!stack.inScope(value)) return; - stack.generateImpliedEndTags(value); - stack.popTag(value); - return; - - case 'h1': - case 'h2': - case 'h3': - case 'h4': - case 'h5': - case 'h6': - if (!stack.elementTypeInScope(impl.HTMLHeadingElement)) return; - stack.generateImpliedEndTags(); - stack.popElementType(impl.HTMLHeadingElement); - return; - - case 'sarcasm': - // Take a deep breath, and then: - break; - - case 'a': - case 'b': - case 'big': - case 'code': - case 'em': - case 'font': - case 'i': - case 'nobr': - case 's': - case 'small': - case 'strike': - case 'strong': - case 'tt': - case 'u': - var result = adoptionAgency(value); - if (result) return; // If we did something we're done - break; // Go to the "any other end tag" case - - case 'applet': - case 'marquee': - case 'object': - if (!stack.inScope(value)) return; - stack.generateImpliedEndTags(); - stack.popTag(value); - afe.clearToMarker(); - return; - - case 'br': - in_body_mode(TAG, value, null); // Turn </br> into <br> - return; - } - - // Any other end tag goes here - for (i = stack.elements.length - 1; i >= 0; i--) { - node = stack.elements[i]; - if (isA(node, value)) { - stack.generateImpliedEndTags(value); - stack.popElement(node); - break; - } else if (isA(node, specialSet)) { - return; - } - } - - return; - } - } - - function text_mode(t, value, arg3, arg4) { - switch (t) { - case 1: // TEXT - insertText(value); - return; - case -1: // EOF - if (stack.top instanceof impl.HTMLScriptElement) stack.top._already_started = true; - stack.pop(); - parser = originalInsertionMode; - parser(t); - return; - case 3: // ENDTAG - if (value === 'script') { - handleScriptEnd(); - } else { - stack.pop(); - parser = originalInsertionMode; - } - return; - default: - // We should never get any other token types - return; - } - } - - function in_table_mode(t, value, arg3, arg4) { - function getTypeAttr(attrs) { - for (var i = 0, n = attrs.length; i < n; i++) { - if (attrs[i][0] === 'type') return attrs[i][1].toLowerCase(); - } - return null; - } - - switch (t) { - case 1: // TEXT - // XXX the text_integration_mode stuff is - // just a hack I made up - if (text_integration_mode) { - in_body_mode(t, value, arg3, arg4); - return; - } else if (isA(stack.top, tablesectionrowSet)) { - pending_table_text = []; - originalInsertionMode = parser; - parser = in_table_text_mode; - parser(t, value, arg3, arg4); - return; - } - break; - case 4: // COMMENT - insertComment(value); - return; - case 5: // DOCTYPE - return; - case 2: // TAG - switch (value) { - case 'caption': - stack.clearToContext(tableContextSet); - afe.insertMarker(); - insertHTMLElement(value, arg3); - parser = in_caption_mode; - return; - case 'colgroup': - stack.clearToContext(tableContextSet); - insertHTMLElement(value, arg3); - parser = in_column_group_mode; - return; - case 'col': - in_table_mode(TAG, 'colgroup', null); - parser(t, value, arg3, arg4); - return; - case 'tbody': - case 'tfoot': - case 'thead': - stack.clearToContext(tableContextSet); - insertHTMLElement(value, arg3); - parser = in_table_body_mode; - return; - case 'td': - case 'th': - case 'tr': - in_table_mode(TAG, 'tbody', null); - parser(t, value, arg3, arg4); - return; - - case 'table': - if (!stack.inTableScope(value)) { - return; // Ignore the token - } - in_table_mode(ENDTAG, value); - parser(t, value, arg3, arg4); - return; - - case 'style': - case 'script': - case 'template': - in_head_mode(t, value, arg3, arg4); - return; - - case 'input': - var type = getTypeAttr(arg3); - if (type !== 'hidden') break; // to the anything else case - insertHTMLElement(value, arg3); - stack.pop(); - return; - - case 'form': - if (form_element_pointer || stack.contains('template')) return; - form_element_pointer = insertHTMLElement(value, arg3); - stack.popElement(form_element_pointer); - return; - } - break; - case 3: // ENDTAG - switch (value) { - case 'table': - if (!stack.inTableScope(value)) return; - stack.popTag(value); - resetInsertionMode(); - return; - case 'body': - case 'caption': - case 'col': - case 'colgroup': - case 'html': - case 'tbody': - case 'td': - case 'tfoot': - case 'th': - case 'thead': - case 'tr': - return; - case 'template': - in_head_mode(t, value, arg3, arg4); - return; - } - - break; - case -1: // EOF - in_body_mode(t, value, arg3, arg4); - return; - } - - // This is the anything else case - foster_parent_mode = true; - in_body_mode(t, value, arg3, arg4); - foster_parent_mode = false; - } - - function in_table_text_mode(t, value, arg3, arg4) { - if (t === TEXT) { - if (textIncludesNUL) { - value = value.replace(NULCHARS, ''); - if (value.length === 0) return; - } - pending_table_text.push(value); - } else { - var s = pending_table_text.join(''); - pending_table_text.length = 0; - if (NONWS.test(s)) { - // If any non-whitespace characters - // This must be the same code as the "anything else" - // case of the in_table mode above. - foster_parent_mode = true; - in_body_mode(TEXT, s); - foster_parent_mode = false; - } else { - insertText(s); - } - parser = originalInsertionMode; - parser(t, value, arg3, arg4); - } - } - - function in_caption_mode(t, value, arg3, arg4) { - function end_caption() { - if (!stack.inTableScope('caption')) return false; - stack.generateImpliedEndTags(); - stack.popTag('caption'); - afe.clearToMarker(); - parser = in_table_mode; - return true; - } - - switch (t) { - case 2: // TAG - switch (value) { - case 'caption': - case 'col': - case 'colgroup': - case 'tbody': - case 'td': - case 'tfoot': - case 'th': - case 'thead': - case 'tr': - if (end_caption()) parser(t, value, arg3, arg4); - return; - } - break; - case 3: // ENDTAG - switch (value) { - case 'caption': - end_caption(); - return; - case 'table': - if (end_caption()) parser(t, value, arg3, arg4); - return; - case 'body': - case 'col': - case 'colgroup': - case 'html': - case 'tbody': - case 'td': - case 'tfoot': - case 'th': - case 'thead': - case 'tr': - return; - } - break; - } - - // The Anything Else case - in_body_mode(t, value, arg3, arg4); - } - - function in_column_group_mode(t, value, arg3, arg4) { - switch (t) { - case 1: // TEXT - var ws = value.match(LEADINGWS); - if (ws) { - insertText(ws[0]); - value = value.substring(ws[0].length); - } - if (value.length === 0) return; - break; // Handle non-whitespace below - - case 4: // COMMENT - insertComment(value); - return; - case 5: // DOCTYPE - return; - case 2: // TAG - switch (value) { - case 'html': - in_body_mode(t, value, arg3, arg4); - return; - case 'col': - insertHTMLElement(value, arg3); - stack.pop(); - return; - case 'template': - in_head_mode(t, value, arg3, arg4); - return; - } - break; - case 3: // ENDTAG - switch (value) { - case 'colgroup': - if (!isA(stack.top, 'colgroup')) { - return; // Ignore the token. - } - stack.pop(); - parser = in_table_mode; - return; - case 'col': - return; - case 'template': - in_head_mode(t, value, arg3, arg4); - return; - } - break; - case -1: // EOF - in_body_mode(t, value, arg3, arg4); - return; - } - - // Anything else - if (!isA(stack.top, 'colgroup')) { - return; // Ignore the token. - } - in_column_group_mode(ENDTAG, 'colgroup'); - parser(t, value, arg3, arg4); - } - - function in_table_body_mode(t, value, arg3, arg4) { - function endsect() { - if ( - !stack.inTableScope('tbody') && - !stack.inTableScope('thead') && - !stack.inTableScope('tfoot') - ) - return; - stack.clearToContext(tableBodyContextSet); - in_table_body_mode(ENDTAG, stack.top.localName, null); - parser(t, value, arg3, arg4); - } - - switch (t) { - case 2: // TAG - switch (value) { - case 'tr': - stack.clearToContext(tableBodyContextSet); - insertHTMLElement(value, arg3); - parser = in_row_mode; - return; - case 'th': - case 'td': - in_table_body_mode(TAG, 'tr', null); - parser(t, value, arg3, arg4); - return; - case 'caption': - case 'col': - case 'colgroup': - case 'tbody': - case 'tfoot': - case 'thead': - endsect(); - return; - } - break; - case 3: // ENDTAG - switch (value) { - case 'table': - endsect(); - return; - case 'tbody': - case 'tfoot': - case 'thead': - if (stack.inTableScope(value)) { - stack.clearToContext(tableBodyContextSet); - stack.pop(); - parser = in_table_mode; - } - return; - case 'body': - case 'caption': - case 'col': - case 'colgroup': - case 'html': - case 'td': - case 'th': - case 'tr': - return; - } - break; - } - - // Anything else: - in_table_mode(t, value, arg3, arg4); - } - - function in_row_mode(t, value, arg3, arg4) { - function endrow() { - if (!stack.inTableScope('tr')) return false; - stack.clearToContext(tableRowContextSet); - stack.pop(); - parser = in_table_body_mode; - return true; - } - - switch (t) { - case 2: // TAG - switch (value) { - case 'th': - case 'td': - stack.clearToContext(tableRowContextSet); - insertHTMLElement(value, arg3); - parser = in_cell_mode; - afe.insertMarker(); - return; - case 'caption': - case 'col': - case 'colgroup': - case 'tbody': - case 'tfoot': - case 'thead': - case 'tr': - if (endrow()) parser(t, value, arg3, arg4); - return; - } - break; - case 3: // ENDTAG - switch (value) { - case 'tr': - endrow(); - return; - case 'table': - if (endrow()) parser(t, value, arg3, arg4); - return; - case 'tbody': - case 'tfoot': - case 'thead': - if (stack.inTableScope(value)) { - if (endrow()) parser(t, value, arg3, arg4); - } - return; - case 'body': - case 'caption': - case 'col': - case 'colgroup': - case 'html': - case 'td': - case 'th': - return; - } - break; - } - - // anything else - in_table_mode(t, value, arg3, arg4); - } - - function in_cell_mode(t, value, arg3, arg4) { - switch (t) { - case 2: // TAG - switch (value) { - case 'caption': - case 'col': - case 'colgroup': - case 'tbody': - case 'td': - case 'tfoot': - case 'th': - case 'thead': - case 'tr': - if (stack.inTableScope('td')) { - in_cell_mode(ENDTAG, 'td'); - parser(t, value, arg3, arg4); - } else if (stack.inTableScope('th')) { - in_cell_mode(ENDTAG, 'th'); - parser(t, value, arg3, arg4); - } - return; - } - break; - case 3: // ENDTAG - switch (value) { - case 'td': - case 'th': - if (!stack.inTableScope(value)) return; - stack.generateImpliedEndTags(); - stack.popTag(value); - afe.clearToMarker(); - parser = in_row_mode; - return; - - case 'body': - case 'caption': - case 'col': - case 'colgroup': - case 'html': - return; - - case 'table': - case 'tbody': - case 'tfoot': - case 'thead': - case 'tr': - if (!stack.inTableScope(value)) return; - in_cell_mode(ENDTAG, stack.inTableScope('td') ? 'td' : 'th'); - parser(t, value, arg3, arg4); - return; - } - break; - } - - // anything else - in_body_mode(t, value, arg3, arg4); - } - - function in_select_mode(t, value, arg3, arg4) { - switch (t) { - case 1: // TEXT - if (textIncludesNUL) { - value = value.replace(NULCHARS, ''); - if (value.length === 0) return; - } - insertText(value); - return; - case 4: // COMMENT - insertComment(value); - return; - case 5: // DOCTYPE - return; - case -1: // EOF - in_body_mode(t, value, arg3, arg4); - return; - case 2: // TAG - switch (value) { - case 'html': - in_body_mode(t, value, arg3, arg4); - return; - case 'option': - if (stack.top instanceof impl.HTMLOptionElement) in_select_mode(ENDTAG, value); - insertHTMLElement(value, arg3); - return; - case 'optgroup': - if (stack.top instanceof impl.HTMLOptionElement) in_select_mode(ENDTAG, 'option'); - if (stack.top instanceof impl.HTMLOptGroupElement) in_select_mode(ENDTAG, value); - insertHTMLElement(value, arg3); - return; - case 'select': - in_select_mode(ENDTAG, value); // treat it as a close tag - return; - - case 'input': - case 'keygen': - case 'textarea': - if (!stack.inSelectScope('select')) return; - in_select_mode(ENDTAG, 'select'); - parser(t, value, arg3, arg4); - return; - - case 'script': - case 'template': - in_head_mode(t, value, arg3, arg4); - return; - } - break; - case 3: // ENDTAG - switch (value) { - case 'optgroup': - if ( - stack.top instanceof impl.HTMLOptionElement && - stack.elements[stack.elements.length - 2] instanceof impl.HTMLOptGroupElement - ) { - in_select_mode(ENDTAG, 'option'); - } - if (stack.top instanceof impl.HTMLOptGroupElement) stack.pop(); - - return; - - case 'option': - if (stack.top instanceof impl.HTMLOptionElement) stack.pop(); - return; - - case 'select': - if (!stack.inSelectScope(value)) return; - stack.popTag(value); - resetInsertionMode(); - return; - - case 'template': - in_head_mode(t, value, arg3, arg4); - return; - } - - break; - } - - // anything else: just ignore the token - } - - function in_select_in_table_mode(t, value, arg3, arg4) { - switch (value) { - case 'caption': - case 'table': - case 'tbody': - case 'tfoot': - case 'thead': - case 'tr': - case 'td': - case 'th': - switch (t) { - case 2: // TAG - in_select_in_table_mode(ENDTAG, 'select'); - parser(t, value, arg3, arg4); - return; - case 3: // ENDTAG - if (stack.inTableScope(value)) { - in_select_in_table_mode(ENDTAG, 'select'); - parser(t, value, arg3, arg4); - } - return; - } - } - - // anything else - in_select_mode(t, value, arg3, arg4); - } - - function in_template_mode(t, value, arg3, arg4) { - function switchModeAndReprocess(mode) { - parser = mode; - templateInsertionModes[templateInsertionModes.length - 1] = parser; - parser(t, value, arg3, arg4); - } - switch (t) { - case 1: // TEXT - case 4: // COMMENT - case 5: // DOCTYPE - in_body_mode(t, value, arg3, arg4); - return; - case -1: // EOF - if (!stack.contains('template')) { - stopParsing(); - } else { - stack.popTag('template'); - afe.clearToMarker(); - templateInsertionModes.pop(); - resetInsertionMode(); - parser(t, value, arg3, arg4); - } - return; - case 2: // TAG - switch (value) { - case 'base': - case 'basefont': - case 'bgsound': - case 'link': - case 'meta': - case 'noframes': - case 'script': - case 'style': - case 'template': - case 'title': - in_head_mode(t, value, arg3, arg4); - return; - case 'caption': - case 'colgroup': - case 'tbody': - case 'tfoot': - case 'thead': - switchModeAndReprocess(in_table_mode); - return; - case 'col': - switchModeAndReprocess(in_column_group_mode); - return; - case 'tr': - switchModeAndReprocess(in_table_body_mode); - return; - case 'td': - case 'th': - switchModeAndReprocess(in_row_mode); - return; - } - switchModeAndReprocess(in_body_mode); - return; - case 3: // ENDTAG - switch (value) { - case 'template': - in_head_mode(t, value, arg3, arg4); - return; - default: - return; - } - } - } - - function after_body_mode(t, value, arg3, arg4) { - switch (t) { - case 1: // TEXT - // If any non-space chars, handle below - if (NONWS.test(value)) break; - in_body_mode(t, value); - return; - case 4: // COMMENT - // Append it to the <html> element - stack.elements[0]._appendChild(doc.createComment(value)); - return; - case 5: // DOCTYPE - return; - case -1: // EOF - stopParsing(); - return; - case 2: // TAG - if (value === 'html') { - in_body_mode(t, value, arg3, arg4); - return; - } - break; // for any other tags - case 3: // ENDTAG - if (value === 'html') { - if (fragment) return; - parser = after_after_body_mode; - return; - } - break; // for any other tags - } - - // anything else - parser = in_body_mode; - parser(t, value, arg3, arg4); - } - - function in_frameset_mode(t, value, arg3, arg4) { - switch (t) { - case 1: // TEXT - // Ignore any non-space characters - value = value.replace(ALLNONWS, ''); - if (value.length > 0) insertText(value); - return; - case 4: // COMMENT - insertComment(value); - return; - case 5: // DOCTYPE - return; - case -1: // EOF - stopParsing(); - return; - case 2: // TAG - switch (value) { - case 'html': - in_body_mode(t, value, arg3, arg4); - return; - case 'frameset': - insertHTMLElement(value, arg3); - return; - case 'frame': - insertHTMLElement(value, arg3); - stack.pop(); - return; - case 'noframes': - in_head_mode(t, value, arg3, arg4); - return; - } - break; - case 3: // ENDTAG - if (value === 'frameset') { - if (fragment && stack.top instanceof impl.HTMLHtmlElement) return; - stack.pop(); - if (!fragment && !(stack.top instanceof impl.HTMLFrameSetElement)) - parser = after_frameset_mode; - return; - } - break; - } - - // ignore anything else - } - - function after_frameset_mode(t, value, arg3, arg4) { - switch (t) { - case 1: // TEXT - // Ignore any non-space characters - value = value.replace(ALLNONWS, ''); - if (value.length > 0) insertText(value); - return; - case 4: // COMMENT - insertComment(value); - return; - case 5: // DOCTYPE - return; - case -1: // EOF - stopParsing(); - return; - case 2: // TAG - switch (value) { - case 'html': - in_body_mode(t, value, arg3, arg4); - return; - case 'noframes': - in_head_mode(t, value, arg3, arg4); - return; - } - break; - case 3: // ENDTAG - if (value === 'html') { - parser = after_after_frameset_mode; - return; - } - break; - } - - // ignore anything else - } - - function after_after_body_mode(t, value, arg3, arg4) { - switch (t) { - case 1: // TEXT - // If any non-space chars, handle below - if (NONWS.test(value)) break; - in_body_mode(t, value, arg3, arg4); - return; - case 4: // COMMENT - doc._appendChild(doc.createComment(value)); - return; - case 5: // DOCTYPE - in_body_mode(t, value, arg3, arg4); - return; - case -1: // EOF - stopParsing(); - return; - case 2: // TAG - if (value === 'html') { - in_body_mode(t, value, arg3, arg4); - return; - } - break; - } - - // anything else - parser = in_body_mode; - parser(t, value, arg3, arg4); - } - - function after_after_frameset_mode(t, value, arg3, arg4) { - switch (t) { - case 1: // TEXT - // Ignore any non-space characters - value = value.replace(ALLNONWS, ''); - if (value.length > 0) in_body_mode(t, value, arg3, arg4); - return; - case 4: // COMMENT - doc._appendChild(doc.createComment(value)); - return; - case 5: // DOCTYPE - in_body_mode(t, value, arg3, arg4); - return; - case -1: // EOF - stopParsing(); - return; - case 2: // TAG - switch (value) { - case 'html': - in_body_mode(t, value, arg3, arg4); - return; - case 'noframes': - in_head_mode(t, value, arg3, arg4); - return; - } - break; - } - - // ignore anything else - } - - // 13.2.5.5 The rules for parsing tokens in foreign content - // - // This is like one of the insertion modes above, but is - // invoked somewhat differently when the current token is not HTML. - // See the insertToken() function. - function insertForeignToken(t, value, arg3, arg4) { - // A <font> tag is an HTML font tag if it has a color, font, or size - // attribute. Otherwise we assume it is foreign content - function isHTMLFont(attrs) { - for (var i = 0, n = attrs.length; i < n; i++) { - switch (attrs[i][0]) { - case 'color': - case 'face': - case 'size': - return true; - } - } - return false; - } - - var current; - - switch (t) { - case 1: // TEXT - // If any non-space, non-nul characters - if (frameset_ok && NONWSNONNUL.test(value)) frameset_ok = false; - if (textIncludesNUL) { - value = value.replace(NULCHARS, '\uFFFD'); - } - insertText(value); - return; - case 4: // COMMENT - insertComment(value); - return; - case 5: // DOCTYPE - // ignore it - return; - case 2: // TAG - switch (value) { - case 'font': - if (!isHTMLFont(arg3)) break; - /* falls through */ - case 'b': - case 'big': - case 'blockquote': - case 'body': - case 'br': - case 'center': - case 'code': - case 'dd': - case 'div': - case 'dl': - case 'dt': - case 'em': - case 'embed': - case 'h1': - case 'h2': - case 'h3': - case 'h4': - case 'h5': - case 'h6': - case 'head': - case 'hr': - case 'i': - case 'img': - case 'li': - case 'listing': - case 'menu': - case 'meta': - case 'nobr': - case 'ol': - case 'p': - case 'pre': - case 'ruby': - case 's': - case 'small': - case 'span': - case 'strong': - case 'strike': - case 'sub': - case 'sup': - case 'table': - case 'tt': - case 'u': - case 'ul': - case 'var': - if (fragment) { - break; - } - do { - stack.pop(); - current = stack.top; - } while ( - current.namespaceURI !== NAMESPACE.HTML && - !isMathmlTextIntegrationPoint(current) && - !isHTMLIntegrationPoint(current) - ); - - insertToken(t, value, arg3, arg4); // reprocess - return; - } - - // Any other start tag case goes here - current = stack.elements.length === 1 && fragment ? fragmentContext : stack.top; - if (current.namespaceURI === NAMESPACE.MATHML) { - adjustMathMLAttributes(arg3); - } else if (current.namespaceURI === NAMESPACE.SVG) { - value = adjustSVGTagName(value); - adjustSVGAttributes(arg3); - } - adjustForeignAttributes(arg3); - - insertForeignElement(value, arg3, current.namespaceURI); - if (arg4) { - // the self-closing flag - if (value === 'script' && current.namespaceURI === NAMESPACE.SVG) { - // XXX deal with SVG scripts here - } - stack.pop(); - } - return; - - case 3: // ENDTAG - current = stack.top; - if ( - value === 'script' && - current.namespaceURI === NAMESPACE.SVG && - current.localName === 'script' - ) { - stack.pop(); - - // XXX - // Deal with SVG scripts here - } else { - // The any other end tag case - var i = stack.elements.length - 1; - var node = stack.elements[i]; - for (;;) { - if (node.localName.toLowerCase() === value) { - stack.popElement(node); - break; - } - node = stack.elements[--i]; - // If non-html, keep looping - if (node.namespaceURI !== NAMESPACE.HTML) continue; - // Otherwise process the end tag as html - parser(t, value, arg3, arg4); - break; - } - } - return; - } - } - - /*** - * Finally, this is the end of the HTMLParser() factory function. - * It returns the htmlparser object with the append() and end() methods. - */ - - // Sneak another method into the htmlparser object to allow us to run - // tokenizer tests. This can be commented out in production code. - // This is a hook for testing the tokenizer. It has to be here - // because the tokenizer details are all hidden away within the closure. - // It should return an array of tokens generated while parsing the - // input string. - htmlparser.testTokenizer = function (input, initialState, lastStartTag, charbychar) { - var tokens = []; - - switch (initialState) { - case 'PCDATA state': - tokenizer = data_state; - break; - case 'RCDATA state': - tokenizer = rcdata_state; - break; - case 'RAWTEXT state': - tokenizer = rawtext_state; - break; - case 'PLAINTEXT state': - tokenizer = plaintext_state; - break; - } - - if (lastStartTag) { - lasttagname = lastStartTag; - } - - insertToken = function (t, value, arg3, arg4) { - flushText(); - switch (t) { - case 1: // TEXT - if (tokens.length > 0 && tokens[tokens.length - 1][0] === 'Character') { - tokens[tokens.length - 1][1] += value; - } else tokens.push(['Character', value]); - break; - case 4: // COMMENT - tokens.push(['Comment', value]); - break; - case 5: // DOCTYPE - tokens.push([ - 'DOCTYPE', - value, - arg3 === undefined ? null : arg3, - arg4 === undefined ? null : arg4, - !force_quirks, - ]); - break; - case 2: // TAG - var attrs = Object.create(null); - for (var i = 0; i < arg3.length; i++) { - // XXX: does attribute order matter? - var a = arg3[i]; - if (a.length === 1) { - attrs[a[0]] = ''; - } else { - attrs[a[0]] = a[1]; - } - } - var token = ['StartTag', value, attrs]; - if (arg4) token.push(true); - tokens.push(token); - break; - case 3: // ENDTAG - tokens.push(['EndTag', value]); - break; - case -1: // EOF - break; - } - }; - - if (!charbychar) { - this.parse(input, true); - } else { - for (var i = 0; i < input.length; i++) { - this.parse(input[i]); - } - this.parse('', true); - } - return tokens; - }; - - // Return the parser object from the HTMLParser() factory function - return htmlparser; -} diff --git a/packages/qwik-dom/lib/Leaf.js b/packages/qwik-dom/lib/Leaf.js deleted file mode 100644 index 220914dcc6b..00000000000 --- a/packages/qwik-dom/lib/Leaf.js +++ /dev/null @@ -1,53 +0,0 @@ -'use strict'; -module.exports = Leaf; - -var Node = require('./Node'); -var NodeList = require('./NodeList'); -var utils = require('./utils'); -var HierarchyRequestError = utils.HierarchyRequestError; -var NotFoundError = utils.NotFoundError; - -// This class defines common functionality for node subtypes that -// can never have children -function Leaf() { - Node.call(this); -} - -Leaf.prototype = Object.create(Node.prototype, { - hasChildNodes: { - value: function () { - return false; - }, - }, - firstChild: { value: null }, - lastChild: { value: null }, - insertBefore: { - value: function (node, child) { - if (!node.nodeType) throw new TypeError('not a node'); - HierarchyRequestError(); - }, - }, - replaceChild: { - value: function (node, child) { - if (!node.nodeType) throw new TypeError('not a node'); - HierarchyRequestError(); - }, - }, - removeChild: { - value: function (node) { - if (!node.nodeType) throw new TypeError('not a node'); - NotFoundError(); - }, - }, - removeChildren: { - value: function () { - /* no op */ - }, - }, - childNodes: { - get: function () { - if (!this._childNodes) this._childNodes = new NodeList(); - return this._childNodes; - }, - }, -}); diff --git a/packages/qwik-dom/lib/LinkedList.js b/packages/qwik-dom/lib/LinkedList.js deleted file mode 100644 index 4a50a4bb850..00000000000 --- a/packages/qwik-dom/lib/LinkedList.js +++ /dev/null @@ -1,48 +0,0 @@ -'use strict'; -var utils = require('./utils'); - -var LinkedList = (module.exports = { - // basic validity tests on a circular linked list a - valid: function (a) { - utils.assert(a, 'list falsy'); - utils.assert(a._previousSibling, 'previous falsy'); - utils.assert(a._nextSibling, 'next falsy'); - // xxx check that list is actually circular - return true; - }, - // insert a before b - insertBefore: function (a, b) { - utils.assert(LinkedList.valid(a) && LinkedList.valid(b)); - var a_first = a, - a_last = a._previousSibling; - var b_first = b, - b_last = b._previousSibling; - a_first._previousSibling = b_last; - a_last._nextSibling = b_first; - b_last._nextSibling = a_first; - b_first._previousSibling = a_last; - utils.assert(LinkedList.valid(a) && LinkedList.valid(b)); - }, - // replace a single node a with a list b (which could be null) - replace: function (a, b) { - utils.assert(LinkedList.valid(a) && (b === null || LinkedList.valid(b))); - if (b !== null) { - LinkedList.insertBefore(b, a); - } - LinkedList.remove(a); - utils.assert(LinkedList.valid(a) && (b === null || LinkedList.valid(b))); - }, - // remove single node a from its list - remove: function (a) { - utils.assert(LinkedList.valid(a)); - var prev = a._previousSibling; - if (prev === a) { - return; - } - var next = a._nextSibling; - prev._nextSibling = next; - next._previousSibling = prev; - a._previousSibling = a._nextSibling = a; - utils.assert(LinkedList.valid(a)); - }, -}); diff --git a/packages/qwik-dom/lib/Location.js b/packages/qwik-dom/lib/Location.js deleted file mode 100644 index 3d9b7866424..00000000000 --- a/packages/qwik-dom/lib/Location.js +++ /dev/null @@ -1,67 +0,0 @@ -'use strict'; -var URL = require('./URL'); -var URLUtils = require('./URLUtils'); - -module.exports = Location; - -function Location(window, href) { - this._window = window; - this._href = href; -} - -Location.prototype = Object.create(URLUtils.prototype, { - constructor: { value: Location }, - - // Special behavior when href is set - href: { - get: function () { - return this._href; - }, - set: function (v) { - this.assign(v); - }, - }, - - assign: { - value: function (url) { - // Resolve the new url against the current one - // XXX: - // This is not actually correct. It should be resolved against - // the URL of the document of the script. For now, though, I only - // support a single window and there is only one base url. - // So this is good enough for now. - var current = new URL(this._href); - var newurl = current.resolve(url); - - // Save the new url - this._href = newurl; - - // Start loading the new document! - // XXX - // This is just something hacked together. - // The real algorithm is: http://www.whatwg.org/specs/web-apps/current-work/multipage/history.html#navigate - }, - }, - - replace: { - value: function (url) { - // XXX - // Since we aren't tracking history yet, replace is the same as assign - this.assign(url); - }, - }, - - reload: { - value: function () { - // XXX: - // Actually, the spec is a lot more complicated than this - this.assign(this.href); - }, - }, - - toString: { - value: function () { - return this.href; - }, - }, -}); diff --git a/packages/qwik-dom/lib/MouseEvent.js b/packages/qwik-dom/lib/MouseEvent.js deleted file mode 100644 index b42d8acf9c8..00000000000 --- a/packages/qwik-dom/lib/MouseEvent.js +++ /dev/null @@ -1,80 +0,0 @@ -'use strict'; -var UIEvent = require('./UIEvent'); - -module.exports = MouseEvent; - -function MouseEvent() { - // Just use the superclass constructor to initialize - UIEvent.call(this); - - this.screenX = this.screenY = this.clientX = this.clientY = 0; - this.ctrlKey = this.altKey = this.shiftKey = this.metaKey = false; - this.button = 0; - this.buttons = 1; - this.relatedTarget = null; -} -MouseEvent.prototype = Object.create(UIEvent.prototype, { - constructor: { value: MouseEvent }, - initMouseEvent: { - value: function ( - type, - bubbles, - cancelable, - view, - detail, - screenX, - screenY, - clientX, - clientY, - ctrlKey, - altKey, - shiftKey, - metaKey, - button, - relatedTarget - ) { - this.initEvent(type, bubbles, cancelable, view, detail); - this.screenX = screenX; - this.screenY = screenY; - this.clientX = clientX; - this.clientY = clientY; - this.ctrlKey = ctrlKey; - this.altKey = altKey; - this.shiftKey = shiftKey; - this.metaKey = metaKey; - this.button = button; - switch (button) { - case 0: - this.buttons = 1; - break; - case 1: - this.buttons = 4; - break; - case 2: - this.buttons = 2; - break; - default: - this.buttons = 0; - break; - } - this.relatedTarget = relatedTarget; - }, - }, - - getModifierState: { - value: function (key) { - switch (key) { - case 'Alt': - return this.altKey; - case 'Control': - return this.ctrlKey; - case 'Shift': - return this.shiftKey; - case 'Meta': - return this.metaKey; - default: - return false; - } - }, - }, -}); diff --git a/packages/qwik-dom/lib/MutationConstants.js b/packages/qwik-dom/lib/MutationConstants.js deleted file mode 100644 index 3f85f36f619..00000000000 --- a/packages/qwik-dom/lib/MutationConstants.js +++ /dev/null @@ -1,9 +0,0 @@ -'use strict'; -module.exports = { - VALUE: 1, // The value of a Text, Comment or PI node changed - ATTR: 2, // A new attribute was added or an attribute value and/or prefix changed - REMOVE_ATTR: 3, // An attribute was removed - REMOVE: 4, // A node was removed - MOVE: 5, // A node was moved - INSERT: 6, // A node (or a subtree of nodes) was inserted -}; diff --git a/packages/qwik-dom/lib/NamedNodeMap.js b/packages/qwik-dom/lib/NamedNodeMap.js deleted file mode 100644 index 2d4cdd1642e..00000000000 --- a/packages/qwik-dom/lib/NamedNodeMap.js +++ /dev/null @@ -1,49 +0,0 @@ -'use strict'; -module.exports = NamedNodeMap; - -var utils = require('./utils'); - -/* This is a hacky implementation of NamedNodeMap, intended primarily to - * satisfy clients (like dompurify and the web-platform-tests) which check - * to ensure that Node#attributes instanceof NamedNodeMap. */ - -function NamedNodeMap(element) { - this.element = element; -} -Object.defineProperties(NamedNodeMap.prototype, { - length: { get: utils.shouldOverride }, - item: { value: utils.shouldOverride }, - - getNamedItem: { - value: function getNamedItem(qualifiedName) { - return this.element.getAttributeNode(qualifiedName); - }, - }, - getNamedItemNS: { - value: function getNamedItemNS(namespace, localName) { - return this.element.getAttributeNodeNS(namespace, localName); - }, - }, - setNamedItem: { value: utils.nyi }, - setNamedItemNS: { value: utils.nyi }, - removeNamedItem: { - value: function removeNamedItem(qualifiedName) { - var attr = this.element.getAttributeNode(qualifiedName); - if (attr) { - this.element.removeAttribute(qualifiedName); - return attr; - } - utils.NotFoundError(); - }, - }, - removeNamedItemNS: { - value: function removeNamedItemNS(ns, lname) { - var attr = this.element.getAttributeNodeNS(ns, lname); - if (attr) { - this.element.removeAttributeNS(ns, lname); - return attr; - } - utils.NotFoundError(); - }, - }, -}); diff --git a/packages/qwik-dom/lib/NavigatorID.js b/packages/qwik-dom/lib/NavigatorID.js deleted file mode 100644 index e47c6c1866a..00000000000 --- a/packages/qwik-dom/lib/NavigatorID.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; - -// https://html.spec.whatwg.org/multipage/webappapis.html#navigatorid -var NavigatorID = Object.create(null, { - appCodeName: { value: 'Mozilla' }, - appName: { value: 'Netscape' }, - appVersion: { value: '4.0' }, - platform: { value: '' }, - product: { value: 'Gecko' }, - productSub: { value: '20100101' }, - userAgent: { value: '' }, - vendor: { value: '' }, - vendorSub: { value: '' }, - taintEnabled: { - value: function () { - return false; - }, - }, -}); - -module.exports = NavigatorID; diff --git a/packages/qwik-dom/lib/Node.js b/packages/qwik-dom/lib/Node.js deleted file mode 100644 index f709188e444..00000000000 --- a/packages/qwik-dom/lib/Node.js +++ /dev/null @@ -1,821 +0,0 @@ -'use strict'; -module.exports = Node; - -var EventTarget = require('./EventTarget'); -var LinkedList = require('./LinkedList'); -var NodeUtils = require('./NodeUtils'); -var utils = require('./utils'); - -// All nodes have a nodeType and an ownerDocument. -// Once inserted, they also have a parentNode. -// This is an abstract class; all nodes in a document are instances -// of a subtype, so all the properties are defined by more specific -// constructors. -function Node() { - EventTarget.call(this); - this.parentNode = null; - this._nextSibling = this._previousSibling = this; - this._index = undefined; -} - -var ELEMENT_NODE = (Node.ELEMENT_NODE = 1); -var ATTRIBUTE_NODE = (Node.ATTRIBUTE_NODE = 2); -var TEXT_NODE = (Node.TEXT_NODE = 3); -var CDATA_SECTION_NODE = (Node.CDATA_SECTION_NODE = 4); -var ENTITY_REFERENCE_NODE = (Node.ENTITY_REFERENCE_NODE = 5); -var ENTITY_NODE = (Node.ENTITY_NODE = 6); -var PROCESSING_INSTRUCTION_NODE = (Node.PROCESSING_INSTRUCTION_NODE = 7); -var COMMENT_NODE = (Node.COMMENT_NODE = 8); -var DOCUMENT_NODE = (Node.DOCUMENT_NODE = 9); -var DOCUMENT_TYPE_NODE = (Node.DOCUMENT_TYPE_NODE = 10); -var DOCUMENT_FRAGMENT_NODE = (Node.DOCUMENT_FRAGMENT_NODE = 11); -var NOTATION_NODE = (Node.NOTATION_NODE = 12); - -var DOCUMENT_POSITION_DISCONNECTED = (Node.DOCUMENT_POSITION_DISCONNECTED = 0x01); -var DOCUMENT_POSITION_PRECEDING = (Node.DOCUMENT_POSITION_PRECEDING = 0x02); -var DOCUMENT_POSITION_FOLLOWING = (Node.DOCUMENT_POSITION_FOLLOWING = 0x04); -var DOCUMENT_POSITION_CONTAINS = (Node.DOCUMENT_POSITION_CONTAINS = 0x08); -var DOCUMENT_POSITION_CONTAINED_BY = (Node.DOCUMENT_POSITION_CONTAINED_BY = 0x10); -var DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = - (Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20); - -Node.prototype = Object.create(EventTarget.prototype, { - // Node that are not inserted into the tree inherit a null parent - - // XXX: the baseURI attribute is defined by dom core, but - // a correct implementation of it requires HTML features, so - // we'll come back to this later. - baseURI: { get: utils.nyi }, - - parentElement: { - get: function () { - return this.parentNode && this.parentNode.nodeType === ELEMENT_NODE ? this.parentNode : null; - }, - }, - - hasChildNodes: { value: utils.shouldOverride }, - - firstChild: { get: utils.shouldOverride }, - - lastChild: { get: utils.shouldOverride }, - - isConnected: { - get: function () { - let node = this; - while (node != null) { - if (node.nodeType === Node.DOCUMENT_NODE) { - return true; - } - - node = node.parentNode; - if (node != null && node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { - node = node.host; - } - } - return false; - }, - }, - - previousSibling: { - get: function () { - var parent = this.parentNode; - if (!parent) return null; - if (this === parent.firstChild) return null; - return this._previousSibling; - }, - }, - - nextSibling: { - get: function () { - var parent = this.parentNode, - next = this._nextSibling; - if (!parent) return null; - if (next === parent.firstChild) return null; - return next; - }, - }, - - textContent: { - // Should override for DocumentFragment/Element/Attr/Text/PI/Comment - get: function () { - return null; - }, - set: function (v) { - /* do nothing */ - }, - }, - - _countChildrenOfType: { - value: function (type) { - var sum = 0; - for (var kid = this.firstChild; kid !== null; kid = kid.nextSibling) { - if (kid.nodeType === type) sum++; - } - return sum; - }, - }, - - _ensureInsertValid: { - value: function _ensureInsertValid(node, child, isPreinsert) { - var parent = this, - i, - kid; - if (!node.nodeType) throw new TypeError('not a node'); - // 1. If parent is not a Document, DocumentFragment, or Element - // node, throw a HierarchyRequestError. - switch (parent.nodeType) { - case DOCUMENT_NODE: - case DOCUMENT_FRAGMENT_NODE: - case ELEMENT_NODE: - break; - default: - utils.HierarchyRequestError(); - } - // 2. If node is a host-including inclusive ancestor of parent, - // throw a HierarchyRequestError. - if (node.isAncestor(parent)) utils.HierarchyRequestError(); - // 3. If child is not null and its parent is not parent, then - // throw a NotFoundError. (replaceChild omits the 'child is not null' - // and throws a TypeError here if child is null.) - if (child !== null || !isPreinsert) { - if (child.parentNode !== parent) utils.NotFoundError(); - } - // 4. If node is not a DocumentFragment, DocumentType, Element, - // Text, ProcessingInstruction, or Comment node, throw a - // HierarchyRequestError. - switch (node.nodeType) { - case DOCUMENT_FRAGMENT_NODE: - case DOCUMENT_TYPE_NODE: - case ELEMENT_NODE: - case TEXT_NODE: - case PROCESSING_INSTRUCTION_NODE: - case COMMENT_NODE: - break; - default: - utils.HierarchyRequestError(); - } - // 5. If either node is a Text node and parent is a document, or - // node is a doctype and parent is not a document, throw a - // HierarchyRequestError. - // 6. If parent is a document, and any of the statements below, switched - // on node, are true, throw a HierarchyRequestError. - if (parent.nodeType === DOCUMENT_NODE) { - switch (node.nodeType) { - case TEXT_NODE: - utils.HierarchyRequestError(); - break; - case DOCUMENT_FRAGMENT_NODE: - // 6a1. If node has more than one element child or has a Text - // node child. - if (node._countChildrenOfType(TEXT_NODE) > 0) utils.HierarchyRequestError(); - switch (node._countChildrenOfType(ELEMENT_NODE)) { - case 0: - break; - case 1: - // 6a2. Otherwise, if node has one element child and either - // parent has an element child, child is a doctype, or child - // is not null and a doctype is following child. [preinsert] - // 6a2. Otherwise, if node has one element child and either - // parent has an element child that is not child or a - // doctype is following child. [replaceWith] - if (child !== null /* always true here for replaceWith */) { - if (isPreinsert && child.nodeType === DOCUMENT_TYPE_NODE) - utils.HierarchyRequestError(); - for (kid = child.nextSibling; kid !== null; kid = kid.nextSibling) { - if (kid.nodeType === DOCUMENT_TYPE_NODE) utils.HierarchyRequestError(); - } - } - i = parent._countChildrenOfType(ELEMENT_NODE); - if (isPreinsert) { - // "parent has an element child" - if (i > 0) utils.HierarchyRequestError(); - } else { - // "parent has an element child that is not child" - if (i > 1 || (i === 1 && child.nodeType !== ELEMENT_NODE)) - utils.HierarchyRequestError(); - } - break; - default: // 6a1, continued. (more than one Element child) - utils.HierarchyRequestError(); - } - break; - case ELEMENT_NODE: - // 6b. parent has an element child, child is a doctype, or - // child is not null and a doctype is following child. [preinsert] - // 6b. parent has an element child that is not child or a - // doctype is following child. [replaceWith] - if (child !== null /* always true here for replaceWith */) { - if (isPreinsert && child.nodeType === DOCUMENT_TYPE_NODE) - utils.HierarchyRequestError(); - for (kid = child.nextSibling; kid !== null; kid = kid.nextSibling) { - if (kid.nodeType === DOCUMENT_TYPE_NODE) utils.HierarchyRequestError(); - } - } - i = parent._countChildrenOfType(ELEMENT_NODE); - if (isPreinsert) { - // "parent has an element child" - if (i > 0) utils.HierarchyRequestError(); - } else { - // "parent has an element child that is not child" - if (i > 1 || (i === 1 && child.nodeType !== ELEMENT_NODE)) - utils.HierarchyRequestError(); - } - break; - case DOCUMENT_TYPE_NODE: - // 6c. parent has a doctype child, child is non-null and an - // element is preceding child, or child is null and parent has - // an element child. [preinsert] - // 6c. parent has a doctype child that is not child, or an - // element is preceding child. [replaceWith] - if (child === null) { - if (parent._countChildrenOfType(ELEMENT_NODE)) utils.HierarchyRequestError(); - } else { - // child is always non-null for [replaceWith] case - for (kid = parent.firstChild; kid !== null; kid = kid.nextSibling) { - if (kid === child) break; - if (kid.nodeType === ELEMENT_NODE) utils.HierarchyRequestError(); - } - } - i = parent._countChildrenOfType(DOCUMENT_TYPE_NODE); - if (isPreinsert) { - // "parent has an doctype child" - if (i > 0) utils.HierarchyRequestError(); - } else { - // "parent has an doctype child that is not child" - if (i > 1 || (i === 1 && child.nodeType !== DOCUMENT_TYPE_NODE)) - utils.HierarchyRequestError(); - } - break; - } - } else { - // 5, continued: (parent is not a document) - if (node.nodeType === DOCUMENT_TYPE_NODE) utils.HierarchyRequestError(); - } - }, - }, - - insertBefore: { - value: function insertBefore(node, child) { - var parent = this; - // 1. Ensure pre-insertion validity - parent._ensureInsertValid(node, child, true); - // 2. Let reference child be child. - var refChild = child; - // 3. If reference child is node, set it to node's next sibling - if (refChild === node) { - refChild = node.nextSibling; - } - // 4. Adopt node into parent's node document. - parent.doc.adoptNode(node); - // 5. Insert node into parent before reference child. - node._insertOrReplace(parent, refChild, false); - // 6. Return node - return node; - }, - }, - - appendChild: { - value: function (child) { - // This invokes _appendChild after doing validity checks. - return this.insertBefore(child, null); - }, - }, - - _appendChild: { - value: function (child) { - child._insertOrReplace(this, null, false); - }, - }, - - removeChild: { - value: function removeChild(child) { - var parent = this; - if (!child.nodeType) throw new TypeError('not a node'); - if (child.parentNode !== parent) utils.NotFoundError(); - child.remove(); - return child; - }, - }, - - // To replace a `child` with `node` within a `parent` (this) - replaceChild: { - value: function replaceChild(node, child) { - var parent = this; - // Ensure validity (slight differences from pre-insertion check) - parent._ensureInsertValid(node, child, false); - // Adopt node into parent's node document. - if (node.doc !== parent.doc) { - // XXX adoptNode has side-effect of removing node from its parent - // and generating a mutation event, thus causing the _insertOrReplace - // to generate two deletes and an insert instead of a 'move' - // event. It looks like the new MutationObserver stuff avoids - // this problem, but for now let's only adopt (ie, remove `node` - // from its parent) here if we need to. - parent.doc.adoptNode(node); - } - // Do the replace. - node._insertOrReplace(parent, child, true); - return child; - }, - }, - - // See: http://ejohn.org/blog/comparing-document-position/ - contains: { - value: function contains(node) { - if (node === null) { - return false; - } - if (this === node) { - return true; /* inclusive descendant */ - } - /* jshint bitwise: false */ - return (this.compareDocumentPosition(node) & DOCUMENT_POSITION_CONTAINED_BY) !== 0; - }, - }, - - compareDocumentPosition: { - value: function compareDocumentPosition(that) { - // Basic algorithm for finding the relative position of two nodes. - // Make a list the ancestors of each node, starting with the - // document element and proceeding down to the nodes themselves. - // Then, loop through the lists, looking for the first element - // that differs. The order of those two elements give the - // order of their descendant nodes. Or, if one list is a prefix - // of the other one, then that node contains the other. - - if (this === that) return 0; - - // If they're not owned by the same document or if one is rooted - // and one is not, then they're disconnected. - if (this.doc !== that.doc || this.rooted !== that.rooted) - return DOCUMENT_POSITION_DISCONNECTED + DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC; - - // Get arrays of ancestors for this and that - var these = [], - those = []; - for (var n = this; n !== null; n = n.parentNode) these.push(n); - for (n = that; n !== null; n = n.parentNode) those.push(n); - these.reverse(); // So we start with the outermost - those.reverse(); - - if (these[0] !== those[0]) - // No common ancestor - return DOCUMENT_POSITION_DISCONNECTED + DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC; - - n = Math.min(these.length, those.length); - for (var i = 1; i < n; i++) { - if (these[i] !== those[i]) { - // We found two different ancestors, so compare - // their positions - if (these[i].index < those[i].index) return DOCUMENT_POSITION_FOLLOWING; - else return DOCUMENT_POSITION_PRECEDING; - } - } - - // If we get to here, then one of the nodes (the one with the - // shorter list of ancestors) contains the other one. - if (these.length < those.length) - return DOCUMENT_POSITION_FOLLOWING + DOCUMENT_POSITION_CONTAINED_BY; - else return DOCUMENT_POSITION_PRECEDING + DOCUMENT_POSITION_CONTAINS; - }, - }, - - isSameNode: { - value: function isSameNode(node) { - return this === node; - }, - }, - - // This method implements the generic parts of node equality testing - // and defers to the (non-recursive) type-specific isEqual() method - // defined by subclasses - isEqualNode: { - value: function isEqualNode(node) { - if (!node) return false; - if (node.nodeType !== this.nodeType) return false; - - // Check type-specific properties for equality - if (!this.isEqual(node)) return false; - - // Now check children for number and equality - for ( - var c1 = this.firstChild, c2 = node.firstChild; - c1 && c2; - c1 = c1.nextSibling, c2 = c2.nextSibling - ) { - if (!c1.isEqualNode(c2)) return false; - } - return c1 === null && c2 === null; - }, - }, - - // This method delegates shallow cloning to a clone() method - // that each concrete subclass must implement - cloneNode: { - value: function (deep) { - // Clone this node - var clone = this.clone(); - - // Handle the recursive case if necessary - if (deep) { - for (var kid = this.firstChild; kid !== null; kid = kid.nextSibling) { - clone._appendChild(kid.cloneNode(true)); - } - } - - return clone; - }, - }, - - lookupPrefix: { - value: function lookupPrefix(ns) { - var e; - if (ns === '' || ns === null || ns === undefined) return null; - switch (this.nodeType) { - case ELEMENT_NODE: - return this._lookupNamespacePrefix(ns, this); - case DOCUMENT_NODE: - e = this.documentElement; - return e ? e.lookupPrefix(ns) : null; - case ENTITY_NODE: - case NOTATION_NODE: - case DOCUMENT_FRAGMENT_NODE: - case DOCUMENT_TYPE_NODE: - return null; - case ATTRIBUTE_NODE: - e = this.ownerElement; - return e ? e.lookupPrefix(ns) : null; - default: - e = this.parentElement; - return e ? e.lookupPrefix(ns) : null; - } - }, - }, - - lookupNamespaceURI: { - value: function lookupNamespaceURI(prefix) { - if (prefix === '' || prefix === undefined) { - prefix = null; - } - var e; - switch (this.nodeType) { - case ELEMENT_NODE: - return utils.shouldOverride(); - case DOCUMENT_NODE: - e = this.documentElement; - return e ? e.lookupNamespaceURI(prefix) : null; - case ENTITY_NODE: - case NOTATION_NODE: - case DOCUMENT_TYPE_NODE: - case DOCUMENT_FRAGMENT_NODE: - return null; - case ATTRIBUTE_NODE: - e = this.ownerElement; - return e ? e.lookupNamespaceURI(prefix) : null; - default: - e = this.parentElement; - return e ? e.lookupNamespaceURI(prefix) : null; - } - }, - }, - - isDefaultNamespace: { - value: function isDefaultNamespace(ns) { - if (ns === '' || ns === undefined) { - ns = null; - } - var defaultNamespace = this.lookupNamespaceURI(null); - return defaultNamespace === ns; - }, - }, - - // Utility methods for nodes. Not part of the DOM - - // Return the index of this node in its parent. - // Throw if no parent, or if this node is not a child of its parent - index: { - get: function () { - var parent = this.parentNode; - if (this === parent.firstChild) return 0; // fast case - var kids = parent.childNodes; - if (this._index === undefined || kids[this._index] !== this) { - // Ensure that we don't have an O(N^2) blowup if none of the - // kids have defined indices yet and we're traversing via - // nextSibling or previousSibling - for (var i = 0; i < kids.length; i++) { - kids[i]._index = i; - } - utils.assert(kids[this._index] === this); - } - return this._index; - }, - }, - - // Return true if this node is equal to or is an ancestor of that node - // Note that nodes are considered to be ancestors of themselves - isAncestor: { - value: function (that) { - // If they belong to different documents, then they're unrelated. - if (this.doc !== that.doc) return false; - // If one is rooted and one isn't then they're not related - if (this.rooted !== that.rooted) return false; - - // Otherwise check by traversing the parentNode chain - for (var e = that; e; e = e.parentNode) { - if (e === this) return true; - } - return false; - }, - }, - - // DOMINO Changed the behavior to conform with the specs. See: - // https://groups.google.com/d/topic/mozilla.dev.platform/77sIYcpdDmc/discussion - ensureSameDoc: { - value: function (that) { - if (that.ownerDocument === null) { - that.ownerDocument = this.doc; - } else if (that.ownerDocument !== this.doc) { - utils.WrongDocumentError(); - } - }, - }, - - removeChildren: { value: utils.shouldOverride }, - - // Insert this node as a child of parent before the specified child, - // or insert as the last child of parent if specified child is null, - // or replace the specified child with this node, firing mutation events as - // necessary - _insertOrReplace: { - value: function _insertOrReplace(parent, before, isReplace) { - var child = this, - before_index, - i; - - if (child.nodeType === DOCUMENT_FRAGMENT_NODE && child.rooted) { - utils.HierarchyRequestError(); - } - - /* Ensure index of `before` is cached before we (possibly) remove it. */ - if (parent._childNodes) { - before_index = - before === null ? parent._childNodes.length : before.index; /* ensure _index is cached */ - - // If we are already a child of the specified parent, then - // the index may have to be adjusted. - if (child.parentNode === parent) { - var child_index = child.index; - // If the child is before the spot it is to be inserted at, - // then when it is removed, the index of that spot will be - // reduced. - if (child_index < before_index) { - before_index--; - } - } - } - - // Delete the old child - if (isReplace) { - if (before.rooted) before.doc.mutateRemove(before); - before.parentNode = null; - } - - var n = before; - if (n === null) { - n = parent.firstChild; - } - - // If both the child and the parent are rooted, then we want to - // transplant the child without uprooting and rerooting it. - var bothRooted = child.rooted && parent.rooted; - if (child.nodeType === DOCUMENT_FRAGMENT_NODE) { - var spliceArgs = [0, isReplace ? 1 : 0], - next; - for (var kid = child.firstChild; kid !== null; kid = next) { - next = kid.nextSibling; - spliceArgs.push(kid); - kid.parentNode = parent; - } - var len = spliceArgs.length; - // Add all nodes to the new parent, overwriting the old child - if (isReplace) { - LinkedList.replace(n, len > 2 ? spliceArgs[2] : null); - } else if (len > 2 && n !== null) { - LinkedList.insertBefore(spliceArgs[2], n); - } - if (parent._childNodes) { - spliceArgs[0] = before === null ? parent._childNodes.length : before._index; - parent._childNodes.splice.apply(parent._childNodes, spliceArgs); - for (i = 2; i < len; i++) { - spliceArgs[i]._index = spliceArgs[0] + (i - 2); - } - } else if (parent._firstChild === before) { - if (len > 2) { - parent._firstChild = spliceArgs[2]; - } else if (isReplace) { - parent._firstChild = null; - } - } - // Remove all nodes from the document fragment - if (child._childNodes) { - child._childNodes.length = 0; - } else { - child._firstChild = null; - } - // Call the mutation handlers - // Use spliceArgs since the original array has been destroyed. The - // liveness guarantee requires us to clone the array so that - // references to the childNodes of the DocumentFragment will be empty - // when the insertion handlers are called. - if (parent.rooted) { - parent.modify(); - for (i = 2; i < len; i++) { - parent.doc.mutateInsert(spliceArgs[i]); - } - } - } else { - if (before === child) { - return; - } - if (bothRooted) { - // Remove the child from its current position in the tree - // without calling remove(), since we don't want to uproot it. - child._remove(); - } else if (child.parentNode) { - child.remove(); - } - - // Insert it as a child of its new parent - child.parentNode = parent; - if (isReplace) { - LinkedList.replace(n, child); - if (parent._childNodes) { - child._index = before_index; - parent._childNodes[before_index] = child; - } else if (parent._firstChild === before) { - parent._firstChild = child; - } - } else { - if (n !== null) { - LinkedList.insertBefore(child, n); - } - if (parent._childNodes) { - child._index = before_index; - parent._childNodes.splice(before_index, 0, child); - } else if (parent._firstChild === before) { - parent._firstChild = child; - } - } - if (bothRooted) { - parent.modify(); - // Generate a move mutation event - parent.doc.mutateMove(child); - } else if (parent.rooted) { - parent.modify(); - parent.doc.mutateInsert(child); - } - } - }, - }, - - // Return the lastModTime value for this node. (For use as a - // cache invalidation mechanism. If the node does not already - // have one, initialize it from the owner document's modclock - // property. (Note that modclock does not return the actual - // time; it is simply a counter incremented on each document - // modification) - lastModTime: { - get: function () { - if (!this._lastModTime) { - this._lastModTime = this.doc.modclock; - } - return this._lastModTime; - }, - }, - - // Increment the owner document's modclock and use the new - // value to update the lastModTime value for this node and - // all of its ancestors. Nodes that have never had their - // lastModTime value queried do not need to have a - // lastModTime property set on them since there is no - // previously queried value to ever compare the new value - // against, so only update nodes that already have a - // _lastModTime property. - modify: { - value: function () { - if (this.doc.modclock) { - // Skip while doc.modclock == 0 - var time = ++this.doc.modclock; - for (var n = this; n; n = n.parentElement) { - if (n._lastModTime) { - n._lastModTime = time; - } - } - } - }, - }, - - // This attribute is not part of the DOM but is quite helpful. - // It returns the document with which a node is associated. Usually - // this is the ownerDocument. But ownerDocument is null for the - // document object itself, so this is a handy way to get the document - // regardless of the node type - doc: { - get: function () { - return this.ownerDocument || this; - }, - }, - - // If the node has a nid (node id), then it is rooted in a document - rooted: { - get: function () { - return !!this._nid; - }, - }, - - normalize: { - value: function () { - var next; - for (var child = this.firstChild; child !== null; child = next) { - next = child.nextSibling; - - if (child.normalize) { - child.normalize(); - } - - if (child.nodeType !== Node.TEXT_NODE) { - continue; - } - - if (child.nodeValue === '') { - this.removeChild(child); - continue; - } - - var prevChild = child.previousSibling; - if (prevChild === null) { - continue; - } else if (prevChild.nodeType === Node.TEXT_NODE) { - // merge this with previous and remove the child - prevChild.appendData(child.nodeValue); - this.removeChild(child); - } - } - }, - }, - - // Convert the children of a node to an HTML string. - // This is used by the innerHTML getter - // The serialization spec is at: - // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#serializing-html-fragments - // - // The serialization logic is intentionally implemented in a separate - // `NodeUtils` helper instead of the more obvious choice of a private - // `_serializeOne()` method on the `Node.prototype` in order to avoid - // the megamorphic `this._serializeOne` property access, which reduces - // performance unnecessarily. If you need specialized behavior for a - // certain subclass, you'll need to implement that in `NodeUtils`. - // See https://github.com/fgnass/domino/pull/142 for more information. - serialize: { - value: function () { - if (this._innerHTML) { - return this._innerHTML; - } - var s = ''; - for (var kid = this.firstChild; kid !== null; kid = kid.nextSibling) { - s += NodeUtils.serializeOne(kid, this); - } - return s; - }, - }, - - // Non-standard, but often useful for debugging. - outerHTML: { - get: function () { - return NodeUtils.serializeOne(this, { nodeType: 0 }); - }, - set: utils.nyi, - }, - - // mirror node type properties in the prototype, so they are present - // in instances of Node (and subclasses) - ELEMENT_NODE: { value: ELEMENT_NODE }, - ATTRIBUTE_NODE: { value: ATTRIBUTE_NODE }, - TEXT_NODE: { value: TEXT_NODE }, - CDATA_SECTION_NODE: { value: CDATA_SECTION_NODE }, - ENTITY_REFERENCE_NODE: { value: ENTITY_REFERENCE_NODE }, - ENTITY_NODE: { value: ENTITY_NODE }, - PROCESSING_INSTRUCTION_NODE: { value: PROCESSING_INSTRUCTION_NODE }, - COMMENT_NODE: { value: COMMENT_NODE }, - DOCUMENT_NODE: { value: DOCUMENT_NODE }, - DOCUMENT_TYPE_NODE: { value: DOCUMENT_TYPE_NODE }, - DOCUMENT_FRAGMENT_NODE: { value: DOCUMENT_FRAGMENT_NODE }, - NOTATION_NODE: { value: NOTATION_NODE }, - - DOCUMENT_POSITION_DISCONNECTED: { value: DOCUMENT_POSITION_DISCONNECTED }, - DOCUMENT_POSITION_PRECEDING: { value: DOCUMENT_POSITION_PRECEDING }, - DOCUMENT_POSITION_FOLLOWING: { value: DOCUMENT_POSITION_FOLLOWING }, - DOCUMENT_POSITION_CONTAINS: { value: DOCUMENT_POSITION_CONTAINS }, - DOCUMENT_POSITION_CONTAINED_BY: { value: DOCUMENT_POSITION_CONTAINED_BY }, - DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: { value: DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC }, -}); diff --git a/packages/qwik-dom/lib/NodeFilter.js b/packages/qwik-dom/lib/NodeFilter.js deleted file mode 100644 index 876955cf42d..00000000000 --- a/packages/qwik-dom/lib/NodeFilter.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; -var NodeFilter = { - // Constants for acceptNode() - FILTER_ACCEPT: 1, - FILTER_REJECT: 2, - FILTER_SKIP: 3, - - // Constants for whatToShow - SHOW_ALL: 0xffffffff, - SHOW_ELEMENT: 0x1, - SHOW_ATTRIBUTE: 0x2, // historical - SHOW_TEXT: 0x4, - SHOW_CDATA_SECTION: 0x8, // historical - SHOW_ENTITY_REFERENCE: 0x10, // historical - SHOW_ENTITY: 0x20, // historical - SHOW_PROCESSING_INSTRUCTION: 0x40, - SHOW_COMMENT: 0x80, - SHOW_DOCUMENT: 0x100, - SHOW_DOCUMENT_TYPE: 0x200, - SHOW_DOCUMENT_FRAGMENT: 0x400, - SHOW_NOTATION: 0x800, // historical -}; - -module.exports = NodeFilter.constructor = NodeFilter.prototype = NodeFilter; diff --git a/packages/qwik-dom/lib/NodeIterator.js b/packages/qwik-dom/lib/NodeIterator.js deleted file mode 100644 index aa35e164e04..00000000000 --- a/packages/qwik-dom/lib/NodeIterator.js +++ /dev/null @@ -1,247 +0,0 @@ -'use strict'; -module.exports = NodeIterator; - -var NodeFilter = require('./NodeFilter'); -var NodeTraversal = require('./NodeTraversal'); -var utils = require('./utils'); - -/* Private methods and helpers */ - -/** - * @based on WebKit's NodeIterator::moveToNext and NodeIterator::moveToPrevious - * https://trac.webkit.org/browser/trunk/Source/WebCore/dom/NodeIterator.cpp?rev=186279#L51 - */ -function move(node, stayWithin, directionIsNext) { - if (directionIsNext) { - return NodeTraversal.next(node, stayWithin); - } else { - if (node === stayWithin) { - return null; - } - return NodeTraversal.previous(node, null); - } -} - -function isInclusiveAncestor(node, possibleChild) { - for (; possibleChild; possibleChild = possibleChild.parentNode) { - if (node === possibleChild) { - return true; - } - } - return false; -} - -/** - * @spec http://www.w3.org/TR/dom/#concept-nodeiterator-traverse - * @method - * @access private - * @param {NodeIterator} ni - * @param {string} direction One of 'next' or 'previous'. - * @return {Node|null} - */ -function traverse(ni, directionIsNext) { - var node, beforeNode; - node = ni._referenceNode; - beforeNode = ni._pointerBeforeReferenceNode; - while (true) { - if (beforeNode === directionIsNext) { - beforeNode = !beforeNode; - } else { - node = move(node, ni._root, directionIsNext); - if (node === null) { - return null; - } - } - var result = ni._internalFilter(node); - if (result === NodeFilter.FILTER_ACCEPT) { - break; - } - } - ni._referenceNode = node; - ni._pointerBeforeReferenceNode = beforeNode; - return node; -} - -/* Public API */ - -/** - * Implemented version: http://www.w3.org/TR/2015/WD-dom-20150618/#nodeiterator - * Latest version: http://www.w3.org/TR/dom/#nodeiterator - * - * @constructor - * @param {Node} root - * @param {number} whatToShow [optional] - * @param {Function|NodeFilter} filter [optional] - * @throws Error - */ -function NodeIterator(root, whatToShow, filter) { - if (!root || !root.nodeType) { - utils.NotSupportedError(); - } - - // Read-only properties - this._root = root; - this._referenceNode = root; - this._pointerBeforeReferenceNode = true; - this._whatToShow = Number(whatToShow) || 0; - this._filter = filter || null; - this._active = false; - // Record active node iterators in the document, in order to perform - // "node iterator pre-removal steps". - root.doc._attachNodeIterator(this); -} - -Object.defineProperties(NodeIterator.prototype, { - root: { - get: function root() { - return this._root; - }, - }, - referenceNode: { - get: function referenceNode() { - return this._referenceNode; - }, - }, - pointerBeforeReferenceNode: { - get: function pointerBeforeReferenceNode() { - return this._pointerBeforeReferenceNode; - }, - }, - whatToShow: { - get: function whatToShow() { - return this._whatToShow; - }, - }, - filter: { - get: function filter() { - return this._filter; - }, - }, - - /** - * @method - * @param {Node} node - * @return {Number} Constant NodeFilter.FILTER_ACCEPT, - * NodeFilter.FILTER_REJECT or NodeFilter.FILTER_SKIP. - */ - _internalFilter: { - value: function _internalFilter(node) { - /* jshint bitwise: false */ - var result, filter; - if (this._active) { - utils.InvalidStateError(); - } - - // Maps nodeType to whatToShow - if (!((1 << (node.nodeType - 1)) & this._whatToShow)) { - return NodeFilter.FILTER_SKIP; - } - - filter = this._filter; - if (filter === null) { - result = NodeFilter.FILTER_ACCEPT; - } else { - this._active = true; - try { - if (typeof filter === 'function') { - result = filter(node); - } else { - result = filter.acceptNode(node); - } - } finally { - this._active = false; - } - } - - // Note that coercing to a number means that - // `true` becomes `1` (which is NodeFilter.FILTER_ACCEPT) - // `false` becomes `0` (neither accept, reject, or skip) - return +result; - }, - }, - - /** - * @spec https://dom.spec.whatwg.org/#nodeiterator-pre-removing-steps - * @method - * @return void - */ - _preremove: { - value: function _preremove(toBeRemovedNode) { - if (isInclusiveAncestor(toBeRemovedNode, this._root)) { - return; - } - if (!isInclusiveAncestor(toBeRemovedNode, this._referenceNode)) { - return; - } - if (this._pointerBeforeReferenceNode) { - var next = toBeRemovedNode; - while (next.lastChild) { - next = next.lastChild; - } - next = NodeTraversal.next(next, this.root); - if (next) { - this._referenceNode = next; - return; - } - this._pointerBeforeReferenceNode = false; - // fall through - } - if (toBeRemovedNode.previousSibling === null) { - this._referenceNode = toBeRemovedNode.parentNode; - } else { - this._referenceNode = toBeRemovedNode.previousSibling; - var lastChild; - for ( - lastChild = this._referenceNode.lastChild; - lastChild; - lastChild = this._referenceNode.lastChild - ) { - this._referenceNode = lastChild; - } - } - }, - }, - - /** - * @spec http://www.w3.org/TR/dom/#dom-nodeiterator-nextnode - * @method - * @return {Node|null} - */ - nextNode: { - value: function nextNode() { - return traverse(this, true); - }, - }, - - /** - * @spec http://www.w3.org/TR/dom/#dom-nodeiterator-previousnode - * @method - * @return {Node|null} - */ - previousNode: { - value: function previousNode() { - return traverse(this, false); - }, - }, - - /** - * @spec http://www.w3.org/TR/dom/#dom-nodeiterator-detach - * @method - * @return void - */ - detach: { - value: function detach() { - /* "The detach() method must do nothing. - * Its functionality (disabling a NodeIterator object) was removed, - * but the method itself is preserved for compatibility. - */ - }, - }, - - /** For compatibility with web-platform-tests. */ - toString: { - value: function toString() { - return '[object NodeIterator]'; - }, - }, -}); diff --git a/packages/qwik-dom/lib/NodeList.es5.js b/packages/qwik-dom/lib/NodeList.es5.js deleted file mode 100644 index 5528ca73249..00000000000 --- a/packages/qwik-dom/lib/NodeList.es5.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; - -// No support for subclassing array, return an actual Array object. -function item(i) { - /* jshint validthis: true */ - return this[i] || null; -} - -function NodeList(a) { - if (!a) a = []; - a.item = item; - return a; -} - -module.exports = NodeList; diff --git a/packages/qwik-dom/lib/NodeList.es6.js b/packages/qwik-dom/lib/NodeList.es6.js deleted file mode 100644 index aeffc50cd96..00000000000 --- a/packages/qwik-dom/lib/NodeList.es6.js +++ /dev/null @@ -1,16 +0,0 @@ -/* jshint esversion: 6 */ -'use strict'; - -module.exports = class NodeList extends Array { - constructor(a) { - super((a && a.length) || 0); - if (a) { - for (var idx in a) { - this[idx] = a[idx]; - } - } - } - item(i) { - return this[i] || null; - } -}; diff --git a/packages/qwik-dom/lib/NodeList.js b/packages/qwik-dom/lib/NodeList.js deleted file mode 100644 index 503308efd96..00000000000 --- a/packages/qwik-dom/lib/NodeList.js +++ /dev/null @@ -1,13 +0,0 @@ -'use strict'; - -var NodeList; - -try { - // Attempt to use ES6-style Array subclass if possible. - NodeList = require('./NodeList.es6.js'); -} catch (e) { - // No support for subclassing array, return an actual Array object. - NodeList = require('./NodeList.es5.js'); -} - -module.exports = NodeList; diff --git a/packages/qwik-dom/lib/NodeTraversal.js b/packages/qwik-dom/lib/NodeTraversal.js deleted file mode 100644 index 6767b52244e..00000000000 --- a/packages/qwik-dom/lib/NodeTraversal.js +++ /dev/null @@ -1,87 +0,0 @@ -'use strict'; -/* exported NodeTraversal */ -var NodeTraversal = (module.exports = { - nextSkippingChildren: nextSkippingChildren, - nextAncestorSibling: nextAncestorSibling, - next: next, - previous: previous, - deepLastChild: deepLastChild, -}); - -/** - * @based on WebKit's NodeTraversal::nextSkippingChildren - * https://trac.webkit.org/browser/trunk/Source/WebCore/dom/NodeTraversal.h?rev=179143#L109 - */ -function nextSkippingChildren(node, stayWithin) { - if (node === stayWithin) { - return null; - } - if (node.nextSibling !== null) { - return node.nextSibling; - } - return nextAncestorSibling(node, stayWithin); -} - -/** - * @based on WebKit's NodeTraversal::nextAncestorSibling - * https://trac.webkit.org/browser/trunk/Source/WebCore/dom/NodeTraversal.cpp?rev=179143#L93 - */ -function nextAncestorSibling(node, stayWithin) { - for (node = node.parentNode; node !== null; node = node.parentNode) { - if (node === stayWithin) { - return null; - } - if (node.nextSibling !== null) { - return node.nextSibling; - } - } - return null; -} - -/** - * @based on WebKit's NodeTraversal::next - * https://trac.webkit.org/browser/trunk/Source/WebCore/dom/NodeTraversal.h?rev=179143#L99 - */ -function next(node, stayWithin) { - var n; - n = node.firstChild; - if (n !== null) { - return n; - } - if (node === stayWithin) { - return null; - } - n = node.nextSibling; - if (n !== null) { - return n; - } - return nextAncestorSibling(node, stayWithin); -} - -/** - * @based on WebKit's NodeTraversal::deepLastChild - * https://trac.webkit.org/browser/trunk/Source/WebCore/dom/NodeTraversal.cpp?rev=179143#L116 - */ -function deepLastChild(node) { - while (node.lastChild) { - node = node.lastChild; - } - return node; -} - -/** - * @based on WebKit's NodeTraversal::previous - * https://trac.webkit.org/browser/trunk/Source/WebCore/dom/NodeTraversal.h?rev=179143#L121 - */ -function previous(node, stayWithin) { - var p; - p = node.previousSibling; - if (p !== null) { - return deepLastChild(p); - } - p = node.parentNode; - if (p === stayWithin) { - return null; - } - return p; -} diff --git a/packages/qwik-dom/lib/NodeUtils.js b/packages/qwik-dom/lib/NodeUtils.js deleted file mode 100644 index 2e2ab8a5a38..00000000000 --- a/packages/qwik-dom/lib/NodeUtils.js +++ /dev/null @@ -1,173 +0,0 @@ -'use strict'; -module.exports = { - // NOTE: The `serializeOne()` function used to live on the `Node.prototype` - // as a private method `Node#_serializeOne(child)`, however that requires - // a megamorphic property access `this._serializeOne` just to get to the - // method, and this is being done on lots of different `Node` subclasses, - // which puts a lot of pressure on V8's megamorphic stub cache. So by - // moving the helper off of the `Node.prototype` and into a separate - // function in this helper module, we get a monomorphic property access - // `NodeUtils.serializeOne` to get to the function and reduce pressure - // on the megamorphic stub cache. - // See https://github.com/fgnass/domino/pull/142 for more information. - serializeOne: serializeOne, -}; - -var utils = require('./utils'); -var NAMESPACE = utils.NAMESPACE; - -var hasRawContent = { - STYLE: true, - SCRIPT: true, - XMP: true, - IFRAME: true, - NOEMBED: true, - NOFRAMES: true, - PLAINTEXT: true, -}; - -var emptyElements = { - area: true, - base: true, - basefont: true, - bgsound: true, - br: true, - col: true, - embed: true, - frame: true, - hr: true, - img: true, - input: true, - keygen: true, - link: true, - meta: true, - param: true, - source: true, - track: true, - wbr: true, -}; - -var extraNewLine = { - /* Removed in https://github.com/whatwg/html/issues/944 - pre: true, - textarea: true, - listing: true - */ -}; - -function escape(s) { - return s.replace(/[&<>\u00A0]/g, function (c) { - switch (c) { - case '&': - return '&'; - case '<': - return '<'; - case '>': - return '>'; - case '\u00A0': - return ' '; - } - }); -} - -function escapeAttr(s) { - var toEscape = /[&"\u00A0]/g; - if (!toEscape.test(s)) { - // nothing to do, fast path - return s; - } else { - return s.replace(toEscape, function (c) { - switch (c) { - case '&': - return '&'; - case '"': - return '"'; - case '\u00A0': - return ' '; - } - }); - } -} - -function attrname(a) { - var ns = a.namespaceURI; - if (!ns) return a.localName; - if (ns === NAMESPACE.XML) return 'xml:' + a.localName; - if (ns === NAMESPACE.XLINK) return 'xlink:' + a.localName; - - if (ns === NAMESPACE.XMLNS) { - if (a.localName === 'xmlns') return 'xmlns'; - else return 'xmlns:' + a.localName; - } - return a.name; -} - -function serializeOne(kid, parent) { - var s = ''; - switch (kid.nodeType) { - case 1: //ELEMENT_NODE - var ns = kid.namespaceURI; - var html = ns === NAMESPACE.HTML; - var tagname = - html || ns === NAMESPACE.SVG || ns === NAMESPACE.MATHML ? kid.localName : kid.tagName; - - s += '<' + tagname; - - for (var j = 0, k = kid._numattrs; j < k; j++) { - var a = kid._attr(j); - s += ' ' + attrname(a); - if (a.value !== undefined) s += '="' + escapeAttr(a.value) + '"'; - } - s += '>'; - - if (!(html && emptyElements[tagname])) { - var ss = kid.serialize(); - if (html && extraNewLine[tagname] && ss.charAt(0) === '\n') s += '\n'; - // Serialize children and add end tag for all others - s += ss; - s += '</' + tagname + '>'; - } - break; - case 3: //TEXT_NODE - case 4: //CDATA_SECTION_NODE - var parenttag; - if (parent.nodeType === 1 /*ELEMENT_NODE*/ && parent.namespaceURI === NAMESPACE.HTML) - parenttag = parent.tagName; - else parenttag = ''; - - if ( - hasRawContent[parenttag] || - (parenttag === 'NOSCRIPT' && parent.ownerDocument._scripting_enabled) - ) { - s += kid.data; - } else { - s += escape(kid.data); - } - break; - case 8: //COMMENT_NODE - s += '<!--' + kid.data + '-->'; - break; - case 7: //PROCESSING_INSTRUCTION_NODE - s += '<?' + kid.target + ' ' + kid.data + '?>'; - break; - case 10: //DOCUMENT_TYPE_NODE - s += '<!DOCTYPE ' + kid.name; - - if (false) { - // Latest HTML serialization spec omits the public/system ID - if (kid.publicID) { - s += ' PUBLIC "' + kid.publicId + '"'; - } - - if (kid.systemId) { - s += ' "' + kid.systemId + '"'; - } - } - - s += '>'; - break; - default: - utils.InvalidStateError(); - } - return s; -} diff --git a/packages/qwik-dom/lib/NonDocumentTypeChildNode.js b/packages/qwik-dom/lib/NonDocumentTypeChildNode.js deleted file mode 100644 index be683e95e0c..00000000000 --- a/packages/qwik-dom/lib/NonDocumentTypeChildNode.js +++ /dev/null @@ -1,28 +0,0 @@ -'use strict'; -var Node = require('./Node'); - -var NonDocumentTypeChildNode = { - nextElementSibling: { - get: function () { - if (this.parentNode) { - for (var kid = this.nextSibling; kid !== null; kid = kid.nextSibling) { - if (kid.nodeType === Node.ELEMENT_NODE) return kid; - } - } - return null; - }, - }, - - previousElementSibling: { - get: function () { - if (this.parentNode) { - for (var kid = this.previousSibling; kid !== null; kid = kid.previousSibling) { - if (kid.nodeType === Node.ELEMENT_NODE) return kid; - } - } - return null; - }, - }, -}; - -module.exports = NonDocumentTypeChildNode; diff --git a/packages/qwik-dom/lib/ProcessingInstruction.js b/packages/qwik-dom/lib/ProcessingInstruction.js deleted file mode 100644 index c0e4e4a8461..00000000000 --- a/packages/qwik-dom/lib/ProcessingInstruction.js +++ /dev/null @@ -1,57 +0,0 @@ -'use strict'; -module.exports = ProcessingInstruction; - -var Node = require('./Node'); -var CharacterData = require('./CharacterData'); -var utils = require('./utils'); - -function ProcessingInstruction(doc, target, data) { - CharacterData.call(this); - this.nodeType = Node.PROCESSING_INSTRUCTION_NODE; - this.ownerDocument = doc; - this.target = target; - this._data = data; -} - -var nodeValue = { - get: function () { - return this._data; - }, - set: function (v) { - if (v === null || v === undefined) { - v = ''; - } else { - v = String(v); - } - this._data = utils.escapeText(v); - if (this.rooted) this.ownerDocument.mutateValue(this); - }, -}; - -ProcessingInstruction.prototype = Object.create(CharacterData.prototype, { - nodeName: { - get: function () { - return this.target; - }, - }, - nodeValue: nodeValue, - textContent: nodeValue, - data: { - get: nodeValue.get, - set: function (v) { - nodeValue.set.call(this, v === null ? '' : String(v)); - }, - }, - - // Utility methods - clone: { - value: function clone() { - return new ProcessingInstruction(this.ownerDocument, this.target, this._data); - }, - }, - isEqual: { - value: function isEqual(n) { - return this.target === n.target && this._data === n._data; - }, - }, -}); diff --git a/packages/qwik-dom/lib/Text.js b/packages/qwik-dom/lib/Text.js deleted file mode 100644 index 2e11835b591..00000000000 --- a/packages/qwik-dom/lib/Text.js +++ /dev/null @@ -1,83 +0,0 @@ -'use strict'; -module.exports = Text; - -var utils = require('./utils'); -var Node = require('./Node'); -var CharacterData = require('./CharacterData'); - -function Text(doc, data) { - CharacterData.call(this); - this.nodeType = Node.TEXT_NODE; - this.ownerDocument = doc; - this._data = utils.escapeText(data); - this._index = undefined; -} - -var nodeValue = { - get: function () { - return this._data; - }, - set: function (v) { - if (v === null || v === undefined) { - v = ''; - } else { - v = String(v); - } - if (v === this._data) return; - this._data = utils.escapeText(v); - if (this.rooted) this.ownerDocument.mutateValue(this); - if (this.parentNode && this.parentNode._textchangehook) this.parentNode._textchangehook(this); - }, -}; - -Text.prototype = Object.create(CharacterData.prototype, { - nodeName: { value: '#text' }, - // These three attributes are all the same. - // The data attribute has a [TreatNullAs=EmptyString] but we'll - // implement that at the interface level - nodeValue: nodeValue, - textContent: nodeValue, - data: { - get: nodeValue.get, - set: function (v) { - nodeValue.set.call(this, v === null ? '' : String(v)); - }, - }, - - splitText: { - value: function splitText(offset) { - if (offset > this._data.length || offset < 0) utils.IndexSizeError(); - - var newdata = this._data.substring(offset), - newnode = this.ownerDocument.createTextNode(newdata); - this.data = this.data.substring(0, offset); - - var parent = this.parentNode; - if (parent !== null) parent.insertBefore(newnode, this.nextSibling); - - return newnode; - }, - }, - - wholeText: { - get: function wholeText() { - var result = this.textContent; - for (var next = this.nextSibling; next; next = next.nextSibling) { - if (next.nodeType !== Node.TEXT_NODE) { - break; - } - result += next.textContent; - } - return result; - }, - }, - // Obsolete, removed from spec. - replaceWholeText: { value: utils.nyi }, - - // Utility methods - clone: { - value: function clone() { - return new Text(this.ownerDocument, this._data); - }, - }, -}); diff --git a/packages/qwik-dom/lib/TreeWalker.js b/packages/qwik-dom/lib/TreeWalker.js deleted file mode 100644 index 41982c51f12..00000000000 --- a/packages/qwik-dom/lib/TreeWalker.js +++ /dev/null @@ -1,364 +0,0 @@ -'use strict'; -module.exports = TreeWalker; - -var Node = require('./Node'); -var NodeFilter = require('./NodeFilter'); -var NodeTraversal = require('./NodeTraversal'); -var utils = require('./utils'); - -var mapChild = { - first: 'firstChild', - last: 'lastChild', - next: 'firstChild', - previous: 'lastChild', -}; - -var mapSibling = { - first: 'nextSibling', - last: 'previousSibling', - next: 'nextSibling', - previous: 'previousSibling', -}; - -/* Private methods and helpers */ - -/** - * @spec https://dom.spec.whatwg.org/#concept-traverse-children - * @method - * @access private - * @param {TreeWalker} tw - * @param {string} type One of 'first' or 'last'. - * @return {Node|null} - */ -function traverseChildren(tw, type) { - var child, node, parent, result, sibling; - node = tw._currentNode[mapChild[type]]; - while (node !== null) { - result = tw._internalFilter(node); - if (result === NodeFilter.FILTER_ACCEPT) { - tw._currentNode = node; - return node; - } - if (result === NodeFilter.FILTER_SKIP) { - child = node[mapChild[type]]; - if (child !== null) { - node = child; - continue; - } - } - while (node !== null) { - sibling = node[mapSibling[type]]; - if (sibling !== null) { - node = sibling; - break; - } - parent = node.parentNode; - if (parent === null || parent === tw.root || parent === tw._currentNode) { - return null; - } else { - node = parent; - } - } - } - return null; -} - -/** - * @spec https://dom.spec.whatwg.org/#concept-traverse-siblings - * @method - * @access private - * @param {TreeWalker} tw - * @param {TreeWalker} type One of 'next' or 'previous'. - * @return {Node|nul} - */ -function traverseSiblings(tw, type) { - var node, result, sibling; - node = tw._currentNode; - if (node === tw.root) { - return null; - } - while (true) { - sibling = node[mapSibling[type]]; - while (sibling !== null) { - node = sibling; - result = tw._internalFilter(node); - if (result === NodeFilter.FILTER_ACCEPT) { - tw._currentNode = node; - return node; - } - sibling = node[mapChild[type]]; - if (result === NodeFilter.FILTER_REJECT || sibling === null) { - sibling = node[mapSibling[type]]; - } - } - node = node.parentNode; - if (node === null || node === tw.root) { - return null; - } - if (tw._internalFilter(node) === NodeFilter.FILTER_ACCEPT) { - return null; - } - } -} - -/* Public API */ - -/** - * Latest version: https://dom.spec.whatwg.org/#treewalker - * - * @constructor - * @param {Node} root - * @param {number} whatToShow [optional] - * @param {Function|NodeFilter} filter [optional] - * @throws Error - */ -function TreeWalker(root, whatToShow, filter) { - if (!root || !root.nodeType) { - utils.NotSupportedError(); - } - - // Read-only properties - this._root = root; - this._whatToShow = Number(whatToShow) || 0; - this._filter = filter || null; - this._active = false; - // Read-write property - this._currentNode = root; -} - -Object.defineProperties(TreeWalker.prototype, { - root: { - get: function () { - return this._root; - }, - }, - whatToShow: { - get: function () { - return this._whatToShow; - }, - }, - filter: { - get: function () { - return this._filter; - }, - }, - - currentNode: { - get: function currentNode() { - return this._currentNode; - }, - set: function setCurrentNode(v) { - if (!(v instanceof Node)) { - throw new TypeError('Not a Node'); // `null` is also not a node - } - this._currentNode = v; - }, - }, - - /** - * @method - * @param {Node} node - * @return {Number} Constant NodeFilter.FILTER_ACCEPT, - * NodeFilter.FILTER_REJECT or NodeFilter.FILTER_SKIP. - */ - _internalFilter: { - value: function _internalFilter(node) { - /* jshint bitwise: false */ - var result, filter; - if (this._active) { - utils.InvalidStateError(); - } - - // Maps nodeType to whatToShow - if (!((1 << (node.nodeType - 1)) & this._whatToShow)) { - return NodeFilter.FILTER_SKIP; - } - - filter = this._filter; - if (filter === null) { - result = NodeFilter.FILTER_ACCEPT; - } else { - this._active = true; - try { - if (typeof filter === 'function') { - result = filter(node); - } else { - result = filter.acceptNode(node); - } - } finally { - this._active = false; - } - } - - // Note that coercing to a number means that - // `true` becomes `1` (which is NodeFilter.FILTER_ACCEPT) - // `false` becomes `0` (neither accept, reject, or skip) - return +result; - }, - }, - - /** - * @spec https://dom.spec.whatwg.org/#dom-treewalker-parentnode - * @based on WebKit's TreeWalker::parentNode - * https://trac.webkit.org/browser/webkit/trunk/Source/WebCore/dom/TreeWalker.cpp?rev=220453#L50 - * @method - * @return {Node|null} - */ - parentNode: { - value: function parentNode() { - var node = this._currentNode; - while (node !== this.root) { - node = node.parentNode; - if (node === null) { - return null; - } - if (this._internalFilter(node) === NodeFilter.FILTER_ACCEPT) { - this._currentNode = node; - return node; - } - } - return null; - }, - }, - - /** - * @spec https://dom.spec.whatwg.org/#dom-treewalker-firstchild - * @method - * @return {Node|null} - */ - firstChild: { - value: function firstChild() { - return traverseChildren(this, 'first'); - }, - }, - - /** - * @spec https://dom.spec.whatwg.org/#dom-treewalker-lastchild - * @method - * @return {Node|null} - */ - lastChild: { - value: function lastChild() { - return traverseChildren(this, 'last'); - }, - }, - - /** - * @spec http://www.w3.org/TR/dom/#dom-treewalker-previoussibling - * @method - * @return {Node|null} - */ - previousSibling: { - value: function previousSibling() { - return traverseSiblings(this, 'previous'); - }, - }, - - /** - * @spec http://www.w3.org/TR/dom/#dom-treewalker-nextsibling - * @method - * @return {Node|null} - */ - nextSibling: { - value: function nextSibling() { - return traverseSiblings(this, 'next'); - }, - }, - - /** - * @spec https://dom.spec.whatwg.org/#dom-treewalker-previousnode - * @based on WebKit's TreeWalker::previousNode - * https://trac.webkit.org/browser/webkit/trunk/Source/WebCore/dom/TreeWalker.cpp?rev=220453#L181 - * @method - * @return {Node|null} - */ - previousNode: { - value: function previousNode() { - var node, result, previousSibling, lastChild; - node = this._currentNode; - while (node !== this._root) { - for ( - previousSibling = node.previousSibling; - previousSibling; - previousSibling = node.previousSibling - ) { - node = previousSibling; - result = this._internalFilter(node); - if (result === NodeFilter.FILTER_REJECT) { - continue; - } - for (lastChild = node.lastChild; lastChild; lastChild = node.lastChild) { - node = lastChild; - result = this._internalFilter(node); - if (result === NodeFilter.FILTER_REJECT) { - break; - } - } - if (result === NodeFilter.FILTER_ACCEPT) { - this._currentNode = node; - return node; - } - } - if (node === this.root || node.parentNode === null) { - return null; - } - node = node.parentNode; - if (this._internalFilter(node) === NodeFilter.FILTER_ACCEPT) { - this._currentNode = node; - return node; - } - } - return null; - }, - }, - - /** - * @spec https://dom.spec.whatwg.org/#dom-treewalker-nextnode - * @based on WebKit's TreeWalker::nextNode - * https://trac.webkit.org/browser/webkit/trunk/Source/WebCore/dom/TreeWalker.cpp?rev=220453#L228 - * @method - * @return {Node|null} - */ - nextNode: { - value: function nextNode() { - var node, result, firstChild, nextSibling; - node = this._currentNode; - result = NodeFilter.FILTER_ACCEPT; - - CHILDREN: while (true) { - for (firstChild = node.firstChild; firstChild; firstChild = node.firstChild) { - node = firstChild; - result = this._internalFilter(node); - if (result === NodeFilter.FILTER_ACCEPT) { - this._currentNode = node; - return node; - } else if (result === NodeFilter.FILTER_REJECT) { - break; - } - } - for ( - nextSibling = NodeTraversal.nextSkippingChildren(node, this.root); - nextSibling; - nextSibling = NodeTraversal.nextSkippingChildren(node, this.root) - ) { - node = nextSibling; - result = this._internalFilter(node); - if (result === NodeFilter.FILTER_ACCEPT) { - this._currentNode = node; - return node; - } else if (result === NodeFilter.FILTER_SKIP) { - continue CHILDREN; - } - } - return null; - } - }, - }, - - /** For compatibility with web-platform-tests. */ - toString: { - value: function toString() { - return '[object TreeWalker]'; - }, - }, -}); diff --git a/packages/qwik-dom/lib/UIEvent.js b/packages/qwik-dom/lib/UIEvent.js deleted file mode 100644 index 0a31d2dd849..00000000000 --- a/packages/qwik-dom/lib/UIEvent.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; -var Event = require('./Event'); - -module.exports = UIEvent; - -function UIEvent() { - // Just use the superclass constructor to initialize - Event.call(this); - this.view = null; // FF uses the current window - this.detail = 0; -} -UIEvent.prototype = Object.create(Event.prototype, { - constructor: { value: UIEvent }, - initUIEvent: { - value: function (type, bubbles, cancelable, view, detail) { - this.initEvent(type, bubbles, cancelable); - this.view = view; - this.detail = detail; - }, - }, -}); diff --git a/packages/qwik-dom/lib/URL.js b/packages/qwik-dom/lib/URL.js deleted file mode 100644 index 74509399bc2..00000000000 --- a/packages/qwik-dom/lib/URL.js +++ /dev/null @@ -1,180 +0,0 @@ -'use strict'; -module.exports = URL; - -function URL(url) { - if (!url) return Object.create(URL.prototype); - // Can't use String.trim() since it defines whitespace differently than HTML - this.url = url.replace(/^[ \t\n\r\f]+|[ \t\n\r\f]+$/g, ''); - - // See http://tools.ietf.org/html/rfc3986#appendix-B - // and https://url.spec.whatwg.org/#parsing - var match = URL.pattern.exec(this.url); - if (match) { - if (match[2]) this.scheme = match[2]; - if (match[4]) { - // parse username/password - var userinfo = match[4].match(URL.userinfoPattern); - if (userinfo) { - this.username = userinfo[1]; - this.password = userinfo[3]; - match[4] = match[4].substring(userinfo[0].length); - } - if (match[4].match(URL.portPattern)) { - var pos = match[4].lastIndexOf(':'); - this.host = match[4].substring(0, pos); - this.port = match[4].substring(pos + 1); - } else { - this.host = match[4]; - } - } - if (match[5]) this.path = match[5]; - if (match[6]) this.query = match[7]; - if (match[8]) this.fragment = match[9]; - } -} - -URL.pattern = /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/; -URL.userinfoPattern = /^([^@:]*)(:([^@]*))?@/; -URL.portPattern = /:\d+$/; -URL.authorityPattern = /^[^:\/?#]+:\/\//; -URL.hierarchyPattern = /^[^:\/?#]+:\//; - -// Return a percentEncoded version of s. -// S should be a single-character string -// XXX: needs to do utf-8 encoding? -URL.percentEncode = function percentEncode(s) { - var c = s.charCodeAt(0); - if (c < 256) return '%' + c.toString(16); - else throw Error("can't percent-encode codepoints > 255 yet"); -}; - -URL.prototype = { - constructor: URL, - - // XXX: not sure if this is the precise definition of absolute - isAbsolute: function () { - return !!this.scheme; - }, - isAuthorityBased: function () { - return URL.authorityPattern.test(this.url); - }, - isHierarchical: function () { - return URL.hierarchyPattern.test(this.url); - }, - - toString: function () { - var s = ''; - if (this.scheme !== undefined) s += this.scheme + ':'; - if (this.isAbsolute()) { - s += '//'; - if (this.username || this.password) { - s += this.username || ''; - if (this.password) { - s += ':' + this.password; - } - s += '@'; - } - if (this.host) { - s += this.host; - } - } - if (this.port !== undefined) s += ':' + this.port; - if (this.path !== undefined) s += this.path; - if (this.query !== undefined) s += '?' + this.query; - if (this.fragment !== undefined) s += '#' + this.fragment; - return s; - }, - - // See: http://tools.ietf.org/html/rfc3986#section-5.2 - // and https://url.spec.whatwg.org/#constructors - resolve: function (relative) { - var base = this; // The base url we're resolving against - var r = new URL(relative); // The relative reference url to resolve - var t = new URL(); // The absolute target url we will return - - if (r.scheme !== undefined) { - t.scheme = r.scheme; - t.username = r.username; - t.password = r.password; - t.host = r.host; - t.port = r.port; - t.path = remove_dot_segments(r.path); - t.query = r.query; - } else { - t.scheme = base.scheme; - if (r.host !== undefined) { - t.username = r.username; - t.password = r.password; - t.host = r.host; - t.port = r.port; - t.path = remove_dot_segments(r.path); - t.query = r.query; - } else { - t.username = base.username; - t.password = base.password; - t.host = base.host; - t.port = base.port; - if (!r.path) { - // undefined or empty - t.path = base.path; - if (r.query !== undefined) t.query = r.query; - else t.query = base.query; - } else { - if (r.path.charAt(0) === '/') { - t.path = remove_dot_segments(r.path); - } else { - t.path = merge(base.path, r.path); - t.path = remove_dot_segments(t.path); - } - t.query = r.query; - } - } - } - t.fragment = r.fragment; - - return t.toString(); - - function merge(basepath, refpath) { - if (base.host !== undefined && !base.path) return '/' + refpath; - - var lastslash = basepath.lastIndexOf('/'); - if (lastslash === -1) return refpath; - else return basepath.substring(0, lastslash + 1) + refpath; - } - - function remove_dot_segments(path) { - if (!path) return path; // For "" or undefined - - var output = ''; - while (path.length > 0) { - if (path === '.' || path === '..') { - path = ''; - break; - } - - var twochars = path.substring(0, 2); - var threechars = path.substring(0, 3); - var fourchars = path.substring(0, 4); - if (threechars === '../') { - path = path.substring(3); - } else if (twochars === './') { - path = path.substring(2); - } else if (threechars === '/./') { - path = '/' + path.substring(3); - } else if (twochars === '/.' && path.length === 2) { - path = '/'; - } else if (fourchars === '/../' || (threechars === '/..' && path.length === 3)) { - path = '/' + path.substring(4); - - output = output.replace(/\/?[^\/]*$/, ''); - } else { - var segment = path.match(/(\/?([^\/]*))/)[0]; - output += segment; - path = path.substring(segment.length); - } - } - - return output; - } - }, -}; diff --git a/packages/qwik-dom/lib/URLUtils.js b/packages/qwik-dom/lib/URLUtils.js deleted file mode 100644 index ce2ad75145c..00000000000 --- a/packages/qwik-dom/lib/URLUtils.js +++ /dev/null @@ -1,267 +0,0 @@ -'use strict'; -var URL = require('./URL'); - -module.exports = URLUtils; - -// Allow the `x == null` pattern. This is eslint's "null: 'ignore'" option, -// but jshint doesn't support this. -/* jshint eqeqeq: false */ - -// This is an abstract superclass for Location, HTMLAnchorElement and -// other types that have the standard complement of "URL decomposition -// IDL attributes". This is now standardized as URLUtils, see: -// https://url.spec.whatwg.org/#urlutils -// Subclasses must define a getter/setter on href. -// The getter and setter methods parse and rebuild the URL on each -// invocation; there is no attempt to cache the value and be more efficient -function URLUtils() {} -URLUtils.prototype = Object.create(Object.prototype, { - _url: { - get: function () { - // XXX: this should do the "Reinitialize url" steps, and "null" should - // be a valid return value. - return new URL(this.href); - }, - }, - - protocol: { - get: function () { - var url = this._url; - if (url && url.scheme) return url.scheme + ':'; - else return ':'; - }, - set: function (v) { - var output = this.href; - var url = new URL(output); - if (url.isAbsolute()) { - v = v.replace(/:+$/, ''); - v = v.replace(/[^-+\.a-zA-Z0-9]/g, URL.percentEncode); - if (v.length > 0) { - url.scheme = v; - output = url.toString(); - } - } - this.href = output; - }, - }, - - host: { - get: function () { - var url = this._url; - if (url.isAbsolute() && url.isAuthorityBased()) - return url.host + (url.port ? ':' + url.port : ''); - else return ''; - }, - set: function (v) { - var output = this.href; - var url = new URL(output); - if (url.isAbsolute() && url.isAuthorityBased()) { - v = v.replace(/[^-+\._~!$&'()*,;:=a-zA-Z0-9]/g, URL.percentEncode); - if (v.length > 0) { - url.host = v; - delete url.port; - output = url.toString(); - } - } - this.href = output; - }, - }, - - hostname: { - get: function () { - var url = this._url; - if (url.isAbsolute() && url.isAuthorityBased()) return url.host; - else return ''; - }, - set: function (v) { - var output = this.href; - var url = new URL(output); - if (url.isAbsolute() && url.isAuthorityBased()) { - v = v.replace(/^\/+/, ''); - v = v.replace(/[^-+\._~!$&'()*,;:=a-zA-Z0-9]/g, URL.percentEncode); - if (v.length > 0) { - url.host = v; - output = url.toString(); - } - } - this.href = output; - }, - }, - - port: { - get: function () { - var url = this._url; - if (url.isAbsolute() && url.isAuthorityBased() && url.port !== undefined) return url.port; - else return ''; - }, - set: function (v) { - var output = this.href; - var url = new URL(output); - if (url.isAbsolute() && url.isAuthorityBased()) { - v = '' + v; - v = v.replace(/[^0-9].*$/, ''); - v = v.replace(/^0+/, ''); - if (v.length === 0) v = '0'; - if (parseInt(v, 10) <= 65535) { - url.port = v; - output = url.toString(); - } - } - this.href = output; - }, - }, - - pathname: { - get: function () { - var url = this._url; - if (url.isAbsolute() && url.isHierarchical()) return url.path; - else return ''; - }, - set: function (v) { - var output = this.href; - var url = new URL(output); - if (url.isAbsolute() && url.isHierarchical()) { - if (v.charAt(0) !== '/') v = '/' + v; - v = v.replace(/[^-+\._~!$&'()*,;:=@\/a-zA-Z0-9]/g, URL.percentEncode); - url.path = v; - output = url.toString(); - } - this.href = output; - }, - }, - - search: { - get: function () { - var url = this._url; - if (url.isAbsolute() && url.isHierarchical() && url.query !== undefined) - return '?' + url.query; - else return ''; - }, - set: function (v) { - var output = this.href; - var url = new URL(output); - if (url.isAbsolute() && url.isHierarchical()) { - if (v.charAt(0) === '?') v = v.substring(1); - v = v.replace(/[^-+\._~!$&'()*,;:=@\/?a-zA-Z0-9]/g, URL.percentEncode); - url.query = v; - output = url.toString(); - } - this.href = output; - }, - }, - - hash: { - get: function () { - var url = this._url; - if (url == null || url.fragment == null || url.fragment === '') { - return ''; - } else { - return '#' + url.fragment; - } - }, - set: function (v) { - var output = this.href; - var url = new URL(output); - - if (v.charAt(0) === '#') v = v.substring(1); - v = v.replace(/[^-+\._~!$&'()*,;:=@\/?a-zA-Z0-9]/g, URL.percentEncode); - url.fragment = v; - output = url.toString(); - - this.href = output; - }, - }, - - username: { - get: function () { - var url = this._url; - return url.username || ''; - }, - set: function (v) { - var output = this.href; - var url = new URL(output); - if (url.isAbsolute()) { - v = v.replace(/[\x00-\x1F\x7F-\uFFFF "#<>?`\/@\\:]/g, URL.percentEncode); - url.username = v; - output = url.toString(); - } - this.href = output; - }, - }, - - password: { - get: function () { - var url = this._url; - return url.password || ''; - }, - set: function (v) { - var output = this.href; - var url = new URL(output); - if (url.isAbsolute()) { - if (v === '') { - url.password = null; - } else { - v = v.replace(/[\x00-\x1F\x7F-\uFFFF "#<>?`\/@\\]/g, URL.percentEncode); - url.password = v; - } - output = url.toString(); - } - this.href = output; - }, - }, - - origin: { - get: function () { - var url = this._url; - if (url == null) { - return ''; - } - var originForPort = function (defaultPort) { - var origin = [url.scheme, url.host, +url.port || defaultPort]; - // XXX should be "unicode serialization" - return origin[0] + '://' + origin[1] + (origin[2] === defaultPort ? '' : ':' + origin[2]); - }; - switch (url.scheme) { - case 'ftp': - return originForPort(21); - case 'gopher': - return originForPort(70); - case 'http': - case 'ws': - return originForPort(80); - case 'https': - case 'wss': - return originForPort(443); - default: - // this is what chrome does - return url.scheme + '://'; - } - }, - }, - - /* - searchParams: { - get: function() { - var url = this._url; - // XXX - }, - set: function(v) { - var output = this.href; - var url = new URL(output); - // XXX - this.href = output; - }, - }, - */ -}); - -URLUtils._inherit = function (proto) { - // copy getters/setters from URLUtils to o. - Object.getOwnPropertyNames(URLUtils.prototype).forEach(function (p) { - if (p === 'constructor' || p === 'href') { - return; - } - var desc = Object.getOwnPropertyDescriptor(URLUtils.prototype, p); - Object.defineProperty(proto, p, desc); - }); -}; diff --git a/packages/qwik-dom/lib/Window.js b/packages/qwik-dom/lib/Window.js deleted file mode 100644 index 020159aad5b..00000000000 --- a/packages/qwik-dom/lib/Window.js +++ /dev/null @@ -1,83 +0,0 @@ -'use strict'; -var DOMImplementation = require('./DOMImplementation'); -var EventTarget = require('./EventTarget'); -var Location = require('./Location'); -var utils = require('./utils'); - -module.exports = Window; - -function Window(document) { - this.document = document || new DOMImplementation(null).createHTMLDocument(''); - this.document._scripting_enabled = true; - this.document.defaultView = this; - this.location = new Location(this, this.document._address || 'about:blank'); -} - -Window.prototype = Object.create(EventTarget.prototype, { - console: { value: console }, - history: { - value: { - back: utils.nyi, - forward: utils.nyi, - go: utils.nyi, - }, - }, - navigator: { value: require('./NavigatorID') }, - - // Self-referential properties - window: { - get: function () { - return this; - }, - }, - self: { - get: function () { - return this; - }, - }, - frames: { - get: function () { - return this; - }, - }, - - // Self-referential properties for a top-level window - parent: { - get: function () { - return this; - }, - }, - top: { - get: function () { - return this; - }, - }, - - // We don't support any other windows for now - length: { value: 0 }, // no frames - frameElement: { value: null }, // not part of a frame - opener: { value: null }, // not opened by another window - - // The onload event handler. - // XXX: need to support a bunch of other event types, too, - // and have them interoperate with document.body. - - onload: { - get: function () { - return this._getEventHandler('load'); - }, - set: function (v) { - this._setEventHandler('load', v); - }, - }, - - // XXX This is a completely broken implementation - getComputedStyle: { - value: function getComputedStyle(elt) { - return elt.style; - }, - }, -}); - -utils.expose(require('./WindowTimers'), Window); -utils.expose(require('./impl'), Window); diff --git a/packages/qwik-dom/lib/WindowTimers.js b/packages/qwik-dom/lib/WindowTimers.js deleted file mode 100644 index 378c762ae82..00000000000 --- a/packages/qwik-dom/lib/WindowTimers.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; - -// https://html.spec.whatwg.org/multipage/webappapis.html#windowtimers -var WindowTimers = { - setTimeout: setTimeout, - clearTimeout: clearTimeout, - setInterval: setInterval, - clearInterval: clearInterval, -}; - -module.exports = WindowTimers; diff --git a/packages/qwik-dom/lib/attributes.js b/packages/qwik-dom/lib/attributes.js deleted file mode 100644 index 86ecf1c3be7..00000000000 --- a/packages/qwik-dom/lib/attributes.js +++ /dev/null @@ -1,166 +0,0 @@ -'use strict'; -var utils = require('./utils'); - -exports.property = function (attr) { - if (Array.isArray(attr.type)) { - var valid = Object.create(null); - attr.type.forEach(function (val) { - valid[val.value || val] = val.alias || val; - }); - var missingValueDefault = attr.missing; - if (missingValueDefault === undefined) { - missingValueDefault = null; - } - var invalidValueDefault = attr.invalid; - if (invalidValueDefault === undefined) { - invalidValueDefault = missingValueDefault; - } - return { - get: function () { - var v = this._getattr(attr.name); - if (v === null) return missingValueDefault; - - v = valid[v.toLowerCase()]; - if (v !== undefined) return v; - if (invalidValueDefault !== null) return invalidValueDefault; - return v; - }, - set: function (v) { - this._setattr(attr.name, v); - }, - }; - } else if (attr.type === Boolean) { - return { - get: function () { - return this.hasAttribute(attr.name); - }, - set: function (v) { - if (v) { - this._setattr(attr.name, ''); - } else { - this.removeAttribute(attr.name); - } - }, - }; - } else if ( - attr.type === Number || - attr.type === 'long' || - attr.type === 'unsigned long' || - attr.type === 'limited unsigned long with fallback' - ) { - return numberPropDesc(attr); - } else if (!attr.type || attr.type === String) { - return { - get: function () { - return this._getattr(attr.name) || ''; - }, - set: function (v) { - if (attr.treatNullAsEmptyString && v === null) { - v = ''; - } - this._setattr(attr.name, v); - }, - }; - } else if (typeof attr.type === 'function') { - return attr.type(attr.name, attr); - } - throw new Error('Invalid attribute definition'); -}; - -// See http://www.whatwg.org/specs/web-apps/current-work/#reflect -// -// defval is the default value. If it is a function, then that function -// will be invoked as a method of the element to obtain the default. -// If no default is specified for a given attribute, then the default -// depends on the type of the attribute, but since this function handles -// 4 integer cases, you must specify the default value in each call -// -// min and max define a valid range for getting the attribute. -// -// setmin defines a minimum value when setting. If the value is less -// than that, then throw INDEX_SIZE_ERR. -// -// Conveniently, JavaScript's parseInt function appears to be -// compatible with HTML's 'rules for parsing integers' -function numberPropDesc(a) { - var def; - if (typeof a.default === 'function') { - def = a.default; - } else if (typeof a.default === 'number') { - def = function () { - return a.default; - }; - } else { - def = function () { - utils.assert(false, typeof a.default); - }; - } - var unsigned_long = a.type === 'unsigned long'; - var signed_long = a.type === 'long'; - var unsigned_fallback = a.type === 'limited unsigned long with fallback'; - var min = a.min, - max = a.max, - setmin = a.setmin; - if (min === undefined) { - if (unsigned_long) min = 0; - if (signed_long) min = -0x80000000; - if (unsigned_fallback) min = 1; - } - if (max === undefined) { - if (unsigned_long || signed_long || unsigned_fallback) max = 0x7fffffff; - } - - return { - get: function () { - var v = this._getattr(a.name); - var n = a.float ? parseFloat(v) : parseInt(v, 10); - if ( - v === null || - !isFinite(n) || - (min !== undefined && n < min) || - (max !== undefined && n > max) - ) { - return def.call(this); - } - if (unsigned_long || signed_long || unsigned_fallback) { - if (!/^[ \t\n\f\r]*[-+]?[0-9]/.test(v)) { - return def.call(this); - } - n = n | 0; // jshint ignore:line - } - return n; - }, - set: function (v) { - if (!a.float) { - v = Math.floor(v); - } - if (setmin !== undefined && v < setmin) { - utils.IndexSizeError(a.name + ' set to ' + v); - } - if (unsigned_long) { - v = v < 0 || v > 0x7fffffff ? def.call(this) : v | 0; // jshint ignore:line - } else if (unsigned_fallback) { - v = v < 1 || v > 0x7fffffff ? def.call(this) : v | 0; // jshint ignore:line - } else if (signed_long) { - v = v < -0x80000000 || v > 0x7fffffff ? def.call(this) : v | 0; // jshint ignore:line - } - this._setattr(a.name, String(v)); - }, - }; -} - -// This is a utility function for setting up change handler functions -// for attributes like 'id' that require special handling when they change. -exports.registerChangeHandler = function (c, name, handler) { - var p = c.prototype; - - // If p does not already have its own _attributeChangeHandlers - // then create one for it, inheriting from the inherited - // _attributeChangeHandlers. At the top (for the Element class) the - // _attributeChangeHandlers object will be created with a null prototype. - if (!Object.prototype.hasOwnProperty.call(p, '_attributeChangeHandlers')) { - p._attributeChangeHandlers = Object.create(p._attributeChangeHandlers || null); - } - - p._attributeChangeHandlers[name] = handler; -}; diff --git a/packages/qwik-dom/lib/config.js b/packages/qwik-dom/lib/config.js deleted file mode 100644 index abd34756f80..00000000000 --- a/packages/qwik-dom/lib/config.js +++ /dev/null @@ -1,7 +0,0 @@ -/* - * This file defines Domino behaviour that can be externally configured. - * To change these settings, set the relevant global property *before* - * you call `require("domino")`. - */ - -exports.isApiWritable = !global.__domino_frozen__; diff --git a/packages/qwik-dom/lib/cssparser.js b/packages/qwik-dom/lib/cssparser.js deleted file mode 100644 index d1862bf45a5..00000000000 --- a/packages/qwik-dom/lib/cssparser.js +++ /dev/null @@ -1,6758 +0,0 @@ -/* jshint node:true, latedef:false */ -'use strict'; // jshint ignore:line -/*! -Parser-Lib -Copyright (c) 2009-2011 Nicholas C. Zakas. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -*/ -/* Version v0.2.5+domino1, Build time: 30-January-2016 05:13:03 */ -var parserlib = Object.create(null); -(function () { - /** - * A generic base to inherit from for any object - * that needs event handling. - * @class EventTarget - * @constructor - */ - function EventTarget() { - /** - * The array of listeners for various events. - * @type Object - * @property _listeners - * @private - */ - this._listeners = Object.create(null); - } - - EventTarget.prototype = { - //restore constructor - constructor: EventTarget, - - /** - * Adds a listener for a given event type. - * @param {String} type The type of event to add a listener for. - * @param {Function} listener The function to call when the event occurs. - * @return {void} - * @method addListener - */ - addListener: function (type, listener) { - if (!this._listeners[type]) { - this._listeners[type] = []; - } - - this._listeners[type].push(listener); - }, - - /** - * Fires an event based on the passed-in object. - * @param {Object|String} event An object with at least a 'type' attribute - * or a string indicating the event name. - * @return {void} - * @method fire - */ - fire: function (event) { - if (typeof event === 'string') { - event = { type: event }; - } - if (typeof event.target !== 'undefined') { - event.target = this; - } - - if (typeof event.type === 'undefined') { - throw new Error("Event object missing 'type' property."); - } - - if (this._listeners[event.type]) { - //create a copy of the array and use that so listeners can't chane - var listeners = this._listeners[event.type].concat(); - for (var i = 0, len = listeners.length; i < len; i++) { - listeners[i].call(this, event); - } - } - }, - - /** - * Removes a listener for a given event type. - * @param {String} type The type of event to remove a listener from. - * @param {Function} listener The function to remove from the event. - * @return {void} - * @method removeListener - */ - removeListener: function (type, listener) { - if (this._listeners[type]) { - var listeners = this._listeners[type]; - for (var i = 0, len = listeners.length; i < len; i++) { - if (listeners[i] === listener) { - listeners.splice(i, 1); - break; - } - } - } - }, - }; - /** - * Convenient way to read through strings. - * @namespace parserlib.util - * @class StringReader - * @constructor - * @param {String} text The text to read. - */ - function StringReader(text) { - /** - * The input text with line endings normalized. - * @property _input - * @type String - * @private - */ - this._input = text.replace(/(\r|\n){1,2}/g, '\n'); - - /** - * The row for the character to be read next. - * @property _line - * @type int - * @private - */ - this._line = 1; - - /** - * The column for the character to be read next. - * @property _col - * @type int - * @private - */ - this._col = 1; - - /** - * The index of the character in the input to be read next. - * @property _cursor - * @type int - * @private - */ - this._cursor = 0; - } - - StringReader.prototype = { - //restore constructor - constructor: StringReader, - - //------------------------------------------------------------------------- - // Position info - //------------------------------------------------------------------------- - - /** - * Returns the column of the character to be read next. - * @return {int} The column of the character to be read next. - * @method getCol - */ - getCol: function () { - return this._col; - }, - - /** - * Returns the row of the character to be read next. - * @return {int} The row of the character to be read next. - * @method getLine - */ - getLine: function () { - return this._line; - }, - - /** - * Determines if you're at the end of the input. - * @return {Boolean} True if there's no more input, false otherwise. - * @method eof - */ - eof: function () { - return this._cursor === this._input.length; - }, - - //------------------------------------------------------------------------- - // Basic reading - //------------------------------------------------------------------------- - - /** - * Reads the next character without advancing the cursor. - * @param {int} count How many characters to look ahead (default is 1). - * @return {String} The next character or null if there is no next character. - * @method peek - */ - peek: function (count) { - var c = null; - count = typeof count === 'undefined' ? 1 : count; - - //if we're not at the end of the input... - if (this._cursor < this._input.length) { - //get character and increment cursor and column - c = this._input.charAt(this._cursor + count - 1); - } - - return c; - }, - - /** - * Reads the next character from the input and adjusts the row and column - * accordingly. - * @return {String} The next character or null if there is no next character. - * @method read - */ - read: function () { - var c = null; - - //if we're not at the end of the input... - if (this._cursor < this._input.length) { - //if the last character was a newline, increment row count - //and reset column count - if (this._input.charAt(this._cursor) === '\n') { - this._line++; - this._col = 1; - } else { - this._col++; - } - - //get character and increment cursor and column - c = this._input.charAt(this._cursor++); - } - - return c; - }, - - //------------------------------------------------------------------------- - // Misc - //------------------------------------------------------------------------- - - /** - * Saves the current location so it can be returned to later. - * @method mark - * @return {void} - */ - mark: function () { - this._bookmark = { - cursor: this._cursor, - line: this._line, - col: this._col, - }; - }, - - reset: function () { - if (this._bookmark) { - this._cursor = this._bookmark.cursor; - this._line = this._bookmark.line; - this._col = this._bookmark.col; - delete this._bookmark; - } - }, - - //------------------------------------------------------------------------- - // Advanced reading - //------------------------------------------------------------------------- - - /** - * Reads up to and including the given string. Throws an error if that - * string is not found. - * @param {String} pattern The string to read. - * @return {String} The string when it is found. - * @throws Error when the string pattern is not found. - * @method readTo - */ - readTo: function (pattern) { - var buffer = '', - c; - - /* - * First, buffer must be the same length as the pattern. - * Then, buffer must end with the pattern or else reach the - * end of the input. - */ - while ( - buffer.length < pattern.length || - buffer.lastIndexOf(pattern) !== buffer.length - pattern.length - ) { - c = this.read(); - if (c) { - buffer += c; - } else { - throw new Error( - 'Expected "' + pattern + '" at line ' + this._line + ', col ' + this._col + '.' - ); - } - } - - return buffer; - }, - - /** - * Reads characters while each character causes the given - * filter function to return true. The function is passed - * in each character and either returns true to continue - * reading or false to stop. - * @param {Function} filter The function to read on each character. - * @return {String} The string made up of all characters that passed the - * filter check. - * @method readWhile - */ - readWhile: function (filter) { - var buffer = '', - c = this.read(); - - while (c !== null && filter(c)) { - buffer += c; - c = this.read(); - } - - return buffer; - }, - - /** - * Reads characters that match either text or a regular expression and - * returns those characters. If a match is found, the row and column - * are adjusted; if no match is found, the reader's state is unchanged. - * reading or false to stop. - * @param {String|RegExp} matchter If a string, then the literal string - * value is searched for. If a regular expression, then any string - * matching the pattern is search for. - * @return {String} The string made up of all characters that matched or - * null if there was no match. - * @method readMatch - */ - readMatch: function (matcher) { - var source = this._input.substring(this._cursor), - value = null; - - //if it's a string, just do a straight match - if (typeof matcher === 'string') { - if (source.indexOf(matcher) === 0) { - value = this.readCount(matcher.length); - } - } else if (matcher instanceof RegExp) { - if (matcher.test(source)) { - value = this.readCount(RegExp.lastMatch.length); - } - } - - return value; - }, - - /** - * Reads a given number of characters. If the end of the input is reached, - * it reads only the remaining characters and does not throw an error. - * @param {int} count The number of characters to read. - * @return {String} The string made up the read characters. - * @method readCount - */ - readCount: function (count) { - var buffer = ''; - - while (count--) { - buffer += this.read(); - } - - return buffer; - }, - }; - /** - * Type to use when a syntax error occurs. - * @class SyntaxError - * @namespace parserlib.util - * @constructor - * @param {String} message The error message. - * @param {int} line The line at which the error occurred. - * @param {int} col The column at which the error occurred. - */ - function SyntaxError(message, line, col) { - Error.call(this); - this.name = this.constructor.name; - - /** - * The column at which the error occurred. - * @type int - * @property col - */ - this.col = col; - - /** - * The line at which the error occurred. - * @type int - * @property line - */ - this.line = line; - - /** - * The text representation of the unit. - * @type String - * @property text - */ - this.message = message; - } - - //inherit from Error - SyntaxError.prototype = Object.create(Error.prototype); // jshint ignore:line - SyntaxError.prototype.constructor = SyntaxError; // jshint ignore:line - /** - * Base type to represent a single syntactic unit. - * @class SyntaxUnit - * @namespace parserlib.util - * @constructor - * @param {String} text The text of the unit. - * @param {int} line The line of text on which the unit resides. - * @param {int} col The column of text on which the unit resides. - */ - function SyntaxUnit(text, line, col, type) { - /** - * The column of text on which the unit resides. - * @type int - * @property col - */ - this.col = col; - - /** - * The line of text on which the unit resides. - * @type int - * @property line - */ - this.line = line; - - /** - * The text representation of the unit. - * @type String - * @property text - */ - this.text = text; - - /** - * The type of syntax unit. - * @type int - * @property type - */ - this.type = type; - } - - /** - * Create a new syntax unit based solely on the given token. - * Convenience method for creating a new syntax unit when - * it represents a single token instead of multiple. - * @param {Object} token The token object to represent. - * @return {parserlib.util.SyntaxUnit} The object representing the token. - * @static - * @method fromToken - */ - SyntaxUnit.fromToken = function (token) { - return new SyntaxUnit(token.value, token.startLine, token.startCol); - }; - - SyntaxUnit.prototype = { - //restore constructor - constructor: SyntaxUnit, - - /** - * Returns the text representation of the unit. - * @return {String} The text representation of the unit. - * @method valueOf - */ - valueOf: function () { - return this.toString(); - }, - - /** - * Returns the text representation of the unit. - * @return {String} The text representation of the unit. - * @method toString - */ - toString: function () { - return this.text; - }, - }; - - /** - * Generic TokenStream providing base functionality. - * @class TokenStreamBase - * @namespace parserlib.util - * @constructor - * @param {String|StringReader} input The text to tokenize or a reader from - * which to read the input. - */ - function TokenStreamBase(input, tokenData) { - /** - * The string reader for easy access to the text. - * @type StringReader - * @property _reader - * @private - */ - this._reader = input ? new StringReader(input.toString()) : null; - - /** - * Token object for the last consumed token. - * @type Token - * @property _token - * @private - */ - this._token = null; - - /** - * The array of token information. - * @type Array - * @property _tokenData - * @private - */ - this._tokenData = tokenData; - - /** - * Lookahead token buffer. - * @type Array - * @property _lt - * @private - */ - this._lt = []; - - /** - * Lookahead token buffer index. - * @type int - * @property _ltIndex - * @private - */ - this._ltIndex = 0; - - this._ltIndexCache = []; - } - - /** - * Accepts an array of token information and outputs - * an array of token data containing key-value mappings - * and matching functions that the TokenStream needs. - * @param {Array} tokens An array of token descriptors. - * @return {Array} An array of processed token data. - * @method createTokenData - * @static - */ - TokenStreamBase.createTokenData = function (tokens) { - var nameMap = [], - typeMap = Object.create(null), - tokenData = tokens.concat([]), - i = 0, - len = tokenData.length + 1; - - tokenData.UNKNOWN = -1; - tokenData.unshift({ name: 'EOF' }); - - for (; i < len; i++) { - nameMap.push(tokenData[i].name); - tokenData[tokenData[i].name] = i; - if (tokenData[i].text) { - typeMap[tokenData[i].text] = i; - } - } - - tokenData.name = function (tt) { - return nameMap[tt]; - }; - - tokenData.type = function (c) { - return typeMap[c]; - }; - - return tokenData; - }; - - TokenStreamBase.prototype = { - //restore constructor - constructor: TokenStreamBase, - - //------------------------------------------------------------------------- - // Matching methods - //------------------------------------------------------------------------- - - /** - * Determines if the next token matches the given token type. - * If so, that token is consumed; if not, the token is placed - * back onto the token stream. You can pass in any number of - * token types and this will return true if any of the token - * types is found. - * @param {int|int[]} tokenTypes Either a single token type or an array of - * token types that the next token might be. If an array is passed, - * it's assumed that the token can be any of these. - * @param {variant} channel (Optional) The channel to read from. If not - * provided, reads from the default (unnamed) channel. - * @return {Boolean} True if the token type matches, false if not. - * @method match - */ - match: function (tokenTypes, channel) { - //always convert to an array, makes things easier - if (!(tokenTypes instanceof Array)) { - tokenTypes = [tokenTypes]; - } - - var tt = this.get(channel), - i = 0, - len = tokenTypes.length; - - while (i < len) { - if (tt === tokenTypes[i++]) { - return true; - } - } - - //no match found, put the token back - this.unget(); - return false; - }, - - /** - * Determines if the next token matches the given token type. - * If so, that token is consumed; if not, an error is thrown. - * @param {int|int[]} tokenTypes Either a single token type or an array of - * token types that the next token should be. If an array is passed, - * it's assumed that the token must be one of these. - * @param {variant} channel (Optional) The channel to read from. If not - * provided, reads from the default (unnamed) channel. - * @return {void} - * @method mustMatch - */ - mustMatch: function (tokenTypes, channel) { - var token; - - //always convert to an array, makes things easier - if (!(tokenTypes instanceof Array)) { - tokenTypes = [tokenTypes]; - } - - if (!this.match.apply(this, arguments)) { - token = this.LT(1); - throw new SyntaxError( - 'Expected ' + - this._tokenData[tokenTypes[0]].name + - ' at line ' + - token.startLine + - ', col ' + - token.startCol + - '.', - token.startLine, - token.startCol - ); - } - }, - - //------------------------------------------------------------------------- - // Consuming methods - //------------------------------------------------------------------------- - - /** - * Keeps reading from the token stream until either one of the specified - * token types is found or until the end of the input is reached. - * @param {int|int[]} tokenTypes Either a single token type or an array of - * token types that the next token should be. If an array is passed, - * it's assumed that the token must be one of these. - * @param {variant} channel (Optional) The channel to read from. If not - * provided, reads from the default (unnamed) channel. - * @return {void} - * @method advance - */ - advance: function (tokenTypes, channel) { - while (this.LA(0) !== 0 && !this.match(tokenTypes, channel)) { - this.get(); - } - - return this.LA(0); - }, - - /** - * Consumes the next token from the token stream. - * @return {int} The token type of the token that was just consumed. - * @method get - */ - get: function (channel) { - var tokenInfo = this._tokenData, - i = 0, - token, - info; - - //check the lookahead buffer first - if (this._lt.length && this._ltIndex >= 0 && this._ltIndex < this._lt.length) { - i++; - this._token = this._lt[this._ltIndex++]; - info = tokenInfo[this._token.type]; - - //obey channels logic - while ( - info.channel !== undefined && - channel !== info.channel && - this._ltIndex < this._lt.length - ) { - this._token = this._lt[this._ltIndex++]; - info = tokenInfo[this._token.type]; - i++; - } - - //here be dragons - if ( - (info.channel === undefined || channel === info.channel) && - this._ltIndex <= this._lt.length - ) { - this._ltIndexCache.push(i); - return this._token.type; - } - } - - //call token retriever method - token = this._getToken(); - - //if it should be hidden, don't save a token - if (token.type > -1 && !tokenInfo[token.type].hide) { - //apply token channel - token.channel = tokenInfo[token.type].channel; - - //save for later - this._token = token; - this._lt.push(token); - - //save space that will be moved (must be done before array is truncated) - this._ltIndexCache.push(this._lt.length - this._ltIndex + i); - - //keep the buffer under 5 items - if (this._lt.length > 5) { - this._lt.shift(); - } - - //also keep the shift buffer under 5 items - if (this._ltIndexCache.length > 5) { - this._ltIndexCache.shift(); - } - - //update lookahead index - this._ltIndex = this._lt.length; - } - - /* - * Skip to the next token if: - * 1. The token type is marked as hidden. - * 2. The token type has a channel specified and it isn't the current channel. - */ - info = tokenInfo[token.type]; - if (info && (info.hide || (info.channel !== undefined && channel !== info.channel))) { - return this.get(channel); - } else { - //return just the type - return token.type; - } - }, - - /** - * Looks ahead a certain number of tokens and returns the token type at - * that position. This will throw an error if you lookahead past the - * end of input, past the size of the lookahead buffer, or back past - * the first token in the lookahead buffer. - * @param {int} The index of the token type to retrieve. 0 for the - * current token, 1 for the next, -1 for the previous, etc. - * @return {int} The token type of the token in the given position. - * @method LA - */ - LA: function (index) { - var total = index, - tt; - if (index > 0) { - //TODO: Store 5 somewhere - if (index > 5) { - throw new Error('Too much lookahead.'); - } - - //get all those tokens - while (total) { - tt = this.get(); - total--; - } - - //unget all those tokens - while (total < index) { - this.unget(); - total++; - } - } else if (index < 0) { - if (this._lt[this._ltIndex + index]) { - tt = this._lt[this._ltIndex + index].type; - } else { - throw new Error('Too much lookbehind.'); - } - } else { - tt = this._token.type; - } - - return tt; - }, - - /** - * Looks ahead a certain number of tokens and returns the token at - * that position. This will throw an error if you lookahead past the - * end of input, past the size of the lookahead buffer, or back past - * the first token in the lookahead buffer. - * @param {int} The index of the token type to retrieve. 0 for the - * current token, 1 for the next, -1 for the previous, etc. - * @return {Object} The token of the token in the given position. - * @method LA - */ - LT: function (index) { - //lookahead first to prime the token buffer - this.LA(index); - - //now find the token, subtract one because _ltIndex is already at the next index - return this._lt[this._ltIndex + index - 1]; - }, - - /** - * Returns the token type for the next token in the stream without - * consuming it. - * @return {int} The token type of the next token in the stream. - * @method peek - */ - peek: function () { - return this.LA(1); - }, - - /** - * Returns the actual token object for the last consumed token. - * @return {Token} The token object for the last consumed token. - * @method token - */ - token: function () { - return this._token; - }, - - /** - * Returns the name of the token for the given token type. - * @param {int} tokenType The type of token to get the name of. - * @return {String} The name of the token or "UNKNOWN_TOKEN" for any - * invalid token type. - * @method tokenName - */ - tokenName: function (tokenType) { - if (tokenType < 0 || tokenType > this._tokenData.length) { - return 'UNKNOWN_TOKEN'; - } else { - return this._tokenData[tokenType].name; - } - }, - - /** - * Returns the token type value for the given token name. - * @param {String} tokenName The name of the token whose value should be returned. - * @return {int} The token type value for the given token name or -1 - * for an unknown token. - * @method tokenName - */ - tokenType: function (tokenName) { - return this._tokenData[tokenName] || -1; - }, - - /** - * Returns the last consumed token to the token stream. - * @method unget - */ - unget: function () { - //if (this._ltIndex > -1){ - if (this._ltIndexCache.length) { - this._ltIndex -= this._ltIndexCache.pop(); //--; - this._token = this._lt[this._ltIndex - 1]; - } else { - throw new Error('Too much lookahead.'); - } - }, - }; - - parserlib.util = { - __proto__: null, - StringReader: StringReader, - SyntaxError: SyntaxError, - SyntaxUnit: SyntaxUnit, - EventTarget: EventTarget, - TokenStreamBase: TokenStreamBase, - }; -})(); -/* -Parser-Lib -Copyright (c) 2009-2011 Nicholas C. Zakas. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -*/ -/* Version v0.2.5+domino1, Build time: 30-January-2016 05:13:03 */ -(function () { - var EventTarget = parserlib.util.EventTarget, - TokenStreamBase = parserlib.util.TokenStreamBase, - StringReader = parserlib.util.StringReader, // jshint ignore:line - SyntaxError = parserlib.util.SyntaxError, - SyntaxUnit = parserlib.util.SyntaxUnit; - - var Colors = { - __proto__: null, - aliceblue: '#f0f8ff', - antiquewhite: '#faebd7', - aqua: '#00ffff', - aquamarine: '#7fffd4', - azure: '#f0ffff', - beige: '#f5f5dc', - bisque: '#ffe4c4', - black: '#000000', - blanchedalmond: '#ffebcd', - blue: '#0000ff', - blueviolet: '#8a2be2', - brown: '#a52a2a', - burlywood: '#deb887', - cadetblue: '#5f9ea0', - chartreuse: '#7fff00', - chocolate: '#d2691e', - coral: '#ff7f50', - cornflowerblue: '#6495ed', - cornsilk: '#fff8dc', - crimson: '#dc143c', - cyan: '#00ffff', - darkblue: '#00008b', - darkcyan: '#008b8b', - darkgoldenrod: '#b8860b', - darkgray: '#a9a9a9', - darkgrey: '#a9a9a9', - darkgreen: '#006400', - darkkhaki: '#bdb76b', - darkmagenta: '#8b008b', - darkolivegreen: '#556b2f', - darkorange: '#ff8c00', - darkorchid: '#9932cc', - darkred: '#8b0000', - darksalmon: '#e9967a', - darkseagreen: '#8fbc8f', - darkslateblue: '#483d8b', - darkslategray: '#2f4f4f', - darkslategrey: '#2f4f4f', - darkturquoise: '#00ced1', - darkviolet: '#9400d3', - deeppink: '#ff1493', - deepskyblue: '#00bfff', - dimgray: '#696969', - dimgrey: '#696969', - dodgerblue: '#1e90ff', - firebrick: '#b22222', - floralwhite: '#fffaf0', - forestgreen: '#228b22', - fuchsia: '#ff00ff', - gainsboro: '#dcdcdc', - ghostwhite: '#f8f8ff', - gold: '#ffd700', - goldenrod: '#daa520', - gray: '#808080', - grey: '#808080', - green: '#008000', - greenyellow: '#adff2f', - honeydew: '#f0fff0', - hotpink: '#ff69b4', - indianred: '#cd5c5c', - indigo: '#4b0082', - ivory: '#fffff0', - khaki: '#f0e68c', - lavender: '#e6e6fa', - lavenderblush: '#fff0f5', - lawngreen: '#7cfc00', - lemonchiffon: '#fffacd', - lightblue: '#add8e6', - lightcoral: '#f08080', - lightcyan: '#e0ffff', - lightgoldenrodyellow: '#fafad2', - lightgray: '#d3d3d3', - lightgrey: '#d3d3d3', - lightgreen: '#90ee90', - lightpink: '#ffb6c1', - lightsalmon: '#ffa07a', - lightseagreen: '#20b2aa', - lightskyblue: '#87cefa', - lightslategray: '#778899', - lightslategrey: '#778899', - lightsteelblue: '#b0c4de', - lightyellow: '#ffffe0', - lime: '#00ff00', - limegreen: '#32cd32', - linen: '#faf0e6', - magenta: '#ff00ff', - maroon: '#800000', - mediumaquamarine: '#66cdaa', - mediumblue: '#0000cd', - mediumorchid: '#ba55d3', - mediumpurple: '#9370d8', - mediumseagreen: '#3cb371', - mediumslateblue: '#7b68ee', - mediumspringgreen: '#00fa9a', - mediumturquoise: '#48d1cc', - mediumvioletred: '#c71585', - midnightblue: '#191970', - mintcream: '#f5fffa', - mistyrose: '#ffe4e1', - moccasin: '#ffe4b5', - navajowhite: '#ffdead', - navy: '#000080', - oldlace: '#fdf5e6', - olive: '#808000', - olivedrab: '#6b8e23', - orange: '#ffa500', - orangered: '#ff4500', - orchid: '#da70d6', - palegoldenrod: '#eee8aa', - palegreen: '#98fb98', - paleturquoise: '#afeeee', - palevioletred: '#d87093', - papayawhip: '#ffefd5', - peachpuff: '#ffdab9', - peru: '#cd853f', - pink: '#ffc0cb', - plum: '#dda0dd', - powderblue: '#b0e0e6', - purple: '#800080', - red: '#ff0000', - rosybrown: '#bc8f8f', - royalblue: '#4169e1', - saddlebrown: '#8b4513', - salmon: '#fa8072', - sandybrown: '#f4a460', - seagreen: '#2e8b57', - seashell: '#fff5ee', - sienna: '#a0522d', - silver: '#c0c0c0', - skyblue: '#87ceeb', - slateblue: '#6a5acd', - slategray: '#708090', - slategrey: '#708090', - snow: '#fffafa', - springgreen: '#00ff7f', - steelblue: '#4682b4', - tan: '#d2b48c', - teal: '#008080', - thistle: '#d8bfd8', - tomato: '#ff6347', - turquoise: '#40e0d0', - violet: '#ee82ee', - wheat: '#f5deb3', - white: '#ffffff', - whitesmoke: '#f5f5f5', - yellow: '#ffff00', - yellowgreen: '#9acd32', - //'currentColor' color keyword http://www.w3.org/TR/css3-color/#currentcolor - currentColor: "The value of the 'color' property.", - //CSS2 system colors http://www.w3.org/TR/css3-color/#css2-system - activeBorder: 'Active window border.', - activecaption: 'Active window caption.', - appworkspace: 'Background color of multiple document interface.', - background: 'Desktop background.', - buttonface: - 'The face background color for 3-D elements that appear 3-D due to one layer of surrounding border.', - buttonhighlight: - 'The color of the border facing the light source for 3-D elements that appear 3-D due to one layer of surrounding border.', - buttonshadow: - 'The color of the border away from the light source for 3-D elements that appear 3-D due to one layer of surrounding border.', - buttontext: 'Text on push buttons.', - captiontext: 'Text in caption, size box, and scrollbar arrow box.', - graytext: - 'Grayed (disabled) text. This color is set to #000 if the current display driver does not support a solid gray color.', - greytext: - 'Greyed (disabled) text. This color is set to #000 if the current display driver does not support a solid grey color.', - highlight: 'Item(s) selected in a control.', - highlighttext: 'Text of item(s) selected in a control.', - inactiveborder: 'Inactive window border.', - inactivecaption: 'Inactive window caption.', - inactivecaptiontext: 'Color of text in an inactive caption.', - infobackground: 'Background color for tooltip controls.', - infotext: 'Text color for tooltip controls.', - menu: 'Menu background.', - menutext: 'Text in menus.', - scrollbar: 'Scroll bar gray area.', - threeddarkshadow: - 'The color of the darker (generally outer) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.', - threedface: - 'The face background color for 3-D elements that appear 3-D due to two concentric layers of surrounding border.', - threedhighlight: - 'The color of the lighter (generally outer) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.', - threedlightshadow: - 'The color of the darker (generally inner) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.', - threedshadow: - 'The color of the lighter (generally inner) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.', - window: 'Window background.', - windowframe: 'Window frame.', - windowtext: 'Text in windows.', - }; - /** - * Represents a selector combinator (whitespace, +, >). - * @namespace parserlib.css - * @class Combinator - * @extends parserlib.util.SyntaxUnit - * @constructor - * @param {String} text The text representation of the unit. - * @param {int} line The line of text on which the unit resides. - * @param {int} col The column of text on which the unit resides. - */ - function Combinator(text, line, col) { - SyntaxUnit.call(this, text, line, col, Parser.COMBINATOR_TYPE); - - /** - * The type of modifier. - * @type String - * @property type - */ - this.type = 'unknown'; - - //pretty simple - if (/^\s+$/.test(text)) { - this.type = 'descendant'; - } else if (text === '>') { - this.type = 'child'; - } else if (text === '+') { - this.type = 'adjacent-sibling'; - } else if (text === '~') { - this.type = 'sibling'; - } - } - - Combinator.prototype = new SyntaxUnit(); - Combinator.prototype.constructor = Combinator; - - /** - * Represents a media feature, such as max-width:500. - * @namespace parserlib.css - * @class MediaFeature - * @extends parserlib.util.SyntaxUnit - * @constructor - * @param {SyntaxUnit} name The name of the feature. - * @param {SyntaxUnit} value The value of the feature or null if none. - */ - function MediaFeature(name, value) { - SyntaxUnit.call( - this, - '(' + name + (value !== null ? ':' + value : '') + ')', - name.startLine, - name.startCol, - Parser.MEDIA_FEATURE_TYPE - ); - - /** - * The name of the media feature - * @type String - * @property name - */ - this.name = name; - - /** - * The value for the feature or null if there is none. - * @type SyntaxUnit - * @property value - */ - this.value = value; - } - - MediaFeature.prototype = new SyntaxUnit(); - MediaFeature.prototype.constructor = MediaFeature; - - /** - * Represents an individual media query. - * @namespace parserlib.css - * @class MediaQuery - * @extends parserlib.util.SyntaxUnit - * @constructor - * @param {String} modifier The modifier "not" or "only" (or null). - * @param {String} mediaType The type of media (i.e., "print"). - * @param {Array} parts Array of selectors parts making up this selector. - * @param {int} line The line of text on which the unit resides. - * @param {int} col The column of text on which the unit resides. - */ - function MediaQuery(modifier, mediaType, features, line, col) { - SyntaxUnit.call( - this, - (modifier ? modifier + ' ' : '') + - (mediaType ? mediaType : '') + - (mediaType && features.length > 0 ? ' and ' : '') + - features.join(' and '), - line, - col, - Parser.MEDIA_QUERY_TYPE - ); - - /** - * The media modifier ("not" or "only") - * @type String - * @property modifier - */ - this.modifier = modifier; - - /** - * The mediaType (i.e., "print") - * @type String - * @property mediaType - */ - this.mediaType = mediaType; - - /** - * The parts that make up the selector. - * @type Array - * @property features - */ - this.features = features; - } - - MediaQuery.prototype = new SyntaxUnit(); - MediaQuery.prototype.constructor = MediaQuery; - - /** - * A CSS3 parser. - * @namespace parserlib.css - * @class Parser - * @constructor - * @param {Object} options (Optional) Various options for the parser: - * starHack (true|false) to allow IE6 star hack as valid, - * underscoreHack (true|false) to interpret leading underscores - * as IE6-7 targeting for known properties, ieFilters (true|false) - * to indicate that IE < 8 filters should be accepted and not throw - * syntax errors. - */ - function Parser(options) { - //inherit event functionality - EventTarget.call(this); - - this.options = options || {}; - - this._tokenStream = null; - } - - //Static constants - Parser.DEFAULT_TYPE = 0; - Parser.COMBINATOR_TYPE = 1; - Parser.MEDIA_FEATURE_TYPE = 2; - Parser.MEDIA_QUERY_TYPE = 3; - Parser.PROPERTY_NAME_TYPE = 4; - Parser.PROPERTY_VALUE_TYPE = 5; - Parser.PROPERTY_VALUE_PART_TYPE = 6; - Parser.SELECTOR_TYPE = 7; - Parser.SELECTOR_PART_TYPE = 8; - Parser.SELECTOR_SUB_PART_TYPE = 9; - - Parser.prototype = (function () { - var proto = new EventTarget(), //new prototype - prop, - additions = { - __proto__: null, - - //restore constructor - constructor: Parser, - - //instance constants - yuck - DEFAULT_TYPE: 0, - COMBINATOR_TYPE: 1, - MEDIA_FEATURE_TYPE: 2, - MEDIA_QUERY_TYPE: 3, - PROPERTY_NAME_TYPE: 4, - PROPERTY_VALUE_TYPE: 5, - PROPERTY_VALUE_PART_TYPE: 6, - SELECTOR_TYPE: 7, - SELECTOR_PART_TYPE: 8, - SELECTOR_SUB_PART_TYPE: 9, - - //----------------------------------------------------------------- - // Grammar - //----------------------------------------------------------------- - - _stylesheet: function () { - /* - * stylesheet - * : [ CHARSET_SYM S* STRING S* ';' ]? - * [S|CDO|CDC]* [ import [S|CDO|CDC]* ]* - * [ namespace [S|CDO|CDC]* ]* - * [ [ ruleset | media | page | font_face | keyframes ] [S|CDO|CDC]* ]* - * ; - */ - - var tokenStream = this._tokenStream, - count, - token, - tt; - - this.fire('startstylesheet'); - - //try to read character set - this._charset(); - - this._skipCruft(); - - //try to read imports - may be more than one - while (tokenStream.peek() === Tokens.IMPORT_SYM) { - this._import(); - this._skipCruft(); - } - - //try to read namespaces - may be more than one - while (tokenStream.peek() === Tokens.NAMESPACE_SYM) { - this._namespace(); - this._skipCruft(); - } - - //get the next token - tt = tokenStream.peek(); - - //try to read the rest - while (tt > Tokens.EOF) { - try { - switch (tt) { - case Tokens.MEDIA_SYM: - this._media(); - this._skipCruft(); - break; - case Tokens.PAGE_SYM: - this._page(); - this._skipCruft(); - break; - case Tokens.FONT_FACE_SYM: - this._font_face(); - this._skipCruft(); - break; - case Tokens.KEYFRAMES_SYM: - this._keyframes(); - this._skipCruft(); - break; - case Tokens.VIEWPORT_SYM: - this._viewport(); - this._skipCruft(); - break; - case Tokens.DOCUMENT_SYM: - this._document(); - this._skipCruft(); - break; - case Tokens.UNKNOWN_SYM: //unknown @ rule - tokenStream.get(); - if (!this.options.strict) { - //fire error event - this.fire({ - type: 'error', - error: null, - message: 'Unknown @ rule: ' + tokenStream.LT(0).value + '.', - line: tokenStream.LT(0).startLine, - col: tokenStream.LT(0).startCol, - }); - - //skip braces - count = 0; - while (tokenStream.advance([Tokens.LBRACE, Tokens.RBRACE]) === Tokens.LBRACE) { - count++; //keep track of nesting depth - } - - while (count) { - tokenStream.advance([Tokens.RBRACE]); - count--; - } - } else { - //not a syntax error, rethrow it - throw new SyntaxError( - 'Unknown @ rule.', - tokenStream.LT(0).startLine, - tokenStream.LT(0).startCol - ); - } - break; - case Tokens.S: - this._readWhitespace(); - break; - default: - if (!this._ruleset()) { - //error handling for known issues - switch (tt) { - case Tokens.CHARSET_SYM: - token = tokenStream.LT(1); - this._charset(false); - throw new SyntaxError( - '@charset not allowed here.', - token.startLine, - token.startCol - ); - case Tokens.IMPORT_SYM: - token = tokenStream.LT(1); - this._import(false); - throw new SyntaxError( - '@import not allowed here.', - token.startLine, - token.startCol - ); - case Tokens.NAMESPACE_SYM: - token = tokenStream.LT(1); - this._namespace(false); - throw new SyntaxError( - '@namespace not allowed here.', - token.startLine, - token.startCol - ); - default: //get the last token - tokenStream.get(); - this._unexpectedToken(tokenStream.token()); - } - } - } - } catch (ex) { - if (ex instanceof SyntaxError && !this.options.strict) { - this.fire({ - type: 'error', - error: ex, - message: ex.message, - line: ex.line, - col: ex.col, - }); - } else { - throw ex; - } - } - - tt = tokenStream.peek(); - } - - if (tt !== Tokens.EOF) { - this._unexpectedToken(tokenStream.token()); - } - - this.fire('endstylesheet'); - }, - - _charset: function (emit) { - var tokenStream = this._tokenStream, - charset, - token, - line, - col; - - if (tokenStream.match(Tokens.CHARSET_SYM)) { - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - - this._readWhitespace(); - tokenStream.mustMatch(Tokens.STRING); - - token = tokenStream.token(); - charset = token.value; - - this._readWhitespace(); - tokenStream.mustMatch(Tokens.SEMICOLON); - - if (emit !== false) { - this.fire({ - type: 'charset', - charset: charset, - line: line, - col: col, - }); - } - } - }, - - _import: function (emit) { - /* - * import - * : IMPORT_SYM S* - * [STRING|URI] S* media_query_list? ';' S* - */ - - var tokenStream = this._tokenStream, - uri, - importToken, - mediaList = []; - - //read import symbol - tokenStream.mustMatch(Tokens.IMPORT_SYM); - importToken = tokenStream.token(); - this._readWhitespace(); - - tokenStream.mustMatch([Tokens.STRING, Tokens.URI]); - - //grab the URI value - uri = tokenStream.token().value.replace(/^(?:url\()?["']?([^"']+?)["']?\)?$/, '$1'); - - this._readWhitespace(); - - mediaList = this._media_query_list(); - - //must end with a semicolon - tokenStream.mustMatch(Tokens.SEMICOLON); - this._readWhitespace(); - - if (emit !== false) { - this.fire({ - type: 'import', - uri: uri, - media: mediaList, - line: importToken.startLine, - col: importToken.startCol, - }); - } - }, - - _namespace: function (emit) { - /* - * namespace - * : NAMESPACE_SYM S* [namespace_prefix S*]? [STRING|URI] S* ';' S* - */ - - var tokenStream = this._tokenStream, - line, - col, - prefix, - uri; - - //read import symbol - tokenStream.mustMatch(Tokens.NAMESPACE_SYM); - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - this._readWhitespace(); - - //it's a namespace prefix - no _namespace_prefix() method because it's just an IDENT - if (tokenStream.match(Tokens.IDENT)) { - prefix = tokenStream.token().value; - this._readWhitespace(); - } - - tokenStream.mustMatch([Tokens.STRING, Tokens.URI]); - /*if (!tokenStream.match(Tokens.STRING)){ - tokenStream.mustMatch(Tokens.URI); - }*/ - - //grab the URI value - uri = tokenStream.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/, '$1'); - - this._readWhitespace(); - - //must end with a semicolon - tokenStream.mustMatch(Tokens.SEMICOLON); - this._readWhitespace(); - - if (emit !== false) { - this.fire({ - type: 'namespace', - prefix: prefix, - uri: uri, - line: line, - col: col, - }); - } - }, - - _media: function () { - /* - * media - * : MEDIA_SYM S* media_query_list S* '{' S* ruleset* '}' S* - * ; - */ - var tokenStream = this._tokenStream, - line, - col, - mediaList; // = []; - - //look for @media - tokenStream.mustMatch(Tokens.MEDIA_SYM); - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - - this._readWhitespace(); - - mediaList = this._media_query_list(); - - tokenStream.mustMatch(Tokens.LBRACE); - this._readWhitespace(); - - this.fire({ - type: 'startmedia', - media: mediaList, - line: line, - col: col, - }); - - while (true) { - if (tokenStream.peek() === Tokens.PAGE_SYM) { - this._page(); - } else if (tokenStream.peek() === Tokens.FONT_FACE_SYM) { - this._font_face(); - } else if (tokenStream.peek() === Tokens.VIEWPORT_SYM) { - this._viewport(); - } else if (tokenStream.peek() === Tokens.DOCUMENT_SYM) { - this._document(); - } else if (!this._ruleset()) { - break; - } - } - - tokenStream.mustMatch(Tokens.RBRACE); - this._readWhitespace(); - - this.fire({ - type: 'endmedia', - media: mediaList, - line: line, - col: col, - }); - }, - - //CSS3 Media Queries - _media_query_list: function () { - /* - * media_query_list - * : S* [media_query [ ',' S* media_query ]* ]? - * ; - */ - var tokenStream = this._tokenStream, - mediaList = []; - - this._readWhitespace(); - - if (tokenStream.peek() === Tokens.IDENT || tokenStream.peek() === Tokens.LPAREN) { - mediaList.push(this._media_query()); - } - - while (tokenStream.match(Tokens.COMMA)) { - this._readWhitespace(); - mediaList.push(this._media_query()); - } - - return mediaList; - }, - - /* - * Note: "expression" in the grammar maps to the _media_expression - * method. - - */ - _media_query: function () { - /* - * media_query - * : [ONLY | NOT]? S* media_type S* [ AND S* expression ]* - * | expression [ AND S* expression ]* - * ; - */ - var tokenStream = this._tokenStream, - type = null, - ident = null, - token = null, - expressions = []; - - if (tokenStream.match(Tokens.IDENT)) { - ident = tokenStream.token().value.toLowerCase(); - - //since there's no custom tokens for these, need to manually check - if (ident !== 'only' && ident !== 'not') { - tokenStream.unget(); - ident = null; - } else { - token = tokenStream.token(); - } - } - - this._readWhitespace(); - - if (tokenStream.peek() === Tokens.IDENT) { - type = this._media_type(); - if (token === null) { - token = tokenStream.token(); - } - } else if (tokenStream.peek() === Tokens.LPAREN) { - if (token === null) { - token = tokenStream.LT(1); - } - expressions.push(this._media_expression()); - } - - if (type === null && expressions.length === 0) { - return null; - } else { - this._readWhitespace(); - while (tokenStream.match(Tokens.IDENT)) { - if (tokenStream.token().value.toLowerCase() !== 'and') { - this._unexpectedToken(tokenStream.token()); - } - - this._readWhitespace(); - expressions.push(this._media_expression()); - } - } - - return new MediaQuery(ident, type, expressions, token.startLine, token.startCol); - }, - - //CSS3 Media Queries - _media_type: function () { - /* - * media_type - * : IDENT - * ; - */ - return this._media_feature(); - }, - - /** - * Note: in CSS3 Media Queries, this is called "expression". - * Renamed here to avoid conflict with CSS3 Selectors - * definition of "expression". Also note that "expr" in the - * grammar now maps to "expression" from CSS3 selectors. - * @method _media_expression - * @private - */ - _media_expression: function () { - /* - * expression - * : '(' S* media_feature S* [ ':' S* expr ]? ')' S* - * ; - */ - var tokenStream = this._tokenStream, - feature = null, - token, - expression = null; - - tokenStream.mustMatch(Tokens.LPAREN); - - feature = this._media_feature(); - this._readWhitespace(); - - if (tokenStream.match(Tokens.COLON)) { - this._readWhitespace(); - token = tokenStream.LT(1); - expression = this._expression(); - } - - tokenStream.mustMatch(Tokens.RPAREN); - this._readWhitespace(); - - return new MediaFeature( - feature, - expression ? new SyntaxUnit(expression, token.startLine, token.startCol) : null - ); - }, - - //CSS3 Media Queries - _media_feature: function () { - /* - * media_feature - * : IDENT - * ; - */ - var tokenStream = this._tokenStream; - - this._readWhitespace(); - - tokenStream.mustMatch(Tokens.IDENT); - - return SyntaxUnit.fromToken(tokenStream.token()); - }, - - //CSS3 Paged Media - _page: function () { - /* - * page: - * PAGE_SYM S* IDENT? pseudo_page? S* - * '{' S* [ declaration | margin ]? [ ';' S* [ declaration | margin ]? ]* '}' S* - * ; - */ - var tokenStream = this._tokenStream, - line, - col, - identifier = null, - pseudoPage = null; - - //look for @page - tokenStream.mustMatch(Tokens.PAGE_SYM); - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - - this._readWhitespace(); - - if (tokenStream.match(Tokens.IDENT)) { - identifier = tokenStream.token().value; - - //The value 'auto' may not be used as a page name and MUST be treated as a syntax error. - if (identifier.toLowerCase() === 'auto') { - this._unexpectedToken(tokenStream.token()); - } - } - - //see if there's a colon upcoming - if (tokenStream.peek() === Tokens.COLON) { - pseudoPage = this._pseudo_page(); - } - - this._readWhitespace(); - - this.fire({ - type: 'startpage', - id: identifier, - pseudo: pseudoPage, - line: line, - col: col, - }); - - this._readDeclarations(true, true); - - this.fire({ - type: 'endpage', - id: identifier, - pseudo: pseudoPage, - line: line, - col: col, - }); - }, - - //CSS3 Paged Media - _margin: function () { - /* - * margin : - * margin_sym S* '{' declaration [ ';' S* declaration? ]* '}' S* - * ; - */ - var tokenStream = this._tokenStream, - line, - col, - marginSym = this._margin_sym(); - - if (marginSym) { - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - - this.fire({ - type: 'startpagemargin', - margin: marginSym, - line: line, - col: col, - }); - - this._readDeclarations(true); - - this.fire({ - type: 'endpagemargin', - margin: marginSym, - line: line, - col: col, - }); - return true; - } else { - return false; - } - }, - - //CSS3 Paged Media - _margin_sym: function () { - /* - * margin_sym : - * TOPLEFTCORNER_SYM | - * TOPLEFT_SYM | - * TOPCENTER_SYM | - * TOPRIGHT_SYM | - * TOPRIGHTCORNER_SYM | - * BOTTOMLEFTCORNER_SYM | - * BOTTOMLEFT_SYM | - * BOTTOMCENTER_SYM | - * BOTTOMRIGHT_SYM | - * BOTTOMRIGHTCORNER_SYM | - * LEFTTOP_SYM | - * LEFTMIDDLE_SYM | - * LEFTBOTTOM_SYM | - * RIGHTTOP_SYM | - * RIGHTMIDDLE_SYM | - * RIGHTBOTTOM_SYM - * ; - */ - - var tokenStream = this._tokenStream; - - if ( - tokenStream.match([ - Tokens.TOPLEFTCORNER_SYM, - Tokens.TOPLEFT_SYM, - Tokens.TOPCENTER_SYM, - Tokens.TOPRIGHT_SYM, - Tokens.TOPRIGHTCORNER_SYM, - Tokens.BOTTOMLEFTCORNER_SYM, - Tokens.BOTTOMLEFT_SYM, - Tokens.BOTTOMCENTER_SYM, - Tokens.BOTTOMRIGHT_SYM, - Tokens.BOTTOMRIGHTCORNER_SYM, - Tokens.LEFTTOP_SYM, - Tokens.LEFTMIDDLE_SYM, - Tokens.LEFTBOTTOM_SYM, - Tokens.RIGHTTOP_SYM, - Tokens.RIGHTMIDDLE_SYM, - Tokens.RIGHTBOTTOM_SYM, - ]) - ) { - return SyntaxUnit.fromToken(tokenStream.token()); - } else { - return null; - } - }, - - _pseudo_page: function () { - /* - * pseudo_page - * : ':' IDENT - * ; - */ - - var tokenStream = this._tokenStream; - - tokenStream.mustMatch(Tokens.COLON); - tokenStream.mustMatch(Tokens.IDENT); - - //TODO: CSS3 Paged Media says only "left", "center", and "right" are allowed - - return tokenStream.token().value; - }, - - _font_face: function () { - /* - * font_face - * : FONT_FACE_SYM S* - * '{' S* declaration [ ';' S* declaration ]* '}' S* - * ; - */ - var tokenStream = this._tokenStream, - line, - col; - - //look for @page - tokenStream.mustMatch(Tokens.FONT_FACE_SYM); - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - - this._readWhitespace(); - - this.fire({ - type: 'startfontface', - line: line, - col: col, - }); - - this._readDeclarations(true); - - this.fire({ - type: 'endfontface', - line: line, - col: col, - }); - }, - - _viewport: function () { - /* - * viewport - * : VIEWPORT_SYM S* - * '{' S* declaration? [ ';' S* declaration? ]* '}' S* - * ; - */ - var tokenStream = this._tokenStream, - line, - col; - - tokenStream.mustMatch(Tokens.VIEWPORT_SYM); - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - - this._readWhitespace(); - - this.fire({ - type: 'startviewport', - line: line, - col: col, - }); - - this._readDeclarations(true); - - this.fire({ - type: 'endviewport', - line: line, - col: col, - }); - }, - - _document: function () { - /* - * document - * : DOCUMENT_SYM S* - * _document_function [ ',' S* _document_function ]* S* - * '{' S* ruleset* '}' - * ; - */ - - var tokenStream = this._tokenStream, - token, - functions = [], - prefix = ''; - - tokenStream.mustMatch(Tokens.DOCUMENT_SYM); - token = tokenStream.token(); - if (/^@\-([^\-]+)\-/.test(token.value)) { - prefix = RegExp.$1; - } - - this._readWhitespace(); - functions.push(this._document_function()); - - while (tokenStream.match(Tokens.COMMA)) { - this._readWhitespace(); - functions.push(this._document_function()); - } - - tokenStream.mustMatch(Tokens.LBRACE); - this._readWhitespace(); - - this.fire({ - type: 'startdocument', - functions: functions, - prefix: prefix, - line: token.startLine, - col: token.startCol, - }); - - while (true) { - if (tokenStream.peek() === Tokens.PAGE_SYM) { - this._page(); - } else if (tokenStream.peek() === Tokens.FONT_FACE_SYM) { - this._font_face(); - } else if (tokenStream.peek() === Tokens.VIEWPORT_SYM) { - this._viewport(); - } else if (tokenStream.peek() === Tokens.MEDIA_SYM) { - this._media(); - } else if (!this._ruleset()) { - break; - } - } - - tokenStream.mustMatch(Tokens.RBRACE); - this._readWhitespace(); - - this.fire({ - type: 'enddocument', - functions: functions, - prefix: prefix, - line: token.startLine, - col: token.startCol, - }); - }, - - _document_function: function () { - /* - * document_function - * : function | URI S* - * ; - */ - - var tokenStream = this._tokenStream, - value; - - if (tokenStream.match(Tokens.URI)) { - value = tokenStream.token().value; - this._readWhitespace(); - } else { - value = this._function(); - } - - return value; - }, - - _operator: function (inFunction) { - /* - * operator (outside function) - * : '/' S* | ',' S* | /( empty )/ - * operator (inside function) - * : '/' S* | '+' S* | '*' S* | '-' S* /( empty )/ - * ; - */ - - var tokenStream = this._tokenStream, - token = null; - - if ( - tokenStream.match([Tokens.SLASH, Tokens.COMMA]) || - (inFunction && tokenStream.match([Tokens.PLUS, Tokens.STAR, Tokens.MINUS])) - ) { - token = tokenStream.token(); - this._readWhitespace(); - } - return token ? PropertyValuePart.fromToken(token) : null; - }, - - _combinator: function () { - /* - * combinator - * : PLUS S* | GREATER S* | TILDE S* | S+ - * ; - */ - - var tokenStream = this._tokenStream, - value = null, - token; - - if (tokenStream.match([Tokens.PLUS, Tokens.GREATER, Tokens.TILDE])) { - token = tokenStream.token(); - value = new Combinator(token.value, token.startLine, token.startCol); - this._readWhitespace(); - } - - return value; - }, - - _unary_operator: function () { - /* - * unary_operator - * : '-' | '+' - * ; - */ - - var tokenStream = this._tokenStream; - - if (tokenStream.match([Tokens.MINUS, Tokens.PLUS])) { - return tokenStream.token().value; - } else { - return null; - } - }, - - _property: function () { - /* - * property - * : IDENT S* - * ; - */ - - var tokenStream = this._tokenStream, - value = null, - hack = null, - tokenValue, - token, - line, - col; - - //check for star hack - throws error if not allowed - if (tokenStream.peek() === Tokens.STAR && this.options.starHack) { - tokenStream.get(); - token = tokenStream.token(); - hack = token.value; - line = token.startLine; - col = token.startCol; - } - - if (tokenStream.match(Tokens.IDENT)) { - token = tokenStream.token(); - tokenValue = token.value; - - //check for underscore hack - no error if not allowed because it's valid CSS syntax - if (tokenValue.charAt(0) === '_' && this.options.underscoreHack) { - hack = '_'; - tokenValue = tokenValue.substring(1); - } - - value = new PropertyName( - tokenValue, - hack, - line || token.startLine, - col || token.startCol - ); - this._readWhitespace(); - } - - return value; - }, - - //Augmented with CSS3 Selectors - _ruleset: function () { - /* - * ruleset - * : selectors_group - * '{' S* declaration? [ ';' S* declaration? ]* '}' S* - * ; - */ - - var tokenStream = this._tokenStream, - tt, - selectors; - - /* - * Error Recovery: If even a single selector fails to parse, - * then the entire ruleset should be thrown away. - */ - try { - selectors = this._selectors_group(); - } catch (ex) { - if (ex instanceof SyntaxError && !this.options.strict) { - //fire error event - this.fire({ - type: 'error', - error: ex, - message: ex.message, - line: ex.line, - col: ex.col, - }); - - //skip over everything until closing brace - tt = tokenStream.advance([Tokens.RBRACE]); - if (tt === Tokens.RBRACE) { - //if there's a right brace, the rule is finished so don't do anything - } else { - //otherwise, rethrow the error because it wasn't handled properly - throw ex; - } - } else { - //not a syntax error, rethrow it - throw ex; - } - - //trigger parser to continue - return true; - } - - //if it got here, all selectors parsed - if (selectors) { - this.fire({ - type: 'startrule', - selectors: selectors, - line: selectors[0].line, - col: selectors[0].col, - }); - - this._readDeclarations(true); - - this.fire({ - type: 'endrule', - selectors: selectors, - line: selectors[0].line, - col: selectors[0].col, - }); - } - - return selectors; - }, - - //CSS3 Selectors - _selectors_group: function () { - /* - * selectors_group - * : selector [ COMMA S* selector ]* - * ; - */ - var tokenStream = this._tokenStream, - selectors = [], - selector; - - selector = this._selector(); - if (selector !== null) { - selectors.push(selector); - while (tokenStream.match(Tokens.COMMA)) { - this._readWhitespace(); - selector = this._selector(); - if (selector !== null) { - selectors.push(selector); - } else { - this._unexpectedToken(tokenStream.LT(1)); - } - } - } - - return selectors.length ? selectors : null; - }, - - //CSS3 Selectors - _selector: function () { - /* - * selector - * : simple_selector_sequence [ combinator simple_selector_sequence ]* - * ; - */ - - var tokenStream = this._tokenStream, - selector = [], - nextSelector = null, - combinator = null, - ws = null; - - //if there's no simple selector, then there's no selector - nextSelector = this._simple_selector_sequence(); - if (nextSelector === null) { - return null; - } - - selector.push(nextSelector); - - do { - //look for a combinator - combinator = this._combinator(); - - if (combinator !== null) { - selector.push(combinator); - nextSelector = this._simple_selector_sequence(); - - //there must be a next selector - if (nextSelector === null) { - this._unexpectedToken(tokenStream.LT(1)); - } else { - //nextSelector is an instance of SelectorPart - selector.push(nextSelector); - } - } else { - //if there's not whitespace, we're done - if (this._readWhitespace()) { - //add whitespace separator - ws = new Combinator( - tokenStream.token().value, - tokenStream.token().startLine, - tokenStream.token().startCol - ); - - //combinator is not required - combinator = this._combinator(); - - //selector is required if there's a combinator - nextSelector = this._simple_selector_sequence(); - if (nextSelector === null) { - if (combinator !== null) { - this._unexpectedToken(tokenStream.LT(1)); - } - } else { - if (combinator !== null) { - selector.push(combinator); - } else { - selector.push(ws); - } - - selector.push(nextSelector); - } - } else { - break; - } - } - } while (true); - - return new Selector(selector, selector[0].line, selector[0].col); - }, - - //CSS3 Selectors - _simple_selector_sequence: function () { - /* - * simple_selector_sequence - * : [ type_selector | universal ] - * [ HASH | class | attrib | pseudo | negation ]* - * | [ HASH | class | attrib | pseudo | negation ]+ - * ; - */ - - var tokenStream = this._tokenStream, - //parts of a simple selector - elementName = null, - modifiers = [], - //complete selector text - selectorText = '', - //the different parts after the element name to search for - components = [ - //HASH - function () { - return tokenStream.match(Tokens.HASH) - ? new SelectorSubPart( - tokenStream.token().value, - 'id', - tokenStream.token().startLine, - tokenStream.token().startCol - ) - : null; - }, - this._class, - this._attrib, - this._pseudo, - this._negation, - ], - i = 0, - len = components.length, - component = null, - line, - col; - - //get starting line and column for the selector - line = tokenStream.LT(1).startLine; - col = tokenStream.LT(1).startCol; - - elementName = this._type_selector(); - if (!elementName) { - elementName = this._universal(); - } - - if (elementName !== null) { - selectorText += elementName; - } - - while (true) { - //whitespace means we're done - if (tokenStream.peek() === Tokens.S) { - break; - } - - //check for each component - while (i < len && component === null) { - component = components[i++].call(this); - } - - if (component === null) { - //we don't have a selector - if (selectorText === '') { - return null; - } else { - break; - } - } else { - i = 0; - modifiers.push(component); - selectorText += component.toString(); - component = null; - } - } - - return selectorText !== '' - ? new SelectorPart(elementName, modifiers, selectorText, line, col) - : null; - }, - - //CSS3 Selectors - _type_selector: function () { - /* - * type_selector - * : [ namespace_prefix ]? element_name - * ; - */ - - var tokenStream = this._tokenStream, - ns = this._namespace_prefix(), - elementName = this._element_name(); - - if (!elementName) { - /* - * Need to back out the namespace that was read due to both - * type_selector and universal reading namespace_prefix - * first. Kind of hacky, but only way I can figure out - * right now how to not change the grammar. - */ - if (ns) { - tokenStream.unget(); - if (ns.length > 1) { - tokenStream.unget(); - } - } - - return null; - } else { - if (ns) { - elementName.text = ns + elementName.text; - elementName.col -= ns.length; - } - return elementName; - } - }, - - //CSS3 Selectors - _class: function () { - /* - * class - * : '.' IDENT - * ; - */ - - var tokenStream = this._tokenStream, - token; - - if (tokenStream.match(Tokens.DOT)) { - tokenStream.mustMatch(Tokens.IDENT); - token = tokenStream.token(); - return new SelectorSubPart( - '.' + token.value, - 'class', - token.startLine, - token.startCol - 1 - ); - } else { - return null; - } - }, - - //CSS3 Selectors - _element_name: function () { - /* - * element_name - * : IDENT - * ; - */ - - var tokenStream = this._tokenStream, - token; - - if (tokenStream.match(Tokens.IDENT)) { - token = tokenStream.token(); - return new SelectorSubPart(token.value, 'elementName', token.startLine, token.startCol); - } else { - return null; - } - }, - - //CSS3 Selectors - _namespace_prefix: function () { - /* - * namespace_prefix - * : [ IDENT | '*' ]? '|' - * ; - */ - var tokenStream = this._tokenStream, - value = ''; - - //verify that this is a namespace prefix - if (tokenStream.LA(1) === Tokens.PIPE || tokenStream.LA(2) === Tokens.PIPE) { - if (tokenStream.match([Tokens.IDENT, Tokens.STAR])) { - value += tokenStream.token().value; - } - - tokenStream.mustMatch(Tokens.PIPE); - value += '|'; - } - - return value.length ? value : null; - }, - - //CSS3 Selectors - _universal: function () { - /* - * universal - * : [ namespace_prefix ]? '*' - * ; - */ - var tokenStream = this._tokenStream, - value = '', - ns; - - ns = this._namespace_prefix(); - if (ns) { - value += ns; - } - - if (tokenStream.match(Tokens.STAR)) { - value += '*'; - } - - return value.length ? value : null; - }, - - //CSS3 Selectors - _attrib: function () { - /* - * attrib - * : '[' S* [ namespace_prefix ]? IDENT S* - * [ [ PREFIXMATCH | - * SUFFIXMATCH | - * SUBSTRINGMATCH | - * '=' | - * INCLUDES | - * DASHMATCH ] S* [ IDENT | STRING ] S* - * ]? ']' - * ; - */ - - var tokenStream = this._tokenStream, - value = null, - ns, - token; - - if (tokenStream.match(Tokens.LBRACKET)) { - token = tokenStream.token(); - value = token.value; - value += this._readWhitespace(); - - ns = this._namespace_prefix(); - - if (ns) { - value += ns; - } - - tokenStream.mustMatch(Tokens.IDENT); - value += tokenStream.token().value; - value += this._readWhitespace(); - - if ( - tokenStream.match([ - Tokens.PREFIXMATCH, - Tokens.SUFFIXMATCH, - Tokens.SUBSTRINGMATCH, - Tokens.EQUALS, - Tokens.INCLUDES, - Tokens.DASHMATCH, - ]) - ) { - value += tokenStream.token().value; - value += this._readWhitespace(); - - tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]); - value += tokenStream.token().value; - value += this._readWhitespace(); - } - - tokenStream.mustMatch(Tokens.RBRACKET); - - return new SelectorSubPart(value + ']', 'attribute', token.startLine, token.startCol); - } else { - return null; - } - }, - - //CSS3 Selectors - _pseudo: function () { - /* - * pseudo - * : ':' ':'? [ IDENT | functional_pseudo ] - * ; - */ - - var tokenStream = this._tokenStream, - pseudo = null, - colons = ':', - line, - col; - - if (tokenStream.match(Tokens.COLON)) { - if (tokenStream.match(Tokens.COLON)) { - colons += ':'; - } - - if (tokenStream.match(Tokens.IDENT)) { - pseudo = tokenStream.token().value; - line = tokenStream.token().startLine; - col = tokenStream.token().startCol - colons.length; - } else if (tokenStream.peek() === Tokens.FUNCTION) { - line = tokenStream.LT(1).startLine; - col = tokenStream.LT(1).startCol - colons.length; - pseudo = this._functional_pseudo(); - } - - if (pseudo) { - pseudo = new SelectorSubPart(colons + pseudo, 'pseudo', line, col); - } - } - - return pseudo; - }, - - //CSS3 Selectors - _functional_pseudo: function () { - /* - * functional_pseudo - * : FUNCTION S* expression ')' - * ; - */ - - var tokenStream = this._tokenStream, - value = null; - - if (tokenStream.match(Tokens.FUNCTION)) { - value = tokenStream.token().value; - value += this._readWhitespace(); - value += this._expression(); - tokenStream.mustMatch(Tokens.RPAREN); - value += ')'; - } - - return value; - }, - - //CSS3 Selectors - _expression: function () { - /* - * expression - * : [ [ PLUS | '-' | DIMENSION | NUMBER | STRING | IDENT ] S* ]+ - * ; - */ - - var tokenStream = this._tokenStream, - value = ''; - - while ( - tokenStream.match([ - Tokens.PLUS, - Tokens.MINUS, - Tokens.DIMENSION, - Tokens.NUMBER, - Tokens.STRING, - Tokens.IDENT, - Tokens.LENGTH, - Tokens.FREQ, - Tokens.ANGLE, - Tokens.TIME, - Tokens.RESOLUTION, - Tokens.SLASH, - ]) - ) { - value += tokenStream.token().value; - value += this._readWhitespace(); - } - - return value.length ? value : null; - }, - - //CSS3 Selectors - _negation: function () { - /* - * negation - * : NOT S* negation_arg S* ')' - * ; - */ - - var tokenStream = this._tokenStream, - line, - col, - value = '', - arg, - subpart = null; - - if (tokenStream.match(Tokens.NOT)) { - value = tokenStream.token().value; - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - value += this._readWhitespace(); - arg = this._negation_arg(); - value += arg; - value += this._readWhitespace(); - tokenStream.match(Tokens.RPAREN); - value += tokenStream.token().value; - - subpart = new SelectorSubPart(value, 'not', line, col); - subpart.args.push(arg); - } - - return subpart; - }, - - //CSS3 Selectors - _negation_arg: function () { - /* - * negation_arg - * : type_selector | universal | HASH | class | attrib | pseudo - * ; - */ - - var tokenStream = this._tokenStream, - args = [ - this._type_selector, - this._universal, - function () { - return tokenStream.match(Tokens.HASH) - ? new SelectorSubPart( - tokenStream.token().value, - 'id', - tokenStream.token().startLine, - tokenStream.token().startCol - ) - : null; - }, - this._class, - this._attrib, - this._pseudo, - ], - arg = null, - i = 0, - len = args.length, - line, - col, - part; - - line = tokenStream.LT(1).startLine; - col = tokenStream.LT(1).startCol; - - while (i < len && arg === null) { - arg = args[i].call(this); - i++; - } - - //must be a negation arg - if (arg === null) { - this._unexpectedToken(tokenStream.LT(1)); - } - - //it's an element name - if (arg.type === 'elementName') { - part = new SelectorPart(arg, [], arg.toString(), line, col); - } else { - part = new SelectorPart(null, [arg], arg.toString(), line, col); - } - - return part; - }, - - _declaration: function () { - /* - * declaration - * : property ':' S* expr prio? - * | /( empty )/ - * ; - */ - - var tokenStream = this._tokenStream, - property = null, - expr = null, - prio = null, - invalid = null, - propertyName = ''; - - property = this._property(); - if (property !== null) { - tokenStream.mustMatch(Tokens.COLON); - this._readWhitespace(); - - expr = this._expr(); - - //if there's no parts for the value, it's an error - if (!expr || expr.length === 0) { - this._unexpectedToken(tokenStream.LT(1)); - } - - prio = this._prio(); - - /* - * If hacks should be allowed, then only check the root - * property. If hacks should not be allowed, treat - * _property or *property as invalid properties. - */ - propertyName = property.toString(); - if ( - (this.options.starHack && property.hack === '*') || - (this.options.underscoreHack && property.hack === '_') - ) { - propertyName = property.text; - } - - try { - this._validateProperty(propertyName, expr); - } catch (ex) { - invalid = ex; - } - - this.fire({ - type: 'property', - property: property, - value: expr, - important: prio, - line: property.line, - col: property.col, - invalid: invalid, - }); - - return true; - } else { - return false; - } - }, - - _prio: function () { - /* - * prio - * : IMPORTANT_SYM S* - * ; - */ - - var tokenStream = this._tokenStream, - result = tokenStream.match(Tokens.IMPORTANT_SYM); - - this._readWhitespace(); - return result; - }, - - _expr: function (inFunction) { - /* - * expr - * : term [ operator term ]* - * ; - */ - - var values = [], - //valueParts = [], - value = null, - operator = null; - - value = this._term(inFunction); - if (value !== null) { - values.push(value); - - do { - operator = this._operator(inFunction); - - //if there's an operator, keep building up the value parts - if (operator) { - values.push(operator); - } /*else { - //if there's not an operator, you have a full value - values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col)); - valueParts = []; - }*/ - - value = this._term(inFunction); - - if (value === null) { - break; - } else { - values.push(value); - } - } while (true); - } - - //cleanup - /*if (valueParts.length){ - values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col)); - }*/ - - return values.length > 0 - ? new PropertyValue(values, values[0].line, values[0].col) - : null; - }, - - _term: function (inFunction) { - /* - * term - * : unary_operator? - * [ NUMBER S* | PERCENTAGE S* | LENGTH S* | ANGLE S* | - * TIME S* | FREQ S* | function | ie_function ] - * | STRING S* | IDENT S* | URI S* | UNICODERANGE S* | hexcolor - * ; - */ - - var tokenStream = this._tokenStream, - unary = null, - value = null, - endChar = null, - token, - line, - col; - - //returns the operator or null - unary = this._unary_operator(); - if (unary !== null) { - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - } - - //exception for IE filters - if (tokenStream.peek() === Tokens.IE_FUNCTION && this.options.ieFilters) { - value = this._ie_function(); - if (unary === null) { - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - } - - //see if it's a simple block - } else if ( - inFunction && - tokenStream.match([Tokens.LPAREN, Tokens.LBRACE, Tokens.LBRACKET]) - ) { - token = tokenStream.token(); - endChar = token.endChar; - value = token.value + this._expr(inFunction).text; - if (unary === null) { - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - } - tokenStream.mustMatch(Tokens.type(endChar)); - value += endChar; - this._readWhitespace(); - - //see if there's a simple match - } else if ( - tokenStream.match([ - Tokens.NUMBER, - Tokens.PERCENTAGE, - Tokens.LENGTH, - Tokens.ANGLE, - Tokens.TIME, - Tokens.FREQ, - Tokens.STRING, - Tokens.IDENT, - Tokens.URI, - Tokens.UNICODE_RANGE, - ]) - ) { - value = tokenStream.token().value; - if (unary === null) { - line = tokenStream.token().startLine; - col = tokenStream.token().startCol; - } - this._readWhitespace(); - } else { - //see if it's a color - token = this._hexcolor(); - if (token === null) { - //if there's no unary, get the start of the next token for line/col info - if (unary === null) { - line = tokenStream.LT(1).startLine; - col = tokenStream.LT(1).startCol; - } - - //has to be a function - if (value === null) { - /* - * This checks for alpha(opacity=0) style of IE - * functions. IE_FUNCTION only presents progid: style. - */ - if (tokenStream.LA(3) === Tokens.EQUALS && this.options.ieFilters) { - value = this._ie_function(); - } else { - value = this._function(); - } - } - - /*if (value === null){ - return null; - //throw new Error("Expected identifier at line " + tokenStream.token().startLine + ", character " + tokenStream.token().startCol + "."); - }*/ - } else { - value = token.value; - if (unary === null) { - line = token.startLine; - col = token.startCol; - } - } - } - - return value !== null - ? new PropertyValuePart(unary !== null ? unary + value : value, line, col) - : null; - }, - - _function: function () { - /* - * function - * : FUNCTION S* expr ')' S* - * ; - */ - - var tokenStream = this._tokenStream, - functionText = null, - expr = null, - lt; - - if (tokenStream.match(Tokens.FUNCTION)) { - functionText = tokenStream.token().value; - this._readWhitespace(); - expr = this._expr(true); - functionText += expr; - - //START: Horrible hack in case it's an IE filter - if (this.options.ieFilters && tokenStream.peek() === Tokens.EQUALS) { - do { - if (this._readWhitespace()) { - functionText += tokenStream.token().value; - } - - //might be second time in the loop - if (tokenStream.LA(0) === Tokens.COMMA) { - functionText += tokenStream.token().value; - } - - tokenStream.match(Tokens.IDENT); - functionText += tokenStream.token().value; - - tokenStream.match(Tokens.EQUALS); - functionText += tokenStream.token().value; - - //functionText += this._term(); - lt = tokenStream.peek(); - while (lt !== Tokens.COMMA && lt !== Tokens.S && lt !== Tokens.RPAREN) { - tokenStream.get(); - functionText += tokenStream.token().value; - lt = tokenStream.peek(); - } - } while (tokenStream.match([Tokens.COMMA, Tokens.S])); - } - - //END: Horrible Hack - - tokenStream.match(Tokens.RPAREN); - functionText += ')'; - this._readWhitespace(); - } - - return functionText; - }, - - _ie_function: function () { - /* (My own extension) - * ie_function - * : IE_FUNCTION S* IDENT '=' term [S* ','? IDENT '=' term]+ ')' S* - * ; - */ - - var tokenStream = this._tokenStream, - functionText = null, - lt; - - //IE function can begin like a regular function, too - if (tokenStream.match([Tokens.IE_FUNCTION, Tokens.FUNCTION])) { - functionText = tokenStream.token().value; - - do { - if (this._readWhitespace()) { - functionText += tokenStream.token().value; - } - - //might be second time in the loop - if (tokenStream.LA(0) === Tokens.COMMA) { - functionText += tokenStream.token().value; - } - - tokenStream.match(Tokens.IDENT); - functionText += tokenStream.token().value; - - tokenStream.match(Tokens.EQUALS); - functionText += tokenStream.token().value; - - //functionText += this._term(); - lt = tokenStream.peek(); - while (lt !== Tokens.COMMA && lt !== Tokens.S && lt !== Tokens.RPAREN) { - tokenStream.get(); - functionText += tokenStream.token().value; - lt = tokenStream.peek(); - } - } while (tokenStream.match([Tokens.COMMA, Tokens.S])); - - tokenStream.match(Tokens.RPAREN); - functionText += ')'; - this._readWhitespace(); - } - - return functionText; - }, - - _hexcolor: function () { - /* - * There is a constraint on the color that it must - * have either 3 or 6 hex-digits (i.e., [0-9a-fA-F]) - * after the "#"; e.g., "#000" is OK, but "#abcd" is not. - * - * hexcolor - * : HASH S* - * ; - */ - - var tokenStream = this._tokenStream, - token = null, - color; - - if (tokenStream.match(Tokens.HASH)) { - //need to do some validation here - - token = tokenStream.token(); - color = token.value; - if (!/#[a-f0-9]{3,6}/i.test(color)) { - throw new SyntaxError( - "Expected a hex color but found '" + - color + - "' at line " + - token.startLine + - ', col ' + - token.startCol + - '.', - token.startLine, - token.startCol - ); - } - this._readWhitespace(); - } - - return token; - }, - - //----------------------------------------------------------------- - // Animations methods - //----------------------------------------------------------------- - - _keyframes: function () { - /* - * keyframes: - * : KEYFRAMES_SYM S* keyframe_name S* '{' S* keyframe_rule* '}' { - * ; - */ - var tokenStream = this._tokenStream, - token, - tt, - name, - prefix = ''; - - tokenStream.mustMatch(Tokens.KEYFRAMES_SYM); - token = tokenStream.token(); - if (/^@\-([^\-]+)\-/.test(token.value)) { - prefix = RegExp.$1; - } - - this._readWhitespace(); - name = this._keyframe_name(); - - this._readWhitespace(); - tokenStream.mustMatch(Tokens.LBRACE); - - this.fire({ - type: 'startkeyframes', - name: name, - prefix: prefix, - line: token.startLine, - col: token.startCol, - }); - - this._readWhitespace(); - tt = tokenStream.peek(); - - //check for key - while (tt === Tokens.IDENT || tt === Tokens.PERCENTAGE) { - this._keyframe_rule(); - this._readWhitespace(); - tt = tokenStream.peek(); - } - - this.fire({ - type: 'endkeyframes', - name: name, - prefix: prefix, - line: token.startLine, - col: token.startCol, - }); - - this._readWhitespace(); - tokenStream.mustMatch(Tokens.RBRACE); - }, - - _keyframe_name: function () { - /* - * keyframe_name: - * : IDENT - * | STRING - * ; - */ - var tokenStream = this._tokenStream; - - tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]); - return SyntaxUnit.fromToken(tokenStream.token()); - }, - - _keyframe_rule: function () { - /* - * keyframe_rule: - * : key_list S* - * '{' S* declaration [ ';' S* declaration ]* '}' S* - * ; - */ - var keyList = this._key_list(); - - this.fire({ - type: 'startkeyframerule', - keys: keyList, - line: keyList[0].line, - col: keyList[0].col, - }); - - this._readDeclarations(true); - - this.fire({ - type: 'endkeyframerule', - keys: keyList, - line: keyList[0].line, - col: keyList[0].col, - }); - }, - - _key_list: function () { - /* - * key_list: - * : key [ S* ',' S* key]* - * ; - */ - var tokenStream = this._tokenStream, - keyList = []; - - //must be least one key - keyList.push(this._key()); - - this._readWhitespace(); - - while (tokenStream.match(Tokens.COMMA)) { - this._readWhitespace(); - keyList.push(this._key()); - this._readWhitespace(); - } - - return keyList; - }, - - _key: function () { - /* - * There is a restriction that IDENT can be only "from" or "to". - * - * key - * : PERCENTAGE - * | IDENT - * ; - */ - - var tokenStream = this._tokenStream, - token; - - if (tokenStream.match(Tokens.PERCENTAGE)) { - return SyntaxUnit.fromToken(tokenStream.token()); - } else if (tokenStream.match(Tokens.IDENT)) { - token = tokenStream.token(); - - if (/from|to/i.test(token.value)) { - return SyntaxUnit.fromToken(token); - } - - tokenStream.unget(); - } - - //if it gets here, there wasn't a valid token, so time to explode - this._unexpectedToken(tokenStream.LT(1)); - }, - - //----------------------------------------------------------------- - // Helper methods - //----------------------------------------------------------------- - - /** - * Not part of CSS grammar, but useful for skipping over - * combination of white space and HTML-style comments. - * @return {void} - * @method _skipCruft - * @private - */ - _skipCruft: function () { - while (this._tokenStream.match([Tokens.S, Tokens.CDO, Tokens.CDC])) { - //noop - } - }, - - /** - * Not part of CSS grammar, but this pattern occurs frequently - * in the official CSS grammar. Split out here to eliminate - * duplicate code. - * @param {Boolean} checkStart Indicates if the rule should check - * for the left brace at the beginning. - * @param {Boolean} readMargins Indicates if the rule should check - * for margin patterns. - * @return {void} - * @method _readDeclarations - * @private - */ - _readDeclarations: function (checkStart, readMargins) { - /* - * Reads the pattern - * S* '{' S* declaration [ ';' S* declaration ]* '}' S* - * or - * S* '{' S* [ declaration | margin ]? [ ';' S* [ declaration | margin ]? ]* '}' S* - * Note that this is how it is described in CSS3 Paged Media, but is actually incorrect. - * A semicolon is only necessary following a declaration if there's another declaration - * or margin afterwards. - */ - var tokenStream = this._tokenStream, - tt; - - this._readWhitespace(); - - if (checkStart) { - tokenStream.mustMatch(Tokens.LBRACE); - } - - this._readWhitespace(); - - try { - while (true) { - if (tokenStream.match(Tokens.SEMICOLON) || (readMargins && this._margin())) { - //noop - } else if (this._declaration()) { - if (!tokenStream.match(Tokens.SEMICOLON)) { - break; - } - } else { - break; - } - - //if ((!this._margin() && !this._declaration()) || !tokenStream.match(Tokens.SEMICOLON)){ - // break; - //} - this._readWhitespace(); - } - - tokenStream.mustMatch(Tokens.RBRACE); - this._readWhitespace(); - } catch (ex) { - if (ex instanceof SyntaxError && !this.options.strict) { - //fire error event - this.fire({ - type: 'error', - error: ex, - message: ex.message, - line: ex.line, - col: ex.col, - }); - - //see if there's another declaration - tt = tokenStream.advance([Tokens.SEMICOLON, Tokens.RBRACE]); - if (tt === Tokens.SEMICOLON) { - //if there's a semicolon, then there might be another declaration - this._readDeclarations(false, readMargins); - } else if (tt !== Tokens.RBRACE) { - //if there's a right brace, the rule is finished so don't do anything - //otherwise, rethrow the error because it wasn't handled properly - throw ex; - } - } else { - //not a syntax error, rethrow it - throw ex; - } - } - }, - - /** - * In some cases, you can end up with two white space tokens in a - * row. Instead of making a change in every function that looks for - * white space, this function is used to match as much white space - * as necessary. - * @method _readWhitespace - * @return {String} The white space if found, empty string if not. - * @private - */ - _readWhitespace: function () { - var tokenStream = this._tokenStream, - ws = ''; - - while (tokenStream.match(Tokens.S)) { - ws += tokenStream.token().value; - } - - return ws; - }, - - /** - * Throws an error when an unexpected token is found. - * @param {Object} token The token that was found. - * @method _unexpectedToken - * @return {void} - * @private - */ - _unexpectedToken: function (token) { - throw new SyntaxError( - "Unexpected token '" + - token.value + - "' at line " + - token.startLine + - ', col ' + - token.startCol + - '.', - token.startLine, - token.startCol - ); - }, - - /** - * Helper method used for parsing subparts of a style sheet. - * @return {void} - * @method _verifyEnd - * @private - */ - _verifyEnd: function () { - if (this._tokenStream.LA(1) !== Tokens.EOF) { - this._unexpectedToken(this._tokenStream.LT(1)); - } - }, - - //----------------------------------------------------------------- - // Validation methods - //----------------------------------------------------------------- - _validateProperty: function (property, value) { - Validation.validate(property, value); - }, - - //----------------------------------------------------------------- - // Parsing methods - //----------------------------------------------------------------- - - parse: function (input) { - this._tokenStream = new TokenStream(input, Tokens); - this._stylesheet(); - }, - - parseStyleSheet: function (input) { - //just passthrough - return this.parse(input); - }, - - parseMediaQuery: function (input) { - this._tokenStream = new TokenStream(input, Tokens); - var result = this._media_query(); - - //if there's anything more, then it's an invalid selector - this._verifyEnd(); - - //otherwise return result - return result; - }, - - /** - * Parses a property value (everything after the semicolon). - * @return {parserlib.css.PropertyValue} The property value. - * @throws parserlib.util.SyntaxError If an unexpected token is found. - * @method parserPropertyValue - */ - parsePropertyValue: function (input) { - this._tokenStream = new TokenStream(input, Tokens); - this._readWhitespace(); - - var result = this._expr(); - - //okay to have a trailing white space - this._readWhitespace(); - - //if there's anything more, then it's an invalid selector - this._verifyEnd(); - - //otherwise return result - return result; - }, - - /** - * Parses a complete CSS rule, including selectors and - * properties. - * @param {String} input The text to parser. - * @return {Boolean} True if the parse completed successfully, false if not. - * @method parseRule - */ - parseRule: function (input) { - this._tokenStream = new TokenStream(input, Tokens); - - //skip any leading white space - this._readWhitespace(); - - var result = this._ruleset(); - - //skip any trailing white space - this._readWhitespace(); - - //if there's anything more, then it's an invalid selector - this._verifyEnd(); - - //otherwise return result - return result; - }, - - /** - * Parses a single CSS selector (no comma) - * @param {String} input The text to parse as a CSS selector. - * @return {Selector} An object representing the selector. - * @throws parserlib.util.SyntaxError If an unexpected token is found. - * @method parseSelector - */ - parseSelector: function (input) { - this._tokenStream = new TokenStream(input, Tokens); - - //skip any leading white space - this._readWhitespace(); - - var result = this._selector(); - - //skip any trailing white space - this._readWhitespace(); - - //if there's anything more, then it's an invalid selector - this._verifyEnd(); - - //otherwise return result - return result; - }, - - /** - * Parses an HTML style attribute: a set of CSS declarations - * separated by semicolons. - * @param {String} input The text to parse as a style attribute - * @return {void} - * @method parseStyleAttribute - */ - parseStyleAttribute: function (input) { - input += '}'; // for error recovery in _readDeclarations() - this._tokenStream = new TokenStream(input, Tokens); - this._readDeclarations(); - }, - }; - - //copy over onto prototype - for (prop in additions) { - if (Object.prototype.hasOwnProperty.call(additions, prop)) { - proto[prop] = additions[prop]; - } - } - - return proto; - })(); - - /* -nth - : S* [ ['-'|'+']? INTEGER? {N} [ S* ['-'|'+'] S* INTEGER ]? | - ['-'|'+']? INTEGER | {O}{D}{D} | {E}{V}{E}{N} ] S* - ; -*/ - var Properties = { - __proto__: null, - - //A - 'align-items': 'flex-start | flex-end | center | baseline | stretch', - 'align-content': 'flex-start | flex-end | center | space-between | space-around | stretch', - 'align-self': 'auto | flex-start | flex-end | center | baseline | stretch', - '-webkit-align-items': 'flex-start | flex-end | center | baseline | stretch', - '-webkit-align-content': - 'flex-start | flex-end | center | space-between | space-around | stretch', - '-webkit-align-self': 'auto | flex-start | flex-end | center | baseline | stretch', - 'alignment-adjust': - 'auto | baseline | before-edge | text-before-edge | middle | central | after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical | <percentage> | <length>', - 'alignment-baseline': - 'baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical', - animation: 1, - 'animation-delay': { multi: '<time>', comma: true }, - 'animation-direction': { multi: 'normal | alternate', comma: true }, - 'animation-duration': { multi: '<time>', comma: true }, - 'animation-fill-mode': { multi: 'none | forwards | backwards | both', comma: true }, - 'animation-iteration-count': { multi: '<number> | infinite', comma: true }, - 'animation-name': { multi: 'none | <ident>', comma: true }, - 'animation-play-state': { multi: 'running | paused', comma: true }, - 'animation-timing-function': 1, - - //vendor prefixed - '-moz-animation-delay': { multi: '<time>', comma: true }, - '-moz-animation-direction': { multi: 'normal | alternate', comma: true }, - '-moz-animation-duration': { multi: '<time>', comma: true }, - '-moz-animation-iteration-count': { multi: '<number> | infinite', comma: true }, - '-moz-animation-name': { multi: 'none | <ident>', comma: true }, - '-moz-animation-play-state': { multi: 'running | paused', comma: true }, - - '-ms-animation-delay': { multi: '<time>', comma: true }, - '-ms-animation-direction': { multi: 'normal | alternate', comma: true }, - '-ms-animation-duration': { multi: '<time>', comma: true }, - '-ms-animation-iteration-count': { multi: '<number> | infinite', comma: true }, - '-ms-animation-name': { multi: 'none | <ident>', comma: true }, - '-ms-animation-play-state': { multi: 'running | paused', comma: true }, - - '-webkit-animation-delay': { multi: '<time>', comma: true }, - '-webkit-animation-direction': { multi: 'normal | alternate', comma: true }, - '-webkit-animation-duration': { multi: '<time>', comma: true }, - '-webkit-animation-fill-mode': { multi: 'none | forwards | backwards | both', comma: true }, - '-webkit-animation-iteration-count': { multi: '<number> | infinite', comma: true }, - '-webkit-animation-name': { multi: 'none | <ident>', comma: true }, - '-webkit-animation-play-state': { multi: 'running | paused', comma: true }, - - '-o-animation-delay': { multi: '<time>', comma: true }, - '-o-animation-direction': { multi: 'normal | alternate', comma: true }, - '-o-animation-duration': { multi: '<time>', comma: true }, - '-o-animation-iteration-count': { multi: '<number> | infinite', comma: true }, - '-o-animation-name': { multi: 'none | <ident>', comma: true }, - '-o-animation-play-state': { multi: 'running | paused', comma: true }, - - appearance: - 'icon | window | desktop | workspace | document | tooltip | dialog | button | push-button | hyperlink | radio | radio-button | checkbox | menu-item | tab | menu | menubar | pull-down-menu | pop-up-menu | list-menu | radio-group | checkbox-group | outline-tree | range | field | combo-box | signature | password | normal | none | inherit', - 'aspect-ratio': 1, - azimuth: function (expression) { - var simple = '<angle> | leftwards | rightwards | inherit', - direction = - 'left-side | far-left | left | center-left | center | center-right | right | far-right | right-side', - behind = false, - valid = false, - part; - - if (!ValidationTypes.isAny(expression, simple)) { - if (ValidationTypes.isAny(expression, 'behind')) { - behind = true; - valid = true; - } - - if (ValidationTypes.isAny(expression, direction)) { - valid = true; - if (!behind) { - ValidationTypes.isAny(expression, 'behind'); - } - } - } - - if (expression.hasNext()) { - part = expression.next(); - if (valid) { - throw new ValidationError( - "Expected end of value but found '" + part + "'.", - part.line, - part.col - ); - } else { - throw new ValidationError( - "Expected (<'azimuth'>) but found '" + part + "'.", - part.line, - part.col - ); - } - } - }, - - //B - 'backface-visibility': 'visible | hidden', - background: 1, - 'background-attachment': { multi: '<attachment>', comma: true }, - 'background-clip': { multi: '<box>', comma: true }, - 'background-color': '<color> | inherit', - 'background-image': { multi: '<bg-image>', comma: true }, - 'background-origin': { multi: '<box>', comma: true }, - 'background-position': { multi: '<bg-position>', comma: true }, - 'background-repeat': { multi: '<repeat-style>' }, - 'background-size': { multi: '<bg-size>', comma: true }, - 'baseline-shift': 'baseline | sub | super | <percentage> | <length>', - behavior: 1, - binding: 1, - bleed: '<length>', - 'bookmark-label': '<content> | <attr> | <string>', - 'bookmark-level': 'none | <integer>', - 'bookmark-state': 'open | closed', - 'bookmark-target': 'none | <uri> | <attr>', - border: '<border-width> || <border-style> || <color>', - 'border-bottom': '<border-width> || <border-style> || <color>', - 'border-bottom-color': '<color> | inherit', - 'border-bottom-left-radius': '<x-one-radius>', - 'border-bottom-right-radius': '<x-one-radius>', - 'border-bottom-style': '<border-style>', - 'border-bottom-width': '<border-width>', - 'border-collapse': 'collapse | separate | inherit', - 'border-color': { multi: '<color> | inherit', max: 4 }, - 'border-image': 1, - 'border-image-outset': { multi: '<length> | <number>', max: 4 }, - 'border-image-repeat': { multi: 'stretch | repeat | round', max: 2 }, - 'border-image-slice': function (expression) { - var valid = false, - numeric = '<number> | <percentage>', - fill = false, - count = 0, - max = 4, - part; - - if (ValidationTypes.isAny(expression, 'fill')) { - fill = true; - valid = true; - } - - while (expression.hasNext() && count < max) { - valid = ValidationTypes.isAny(expression, numeric); - if (!valid) { - break; - } - count++; - } - - if (!fill) { - ValidationTypes.isAny(expression, 'fill'); - } else { - valid = true; - } - - if (expression.hasNext()) { - part = expression.next(); - if (valid) { - throw new ValidationError( - "Expected end of value but found '" + part + "'.", - part.line, - part.col - ); - } else { - throw new ValidationError( - "Expected ([<number> | <percentage>]{1,4} && fill?) but found '" + part + "'.", - part.line, - part.col - ); - } - } - }, - 'border-image-source': '<image> | none', - 'border-image-width': { multi: '<length> | <percentage> | <number> | auto', max: 4 }, - 'border-left': '<border-width> || <border-style> || <color>', - 'border-left-color': '<color> | inherit', - 'border-left-style': '<border-style>', - 'border-left-width': '<border-width>', - 'border-radius': function (expression) { - var valid = false, - simple = '<length> | <percentage> | inherit', - slash = false, - count = 0, - max = 8, - part; - - while (expression.hasNext() && count < max) { - valid = ValidationTypes.isAny(expression, simple); - if (!valid) { - if (String(expression.peek()) === '/' && count > 0 && !slash) { - slash = true; - max = count + 5; - expression.next(); - } else { - break; - } - } - count++; - } - - if (expression.hasNext()) { - part = expression.next(); - if (valid) { - throw new ValidationError( - "Expected end of value but found '" + part + "'.", - part.line, - part.col - ); - } else { - throw new ValidationError( - "Expected (<'border-radius'>) but found '" + part + "'.", - part.line, - part.col - ); - } - } - }, - 'border-right': '<border-width> || <border-style> || <color>', - 'border-right-color': '<color> | inherit', - 'border-right-style': '<border-style>', - 'border-right-width': '<border-width>', - 'border-spacing': { multi: '<length> | inherit', max: 2 }, - 'border-style': { multi: '<border-style>', max: 4 }, - 'border-top': '<border-width> || <border-style> || <color>', - 'border-top-color': '<color> | inherit', - 'border-top-left-radius': '<x-one-radius>', - 'border-top-right-radius': '<x-one-radius>', - 'border-top-style': '<border-style>', - 'border-top-width': '<border-width>', - 'border-width': { multi: '<border-width>', max: 4 }, - bottom: '<margin-width> | inherit', - '-moz-box-align': 'start | end | center | baseline | stretch', - '-moz-box-decoration-break': 'slice |clone', - '-moz-box-direction': 'normal | reverse | inherit', - '-moz-box-flex': '<number>', - '-moz-box-flex-group': '<integer>', - '-moz-box-lines': 'single | multiple', - '-moz-box-ordinal-group': '<integer>', - '-moz-box-orient': 'horizontal | vertical | inline-axis | block-axis | inherit', - '-moz-box-pack': 'start | end | center | justify', - '-o-box-decoration-break': 'slice | clone', - '-webkit-box-align': 'start | end | center | baseline | stretch', - '-webkit-box-decoration-break': 'slice |clone', - '-webkit-box-direction': 'normal | reverse | inherit', - '-webkit-box-flex': '<number>', - '-webkit-box-flex-group': '<integer>', - '-webkit-box-lines': 'single | multiple', - '-webkit-box-ordinal-group': '<integer>', - '-webkit-box-orient': 'horizontal | vertical | inline-axis | block-axis | inherit', - '-webkit-box-pack': 'start | end | center | justify', - 'box-decoration-break': 'slice | clone', - 'box-shadow': function (expression) { - var part; - - if (!ValidationTypes.isAny(expression, 'none')) { - Validation.multiProperty('<shadow>', expression, true, Infinity); - } else { - if (expression.hasNext()) { - part = expression.next(); - throw new ValidationError( - "Expected end of value but found '" + part + "'.", - part.line, - part.col - ); - } - } - }, - 'box-sizing': 'content-box | border-box | inherit', - 'break-after': - 'auto | always | avoid | left | right | page | column | avoid-page | avoid-column', - 'break-before': - 'auto | always | avoid | left | right | page | column | avoid-page | avoid-column', - 'break-inside': 'auto | avoid | avoid-page | avoid-column', - - //C - 'caption-side': 'top | bottom | inherit', - clear: 'none | right | left | both | inherit', - clip: 1, - color: '<color> | inherit', - 'color-profile': 1, - 'column-count': '<integer> | auto', //http://www.w3.org/TR/css3-multicol/ - 'column-fill': 'auto | balance', - 'column-gap': '<length> | normal', - 'column-rule': '<border-width> || <border-style> || <color>', - 'column-rule-color': '<color>', - 'column-rule-style': '<border-style>', - 'column-rule-width': '<border-width>', - 'column-span': 'none | all', - 'column-width': '<length> | auto', - columns: 1, - content: 1, - 'counter-increment': 1, - 'counter-reset': 1, - crop: '<shape> | auto', - cue: 'cue-after | cue-before | inherit', - 'cue-after': 1, - 'cue-before': 1, - cursor: 1, - - //D - direction: 'ltr | rtl | inherit', - display: - 'inline | block | list-item | inline-block | table | inline-table | table-row-group | table-header-group | table-footer-group | table-row | table-column-group | table-column | table-cell | table-caption | grid | inline-grid | run-in | ruby | ruby-base | ruby-text | ruby-base-container | ruby-text-container | contents | none | inherit | -moz-box | -moz-inline-block | -moz-inline-box | -moz-inline-grid | -moz-inline-stack | -moz-inline-table | -moz-grid | -moz-grid-group | -moz-grid-line | -moz-groupbox | -moz-deck | -moz-popup | -moz-stack | -moz-marker | -webkit-box | -webkit-inline-box | -ms-flexbox | -ms-inline-flexbox | flex | -webkit-flex | inline-flex | -webkit-inline-flex', - 'dominant-baseline': 1, - 'drop-initial-after-adjust': - 'central | middle | after-edge | text-after-edge | ideographic | alphabetic | mathematical | <percentage> | <length>', - 'drop-initial-after-align': - 'baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical', - 'drop-initial-before-adjust': - 'before-edge | text-before-edge | central | middle | hanging | mathematical | <percentage> | <length>', - 'drop-initial-before-align': - 'caps-height | baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical', - 'drop-initial-size': 'auto | line | <length> | <percentage>', - 'drop-initial-value': 'initial | <integer>', - - //E - elevation: '<angle> | below | level | above | higher | lower | inherit', - 'empty-cells': 'show | hide | inherit', - - //F - filter: 1, - fit: 'fill | hidden | meet | slice', - 'fit-position': 1, - flex: '<flex>', - 'flex-basis': '<width>', - 'flex-direction': 'row | row-reverse | column | column-reverse', - 'flex-flow': '<flex-direction> || <flex-wrap>', - 'flex-grow': '<number>', - 'flex-shrink': '<number>', - 'flex-wrap': 'nowrap | wrap | wrap-reverse', - '-webkit-flex': '<flex>', - '-webkit-flex-basis': '<width>', - '-webkit-flex-direction': 'row | row-reverse | column | column-reverse', - '-webkit-flex-flow': '<flex-direction> || <flex-wrap>', - '-webkit-flex-grow': '<number>', - '-webkit-flex-shrink': '<number>', - '-webkit-flex-wrap': 'nowrap | wrap | wrap-reverse', - '-ms-flex': '<flex>', - '-ms-flex-align': 'start | end | center | stretch | baseline', - '-ms-flex-direction': 'row | row-reverse | column | column-reverse | inherit', - '-ms-flex-order': '<number>', - '-ms-flex-pack': 'start | end | center | justify', - '-ms-flex-wrap': 'nowrap | wrap | wrap-reverse', - float: 'left | right | none | inherit', - 'float-offset': 1, - font: 1, - 'font-family': 1, - 'font-feature-settings': '<feature-tag-value> | normal | inherit', - 'font-kerning': 'auto | normal | none | initial | inherit | unset', - 'font-size': '<absolute-size> | <relative-size> | <length> | <percentage> | inherit', - 'font-size-adjust': '<number> | none | inherit', - 'font-stretch': - 'normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded | inherit', - 'font-style': 'normal | italic | oblique | inherit', - 'font-variant': 'normal | small-caps | inherit', - 'font-variant-caps': - 'normal | small-caps | all-small-caps | petite-caps | all-petite-caps | unicase | titling-caps', - 'font-variant-position': 'normal | sub | super | inherit | initial | unset', - 'font-weight': - 'normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit', - - //G - grid: 1, - 'grid-area': 1, - 'grid-auto-columns': 1, - 'grid-auto-flow': 1, - 'grid-auto-position': 1, - 'grid-auto-rows': 1, - 'grid-cell-stacking': 'columns | rows | layer', - 'grid-column': 1, - 'grid-columns': 1, - 'grid-column-align': 'start | end | center | stretch', - 'grid-column-sizing': 1, - 'grid-column-start': 1, - 'grid-column-end': 1, - 'grid-column-span': '<integer>', - 'grid-flow': 'none | rows | columns', - 'grid-layer': '<integer>', - 'grid-row': 1, - 'grid-rows': 1, - 'grid-row-align': 'start | end | center | stretch', - 'grid-row-start': 1, - 'grid-row-end': 1, - 'grid-row-span': '<integer>', - 'grid-row-sizing': 1, - 'grid-template': 1, - 'grid-template-areas': 1, - 'grid-template-columns': 1, - 'grid-template-rows': 1, - - //H - 'hanging-punctuation': 1, - height: '<margin-width> | <content-sizing> | inherit', - 'hyphenate-after': '<integer> | auto', - 'hyphenate-before': '<integer> | auto', - 'hyphenate-character': '<string> | auto', - 'hyphenate-lines': 'no-limit | <integer>', - 'hyphenate-resource': 1, - hyphens: 'none | manual | auto', - - //I - icon: 1, - 'image-orientation': 'angle | auto', - 'image-rendering': 1, - 'image-resolution': 1, - 'ime-mode': 'auto | normal | active | inactive | disabled | inherit', - 'inline-box-align': 'initial | last | <integer>', - - //J - 'justify-content': 'flex-start | flex-end | center | space-between | space-around', - '-webkit-justify-content': 'flex-start | flex-end | center | space-between | space-around', - - //L - left: '<margin-width> | inherit', - 'letter-spacing': '<length> | normal | inherit', - 'line-height': '<number> | <length> | <percentage> | normal | inherit', - 'line-break': 'auto | loose | normal | strict', - 'line-stacking': 1, - 'line-stacking-ruby': 'exclude-ruby | include-ruby', - 'line-stacking-shift': 'consider-shifts | disregard-shifts', - 'line-stacking-strategy': 'inline-line-height | block-line-height | max-height | grid-height', - 'list-style': 1, - 'list-style-image': '<uri> | none | inherit', - 'list-style-position': 'inside | outside | inherit', - 'list-style-type': - 'disc | circle | square | decimal | decimal-leading-zero | lower-roman | upper-roman | lower-greek | lower-latin | upper-latin | armenian | georgian | lower-alpha | upper-alpha | none | inherit', - - //M - margin: { multi: '<margin-width> | inherit', max: 4 }, - 'margin-bottom': '<margin-width> | inherit', - 'margin-left': '<margin-width> | inherit', - 'margin-right': '<margin-width> | inherit', - 'margin-top': '<margin-width> | inherit', - mark: 1, - 'mark-after': 1, - 'mark-before': 1, - marks: 1, - 'marquee-direction': 1, - 'marquee-play-count': 1, - 'marquee-speed': 1, - 'marquee-style': 1, - 'max-height': '<length> | <percentage> | <content-sizing> | none | inherit', - 'max-width': '<length> | <percentage> | <content-sizing> | none | inherit', - 'min-height': - '<length> | <percentage> | <content-sizing> | contain-floats | -moz-contain-floats | -webkit-contain-floats | inherit', - 'min-width': - '<length> | <percentage> | <content-sizing> | contain-floats | -moz-contain-floats | -webkit-contain-floats | inherit', - 'move-to': 1, - - //N - 'nav-down': 1, - 'nav-index': 1, - 'nav-left': 1, - 'nav-right': 1, - 'nav-up': 1, - - //O - 'object-fit': 'fill | contain | cover | none | scale-down', - 'object-position': '<bg-position>', - opacity: '<number> | inherit', - order: '<integer>', - '-webkit-order': '<integer>', - orphans: '<integer> | inherit', - outline: 1, - 'outline-color': '<color> | invert | inherit', - 'outline-offset': 1, - 'outline-style': '<border-style> | inherit', - 'outline-width': '<border-width> | inherit', - overflow: 'visible | hidden | scroll | auto | inherit', - 'overflow-style': 1, - 'overflow-wrap': 'normal | break-word', - 'overflow-x': 1, - 'overflow-y': 1, - - //P - padding: { multi: '<padding-width> | inherit', max: 4 }, - 'padding-bottom': '<padding-width> | inherit', - 'padding-left': '<padding-width> | inherit', - 'padding-right': '<padding-width> | inherit', - 'padding-top': '<padding-width> | inherit', - page: 1, - 'page-break-after': 'auto | always | avoid | left | right | inherit', - 'page-break-before': 'auto | always | avoid | left | right | inherit', - 'page-break-inside': 'auto | avoid | inherit', - 'page-policy': 1, - pause: 1, - 'pause-after': 1, - 'pause-before': 1, - perspective: 1, - 'perspective-origin': 1, - phonemes: 1, - pitch: 1, - 'pitch-range': 1, - 'play-during': 1, - 'pointer-events': - 'auto | none | visiblePainted | visibleFill | visibleStroke | visible | painted | fill | stroke | all | inherit', - position: 'static | relative | absolute | fixed | inherit', - 'presentation-level': 1, - 'punctuation-trim': 1, - - //Q - quotes: 1, - - //R - 'rendering-intent': 1, - resize: 1, - rest: 1, - 'rest-after': 1, - 'rest-before': 1, - richness: 1, - right: '<margin-width> | inherit', - rotation: 1, - 'rotation-point': 1, - 'ruby-align': 1, - 'ruby-overhang': 1, - 'ruby-position': 1, - 'ruby-span': 1, - - //S - size: 1, - speak: 'normal | none | spell-out | inherit', - 'speak-header': 'once | always | inherit', - 'speak-numeral': 'digits | continuous | inherit', - 'speak-punctuation': 'code | none | inherit', - 'speech-rate': 1, - src: 1, - stress: 1, - 'string-set': 1, - - 'table-layout': 'auto | fixed | inherit', - 'tab-size': '<integer> | <length>', - target: 1, - 'target-name': 1, - 'target-new': 1, - 'target-position': 1, - 'text-align': 'left | right | center | justify | match-parent | start | end | inherit', - 'text-align-last': 1, - 'text-decoration': 1, - 'text-emphasis': 1, - 'text-height': 1, - 'text-indent': '<length> | <percentage> | inherit', - 'text-justify': - 'auto | none | inter-word | inter-ideograph | inter-cluster | distribute | kashida', - 'text-outline': 1, - 'text-overflow': 1, - 'text-rendering': 'auto | optimizeSpeed | optimizeLegibility | geometricPrecision | inherit', - 'text-shadow': 1, - 'text-transform': 'capitalize | uppercase | lowercase | none | inherit', - 'text-wrap': 'normal | none | avoid', - top: '<margin-width> | inherit', - '-ms-touch-action': - 'auto | none | pan-x | pan-y | pan-left | pan-right | pan-up | pan-down | manipulation', - 'touch-action': - 'auto | none | pan-x | pan-y | pan-left | pan-right | pan-up | pan-down | manipulation', - transform: 1, - 'transform-origin': 1, - 'transform-style': 1, - transition: 1, - 'transition-delay': 1, - 'transition-duration': 1, - 'transition-property': 1, - 'transition-timing-function': 1, - - //U - 'unicode-bidi': - 'normal | embed | isolate | bidi-override | isolate-override | plaintext | inherit', - 'user-modify': 'read-only | read-write | write-only | inherit', - 'user-select': 'none | text | toggle | element | elements | all | inherit', - - //V - 'vertical-align': - 'auto | use-script | baseline | sub | super | top | text-top | central | middle | bottom | text-bottom | <percentage> | <length> | inherit', - visibility: 'visible | hidden | collapse | inherit', - 'voice-balance': 1, - 'voice-duration': 1, - 'voice-family': 1, - 'voice-pitch': 1, - 'voice-pitch-range': 1, - 'voice-rate': 1, - 'voice-stress': 1, - 'voice-volume': 1, - volume: 1, - - //W - 'white-space': - 'normal | pre | nowrap | pre-wrap | pre-line | inherit | -pre-wrap | -o-pre-wrap | -moz-pre-wrap | -hp-pre-wrap', //http://perishablepress.com/wrapping-content/ - 'white-space-collapse': 1, - widows: '<integer> | inherit', - width: '<length> | <percentage> | <content-sizing> | auto | inherit', - 'will-change': { multi: '<ident>', comma: true }, - 'word-break': 'normal | keep-all | break-all', - 'word-spacing': '<length> | normal | inherit', - 'word-wrap': 'normal | break-word', - 'writing-mode': - 'horizontal-tb | vertical-rl | vertical-lr | lr-tb | rl-tb | tb-rl | bt-rl | tb-lr | bt-lr | lr-bt | rl-bt | lr | rl | tb | inherit', - - //Z - 'z-index': '<integer> | auto | inherit', - zoom: '<number> | <percentage> | normal', - }; - /** - * Represents a selector combinator (whitespace, +, >). - * @namespace parserlib.css - * @class PropertyName - * @extends parserlib.util.SyntaxUnit - * @constructor - * @param {String} text The text representation of the unit. - * @param {String} hack The type of IE hack applied ("*", "_", or null). - * @param {int} line The line of text on which the unit resides. - * @param {int} col The column of text on which the unit resides. - */ - function PropertyName(text, hack, line, col) { - SyntaxUnit.call(this, text, line, col, Parser.PROPERTY_NAME_TYPE); - - /** - * The type of IE hack applied ("*", "_", or null). - * @type String - * @property hack - */ - this.hack = hack; - } - - PropertyName.prototype = new SyntaxUnit(); - PropertyName.prototype.constructor = PropertyName; - PropertyName.prototype.toString = function () { - return (this.hack ? this.hack : '') + this.text; - }; - /** - * Represents a single part of a CSS property value, meaning that it represents - * just everything single part between ":" and ";". If there are multiple values - * separated by commas, this type represents just one of the values. - * @param {String[]} parts An array of value parts making up this value. - * @param {int} line The line of text on which the unit resides. - * @param {int} col The column of text on which the unit resides. - * @namespace parserlib.css - * @class PropertyValue - * @extends parserlib.util.SyntaxUnit - * @constructor - */ - function PropertyValue(parts, line, col) { - SyntaxUnit.call(this, parts.join(' '), line, col, Parser.PROPERTY_VALUE_TYPE); - - /** - * The parts that make up the selector. - * @type Array - * @property parts - */ - this.parts = parts; - } - - PropertyValue.prototype = new SyntaxUnit(); - PropertyValue.prototype.constructor = PropertyValue; - - /** - * A utility class that allows for easy iteration over the various parts of a - * property value. - * @param {parserlib.css.PropertyValue} value The property value to iterate over. - * @namespace parserlib.css - * @class PropertyValueIterator - * @constructor - */ - function PropertyValueIterator(value) { - /** - * Iterator value - * @type int - * @property _i - * @private - */ - this._i = 0; - - /** - * The parts that make up the value. - * @type Array - * @property _parts - * @private - */ - this._parts = value.parts; - - /** - * Keeps track of bookmarks along the way. - * @type Array - * @property _marks - * @private - */ - this._marks = []; - - /** - * Holds the original property value. - * @type parserlib.css.PropertyValue - * @property value - */ - this.value = value; - } - - /** - * Returns the total number of parts in the value. - * @return {int} The total number of parts in the value. - * @method count - */ - PropertyValueIterator.prototype.count = function () { - return this._parts.length; - }; - - /** - * Indicates if the iterator is positioned at the first item. - * @return {Boolean} True if positioned at first item, false if not. - * @method isFirst - */ - PropertyValueIterator.prototype.isFirst = function () { - return this._i === 0; - }; - - /** - * Indicates if there are more parts of the property value. - * @return {Boolean} True if there are more parts, false if not. - * @method hasNext - */ - PropertyValueIterator.prototype.hasNext = function () { - return this._i < this._parts.length; - }; - - /** - * Marks the current spot in the iteration so it can be restored to - * later on. - * @return {void} - * @method mark - */ - PropertyValueIterator.prototype.mark = function () { - this._marks.push(this._i); - }; - - /** - * Returns the next part of the property value or null if there is no next - * part. Does not move the internal counter forward. - * @return {parserlib.css.PropertyValuePart} The next part of the property value or null if there is no next - * part. - * @method peek - */ - PropertyValueIterator.prototype.peek = function (count) { - return this.hasNext() ? this._parts[this._i + (count || 0)] : null; - }; - - /** - * Returns the next part of the property value or null if there is no next - * part. - * @return {parserlib.css.PropertyValuePart} The next part of the property value or null if there is no next - * part. - * @method next - */ - PropertyValueIterator.prototype.next = function () { - return this.hasNext() ? this._parts[this._i++] : null; - }; - - /** - * Returns the previous part of the property value or null if there is no - * previous part. - * @return {parserlib.css.PropertyValuePart} The previous part of the - * property value or null if there is no previous part. - * @method previous - */ - PropertyValueIterator.prototype.previous = function () { - return this._i > 0 ? this._parts[--this._i] : null; - }; - - /** - * Restores the last saved bookmark. - * @return {void} - * @method restore - */ - PropertyValueIterator.prototype.restore = function () { - if (this._marks.length) { - this._i = this._marks.pop(); - } - }; - - /** - * Represents a single part of a CSS property value, meaning that it represents - * just one part of the data between ":" and ";". - * @param {String} text The text representation of the unit. - * @param {int} line The line of text on which the unit resides. - * @param {int} col The column of text on which the unit resides. - * @namespace parserlib.css - * @class PropertyValuePart - * @extends parserlib.util.SyntaxUnit - * @constructor - */ - function PropertyValuePart(text, line, col) { - SyntaxUnit.call(this, text, line, col, Parser.PROPERTY_VALUE_PART_TYPE); - - /** - * Indicates the type of value unit. - * @type String - * @property type - */ - this.type = 'unknown'; - - //figure out what type of data it is - - var temp; - - //it is a measurement? - if (/^([+\-]?[\d\.]+)([a-z]+)$/i.test(text)) { - //dimension - this.type = 'dimension'; - this.value = +RegExp.$1; - this.units = RegExp.$2; - - //try to narrow down - switch (this.units.toLowerCase()) { - case 'em': - case 'rem': - case 'ex': - case 'px': - case 'cm': - case 'mm': - case 'in': - case 'pt': - case 'pc': - case 'ch': - case 'vh': - case 'vw': - case 'vmax': - case 'vmin': - this.type = 'length'; - break; - - case 'fr': - this.type = 'grid'; - break; - - case 'deg': - case 'rad': - case 'grad': - this.type = 'angle'; - break; - - case 'ms': - case 's': - this.type = 'time'; - break; - - case 'hz': - case 'khz': - this.type = 'frequency'; - break; - - case 'dpi': - case 'dpcm': - this.type = 'resolution'; - break; - - //default - } - } else if (/^([+\-]?[\d\.]+)%$/i.test(text)) { - //percentage - this.type = 'percentage'; - this.value = +RegExp.$1; - } else if (/^([+\-]?\d+)$/i.test(text)) { - //integer - this.type = 'integer'; - this.value = +RegExp.$1; - } else if (/^([+\-]?[\d\.]+)$/i.test(text)) { - //number - this.type = 'number'; - this.value = +RegExp.$1; - } else if (/^#([a-f0-9]{3,6})/i.test(text)) { - //hexcolor - this.type = 'color'; - temp = RegExp.$1; - if (temp.length === 3) { - this.red = parseInt(temp.charAt(0) + temp.charAt(0), 16); - this.green = parseInt(temp.charAt(1) + temp.charAt(1), 16); - this.blue = parseInt(temp.charAt(2) + temp.charAt(2), 16); - } else { - this.red = parseInt(temp.substring(0, 2), 16); - this.green = parseInt(temp.substring(2, 4), 16); - this.blue = parseInt(temp.substring(4, 6), 16); - } - } else if (/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/i.test(text)) { - //rgb() color with absolute numbers - this.type = 'color'; - this.red = +RegExp.$1; - this.green = +RegExp.$2; - this.blue = +RegExp.$3; - } else if (/^rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i.test(text)) { - //rgb() color with percentages - this.type = 'color'; - this.red = (+RegExp.$1 * 255) / 100; - this.green = (+RegExp.$2 * 255) / 100; - this.blue = (+RegExp.$3 * 255) / 100; - } else if (/^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d\.]+)\s*\)/i.test(text)) { - //rgba() color with absolute numbers - this.type = 'color'; - this.red = +RegExp.$1; - this.green = +RegExp.$2; - this.blue = +RegExp.$3; - this.alpha = +RegExp.$4; - } else if (/^rgba\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i.test(text)) { - //rgba() color with percentages - this.type = 'color'; - this.red = (+RegExp.$1 * 255) / 100; - this.green = (+RegExp.$2 * 255) / 100; - this.blue = (+RegExp.$3 * 255) / 100; - this.alpha = +RegExp.$4; - } else if (/^hsl\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i.test(text)) { - //hsl() - this.type = 'color'; - this.hue = +RegExp.$1; - this.saturation = +RegExp.$2 / 100; - this.lightness = +RegExp.$3 / 100; - } else if (/^hsla\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i.test(text)) { - //hsla() color with percentages - this.type = 'color'; - this.hue = +RegExp.$1; - this.saturation = +RegExp.$2 / 100; - this.lightness = +RegExp.$3 / 100; - this.alpha = +RegExp.$4; - } else if (/^url\(["']?([^\)"']+)["']?\)/i.test(text)) { - //URI - this.type = 'uri'; - this.uri = RegExp.$1; - } else if (/^([^\(]+)\(/i.test(text)) { - this.type = 'function'; - this.name = RegExp.$1; - this.value = text; - } else if ( - /^"([^\n\r\f\\"]|\\\r\n|\\[^\r0-9a-f]|\\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?)*"/i.test(text) - ) { - //double-quoted string - this.type = 'string'; - this.value = PropertyValuePart.parseString(text); - } else if ( - /^'([^\n\r\f\\']|\\\r\n|\\[^\r0-9a-f]|\\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?)*'/i.test(text) - ) { - //single-quoted string - this.type = 'string'; - this.value = PropertyValuePart.parseString(text); - } else if (Colors[text.toLowerCase()]) { - //named color - this.type = 'color'; - temp = Colors[text.toLowerCase()].substring(1); - this.red = parseInt(temp.substring(0, 2), 16); - this.green = parseInt(temp.substring(2, 4), 16); - this.blue = parseInt(temp.substring(4, 6), 16); - } else if (/^[\,\/]$/.test(text)) { - this.type = 'operator'; - this.value = text; - } else if (/^[a-z\-_\u0080-\uFFFF][a-z0-9\-_\u0080-\uFFFF]*$/i.test(text)) { - this.type = 'identifier'; - this.value = text; - } - } - - PropertyValuePart.prototype = new SyntaxUnit(); - PropertyValuePart.prototype.constructor = PropertyValuePart; - - /** - * Helper method to parse a CSS string. - */ - PropertyValuePart.parseString = function (str) { - str = str.slice(1, -1); // Strip surrounding single/double quotes - var replacer = function (match, esc) { - if (/^(\n|\r\n|\r|\f)$/.test(esc)) { - return ''; - } - var m = /^[0-9a-f]{1,6}/i.exec(esc); - if (m) { - var codePoint = parseInt(m[0], 16); - if (String.fromCodePoint) { - return String.fromCodePoint(codePoint); - } else { - // XXX No support for surrogates on old JavaScript engines. - return String.fromCharCode(codePoint); - } - } - return esc; - }; - return str.replace(/\\(\r\n|[^\r0-9a-f]|[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?)/gi, replacer); - }; - - /** - * Helper method to serialize a CSS string. - */ - PropertyValuePart.serializeString = function (value) { - var replacer = function (match, c) { - if (c === '"') { - return '\\' + c; - } - var cp = String.codePointAt - ? String.codePointAt(0) - : // We only escape non-surrogate chars, so using charCodeAt - // is harmless here. - String.charCodeAt(0); - return '\\' + cp.toString(16) + ' '; - }; - return '"' + value.replace(/["\r\n\f]/g, replacer) + '"'; - }; - - /** - * Create a new syntax unit based solely on the given token. - * Convenience method for creating a new syntax unit when - * it represents a single token instead of multiple. - * @param {Object} token The token object to represent. - * @return {parserlib.css.PropertyValuePart} The object representing the token. - * @static - * @method fromToken - */ - PropertyValuePart.fromToken = function (token) { - return new PropertyValuePart(token.value, token.startLine, token.startCol); - }; - var Pseudos = { - __proto__: null, - ':first-letter': 1, - ':first-line': 1, - ':before': 1, - ':after': 1, - }; - - Pseudos.ELEMENT = 1; - Pseudos.CLASS = 2; - - Pseudos.isElement = function (pseudo) { - return pseudo.indexOf('::') === 0 || Pseudos[pseudo.toLowerCase()] === Pseudos.ELEMENT; - }; - /** - * Represents an entire single selector, including all parts but not - * including multiple selectors (those separated by commas). - * @namespace parserlib.css - * @class Selector - * @extends parserlib.util.SyntaxUnit - * @constructor - * @param {Array} parts Array of selectors parts making up this selector. - * @param {int} line The line of text on which the unit resides. - * @param {int} col The column of text on which the unit resides. - */ - function Selector(parts, line, col) { - SyntaxUnit.call(this, parts.join(' '), line, col, Parser.SELECTOR_TYPE); - - /** - * The parts that make up the selector. - * @type Array - * @property parts - */ - this.parts = parts; - - /** - * The specificity of the selector. - * @type parserlib.css.Specificity - * @property specificity - */ - this.specificity = Specificity.calculate(this); - } - - Selector.prototype = new SyntaxUnit(); - Selector.prototype.constructor = Selector; - - /** - * Represents a single part of a selector string, meaning a single set of - * element name and modifiers. This does not include combinators such as - * spaces, +, >, etc. - * @namespace parserlib.css - * @class SelectorPart - * @extends parserlib.util.SyntaxUnit - * @constructor - * @param {String} elementName The element name in the selector or null - * if there is no element name. - * @param {Array} modifiers Array of individual modifiers for the element. - * May be empty if there are none. - * @param {String} text The text representation of the unit. - * @param {int} line The line of text on which the unit resides. - * @param {int} col The column of text on which the unit resides. - */ - function SelectorPart(elementName, modifiers, text, line, col) { - SyntaxUnit.call(this, text, line, col, Parser.SELECTOR_PART_TYPE); - - /** - * The tag name of the element to which this part - * of the selector affects. - * @type String - * @property elementName - */ - this.elementName = elementName; - - /** - * The parts that come after the element name, such as class names, IDs, - * pseudo classes/elements, etc. - * @type Array - * @property modifiers - */ - this.modifiers = modifiers; - } - - SelectorPart.prototype = new SyntaxUnit(); - SelectorPart.prototype.constructor = SelectorPart; - - /** - * Represents a selector modifier string, meaning a class name, element name, - * element ID, pseudo rule, etc. - * @namespace parserlib.css - * @class SelectorSubPart - * @extends parserlib.util.SyntaxUnit - * @constructor - * @param {String} text The text representation of the unit. - * @param {String} type The type of selector modifier. - * @param {int} line The line of text on which the unit resides. - * @param {int} col The column of text on which the unit resides. - */ - function SelectorSubPart(text, type, line, col) { - SyntaxUnit.call(this, text, line, col, Parser.SELECTOR_SUB_PART_TYPE); - - /** - * The type of modifier. - * @type String - * @property type - */ - this.type = type; - - /** - * Some subparts have arguments, this represents them. - * @type Array - * @property args - */ - this.args = []; - } - - SelectorSubPart.prototype = new SyntaxUnit(); - SelectorSubPart.prototype.constructor = SelectorSubPart; - - /** - * Represents a selector's specificity. - * @namespace parserlib.css - * @class Specificity - * @constructor - * @param {int} a Should be 1 for inline styles, zero for stylesheet styles - * @param {int} b Number of ID selectors - * @param {int} c Number of classes and pseudo classes - * @param {int} d Number of element names and pseudo elements - */ - function Specificity(a, b, c, d) { - this.a = a; - this.b = b; - this.c = c; - this.d = d; - } - - Specificity.prototype = { - constructor: Specificity, - - /** - * Compare this specificity to another. - * @param {Specificity} other The other specificity to compare to. - * @return {int} -1 if the other specificity is larger, 1 if smaller, 0 if equal. - * @method compare - */ - compare: function (other) { - var comps = ['a', 'b', 'c', 'd'], - i, - len; - - for (i = 0, len = comps.length; i < len; i++) { - if (this[comps[i]] < other[comps[i]]) { - return -1; - } else if (this[comps[i]] > other[comps[i]]) { - return 1; - } - } - - return 0; - }, - - /** - * Creates a numeric value for the specificity. - * @return {int} The numeric value for the specificity. - * @method valueOf - */ - valueOf: function () { - return this.a * 1000 + this.b * 100 + this.c * 10 + this.d; - }, - - /** - * Returns a string representation for specificity. - * @return {String} The string representation of specificity. - * @method toString - */ - toString: function () { - return this.a + ',' + this.b + ',' + this.c + ',' + this.d; - }, - }; - - /** - * Calculates the specificity of the given selector. - * @param {parserlib.css.Selector} The selector to calculate specificity for. - * @return {parserlib.css.Specificity} The specificity of the selector. - * @static - * @method calculate - */ - Specificity.calculate = function (selector) { - var i, - len, - part, - b = 0, - c = 0, - d = 0; - - function updateValues(part) { - var i, - j, - len, - num, - elementName = part.elementName ? part.elementName.text : '', - modifier; - - if (elementName && elementName.charAt(elementName.length - 1) !== '*') { - d++; - } - - for (i = 0, len = part.modifiers.length; i < len; i++) { - modifier = part.modifiers[i]; - switch (modifier.type) { - case 'class': - case 'attribute': - c++; - break; - - case 'id': - b++; - break; - - case 'pseudo': - if (Pseudos.isElement(modifier.text)) { - d++; - } else { - c++; - } - break; - - case 'not': - for (j = 0, num = modifier.args.length; j < num; j++) { - updateValues(modifier.args[j]); - } - } - } - } - - for (i = 0, len = selector.parts.length; i < len; i++) { - part = selector.parts[i]; - - if (part instanceof SelectorPart) { - updateValues(part); - } - } - - return new Specificity(0, b, c, d); - }; - - var h = /^[0-9a-fA-F]$/, - //nonascii = /^[\u0080-\uFFFF]$/, - nl = /\n|\r\n|\r|\f/; - - //----------------------------------------------------------------------------- - // Helper functions - //----------------------------------------------------------------------------- - - function isHexDigit(c) { - return c !== null && h.test(c); - } - - function isDigit(c) { - return c !== null && /\d/.test(c); - } - - function isWhitespace(c) { - return c !== null && /\s/.test(c); - } - - function isNewLine(c) { - return c !== null && nl.test(c); - } - - function isNameStart(c) { - return c !== null && /[a-z_\u0080-\uFFFF\\]/i.test(c); - } - - function isNameChar(c) { - return c !== null && (isNameStart(c) || /[0-9\-\\]/.test(c)); - } - - function isIdentStart(c) { - return c !== null && (isNameStart(c) || /\-\\/.test(c)); - } - - function mix(receiver, supplier) { - for (var prop in supplier) { - if (Object.prototype.hasOwnProperty.call(supplier, prop)) { - receiver[prop] = supplier[prop]; - } - } - return receiver; - } - - //----------------------------------------------------------------------------- - // CSS Token Stream - //----------------------------------------------------------------------------- - - /** - * A token stream that produces CSS tokens. - * @param {String|Reader} input The source of text to tokenize. - * @constructor - * @class TokenStream - * @namespace parserlib.css - */ - function TokenStream(input) { - TokenStreamBase.call(this, input, Tokens); - } - - TokenStream.prototype = mix(new TokenStreamBase(), { - /** - * Overrides the TokenStreamBase method of the same name - * to produce CSS tokens. - * @param {variant} channel The name of the channel to use - * for the next token. - * @return {Object} A token object representing the next token. - * @method _getToken - * @private - */ - _getToken: function (channel) { - var c, - reader = this._reader, - token = null, - startLine = reader.getLine(), - startCol = reader.getCol(); - - c = reader.read(); - - while (c) { - switch (c) { - /* - * Potential tokens: - * - COMMENT - * - SLASH - * - CHAR - */ - case '/': - if (reader.peek() === '*') { - token = this.commentToken(c, startLine, startCol); - } else { - token = this.charToken(c, startLine, startCol); - } - break; - - /* - * Potential tokens: - * - DASHMATCH - * - INCLUDES - * - PREFIXMATCH - * - SUFFIXMATCH - * - SUBSTRINGMATCH - * - CHAR - */ - case '|': - case '~': - case '^': - case '$': - case '*': - if (reader.peek() === '=') { - token = this.comparisonToken(c, startLine, startCol); - } else { - token = this.charToken(c, startLine, startCol); - } - break; - - /* - * Potential tokens: - * - STRING - * - INVALID - */ - case '"': - case "'": - token = this.stringToken(c, startLine, startCol); - break; - - /* - * Potential tokens: - * - HASH - * - CHAR - */ - case '#': - if (isNameChar(reader.peek())) { - token = this.hashToken(c, startLine, startCol); - } else { - token = this.charToken(c, startLine, startCol); - } - break; - - /* - * Potential tokens: - * - DOT - * - NUMBER - * - DIMENSION - * - PERCENTAGE - */ - case '.': - if (isDigit(reader.peek())) { - token = this.numberToken(c, startLine, startCol); - } else { - token = this.charToken(c, startLine, startCol); - } - break; - - /* - * Potential tokens: - * - CDC - * - MINUS - * - NUMBER - * - DIMENSION - * - PERCENTAGE - */ - case '-': - if (reader.peek() === '-') { - //could be closing HTML-style comment - token = this.htmlCommentEndToken(c, startLine, startCol); - } else if (isNameStart(reader.peek())) { - token = this.identOrFunctionToken(c, startLine, startCol); - } else { - token = this.charToken(c, startLine, startCol); - } - break; - - /* - * Potential tokens: - * - IMPORTANT_SYM - * - CHAR - */ - case '!': - token = this.importantToken(c, startLine, startCol); - break; - - /* - * Any at-keyword or CHAR - */ - case '@': - token = this.atRuleToken(c, startLine, startCol); - break; - - /* - * Potential tokens: - * - NOT - * - CHAR - */ - case ':': - token = this.notToken(c, startLine, startCol); - break; - - /* - * Potential tokens: - * - CDO - * - CHAR - */ - case '<': - token = this.htmlCommentStartToken(c, startLine, startCol); - break; - - /* - * Potential tokens: - * - UNICODE_RANGE - * - URL - * - CHAR - */ - case 'U': - case 'u': - if (reader.peek() === '+') { - token = this.unicodeRangeToken(c, startLine, startCol); - break; - } - /* falls through */ - default: - /* - * Potential tokens: - * - NUMBER - * - DIMENSION - * - LENGTH - * - FREQ - * - TIME - * - EMS - * - EXS - * - ANGLE - */ - if (isDigit(c)) { - token = this.numberToken(c, startLine, startCol); - } else if (isWhitespace(c)) { - /* - * Potential tokens: - * - S - */ - token = this.whitespaceToken(c, startLine, startCol); - } else if (isIdentStart(c)) { - /* - * Potential tokens: - * - IDENT - */ - token = this.identOrFunctionToken(c, startLine, startCol); - } else { - /* - * Potential tokens: - * - CHAR - * - PLUS - */ - token = this.charToken(c, startLine, startCol); - } - } - - //make sure this token is wanted - //TODO: check channel - break; - } - - if (!token && c === null) { - token = this.createToken(Tokens.EOF, null, startLine, startCol); - } - - return token; - }, - - //------------------------------------------------------------------------- - // Methods to create tokens - //------------------------------------------------------------------------- - - /** - * Produces a token based on available data and the current - * reader position information. This method is called by other - * private methods to create tokens and is never called directly. - * @param {int} tt The token type. - * @param {String} value The text value of the token. - * @param {int} startLine The beginning line for the character. - * @param {int} startCol The beginning column for the character. - * @param {Object} options (Optional) Specifies a channel property - * to indicate that a different channel should be scanned - * and/or a hide property indicating that the token should - * be hidden. - * @return {Object} A token object. - * @method createToken - */ - createToken: function (tt, value, startLine, startCol, options) { - var reader = this._reader; - options = options || {}; - - return { - value: value, - type: tt, - channel: options.channel, - endChar: options.endChar, - hide: options.hide || false, - startLine: startLine, - startCol: startCol, - endLine: reader.getLine(), - endCol: reader.getCol(), - }; - }, - - //------------------------------------------------------------------------- - // Methods to create specific tokens - //------------------------------------------------------------------------- - - /** - * Produces a token for any at-rule. If the at-rule is unknown, then - * the token is for a single "@" character. - * @param {String} first The first character for the token. - * @param {int} startLine The beginning line for the character. - * @param {int} startCol The beginning column for the character. - * @return {Object} A token object. - * @method atRuleToken - */ - atRuleToken: function (first, startLine, startCol) { - var rule = first, - reader = this._reader, - tt = Tokens.CHAR, - ident; - - /* - * First, mark where we are. There are only four @ rules, - * so anything else is really just an invalid token. - * Basically, if this doesn't match one of the known @ - * rules, just return '@' as an unknown token and allow - * parsing to continue after that point. - */ - reader.mark(); - - //try to find the at-keyword - ident = this.readName(); - rule = first + ident; - tt = Tokens.type(rule.toLowerCase()); - - //if it's not valid, use the first character only and reset the reader - if (tt === Tokens.CHAR || tt === Tokens.UNKNOWN) { - if (rule.length > 1) { - tt = Tokens.UNKNOWN_SYM; - } else { - tt = Tokens.CHAR; - rule = first; - reader.reset(); - } - } - - return this.createToken(tt, rule, startLine, startCol); - }, - - /** - * Produces a character token based on the given character - * and location in the stream. If there's a special (non-standard) - * token name, this is used; otherwise CHAR is used. - * @param {String} c The character for the token. - * @param {int} startLine The beginning line for the character. - * @param {int} startCol The beginning column for the character. - * @return {Object} A token object. - * @method charToken - */ - charToken: function (c, startLine, startCol) { - var tt = Tokens.type(c); - var opts = {}; - - if (tt === -1) { - tt = Tokens.CHAR; - } else { - opts.endChar = Tokens[tt].endChar; - } - - return this.createToken(tt, c, startLine, startCol, opts); - }, - - /** - * Produces a character token based on the given character - * and location in the stream. If there's a special (non-standard) - * token name, this is used; otherwise CHAR is used. - * @param {String} first The first character for the token. - * @param {int} startLine The beginning line for the character. - * @param {int} startCol The beginning column for the character. - * @return {Object} A token object. - * @method commentToken - */ - commentToken: function (first, startLine, startCol) { - var comment = this.readComment(first); - - return this.createToken(Tokens.COMMENT, comment, startLine, startCol); - }, - - /** - * Produces a comparison token based on the given character - * and location in the stream. The next character must be - * read and is already known to be an equals sign. - * @param {String} c The character for the token. - * @param {int} startLine The beginning line for the character. - * @param {int} startCol The beginning column for the character. - * @return {Object} A token object. - * @method comparisonToken - */ - comparisonToken: function (c, startLine, startCol) { - var reader = this._reader, - comparison = c + reader.read(), - tt = Tokens.type(comparison) || Tokens.CHAR; - - return this.createToken(tt, comparison, startLine, startCol); - }, - - /** - * Produces a hash token based on the specified information. The - * first character provided is the pound sign (#) and then this - * method reads a name afterward. - * @param {String} first The first character (#) in the hash name. - * @param {int} startLine The beginning line for the character. - * @param {int} startCol The beginning column for the character. - * @return {Object} A token object. - * @method hashToken - */ - hashToken: function (first, startLine, startCol) { - var name = this.readName(first); - - return this.createToken(Tokens.HASH, name, startLine, startCol); - }, - - /** - * Produces a CDO or CHAR token based on the specified information. The - * first character is provided and the rest is read by the function to determine - * the correct token to create. - * @param {String} first The first character in the token. - * @param {int} startLine The beginning line for the character. - * @param {int} startCol The beginning column for the character. - * @return {Object} A token object. - * @method htmlCommentStartToken - */ - htmlCommentStartToken: function (first, startLine, startCol) { - var reader = this._reader, - text = first; - - reader.mark(); - text += reader.readCount(3); - - if (text === '<!--') { - return this.createToken(Tokens.CDO, text, startLine, startCol); - } else { - reader.reset(); - return this.charToken(first, startLine, startCol); - } - }, - - /** - * Produces a CDC or CHAR token based on the specified information. The - * first character is provided and the rest is read by the function to determine - * the correct token to create. - * @param {String} first The first character in the token. - * @param {int} startLine The beginning line for the character. - * @param {int} startCol The beginning column for the character. - * @return {Object} A token object. - * @method htmlCommentEndToken - */ - htmlCommentEndToken: function (first, startLine, startCol) { - var reader = this._reader, - text = first; - - reader.mark(); - text += reader.readCount(2); - - if (text === '-->') { - return this.createToken(Tokens.CDC, text, startLine, startCol); - } else { - reader.reset(); - return this.charToken(first, startLine, startCol); - } - }, - - /** - * Produces an IDENT or FUNCTION token based on the specified information. The - * first character is provided and the rest is read by the function to determine - * the correct token to create. - * @param {String} first The first character in the identifier. - * @param {int} startLine The beginning line for the character. - * @param {int} startCol The beginning column for the character. - * @return {Object} A token object. - * @method identOrFunctionToken - */ - identOrFunctionToken: function (first, startLine, startCol) { - var reader = this._reader, - ident = this.readName(first), - tt = Tokens.IDENT, - uriFns = ['url(', 'url-prefix(', 'domain(']; - - //if there's a left paren immediately after, it's a URI or function - if (reader.peek() === '(') { - ident += reader.read(); - if (uriFns.indexOf(ident.toLowerCase()) > -1) { - tt = Tokens.URI; - ident = this.readURI(ident); - - //didn't find a valid URL or there's no closing paren - if (uriFns.indexOf(ident.toLowerCase()) > -1) { - tt = Tokens.FUNCTION; - } - } else { - tt = Tokens.FUNCTION; - } - } else if (reader.peek() === ':') { - //might be an IE function - - //IE-specific functions always being with progid: - if (ident.toLowerCase() === 'progid') { - ident += reader.readTo('('); - tt = Tokens.IE_FUNCTION; - } - } - - return this.createToken(tt, ident, startLine, startCol); - }, - - /** - * Produces an IMPORTANT_SYM or CHAR token based on the specified information. The - * first character is provided and the rest is read by the function to determine - * the correct token to create. - * @param {String} first The first character in the token. - * @param {int} startLine The beginning line for the character. - * @param {int} startCol The beginning column for the character. - * @return {Object} A token object. - * @method importantToken - */ - importantToken: function (first, startLine, startCol) { - var reader = this._reader, - important = first, - tt = Tokens.CHAR, - temp, - c; - - reader.mark(); - c = reader.read(); - - while (c) { - //there can be a comment in here - if (c === '/') { - //if the next character isn't a star, then this isn't a valid !important token - if (reader.peek() !== '*') { - break; - } else { - temp = this.readComment(c); - if (temp === '') { - //broken! - break; - } - } - } else if (isWhitespace(c)) { - important += c + this.readWhitespace(); - } else if (/i/i.test(c)) { - temp = reader.readCount(8); - if (/mportant/i.test(temp)) { - important += c + temp; - tt = Tokens.IMPORTANT_SYM; - } - break; //we're done - } else { - break; - } - - c = reader.read(); - } - - if (tt === Tokens.CHAR) { - reader.reset(); - return this.charToken(first, startLine, startCol); - } else { - return this.createToken(tt, important, startLine, startCol); - } - }, - - /** - * Produces a NOT or CHAR token based on the specified information. The - * first character is provided and the rest is read by the function to determine - * the correct token to create. - * @param {String} first The first character in the token. - * @param {int} startLine The beginning line for the character. - * @param {int} startCol The beginning column for the character. - * @return {Object} A token object. - * @method notToken - */ - notToken: function (first, startLine, startCol) { - var reader = this._reader, - text = first; - - reader.mark(); - text += reader.readCount(4); - - if (text.toLowerCase() === ':not(') { - return this.createToken(Tokens.NOT, text, startLine, startCol); - } else { - reader.reset(); - return this.charToken(first, startLine, startCol); - } - }, - - /** - * Produces a number token based on the given character - * and location in the stream. This may return a token of - * NUMBER, EMS, EXS, LENGTH, ANGLE, TIME, FREQ, DIMENSION, - * or PERCENTAGE. - * @param {String} first The first character for the token. - * @param {int} startLine The beginning line for the character. - * @param {int} startCol The beginning column for the character. - * @return {Object} A token object. - * @method numberToken - */ - numberToken: function (first, startLine, startCol) { - var reader = this._reader, - value = this.readNumber(first), - ident, - tt = Tokens.NUMBER, - c = reader.peek(); - - if (isIdentStart(c)) { - ident = this.readName(reader.read()); - value += ident; - - if ( - /^em$|^ex$|^px$|^gd$|^rem$|^vw$|^vh$|^vmax$|^vmin$|^ch$|^cm$|^mm$|^in$|^pt$|^pc$/i.test( - ident - ) - ) { - tt = Tokens.LENGTH; - } else if (/^deg|^rad$|^grad$/i.test(ident)) { - tt = Tokens.ANGLE; - } else if (/^ms$|^s$/i.test(ident)) { - tt = Tokens.TIME; - } else if (/^hz$|^khz$/i.test(ident)) { - tt = Tokens.FREQ; - } else if (/^dpi$|^dpcm$/i.test(ident)) { - tt = Tokens.RESOLUTION; - } else { - tt = Tokens.DIMENSION; - } - } else if (c === '%') { - value += reader.read(); - tt = Tokens.PERCENTAGE; - } - - return this.createToken(tt, value, startLine, startCol); - }, - - /** - * Produces a string token based on the given character - * and location in the stream. Since strings may be indicated - * by single or double quotes, a failure to match starting - * and ending quotes results in an INVALID token being generated. - * The first character in the string is passed in and then - * the rest are read up to and including the final quotation mark. - * @param {String} first The first character in the string. - * @param {int} startLine The beginning line for the character. - * @param {int} startCol The beginning column for the character. - * @return {Object} A token object. - * @method stringToken - */ - stringToken: function (first, startLine, startCol) { - var delim = first, - string = first, - reader = this._reader, - prev = first, - tt = Tokens.STRING, - c = reader.read(); - - while (c) { - string += c; - - //if the delimiter is found with an escapement, we're done. - if (c === delim && prev !== '\\') { - break; - } - - //if there's a newline without an escapement, it's an invalid string - if (isNewLine(reader.peek()) && c !== '\\') { - tt = Tokens.INVALID; - break; - } - - //save previous and get next - prev = c; - c = reader.read(); - } - - //if c is null, that means we're out of input and the string was never closed - if (c === null) { - tt = Tokens.INVALID; - } - - return this.createToken(tt, string, startLine, startCol); - }, - - unicodeRangeToken: function (first, startLine, startCol) { - var reader = this._reader, - value = first, - temp, - tt = Tokens.CHAR; - - //then it should be a unicode range - if (reader.peek() === '+') { - reader.mark(); - value += reader.read(); - value += this.readUnicodeRangePart(true); - - //ensure there's an actual unicode range here - if (value.length === 2) { - reader.reset(); - } else { - tt = Tokens.UNICODE_RANGE; - - //if there's a ? in the first part, there can't be a second part - if (value.indexOf('?') === -1) { - if (reader.peek() === '-') { - reader.mark(); - temp = reader.read(); - temp += this.readUnicodeRangePart(false); - - //if there's not another value, back up and just take the first - if (temp.length === 1) { - reader.reset(); - } else { - value += temp; - } - } - } - } - } - - return this.createToken(tt, value, startLine, startCol); - }, - - /** - * Produces a S token based on the specified information. Since whitespace - * may have multiple characters, this consumes all whitespace characters - * into a single token. - * @param {String} first The first character in the token. - * @param {int} startLine The beginning line for the character. - * @param {int} startCol The beginning column for the character. - * @return {Object} A token object. - * @method whitespaceToken - */ - whitespaceToken: function (first, startLine, startCol) { - var value = first + this.readWhitespace(); - return this.createToken(Tokens.S, value, startLine, startCol); - }, - - //------------------------------------------------------------------------- - // Methods to read values from the string stream - //------------------------------------------------------------------------- - - readUnicodeRangePart: function (allowQuestionMark) { - var reader = this._reader, - part = '', - c = reader.peek(); - - //first read hex digits - while (isHexDigit(c) && part.length < 6) { - reader.read(); - part += c; - c = reader.peek(); - } - - //then read question marks if allowed - if (allowQuestionMark) { - while (c === '?' && part.length < 6) { - reader.read(); - part += c; - c = reader.peek(); - } - } - - //there can't be any other characters after this point - - return part; - }, - - readWhitespace: function () { - var reader = this._reader, - whitespace = '', - c = reader.peek(); - - while (isWhitespace(c)) { - reader.read(); - whitespace += c; - c = reader.peek(); - } - - return whitespace; - }, - readNumber: function (first) { - var reader = this._reader, - number = first, - hasDot = first === '.', - c = reader.peek(); - - while (c) { - if (isDigit(c)) { - number += reader.read(); - } else if (c === '.') { - if (hasDot) { - break; - } else { - hasDot = true; - number += reader.read(); - } - } else { - break; - } - - c = reader.peek(); - } - - return number; - }, - readString: function () { - var reader = this._reader, - delim = reader.read(), - string = delim, - prev = delim, - c = reader.peek(); - - while (c) { - c = reader.read(); - string += c; - - //if the delimiter is found with an escapement, we're done. - if (c === delim && prev !== '\\') { - break; - } - - //if there's a newline without an escapement, it's an invalid string - if (isNewLine(reader.peek()) && c !== '\\') { - string = ''; - break; - } - - //save previous and get next - prev = c; - c = reader.peek(); - } - - //if c is null, that means we're out of input and the string was never closed - if (c === null) { - string = ''; - } - - return string; - }, - readURI: function (first) { - var reader = this._reader, - uri = first, - inner = '', - c = reader.peek(); - - reader.mark(); - - //skip whitespace before - while (c && isWhitespace(c)) { - reader.read(); - c = reader.peek(); - } - - //it's a string - if (c === "'" || c === '"') { - inner = this.readString(); - } else { - inner = this.readURL(); - } - - c = reader.peek(); - - //skip whitespace after - while (c && isWhitespace(c)) { - reader.read(); - c = reader.peek(); - } - - //if there was no inner value or the next character isn't closing paren, it's not a URI - if (inner === '' || c !== ')') { - uri = first; - reader.reset(); - } else { - uri += inner + reader.read(); - } - - return uri; - }, - readURL: function () { - var reader = this._reader, - url = '', - c = reader.peek(); - - //TODO: Check for escape and nonascii - while (/^[!#$%&\\*-~]$/.test(c)) { - url += reader.read(); - c = reader.peek(); - } - - return url; - }, - readName: function (first) { - var reader = this._reader, - ident = first || '', - c = reader.peek(); - - while (true) { - if (c === '\\') { - ident += this.readEscape(reader.read()); - c = reader.peek(); - } else if (c && isNameChar(c)) { - ident += reader.read(); - c = reader.peek(); - } else { - break; - } - } - - return ident; - }, - - readEscape: function (first) { - var reader = this._reader, - cssEscape = first || '', - i = 0, - c = reader.peek(); - - if (isHexDigit(c)) { - do { - cssEscape += reader.read(); - c = reader.peek(); - } while (c && isHexDigit(c) && ++i < 6); - } - - if ( - (cssEscape.length === 3 && /\s/.test(c)) || - cssEscape.length === 7 || - cssEscape.length === 1 - ) { - reader.read(); - } else { - c = ''; - } - - return cssEscape + c; - }, - - readComment: function (first) { - var reader = this._reader, - comment = first || '', - c = reader.read(); - - if (c === '*') { - while (c) { - comment += c; - - //look for end of comment - if (comment.length > 2 && c === '*' && reader.peek() === '/') { - comment += reader.read(); - break; - } - - c = reader.read(); - } - - return comment; - } else { - return ''; - } - }, - }); - - var Tokens = [ - /* - * The following token names are defined in CSS3 Grammar: http://www.w3.org/TR/css3-syntax/#lexical - */ - - //HTML-style comments - { name: 'CDO' }, - { name: 'CDC' }, - - //ignorables - { name: 'S', whitespace: true /*, channel: "ws"*/ }, - { name: 'COMMENT', comment: true, hide: true, channel: 'comment' }, - - //attribute equality - { name: 'INCLUDES', text: '~=' }, - { name: 'DASHMATCH', text: '|=' }, - { name: 'PREFIXMATCH', text: '^=' }, - { name: 'SUFFIXMATCH', text: '$=' }, - { name: 'SUBSTRINGMATCH', text: '*=' }, - - //identifier types - { name: 'STRING' }, - { name: 'IDENT' }, - { name: 'HASH' }, - - //at-keywords - { name: 'IMPORT_SYM', text: '@import' }, - { name: 'PAGE_SYM', text: '@page' }, - { name: 'MEDIA_SYM', text: '@media' }, - { name: 'FONT_FACE_SYM', text: '@font-face' }, - { name: 'CHARSET_SYM', text: '@charset' }, - { name: 'NAMESPACE_SYM', text: '@namespace' }, - { name: 'VIEWPORT_SYM', text: ['@viewport', '@-ms-viewport', '@-o-viewport'] }, - { name: 'DOCUMENT_SYM', text: ['@document', '@-moz-document'] }, - { name: 'UNKNOWN_SYM' }, - //{ name: "ATKEYWORD"}, - - //CSS3 animations - { - name: 'KEYFRAMES_SYM', - text: ['@keyframes', '@-webkit-keyframes', '@-moz-keyframes', '@-o-keyframes'], - }, - - //important symbol - { name: 'IMPORTANT_SYM' }, - - //measurements - { name: 'LENGTH' }, - { name: 'ANGLE' }, - { name: 'TIME' }, - { name: 'FREQ' }, - { name: 'DIMENSION' }, - { name: 'PERCENTAGE' }, - { name: 'NUMBER' }, - - //functions - { name: 'URI' }, - { name: 'FUNCTION' }, - - //Unicode ranges - { name: 'UNICODE_RANGE' }, - - /* - * The following token names are defined in CSS3 Selectors: http://www.w3.org/TR/css3-selectors/#selector-syntax - */ - - //invalid string - { name: 'INVALID' }, - - //combinators - { name: 'PLUS', text: '+' }, - { name: 'GREATER', text: '>' }, - { name: 'COMMA', text: ',' }, - { name: 'TILDE', text: '~' }, - - //modifier - { name: 'NOT' }, - - /* - * Defined in CSS3 Paged Media - */ - { name: 'TOPLEFTCORNER_SYM', text: '@top-left-corner' }, - { name: 'TOPLEFT_SYM', text: '@top-left' }, - { name: 'TOPCENTER_SYM', text: '@top-center' }, - { name: 'TOPRIGHT_SYM', text: '@top-right' }, - { name: 'TOPRIGHTCORNER_SYM', text: '@top-right-corner' }, - { name: 'BOTTOMLEFTCORNER_SYM', text: '@bottom-left-corner' }, - { name: 'BOTTOMLEFT_SYM', text: '@bottom-left' }, - { name: 'BOTTOMCENTER_SYM', text: '@bottom-center' }, - { name: 'BOTTOMRIGHT_SYM', text: '@bottom-right' }, - { name: 'BOTTOMRIGHTCORNER_SYM', text: '@bottom-right-corner' }, - { name: 'LEFTTOP_SYM', text: '@left-top' }, - { name: 'LEFTMIDDLE_SYM', text: '@left-middle' }, - { name: 'LEFTBOTTOM_SYM', text: '@left-bottom' }, - { name: 'RIGHTTOP_SYM', text: '@right-top' }, - { name: 'RIGHTMIDDLE_SYM', text: '@right-middle' }, - { name: 'RIGHTBOTTOM_SYM', text: '@right-bottom' }, - - /* - * The following token names are defined in CSS3 Media Queries: http://www.w3.org/TR/css3-mediaqueries/#syntax - */ - /*{ name: "MEDIA_ONLY", state: "media"}, - { name: "MEDIA_NOT", state: "media"}, - { name: "MEDIA_AND", state: "media"},*/ - { name: 'RESOLUTION', state: 'media' }, - - /* - * The following token names are not defined in any CSS specification but are used by the lexer. - */ - - //not a real token, but useful for stupid IE filters - { name: 'IE_FUNCTION' }, - - //part of CSS3 grammar but not the Flex code - { name: 'CHAR' }, - - //TODO: Needed? - //Not defined as tokens, but might as well be - { - name: 'PIPE', - text: '|', - }, - { - name: 'SLASH', - text: '/', - }, - { - name: 'MINUS', - text: '-', - }, - { - name: 'STAR', - text: '*', - }, - - { - name: 'LBRACE', - endChar: '}', - text: '{', - }, - { - name: 'RBRACE', - text: '}', - }, - { - name: 'LBRACKET', - endChar: ']', - text: '[', - }, - { - name: 'RBRACKET', - text: ']', - }, - { - name: 'EQUALS', - text: '=', - }, - { - name: 'COLON', - text: ':', - }, - { - name: 'SEMICOLON', - text: ';', - }, - - { - name: 'LPAREN', - endChar: ')', - text: '(', - }, - { - name: 'RPAREN', - text: ')', - }, - { - name: 'DOT', - text: '.', - }, - ]; - - (function () { - var nameMap = [], - typeMap = Object.create(null); - - Tokens.UNKNOWN = -1; - Tokens.unshift({ name: 'EOF' }); - for (var i = 0, len = Tokens.length; i < len; i++) { - nameMap.push(Tokens[i].name); - Tokens[Tokens[i].name] = i; - if (Tokens[i].text) { - if (Tokens[i].text instanceof Array) { - for (var j = 0; j < Tokens[i].text.length; j++) { - typeMap[Tokens[i].text[j]] = i; - } - } else { - typeMap[Tokens[i].text] = i; - } - } - } - - Tokens.name = function (tt) { - return nameMap[tt]; - }; - - Tokens.type = function (c) { - return typeMap[c] || -1; - }; - })(); - - //This file will likely change a lot! Very experimental! - var Validation = { - validate: function (property, value) { - //normalize name - var name = property.toString().toLowerCase(), - expression = new PropertyValueIterator(value), - spec = Properties[name]; - - if (!spec) { - if (name.indexOf('-') !== 0) { - //vendor prefixed are ok - throw new ValidationError( - "Unknown property '" + property + "'.", - property.line, - property.col - ); - } - } else if (typeof spec !== 'number') { - //initialization - if (typeof spec === 'string') { - if (spec.indexOf('||') > -1) { - this.groupProperty(spec, expression); - } else { - this.singleProperty(spec, expression, 1); - } - } else if (spec.multi) { - this.multiProperty(spec.multi, expression, spec.comma, spec.max || Infinity); - } else if (typeof spec === 'function') { - spec(expression); - } - } - }, - - singleProperty: function (types, expression, max, partial) { - var result = false, - value = expression.value, - count = 0, - part; - - while (expression.hasNext() && count < max) { - result = ValidationTypes.isAny(expression, types); - if (!result) { - break; - } - count++; - } - - if (!result) { - if (expression.hasNext() && !expression.isFirst()) { - part = expression.peek(); - throw new ValidationError( - "Expected end of value but found '" + part + "'.", - part.line, - part.col - ); - } else { - throw new ValidationError( - 'Expected (' + types + ") but found '" + value + "'.", - value.line, - value.col - ); - } - } else if (expression.hasNext()) { - part = expression.next(); - throw new ValidationError( - "Expected end of value but found '" + part + "'.", - part.line, - part.col - ); - } - }, - - multiProperty: function (types, expression, comma, max) { - var result = false, - value = expression.value, - count = 0, - part; - - while (expression.hasNext() && !result && count < max) { - if (ValidationTypes.isAny(expression, types)) { - count++; - if (!expression.hasNext()) { - result = true; - } else if (comma) { - if (String(expression.peek()) === ',') { - part = expression.next(); - } else { - break; - } - } - } else { - break; - } - } - - if (!result) { - if (expression.hasNext() && !expression.isFirst()) { - part = expression.peek(); - throw new ValidationError( - "Expected end of value but found '" + part + "'.", - part.line, - part.col - ); - } else { - part = expression.previous(); - if (comma && String(part) === ',') { - throw new ValidationError( - "Expected end of value but found '" + part + "'.", - part.line, - part.col - ); - } else { - throw new ValidationError( - 'Expected (' + types + ") but found '" + value + "'.", - value.line, - value.col - ); - } - } - } else if (expression.hasNext()) { - part = expression.next(); - throw new ValidationError( - "Expected end of value but found '" + part + "'.", - part.line, - part.col - ); - } - }, - - groupProperty: function (types, expression, comma) { - var result = false, - value = expression.value, - typeCount = types.split('||').length, - groups = { count: 0 }, - partial = false, - name, - part; - - while (expression.hasNext() && !result) { - name = ValidationTypes.isAnyOfGroup(expression, types); - if (name) { - //no dupes - if (groups[name]) { - break; - } else { - groups[name] = 1; - groups.count++; - partial = true; - - if (groups.count === typeCount || !expression.hasNext()) { - result = true; - } - } - } else { - break; - } - } - - if (!result) { - if (partial && expression.hasNext()) { - part = expression.peek(); - throw new ValidationError( - "Expected end of value but found '" + part + "'.", - part.line, - part.col - ); - } else { - throw new ValidationError( - 'Expected (' + types + ") but found '" + value + "'.", - value.line, - value.col - ); - } - } else if (expression.hasNext()) { - part = expression.next(); - throw new ValidationError( - "Expected end of value but found '" + part + "'.", - part.line, - part.col - ); - } - }, - }; - /** - * Type to use when a validation error occurs. - * @class ValidationError - * @namespace parserlib.util - * @constructor - * @param {String} message The error message. - * @param {int} line The line at which the error occurred. - * @param {int} col The column at which the error occurred. - */ - function ValidationError(message, line, col) { - /** - * The column at which the error occurred. - * @type int - * @property col - */ - this.col = col; - - /** - * The line at which the error occurred. - * @type int - * @property line - */ - this.line = line; - - /** - * The text representation of the unit. - * @type String - * @property text - */ - this.message = message; - } - - //inherit from Error - ValidationError.prototype = new Error(); - //This file will likely change a lot! Very experimental! - var ValidationTypes = { - isLiteral: function (part, literals) { - var text = part.text.toString().toLowerCase(), - args = literals.split(' | '), - i, - len, - found = false; - - for (i = 0, len = args.length; i < len && !found; i++) { - if (text === args[i].toLowerCase()) { - found = true; - } - } - - return found; - }, - - isSimple: function (type) { - return !!this.simple[type]; - }, - - isComplex: function (type) { - return !!this.complex[type]; - }, - - /** - * Determines if the next part(s) of the given expression - * are any of the given types. - */ - isAny: function (expression, types) { - var args = types.split(' | '), - i, - len, - found = false; - - for (i = 0, len = args.length; i < len && !found && expression.hasNext(); i++) { - found = this.isType(expression, args[i]); - } - - return found; - }, - - /** - * Determines if the next part(s) of the given expression - * are one of a group. - */ - isAnyOfGroup: function (expression, types) { - var args = types.split(' || '), - i, - len, - found = false; - - for (i = 0, len = args.length; i < len && !found; i++) { - found = this.isType(expression, args[i]); - } - - return found ? args[i - 1] : false; - }, - - /** - * Determines if the next part(s) of the given expression - * are of a given type. - */ - isType: function (expression, type) { - var part = expression.peek(), - result = false; - - if (type.charAt(0) !== '<') { - result = this.isLiteral(part, type); - if (result) { - expression.next(); - } - } else if (this.simple[type]) { - result = this.simple[type](part); - if (result) { - expression.next(); - } - } else { - result = this.complex[type](expression); - } - - return result; - }, - - simple: { - __proto__: null, - - '<absolute-size>': function (part) { - return ValidationTypes.isLiteral( - part, - 'xx-small | x-small | small | medium | large | x-large | xx-large' - ); - }, - - '<attachment>': function (part) { - return ValidationTypes.isLiteral(part, 'scroll | fixed | local'); - }, - - '<attr>': function (part) { - return part.type === 'function' && part.name === 'attr'; - }, - - '<bg-image>': function (part) { - return this['<image>'](part) || this['<gradient>'](part) || String(part) === 'none'; - }, - - '<gradient>': function (part) { - return ( - part.type === 'function' && - /^(?:\-(?:ms|moz|o|webkit)\-)?(?:repeating\-)?(?:radial\-|linear\-)?gradient/i.test(part) - ); - }, - - '<box>': function (part) { - return ValidationTypes.isLiteral(part, 'padding-box | border-box | content-box'); - }, - - '<content>': function (part) { - return part.type === 'function' && part.name === 'content'; - }, - - '<relative-size>': function (part) { - return ValidationTypes.isLiteral(part, 'smaller | larger'); - }, - - //any identifier - '<ident>': function (part) { - return part.type === 'identifier'; - }, - - '<length>': function (part) { - if (part.type === 'function' && /^(?:\-(?:ms|moz|o|webkit)\-)?calc/i.test(part)) { - return true; - } else { - return ( - part.type === 'length' || - part.type === 'number' || - part.type === 'integer' || - String(part) === '0' - ); - } - }, - - '<color>': function (part) { - return ( - part.type === 'color' || String(part) === 'transparent' || String(part) === 'currentColor' - ); - }, - - '<number>': function (part) { - return part.type === 'number' || this['<integer>'](part); - }, - - '<integer>': function (part) { - return part.type === 'integer'; - }, - - '<line>': function (part) { - return part.type === 'integer'; - }, - - '<angle>': function (part) { - return part.type === 'angle'; - }, - - '<uri>': function (part) { - return part.type === 'uri'; - }, - - '<image>': function (part) { - return this['<uri>'](part); - }, - - '<percentage>': function (part) { - return part.type === 'percentage' || String(part) === '0'; - }, - - '<border-width>': function (part) { - return this['<length>'](part) || ValidationTypes.isLiteral(part, 'thin | medium | thick'); - }, - - '<border-style>': function (part) { - return ValidationTypes.isLiteral( - part, - 'none | hidden | dotted | dashed | solid | double | groove | ridge | inset | outset' - ); - }, - - '<content-sizing>': function (part) { - // http://www.w3.org/TR/css3-sizing/#width-height-keywords - return ValidationTypes.isLiteral( - part, - 'fill-available | -moz-available | -webkit-fill-available | max-content | -moz-max-content | -webkit-max-content | min-content | -moz-min-content | -webkit-min-content | fit-content | -moz-fit-content | -webkit-fit-content' - ); - }, - - '<margin-width>': function (part) { - return ( - this['<length>'](part) || - this['<percentage>'](part) || - ValidationTypes.isLiteral(part, 'auto') - ); - }, - - '<padding-width>': function (part) { - return this['<length>'](part) || this['<percentage>'](part); - }, - - '<shape>': function (part) { - return part.type === 'function' && (part.name === 'rect' || part.name === 'inset-rect'); - }, - - '<time>': function (part) { - return part.type === 'time'; - }, - - '<flex-grow>': function (part) { - return this['<number>'](part); - }, - - '<flex-shrink>': function (part) { - return this['<number>'](part); - }, - - '<width>': function (part) { - return this['<margin-width>'](part); - }, - - '<flex-basis>': function (part) { - return this['<width>'](part); - }, - - '<flex-direction>': function (part) { - return ValidationTypes.isLiteral(part, 'row | row-reverse | column | column-reverse'); - }, - - '<flex-wrap>': function (part) { - return ValidationTypes.isLiteral(part, 'nowrap | wrap | wrap-reverse'); - }, - - '<feature-tag-value>': function (part) { - return part.type === 'function' && /^[A-Z0-9]{4}$/i.test(part); - }, - }, - - complex: { - __proto__: null, - - '<bg-position>': function (expression) { - var result = false, - numeric = '<percentage> | <length>', - xDir = 'left | right', - yDir = 'top | bottom', - count = 0; - - while (expression.peek(count) && expression.peek(count).text !== ',') { - count++; - } - - /* -<position> = [ - [ left | center | right | top | bottom | <percentage> | <length> ] -| - [ left | center | right | <percentage> | <length> ] - [ top | center | bottom | <percentage> | <length> ] -| - [ center | [ left | right ] [ <percentage> | <length> ]? ] && - [ center | [ top | bottom ] [ <percentage> | <length> ]? ] -] -*/ - - if (count < 3) { - if (ValidationTypes.isAny(expression, xDir + ' | center | ' + numeric)) { - result = true; - ValidationTypes.isAny(expression, yDir + ' | center | ' + numeric); - } else if (ValidationTypes.isAny(expression, yDir)) { - result = true; - ValidationTypes.isAny(expression, xDir + ' | center'); - } - } else { - if (ValidationTypes.isAny(expression, xDir)) { - if (ValidationTypes.isAny(expression, yDir)) { - result = true; - ValidationTypes.isAny(expression, numeric); - } else if (ValidationTypes.isAny(expression, numeric)) { - if (ValidationTypes.isAny(expression, yDir)) { - result = true; - ValidationTypes.isAny(expression, numeric); - } else if (ValidationTypes.isAny(expression, 'center')) { - result = true; - } - } - } else if (ValidationTypes.isAny(expression, yDir)) { - if (ValidationTypes.isAny(expression, xDir)) { - result = true; - ValidationTypes.isAny(expression, numeric); - } else if (ValidationTypes.isAny(expression, numeric)) { - if (ValidationTypes.isAny(expression, xDir)) { - result = true; - ValidationTypes.isAny(expression, numeric); - } else if (ValidationTypes.isAny(expression, 'center')) { - result = true; - } - } - } else if (ValidationTypes.isAny(expression, 'center')) { - if (ValidationTypes.isAny(expression, xDir + ' | ' + yDir)) { - result = true; - ValidationTypes.isAny(expression, numeric); - } - } - } - - return result; - }, - - '<bg-size>': function (expression) { - //<bg-size> = [ <length> | <percentage> | auto ]{1,2} | cover | contain - var result = false, - numeric = '<percentage> | <length> | auto'; - - if (ValidationTypes.isAny(expression, 'cover | contain')) { - result = true; - } else if (ValidationTypes.isAny(expression, numeric)) { - result = true; - ValidationTypes.isAny(expression, numeric); - } - - return result; - }, - - '<repeat-style>': function (expression) { - //repeat-x | repeat-y | [repeat | space | round | no-repeat]{1,2} - var result = false, - values = 'repeat | space | round | no-repeat', - part; - - if (expression.hasNext()) { - part = expression.next(); - - if (ValidationTypes.isLiteral(part, 'repeat-x | repeat-y')) { - result = true; - } else if (ValidationTypes.isLiteral(part, values)) { - result = true; - - if (expression.hasNext() && ValidationTypes.isLiteral(expression.peek(), values)) { - expression.next(); - } - } - } - - return result; - }, - - '<shadow>': function (expression) { - //inset? && [ <length>{2,4} && <color>? ] - var result = false, - count = 0, - inset = false, - color = false; - - if (expression.hasNext()) { - if (ValidationTypes.isAny(expression, 'inset')) { - inset = true; - } - - if (ValidationTypes.isAny(expression, '<color>')) { - color = true; - } - - while (ValidationTypes.isAny(expression, '<length>') && count < 4) { - count++; - } - - if (expression.hasNext()) { - if (!color) { - ValidationTypes.isAny(expression, '<color>'); - } - - if (!inset) { - ValidationTypes.isAny(expression, 'inset'); - } - } - - result = count >= 2 && count <= 4; - } - - return result; - }, - - '<x-one-radius>': function (expression) { - //[ <length> | <percentage> ] [ <length> | <percentage> ]? - var result = false, - simple = '<length> | <percentage> | inherit'; - - if (ValidationTypes.isAny(expression, simple)) { - result = true; - ValidationTypes.isAny(expression, simple); - } - - return result; - }, - - '<flex>': function (expression) { - // http://www.w3.org/TR/2014/WD-css-flexbox-1-20140325/#flex-property - // none | [ <flex-grow> <flex-shrink>? || <flex-basis> ] - // Valid syntaxes, according to https://developer.mozilla.org/en-US/docs/Web/CSS/flex#Syntax - // * none - // * <flex-grow> - // * <flex-basis> - // * <flex-grow> <flex-basis> - // * <flex-grow> <flex-shrink> - // * <flex-grow> <flex-shrink> <flex-basis> - // * inherit - var part, - result = false; - if (ValidationTypes.isAny(expression, 'none | inherit')) { - result = true; - } else { - if (ValidationTypes.isType(expression, '<flex-grow>')) { - if (expression.peek()) { - if (ValidationTypes.isType(expression, '<flex-shrink>')) { - if (expression.peek()) { - result = ValidationTypes.isType(expression, '<flex-basis>'); - } else { - result = true; - } - } else if (ValidationTypes.isType(expression, '<flex-basis>')) { - result = expression.peek() === null; - } - } else { - result = true; - } - } else if (ValidationTypes.isType(expression, '<flex-basis>')) { - result = true; - } - } - - if (!result) { - // Generate a more verbose error than "Expected <flex>..." - part = expression.peek(); - throw new ValidationError( - "Expected (none | [ <flex-grow> <flex-shrink>? || <flex-basis> ]) but found '" + - expression.value.text + - "'.", - part.line, - part.col - ); - } - - return result; - }, - }, - }; - - parserlib.css = { - __proto__: null, - Colors: Colors, - Combinator: Combinator, - Parser: Parser, - PropertyName: PropertyName, - PropertyValue: PropertyValue, - PropertyValuePart: PropertyValuePart, - MediaFeature: MediaFeature, - MediaQuery: MediaQuery, - Selector: Selector, - SelectorPart: SelectorPart, - SelectorSubPart: SelectorSubPart, - Specificity: Specificity, - TokenStream: TokenStream, - Tokens: Tokens, - ValidationError: ValidationError, - }; -})(); - -(function () { - /* jshint forin:false */ - for (var prop in parserlib) { - exports[prop] = parserlib[prop]; - } -})(); diff --git a/packages/qwik-dom/lib/defineElement.js b/packages/qwik-dom/lib/defineElement.js deleted file mode 100644 index 31265d53233..00000000000 --- a/packages/qwik-dom/lib/defineElement.js +++ /dev/null @@ -1,70 +0,0 @@ -'use strict'; - -var attributes = require('./attributes'); -var isApiWritable = require('./config').isApiWritable; - -module.exports = function (spec, defaultConstructor, tagList, tagNameToImpl) { - var c = spec.ctor; - if (c) { - var props = spec.props || {}; - - if (spec.attributes) { - for (var n in spec.attributes) { - var attr = spec.attributes[n]; - if (typeof attr !== 'object' || Array.isArray(attr)) attr = { type: attr }; - if (!attr.name) attr.name = n.toLowerCase(); - props[n] = attributes.property(attr); - } - } - - props.constructor = { value: c, writable: isApiWritable }; - c.prototype = Object.create((spec.superclass || defaultConstructor).prototype, props); - if (spec.events) { - addEventHandlers(c, spec.events); - } - tagList[spec.name] = c; - } else { - c = defaultConstructor; - } - - (spec.tags || (spec.tag && [spec.tag]) || []).forEach(function (tag) { - tagNameToImpl[tag] = c; - }); - - return c; -}; - -function EventHandlerBuilder(body, document, form, element) { - this.body = body; - this.document = document; - this.form = form; - this.element = element; -} - -EventHandlerBuilder.prototype.build = function () { - return () => {}; -}; - -function EventHandlerChangeHandler(elt, name, oldval, newval) { - var doc = elt.ownerDocument || Object.create(null); - var form = elt.form || Object.create(null); - elt[name] = new EventHandlerBuilder(newval, doc, form, elt).build(); -} - -function addEventHandlers(c, eventHandlerTypes) { - var p = c.prototype; - eventHandlerTypes.forEach(function (type) { - // Define the event handler registration IDL attribute for this type - Object.defineProperty(p, 'on' + type, { - get: function () { - return this._getEventHandler(type); - }, - set: function (v) { - this._setEventHandler(type, v); - }, - }); - - // Define special behavior for the content attribute as well - attributes.registerChangeHandler(c, 'on' + type, EventHandlerChangeHandler); - }); -} diff --git a/packages/qwik-dom/lib/events.js b/packages/qwik-dom/lib/events.js deleted file mode 100644 index a3d41baf954..00000000000 --- a/packages/qwik-dom/lib/events.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; -module.exports = { - Event: require('./Event'), - UIEvent: require('./UIEvent'), - MouseEvent: require('./MouseEvent'), - CustomEvent: require('./CustomEvent'), -}; diff --git a/packages/qwik-dom/lib/htmlelts.js b/packages/qwik-dom/lib/htmlelts.js deleted file mode 100644 index 06734bbf893..00000000000 --- a/packages/qwik-dom/lib/htmlelts.js +++ /dev/null @@ -1,1759 +0,0 @@ -'use strict'; -var Node = require('./Node'); -var Element = require('./Element'); -var CSSStyleDeclaration = require('./CSSStyleDeclaration'); -var utils = require('./utils'); -var URLUtils = require('./URLUtils'); -var defineElement = require('./defineElement'); - -var htmlElements = (exports.elements = {}); -var htmlNameToImpl = Object.create(null); - -exports.createElement = function (doc, localName, prefix) { - var impl = htmlNameToImpl[localName] || HTMLUnknownElement; - return new impl(doc, localName, prefix); -}; - -function define(spec) { - return defineElement(spec, HTMLElement, htmlElements, htmlNameToImpl); -} - -function URL(attr) { - return { - get: function () { - var v = this._getattr(attr); - if (v === null) { - return ''; - } - var url = this.doc._resolve(v); - return url === null ? v : url; - }, - set: function (value) { - this._setattr(attr, value); - }, - }; -} - -function CORS(attr) { - return { - get: function () { - var v = this._getattr(attr); - if (v === null) { - return null; - } - if (v.toLowerCase() === 'use-credentials') { - return 'use-credentials'; - } - return 'anonymous'; - }, - set: function (value) { - if (value === null || value === undefined) { - this.removeAttribute(attr); - } else { - this._setattr(attr, value); - } - }, - }; -} - -var REFERRER = { - type: [ - '', - 'no-referrer', - 'no-referrer-when-downgrade', - 'same-origin', - 'origin', - 'strict-origin', - 'origin-when-cross-origin', - 'strict-origin-when-cross-origin', - 'unsafe-url', - ], - missing: '', -}; - -// XXX: the default value for tabIndex should be 0 if the element is -// focusable and -1 if it is not. But the full definition of focusable -// is actually hard to compute, so for now, I'll follow Firefox and -// just base the default value on the type of the element. -var focusableElements = { - A: true, - LINK: true, - BUTTON: true, - INPUT: true, - SELECT: true, - TEXTAREA: true, - COMMAND: true, -}; - -var HTMLFormElement = function (doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - this._form = null; // Prevent later deoptimization -}; - -var HTMLElement = (exports.HTMLElement = define({ - superclass: Element, - name: 'HTMLElement', - ctor: function HTMLElement(doc, localName, prefix) { - Element.call(this, doc, localName, utils.NAMESPACE.HTML, prefix); - }, - props: { - dangerouslySetInnerHTML: { - set: function (v) { - this._innerHTML = v; - }, - }, - innerHTML: { - get: function () { - return this.serialize(); - }, - set: function (v) { - var parser = this.ownerDocument.implementation.mozHTMLParser( - this.ownerDocument._address, - this - ); - parser.parse(v === null ? '' : String(v), true); - - // Remove any existing children of this node - var target = this instanceof htmlNameToImpl.template ? this.content : this; - while (target.hasChildNodes()) target.removeChild(target.firstChild); - - // Now copy newly parsed children to this node - target.appendChild(parser._asDocumentFragment()); - }, - }, - style: { - get: function () { - if (!this._style) this._style = new CSSStyleDeclaration(this); - return this._style; - }, - set: function (v) { - if (v === null || v === undefined) { - v = ''; - } - this._setattr('style', String(v)); - }, - }, - - // These can't really be implemented server-side in a reasonable way. - blur: { value: function () {} }, - focus: { value: function () {} }, - forceSpellCheck: { value: function () {} }, - - click: { - value: function () { - if (this._click_in_progress) return; - this._click_in_progress = true; - try { - if (this._pre_click_activation_steps) this._pre_click_activation_steps(); - - var event = this.ownerDocument.createEvent('MouseEvent'); - event.initMouseEvent( - 'click', - true, - true, - this.ownerDocument.defaultView, - 1, - 0, - 0, - 0, - 0, - // These 4 should be initialized with - // the actually current keyboard state - // somehow... - false, - false, - false, - false, - 0, - null - ); - - // Dispatch this as an untrusted event since it is synthetic - var success = this.dispatchEvent(event); - - if (success) { - if (this._post_click_activation_steps) this._post_click_activation_steps(event); - } else { - if (this._cancelled_activation_steps) this._cancelled_activation_steps(); - } - } finally { - this._click_in_progress = false; - } - }, - }, - submit: { value: utils.nyi }, - }, - attributes: { - title: String, - lang: String, - dir: { type: ['ltr', 'rtl', 'auto'], missing: '' }, - accessKey: String, - hidden: Boolean, - tabIndex: { - type: 'long', - default: function () { - if (this.tagName in focusableElements || this.contentEditable) return 0; - else return -1; - }, - }, - }, - events: [ - 'abort', - 'canplay', - 'canplaythrough', - 'change', - 'click', - 'contextmenu', - 'cuechange', - 'dblclick', - 'drag', - 'dragend', - 'dragenter', - 'dragleave', - 'dragover', - 'dragstart', - 'drop', - 'durationchange', - 'emptied', - 'ended', - 'input', - 'invalid', - 'keydown', - 'keypress', - 'keyup', - 'loadeddata', - 'loadedmetadata', - 'loadstart', - 'mousedown', - 'mousemove', - 'mouseout', - 'mouseover', - 'mouseup', - 'mousewheel', - 'pause', - 'play', - 'playing', - 'progress', - 'ratechange', - 'readystatechange', - 'reset', - 'seeked', - 'seeking', - 'select', - 'show', - 'stalled', - 'submit', - 'suspend', - 'timeupdate', - 'volumechange', - 'waiting', - - // These last 5 event types will be overriden by HTMLBodyElement - 'blur', - 'error', - 'focus', - 'load', - 'scroll', - ], -})); - -// XXX: reflect contextmenu as contextMenu, with element type - -// style: the spec doesn't call this a reflected attribute. -// may want to handle it manually. - -// contentEditable: enumerated, not clear if it is actually -// reflected or requires custom getter/setter. Not listed as -// "limited to known values". Raises syntax_err on bad setting, -// so I think this is custom. - -// contextmenu: content is element id, idl type is an element -// draggable: boolean, but not a reflected attribute -// dropzone: reflected SettableTokenList, experimental, so don't -// implement it right away. - -// data-* attributes: need special handling in setAttribute? -// Or maybe that isn't necessary. Can I just scan the attribute list -// when building the dataset? Liveness and caching issues? - -// microdata attributes: many are simple reflected attributes, but -// I'm not going to implement this now. - -const HTMLUnknownElement = define({ - name: 'HTMLUnknownElement', - ctor: function HTMLUnknownElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, -}); - -var formAssociatedProps = { - // See http://www.w3.org/TR/html5/association-of-controls-and-forms.html#form-owner - form: { - get: function () { - return this._form; - }, - }, -}; - -define({ - tag: 'a', - name: 'HTMLAnchorElement', - ctor: function HTMLAnchorElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - props: { - _post_click_activation_steps: { - value: function (e) { - if (this.href) { - // Follow the link - // XXX: this is just a quick hack - // XXX: the HTML spec probably requires more than this - this.ownerDocument.defaultView.location = this.href; - } - }, - }, - }, - attributes: { - href: URL, - ping: String, - download: String, - target: String, - rel: String, - media: String, - hreflang: String, - type: String, - referrerPolicy: REFERRER, - // Obsolete - coords: String, - charset: String, - name: String, - rev: String, - shape: String, - }, -}); -// Latest WhatWG spec says these methods come via HTMLHyperlinkElementUtils -URLUtils._inherit(htmlNameToImpl.a.prototype); - -define({ - tag: 'area', - name: 'HTMLAreaElement', - ctor: function HTMLAreaElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - alt: String, - target: String, - download: String, - rel: String, - media: String, - href: URL, - hreflang: String, - type: String, - shape: String, - coords: String, - ping: String, - // XXX: also reflect relList - referrerPolicy: REFERRER, - // Obsolete - noHref: Boolean, - }, -}); -// Latest WhatWG spec says these methods come via HTMLHyperlinkElementUtils -URLUtils._inherit(htmlNameToImpl.area.prototype); - -define({ - tag: 'br', - name: 'HTMLBRElement', - ctor: function HTMLBRElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - // Obsolete - clear: String, - }, -}); - -define({ - tag: 'base', - name: 'HTMLBaseElement', - ctor: function HTMLBaseElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - target: String, - }, -}); - -define({ - tag: 'body', - name: 'HTMLBodyElement', - ctor: function HTMLBodyElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - // Certain event handler attributes on a <body> tag actually set - // handlers for the window rather than just that element. Define - // getters and setters for those here. Note that some of these override - // properties on HTMLElement.prototype. - // XXX: If I add support for <frameset>, these have to go there, too - // XXX - // When the Window object is implemented, these attribute will have - // to work with the same-named attributes on the Window. - events: [ - 'afterprint', - 'beforeprint', - 'beforeunload', - 'blur', - 'error', - 'focus', - 'hashchange', - 'load', - 'message', - 'offline', - 'online', - 'pagehide', - 'pageshow', - 'popstate', - 'resize', - 'scroll', - 'storage', - 'unload', - ], - attributes: { - // Obsolete - text: { type: String, treatNullAsEmptyString: true }, - link: { type: String, treatNullAsEmptyString: true }, - vLink: { type: String, treatNullAsEmptyString: true }, - aLink: { type: String, treatNullAsEmptyString: true }, - bgColor: { type: String, treatNullAsEmptyString: true }, - background: String, - }, -}); - -define({ - tag: 'button', - name: 'HTMLButtonElement', - ctor: function HTMLButtonElement(doc, localName, prefix) { - HTMLFormElement.call(this, doc, localName, prefix); - }, - props: formAssociatedProps, - attributes: { - name: String, - value: String, - disabled: Boolean, - autofocus: Boolean, - type: { type: ['submit', 'reset', 'button', 'menu'], missing: 'submit' }, - formTarget: String, - formNoValidate: Boolean, - formMethod: { type: ['get', 'post', 'dialog'], invalid: 'get', missing: '' }, - formEnctype: { - type: ['application/x-www-form-urlencoded', 'multipart/form-data', 'text/plain'], - invalid: 'application/x-www-form-urlencoded', - missing: '', - }, - }, -}); - -define({ - tag: 'dl', - name: 'HTMLDListElement', - ctor: function HTMLDListElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - // Obsolete - compact: Boolean, - }, -}); - -define({ - tag: 'data', - name: 'HTMLDataElement', - ctor: function HTMLDataElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - value: String, - }, -}); - -define({ - tag: 'datalist', - name: 'HTMLDataListElement', - ctor: function HTMLDataListElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, -}); - -define({ - tag: 'details', - name: 'HTMLDetailsElement', - ctor: function HTMLDetailsElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - open: Boolean, - }, -}); - -define({ - tag: 'div', - name: 'HTMLDivElement', - ctor: function HTMLDivElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - // Obsolete - align: String, - }, -}); - -define({ - tag: 'embed', - name: 'HTMLEmbedElement', - ctor: function HTMLEmbedElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - src: URL, - type: String, - width: String, - height: String, - // Obsolete - align: String, - name: String, - }, -}); - -define({ - tag: 'fieldset', - name: 'HTMLFieldSetElement', - ctor: function HTMLFieldSetElement(doc, localName, prefix) { - HTMLFormElement.call(this, doc, localName, prefix); - }, - props: formAssociatedProps, - attributes: { - disabled: Boolean, - name: String, - }, -}); - -define({ - tag: 'form', - name: 'HTMLFormElement', - ctor: function HTMLFormElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - action: String, - autocomplete: { type: ['on', 'off'], missing: 'on' }, - name: String, - acceptCharset: { name: 'accept-charset' }, - target: String, - noValidate: Boolean, - method: { type: ['get', 'post', 'dialog'], invalid: 'get', missing: 'get' }, - // Both enctype and encoding reflect the enctype content attribute - enctype: { - type: ['application/x-www-form-urlencoded', 'multipart/form-data', 'text/plain'], - invalid: 'application/x-www-form-urlencoded', - missing: 'application/x-www-form-urlencoded', - }, - encoding: { - name: 'enctype', - type: ['application/x-www-form-urlencoded', 'multipart/form-data', 'text/plain'], - invalid: 'application/x-www-form-urlencoded', - missing: 'application/x-www-form-urlencoded', - }, - }, -}); - -define({ - tag: 'hr', - name: 'HTMLHRElement', - ctor: function HTMLHRElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - // Obsolete - align: String, - color: String, - noShade: Boolean, - size: String, - width: String, - }, -}); - -define({ - tag: 'head', - name: 'HTMLHeadElement', - ctor: function HTMLHeadElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, -}); - -define({ - tags: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'], - name: 'HTMLHeadingElement', - ctor: function HTMLHeadingElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - // Obsolete - align: String, - }, -}); - -define({ - tag: 'html', - name: 'HTMLHtmlElement', - ctor: function HTMLHtmlElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - // Obsolete - version: String, - }, -}); - -define({ - tag: 'iframe', - name: 'HTMLIFrameElement', - ctor: function HTMLIFrameElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - src: URL, - srcdoc: String, - name: String, - width: String, - height: String, - // XXX: sandbox is a reflected settable token list - seamless: Boolean, - allowFullscreen: Boolean, - allowUserMedia: Boolean, - allowPaymentRequest: Boolean, - referrerPolicy: REFERRER, - // Obsolete - align: String, - scrolling: String, - frameBorder: String, - longDesc: URL, - marginHeight: { type: String, treatNullAsEmptyString: true }, - marginWidth: { type: String, treatNullAsEmptyString: true }, - }, -}); - -define({ - tag: 'img', - name: 'HTMLImageElement', - ctor: function HTMLImageElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - alt: String, - src: URL, - srcset: String, - crossOrigin: CORS, - useMap: String, - isMap: Boolean, - height: { type: 'unsigned long', default: 0 }, - width: { type: 'unsigned long', default: 0 }, - referrerPolicy: REFERRER, - // Obsolete: - name: String, - lowsrc: URL, - align: String, - hspace: { type: 'unsigned long', default: 0 }, - vspace: { type: 'unsigned long', default: 0 }, - longDesc: URL, - border: { type: String, treatNullAsEmptyString: true }, - }, -}); - -define({ - tag: 'input', - name: 'HTMLInputElement', - ctor: function HTMLInputElement(doc, localName, prefix) { - HTMLFormElement.call(this, doc, localName, prefix); - }, - props: { - form: formAssociatedProps.form, - _post_click_activation_steps: { - value: function (e) { - if (this.type === 'checkbox') { - this.checked = !this.checked; - } else if (this.type === 'radio') { - var group = this.form.getElementsByName(this.name); - for (var i = group.length - 1; i >= 0; i--) { - var el = group[i]; - el.checked = el === this; - } - } - }, - }, - }, - attributes: { - name: String, - disabled: Boolean, - autofocus: Boolean, - accept: String, - alt: String, - max: String, - min: String, - pattern: String, - placeholder: String, - step: String, - dirName: String, - defaultValue: { name: 'value' }, - multiple: Boolean, - required: Boolean, - readOnly: Boolean, - checked: Boolean, - value: String, - src: URL, - defaultChecked: { name: 'checked', type: Boolean }, - size: { type: 'unsigned long', default: 20, min: 1, setmin: 1 }, - width: { type: 'unsigned long', min: 0, setmin: 0, default: 0 }, - height: { type: 'unsigned long', min: 0, setmin: 0, default: 0 }, - minLength: { type: 'unsigned long', min: 0, setmin: 0, default: -1 }, - maxLength: { type: 'unsigned long', min: 0, setmin: 0, default: -1 }, - autocomplete: String, // It's complicated - type: { - type: [ - 'text', - 'hidden', - 'search', - 'tel', - 'url', - 'email', - 'password', - 'datetime', - 'date', - 'month', - 'week', - 'time', - 'datetime-local', - 'number', - 'range', - 'color', - 'checkbox', - 'radio', - 'file', - 'submit', - 'image', - 'reset', - 'button', - ], - missing: 'text', - }, - formTarget: String, - formNoValidate: Boolean, - formMethod: { type: ['get', 'post'], invalid: 'get', missing: '' }, - formEnctype: { - type: ['application/x-www-form-urlencoded', 'multipart/form-data', 'text/plain'], - invalid: 'application/x-www-form-urlencoded', - missing: '', - }, - inputMode: { - type: [ - 'verbatim', - 'latin', - 'latin-name', - 'latin-prose', - 'full-width-latin', - 'kana', - 'kana-name', - 'katakana', - 'numeric', - 'tel', - 'email', - 'url', - ], - missing: '', - }, - // Obsolete - align: String, - useMap: String, - }, -}); - -define({ - tag: 'keygen', - name: 'HTMLKeygenElement', - ctor: function HTMLKeygenElement(doc, localName, prefix) { - HTMLFormElement.call(this, doc, localName, prefix); - }, - props: formAssociatedProps, - attributes: { - name: String, - disabled: Boolean, - autofocus: Boolean, - challenge: String, - keytype: { type: ['rsa'], missing: '' }, - }, -}); - -define({ - tag: 'li', - name: 'HTMLLIElement', - ctor: function HTMLLIElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - value: { type: 'long', default: 0 }, - // Obsolete - type: String, - }, -}); - -define({ - tag: 'label', - name: 'HTMLLabelElement', - ctor: function HTMLLabelElement(doc, localName, prefix) { - HTMLFormElement.call(this, doc, localName, prefix); - }, - props: formAssociatedProps, - attributes: { - htmlFor: { name: 'for', type: String }, - }, -}); - -define({ - tag: 'legend', - name: 'HTMLLegendElement', - ctor: function HTMLLegendElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - // Obsolete - align: String, - }, -}); - -define({ - tag: 'link', - name: 'HTMLLinkElement', - ctor: function HTMLLinkElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - // XXX Reflect DOMSettableTokenList sizes also DOMTokenList relList - href: URL, - rel: String, - media: String, - hreflang: String, - type: String, - crossOrigin: CORS, - nonce: String, - integrity: String, - referrerPolicy: REFERRER, - // Obsolete - charset: String, - rev: String, - target: String, - }, -}); - -define({ - tag: 'map', - name: 'HTMLMapElement', - ctor: function HTMLMapElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - name: String, - }, -}); - -define({ - tag: 'menu', - name: 'HTMLMenuElement', - ctor: function HTMLMenuElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - // XXX: not quite right, default should be popup if parent element is - // popup. - type: { type: ['context', 'popup', 'toolbar'], missing: 'toolbar' }, - label: String, - // Obsolete - compact: Boolean, - }, -}); - -define({ - tag: 'meta', - name: 'HTMLMetaElement', - ctor: function HTMLMetaElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - name: String, - content: String, - httpEquiv: { name: 'http-equiv', type: String }, - // Obsolete - scheme: String, - }, -}); - -define({ - tag: 'meter', - name: 'HTMLMeterElement', - ctor: function HTMLMeterElement(doc, localName, prefix) { - HTMLFormElement.call(this, doc, localName, prefix); - }, - props: formAssociatedProps, -}); - -define({ - tags: ['ins', 'del'], - name: 'HTMLModElement', - ctor: function HTMLModElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - cite: URL, - dateTime: String, - }, -}); - -define({ - tag: 'ol', - name: 'HTMLOListElement', - ctor: function HTMLOListElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - props: { - // Utility function (see the start attribute default value). Returns - // the number of <li> children of this element - _numitems: { - get: function () { - var items = 0; - this.childNodes.forEach(function (n) { - if (n.nodeType === Node.ELEMENT_NODE && n.tagName === 'LI') items++; - }); - return items; - }, - }, - }, - attributes: { - type: String, - reversed: Boolean, - start: { - type: 'long', - default: function () { - // The default value of the start attribute is 1 unless the list is - // reversed. Then it is the # of li children - if (this.reversed) return this._numitems; - else return 1; - }, - }, - // Obsolete - compact: Boolean, - }, -}); - -define({ - tag: 'object', - name: 'HTMLObjectElement', - ctor: function HTMLObjectElement(doc, localName, prefix) { - HTMLFormElement.call(this, doc, localName, prefix); - }, - props: formAssociatedProps, - attributes: { - data: URL, - type: String, - name: String, - useMap: String, - typeMustMatch: Boolean, - width: String, - height: String, - // Obsolete - align: String, - archive: String, - code: String, - declare: Boolean, - hspace: { type: 'unsigned long', default: 0 }, - standby: String, - vspace: { type: 'unsigned long', default: 0 }, - codeBase: URL, - codeType: String, - border: { type: String, treatNullAsEmptyString: true }, - }, -}); - -define({ - tag: 'optgroup', - name: 'HTMLOptGroupElement', - ctor: function HTMLOptGroupElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - disabled: Boolean, - label: String, - }, -}); - -define({ - tag: 'option', - name: 'HTMLOptionElement', - ctor: function HTMLOptionElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - props: { - form: { - get: function () { - var p = this.parentNode; - while (p && p.nodeType === Node.ELEMENT_NODE) { - if (p.localName === 'select') return p.form; - p = p.parentNode; - } - }, - }, - value: { - get: function () { - return this._getattr('value') || this.text; - }, - set: function (v) { - this._setattr('value', v); - }, - }, - text: { - get: function () { - // Strip and collapse whitespace - return this.textContent.replace(/[ \t\n\f\r]+/g, ' ').trim(); - }, - set: function (v) { - this.textContent = v; - }, - }, - // missing: index - }, - attributes: { - disabled: Boolean, - defaultSelected: { name: 'selected', type: Boolean }, - label: String, - }, -}); - -define({ - tag: 'output', - name: 'HTMLOutputElement', - ctor: function HTMLOutputElement(doc, localName, prefix) { - HTMLFormElement.call(this, doc, localName, prefix); - }, - props: formAssociatedProps, - attributes: { - // XXX Reflect for/htmlFor as a settable token list - name: String, - }, -}); - -define({ - tag: 'p', - name: 'HTMLParagraphElement', - ctor: function HTMLParagraphElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - // Obsolete - align: String, - }, -}); - -define({ - tag: 'param', - name: 'HTMLParamElement', - ctor: function HTMLParamElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - name: String, - value: String, - // Obsolete - type: String, - valueType: String, - }, -}); - -define({ - tags: ['pre', /*legacy elements:*/ 'listing', 'xmp'], - name: 'HTMLPreElement', - ctor: function HTMLPreElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - // Obsolete - width: { type: 'long', default: 0 }, - }, -}); - -define({ - tag: 'progress', - name: 'HTMLProgressElement', - ctor: function HTMLProgressElement(doc, localName, prefix) { - HTMLFormElement.call(this, doc, localName, prefix); - }, - props: formAssociatedProps, - attributes: { - max: { type: Number, float: true, default: 1.0, min: 0 }, - }, -}); - -define({ - tags: ['q', 'blockquote'], - name: 'HTMLQuoteElement', - ctor: function HTMLQuoteElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - cite: URL, - }, -}); - -define({ - tag: 'script', - name: 'HTMLScriptElement', - ctor: function HTMLScriptElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - props: { - text: { - get: function () { - var s = ''; - for (var i = 0, n = this.childNodes.length; i < n; i++) { - var child = this.childNodes[i]; - if (child.nodeType === Node.TEXT_NODE) s += child._data; - } - return s; - }, - set: function (value) { - this.removeChildren(); - if (value !== null && value !== '') { - this.appendChild(this.ownerDocument.createTextNode(value)); - } - }, - }, - }, - attributes: { - src: URL, - type: String, - charset: String, - defer: Boolean, - async: Boolean, - crossOrigin: CORS, - nonce: String, - integrity: String, - }, -}); - -define({ - tag: 'select', - name: 'HTMLSelectElement', - ctor: function HTMLSelectElement(doc, localName, prefix) { - HTMLFormElement.call(this, doc, localName, prefix); - }, - props: { - form: formAssociatedProps.form, - options: { - get: function () { - return this.getElementsByTagName('option'); - }, - }, - }, - attributes: { - autocomplete: String, // It's complicated - name: String, - disabled: Boolean, - autofocus: Boolean, - multiple: Boolean, - required: Boolean, - size: { type: 'unsigned long', default: 0 }, - }, -}); - -define({ - tag: 'source', - name: 'HTMLSourceElement', - ctor: function HTMLSourceElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - src: URL, - type: String, - media: String, - }, -}); - -define({ - tag: 'span', - name: 'HTMLSpanElement', - ctor: function HTMLSpanElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, -}); - -define({ - tag: 'style', - name: 'HTMLStyleElement', - ctor: function HTMLStyleElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - media: String, - type: String, - scoped: Boolean, - }, -}); - -define({ - tag: 'caption', - name: 'HTMLTableCaptionElement', - ctor: function HTMLTableCaptionElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - // Obsolete - align: String, - }, -}); - -define({ - name: 'HTMLTableCellElement', - ctor: function HTMLTableCellElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - colSpan: { type: 'unsigned long', default: 1 }, - rowSpan: { type: 'unsigned long', default: 1 }, - //XXX Also reflect settable token list headers - scope: { type: ['row', 'col', 'rowgroup', 'colgroup'], missing: '' }, - abbr: String, - // Obsolete - align: String, - axis: String, - height: String, - width: String, - ch: { name: 'char', type: String }, - chOff: { name: 'charoff', type: String }, - noWrap: Boolean, - vAlign: String, - bgColor: { type: String, treatNullAsEmptyString: true }, - }, -}); - -define({ - tags: ['col', 'colgroup'], - name: 'HTMLTableColElement', - ctor: function HTMLTableColElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - span: { type: 'limited unsigned long with fallback', default: 1, min: 1 }, - // Obsolete - align: String, - ch: { name: 'char', type: String }, - chOff: { name: 'charoff', type: String }, - vAlign: String, - width: String, - }, -}); - -define({ - tag: 'table', - name: 'HTMLTableElement', - ctor: function HTMLTableElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - props: { - rows: { - get: function () { - return this.getElementsByTagName('tr'); - }, - }, - }, - attributes: { - // Obsolete - align: String, - border: String, - frame: String, - rules: String, - summary: String, - width: String, - bgColor: { type: String, treatNullAsEmptyString: true }, - cellPadding: { type: String, treatNullAsEmptyString: true }, - cellSpacing: { type: String, treatNullAsEmptyString: true }, - }, -}); - -define({ - tag: 'template', - name: 'HTMLTemplateElement', - ctor: function HTMLTemplateElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - this._contentFragment = doc._templateDoc.createDocumentFragment(); - }, - props: { - content: { - get: function () { - return this._contentFragment; - }, - }, - serialize: { - value: function () { - return this.content.serialize(); - }, - }, - }, -}); - -define({ - tag: 'tr', - name: 'HTMLTableRowElement', - ctor: function HTMLTableRowElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - props: { - cells: { - get: function () { - return this.querySelectorAll('td,th'); - }, - }, - }, - attributes: { - // Obsolete - align: String, - ch: { name: 'char', type: String }, - chOff: { name: 'charoff', type: String }, - vAlign: String, - bgColor: { type: String, treatNullAsEmptyString: true }, - }, -}); - -define({ - tags: ['thead', 'tfoot', 'tbody'], - name: 'HTMLTableSectionElement', - ctor: function HTMLTableSectionElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - props: { - rows: { - get: function () { - return this.getElementsByTagName('tr'); - }, - }, - }, - attributes: { - // Obsolete - align: String, - ch: { name: 'char', type: String }, - chOff: { name: 'charoff', type: String }, - vAlign: String, - }, -}); - -define({ - tag: 'textarea', - name: 'HTMLTextAreaElement', - ctor: function HTMLTextAreaElement(doc, localName, prefix) { - HTMLFormElement.call(this, doc, localName, prefix); - }, - props: { - form: formAssociatedProps.form, - type: { - get: function () { - return 'textarea'; - }, - }, - defaultValue: { - get: function () { - return this.textContent; - }, - set: function (v) { - this.textContent = v; - }, - }, - value: { - get: function () { - return this.defaultValue; /* never dirty */ - }, - set: function (v) { - // This isn't completely correct: according to the spec, this - // should "dirty" the API value, and result in - // `this.value !== this.defaultValue`. But for most of what - // folks want to do, this implementation should be fine: - this.defaultValue = v; - }, - }, - textLength: { - get: function () { - return this.value.length; - }, - }, - }, - attributes: { - autocomplete: String, // It's complicated - name: String, - disabled: Boolean, - autofocus: Boolean, - placeholder: String, - wrap: String, - dirName: String, - required: Boolean, - readOnly: Boolean, - rows: { type: 'limited unsigned long with fallback', default: 2 }, - cols: { type: 'limited unsigned long with fallback', default: 20 }, - maxLength: { type: 'unsigned long', min: 0, setmin: 0, default: -1 }, - minLength: { type: 'unsigned long', min: 0, setmin: 0, default: -1 }, - inputMode: { - type: [ - 'verbatim', - 'latin', - 'latin-name', - 'latin-prose', - 'full-width-latin', - 'kana', - 'kana-name', - 'katakana', - 'numeric', - 'tel', - 'email', - 'url', - ], - missing: '', - }, - }, -}); - -define({ - tag: 'time', - name: 'HTMLTimeElement', - ctor: function HTMLTimeElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - dateTime: String, - pubDate: Boolean, - }, -}); - -define({ - tag: 'title', - name: 'HTMLTitleElement', - ctor: function HTMLTitleElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - props: { - text: { - get: function () { - return this.textContent; - }, - }, - }, -}); - -define({ - tag: 'ul', - name: 'HTMLUListElement', - ctor: function HTMLUListElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - type: String, - // Obsolete - compact: Boolean, - }, -}); - -define({ - name: 'HTMLMediaElement', - ctor: function HTMLMediaElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - src: URL, - crossOrigin: CORS, - preload: { type: ['metadata', 'none', 'auto', { value: '', alias: 'auto' }], missing: 'auto' }, - loop: Boolean, - autoplay: Boolean, - mediaGroup: String, - controls: Boolean, - defaultMuted: { name: 'muted', type: Boolean }, - }, -}); - -define({ - tag: 'audio', - superclass: htmlElements.HTMLMediaElement, - name: 'HTMLAudioElement', - ctor: function HTMLAudioElement(doc, localName, prefix) { - htmlElements.HTMLMediaElement.call(this, doc, localName, prefix); - }, -}); - -define({ - tag: 'video', - superclass: htmlElements.HTMLMediaElement, - name: 'HTMLVideoElement', - ctor: function HTMLVideoElement(doc, localName, prefix) { - htmlElements.HTMLMediaElement.call(this, doc, localName, prefix); - }, - attributes: { - poster: URL, - width: { type: 'unsigned long', min: 0, default: 0 }, - height: { type: 'unsigned long', min: 0, default: 0 }, - }, -}); - -define({ - tag: 'td', - superclass: htmlElements.HTMLTableCellElement, - name: 'HTMLTableDataCellElement', - ctor: function HTMLTableDataCellElement(doc, localName, prefix) { - htmlElements.HTMLTableCellElement.call(this, doc, localName, prefix); - }, -}); - -define({ - tag: 'th', - superclass: htmlElements.HTMLTableCellElement, - name: 'HTMLTableHeaderCellElement', - ctor: function HTMLTableHeaderCellElement(doc, localName, prefix) { - htmlElements.HTMLTableCellElement.call(this, doc, localName, prefix); - }, -}); - -define({ - tag: 'frameset', - name: 'HTMLFrameSetElement', - ctor: function HTMLFrameSetElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, -}); - -define({ - tag: 'frame', - name: 'HTMLFrameElement', - ctor: function HTMLFrameElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, -}); - -define({ - tag: 'canvas', - name: 'HTMLCanvasElement', - ctor: function HTMLCanvasElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - props: { - getContext: { value: utils.nyi }, - probablySupportsContext: { value: utils.nyi }, - setContext: { value: utils.nyi }, - transferControlToProxy: { value: utils.nyi }, - toDataURL: { value: utils.nyi }, - toBlob: { value: utils.nyi }, - }, - attributes: { - width: { type: 'unsigned long', default: 300 }, - height: { type: 'unsigned long', default: 150 }, - }, -}); - -define({ - tag: 'dialog', - name: 'HTMLDialogElement', - ctor: function HTMLDialogElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - props: { - show: { value: utils.nyi }, - showModal: { value: utils.nyi }, - close: { value: utils.nyi }, - }, - attributes: { - open: Boolean, - returnValue: String, - }, -}); - -define({ - tag: 'menuitem', - name: 'HTMLMenuItemElement', - ctor: function HTMLMenuItemElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - props: { - // The menuitem's label - _label: { - get: function () { - var val = this._getattr('label'); - if (val !== null && val !== '') { - return val; - } - val = this.textContent; - // Strip and collapse whitespace - return val.replace(/[ \t\n\f\r]+/g, ' ').trim(); - }, - }, - // The menuitem label IDL attribute - label: { - get: function () { - var val = this._getattr('label'); - if (val !== null) { - return val; - } - return this._label; - }, - set: function (v) { - this._setattr('label', v); - }, - }, - }, - attributes: { - type: { type: ['command', 'checkbox', 'radio'], missing: 'command' }, - icon: URL, - disabled: Boolean, - checked: Boolean, - radiogroup: String, - default: Boolean, - }, -}); - -define({ - tag: 'source', - name: 'HTMLSourceElement', - ctor: function HTMLSourceElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - srcset: String, - sizes: String, - media: String, - src: URL, - type: String, - }, -}); - -define({ - tag: 'track', - name: 'HTMLTrackElement', - ctor: function HTMLTrackElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - src: URL, - srclang: String, - label: String, - default: Boolean, - kind: { - type: ['subtitles', 'captions', 'descriptions', 'chapters', 'metadata'], - missing: 'subtitles', - invalid: 'metadata', - }, - }, - props: { - NONE: { - get: function () { - return 0; - }, - }, - LOADING: { - get: function () { - return 1; - }, - }, - LOADED: { - get: function () { - return 2; - }, - }, - ERROR: { - get: function () { - return 3; - }, - }, - readyState: { get: utils.nyi }, - track: { get: utils.nyi }, - }, -}); - -define({ - // obsolete - tag: 'font', - name: 'HTMLFontElement', - ctor: function HTMLFontElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - color: { type: String, treatNullAsEmptyString: true }, - face: { type: String }, - size: { type: String }, - }, -}); - -define({ - // obsolete - tag: 'dir', - name: 'HTMLDirectoryElement', - ctor: function HTMLDirectoryElement(doc, localName, prefix) { - HTMLElement.call(this, doc, localName, prefix); - }, - attributes: { - compact: Boolean, - }, -}); - -define({ - tags: [ - 'abbr', - 'address', - 'article', - 'aside', - 'b', - 'bdi', - 'bdo', - 'cite', - 'code', - 'dd', - 'dfn', - 'dt', - 'em', - 'figcaption', - 'figure', - 'footer', - 'header', - 'hgroup', - 'i', - 'kbd', - 'main', - 'mark', - 'nav', - 'noscript', - 'rb', - 'rp', - 'rt', - 'rtc', - 'ruby', - 's', - 'samp', - 'section', - 'small', - 'strong', - 'sub', - 'summary', - 'sup', - 'u', - 'var', - 'wbr', - // Legacy elements - 'acronym', - 'basefont', - 'big', - 'center', - 'nobr', - 'noembed', - 'noframes', - 'plaintext', - 'strike', - 'tt', - ], -}); diff --git a/packages/qwik-dom/lib/impl.js b/packages/qwik-dom/lib/impl.js deleted file mode 100644 index 6fd0e0a5673..00000000000 --- a/packages/qwik-dom/lib/impl.js +++ /dev/null @@ -1,27 +0,0 @@ -'use strict'; -var utils = require('./utils'); - -exports = module.exports = { - CSSStyleDeclaration: require('./CSSStyleDeclaration'), - CharacterData: require('./CharacterData'), - Comment: require('./Comment'), - DOMException: require('./DOMException'), - DOMImplementation: require('./DOMImplementation'), - DOMTokenList: require('./DOMTokenList'), - Document: require('./Document'), - DocumentFragment: require('./DocumentFragment'), - DocumentType: require('./DocumentType'), - Element: require('./Element'), - HTMLParser: require('./HTMLParser'), - NamedNodeMap: require('./NamedNodeMap'), - Node: require('./Node'), - NodeList: require('./NodeList'), - NodeFilter: require('./NodeFilter'), - ProcessingInstruction: require('./ProcessingInstruction'), - Text: require('./Text'), - Window: require('./Window'), -}; - -utils.merge(exports, require('./events')); -utils.merge(exports, require('./htmlelts').elements); -utils.merge(exports, require('./svg').elements); diff --git a/packages/qwik-dom/lib/index.d.ts b/packages/qwik-dom/lib/index.d.ts deleted file mode 100644 index 23a6d40f3b1..00000000000 --- a/packages/qwik-dom/lib/index.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare module '@qwik.dev/dom' { - function createDOMImplementation(): DOMImplementation; - function createDocument(html?: string, force?: boolean): Document; -} diff --git a/packages/qwik-dom/lib/index.js b/packages/qwik-dom/lib/index.js deleted file mode 100644 index 767c4c05b1a..00000000000 --- a/packages/qwik-dom/lib/index.js +++ /dev/null @@ -1,77 +0,0 @@ -'use strict'; -var DOMImplementation = require('./DOMImplementation'); -var HTMLParser = require('./HTMLParser'); -var Window = require('./Window'); - -exports.createDOMImplementation = function () { - return new DOMImplementation(null); -}; - -exports.createDocument = function (html, force) { - // Previous API couldn't let you pass '' as a document, and that - // yields a slightly different document than createHTMLDocument('') - // does. The new `force` parameter lets you pass '' if you want to. - if (html || force) { - var parser = new HTMLParser(); - parser.parse(html || '', true); - return parser.document(); - } - return new DOMImplementation(null).createHTMLDocument(''); -}; - -exports.createIncrementalHTMLParser = function () { - var parser = new HTMLParser(); - /** API for incremental parser. */ - return { - /** Provide an additional chunk of text to be parsed. */ - write: function (s) { - if (s.length > 0) { - parser.parse(s, false, function () { - return true; - }); - } - }, - /** - * Signal that we are done providing input text, optionally - * providing one last chunk as a parameter. - */ - end: function (s) { - parser.parse(s || '', true, function () { - return true; - }); - }, - /** - * Performs a chunk of parsing work, returning at the end of - * the next token as soon as shouldPauseFunc() returns true. - * Returns true iff there is more work to do. - * - * For example: - * ``` - * var incrParser = domino.createIncrementalHTMLParser(); - * incrParser.end('...long html document...'); - * while (true) { - * // Pause every 10ms - * var start = Date.now(); - * var pauseIn10 = function() { return (Date.now() - start) >= 10; }; - * if (!incrParser.process(pauseIn10)) { - * break; - * } - * ...yield to other tasks, do other housekeeping, etc... - * } - * ``` - */ - process: function (shouldPauseFunc) { - return parser.parse('', false, shouldPauseFunc); - }, - /** - * Returns the result of the incremental parse. Valid after - * `this.end()` has been called and `this.process()` has returned - * false. - */ - document: function () { - return parser.document(); - }, - }; -}; - -exports.impl = require('./impl'); diff --git a/packages/qwik-dom/lib/select.js b/packages/qwik-dom/lib/select.js deleted file mode 100644 index ef5d6417fbb..00000000000 --- a/packages/qwik-dom/lib/select.js +++ /dev/null @@ -1,937 +0,0 @@ -'use strict'; -/* jshint eqnull: true */ -/** - * Zest (https://github.com/chjj/zest) - * A css selector engine. - * Copyright (c) 2011-2012, Christopher Jeffrey. (MIT Licensed) - * Domino version based on Zest v0.1.3 with bugfixes applied. - */ - -/** - * Helpers - */ - -var window = Object.create(null, { - location: { - get: function () { - throw new Error('window.location is not supported.'); - }, - }, -}); - -var compareDocumentPosition = function (a, b) { - return a.compareDocumentPosition(b); -}; - -var order = function (a, b) { - /* jshint bitwise: false */ - return compareDocumentPosition(a, b) & 2 ? 1 : -1; -}; - -var next = function (el) { - while ((el = el.nextSibling) && el.nodeType !== 1); - return el; -}; - -var prev = function (el) { - while ((el = el.previousSibling) && el.nodeType !== 1); - return el; -}; - -var child = function (el) { - /*jshint -W084 */ - if ((el = el.firstChild)) { - while (el.nodeType !== 1 && (el = el.nextSibling)); - } - return el; -}; - -var lastChild = function (el) { - /*jshint -W084 */ - if ((el = el.lastChild)) { - while (el.nodeType !== 1 && (el = el.previousSibling)); - } - return el; -}; - -var parentIsElement = function (n) { - if (!n.parentNode) { - return false; - } - var nodeType = n.parentNode.nodeType; - // The root `html` element can be a first- or last-child, too. - return nodeType === 1 || nodeType === 9; -}; - -var unquote = function (str) { - if (!str) return str; - var ch = str[0]; - if (ch === '"' || ch === "'") { - if (str[str.length - 1] === ch) { - str = str.slice(1, -1); - } else { - // bad string. - str = str.slice(1); - } - return str.replace(rules.str_escape, function (s) { - var m = /^\\(?:([0-9A-Fa-f]+)|([\r\n\f]+))/.exec(s); - if (!m) { - return s.slice(1); - } - if (m[2]) { - return ''; /* escaped newlines are ignored in strings. */ - } - var cp = parseInt(m[1], 16); - return String.fromCodePoint - ? String.fromCodePoint(cp) - : // Not all JavaScript implementations have String.fromCodePoint yet. - String.fromCharCode(cp); - }); - } else if (rules.ident.test(str)) { - return decodeid(str); - } else { - // NUMBER, PERCENTAGE, DIMENSION, etc - return str; - } -}; - -var decodeid = function (str) { - return str.replace(rules.escape, function (s) { - var m = /^\\([0-9A-Fa-f]+)/.exec(s); - if (!m) { - return s[1]; - } - var cp = parseInt(m[1], 16); - return String.fromCodePoint - ? String.fromCodePoint(cp) - : // Not all JavaScript implementations have String.fromCodePoint yet. - String.fromCharCode(cp); - }); -}; - -var indexOf = (function () { - if (Array.prototype.indexOf) { - return Array.prototype.indexOf; - } - return function (obj, item) { - var i = this.length; - while (i--) { - if (this[i] === item) return i; - } - return -1; - }; -})(); - -var makeInside = function (start, end) { - var regex = rules.inside.source.replace(/</g, start).replace(/>/g, end); - - return new RegExp(regex); -}; - -var replace = function (regex, name, val) { - regex = regex.source; - regex = regex.replace(name, val.source || val); - return new RegExp(regex); -}; - -var truncateUrl = function (url, num) { - return url - .replace(/^(?:\w+:\/\/|\/+)/, '') - .replace(/(?:\/+|\/*#.*?)$/, '') - .split('/', num) - .join('/'); -}; - -/** - * Handle `nth` Selectors - */ - -var parseNth = function (param_, test) { - var param = param_.replace(/\s+/g, ''), - cap; - - if (param === 'even') { - param = '2n+0'; - } else if (param === 'odd') { - param = '2n+1'; - } else if (param.indexOf('n') === -1) { - param = '0n' + param; - } - - cap = /^([+-])?(\d+)?n([+-])?(\d+)?$/.exec(param); - - return { - group: cap[1] === '-' ? -(cap[2] || 1) : +(cap[2] || 1), - offset: cap[4] ? (cap[3] === '-' ? -cap[4] : +cap[4]) : 0, - }; -}; - -var nth = function (param_, test, last) { - var param = parseNth(param_), - group = param.group, - offset = param.offset, - find = !last ? child : lastChild, - advance = !last ? next : prev; - - return function (el) { - if (!parentIsElement(el)) return; - - var rel = find(el.parentNode), - pos = 0; - - while (rel) { - if (test(rel, el)) pos++; - if (rel === el) { - pos -= offset; - return group && pos ? pos % group === 0 && pos < 0 === group < 0 : !pos; - } - rel = advance(rel); - } - }; -}; - -/** - * Simple Selectors - */ - -var selectors = { - '*': (function () { - if ( - false /*function() { - var el = document.createElement('div'); - el.appendChild(document.createComment('')); - return !!el.getElementsByTagName('*')[0]; - }()*/ - ) { - return function (el) { - if (el.nodeType === 1) return true; - }; - } - return function () { - return true; - }; - })(), - type: function (type) { - type = type.toLowerCase(); - return function (el) { - return el.nodeName.toLowerCase() === type; - }; - }, - attr: function (key, op, val, i) { - op = operators[op]; - return function (el) { - var attr; - switch (key) { - case 'for': - attr = el.htmlFor; - break; - case 'class': - // className is '' when non-existent - // getAttribute('class') is null - attr = el.className; - if (attr === '' && el.getAttribute('class') == null) { - attr = null; - } - break; - case 'href': - case 'src': - attr = el.getAttribute(key, 2); - break; - case 'title': - // getAttribute('title') can be '' when non-existent sometimes? - attr = el.getAttribute('title') || null; - break; - // careful with attributes with special getter functions - case 'id': - case 'lang': - case 'dir': - case 'accessKey': - case 'hidden': - case 'tabIndex': - case 'style': - if (el.getAttribute) { - attr = el.getAttribute(key); - break; - } - /* falls through */ - default: - if (el.hasAttribute && !el.hasAttribute(key)) { - break; - } - attr = el[key] != null ? el[key] : el.getAttribute && el.getAttribute(key); - break; - } - if (attr == null) return; - attr = attr + ''; - if (i) { - attr = attr.toLowerCase(); - val = val.toLowerCase(); - } - return op(attr, val); - }; - }, - ':first-child': function (el) { - return !prev(el) && parentIsElement(el); - }, - ':last-child': function (el) { - return !next(el) && parentIsElement(el); - }, - ':only-child': function (el) { - return !prev(el) && !next(el) && parentIsElement(el); - }, - ':nth-child': function (param, last) { - return nth( - param, - function () { - return true; - }, - last - ); - }, - ':nth-last-child': function (param) { - return selectors[':nth-child'](param, true); - }, - ':root': function (el) { - return el.ownerDocument.documentElement === el; - }, - ':empty': function (el) { - return !el.firstChild; - }, - ':not': function (sel) { - var test = compileGroup(sel); - return function (el) { - return !test(el); - }; - }, - ':first-of-type': function (el) { - if (!parentIsElement(el)) return; - var type = el.nodeName; - /*jshint -W084 */ - while ((el = prev(el))) { - if (el.nodeName === type) return; - } - return true; - }, - ':last-of-type': function (el) { - if (!parentIsElement(el)) return; - var type = el.nodeName; - /*jshint -W084 */ - while ((el = next(el))) { - if (el.nodeName === type) return; - } - return true; - }, - ':only-of-type': function (el) { - return selectors[':first-of-type'](el) && selectors[':last-of-type'](el); - }, - ':nth-of-type': function (param, last) { - return nth( - param, - function (rel, el) { - return rel.nodeName === el.nodeName; - }, - last - ); - }, - ':nth-last-of-type': function (param) { - return selectors[':nth-of-type'](param, true); - }, - ':checked': function (el) { - return !!(el.checked || el.selected); - }, - ':indeterminate': function (el) { - return !selectors[':checked'](el); - }, - ':enabled': function (el) { - return !el.disabled && el.type !== 'hidden'; - }, - ':disabled': function (el) { - return !!el.disabled; - }, - ':target': function (el) { - return el.id === window.location.hash.substring(1); - }, - ':focus': function (el) { - return el === el.ownerDocument.activeElement; - }, - ':is': function (sel) { - return compileGroup(sel); - }, - // :matches is an older name for :is; see - // https://github.com/w3c/csswg-drafts/issues/3258 - ':matches': function (sel) { - return selectors[':is'](sel); - }, - ':nth-match': function (param, last) { - var args = param.split(/\s*,\s*/), - arg = args.shift(), - test = compileGroup(args.join(',')); - - return nth(arg, test, last); - }, - ':nth-last-match': function (param) { - return selectors[':nth-match'](param, true); - }, - ':links-here': function (el) { - return el + '' === window.location + ''; - }, - ':lang': function (param) { - return function (el) { - while (el) { - if (el.lang) return el.lang.indexOf(param) === 0; - el = el.parentNode; - } - }; - }, - ':dir': function (param) { - return function (el) { - while (el) { - if (el.dir) return el.dir === param; - el = el.parentNode; - } - }; - }, - ':scope': function (el, con) { - var context = con || el.ownerDocument; - if (context.nodeType === 9) { - return el === context.documentElement; - } - return el === context; - }, - ':any-link': function (el) { - return typeof el.href === 'string'; - }, - ':local-link': function (el) { - if (el.nodeName) { - return el.href && el.host === window.location.host; - } - var param = +el + 1; - return function (el) { - if (!el.href) return; - - var url = window.location + '', - href = el + ''; - - return truncateUrl(url, param) === truncateUrl(href, param); - }; - }, - ':default': function (el) { - return !!el.defaultSelected; - }, - ':valid': function (el) { - return el.willValidate || (el.validity && el.validity.valid); - }, - ':invalid': function (el) { - return !selectors[':valid'](el); - }, - ':in-range': function (el) { - return el.value > el.min && el.value <= el.max; - }, - ':out-of-range': function (el) { - return !selectors[':in-range'](el); - }, - ':required': function (el) { - return !!el.required; - }, - ':optional': function (el) { - return !el.required; - }, - ':read-only': function (el) { - if (el.readOnly) return true; - - var attr = el.getAttribute('contenteditable'), - prop = el.contentEditable, - name = el.nodeName.toLowerCase(); - - name = name !== 'input' && name !== 'textarea'; - - return (name || el.disabled) && attr == null && prop !== 'true'; - }, - ':read-write': function (el) { - return !selectors[':read-only'](el); - }, - ':hover': function () { - throw new Error(':hover is not supported.'); - }, - ':active': function () { - throw new Error(':active is not supported.'); - }, - ':link': function () { - throw new Error(':link is not supported.'); - }, - ':visited': function () { - throw new Error(':visited is not supported.'); - }, - ':column': function () { - throw new Error(':column is not supported.'); - }, - ':nth-column': function () { - throw new Error(':nth-column is not supported.'); - }, - ':nth-last-column': function () { - throw new Error(':nth-last-column is not supported.'); - }, - ':current': function () { - throw new Error(':current is not supported.'); - }, - ':past': function () { - throw new Error(':past is not supported.'); - }, - ':future': function () { - throw new Error(':future is not supported.'); - }, - // Non-standard, for compatibility purposes. - ':contains': function (param) { - return function (el) { - var text = el.innerText || el.textContent || el.value || ''; - return text.indexOf(param) !== -1; - }; - }, - ':has': function (param) { - return function (el) { - return find(param, el).length > 0; - }; - }, - // Potentially add more pseudo selectors for - // compatibility with sizzle and most other - // selector engines (?). -}; - -/** - * Attribute Operators - */ - -var operators = { - '-': function () { - return true; - }, - '=': function (attr, val) { - return attr === val; - }, - '*=': function (attr, val) { - return attr.indexOf(val) !== -1; - }, - '~=': function (attr, val) { - var i, s, f, l; - - for (s = 0; true; s = i + 1) { - i = attr.indexOf(val, s); - if (i === -1) return false; - f = attr[i - 1]; - l = attr[i + val.length]; - if ((!f || f === ' ') && (!l || l === ' ')) return true; - } - }, - '|=': function (attr, val) { - var i = attr.indexOf(val), - l; - - if (i !== 0) return; - l = attr[i + val.length]; - - return l === '-' || !l; - }, - '^=': function (attr, val) { - return attr.indexOf(val) === 0; - }, - '$=': function (attr, val) { - var i = attr.lastIndexOf(val); - return i !== -1 && i + val.length === attr.length; - }, - // non-standard - '!=': function (attr, val) { - return attr !== val; - }, -}; - -/** - * Combinator Logic - */ - -var combinators = { - ' ': function (test) { - return function (el) { - /*jshint -W084 */ - while ((el = el.parentNode)) { - if (test(el)) return el; - } - }; - }, - '>': function (test) { - return function (el) { - /*jshint -W084 */ - if ((el = el.parentNode)) { - return test(el) && el; - } - }; - }, - '+': function (test) { - return function (el) { - /*jshint -W084 */ - if ((el = prev(el))) { - return test(el) && el; - } - }; - }, - '~': function (test) { - return function (el) { - /*jshint -W084 */ - while ((el = prev(el))) { - if (test(el)) return el; - } - }; - }, - noop: function (test) { - return function (el) { - return test(el) && el; - }; - }, - ref: function (test, name) { - var node; - - function ref(el) { - var doc = el.ownerDocument, - nodes = doc.getElementsByTagName('*'), - i = nodes.length; - - while (i--) { - node = nodes[i]; - if (ref.test(el)) { - node = null; - return true; - } - } - - node = null; - } - - ref.combinator = function (el) { - if (!node || !node.getAttribute) return; - - var attr = node.getAttribute(name) || ''; - if (attr[0] === '#') attr = attr.substring(1); - - if (attr === el.id && test(node)) { - return node; - } - }; - - return ref; - }, -}; - -/** - * Grammar - */ - -var rules = { - escape: /\\(?:[^0-9A-Fa-f\r\n]|[0-9A-Fa-f]{1,6}[\r\n\t ]?)/g, - str_escape: /(escape)|\\(\n|\r\n?|\f)/g, - nonascii: /[\u00A0-\uFFFF]/, - cssid: /(?:(?!-?[0-9])(?:escape|nonascii|[-_a-zA-Z0-9])+)/, - qname: /^ *(cssid|\*)/, - simple: /^(?:([.#]cssid)|pseudo|attr)/, - ref: /^ *\/(cssid)\/ */, - combinator: /^(?: +([^ \w*.#\\]) +|( )+|([^ \w*.#\\]))(?! *$)/, - attr: /^\[(cssid)(?:([^\w]?=)(inside))?\]/, - pseudo: /^(:cssid)(?:\((inside)\))?/, - inside: /(?:"(?:\\"|[^"])*"|'(?:\\'|[^'])*'|<[^"'>]*>|\\["'>]|[^"'>])*/, - ident: /^(cssid)$/, -}; - -rules.cssid = replace(rules.cssid, 'nonascii', rules.nonascii); -rules.cssid = replace(rules.cssid, 'escape', rules.escape); -rules.qname = replace(rules.qname, 'cssid', rules.cssid); -rules.simple = replace(rules.simple, 'cssid', rules.cssid); -rules.ref = replace(rules.ref, 'cssid', rules.cssid); -rules.attr = replace(rules.attr, 'cssid', rules.cssid); -rules.pseudo = replace(rules.pseudo, 'cssid', rules.cssid); -rules.inside = replace(rules.inside, '[^"\'>]*', rules.inside); -rules.attr = replace(rules.attr, 'inside', makeInside('\\[', '\\]')); -rules.pseudo = replace(rules.pseudo, 'inside', makeInside('\\(', '\\)')); -rules.simple = replace(rules.simple, 'pseudo', rules.pseudo); -rules.simple = replace(rules.simple, 'attr', rules.attr); -rules.ident = replace(rules.ident, 'cssid', rules.cssid); -rules.str_escape = replace(rules.str_escape, 'escape', rules.escape); - -/** - * Compiling - */ - -var compile = function (sel_) { - var sel = sel_.replace(/^\s+|\s+$/g, ''), - test, - filter = [], - buff = [], - subject, - qname, - cap, - op, - ref; - - /*jshint -W084 */ - while (sel) { - if ((cap = rules.qname.exec(sel))) { - sel = sel.substring(cap[0].length); - qname = decodeid(cap[1]); - buff.push(tok(qname, true)); - } else if ((cap = rules.simple.exec(sel))) { - sel = sel.substring(cap[0].length); - qname = '*'; - buff.push(tok(qname, true)); - buff.push(tok(cap)); - } else { - throw new SyntaxError('Invalid selector.'); - } - - while ((cap = rules.simple.exec(sel))) { - sel = sel.substring(cap[0].length); - buff.push(tok(cap)); - } - - if (sel[0] === '!') { - sel = sel.substring(1); - subject = makeSubject(); - subject.qname = qname; - buff.push(subject.simple); - } - - if ((cap = rules.ref.exec(sel))) { - sel = sel.substring(cap[0].length); - ref = combinators.ref(makeSimple(buff), decodeid(cap[1])); - filter.push(ref.combinator); - buff = []; - continue; - } - - if ((cap = rules.combinator.exec(sel))) { - sel = sel.substring(cap[0].length); - op = cap[1] || cap[2] || cap[3]; - if (op === ',') { - filter.push(combinators.noop(makeSimple(buff))); - break; - } - } else { - op = 'noop'; - } - - if (!combinators[op]) { - throw new SyntaxError('Bad combinator.'); - } - filter.push(combinators[op](makeSimple(buff))); - buff = []; - } - - test = makeTest(filter); - test.qname = qname; - test.sel = sel; - - if (subject) { - subject.lname = test.qname; - - subject.test = test; - subject.qname = subject.qname; - subject.sel = test.sel; - test = subject; - } - - if (ref) { - ref.test = test; - ref.qname = test.qname; - ref.sel = test.sel; - test = ref; - } - - return test; -}; - -var tok = function (cap, qname) { - // qname - if (qname) { - return cap === '*' ? selectors['*'] : selectors.type(cap); - } - - // class/id - if (cap[1]) { - return cap[1][0] === '.' - ? // XXX unescape here? or in attr? - selectors.attr('class', '~=', decodeid(cap[1].substring(1)), false) - : selectors.attr('id', '=', decodeid(cap[1].substring(1)), false); - } - - // pseudo-name - // inside-pseudo - if (cap[2]) { - return cap[3] ? selectors[decodeid(cap[2])](unquote(cap[3])) : selectors[decodeid(cap[2])]; - } - - // attr name - // attr op - // attr value - if (cap[4]) { - var value = cap[6]; - var i = /["'\s]\s*I$/i.test(value); - if (i) { - value = value.replace(/\s*I$/i, ''); - } - return selectors.attr(decodeid(cap[4]), cap[5] || '-', unquote(value), i); - } - - throw new SyntaxError('Unknown Selector.'); -}; - -var makeSimple = function (func) { - var l = func.length, - i; - - // Potentially make sure - // `el` is truthy. - if (l < 2) return func[0]; - - return function (el) { - if (!el) return; - for (i = 0; i < l; i++) { - if (!func[i](el)) return; - } - return true; - }; -}; - -var makeTest = function (func) { - if (func.length < 2) { - return function (el) { - return !!func[0](el); - }; - } - return function (el) { - var i = func.length; - while (i--) { - if (!(el = func[i](el))) return; - } - return true; - }; -}; - -var makeSubject = function () { - var target; - - function subject(el) { - var node = el.ownerDocument, - scope = node.getElementsByTagName(subject.lname), - i = scope.length; - - while (i--) { - if (subject.test(scope[i]) && target === el) { - target = null; - return true; - } - } - - target = null; - } - - subject.simple = function (el) { - target = el; - return true; - }; - - return subject; -}; - -var compileGroup = function (sel) { - var test = compile(sel), - tests = [test]; - - while (test.sel) { - test = compile(test.sel); - tests.push(test); - } - - if (tests.length < 2) return test; - - return function (el) { - var l = tests.length, - i = 0; - - for (; i < l; i++) { - if (tests[i](el)) return true; - } - }; -}; - -/** - * Selection - */ - -var find = function (sel, node) { - var results = [], - test = compile(sel), - scope = node.getElementsByTagName(test.qname), - i = 0, - el; - - /*jshint -W084 */ - while ((el = scope[i++])) { - if (test(el)) results.push(el); - } - - if (test.sel) { - while (test.sel) { - test = compile(test.sel); - scope = node.getElementsByTagName(test.qname); - i = 0; - /*jshint -W084 */ - while ((el = scope[i++])) { - if (test(el) && indexOf.call(results, el) === -1) { - results.push(el); - } - } - } - results.sort(order); - } - - return results; -}; - -/** - * Expose - */ - -module.exports = exports = function (sel, context) { - /* when context isn't a DocumentFragment and the selector is simple: */ - var id, r; - if (context.nodeType !== 11 && sel.indexOf(' ') === -1) { - if (sel[0] === '#' && context.rooted && /^#[A-Z_][-A-Z0-9_]*$/i.test(sel)) { - if (context.doc._hasMultipleElementsWithId) { - id = sel.substring(1); - if (!context.doc._hasMultipleElementsWithId(id)) { - r = context.doc.getElementById(id); - return r ? [r] : []; - } - } - } - if (sel[0] === '.' && /^\.\w+$/.test(sel)) { - return context.getElementsByClassName(sel.substring(1)); - } - if (/^\w+$/.test(sel)) { - return context.getElementsByTagName(sel); - } - } - /* do things the hard/slow way */ - return find(sel, context); -}; - -exports.selectors = selectors; -exports.operators = operators; -exports.combinators = combinators; - -exports.matches = function (el, sel) { - var test = { sel: sel }; - do { - test = compile(test.sel); - if (test(el)) { - return true; - } - } while (test.sel); - return false; -}; diff --git a/packages/qwik-dom/lib/sloppy.js b/packages/qwik-dom/lib/sloppy.js deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/packages/qwik-dom/lib/svg.js b/packages/qwik-dom/lib/svg.js deleted file mode 100644 index 7d48ed67ec6..00000000000 --- a/packages/qwik-dom/lib/svg.js +++ /dev/null @@ -1,132 +0,0 @@ -'use strict'; -var Element = require('./Element'); -var defineElement = require('./defineElement'); -var utils = require('./utils'); -var CSSStyleDeclaration = require('./CSSStyleDeclaration'); - -var svgElements = (exports.elements = {}); -var svgNameToImpl = Object.create(null); - -exports.createElement = function (doc, localName, prefix) { - var impl = svgNameToImpl[localName] || SVGElement; - return new impl(doc, localName, prefix); -}; - -function define(spec) { - return defineElement(spec, SVGElement, svgElements, svgNameToImpl); -} - -var SVGElement = define({ - superclass: Element, - name: 'SVGElement', - ctor: function SVGElement(doc, localName, prefix) { - Element.call(this, doc, localName, utils.NAMESPACE.SVG, prefix); - }, - props: { - style: { - get: function () { - if (!this._style) this._style = new CSSStyleDeclaration(this); - return this._style; - }, - }, - }, -}); - -define({ - name: 'SVGSVGElement', - ctor: function SVGSVGElement(doc, localName, prefix) { - SVGElement.call(this, doc, localName, prefix); - }, - tag: 'svg', - props: { - createSVGRect: { - value: function () { - return exports.createElement(this.ownerDocument, 'rect', null); - }, - }, - }, -}); - -define({ - tags: [ - 'a', - 'altGlyph', - 'altGlyphDef', - 'altGlyphItem', - 'animate', - 'animateColor', - 'animateMotion', - 'animateTransform', - 'circle', - 'clipPath', - 'color-profile', - 'cursor', - 'defs', - 'desc', - 'ellipse', - 'feBlend', - 'feColorMatrix', - 'feComponentTransfer', - 'feComposite', - 'feConvolveMatrix', - 'feDiffuseLighting', - 'feDisplacementMap', - 'feDistantLight', - 'feFlood', - 'feFuncA', - 'feFuncB', - 'feFuncG', - 'feFuncR', - 'feGaussianBlur', - 'feImage', - 'feMerge', - 'feMergeNode', - 'feMorphology', - 'feOffset', - 'fePointLight', - 'feSpecularLighting', - 'feSpotLight', - 'feTile', - 'feTurbulence', - 'filter', - 'font', - 'font-face', - 'font-face-format', - 'font-face-name', - 'font-face-src', - 'font-face-uri', - 'foreignObject', - 'g', - 'glyph', - 'glyphRef', - 'hkern', - 'image', - 'line', - 'linearGradient', - 'marker', - 'mask', - 'metadata', - 'missing-glyph', - 'mpath', - 'path', - 'pattern', - 'polygon', - 'polyline', - 'radialGradient', - 'rect', - 'script', - 'set', - 'stop', - 'style', - 'switch', - 'symbol', - 'text', - 'textPath', - 'title', - 'tref', - 'tspan', - 'use', - 'view', - 'vkern', - ], -}); diff --git a/packages/qwik-dom/lib/utils.js b/packages/qwik-dom/lib/utils.js deleted file mode 100644 index 84acc6e27e5..00000000000 --- a/packages/qwik-dom/lib/utils.js +++ /dev/null @@ -1,131 +0,0 @@ -'use strict'; -var DOMException = require('./DOMException'); -var ERR = DOMException; -var isApiWritable = require('./config').isApiWritable; - -exports.NAMESPACE = { - HTML: 'http://www.w3.org/1999/xhtml', - XML: 'http://www.w3.org/XML/1998/namespace', - XMLNS: 'http://www.w3.org/2000/xmlns/', - MATHML: 'http://www.w3.org/1998/Math/MathML', - SVG: 'http://www.w3.org/2000/svg', - XLINK: 'http://www.w3.org/1999/xlink', -}; - -// -// Shortcut functions for throwing errors of various types. -// -exports.IndexSizeError = function () { - throw new DOMException(ERR.INDEX_SIZE_ERR); -}; -exports.HierarchyRequestError = function () { - throw new DOMException(ERR.HIERARCHY_REQUEST_ERR); -}; -exports.WrongDocumentError = function () { - throw new DOMException(ERR.WRONG_DOCUMENT_ERR); -}; -exports.InvalidCharacterError = function () { - throw new DOMException(ERR.INVALID_CHARACTER_ERR); -}; -exports.NoModificationAllowedError = function () { - throw new DOMException(ERR.NO_MODIFICATION_ALLOWED_ERR); -}; -exports.NotFoundError = function () { - throw new DOMException(ERR.NOT_FOUND_ERR); -}; -exports.NotSupportedError = function () { - throw new DOMException(ERR.NOT_SUPPORTED_ERR); -}; -exports.InvalidStateError = function () { - throw new DOMException(ERR.INVALID_STATE_ERR); -}; -exports.SyntaxError = function () { - throw new DOMException(ERR.SYNTAX_ERR); -}; -exports.InvalidModificationError = function () { - throw new DOMException(ERR.INVALID_MODIFICATION_ERR); -}; -exports.NamespaceError = function () { - throw new DOMException(ERR.NAMESPACE_ERR); -}; -exports.InvalidAccessError = function () { - throw new DOMException(ERR.INVALID_ACCESS_ERR); -}; -exports.TypeMismatchError = function () { - throw new DOMException(ERR.TYPE_MISMATCH_ERR); -}; -exports.SecurityError = function () { - throw new DOMException(ERR.SECURITY_ERR); -}; -exports.NetworkError = function () { - throw new DOMException(ERR.NETWORK_ERR); -}; -exports.AbortError = function () { - throw new DOMException(ERR.ABORT_ERR); -}; -exports.UrlMismatchError = function () { - throw new DOMException(ERR.URL_MISMATCH_ERR); -}; -exports.QuotaExceededError = function () { - throw new DOMException(ERR.QUOTA_EXCEEDED_ERR); -}; -exports.TimeoutError = function () { - throw new DOMException(ERR.TIMEOUT_ERR); -}; -exports.InvalidNodeTypeError = function () { - throw new DOMException(ERR.INVALID_NODE_TYPE_ERR); -}; -exports.DataCloneError = function () { - throw new DOMException(ERR.DATA_CLONE_ERR); -}; - -exports.nyi = function () { - throw new Error('NotYetImplemented'); -}; - -exports.shouldOverride = function () { - throw new Error('Abstract function; should be overriding in subclass.'); -}; - -exports.assert = function (expr, msg) { - if (!expr) { - throw new Error('Assertion failed: ' + (msg || '') + '\n' + new Error().stack); - } -}; - -exports.expose = function (src, c) { - for (var n in src) { - Object.defineProperty(c.prototype, n, { value: src[n], writable: isApiWritable }); - } -}; - -exports.merge = function (a, b) { - for (var n in b) { - a[n] = b[n]; - } -}; - -exports.escapeText = function (str) { - return str; -}; - -// Compare two nodes based on their document order. This function is intended -// to be passed to sort(). Assumes that the array being sorted does not -// contain duplicates. And that all nodes are connected and comparable. -// Clever code by ppk via jeresig. -exports.documentOrder = function (n, m) { - /* jshint bitwise: false */ - return 3 - (n.compareDocumentPosition(m) & 6); -}; - -exports.toASCIILowerCase = function (s) { - return s.replace(/[A-Z]+/g, function (c) { - return c.toLowerCase(); - }); -}; - -exports.toASCIIUpperCase = function (s) { - return s.replace(/[a-z]+/g, function (c) { - return c.toUpperCase(); - }); -}; diff --git a/packages/qwik-dom/lib/xmlnames.js b/packages/qwik-dom/lib/xmlnames.js deleted file mode 100644 index dbd5fc0fe5f..00000000000 --- a/packages/qwik-dom/lib/xmlnames.js +++ /dev/null @@ -1,95 +0,0 @@ -'use strict'; -// This grammar is from the XML and XML Namespace specs. It specifies whether -// a string (such as an element or attribute name) is a valid Name or QName. -// -// Name ::= NameStartChar (NameChar)* -// NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | -// [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | -// [#x370-#x37D] | [#x37F-#x1FFF] | -// [#x200C-#x200D] | [#x2070-#x218F] | -// [#x2C00-#x2FEF] | [#x3001-#xD7FF] | -// [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | -// [#x10000-#xEFFFF] -// -// NameChar ::= NameStartChar | "-" | "." | [0-9] | -// #xB7 | [#x0300-#x036F] | [#x203F-#x2040] -// -// QName ::= PrefixedName| UnprefixedName -// PrefixedName ::= Prefix ':' LocalPart -// UnprefixedName ::= LocalPart -// Prefix ::= NCName -// LocalPart ::= NCName -// NCName ::= Name - (Char* ':' Char*) -// # An XML Name, minus the ":" -// - -exports.isValidName = isValidName; -exports.isValidQName = isValidQName; - -// Most names will be ASCII only. Try matching against simple regexps first -var simplename = /^[_:A-Za-z][-.:\w]+$/; -var simpleqname = /^([_A-Za-z][-.\w]+|[_A-Za-z][-.\w]+:[_A-Za-z][-.\w]+)$/; - -// If the regular expressions above fail, try more complex ones that work -// for any identifiers using codepoints from the Unicode BMP -var ncnamestartchars = - '_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02ff\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD'; -var ncnamechars = - '-._A-Za-z0-9\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02ff\u0300-\u037D\u037F-\u1FFF\u200C\u200D\u203f\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD'; - -var ncname = '[' + ncnamestartchars + '][' + ncnamechars + ']*'; -var namestartchars = ncnamestartchars + ':'; -var namechars = ncnamechars + ':'; -var name = new RegExp('^[' + namestartchars + ']' + '[' + namechars + ']*$'); -var qname = new RegExp('^(' + ncname + '|' + ncname + ':' + ncname + ')$'); - -// XML says that these characters are also legal: -// [#x10000-#xEFFFF]. So if the patterns above fail, and the -// target string includes surrogates, then try the following -// patterns that allow surrogates and then run an extra validation -// step to make sure that the surrogates are in valid pairs and in -// the right range. Note that since the characters \uf0000 to \u1f0000 -// are not allowed, it means that the high surrogate can only go up to -// \uDB7f instead of \uDBFF. -var hassurrogates = /[\uD800-\uDB7F\uDC00-\uDFFF]/; -var surrogatechars = /[\uD800-\uDB7F\uDC00-\uDFFF]/g; -var surrogatepairs = /[\uD800-\uDB7F][\uDC00-\uDFFF]/g; - -// Modify the variables above to allow surrogates -ncnamestartchars += '\uD800-\uDB7F\uDC00-\uDFFF'; -ncnamechars += '\uD800-\uDB7F\uDC00-\uDFFF'; -ncname = '[' + ncnamestartchars + '][' + ncnamechars + ']*'; -namestartchars = ncnamestartchars + ':'; -namechars = ncnamechars + ':'; - -// Build another set of regexps that include surrogates -var surrogatename = new RegExp('^[' + namestartchars + ']' + '[' + namechars + ']*$'); -var surrogateqname = new RegExp('^(' + ncname + '|' + ncname + ':' + ncname + ')$'); - -function isValidName(s) { - if (simplename.test(s)) return true; // Plain ASCII - if (name.test(s)) return true; // Unicode BMP - - // Maybe the tests above failed because s includes surrogate pairs - // Most likely, though, they failed for some more basic syntax problem - if (!hassurrogates.test(s)) return false; - - // Is the string a valid name if we allow surrogates? - if (!surrogatename.test(s)) return false; - - // Finally, are the surrogates all correctly paired up? - var chars = s.match(surrogatechars), - pairs = s.match(surrogatepairs); - return pairs !== null && 2 * pairs.length === chars.length; -} - -function isValidQName(s) { - if (simpleqname.test(s)) return true; // Plain ASCII - if (qname.test(s)) return true; // Unicode BMP - - if (!hassurrogates.test(s)) return false; - if (!surrogateqname.test(s)) return false; - var chars = s.match(surrogatechars), - pairs = s.match(surrogatepairs); - return pairs !== null && 2 * pairs.length === chars.length; -} diff --git a/packages/qwik-dom/package.json b/packages/qwik-dom/package.json deleted file mode 100644 index 211381ab6d4..00000000000 --- a/packages/qwik-dom/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "@qwik.dev/dom", - "description": "Server-side DOM implementation based on Mozilla's dom.js", - "version": "2.1.19", - "author": "Felix Gnass <fgnass@gmail.com>", - "files": [ - "CHANGELOG.md", - "LICENSE", - "README.md", - "lib" - ], - "homepage": "https://github.com/fgnass/domino", - "license": "BSD-2-Clause", - "main": "./lib", - "repository": "fgnass/domino.git", - "publishConfig": { - "access": "public" - }, - "types": "lib/index.d.ts" -} diff --git a/packages/qwik/package.json b/packages/qwik/package.json index 29abdb24823..9970a128cdd 100644 --- a/packages/qwik/package.json +++ b/packages/qwik/package.json @@ -11,9 +11,10 @@ "csstype": "^3.1" }, "devDependencies": { + "@types/jsdom": "^21.1.7", "@qwik.dev/core": "workspace:*", - "@qwik.dev/dom": "workspace:*", "image-size": "1.1.1", + "jsdom": "^25.0.1", "kleur": "4.1.5", "ignore": "5.3.1", "prettier": "3.3.3", @@ -170,16 +171,20 @@ "license": "MIT", "main": "./src/index.ts", "peerDependencies": { + "jsdom": "*", "prettier": "*", "vite": "^5", "vitest": "^2" }, "peerDependenciesMeta": { - "vitest": { + "jsdom": { "optional": true }, "prettier": { "optional": true + }, + "vitest": { + "optional": true } }, "publishConfig": { diff --git a/packages/qwik/src/core/client/dom-container.ts b/packages/qwik/src/core/client/dom-container.ts index 1d7d88339f0..cf87c8459d5 100644 --- a/packages/qwik/src/core/client/dom-container.ts +++ b/packages/qwik/src/core/client/dom-container.ts @@ -53,8 +53,6 @@ import { } from './types'; import { VNodeJournalOpCode, - mapArray_get, - mapArray_set, vnode_applyJournal, vnode_getDOMChildNodes, vnode_getDomParent, @@ -69,6 +67,7 @@ import { vnode_setProp, type VNodeJournal, } from './vnode'; +import { mapArray_get, mapArray_set } from './mapArray'; import { vnode_diff } from './vnode-diff'; /** @public */ diff --git a/packages/qwik/src/core/client/mapArray.ts b/packages/qwik/src/core/client/mapArray.ts new file mode 100644 index 00000000000..9fb36c5ad31 --- /dev/null +++ b/packages/qwik/src/core/client/mapArray.ts @@ -0,0 +1,70 @@ +import { assertTrue } from '../shared/error/assert'; + +export const mapApp_findIndx = <T>( + elementVNode: (T | null)[], + key: string, + start: number +): number => { + assertTrue(start % 2 === 0, 'Expecting even number.'); + let bottom = (start as number) >> 1; + let top = (elementVNode.length - 2) >> 1; + while (bottom <= top) { + const mid = bottom + ((top - bottom) >> 1); + const midKey = elementVNode[mid << 1] as string; + if (midKey === key) { + return mid << 1; + } + if (midKey < key) { + bottom = mid + 1; + } else { + top = mid - 1; + } + } + return (bottom << 1) ^ -1; +}; + +export const mapArray_set = <T>( + elementVNode: (T | null)[], + key: string, + value: T | null, + start: number +) => { + const indx = mapApp_findIndx(elementVNode, key, start); + if (indx >= 0) { + if (value == null) { + elementVNode.splice(indx, 2); + } else { + elementVNode[indx + 1] = value; + } + } else if (value != null) { + elementVNode.splice(indx ^ -1, 0, key as any, value); + } +}; + +export const mapApp_remove = <T>( + elementVNode: (T | null)[], + key: string, + start: number +): T | null => { + const indx = mapApp_findIndx(elementVNode, key, start); + let value: T | null = null; + if (indx >= 0) { + value = elementVNode[indx + 1]; + elementVNode.splice(indx, 2); + return value; + } + return value; +}; + +export const mapArray_get = <T>( + elementVNode: (T | null)[], + key: string, + start: number +): T | null => { + const indx = mapApp_findIndx(elementVNode, key, start); + if (indx >= 0) { + return elementVNode[indx + 1] as T | null; + } else { + return null; + } +}; diff --git a/packages/qwik/src/core/client/vnode-diff.ts b/packages/qwik/src/core/client/vnode-diff.ts index ad9799b5087..2eadc0a416b 100644 --- a/packages/qwik/src/core/client/vnode-diff.ts +++ b/packages/qwik/src/core/client/vnode-diff.ts @@ -1,8 +1,7 @@ import { isDev } from '@qwik.dev/core/build'; +import { executeComponent } from '../shared/component-execution'; import { SERIALIZABLE_STATE, type OnRenderFn } from '../shared/component.public'; import { assertDefined, assertFalse, assertTrue } from '../shared/error/assert'; -import type { QRLInternal } from '../shared/qrl/qrl-class'; -import type { QRL } from '../shared/qrl/qrl.public'; import { Fragment, JSXNodeImpl, @@ -14,9 +13,21 @@ import { Slot } from '../shared/jsx/slot.public'; import type { JSXNodeInternal, JSXOutput } from '../shared/jsx/types/jsx-node'; import type { JSXChildren } from '../shared/jsx/types/jsx-qwik-attributes'; import { SSRComment, SSRRaw, SkipRender } from '../shared/jsx/utils.public'; -import { trackSignal, untrack } from '../use/use-core'; -import { TaskFlags, cleanupTask, isTask } from '../use/use-task'; +import type { QRLInternal } from '../shared/qrl/qrl-class'; +import type { QRL } from '../shared/qrl/qrl.public'; +import { ChoreType, type NodePropData } from '../shared/scheduler'; +import type { HostElement, QElement, QwikLoaderEventScope, qWindow } from '../shared/types'; +import { DEBUG_TYPE, QContainerValue, VirtualType } from '../shared/types'; +import { escapeHTML } from '../shared/utils/character-escaping'; +import { + convertEventNameFromJsxPropToHtmlAttr, + getEventNameFromJsxProp, + getEventNameScopeFromJsxProp, + isHtmlAttributeAnEventName, + isJsxPropertyAnEventName, +} from '../shared/utils/event-names'; import { EMPTY_OBJ } from '../shared/utils/flyweight'; +import { throwErrorAndStop } from '../shared/utils/log'; import { ELEMENT_KEY, ELEMENT_PROPS, @@ -31,19 +42,20 @@ import { dangerouslySetInnerHTML, } from '../shared/utils/markers'; import { isPromise } from '../shared/utils/promises'; +import { isParentSlotProp, isSlotProp } from '../shared/utils/prop'; +import { hasClassAttr } from '../shared/utils/scoped-styles'; +import { serializeAttribute } from '../shared/utils/styles'; import { type ValueOrPromise } from '../shared/utils/types'; +import { EffectData, EffectProperty, WrappedSignal, isSignal } from '../signal/signal'; import { - convertEventNameFromJsxPropToHtmlAttr, - getEventNameFromJsxProp, - getEventNameScopeFromJsxProp, - isHtmlAttributeAnEventName, - isJsxPropertyAnEventName, -} from '../shared/utils/event-names'; -import { ChoreType, type NodePropData } from '../shared/scheduler'; -import { hasClassAttr } from '../shared/utils/scoped-styles'; -import type { HostElement, QElement, QwikLoaderEventScope, qWindow } from '../shared/types'; -import { DEBUG_TYPE, QContainerValue, VirtualType } from '../shared/types'; + clearSubscriberEffectDependencies, + clearVNodeEffectDependencies, +} from '../signal/signal-subscriber'; +import type { Signal } from '../signal/signal.public'; +import { trackSignal, untrack } from '../use/use-core'; +import { TaskFlags, cleanupTask, isTask } from '../use/use-task'; import type { DomContainer } from './dom-container'; +import { mapApp_findIndx, mapArray_set } from './mapArray'; import { ElementVNodeProps, VNodeFlags, @@ -58,8 +70,6 @@ import { type VirtualVNode, } from './types'; import { - mapApp_findIndx, - mapArray_set, vnode_ensureElementInflated, vnode_getAttr, vnode_getDomParentVNode, @@ -91,17 +101,6 @@ import { type VNodeJournal, } from './vnode'; import { getNewElementNamespaceData } from './vnode-namespace'; -import { WrappedSignal, EffectProperty, isSignal, EffectData } from '../signal/signal'; -import type { Signal } from '../signal/signal.public'; -import { executeComponent } from '../shared/component-execution'; -import { isParentSlotProp, isSlotProp } from '../shared/utils/prop'; -import { escapeHTML } from '../shared/utils/character-escaping'; -import { - clearSubscriberEffectDependencies, - clearVNodeEffectDependencies, -} from '../signal/signal-subscriber'; -import { throwErrorAndStop } from '../shared/utils/log'; -import { serializeAttribute } from '../shared/utils/styles'; export type ComponentQueue = Array<VNode>; diff --git a/packages/qwik/src/core/client/vnode-diff.unit.tsx b/packages/qwik/src/core/client/vnode-diff.unit.tsx index 41db2647f37..eeb0d2add33 100644 --- a/packages/qwik/src/core/client/vnode-diff.unit.tsx +++ b/packages/qwik/src/core/client/vnode-diff.unit.tsx @@ -418,7 +418,7 @@ describe('vNode-diff', () => { <b>new</b> </test> ); - const bOriginal = document.querySelector('b[key=1]')!; + const bOriginal = document.querySelector('b[key="1"]')!; vnode_diff( { $journal$: journal, $scheduler$: scheduler, document } as any, test, @@ -447,13 +447,13 @@ describe('vNode-diff', () => { <b>after</b> </test> ); - const b1 = document.querySelector('b[key=1]')!; - const b2 = document.querySelector('b[key=1]')!; + const b1 = document.querySelector('b[key="1"]')!; + const b2 = document.querySelector('b[key="1"]')!; vnode_diff({ $journal$: journal, document } as any, test, vParent, null); vnode_applyJournal(journal); expect(vNode).toMatchVDOM(test); - expect(b1).toBe(document.querySelector('b[key=1]')!); - expect(b2).toBe(document.querySelector('b[key=2]')!); + expect(b1).toBe(document.querySelector('b[key="1"]')!); + expect(b2).toBe(document.querySelector('b[key="2"]')!); }); }); describe.todo('fragments', () => {}); diff --git a/packages/qwik/src/core/client/vnode.ts b/packages/qwik/src/core/client/vnode.ts index 52eaaa4b069..1c10c1f0fcb 100644 --- a/packages/qwik/src/core/client/vnode.ts +++ b/packages/qwik/src/core/client/vnode.ts @@ -169,6 +169,7 @@ import { vnode_getElementNamespaceFlags, } from './vnode-namespace'; import { escapeHTML } from '../shared/utils/character-escaping'; +import { mapArray_set, mapArray_get, mapApp_findIndx } from './mapArray'; ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -940,77 +941,6 @@ export const vnode_applyJournal = (journal: VNodeJournal) => { ////////////////////////////////////////////////////////////////////////////////////////////////////// -export const mapApp_findIndx = <T>( - elementVNode: (T | null)[], - key: string, - start: number -): number => { - assertTrue(start % 2 === 0, 'Expecting even number.'); - let bottom = (start as number) >> 1; - let top = (elementVNode.length - 2) >> 1; - while (bottom <= top) { - const mid = bottom + ((top - bottom) >> 1); - const midKey = elementVNode[mid << 1] as string; - if (midKey === key) { - return mid << 1; - } - if (midKey < key) { - bottom = mid + 1; - } else { - top = mid - 1; - } - } - return (bottom << 1) ^ -1; -}; - -export const mapArray_set = <T>( - elementVNode: (T | null)[], - key: string, - value: T | null, - start: number -) => { - const indx = mapApp_findIndx(elementVNode, key, start); - if (indx >= 0) { - if (value == null) { - elementVNode.splice(indx, 2); - } else { - elementVNode[indx + 1] = value; - } - } else if (value != null) { - elementVNode.splice(indx ^ -1, 0, key as any, value); - } -}; - -export const mapApp_remove = <T>( - elementVNode: (T | null)[], - key: string, - start: number -): T | null => { - const indx = mapApp_findIndx(elementVNode, key, start); - let value: T | null = null; - if (indx >= 0) { - value = elementVNode[indx + 1]; - elementVNode.splice(indx, 2); - return value; - } - return value; -}; - -export const mapArray_get = <T>( - elementVNode: (T | null)[], - key: string, - start: number -): T | null => { - const indx = mapApp_findIndx(elementVNode, key, start); - if (indx >= 0) { - return elementVNode[indx + 1] as T | null; - } else { - return null; - } -}; - -////////////////////////////////////////////////////////////////////////////////////////////////////// - export const vnode_insertBefore = ( journal: VNodeJournal, parent: ElementVNode | VirtualVNode, diff --git a/packages/qwik/src/core/shared/component-execution.ts b/packages/qwik/src/core/shared/component-execution.ts index ca53bf3a1ec..606d37d46ea 100644 --- a/packages/qwik/src/core/shared/component-execution.ts +++ b/packages/qwik/src/core/shared/component-execution.ts @@ -1,7 +1,7 @@ import { isDev } from '@qwik.dev/core/build'; import { isQwikComponent, type OnRenderFn } from './component.public'; import { assertDefined } from './error/assert'; -import { isQrl, type QRLInternal } from './qrl/qrl-class'; +import type { QRLInternal } from './qrl/qrl-class'; import { JSXNodeImpl, isJSXNode, type Props } from './jsx/jsx-runtime'; import type { JSXNodeInternal, JSXOutput } from './jsx/types/jsx-node'; import type { KnownEventNames } from './jsx/types/jsx-qwik-events'; @@ -23,6 +23,7 @@ import { logWarn } from './utils/log'; import { EffectProperty, isSignal } from '../signal/signal'; import { vnode_isVNode } from '../client/vnode'; import { clearVNodeEffectDependencies } from '../signal/signal-subscriber'; +import { isQrl } from './qrl/qrl-utils'; /** * Use `executeComponent` to execute a component. diff --git a/packages/qwik/src/core/shared/component.public.ts b/packages/qwik/src/core/shared/component.public.ts index c96d7677c33..e60697f6c59 100644 --- a/packages/qwik/src/core/shared/component.public.ts +++ b/packages/qwik/src/core/shared/component.public.ts @@ -9,7 +9,7 @@ import type { import type { FunctionComponent } from './jsx/types/jsx-node'; import { _CONST_PROPS, _VAR_PROPS, _jsxSorted, _jsxSplit } from '../internal'; import type { QwikIntrinsicElements } from './jsx/types/jsx-qwik-elements'; -import { assertQrl } from './qrl/qrl-class'; +import { assertQrl } from './qrl/qrl-utils'; import { assertNumber } from './error/assert'; import { qTest } from './utils/qdev'; diff --git a/packages/qwik/src/core/shared/platform/platform.ts b/packages/qwik/src/core/shared/platform/platform.ts index afa9730b3ea..15314b4d304 100644 --- a/packages/qwik/src/core/shared/platform/platform.ts +++ b/packages/qwik/src/core/shared/platform/platform.ts @@ -1,6 +1,6 @@ import { isServer } from '@qwik.dev/core/build'; import { qError, QError_qrlMissingChunk, QError_qrlMissingContainer } from '../error/error'; -import { getSymbolHash } from '../qrl/qrl-class'; +import { getSymbolHash } from '../qrl/qrl-utils'; import { qDynamicPlatform } from '../utils/qdev'; import type { CorePlatform } from './types'; diff --git a/packages/qwik/src/core/shared/qrl/qrl-class.ts b/packages/qwik/src/core/shared/qrl/qrl-class.ts index e4e41403b7d..2000292ee37 100644 --- a/packages/qwik/src/core/shared/qrl/qrl-class.ts +++ b/packages/qwik/src/core/shared/qrl/qrl-class.ts @@ -15,17 +15,9 @@ import { getQFuncs, QInstanceAttr } from '../utils/markers'; import { isPromise, maybeThen } from '../utils/promises'; import { qDev, qSerialize, qTest, seal } from '../utils/qdev'; import { isArray, isFunction, type ValueOrPromise } from '../utils/types'; -import { isSignal } from '../../signal/signal'; import type { QRLDev } from './qrl'; import type { QRL, QrlArgs, QrlReturn } from './qrl.public'; -import type { Signal } from '../../signal/signal.public'; - -export const isQrl = <T = unknown>(value: unknown): value is QRLInternal<T> => { - return typeof value === 'function' && typeof (value as any).getSymbol === 'function'; -}; - -// Make sure this value is same as value in `platform.ts` -export const SYNC_QRL = '<sync>'; +import { getSymbolHash, SYNC_QRL } from './qrl-utils'; interface SyncQRLSymbol { $symbol$: typeof SYNC_QRL; @@ -33,11 +25,6 @@ interface SyncQRLSymbol { export type SyncQRLInternal = QRLInternal & SyncQRLSymbol; -/** Sync QRL is a function which is serialized into `<script q:func="qwik/json">` tag. */ -export const isSyncQrl = (value: any): value is SyncQRLInternal => { - return isQrl(value) && value.$symbol$ == SYNC_QRL; -}; - export type QRLInternalMethods<TYPE> = { readonly $chunk$: string | null; readonly $symbol$: string; @@ -239,30 +226,6 @@ export const createQRL = <TYPE>( return qrl; }; -export const getSymbolHash = (symbolName: string) => { - const index = symbolName.lastIndexOf('_'); - if (index > -1) { - return symbolName.slice(index + 1); - } - return symbolName; -}; - -export function assertQrl<T>(qrl: QRL<T>): asserts qrl is QRLInternal<T> { - if (qDev) { - if (!isQrl(qrl)) { - throw new Error('Not a QRL'); - } - } -} - -export function assertSignal<T>(obj: unknown): asserts obj is Signal<T> { - if (qDev) { - if (!isSignal(obj) && !isSignal(obj)) { - throw new Error('Not a Signal'); - } - } -} - const EMITTED = /*#__PURE__*/ new Set(); export const emitUsedSymbol = (symbol: string, element: Element | undefined, reqTime: number) => { diff --git a/packages/qwik/src/core/shared/qrl/qrl-utils.ts b/packages/qwik/src/core/shared/qrl/qrl-utils.ts new file mode 100644 index 00000000000..d7a48a7f247 --- /dev/null +++ b/packages/qwik/src/core/shared/qrl/qrl-utils.ts @@ -0,0 +1,32 @@ +/** QRL related utilities that you can import without importing all of Qwik. */ + +import { isDev } from '@qwik.dev/core/build'; +import type { QRLInternal, SyncQRLInternal } from './qrl-class'; +import type { QRL } from './qrl.public'; + +export const SYNC_QRL = '<sync>'; + +/** Sync QRL is a function which is serialized into `<script q:func="qwik/json">` tag. */ +export const isSyncQrl = (value: any): value is SyncQRLInternal => { + return isQrl(value) && value.$symbol$ == SYNC_QRL; +}; + +export const isQrl = <T = unknown>(value: unknown): value is QRLInternal<T> => { + return typeof value === 'function' && typeof (value as any).getSymbol === 'function'; +}; + +export function assertQrl<T>(qrl: QRL<T>): asserts qrl is QRLInternal<T> { + if (isDev) { + if (!isQrl(qrl)) { + throw new Error('Not a QRL'); + } + } +} + +export const getSymbolHash = (symbolName: string) => { + const index = symbolName.lastIndexOf('_'); + if (index > -1) { + return symbolName.slice(index + 1); + } + return symbolName; +}; diff --git a/packages/qwik/src/core/shared/qrl/qrl.public.ts b/packages/qwik/src/core/shared/qrl/qrl.public.ts index b1fd5187358..c8b910e1d1c 100644 --- a/packages/qwik/src/core/shared/qrl/qrl.public.ts +++ b/packages/qwik/src/core/shared/qrl/qrl.public.ts @@ -1,6 +1,7 @@ import { qDev, qRuntimeQrl } from '../utils/qdev'; import type { QRLDev } from './qrl'; -import { SYNC_QRL, createQRL } from './qrl-class'; +import { createQRL } from './qrl-class'; +import { SYNC_QRL } from './qrl-utils'; // We use `unknown` instead of `never` when it's not a function so we allow assigning QRL<function> to QRL<any> export type QrlArgs<T> = T extends (...args: infer ARGS) => any ? ARGS : unknown[]; diff --git a/packages/qwik/src/core/shared/qrl/qrl.ts b/packages/qwik/src/core/shared/qrl/qrl.ts index 41533c784fc..c3b47076297 100644 --- a/packages/qwik/src/core/shared/qrl/qrl.ts +++ b/packages/qwik/src/core/shared/qrl/qrl.ts @@ -2,7 +2,8 @@ import { QError_dynamicImportFailed, QError_unknownTypeArgument, qError } from ' import { EMPTY_ARRAY } from '../utils/flyweight'; import { qSerialize } from '../utils/qdev'; import { isFunction, isString } from '../utils/types'; -import { createQRL, emitEvent, getSymbolHash, type QRLInternal } from './qrl-class'; +import { createQRL, emitEvent, type QRLInternal } from './qrl-class'; +import { getSymbolHash } from './qrl-utils'; import type { QRL } from './qrl.public'; // https://regexr.com/68v72 diff --git a/packages/qwik/src/core/shared/shared-serialization.ts b/packages/qwik/src/core/shared/shared-serialization.ts index 81622b478a8..a2d5ca20112 100644 --- a/packages/qwik/src/core/shared/shared-serialization.ts +++ b/packages/qwik/src/core/shared/shared-serialization.ts @@ -36,13 +36,8 @@ import { } from './jsx/jsx-runtime'; import { Slot } from './jsx/slot.public'; import { getPlatform } from './platform/platform'; -import { - createQRL, - isQrl, - isSyncQrl, - type QRLInternal, - type SyncQRLInternal, -} from './qrl/qrl-class'; +import { createQRL, type QRLInternal, type SyncQRLInternal } from './qrl/qrl-class'; +import { isQrl, isSyncQrl } from './qrl/qrl-utils'; import type { QRL } from './qrl/qrl.public'; import { ChoreType } from './scheduler'; import type { DeserializeContainer, HostElement, ObjToProxyMap } from './types'; diff --git a/packages/qwik/src/core/shared/shared-serialization.unit.ts b/packages/qwik/src/core/shared/shared-serialization.unit.ts index e766e9b9a4a..76cf5d420f1 100644 --- a/packages/qwik/src/core/shared/shared-serialization.unit.ts +++ b/packages/qwik/src/core/shared/shared-serialization.unit.ts @@ -7,7 +7,7 @@ import { StoreFlags, createStore } from '../signal/store'; import { createResourceReturn } from '../use/use-resource'; import { Task } from '../use/use-task'; import { inlinedQrl } from './qrl/qrl'; -import { createQRL, isQrl, type QRLInternal } from './qrl/qrl-class'; +import { createQRL, type QRLInternal } from './qrl/qrl-class'; import { TypeIds, _constants, @@ -17,6 +17,7 @@ import { dumpState, } from './shared-serialization'; import { EMPTY_ARRAY, EMPTY_OBJ } from './utils/flyweight'; +import { isQrl } from './qrl/qrl-utils'; const DEBUG = false; diff --git a/packages/qwik/src/core/shared/utils/scoped-styles.ts b/packages/qwik/src/core/shared/utils/scoped-styles.ts index 37a3d60cd33..2aede98ba44 100644 --- a/packages/qwik/src/core/shared/utils/scoped-styles.ts +++ b/packages/qwik/src/core/shared/utils/scoped-styles.ts @@ -1,5 +1,9 @@ import type { Props } from '../jsx/jsx-runtime'; -import { styleContent } from './styles'; +import { ComponentStylesPrefixContent } from './markers'; + +export const styleContent = (styleId: string): string => { + return ComponentStylesPrefixContent + styleId; +}; export function hasClassAttr(props: Props): boolean { for (const key in props) { diff --git a/packages/qwik/src/core/shared/utils/styles.ts b/packages/qwik/src/core/shared/utils/styles.ts index 3447b302bd5..6c2455a3d39 100644 --- a/packages/qwik/src/core/shared/utils/styles.ts +++ b/packages/qwik/src/core/shared/utils/styles.ts @@ -4,10 +4,9 @@ import { isPreventDefault } from './event-names'; import { isClassAttr } from './scoped-styles'; import { isArray, isString } from './types'; import { isUnitlessNumber } from './unitless_number'; -import { assertQrl } from '../qrl/qrl-class'; +import { assertQrl } from '../qrl/qrl-utils'; import type { QRL } from '../qrl/qrl.public'; import { hashCode } from './hash_code'; -import { ComponentStylesPrefixContent } from './markers'; export const serializeClass = (obj: ClassList): string => { if (!obj) { @@ -75,7 +74,7 @@ export const serializeBooleanOrNumberAttribute = (value: any) => { export function serializeAttribute( key: string, - value: any, + value: unknown, styleScopedId?: string | null ): string | null | boolean { if (isClassAttr(key)) { @@ -93,7 +92,7 @@ export function serializeAttribute( } else if (value === true && isPreventDefault(key)) { value = ''; } - return value; + return value as string | null | boolean; } function isEnumeratedBooleanAttribute(key: string) { @@ -115,7 +114,3 @@ export const styleKey = (qStyles: QRL<string>, index: number): string => { assertQrl(qStyles); return `${hashCode(qStyles.$hash$)}-${index}`; }; - -export const styleContent = (styleId: string): string => { - return ComponentStylesPrefixContent + styleId; -}; diff --git a/packages/qwik/src/core/ssr/ssr-render-jsx.ts b/packages/qwik/src/core/ssr/ssr-render-jsx.ts index 14ee2dbc449..cc06df41070 100644 --- a/packages/qwik/src/core/ssr/ssr-render-jsx.ts +++ b/packages/qwik/src/core/ssr/ssr-render-jsx.ts @@ -1,14 +1,21 @@ import { isDev } from '@qwik.dev/core/build'; import { isQwikComponent } from '../shared/component.public'; -import { isQrl } from '../shared/qrl/qrl-class'; -import type { QRL } from '../shared/qrl/qrl.public'; import { Fragment, directGetPropsProxyProp } from '../shared/jsx/jsx-runtime'; import { Slot } from '../shared/jsx/slot.public'; import type { DevJSX, JSXNodeInternal, JSXOutput } from '../shared/jsx/types/jsx-node'; import type { JSXChildren } from '../shared/jsx/types/jsx-qwik-attributes'; import { SSRComment, SSRRaw, SSRStream, type SSRStreamChildren } from '../shared/jsx/utils.public'; -import { trackSignal } from '../use/use-core'; +import { isQrl } from '../shared/qrl/qrl-utils'; +import type { QRL } from '../shared/qrl/qrl.public'; +import { qrlToString, type SerializationContext } from '../shared/shared-serialization'; +import { DEBUG_TYPE, VirtualType } from '../shared/types'; import { isAsyncGenerator } from '../shared/utils/async-generator'; +import { + convertEventNameFromJsxPropToHtmlAttr, + getEventNameFromJsxProp, + isJsxPropertyAnEventName, + isPreventDefault, +} from '../shared/utils/event-names'; import { EMPTY_ARRAY } from '../shared/utils/flyweight'; import { throwErrorAndStop } from '../shared/utils/log'; import { @@ -20,21 +27,14 @@ import { qwikInspectorAttr, } from '../shared/utils/markers'; import { isPromise } from '../shared/utils/promises'; -import { isFunction, type ValueOrPromise } from '../shared/utils/types'; -import { - convertEventNameFromJsxPropToHtmlAttr, - getEventNameFromJsxProp, - isJsxPropertyAnEventName, - isPreventDefault, -} from '../shared/utils/event-names'; +import { qInspector } from '../shared/utils/qdev'; import { addComponentStylePrefix, isClassAttr } from '../shared/utils/scoped-styles'; -import { qrlToString, type SerializationContext } from '../shared/shared-serialization'; -import { DEBUG_TYPE, VirtualType } from '../shared/types'; -import { WrappedSignal, EffectProperty, isSignal } from '../signal/signal'; +import { serializeAttribute } from '../shared/utils/styles'; +import { isFunction, type ValueOrPromise } from '../shared/utils/types'; +import { EffectProperty, WrappedSignal, isSignal } from '../signal/signal'; +import { trackSignal } from '../use/use-core'; import { applyInlineComponent, applyQwikComponentBody } from './ssr-render-component'; import type { ISsrComponentFrame, ISsrNode, SSRContainer, SsrAttrs } from './ssr-types'; -import { qInspector } from '../shared/utils/qdev'; -import { serializeAttribute } from '../shared/utils/styles'; class ParentComponentData { constructor( diff --git a/packages/qwik/src/core/tests/projection.spec.tsx b/packages/qwik/src/core/tests/projection.spec.tsx index 78a1be5c02a..05926b9e08a 100644 --- a/packages/qwik/src/core/tests/projection.spec.tsx +++ b/packages/qwik/src/core/tests/projection.spec.tsx @@ -1272,7 +1272,7 @@ describe.each([ const content = <span>Some content</span>; const { document } = await render(<Cmp>{content}</Cmp>, { debug: DEBUG }); - expect(document.querySelector('q\\:template')).toBeUndefined(); + expect(document.querySelector('q\\:template')).toBeFalsy(); }); it('should add and delete projection content inside q:template for CSR rerender after SSR', async () => { diff --git a/packages/qwik/src/core/tests/render-api.spec.tsx b/packages/qwik/src/core/tests/render-api.spec.tsx index 3950002de34..0c6aeeb3701 100644 --- a/packages/qwik/src/core/tests/render-api.spec.tsx +++ b/packages/qwik/src/core/tests/render-api.spec.tsx @@ -500,7 +500,7 @@ describe('render api', () => { containerTagName: 'div', }); const document = createDocument({ html: result.html }); - const qwikFuncScriptElements = document.querySelectorAll('script[q\\:func=qwik/json]'); + const qwikFuncScriptElements = document.querySelectorAll('script[q\\:func="qwik/json"]'); expect(qwikFuncScriptElements).toHaveLength(1); expect(qwikFuncScriptElements[0].textContent).toMatch( /document\["qFuncs_(\w+)"\]=\[\(p0\)=>p0\.value\]/ diff --git a/packages/qwik/src/core/tests/ssr-render.spec.tsx b/packages/qwik/src/core/tests/ssr-render.spec.tsx index d68091d1ae2..675ae9d3480 100644 --- a/packages/qwik/src/core/tests/ssr-render.spec.tsx +++ b/packages/qwik/src/core/tests/ssr-render.spec.tsx @@ -158,7 +158,7 @@ describe('v2 ssr render', () => { const { vNode, document } = await ssrRenderToDom(<CommentCmp />, { debug }); expect(vNode).toBe(null); - expect((document.body.firstChild as Element).outerHTML).toEqual('<!--foo-->'); + expect((document.body.firstChild as Comment).data).toEqual('foo'); }); it('should render SSRStreamBlock', async () => { diff --git a/packages/qwik/src/core/tests/use-computed.spec.tsx b/packages/qwik/src/core/tests/use-computed.spec.tsx index a2abf59504a..b6d2c6477bf 100644 --- a/packages/qwik/src/core/tests/use-computed.spec.tsx +++ b/packages/qwik/src/core/tests/use-computed.spec.tsx @@ -93,7 +93,7 @@ describe.each([ </button> </> ); - expect(container.document.querySelector('button[id=123]')).toBeTruthy(); + expect(container.document.querySelector('button[id="123"]')).toBeTruthy(); await trigger(container.element, 'button', 'click'); expect(vNode).toMatchVDOM( <> @@ -102,7 +102,7 @@ describe.each([ </button> </> ); - expect(container.document.querySelector('button[id=124]')).toBeTruthy(); + expect(container.document.querySelector('button[id="124"]')).toBeTruthy(); }); it('should update value based on another computed', async () => { diff --git a/packages/qwik/src/core/use/use-computed.ts b/packages/qwik/src/core/use/use-computed.ts index 9b3d3309af5..fce8e5e093d 100644 --- a/packages/qwik/src/core/use/use-computed.ts +++ b/packages/qwik/src/core/use/use-computed.ts @@ -1,4 +1,4 @@ -import { assertQrl } from '../shared/qrl/qrl-class'; +import { assertQrl } from '../shared/qrl/qrl-utils'; import type { QRL } from '../shared/qrl/qrl.public'; import { ComputedSignal, throwIfQRLNotResolved } from '../signal/signal'; import type { ReadonlySignal, Signal } from '../signal/signal.public'; diff --git a/packages/qwik/src/core/use/use-lexical-scope.public.ts b/packages/qwik/src/core/use/use-lexical-scope.public.ts index 1a46d7b00b9..92fa8acfe9a 100644 --- a/packages/qwik/src/core/use/use-lexical-scope.public.ts +++ b/packages/qwik/src/core/use/use-lexical-scope.public.ts @@ -1,7 +1,8 @@ import { assertDefined } from '../shared/error/assert'; import { getInvokeContext } from './use-core'; -import { assertQrl, type QRLInternal } from '../shared/qrl/qrl-class'; +import type { QRLInternal } from '../shared/qrl/qrl-class'; import { _getQContainerElement, getDomContainer } from '../client/dom-container'; +import { assertQrl } from '../shared/qrl/qrl-utils'; // <docs markdown="../readme.md#useLexicalScope"> // !!DO NOT EDIT THIS COMMENT DIRECTLY!!! diff --git a/packages/qwik/src/core/use/use-resource.ts b/packages/qwik/src/core/use/use-resource.ts index 216fcc81421..310426a1bd8 100644 --- a/packages/qwik/src/core/use/use-resource.ts +++ b/packages/qwik/src/core/use/use-resource.ts @@ -1,5 +1,5 @@ import { isServerPlatform } from '../shared/platform/platform'; -import { assertQrl } from '../shared/qrl/qrl-class'; +import { assertQrl } from '../shared/qrl/qrl-utils'; import { type QRL } from '../shared/qrl/qrl.public'; import { Fragment, _jsxSorted } from '../shared/jsx/jsx-runtime'; import { invoke, newInvokeContext, untrack, useBindInvokeContext } from './use-core'; diff --git a/packages/qwik/src/core/use/use-styles.ts b/packages/qwik/src/core/use/use-styles.ts index c9bac80abfc..c5d2483ea4e 100644 --- a/packages/qwik/src/core/use/use-styles.ts +++ b/packages/qwik/src/core/use/use-styles.ts @@ -2,7 +2,7 @@ import { type QRL } from '../shared/qrl/qrl.public'; import { implicit$FirstArg } from '../shared/qrl/implicit_dollar'; import { getScopedStyles } from '../shared/utils/scoped-stylesheet'; import { useSequentialScope } from './use-sequential-scope'; -import { assertQrl } from '../shared/qrl/qrl-class'; +import { assertQrl } from '../shared/qrl/qrl-utils'; import { isPromise } from '../shared/utils/promises'; import { ComponentStylesPrefixContent } from '../shared/utils/markers'; import { styleKey } from '../shared/utils/styles'; diff --git a/packages/qwik/src/core/use/use-task.ts b/packages/qwik/src/core/use/use-task.ts index 19ce8cee00a..0eeeb951f3b 100644 --- a/packages/qwik/src/core/use/use-task.ts +++ b/packages/qwik/src/core/use/use-task.ts @@ -1,7 +1,8 @@ import { getDomContainer } from '../client/dom-container'; import type { VNode } from '../client/types'; import { isServerPlatform } from '../shared/platform/platform'; -import { assertQrl, createQRL, type QRLInternal } from '../shared/qrl/qrl-class'; +import { createQRL, type QRLInternal } from '../shared/qrl/qrl-class'; +import { assertQrl } from '../shared/qrl/qrl-utils'; import type { QRL } from '../shared/qrl/qrl.public'; import { ChoreType } from '../shared/scheduler'; import { type Container, type HostElement } from '../shared/types'; diff --git a/packages/qwik/src/core/use/use-visible-task.ts b/packages/qwik/src/core/use/use-visible-task.ts index 75c139d14b7..54091f42668 100644 --- a/packages/qwik/src/core/use/use-visible-task.ts +++ b/packages/qwik/src/core/use/use-visible-task.ts @@ -1,5 +1,5 @@ import { isServerPlatform } from '../shared/platform/platform'; -import { assertQrl } from '../shared/qrl/qrl-class'; +import { assertQrl } from '../shared/qrl/qrl-utils'; import type { QRL } from '../shared/qrl/qrl.public'; import { ChoreType } from '../shared/scheduler'; import { useSequentialScope } from './use-sequential-scope'; diff --git a/packages/qwik/src/optimizer/src/plugins/plugin.ts b/packages/qwik/src/optimizer/src/plugins/plugin.ts index 964134b42c1..4a139366762 100644 --- a/packages/qwik/src/optimizer/src/plugins/plugin.ts +++ b/packages/qwik/src/optimizer/src/plugins/plugin.ts @@ -947,9 +947,6 @@ export function parseId(originalId: string) { }; } -export const getSymbolHash = (symbolName: string) => - /_([a-z0-9]+)($|\.js($|\?))/.exec(symbolName)?.[1]; - const TRANSFORM_EXTS = { '.jsx': true, '.ts': true, diff --git a/packages/qwik/src/optimizer/src/plugins/vite-dev-server.ts b/packages/qwik/src/optimizer/src/plugins/vite-dev-server.ts index 2f2190de85f..34424f395c8 100644 --- a/packages/qwik/src/optimizer/src/plugins/vite-dev-server.ts +++ b/packages/qwik/src/optimizer/src/plugins/vite-dev-server.ts @@ -4,7 +4,6 @@ import type { IncomingMessage, ServerResponse } from 'http'; import { magenta } from 'kleur/colors'; import type { Connect, ViteDevServer } from 'vite'; -import { SYNC_QRL } from '../../../core/shared/qrl/qrl-class'; import type { OptimizerSystem, Path, QwikManifest, SymbolMapper, SymbolMapperFn } from '../types'; import clickToComponent from './click-to-component.html?raw'; import errorHost from './error-host.html?raw'; @@ -14,6 +13,7 @@ import { type NormalizedQwikPluginOptions, parseId } from './plugin'; import type { QwikViteDevResponse } from './vite'; import { VITE_ERROR_OVERLAY_STYLES } from './vite-error'; import { formatError } from './vite-utils'; +import { SYNC_QRL } from 'packages/qwik/src/server/qwik-copy'; function getOrigin(req: IncomingMessage) { const { PROTOCOL_HEADER, HOST_HEADER } = process.env; diff --git a/packages/qwik/src/server/platform.ts b/packages/qwik/src/server/platform.ts index 22ae4e8d77f..17025f85992 100644 --- a/packages/qwik/src/server/platform.ts +++ b/packages/qwik/src/server/platform.ts @@ -2,12 +2,10 @@ import type { SerializeDocumentOptions } from './types'; import { setPlatform } from '@qwik.dev/core'; import type { ResolvedManifest } from '@qwik.dev/core/optimizer'; import type { CorePlatformServer } from './qwik-types'; +import { SYNC_QRL } from './qwik-copy'; declare const require: (module: string) => Record<string, any>; -// Make sure this value is same as value in `qrl-class.ts` -const SYNC_QRL = '<sync>'; - export function createPlatform( opts: SerializeDocumentOptions, resolvedManifest: ResolvedManifest | undefined diff --git a/packages/qwik/src/server/qwik-copy.ts b/packages/qwik/src/server/qwik-copy.ts index 49157a615f4..1c751111889 100644 --- a/packages/qwik/src/server/qwik-copy.ts +++ b/packages/qwik/src/server/qwik-copy.ts @@ -9,8 +9,8 @@ * ensuring that this rule is followed, this file is the only place where relative `../` imports * of types only are allowed. * - * Sum code we are OK by importing and making a copy because it will have no adverse affect. This - * file lists code which we are OK to have duplicated. + * Some code is OK to import and make a copy of because it will have no adverse affect. This file + * lists code which we are OK to have duplicated, so we don't export more internals from core. */ export { serializeAttribute } from '../core/shared/utils/styles'; @@ -45,14 +45,14 @@ export { NON_SERIALIZABLE_MARKER_PREFIX, } from '../core/shared/utils/markers'; export { maybeThen } from '../core/shared/utils/promises'; -export { mapApp_remove, mapArray_get, mapArray_set } from '../core/client/vnode'; +export { mapApp_remove, mapArray_get, mapArray_set } from '../core/client/mapArray'; export { convertStyleIdsToString, getScopedStyleIdsAsPrefix, isClassAttr, } from '../core/shared/utils/scoped-styles'; export { DEBUG_TYPE, VirtualType, QContainerValue } from '../core/shared/types'; -export { VNodeDataChar } from '../core/shared/vnode-data-types'; -export { VNodeDataSeparator } from '../core/shared/vnode-data-types'; +export { VNodeDataChar, VNodeDataSeparator } from '../core/shared/vnode-data-types'; export { escapeHTML } from '../core/shared/utils/character-escaping'; export { getValidManifest } from '../optimizer/src/manifest'; +export { SYNC_QRL } from '../core/shared/qrl/qrl-utils'; diff --git a/packages/qwik/src/server/scripts.ts b/packages/qwik/src/server/scripts.ts index 6539d907aec..7c552bad0d7 100644 --- a/packages/qwik/src/server/scripts.ts +++ b/packages/qwik/src/server/scripts.ts @@ -1,5 +1,7 @@ -const QWIK_LOADER_DEFAULT_MINIFIED: string = (globalThis as any).QWIK_LOADER_DEFAULT_MINIFIED; -const QWIK_LOADER_DEFAULT_DEBUG: string = (globalThis as any).QWIK_LOADER_DEFAULT_DEBUG; +const QWIK_LOADER_DEFAULT_MINIFIED: string = + (globalThis as any).QWIK_LOADER_DEFAULT_MINIFIED || 'window.qwikevents||=[]'; +const QWIK_LOADER_DEFAULT_DEBUG: string = + (globalThis as any).QWIK_LOADER_DEFAULT_DEBUG || QWIK_LOADER_DEFAULT_MINIFIED; /** * Provides the `qwikloader.js` file as a string. Useful for tooling to inline the qwikloader script diff --git a/packages/qwik/src/server/ssr-container.ts b/packages/qwik/src/server/ssr-container.ts index 2f3801fae11..dfb21b1cfcc 100644 --- a/packages/qwik/src/server/ssr-container.ts +++ b/packages/qwik/src/server/ssr-container.ts @@ -49,22 +49,22 @@ import { escapeHTML, Q_PROPS_SEPARATOR, } from './qwik-copy'; -import { - type ContextId, - type HostElement, - type SSRContainer as ISSRContainer, - type ISsrComponentFrame, - type ISsrNode, - type JSXChildren, - type JSXOutput, - type NodePropData, - type SerializationContext, - type SsrAttrKey, - type SsrAttrValue, - type SsrAttrs, - type StreamWriter, - type SymbolToChunkResolver, - type ValueOrPromise, +import type { + ContextId, + HostElement, + SSRContainer as ISSRContainer, + ISsrComponentFrame, + ISsrNode, + JSXChildren, + JSXOutput, + NodePropData, + SerializationContext, + SsrAttrKey, + SsrAttrValue, + SsrAttrs, + StreamWriter, + SymbolToChunkResolver, + ValueOrPromise, } from './qwik-types'; import { Q_FUNCS_PREFIX } from './ssr-render'; import type { PrefetchResource, RenderOptions, RenderToStreamResult } from './types'; diff --git a/packages/qwik/src/server/vnode-data.ts b/packages/qwik/src/server/vnode-data.ts index 4acceb70aec..60e17ad436b 100644 --- a/packages/qwik/src/server/vnode-data.ts +++ b/packages/qwik/src/server/vnode-data.ts @@ -1,4 +1,4 @@ -import { type ISsrNode, type SsrAttrs } from './qwik-types'; +import type { ISsrNode, SsrAttrs } from './qwik-types'; import { SsrNode, type SsrNodeType } from './ssr-node'; import type { CleanupQueue } from './ssr-container'; diff --git a/packages/qwik/src/testing/api.md b/packages/qwik/src/testing/api.md index 0181ae13d24..449765d6ac3 100644 --- a/packages/qwik/src/testing/api.md +++ b/packages/qwik/src/testing/api.md @@ -4,9 +4,13 @@ ```ts +/// <reference types="jsdom" /> +/// <reference types="node_modules/.pnpm/@types+jsdom@21.1.7/node_modules/@types/jsdom/base" /> + import { ClientContainer } from '@qwik.dev/core/internal'; import type { CorePlatform } from '@qwik.dev/core'; import type { _DomContainer } from '@qwik.dev/core/internal'; +import { DOMWindow } from 'jsdom'; import type { _ElementVNode } from '@qwik.dev/core/internal'; import type { JSXNodeInternal } from '@qwik.dev/core/internal'; import { JSXOutput } from '@qwik.dev/core'; @@ -46,20 +50,18 @@ export class ElementFixture { constructor(options?: ElementFixtureOptions); // (undocumented) child: HTMLElement; - // Warning: (ae-forgotten-export) The symbol "MockDocument" needs to be exported by the entry point index.d.ts - // // (undocumented) - document: MockDocument; + document: Document; // (undocumented) host: HTMLElement; // (undocumented) parent: HTMLElement; // (undocumented) superParent: HTMLElement; - // Warning: (ae-forgotten-export) The symbol "MockWindow" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "createWindow" needs to be exported by the entry point index.d.ts // // (undocumented) - window: MockWindow; + window: ReturnType<typeof createWindow>; } // @public (undocumented) diff --git a/packages/qwik/src/testing/document.ts b/packages/qwik/src/testing/document.ts index 2e60f7afc56..5bbf3f820c4 100644 --- a/packages/qwik/src/testing/document.ts +++ b/packages/qwik/src/testing/document.ts @@ -1,5 +1,5 @@ -import type { MockDocumentOptions, MockWindow } from './types'; -import qwikDom from '@qwik.dev/dom'; +import type { MockDocumentOptions } from './types'; +import { JSDOM } from 'jsdom'; import { normalizeUrl } from './util'; /** @@ -8,10 +8,8 @@ import { normalizeUrl } from './util'; * * @public */ -export function createDocument(opts?: MockDocumentOptions) { - const doc = qwikDom.createDocument(opts?.html); - ensureGlobals(doc, opts); - return doc; +export function createDocument(opts: MockDocumentOptions = {}) { + return createWindow(opts).document; } /** @@ -19,8 +17,17 @@ export function createDocument(opts?: MockDocumentOptions) { * * @public */ -export function createWindow(opts: MockDocumentOptions = {}): MockWindow { - return createDocument(opts).defaultView!; +export function createWindow(opts: MockDocumentOptions = {}) { + const { window } = new JSDOM(opts.html || '<!DOCTYPE html>', { + url: typeof opts.url === 'string' ? opts.url : opts.url?.href, + runScripts: 'dangerously', + contentType: 'text/html; charset=utf-8', + pretendToBeVisual: true, + }); + // Our backchannel for QRLs during testing + const map = ((globalThis as any)['mock-chunk'] ||= new Map()); + window['mock-chunk'] = map; + return window; } export function ensureGlobals(doc: any, opts?: MockDocumentOptions) { @@ -29,6 +36,7 @@ export function ensureGlobals(doc: any, opts?: MockDocumentOptions) { } if (!doc || doc.nodeType !== 9) { + console.error('Invalid document', doc); throw new Error(`Invalid document`); } diff --git a/packages/qwik/src/testing/document.unit.ts b/packages/qwik/src/testing/document.unit.ts index e1b61cd1676..ba2ba0657e9 100644 --- a/packages/qwik/src/testing/document.unit.ts +++ b/packages/qwik/src/testing/document.unit.ts @@ -105,7 +105,7 @@ test('qwik server createDocument()', () => { test('qwik server createWindow()', () => { const win = createWindow(); assert.notEqual(win.document.defaultView, undefined); - assert.equal(win.document.defaultView, win); + assert.equal(win.document.defaultView, win as any as Window); }); test('some other document', () => { diff --git a/packages/qwik/src/testing/element-fixture.ts b/packages/qwik/src/testing/element-fixture.ts index eb001433201..d1c3533469e 100644 --- a/packages/qwik/src/testing/element-fixture.ts +++ b/packages/qwik/src/testing/element-fixture.ts @@ -4,7 +4,6 @@ import type { QRLInternal } from '../core/shared/qrl/qrl-class'; import { _getQContainerElement, getDomContainer } from '@qwik.dev/core'; import { createWindow } from './document'; import { getTestPlatform } from './platform'; -import type { MockDocument, MockWindow } from './types'; import { delay } from '../core/shared/utils/promises'; import type { QElement, QwikLoaderEventScope } from '../core/shared/types'; import { fromCamelToKebabCase } from '../core/shared/utils/event-names'; @@ -24,8 +23,8 @@ import { QFuncsPrefix, QInstanceAttr } from '../core/shared/utils/markers'; * @public */ export class ElementFixture { - window: MockWindow; - document: MockDocument; + window: ReturnType<typeof createWindow>; + document: Document; superParent: HTMLElement; parent: HTMLElement; host: HTMLElement; diff --git a/packages/qwik/src/testing/library.ts b/packages/qwik/src/testing/library.ts index 21c72cd8895..4ed966a76d3 100644 --- a/packages/qwik/src/testing/library.ts +++ b/packages/qwik/src/testing/library.ts @@ -1,6 +1,7 @@ import { ElementFixture, trigger } from './element-fixture'; import { setTestPlatform } from './platform'; import type { JSXOutput } from '@qwik.dev/core'; +import { render, setPlatform } from '@qwik.dev/core'; /** * CreatePlatform and CreateDocument @@ -8,12 +9,11 @@ import type { JSXOutput } from '@qwik.dev/core'; * @public */ export const createDOM = async function ({ html }: { html?: string } = {}) { - const qwik = await getQwik(); - setTestPlatform(qwik.setPlatform); + setTestPlatform(setPlatform); const host = new ElementFixture({ html }).host; return { render: function (jsxElement: JSXOutput) { - return qwik.render(host, jsxElement); + return render(host, jsxElement); }, screen: host, userEvent: async function ( @@ -25,11 +25,3 @@ export const createDOM = async function ({ html }: { html?: string } = {}) { }, }; }; - -const getQwik = async (): Promise<typeof import('@qwik.dev/core')> => { - if ((globalThis as any).RUNNER !== false) { - return await import('../core/index'); - } else { - return await import('@qwik.dev/core'); - } -}; diff --git a/packages/qwik/src/testing/types.ts b/packages/qwik/src/testing/types.ts index d4d4dda7e81..a12e0cd5ee3 100644 --- a/packages/qwik/src/testing/types.ts +++ b/packages/qwik/src/testing/types.ts @@ -1,13 +1,5 @@ import type { CorePlatform } from '@qwik.dev/core'; -/** @public */ -export interface MockDocument extends Document {} - -/** @public */ -export interface MockWindow extends Window { - document: MockDocument; -} - /** * Options when creating a mock Qwik Document object. * @@ -18,13 +10,6 @@ export interface MockDocumentOptions { html?: string; } -/** - * Options when creating a mock Qwik Window object. - * - * @public - */ -export interface MockWindowOptions extends MockDocumentOptions {} - /** @public */ export interface TestPlatform extends CorePlatform { flush: () => Promise<void>; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bb7be936f1f..fbd46f47d87 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -234,7 +234,7 @@ importers: version: 5.0.1(typescript@5.4.5)(vite@5.4.10(@types/node@20.14.11)(terser@5.36.0)) vitest: specifier: 2.1.4 - version: 2.1.4(@types/node@20.14.11)(terser@5.36.0) + version: 2.1.4(@types/node@20.14.11)(jsdom@25.0.1)(terser@5.36.0) watchlist: specifier: 0.3.1 version: 0.3.1 @@ -551,7 +551,7 @@ importers: version: 5.0.1(typescript@5.4.5)(vite@5.4.10(@types/node@20.14.11)(terser@5.36.0)) vitest: specifier: 2.1.4 - version: 2.1.4(@types/node@20.14.11)(terser@5.36.0) + version: 2.1.4(@types/node@20.14.11)(jsdom@25.0.1)(terser@5.36.0) zod: specifier: 3.22.4 version: 3.22.4 @@ -565,15 +565,18 @@ importers: '@qwik.dev/core': specifier: workspace:* version: 'link:' - '@qwik.dev/dom': - specifier: workspace:* - version: link:../qwik-dom + '@types/jsdom': + specifier: ^21.1.7 + version: 21.1.7 ignore: specifier: 5.3.1 version: 5.3.1 image-size: specifier: 1.1.1 version: 1.1.1 + jsdom: + specifier: ^25.0.1 + version: 25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10) kleur: specifier: 4.1.5 version: 4.1.5 @@ -585,9 +588,7 @@ importers: version: 23.0.0 vitest: specifier: 2.1.4 - version: 2.1.4(@types/node@20.14.11)(terser@5.36.0) - - packages/qwik-dom: {} + version: 2.1.4(@types/node@20.14.11)(jsdom@25.0.1)(terser@5.36.0) packages/qwik-react: devDependencies: @@ -3397,6 +3398,9 @@ packages: '@types/istanbul-reports@3.0.4': resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + '@types/jsdom@21.1.7': + resolution: {integrity: sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -3490,6 +3494,9 @@ packages: '@types/tmp@0.2.6': resolution: {integrity: sha512-chhaNf2oKHlRkDGt+tiKE2Z5aJ6qalm7Z9rlLdBwmOiAAf09YQvvoLXjWK4HWPF1xU/fqvMgfNfpVoBscA/tKA==} + '@types/tough-cookie@4.0.5': + resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} + '@types/triple-beam@1.3.5': resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==} @@ -4638,6 +4645,10 @@ packages: resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + cssstyle@4.1.0: + resolution: {integrity: sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==} + engines: {node: '>=18'} + csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} @@ -4659,6 +4670,10 @@ packages: resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} engines: {node: '>= 14'} + data-urls@5.0.0: + resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} + engines: {node: '>=18'} + data-view-buffer@1.0.1: resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} engines: {node: '>= 0.4'} @@ -4729,6 +4744,9 @@ packages: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} engines: {node: '>=0.10.0'} + decimal.js@10.4.3: + resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} + decode-formdata@0.7.5: resolution: {integrity: sha512-zwz+xh+Z2R1s2hk14pGiwgVnYiw1UnlsoxHZ5neSXnslgET1weO0dw0d9dLpf1rxAtcvNXo59IMKq5avdaOcvA==} @@ -6122,6 +6140,10 @@ packages: resolution: {integrity: sha512-uy/uGpuJk7yuyiKRfZMBNkF1GAOX5O2ifO9rDCaX9jw8fu6eW9QeWC7WRPDI+O98frW1HQgV3+xwjWsZPECIzQ==} engines: {node: '>=10.0.0'} + html-encoding-sniffer@4.0.0: + resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} + engines: {node: '>=18'} + http-cache-semantics@4.1.1: resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} @@ -6448,6 +6470,9 @@ packages: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-promise@2.2.2: resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} @@ -6601,6 +6626,15 @@ packages: jsbn@1.1.0: resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} + jsdom@25.0.1: + resolution: {integrity: sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==} + engines: {node: '>=18'} + peerDependencies: + canvas: ^2.11.2 + peerDependenciesMeta: + canvas: + optional: true + json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -7450,6 +7484,9 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + nwsapi@2.2.13: + resolution: {integrity: sha512-cTGB9ptp9dY9A5VbMSe7fQBcl/tt22Vcqdq8+eN93rblOuE0aCFu4aZ2vMwct/2t+lFnosm8RkQW1I0Omb1UtQ==} + oauth4webapi@2.10.4: resolution: {integrity: sha512-DSoj8QoChzOCQlJkRmYxAJCIpnXFW32R0Uq7avyghIeB6iJq0XAblOD7pcq3mx4WEBDwMuKr0Y1qveCBleG2Xw==} @@ -8400,6 +8437,9 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + rrweb-cssom@0.7.1: + resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==} + run-applescript@7.0.0: resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==} engines: {node: '>=18'} @@ -8449,6 +8489,10 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + scheduler@0.23.2: resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} @@ -8903,6 +8947,9 @@ packages: engines: {node: '>=14.0.0'} hasBin: true + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + syncpack@12.3.3: resolution: {integrity: sha512-r154Rk8YtJA0My8Nu5v4e58n3y85atG4WlxekTQ/DT4toqiMtprqn5LrHuNVAhbpsOfUHPv6EFMj9k+FdDvgDA==} engines: {node: '>=16'} @@ -9033,6 +9080,13 @@ packages: resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} engines: {node: '>=14.0.0'} + tldts-core@6.1.63: + resolution: {integrity: sha512-H1XCt54xY+QPbwhTgmxLkepX0MVHu3USfMmejiCOdkMbRcP22Pn2FVF127r/GWXVDmXTRezyF3Ckvhn4Fs6j7Q==} + + tldts@6.1.63: + resolution: {integrity: sha512-YWwhsjyn9sB/1rOkSRYxvkN/wl5LFM1QDv6F2pVR+pb/jFne4EOBxHfkKVWvDIBEAw9iGOwwubHtQTm0WRT5sQ==} + hasBin: true + tmp-promise@3.0.3: resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==} @@ -9074,9 +9128,17 @@ packages: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} + tough-cookie@5.0.0: + resolution: {integrity: sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==} + engines: {node: '>=16'} + tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + tr46@5.0.0: + resolution: {integrity: sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==} + engines: {node: '>=18'} + tree-dump@1.0.2: resolution: {integrity: sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==} engines: {node: '>=10.0'} @@ -9601,6 +9663,10 @@ packages: vscode-uri@3.0.8: resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} + wait-port@1.1.0: resolution: {integrity: sha512-3e04qkoN3LxTMLakdqeWth8nih8usyg+sf1Bgdf9wwUkp05iuK1eSY/QpLvscT/+F/gA89+LpUmmgBtesbqI2Q==} engines: {node: '>=10'} @@ -9621,6 +9687,10 @@ packages: webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + websocket@1.0.35: resolution: {integrity: sha512-/REy6amwPZl44DDzvRCkaI1q1bIiQB0mEFQLUrhz3z2EK91cp3n72rAjUlrTP0zV22HJIUOVHQGPxhFRjxjt+Q==} engines: {node: '>=4.0.0'} @@ -9629,6 +9699,18 @@ packages: resolution: {integrity: sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==} engines: {node: '>=6'} + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + + whatwg-url@14.0.0: + resolution: {integrity: sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==} + engines: {node: '>=18'} + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -9763,6 +9845,13 @@ packages: resolution: {integrity: sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==} engines: {node: '>=12'} + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + xss@1.0.15: resolution: {integrity: sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==} engines: {node: '>= 0.10.0'} @@ -10989,7 +11078,7 @@ snapshots: '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 espree: 9.6.1 globals: 13.24.0 ignore: 5.3.1 @@ -11003,7 +11092,7 @@ snapshots: '@eslint/eslintrc@3.1.0': dependencies: ajv: 6.12.6 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 espree: 10.0.1 globals: 14.0.0 ignore: 5.3.1 @@ -11074,7 +11163,7 @@ snapshots: '@humanwhocodes/config-array@0.11.14': dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -12079,7 +12168,7 @@ snapshots: '@puppeteer/browsers@2.2.4': dependencies: - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 extract-zip: 2.0.1 progress: 2.0.3 proxy-agent: 6.4.0 @@ -12405,6 +12494,12 @@ snapshots: dependencies: '@types/istanbul-lib-report': 3.0.3 + '@types/jsdom@21.1.7': + dependencies: + '@types/node': 20.14.11 + '@types/tough-cookie': 4.0.5 + parse5: 7.1.2 + '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': {} @@ -12501,6 +12596,8 @@ snapshots: '@types/tmp@0.2.6': {} + '@types/tough-cookie@4.0.5': {} + '@types/triple-beam@1.3.5': {} '@types/unist@2.0.10': {} @@ -12556,7 +12653,7 @@ snapshots: '@typescript-eslint/types': 7.16.1 '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.4.5) '@typescript-eslint/visitor-keys': 7.16.1 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 eslint: 8.57.0 optionalDependencies: typescript: 5.4.5 @@ -12595,7 +12692,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.4.5) '@typescript-eslint/utils': 7.16.1(eslint@8.57.0)(typescript@5.4.5) - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 eslint: 8.57.0 ts-api-utils: 1.3.0(typescript@5.4.5) optionalDependencies: @@ -12629,7 +12726,7 @@ snapshots: dependencies: '@typescript-eslint/types': 7.16.1 '@typescript-eslint/visitor-keys': 7.16.1 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.4 @@ -12644,7 +12741,7 @@ snapshots: dependencies: '@typescript-eslint/types': 7.8.0 '@typescript-eslint/visitor-keys': 7.8.0 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.4 @@ -12930,13 +13027,13 @@ snapshots: agent-base@6.0.2(supports-color@9.4.0): dependencies: - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) transitivePeerDependencies: - supports-color agent-base@7.1.1: dependencies: - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 transitivePeerDependencies: - supports-color @@ -13472,7 +13569,7 @@ snapshots: capnp-ts@0.7.0: dependencies: - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 tslib: 2.6.3 transitivePeerDependencies: - supports-color @@ -13882,6 +13979,10 @@ snapshots: dependencies: css-tree: 2.2.1 + cssstyle@4.1.0: + dependencies: + rrweb-cssom: 0.7.1 + csstype@3.1.3: {} cyclist@1.0.2: {} @@ -13897,6 +13998,11 @@ snapshots: data-uri-to-buffer@6.0.2: {} + data-urls@5.0.0: + dependencies: + whatwg-mimetype: 4.0.0 + whatwg-url: 14.0.0 + data-view-buffer@1.0.1: dependencies: call-bind: 1.0.7 @@ -13937,11 +14043,9 @@ snapshots: dependencies: ms: 2.1.3 - debug@4.3.5(supports-color@9.4.0): + debug@4.3.5: dependencies: ms: 2.1.2 - optionalDependencies: - supports-color: 9.4.0 debug@4.3.7(supports-color@9.4.0): dependencies: @@ -13955,6 +14059,8 @@ snapshots: decamelize@1.2.0: {} + decimal.js@10.4.3: {} + decode-formdata@0.7.5: {} decode-named-character-reference@1.0.2: @@ -14390,7 +14496,7 @@ snapshots: esbuild-register@3.5.0(esbuild@0.19.12): dependencies: - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 esbuild: 0.19.12 transitivePeerDependencies: - supports-color @@ -14729,7 +14835,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -14992,7 +15098,7 @@ snapshots: extract-zip@2.0.1: dependencies: - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -15223,7 +15329,7 @@ snapshots: follow-redirects@1.15.6(debug@4.3.5): optionalDependencies: - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 for-each@0.3.3: dependencies: @@ -15374,7 +15480,7 @@ snapshots: dependencies: basic-ftp: 5.0.5 data-uri-to-buffer: 6.0.2 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) fs-extra: 11.2.0 transitivePeerDependencies: - supports-color @@ -15705,6 +15811,10 @@ snapshots: optionalDependencies: unix-dgram: 2.0.6 + html-encoding-sniffer@4.0.0: + dependencies: + whatwg-encoding: 3.1.1 + http-cache-semantics@4.1.1: {} http-errors@1.8.1: @@ -15726,7 +15836,7 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.1 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) transitivePeerDependencies: - supports-color @@ -15760,14 +15870,14 @@ snapshots: https-proxy-agent@5.0.1(supports-color@9.4.0): dependencies: agent-base: 6.0.2(supports-color@9.4.0) - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) transitivePeerDependencies: - supports-color https-proxy-agent@7.0.5: dependencies: agent-base: 7.1.1 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) transitivePeerDependencies: - supports-color @@ -16037,6 +16147,8 @@ snapshots: is-plain-obj@4.1.0: {} + is-potential-custom-element-name@1.0.1: {} + is-promise@2.2.2: {} is-reference@3.0.2: @@ -16165,6 +16277,34 @@ snapshots: jsbn@1.1.0: {} + jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10): + dependencies: + cssstyle: 4.1.0 + data-urls: 5.0.0 + decimal.js: 10.4.3 + form-data: 4.0.0 + html-encoding-sniffer: 4.0.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.5 + is-potential-custom-element-name: 1.0.1 + nwsapi: 2.2.13 + parse5: 7.1.2 + rrweb-cssom: 0.7.1 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 5.0.0 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 7.0.0 + whatwg-encoding: 3.1.1 + whatwg-mimetype: 4.0.0 + whatwg-url: 14.0.0 + ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + json-buffer@3.0.1: {} json-diff@0.9.0: @@ -16987,7 +17127,7 @@ snapshots: micromark@4.0.0: dependencies: '@types/debug': 4.1.12 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 decode-named-character-reference: 1.0.2 devlop: 1.1.0 micromark-core-commonmark: 2.0.1 @@ -17197,7 +17337,7 @@ snapshots: content-type: 1.0.5 cookie: 0.6.0 cron-parser: 4.9.0 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 decache: 4.6.2 dot-prop: 9.0.0 dotenv: 16.4.5 @@ -17441,6 +17581,8 @@ snapshots: dependencies: boolbase: 1.0.0 + nwsapi@2.2.13: {} + oauth4webapi@2.10.4: {} object-assign@4.1.1: {} @@ -17656,7 +17798,7 @@ snapshots: dependencies: '@tootallnate/quickjs-emscripten': 0.23.0 agent-base: 7.1.1 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 get-uri: 6.0.3 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.5 @@ -18020,7 +18162,7 @@ snapshots: proxy-agent@6.4.0: dependencies: agent-base: 7.1.1 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.5 lru-cache: 7.18.3 @@ -18056,7 +18198,7 @@ snapshots: dependencies: '@puppeteer/browsers': 2.2.4 chromium-bidi: 0.6.1(devtools-protocol@0.0.1299070) - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 devtools-protocol: 0.0.1299070 ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) transitivePeerDependencies: @@ -18455,6 +18597,8 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.24.2 fsevents: 2.3.3 + rrweb-cssom@0.7.1: {} + run-applescript@7.0.0: {} run-async@2.4.1: {} @@ -18502,6 +18646,10 @@ snapshots: safer-buffer@2.1.2: {} + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + scheduler@0.23.2: dependencies: loose-envify: 1.4.0 @@ -18740,7 +18888,7 @@ snapshots: socks-proxy-agent@8.0.3: dependencies: agent-base: 7.1.1 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 socks: 2.8.3 transitivePeerDependencies: - supports-color @@ -19013,6 +19161,8 @@ snapshots: csso: 5.0.5 picocolors: 1.0.1 + symbol-tree@3.2.4: {} + syncpack@12.3.3(typescript@5.4.5): dependencies: '@effect/schema': 0.66.5(effect@3.0.3)(fast-check@3.17.2) @@ -19041,7 +19191,7 @@ snapshots: tabtab@3.0.2: dependencies: - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 es6-promisify: 6.1.1 inquirer: 6.5.2 minimist: 1.2.8 @@ -19200,6 +19350,12 @@ snapshots: tinyspy@3.0.2: {} + tldts-core@6.1.63: {} + + tldts@6.1.63: + dependencies: + tldts-core: 6.1.63 + tmp-promise@3.0.3: dependencies: tmp: 0.2.3 @@ -19231,8 +19387,16 @@ snapshots: totalist@3.0.1: {} + tough-cookie@5.0.0: + dependencies: + tldts: 6.1.63 + tr46@0.0.3: {} + tr46@5.0.0: + dependencies: + punycode: 2.3.1 + tree-dump@1.0.2(tslib@2.6.3): dependencies: tslib: 2.6.3 @@ -19618,7 +19782,7 @@ snapshots: vite-node@0.32.4(@types/node@20.14.11)(terser@5.36.0): dependencies: cac: 6.7.14 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 mlly: 1.7.0 pathe: 1.1.2 picocolors: 1.0.1 @@ -19673,7 +19837,7 @@ snapshots: dependencies: '@antfu/utils': 0.7.10 '@rollup/pluginutils': 5.1.0(rollup@4.24.2) - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 error-stack-parser-es: 0.1.4 fs-extra: 11.2.0 open: 10.1.0 @@ -19687,7 +19851,7 @@ snapshots: vite-tsconfig-paths@5.0.1(typescript@5.4.5)(vite@5.4.10(@types/node@20.14.11)(terser@5.36.0)): dependencies: - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 globrex: 0.1.2 tsconfck: 3.1.0(typescript@5.4.5) optionalDependencies: @@ -19716,7 +19880,7 @@ snapshots: fsevents: 2.3.3 terser: 5.36.0 - vitest@2.1.4(@types/node@20.14.11)(terser@5.36.0): + vitest@2.1.4(@types/node@20.14.11)(jsdom@25.0.1)(terser@5.36.0): dependencies: '@vitest/expect': 2.1.4 '@vitest/mocker': 2.1.4(vite@5.4.10(@types/node@20.14.11)(terser@5.36.0)) @@ -19740,6 +19904,7 @@ snapshots: why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 20.14.11 + jsdom: 25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10) transitivePeerDependencies: - less - lightningcss @@ -19757,11 +19922,15 @@ snapshots: vscode-uri@3.0.8: {} + w3c-xmlserializer@5.0.0: + dependencies: + xml-name-validator: 5.0.0 + wait-port@1.1.0: dependencies: chalk: 4.1.2 commander: 9.5.0 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.5 transitivePeerDependencies: - supports-color @@ -19775,6 +19944,8 @@ snapshots: webidl-conversions@3.0.1: {} + webidl-conversions@7.0.0: {} + websocket@1.0.35: dependencies: bufferutil: 4.0.8 @@ -19788,6 +19959,17 @@ snapshots: well-known-symbols@2.0.0: {} + whatwg-encoding@3.1.1: + dependencies: + iconv-lite: 0.6.3 + + whatwg-mimetype@4.0.0: {} + + whatwg-url@14.0.0: + dependencies: + tr46: 5.0.0 + webidl-conversions: 7.0.0 + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -19955,6 +20137,10 @@ snapshots: xdg-basedir@5.1.0: {} + xml-name-validator@5.0.0: {} + + xmlchars@2.2.0: {} + xss@1.0.15: dependencies: commander: 2.20.3 diff --git a/scripts/build.ts b/scripts/build.ts index 604b4612695..df570fd480d 100644 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -176,7 +176,7 @@ export async function build(config: BuildConfig) { }); } } catch (e: any) { - panic(String(e ? e.stack || e : 'Error')); + panic(e); } } diff --git a/scripts/submodule-core.ts b/scripts/submodule-core.ts index f5c611b1b3d..480336c7fca 100644 --- a/scripts/submodule-core.ts +++ b/scripts/submodule-core.ts @@ -78,6 +78,7 @@ async function submoduleCoreProd(config: BuildConfig) { const inputMin: InputOptions = { input: inputCore, onwarn: rollupOnWarn, + external: ['jsdom'], plugins: [ { name: 'build', @@ -230,7 +231,7 @@ async function submoduleCoreDev(config: BuildConfig) { const esm = build({ ...opts, - external: ['@qwik.dev/core/build'], + external: ['@qwik.dev/core/build', 'jsdom'], format: 'esm', outExtension: { '.js': '.mjs' }, }); @@ -238,6 +239,7 @@ async function submoduleCoreDev(config: BuildConfig) { const cjs = build({ ...opts, // we don't externalize qwik build because then the repl service worker sees require() + external: ['jsdom'], define: { ...opts.define, // Vite's base url diff --git a/scripts/submodule-optimizer.ts b/scripts/submodule-optimizer.ts index b3ae388a288..12b235e56b3 100644 --- a/scripts/submodule-optimizer.ts +++ b/scripts/submodule-optimizer.ts @@ -19,22 +19,18 @@ import { export async function submoduleOptimizer(config: BuildConfig) { const submodule = 'optimizer'; - await generatePlatformBindingsData(config); + // uncomment this when adding a platform binding + // await generatePlatformBindingsData(config); async function buildOptimizer() { const opts: BuildOptions = { - entryPoints: [join(config.srcQwikDir, submodule, 'src', 'index.ts')], + entryPoints: [join(config.optimizerDir, 'index.ts')], entryNames: 'optimizer', outdir: config.distQwikPkgDir, bundle: true, sourcemap: false, platform: 'node', target, - external: [ - /* no Node.js built-in externals allowed! */ - 'espree', - 'lightningcss', - ], }; const qwikloaderScripts = await inlineQwikScriptsEsBuild(config); @@ -120,6 +116,7 @@ export async function submoduleOptimizer(config: BuildConfig) { await Promise.all([buildOptimizer()]); } +// @ts-expect-error -- we only use this when adding a platform binding async function generatePlatformBindingsData(config: BuildConfig) { // generate the platform binding information for only what qwik provides // allows us to avoid using a file system in the optimizer, take a look at: diff --git a/scripts/submodule-server.ts b/scripts/submodule-server.ts index 4bd42e32927..ea3dc287772 100644 --- a/scripts/submodule-server.ts +++ b/scripts/submodule-server.ts @@ -1,6 +1,5 @@ -import { build, type BuildOptions, type Plugin } from 'esbuild'; +import { build, type BuildOptions } from 'esbuild'; import { join } from 'node:path'; -import { readPackageJson } from './package-json'; import { inlineQwikScriptsEsBuild } from './submodule-qwikloader'; import { type BuildConfig, getBanner, importPath, nodeTarget, target } from './util'; @@ -13,9 +12,6 @@ import { type BuildConfig, getBanner, importPath, nodeTarget, target } from './u export async function submoduleServer(config: BuildConfig) { const submodule = 'server'; - const qwikDomPlugin = await bundleQwikDom(config); - const qwikDomVersion = await getQwikDomVersion(config); - const opts: BuildOptions = { entryPoints: [join(config.srcQwikDir, submodule, 'index.ts')], entryNames: 'server', @@ -24,10 +20,7 @@ export async function submoduleServer(config: BuildConfig) { bundle: true, platform: 'node', target, - external: [ - /* no Node.js built-in externals allowed! */ '@qwik.dev/dom', - '@qwik.dev/core/build', - ], + external: ['@qwik.dev/core', '@qwik.dev/core/build', 'jsdom'], }; const esm = build({ @@ -35,13 +28,24 @@ export async function submoduleServer(config: BuildConfig) { format: 'esm', banner: { js: getBanner('@qwik.dev/core/server', config.distVersion) }, outExtension: { '.js': '.mjs' }, - plugins: [importPath(/^@qwik\.dev\/core$/, '@qwik.dev/core'), qwikDomPlugin], + plugins: [ + // uncomment this if you want to find what imports qwik-external + // { + // name: 'spy-resolve', + // setup(build) { + // build.onResolve({ filter: /./ }, (args) => { + // console.log('spy-resolve', args); + // return undefined; + // }); + // }, + // }, + importPath(/^@qwik\.dev\/core$/, '@qwik.dev/core'), + ], define: { ...(await inlineQwikScriptsEsBuild(config)), 'globalThis.IS_CJS': 'false', 'globalThis.IS_ESM': 'true', 'globalThis.QWIK_VERSION': JSON.stringify(config.distVersion), - 'globalThis.QWIK_DOM_VERSION': JSON.stringify(qwikDomVersion), }, }); @@ -61,14 +65,13 @@ export async function submoduleServer(config: BuildConfig) { js: `return module.exports; })(typeof module === 'object' && module.exports ? module : { exports: {} });`, }, outExtension: { '.js': '.cjs' }, - plugins: [importPath(/^@qwik\.dev\/core$/, '@qwik.dev/core'), qwikDomPlugin], + plugins: [importPath(/^@qwik\.dev\/core$/, '@qwik.dev/core')], target: nodeTarget, define: { ...(await inlineQwikScriptsEsBuild(config)), 'globalThis.IS_CJS': 'true', 'globalThis.IS_ESM': 'false', 'globalThis.QWIK_VERSION': JSON.stringify(config.distVersion), - 'globalThis.QWIK_DOM_VERSION': JSON.stringify(qwikDomVersion), }, }); @@ -77,42 +80,6 @@ export async function submoduleServer(config: BuildConfig) { console.log('šŸ°', submodule); } -async function bundleQwikDom(config: BuildConfig) { - const input = join(config.packagesDir, 'qwik-dom', 'lib', 'index.js'); - const outfile = join(config.tmpDir, 'qwikdom.mjs'); - - const opts: BuildOptions = { - entryPoints: [input], - sourcemap: false, - minify: !config.dev, - bundle: true, - target, - outfile, - format: 'esm', - }; - - await build(opts); - - const qwikDomPlugin: Plugin = { - name: 'qwikDomPlugin', - setup(build) { - build.onResolve({ filter: /@qwik.dev\/dom/ }, () => { - return { - path: outfile, - }; - }); - }, - }; - - return qwikDomPlugin; -} - -async function getQwikDomVersion(config: BuildConfig) { - const pkgJsonPath = join(config.packagesDir, 'qwik-dom'); - const pkgJson = await readPackageJson(pkgJsonPath); - return pkgJson.version; -} - const browserCjsRequireShim = ` if (typeof require !== 'function' && typeof location !== 'undefined' && typeof navigator !== 'undefined') { // shim cjs require() for core.cjs within a browser diff --git a/scripts/submodule-testing.ts b/scripts/submodule-testing.ts index 75fa98f4799..24a1eb4f34d 100644 --- a/scripts/submodule-testing.ts +++ b/scripts/submodule-testing.ts @@ -14,9 +14,8 @@ export async function submoduleTesting(config: BuildConfig) { sourcemap: config.dev, bundle: true, target, - external: ['@qwik.dev/core/build', 'prettier', 'vitest'], + external: ['@qwik.dev/core/build', 'prettier', 'vitest', 'jsdom'], platform: 'node', - // external: [...nodeBuiltIns], }; const esm = build({ diff --git a/scripts/util.ts b/scripts/util.ts index 176e137c1c7..a9064ed697d 100644 --- a/scripts/util.ts +++ b/scripts/util.ts @@ -20,24 +20,7 @@ import { minify, type MinifyOptions } from 'terser'; import { promisify } from 'util'; import { readPackageJson } from './package-json'; -const stringOptions = [ - 'distBindingsDir', - 'distQwikRouterPkgDir', - 'distQwikPkgDir', - 'distVersion', - 'dtsDir', - 'packagesDir', - 'platformTarget', - 'rootDir', - 'scriptsDir', - 'setDistTag', - 'srcNapiDir', - 'srcQwikRouterDir', - 'srcQwikDir', - 'startersDir', - 'tmpDir', - 'tscDir', -] as const; +const stringOptions = ['distVersion', 'platformTarget', 'setDistTag'] as const; const booleanOptions = [ 'api', 'cli', @@ -70,6 +53,21 @@ const booleanOptions = [ */ export type BuildConfig = { [key in (typeof stringOptions)[number]]: string } & { [key in (typeof booleanOptions)[number]]?: boolean; +} & { + distBindingsDir: string; + distQwikRouterPkgDir: string; + distQwikPkgDir: string; + dtsDir: string; + packagesDir: string; + rootDir: string; + scriptsDir: string; + srcNapiDir: string; + optimizerDir: string; + srcQwikRouterDir: string; + srcQwikDir: string; + startersDir: string; + tmpDir: string; + tscDir: string; }; const kebab = (str: string) => str.replace(/[A-Z]/g, (l) => `-${l.toLowerCase()}`); @@ -78,11 +76,12 @@ const kebab = (str: string) => str.replace(/[A-Z]/g, (l) => `-${l.toLowerCase()} * Create the `BuildConfig` from the process args, and set the absolute paths the build will be * reading from and writing to. */ -export function loadConfig(args: string[] = []) { +export function loadConfig(args: string[] = []): BuildConfig { const __dirname = fileURLToPath(new URL('.', import.meta.url)); const rootDir = join(__dirname, '..'); const packagesDir = join(rootDir, 'packages'); const srcQwikDir = join(packagesDir, 'qwik', 'src'); + const optimizerDir = join(packagesDir, 'qwik', 'src', 'optimizer', 'src'); const distQwikPkgDir = join(packagesDir, 'qwik', 'dist'); const tmpDir = join(rootDir, 'dist-dev'); const knownOptions = [...stringOptions, ...booleanOptions] as const; @@ -97,22 +96,6 @@ export function loadConfig(args: string[] = []) { boolean: [...booleanOptions], string: [...stringOptions], alias, - default: { - rootDir, - packagesDir, - srcQwikDir, - tmpDir, - srcQwikRouterDir: join(packagesDir, 'qwik-router', 'src'), - srcNapiDir: join(srcQwikDir, 'napi'), - scriptsDir: join(rootDir, 'scripts'), - startersDir: join(rootDir, 'starters'), - distQwikPkgDir, - distQwikRouterPkgDir: join(packagesDir, 'qwik-router', 'lib'), - distBindingsDir: join(packagesDir, 'qwik', 'bindings'), - tscDir: join(tmpDir, 'tsc-out'), - dtsDir: join(tmpDir, 'dts-out'), - esmNode: parseInt(process.version.slice(1).split('.')[0], 10) >= 14, - } as BuildConfig, }); const parseError = config._.length > 0 @@ -135,7 +118,24 @@ export function loadConfig(args: string[] = []) { process.exit(1); } - return config; + return { + ...config, + rootDir, + packagesDir, + optimizerDir, + srcQwikDir, + tmpDir, + srcQwikRouterDir: join(packagesDir, 'qwik-router', 'src'), + srcNapiDir: join(srcQwikDir, 'napi'), + scriptsDir: join(rootDir, 'scripts'), + startersDir: join(rootDir, 'starters'), + distQwikPkgDir, + distQwikRouterPkgDir: join(packagesDir, 'qwik-router', 'lib'), + distBindingsDir: join(packagesDir, 'qwik', 'bindings'), + tscDir: join(tmpDir, 'tsc-out'), + dtsDir: join(tmpDir, 'dts-out'), + esmNode: parseInt(process.version.slice(1).split('.')[0], 10) >= 14, + }; } export function terser(opts: MinifyOptions): RollupPlugin { @@ -280,8 +280,9 @@ export async function run( } } -export function panic(msg: string) { - console.error(`\nāŒ ${msg}\n`, new Error(msg).stack); +export function panic(msg: string | Error) { + const err = typeof msg === 'string' ? new Error(msg) : msg; + console.error(`\nāŒ `, err); process.exit(1); }