Skip to content

Commit

Permalink
Unified the DOM model
Browse files Browse the repository at this point in the history
Added two new APIs: injectBefore() and empty()
  • Loading branch information
sebmarkbage committed Mar 3, 2013
1 parent ad1af16 commit 988f190
Show file tree
Hide file tree
Showing 23 changed files with 417 additions and 271 deletions.
9 changes: 9 additions & 0 deletions demos/objectmodel/index.html
@@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>Object Model</title>
</head>
<body>
<script src="../../lib/link/Source/Web/link.js" data-main="objectmodel.js" data-nocache></script>
</body>
</html>
93 changes: 93 additions & 0 deletions demos/objectmodel/objectmodel.js
@@ -0,0 +1,93 @@
require('../mode');
var ART = require('../../art');

var art = ART.Surface(1000, 600);

var group = ART.Group()
.inject(art);

var text = ART.Text('DOM', 'bold 60px "Arial"')
.move(0, 0)
.fill('red')
.inject(group);

var green = ART.Rectangle(100, 100)
.move(10, 10)
.fill('green')
.inject(group);

var group2 = ART.Group()
.move(10,10)
.rotate(5)
.inject(group);

var blue = ART.Rectangle(100, 100)
.move(10,10)
.rotate(-5)
.fill('blue')
.inject(group2);

function eq(){
var a = arguments[0];
for (var i = 1; i < arguments.length; i++){
var b = arguments[i];
if (a !== b){ debugger; throw new Error('Assertion failed'); }
}
}

function verifyState(){
// art
// group
// text
// green
// group2
// blue

eq(art.firstChild, art.lastChild, group);
eq(group.nextSibling, group.previousSibling, null);

eq(group.firstChild, text);
eq(group.lastChild, group2);

eq(text.previousSibling, group2.nextSibling, null);

eq(text.nextSibling, green);
eq(green.previousSibling, text);

eq(green.nextSibling, group2);
eq(group2.previousSibling, green);

eq(group2.firstChild, group2.lastChild, blue);
eq(blue.nextSibling, blue.previousSibling, null);

eq(blue.parentNode, group2);
eq(text.parentNode, green.parentNode, group2.parentNode, group);
eq(group.parentNode, art);
}

verifyState();

var alt = true;

var timer = setInterval(function(){
alt = !alt;
if (alt)
green.eject();
else {
green.injectBefore(group2);
console.log('injecting' + green.parentNode);
verifyState();
//green.injectBefore(group2);
//group2.injectBefore(green);
}
group2.rotate(1, 50, 50);
}, 500);

group2.subscribe('click', function(){
clearInterval(timer);
group.empty();
art.empty();
blue.inject(art);
});

art.inject(document.body);
10 changes: 0 additions & 10 deletions src/core/container.js

This file was deleted.

16 changes: 16 additions & 0 deletions src/dom/container.js
@@ -0,0 +1,16 @@
var Class = require('../core/class');

module.exports = Class({

grab: function(){
for (var i = 0; i < arguments.length; i++) arguments[i].inject(this);
return this;
},

empty: function(){
var node;
while (node = this.firstChild) node.eject();
return this;
}

});
116 changes: 116 additions & 0 deletions src/dom/dummy.js
@@ -0,0 +1,116 @@
var Class = require('../core/class');

module.exports = Class({

// placement

_resetPlacement: function(){
var container = this.parentNode;
if (container){
var previous = this.previousSibling, next = this.nextSibling;
if (previous){
previous.nextSibling = next;
} else {
container.firstChild = next;
}
if (next){
next.previousSibling = previous;
} else {
container.lastChild = this.previousSibling;
}
}
this.previousSibling = null;
this.nextSibling = null;
this.parentNode = null;
return this;
},

inject: function(container){
this._resetPlacement();
var last = container.lastChild;
if (last){
last.nextSibling = this;
this.previousSibling = last;
} else {
container.firstChild = this;
}
container.lastChild = this;
this.parentNode = container;
this._place();
return this;
},

injectBefore: function(sibling){
this._resetPlacement();
var container = sibling.parentNode;
if (!container) return this;
var previous = sibling.previousSibling;
if (previous){
previous.nextSibling = this;
this.previousSibling = previous;
} else {
container.firstChild = this;
}
sibling.previousSibling = this;
this.nextSibling = sibling;
this.parentNode = container;
this._place();
return this;
},

eject: function(){
this._resetPlacement();
this._place();
return this;
},

_place: function(){},

// events

dispatch: function(event){
var events = this._events,
listeners = events && events[event.type];
if (listeners){
listeners = listeners.slice(0);
for (var i = 0, l = listeners.length; i < l; i++){
var fn = listeners[i], result;
if (typeof fn == 'function')
result = fn.call(this, event);
else
result = fn.handleEvent(event);
if (result === false) event.preventDefault();
}
}
if (this.parentNode && this.parentNode.dispatch){
this.parentNode.dispatch(event);
}
},

subscribe: function(type, fn, bind){
if (typeof type != 'string'){ // listen type / fn with object
var subscriptions = [];
for (var t in type) subscriptions.push(this.subscribe(t, type[t]));
return function(){ // unsubscribe
for (var i = 0, l = subscriptions.length; i < l; i++)
subscriptions[i]();
return this;
};
} else { // listen to one
var bound = typeof fn === 'function' ? fn.bind(bind || this) : fn,
events = this._events || (this._events = {}),
listeners = events[type] || (events[type] = []);
listeners.push(bound);
return function(){
// unsubscribe
for (var i = 0, l = listeners.length; i < l; i++){
if (listeners[i] === bound){
listeners.splice(i, 1);
break;
}
}
}
}
}

});
39 changes: 34 additions & 5 deletions src/dom/element.js → src/dom/native.js
@@ -1,12 +1,34 @@
var Class = require('../core/class');

