├── .gitignore ├── .npmignore ├── .travis.yml ├── Readme.md ├── index.js ├── lib ├── CSSStyleDeclaration.js ├── DOMTokenList.js ├── Document.js ├── Element.js ├── Event.js ├── EventTarget.js ├── HTMLCollection.js ├── History.js ├── HttpRequest.js ├── Location.js ├── Navigator.js ├── Node.js ├── NodeList.js ├── Storage.js ├── Window.js ├── XMLHttpRequest.js └── jquery.js ├── package.json └── test ├── Navigator.js ├── Window.js ├── css2xpath.html ├── css2xpath.js ├── jQuery.js └── spec ├── browser.js ├── element.json ├── index.html └── server.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | docs/ 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | #Moved 2 | 3 | This repository has moved to [https://github.com/libxmljs/libxmljs-dom](https://github.com/libxmljs/libxmljs-dom) 4 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var libxmljs = require('libxmljs'), 4 | css2xpath = require('css2xpath'), 5 | EventTarget = require('./lib/EventTarget.js'), 6 | Window = require('./lib/Window.js')(libxmljs), 7 | XMLDocument = libxmljs.Document.prototype, 8 | XMLElement = libxmljs.Element.prototype; 9 | 10 | libxmljs.css2xpath = css2xpath; 11 | 12 | extend(Window.prototype, EventTarget); 13 | libxmljs.Window = Window; 14 | 15 | 16 | XMLDocument.css2xpath = libxmljs.css2xpath; 17 | XMLDocument.doc = function () { 18 | return this; 19 | }; 20 | 21 | XMLElement.css2xpath = libxmljs.css2xpath; 22 | XMLElement.__childNodes = XMLElement.childNodes; 23 | XMLElement.__nextSibling = XMLElement.nextSibling; 24 | XMLElement.__name = XMLElement.name; 25 | XMLElement.__type = XMLElement.type; 26 | delete XMLElement.childNodes; 27 | 28 | var Node = require('./lib/Node.js'); 29 | var Element = extend(require('./lib/Element.js'), Node, true); 30 | 31 | extend(XMLElement, Element, true); 32 | extend(XMLElement, EventTarget); 33 | 34 | var Document = extend(require('./lib/Document.js')(libxmljs), Node, true); 35 | 36 | extend(XMLDocument, Document, true); 37 | extend(XMLDocument, EventTarget); 38 | 39 | function extend(parent, child, replace) { 40 | for (var key in child) { 41 | if (parent.hasOwnProperty(key) && replace !== true) continue; 42 | var desc = Object.getOwnPropertyDescriptor(child, key); 43 | 44 | if (desc.value !== undefined) { 45 | parent[key] = child[key]; 46 | } else { 47 | Object.defineProperty(parent, key, { get: desc.get, set: desc.set, enumerable: true, configurable: true }); 48 | } 49 | } 50 | 51 | return parent; 52 | } 53 | 54 | var readFileSync = require('fs').readFileSync; 55 | var jQueryFile = __dirname + '/lib/jquery.js'; 56 | var jQuery = null; 57 | 58 | Object.defineProperty(libxmljs, 'jQuery', { 59 | get: function () { 60 | if (jQuery === null) 61 | jQuery = readFileSync(jQueryFile).toString(); 62 | return jQuery; 63 | }, 64 | set: function () { 65 | 66 | } 67 | }); 68 | 69 | module.exports = libxmljs; 70 | -------------------------------------------------------------------------------- /lib/CSSStyleDeclaration.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var CSSStyleDeclaration = function(str) { 3 | this.keys = []; 4 | this.vals = []; 5 | } 6 | 7 | CSSStyleDeclaration.prototype = { 8 | get cssText() { 9 | var str = '', 10 | length = this.keys.length; 11 | for (var i = 0; i < length; i++) { 12 | str += this.keys[i]+':'+this.vals[i]; 13 | } 14 | return str; 15 | }, 16 | set cssText(str) { 17 | this.items = []; 18 | var arr = str.split(';'), 19 | length = arr.length; 20 | for (var i = 0; i < length; i++) { 21 | var s = arr[i].split(':'); 22 | if (s[0].length === 0) continue; 23 | this.keys.push(s[0]); 24 | this.vals.push(s[1]); 25 | } 26 | }, 27 | parentRule: null, 28 | getPropertyPriority: function() { 29 | return ''; 30 | }, 31 | getPropertyValue: function(key) { 32 | return this.vals[this.keys.indexOf(key)]; 33 | }, 34 | item: function(i) { 35 | return this.keys[i]; 36 | }, 37 | get length() { 38 | return this.keys.length; 39 | }, 40 | removeProperty: function(key) { 41 | var index = this.keys.indexOf(key); 42 | this.keys.splice(index, 1); 43 | this.vals.splice(index, 1); 44 | }, 45 | setProperty: function(key, value, important) { 46 | var index = this.keys.indexOf(key); 47 | if (index !== -1) { 48 | this.vals[index] = value; 49 | }else{ 50 | this.keys.push(key); 51 | this.vals.push(val); 52 | } 53 | }, 54 | getPropertyCSSValue: function() { 55 | 56 | } 57 | } 58 | 59 | 60 | var CSSProperties = { 61 | 'background': 'background', 62 | 'background-attachment': 'backgroundAttachment', 63 | 'background-color': 'backgroundColor', 64 | 'background-image': 'backgroundImage', 65 | 'background-position': 'backgroundPosition', 66 | 'background-repeat': 'backgroundRepeat', 67 | 'border': 'border', 68 | 'border-bottom': 'borderBottom', 69 | 'border-bottom-color': 'borderBottomColor', 70 | 'border-bottom-style': 'borderBottomStyle', 71 | 'border-bottom-width': 'borderBottomWidth', 72 | 'border-color': 'borderColor', 73 | 'border-left': 'borderLeft', 74 | 'border-left-color': 'borderLeftColor', 75 | 'border-left-style': 'borderLeftStyle', 76 | 'border-left-width': 'borderLeftWidth', 77 | 'border-right': 'borderRight', 78 | 'border-right-color': 'borderRightColor', 79 | 'border-right-style': 'borderRightStyle', 80 | 'border-right-width': 'borderRightWidth', 81 | 'border-style': 'borderStyle', 82 | 'border-top': 'borderTop', 83 | 'border-top-color': 'borderTopColor', 84 | 'border-top-style': 'borderTopStyle', 85 | 'border-top-width': 'borderTopWidth', 86 | 'border-width': 'borderWidth', 87 | 'clear': 'clear', 88 | 'clip': 'clip', 89 | 'color': 'color', 90 | 'cursor': 'cursor', 91 | 'display': 'display', 92 | 'filter': 'filter', 93 | 'font': 'font', 94 | 'font-family': 'fontFamily', 95 | 'font-size': 'fontSize', 96 | 'font-variant': 'fontVariant', 97 | 'font-weight': 'fontWeight', 98 | 'height': 'height', 99 | 'left': 'left', 100 | 'letter-spacing': 'letterSpacing', 101 | 'line-height': 'lineHeight', 102 | 'list-style': 'listStyle', 103 | 'list-style-image': 'listStyleImage', 104 | 'list-style-position': 'listStylePosition', 105 | 'list-style-type': 'listStyleType', 106 | 'margin': 'margin', 107 | 'margin-bottom': 'marginBottom', 108 | 'margin-left': 'marginLeft', 109 | 'margin-right': 'marginRight', 110 | 'margin-top': 'marginTop', 111 | 'overflow': 'overflow', 112 | 'padding': 'padding', 113 | 'padding-bottom': 'paddingBottom', 114 | 'padding-left': 'paddingLeft', 115 | 'padding-right': 'paddingRight', 116 | 'padding-top': 'paddingTop', 117 | 'page-break-after': 'pageBreakAfter', 118 | 'page-break-before': 'pageBreakBefore', 119 | 'position': 'position', 120 | 'float': 'cssFloat', 121 | 'text-align': 'textAlign', 122 | 'text-decoration': 'textDecoration', 123 | 'text-decoration: blink': 'textDecorationBlink', 124 | 'text-decoration: line-through': 'textDecorationLineThrough', 125 | 'text-decoration: none': 'textDecorationNone', 126 | 'text-decoration: overline': 'textDecorationOverline', 127 | 'text-decoration: underline': 'textDecorationUnderline', 128 | 'text-indent': 'textIndent', 129 | 'text-transform': 'textTransform', 130 | 'top': 'top', 131 | 'vertical-align': 'verticalAlign', 132 | 'visibility': 'visibility', 133 | 'width': 'width', 134 | 'z-index': 'zIndex', 135 | } 136 | 137 | for (var prop in CSSProperties) { 138 | (function(prop, attr) { 139 | Object.defineProperty(CSSStyleDeclaration.prototype, attr, { 140 | get: function() { 141 | var index = this.keys.indexOf(prop); 142 | if (index === -1) return null; 143 | return this.vals[index]; 144 | }, 145 | set: function(val) { 146 | return this.vals[prop] = val; 147 | } 148 | }) 149 | })(prop, CSSProperties[prop]); 150 | } 151 | 152 | module.exports = CSSStyleDeclaration; 153 | -------------------------------------------------------------------------------- /lib/DOMTokenList.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | function DOMTokenList(str) { 3 | if (str === undefined) 4 | this.keys = []; 5 | else 6 | this.keys = str.split(' '); 7 | } 8 | 9 | DOMTokenList.prototype = { 10 | add: function(key) { 11 | for (var i = 0; i < arguments.length; i++) { 12 | this.keys.push(arguments[i]) 13 | } 14 | }, 15 | contains: function(keys) { 16 | return this.keys.indexOf(key)!== -1; 17 | }, 18 | item: function(index) { 19 | return this.keys[index]; 20 | }, 21 | get keys() { 22 | 23 | }, 24 | set keys(val) { 25 | 26 | }, 27 | get length() { 28 | return this.keys.length; 29 | }, 30 | set length(val) { 31 | 32 | }, 33 | remove: function() { 34 | for (var i = 0; i < arguments.length; i++) { 35 | this.keys.splice(this.keys.indexOf(arguments[i]), 1); 36 | } 37 | }, 38 | toggle: function(key) { 39 | if (this.contains(key)) { 40 | this.remove(key); 41 | return false; 42 | }else{ 43 | this.add(key); 44 | return true; 45 | } 46 | }, 47 | value: function(key) { 48 | return this.keys.join(' '); 49 | } 50 | } 51 | 52 | module.exports = DOMTokenList; 53 | -------------------------------------------------------------------------------- /lib/Document.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Element = require('./Element.js'), 4 | Location = require('./Location.js'), 5 | noop = function (name) { 6 | return function () { 7 | console.log("DOCUMENT NOOP", name, JSON.stringify(arguments)); 8 | }; 9 | }, 10 | 11 | libxmljs, 12 | Document = { 13 | get activeElement() { 14 | return this.__activeElement || this.body; 15 | }, 16 | set activeElement(el) { 17 | return this.__activeElement = el; 18 | }, 19 | adoptNode: noop, 20 | alinkColor: '', 21 | get all() { 22 | return this.querySelectorAll('[id]'); 23 | }, 24 | get anchors() { 25 | return this.getElementsByTagName('a'); 26 | }, 27 | get applets() { 28 | return this.getElementsByTagName('applet'); 29 | }, 30 | get baseURI() { 31 | return this.URL; 32 | }, 33 | bgColor: '', 34 | get body() { 35 | return this.getElementsByTagName('body')[0]; 36 | }, 37 | charset: 'UTF-8', 38 | characterSet: 'UTF-8', 39 | childElementCount: 1, 40 | get childNodes() { 41 | return this.documentElement.childNodes; 42 | }, 43 | get children() { 44 | return this.documentElement; 45 | }, 46 | close: function () { 47 | return this; 48 | }, 49 | compatMode: 'CSS1Compat', 50 | contentType: 'text/html', 51 | get cookie() { 52 | var i = 0, str = '', keys; 53 | 54 | if (this.cookies === undefined) { 55 | return ''; 56 | } 57 | 58 | keys = Object.keys(this.cookies); 59 | 60 | for (; i < keys.length; i++) { 61 | str += keys[i] + ':' + this.cookies[keys[i]]; 62 | 63 | if (i !== keys.length - 1) { 64 | str += '; '; 65 | } 66 | } 67 | 68 | return str; 69 | }, 70 | set cookie(value) { 71 | var key, arr, length, cookie; 72 | 73 | if (this.cookies === undefined) { 74 | this.cookies = {}; 75 | } 76 | 77 | if (typeof value === 'object') { 78 | for (key in value) { 79 | this.cookies[key] = value[key]; 80 | } 81 | 82 | return; 83 | } 84 | 85 | arr = value.split('; '); 86 | length = arr.length; 87 | 88 | while (length--) { 89 | cookie = arr[length].split(':'); 90 | this.cookies[cookie[0]] = cookie[1]; 91 | } 92 | }, 93 | currentScript: null, 94 | createAttribute: function (name) { 95 | //console.log('create attribute:', name); 96 | var el = this.createElement('attrElement'); 97 | 98 | el.setAttribute(name, ''); 99 | return el.getAttributeNode(name); 100 | }, 101 | createComment: function (text) { 102 | //console.log('create comment:', text) 103 | return new libxmljs.Comment(this, text); 104 | }, 105 | createDocument: function () { 106 | //console.log('create document') 107 | return new libxmljs.Document; 108 | }, 109 | createDocumentFragment: function () { 110 | //console.log('create document fragment') 111 | var frag = this.createElement('#document-fragment'); 112 | //Object.defineProperty 113 | return frag; 114 | }, 115 | createElement: function (name) { 116 | //console.log('create element:', name) 117 | var child = new libxmljs.Element(this, name); 118 | 119 | return child; 120 | }, 121 | createTextNode: function (text) { 122 | //console.log("create text:", text) 123 | return new libxmljs.Text(this, new String(text)); 124 | }, 125 | get defaultView() { 126 | if (this.__window === undefined) 127 | this.__window = new libxmljs.Window(this); 128 | return this.__window; 129 | }, 130 | set defaultView(window) { 131 | this.__window = window; 132 | }, 133 | designMode: 'off', 134 | dir: 'ltr', 135 | doctype: { 136 | 137 | }, 138 | get documentElement() { 139 | return this.root() || null; 140 | }, 141 | get documentURI() { 142 | return this.URL; 143 | }, 144 | get domain() { 145 | return this.location.hostname; 146 | }, 147 | get embeds() { 148 | return this.getElementsByTagName('embeds'); 149 | }, 150 | evaluate: function () { 151 | 152 | }, 153 | fgColor: '', 154 | fonts: { 155 | 156 | }, 157 | get forms() { 158 | return this.getElementsByTagName('form'); 159 | }, 160 | getElementById: function (id) { 161 | return this.querySelector('#' + id); 162 | }, 163 | getElementsByClassName: function (name) { 164 | return this.documentElement.getElementsByClassName(name); 165 | }, 166 | getElementsByName: function (name) { 167 | return this.documentElement.querySelectorAll('[name="' + name + '"]'); 168 | }, 169 | getElementsByTagName: function (name) { 170 | return this.documentElement.getElementsByTagName(name); 171 | }, 172 | getElementsByTagNameNS: function (namespace, name) { 173 | return this.documentElement.getElementsByTagNameNS(name); 174 | }, 175 | hasFocus: function () { 176 | return true; 177 | }, 178 | get head() { 179 | return this.getElementsByTagName('head')[0]; 180 | }, 181 | hidden: false, 182 | get images() { 183 | return this.getElementsByTagName('img'); 184 | }, 185 | implementation: { 186 | hasFeature: function (name, version) { 187 | console.log("checking for feature", name, version); 188 | return true; 189 | } 190 | }, 191 | importNode: noop, 192 | inputEncoding: 'UTF-8', 193 | get lastModified() { 194 | return this.defaultView.request.headers['last-modified']; 195 | }, 196 | lastStyleSheet: null, 197 | linkColor: '', 198 | get links() { 199 | return this.querySelector('a[href]'); 200 | }, 201 | localName: null, 202 | get location() { 203 | if (this.__location === undefined) 204 | this.__location = new Location('http://localhost', this); 205 | return this.__location; 206 | }, 207 | set location(val) { 208 | this.__location = new Location(val, this); 209 | 210 | if (this.documentElement !== null) { 211 | this.documentElement.setAttribute('url', this.__location.href); 212 | } 213 | }, 214 | namespaceURI: null, 215 | open: function () { 216 | return this; 217 | }, 218 | parse: function (str) { 219 | return libxmljs.parseHtml(str); // parseHtmlFragment when available 220 | }, 221 | plugins: {}, 222 | prefix: null, 223 | get querySelector() { 224 | return this.documentElement.querySelector; 225 | }, 226 | get querySelectorAll() { 227 | return this.documentElement.querySelectorAll; 228 | }, 229 | readyState: "loading", 230 | /* 231 | __readyState: "loading", 232 | get readyState() { 233 | console.log("GET READY STATE:", this.__readyState, this.querySelectorAll('script:not([@ran])').length); 234 | return this.__readyState; 235 | }, 236 | set readyState(val) { 237 | if (val === this.__readyState) return; 238 | this.__readyState = val; 239 | console.log("READY STATE CHANGE", val) 240 | this.dispatchEvent('readystatechange'); 241 | },*/ 242 | get referrer() { 243 | return this.request.headers.referer; 244 | }, 245 | renameNode: function () { 246 | 247 | }, 248 | get scripts() { 249 | return this.getElementsByTagName('script'); 250 | }, 251 | title: function (str) { 252 | if (!str) { 253 | return this.querySelector('title').innerHTML; 254 | } else { 255 | 256 | } 257 | }, 258 | visibilityState: 'visible', 259 | vlinkColor: '', 260 | write: function (data) { 261 | var script = this.currentScript; 262 | var b = libxmljs.parseHtml('
' + data + '').get('body'); 263 | 264 | if (!b) return; 265 | var children = b.childNodes; 266 | var i = children.length; 267 | 268 | while (i--) { 269 | script.addNextSibling(children[i]); 270 | } 271 | }, 272 | get URL() { 273 | return this.location.toString(); 274 | } 275 | }; 276 | 277 | module.exports = function (libxml) { 278 | libxmljs = libxml; 279 | return Document; 280 | }; 281 | -------------------------------------------------------------------------------- /lib/Element.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var NodeList = require('./NodeList.js'); 3 | var Event = require('./Event.js'); 4 | var CSSStyleDeclaration = require('./CSSStyleDeclaration.js'); 5 | var DOMTokenList = require('./DOMTokenList.js'); 6 | 7 | var noop = function() { 8 | console.log("ELEMENT NOOP") 9 | } 10 | 11 | var Element = { 12 | get accessKeyLabel() { 13 | return this.accessKey 14 | }, 15 | get attributes() { 16 | var arr = this.attrs(); 17 | var obj = { length: arr.length }; 18 | var i = arr.length; 19 | while (i--) { 20 | var attr = arr[i]; 21 | obj[attr.name()] = obj[i] = this.getAttributeNode(attr.name()); 22 | } 23 | return obj; 24 | }, 25 | blur: function() { 26 | this.doc().activeElement = this.doc().documentElement; 27 | }, 28 | get classList() { 29 | return (this.getAttribute('class')||'').split(' '); 30 | }, 31 | set classList(val) { 32 | }, 33 | get className() { 34 | return this.getAttribute('class')||''; 35 | }, 36 | set className(val) { 37 | this.setAttribute('class', val); 38 | }, 39 | clientHeight: null, 40 | clientLeft: null, 41 | clientTop: null, 42 | clientWidth: null, 43 | closest: function(selector) { 44 | return this.querySelector('(ancestor::'+selector+'|preceding::'+selector+')[last()]') 45 | }, 46 | checked: false, 47 | contentEditable: "inherit", 48 | isContentEditable: false, 49 | contextMenu: null, 50 | get contentWindow() { 51 | return this.doc().defaultView; 52 | }, 53 | dataset: { 54 | 55 | }, 56 | dir: "", 57 | draggable: false, 58 | focus: function() { 59 | this.doc().activeElement = this; 60 | }, 61 | get form() { 62 | return this.querySelector('parent::form')||undefined; 63 | }, 64 | get: function(selector) { 65 | var nodes = this.find(selector); 66 | if (!nodes || nodes.length === 0) 67 | return null; 68 | return nodes[0]; 69 | }, 70 | getAttribute: function(name) { 71 | if (this.attr === undefined) 72 | return null; 73 | var attr = this.attr(name); 74 | if (attr === null) 75 | return null; 76 | return attr.value(); 77 | }, 78 | getAttributeNS: function(namespace, attr, node) { 79 | var attr = this.getAttributeNode(attr); 80 | if (!attr) return null; 81 | if (!namespace) return node?attr:attr.value; 82 | var ns = attr.namespace(); 83 | if (!ns) return null; 84 | if (namespace.href() !== this.namespaceURI) 85 | return null; 86 | return node?attr:attr.value; 87 | }, 88 | getAttributeNode: function(name) { 89 | var attrs = this.attrs(); 90 | if (!attr) return null; 91 | for (var i = 0; i < attrs.length; i++) { 92 | if (attrs[i].name() === name) { 93 | var attr = attrs[i]; 94 | attr.name = name; 95 | attr.value = attr; 96 | return attr; 97 | } 98 | } 99 | return null; 100 | }, 101 | getAttributeNodeNS: function(namespace, attr) { 102 | return this.getAttributeNS(namespace, attr, true) 103 | }, 104 | getBoundingClientRect: function() { 105 | // The Element.getBoundingClientRect() method returns the size of an element and its position relative to the viewport.; 106 | return { 107 | x: 0, 108 | y: 0, 109 | width: 0, 110 | height: 0, 111 | top: 0, 112 | right: 0, 113 | bottom: 0, 114 | left: 0, 115 | } 116 | }, 117 | getClientRects: function() { 118 | return [this.getBoundingClientRect()] 119 | }, 120 | getElementsByClassName: function(name) { 121 | return this.querySelectorAll('.'+name); 122 | }, 123 | getElementsByTagName: function(name) { 124 | return this.querySelectorAll(name); 125 | }, 126 | getElementsByTagNameNS: function(namespaceURI, name) { 127 | return this.find('.//'+name, namespaceURI)||[]; 128 | }, 129 | hasAttribute: function(name) { 130 | return this.attr(name)!==null; 131 | }, 132 | hasAttributeNS: function(namespaceURI, name) { 133 | if (!this.hasAttribute(name)) 134 | return false; 135 | return this.attr(name).namespace().href() == namespaceURI; 136 | }, 137 | hasAttributes: function() { 138 | if (this.nodeType === Node.DOCUMENT_NODE) 139 | return false; 140 | return this.attrs().length !== 0; 141 | }, 142 | hidden: false, 143 | get id() { 144 | return this.getAttribute('id'); 145 | }, 146 | get innerHTML() { 147 | if (this.documentElement === undefined) { 148 | var src = this.toString(false); 149 | return src.substring((src.indexOf(">")||-1)+1, src.lastIndexOf("<")||src.length) 150 | }else 151 | return this.toString(false); 152 | }, 153 | set innerHTML(str) { 154 | var self = this; 155 | var doc = this.doc().parse(''+str+'').root() 156 | if (doc === null) { 157 | self.text(str); 158 | return; 159 | } 160 | var body = doc.get('body'); 161 | if (body !== null) 162 | doc = body; 163 | self.childNodes.forEach(function(child) { 164 | child.remove(); 165 | }) 166 | self.text(""); 167 | doc.childNodes.forEach(function(child) { 168 | self.appendChild(child); 169 | }) 170 | }, 171 | insertAdjacentHTML: function(position, text) { 172 | return; 173 | var html = this.doc.parse(''+str+'').root(); 174 | if (html === null) 175 | return; 176 | var body = doc.get('body'); 177 | var next = true; 178 | var node = this; 179 | switch (position) { 180 | case 'beforebegin': 181 | next = true; 182 | node = this.previousSibling; 183 | break; 184 | case 'afterbegin': 185 | next = false; 186 | node = this.firstChild; 187 | break; 188 | case 'beforeend': 189 | next = true; 190 | node = this.lastChild; 191 | break; 192 | case 'afterend': 193 | next = true; 194 | node = this; 195 | break; 196 | } 197 | body.childNodes.forEach(function(child) { 198 | if (next) 199 | node.addNextSibling(child) 200 | else 201 | node.addPrevSibling(child) 202 | }) 203 | }, 204 | isContentEditable: null, 205 | itemScope: false, 206 | itemId: "", 207 | get itemRef() { 208 | if (!this.__itemRef) 209 | this.__itemRef = new DOMTokenList; 210 | return this.__itemRef; 211 | }, 212 | get itemType() { 213 | if (!this.__itemType) 214 | this.__itemType = new DOMTokenList; 215 | return this.__itemType; 216 | }, 217 | get itemProp() { 218 | if (!this.__itemProp) 219 | this.__itemProp = new DOMTokenList; 220 | return this.__itemProp; 221 | }, 222 | itemValue: null, 223 | get labels() { 224 | return this.querySelectorAll('label'); 225 | }, 226 | lang: null, 227 | get length() { 228 | var name = this.name(); 229 | if (name === 'form') 230 | return this.querySelectorAll('input, select, textarea').length; 231 | else if (name === 'select') 232 | return this.querySelectorAll('option').length; 233 | }, 234 | matches: function(selector) { 235 | return this.get('self::node()/'+selector) !== null; 236 | }, 237 | get nextElementSibling() { 238 | return this.nextElement(); 239 | }, 240 | offsetHeight: null, 241 | offsetWidth: null, 242 | offsetLeft: null, 243 | offsetParent: null, 244 | offsetTop: null, 245 | get options() { 246 | return this.querySelectorAll('options'); 247 | }, 248 | get outerHTML() { 249 | return this.toString(); 250 | }, 251 | properties: { 252 | names: [], 253 | length: 0, 254 | }, 255 | get previousElementSibling() { 256 | return this.previousElement(); 257 | }, 258 | querySelector: function(selector) { 259 | return this.get(this.css2xpath(selector))||null; 260 | }, 261 | querySelectorAll: function(selector) { 262 | return NodeList(this.find(this.css2xpath(selector))||[]); 263 | }, 264 | get rel() { 265 | return this.getAttribute('rel'); 266 | }, 267 | set rel(str) { 268 | this.relList.keys = str.split(' '); 269 | }, 270 | get relList() { 271 | if (!this.__relList) { 272 | if (!this.hasAttribute('rel')) 273 | this.setAttribute('rel', ''); 274 | this.__relList = new DOMTokenList(this.getAttribute('rel')); 275 | } 276 | }, 277 | set relList(val) { 278 | 279 | }, 280 | removeAttribute: function(name) { 281 | var attr = this.getAttributeNode(name); 282 | if (attr !== null) 283 | return attr.remove(); 284 | }, 285 | removeAttributeNS: function(name) { 286 | this.removeAttribute(name); 287 | }, 288 | removeAttributeNode: function(attr) { 289 | return attr.remove(); 290 | }, 291 | removeEventListener: function(ev, cb) { 292 | if (ev.indexOf('load')) cb(); 293 | }, 294 | removeAttributeNode: noop, 295 | scrollHeight: null, 296 | scrollLeft: null, 297 | scrollTop: null, 298 | scrollWidth: null, 299 | setAttribute: function(name, val) { 300 | //if (this.getAttributeNode(name) !== null) 301 | // return this.getAttributeNode(name).value(val); 302 | var attr = {}; 303 | attr[name] = val; 304 | this.attr(attr); 305 | }, 306 | setAttributeNS: function(namespace, name, value) { 307 | this.setAttribute(name, value); 308 | }, 309 | setAttributeNode: function(attr) { 310 | this.setAttribute(attr.name, attr.value); 311 | }, 312 | setAttributeNodeNS: function(attr) { 313 | return this.setAttributeNode(attr); 314 | }, 315 | spellcheck: false, 316 | get style() { 317 | if (!this.__styles) 318 | this.__styles = new CSSStyleDeclaration(this.getAttribute('style')||''); 319 | return this.__styles; 320 | }, 321 | set style(str) { 322 | var arr = str.split(':'); 323 | this.style.setProperty(arr[0], arr[1]); 324 | }, 325 | tabIndex: -1, 326 | get tagName() { 327 | return (this.nodeName||'').toUpperCase(); 328 | }, 329 | get type() { 330 | if (this.nodeName === 'button') { 331 | // button, submit, reset, menu 332 | // default: submit 333 | }else{ 334 | return this.getAttribute('type')||undefined; 335 | } 336 | }, 337 | validity: { 338 | valueMissing: false, typeMismatch: false, patternMismatch: false, tooLong: false, 339 | rangeUnderflow: false, rangeOverflow: false, stepMismatch: false, badInput: false, customError: false, valid: true }, 340 | validationMessage: '', 341 | } 342 | 343 | var attributes = { 344 | 'autofocus': { 345 | type: 'bool', 346 | }, 347 | 'accessKey': { 348 | }, 349 | 'charset': {}, 350 | 'coords': { 351 | types: ['a'] 352 | }, 353 | 'disabled': { 354 | type: 'bool' 355 | }, 356 | 'formAction': { 357 | types: ['button'] 358 | }, 359 | 'formEncType': { 360 | types: ['button'] 361 | }, 362 | 'formMethod': { 363 | types: ['button'] 364 | }, 365 | 'formNoValidate': { 366 | types: ['button'] 367 | }, 368 | 'formTarget': { 369 | types: ['button'] 370 | }, 371 | 'height': {}, 372 | 'href': { 373 | value:'', 374 | }, 375 | 'hreflang': { 376 | types: ['a'] 377 | }, 378 | 'link': {}, 379 | 'media': {}, 380 | 'name': {}, 381 | 'shape': {}, 382 | 'src': { 383 | value:'', 384 | }, 385 | 'target': {}, 386 | 'title': {}, 387 | 'value': {}, 388 | 'width': {} 389 | } 390 | 391 | for (var name in attributes) { 392 | var attr = attributes[name]; 393 | (function(name, value) { 394 | Object.defineProperty(Element, name, { 395 | enumerable: true, 396 | get: function() { return this.getAttribute(name)||value; }, 397 | set: function(key) { this.setAttribute(name, key) } 398 | }) 399 | })(name.toLowerCase(), attr.value) 400 | } 401 | 402 | module.exports = Element; 403 | -------------------------------------------------------------------------------- /lib/Event.js: -------------------------------------------------------------------------------- 1 | var Event = function(type, eventInit) { 2 | var self = this; 3 | this.timeStamp = (new Date()).getTime(); 4 | this.type = type; 5 | return this; 6 | } 7 | 8 | Event.prototype = { 9 | bubbles: true, 10 | cancelable: true, 11 | target: null, 12 | currentTarget: null, 13 | defaultPrevented: false, 14 | eventPhase: 0, 15 | type: null, 16 | isTrusted: false, 17 | preventDefault: function() { 18 | this.defaultPrevented = true; 19 | }, 20 | stopImmediatePropagation: function() { 21 | 22 | }, 23 | stopPropagation: function() { 24 | 25 | } 26 | } 27 | 28 | var phases = { 29 | NONE: 0, 30 | CAPTURING_PHASE: 1, 31 | AT_TARGET: 2, 32 | BUBBLING_PHASE: 3 33 | } 34 | 35 | module.exports = Event; 36 | -------------------------------------------------------------------------------- /lib/EventTarget.js: -------------------------------------------------------------------------------- 1 | var Event = require('./Event.js'); 2 | 3 | EventTarget = { 4 | addEventListener: function(name, cb, capture) { 5 | //console.log("addEventListener", this.nodeName||'window', name) 6 | var events = this.__events__; 7 | if (events === undefined) 8 | events = this.__events__ = {}; 9 | if (events[name] === undefined) 10 | events[name] = []; 11 | events[name].push(cb) 12 | 13 | if (name === 'done') { 14 | var window = this.window||this.defaultView||this.doc().defaultView; 15 | if (window.__stackCount === 0) 16 | this.dispatchEvent('done'); 17 | } 18 | }, 19 | dispatchEvent: function(event) { 20 | if (this.window !== undefined && !this.document) return true; 21 | if (typeof event === 'string') { 22 | event = new Event(event); 23 | event.target = this; 24 | } 25 | //console.log("dispatchEvent", this.nodeName||'window', event.type) 26 | var type = event.type; 27 | var events = this.__events__; 28 | if (events === undefined) 29 | return this.__events__ = {}; 30 | if (events[type] === undefined || events[type].length === 0) 31 | return false; 32 | var window = window||this.window||this.defaultView||this.doc().defaultView; 33 | 34 | if (this.getAttribute !== undefined) { 35 | var f = this['on'+type]; 36 | if (f !== undefined && f !== null) { 37 | if (typeof f === 'function') 38 | f = f.toString(); 39 | console.log("on"+type+'="'+f.toString()+'"'); 40 | window.eval(f); 41 | } 42 | } 43 | 44 | if (event.target === undefined) 45 | event.target = this; 46 | if (event.target.getAttribute === undefined) 47 | event.target = this.document?this.document.documentElement:this.documentElement||this.doc().documentElement; 48 | event.currentTarget = this; 49 | 50 | window.__stackPush(); 51 | var arr = events[type]; 52 | var i = arr.length; 53 | while (i--) { 54 | var cb = arr[i]; 55 | if (event.defaultPrevented === true) { 56 | console.log("got prevent default") 57 | window.__stackPop(); 58 | return; 59 | } 60 | cb.call(event.currentTarget, event) 61 | if (type === 'done') 62 | event.currentTarget.removeEventListener(type, cb) 63 | } 64 | window.__stackPop(); 65 | //window.__evalScripts(); 66 | return true; 67 | }, 68 | removeEventListener: function(name, cb, capture) { 69 | //console.log("removeEventListener", name) 70 | var events = this.__events__; 71 | if (events === undefined) 72 | return this.__events__ = {}; 73 | if (events[name] === undefined) 74 | return; 75 | for (var i = events[name].length; i--;) { 76 | if (events[name][i] != cb) continue; 77 | events[name][i] = null; 78 | events[name].splice(i, 1); 79 | break; 80 | } 81 | }, 82 | } 83 | 84 | var handlers = ['abort', 'afterprint', 'beforeprint', 'beforeunload', //'blur', 85 | 'change', 'click', 'contextmenu', 'dblclick', 86 | 'error',/* 'focus',*/, 'focusin', 'hashchange', 'input', 'keydown', 'keypress', 87 | 'keyup', 'languagechange', 'load', 'mousedown', 'mousemove', 88 | 'mouseout', 'mouseover', 'mouseup', 'popstate', 'reset', 89 | 'resize', 'scroll', 'select', 'selectstart', 'submit', 'unload', 90 | 'wheel']; 91 | 92 | handlers.forEach(function(handler) { 93 | EventTarget[handler] = (function(type) { 94 | return function() { console.log(type+'()'); var event = new Event(type); event.target = this; this.dispatchEvent(event); console.log("done") } 95 | })(handler) 96 | Object.defineProperty(EventTarget, 'on'+handler, { 97 | enumerable: true, 98 | get: (function(type) { 99 | return function() { return (this.getAttribute !== undefined)?this.getAttribute('on'+type):null; } 100 | })(handler), 101 | set: function(val) { 102 | 103 | } 104 | }) 105 | }) 106 | 107 | module.exports = EventTarget; 108 | -------------------------------------------------------------------------------- /lib/HTMLCollection.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rchipka/node-libxmljs-dom/794a5ec07d6a076c4f150b1bad6945937ee76f5a/lib/HTMLCollection.js -------------------------------------------------------------------------------- /lib/History.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var History = function(window) { 3 | } 4 | 5 | History.prototype.go = function() { 6 | 7 | } 8 | 9 | History.prototype.back = function() { 10 | 11 | } 12 | 13 | History.prototype.forward = function() { 14 | 15 | } 16 | 17 | module.exports = History; 18 | -------------------------------------------------------------------------------- /lib/HttpRequest.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var URL = require('url'); 3 | var needle = require('needle'); 4 | 5 | needle.defaults({ 6 | follow: 3, 7 | compressed: true, 8 | parse_response: false, 9 | decode_response: true, 10 | follow_set_cookies: true, 11 | follow_set_referer: true, 12 | rejectUnauthorized: false 13 | }) 14 | 15 | function HttpRequest(window, url, callback) { 16 | if (url.substr(0, 2) === '//') 17 | url = window.location.protocol+url; 18 | if (typeof url === 'string') 19 | url = URL.parse(url); 20 | var method = url.method||'get'; 21 | var href = URL.format(url); 22 | if (url.host === null || url.protocol === null) 23 | href = URL.resolve(window.location.href, href); 24 | 25 | var data = url.data; 26 | var opts = { 27 | proxy: url.proxy, 28 | timeout: url.timeout||30*1000, 29 | user_agent: url.user_agent||window.navigator.userAgent, 30 | //headers: url.headers, 31 | headers: { 32 | referer: url.referer||window.location.href, 33 | }, 34 | cookies: window.document.cookies, 35 | accept: url.accept 36 | } 37 | 38 | window.__stackPush(); 39 | console.log('[libxmljs-dom] '+method+' '+href); 40 | needle.request(method, href, data, opts, function(err, res, data) { 41 | if (res !== undefined && res.cookies !== undefined) 42 | window.document.cookies = res.cookies; 43 | callback(err, res, data); 44 | window.__stackPop(); 45 | }) 46 | } 47 | 48 | module.exports = HttpRequest; 49 | -------------------------------------------------------------------------------- /lib/Location.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var URL = require('url'); 3 | 4 | function Location(url, document) { 5 | this.url = url; 6 | if (typeof this.url === 'string') 7 | this.url = URL.parse(url); 8 | if (this.url.host === null || this.url.protocol === null) 9 | this.url = URL.parse(URL.resolve(document.location.href, this.url.href)); 10 | 11 | this.document = document; 12 | return this; 13 | } 14 | 15 | Location.prototype = { 16 | assign: function() { 17 | 18 | }, 19 | get hash() { 20 | return this.url.hash||''; 21 | }, 22 | set hash(val) { 23 | this.url.hash = '#'+val; 24 | }, 25 | get host() { 26 | return this.url.host; 27 | }, 28 | set host(val) { 29 | this.url.host = val; 30 | this.reload(); 31 | }, 32 | get hostname() { 33 | return this.url.hostname; 34 | }, 35 | set hostname(val) { 36 | this.url.hostname = val; 37 | this.reload(); 38 | }, 39 | get href() { 40 | return URL.format(this.url);//this.url.href; 41 | }, 42 | set href(val) { 43 | console.log("setting href", val) 44 | this.url = URL.parse(val); 45 | this.reload(); 46 | }, 47 | get origin() { 48 | return this.url.protocol.replace(/:$/, '://')+this.host; 49 | }, 50 | get password() { 51 | return this.url.password||''; 52 | }, 53 | set password(val) { 54 | this.url.password = val; 55 | var auth = this.username; 56 | }, 57 | get pathname() { 58 | return this.url.pathname; 59 | }, 60 | set pathname(val) { 61 | this.url.pathname = val; 62 | this.reload(); 63 | }, 64 | get port() { 65 | return this.url.port||''; 66 | }, 67 | set port(val) { 68 | this.url.port = val; 69 | this.reload(); 70 | }, 71 | get protocol() { 72 | return this.url.protocol; 73 | }, 74 | set protocol(val) { 75 | this.url.protocol = val; 76 | }, 77 | reload: function(cache) { 78 | this.document.reload(); 79 | }, 80 | replace: function() { 81 | this.document.reload(); 82 | }, 83 | resolve: function(url) { 84 | return URL.resolve(this.url, url); 85 | }, 86 | get search() { 87 | if (this.url.search !== null && this.url.search.length > 0 && this.url.search.charAt(0) !== '?') 88 | return '?'+this.url.search; 89 | return this.url.search; 90 | }, 91 | set search(val) { 92 | this.url.search = val; 93 | this.reload(); 94 | }, 95 | get username() { 96 | return this.url.username; 97 | }, 98 | set username(val) { 99 | this.url.username = val.username; 100 | }, 101 | toString: function() { 102 | return URL.format(this.url); 103 | } 104 | } 105 | 106 | module.exports = Location; 107 | -------------------------------------------------------------------------------- /lib/Navigator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = { 3 | appCodeName: 'Mozilla', 4 | appName: 'Netscape', 5 | appVersion: '5.0', 6 | buildID: '20151029151422', 7 | cookieEnabled: true, 8 | geolocation: {}, 9 | getUserMedia: function() { 10 | 11 | }, 12 | javaEnabled: function() { 13 | return false; 14 | }, 15 | language: 'en-US', 16 | onLine: true, 17 | platform: 'MacIntel', 18 | product: 'Gecko', 19 | registerContentHandler: function() { 20 | 21 | }, 22 | registerProtocolHandler: function() { 23 | 24 | }, 25 | /*sendBeacon: function(url, data) { 26 | return true; 27 | },*/ 28 | userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:42.0) Gecko/20100101 Firefox/42.0", 29 | plugins: [], 30 | vibrate: function() { 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/Node.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var NodeList = require('./NodeList.js'); 4 | 5 | var Node = { 6 | appendChild: function (child) { 7 | if (this.nodeType === Node.DOCUMENT_NODE) { 8 | console.log("append to DOC"); 9 | this.documentElement.addChild(child); 10 | return; 11 | } 12 | 13 | this.addChild(child); 14 | 15 | if (child.nodeName === 'script') 16 | this.doc().defaultView.__evalScripts(); 17 | return child; 18 | }, 19 | get baseURI() { 20 | return this.doc().baseURI; 21 | }, 22 | get childElementCount() { 23 | return this.childNodes.length; 24 | }, 25 | get childNodes() { 26 | if (this.nodeType === Node.DOCUMENT_NODE) 27 | return NodeList([this.documentElement]); 28 | return NodeList(this.__childNodes()); 29 | }, 30 | get children() { 31 | return this.childNodes; 32 | }, 33 | cloneNode: function (recursive) { 34 | //console.log("CLONING", recursive==true, this.nodeName) 35 | return this.clone(recursive); 36 | }, 37 | compareDocumentPosition: function (node) { 38 | var bitmask = 0; 39 | var h1 = this.path(); 40 | var h2 = node.path(); 41 | 42 | if (h1.length > h2.length) { 43 | bitmask += Node.DOCUMENT_POSITION_PRECEDING; 44 | 45 | if (h2.indexOf(h1) === 0) { 46 | bitmask += Node.DOCUMENT_POSITION_CONTAINS; 47 | } 48 | } else if (h2.length > h1.length) { 49 | bitmask += Node.DOCUMENT_POSITION_FOLLOWING; 50 | 51 | if (h1.indexOf(h2) === 0) { 52 | bitmask += Node.DOCUMENT_POSITION_CONTAINED_BY; 53 | } 54 | 55 | } 56 | 57 | return bitmask; 58 | }, 59 | contains: function (node) { 60 | return node.path().indexOf(this.path()) === 0; 61 | }, 62 | get firstChild() { 63 | return this.childNodes[0] || null; 64 | }, 65 | get firstElementChild() { 66 | return this.firstChild; 67 | }, 68 | // getFeature() 69 | getUserData: function (key) { 70 | if (this.__userData === undefined) 71 | return; 72 | return this.__userData[key]; 73 | }, 74 | hasAttributes: function () { 75 | if (this.nodeType === Node.DOCUMENT_NODE) 76 | return false; 77 | return this.attrs().length !== 0; 78 | }, 79 | hasChildNodes: function () { 80 | return this.childNodes.length !== 0; 81 | }, 82 | // TODO: innerText != textContent 83 | get innerText() { 84 | return this.text(); 85 | }, 86 | insertBefore: function (node, sibling) { 87 | if (node.nodeName === 'script') { 88 | var window = this.doc().defaultView; 89 | 90 | process.nextTick(function () { 91 | window.__evalScripts(); 92 | }); 93 | } 94 | 95 | if (!sibling) { 96 | if (this.lastChild !== null) 97 | return this.lastChild.addNextSibling(node); 98 | return null; 99 | } 100 | 101 | return sibling.addPrevSibling(node); 102 | }, 103 | isDefaultNamespace: function () { 104 | return true; 105 | }, 106 | isEqualNode: function (node) { 107 | return this.toString() === node.toString(); 108 | }, 109 | isSameNode: function (node) { 110 | return this.path() === node.path(); 111 | }, 112 | isSupported: function () { 113 | return true; 114 | }, 115 | get lastElementChild() { 116 | return this.lastChild; 117 | }, 118 | get lastChild() { 119 | return this.childNodes[this.childNodes.length - 1] || null; 120 | }, 121 | get localName() { 122 | return this.nodeName; 123 | }, 124 | lookupNamespaceURI: function () { 125 | return null; 126 | }, 127 | lookupPrefix: function () { 128 | return null; 129 | }, 130 | namespaceURI: null, 131 | get nextSibling() { 132 | return this.__nextSibling(); 133 | }, 134 | get nodeName() { 135 | if (this.nodeType === Node.DOCUMENT_NODE) 136 | return '#document'; 137 | return this.__name(); 138 | }, 139 | set nodeName(val) { 140 | this.__name(val); 141 | }, 142 | nodePrincipal: undefined, 143 | get nodeType() { 144 | if (this.documentElement !== undefined) 145 | return Node.DOCUMENT_NODE; 146 | 147 | if (this.__name() === '#document-fragment') 148 | return Node.DOCUMENT_FRAGMENT_NODE; 149 | /*if (Object.getOwnPropertyDescriptor(this, 'type').get === undefined) { 150 | switch (this.type()) { 151 | case 'attribute': 152 | return Node.ATTRIBUTE_NODE; 153 | case 'text': 154 | return Node.TEXT_NODE; 155 | case 'comment': 156 | return Node.COMMENT_NODE; 157 | } 158 | }*/ 159 | return Node.ELEMENT_NODE; 160 | }, 161 | get nodeValue() { 162 | // TODO: return text for Node.TEXT_NODE and Node.COMMENT_NODE 163 | return null; 164 | }, 165 | normalize: function () { 166 | // TODO: remove empty text nodes and join adjacent text nodes 167 | }, 168 | get ownerDocument() { 169 | return this.doc(); 170 | }, 171 | get parentElement() { 172 | if (this.nodeType === Node.DOCUMENT_FRAGMENT_NODE) 173 | return null; 174 | 175 | if (this.parent === undefined) 176 | return null; 177 | 178 | if (this.parent().nodeType === Node.DOCUMENT_NODE) 179 | return null; 180 | return this.parent(); 181 | }, 182 | get parentNode() { 183 | if (this.nodeType === Node.DOCUMENT_NODE) 184 | return null; 185 | 186 | if (this.nodeType === Node.DOCUMENT_FRAGMENT_NODE) 187 | return null; 188 | 189 | if (this.parent === undefined) 190 | return null; 191 | return this.parent(); 192 | }, 193 | prefix: null, 194 | get previousSibling() { 195 | return this.prevSibling(); 196 | }, 197 | removeChild: function (child) { 198 | //console.log("REMOVE", child.nodeName); 199 | return child.remove(); 200 | }, 201 | replaceChild: function (newChild, oldChild) { 202 | //console.log("REPLACE", oldChild.nodeName, "with", newChild.nodeName); 203 | return oldChild.replace(newChild); 204 | }, 205 | setUserData: function (key, value) { 206 | // TODO: handler callback on Node clone, import, rename, delete or adopt 207 | if (!this.__userData) 208 | this.__userData = {}; 209 | this.__userData[key] = value; 210 | }, 211 | get textContent() { 212 | return this.text(); 213 | }, 214 | DOCUMENT_POSITION_DISCONNECTED: 1, 215 | DOCUMENT_POSITION_PRECEDING: 2, 216 | DOCUMENT_POSITION_FOLLOWING: 4, 217 | DOCUMENT_POSITION_CONTAINS: 8, 218 | DOCUMENT_POSITION_CONTAINED_BY: 16, 219 | DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: 32, 220 | ELEMENT_NODE: 1, 221 | ATTRIBUTE_NODE: 2, 222 | TEXT_NODE: 3, 223 | CDATA_SECTION_NODE: 4, 224 | ENTITY_REFERENCE_NODE: 5, 225 | ENTITY_NODE: 6, 226 | PROCESSING_INSTRUCTION_NODE: 7, 227 | COMMENT_NODE: 8, 228 | DOCUMENT_NODE: 9, 229 | DOCUMENT_TYPE_NODE: 10, 230 | DOCUMENT_FRAGMENT_NODE: 11, 231 | NOTATION_NODE: 12 232 | }; 233 | 234 | module.exports = Node; 235 | -------------------------------------------------------------------------------- /lib/NodeList.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var NodeList = function(array) { 3 | if (array.item === undefined) 4 | array.item = item; 5 | return array; 6 | } 7 | 8 | function item(i) { 9 | return this[i]; 10 | } 11 | 12 | module.exports = NodeList; 13 | -------------------------------------------------------------------------------- /lib/Storage.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var Storage = function() { 3 | this.items = []; 4 | return this; 5 | } 6 | 7 | Storage.prototype = { 8 | get length() { 9 | return items.length; 10 | }, 11 | clear: function() { 12 | this.items = []; 13 | }, 14 | key: function(i) { 15 | return this[i]; 16 | }, 17 | getItem: function(key) { 18 | return this.items[this[key]]||null; 19 | }, 20 | setItem: function(key, val) { 21 | if (this[key] === undefined) { 22 | this[key] = this.items.push(val)-1; 23 | } 24 | this.items[this[key]] = val; 25 | }, 26 | removeItem: function(key) { 27 | this.items[this[key]] = undefined; 28 | this[key] = undefined; 29 | } 30 | } 31 | 32 | module.exports = Storage; 33 | -------------------------------------------------------------------------------- /lib/Window.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var History = require('./History.js'); 3 | var vm = require('vm'); 4 | var needle = require('needle'); 5 | var URL = require('url'); 6 | var Event = require('./Event.js'); 7 | var Storage = require('./Storage.js'); 8 | var HttpRequest = require('./HttpRequest.js') 9 | var XMLHttpRequest = require('./XMLHttpRequest.js') 10 | 11 | function bindEvent(name, cb) { 12 | return cb; 13 | } 14 | 15 | var noop = function() { 16 | console.log("WINDOW NOOP"); 17 | } 18 | 19 | function Window(context) { 20 | var window = this; 21 | 22 | if (context !== undefined) 23 | this.document = context; 24 | 25 | return this; 26 | } 27 | 28 | Object.defineProperty(console, 'log', { 29 | configurable: false, 30 | writable: false 31 | }) 32 | 33 | Window.prototype = { 34 | alert: function(m) { console.log('alert:', m) }, 35 | applicationCache: { 36 | status: 0, 37 | }, 38 | atob: function(s) { return (new Buffer(s, 'base64')).toString() }, 39 | btoa: function(s) { return s.toString('base64') }, 40 | back: function() { 41 | this.history.back(); 42 | }, 43 | blur: noop, 44 | cancelAnimationFrame: noop, 45 | close: function() { 46 | this.closed = true; 47 | }, 48 | closed: false, 49 | confirm: noop, 50 | crypto: {}, 51 | defaultStatus: '', 52 | devicePixelRatio: 1, 53 | get document() { 54 | if (this.__document === undefined) 55 | this.__document = new libxmljs.Document(); 56 | return this.__document; 57 | }, 58 | set document(doc) { 59 | this.__document = doc; 60 | this.__document.defaultView = this; 61 | this.__document.readyState = 'interactive'; 62 | this.__evalScripts(); 63 | }, 64 | domain: '', 65 | //dump: console.log, 66 | __evalScripts: function() { 67 | var window = this; 68 | window.__stackPush(); 69 | var script = window.document.querySelector('script:not([ran])'); 70 | if (!script) { 71 | if (this.document.readyState !== "complete") { 72 | this.document.readyState = "complete"; 73 | this.document.dispatchEvent('DOMContentLoaded'); 74 | this.dispatchEvent('load'); 75 | } 76 | window.__stackPop(); 77 | return; 78 | } 79 | script.setAttribute('ran', true); 80 | window.document.currentScript = script; 81 | var src = script.src; 82 | if (src && src.length > 0) { 83 | HttpRequest(window, src, function(err, res, data) { 84 | if (err) { 85 | console.log("error:", err) 86 | }else if (res.headers && res.headers['content-type'] !== undefined && res.headers['content-type'].indexOf('javascript') === -1) { 87 | //console.log("Got non javascript", res.headers['content-type']) 88 | }else{ 89 | console.log("[libxmljs-dom] Executing remote script: "+src); 90 | window.eval(data.toString(), src); 91 | } 92 | window.__evalScripts(); 93 | window.__stackPop(); 94 | }) 95 | }else{ 96 | var type = script.getAttribute('type'); 97 | if (type === null || type.toLowerCase().indexOf('text/j') === -1) { 98 | var src = window.location.href+'. 6 | 7 | 8 | 9 | 10 | The content of the document...... 11 | 12 | 13 |