mirror of
https://gitlab.com/octtspacc/sitoctt
synced 2025-06-05 22:09:20 +02:00
.
This commit is contained in:
234
node_modules/@mixmark-io/domino/CSSStyleDeclaration.js
generated
vendored
Normal file
234
node_modules/@mixmark-io/domino/CSSStyleDeclaration.js
generated
vendored
Normal file
@ -0,0 +1,234 @@
|
||||
"use strict";
|
||||
|
||||
const { parse } = require('./style_parser');
|
||||
|
||||
module.exports = function (elt) {
|
||||
const style = new CSSStyleDeclaration(elt)
|
||||
const handler = {
|
||||
get: function(target, property) {
|
||||
return property in target ? target[property] : target.getPropertyValue(dasherizeProperty(property));
|
||||
},
|
||||
has: function(target, key) {
|
||||
return true;
|
||||
},
|
||||
set: function(target, property, value) {
|
||||
if (property in target) {
|
||||
target[property] = value;
|
||||
} else {
|
||||
target.setProperty(dasherizeProperty(property), value ?? undefined);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
return new Proxy(style, handler);
|
||||
};
|
||||
|
||||
function dasherizeProperty(property) {
|
||||
return property.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
|
||||
}
|
||||
|
||||
|
||||
function CSSStyleDeclaration(elt) {
|
||||
this._element = elt;
|
||||
}
|
||||
|
||||
const IMPORTANT_BANG = '!important';
|
||||
|
||||
// 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(value) {
|
||||
const result = {
|
||||
property: {},
|
||||
priority: {},
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const styleValues = parse(value);
|
||||
if (styleValues.length < 2) {
|
||||
return result;
|
||||
}
|
||||
|
||||
for (let i = 0; i < styleValues.length; i += 2) {
|
||||
const name = styleValues[i];
|
||||
let value = styleValues[i+1];
|
||||
|
||||
if (value.endsWith(IMPORTANT_BANG)) {
|
||||
result.priority[name] = 'important';
|
||||
value = value.slice(0, -IMPORTANT_BANG.length).trim();
|
||||
}
|
||||
|
||||
result.property[name] = value;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
value = value.trim();
|
||||
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();
|
||||
}
|
||||
}},
|
||||
});
|
120
node_modules/@mixmark-io/domino/CharacterData.js
generated
vendored
Normal file
120
node_modules/@mixmark-io/domino/CharacterData.js
generated
vendored
Normal file
@ -0,0 +1,120 @@
|
||||
/* 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);
|
119
node_modules/@mixmark-io/domino/ChildNode.js
generated
vendored
Normal file
119
node_modules/@mixmark-io/domino/ChildNode.js
generated
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
"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;
|
40
node_modules/@mixmark-io/domino/Comment.js
generated
vendored
Normal file
40
node_modules/@mixmark-io/domino/Comment.js
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
"use strict";
|
||||
module.exports = Comment;
|
||||
|
||||
var Node = require('./Node');
|
||||
var CharacterData = require('./CharacterData');
|
||||
|
||||
function Comment(doc, data) {
|
||||
CharacterData.call(this);
|
||||
this.nodeType = Node.COMMENT_NODE;
|
||||
this.ownerDocument = doc;
|
||||
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 = v;
|
||||
if (this.rooted)
|
||||
this.ownerDocument.mutateValue(this);
|
||||
}
|
||||
};
|
||||
|
||||
Comment.prototype = Object.create(CharacterData.prototype, {
|
||||
nodeName: { value: '#comment' },
|
||||
nodeValue: nodeValue,
|
||||
textContent: nodeValue,
|
||||
innerText: 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);
|
||||
}},
|
||||
});
|
80
node_modules/@mixmark-io/domino/ContainerNode.js
generated
vendored
Normal file
80
node_modules/@mixmark-io/domino/ContainerNode.js
generated
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
"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
|
||||
}},
|
||||
|
||||
// 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
|
||||
}},
|
||||
|
||||
});
|
12
node_modules/@mixmark-io/domino/CustomEvent.js
generated
vendored
Normal file
12
node_modules/@mixmark-io/domino/CustomEvent.js
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
"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 }
|
||||
});
|
134
node_modules/@mixmark-io/domino/DOMException.js
generated
vendored
Normal file
134
node_modules/@mixmark-io/domino/DOMException.js
generated
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
"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);
|
||||
}
|
94
node_modules/@mixmark-io/domino/DOMImplementation.js
generated
vendored
Normal file
94
node_modules/@mixmark-io/domino/DOMImplementation.js
generated
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
"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 propertly 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,
|
||||
};
|
186
node_modules/@mixmark-io/domino/DOMTokenList.js
generated
vendored
Normal file
186
node_modules/@mixmark-io/domino/DOMTokenList.js
generated
vendored
Normal file
@ -0,0 +1,186 @@
|
||||
"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;
|
||||
});
|
||||
}
|
||||
}
|
884
node_modules/@mixmark-io/domino/Document.js
generated
vendored
Normal file
884
node_modules/@mixmark-io/domino/Document.js
generated
vendored
Normal file
@ -0,0 +1,884 @@
|
||||
"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;
|
||||
};
|
71
node_modules/@mixmark-io/domino/DocumentFragment.js
generated
vendored
Normal file
71
node_modules/@mixmark-io/domino/DocumentFragment.js
generated
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
"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'),
|
||||
|
||||
// Copy the text content getter/setter from Element
|
||||
innerText: Object.getOwnPropertyDescriptor(Element.prototype, 'innerText'),
|
||||
|
||||
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
|
||||
},
|
||||
|
||||
});
|
36
node_modules/@mixmark-io/domino/DocumentType.js
generated
vendored
Normal file
36
node_modules/@mixmark-io/domino/DocumentType.js
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
"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);
|
1228
node_modules/@mixmark-io/domino/Element.js
generated
vendored
Normal file
1228
node_modules/@mixmark-io/domino/Element.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
66
node_modules/@mixmark-io/domino/Event.js
generated
vendored
Normal file
66
node_modules/@mixmark-io/domino/Event.js
generated
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
"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;
|
||||
}},
|
||||
|
||||
});
|
298
node_modules/@mixmark-io/domino/EventTarget.js
generated
vendored
Normal file
298
node_modules/@mixmark-io/domino/EventTarget.js
generated
vendored
Normal file
@ -0,0 +1,298 @@
|
||||
"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;
|
||||
}
|
||||
|
||||
};
|
92
node_modules/@mixmark-io/domino/FilteredElementList.js
generated
vendored
Normal file
92
node_modules/@mixmark-io/domino/FilteredElementList.js
generated
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
"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;
|
||||
} },
|
||||
});
|
7254
node_modules/@mixmark-io/domino/HTMLParser.js
generated
vendored
Normal file
7254
node_modules/@mixmark-io/domino/HTMLParser.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
37
node_modules/@mixmark-io/domino/Leaf.js
generated
vendored
Normal file
37
node_modules/@mixmark-io/domino/Leaf.js
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
"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;
|
||||
}}
|
||||
});
|
44
node_modules/@mixmark-io/domino/LinkedList.js
generated
vendored
Normal file
44
node_modules/@mixmark-io/domino/LinkedList.js
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
"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));
|
||||
}
|
||||
};
|
56
node_modules/@mixmark-io/domino/Location.js
generated
vendored
Normal file
56
node_modules/@mixmark-io/domino/Location.js
generated
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
"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;
|
||||
}}
|
||||
|
||||
});
|
52
node_modules/@mixmark-io/domino/MouseEvent.js
generated
vendored
Normal file
52
node_modules/@mixmark-io/domino/MouseEvent.js
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
"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;
|
||||
}
|
||||
}}
|
||||
});
|
9
node_modules/@mixmark-io/domino/MutationConstants.js
generated
vendored
Normal file
9
node_modules/@mixmark-io/domino/MutationConstants.js
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
"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
|
||||
};
|
41
node_modules/@mixmark-io/domino/NamedNodeMap.js
generated
vendored
Normal file
41
node_modules/@mixmark-io/domino/NamedNodeMap.js
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
"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();
|
||||
} },
|
||||
});
|
17
node_modules/@mixmark-io/domino/NavigatorID.js
generated
vendored
Normal file
17
node_modules/@mixmark-io/domino/NavigatorID.js
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
"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;
|
764
node_modules/@mixmark-io/domino/Node.js
generated
vendored
Normal file
764
node_modules/@mixmark-io/domino/Node.js
generated
vendored
Normal file
@ -0,0 +1,764 @@
|
||||
"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 */ },
|
||||
},
|
||||
|
||||
innerText: {
|
||||
// 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 },
|
||||
});
|
24
node_modules/@mixmark-io/domino/NodeFilter.js
generated
vendored
Normal file
24
node_modules/@mixmark-io/domino/NodeFilter.js
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
"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);
|
217
node_modules/@mixmark-io/domino/NodeIterator.js
generated
vendored
Normal file
217
node_modules/@mixmark-io/domino/NodeIterator.js
generated
vendored
Normal file
@ -0,0 +1,217 @@
|
||||
"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]";
|
||||
} },
|
||||
});
|
15
node_modules/@mixmark-io/domino/NodeList.es5.js
generated
vendored
Normal file
15
node_modules/@mixmark-io/domino/NodeList.es5.js
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
"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;
|
12
node_modules/@mixmark-io/domino/NodeList.es6.js
generated
vendored
Normal file
12
node_modules/@mixmark-io/domino/NodeList.es6.js
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
/* 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; }
|
||||
};
|
13
node_modules/@mixmark-io/domino/NodeList.js
generated
vendored
Normal file
13
node_modules/@mixmark-io/domino/NodeList.js
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
"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;
|
87
node_modules/@mixmark-io/domino/NodeTraversal.js
generated
vendored
Normal file
87
node_modules/@mixmark-io/domino/NodeTraversal.js
generated
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
"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;
|
||||
}
|
246
node_modules/@mixmark-io/domino/NodeUtils.js
generated
vendored
Normal file
246
node_modules/@mixmark-io/domino/NodeUtils.js
generated
vendored
Normal file
@ -0,0 +1,246 @@
|
||||
"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,
|
||||
|
||||
// Export util functions so that we can run extra test for them.
|
||||
// Note: we prefix function names with `ɵ`, similar to what we do
|
||||
// with internal functions in Angular packages.
|
||||
ɵescapeMatchingClosingTag: escapeMatchingClosingTag,
|
||||
ɵescapeClosingCommentTag: escapeClosingCommentTag,
|
||||
ɵescapeProcessingInstructionContent: escapeProcessingInstructionContent
|
||||
};
|
||||
|
||||
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
|
||||
*/
|
||||
};
|
||||
|
||||
const ESCAPE_REGEXP = /[&<>\u00A0]/g;
|
||||
const ESCAPE_ATTR_REGEXP = /[&"<>\u00A0]/g;
|
||||
|
||||
function escape(s) {
|
||||
if (!ESCAPE_REGEXP.test(s)) {
|
||||
// nothing to do, fast path
|
||||
return s;
|
||||
}
|
||||
|
||||
return s.replace(ESCAPE_REGEXP, (c) => {
|
||||
switch (c) {
|
||||
case "&":
|
||||
return "&";
|
||||
case "<":
|
||||
return "<";
|
||||
case ">":
|
||||
return ">";
|
||||
case "\u00A0":
|
||||
return " ";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function escapeAttr(s) {
|
||||
if (!ESCAPE_ATTR_REGEXP.test(s)) {
|
||||
// nothing to do, fast path
|
||||
return s;
|
||||
}
|
||||
|
||||
return s.replace(ESCAPE_ATTR_REGEXP, (c) => {
|
||||
switch (c) {
|
||||
case "<":
|
||||
return "<";
|
||||
case ">":
|
||||
return ">";
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes matching closing tag in a raw text.
|
||||
*
|
||||
* For example, given `<style>#text(</style><script></script>)</style>`,
|
||||
* the parent tag would by "style" and the raw text is
|
||||
* "</style><script></script>". If we come across a matching closing tag
|
||||
* (in out case `</style>`) - replace `<` with `<` to avoid unexpected
|
||||
* and unsafe behavior after de-serialization.
|
||||
*/
|
||||
function escapeMatchingClosingTag(rawText, parentTag) {
|
||||
const parentClosingTag = '</' + parentTag;
|
||||
if (!rawText.toLowerCase().includes(parentClosingTag)) {
|
||||
return rawText; // fast path
|
||||
}
|
||||
const result = [...rawText];
|
||||
const matches = rawText.matchAll(new RegExp(parentClosingTag, 'ig'));
|
||||
for (const match of matches) {
|
||||
result[match.index] = '<';
|
||||
}
|
||||
return result.join('');
|
||||
}
|
||||
|
||||
const CLOSING_COMMENT_REGEXP = /--!?>/;
|
||||
|
||||
/**
|
||||
* Escapes closing comment tag in a comment content.
|
||||
*
|
||||
* For example, given `#comment('-->')`, the content of a comment would be
|
||||
* updated to `-->` to avoid unexpected and unsafe behavior after
|
||||
* de-serialization.
|
||||
*/
|
||||
function escapeClosingCommentTag(rawContent) {
|
||||
if (!CLOSING_COMMENT_REGEXP.test(rawContent)) {
|
||||
return rawContent; // fast path
|
||||
}
|
||||
return rawContent.replace(/(--\!?)>/g, '$1>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes processing instruction content by replacing `>` with `>`.
|
||||
*/
|
||||
function escapeProcessingInstructionContent(rawContent) {
|
||||
return rawContent.includes('>')
|
||||
? rawContent.replaceAll('>', '>')
|
||||
: rawContent;
|
||||
}
|
||||
|
||||
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 an element can have raw content, this content may
|
||||
// potentially require escaping to avoid XSS.
|
||||
if (hasRawContent[tagname.toUpperCase()]) {
|
||||
ss = escapeMatchingClosingTag(ss, tagname);
|
||||
}
|
||||
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 += '<!--' + escapeClosingCommentTag(kid.data) + '-->';
|
||||
break;
|
||||
case 7: //PROCESSING_INSTRUCTION_NODE
|
||||
const content = escapeProcessingInstructionContent(kid.data);
|
||||
s += '<?' + kid.target + ' ' + content + '?>';
|
||||
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;
|
||||
}
|
26
node_modules/@mixmark-io/domino/NonDocumentTypeChildNode.js
generated
vendored
Normal file
26
node_modules/@mixmark-io/domino/NonDocumentTypeChildNode.js
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
"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;
|
44
node_modules/@mixmark-io/domino/ProcessingInstruction.js
generated
vendored
Normal file
44
node_modules/@mixmark-io/domino/ProcessingInstruction.js
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
"use strict";
|
||||
module.exports = ProcessingInstruction;
|
||||
|
||||
var Node = require('./Node');
|
||||
var CharacterData = require('./CharacterData');
|
||||
|
||||
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 = v;
|
||||
if (this.rooted) this.ownerDocument.mutateValue(this);
|
||||
}
|
||||
};
|
||||
|
||||
ProcessingInstruction.prototype = Object.create(CharacterData.prototype, {
|
||||
nodeName: { get: function() { return this.target; }},
|
||||
nodeValue: nodeValue,
|
||||
textContent: nodeValue,
|
||||
innerText: 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;
|
||||
}}
|
||||
|
||||
});
|
75
node_modules/@mixmark-io/domino/Text.js
generated
vendored
Normal file
75
node_modules/@mixmark-io/domino/Text.js
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
"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 = 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 = 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,
|
||||
innerText: 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);
|
||||
}},
|
||||
|
||||
});
|
336
node_modules/@mixmark-io/domino/TreeWalker.js
generated
vendored
Normal file
336
node_modules/@mixmark-io/domino/TreeWalker.js
generated
vendored
Normal file
@ -0,0 +1,336 @@
|
||||
"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]";
|
||||
}},
|
||||
});
|
19
node_modules/@mixmark-io/domino/UIEvent.js
generated
vendored
Normal file
19
node_modules/@mixmark-io/domino/UIEvent.js
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
"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;
|
||||
}}
|
||||
});
|
194
node_modules/@mixmark-io/domino/URL.js
generated
vendored
Normal file
194
node_modules/@mixmark-io/domino/URL.js
generated
vendored
Normal file
@ -0,0 +1,194 @@
|
||||
"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;
|
||||
}
|
||||
},
|
||||
};
|
270
node_modules/@mixmark-io/domino/URLUtils.js
generated
vendored
Normal file
270
node_modules/@mixmark-io/domino/URLUtils.js
generated
vendored
Normal file
@ -0,0 +1,270 @@
|
||||
"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);
|
||||
});
|
||||
};
|
60
node_modules/@mixmark-io/domino/Window.js
generated
vendored
Normal file
60
node_modules/@mixmark-io/domino/Window.js
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
"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);
|
11
node_modules/@mixmark-io/domino/WindowTimers.js
generated
vendored
Normal file
11
node_modules/@mixmark-io/domino/WindowTimers.js
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
"use strict";
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/webappapis.html#windowtimers
|
||||
var WindowTimers = {
|
||||
setTimeout: setTimeout,
|
||||
clearTimeout: clearTimeout,
|
||||
setInterval: setInterval,
|
||||
clearInterval: clearInterval
|
||||
};
|
||||
|
||||
module.exports = WindowTimers;
|
152
node_modules/@mixmark-io/domino/attributes.js
generated
vendored
Normal file
152
node_modules/@mixmark-io/domino/attributes.js
generated
vendored
Normal file
@ -0,0 +1,152 @@
|
||||
"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;
|
||||
};
|
7
node_modules/@mixmark-io/domino/config.js
generated
vendored
Normal file
7
node_modules/@mixmark-io/domino/config.js
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* 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 = !globalThis.__domino_frozen__;
|
71
node_modules/@mixmark-io/domino/defineElement.js
generated
vendored
Normal file
71
node_modules/@mixmark-io/domino/defineElement.js
generated
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
"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);
|
||||
});
|
||||
}
|
7
node_modules/@mixmark-io/domino/events.js
generated
vendored
Normal file
7
node_modules/@mixmark-io/domino/events.js
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
"use strict";
|
||||
module.exports = {
|
||||
Event: require('./Event'),
|
||||
UIEvent: require('./UIEvent'),
|
||||
MouseEvent: require('./MouseEvent'),
|
||||
CustomEvent: require('./CustomEvent')
|
||||
};
|
1499
node_modules/@mixmark-io/domino/htmlelts.js
generated
vendored
Normal file
1499
node_modules/@mixmark-io/domino/htmlelts.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
27
node_modules/@mixmark-io/domino/impl.js
generated
vendored
Normal file
27
node_modules/@mixmark-io/domino/impl.js
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
"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);
|
5
node_modules/@mixmark-io/domino/index.d.ts
generated
vendored
Normal file
5
node_modules/@mixmark-io/domino/index.d.ts
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
declare module 'domino' {
|
||||
function createDOMImplementation(): DOMImplementation;
|
||||
function createDocument(html?: string, force?: boolean): Document;
|
||||
function createWindow(html?: string, address?: string): Window;
|
||||
}
|
80
node_modules/@mixmark-io/domino/index.js
generated
vendored
Normal file
80
node_modules/@mixmark-io/domino/index.js
generated
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
"use strict";
|
||||
var DOMImplementation = require('./DOMImplementation');
|
||||
var HTMLParser = require('./HTMLParser');
|
||||
var Window = require('./Window');
|
||||
var impl = require('./impl');
|
||||
|
||||
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.createWindow = function(html, address) {
|
||||
var document = exports.createDocument(html);
|
||||
if (address !== undefined) { document._address = address; }
|
||||
return new impl.Window(document);
|
||||
};
|
||||
|
||||
exports.impl = impl;
|
933
node_modules/@mixmark-io/domino/select.js
generated
vendored
Normal file
933
node_modules/@mixmark-io/domino/select.js
generated
vendored
Normal file
@ -0,0 +1,933 @@
|
||||
"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;
|
||||
};
|
106
node_modules/@mixmark-io/domino/style_parser.js
generated
vendored
Normal file
106
node_modules/@mixmark-io/domino/style_parser.js
generated
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
"use strict";
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// The below is a compiled copy of https://github.com/angular/angular/blob/92e41e9cb417223d9888a4c23b4c0e73188f87d0/packages/compiler/src/render3/view/style_parser.ts
|
||||
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.hyphenate = exports.parse = void 0;
|
||||
/**
|
||||
* Parses string representation of a style and converts it into object literal.
|
||||
*
|
||||
* @param value string representation of style as used in the `style` attribute in HTML.
|
||||
* Example: `color: red; height: auto`.
|
||||
* @returns An array of style property name and value pairs, e.g. `['color', 'red', 'height',
|
||||
* 'auto']`
|
||||
*/
|
||||
function parse(value) {
|
||||
// we use a string array here instead of a string map
|
||||
// because a string-map is not guaranteed to retain the
|
||||
// order of the entries whereas a string array can be
|
||||
// constructed in a [key, value, key, value] format.
|
||||
const styles = [];
|
||||
let i = 0;
|
||||
let parenDepth = 0;
|
||||
let quote = 0; /* Char.QuoteNone */
|
||||
let valueStart = 0;
|
||||
let propStart = 0;
|
||||
let currentProp = null;
|
||||
while (i < value.length) {
|
||||
const token = value.charCodeAt(i++);
|
||||
switch (token) {
|
||||
case 40 /* Char.OpenParen */:
|
||||
parenDepth++;
|
||||
break;
|
||||
case 41 /* Char.CloseParen */:
|
||||
parenDepth--;
|
||||
break;
|
||||
case 39 /* Char.QuoteSingle */:
|
||||
// valueStart needs to be there since prop values don't
|
||||
// have quotes in CSS
|
||||
if (quote === 0 /* Char.QuoteNone */) {
|
||||
quote = 39 /* Char.QuoteSingle */;
|
||||
} else if (
|
||||
quote === 39 /* Char.QuoteSingle */ &&
|
||||
value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */
|
||||
) {
|
||||
quote = 0 /* Char.QuoteNone */;
|
||||
}
|
||||
break;
|
||||
case 34 /* Char.QuoteDouble */:
|
||||
// same logic as above
|
||||
if (quote === 0 /* Char.QuoteNone */) {
|
||||
quote = 34 /* Char.QuoteDouble */;
|
||||
} else if (
|
||||
quote === 34 /* Char.QuoteDouble */ &&
|
||||
value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */
|
||||
) {
|
||||
quote = 0 /* Char.QuoteNone */;
|
||||
}
|
||||
break;
|
||||
case 58 /* Char.Colon */:
|
||||
if (
|
||||
!currentProp &&
|
||||
parenDepth === 0 &&
|
||||
quote === 0 /* Char.QuoteNone */
|
||||
) {
|
||||
currentProp = hyphenate(value.substring(propStart, i - 1).trim());
|
||||
valueStart = i;
|
||||
}
|
||||
break;
|
||||
case 59 /* Char.Semicolon */:
|
||||
if (
|
||||
currentProp &&
|
||||
valueStart > 0 &&
|
||||
parenDepth === 0 &&
|
||||
quote === 0 /* Char.QuoteNone */
|
||||
) {
|
||||
const styleVal = value.substring(valueStart, i - 1).trim();
|
||||
styles.push(currentProp, styleVal);
|
||||
propStart = i;
|
||||
valueStart = 0;
|
||||
currentProp = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (currentProp && valueStart) {
|
||||
const styleVal = value.slice(valueStart).trim();
|
||||
styles.push(currentProp, styleVal);
|
||||
}
|
||||
return styles;
|
||||
}
|
||||
exports.parse = parse;
|
||||
function hyphenate(value) {
|
||||
return value
|
||||
.replace(/[a-z][A-Z]/g, (v) => {
|
||||
return v.charAt(0) + "-" + v.charAt(1);
|
||||
})
|
||||
.toLowerCase();
|
||||
}
|
||||
exports.hyphenate = hyphenate;
|
59
node_modules/@mixmark-io/domino/svg.js
generated
vendored
Normal file
59
node_modules/@mixmark-io/domino/svg.js
generated
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
"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'
|
||||
]
|
||||
});
|
85
node_modules/@mixmark-io/domino/utils.js
generated
vendored
Normal file
85
node_modules/@mixmark-io/domino/utils.js
generated
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
"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];
|
||||
}
|
||||
};
|
||||
|
||||
// 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();
|
||||
});
|
||||
};
|
91
node_modules/@mixmark-io/domino/xmlnames.js
generated
vendored
Normal file
91
node_modules/@mixmark-io/domino/xmlnames.js
generated
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
"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;
|
||||
}
|
953
node_modules/turndown.js
generated
vendored
Normal file
953
node_modules/turndown.js
generated
vendored
Normal file
@ -0,0 +1,953 @@
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
||||
typeof define === 'function' && define.amd ? define(factory) :
|
||||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.TurndownService = factory());
|
||||
}(this, (function () { 'use strict';
|
||||
|
||||
function extend (destination) {
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
var source = arguments[i];
|
||||
for (var key in source) {
|
||||
if (source.hasOwnProperty(key)) destination[key] = source[key];
|
||||
}
|
||||
}
|
||||
return destination
|
||||
}
|
||||
|
||||
function repeat (character, count) {
|
||||
return Array(count + 1).join(character)
|
||||
}
|
||||
|
||||
function trimLeadingNewlines (string) {
|
||||
return string.replace(/^\n*/, '')
|
||||
}
|
||||
|
||||
function trimTrailingNewlines (string) {
|
||||
// avoid match-at-end regexp bottleneck, see #370
|
||||
var indexEnd = string.length;
|
||||
while (indexEnd > 0 && string[indexEnd - 1] === '\n') indexEnd--;
|
||||
return string.substring(0, indexEnd)
|
||||
}
|
||||
|
||||
var blockElements = [
|
||||
'ADDRESS', 'ARTICLE', 'ASIDE', 'AUDIO', 'BLOCKQUOTE', 'BODY', 'CANVAS',
|
||||
'CENTER', 'DD', 'DIR', 'DIV', 'DL', 'DT', 'FIELDSET', 'FIGCAPTION', 'FIGURE',
|
||||
'FOOTER', 'FORM', 'FRAMESET', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEADER',
|
||||
'HGROUP', 'HR', 'HTML', 'ISINDEX', 'LI', 'MAIN', 'MENU', 'NAV', 'NOFRAMES',
|
||||
'NOSCRIPT', 'OL', 'OUTPUT', 'P', 'PRE', 'SECTION', 'TABLE', 'TBODY', 'TD',
|
||||
'TFOOT', 'TH', 'THEAD', 'TR', 'UL'
|
||||
];
|
||||
|
||||
function isBlock (node) {
|
||||
return is(node, blockElements)
|
||||
}
|
||||
|
||||
var voidElements = [
|
||||
'AREA', 'BASE', 'BR', 'COL', 'COMMAND', 'EMBED', 'HR', 'IMG', 'INPUT',
|
||||
'KEYGEN', 'LINK', 'META', 'PARAM', 'SOURCE', 'TRACK', 'WBR'
|
||||
];
|
||||
|
||||
function isVoid (node) {
|
||||
return is(node, voidElements)
|
||||
}
|
||||
|
||||
function hasVoid (node) {
|
||||
return has(node, voidElements)
|
||||
}
|
||||
|
||||
var meaningfulWhenBlankElements = [
|
||||
'A', 'TABLE', 'THEAD', 'TBODY', 'TFOOT', 'TH', 'TD', 'IFRAME', 'SCRIPT',
|
||||
'AUDIO', 'VIDEO'
|
||||
];
|
||||
|
||||
function isMeaningfulWhenBlank (node) {
|
||||
return is(node, meaningfulWhenBlankElements)
|
||||
}
|
||||
|
||||
function hasMeaningfulWhenBlank (node) {
|
||||
return has(node, meaningfulWhenBlankElements)
|
||||
}
|
||||
|
||||
function is (node, tagNames) {
|
||||
return tagNames.indexOf(node.nodeName) >= 0
|
||||
}
|
||||
|
||||
function has (node, tagNames) {
|
||||
return (
|
||||
node.getElementsByTagName &&
|
||||
tagNames.some(function (tagName) {
|
||||
return node.getElementsByTagName(tagName).length
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
var rules = {};
|
||||
|
||||
rules.paragraph = {
|
||||
filter: 'p',
|
||||
|
||||
replacement: function (content) {
|
||||
return '\n\n' + content + '\n\n'
|
||||
}
|
||||
};
|
||||
|
||||
rules.lineBreak = {
|
||||
filter: 'br',
|
||||
|
||||
replacement: function (content, node, options) {
|
||||
return options.br + '\n'
|
||||
}
|
||||
};
|
||||
|
||||
rules.heading = {
|
||||
filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
|
||||
|
||||
replacement: function (content, node, options) {
|
||||
var hLevel = Number(node.nodeName.charAt(1));
|
||||
|
||||
if (options.headingStyle === 'setext' && hLevel < 3) {
|
||||
var underline = repeat((hLevel === 1 ? '=' : '-'), content.length);
|
||||
return (
|
||||
'\n\n' + content + '\n' + underline + '\n\n'
|
||||
)
|
||||
} else {
|
||||
return '\n\n' + repeat('#', hLevel) + ' ' + content + '\n\n'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
rules.blockquote = {
|
||||
filter: 'blockquote',
|
||||
|
||||
replacement: function (content) {
|
||||
content = content.replace(/^\n+|\n+$/g, '');
|
||||
content = content.replace(/^/gm, '> ');
|
||||
return '\n\n' + content + '\n\n'
|
||||
}
|
||||
};
|
||||
|
||||
rules.list = {
|
||||
filter: ['ul', 'ol'],
|
||||
|
||||
replacement: function (content, node) {
|
||||
var parent = node.parentNode;
|
||||
if (parent.nodeName === 'LI' && parent.lastElementChild === node) {
|
||||
return '\n' + content
|
||||
} else {
|
||||
return '\n\n' + content + '\n\n'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
rules.listItem = {
|
||||
filter: 'li',
|
||||
|
||||
replacement: function (content, node, options) {
|
||||
content = content
|
||||
.replace(/^\n+/, '') // remove leading newlines
|
||||
.replace(/\n+$/, '\n') // replace trailing newlines with just a single one
|
||||
.replace(/\n/gm, '\n '); // indent
|
||||
var prefix = options.bulletListMarker + ' ';
|
||||
var parent = node.parentNode;
|
||||
if (parent.nodeName === 'OL') {
|
||||
var start = parent.getAttribute('start');
|
||||
var index = Array.prototype.indexOf.call(parent.children, node);
|
||||
prefix = (start ? Number(start) + index : index + 1) + '. ';
|
||||
}
|
||||
return (
|
||||
prefix + content + (node.nextSibling && !/\n$/.test(content) ? '\n' : '')
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
rules.indentedCodeBlock = {
|
||||
filter: function (node, options) {
|
||||
return (
|
||||
options.codeBlockStyle === 'indented' &&
|
||||
node.nodeName === 'PRE' &&
|
||||
node.firstChild &&
|
||||
node.firstChild.nodeName === 'CODE'
|
||||
)
|
||||
},
|
||||
|
||||
replacement: function (content, node, options) {
|
||||
return (
|
||||
'\n\n ' +
|
||||
node.firstChild.textContent.replace(/\n/g, '\n ') +
|
||||
'\n\n'
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
rules.fencedCodeBlock = {
|
||||
filter: function (node, options) {
|
||||
return (
|
||||
options.codeBlockStyle === 'fenced' &&
|
||||
node.nodeName === 'PRE' &&
|
||||
node.firstChild &&
|
||||
node.firstChild.nodeName === 'CODE'
|
||||
)
|
||||
},
|
||||
|
||||
replacement: function (content, node, options) {
|
||||
var className = node.firstChild.getAttribute('class') || '';
|
||||
var language = (className.match(/language-(\S+)/) || [null, ''])[1];
|
||||
var code = node.firstChild.textContent;
|
||||
|
||||
var fenceChar = options.fence.charAt(0);
|
||||
var fenceSize = 3;
|
||||
var fenceInCodeRegex = new RegExp('^' + fenceChar + '{3,}', 'gm');
|
||||
|
||||
var match;
|
||||
while ((match = fenceInCodeRegex.exec(code))) {
|
||||
if (match[0].length >= fenceSize) {
|
||||
fenceSize = match[0].length + 1;
|
||||
}
|
||||
}
|
||||
|
||||
var fence = repeat(fenceChar, fenceSize);
|
||||
|
||||
return (
|
||||
'\n\n' + fence + language + '\n' +
|
||||
code.replace(/\n$/, '') +
|
||||
'\n' + fence + '\n\n'
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
rules.horizontalRule = {
|
||||
filter: 'hr',
|
||||
|
||||
replacement: function (content, node, options) {
|
||||
return '\n\n' + options.hr + '\n\n'
|
||||
}
|
||||
};
|
||||
|
||||
rules.inlineLink = {
|
||||
filter: function (node, options) {
|
||||
return (
|
||||
options.linkStyle === 'inlined' &&
|
||||
node.nodeName === 'A' &&
|
||||
node.getAttribute('href')
|
||||
)
|
||||
},
|
||||
|
||||
replacement: function (content, node) {
|
||||
var href = node.getAttribute('href');
|
||||
if (href) href = href.replace(/([()])/g, '\\$1');
|
||||
var title = cleanAttribute(node.getAttribute('title'));
|
||||
if (title) title = ' "' + title.replace(/"/g, '\\"') + '"';
|
||||
return '[' + content + '](' + href + title + ')'
|
||||
}
|
||||
};
|
||||
|
||||
rules.referenceLink = {
|
||||
filter: function (node, options) {
|
||||
return (
|
||||
options.linkStyle === 'referenced' &&
|
||||
node.nodeName === 'A' &&
|
||||
node.getAttribute('href')
|
||||
)
|
||||
},
|
||||
|
||||
replacement: function (content, node, options) {
|
||||
var href = node.getAttribute('href');
|
||||
var title = cleanAttribute(node.getAttribute('title'));
|
||||
if (title) title = ' "' + title + '"';
|
||||
var replacement;
|
||||
var reference;
|
||||
|
||||
switch (options.linkReferenceStyle) {
|
||||
case 'collapsed':
|
||||
replacement = '[' + content + '][]';
|
||||
reference = '[' + content + ']: ' + href + title;
|
||||
break
|
||||
case 'shortcut':
|
||||
replacement = '[' + content + ']';
|
||||
reference = '[' + content + ']: ' + href + title;
|
||||
break
|
||||
default:
|
||||
var id = this.references.length + 1;
|
||||
replacement = '[' + content + '][' + id + ']';
|
||||
reference = '[' + id + ']: ' + href + title;
|
||||
}
|
||||
|
||||
this.references.push(reference);
|
||||
return replacement
|
||||
},
|
||||
|
||||
references: [],
|
||||
|
||||
append: function (options) {
|
||||
var references = '';
|
||||
if (this.references.length) {
|
||||
references = '\n\n' + this.references.join('\n') + '\n\n';
|
||||
this.references = []; // Reset references
|
||||
}
|
||||
return references
|
||||
}
|
||||
};
|
||||
|
||||
rules.emphasis = {
|
||||
filter: ['em', 'i'],
|
||||
|
||||
replacement: function (content, node, options) {
|
||||
if (!content.trim()) return ''
|
||||
return options.emDelimiter + content + options.emDelimiter
|
||||
}
|
||||
};
|
||||
|
||||
rules.strong = {
|
||||
filter: ['strong', 'b'],
|
||||
|
||||
replacement: function (content, node, options) {
|
||||
if (!content.trim()) return ''
|
||||
return options.strongDelimiter + content + options.strongDelimiter
|
||||
}
|
||||
};
|
||||
|
||||
rules.code = {
|
||||
filter: function (node) {
|
||||
var hasSiblings = node.previousSibling || node.nextSibling;
|
||||
var isCodeBlock = node.parentNode.nodeName === 'PRE' && !hasSiblings;
|
||||
|
||||
return node.nodeName === 'CODE' && !isCodeBlock
|
||||
},
|
||||
|
||||
replacement: function (content) {
|
||||
if (!content) return ''
|
||||
content = content.replace(/\r?\n|\r/g, ' ');
|
||||
|
||||
var extraSpace = /^`|^ .*?[^ ].* $|`$/.test(content) ? ' ' : '';
|
||||
var delimiter = '`';
|
||||
var matches = content.match(/`+/gm) || [];
|
||||
while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`';
|
||||
|
||||
return delimiter + extraSpace + content + extraSpace + delimiter
|
||||
}
|
||||
};
|
||||
|
||||
rules.image = {
|
||||
filter: 'img',
|
||||
|
||||
replacement: function (content, node) {
|
||||
var alt = cleanAttribute(node.getAttribute('alt'));
|
||||
var src = node.getAttribute('src') || '';
|
||||
var title = cleanAttribute(node.getAttribute('title'));
|
||||
var titlePart = title ? ' "' + title + '"' : '';
|
||||
return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : ''
|
||||
}
|
||||
};
|
||||
|
||||
function cleanAttribute (attribute) {
|
||||
return attribute ? attribute.replace(/(\n+\s*)+/g, '\n') : ''
|
||||
}
|
||||
|
||||
/**
|
||||
* Manages a collection of rules used to convert HTML to Markdown
|
||||
*/
|
||||
|
||||
function Rules (options) {
|
||||
this.options = options;
|
||||
this._keep = [];
|
||||
this._remove = [];
|
||||
|
||||
this.blankRule = {
|
||||
replacement: options.blankReplacement
|
||||
};
|
||||
|
||||
this.keepReplacement = options.keepReplacement;
|
||||
|
||||
this.defaultRule = {
|
||||
replacement: options.defaultReplacement
|
||||
};
|
||||
|
||||
this.array = [];
|
||||
for (var key in options.rules) this.array.push(options.rules[key]);
|
||||
}
|
||||
|
||||
Rules.prototype = {
|
||||
add: function (key, rule) {
|
||||
this.array.unshift(rule);
|
||||
},
|
||||
|
||||
keep: function (filter) {
|
||||
this._keep.unshift({
|
||||
filter: filter,
|
||||
replacement: this.keepReplacement
|
||||
});
|
||||
},
|
||||
|
||||
remove: function (filter) {
|
||||
this._remove.unshift({
|
||||
filter: filter,
|
||||
replacement: function () {
|
||||
return ''
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
forNode: function (node) {
|
||||
if (node.isBlank) return this.blankRule
|
||||
var rule;
|
||||
|
||||
if ((rule = findRule(this.array, node, this.options))) return rule
|
||||
if ((rule = findRule(this._keep, node, this.options))) return rule
|
||||
if ((rule = findRule(this._remove, node, this.options))) return rule
|
||||
|
||||
return this.defaultRule
|
||||
},
|
||||
|
||||
forEach: function (fn) {
|
||||
for (var i = 0; i < this.array.length; i++) fn(this.array[i], i);
|
||||
}
|
||||
};
|
||||
|
||||
function findRule (rules, node, options) {
|
||||
for (var i = 0; i < rules.length; i++) {
|
||||
var rule = rules[i];
|
||||
if (filterValue(rule, node, options)) return rule
|
||||
}
|
||||
return void 0
|
||||
}
|
||||
|
||||
function filterValue (rule, node, options) {
|
||||
var filter = rule.filter;
|
||||
if (typeof filter === 'string') {
|
||||
if (filter === node.nodeName.toLowerCase()) return true
|
||||
} else if (Array.isArray(filter)) {
|
||||
if (filter.indexOf(node.nodeName.toLowerCase()) > -1) return true
|
||||
} else if (typeof filter === 'function') {
|
||||
if (filter.call(rule, node, options)) return true
|
||||
} else {
|
||||
throw new TypeError('`filter` needs to be a string, array, or function')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The collapseWhitespace function is adapted from collapse-whitespace
|
||||
* by Luc Thevenard.
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Luc Thevenard <lucthevenard@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* collapseWhitespace(options) removes extraneous whitespace from an the given element.
|
||||
*
|
||||
* @param {Object} options
|
||||
*/
|
||||
function collapseWhitespace (options) {
|
||||
var element = options.element;
|
||||
var isBlock = options.isBlock;
|
||||
var isVoid = options.isVoid;
|
||||
var isPre = options.isPre || function (node) {
|
||||
return node.nodeName === 'PRE'
|
||||
};
|
||||
|
||||
if (!element.firstChild || isPre(element)) return
|
||||
|
||||
var prevText = null;
|
||||
var keepLeadingWs = false;
|
||||
|
||||
var prev = null;
|
||||
var node = next(prev, element, isPre);
|
||||
|
||||
while (node !== element) {
|
||||
if (node.nodeType === 3 || node.nodeType === 4) { // Node.TEXT_NODE or Node.CDATA_SECTION_NODE
|
||||
var text = node.data.replace(/[ \r\n\t]+/g, ' ');
|
||||
|
||||
if ((!prevText || / $/.test(prevText.data)) &&
|
||||
!keepLeadingWs && text[0] === ' ') {
|
||||
text = text.substr(1);
|
||||
}
|
||||
|
||||
// `text` might be empty at this point.
|
||||
if (!text) {
|
||||
node = remove(node);
|
||||
continue
|
||||
}
|
||||
|
||||
node.data = text;
|
||||
|
||||
prevText = node;
|
||||
} else if (node.nodeType === 1) { // Node.ELEMENT_NODE
|
||||
if (isBlock(node) || node.nodeName === 'BR') {
|
||||
if (prevText) {
|
||||
prevText.data = prevText.data.replace(/ $/, '');
|
||||
}
|
||||
|
||||
prevText = null;
|
||||
keepLeadingWs = false;
|
||||
} else if (isVoid(node) || isPre(node)) {
|
||||
// Avoid trimming space around non-block, non-BR void elements and inline PRE.
|
||||
prevText = null;
|
||||
keepLeadingWs = true;
|
||||
} else if (prevText) {
|
||||
// Drop protection if set previously.
|
||||
keepLeadingWs = false;
|
||||
}
|
||||
} else {
|
||||
node = remove(node);
|
||||
continue
|
||||
}
|
||||
|
||||
var nextNode = next(prev, node, isPre);
|
||||
prev = node;
|
||||
node = nextNode;
|
||||
}
|
||||
|
||||
if (prevText) {
|
||||
prevText.data = prevText.data.replace(/ $/, '');
|
||||
if (!prevText.data) {
|
||||
remove(prevText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* remove(node) removes the given node from the DOM and returns the
|
||||
* next node in the sequence.
|
||||
*
|
||||
* @param {Node} node
|
||||
* @return {Node} node
|
||||
*/
|
||||
function remove (node) {
|
||||
var next = node.nextSibling || node.parentNode;
|
||||
|
||||
node.parentNode.removeChild(node);
|
||||
|
||||
return next
|
||||
}
|
||||
|
||||
/**
|
||||
* next(prev, current, isPre) returns the next node in the sequence, given the
|
||||
* current and previous nodes.
|
||||
*
|
||||
* @param {Node} prev
|
||||
* @param {Node} current
|
||||
* @param {Function} isPre
|
||||
* @return {Node}
|
||||
*/
|
||||
function next (prev, current, isPre) {
|
||||
if ((prev && prev.parentNode === current) || isPre(current)) {
|
||||
return current.nextSibling || current.parentNode
|
||||
}
|
||||
|
||||
return current.firstChild || current.nextSibling || current.parentNode
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up window for Node.js
|
||||
*/
|
||||
|
||||
var root = (typeof window !== 'undefined' ? window : {});
|
||||
|
||||
/*
|
||||
* Parsing HTML strings
|
||||
*/
|
||||
|
||||
function canParseHTMLNatively () {
|
||||
var Parser = root.DOMParser;
|
||||
var canParse = false;
|
||||
|
||||
// Adapted from https://gist.github.com/1129031
|
||||
// Firefox/Opera/IE throw errors on unsupported types
|
||||
try {
|
||||
// WebKit returns null on unsupported types
|
||||
if (new Parser().parseFromString('', 'text/html')) {
|
||||
canParse = true;
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
return canParse
|
||||
}
|
||||
|
||||
function createHTMLParser () {
|
||||
var Parser = function () {};
|
||||
|
||||
{
|
||||
var domino = require('@mixmark-io/domino');
|
||||
Parser.prototype.parseFromString = function (string) {
|
||||
return domino.createDocument(string)
|
||||
};
|
||||
}
|
||||
return Parser
|
||||
}
|
||||
|
||||
var HTMLParser = canParseHTMLNatively() ? root.DOMParser : createHTMLParser();
|
||||
|
||||
function RootNode (input, options) {
|
||||
var root;
|
||||
if (typeof input === 'string') {
|
||||
var doc = htmlParser().parseFromString(
|
||||
// DOM parsers arrange elements in the <head> and <body>.
|
||||
// Wrapping in a custom element ensures elements are reliably arranged in
|
||||
// a single element.
|
||||
'<x-turndown id="turndown-root">' + input + '</x-turndown>',
|
||||
'text/html'
|
||||
);
|
||||
root = doc.getElementById('turndown-root');
|
||||
} else {
|
||||
root = input.cloneNode(true);
|
||||
}
|
||||
collapseWhitespace({
|
||||
element: root,
|
||||
isBlock: isBlock,
|
||||
isVoid: isVoid,
|
||||
isPre: options.preformattedCode ? isPreOrCode : null
|
||||
});
|
||||
|
||||
return root
|
||||
}
|
||||
|
||||
var _htmlParser;
|
||||
function htmlParser () {
|
||||
_htmlParser = _htmlParser || new HTMLParser();
|
||||
return _htmlParser
|
||||
}
|
||||
|
||||
function isPreOrCode (node) {
|
||||
return node.nodeName === 'PRE' || node.nodeName === 'CODE'
|
||||
}
|
||||
|
||||
function Node (node, options) {
|
||||
node.isBlock = isBlock(node);
|
||||
node.isCode = node.nodeName === 'CODE' || node.parentNode.isCode;
|
||||
node.isBlank = isBlank(node);
|
||||
node.flankingWhitespace = flankingWhitespace(node, options);
|
||||
return node
|
||||
}
|
||||
|
||||
function isBlank (node) {
|
||||
return (
|
||||
!isVoid(node) &&
|
||||
!isMeaningfulWhenBlank(node) &&
|
||||
/^\s*$/i.test(node.textContent) &&
|
||||
!hasVoid(node) &&
|
||||
!hasMeaningfulWhenBlank(node)
|
||||
)
|
||||
}
|
||||
|
||||
function flankingWhitespace (node, options) {
|
||||
if (node.isBlock || (options.preformattedCode && node.isCode)) {
|
||||
return { leading: '', trailing: '' }
|
||||
}
|
||||
|
||||
var edges = edgeWhitespace(node.textContent);
|
||||
|
||||
// abandon leading ASCII WS if left-flanked by ASCII WS
|
||||
if (edges.leadingAscii && isFlankedByWhitespace('left', node, options)) {
|
||||
edges.leading = edges.leadingNonAscii;
|
||||
}
|
||||
|
||||
// abandon trailing ASCII WS if right-flanked by ASCII WS
|
||||
if (edges.trailingAscii && isFlankedByWhitespace('right', node, options)) {
|
||||
edges.trailing = edges.trailingNonAscii;
|
||||
}
|
||||
|
||||
return { leading: edges.leading, trailing: edges.trailing }
|
||||
}
|
||||
|
||||
function edgeWhitespace (string) {
|
||||
var m = string.match(/^(([ \t\r\n]*)(\s*))(?:(?=\S)[\s\S]*\S)?((\s*?)([ \t\r\n]*))$/);
|
||||
return {
|
||||
leading: m[1], // whole string for whitespace-only strings
|
||||
leadingAscii: m[2],
|
||||
leadingNonAscii: m[3],
|
||||
trailing: m[4], // empty for whitespace-only strings
|
||||
trailingNonAscii: m[5],
|
||||
trailingAscii: m[6]
|
||||
}
|
||||
}
|
||||
|
||||
function isFlankedByWhitespace (side, node, options) {
|
||||
var sibling;
|
||||
var regExp;
|
||||
var isFlanked;
|
||||
|
||||
if (side === 'left') {
|
||||
sibling = node.previousSibling;
|
||||
regExp = / $/;
|
||||
} else {
|
||||
sibling = node.nextSibling;
|
||||
regExp = /^ /;
|
||||
}
|
||||
|
||||
if (sibling) {
|
||||
if (sibling.nodeType === 3) {
|
||||
isFlanked = regExp.test(sibling.nodeValue);
|
||||
} else if (options.preformattedCode && sibling.nodeName === 'CODE') {
|
||||
isFlanked = false;
|
||||
} else if (sibling.nodeType === 1 && !isBlock(sibling)) {
|
||||
isFlanked = regExp.test(sibling.textContent);
|
||||
}
|
||||
}
|
||||
return isFlanked
|
||||
}
|
||||
|
||||
var reduce = Array.prototype.reduce;
|
||||
var escapes = [
|
||||
[/\\/g, '\\\\'],
|
||||
[/\*/g, '\\*'],
|
||||
[/^-/g, '\\-'],
|
||||
[/^\+ /g, '\\+ '],
|
||||
[/^(=+)/g, '\\$1'],
|
||||
[/^(#{1,6}) /g, '\\$1 '],
|
||||
[/`/g, '\\`'],
|
||||
[/^~~~/g, '\\~~~'],
|
||||
[/\[/g, '\\['],
|
||||
[/\]/g, '\\]'],
|
||||
[/^>/g, '\\>'],
|
||||
[/_/g, '\\_'],
|
||||
[/^(\d+)\. /g, '$1\\. ']
|
||||
];
|
||||
|
||||
function TurndownService (options) {
|
||||
if (!(this instanceof TurndownService)) return new TurndownService(options)
|
||||
|
||||
var defaults = {
|
||||
rules: rules,
|
||||
headingStyle: 'setext',
|
||||
hr: '* * *',
|
||||
bulletListMarker: '*',
|
||||
codeBlockStyle: 'indented',
|
||||
fence: '```',
|
||||
emDelimiter: '_',
|
||||
strongDelimiter: '**',
|
||||
linkStyle: 'inlined',
|
||||
linkReferenceStyle: 'full',
|
||||
br: ' ',
|
||||
preformattedCode: false,
|
||||
blankReplacement: function (content, node) {
|
||||
return node.isBlock ? '\n\n' : ''
|
||||
},
|
||||
keepReplacement: function (content, node) {
|
||||
return node.isBlock ? '\n\n' + node.outerHTML + '\n\n' : node.outerHTML
|
||||
},
|
||||
defaultReplacement: function (content, node) {
|
||||
return node.isBlock ? '\n\n' + content + '\n\n' : content
|
||||
}
|
||||
};
|
||||
this.options = extend({}, defaults, options);
|
||||
this.rules = new Rules(this.options);
|
||||
}
|
||||
|
||||
TurndownService.prototype = {
|
||||
/**
|
||||
* The entry point for converting a string or DOM node to Markdown
|
||||
* @public
|
||||
* @param {String|HTMLElement} input The string or DOM node to convert
|
||||
* @returns A Markdown representation of the input
|
||||
* @type String
|
||||
*/
|
||||
|
||||
turndown: function (input) {
|
||||
if (!canConvert(input)) {
|
||||
throw new TypeError(
|
||||
input + ' is not a string, or an element/document/fragment node.'
|
||||
)
|
||||
}
|
||||
|
||||
if (input === '') return ''
|
||||
|
||||
var output = process.call(this, new RootNode(input, this.options));
|
||||
return postProcess.call(this, output)
|
||||
},
|
||||
|
||||
/**
|
||||
* Add one or more plugins
|
||||
* @public
|
||||
* @param {Function|Array} plugin The plugin or array of plugins to add
|
||||
* @returns The Turndown instance for chaining
|
||||
* @type Object
|
||||
*/
|
||||
|
||||
use: function (plugin) {
|
||||
if (Array.isArray(plugin)) {
|
||||
for (var i = 0; i < plugin.length; i++) this.use(plugin[i]);
|
||||
} else if (typeof plugin === 'function') {
|
||||
plugin(this);
|
||||
} else {
|
||||
throw new TypeError('plugin must be a Function or an Array of Functions')
|
||||
}
|
||||
return this
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a rule
|
||||
* @public
|
||||
* @param {String} key The unique key of the rule
|
||||
* @param {Object} rule The rule
|
||||
* @returns The Turndown instance for chaining
|
||||
* @type Object
|
||||
*/
|
||||
|
||||
addRule: function (key, rule) {
|
||||
this.rules.add(key, rule);
|
||||
return this
|
||||
},
|
||||
|
||||
/**
|
||||
* Keep a node (as HTML) that matches the filter
|
||||
* @public
|
||||
* @param {String|Array|Function} filter The unique key of the rule
|
||||
* @returns The Turndown instance for chaining
|
||||
* @type Object
|
||||
*/
|
||||
|
||||
keep: function (filter) {
|
||||
this.rules.keep(filter);
|
||||
return this
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a node that matches the filter
|
||||
* @public
|
||||
* @param {String|Array|Function} filter The unique key of the rule
|
||||
* @returns The Turndown instance for chaining
|
||||
* @type Object
|
||||
*/
|
||||
|
||||
remove: function (filter) {
|
||||
this.rules.remove(filter);
|
||||
return this
|
||||
},
|
||||
|
||||
/**
|
||||
* Escapes Markdown syntax
|
||||
* @public
|
||||
* @param {String} string The string to escape
|
||||
* @returns A string with Markdown syntax escaped
|
||||
* @type String
|
||||
*/
|
||||
|
||||
escape: function (string) {
|
||||
return escapes.reduce(function (accumulator, escape) {
|
||||
return accumulator.replace(escape[0], escape[1])
|
||||
}, string)
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reduces a DOM node down to its Markdown string equivalent
|
||||
* @private
|
||||
* @param {HTMLElement} parentNode The node to convert
|
||||
* @returns A Markdown representation of the node
|
||||
* @type String
|
||||
*/
|
||||
|
||||
function process (parentNode) {
|
||||
var self = this;
|
||||
return reduce.call(parentNode.childNodes, function (output, node) {
|
||||
node = new Node(node, self.options);
|
||||
|
||||
var replacement = '';
|
||||
if (node.nodeType === 3) {
|
||||
replacement = node.isCode ? node.nodeValue : self.escape(node.nodeValue);
|
||||
} else if (node.nodeType === 1) {
|
||||
replacement = replacementForNode.call(self, node);
|
||||
}
|
||||
|
||||
return join(output, replacement)
|
||||
}, '')
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends strings as each rule requires and trims the output
|
||||
* @private
|
||||
* @param {String} output The conversion output
|
||||
* @returns A trimmed version of the ouput
|
||||
* @type String
|
||||
*/
|
||||
|
||||
function postProcess (output) {
|
||||
var self = this;
|
||||
this.rules.forEach(function (rule) {
|
||||
if (typeof rule.append === 'function') {
|
||||
output = join(output, rule.append(self.options));
|
||||
}
|
||||
});
|
||||
|
||||
return output.replace(/^[\t\r\n]+/, '').replace(/[\t\r\n\s]+$/, '')
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an element node to its Markdown equivalent
|
||||
* @private
|
||||
* @param {HTMLElement} node The node to convert
|
||||
* @returns A Markdown representation of the node
|
||||
* @type String
|
||||
*/
|
||||
|
||||
function replacementForNode (node) {
|
||||
var rule = this.rules.forNode(node);
|
||||
var content = process.call(this, node);
|
||||
var whitespace = node.flankingWhitespace;
|
||||
if (whitespace.leading || whitespace.trailing) content = content.trim();
|
||||
return (
|
||||
whitespace.leading +
|
||||
rule.replacement(content, node, this.options) +
|
||||
whitespace.trailing
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins replacement to the current output with appropriate number of new lines
|
||||
* @private
|
||||
* @param {String} output The current conversion output
|
||||
* @param {String} replacement The string to append to the output
|
||||
* @returns Joined output
|
||||
* @type String
|
||||
*/
|
||||
|
||||
function join (output, replacement) {
|
||||
var s1 = trimTrailingNewlines(output);
|
||||
var s2 = trimLeadingNewlines(replacement);
|
||||
var nls = Math.max(output.length - s1.length, replacement.length - s2.length);
|
||||
var separator = '\n\n'.substring(0, nls);
|
||||
|
||||
return s1 + separator + s2
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether an input can be converted
|
||||
* @private
|
||||
* @param {String|HTMLElement} input Describe this parameter
|
||||
* @returns Describe what it returns
|
||||
* @type String|Object|Array|Boolean|Number
|
||||
*/
|
||||
|
||||
function canConvert (input) {
|
||||
return (
|
||||
input != null && (
|
||||
typeof input === 'string' ||
|
||||
(input.nodeType && (
|
||||
input.nodeType === 1 || input.nodeType === 9 || input.nodeType === 11
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
return TurndownService;
|
||||
|
||||
})));
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"axios": "^1.4.0",
|
||||
"jsdom": "^22.0.0"
|
||||
"jsdom": "^22.0.0",
|
||||
"turndown": "^7.2.0"
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user