Skip to content

Commit

Permalink
Make key properties writable to allow polyfilling
Browse files Browse the repository at this point in the history
Many polyfills rewrite built-ins on the DOM to add new functionality and
support new upcoming specs. In the browser, this is fine - DOM
properties are reliably writable. In Domino they weren't.

The specific changes here are to support the custom-elements polyfill
  https://github.com/webcomponents/custom-elements/blob/master/src/custom-elements.js
but cover the most popular and widely applicable methods. This should
probably be extended in future to cover the whole API.

Writability is configurable.  If you wish to lock down the DOM API,
set the global `__domino_frozen__` to `true` before your first
`require('domino')`.

Fixes: #89
  • Loading branch information
pimterry authored and cscott committed Jan 26, 2017
1 parent c8f88f9 commit 841d292
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Fix unescape mechanism in attribute values. (#95)
* Disable nonstandard "ignore case" version of attribute matching.
* Add `dom/nodes` tests from w3c/web-platform-tests. (#92, @pimterry)
* Make selected API methods writable to support polyfills. (#89, @pimterry)

# domino 1.0.27 (17 Oct 2016)
* Fix bug in AFE list replacement over existing bookmark.
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ var h1 = document.querySelector('h1');
console.log(h1.innerHTML);
```

By default many domino methods will be stored in writable properties, to
allow polyfills (as browsers do). You can lock down the implementation
if desired as follows:
```javascript
global.__domino_frozen__ = true; // Must precede any `require('domino')`
var domino = require('domino');
```

## Tests

Domino includes test from the [W3C DOM Conformance Suites](http://www.w3.org/DOM/Test/)
Expand Down
7 changes: 4 additions & 3 deletions lib/Document.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ var svg = require('./svg');
var utils = require('./utils');
var MUTATE = require('./MutationConstants');
var NAMESPACE = utils.NAMESPACE;
var isApiWritable = require("./config").isApiWritable;

function Document(isHTML, address) {
this.nodeType = Node.DOCUMENT_NODE;
Expand Down Expand Up @@ -135,7 +136,7 @@ Document.prototype = Object.create(Node.prototype, {
if (!xml.isValidName(localName)) utils.InvalidCharacterError();
if (this.isHTML) localName = utils.toASCIILowerCase(localName);
return html.createElement(this, localName, null);
}},
}, writable: isApiWritable },

createElementNS: { value: function(namespace, qualifiedName) {
if (!xml.isValidName(qualifiedName)) utils.InvalidCharacterError();
Expand Down Expand Up @@ -170,7 +171,7 @@ Document.prototype = Object.create(Node.prototype, {
}

return new Element(this, localName, namespace, prefix);
}},
}, writable: isApiWritable },

createEvent: { value: function createEvent(interfaceName) {
interfaceName = interfaceName.toLowerCase();
Expand Down Expand Up @@ -346,7 +347,7 @@ Document.prototype = Object.create(Node.prototype, {

importNode: { value: function importNode(node, deep) {
return this.adoptNode(node.cloneNode());
}},
}, writable: isApiWritable },

// The following attributes and methods are from the HTML spec
URL: { get: utils.nyi },
Expand Down
7 changes: 7 additions & 0 deletions lib/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
* This file defines Domino behaviour that can be externally configured.
* To change these settings, set the relevant global property *before*
* you call `require("domino")`.
*/

exports.isApiWritable = !global.__domino_frozen__;
3 changes: 2 additions & 1 deletion lib/utils.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use strict";
var DOMException = require('./DOMException');
var ERR = DOMException;
var isApiWritable = require("./config").isApiWritable;

exports.NAMESPACE = {
HTML: 'http://www.w3.org/1999/xhtml',
Expand Down Expand Up @@ -48,7 +49,7 @@ exports.assert = function(expr, msg) {

exports.expose = function(src, c) {
for (var n in src) {
Object.defineProperty(c.prototype, n, {value: src[n] });
Object.defineProperty(c.prototype, n, { value: src[n], writable: isApiWritable });
}
};

Expand Down
16 changes: 16 additions & 0 deletions test/domino.js
Original file line number Diff line number Diff line change
Expand Up @@ -862,3 +862,19 @@ exports.gh95 = function() {
}).should.throw({ name: 'SyntaxError' });
document.querySelectorAll("a[href=foo\\'s]").length.should.equal(1);
};

exports.propertyWritability = function () { // gh #89
var window = domino.createWindow('');
var document = domino.createDocument();

function assertWritable(object, property) {
var replacement = function () { };
object[property] = replacement;
object[property].should.equal(replacement, property + " should be writable");
}

assertWritable(window, 'HTMLElement');
assertWritable(document, 'importNode');
assertWritable(document, 'createElement');
assertWritable(document, 'createElementNS');
}

0 comments on commit 841d292

Please sign in to comment.