var dom = exports.dom = require("./jsdom/level3/index").dom, fs = require("fs"), pkg = JSON.parse(fs.readFileSync(__dirname + "/../package.json")), request = require('request'), URL = require('url'); var style = require('./jsdom/level2/style'); exports.defaultLevel = dom.level3.html; exports.browserAugmentation = require("./jsdom/browser/index").browserAugmentation; exports.windowAugmentation = require("./jsdom/browser/index").windowAugmentation; exports.debugMode = false; var createWindow = exports.createWindow = require("./jsdom/browser/index").createWindow; exports.__defineGetter__('version', function() { return pkg.version; }); exports.level = function (level, feature) { if(!feature) feature = 'core' return require('./jsdom/level' + level + '/' + feature).dom['level' + level][feature] } exports.jsdom = function (html, level, options) { options = options || {}; if(typeof level == "string") { level = exports.level(level, 'html') } else { level = level || exports.defaultLevel; } if (!options.url) { options.url = (module.parent.id === 'jsdom') ? module.parent.parent.filename : module.parent.filename; } if (options.features && options.features.QuerySelector) { require("./jsdom/selectors/index").applyQuerySelectorPrototype(level); } var browser = exports.browserAugmentation(level, options), doc = (browser.HTMLDocument) ? new browser.HTMLDocument(options) : new browser.Document(options); exports.applyDocumentFeatures(doc, options.features); if (!!html) { doc.write(html + ''); } else { doc.write(''); } if (doc.close && !options.deferClose) { doc.close(); } // Kept for backwards-compatibility. The window is lazily created when // document.parentWindow or document.defaultView is accessed. doc.createWindow = function() { // Remove ourself if (doc.createWindow) { delete doc.createWindow; } return doc.parentWindow; }; return doc; }; exports.html = function(html, level, options) { html += ''; // TODO: cache a regex and use it here instead // or make the parser handle it var htmlLowered = html.toLowerCase(); // body if (!~htmlLowered.indexOf(''; } // html if (!~htmlLowered.indexOf(''; } return exports.jsdom(html, level, options); }; exports.availableDocumentFeatures = [ 'FetchExternalResources', 'ProcessExternalResources', 'MutationEvents', 'QuerySelector' ]; exports.defaultDocumentFeatures = { "FetchExternalResources" : ['script'/*, 'img', 'css', 'frame', 'link'*/], "ProcessExternalResources" : ['script'/*, 'frame', 'iframe'*/], "MutationEvents" : '2.0', "QuerySelector" : false }; exports.applyDocumentFeatures = function(doc, features) { var i, maxFeatures = exports.availableDocumentFeatures.length, defaultFeatures = exports.defaultDocumentFeatures, j, k, featureName, featureSource; features = features || {}; for (i=0; i 1 && typeof(args[1] === 'string')) { path = args[1]; } var features = window.document.implementation._features; window.document.implementation.addFeature('FetchExternalResources', ['script']); window.document.implementation.addFeature('ProcessExternalResources', ['script']); window.document.implementation.addFeature('MutationEvents', ["1.0"]); jQueryTag.src = path || 'http://code.jquery.com/jquery-latest.js'; window.document.body.appendChild(jQueryTag); jQueryTag.onload = function() { if (callback) { callback(window, window.jQuery); } window.document.implementation._features = features; }; return window; }; exports.env = exports.jsdom.env = function() { var args = Array.prototype.slice.call(arguments), config = exports.env.processArguments(args), callback = config.done, processHTML = function(err, html) { html += ''; if(err) { return callback(err); } config.scripts = config.scripts || []; if (typeof config.scripts === 'string') { config.scripts = [config.scripts]; } config.src = config.src || []; if (typeof config.src === 'string') { config.src = [config.src]; } var options = { features: { 'FetchExternalResources' : false, 'ProcessExternalResources' : false }, url: config.url }, window = exports.html(html, null, options).createWindow(), features = window.document.implementation._features, docsLoaded = 0, totalDocs = config.scripts.length, readyState = null, errors = null; if (!window || !window.document) { return callback(new Error('JSDOM: a window object could not be created.')); } window.document.implementation.addFeature('FetchExternalResources', ['script']); window.document.implementation.addFeature('ProcessExternalResources', ['script']); window.document.implementation.addFeature('MutationEvents', ['1.0']); var scriptComplete = function() { docsLoaded++; if (docsLoaded >= totalDocs) { window.document.implementation._features = features; callback(errors, window); } } if (config.scripts.length > 0 || config.src.length > 0) { config.scripts.forEach(function(src) { var script = window.document.createElement('script'); script.onload = function() { scriptComplete() }; script.onerror = function(e) { if (!errors) { errors = []; } errors.push(e.error); scriptComplete(); }; script.src = src; window.document.documentElement.appendChild(script); }); config.src.forEach(function(src) { var script = window.document.createElement('script'); script.onload = function() { process.nextTick(scriptComplete); }; script.onerror = function(e) { if (!errors) { errors = []; } errors.push(e.error || e.message); // nextTick so that an exception within scriptComplete won't cause // another script onerror (which would be an infinite loop) process.nextTick(scriptComplete); }; script.text = src; window.document.documentElement.appendChild(script); window.document.documentElement.removeChild(script); }); } else { callback(errors, window); } }; config.html += ''; // Handle markup if (config.html.indexOf("\n") > 0 || config.html.match(/^\W*