Comparing version 0.1.21 to 0.1.22
var dom = exports.dom = require("./jsdom/level3/index").dom; | ||
var dom = exports.dom = require("./jsdom/level3/index").dom, | ||
fs = require("fs"), | ||
pkg = JSON.parse(fs.readFileSync(__dirname + "/../package.json")); | ||
exports.defaultLevel = dom.level3.html; | ||
@@ -7,11 +9,25 @@ exports.browserAugmentation = require("./jsdom/browser/index").browserAugmentation; | ||
exports.debugMode = false; | ||
var createWindow = exports.createWindow = require("./jsdom/browser/index").createWindow; | ||
exports.__defineGetter__('version', function() { | ||
return pkg.version; | ||
}); | ||
exports.jsdom = function (html, level, options) { | ||
options = options || {}; | ||
level = level || exports.defaultLevel; | ||
if (!options.url) { | ||
options.url = module.parent.filename; | ||
options.url = module.parent.id == 'jsdom' ? | ||
module.parent.parent.filename : | ||
module.parent.filename; | ||
} | ||
var browser = exports.browserAugmentation(level || exports.defaultLevel, options), | ||
if (options.features && options.features.QuerySelector) { | ||
require("./jsdom/selectors/index").applyQuerySelectorPrototype(level); | ||
} | ||
var browser = exports.browserAugmentation(level, options), | ||
doc = (browser.HTMLDocument) ? | ||
@@ -22,4 +38,5 @@ new browser.HTMLDocument(options) : | ||
exports.applyDocumentFeatures(doc, options.features); | ||
doc.write(html || '<html><head></head><body></body></html>'); | ||
if (html !== false) { | ||
doc.write(html || '<html><head></head><body></body></html>'); | ||
} | ||
if (doc.close && !options.deferClose) { | ||
@@ -44,3 +61,4 @@ doc.close(); | ||
'FetchExternalResources', | ||
'ProcessExternalResources' | ||
'ProcessExternalResources', | ||
'QuerySelector' | ||
]; | ||
@@ -50,3 +68,4 @@ | ||
"FetchExternalResources" : ['script'/*, 'img', 'css', 'frame', 'link'*/], | ||
"ProcessExternalResources" : ['script'/*, 'frame', 'iframe'*/] | ||
"ProcessExternalResources" : ['script'/*, 'frame', 'iframe'*/], | ||
"QuerySelector" : false | ||
}; | ||
@@ -81,3 +100,3 @@ | ||
} | ||
} | ||
}; | ||
@@ -84,0 +103,0 @@ exports.jQueryify = function (window /* path [optional], callback */) { |
var HTMLDecode = require('./htmlencoding').HTMLDecode; | ||
var HtmlToDom = function(parser){ | ||
function HtmlToDom(parser) { | ||
if(parser && parser.write) { | ||
@@ -24,8 +24,7 @@ // sax parser | ||
i = 0, | ||
length = (node.attributes && node.attributes.length) ? | ||
length = (node.attributes && node.attributes.length) ? | ||
node.attributes.length : | ||
0; | ||
for (i in node.attributes) | ||
{ | ||
for (i in node.attributes) { | ||
if (node.attributes.hasOwnProperty(i)) { | ||
@@ -35,6 +34,6 @@ newElement.setAttribute(i, node.attributes[i]); | ||
} | ||
for (var i=0; i<node.attributes.length; i++) { | ||
newElement.setAttribute(i, node.attributes.item(i)); | ||
} | ||
for (i=0; i<node.attributes.length; i++) { | ||
newElement.setAttribute(i, node.attributes.item(i)); | ||
} | ||
currentElement.appendChild(newElement); | ||
@@ -46,3 +45,3 @@ currentElement = newElement; | ||
currentElement = currentElement.parentNode; | ||
} | ||
}; | ||
@@ -52,11 +51,11 @@ parser.write(html).close(); | ||
return element; | ||
} | ||
} else if(parser && (parser.ParseHtml || parser.DefaultHandler)) { | ||
}; | ||
} else if (parser && (parser.ParseHtml || parser.DefaultHandler)) { | ||
// Forgiving HTML parser | ||
if(parser.ParseHtml){ | ||
if (parser.ParseHtml) { | ||
// davglass/node-htmlparser | ||
} else if(parser.DefaultHandler){ | ||
} else if (parser.DefaultHandler){ | ||
// tautologistics/node-htmlparser | ||
@@ -69,9 +68,9 @@ parser.ParseHtml = function(rawHtml){ | ||
return handler.dom; | ||
} | ||
}; | ||
} | ||
this.appendHtmlToElement = function(html, element){ | ||
this.appendHtmlToElement = function(html, element) { | ||
if (typeof html !== 'string') { | ||
html +=''; | ||
html +=''; | ||
} | ||
@@ -82,18 +81,27 @@ | ||
for (var i = 0; i < parsed.length; i++) { | ||
setChild.call(element, parsed[i]); | ||
setChild.call(element, parsed[i]); | ||
} | ||
return element; | ||
} | ||
} else if(parser && parser.moduleName == 'HTML5') { /* HTML5 parser */ | ||
}; | ||
} else if (parser && parser.moduleName == 'HTML5') { /* HTML5 parser */ | ||
this.appendHtmlToElement = function(html, element) { | ||
if(typeof html !== 'string') html += ''; | ||
var p = new parser.Parser({document: element.ownerDocument}); | ||
p.parse_fragment(html, element); | ||
element.appendChild(p.fragment); | ||
} | ||
if (typeof html !== 'string') { | ||
html += ''; | ||
} | ||
if (html.length > 0) { | ||
if (element.nodeType == 9) { | ||
new parser.Parser({document: element}).parse(html); | ||
} | ||
else { | ||
var p = new parser.Parser({document: element.ownerDocument}); | ||
p.parse_fragment(html, element); | ||
element.appendChild(p.fragment); | ||
} | ||
} | ||
}; | ||
} else { | ||
this.appendHtmlToElement = function(){ | ||
@@ -109,56 +117,50 @@ var sys = require('sys'); | ||
sys.puts(''); | ||
}; | ||
} | ||
} | ||
}; | ||
} | ||
} | ||
// utility function for forgiving parser | ||
var setChild = function(node) { | ||
function setChild(node) { | ||
var newNode, currentDocument = this._ownerDocument || this; | ||
if (node.type == 'tag' || node.type == 'script' || node.type == 'style') { | ||
try{ | ||
newNode = currentDocument.createElement(node.name); | ||
if (node.location) { | ||
newNode.sourceLocation = node.location; | ||
newNode.sourceLocation.file = this.sourceLocation.file; | ||
} | ||
var c, newNode, currentDocument = this._ownerDocument || this; | ||
}catch (err) { | ||
//console.log("raw: "+node.raw); | ||
} | ||
if (node.type == 'tag' || node.type == 'script' || node.type == 'style') { | ||
try { | ||
newNode = currentDocument.createElement(node.name); | ||
if (node.location) { | ||
newNode.sourceLocation = node.location; | ||
newNode.sourceLocation.file = this.sourceLocation.file; | ||
} | ||
} catch (err) { | ||
//console.log("raw: "+node.raw); | ||
} | ||
if (node.type == 'text') { | ||
newNode = currentDocument.createTextNode(HTMLDecode(node.data)); | ||
} | ||
if (node.type == 'text') { | ||
newNode = currentDocument.createTextNode(HTMLDecode(node.data)); | ||
} | ||
if (node.type == 'comment') { | ||
newNode = currentDocument.createComment(node.data); | ||
} | ||
if (node.attribs && newNode) { | ||
for (c in node.attribs) { | ||
// catchin errors here helps with improperly escaped attributes | ||
// but properly fixing this should (can only?) be done in the htmlparser itself | ||
try { | ||
newNode.setAttribute(c.toLowerCase(), HTMLDecode(node.attribs[c])); | ||
} catch(e2) { /* noop */ } | ||
} | ||
if (node.type == 'comment') { | ||
newNode = currentDocument.createComment(node.data); | ||
} | ||
if (node.children && newNode) { | ||
for (c = 0; c < node.children.length; c++) { | ||
setChild.call(newNode, node.children[c]); | ||
} | ||
if (node.attribs && newNode) { | ||
for (var c in node.attribs) { | ||
// catchin errors here helps with improperly escaped attributes | ||
// but properly fixing this should (can only?) be done in the htmlparser itself | ||
try{ | ||
newNode.setAttribute(c.toLowerCase(), HTMLDecode(node.attribs[c])); | ||
}catch(err) { | ||
//console.log("raw: "+node.raw); | ||
//console.log(node.attribs); | ||
//console.log("offender: "+node.attribs[c]); | ||
} | ||
} | ||
} | ||
if (node.children && newNode) { | ||
for (var c = 0; c < node.children.length; c++) { | ||
setChild.call(newNode, node.children[c]); | ||
} | ||
} | ||
if (newNode) { | ||
return this.appendChild(newNode); | ||
} else { | ||
return null; | ||
} | ||
}; | ||
} | ||
if (newNode) { | ||
return this.appendChild(newNode); | ||
} else { | ||
return null; | ||
} | ||
} | ||
exports.HtmlToDom = HtmlToDom; |
@@ -8,6 +8,9 @@ var sys = require('sys'), | ||
HTMLEncode = htmlencoding.HTMLEncode, | ||
HTMLDecode = htmlencoding.HTMLDecode; | ||
HTMLDecode = htmlencoding.HTMLDecode, | ||
jsdom = require('../../jsdom'); | ||
function NOT_IMPLEMENTED() { | ||
console.log(new Error().stack); | ||
if (jsdom.debugMode) { | ||
console.log(new Error().stack); | ||
} | ||
} | ||
@@ -25,2 +28,7 @@ | ||
var browser = browserAugmentation(dom, options); | ||
if (options.features && options.features.QuerySelector) { | ||
require(__dirname + "/../selectors/index").applyQuerySelectorPrototype(browser); | ||
} | ||
options.document = (browser.HTMLDocument) ? | ||
@@ -30,5 +38,10 @@ new browser.HTMLDocument(options) : | ||
options.document.write('<html><head></head><body></body></html>'); | ||
} | ||
for (key in dom) | ||
window[key] = dom[key]; | ||
var doc = window.document = options.document; | ||
@@ -195,3 +208,3 @@ | ||
// set up html parser - use a provided one or try and load from library | ||
var htmltodom = new HtmlToDom(options.parser || getDefaultParser()); | ||
var htmltodom = new HtmlToDom(options.parser || getDefaultParser()); | ||
@@ -201,3 +214,3 @@ if (!dom.HTMLDocument) { | ||
} | ||
if (!dom.HTMLDocument.write) { | ||
if (!dom.HTMLDocument.prototype.write) { | ||
dom.HTMLDocument.prototype.write = function(html) { | ||
@@ -301,2 +314,27 @@ this.innerHTML = html; | ||
dom.Document.prototype.__defineGetter__('innerHTML', function() { | ||
return domToHtml(this.childNodes, true); | ||
}); | ||
dom.Document.prototype.__defineSetter__('innerHTML', function(html) { | ||
//Check for lib first | ||
if (html === null) { | ||
return null; | ||
} | ||
//Clear the children first: | ||
var child; | ||
while ((child = this._childNodes[0])) { | ||
this.removeChild(child); | ||
} | ||
if (this.nodeName === '#document') { | ||
parseDocType(this, html); | ||
} | ||
var nodes = htmltodom.appendHtmlToElement(html, this); | ||
return html; | ||
}); | ||
var DOC_HTML5 = /<!doctype html>/i, | ||
@@ -355,2 +393,30 @@ DOC_TYPE = /<!DOCTYPE (\w.*)">/i; | ||
dom.Document.prototype.getElementsByClassName = function(className) { | ||
function filterByClassName(child) { | ||
if (!child) { | ||
return false; | ||
} | ||
if (child.nodeType && | ||
child.nodeType === dom.Node.prototype.ENTITY_REFERENCE_NODE) | ||
{ | ||
child = child._entity; | ||
} | ||
var classString = child.className; | ||
if (classString) { | ||
var s = classString.split(" "); | ||
for (var i=0; i<s.length; i++) { | ||
if (s[i] === className) { | ||
return true; | ||
} | ||
} | ||
} | ||
return false; | ||
} | ||
return new dom.NodeList(this.ownerDocument || this, dom.mapper(this, filterByClassName)); | ||
}; | ||
// Author: Swizec | ||
@@ -357,0 +423,0 @@ // styleSheets is an interface to all of the css on a page |
@@ -25,2 +25,3 @@ /* | ||
} | ||
return visit(parent, []); | ||
@@ -53,3 +54,2 @@ }, | ||
}; | ||
var sys = require("sys"); | ||
@@ -235,3 +235,14 @@ // ExceptionCode | ||
get children() { return this._children;}, | ||
get children() { | ||
//el.children list should not contain non-element nodes (el.tagName) | ||
var ret = []; | ||
var c = this._children; | ||
c.toArray().forEach(function(v) { | ||
if (v.tagName) { | ||
ret.push(v); | ||
} | ||
}); | ||
ret = new core.NodeList(this, function() { return ret }) | ||
return ret; | ||
}, | ||
get nodeValue() { return this._nodeValue;}, | ||
@@ -377,3 +388,3 @@ set nodeValue(value) { | ||
var tmpNode; | ||
while (newChild.children.length > 0) { | ||
while (newChild.childNodes.length > 0) { | ||
tmpNode = newChild.removeChild(newChild.firstChild); | ||
@@ -446,4 +457,4 @@ this.insertBefore(tmpNode, refChild); | ||
var child; | ||
for (var j = 0;j<newChild.children.length;j++) { | ||
child = newChild.children.item(j); | ||
for (var j = 0;j<newChild.childNodes.length;j++) { | ||
child = newChild.childNodes.item(j); | ||
this._childNodes.splice(i+j,0, child); | ||
@@ -462,2 +473,15 @@ } | ||
/* returns void */ | ||
_removeIds : function(){ | ||
if (this.id) { | ||
if (this._ownerDocument._ids) { | ||
this._ownerDocument._ids[this.id] = null; | ||
delete this._ownerDocument._ids[this.id]; | ||
} | ||
} | ||
for (var i=0;i<this._childNodes.length;i++) { | ||
this._childNodes[i]._removeIds(); | ||
} | ||
}, | ||
/* returns Node */ | ||
@@ -479,9 +503,3 @@ removeChild : function(/* Node */ oldChild){ | ||
this._modified(); | ||
if (child.id) { | ||
if (child._ownerDocument._ids) { | ||
child._ownerDocument._ids[child.id] = null; | ||
delete child._ownerDocument._ids[child.id]; | ||
} | ||
} | ||
child._removeIds(); | ||
return oldChild; | ||
@@ -532,3 +550,3 @@ } | ||
var transfer = []; | ||
var length = newChild.children.length; | ||
var length = newChild.childNodes.length; | ||
var i = length-1; | ||
@@ -540,3 +558,3 @@ var tmpNode; | ||
{ | ||
transfer.unshift(newChild.removeChild(newChild.children.item(i))); | ||
transfer.unshift(newChild.removeChild(newChild.childNodes.item(i))); | ||
} | ||
@@ -654,12 +672,12 @@ for (i=0;i<transfer.length;i++) | ||
var clone = null; | ||
for (var i=0;i<this.children.length;i++) | ||
for (var i=0;i<this.childNodes.length;i++) | ||
{ | ||
clone = this.children.item(i).cloneNode(true); | ||
if (!clone) { | ||
debug(this.children.item(i).nodeType); | ||
} | ||
clone = this.childNodes.item(i).cloneNode(true); | ||
if (clone.nodeType === this.ATTRIBUTE_NODE) { | ||
object.setAttributeNode(clone); | ||
} else { | ||
var readonly = object.readonly; | ||
object._readonly = false; | ||
object.appendChild(clone); | ||
object._readonly = readonly; | ||
} | ||
@@ -900,8 +918,6 @@ } | ||
get attributes() { | ||
// Author: Swizec | ||
// some scripts expect access to attributes by index | ||
for(var i=0; i<this._attributes.length; i++) { | ||
this._attributes[i] = this._attributes.item(i); | ||
} | ||
return this._attributes; | ||
for(var i=0; i<this._attributes.length; i++) { | ||
this._attributes[i] = this._attributes.item(i); | ||
} | ||
return this._attributes; | ||
}, | ||
@@ -1034,3 +1050,3 @@ | ||
} else if (child.ownerDocument && child.ownerDocument.doctype && | ||
child.ownerDocument.doctype.name === "html" && | ||
//child.ownerDocument.doctype.name === "html" && | ||
child.nodeName.toLowerCase() === name.toLowerCase()) | ||
@@ -1045,4 +1061,3 @@ { | ||
} | ||
return new core.NodeList(this.ownerDocument || this, core.mapper(this, filterByTagName)); | ||
return new core.NodeList(this.ownerDocument || this, core.mapper(this, filterByTagName, true)); | ||
}, | ||
@@ -1093,3 +1108,3 @@ }; | ||
} | ||
core.Element.call(this, "#document"); | ||
core.Node.call(this, "#document"); | ||
this._nodeName = this._tagName = "#document"; | ||
@@ -1117,3 +1132,3 @@ this._contentType = options.contentType || "text/xml"; | ||
try { | ||
canvas = (require('canvas'))(0,0); | ||
canvas = new (require('canvas'))(0,0); | ||
for (attr in element) { | ||
@@ -1133,3 +1148,2 @@ if (!canvas[attr]) { | ||
}, | ||
_nodes: null, | ||
get contentType() { return this._contentType;}, | ||
@@ -1166,2 +1180,4 @@ get doctype() { return this._doctype || null;}, | ||
}, | ||
get nodeValue() { return null; }, | ||
set nodeValue() { /* noop */ }, | ||
get attributes() { return null;}, | ||
@@ -1183,3 +1199,3 @@ get ownerDocument() { return null;}, | ||
var attrElement = this.doctype._attributes.getNamedItem(tagName); | ||
if (attrElement && attrElement.children) { | ||
if (attrElement && attrElement.childNodes) { | ||
@@ -1197,7 +1213,2 @@ attrs = attrElement.attributes; | ||
if (!this._nodes) { | ||
this._nodes = []; | ||
} | ||
this._nodes.push(this); | ||
return element; | ||
@@ -1331,5 +1342,34 @@ }, //raises: function(DOMException) {}, | ||
return ret; | ||
} | ||
}, | ||
/* returns NodeList */ | ||
getElementsByTagName: function(/* string */ name) { | ||
function filterByTagName(child) { | ||
if (child.nodeType && child.nodeType === | ||
core.Node.prototype.ENTITY_REFERENCE_NODE) | ||
{ | ||
child = child._entity; | ||
} | ||
if (child.nodeName && child.nodeType === core.Node.prototype.ELEMENT_NODE) | ||
{ | ||
if (name === "*") { | ||
return true; | ||
// case insensitivity for html | ||
} else if (child.ownerDocument && child.ownerDocument.doctype && | ||
//child.ownerDocument.doctype.name === "html" && | ||
child.nodeName.toLowerCase() === name.toLowerCase()) | ||
{ | ||
return true; | ||
} else if (child.nodeName.toLowerCase() === name.toLowerCase()) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
return new core.NodeList(this.documentElement || this, core.mapper(this, filterByTagName, true)); | ||
}, | ||
}; | ||
core.Document.prototype.__proto__ = core.Element.prototype; | ||
core.Document.prototype.__proto__ = core.Node.prototype; | ||
@@ -1336,0 +1376,0 @@ core.CharacterData = function(document, value) { |
@@ -191,2 +191,25 @@ var core = require("../level1/core").dom.level1.core, | ||
core.Document.prototype.getElementsByTagNameNS = function(/* String */ namespaceURI, | ||
/* String */ localName) | ||
{ | ||
var nsPrefixCache = {}; | ||
function filterByTagName(child) { | ||
if (child.nodeType && child.nodeType === this.ENTITY_REFERENCE_NODE) { | ||
child = child._entity; | ||
} | ||
var localMatch = child.localName === localName, | ||
nsMatch = child.namespaceURI === namespaceURI; | ||
if ((localMatch || localName === "*") && | ||
(nsMatch || namespaceURI === "*")) | ||
{ | ||
return true; | ||
} | ||
return false; | ||
} | ||
return new core.NodeList(this.ownerDocument || this, core.mapper(this, filterByTagName)); | ||
}; | ||
core.Element.prototype.getAttributeNS = function(/* string */ namespaceURI, | ||
@@ -330,8 +353,23 @@ /* string */ localName) | ||
var newNode = importedNode.cloneNode(deep); | ||
newNode._ownerDocument = this; | ||
newNode._ownerElement = null; | ||
newNode._prefix = importedNode.prefix; | ||
newNode._localName = importedNode.localName; | ||
newNode._namespaceURI = importedNode.namespaceURI; | ||
var self = this, | ||
newNode = importedNode.cloneNode(deep); | ||
function setOwnerDocument(el) { | ||
el._ownerDocument = self; | ||
if (el.id) { | ||
self._ids[el.id] = el; | ||
} | ||
if (el.attributes) { | ||
el.attributes._ownerDocument = self; | ||
for (var i=0,len=el.attributes.length; i < len; i++) { | ||
el.attributes.item(i)._ownerDocument = self; | ||
} | ||
} | ||
} | ||
if (deep) { | ||
core.visitTree(newNode, setOwnerDocument); | ||
} | ||
else { | ||
setOwnerDocument(newNode); | ||
} | ||
return newNode; | ||
@@ -377,2 +415,25 @@ }; | ||
core.Document.prototype.getElementsByTagNameNS = function(/* String */ namespaceURI, | ||
/* String */ localName) | ||
{ | ||
var nsPrefixCache = {}; | ||
function filterByTagName(child) { | ||
if (child.nodeType && child.nodeType === this.ENTITY_REFERENCE_NODE) { | ||
child = child._entity; | ||
} | ||
var localMatch = child.localName === localName, | ||
nsMatch = child.namespaceURI === namespaceURI; | ||
if ((localMatch || localName === "*") && | ||
(nsMatch || namespaceURI === "*")) | ||
{ | ||
return true; | ||
} | ||
return false; | ||
} | ||
return new core.NodeList(this.ownerDocument || this, core.mapper(this, filterByTagName)); | ||
}; | ||
core.Element.prototype.__defineSetter__("id", function(id) { | ||
@@ -379,0 +440,0 @@ this.setAttribute("id", id); |
@@ -236,3 +236,3 @@ /* DOM Level2 Events implemented as described here: | ||
+ "\n\n threw error \n\n" | ||
+ sys.inspect(e) | ||
+ sys.inspect(e.stack) | ||
+ "\n\n handling event \n\n" | ||
@@ -239,0 +239,0 @@ + sys.inspect(event)); |
@@ -34,5 +34,8 @@ var core = require("./core").dom.level2.core, | ||
doc = element.nodeType === 9 ? | ||
element : | ||
element : | ||
element.ownerDocument; | ||
if (!doc._queue) { | ||
return function() {}; | ||
} | ||
@@ -59,16 +62,15 @@ return doc._queue.push(function(err, data) { | ||
resolve: function(document, path) { | ||
if (['/','.'].indexOf(path.charAt(0)) !== -1) { | ||
if (!document._documentRoot) { | ||
throw new Error('document._documentRoot must be set to resolve absolute paths.'); | ||
} | ||
path = require('path').join(document._documentRoot, path); | ||
} else if (document.URL) { | ||
path = URL.resolve(document.URL, path); | ||
var baseElements = document.getElementsByTagName('base'), | ||
baseUrl = document.URL; | ||
if (baseElements.length > 0) { | ||
baseUrl = baseElements.item(0).href; | ||
} | ||
return path.replace(/^file:/, '').replace(/^([\/]*)/, "/"); | ||
return URL.resolve(baseUrl, path).replace(/^file:\/\//, ''); | ||
}, | ||
download: function(url, callback) { | ||
var path = url.pathname + (url.search || ''), | ||
client = http.createClient(url.port || 80, url.hostname), | ||
request = client.request('GET', path, {'host': url.hostname }); | ||
var path = url.pathname + (url.search || ''), | ||
client = http.createClient(url.port || 80, url.hostname), | ||
request = client.request('GET', path, {'host': url.hostname }); | ||
@@ -82,3 +84,8 @@ request.on('response', function (response) { | ||
response.on('end', function() { | ||
callback(null, data); | ||
if ([301, 302, 303, 307].indexOf(response.statusCode) > -1) { | ||
var redirect = URL.resolve(url, response.headers["location"]) | ||
core.resourceLoader.download(redirect, callback); | ||
} else { | ||
callback(null, data); | ||
} | ||
}); | ||
@@ -95,2 +102,16 @@ }); | ||
core.CharacterData.prototype.__defineSetter__("_nodeValue", function(value) { | ||
oldValue = this._nodeValue; | ||
this._text = value; | ||
if (this.ownerDocument && this.parentNode) { | ||
var ev = this.ownerDocument.createEvent("MutationEvents") | ||
ev.initMutationEvent("DOMCharacterDataModified", true, false, this, oldValue, newValue, null, null) | ||
this.dispatchEvent(ev) | ||
} | ||
}); | ||
core.CharacterData.prototype.__defineGetter__("_nodeValue",function() { | ||
return this._text || ""; | ||
}); | ||
function define(elementClass, def) { | ||
@@ -262,3 +283,3 @@ var tagName = def.tagName, | ||
this.readyState = 'loading'; | ||
// Add level2 features | ||
@@ -332,7 +353,17 @@ this.implementation.addFeature('core' , '2.0'); | ||
write : function(text) { | ||
this.innerHTML = text; | ||
if (this.readyState === "loading") { | ||
// During page loading, document.write appends to the current element | ||
// Find the last child that has been added to the document. | ||
var node = this; | ||
while (node.lastChild && node.lastChild.nodeType == this.ELEMENT_NODE) { | ||
node = node.lastChild; | ||
} | ||
node.innerHTML = text; | ||
} else { | ||
this.innerHTML = text; | ||
} | ||
}, | ||
writeln : function(text) { | ||
this.innerHTML = text + '\n'; | ||
this.write(text + '\n'); | ||
}, | ||
@@ -369,2 +400,4 @@ | ||
}, | ||
set head() { /* noop */ }, | ||
@@ -388,5 +421,32 @@ get body() { | ||
define('HTMLElement', { | ||
parentClass: core.Element, | ||
proto : { | ||
appendChild : function(newChild) { | ||
if (core.Element.prototype.appendChild.call(this, newChild)) { | ||
if (this.ownerDocument && newChild && newChild.nodeType === this.TEXT_NODE) { | ||
var ev = this.ownerDocument.createEvent("MutationEvents"); | ||
ev.initMutationEvent("DOMNodeInsertedIntoDocument", true, false, this, null, null, null, null); | ||
newChild.parentNode.dispatchEvent(ev); | ||
} | ||
return newChild; | ||
} | ||
}, | ||
// Add default event behavior (click link to navigate, click button to submit | ||
// form, etc). We start by wrapping dispatchEvent so we can forward events to | ||
// the element's _eventDefault function (only events that did not incur | ||
// preventDefault). | ||
dispatchEvent : function (event) { | ||
var outcome = core.Node.prototype.dispatchEvent.call(this, event) | ||
if (!event._preventDefault && | ||
event.target._eventDefaults[event.type] && | ||
typeof event.target._eventDefaults[event.type] === 'function') | ||
{ | ||
event.target._eventDefaults[event.type](event) | ||
} | ||
return outcome; | ||
}, | ||
_eventDefaults : {} | ||
}, | ||
attributes: [ | ||
@@ -422,3 +482,5 @@ 'id', | ||
ev.initEvent('submit', true, true); | ||
this.dispatchEvent(ev); | ||
if (!this.dispatchEvent(ev)) { | ||
this.submit(); | ||
}; | ||
}, | ||
@@ -428,2 +490,5 @@ submit: function() { | ||
reset: function() { | ||
this.elements.toArray().forEach(function(el) { | ||
el.value = el.defaultValue; | ||
}); | ||
} | ||
@@ -579,5 +644,12 @@ }, | ||
set value(val) { | ||
var self = this; | ||
this.options.toArray().forEach(function(option) { | ||
if (option.value === val) { | ||
option.selected = true; | ||
} else { | ||
if (!self.hasAttribute('multiple')) { | ||
// Remove the selected bit from all other options in this group | ||
// if the multiple attr is not present on the select | ||
option.selected = false; | ||
} | ||
} | ||
@@ -671,2 +743,13 @@ }); | ||
this.setAttribute('selected', 'selected'); | ||
//Remove the selected bit from all other options in this group | ||
if (this.parentNode) { | ||
if (!this.parentNode.hasAttribute('multiple')) { | ||
var o = this.parentNode.options; | ||
for (var i = 0; i < o.length; i++) { | ||
if (o[i] !== this) { | ||
o[i].selected = false; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
@@ -689,3 +772,4 @@ else { | ||
if (this._defaultValue === undefined) { | ||
this._defaultValue = this.getAttribute('value'); | ||
var attr = this.getAttributeNode('value'); | ||
this._defaultValue = attr ? attr.value : null; | ||
} | ||
@@ -721,3 +805,8 @@ return this._defaultValue; | ||
this._initDefaultValue(); | ||
this.setAttribute('value', value); | ||
if (val === null) { | ||
this.removeAttribute('value'); | ||
} | ||
else { | ||
this.setAttribute('value', val); | ||
} | ||
}, | ||
@@ -757,4 +846,3 @@ blur: function() { | ||
}}, | ||
'useMap', | ||
'value' | ||
'useMap' | ||
] | ||
@@ -1128,3 +1216,3 @@ }); | ||
filename += '<script>'; | ||
core.resourceLoader.enqueue(this, this._eval, filename)(null, this.text); | ||
@@ -1148,8 +1236,18 @@ } | ||
get text() { | ||
return this.children.item(0).value; | ||
var i=0, children = this.childNodes, l = children.length, ret = []; | ||
for (i; i<l; i++) { | ||
ret.push(children.item(i).value); | ||
} | ||
return ret.join(""); | ||
}, | ||
set text(text) { | ||
if (!this.children.item(0)) { | ||
this.appendChild(this.ownerDocument.createTextNode(text)); | ||
if (this.childNodes.length > 0) { | ||
var l = this.childNodes.length, i; | ||
for (i; i<l; i++) { | ||
this.removeChild(this.childNodes[i]); | ||
} | ||
} | ||
this.appendChild(this.ownerDocument.createTextNode(text)); | ||
} | ||
@@ -1416,3 +1514,18 @@ }, | ||
proto: { | ||
_headers: null, | ||
set headers(h) { | ||
if (h === '') { | ||
//Handle resetting headers so the dynamic getter returns a query | ||
this._headers = null; | ||
return; | ||
} | ||
if (!(h instanceof Array)) { | ||
h = [h]; | ||
} | ||
this._headers = h; | ||
}, | ||
get headers() { | ||
if (this._headers) { | ||
return this._headers.join(' '); | ||
} | ||
var cellIndex = this.cellIndex, | ||
@@ -1428,3 +1541,3 @@ headings = [], | ||
} | ||
this._headers = headings; | ||
return headings.join(' '); | ||
@@ -1431,0 +1544,0 @@ }, |
@@ -0,10 +1,16 @@ | ||
exports.javascript = function(element, code, filename) { | ||
var document = element.ownerDocument,window = document.parentWindow; | ||
if (window) { | ||
if (!window.__javascriptEval) { | ||
// Yeah, its hackery, but it works | ||
var Script = process.binding('evals').Script, | ||
setupCode = "function __javascriptEval(c, w, f) { runInNewContext(c, w, f); }"; | ||
window.runInNewContext = Script.runInNewContext; | ||
Script.runInNewContext(setupCode, window); | ||
} | ||
try { | ||
process.binding('evals').Script.runInNewContext( | ||
code, | ||
window, | ||
filename | ||
); | ||
window.__javascriptEval(code, window, filename); | ||
} catch(e) { | ||
@@ -11,0 +17,0 @@ console.log(e.stack); |
{ | ||
"name": "jsdom", | ||
"version": "0.1.21", | ||
"version": "0.1.22", | ||
"description": "CommonJS implementation of the DOM intended to be platform independent and as minimal/light as possible while completely adhering to the w3c DOM specifications.", | ||
@@ -40,2 +40,6 @@ "keywords": [ | ||
"email": "N.A." | ||
}, | ||
{ | ||
"name" : "Olivier El Mekki (http://blog.olivier-elmekki.com/)", | ||
"email" : "unknown" | ||
} | ||
@@ -63,7 +67,10 @@ ], | ||
"dependencies": { | ||
"mjsunit.runner": ">=0.1.0" | ||
"htmlparser": ">=1.7.0" | ||
}, | ||
"devDependiencies" : { | ||
"mjsunit.runner" : ">=0.1.0" | ||
}, | ||
"engines" : { "node" : ">=0.1.9" }, | ||
"directories": { | ||
"lib": "lib" | ||
"lib": "./lib/jsdom" | ||
}, | ||
@@ -70,0 +77,0 @@ "main": "./lib/jsdom" |
@@ -25,3 +25,3 @@ var sys = require("sys"); | ||
jquerify : function() { | ||
var jQueryFile = "/../../example/jquery/jquery.js", | ||
var jQueryFile = __dirname + "/../../example/jquery/jquery.js", | ||
jQueryUrl = "http://code.jquery.com/jquery-1.4.2.min.js", | ||
@@ -39,8 +39,9 @@ caught = false, | ||
jQuery("body").html('<p id="para"><a class="link">click <em class="emph">ME</em></a></p>'); | ||
try { | ||
res = jQuery("#para .emph", window.document.body); | ||
} catch (e) { | ||
caught = true; | ||
} | ||
assertEquals("selector should work as expected", "ME", res.text()); | ||
res = jQuery("#para .emph").text(); | ||
res2 = jQuery("a.link .emph").text(); | ||
// TODO: there seems to be a problem when selecting from window.document.body | ||
assertEquals("selector should work as expected", "ME", res); | ||
assertEquals("selector should work as expected", "ME", res2); | ||
assertFalse("compareDocumentPosition should not fail", caught); | ||
@@ -69,3 +70,3 @@ }; | ||
}, | ||
apply_jsdom_features_at_build_time : function() { | ||
@@ -83,3 +84,3 @@ var doc = new (jsdom.defaultLevel.Document)(), | ||
} | ||
jsdom.applyDocumentFeatures(doc2, { | ||
@@ -111,3 +112,3 @@ 'FetchExternalResources' : false | ||
}; | ||
doc2 = jsdom.jsdom(html, null, { | ||
@@ -124,6 +125,158 @@ features : { | ||
doc2.getElementById("test").innerHTML); | ||
} | ||
} | ||
}, | ||
importNode: function() { | ||
var caught = false; | ||
try { | ||
var doc1 = jsdom.jsdom('<html><body><h1 id="headline">Hello <span id="world">World</span></h1></body></html>'), | ||
doc2 = jsdom.jsdom(); | ||
doc2.body.appendChild(doc2.importNode(doc1.getElementById('headline'), true)); | ||
doc2.getElementById('world').className = 'foo'; | ||
} | ||
catch (err) { | ||
caught = err; | ||
} | ||
assertFalse("Importing nodes should not fail", caught); | ||
}, | ||
window_is_augmented_with_dom_features : function() { | ||
var document = jsdom.jsdom(), | ||
window = document.createWindow(); | ||
assertEquals("window must be augmented", true, window._augmented); | ||
assertNotNull("window must include Element", window.Element); | ||
}, | ||
queryselector : function() { | ||
var html = '<html><body><div id="main"><p>Foo</p><p>Bar</p></div></body></html>', | ||
document = jsdom.jsdom(html, null, { | ||
features : { | ||
'QuerySelector' : true | ||
} | ||
}), | ||
div = document.body.children.item(0); | ||
var element = document.querySelector("#main p"); | ||
assertSame("p and first-p", div.children.item(0), element); | ||
var element2 = div.querySelector("p"); | ||
assertSame("p and first-p", div.children.item(0), element2); | ||
}, | ||
queryselectorall : function() { | ||
var html = '<html><body><div id="main"><p>Foo</p><p>Bar</p></div></body></html>', | ||
document = jsdom.jsdom(html, null, { | ||
features : { | ||
'QuerySelector' : true | ||
} | ||
}), | ||
div = document.body.children.item(0), | ||
elements = document.querySelectorAll("#main p"); | ||
assertEquals("two results", 2, elements.length); | ||
assertSame("p and first-p", div.children.item(0), elements.item(0)); | ||
assertSame("p and second-p", div.children.item(1), elements.item(1)); | ||
var elements2 = div.querySelectorAll("p"); | ||
assertEquals("two results", 2, elements.length); | ||
assertSame("p and first-p", div.children.item(0), elements2.item(0)); | ||
assertSame("p and second-p", div.children.item(1), elements2.item(1)); | ||
}, | ||
scripts_share_a_global_context : function() { | ||
var window = jsdom.jsdom('<html><head><script type="text/javascript">\ | ||
hello = "hello";\ | ||
window.bye = "good";\ | ||
var abc = 123;\ | ||
</script><script type="text/javascript">\ | ||
hello += " world";\ | ||
bye = bye + "bye";\ | ||
(function() { var hidden = "hidden"; window.exposed = hidden; })();\ | ||
</script></head><body></body></html>').createWindow(); | ||
assertEquals("window should be the global context", | ||
"hello world", window.hello); | ||
assertEquals("window should be the global context", | ||
"goodbye", window.bye); | ||
assertEquals('local vars should not leak out to the window', | ||
123, window.abc); | ||
assertTrue('vars in a closure are safe', typeof window.hidden === 'undefined'); | ||
assertEquals('vars exposed to the window are global', 'hidden', window.exposed); | ||
}, | ||
url_resolution: function() { | ||
var html = '\ | ||
<html>\ | ||
<head></head>\ | ||
<body>\ | ||
<a href="http://example.com" id="link1">link1</a>\ | ||
<a href="/local.html" id="link2">link2</a>\ | ||
<a href="local.html" id="link3">link3</a>\ | ||
<a href="../../local.html" id="link4">link4</a>\ | ||
<a href="#here" id="link5">link5</a>\ | ||
<a href="//example.com/protocol/avoidance.html" id="link6">protocol</a>\ | ||
</body>\ | ||
</html>' | ||
function testLocal() { | ||
var url = '/path/to/docroot/index.html' | ||
var doc = jsdom.jsdom(html, null, {url: url}); | ||
assertEquals("Absolute URL should be left alone", 'http://example.com', doc.getElementById("link1").href); | ||
assertEquals("Relative URL should be resolved", '/local.html', doc.getElementById("link2").href); | ||
assertEquals("Relative URL should be resolved", '/path/to/docroot/local.html', doc.getElementById("link3").href); | ||
assertEquals("Relative URL should be resolved", '/path/local.html', doc.getElementById("link4").href); | ||
assertEquals("Relative URL should be resolved", '/path/to/docroot/index.html#here', doc.getElementById("link5").href); | ||
//assertEquals("Protocol-less URL should be resolved", '//prototol/avoidance.html', doc.getElementById("link6").href); | ||
} | ||
function testRemote() { | ||
var url = 'http://example.com/path/to/docroot/index.html' | ||
var doc = jsdom.jsdom(html, null, {url: url}); | ||
assertEquals("Absolute URL should be left alone", 'http://example.com', | ||
doc.getElementById("link1").href); | ||
assertEquals("Relative URL should be resolved", 'http://example.com/local.html', | ||
doc.getElementById("link2").href); | ||
assertEquals("Relative URL should be resolved", 'http://example.com/path/to/docroot/local.html', | ||
doc.getElementById("link3").href); | ||
assertEquals("Relative URL should be resolved", 'http://example.com/path/local.html', | ||
doc.getElementById("link4").href); | ||
assertEquals("Relative URL should be resolved", 'http://example.com/path/to/docroot/index.html#here', | ||
doc.getElementById("link5").href); | ||
assertEquals("Relative URL should be resolved", 'http://example.com/protocol/avoidance.html', | ||
doc.getElementById("link6").href); | ||
} | ||
function testBase() { | ||
var url = 'blahblahblah-invalid', | ||
doc = jsdom.jsdom(html, null, {url: url}), | ||
base = doc.createElement("base"); | ||
base.href = 'http://example.com/path/to/docroot/index.html'; | ||
doc.getElementsByTagName("head").item(0).appendChild(base); | ||
assertEquals("Absolute URL should be left alone", 'http://example.com', | ||
doc.getElementById("link1").href); | ||
assertEquals("Relative URL should be resolved", 'http://example.com/local.html', | ||
doc.getElementById("link2").href); | ||
assertEquals("Relative URL should be resolved", 'http://example.com/path/to/docroot/local.html', | ||
doc.getElementById("link3").href); | ||
assertEquals("Relative URL should be resolved", 'http://example.com/path/local.html', | ||
doc.getElementById("link4").href); | ||
assertEquals("Relative URL should be resolved", 'http://example.com/path/to/docroot/index.html#here', | ||
doc.getElementById("link5").href); | ||
assertEquals("Relative URL should be resolved", 'http://example.com/protocol/avoidance.html', | ||
doc.getElementById("link6").href); | ||
} | ||
testLocal(); | ||
testRemote(); | ||
testBase(); | ||
}, | ||
}; |
@@ -123,5 +123,5 @@ var sys = require("sys"), | ||
var core = require("../lib/jsdom/level2/html").dom.level2.html; | ||
global.level2 = require("../lib/jsdom/level2/html").dom.level2.html; | ||
global.getImplementation = function() { | ||
var doc = new (core.HTMLDocument)(); | ||
var doc = new (global.level2.HTMLDocument)(); | ||
return doc.implementation; | ||
@@ -128,0 +128,0 @@ }; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
76776132
295
140549
6
+ Addedhtmlparser@>=1.7.0
+ Addedhtmlparser@1.7.7(transitive)
- Removedmjsunit.runner@>=0.1.0
- Removedmjsunit.runner@0.1.3(transitive)