includejs
Version:
IncludeJS Resource Builder Tool
375 lines (321 loc) • 10 kB
JavaScript
include.js({
lib: 'mask'
}).done(function() {
var w = window,
regexp = {
trailingSpaces: /^\s+/
},
Helper = {
resolveDom: function(compo, values) {
if (compo.nodes != null) {
if (compo.tagName != null) return compo;
return mask.renderDom(compo.nodes, values);
}
if (compo.attr.template != null) {
var e;
if (compo.attr.template[0] === '#') {
e = document.getElementById(compo.attr.template.substring(1));
if (e == null) {
console.error('Template Element not Found:', arg);
return null;
}
}
return mask.renderDom(e != null ? e.innerHTML : compo.attr.template, values);
}
return null;
},
ensureTemplate: function(compo) {
if (compo.nodes != null) return;
var template;
if (compo.attr.template != null) {
if (compo.attr.template[0] === '#') template = this.templateById(compo.attr.template.substring(1));
else template = compo.attr.template;
delete compo.attr.template;
}
if (typeof template == 'string') {
template = mask.compile(template);
}
if (template != null) {
compo.nodes = template;
return;
}
return;
},
templateById: function(id) {
var e = document.getElementById(id);
if (e == null) console.error('Template Element not Found:', id);
else
return e.innerHTML;
return '';
},
containerArray: function() {
var arr = [];
arr.appendChild = function(child) {
this.push(child);
}
return arr;
},
parseSelector: function(selector, type, direction) {
var key, prop, nextKey;
if (key == null) {
switch (selector[0]) {
case '#':
key = 'id';
selector = selector.substring(1);
prop = 'attr';
break;
case '.':
key = 'class';
selector = new RegExp('\\b' + selector.substring(1) + '\\b');
prop = 'attr';
break;
default:
key = type == 'node' ? 'tagName' : 'compoName';
break;
}
}
if (direction == 'up') nextKey = 'parent';
else nextKey = type == 'node' ? 'nodes' : 'components';
return {
key: key,
prop: prop,
selector: selector,
nextKey: nextKey
}
}
},
/**
* Component Events. Fires only once.
* Used for component Initialization.
* Supported events:
* DOMInsert
* +custom
* UI-Eevent exchange must be made over DOMLibrary
*/
Shots = { /** from parent to childs */
emit: function(component, event, args) {
if (component.listeners != null && event in component.listeners) {
component.listeners[event].apply(component, args);
delete component.listeners[event];
}
if (component.components instanceof Array) {
for (var i = 0; i < component.components.length; i++) {
Shots.emit(component.components[i], event, args);
}
}
},
on: function(component, event, fn) {
if (component.listeners == null) component.listeners = {};
component.listeners[event] = fn;
}
},
Events_ = {
on: function(component, events) {
var isarray = events instanceof Array,
length = isarray ? events.length : 1,
x = null;
for (var i = 0; x = isarray ? events[i] : events, isarray ? i < length : i < 1; i++) {
if (x instanceof Array) {
component.$.on.apply(component.$, x);
continue;
}
for (var key in x) {
var fn = typeof x[key] === 'string' ? component[x[key]] : x[key],
parts = key.split(':');
component.$.on(parts[0] || 'click', parts.splice(1).join(':'), fn.bind(component));
}
}
}
};
w.Compo = Class({
/**
* @param - arg -
* 1. object - model object, receive from mask.renderDom
* Custom Initialization:
* 2. String - template
* @param cntx
* 1. maskDOM context
*/
Construct: function(arg) {
if (typeof arg === 'string') {
var template = arg;
if (template[0] == '#') template = Helper.templateById(template.substring(1));
this.nodes = mask.compile(template);
}
},
render: function(values, container, cntx) {
this.create(values, cntx);
if (container != null) {
for (var i = 0; i < this.$.length; i++) container.appendChild(this.$[i]);
}
return this;
},
insert: function(parent) {
for (var i = 0; i < this.$.length; i++) parent.appendChild(this.$[i]);
Shots.emit(this, 'DOMInsert');
return this;
},
append: function(template, values, selector) {
if (this.$ == null) {
var dom = typeof template == 'string' ? mask.compile(template) : template,
parent = selector ? Compo.findNode(this, selector) : this;
if (parent.nodes == null) this.nodes = dom;
else if (parent.nodes instanceof Array) parent.nodes.push(dom);
else parent.nodes = [this.nodes, dom];
return this;
}
var array = mask.renderDom(template, values, Helper.containerArray(), this),
parent = selector ? this.$.find(selector) : this.$;
for (var i = 0; i < array.length; i++) parent.append(array[i]);
Shots.emit(this, 'DOMInsert');
return this;
},
create: function(values, cntx) {
if (cntx == null) cntx = this;
Helper.ensureTemplate(this);
var elements = mask.renderDom(this.tagName == null ? this.nodes : this, values, Helper.containerArray(), cntx);
this.$ = $(elements);
if (this.events != null) {
Events_.on(this, this.events);
}
if (this.compos != null) {
for (var key in this.compos) {
if (typeof this.compos[key] !== 'string') continue;
var selector = this.compos[key],
index = selector.indexOf(':'),
engine = selector.substring(0, index);
engine = Compo.config.selectors[engine];
if (engine == null) {
this.compos[key] = this.$.get(0).querySelector(selector);
continue;
}
selector = selector.substring(++index).replace(regexp.trailingSpaces, '');
this.compos[key] = engine(this, selector);
}
}
return this;
},
on: function() {
var x = Array.prototype.slice.call(arguments)
switch (arguments.length) {
case 1:
case 2:
x.unshift('click');
break;
}
if (this.events == null) this.events = [x];
else if (this.events instanceof Array) this.events.push(x)
else this.events = [x, this.events];
return this;
},
remove: function() {
this.$ && this.$.remove();
Compo.dispose(this);
if (this.parent != null) {
var i = this.parent.components.indexOf(compo);
this.parent.components.splice(i, 1);
}
return this;
},
Static: {
config: {
selectors: {
'$': function(compo, selector) {
var r = compo.$.find(selector);
return r.length > 0 ? r : compo.$.filter(selector);
},
'compo': function(compo, selector) {
var r = Compo.findCompo(compo, selector);
return r;
}
},
/**
@default, global $ is used
IDOMLibrary = {
{fn}(elements) - create dom-elements wrapper,
on(event, selector, fn) - @see jQuery 'on'
}
*/
setDOMLibrary: function(lib) {
$ = lib;
}
},
match: function(compo, selector, type) {
if (typeof selector === 'string') {
if (type == null) type = compo.compoName ? 'compo' : 'node';
selector = Helper.parseSelector(selector, type, direction);
}
var obj = selector.prop ? compo[selector.prop] : compo;
if (obj == null) return false;
if (selector.selector.test != null) {
if (selector.selector.test(obj[selector.key])) return true;
} else {
if (obj[selector.key] == selector.selector) return true;
}
return false;
},
find: function(compo, selector, direction, type) {
if (compo == null) return null;
if (typeof selector === 'string') {
if (type == null) type = compo.compoName ? 'compo' : 'node';
selector = Helper.parseSelector(selector, type, direction);
}
if (compo instanceof Array) {
for (var i = 0, x, length = compo.length; x = compo[i], i < length; i++) {
var r = Compo.find(x, selector);
if (r != null) return r;
}
return null;
}
if (Compo.match(compo, selector) == true) return compo;
return Compo.find(compo[selector.nextKey], selector);
},
findCompo: function(compo, selector, direction) {
return Compo.find(compo, selector, direction, 'compo');
},
findNode: function(compo, selector, direction) {
return Compo.find(compo, selector, direction, 'node');
},
dispose: function(compo) {
compo.dispose && compo.dispose();
if (this.components == null) return;
for (var i = 0, x, length = compo.components.length; x = compo.components[i], i < length; i++) {
Compo.dispose(x);
}
},
events: Shots
}
});
/** CompoUtils */
var Traversing = {
find: function(selector, type) {
return Compo.find(this, selector, null, type || 'compo');
},
closest: function(selector, type) {
return Compo.find(this, selector, 'up', type || 'compo');
},
all: function(selector, type) {
var current = arguments[2] || this,
arr = arguments[3] || []
if (typeof selector === 'string') selector = Helper.parseSelector(selector, type);
if (Compo.match(current, selector)) {
arr.push(current);
}
var childs = current[selector.nextKey];
if (childs != null) {
for (var i = 0; i < childs.length; i++) {
this.all(selector, null, childs[i], arr);
}
}
return arr;
}
}
var Manipulate = {
addClass: function(_class) {
this.attr.class = this.attr.class ? this.attr.class + ' ' + _class : _class;
}
}
w.CompoUtils = Class({
Extends: [Traversing, Manipulate]
});
});