function elementFrom(node){
if (node.toElement) return node.toElement();
if (node.getDOMNode) return node.getDOMNode();
return node;
}

module.exports = Class({

// dom
// conventions

toElement: function(){
return this.element;
},

getDOMNode: function(){
return this.toElement();
},

// placement

inject: function(element){
if (element.element) element = element.element;
element.appendChild(this.element);
inject: function(container){
(container.containerElement || elementFrom(container))
.appendChild(this.element);
return this;
},

injectBefore: function(sibling){
var element = elementFrom(sibling);
element.parentNode.insertBefore(this.element, element);
return this;
},

Expand All @@ -28,7 +50,14 @@ module.exports = Class({
return this;
};
} else { // listen to one
var bound = typeof fn === 'function' ? fn.bind(bind || this) : fn;
if (!bind) bind = this;
var bound;
if (typeof fn === 'function'){
bound = fn.bind ? fn.bind(bind)
: function(){ return fn.apply(bind, arguments); };
} else {
bound = fn;
}
var element = this.element;
if (element.addEventListener){
element.addEventListener(type, bound, false);
Expand Down
32 changes: 32 additions & 0 deletions src/dom/shadow.js
@@ -0,0 +1,32 @@
var Class = require('../core/class');
var Dummy = require('./dummy');
var Native = require('./native');

module.exports = Class(Dummy, Native, {

dummy_inject: Dummy.prototype.inject,
dummy_injectBefore: Dummy.prototype.injectBefore,
dummy_eject: Dummy.prototype.eject,
native_inject: Native.prototype.inject,
native_injectBefore: Native.prototype.injectBefore,
native_eject: Native.prototype.eject,

inject: function(container){
this.dummy_inject(container);
this.native_inject(container);
return this;
},

injectBefore: function(sibling){
this.dummy_injectBefore(sibling);
this.native_injectBefore(sibling);
return this;
},

eject: function(){
this.dummy_eject();
this.native_eject();
return this;
}

});
21 changes: 13 additions & 8 deletions src/modes/canvas/group.js
@@ -1,20 +1,22 @@
var Class = require('../../core/class');
var Container = require('../../core/container');
var Container = require('../../dom/container');
var Node = require('./node');

module.exports = Class(Node, Container, {

initialize: function(width, height){
this.width = width;
this.height = height;
this.children = [];
},

localHitTest: function(x, y){
var children = this.children, i = children.length;
while (i--){
var hit = children[i].hitTest(x, y);
var i = 0;
var node = this.lastChild;
while (node){
var hit = node.hitTest(x, y);
if (hit) return hit;
node = node.previousSibling;
if (i++ > 100){ debugger; throw new Error('recursion'); }
}
return null;
},
Expand All @@ -32,9 +34,12 @@ module.exports = Class(Node, Container, {
yx = t * this.xx + yy * this.yx;
yy = t * this.xy + yy * this.yy;

var children = this.children;
for (var i = 0, l = children.length; i < l; i++){
children[i].renderTo(context, xx, yx, xy, yy, x, y);
var i = 0;
var node = this.firstChild;
while (node){
node.renderTo(context, xx, yx, xy, yy, x, y);
node = node.nextSibling;
if (i++ > 100){ debugger; throw new Error('recursion'); }
}
}

Expand Down

0 comments on commit 988f190

Please sign in to comment.