Skip to content

Commit

Permalink
Implement document.body correctly per-spec
Browse files Browse the repository at this point in the history
Notably, implement its setter.
  • Loading branch information
domenic committed Dec 19, 2016
1 parent 656f606 commit ae19887
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 5 deletions.
10 changes: 10 additions & 0 deletions lib/jsdom/living/helpers/traversal.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,13 @@ exports.firstChildWithHTMLLocalName = (parent, localName) => {
}
return null;
};

exports.firstChildWithHTMLLocalNames = (parent, localNamesSet) => {
const iterator = domSymbolTree.childrenIterator(parent);
for (const child of iterator) {
if (localNamesSet.has(child._localName) && child._namespaceURI === "http://www.w3.org/1999/xhtml") {
return child;
}
}
return null;
};
37 changes: 32 additions & 5 deletions lib/jsdom/living/nodes/Document-impl.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const isNodeImpl = require("../generated/Node").isImpl;
const NODE_TYPE = require("../node-type");
const memoizeQuery = require("../../utils").memoizeQuery;
const firstChildWithHTMLLocalName = require("../helpers/traversal").firstChildWithHTMLLocalName;
const firstChildWithHTMLLocalNames = require("../helpers/traversal").firstChildWithHTMLLocalNames;
const whatwgURL = require("whatwg-url");
const domSymbolTree = require("../helpers/internal-constants").domSymbolTree;
const DOMException = require("../../web-idl/DOMException");
Expand Down Expand Up @@ -559,15 +560,41 @@ class DocumentImpl extends NodeImpl {
}

get body() {
if (!this.documentElement) {
const documentElement = this.documentElement;
if (!documentElement || documentElement._localName !== "html" ||
documentElement._namespaceURI !== "http://www.w3.org/1999/xhtml") {
return null;
}

let body = firstChildWithHTMLLocalName(this.documentElement, "body");
if (!body) {
body = firstChildWithHTMLLocalName(this.documentElement, "frameset");
return firstChildWithHTMLLocalNames(this.documentElement, new Set(["body", "frameset"]));
}

set body(value) {
if (!HTMLElement.isImpl(value)) {
throw new TypeError("Argument must be a HTMLElement");
}
if (value._namespaceURI !== "http://www.w3.org/1999/xhtml" ||
(value._localName !== "body" && value._localName !== "frameset")) {
throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, "Cannot set the body to a non-body/frameset element");
}

const bodyElement = this.body;
if (value === bodyElement) {
return;
}
return body;

if (bodyElement !== null) {
bodyElement.parentNode.replaceChild(value, bodyElement);
return;
}

const documentElement = this.documentElement;
if (documentElement === null) {
throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
"Cannot set the body when there is no document element");
}

documentElement.appendChild(value);
}

_runRemovingSteps(oldNode, oldParent, oldPreviousSibling) {
Expand Down
1 change: 1 addition & 0 deletions test/web-platform-tests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ describe("Web Platform Tests", () => {
"html/browsers/history/the-location-interface/location_search.html",
"html/browsers/offline/browser-state/navigator_online_online.html",
// "html/browsers/windows/browsing-context-first-created.xhtml", // jsdom will try to feed <![CDATA[ to the script parser, causing errors
"html/dom/documents/dom-tree-accessors/Document.body.html",
"html/dom/dynamic-markup-insertion/document-writeln/document.writeln-02.html",
"html/dom/dynamic-markup-insertion/document-writeln/document.writeln-03.html",
"html/dom/elements/global-attributes/classlist-nonstring.html",
Expand Down

0 comments on commit ae19887

Please sign in to comment.