Created
July 5, 2011 21:17
-
-
Save tmpvar/1065966 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/lib/jsdom.js b/lib/jsdom.js | |
| index acd3046..14c99e3 100644 | |
| --- a/lib/jsdom.js | |
| +++ b/lib/jsdom.js | |
| @@ -1,11 +1,16 @@ | |
| +var ini=new Date().valueOf(); | |
| + | |
| var dom = exports.dom = require("./jsdom/level3/index").dom, | |
| request = require('request'), | |
| fs = require("fs"), | |
| pkg = JSON.parse(fs.readFileSync(__dirname + "/../package.json")); | |
| URL = require('url'); | |
| - | |
| -var style = require('./jsdom/level2/style'); | |
| +//generic jsdom to be pushed to master | |
| +//var style = require('./jsdom/level2/style'); | |
| +//specific jsdom do not push to master | |
| +var ew=require('./jsdom/level2/ew'); | |
| +// | |
| exports.defaultLevel = dom.level3.html; | |
| exports.browserAugmentation = require("./jsdom/browser/index").browserAugmentation; | |
| exports.windowAugmentation = require("./jsdom/browser/index").windowAugmentation; | |
| @@ -28,6 +33,7 @@ exports.jsdom = function (html, level, options) { | |
| module.parent.parent.filename : | |
| module.parent.filename; | |
| } | |
| + | |
| if (options.features && options.features.QuerySelector) { | |
| require("./jsdom/selectors/index").applyQuerySelectorPrototype(level); | |
| diff --git a/lib/jsdom/browser/domtohtml.js b/lib/jsdom/browser/domtohtml.js | |
| index 5d55ad8..3f25995 100644 | |
| --- a/lib/jsdom/browser/domtohtml.js | |
| +++ b/lib/jsdom/browser/domtohtml.js | |
| @@ -61,12 +61,27 @@ exports.stringifyElement = function stringifyElement(element) { | |
| ret.start += " "; | |
| for (i = 0; i<element.attributes.length; i++) { | |
| attribute = element.attributes.item(i); | |
| + //modifew | |
| + if (attribute.name!="style") | |
| + { | |
| attributes.push(attribute.name + '="' + | |
| HTMLEncode(attribute.nodeValue) + '"'); | |
| + } | |
| + //modifew | |
| } | |
| //sys.puts('attributes: ' + sys.inspect(attributes)); | |
| } | |
| ret.start += attributes.join(" "); | |
| + //modifew | |
| + if (element.style) { | |
| + var tmp=element.style.cssText; | |
| + if (tmp!='') | |
| + { | |
| + ret.start += ' style="' + HTMLEncode(tmp) + '"'; | |
| + } | |
| + } | |
| + //modifew | |
| + | |
| if (singleTags[tagName]) { | |
| if (isXHTML) { | |
| diff --git a/lib/jsdom/browser/htmltodom.js b/lib/jsdom/browser/htmltodom.js | |
| index f04f7f4..f9fc8f3 100644 | |
| --- a/lib/jsdom/browser/htmltodom.js | |
| +++ b/lib/jsdom/browser/htmltodom.js | |
| @@ -48,7 +48,6 @@ function HtmlToDom(parser) { | |
| }; | |
| } else if (parser && (parser.ParseHtml || parser.DefaultHandler)) { | |
| - | |
| // Forgiving HTML parser | |
| if (parser.ParseHtml) { | |
| @@ -97,7 +96,6 @@ function HtmlToDom(parser) { | |
| } | |
| }; | |
| } else { | |
| - | |
| this.appendHtmlToElement = function(){ | |
| var sys = require('sys'); | |
| sys.puts(''); | |
| diff --git a/lib/jsdom/browser/index.js b/lib/jsdom/browser/index.js | |
| index 6822f24..e28487f 100644 | |
| --- a/lib/jsdom/browser/index.js | |
| +++ b/lib/jsdom/browser/index.js | |
| @@ -69,7 +69,7 @@ exports.createWindow = function(dom, options) { | |
| this.contentWindow = this; | |
| this.window = this; | |
| this.self = this; | |
| - | |
| + | |
| var href = (options || {}).url || 'file://' + __filename; | |
| this.location = URL.parse(href); | |
| this.location.reload = NOT_IMPLEMENTED(this); | |
| @@ -106,24 +106,15 @@ exports.createWindow = function(dom, options) { | |
| this.document.trigger.apply(this._document, arguments); | |
| }, | |
| getComputedStyle: function(node) { | |
| - var s = node.style, | |
| - cs = {}; | |
| - | |
| - for (var n in s) { | |
| - cs[n] = s[n]; | |
| - } | |
| - cs.__proto__ = { | |
| - getPropertyValue: function(name) { | |
| - return node.style[name]; | |
| - } | |
| - }; | |
| - return cs; | |
| + //modif ew | |
| + return node.style; | |
| + //modif ew | |
| }, | |
| console: { | |
| - log: function(message) { this._window.trigger('log', message) }, | |
| - info: function(message) { this._window.trigger('info', message) }, | |
| - warn: function(message) { this._window.trigger('warn', message) }, | |
| - error: function(message) { this._window.trigger('error', message) } | |
| + log: function(message) { this._window.trigger('log', message);console.log('Log : '+message);}, | |
| + info: function(message) { this._window.trigger('info', message);console.log('Info : '+message); }, | |
| + warn: function(message) { this._window.trigger('warn', message);console.log('Warn : '+message); }, | |
| + error: function(message) { this._window.trigger('error', message);console.log('Error : '+message); } | |
| }, | |
| navigator: { | |
| userAgent: 'Node.js (' + process.platform + '; U; rv:' + process.version + ')', | |
| @@ -316,6 +307,115 @@ var browserAugmentation = exports.browserAugmentation = function(dom, options) { | |
| return html; | |
| }); | |
| +//modif | |
| + | |
| +var lastChildCont=function() { | |
| + | |
| +Array.prototype.inArray=function(xvalue) | |
| +{ | |
| +for (var i=0; i < this.length; i++) { | |
| +if (this[i] === xvalue){ | |
| +return true; | |
| +} | |
| +} | |
| +return false; | |
| +}; | |
| + | |
| +var isCont=function(obj) { | |
| + | |
| +if (obj.nodeType!=obj.ELEMENT_NODE) {return false;}; | |
| + | |
| +var noCont=['script','style','br','head','meta','title','link','base','noscript','#text','#comment']; | |
| + | |
| +if (noCont.inArray(obj.nodeName.toLowerCase())) | |
| +{ | |
| +return false; | |
| +} else { | |
| +return true; | |
| +} | |
| + | |
| +}; | |
| + | |
| +var dummyDiv=function(obj) { | |
| + | |
| +var tmp=document.createElement('DIV'); | |
| +obj.appendChild(tmp); | |
| +return tmp; | |
| + | |
| +}; | |
| + | |
| +if (this.lastChild==null) { | |
| +return (null); | |
| +}; | |
| + | |
| +var tmp=[]; | |
| + | |
| +while (!isCont(this.lastChild)) //while lastChild is not a node container | |
| +{ | |
| +tmp.push(this.lastChild); | |
| +this.removeChild(this.lastChild) //remove lastChild and check new last Child | |
| +}; | |
| + | |
| +var obj=null; | |
| + | |
| +if (this.childNodes.length>0) //if one child node container found | |
| +{ | |
| +obj=this.lastChild; | |
| +} else { | |
| +obj=dummyDiv(this); //if no child is a container, create dummy div | |
| +}; | |
| + | |
| +for (var i=0;i<tmp.length;i++) //reattach childs | |
| +{ | |
| +this.appendChild(tmp[i]); | |
| +}; | |
| + | |
| +return obj; | |
| + | |
| +}; | |
| + | |
| +dom.Document.prototype.__defineGetter__('lastChildCont', lastChildCont); | |
| + | |
| +dom.Element.prototype.__defineGetter__('lastChildCont', lastChildCont); | |
| + | |
| +var pixel=function(size,SIZE) { | |
| +var tmp=size.substr(size.length-2,2); | |
| +switch(tmp) { | |
| +case 'px': return size.substr(0,size.length-2); | |
| +case '%'||'em': return parseInt(size.substr(0,size.length-3)*SIZE/100); | |
| +}; | |
| +return size; | |
| +}; | |
| + | |
| +dom.Element.prototype.__defineGetter__('offsetWidth', function() { | |
| +//approximation offsetwidth calculation | |
| +var tmp=this._ownerDocument.parentWindow.getComputedStyle(this).getPropertyValue('width'); | |
| +if (!tmp) { | |
| +tmp=this.getAttribute('width'); | |
| +}; | |
| + | |
| +if (!tmp) { | |
| +return 320; | |
| +} else { | |
| +return pixel(tmp,this._ownerDocument.parentWindow.screen.width); | |
| +}; | |
| +}); | |
| + | |
| +dom.Element.prototype.__defineGetter__('offsetHeight', function() { | |
| +//approximation offsetheight calculation | |
| +var tmp=this._ownerDocument.parentWindow.getComputedStyle(this).getPropertyValue('height'); | |
| +if (!tmp) { | |
| +tmp=this.getAttribute('height'); | |
| +}; | |
| + | |
| +if (!tmp) { | |
| +return 480; | |
| +} else { | |
| +return pixel(tmp,this._ownerDocument.parentWindow.screen.height); | |
| +}; | |
| +}); | |
| + | |
| +//modif | |
| dom.Document.prototype.__defineGetter__('innerHTML', function() { | |
| return domToHtml(this._childNodes, true); | |
| @@ -337,6 +437,7 @@ var browserAugmentation = exports.browserAugmentation = function(dom, options) { | |
| if (this.nodeName === '#document') { | |
| parseDocType(this, html); | |
| } | |
| + | |
| var nodes = htmltodom.appendHtmlToElement(html, this); | |
| return html; | |
| }); | |
| diff --git a/lib/jsdom/level1/core.js b/lib/jsdom/level1/core.js | |
| index 57fb9f4..bf5e63d 100644 | |
| --- a/lib/jsdom/level1/core.js | |
| +++ b/lib/jsdom/level1/core.js | |
| @@ -11,6 +11,7 @@ var core = { | |
| // Returns Array | |
| mapDOMNodes : function(parent, recursive, callback) { | |
| + | |
| function visit(parent, result) { | |
| return parent.childNodes.toArray().reduce(reducer, result); | |
| } | |
| @@ -135,6 +136,7 @@ core.NodeList = function NodeList(element, query) { | |
| }; | |
| core.NodeList.prototype = { | |
| update: function() { | |
| + | |
| if (this._version < this._element._version) { | |
| for (var i = 0; i < this._length; i++) { | |
| this[i] = undefined; | |
| @@ -201,7 +203,7 @@ core.DOMImplementation.prototype = { | |
| addFeature: function(feature, version) { | |
| feature = feature.toLowerCase(); | |
| - | |
| + | |
| if (version) { | |
| if (!this._features[feature]) { | |
| @@ -267,17 +269,25 @@ core.Node = function Node(ownerDocument) { | |
| this._childNodes = []; | |
| this._ownerDocument = ownerDocument; | |
| this._attributes = new core.AttrNodeMap(ownerDocument, this); | |
| + | |
| + //Yonran modif | |
| - this._childrenList = new core.NodeList(this, function() { | |
| - return self._childNodes.filter(function(node) { | |
| - return node.tagName; | |
| - }); | |
| - }); | |
| + //this._childrenList = new core.NodeList(this, function() { | |
| + // return self._childNodes.filter(function(node) { | |
| + // return node.tagName; | |
| + // }); | |
| + //}); | |
| - this._childNodesList = new core.NodeList(this, function() { | |
| - return self._childNodes; | |
| - }); | |
| + //this._childNodesList = new core.NodeList(this, function() { | |
| + // return self._childNodes; | |
| + //}); | |
| + this._childrenList = null; // creatd lazily | |
| + | |
| + this._childNodesList = null; // created lazily | |
| + | |
| + // | |
| + | |
| }; | |
| core.Node.prototype = { | |
| _attributes: null, | |
| @@ -305,6 +315,16 @@ core.Node.prototype = { | |
| NOTATION_NODE : 12, | |
| get children() { | |
| + //Yonran modif | |
| + if (null == this._childrenList) { | |
| + var self = this; | |
| + this._childrenList = new core.NodeList(this, function() { | |
| + return self._childNodes.filter(function(node) { | |
| + return node.tagName; | |
| + }); | |
| + }); | |
| + }; | |
| + // | |
| return this._childrenList; | |
| }, | |
| get nodeValue() { | |
| @@ -347,6 +367,14 @@ core.Node.prototype = { | |
| set lastChild() { throw new core.DOMException();}, | |
| get childNodes() { | |
| + //Yonran modif | |
| + if (null == this._childNodesList) { | |
| + var self = this; | |
| + this._childNodesList = new core.NodeList(this, function() { | |
| + return self._childNodes; | |
| + }); | |
| + } | |
| + // | |
| return this._childNodesList; | |
| }, | |
| set childNodes() { throw new core.DOMException();}, | |
| @@ -451,7 +479,7 @@ core.Node.prototype = { | |
| this._childNodes.splice(refChildIndex, 0, newChild); | |
| newChild._parentNode = this; | |
| if (newChild._addIds) { | |
| - newChild._addIds(); | |
| + newChild._addIds(); | |
| } | |
| } | |
| @@ -465,9 +493,15 @@ core.Node.prototype = { | |
| this._ownerDocument._version++; | |
| } | |
| - this._childrenList.update(); | |
| - this._childNodesList.update(); | |
| - | |
| + //Yonran modifs | |
| + //this._childrenList.update(); | |
| + //this._childNodesList.update(); | |
| + | |
| + if (null != this._childrenList) | |
| + this._childrenList.update(); | |
| + if (null != this._childNodesList) | |
| + this._childNodesList.update(); | |
| + // | |
| }, | |
| /* returns Node */ | |
| @@ -683,7 +717,6 @@ core.Node.prototype = { | |
| trigger: function(type, message, data) { | |
| var text = type + ": " + message; | |
| if (data) text += " - More:\n" + data; | |
| - console.log(text); | |
| } | |
| }; | |
| @@ -710,7 +743,6 @@ core.NamedNodeMap.prototype = { | |
| /* returns Node */ | |
| setNamedItem: function(/* Node */ arg) { | |
| - | |
| // readonly | |
| if (this._readonly === true) { | |
| throw new core.DOMException(NO_MODIFICATION_ALLOWED_ERR); | |
| @@ -880,6 +912,7 @@ core.Element.prototype = { | |
| /* returns string */ | |
| setAttribute: function(/* string */ name, /* string */ value) { | |
| + | |
| // readonly | |
| if (this._readonly === true) { | |
| @@ -899,6 +932,7 @@ core.Element.prototype = { | |
| if (attributes.exists(name)) { | |
| attributes.removeNamedItem(name); | |
| } | |
| + | |
| attributes.setNamedItem(attr); | |
| } | |
| if (name === 'id') { | |
| @@ -1113,6 +1147,7 @@ core.Document.prototype = { | |
| get readonly() { return this._readonly;}, | |
| /* returns Element */ | |
| createElement: function(/* string */ tagName) { | |
| + | |
| var c = [], lower = tagName.toLowerCase(), element; | |
| if (!tagName || !tagName.match || (c = tagName.match(tagRegEx))) { | |
| @@ -1565,7 +1600,6 @@ core.DocumentType = function DocumentType(document, name, entities, notations, a | |
| this._nodeName = name; | |
| this._entities = entities || new core.EntityNodeMap(document); | |
| this._notations = notations || new core.NotationNodeMap(document); | |
| - | |
| core.markTreeReadonly(this._notations); | |
| this._attributes = attributes || new core.AttrNodeMap(document); | |
| diff --git a/lib/jsdom/level2/html.js b/lib/jsdom/level2/html.js | |
| index 2a0b6bd..7e19b68 100644 | |
| --- a/lib/jsdom/level2/html.js | |
| +++ b/lib/jsdom/level2/html.js | |
| @@ -4,7 +4,11 @@ var core = require("./core").dom.level2.core, | |
| Path = require('path'), | |
| fs = require("fs"), | |
| http = require('http'), | |
| - https = require('https'); | |
| + https = require('https'); | |
| + | |
| +//modif ew | |
| +var im = require('imagemagick'); | |
| +//modif ew | |
| // Setup the javascript language processor | |
| core.languageProcessors = { | |
| @@ -14,13 +18,25 @@ core.languageProcessors = { | |
| core.resourceLoader = { | |
| load: function(element, href, callback) { | |
| var ownerImplementation = element._ownerDocument.implementation, url; | |
| - | |
| - if (ownerImplementation.hasFeature('FetchExternalResources', element.tagName.toLowerCase())) { | |
| - //modif ced 16/05/11 (ajout resolve manquant) | |
| + //modifew load bgimage | |
| + if (typeof(element._bgimage)=="undefined") {element._bgimage=false;}; | |
| + if ((ownerImplementation.hasFeature('FetchExternalResources', element.tagName.toLowerCase()))||((element._bgimage)&&ownerImplementation.hasFeature('FetchExternalResources', 'img'))) { | |
| var full = this.resolve(element._ownerDocument, href); | |
| url = URL.parse(full); | |
| if (url.hostname) { | |
| - this.download(url, this.enqueue(element, callback)); | |
| + //modif ew | |
| + if (element.tagName=='IMG') { | |
| + this.downloadimage(url, this.enqueue(element, callback),element); | |
| + } else if (element.tagName=='INPUT') { | |
| + if (element.type=='image') { | |
| + this.downloadimage(url, this.enqueue(element, callback),element); | |
| + } | |
| + } else if (element._bgimage) { | |
| + this.downloadimage(url, this.enqueue(element, callback),element); | |
| + } else { | |
| + this.download(url, this.enqueue(element, callback),element); | |
| + } | |
| + //modif ew | |
| } | |
| else { | |
| var file = this.resolve(element._ownerDocument, url.pathname); | |
| @@ -38,12 +54,15 @@ core.resourceLoader = { | |
| return function() {}; | |
| } | |
| - return doc._queue.push(function(err, data) { | |
| + return doc._queue.push(function(err, data, url) { | |
| + | |
| var ev = doc.createEvent('HTMLEvents'); | |
| + | |
| + if (typeof(url)=="undefined") {url='inline';}; | |
| if (!err) { | |
| try { | |
| - callback.call(element, data, filename || doc.URL); | |
| + callback.call(element, data, filename || doc.URL); | |
| ev.initEvent('load', false, false); | |
| } | |
| catch(e) { | |
| @@ -69,7 +88,12 @@ core.resourceLoader = { | |
| return URL.resolve(baseUrl, path).replace(/^file:\/\//, ''); | |
| }, | |
| - download: function(url, callback) { | |
| + //modifew | |
| + download: function(url, callback,element) { | |
| + var doc = element.nodeType === 9 ? | |
| + element : | |
| + element._ownerDocument; | |
| + //modifew | |
| var path = url.pathname + (url.search || ''), | |
| options = {'method': 'GET', 'host': url.hostname, 'path': url.pathname}, | |
| request; | |
| @@ -80,7 +104,11 @@ core.resourceLoader = { | |
| options.port = url.port || 80; | |
| request = http.request(options); | |
| } | |
| - | |
| + | |
| + //modifew create synchronous queue | |
| + //add in queue synchronously before request response | |
| + var item=callback(false,false,url.href); | |
| + //modifew | |
| request.on('response', function (response) { | |
| response.setEncoding('utf8'); | |
| var data = ''; | |
| @@ -90,16 +118,68 @@ core.resourceLoader = { | |
| response.on('end', function() { | |
| if ([301, 302, 303, 307].indexOf(response.statusCode) > -1) { | |
| var redirect = URL.resolve(url, response.headers["location"]) | |
| - core.resourceLoader.download(URL.parse(redirect), callback); | |
| + //modifew | |
| + core.resourceLoader.download(URL.parse(redirect), callback,element); | |
| + //modifew | |
| } else { | |
| - callback(null, data); | |
| + //modifew | |
| + if (doc._queue) { | |
| + doc._queue.filldata(item,false,data); | |
| + } | |
| + //modifew | |
| } | |
| }); | |
| }); | |
| - request.on('error', callback); | |
| +// request.on('error', callback); | |
| + | |
| + request.on('error', function(err) {doc._queue.filldata(item,err,'')}); | |
| + | |
| request.end(); | |
| }, | |
| + //modif ew | |
| + downloadimage: function(url,callback,element) { | |
| + var doc = element.nodeType === 9 ? | |
| + element : | |
| + element._ownerDocument; | |
| + | |
| + | |
| + Array.prototype.inArrayImages=function(xvalue) { | |
| + for (var i=0; i < this.length; i++) { | |
| + if (this[i][0] === xvalue){ | |
| + return this[i]; | |
| + } | |
| + } | |
| + return false; | |
| + }; | |
| + | |
| + if (typeof(element._ownerDocument._downloadedImages)=="undefined") {element._ownerDocument._downloadedImages=[];}; | |
| + | |
| + var item=callback(false,false,url.href); | |
| + | |
| + var tmp=element._ownerDocument._downloadedImages.inArrayImages(url.href); | |
| + | |
| + if (!tmp) { | |
| + element._ownerDocument._downloadedImages.push([url.href,0,0]); | |
| + im.identify(['-format', '%wx%h', url.href], function(err, output){ | |
| + if (!err) { | |
| + element._ownerDocument._downloadedImages.push([url.href,output.split('x')[0],output.split('x')[1]]); | |
| + if (doc._queue) { | |
| + doc._queue.filldata(item,false,output); | |
| + } | |
| + } else { | |
| + if (doc._queue) { | |
| + doc._queue.filldata(item,true,'0x0'); | |
| + } | |
| + } | |
| + })} else { | |
| + if (doc._queue) { | |
| + doc._queue.filldata(item,false,tmp[1]+'x'+tmp[2]); | |
| + } | |
| + } | |
| + | |
| + }, | |
| + //modif ew | |
| readFile: function(path, callback) { | |
| fs.readFile(path, 'utf8', callback); | |
| } | |
| @@ -130,7 +210,7 @@ function define(elementClass, def) { | |
| elem.prototype = proto; | |
| elem.prototype.__proto__ = parentClass.prototype; | |
| - | |
| + | |
| attrs.forEach(function(n) { | |
| var prop = n.prop || n, | |
| attr = n.attr || prop.toLowerCase(); | |
| @@ -138,6 +218,7 @@ function define(elementClass, def) { | |
| if (!n.prop || n.read !== false) { | |
| elem.prototype.__defineGetter__(prop, function() { | |
| var s = this.getAttribute(attr); | |
| + | |
| if (n.type && n.type == 'boolean') { | |
| return !!s; | |
| } | |
| @@ -233,40 +314,88 @@ function firstChild(e, tagName) { | |
| return c.length > 0 ? c[0] : null; | |
| } | |
| -function ResourceQueue(paused) { | |
| +function ResourceQueue(paused,_doc) { | |
| this.paused = !!paused; | |
| + //modifew | |
| + this._doc=_doc; | |
| + this.tail=[]; | |
| + //modifew | |
| } | |
| ResourceQueue.prototype = { | |
| +//modif ew | |
| +//filldata when loaded and execute if readyState complete | |
| + filldata: function(item,err,data) { | |
| + item.err=err; | |
| + item.data=data; | |
| + if (this._doc.readyState=='complete') | |
| + { | |
| + item.check(); | |
| + } | |
| + }, | |
| +//modifew | |
| push: function(callback) { | |
| + //modifew | |
| + //if (typeof(this.tail)=="undefined") {this.tail=null;}; | |
| + //modifew | |
| var q = this; | |
| var item = { | |
| - prev: q.tail, | |
| + | |
| check: function() { | |
| - if (!q.paused && (this.data || this.err) && !this.prev) { | |
| - callback(this.err, this.data); | |
| - q.tail = this.next; | |
| - if (this.next) { | |
| - this.next.prev = null; | |
| - this.next.check(); | |
| - } | |
| + | |
| + var fn=function() { | |
| + callback(this.err, this.data,this.url); | |
| + q.tail.shift(); | |
| + if (q.tail.length!=0) | |
| + { | |
| + q.tail[0].check(); | |
| + } | |
| + }; | |
| + var that=this; | |
| + var FN=function() {fn.call(that);}; | |
| + if (!q.paused) { | |
| + if (this.data || this.err) { | |
| + fn.call(this); | |
| + } else { | |
| + //if data not available, retry later | |
| + setTimeout(FN,100); | |
| + } | |
| } | |
| } | |
| }; | |
| - if (q.tail) { | |
| - q.tail.next = item; | |
| - } | |
| - q.tail = item; | |
| - return function(err, data) { | |
| - item.err = err; | |
| - item.data = data; | |
| - item.check(); | |
| + //Stop queuing if readyState complete | |
| + if (this._doc.readyState!='complete') | |
| + { | |
| + this.tail.push(item); | |
| + } | |
| + | |
| + //modifew | |
| + var that=this; | |
| + return function(err, data,url) { | |
| + if (typeof(url)=="undefined") {url='inline';}; | |
| + item.err = err; | |
| + item.data = data; | |
| + item.url = url; | |
| + if (data) | |
| + { | |
| + //data not empty, execute it if readyState complete | |
| + if (that._doc.readyState=='complete') | |
| + { | |
| + item.check(); | |
| + } | |
| + } else { | |
| + return item; | |
| + } | |
| }; | |
| + //modif ew | |
| + | |
| }, | |
| resume: function() { | |
| this.paused = false; | |
| - if (this.tail) { | |
| - this.tail.check(); | |
| - } | |
| + | |
| + if (this.tail.length>0) { | |
| + | |
| + this.tail[0].check(); | |
| + } | |
| } | |
| }; | |
| @@ -278,7 +407,9 @@ core.HTMLDocument = function HTMLDocument(options) { | |
| core.Document.call(this, options); | |
| this._URL = options.url || '/'; | |
| this._documentRoot = options.documentRoot || Path.dirname(this._URL); | |
| - this._queue = new ResourceQueue(options.deferClose); | |
| + //modifew | |
| + this._queue = new ResourceQueue(options.deferClose,this); | |
| + //modifew | |
| this.readyState = 'loading'; | |
| // Add level2 features | |
| @@ -286,6 +417,9 @@ core.HTMLDocument = function HTMLDocument(options) { | |
| this.implementation.addFeature('html' , '2.0'); | |
| this.implementation.addFeature('xhtml' , '2.0'); | |
| this.implementation.addFeature('xml' , '2.0'); | |
| + //modifew yonran change | |
| + this._defaultStyleSheet = new core.defaultCSSStyleSheet(); | |
| + this._styleSheets = new core.StyleSheetList(); | |
| }; | |
| core.HTMLDocument.prototype = { | |
| @@ -408,11 +542,7 @@ core.HTMLDocument.prototype = { | |
| this._documentElement = firstChild(this, 'HTML'); | |
| } | |
| return this._documentElement; | |
| - }, | |
| - | |
| - _cookie : "", | |
| - get cookie() { return this._cookie; }, | |
| - set cookie(val) { this._cookie = val; } | |
| + } | |
| }; | |
| core.HTMLDocument.prototype.__proto__ = core.Document.prototype; | |
| @@ -749,14 +879,47 @@ define('HTMLOptionElement', { | |
| define('HTMLInputElement', { | |
| tagName: 'INPUT', | |
| + | |
| + init: function() { | |
| + var evals=function() { | |
| + if ((this.src)&&(this.type=='image')) { | |
| + var tmp=this._ownerDocument.parentWindow.getComputedStyle(this); | |
| + //if no size defined for image,load it and set real width height of image | |
| + if (!(tmp.getPropertyValue('width')&&(tmp.getPropertyValue('height')))) | |
| + { | |
| + core.resourceLoader.load(this, this.src, this._evalsize); | |
| + } | |
| + } | |
| + }; | |
| + | |
| + var evalsize=function() { | |
| + evals.call(this); | |
| + this.addEventListener('DOMAttrModified', function(e) { | |
| + if (('src' === e.attrName)&&(e.newValue!=e.oldValue)) { | |
| + evals.call(this); | |
| + }}); | |
| + }; | |
| + this.addEventListener('DOMNodeInsertedIntoDocument', evalsize); | |
| + }, | |
| + | |
| proto: { | |
| + //modifew | |
| + _evalsize: function(size) { | |
| + | |
| + var tmp=size.split('x'); | |
| + | |
| + this.style.width=tmp[0]+'px'; | |
| + | |
| + this.style.height=tmp[1]+'px'; | |
| + | |
| + }, | |
| _initDefaultValue: function() { | |
| if (this._defaultValue === undefined) { | |
| var attr = this.getAttributeNode('value'); | |
| this._defaultValue = attr ? attr.value : null; | |
| } | |
| return this._defaultValue; | |
| - }, | |
| + }, //modifew | |
| _initDefaultChecked: function() { | |
| if (this._defaultChecked === undefined) { | |
| this._defaultChecked = !!this.getAttribute('checked'); | |
| @@ -1091,7 +1254,42 @@ define('HTMLImageElement', { | |
| 'useMap', | |
| {prop: 'vspace', type: 'long'}, | |
| {prop: 'width', type: 'long'} | |
| - ] | |
| + ], | |
| + //modifew | |
| + init: function() { | |
| + var evals=function() { | |
| + if (this.src) { | |
| + var tmp=this._ownerDocument.parentWindow.getComputedStyle(this); | |
| + //if no size defined for image,load it and set real width height of image | |
| + if (!((this.getAttribute('width')&&(this.getAttribute('height')))||(tmp.getPropertyValue('width')&&(tmp.getPropertyValue('height'))))) | |
| + { | |
| + core.resourceLoader.load(this, this.src, this._evalsize); | |
| + } | |
| + } | |
| + }; | |
| + | |
| + var evalsize=function() { | |
| + evals.call(this); | |
| + this.addEventListener('DOMAttrModified', function(e) { | |
| + if (('src' === e.attrName)&&(e.newValue!=e.oldValue)) { | |
| + evals.call(this); | |
| + }}); | |
| + }; | |
| + | |
| + this.addEventListener('DOMNodeInsertedIntoDocument', evalsize); | |
| + }, | |
| + proto: { | |
| + _evalsize: function(size) { | |
| + | |
| + var tmp=size.split('x'); | |
| + | |
| + this.setAttribute('width',tmp[0]); | |
| + | |
| + this.setAttribute('height',tmp[1]); | |
| + | |
| + } | |
| + } | |
| + //modifew | |
| }); | |
| define('HTMLObjectElement', { | |
| @@ -1193,8 +1391,8 @@ define('HTMLScriptElement', { | |
| filename += ':' + src.line + ':' + src.col; | |
| } | |
| filename += '<script>'; | |
| - | |
| core.resourceLoader.enqueue(this, this._eval, filename)(null, this.text); | |
| + | |
| } | |
| }); | |
| }, | |
| @@ -1204,6 +1402,8 @@ define('HTMLScriptElement', { | |
| this.language && | |
| core.languageProcessors[this.language]) | |
| { | |
| + | |
| + //modifew | |
| var that=this; | |
| this._ownerDocument.write=function(text) { | |
| @@ -1215,6 +1415,7 @@ define('HTMLScriptElement', { | |
| this.innerHTML=text; | |
| }; | |
| }; | |
| + | |
| core.languageProcessors[this.language](this, text, filename); | |
| } | |
| }, | |
| diff --git a/lib/jsdom/level2/style.js b/lib/jsdom/level2/style.js | |
| index 6fdb37f..5bcac24 100644 | |
| --- a/lib/jsdom/level2/style.js | |
| +++ b/lib/jsdom/level2/style.js | |
| @@ -1,7 +1,10 @@ | |
| var core = require("./core").dom.level2.core, | |
| html = require("./html").dom.level2.html, | |
| cssom = require("cssom"), | |
| - assert = require('assert'); | |
| + assert = require('assert'), | |
| + fs = require('fs'); | |
| + | |
| + var inheritPropList = ['color' , 'font-style' , 'font-variant' , 'font-weight' , 'font-size' , 'font-family' , 'letter-spacing' , 'line-height' , 'list-style-type' ,'list-style-position' , 'list-style-image' , 'text-align' , 'text-indent' , 'text-transform' , 'visibility' , 'white-space' , 'word-spacing']; | |
| // What works now: | |
| // - Accessing the rules defined in individual stylesheets | |
| @@ -57,18 +60,48 @@ core.CSSStyleDeclaration = cssom.CSSStyleDeclaration; | |
| // StyleSheetList has the same interface as NodeList, so we'll use the same | |
| // object. | |
| -core.StyleSheetList = core.NodeList; | |
| +//core.StyleSheetList = core.NodeList; | |
| -core.Document.prototype.__defineGetter__('styleSheets', function() { | |
| - if (!this._styleSheets) { | |
| - this._styleSheets = new core.StyleSheetList; | |
| +//modifew ced | |
| +// styleSheetList core object | |
| +core.StyleSheetList = function(){ | |
| +this._m_sheets = []; | |
| +this._r_sheets = []; | |
| +} | |
| + | |
| +// StylesheetList getters/setters | |
| +core.StyleSheetList.prototype = { | |
| + | |
| + get length() { | |
| + return this._m_sheets.length; | |
| + }, | |
| + item: function(index) { | |
| + return this._m_sheets[index] || null; | |
| } | |
| - // TODO: each style and link element should register its sheet on creation | |
| - // nad remove it on removal. | |
| - return this._styleSheets; | |
| +} | |
| + | |
| +// Default stylesheet object | |
| +core.defaultCSSStyleSheet = function(){ | |
| +var sheet = new core.CSSStyleSheet(); | |
| +//modifew ced : fixed default.css path | |
| +var filename = require.resolve('jsdom').replace('jsdom.js','jsdom/level2/default.css'); | |
| +fs.readFile(filename, 'utf8',function(err,data){ | |
| +if (err) throw err; | |
| +var newStyleSheet = cssom.parse(data); | |
| +var spliceArgs = newStyleSheet.cssRules; | |
| +spliceArgs.unshift(0, sheet.cssRules.length); | |
| +Array.prototype.splice.apply(sheet.cssRules, spliceArgs); | |
| }); | |
| +return sheet; | |
| +} | |
| +// expose stylesheetlist to the dom document | |
| +core.Document.prototype.__defineGetter__('styleSheets', function() { | |
| + return this._styleSheets; | |
| +}); | |
| +//modifew ced | |
| + | |
| /** | |
| * @this {html.HTMLLinkElement|html.HTMLStyleElement} | |
| * @param {string} url | |
| @@ -126,10 +159,10 @@ function evaluateStyleAttribute(data) { | |
| // currently, cssom's parse doesn't really work if you pass in | |
| // {state: 'name'}, so instead we just build a dummy sheet. | |
| + | |
| var styleSheet = cssom.parse('dummy{' + data + '}') | |
| - , style = this.style; | |
| - console.log('evaluating style on ' + this.tagName + ': ' + data + ' ->') | |
| - console.log(styleSheet); | |
| + , style = this._cssStyleDeclaration?this.style:this; | |
| + //modifew to be called from Proxy | |
| while (style.length > 0) { | |
| // TODO: find a non-n^2 way to remove all properties (this calls splice | |
| // n times). | |
| @@ -146,31 +179,34 @@ function evaluateStyleAttribute(data) { | |
| } | |
| } | |
| } | |
| + | |
| +//modifew | |
| +cssom.CSSStyleDeclaration.evaluateStyleAttribute=evaluateStyleAttribute; | |
| +//modifew | |
| + | |
| html.HTMLElement.prototype.__defineGetter__('style', function() { | |
| if (!this._cssStyleDeclaration) { | |
| - this._cssStyleDeclaration = new cssom.CSSStyleDeclaration; | |
| - console.log('creating style atribute on ' + this.nodeName) | |
| + | |
| + // Case <Tag style='xxx'> in html | |
| + // parser htmltodom creates style attributes | |
| + this._cssStyleDeclaration = cssom.CSSStyleDeclaration.call(this); | |
| + // monitor changes of style attribute (htmltodom) | |
| this.addEventListener('DOMAttrModified', function(e) { | |
| - console.log('style modified') | |
| - if ('style' === e.attrName) { | |
| - evaluateStyleAttribute.call(this, e.newValue); | |
| - } | |
| + if ('style' === e.attrName) { | |
| + | |
| + evaluateStyleAttribute.call(this, e.newValue); | |
| + | |
| + } | |
| }); | |
| + | |
| evaluateStyleAttribute.call(this, this.getAttribute('style')); | |
| + | |
| } | |
| + | |
| return this._cssStyleDeclaration; | |
| + | |
| }); | |
| -html.HTMLElement.prototype.__defineSetter__('style', function(val) { | |
| - // copied from the define helper function within html.js to define reflected | |
| - // attributes. | |
| - if (!val) { | |
| - this.removeAttribute(attr); | |
| - } | |
| - else { | |
| - var s = val.toString(); | |
| - this.setAttribute('style', s); | |
| - } | |
| -}); | |
| + | |
| assert.equal(undefined, html.HTMLLinkElement._init) | |
| html.HTMLLinkElement._init = function() { | |
| this.addEventListener('DOMNodeInsertedIntoDocument', function() { | |
| @@ -181,9 +217,16 @@ html.HTMLLinkElement._init = function() { | |
| } | |
| if (this.href) { | |
| fetchStylesheet.call(this, this.href, this.sheet); | |
| + | |
| + //modifew ced | |
| + //Add stylesheet to the stylesheets list | |
| + this._ownerDocument._styleSheets._m_sheets.push(this.sheet); | |
| + | |
| } | |
| }); | |
| this.addEventListener('DOMNodeRemovedFromDocument', function() { | |
| + //modifew ced | |
| + //todo remove stylesheet from styleSheetList | |
| }); | |
| }; | |
| /** | |
| @@ -199,19 +242,31 @@ html.HTMLLinkElement.prototype.__defineGetter__('sheet', getOrCreateSheet); | |
| assert.equal(undefined, html.HTMLStyleElement._init) | |
| html.HTMLStyleElement._init = function() { | |
| - console.log('init style') | |
| + | |
| this.addEventListener('DOMNodeInsertedIntoDocument', function() { | |
| - console.log('style inserted') | |
| - console.log('sheet: ', this.sheet); | |
| + | |
| + core.resourceLoader.enqueue(this, this._eval)(null, this.textContent || true); | |
| + | |
| + }); | |
| +}; | |
| + | |
| +//modifew | |
| +html.HTMLStyleElement._eval = function() { | |
| + | |
| if (this.type && this.type !== 'text/css') { | |
| - console.log('bad type: ' + this.type) | |
| return; | |
| } | |
| evaluateStylesheet.call(this, this.textContent, this.sheet, this._ownerDocument.URL); | |
| - }); | |
| -}; | |
| + | |
| + //modifew ced | |
| + //Add stylesheet to the stylesheets list | |
| + this._ownerDocument._styleSheets._m_sheets.push(this.sheet); | |
| +} | |
| +//modifew | |
| + | |
| html.HTMLStyleElement.prototype.__defineGetter__('sheet', getOrCreateSheet); | |
| + | |
| exports.dom = { | |
| level2 : { | |
| html : html, |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment