Skip to content

Commit

Permalink
Instantiable env (#25)
Browse files Browse the repository at this point in the history
* Experiment: Re-enable instantiability by providing an undom.env() function that returns a new undom() factory with new prototypes.

* fix whitespace from merge
  • Loading branch information
developit authored Mar 2, 2019
1 parent f58a931 commit e425075
Showing 1 changed file with 164 additions and 157 deletions.
321 changes: 164 additions & 157 deletions src/undom.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,192 +19,199 @@ const NODE_TYPES = {
};
*/

function createEnvironment() {

function isElement(node) {
return node.nodeType===1;
}

class Node {
constructor(nodeType, nodeName) {
this.nodeType = nodeType;
this.nodeName = nodeName;
this.childNodes = [];
}
get nextSibling() {
let p = this.parentNode;
if (p) return p.childNodes[findWhere(p.childNodes, this, true, true) + 1];
}
get previousSibling() {
let p = this.parentNode;
if (p) return p.childNodes[findWhere(p.childNodes, this, true, true) - 1];
}
get firstChild() {
return this.childNodes[0];
function isElement(node) {
return node.nodeType===1;
}
get lastChild() {
return this.childNodes[this.childNodes.length-1];
}
appendChild(child) {
this.insertBefore(child);
return child;
}
insertBefore(child, ref) {
child.remove();
child.parentNode = this;
if (ref) splice(this.childNodes, ref, child, true);
else this.childNodes.push(child);
return child;
}
replaceChild(child, ref) {
if (ref.parentNode===this) {
this.insertBefore(child, ref);
ref.remove();
return ref;

class Node {
constructor(nodeType, nodeName) {
this.nodeType = nodeType;
this.nodeName = nodeName;
this.childNodes = [];
}
get nextSibling() {
let p = this.parentNode;
if (p) return p.childNodes[findWhere(p.childNodes, this, true, true) + 1];
}
get previousSibling() {
let p = this.parentNode;
if (p) return p.childNodes[findWhere(p.childNodes, this, true, true) - 1];
}
get firstChild() {
return this.childNodes[0];
}
get lastChild() {
return this.childNodes[this.childNodes.length-1];
}
appendChild(child) {
this.insertBefore(child);
return child;
}
insertBefore(child, ref) {
child.remove();
child.parentNode = this;
if (ref) splice(this.childNodes, ref, child, true);
else this.childNodes.push(child);
return child;
}
replaceChild(child, ref) {
if (ref.parentNode===this) {
this.insertBefore(child, ref);
ref.remove();
return ref;
}
}
removeChild(child) {
splice(this.childNodes, child, false, true);
return child;
}
remove() {
if (this.parentNode) this.parentNode.removeChild(this);
}
}
removeChild(child) {
splice(this.childNodes, child, false, true);
return child;
}
remove() {
if (this.parentNode) this.parentNode.removeChild(this);
}
}


class Text extends Node {
constructor(text) {
super(3, '#text'); // TEXT_NODE
this.nodeValue = text;
}
set textContent(text) {
this.nodeValue = text;
}
get textContent() {
return this.nodeValue;
class Text extends Node {
constructor(text) {
super(3, '#text'); // TEXT_NODE
this.nodeValue = text;
}
set textContent(text) {
this.nodeValue = text;
}
get textContent() {
return this.nodeValue;
}
}
}


class Element extends Node {
constructor(nodeType, nodeName) {
super(nodeType || 1, nodeName); // ELEMENT_NODE
this.attributes = [];
this.__handlers = {};
this.style = {};
}
class Element extends Node {
constructor(nodeType, nodeName) {
super(nodeType || 1, nodeName); // ELEMENT_NODE
this.attributes = [];
this.__handlers = {};
this.style = {};
}

get className() { return this.getAttribute('class'); }
set className(val) { this.setAttribute('class', val); }
get className() { return this.getAttribute('class'); }
set className(val) { this.setAttribute('class', val); }

get cssText() { return this.getAttribute('style'); }
set cssText(val) { this.setAttribute('style', val); }
get cssText() { return this.getAttribute('style'); }
set cssText(val) { this.setAttribute('style', val); }

get children() {
return this.childNodes.filter(isElement);
}
get children() {
return this.childNodes.filter(isElement);
}

setAttribute(key, value) {
this.setAttributeNS(null, key, value);
}
getAttribute(key) {
return this.getAttributeNS(null, key);
}
removeAttribute(key) {
this.removeAttributeNS(null, key);
}
setAttribute(key, value) {
this.setAttributeNS(null, key, value);
}
getAttribute(key) {
return this.getAttributeNS(null, key);
}
removeAttribute(key) {
this.removeAttributeNS(null, key);
}

setAttributeNS(ns, name, value) {
let attr = findWhere(this.attributes, createAttributeFilter(ns, name), false, false);
if (!attr) this.attributes.push(attr = { ns, name });
attr.value = String(value);
}
getAttributeNS(ns, name) {
let attr = findWhere(this.attributes, createAttributeFilter(ns, name), false, false);
return attr && attr.value;
}
removeAttributeNS(ns, name) {
splice(this.attributes, createAttributeFilter(ns, name), false, false);
}
setAttributeNS(ns, name, value) {
let attr = findWhere(this.attributes, createAttributeFilter(ns, name), false, false);
if (!attr) this.attributes.push(attr = { ns, name });
attr.value = String(value);
}
getAttributeNS(ns, name) {
let attr = findWhere(this.attributes, createAttributeFilter(ns, name), false, false);
return attr && attr.value;
}
removeAttributeNS(ns, name) {
splice(this.attributes, createAttributeFilter(ns, name), false, false);
}

addEventListener(type, handler) {
(this.__handlers[toLower(type)] || (this.__handlers[toLower(type)] = [])).push(handler);
}
removeEventListener(type, handler) {
splice(this.__handlers[toLower(type)], handler, false, true);
}
dispatchEvent(event) {
let t = event.target = this,
c = event.cancelable,
l, i;
do {
event.currentTarget = t;
l = t.__handlers && t.__handlers[toLower(event.type)];
if (l) for (i=l.length; i--; ) {
if ((l[i].call(t, event) === false || event._end) && c) {
event.defaultPrevented = true;
addEventListener(type, handler) {
(this.__handlers[toLower(type)] || (this.__handlers[toLower(type)] = [])).push(handler);
}
removeEventListener(type, handler) {
splice(this.__handlers[toLower(type)], handler, false, true);
}
dispatchEvent(event) {
let t = event.target = this,
c = event.cancelable,
l, i;
do {
event.currentTarget = t;
l = t.__handlers && t.__handlers[toLower(event.type)];
if (l) for (i=l.length; i--; ) {
if ((l[i].call(t, event) === false || event._end) && c) {
event.defaultPrevented = true;
}
}
}
} while (event.bubbles && !(c && event._stop) && (t=t.parentNode));
return l!=null;
} while (event.bubbles && !(c && event._stop) && (t=t.parentNode));
return l!=null;
}
}
}


class Document extends Element {
constructor() {
super(9, '#document'); // DOCUMENT_NODE
}
class Document extends Element {
constructor() {
super(9, '#document'); // DOCUMENT_NODE
}

createElement(type) {
return new Element(null, String(type).toUpperCase());
}
createElement(type) {
return new Element(null, String(type).toUpperCase());
}

createElementNS(ns, type) {
let element = this.createElement(type);
element.namespace = ns;
return element;
}
createElementNS(ns, type) {
let element = this.createElement(type);
element.namespace = ns;
return element;
}


createTextNode(text) {
return new Text(text);
createTextNode(text) {
return new Text(text);
}
}
}


class Event {
constructor(type, opts) {
this.type = type;
this.bubbles = !!(opts && opts.bubbles);
this.cancelable = !!(opts && opts.cancelable);
}
stopPropagation() {
this._stop = true;
}
stopImmediatePropagation() {
this._end = this._stop = true;
}
preventDefault() {
this.defaultPrevented = true;
class Event {
constructor(type, opts) {
this.type = type;
this.bubbles = !!(opts && opts.bubbles);
this.cancelable = !!(opts && opts.cancelable);
}
stopPropagation() {
this._stop = true;
}
stopImmediatePropagation() {
this._end = this._stop = true;
}
preventDefault() {
this.defaultPrevented = true;
}
}
}


/** Create a minimally viable DOM Document
/** Create a minimally viable DOM Document
* @returns {Document} document
*/
export default function createDocument() {
let document = new Document();
assign(document, document.defaultView = { document, Document, Node, Text, Element, SVGElement: Element, Event });
document.appendChild(
document.documentElement = document.createElement('html')
);
document.documentElement.appendChild(
document.head = document.createElement('head')
);
document.documentElement.appendChild(
document.body = document.createElement('body')
);
return document;
function createDocument() {
let document = new Document();
assign(document, document.defaultView = { document, Document, Node, Text, Element, SVGElement: Element, Event });
document.appendChild(
document.documentElement = document.createElement('html')
);
document.documentElement.appendChild(
document.head = document.createElement('head')
);
document.documentElement.appendChild(
document.body = document.createElement('body')
);
return document;
}

createDocument.env = createEnvironment;
return createDocument;
}

export default createEnvironment();

0 comments on commit e425075

Please sign in to comment.