Skip to content

Commit

Permalink
Merge pull request #21 from artemisbot/master
Browse files Browse the repository at this point in the history
Feature: allow d3 to run using nodom
  • Loading branch information
pakastin committed Mar 19, 2019
2 parents 6e9a191 + 73ab901 commit e1f371e
Show file tree
Hide file tree
Showing 11 changed files with 1,144 additions and 1,041 deletions.
1,188 changes: 704 additions & 484 deletions dist/nodom.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/nodom.min.js

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions lib/attributes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

export function Attributes () { }
Attributes.prototype = {};
3 changes: 3 additions & 0 deletions lib/dataset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

export function Dataset () { }
Dataset.prototype = {};
61 changes: 57 additions & 4 deletions lib/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,63 @@ export function Document () {
}

Document.prototype.createElement = function (tagName) {
return new HTMLElement({
let element = new HTMLElement({
tagName: tagName
});

// element.ownerDocument = this;

if (!('ownerDocument' in element)) {
Object.defineProperty(element, 'ownerDocument', {
enumerable: false,
get: (function (t) { return function () { return t; }; })(this)
});
}

return element;
};

Document.prototype.createElementNS = function (ns, tagName) {
let element;
if (tagName === 'http://www.w3.org/2000/svg') {
return new SVGElement({
element = new SVGElement({
tagName: tagName
});
} else {
return new HTMLElement({
element = new HTMLElement({
tagName: tagName
});
}

// element.ownerDocument = this;

if (!('ownerDocument' in element)) {
Object.defineProperty(element, 'ownerDocument', {
enumerable: false,
get: (function (t) { return function () { return t; }; })(this)
});
}

return element;
};

Document.prototype.createDocumentFragment = function () {
return (new Document()).body;
};

Document.prototype.createTextNode = function (text) {
return new TextNode(text);
let textNode = new TextNode(text);

// element.textNode = this;

if (!('ownerDocument' in textNode)) {
Object.defineProperty(textNode, 'ownerDocument', {
enumerable: false,
get: (function (t) { return function () { return t; }; })(this)
});
}

return textNode;
};

Document.prototype.getElementsByTagName = function (tagName) {
Expand Down Expand Up @@ -98,3 +136,18 @@ Document.prototype.querySelector = function (query) {
Document.prototype.querySelectorAll = function (query) {
return querySelectorAll(query, this);
};

Document.prototype.implementation = Object.create(null);

Document.prototype.implementation.hasFeature = function (feature/*, version */) {
switch (feature) {
default:
return false;
}
};

Document.prototype.implementation.createHTMLDocument = function (textContent) {
let document = new Document();
document.outerHTML = textContent;
return document;
};
133 changes: 107 additions & 26 deletions lib/element.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,25 @@ import { ClassList } from './classlist';
import { Node } from './node';
import { TextNode } from './textnode';
import { querySelector, querySelectorAll } from './utils/querySelector';
import { Attributes } from './attributes';
import { CSSStyleDeclaration } from './style';
import { Dataset } from './dataset';
import { dashToCamel } from './utils/notation';
import { elementMatches } from './utils/elementMatches';
import { parseSelector } from './utils/parseSelector';

const voidElementLookup = 'area base br col command embed hr img input keygen link meta param source track wbr'.split(' ').reduce(function (lookup, tagName) {
lookup[tagName] = true;
return lookup;
}, {});

export function HTMLElement (options) {
this.childNodes = [];
this.style = {};
Node.apply(this);

this.attributes = new Attributes();
this.style = new CSSStyleDeclaration();
this.dataset = new Dataset();

this.nodeType = 1;

for (const key in options) {
Expand Down Expand Up @@ -51,37 +61,56 @@ HTMLElement.prototype.render = function (inner) {
let content = '';

for (const key in this) {
if (key === 'isMounted' || !this.hasOwnProperty(key)) {
if (key === 'isMounted' ||
key === 'style' ||
key === 'attributes' ||
key === 'dataset' ||
key === '_classList' ||
!this.hasOwnProperty(key)) {
continue;
}
if (shouldNotRender[key] || !isVoidEl) {
if (shouldNotRender[key]/* || !isVoidEl */) { // FIXME: no need?
if (this.childNodes.length) {
hasChildren = true;
}
} else if (key === '_innerHTML') {
content = this._innerHTML;
} else if (key === 'style') {
let styles = '';

for (const styleName in this.style) {
styles += styleName + ':' + this.style[styleName] + ';';
}

if (styles && styles.length) {
attributes.push('style="' + styles + '"');
}
} else if (!shouldNotRender[key]) {
if (typeof this[key] === 'function') {
continue;
}
attributes.push(key + '="' + this[key] + '"');

let value;
switch (typeof this[key]) {
case 'string':
case 'number':
value = '"' + this[key] + '"';
break;

default:
// FIXME: is it better to use 'data-${key}' for jQuery .data(key) ?
value = "'" + JSON.stringify(this[key]) + "'";
}
attributes.push(key + '=' + value);
}
}

if (this.className) {
attributes.push('class="' + this.className + '"');
}

let cssText = this.style.cssText;
if (cssText.length > 0) {
attributes.push('style="' + cssText + '"');
}

let attrNames = Object.keys(this.attributes);
if (attrNames.length > 0) {
attrNames
.filter((e) => !(e in ['style', '_classList']))
.map((e) => attributes.push(e + '="' + this.attributes[e] + '"'));
}

if (inner) {
if (!isVoidEl && hasChildren) {
return this.childNodes.map(childRenderer).join('');
Expand Down Expand Up @@ -119,11 +148,44 @@ HTMLElement.prototype.addEventListener = function () {};
HTMLElement.prototype.removeEventListener = function () {};

HTMLElement.prototype.setAttribute = function (attr, value) {
this[attr] = value;
switch (attr) {
case 'class': {
this.classList.splice(0, this.classList.length);
let classes = value.split(' ');
classes.forEach((cls) => this.classList.add(cls));
break;
}

default:
break;
}

let propertyName = attr;

if (/^data-/.test(attr)) {
propertyName = dashToCamel(attr);
this.dataset[propertyName] = value;

Object.defineProperty(this, propertyName, {
get: (function (t, a) {
return function () { return t.dataset[a]; };
})(this, propertyName),
enumerable: true
});
} else if (!this.hasOwnProperty(propertyName)) {
Object.defineProperty(this, propertyName, {
get: (function (t, a) {
return function () { return t.attributes[a]; };
})(this, propertyName),
enumerable: true
});
}

this.attributes[attr] = value;
};

HTMLElement.prototype.getAttribute = function (attr) {
return this[attr];
return this.attributes[attr] || this[attr];
};

HTMLElement.prototype.appendChild = function (child) {
Expand All @@ -141,17 +203,24 @@ HTMLElement.prototype.appendChild = function (child) {
};

HTMLElement.prototype.insertBefore = function (child, before) {
let this$1 = this;

if (this.isVoidEl) {
return; // Silently ignored
}
child.parentNode = this;
for (let i = 0; i < this.childNodes.length; i++) {
if (this.childNodes[i] === before) {
this.childNodes.splice(i++, 0, child);
} else if (this.childNodes[i] === child) {
this.childNodes.splice(i, 1);
if (before == null) {
this$1.childNodes.push(child);
} else {
for (let i = 0; i < this.childNodes.length; i++) {
if (this$1.childNodes[i] === before) {
this$1.childNodes.splice(i++, 0, child);
} else if (this$1.childNodes[i] === child) {
this$1.childNodes.splice(i, 1);
}
}
}
return child;
};

HTMLElement.prototype.replaceChild = function (child, replace) {
Expand Down Expand Up @@ -186,11 +255,15 @@ HTMLElement.prototype.getElementsByTagName = function (tagName) {
}

return this.childNodes.reduce(function (results, child) {
if (lowerTagName === '*' || child.tagName === lowerTagName) {
return results.concat(child, child.getElementsByTagName(lowerTagName));
}
if (child.getElementsByTagName) {
if (lowerTagName === '*' || child.tagName === lowerTagName) {
return results.concat(child, child.getElementsByTagName(lowerTagName));
}

return results.concat(child.getElementsByTagName(lowerTagName));
return results.concat(child.getElementsByTagName(lowerTagName));
} else {
return results;
}
}, []);
};

Expand Down Expand Up @@ -222,6 +295,14 @@ HTMLElement.prototype.querySelectorAll = function (query) {
return querySelectorAll(query, this);
};

HTMLElement.prototype.matches = function (query) {
let terms = parseSelector(query);
if (terms == null || terms.length > 1) {
return false;
}
return elementMatches(this, terms[0]);
};

Object.defineProperties(HTMLElement.prototype, {
_classList: {
value: null,
Expand Down
39 changes: 36 additions & 3 deletions lib/node.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,40 @@
export function Node () {}
export function Node () {
this.childNodes = [];
}

Node.prototype.cloneNode = function (deep) {
const Class = Object.getPrototypeOf(this);
if (!deep || ('childNodes' in this && Array.isArray(this.childNodes) && this.childNodes.length === 0)) {
let Class = Object.getPrototypeOf(this);
return new Class.constructor(this);
} else {
let Class = Object.getPrototypeOf(this);
let object = new Class.constructor(this);

return new Class.constructor(this);
let childNodes = [];

this.childNodes.map((e) => childNodes.push(e.cloneNode(true)));

object.childNodes = childNodes;
return object;
}
};

Object.defineProperty(Node.prototype, 'nodeValue', {
get: function () { return null; }
});

Object.defineProperty(Node.prototype, 'children', {
get: function () { return this.childNodes; }
});

Object.defineProperty(Node.prototype, 'firstChild', {
get: function () { return this.childNodes[0]; }
});

Object.defineProperty(Node.prototype, 'lastChild', {
get: function () { return this.childNodes[this.childNodes.length - 1]; }
});

Object.defineProperty(Node.prototype, 'nodeName', {
get: function () { return this.tagName; }
});
39 changes: 39 additions & 0 deletions lib/style.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

import { dashToCamel, camelToDash } from './utils/notation';

export function CSSStyleDeclaration () {}

CSSStyleDeclaration.prototype = Object.create({});

CSSStyleDeclaration.prototype.setProperty = function (propertyName, value/*, priority */) {
this[dashToCamel(propertyName)] = value;
};

CSSStyleDeclaration.prototype.valueOf = function () {
return this;
};

CSSStyleDeclaration.prototype.toString = function () {
let str = '';
for (let p in this) {
if (!this.hasOwnProperty(p)) {
continue;
}
str += camelToDash(p) + ': ' + this[p] + '; ';
}
return str;
};

CSSStyleDeclaration.prototype.setValue = function (style) {
let list = style.split(';');
for (let p in list) {
let pair = p.split(':');
this[pair[0].trim()] = pair[1].trim();
}
};

Object.defineProperty(CSSStyleDeclaration.prototype, 'cssText', {
get: function () { return this.toString(); },
set: function (text) { this.setValue(text); },
enumerable: true
});
Loading

0 comments on commit e1f371e

Please sign in to comment.