You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
230 lines
6.0 KiB
230 lines
6.0 KiB
/* Copyright 2017 Mozilla Foundation |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
'use strict'; |
|
|
|
function xmlEncode(s) { |
|
var i = 0, |
|
ch; |
|
s = String(s); |
|
while (i < s.length && (ch = s[i]) !== '&' && ch !== '<' && ch !== '\"' && ch !== '\n' && ch !== '\r' && ch !== '\t') { |
|
i++; |
|
} |
|
if (i >= s.length) { |
|
return s; |
|
} |
|
var buf = s.substring(0, i); |
|
while (i < s.length) { |
|
ch = s[i++]; |
|
switch (ch) { |
|
case '&': |
|
buf += '&'; |
|
break; |
|
case '<': |
|
buf += '<'; |
|
break; |
|
case '\"': |
|
buf += '"'; |
|
break; |
|
case '\n': |
|
buf += '
'; |
|
break; |
|
case '\r': |
|
buf += '
'; |
|
break; |
|
case '\t': |
|
buf += '	'; |
|
break; |
|
default: |
|
buf += ch; |
|
break; |
|
} |
|
} |
|
return buf; |
|
} |
|
function DOMElement(name) { |
|
this.nodeName = name; |
|
this.childNodes = []; |
|
this.attributes = {}; |
|
this.textContent = ''; |
|
if (name === 'style') { |
|
this.sheet = { |
|
cssRules: [], |
|
insertRule: function insertRule(rule) { |
|
this.cssRules.push(rule); |
|
} |
|
}; |
|
} |
|
} |
|
DOMElement.prototype = { |
|
getAttributeNS: function DOMElement_getAttributeNS(NS, name) { |
|
if (name in this.attributes) { |
|
return this.attributes[name]; |
|
} |
|
if (NS) { |
|
var suffix = ':' + name; |
|
for (var fullName in this.attributes) { |
|
if (fullName.slice(-suffix.length) === suffix) { |
|
return this.attributes[fullName]; |
|
} |
|
} |
|
} |
|
return null; |
|
}, |
|
setAttributeNS: function DOMElement_setAttributeNS(NS, name, value) { |
|
value = value || ''; |
|
value = xmlEncode(value); |
|
this.attributes[name] = value; |
|
}, |
|
appendChild: function DOMElement_appendChild(element) { |
|
var childNodes = this.childNodes; |
|
if (childNodes.indexOf(element) === -1) { |
|
childNodes.push(element); |
|
} |
|
}, |
|
cloneNode: function DOMElement_cloneNode() { |
|
var newNode = new DOMElement(this.nodeName); |
|
newNode.childNodes = this.childNodes; |
|
newNode.attributes = this.attributes; |
|
newNode.textContent = this.textContent; |
|
return newNode; |
|
}, |
|
toString: function DOMElement_toString() { |
|
var buf = []; |
|
var serializer = this.getSerializer(); |
|
var chunk; |
|
while ((chunk = serializer.getNext()) !== null) { |
|
buf.push(chunk); |
|
} |
|
return buf.join(''); |
|
}, |
|
getSerializer: function DOMElement_getSerializer() { |
|
return new DOMElementSerializer(this); |
|
} |
|
}; |
|
function DOMElementSerializer(node) { |
|
this._node = node; |
|
this._state = 0; |
|
this._loopIndex = 0; |
|
this._attributeKeys = null; |
|
this._childSerializer = null; |
|
} |
|
DOMElementSerializer.prototype = { |
|
getNext: function DOMElementSerializer_getNext() { |
|
var node = this._node; |
|
switch (this._state) { |
|
case 0: |
|
++this._state; |
|
return '<' + node.nodeName; |
|
case 1: |
|
++this._state; |
|
if (node.nodeName === 'svg:svg') { |
|
return ' xmlns:xlink="http://www.w3.org/1999/xlink"' + ' xmlns:svg="http://www.w3.org/2000/svg"'; |
|
} |
|
case 2: |
|
++this._state; |
|
this._loopIndex = 0; |
|
this._attributeKeys = Object.keys(node.attributes); |
|
case 3: |
|
if (this._loopIndex < this._attributeKeys.length) { |
|
var name = this._attributeKeys[this._loopIndex++]; |
|
return ' ' + name + '="' + xmlEncode(node.attributes[name]) + '"'; |
|
} |
|
++this._state; |
|
return '>'; |
|
case 4: |
|
if (node.nodeName === 'svg:tspan' || node.nodeName === 'svg:style') { |
|
this._state = 6; |
|
return xmlEncode(node.textContent); |
|
} |
|
++this._state; |
|
this._loopIndex = 0; |
|
case 5: |
|
var value; |
|
while (true) { |
|
value = this._childSerializer && this._childSerializer.getNext(); |
|
if (value !== null) { |
|
return value; |
|
} |
|
var nextChild = node.childNodes[this._loopIndex++]; |
|
if (nextChild) { |
|
this._childSerializer = new DOMElementSerializer(nextChild); |
|
} else { |
|
this._childSerializer = null; |
|
++this._state; |
|
break; |
|
} |
|
} |
|
case 6: |
|
++this._state; |
|
return '</' + node.nodeName + '>'; |
|
case 7: |
|
return null; |
|
default: |
|
throw new Error('Unexpected serialization state: ' + this._state); |
|
} |
|
} |
|
}; |
|
var document = { |
|
childNodes: [], |
|
get currentScript() { |
|
return { src: '' }; |
|
}, |
|
get documentElement() { |
|
return this; |
|
}, |
|
createElementNS: function createElementNS(NS, element) { |
|
var elObject = new DOMElement(element); |
|
return elObject; |
|
}, |
|
createElement: function createElement(element) { |
|
return this.createElementNS('', element); |
|
}, |
|
getElementsByTagName: function getElementsByTagName(element) { |
|
if (element === 'head') { |
|
return [this.head || (this.head = new DOMElement('head'))]; |
|
} |
|
return []; |
|
} |
|
}; |
|
function Image() { |
|
this._src = null; |
|
this.onload = null; |
|
} |
|
Image.prototype = { |
|
get src() { |
|
return this._src; |
|
}, |
|
set src(value) { |
|
this._src = value; |
|
if (this.onload) { |
|
this.onload(); |
|
} |
|
} |
|
}; |
|
exports.document = document; |
|
exports.Image = Image; |
|
var exported_symbols = Object.keys(exports); |
|
exports.setStubs = function (namespace) { |
|
exported_symbols.forEach(function (key) { |
|
console.assert(!(key in namespace), 'property should not be set: ' + key); |
|
namespace[key] = exports[key]; |
|
}); |
|
}; |
|
exports.unsetStubs = function (namespace) { |
|
exported_symbols.forEach(function (key) { |
|
console.assert(key in namespace, 'property should be set: ' + key); |
|
delete namespace[key]; |
|
}); |
|
}; |