Commit 4da42bc1 authored by Romuald Quantin's avatar Romuald Quantin Committed by Sindre Sorhus

Close GH-901: soma.js - Fixes selenium tests #819..

parent a5d0ac74
......@@ -4,7 +4,7 @@
"dependencies": {
"todomvc-common": "~0.1.6",
"director": "~1.2.0",
"soma.js": "~2.0.0",
"soma-template": "~0.1.8"
"soma.js": "~2.1.0",
"soma-template": "~0.2.8"
}
}
//
// Generated on Sun Dec 16 2012 22:47:05 GMT-0500 (EST) by Nodejitsu, Inc (Using Codesurgeon).
// Version 1.1.9
// Generated on Fri Dec 27 2013 12:02:11 GMT-0500 (EST) by Nodejitsu, Inc (Using Codesurgeon).
// Version 1.2.2
//
(function (exports) {
/*
* browser.js: Browser specific functionality for director.
*
......@@ -201,7 +200,7 @@ Router.prototype.init = function (r) {
this.handler = function(onChangeEvent) {
var newURL = onChangeEvent && onChangeEvent.newURL || window.location.hash;
var url = self.history === true ? self.getPath() : newURL.replace(/.*#/, '');
self.dispatch('on', url);
self.dispatch('on', url.charAt(0) === '/' ? url : '/' + url);
};
listener.init(this.handler, this.history);
......@@ -210,7 +209,7 @@ Router.prototype.init = function (r) {
if (dlocHashEmpty() && r) {
dloc.hash = r;
} else if (!dlocHashEmpty()) {
self.dispatch('on', dloc.hash.replace(/^#/, ''));
self.dispatch('on', '/' + dloc.hash.replace(/^(#\/|#|\/)/, ''));
}
}
else {
......@@ -363,11 +362,16 @@ function regifyString(str, params) {
out += str.substr(0, matches.index) + matches[0];
}
str = out += str.substr(last);
var captures = str.match(/:([^\/]+)/ig), length;
var captures = str.match(/:([^\/]+)/ig), capture, length;
if (captures) {
length = captures.length;
for (var i = 0; i < length; i++) {
str = str.replace(captures[i], paramifyString(captures[i], params));
capture = captures[i];
if (capture.slice(0, 2) === "::") {
str = capture.slice(1);
} else {
str = str.replace(capture, paramifyString(capture, params));
}
}
}
return str;
......@@ -485,20 +489,22 @@ Router.prototype.dispatch = function(method, path, callback) {
Router.prototype.invoke = function(fns, thisArg, callback) {
var self = this;
var apply;
if (this.async) {
_asyncEverySeries(fns, function apply(fn, next) {
apply = function(fn, next) {
if (Array.isArray(fn)) {
return _asyncEverySeries(fn, apply, next);
} else if (typeof fn == "function") {
fn.apply(thisArg, fns.captures.concat(next));
}
}, function() {
};
_asyncEverySeries(fns, apply, function() {
if (callback) {
callback.apply(thisArg, arguments);
}
});
} else {
_every(fns, function apply(fn) {
apply = function(fn) {
if (Array.isArray(fn)) {
return _every(fn, apply);
} else if (typeof fn === "function") {
......@@ -506,7 +512,8 @@ Router.prototype.invoke = function(fns, thisArg, callback) {
} else if (typeof fn === "string" && self.resource) {
self.resource[fn].apply(thisArg, fns.captures || []);
}
});
};
_every(fns, apply);
}
};
......@@ -686,7 +693,7 @@ Router.prototype.mount = function(routes, path) {
function insertOrMount(route, local) {
var rename = route, parts = route.split(self.delimiter), routeType = typeof routes[route], isRoute = parts[0] === "" || !self._methods[parts[0]], event = isRoute ? "on" : rename;
if (isRoute) {
rename = rename.slice((rename.match(new RegExp(self.delimiter)) || [ "" ])[0].length);
rename = rename.slice((rename.match(new RegExp("^" + self.delimiter)) || [ "" ])[0].length);
parts.shift();
}
if (isRoute && routeType === "object" && !Array.isArray(routes[route])) {
......
;(function (soma, undefined) {
(function (soma) {
'use strict';
soma.template = soma.template || {};
soma.template.version = "0.1.8";
soma.template = soma.template || {};
soma.template.version = '0.2.8';
var errors = soma.template.errors = {
TEMPLATE_STRING_NO_ELEMENT: "Error in soma.template, a string template requirement a second parameter: an element target - soma.template.create('string', element)",
TEMPLATE_NO_PARAM: "Error in soma.template, a template requires at least 1 parameter - soma.template.create(element)"
};
soma.template.errors = {
TEMPLATE_STRING_NO_ELEMENT: 'Error in soma.template, a string template requirement a second parameter: an element target - soma.template.create(\'string\', element)',
TEMPLATE_NO_PARAM: 'Error in soma.template, a template requires at least 1 parameter - soma.template.create(element)'
};
var tokenStart = '{{';
var tokenEnd = '}}';
var helpersObject = {};
var helpersScopeObject = {};
var tokenStart = '{{';
var tokenEnd = '}}';
var helpersObject = {};
var helpersScopeObject = {};
var settings = soma.template.settings = soma.template.settings || {};
var settings = soma.template.settings = soma.template.settings || {};
settings.autocreate = true;
settings.autocreate = true;
var tokens = settings.tokens = {
var tokens = settings.tokens = {
start: function(value) {
if (isDefined(value) && value !== '') {
tokenStart = escapeRegExp(value);
......@@ -34,41 +34,45 @@ var tokens = settings.tokens = {
}
return tokenEnd;
}
};
var attributes = settings.attributes = {
skip: "data-skip",
repeat: "data-repeat",
src: "data-src",
href: "data-href",
show: "data-show",
hide: "data-hide",
cloak: "data-cloak",
checked: "data-checked",
disabled: "data-disabled",
multiple: "data-multiple",
readonly: "data-readonly",
selected: "data-selected",
template: "data-template",
html: "data-html"
};
var vars = settings.vars = {
index: "$index",
key: "$key"
};
var events = settings.events = {};
settings.eventsPrefix = 'data-';
var eventsString = 'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup focus blur change select selectstart scroll copy cut paste mousewheel keypress error contextmenu input textinput drag dragenter dragleave dragover dragend dragstart dragover drop load submit reset search resize beforepaste beforecut beforecopy';
eventsString += ' touchstart touchend touchmove touchenter touchleave touchcancel gesturestart gesturechange gestureend';
var eventsArray = eventsString.split(' ');
var i = -1, l = eventsArray.length;
while(++i < l) {
};
var attributes = settings.attributes = {
skip: 'data-skip',
repeat: 'data-repeat',
src: 'data-src',
href: 'data-href',
show: 'data-show',
hide: 'data-hide',
cloak: 'data-cloak',
checked: 'data-checked',
disabled: 'data-disabled',
multiple: 'data-multiple',
readonly: 'data-readonly',
selected: 'data-selected',
template: 'data-template',
html: 'data-html'
};
var vars = settings.vars = {
index: '$index',
key: '$key',
element: '$element',
parentElement: '$parentElement',
attribute: '$attribute',
scope: '$scope'
};
var events = settings.events = {};
settings.eventsPrefix = 'data-';
var eventsString = 'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup focus blur change select selectstart scroll copy cut paste mousewheel keypress error contextmenu input textinput drag dragenter dragleave dragover dragend dragstart dragover drop load submit reset search resize beforepaste beforecut beforecopy';
eventsString += ' touchstart touchend touchmove touchenter touchleave touchcancel gesturestart gesturechange gestureend';
var eventsArray = eventsString.split(' ');
var i = -1, l = eventsArray.length;
while(++i < l) {
events[settings.eventsPrefix + eventsArray[i]] = eventsArray[i];
}
}
var regex = {
var regex = {
sequence: null,
token: null,
expression: null,
......@@ -81,117 +85,138 @@ var regex = {
content: /[^.|^\s]/gm,
depth: /..\//g,
string: /^(\"|\')(.*)(\"|\')$/
};
var ie = (function(){
if (typeof document !== 'object') return undefined;
var undef,
v = 3,
div = document.createElement('div'),
all = div.getElementsByTagName('i');
while (
div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->', all[0]
);
return v > 4 ? v : undef;
}());
function isArray(value) {
};
var ie = (function(){
if (typeof document !== 'object') {
return undefined;
}
var v = 3,
stop = false,
div = document.createElement('div');
while (!stop) {
div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->';
if (!div.getElementsByTagName('i')[0]) {
stop = true;
}
}
return v > 4 ? v : undefined;
}());
function isArray(value) {
return Object.prototype.toString.apply(value) === '[object Array]';
};
function isObject(value) {
}
function isObject(value) {
return typeof value === 'object';
}
function isString(value) {
}
function isString(value) {
return typeof value === 'string';
}
function isElement(value) {
}
function isElement(value) {
return value ? value.nodeType > 0 : false;
};
function isTextNode(el) {
}
function isTextNode(el) {
return el && el.nodeType && el.nodeType === 3;
}
function isFunction(value) {
}
function isFunction(value) {
return value && typeof value === 'function';
}
function isDefined(value) {
}
function isDefined(value) {
return value !== null && value !== undefined;
}
function isAttributeDefined(value) {
return (value === "" || value === true || value === "true" || !isDefined(value));
}
function isExpression(value) {
}
function normalizeBoolean(value) {
if (!isDefined(value)) {
return false;
}
if (value === 'true' || value === '1' || value === true || value === 1) {
return true;
}
if (value === 'false' || value === '0' || value === false || value === 0 || (isString(value) && hasInterpolation(value))) {
return false;
}
return !!value;
}
function isExpression(value) {
return value && isFunction(value.toString) && value.toString() === '[object Expression]';
}
function isNode(value) {
return value && isFunction(value.toString) && value.toString() === '[object Node]';
}
function isExpFunction(value) {
if (!isString(value)) return false;
}
function isExpFunction(value) {
if (!isString(value)) {
return false;
}
return !!value.match(regex.func);
}
function childNodeIsTemplate(node) {
}
function childNodeIsTemplate(node) {
return node && node.parent && templates.get(node.element);
}
function escapeRegExp(str) {
return str.replace(regex.escape, "\\$&");
}
function setRegEX(nonEscapedValue, isStartToken) {
}
function escapeRegExp(str) {
return str.replace(regex.escape, '\\$&');
}
function setRegEX(nonEscapedValue, isStartToken) {
// sequence: \{\{.+?\}\}|[^{]+|\{(?!\{)[^{]*
var unescapedCurrentStartToken = tokens.start().replace(/\\/g, '');
var endSequence = "";
var endSequence = '';
var ts = isStartToken ? nonEscapedValue : unescapedCurrentStartToken;
if (ts.length > 1) {
endSequence = "|\\" + ts.substr(0, 1) + "(?!\\" + ts.substr(1, 1) + ")[^" + ts.substr(0, 1) + "]*";
endSequence = '|\\' + ts.substr(0, 1) + '(?!\\' + ts.substr(1, 1) + ')[^' + ts.substr(0, 1) + ']*';
}
regex.sequence = new RegExp(tokens.start() + ".+?" + tokens.end() + "|[^" + tokens.start() + "]+" + endSequence, "g");
regex.token = new RegExp(tokens.start() + ".*?" + tokens.end(), "g");
regex.expression = new RegExp(tokens.start() + "|" + tokens.end(), "gm");
}
function trim(value) {
regex.sequence = new RegExp(tokens.start() + '.+?' + tokens.end() + '|[^' + tokens.start() + ']+' + endSequence, 'g');
regex.token = new RegExp(tokens.start() + '.*?' + tokens.end(), 'g');
regex.expression = new RegExp(tokens.start() + '|' + tokens.end(), 'gm');
}
function trim(value) {
return value.replace(regex.trim, '');
}
function trimQuotes(value) {
}
function trimQuotes(value) {
if (regex.string.test(value)) {
return value.substr(1, value.length-2);
}
return value;
}
function trimArray(value) {
if (value[0] === "") value.shift();
if (value[value.length-1] === "") value.pop();
}
function trimArray(value) {
if (value[0] === '') {
value.shift();
}
if (value[value.length-1] === '') {
value.pop();
}
return value;
}
function trimTokens(value) {
}
function trimTokens(value) {
return value.replace(regex.expression, '');
}
function trimScopeDepth(value) {
}
function trimScopeDepth(value) {
return value.replace(regex.depth, '');
}
function insertBefore(referenceNode, newNode) {
if (!referenceNode.parentNode) return;
}
function insertBefore(referenceNode, newNode) {
if (!referenceNode.parentNode) {
return;
}
referenceNode.parentNode.insertBefore(newNode, referenceNode);
}
function insertAfter(referenceNode, newNode) {
if (!referenceNode.parentNode) return;
}
function insertAfter(referenceNode, newNode) {
if (!referenceNode.parentNode) {
return;
}
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}
function removeClass(elm, className) {
if (document.documentElement.classList) {
removeClass = function (elm, className) {
elm.classList.remove(className);
}
function removeClass(elm, className) {
var rmc;
if (typeof document === 'object' && document.documentElement.classList) {
rmc = function (elm, className) {
elm.classList.remove(className);
};
} else {
removeClass = function (elm, className) {
rmc = function (elm, className) {
if (!elm || !elm.className) {
return false;
}
var reg = new RegExp("(^|\\s)" + className + "(\\s|$)", "g");
elm.className = elm.className.replace(reg, "$2");
var reg = new RegExp('(^|\\s)' + className + '(\\s|$)', 'g');
elm.className = elm.className.replace(reg, '$2');
};
}
rmc(elm, className);
}
removeClass(elm, className);
}
// jquery contains
var contains = typeof document !== 'object' ? function(){} : document.documentElement.contains ?
// jquery contains
var contains = typeof document !== 'object' ? function(){} : document.documentElement.contains ?
function( a, b ) {
var adown = a.nodeType === 9 ? a.documentElement : a,
bup = b && b.parentNode;
......@@ -210,66 +235,79 @@ var contains = typeof document !== 'object' ? function(){} : document.documentEl
return false;
};
function HashMap() {
function HashMap(id) {
var items = {};
var id = 1;
var count = 0;
//var uuid = function(a,b){for(b=a='';a++<36;b+=a*51&52?(a^15?8^Math.random()*(a^20?16:4):4).toString(16):'-');return b;}
function uuid() { return ++id; };
function uuid() { return ++count + id; }
function getKey(target) {
if (!target) return;
if (typeof target !== 'object') return target;
if (!target) {
return;
}
if (typeof target !== 'object') {
return target;
}
var result;
try {
// IE 7-8 needs a try catch, seems like I can't add a property on text nodes
result = target.hashkey ? target.hashkey : target.hashkey = uuid();
} catch(err){};
result = target[id] ? target[id] : target[id] = uuid();
} catch(err){}
return result;
}
this.remove = function(key) {
delete items[getKey(key)];
}
};
this.get = function(key) {
return items[getKey(key)];
}
};
this.put = function(key, value) {
items[getKey(key)] = value;
}
};
this.has = function(key) {
return typeof items[getKey(key)] !== 'undefined';
}
};
this.getData = function() {
return items;
}
};
this.dispose = function() {
for (var key in items) {
if (items.hasOwnProperty(key)) {
delete items[key];
}
}
this.length = 0;
};
}
}
function getRepeaterData(repeaterValue, scope) {
function getRepeaterData(repeaterValue, scope) {
var parts = repeaterValue.match(regex.repeat);
if (!parts) return;
if (!parts) {
return;
}
var source = parts[2];
var exp = new Expression(source);
return exp.getValue(scope);
}
}
function updateScopeWithRepeaterData(repeaterValue, scope, data) {
function updateScopeWithRepeaterData(repeaterValue, scope, data) {
var parts = repeaterValue.match(regex.repeat);
if (!parts) return;
if (!parts) {
return;
}
var name = parts[1];
scope[name] = data;
}
function getWatcherValue(exp, newValue) {
}
function getWatcherValue(exp, newValue) {
var node = exp.node || exp.attribute.node;
var watchers = node.template.watchers;
var nodeTarget = node.element;
if (!watchers) return newValue;
if (!watchers) {
return newValue;
}
var watcherNode = watchers.get(nodeTarget);
if (!watcherNode && isTextNode(node.element) && node.parent) watcherNode = watchers.get(node.parent.element);
if (!watcherNode && isTextNode(node.element) && node.parent) {
watcherNode = watchers.get(node.parent.element);
}
var watcher = watcherNode ? watcherNode : watchers.get(exp.pattern);
if (isFunction(watcher)) {
var watcherValue = watcher(exp.value, newValue, exp.pattern, node.scope, node, exp.attribute);
......@@ -278,9 +316,9 @@ function getWatcherValue(exp, newValue) {
}
}
return newValue;
}
}
function getScopeFromPattern(scope, pattern) {
function getScopeFromPattern(scope, pattern) {
var depth = getScopeDepth(pattern);
var scopeTarget = scope;
while (depth > 0) {
......@@ -288,14 +326,27 @@ function getScopeFromPattern(scope, pattern) {
depth--;
}
return scopeTarget;
}
}
function getValueFromPattern(scope, pattern) {
function getValueFromPattern(scope, pattern, context) {
var exp = new Expression(pattern);
return getValue(scope, exp.pattern, exp.path, exp.params);
}
return getValue(scope, exp.pattern, exp.path, exp.params, undefined, undefined, undefined, context);
}
function getValue(scope, pattern, pathString, params, getFunction, getParams, paramsFound) {
function getValue(scope, pattern, pathString, params, getFunction, getParams, paramsFound, context) {
// context
if (pattern === vars.element) {
return context[vars.element];
}
if (pattern === vars.parentElement) {
return context[vars.parentElement];
}
if (pattern === vars.attribute) {
return context[vars.attribute];
}
if (pattern === vars.scope) {
return context[vars.scope];
}
// string
if (regex.string.test(pattern)) {
return trimQuotes(pattern);
......@@ -304,29 +355,39 @@ function getValue(scope, pattern, pathString, params, getFunction, getParams, pa
var paramsValues = [];
if (!paramsFound && params) {
for (var j = 0, jl = params.length; j < jl; j++) {
paramsValues.push(getValueFromPattern(scope, params[j]));
paramsValues.push(getValueFromPattern(scope, params[j], context));
}
}
else {
paramsValues = paramsFound;
}
if (getParams) {
return paramsValues;
}
else paramsValues = paramsFound;
if (getParams) return paramsValues;
// find scope
var scopeTarget = getScopeFromPattern(scope, pattern);
// remove parent string
pattern = pattern.replace(/..\//g, '');
pathString = pathString.replace(/..\//g, '');
if (!scopeTarget) return undefined;
if (!scopeTarget) {
return undefined;
}
// search path
var path = scopeTarget;
var pathParts = pathString.split(/\.|\[|\]/g);
if (pathParts.length > 0) {
for (var i = 0, l = pathParts.length; i < l; i++) {
if (pathParts[i] !== "") {
if (pathParts[i] !== '') {
path = path[pathParts[i]];
}
if (!isDefined(path)) {
// no path, search in parent
if (scopeTarget._parent) return getValue(scopeTarget._parent, pattern, pathString, params, getFunction, getParams, paramsValues);
else return undefined;
if (scopeTarget._parent) {
return getValue(scopeTarget._parent, pattern, pathString, params, getFunction, getParams, paramsValues);
}
else {
return undefined;
}
}
}
}
......@@ -335,46 +396,42 @@ function getValue(scope, pattern, pathString, params, getFunction, getParams, pa
return path;
}
else {
if (getFunction) return path;
else return path.apply(null, paramsValues);
if (getFunction) {
return path;
}
else {
return path.apply(null, paramsValues);
}
}
return undefined;
}
}
function getExpressionPath(value) {
function getExpressionPath(value) {
var val = value.split('(')[0];
val = trimScopeDepth(val);
return val;
}
}
function getParamsFromString(value) {
function getParamsFromString(value) {
return trimArray(value.split(regex.params));
}
}
function getScopeDepth(value) {
function getScopeDepth(value) {
var val = value.split('(')[0];
var matches = val.match(regex.depth);
return !matches ? 0 : matches.length;
}
}
function getNodeFromElement(element, scope, isRepeaterDescendant) {
var node = new Node(element, scope);
node.previousSibling = element.previousSibling;
node.nextSibling = element.nextSibling;
var attributes = [];
var eventsArray = [];
for (var attr, name, value, attrs = element.attributes, j = 0, jj = attrs && attrs.length; j < jj; j++) {
attr = attrs[j];
if (attr.specified) {
name = attr.name;
value = attr.value;
function addAttribute(node, name, value) {
var attr;
node.attributes = node.attributes || [];
if (name === settings.attributes.skip) {
node.skip = (value === "" || value === "true");
node.skip = normalizeBoolean(value);
}
if (name === settings.attributes.html) {
node.html = (value === "" || value === "true");
node.html = normalizeBoolean(value);
}
if (name === settings.attributes.repeat && !isRepeaterDescendant) {
if (name === settings.attributes.repeat && !node.isRepeaterDescendant) {
node.repeater = value;
}
if (
......@@ -392,59 +449,88 @@ function getNodeFromElement(element, scope, isRepeaterDescendant) {
name === settings.attributes.selected ||
value.indexOf(settings.attributes.cloak) !== -1
) {
attributes.push(new Attribute(name, value, node));
attr = new Attribute(name, value, node);
node.attributes.push(attr);
}
if (events[name]) {
attr = new Attribute(name, value, node);
node.attributes.push(attr);
}
return attr;
}
function getNodeFromElement(element, scope) {
var node = new Node(element, scope);
node.previousSibling = element.previousSibling;
node.nextSibling = element.nextSibling;
var eventsArray = [];
for (var attr, attrs = element.attributes, j = 0, jj = attrs && attrs.length; j < jj; j++) {
attr = attrs[j];
if (attr.specified || attr.name === 'value') {
var newAttr = addAttribute(node, attr.name, attr.value);
if (events[attr.name]) {
if (events[attr.name] && !node.isRepeaterChild) {
eventsArray.push({name:events[attr.name], value:attr.value, attr: newAttr});
}
if (events[name] && !isRepeaterDescendant) {
eventsArray.push({name:events[name], value:value});
attributes.push(new Attribute(name, value, node));
}
}
}
node.attributes = attributes;
for (var i = 0, l = eventsArray.length; i < l; i++) {
node.addEvent(eventsArray[i].name, eventsArray[i].value);
for (var a=0, b=eventsArray.length; a<b; a++) {
node.addEvent(eventsArray[a].name, eventsArray[a].value, eventsArray[a].attr);
}
return node;
}
}
function hasInterpolation(value) {
function hasInterpolation(value) {
var matches = value.match(regex.token);
return matches && matches.length > 0;
}
}
function hasContent(value) {
return regex.content.test(value)
}
function hasContent(value) {
return regex.content.test(value);
}
function isElementValid(element) {
if (!element) return;
function isElementValid(element) {
if (!element) {
return;
}
var type = element.nodeType;
if (!element || !type) return false;
if (!element || !type) {
return false;
}
// comment
if (type === 8) return false;
if (type === 8) {
return false;
}
// empty text node
if (type === 3 && !hasContent(element.nodeValue) && !hasInterpolation(element.nodeValue)) return false;
if (type === 3 && !hasContent(element.nodeValue) && !hasInterpolation(element.nodeValue)) {
return false;
}
// result
return true;
}
}
function compile(template, element, parent, nodeTarget) {
if (!isElementValid(element)) return;
function compile(template, element, parent, nodeTarget) {
if (!isElementValid(element)) {
return;
}
// get node
var node;
if (!nodeTarget) {
node = getNodeFromElement(element, parent ? parent.scope : new Scope(helpersScopeObject)._createChild(), parent && (parent.repeater || parent.isRepeaterDescendant) );
node = getNodeFromElement(element, parent ? parent.scope : new Scope(helpersScopeObject)._createChild());
}
else {
node = nodeTarget;
node.parent = parent;
}
if (parent && (parent.repeater || parent.isRepeaterDescendant)) {
node.isRepeaterDescendant = true;
if (parent && (parent.repeater || parent.isRepeaterChild)) {
node.isRepeaterChild = true;
}
node.template = template;
// children
if (node.skip) return;
if (node.skip) {
return;
}
var child = element.firstChild;
while (child) {
var childNode = compile(template, child, node);
......@@ -455,39 +541,47 @@ function compile(template, element, parent, nodeTarget) {
child = child.nextSibling;
}
return node;
}
}
function updateScopeWithData(scope, data) {
function updateScopeWithData(scope, data) {
clearScope(scope);
for (var d in data) {
if (data.hasOwnProperty(d)) {
scope[d] = data[d];
}
}
}
}
function clearScope(scope) {
function clearScope(scope) {
for (var key in scope) {
if (scope.hasOwnProperty(key)) {
if (key.substr(0, 1) !== '_') {
scope[key] = null;
delete scope[key];
}
}
}
}
}
function updateNodeChildren(node) {
if (node.repeater || !node.children || childNodeIsTemplate(node)) return;
function updateNodeChildren(node) {
if (node.repeater || !node.children || childNodeIsTemplate(node)) {
return;
}
for (var i = 0, l = node.children.length; i < l; i++) {
node.children[i].update();
}
}
}
function renderNodeChildren(node) {
if (!node.children || childNodeIsTemplate(node)) return;
function renderNodeChildren(node) {
if (!node.children || childNodeIsTemplate(node)) {
return;
}
for (var i = 0, l = node.children.length; i < l; i++) {
node.children[i].render();
}
}
}
function renderNodeRepeater(node) {
function renderNodeRepeater(node) {
var data = getRepeaterData(node.repeater, node.scope);
var previousElement;
if (isArray(data)) {
......@@ -509,9 +603,11 @@ function renderNodeRepeater(node) {
// process object
var count = -1;
for (var o in data) {
if (data.hasOwnProperty(o)) {
count++;
previousElement = createRepeaterChild(node, count, data[o], vars.key, o, previousElement);
}
}
var size = count;
while (count++ < node.childrenRepeater.length-1) {
node.parent.element.removeChild(node.childrenRepeater[count].element);
......@@ -522,59 +618,88 @@ function renderNodeRepeater(node) {
if (node.element.parentNode) {
node.element.parentNode.removeChild(node.element);
}
}
}
function cloneRepeaterNode(element, node) {
var newNode = new Node(element, node.scope._createChild());
function compileClone(node, newNode) {
if (!isElementValid(newNode.element)) {
return;
}
// create attribute
if (node.attributes) {
var attrs = [];
for (var i = 0, l = node.attributes.length; i < l; i++) {
newNode.renderAsHtml = node.renderAsHtml;
if (node.attributes[i].name === settings.attributes.skip) {
newNode.skip = (node.attributes[i].value === "" || node.attributes[i].value === "true");
for (var i= 0, l=node.attributes.length; i<l; i++) {
var attr = node.attributes[i];
var newAttr = addAttribute(newNode, attr.name, attr.value);
if (events[attr.name]) {
newNode.addEvent(events[attr.name], attr.value, newAttr);
}
if (node.attributes[i].name === settings.attributes.html) {
newNode.html = (node.attributes[i].value === "" || node.attributes[i].value === "true");
}
if (node.attributes[i].name !== attributes.repeat) {
var attribute = new Attribute(node.attributes[i].name, node.attributes[i].value, newNode);
attrs.push(attribute);
}
if (events[node.attributes[i].name]) {
newNode.addEvent(events[node.attributes[i].name], node.attributes[i].value);
// children
var child = node.element.firstChild;
var newChild = newNode.element.firstChild;
// loop
while (child && newChild) {
var childNode = node.getNode(child);
var newChildNode = new Node(newChild, newNode.scope);
newNode.children.push(newChildNode);
newChildNode.parent = newNode;
newChildNode.template = newNode.template;
newChildNode.isRepeaterChild = true;
var compiledNode = compileClone(childNode, newChildNode);
if (compiledNode) {
compiledNode.parent = newChildNode;
compiledNode.template = newChildNode.template;
newChildNode.children.push(compiledNode);
}
child = child.nextSibling;
newChild = newChild.nextSibling;
}
newNode.attributes = attrs;
return newChildNode;
}
function cloneRepeaterNode(element, node) {
var newNode = new Node(element, node.scope._createChild());
newNode.template = node.template;
newNode.parent = node;
newNode.isRepeaterChild = true;
newNode.isRepeaterDescendant = true;
compileClone(node, newNode);
return newNode;
}
}
function appendRepeaterElement(previousElement, node, newElement) {
if (!previousElement) {
if (node.element.previousSibling) {
insertAfter(node.element.previousSibling, newElement);
}
else if (node.element.nextSibling) {
insertBefore(node.element.nextSibling, newElement);
}
else {
node.parent.element.appendChild(newElement);
}
}
else {
insertAfter(previousElement, newElement);
}
}
function createRepeaterChild(node, count, data, indexVar, indexVarValue, previousElement) {
function createRepeaterChild(node, count, data, indexVar, indexVarValue, previousElement) {
var existingChild = node.childrenRepeater[count];
if (!existingChild) {
// no existing node
var newElement = node.element.cloneNode(true);
// need to append the cloned element to the DOM
// before changing attributes or IE will crash
appendRepeaterElement(previousElement, node, newElement);
// can't recreate the node with a cloned element on IE7
// be cause the attributes are not specified annymore (attribute.specified)
// be cause the attributes are not specified anymore (attribute.specified)
//var newNode = getNodeFromElement(newElement, node.scope._createChild(), true);
var newNode = cloneRepeaterNode(newElement, node);
newNode.isRepeaterChild = true;
newNode.parent = node.parent;
newNode.template = node.template;
node.childrenRepeater[count] = newNode;
updateScopeWithRepeaterData(node.repeater, newNode.scope, data);
newNode.scope[indexVar] = indexVarValue;
compile(node.template, newElement, node.parent, newNode);
newNode.update();
newNode.render();
if (!previousElement) {
if (node.previousSibling) insertAfter(node.previousSibling, newElement);
else if (node.nextSibling) insertBefore(node.nextSibling, newElement);
else node.parent.element.appendChild(newElement);
}
else {
insertAfter(previousElement, newElement);
}
return newElement;
}
else {
......@@ -585,28 +710,29 @@ function createRepeaterChild(node, count, data, indexVar, indexVarValue, previou
existingChild.render();
return existingChild.element;
}
}
}
var Scope = function(data) {
var Scope = function(data) {
var self;
function createChild(data) {
var obj = createObject(data);
obj._parent = this;
this._children.push(obj);
obj._parent = self;
self._children.push(obj);
return obj;
}
function createObject(data) {
var obj = data || {};
obj._parent = null;
obj._children = [];
obj._createChild = function(data) {
obj._createChild = function() {
self = obj;
return createChild.apply(obj, arguments);
}
};
return obj;
}
return createObject(data);
};
var Node = function(element, scope) {
};
var Node = function(element, scope) {
this.element = element;
this.scope = scope;
this.attributes = null;
......@@ -631,8 +757,8 @@ var Node = function(element, scope) {
this.interpolation = new Interpolation(this.value, this, undefined);
}
};
Node.prototype = {
};
Node.prototype = {
toString: function() {
return '[object Node]';
},
......@@ -660,7 +786,6 @@ Node.prototype = {
this.element = null;
this.scope = null;
this.attributes = null;
this.attributesHashMap = null;
this.value = null;
this.interpolation = null;
this.repeater = null;
......@@ -674,17 +799,21 @@ Node.prototype = {
},
getNode: function(element) {
var node;
if (element === this.element) return this;
else if (this.childrenRepeater.length > 0) {
if (element === this.element) {
return this;
}
if (this.childrenRepeater.length > 0) {
for (var k = 0, kl = this.childrenRepeater.length; k < kl; k++) {
node = this.childrenRepeater[k].getNode(element);
if (node) return node;
if (node) {
return node;
}
}
}
else {
for (var i = 0, l = this.children.length; i < l; i++) {
node = this.children[i].getNode(element);
if (node) return node;
if (node) {
return node;
}
}
return null;
......@@ -700,7 +829,9 @@ Node.prototype = {
}
},
update: function() {
if (childNodeIsTemplate(this)) return;
if (childNodeIsTemplate(this)) {
return;
}
if (isDefined(this.interpolation)) {
this.interpolation.update();
}
......@@ -712,7 +843,9 @@ Node.prototype = {
updateNodeChildren(this);
},
invalidateData: function() {
if (childNodeIsTemplate(this)) return;
if (childNodeIsTemplate(this)) {
return;
}
this.invalidate = true;
var i, l;
if (this.attributes) {
......@@ -727,14 +860,17 @@ Node.prototype = {
this.children[i].invalidateData();
}
},
addEvent: function(type, pattern) {
if (this.repeater) return;
addEvent: function(type, pattern, attr) {
if (this.repeater) {
return;
}
if (this.eventHandlers[type]) {
this.removeEvent(type);
}
var scope = this.scope;
var node = this;
var handler = function(event) {
var exp = new Expression(pattern, this.node);
var exp = new Expression(pattern, node, attr);
var func = exp.getValue(scope, true);
var params = exp.getValue(scope, false, true);
params.unshift(event);
......@@ -753,7 +889,9 @@ Node.prototype = {
clearEvents: function() {
if (this.eventHandlers) {
for (var key in this.eventHandlers) {
this.removeEvent(key, this.eventHandlers[key]);
if (this.eventHandlers.hasOwnProperty(key)) {
this.removeEvent(key);
}
}
}
if (this.children) {
......@@ -768,7 +906,9 @@ Node.prototype = {
}
},
render: function() {
if (childNodeIsTemplate(this)) return;
if (childNodeIsTemplate(this)) {
return;
}
if (this.invalidate) {
this.invalidate = false;
if (isTextNode(this.element)) {
......@@ -792,22 +932,26 @@ Node.prototype = {
renderNodeChildren(this);
}
}
};
var Attribute = function(name, value, node) {
};
var Attribute = function(name, value, node) {
this.name = name;
this.value = value;
this.node = node;
this.interpolationName = new Interpolation(this.name, null, this);
this.interpolationValue = new Interpolation(this.value, null, this);
this.invalidate = false;
};
Attribute.prototype = {
};
Attribute.prototype = {
toString: function() {
return '[object Attribute]';
},
dispose: function() {
if (this.interpolationName) this.interpolationName.dispose();
if (this.interpolationValue) this.interpolationValue.dispose();
if (this.interpolationName) {
this.interpolationName.dispose();
}
if (this.interpolationValue) {
this.interpolationValue.dispose();
}
this.interpolationName = null;
this.interpolationValue = null;
this.node = null;
......@@ -816,47 +960,77 @@ Attribute.prototype = {
this.previousName = null;
},
update: function() {
if (this.node.repeater) {
return;
}
this.interpolationName.update();
this.interpolationValue.update();
},
render: function() {
if (this.node.repeater) return;
if (this.node.repeater) {
return;
}
// normal attribute
function renderAttribute(name, value, node) {
if (name === 'value' && node.element['value'] !== undefined) {
element.value = value;
}
else if (ie === 7 && name === 'class') {
element.className = value;
}
else {
element.setAttribute(name, value);
}
}
// boolean attribute
function renderBooleanAttribute(name, value) {
element.setAttribute(name, value);
}
// special attribute
function renderSpecialAttribute(value, attrName) {
if (normalizeBoolean(value)) {
element.setAttribute(attrName, attrName);
}
else {
element.removeAttribute(attrName);
}
}
// src attribute
function renderSrc(value) {
element.setAttribute('src', value);
}
// href attribute
function renderHref(value) {
element.setAttribute('href', value);
}
var element = this.node.element;
if (this.invalidate) {
this.invalidate = false;
this.previousName = this.name;
this.name = isDefined(this.interpolationName.render()) ? this.interpolationName.render() : this.name;
this.value = isDefined(this.interpolationValue.render()) ? this.interpolationValue.render() : this.value;
if (this.name === attributes.src) {
renderSrc(this.name, this.value);
renderSrc(this.value);
}
else if (this.name === attributes.href) {
renderHref(this.name, this.value);
}
else {
if (this.node.isRepeaterChild && ie === 7) {
// delete attributes on cloned elements crash IE7
renderHref(this.value);
}
else {
if (ie !== 7 || (ie === 7 && !this.node.isRepeaterChild)) {
this.node.element.removeAttribute(this.interpolationName.value);
}
if (this.previousName) {
if (ie === 7 && this.previousName === 'class') {
// iE
this.node.element.className = "";
}
else {
if (this.node.isRepeaterChild && ie === 7) {
// delete attributes on cloned elements crash IE7
this.node.element.className = '';
}
else {
if (ie !== 7 || (ie === 7 && !this.node.isRepeaterChild)) {
this.node.element.removeAttribute(this.previousName);
}
}
}
renderAttribute(this.name, this.value, this.previousName);
renderAttribute(this.name, this.value, this.node);
}
}
// cloak
......@@ -865,68 +1039,52 @@ Attribute.prototype = {
}
// hide
if (this.name === attributes.hide) {
element.style.display = isAttributeDefined(this.value) ? "none" : "block";
var bool = normalizeBoolean(this.value);
renderAttribute(this.name, bool, this.node);
element.style.display = bool ? 'none' : '';
}
// show
if (this.name === attributes.show) {
element.style.display = isAttributeDefined(this.value) ? "block" : "none";
var bool = normalizeBoolean(this.value);
renderAttribute(this.name, bool, this.node);
element.style.display = bool ? '' : 'none';
}
// checked
if (this.name === attributes.checked) {
renderSpecialAttribute(this.name, this.value, 'checked');
element.checked = isAttributeDefined(this.value) ? true : false;
renderSpecialAttribute(this.value, 'checked');
renderAttribute(this.name, normalizeBoolean(this.value) ? true : false, this.node);
element.checked = normalizeBoolean(this.value) ? true : false;
}
// disabled
if (this.name === attributes.disabled) {
renderSpecialAttribute(this.name, this.value, 'disabled');
renderSpecialAttribute(this.value, 'disabled');
renderAttribute(this.name, normalizeBoolean(this.value) ? true : false, this.node);
}
// multiple
if (this.name === attributes.multiple) {
renderSpecialAttribute(this.name, this.value, 'multiple');
renderSpecialAttribute(this.value, 'multiple');
renderAttribute(this.name, normalizeBoolean(this.value) ? true : false, this.node);
}
// readonly
if (this.name === attributes.readonly) {
var bool = normalizeBoolean(this.value);
if (ie === 7) {
element.readOnly = isAttributeDefined(this.value) ? true : false;
element.readOnly = bool ? true : false;
}
else {
renderSpecialAttribute(this.name, this.value, 'readonly');
renderSpecialAttribute(this.value, 'readonly');
}
renderAttribute(this.name, bool ? true : false, this.node);
}
// selected
if (this.name === attributes.selected) {
renderSpecialAttribute(this.name, this.value, 'selected');
}
// normal attribute
function renderAttribute(name, value) {
if (ie === 7 && name === "class") {
element.className = value;
}
else {
element.setAttribute(name, value);
renderSpecialAttribute(this.value, 'selected');
renderAttribute(this.name, normalizeBoolean(this.value) ? true : false, this.node);
}
}
// special attribute
function renderSpecialAttribute(name, value, attrName) {
if (isAttributeDefined(value)) {
element.setAttribute(attrName, attrName);
}
else {
element.removeAttribute(attrName);
}
}
// src attribute
function renderSrc(name, value) {
element.setAttribute('src', value);
}
// href attribute
function renderHref(name, value) {
element.setAttribute('href', value);
}
}
};
};
var Interpolation = function(value, node, attribute) {
var Interpolation = function(value, node, attribute) {
this.value = node && !isTextNode(node.element) ? trim(value) : value;
this.node = node;
this.attribute = attribute;
......@@ -946,8 +1104,8 @@ var Interpolation = function(value, node, attribute) {
}
trimArray(this.sequence);
}
};
Interpolation.prototype = {
};
Interpolation.prototype = {
toString: function() {
return '[object Interpolation]';
},
......@@ -970,22 +1128,30 @@ Interpolation.prototype = {
}
},
render: function() {
var rendered = "";
var rendered = '';
if (this.sequence) {
for (var i = 0, l = this.sequence.length; i < l; i++) {
var val = "";
if (isExpression(this.sequence[i])) val = this.sequence[i].value;
else val = this.sequence[i];
if (!isDefined(val)) val = "";
var val = '';
if (isExpression(this.sequence[i])) {
val = this.sequence[i].value;
}
else {
val = this.sequence[i];
}
if (!isDefined(val)) {
val = '';
}
rendered += val;
}
}
return rendered;
}
};
};
var Expression = function(pattern, node, attribute) {
if (!isDefined(pattern)) return;
var Expression = function(pattern, node, attribute) {
if (!isDefined(pattern)) {
return;
}
this.pattern = pattern;
this.isString = regex.string.test(pattern);
this.node = node;
......@@ -1003,8 +1169,8 @@ var Expression = function(pattern, node, attribute) {
this.path = getExpressionPath(this.pattern);
this.params = !this.isFunction ? null : getParamsFromString(this.pattern.match(regex.func)[2]);
}
};
Expression.prototype = {
};
Expression.prototype = {
toString: function() {
return '[object Expression]';
},
......@@ -1018,8 +1184,12 @@ Expression.prototype = {
},
update: function() {
var node = this.node;
if (!node && this.attribute) node = this.attribute.node;
if (!node && node.scope) return;
if (!node && this.attribute) {
node = this.attribute.node;
}
if (!node && node.scope) {
return;
}
var newValue = this.getValue(node.scope);
newValue = getWatcherValue(this, newValue);
if (this.value !== newValue) {
......@@ -1028,42 +1198,69 @@ Expression.prototype = {
}
},
getValue: function(scope, getFunction, getParams) {
return getValue(scope, this.pattern, this.path, this.params, getFunction, getParams);
var node = this.node;
if (!node && this.attribute) {
node = this.attribute.node;
}
var context = {};
if (node) {
context[vars.element] = node.element;
if (node.element) {
context[vars.parentElement] = node.element.parentNode;
}
}
};
context[vars.attribute] = this.attribute;
context[vars.scope] = scope;
return getValue(scope, this.pattern, this.path, this.params, getFunction, getParams, undefined, context);
}
};
var templates = new HashMap();
var templates = new HashMap('st');
var Template = function(element) {
this.watchers = new HashMap();
var Template = function(element) {
this.watchers = new HashMap('stw');
this.node = null;
this.scope = null;
this.compile(element);
};
Template.prototype = {
};
Template.prototype = {
toString: function() {
return '[object Template]';
},
compile: function(element) {
if (element) this.element = element;
if (this.node) this.node.dispose();
if (element) {
this.element = element;
}
if (this.node) {
this.node.dispose();
}
this.node = compile(this, this.element);
this.node.root = true;
this.scope = this.node.scope;
},
update: function(data) {
if (isDefined(data)) updateScopeWithData(this.node.scope, data);
if (this.node) this.node.update();
if (isDefined(data)) {
updateScopeWithData(this.node.scope, data);
}
if (this.node) {
this.node.update();
}
},
render: function(data) {
this.update(data);
if (this.node) this.node.render();
if (this.node) {
this.node.render();
}
},
invalidate: function() {
if (this.node) this.node.invalidateData();
if (this.node) {
this.node.invalidateData();
}
},
watch: function(target, watcher) {
if ( (!isString(target) && !isElement(target)) || !isFunction(watcher)) return;
if ( (!isString(target) && !isElement(target)) || !isFunction(watcher)) {
return;
}
this.watchers.put(target, watcher);
},
unwatch: function(target) {
......@@ -1090,47 +1287,36 @@ Template.prototype = {
this.watchers = null;
this.node = null;
}
};
};
// written by Dean Edwards, 2005
// with input from Tino Zijdel, Matthias Miller, Diego Perini
// http://dean.edwards.name/weblog/2005/10/add-event/
function addEvent(element, type, handler) {
// written by Dean Edwards, 2005
// with input from Tino Zijdel, Matthias Miller, Diego Perini
// http://dean.edwards.name/weblog/2005/10/add-event/
function addEvent(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else {
// assign each event handler a unique ID
if (!handler.$$guid) handler.$$guid = addEvent.guid++;
if (!handler.$$guid) {
handler.$$guid = addEvent.guid++;
}
// create a hash table of event types for the element
if (!element.events) element.events = {};
if (!element.events) {
element.events = {};
}
// create a hash table of event handlers for each element/event pair
var handlers = element.events[type];
if (!handlers) {
handlers = element.events[type] = {};
// store the existing event handler (if there is one)
if (element["on" + type]) {
handlers[0] = element["on" + type];
if (element['on' + type]) {
handlers[0] = element['on' + type];
}
}
// store the event handler in the hash table
handlers[handler.$$guid] = handler;
// assign a global event handler to do all the work
element["on" + type] = handleEvent;
}
};
// a counter used to create unique IDs
addEvent.guid = 1;
function removeEvent(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else {
// delete the event handler from the hash table
if (element.events && element.events[type]) {
delete element.events[type][handler.$$guid];
}
}
};
function handleEvent(event) {
element['on' + type] = function(event) {
var returnValue = true;
// grab the event object (IE uses a global event object)
event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event);
......@@ -1138,38 +1324,60 @@ function handleEvent(event) {
var handlers = this.events[event.type];
// execute each event handler
for (var i in handlers) {
if (handlers.hasOwnProperty(i)) {
this.$$handleEvent = handlers[i];
if (this.$$handleEvent(event) === false) {
returnValue = false;
}
}
}
return returnValue;
};
function fixEvent(event) {
};
}
}
// a counter used to create unique IDs
addEvent.guid = 1;
function removeEvent(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else {
// delete the event handler from the hash table
if (element.events && element.events[type]) {
delete element.events[type][handler.$$guid];
}
}
}
function fixEvent(event) {
// add W3C standard event methods
event.preventDefault = fixEvent.preventDefault;
event.stopPropagation = fixEvent.stopPropagation;
return event;
};
fixEvent.preventDefault = function() {
}
fixEvent.preventDefault = function() {
this.returnValue = false;
};
fixEvent.stopPropagation = function() {
};
fixEvent.stopPropagation = function() {
this.cancelBubble = true;
};
};
var maxDepth;
var eventStore = [];
var maxDepth;
var eventStore = [];
function parseEvents(element, object, depth) {
function parseEvents(element, object, depth) {
maxDepth = depth === undefined ? Number.MAX_VALUE : depth;
parseNode(element, object, 0, true);
}
}
function parseNode(element, object, depth, isRoot) {
if (!isElement(element)) throw new Error('Error in soma.template.parseEvents, only a DOM Element can be parsed.');
if (isRoot) parseAttributes(element, object);
if (maxDepth === 0) return;
function parseNode(element, object, depth, isRoot) {
if (!isElement(element)) {
throw new Error('Error in soma.template.parseEvents, only a DOM Element can be parsed.');
}
if (isRoot) {
parseAttributes(element, object);
}
if (maxDepth === 0) {
return;
}
var child = element.firstChild;
while (child) {
if (child.nodeType === 1) {
......@@ -1180,17 +1388,16 @@ function parseNode(element, object, depth, isRoot) {
}
child = child.nextSibling;
}
}
}
function parseAttributes(element, object) {
var attributes = [];
function parseAttributes(element, object) {
for (var attr, name, value, attrs = element.attributes, j = 0, jj = attrs && attrs.length; j < jj; j++) {
attr = attrs[j];
if (attr.specified) {
name = attr.name;
value = attr.value;
if (events[name]) {
var handler = getHandlerFromPattern(object, value, element);
var handler = getHandlerFromPattern(object, value);
if (handler && isFunction(handler)) {
addEvent(element, events[name], handler);
eventStore.push({element:element, type:events[name], handler:handler});
......@@ -1198,9 +1405,9 @@ function parseAttributes(element, object) {
}
}
}
}
}
function getHandlerFromPattern(object, pattern, child) {
function getHandlerFromPattern(object, pattern) {
var parts = pattern.match(regex.func);
if (parts) {
var func = parts[1];
......@@ -1208,9 +1415,9 @@ function getHandlerFromPattern(object, pattern, child) {
return object[func];
}
}
}
}
function clearEvents(element) {
function clearEvents(element) {
var i = eventStore.length, l = 0;
while (--i >= l) {
var item = eventStore[i];
......@@ -1219,12 +1426,16 @@ function clearEvents(element) {
eventStore.splice(i, 1);
}
}
}
}
if (settings.autocreate && typeof document === 'object') {
var ready;
if (typeof document === 'object') {
// https://github.com/ded/domready
var ready=function(){function l(b){for(k=1;b=a.shift();)b()}var b,a=[],c=!1,d=document,e=d.documentElement,f=e.doScroll,g="DOMContentLoaded",h="addEventListener",i="onreadystatechange",j="readyState",k=/^loade|c/.test(d[j]);return d[h]&&d[h](g,b=function(){d.removeEventListener(g,b,c),l()},c),f&&d.attachEvent(i,b=function(){/^c/.test(d[j])&&(d.detachEvent(i,b),l())}),f?function(b){self!=top?k?b():a.push(b):function(){try{e.doScroll("left")}catch(a){return setTimeout(function(){ready(b)},50)}b()}()}:function(b){k?b():a.push(b)}}();
if (settings.autocreate) {
var parse = function(element) {
var child = !element ? document.body : element.firstChild;
while (child) {
......@@ -1238,19 +1449,21 @@ if (settings.autocreate && typeof document === 'object') {
if (isFunction(f)) {
soma.template.bootstrap(attrValue, child, f);
}
} catch(err){};
} catch(err){}
}
}
child = child.nextSibling;
}
};
ready(parse);
}
function bootstrapTemplate(attrValue, element, func) {
}
}
function bootstrapTemplate(attrValue, element, func) {
var tpl = createTemplate(element);
func(tpl, tpl.scope, tpl.element, tpl.node);
}
function createTemplate(source, target) {
}
function createTemplate(source, target) {
var element;
if (isString(source)) {
// string template
......@@ -1283,19 +1496,22 @@ function createTemplate(source, target) {
var template = new Template(element);
templates.put(element, template);
return template;
}
}
function getTemplate(element) {
function getTemplate(element) {
return templates.get(element);
}
}
function renderAllTemplates() {
function renderAllTemplates() {
var data = templates.getData();
for (var key in templates.getData()) {
if (data.hasOwnProperty(key)) {
templates.get(key).render();
}
}
}
}
function appendHelpers(obj) {
function appendHelpers(obj) {
if (obj === null) {
helpersObject = {};
helpersScopeObject = {};
......@@ -1308,20 +1524,20 @@ function appendHelpers(obj) {
}
}
return helpersObject;
}
}
// set regex
tokens.start(tokenStart);
tokens.end(tokenEnd);
// set regex
tokens.start(tokenStart);
tokens.end(tokenEnd);
// plugins
// plugins
soma.plugins = soma.plugins || {};
soma.plugins = soma.plugins || {};
var TemplatePlugin = function(instance, injector) {
var TemplatePlugin = function(instance, injector) {
instance.constructor.prototype.createTemplate = function(cl, domElement) {
if (!cl || typeof cl !== "function") {
throw new Error("Error creating a template, the first parameter must be a function.");
if (!cl || typeof cl !== 'function') {
throw new Error('Error creating a template, the first parameter must be a function.');
}
if (domElement && isElement(domElement)) {
var template = soma.template.create(domElement);
......@@ -1332,46 +1548,46 @@ var TemplatePlugin = function(instance, injector) {
}
cl.prototype.render = template.render.bind(template);
var childInjector = injector.createChild();
childInjector.mapValue("template", template);
childInjector.mapValue("scope", template.scope);
childInjector.mapValue("element", template.element);
childInjector.mapValue('template', template);
childInjector.mapValue('scope', template.scope);
childInjector.mapValue('element', template.element);
return childInjector.createInstance(cl);
}
return null;
}
};
soma.template.bootstrap = function(attrValue, element, func) {
instance.createTemplate(func, element);
}
}
if (soma.plugins && soma.plugins.add) {
};
};
if (soma.plugins && soma.plugins.add) {
soma.plugins.add(TemplatePlugin);
}
soma.template.Plugin = TemplatePlugin;
// exports
soma.template.create = createTemplate;
soma.template.get = getTemplate;
soma.template.renderAll = renderAllTemplates;
soma.template.helpers = appendHelpers;
soma.template.bootstrap = bootstrapTemplate;
soma.template.addEvent = addEvent;
soma.template.removeEvent = removeEvent;
soma.template.parseEvents = parseEvents;
soma.template.clearEvents = clearEvents;
soma.template.ready = ready;
// register for AMD module
if (typeof define === 'function' && define.amd) {
define("soma-template", soma.template);
}
// export for node.js
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = soma.template;
}
soma.template.Plugin = TemplatePlugin;
// exports
soma.template.create = createTemplate;
soma.template.get = getTemplate;
soma.template.renderAll = renderAllTemplates;
soma.template.helpers = appendHelpers;
soma.template.bootstrap = bootstrapTemplate;
soma.template.addEvent = addEvent;
soma.template.removeEvent = removeEvent;
soma.template.parseEvents = parseEvents;
soma.template.clearEvents = clearEvents;
soma.template.ready = ready;
// register for AMD module
if (typeof define === 'function' && typeof define.amd !== 'undefined') {
define('soma-template', soma.template);
}
// export for node.js
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
module.exports = soma.template;
}
if (typeof exports !== 'undefined') {
exports = soma.template;
}
}
})(this['soma'] = this['soma'] || {});
\ No newline at end of file
/*
Copyright (c) | 2012 | infuse.js | Romuald Quantin | www.soundstep.com | romu@soundstep.com
Copyright (c) | 2013 | infuse.js | Romuald Quantin | www.soundstep.com | romu@soundstep.com
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without restriction,
......@@ -17,10 +17,11 @@ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
;(function(infuse, undefined) {
"use strict";
(function(infuse) {
infuse.version = "0.6.3";
'use strict';
infuse.version = '0.7.0';
// regex from angular JS (https://github.com/angular/angular.js)
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
......@@ -28,26 +29,26 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
if(!Array.prototype.contains) {
Array.prototype.contains = function(value) {
var i = this.length;
function contains(arr, value) {
var i = arr.length;
while (i--) {
if (this[i] === value) return true;
if (arr[i] === value) {
return true;
}
}
return false;
};
}
infuse.InjectorError = {
MAPPING_BAD_PROP: "[Error infuse.Injector.mapClass/mapValue] the first parameter is invalid, a string is expected",
MAPPING_BAD_VALUE: "[Error infuse.Injector.mapClass/mapValue] the second parameter is invalid, it can't null or undefined, with property: ",
MAPPING_BAD_CLASS: "[Error infuse.Injector.mapClass/mapValue] the second parameter is invalid, a function is expected, with property: ",
MAPPING_BAD_SINGLETON: "[Error infuse.Injector.mapClass] the third parameter is invalid, a boolean is expected, with property: ",
MAPPING_ALREADY_EXISTS: "[Error infuse.Injector.mapClass/mapValue] this mapping already exists, with property: ",
CREATE_INSTANCE_INVALID_PARAM: "[Error infuse.Injector.createInstance] invalid parameter, a function is expected",
NO_MAPPING_FOUND: "[Error infuse.Injector.getInstance] no mapping found",
INJECT_INSTANCE_IN_ITSELF_PROPERTY: "[Error infuse.Injector.getInjectedValue] A matching property has been found in the target, you can't inject an instance in itself",
INJECT_INSTANCE_IN_ITSELF_CONSTRUCTOR: "[Error infuse.Injector.getInjectedValue] A matching constructor parameter has been found in the target, you can't inject an instance in itself"
MAPPING_BAD_PROP: '[Error infuse.Injector.mapClass/mapValue] the first parameter is invalid, a string is expected',
MAPPING_BAD_VALUE: '[Error infuse.Injector.mapClass/mapValue] the second parameter is invalid, it can\'t null or undefined, with property: ',
MAPPING_BAD_CLASS: '[Error infuse.Injector.mapClass/mapValue] the second parameter is invalid, a function is expected, with property: ',
MAPPING_BAD_SINGLETON: '[Error infuse.Injector.mapClass] the third parameter is invalid, a boolean is expected, with property: ',
MAPPING_ALREADY_EXISTS: '[Error infuse.Injector.mapClass/mapValue] this mapping already exists, with property: ',
CREATE_INSTANCE_INVALID_PARAM: '[Error infuse.Injector.createInstance] invalid parameter, a function is expected',
NO_MAPPING_FOUND: '[Error infuse.Injector.getInstance] no mapping found',
INJECT_INSTANCE_IN_ITSELF_PROPERTY: '[Error infuse.Injector.getInjectedValue] A matching property has been found in the target, you can\'t inject an instance in itself',
INJECT_INSTANCE_IN_ITSELF_CONSTRUCTOR: '[Error infuse.Injector.getInjectedValue] A matching constructor parameter has been found in the target, you can\'t inject an instance in itself'
};
var MappingVO = function(prop, value, cl, singleton) {
......@@ -58,7 +59,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
};
var validateProp = function(prop) {
if (typeof prop !== "string") {
if (typeof prop !== 'string') {
throw new Error(infuse.InjectorError.MAPPING_BAD_PROP);
}
};
......@@ -70,20 +71,20 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
};
var validateClass = function(prop, val) {
if (typeof val !== "function") {
if (typeof val !== 'function') {
throw new Error(infuse.InjectorError.MAPPING_BAD_CLASS + prop);
}
};
var validateBooleanSingleton = function(prop, singleton) {
if (typeof singleton !== "boolean") {
if (typeof singleton !== 'boolean') {
throw new Error(infuse.InjectorError.MAPPING_BAD_SINGLETON + prop);
}
};
var validateConstructorInjectionLoop = function(name, cl) {
var params = infuse.getConstructorParams(cl);
if (params.contains(name)) {
if (contains(params, name)) {
throw new Error(infuse.InjectorError.INJECT_INSTANCE_IN_ITSELF_CONSTRUCTOR);
}
};
......@@ -94,33 +95,29 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}
};
var instantiateIgnoringConstructor = function() {
if (typeof arguments[0] !== "function") {
throw new Error(infuse.InjectorError.CREATE_INSTANCE_INVALID_PARAM);
}
var TargetClass = arguments[0];
var args = [null];
for (var i=1; i<arguments.length; i++) {
args.push(arguments[i]);
}
return new (Function.prototype.bind.apply(TargetClass, args));
};
infuse.Injector = function() {
this.mappings = {};
this.parent = null;
};
infuse.getConstructorParams = function(cl) {
var args = [];
var args = [],
inject;
function extractName(all, underscore, name) {
args.push(name);
}
// Override arg name with inject array values if present
if( cl.hasOwnProperty('inject') && toString.call(cl.inject) === '[object Array]' && cl.inject.length > 0)
inject = cl.inject;
var clStr = cl.toString().replace(STRIP_COMMENTS, '');
var argsFlat = clStr.match(FN_ARGS);
var spl = argsFlat[1].split(FN_ARG_SPLIT);
for (var i=0; i<spl.length; i++) {
var arg = spl[i];
arg.replace(FN_ARG, function(all, underscore, name){
args.push(name);
});
// Only override arg with non-falsey inject value at same key
var arg = (inject && inject[i]) ? inject[i] : spl[i];
arg.replace(FN_ARG, extractName);
}
return args;
};
......@@ -134,9 +131,15 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
},
getMappingVo: function(prop) {
if (!this.mappings) return null;
if (this.mappings[prop]) return this.mappings[prop];
if (this.parent) return this.parent.getMappingVo(prop);
if (!this.mappings) {
return null;
}
if (this.mappings[prop]) {
return this.mappings[prop];
}
if (this.parent) {
return this.parent.getMappingVo(prop);
}
return null;
},
......@@ -146,7 +149,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}
validateProp(prop);
validateValue(prop, val);
this.mappings[prop] = new MappingVO(prop, val);
this.mappings[prop] = new MappingVO(prop, val, undefined, undefined);
return this;
},
......@@ -156,7 +159,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}
validateProp(prop);
validateClass(prop, cl);
if (singleton) validateBooleanSingleton(prop, singleton);
if (singleton) {
validateBooleanSingleton(prop, singleton);
}
this.mappings[prop] = new MappingVO(prop, null, cl, singleton);
return this;
},
......@@ -177,22 +182,38 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
getMapping: function(value) {
for (var name in this.mappings) {
if (this.mappings.hasOwnProperty(name)) {
var vo = this.mappings[name];
if (vo.value === value || vo.cl === value) {
return vo.prop;
}
}
}
return undefined;
},
getValue: function(prop) {
var vo = this.mappings[prop];
if (!vo) {
if (this.parent) return this.parent.getValue.apply(this.parent, arguments);
else throw new Error(infuse.InjectorError.NO_MAPPING_FOUND);
if (this.parent) {
return this.parent.getValue.apply(this.parent, arguments);
}
else {
throw new Error(infuse.InjectorError.NO_MAPPING_FOUND);
}
}
if (vo.cl) {
arguments[0] = vo.cl;
return this.getValueFromClass.apply(this, arguments);
var args = Array.prototype.slice.call(arguments);
args[0] = vo.cl;
if (vo.singleton) {
if (!vo.value) {
vo.value = this.createInstance.apply(this, args);
}
return vo.value;
}
else {
return this.createInstance.apply(this, args);
}
}
return vo.value;
},
......@@ -200,20 +221,25 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
getClass: function(prop) {
var vo = this.mappings[prop];
if (!vo) {
if (this.parent) return this.parent.getClass(prop);
else return undefined;
if (this.parent) {
return this.parent.getClass(prop);
}
else {
return undefined;
}
}
if (vo.cl) {
return vo.cl;
}
if (vo.cl) return vo.cl;
return undefined;
},
instantiate: function(TargetClass) {
if (typeof TargetClass !== "function") {
if (typeof TargetClass !== 'function') {
throw new Error(infuse.InjectorError.CREATE_INSTANCE_INVALID_PARAM);
}
var TargetClass = arguments[0];
var args = [null];
var params = infuse.getConstructorParams(TargetClass, this.mappings);
var params = infuse.getConstructorParams(TargetClass);
for (var i=0; i<params.length; i++) {
if (arguments[i+1] !== undefined && arguments[i+1] !== null) {
// argument found
......@@ -234,7 +260,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}
}
}
return new (Function.prototype.bind.apply(TargetClass, args));
return new (Function.prototype.bind.apply(TargetClass, args))();
},
inject: function (target, isParent) {
......@@ -242,10 +268,11 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
this.parent.inject(target, true);
}
for (var name in this.mappings) {
if (this.mappings.hasOwnProperty(name)) {
var vo = this.getMappingVo(name);
if (target.hasOwnProperty(vo.prop)) {
var val = this.getInjectedValue(vo, name);
target[name] = val;
if (target.hasOwnProperty(vo.prop) || (target.constructor && target.constructor.prototype && target.constructor.prototype.hasOwnProperty(vo.prop)) ) {
target[name] = this.getInjectedValue(vo, name);
}
}
}
if (typeof target.postConstruct === 'function' && !isParent) {
......@@ -258,7 +285,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var val = vo.value;
var injectee;
if (vo.cl) {
var params = infuse.getConstructorParams(vo.cl);
if (vo.singleton) {
if (!vo.value) {
validateConstructorInjectionLoop(name, vo.cl);
......@@ -288,10 +314,13 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
getValueFromClass: function(cl) {
for (var name in this.mappings) {
if (this.mappings.hasOwnProperty(name)) {
var vo = this.mappings[name];
if (vo.cl == cl) {
if (vo.cl === cl) {
if (vo.singleton) {
if (!vo.value) vo.value = this.createInstance.apply(this, arguments);
if (!vo.value) {
vo.value = this.createInstance.apply(this, arguments);
}
return vo.value;
}
else {
......@@ -299,6 +328,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}
}
}
}
if (this.parent) {
return this.parent.getValueFromClass.apply(this.parent, arguments);
} else {
......@@ -315,15 +345,15 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
if (!Function.prototype.bind) {
Function.prototype.bind = function bind(that) {
var target = this;
if (typeof target != "function") {
throw new Error("Error, you must bind a function.");
if (typeof target !== 'function') {
throw new Error('Error, you must bind a function.');
}
var args = Array.prototype.slice.call(arguments, 1); // for normal call
var bound = function () {
if (this instanceof bound) {
var F = function(){};
F.prototype = target.prototype;
var self = new F;
var self = new F();
var result = target.apply(
self,
args.concat(Array.prototype.slice.call(arguments))
......@@ -344,55 +374,54 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}
// register for AMD module
if (typeof define === 'function' && define.amd) {
if (typeof define === 'function' && typeof define.amd !== 'undefined') {
define("infuse", infuse);
}
// export for node.js
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = infuse;
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
module.exports = infuse;
}
if (typeof exports !== 'undefined') {
exports = infuse;
}
})(this['infuse'] = this['infuse'] || {});
/*
Copyright (c) | 2012 | soma-events | Romuald Quantin | www.soundstep.com
Copyright (c) | 2013 | soma-events | Romuald Quantin | www.soundstep.com
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
(function (soma) {
;(function (soma, undefined) {
"use strict";
'use strict';
soma.events = {};
soma.events.version = "0.5.2";
soma.events.version = '0.5.6';
if (!Function.prototype.bind) {
Function.prototype.bind = function bind(that) {
var target = this;
if (typeof target != "function") {
throw new Error("Error, you must bind a function.");
if (typeof target !== 'function') {
throw new Error('Error, you must bind a function.');
}
var args = Array.prototype.slice.call(arguments, 1); // for normal call
var bound = function () {
if (this instanceof bound) {
var F = function(){};
F.prototype = target.prototype;
var self = new F;
var self = new F();
var result = target.apply(
self,
args.concat(Array.prototype.slice.call(arguments))
......@@ -410,7 +439,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
};
return bound;
};
};
}
soma.Event = function (type, params, bubbles, cancelable) {
var e = soma.Event.createGenericEvent(type, bubbles, cancelable);
......@@ -419,12 +448,14 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}
e.isCloned = false;
e.clone = this.clone.bind(e);
e.isIE9 = this.isIE9;
e.isIE9orIE10 = this.isIE9orIE10;
e.isDefaultPrevented = this.isDefaultPrevented;
if (this.isIE9() || !e.preventDefault || (e.getDefaultPrevented === undefined && e.defaultPrevented === undefined )) {
if (this.isIE9orIE10() || !e.preventDefault || (e.getDefaultPrevented === undefined && e.defaultPrevented === undefined )) {
e.preventDefault = this.preventDefault.bind(e);
}
if (this.isIE9()) e.IE9PreventDefault = false;
if (this.isIE9orIE10()) {
e.IE9or10PreventDefault = false;
}
return e;
};
......@@ -434,22 +465,32 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
e.isCloned = true;
e.clone = this.clone;
e.isDefaultPrevented = this.isDefaultPrevented;
e.isIE9 = this.isIE9;
if (this.isIE9()) e.IE9PreventDefault = this.IE9PreventDefault;
e.isIE9orIE10 = this.isIE9orIE10;
if (this.isIE9orIE10()) {
e.IE9or10PreventDefault = this.IE9or10PreventDefault;
}
return e;
};
soma.Event.prototype.preventDefault = function () {
if (!this.cancelable) return false;
if (!this.cancelable) {
return false;
}
if (this.isIE9orIE10()) {
this.IE9or10PreventDefault = true;
}
else {
this.defaultPrevented = true;
if (this.isIE9()) this.IE9PreventDefault = true;
}
return this;
};
soma.Event.prototype.isDefaultPrevented = function () {
if (!this.cancelable) return false;
if (this.isIE9()) {
return this.IE9PreventDefault;
if (!this.cancelable) {
return false;
}
if (this.isIE9orIE10()) {
return this.IE9or10PreventDefault;
}
if (this.defaultPrevented !== undefined) {
return this.defaultPrevented;
......@@ -462,10 +503,10 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
soma.Event.createGenericEvent = function (type, bubbles, cancelable) {
var event;
bubbles = bubbles !== undefined ? bubbles : true;
if (typeof document === "object" && document.createEvent) {
event = document.createEvent("Event");
if (typeof document === 'object' && document.createEvent) {
event = document.createEvent('Event');
event.initEvent(type, !!bubbles, !!cancelable);
} else if (typeof document === "object" && document.createEventObject) {
} else if (typeof document === 'object' && document.createEventObject) {
event = document.createEventObject();
event.type = type;
event.bubbles = !!bubbles;
......@@ -476,13 +517,15 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
return event;
};
soma.Event.prototype.isIE9 = function() {
if (typeof document !== "object") return false;
return document.body.style.scrollbar3dLightColor !== undefined && document.body.style.opacity !== undefined;
soma.Event.prototype.isIE9orIE10 = function() {
if (typeof document !== 'object') {
return false;
}
return (document.body.style.scrollbar3dLightColor !== undefined && document.body.style.opacity !== undefined) || document.body.style.msTouchAction !== undefined;
};
soma.Event.prototype.toString = function() {
return "[soma.Event]";
return '[soma.Event]';
};
var EventObject = function(type, bubbles, cancelable) {
......@@ -499,8 +542,12 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
};
soma.EventDispatcher.prototype.addEventListener = function(type, listener, priority) {
if (!this.listeners || !type || !listener) return;
if (isNaN(priority)) priority = 0;
if (!this.listeners || !type || !listener) {
return;
}
if (isNaN(priority)) {
priority = 0;
}
for (var i=0; i<this.listeners.length; i++) {
var eventObj = this.listeners[i];
if (eventObj.type === type && eventObj.listener === listener) {
......@@ -511,7 +558,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
};
soma.EventDispatcher.prototype.removeEventListener = function(type, listener) {
if (!this.listeners || !type || !listener) return;
if (!this.listeners || !type || !listener) {
return;
}
var i = this.listeners.length;
while(i-- > 0) {
var eventObj = this.listeners[i];
......@@ -522,7 +571,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
};
soma.EventDispatcher.prototype.hasEventListener = function(type) {
if (!this.listeners || !type) return false;
if (!this.listeners || !type) {
return false;
}
var i = 0;
var l = this.listeners.length;
for (; i < l; ++i) {
......@@ -535,7 +586,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
};
soma.EventDispatcher.prototype.dispatchEvent = function(event) {
if (!this.listeners || !event) throw new Error("Error in EventDispatcher (dispatchEvent), one of the parameters is null or undefined.");
if (!this.listeners || !event) {
throw new Error('Error in EventDispatcher (dispatchEvent), one of the parameters is null or undefined.');
}
var events = [];
var i;
for (i = 0; i < this.listeners.length; i++) {
......@@ -554,7 +607,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
};
soma.EventDispatcher.prototype.dispatch = function(type, params, bubbles, cancelable) {
if (!this.listeners || !type || type === "") throw new Error("Error in EventDispatcher (dispatch), one of the parameters is null or undefined.");
if (!this.listeners || !type || type === '') {
throw new Error('Error in EventDispatcher (dispatch), one of the parameters is null or undefined.');
}
var event = new soma.Event(type, params, bubbles, cancelable);
this.dispatchEvent(event);
return event;
......@@ -565,30 +620,30 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
};
soma.EventDispatcher.prototype.toString = function() {
return "[soma.EventDispatcher]";
return '[soma.EventDispatcher]';
};
// register for AMD module
if (typeof define === 'function' && define.amd) {
if (typeof define === 'function' && typeof define.amd !== 'undefined') {
define("soma-events", soma);
};
}
// export for node.js
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = soma;
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
module.exports = soma;
}
if (typeof exports !== 'undefined') {
exports = soma;
};
}
})(this['soma'] = this['soma'] || {});
;(function (soma, infuse, undefined) {
(function (soma, infuse) {
'use strict';
soma.version = "2.0.0";
soma.version = '2.1.0';
soma.applyProperties = function(target, extension, bindToExtension, list) {
if (Object.prototype.toString.apply(list) === '[object Array]') {
......@@ -651,7 +706,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Chain.prototype = parent.prototype;
Subclass.prototype = new Chain();
// add obj properties
if (obj) soma.applyProperties(Subclass.prototype, obj);
if (obj) {
soma.applyProperties(Subclass.prototype, obj);
}
// point constructor to the Subclass
Subclass.prototype.constructor = Subclass;
// set super class reference
......@@ -685,35 +742,38 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// framework
soma.Application = soma.extend({
constructor: function() {
setup.bind(this)();
this.init();
this.start();
var self = this;
function setup() {
// injector
this.injector = new infuse.Injector(this.dispatcher);
self.injector = new infuse.Injector(self.dispatcher);
// dispatcher
this.dispatcher = new soma.EventDispatcher();
self.dispatcher = new soma.EventDispatcher();
// mapping
this.injector.mapValue('injector', this.injector);
this.injector.mapValue('instance', this);
this.injector.mapValue('dispatcher', this.dispatcher);
self.injector.mapValue('injector', self.injector);
self.injector.mapValue('instance', self);
self.injector.mapValue('dispatcher', self.dispatcher);
// mediator
this.injector.mapClass('mediators', Mediators, true);
this.mediators = this.injector.getValue('mediators');
self.injector.mapClass('mediators', Mediators, true);
self.mediators = self.injector.getValue('mediators');
// commands
this.injector.mapClass('commands', Commands, true);
this.commands = this.injector.getValue('commands');
self.injector.mapClass('commands', Commands, true);
self.commands = self.injector.getValue('commands');
// plugins
for (var i = 0, l = plugins.length; i < l; i++) {
this.createPlugin(plugins[i]);
self.createPlugin(plugins[i]);
}
}
setup.bind(this)();
this.init();
this.start();
},
createPlugin: function() {
if (arguments.length == 0 || !arguments[0]) {
throw new Error("Error creating a plugin, plugin class is missing.");
if (arguments.length === 0 || !arguments[0]) {
throw new Error('Error creating a plugin, plugin class is missing.');
}
var params = infuse.getConstructorParams(arguments[0]);
var args = [arguments[0]];
......@@ -769,11 +829,11 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
this.dispatcher = null;
},
create: function(cl, target) {
if (!cl || typeof cl !== "function") {
throw new Error("Error creating a mediator, the first parameter must be a function.");
if (!cl || typeof cl !== 'function') {
throw new Error('Error creating a mediator, the first parameter must be a function.');
}
if (target === undefined || target === null) {
throw new Error("Error creating a mediator, the second parameter cannot be undefined or null.");
throw new Error('Error creating a mediator, the second parameter cannot be undefined or null.');
}
var targets = [];
var meds = [];
......@@ -785,11 +845,11 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}
for (var i= 0, l=targets.length; i<l; i++) {
var injector = this.injector.createChild();
injector.mapValue("target", targets[i]);
//var mediator = injector.createInstance.apply(this.injector, params);
injector.mapValue('target', targets[i]);
var mediator = injector.createInstance(cl);
// soma.applyProperties(mediator, this.dispatcher, true, ['dispatch', 'dispatchEvent', 'addEventListener', 'removeEventListener', 'hasEventListener']);
if (targets.length === 1) return mediator;
if (targets.length === 1) {
return mediator;
}
meds.push(mediator);
}
return meds;
......@@ -819,19 +879,21 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
getAll: function() {
var copy = {};
for (var cmd in this.list) {
if (this.list.hasOwnProperty(cmd)) {
copy[cmd] = this.list[cmd];
}
}
return copy;
},
add: function(commandName, command) {
if (typeof commandName !== 'string') {
throw new Error("Error adding a command, the first parameter must be a string.");
throw new Error('Error adding a command, the first parameter must be a string.');
}
if (typeof command !== 'function') {
throw new Error("Error adding a command with the name \"" + command + "\", the second parameter must be a function, and must contain an \"execute\" public method.");
throw new Error('Error adding a command with the name "' + command + '", the second parameter must be a function, and must contain an "execute" public method.');
}
if (this.has(commandName)) {
throw new Error("Error adding a command with the name: \"" + commandName + "\", already registered.");
throw new Error('Error adding a command with the name: "' + commandName + '", already registered.');
}
this.list[ commandName ] = command;
this.addInterceptor(commandName);
......@@ -860,16 +922,17 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
if (this.has(commandName)) {
var command = this.injector.createInstance(this.list[commandName]);
if (!command.hasOwnProperty('execute') && command['execute'] === 'function') {
throw new Error("Error in " + this + " Command \"" + command + "\" must contain an execute public method.");
throw new Error('Error in ' + this + ' Command ' + command + ' must contain an execute public method.');
}
// soma.applyProperties(command, this.dispatcher, true, ['dispatch', 'dispatchEvent', 'addEventListener', 'removeEventListener', 'hasEventListener']);
command.execute(event);
}
},
dispose: function() {
for (var cmd in this.list) {
if (this.list.hasOwnProperty(cmd)) {
this.remove(cmd);
}
}
this.boundHandler = undefined;
this.dispatcher = undefined;
this.injector = undefined;
......@@ -893,16 +956,17 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// register for AMD module
if (typeof define === 'function' && define.amd) {
define("soma", soma);
/* globals define:false */
if (typeof define === 'function' && typeof define.amd !== 'undefined') {
define('soma', soma);
}
// export for node.js
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = soma;
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
module.exports = soma;
}
exports = soma;
else {
window.soma = soma;
}
})(this['soma'] = this['soma'] || {}, this['infuse']);
\ No newline at end of file
......@@ -26,7 +26,7 @@
<label data-dblclick="edit(todo)">{{todo.title}}</label>
<button class="destroy" data-click="remove(todo)"></button>
</div>
<input class="edit" value="{{todo.title}}" data-keypress="update(todo)" data-blur="update(todo)">
<input class="edit" value="{{todo.title}}" data-keydown="update(todo)" data-blur="update(todo)">
</li>
</ul>
</section>
......
......@@ -6,12 +6,16 @@
todo.Router = function (dispatcher) {
// create the router (director.js)
var router = new Router().init();
var router = new Router().init().configure({
notfound: render
});
// dispatch a custom event to render the template on a route change
router.on(/.*/, function () {
router.on(/.*/, render);
function render() {
dispatcher.dispatch('render');
});
}
return {
getRoute: function () {
......
......@@ -2,6 +2,7 @@
'use strict';
var ENTER_KEY = 13;
var ESCAPE_KEY = 27;
todo.MainView = function (scope, template, model, router, dispatcher) {
......@@ -51,10 +52,14 @@
scope.edit = function (event, item) {
item.editing = 'editing';
template.render();
template.element.querySelector('.edit').focus();
};
// template function: during edit mode, changes the value of an item after an enter key press
scope.update = function (event, item) {
if (cancelEditing(event, item)) {
return;
}
var value = event.currentTarget.value.trim();
if (event.which === ENTER_KEY || event.type === 'blur') {
if (value) {
......@@ -69,6 +74,19 @@
}
};
// escape has been pressed, revert the value of the input
function cancelEditing(event, item) {
if (event.which === ESCAPE_KEY) {
event.currentTarget.value = item.title;
event.currentTarget.blur();
update();
return true;
}
else {
return false;
}
}
// save the changes to the model and dispatch a custom event to render the templates
function update() {
model.set(items);
......
......@@ -5,7 +5,7 @@
"todomvc-common": "~0.1.6",
"director": "~1.2.0",
"requirejs": "~2.1.5",
"soma.js": "~2.0.0",
"soma-template": "~0.1.8"
"soma.js": "~2.1.0",
"soma-template": "~0.2.8"
}
}
//
// Generated on Sun Dec 16 2012 22:47:05 GMT-0500 (EST) by Nodejitsu, Inc (Using Codesurgeon).
// Version 1.1.9
// Generated on Fri Dec 27 2013 12:02:11 GMT-0500 (EST) by Nodejitsu, Inc (Using Codesurgeon).
// Version 1.2.2
//
(function (exports) {
/*
* browser.js: Browser specific functionality for director.
*
......@@ -201,7 +200,7 @@ Router.prototype.init = function (r) {
this.handler = function(onChangeEvent) {
var newURL = onChangeEvent && onChangeEvent.newURL || window.location.hash;
var url = self.history === true ? self.getPath() : newURL.replace(/.*#/, '');
self.dispatch('on', url);
self.dispatch('on', url.charAt(0) === '/' ? url : '/' + url);
};
listener.init(this.handler, this.history);
......@@ -210,7 +209,7 @@ Router.prototype.init = function (r) {
if (dlocHashEmpty() && r) {
dloc.hash = r;
} else if (!dlocHashEmpty()) {
self.dispatch('on', dloc.hash.replace(/^#/, ''));
self.dispatch('on', '/' + dloc.hash.replace(/^(#\/|#|\/)/, ''));
}
}
else {
......@@ -363,11 +362,16 @@ function regifyString(str, params) {
out += str.substr(0, matches.index) + matches[0];
}
str = out += str.substr(last);
var captures = str.match(/:([^\/]+)/ig), length;
var captures = str.match(/:([^\/]+)/ig), capture, length;
if (captures) {
length = captures.length;
for (var i = 0; i < length; i++) {
str = str.replace(captures[i], paramifyString(captures[i], params));
capture = captures[i];
if (capture.slice(0, 2) === "::") {
str = capture.slice(1);
} else {
str = str.replace(capture, paramifyString(capture, params));
}
}
}
return str;
......@@ -485,20 +489,22 @@ Router.prototype.dispatch = function(method, path, callback) {
Router.prototype.invoke = function(fns, thisArg, callback) {
var self = this;
var apply;
if (this.async) {
_asyncEverySeries(fns, function apply(fn, next) {
apply = function(fn, next) {
if (Array.isArray(fn)) {
return _asyncEverySeries(fn, apply, next);
} else if (typeof fn == "function") {
fn.apply(thisArg, fns.captures.concat(next));
}
}, function() {
};
_asyncEverySeries(fns, apply, function() {
if (callback) {
callback.apply(thisArg, arguments);
}
});
} else {
_every(fns, function apply(fn) {
apply = function(fn) {
if (Array.isArray(fn)) {
return _every(fn, apply);
} else if (typeof fn === "function") {
......@@ -506,7 +512,8 @@ Router.prototype.invoke = function(fns, thisArg, callback) {
} else if (typeof fn === "string" && self.resource) {
self.resource[fn].apply(thisArg, fns.captures || []);
}
});
};
_every(fns, apply);
}
};
......@@ -686,7 +693,7 @@ Router.prototype.mount = function(routes, path) {
function insertOrMount(route, local) {
var rename = route, parts = route.split(self.delimiter), routeType = typeof routes[route], isRoute = parts[0] === "" || !self._methods[parts[0]], event = isRoute ? "on" : rename;
if (isRoute) {
rename = rename.slice((rename.match(new RegExp(self.delimiter)) || [ "" ])[0].length);
rename = rename.slice((rename.match(new RegExp("^" + self.delimiter)) || [ "" ])[0].length);
parts.shift();
}
if (isRoute && routeType === "object" && !Array.isArray(routes[route])) {
......
/** vim: et:ts=4:sw=4:sts=4
* @license RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
* @license RequireJS 2.1.11 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
* Available via the MIT or new BSD license.
* see: http://github.com/jrburke/requirejs for details
*/
......@@ -12,7 +12,7 @@ var requirejs, require, define;
(function (global) {
var req, s, head, baseElement, dataMain, src,
interactiveScript, currentlyAddingScript, mainScript, subPath,
version = '2.1.5',
version = '2.1.11',
commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,
cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,
jsSuffixRegExp = /\.js$/,
......@@ -22,7 +22,7 @@ var requirejs, require, define;
hasOwn = op.hasOwnProperty,
ap = Array.prototype,
apsp = ap.splice,
isBrowser = !!(typeof window !== 'undefined' && navigator && document),
isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document),
isWebWorker = !isBrowser && typeof importScripts !== 'undefined',
//PS3 indicates loaded and complete, but need to wait for complete
//specifically. Sequence is 'loading', 'loaded', execution,
......@@ -108,7 +108,10 @@ var requirejs, require, define;
if (source) {
eachProp(source, function (value, prop) {
if (force || !hasProp(target, prop)) {
if (deepStringMixin && typeof value !== 'string') {
if (deepStringMixin && typeof value === 'object' && value &&
!isArray(value) && !isFunction(value) &&
!(value instanceof RegExp)) {
if (!target[prop]) {
target[prop] = {};
}
......@@ -134,7 +137,11 @@ var requirejs, require, define;
return document.getElementsByTagName('script');
}
//Allow getting a global that expressed in
function defaultOnError(err) {
throw err;
}
//Allow getting a global that is expressed in
//dot notation, like 'a.b.c'.
function getGlobal(value) {
if (!value) {
......@@ -197,6 +204,7 @@ var requirejs, require, define;
waitSeconds: 7,
baseUrl: './',
paths: {},
bundles: {},
pkgs: {},
shim: {},
config: {}
......@@ -210,6 +218,7 @@ var requirejs, require, define;
defQueue = [],
defined = {},
urlFetched = {},
bundlesMap = {},
requireCounter = 1,
unnormalizedCounter = 1;
......@@ -223,8 +232,8 @@ var requirejs, require, define;
* @param {Array} ary the array of path segments.
*/
function trimDots(ary) {
var i, part;
for (i = 0; ary[i]; i += 1) {
var i, part, length = ary.length;
for (i = 0; i < length; i++) {
part = ary[i];
if (part === '.') {
ary.splice(i, 1);
......@@ -257,7 +266,7 @@ var requirejs, require, define;
* @returns {String} normalized name
*/
function normalize(name, baseName, applyMap) {
var pkgName, pkgConfig, mapValue, nameParts, i, j, nameSegment,
var pkgMain, mapValue, nameParts, i, j, nameSegment, lastIndex,
foundMap, foundI, foundStarMap, starI,
baseParts = baseName && baseName.split('/'),
normalizedBaseParts = baseParts,
......@@ -270,29 +279,26 @@ var requirejs, require, define;
//otherwise, assume it is a top-level require that will
//be relative to baseUrl in the end.
if (baseName) {
if (getOwn(config.pkgs, baseName)) {
//If the baseName is a package name, then just treat it as one
//name to concat the name with.
normalizedBaseParts = baseParts = [baseName];
} else {
//Convert baseName to array, and lop off the last part,
//so that . matches that 'directory' and not name of the baseName's
//module. For instance, baseName of 'one/two/three', maps to
//'one/two/three.js', but we want the directory, 'one/two' for
//this normalization.
normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
name = name.split('/');
lastIndex = name.length - 1;
// If wanting node ID compatibility, strip .js from end
// of IDs. Have to do this here, and not in nameToUrl
// because node allows either .js or non .js to map
// to same file.
if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
}
name = normalizedBaseParts.concat(name.split('/'));
name = normalizedBaseParts.concat(name);
trimDots(name);
//Some use of packages may use a . path to reference the
//'main' module name, so normalize for that.
pkgConfig = getOwn(config.pkgs, (pkgName = name[0]));
name = name.join('/');
if (pkgConfig && name === pkgName + '/' + pkgConfig.main) {
name = pkgName;
}
} else if (name.indexOf('./') === 0) {
// No baseName, so this is ID is resolved relative
// to baseUrl, pull off the leading dot.
......@@ -304,7 +310,7 @@ var requirejs, require, define;
if (applyMap && map && (baseParts || starMap)) {
nameParts = name.split('/');
for (i = nameParts.length; i > 0; i -= 1) {
outerLoop: for (i = nameParts.length; i > 0; i -= 1) {
nameSegment = nameParts.slice(0, i).join('/');
if (baseParts) {
......@@ -321,16 +327,12 @@ var requirejs, require, define;
//Match, update name to the new value.
foundMap = mapValue;
foundI = i;
break;
break outerLoop;
}
}
}
}
if (foundMap) {
break;
}
//Check for a star map match, but just hold on to it,
//if there is a shorter segment match later in a matching
//config, then favor over this star map.
......@@ -351,7 +353,11 @@ var requirejs, require, define;
}
}
return name;
// If the name points to a package's name, use
// the package main instead.
pkgMain = getOwn(config.pkgs, name);
return pkgMain ? pkgMain : name;
}
function removeScript(name) {
......@@ -369,7 +375,6 @@ var requirejs, require, define;
function hasPathFallback(id) {
var pathConfig = getOwn(config.paths, id);
if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) {
removeScript(id);
//Pop off the first array value, since it failed, and
//retry
pathConfig.shift();
......@@ -500,7 +505,12 @@ var requirejs, require, define;
fn(defined[id]);
}
} else {
getModule(depMap).on(name, fn);
mod = getModule(depMap);
if (mod.error && name === 'error') {
fn(mod.error);
} else {
mod.on(name, fn);
}
}
}
......@@ -540,7 +550,7 @@ var requirejs, require, define;
//local var ref to defQueue, so cannot just reassign the one
//on context.
apsp.apply(defQueue,
[defQueue.length - 1, 0].concat(globalDefQueue));
[defQueue.length, 0].concat(globalDefQueue));
globalDefQueue = [];
}
}
......@@ -557,7 +567,7 @@ var requirejs, require, define;
mod.usingExports = true;
if (mod.map.isDefine) {
if (mod.exports) {
return mod.exports;
return (defined[mod.map.id] = mod.exports);
} else {
return (mod.exports = defined[mod.map.id] = {});
}
......@@ -571,9 +581,9 @@ var requirejs, require, define;
id: mod.map.id,
uri: mod.map.url,
config: function () {
return (config.config && getOwn(config.config, mod.map.id)) || {};
return getOwn(config.config, mod.map.id) || {};
},
exports: defined[mod.map.id]
exports: mod.exports || (mod.exports = {})
});
}
}
......@@ -614,7 +624,7 @@ var requirejs, require, define;
}
function checkLoaded() {
var map, modId, err, usingPathFallback,
var err, usingPathFallback,
waitInterval = config.waitSeconds * 1000,
//It is possible to disable the wait interval by using waitSeconds of 0.
expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(),
......@@ -632,7 +642,7 @@ var requirejs, require, define;
//Figure out the state of all the modules.
eachProp(enabledRegistry, function (mod) {
map = mod.map;
var map = mod.map,
modId = map.id;
//Skip things that are not enabled or in error state.
......@@ -840,8 +850,13 @@ var requirejs, require, define;
if (this.depCount < 1 && !this.defined) {
if (isFunction(factory)) {
//If there is an error listener, favor passing
//to that instead of throwing an error.
if (this.events.error) {
//to that instead of throwing an error. However,
//only do it for define()'d modules. require
//errbacks should not be called for failures in
//their callbacks (#699). However if a global
//onError is set, use that.
if ((this.events.error && this.map.isDefine) ||
req.onError !== defaultOnError) {
try {
exports = context.execCb(id, factory, depExports, exports);
} catch (e) {
......@@ -851,17 +866,14 @@ var requirejs, require, define;
exports = context.execCb(id, factory, depExports, exports);
}
if (this.map.isDefine) {
//If setting exports via 'module' is in play,
//favor that over return value and exports. After that,
//favor a non-undefined return value over exports use.
// Favor return value over exports. If node/cjs in play,
// then will not have a return value anyway. Favor
// module.exports assignment over exports object.
if (this.map.isDefine && exports === undefined) {
cjsModule = this.module;
if (cjsModule &&
cjsModule.exports !== undefined &&
//Make sure it is not already the exports value
cjsModule.exports !== this.exports) {
if (cjsModule) {
exports = cjsModule.exports;
} else if (exports === undefined && this.usingExports) {
} else if (this.usingExports) {
//exports already set the defined value.
exports = this.exports;
}
......@@ -869,8 +881,8 @@ var requirejs, require, define;
if (err) {
err.requireMap = this.map;
err.requireModules = [this.map.id];
err.requireType = 'define';
err.requireModules = this.map.isDefine ? [this.map.id] : null;
err.requireType = this.map.isDefine ? 'define' : 'require';
return onError((this.error = err));
}
......@@ -921,6 +933,7 @@ var requirejs, require, define;
on(pluginMap, 'defined', bind(this, function (plugin) {
var load, normalizedMap, normalizedMod,
bundleId = getOwn(bundlesMap, this.map.id),
name = this.map.name,
parentName = this.map.parentMap ? this.map.parentMap.name : null,
localRequire = context.makeRequire(map.parentMap, {
......@@ -966,6 +979,14 @@ var requirejs, require, define;
return;
}
//If a paths config, then just load that file instead to
//resolve the plugin, as it is built into that paths layer.
if (bundleId) {
this.map.url = context.nameToUrl(bundleId);
this.load();
return;
}
load = bind(this, function (value) {
this.init([], function () { return value; }, null, {
enabled: true
......@@ -1093,7 +1114,7 @@ var requirejs, require, define;
}));
if (this.errback) {
on(depMap, 'error', this.errback);
on(depMap, 'error', bind(this, this.errback));
}
}
......@@ -1230,31 +1251,38 @@ var requirejs, require, define;
}
}
//Save off the paths and packages since they require special processing,
//Save off the paths since they require special processing,
//they are additive.
var pkgs = config.pkgs,
shim = config.shim,
var shim = config.shim,
objs = {
paths: true,
bundles: true,
config: true,
map: true
};
eachProp(cfg, function (value, prop) {
if (objs[prop]) {
if (prop === 'map') {
if (!config.map) {
config.map = {};
if (!config[prop]) {
config[prop] = {};
}
mixin(config[prop], value, true, true);
} else {
mixin(config[prop], value, true);
}
} else {
config[prop] = value;
}
});
//Reverse map the bundles
if (cfg.bundles) {
eachProp(cfg.bundles, function (value, prop) {
each(value, function (v) {
if (v !== prop) {
bundlesMap[v] = prop;
}
});
});
}
//Merge shim
if (cfg.shim) {
eachProp(cfg.shim, function (value, id) {
......@@ -1275,29 +1303,25 @@ var requirejs, require, define;
//Adjust packages if necessary.
if (cfg.packages) {
each(cfg.packages, function (pkgObj) {
var location;
var location, name;
pkgObj = typeof pkgObj === 'string' ? { name: pkgObj } : pkgObj;
name = pkgObj.name;
location = pkgObj.location;
if (location) {
config.paths[name] = pkgObj.location;
}
//Create a brand new object on pkgs, since currentPackages can
//be passed in again, and config.pkgs is the internal transformed
//state for all package configs.
pkgs[pkgObj.name] = {
name: pkgObj.name,
location: location || pkgObj.name,
//Save pointer to main module ID for pkg name.
//Remove leading dot in main, so main paths are normalized,
//and remove any trailing .js, since different package
//envs have different conventions: some use a module name,
//some use a file name.
main: (pkgObj.main || 'main')
config.pkgs[name] = pkgObj.name + '/' + (pkgObj.main || 'main')
.replace(currDirRegExp, '')
.replace(jsSuffixRegExp, '')
};
.replace(jsSuffixRegExp, '');
});
//Done with modifications, assing packages back to context config
config.pkgs = pkgs;
}
//If there are any "waiting to execute" modules in the registry,
......@@ -1444,10 +1468,21 @@ var requirejs, require, define;
var map = makeModuleMap(id, relMap, true),
mod = getOwn(registry, id);
removeScript(id);
delete defined[id];
delete urlFetched[map.url];
delete undefEvents[id];
//Clean queued defines too. Go backwards
//in array so that the splices do not
//mess up the iteration.
eachReverse(defQueue, function(args, i) {
if(args[0] === id) {
defQueue.splice(i, 1);
}
});
if (mod) {
//Hold on to listeners in case the
//module will be attempted to be reloaded
......@@ -1467,7 +1502,7 @@ var requirejs, require, define;
/**
* Called to enable a module if it is still in the registry
* awaiting enablement. A second arg, parent, the parent module,
* is passed in for context, when this method is overriden by
* is passed in for context, when this method is overridden by
* the optimizer. Not shown here to keep code compact.
*/
enable: function (depMap) {
......@@ -1541,8 +1576,19 @@ var requirejs, require, define;
* internal API, not a public one. Use toUrl for the public API.
*/
nameToUrl: function (moduleName, ext, skipExt) {
var paths, pkgs, pkg, pkgPath, syms, i, parentModule, url,
parentPath;
var paths, syms, i, parentModule, url,
parentPath, bundleId,
pkgMain = getOwn(config.pkgs, moduleName);
if (pkgMain) {
moduleName = pkgMain;
}
bundleId = getOwn(bundlesMap, moduleName);
if (bundleId) {
return context.nameToUrl(bundleId, ext, skipExt);
}
//If a colon is in the URL, it indicates a protocol is used and it is just
//an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?)
......@@ -1556,7 +1602,6 @@ var requirejs, require, define;
} else {
//A module that needs to be converted to a path.
paths = config.paths;
pkgs = config.pkgs;
syms = moduleName.split('/');
//For each module name segment, see if there is a path
......@@ -1564,7 +1609,7 @@ var requirejs, require, define;
//and work up from it.
for (i = syms.length; i > 0; i -= 1) {
parentModule = syms.slice(0, i).join('/');
pkg = getOwn(pkgs, parentModule);
parentPath = getOwn(paths, parentModule);
if (parentPath) {
//If an array, it means there are a few choices,
......@@ -1574,22 +1619,12 @@ var requirejs, require, define;
}
syms.splice(0, i, parentPath);
break;
} else if (pkg) {
//If module name is just the package name, then looking
//for the main module.
if (moduleName === pkg.name) {
pkgPath = pkg.location + '/' + pkg.main;
} else {
pkgPath = pkg.location;
}
syms.splice(0, i, pkgPath);
break;
}
}
//Join the path parts together, then figure out if baseUrl is needed.
url = syms.join('/');
url += (ext || (/\?/.test(url) || skipExt ? '' : '.js'));
url += (ext || (/^data\:|\?/.test(url) || skipExt ? '' : '.js'));
url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url;
}
......@@ -1605,7 +1640,7 @@ var requirejs, require, define;
},
/**
* Executes a module callack function. Broken out as a separate function
* Executes a module callback function. Broken out as a separate function
* solely to allow the build system to sequence the files in the built
* layer in the right sequence.
*
......@@ -1643,7 +1678,7 @@ var requirejs, require, define;
onScriptError: function (evt) {
var data = getScriptData(evt);
if (!hasPathFallback(data.id)) {
return onError(makeError('scripterror', 'Script error', evt, [data.id]));
return onError(makeError('scripterror', 'Script error for: ' + data.id, evt, [data.id]));
}
}
};
......@@ -1772,8 +1807,19 @@ var requirejs, require, define;
* function. Intercept/override it if you want custom error handling.
* @param {Error} err the error object.
*/
req.onError = function (err) {
throw err;
req.onError = defaultOnError;
/**
* Creates the node for the load command. Only used in browser envs.
*/
req.createNode = function (config, moduleName, url) {
var node = config.xhtml ?
document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') :
document.createElement('script');
node.type = config.scriptType || 'text/javascript';
node.charset = 'utf-8';
node.async = true;
return node;
};
/**
......@@ -1790,12 +1836,7 @@ var requirejs, require, define;
node;
if (isBrowser) {
//In the browser so use a script tag
node = config.xhtml ?
document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') :
document.createElement('script');
node.type = config.scriptType || 'text/javascript';
node.charset = 'utf-8';
node.async = true;
node = req.createNode(config, moduleName, url);
node.setAttribute('data-requirecontext', context.contextName);
node.setAttribute('data-requiremodule', moduleName);
......@@ -1892,7 +1933,7 @@ var requirejs, require, define;
}
//Look for a data-main script attribute, which could also adjust the baseUrl.
if (isBrowser) {
if (isBrowser && !cfg.skipDataMain) {
//Figure out baseUrl. Get it from the script tag with require.js in it.
eachReverse(scripts(), function (script) {
//Set the 'head' where we can append children by
......@@ -1906,24 +1947,31 @@ var requirejs, require, define;
//baseUrl, if it is not already set.
dataMain = script.getAttribute('data-main');
if (dataMain) {
//Preserve dataMain in case it is a path (i.e. contains '?')
mainScript = dataMain;
//Set final baseUrl if there is not already an explicit one.
if (!cfg.baseUrl) {
//Pull off the directory of data-main for use as the
//baseUrl.
src = dataMain.split('/');
src = mainScript.split('/');
mainScript = src.pop();
subPath = src.length ? src.join('/') + '/' : './';
cfg.baseUrl = subPath;
dataMain = mainScript;
}
//Strip off any trailing .js since dataMain is now
//Strip off any trailing .js since mainScript is now
//like a module name.
dataMain = dataMain.replace(jsSuffixRegExp, '');
mainScript = mainScript.replace(jsSuffixRegExp, '');
//If mainScript is still a path, fall back to dataMain
if (req.jsExtRegExp.test(mainScript)) {
mainScript = dataMain;
}
//Put the data-main script in the files to load.
cfg.deps = cfg.deps ? cfg.deps.concat(dataMain) : [dataMain];
cfg.deps = cfg.deps ? cfg.deps.concat(mainScript) : [mainScript];
return true;
}
......@@ -1951,12 +1999,13 @@ var requirejs, require, define;
//This module may not have dependencies
if (!isArray(deps)) {
callback = deps;
deps = [];
deps = null;
}
//If no name, and callback is a function, then figure out if it a
//CommonJS thing with dependencies.
if (!deps.length && isFunction(callback)) {
if (!deps && isFunction(callback)) {
deps = [];
//Remove comments from the callback string,
//look for require calls, and pull them into the dependencies,
//but only if there are function args.
......
;(function (soma, undefined) {
(function (soma) {
'use strict';
soma.template = soma.template || {};
soma.template.version = "0.1.8";
soma.template = soma.template || {};
soma.template.version = '0.2.8';
var errors = soma.template.errors = {
TEMPLATE_STRING_NO_ELEMENT: "Error in soma.template, a string template requirement a second parameter: an element target - soma.template.create('string', element)",
TEMPLATE_NO_PARAM: "Error in soma.template, a template requires at least 1 parameter - soma.template.create(element)"
};
soma.template.errors = {
TEMPLATE_STRING_NO_ELEMENT: 'Error in soma.template, a string template requirement a second parameter: an element target - soma.template.create(\'string\', element)',
TEMPLATE_NO_PARAM: 'Error in soma.template, a template requires at least 1 parameter - soma.template.create(element)'
};
var tokenStart = '{{';
var tokenEnd = '}}';
var helpersObject = {};
var helpersScopeObject = {};
var tokenStart = '{{';
var tokenEnd = '}}';
var helpersObject = {};
var helpersScopeObject = {};
var settings = soma.template.settings = soma.template.settings || {};
var settings = soma.template.settings = soma.template.settings || {};
settings.autocreate = true;
settings.autocreate = true;
var tokens = settings.tokens = {
var tokens = settings.tokens = {
start: function(value) {
if (isDefined(value) && value !== '') {
tokenStart = escapeRegExp(value);
......@@ -34,41 +34,45 @@ var tokens = settings.tokens = {
}
return tokenEnd;
}
};
var attributes = settings.attributes = {
skip: "data-skip",
repeat: "data-repeat",
src: "data-src",
href: "data-href",
show: "data-show",
hide: "data-hide",
cloak: "data-cloak",
checked: "data-checked",
disabled: "data-disabled",
multiple: "data-multiple",
readonly: "data-readonly",
selected: "data-selected",
template: "data-template",
html: "data-html"
};
var vars = settings.vars = {
index: "$index",
key: "$key"
};
var events = settings.events = {};
settings.eventsPrefix = 'data-';
var eventsString = 'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup focus blur change select selectstart scroll copy cut paste mousewheel keypress error contextmenu input textinput drag dragenter dragleave dragover dragend dragstart dragover drop load submit reset search resize beforepaste beforecut beforecopy';
eventsString += ' touchstart touchend touchmove touchenter touchleave touchcancel gesturestart gesturechange gestureend';
var eventsArray = eventsString.split(' ');
var i = -1, l = eventsArray.length;
while(++i < l) {
};
var attributes = settings.attributes = {
skip: 'data-skip',
repeat: 'data-repeat',
src: 'data-src',
href: 'data-href',
show: 'data-show',
hide: 'data-hide',
cloak: 'data-cloak',
checked: 'data-checked',
disabled: 'data-disabled',
multiple: 'data-multiple',
readonly: 'data-readonly',
selected: 'data-selected',
template: 'data-template',
html: 'data-html'
};
var vars = settings.vars = {
index: '$index',
key: '$key',
element: '$element',
parentElement: '$parentElement',
attribute: '$attribute',
scope: '$scope'
};
var events = settings.events = {};
settings.eventsPrefix = 'data-';
var eventsString = 'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup focus blur change select selectstart scroll copy cut paste mousewheel keypress error contextmenu input textinput drag dragenter dragleave dragover dragend dragstart dragover drop load submit reset search resize beforepaste beforecut beforecopy';
eventsString += ' touchstart touchend touchmove touchenter touchleave touchcancel gesturestart gesturechange gestureend';
var eventsArray = eventsString.split(' ');
var i = -1, l = eventsArray.length;
while(++i < l) {
events[settings.eventsPrefix + eventsArray[i]] = eventsArray[i];
}
}
var regex = {
var regex = {
sequence: null,
token: null,
expression: null,
......@@ -81,117 +85,138 @@ var regex = {
content: /[^.|^\s]/gm,
depth: /..\//g,
string: /^(\"|\')(.*)(\"|\')$/
};
var ie = (function(){
if (typeof document !== 'object') return undefined;
var undef,
v = 3,
div = document.createElement('div'),
all = div.getElementsByTagName('i');
while (
div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->', all[0]
);
return v > 4 ? v : undef;
}());
function isArray(value) {
};
var ie = (function(){
if (typeof document !== 'object') {
return undefined;
}
var v = 3,
stop = false,
div = document.createElement('div');
while (!stop) {
div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->';
if (!div.getElementsByTagName('i')[0]) {
stop = true;
}
}
return v > 4 ? v : undefined;
}());
function isArray(value) {
return Object.prototype.toString.apply(value) === '[object Array]';
};
function isObject(value) {
}
function isObject(value) {
return typeof value === 'object';
}
function isString(value) {
}
function isString(value) {
return typeof value === 'string';
}
function isElement(value) {
}
function isElement(value) {
return value ? value.nodeType > 0 : false;
};
function isTextNode(el) {
}
function isTextNode(el) {
return el && el.nodeType && el.nodeType === 3;
}
function isFunction(value) {
}
function isFunction(value) {
return value && typeof value === 'function';
}
function isDefined(value) {
}
function isDefined(value) {
return value !== null && value !== undefined;
}
function isAttributeDefined(value) {
return (value === "" || value === true || value === "true" || !isDefined(value));
}
function isExpression(value) {
}
function normalizeBoolean(value) {
if (!isDefined(value)) {
return false;
}
if (value === 'true' || value === '1' || value === true || value === 1) {
return true;
}
if (value === 'false' || value === '0' || value === false || value === 0 || (isString(value) && hasInterpolation(value))) {
return false;
}
return !!value;
}
function isExpression(value) {
return value && isFunction(value.toString) && value.toString() === '[object Expression]';
}
function isNode(value) {
return value && isFunction(value.toString) && value.toString() === '[object Node]';
}
function isExpFunction(value) {
if (!isString(value)) return false;
}
function isExpFunction(value) {
if (!isString(value)) {
return false;
}
return !!value.match(regex.func);
}
function childNodeIsTemplate(node) {
}
function childNodeIsTemplate(node) {
return node && node.parent && templates.get(node.element);
}
function escapeRegExp(str) {
return str.replace(regex.escape, "\\$&");
}
function setRegEX(nonEscapedValue, isStartToken) {
}
function escapeRegExp(str) {
return str.replace(regex.escape, '\\$&');
}
function setRegEX(nonEscapedValue, isStartToken) {
// sequence: \{\{.+?\}\}|[^{]+|\{(?!\{)[^{]*
var unescapedCurrentStartToken = tokens.start().replace(/\\/g, '');
var endSequence = "";
var endSequence = '';
var ts = isStartToken ? nonEscapedValue : unescapedCurrentStartToken;
if (ts.length > 1) {
endSequence = "|\\" + ts.substr(0, 1) + "(?!\\" + ts.substr(1, 1) + ")[^" + ts.substr(0, 1) + "]*";
endSequence = '|\\' + ts.substr(0, 1) + '(?!\\' + ts.substr(1, 1) + ')[^' + ts.substr(0, 1) + ']*';
}
regex.sequence = new RegExp(tokens.start() + ".+?" + tokens.end() + "|[^" + tokens.start() + "]+" + endSequence, "g");
regex.token = new RegExp(tokens.start() + ".*?" + tokens.end(), "g");
regex.expression = new RegExp(tokens.start() + "|" + tokens.end(), "gm");
}
function trim(value) {
regex.sequence = new RegExp(tokens.start() + '.+?' + tokens.end() + '|[^' + tokens.start() + ']+' + endSequence, 'g');
regex.token = new RegExp(tokens.start() + '.*?' + tokens.end(), 'g');
regex.expression = new RegExp(tokens.start() + '|' + tokens.end(), 'gm');
}
function trim(value) {
return value.replace(regex.trim, '');
}
function trimQuotes(value) {
}
function trimQuotes(value) {
if (regex.string.test(value)) {
return value.substr(1, value.length-2);
}
return value;
}
function trimArray(value) {
if (value[0] === "") value.shift();
if (value[value.length-1] === "") value.pop();
}
function trimArray(value) {
if (value[0] === '') {
value.shift();
}
if (value[value.length-1] === '') {
value.pop();
}
return value;
}
function trimTokens(value) {
}
function trimTokens(value) {
return value.replace(regex.expression, '');
}
function trimScopeDepth(value) {
}
function trimScopeDepth(value) {
return value.replace(regex.depth, '');
}
function insertBefore(referenceNode, newNode) {
if (!referenceNode.parentNode) return;
}
function insertBefore(referenceNode, newNode) {
if (!referenceNode.parentNode) {
return;
}
referenceNode.parentNode.insertBefore(newNode, referenceNode);
}
function insertAfter(referenceNode, newNode) {
if (!referenceNode.parentNode) return;
}
function insertAfter(referenceNode, newNode) {
if (!referenceNode.parentNode) {
return;
}
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}
function removeClass(elm, className) {
if (document.documentElement.classList) {
removeClass = function (elm, className) {
elm.classList.remove(className);
}
function removeClass(elm, className) {
var rmc;
if (typeof document === 'object' && document.documentElement.classList) {
rmc = function (elm, className) {
elm.classList.remove(className);
};
} else {
removeClass = function (elm, className) {
rmc = function (elm, className) {
if (!elm || !elm.className) {
return false;
}
var reg = new RegExp("(^|\\s)" + className + "(\\s|$)", "g");
elm.className = elm.className.replace(reg, "$2");
var reg = new RegExp('(^|\\s)' + className + '(\\s|$)', 'g');
elm.className = elm.className.replace(reg, '$2');
};
}
rmc(elm, className);
}
removeClass(elm, className);
}
// jquery contains
var contains = typeof document !== 'object' ? function(){} : document.documentElement.contains ?
// jquery contains
var contains = typeof document !== 'object' ? function(){} : document.documentElement.contains ?
function( a, b ) {
var adown = a.nodeType === 9 ? a.documentElement : a,
bup = b && b.parentNode;
......@@ -210,66 +235,79 @@ var contains = typeof document !== 'object' ? function(){} : document.documentEl
return false;
};
function HashMap() {
function HashMap(id) {
var items = {};
var id = 1;
var count = 0;
//var uuid = function(a,b){for(b=a='';a++<36;b+=a*51&52?(a^15?8^Math.random()*(a^20?16:4):4).toString(16):'-');return b;}
function uuid() { return ++id; };
function uuid() { return ++count + id; }
function getKey(target) {
if (!target) return;
if (typeof target !== 'object') return target;
if (!target) {
return;
}
if (typeof target !== 'object') {
return target;
}
var result;
try {
// IE 7-8 needs a try catch, seems like I can't add a property on text nodes
result = target.hashkey ? target.hashkey : target.hashkey = uuid();
} catch(err){};
result = target[id] ? target[id] : target[id] = uuid();
} catch(err){}
return result;
}
this.remove = function(key) {
delete items[getKey(key)];
}
};
this.get = function(key) {
return items[getKey(key)];
}
};
this.put = function(key, value) {
items[getKey(key)] = value;
}
};
this.has = function(key) {
return typeof items[getKey(key)] !== 'undefined';
}
};
this.getData = function() {
return items;
}
};
this.dispose = function() {
for (var key in items) {
if (items.hasOwnProperty(key)) {
delete items[key];
}
}
this.length = 0;
};
}
}
function getRepeaterData(repeaterValue, scope) {
function getRepeaterData(repeaterValue, scope) {
var parts = repeaterValue.match(regex.repeat);
if (!parts) return;
if (!parts) {
return;
}
var source = parts[2];
var exp = new Expression(source);
return exp.getValue(scope);
}
}
function updateScopeWithRepeaterData(repeaterValue, scope, data) {
function updateScopeWithRepeaterData(repeaterValue, scope, data) {
var parts = repeaterValue.match(regex.repeat);
if (!parts) return;
if (!parts) {
return;
}
var name = parts[1];
scope[name] = data;
}
function getWatcherValue(exp, newValue) {
}
function getWatcherValue(exp, newValue) {
var node = exp.node || exp.attribute.node;
var watchers = node.template.watchers;
var nodeTarget = node.element;
if (!watchers) return newValue;
if (!watchers) {
return newValue;
}
var watcherNode = watchers.get(nodeTarget);
if (!watcherNode && isTextNode(node.element) && node.parent) watcherNode = watchers.get(node.parent.element);
if (!watcherNode && isTextNode(node.element) && node.parent) {
watcherNode = watchers.get(node.parent.element);
}
var watcher = watcherNode ? watcherNode : watchers.get(exp.pattern);
if (isFunction(watcher)) {
var watcherValue = watcher(exp.value, newValue, exp.pattern, node.scope, node, exp.attribute);
......@@ -278,9 +316,9 @@ function getWatcherValue(exp, newValue) {
}
}
return newValue;
}
}
function getScopeFromPattern(scope, pattern) {
function getScopeFromPattern(scope, pattern) {
var depth = getScopeDepth(pattern);
var scopeTarget = scope;
while (depth > 0) {
......@@ -288,14 +326,27 @@ function getScopeFromPattern(scope, pattern) {
depth--;
}
return scopeTarget;
}
}
function getValueFromPattern(scope, pattern) {
function getValueFromPattern(scope, pattern, context) {
var exp = new Expression(pattern);
return getValue(scope, exp.pattern, exp.path, exp.params);
}
return getValue(scope, exp.pattern, exp.path, exp.params, undefined, undefined, undefined, context);
}
function getValue(scope, pattern, pathString, params, getFunction, getParams, paramsFound) {
function getValue(scope, pattern, pathString, params, getFunction, getParams, paramsFound, context) {
// context
if (pattern === vars.element) {
return context[vars.element];
}
if (pattern === vars.parentElement) {
return context[vars.parentElement];
}
if (pattern === vars.attribute) {
return context[vars.attribute];
}
if (pattern === vars.scope) {
return context[vars.scope];
}
// string
if (regex.string.test(pattern)) {
return trimQuotes(pattern);
......@@ -304,29 +355,39 @@ function getValue(scope, pattern, pathString, params, getFunction, getParams, pa
var paramsValues = [];
if (!paramsFound && params) {
for (var j = 0, jl = params.length; j < jl; j++) {
paramsValues.push(getValueFromPattern(scope, params[j]));
paramsValues.push(getValueFromPattern(scope, params[j], context));
}
}
else {
paramsValues = paramsFound;
}
if (getParams) {
return paramsValues;
}
else paramsValues = paramsFound;
if (getParams) return paramsValues;
// find scope
var scopeTarget = getScopeFromPattern(scope, pattern);
// remove parent string
pattern = pattern.replace(/..\//g, '');
pathString = pathString.replace(/..\//g, '');
if (!scopeTarget) return undefined;
if (!scopeTarget) {
return undefined;
}
// search path
var path = scopeTarget;
var pathParts = pathString.split(/\.|\[|\]/g);
if (pathParts.length > 0) {
for (var i = 0, l = pathParts.length; i < l; i++) {
if (pathParts[i] !== "") {
if (pathParts[i] !== '') {
path = path[pathParts[i]];
}
if (!isDefined(path)) {
// no path, search in parent
if (scopeTarget._parent) return getValue(scopeTarget._parent, pattern, pathString, params, getFunction, getParams, paramsValues);
else return undefined;
if (scopeTarget._parent) {
return getValue(scopeTarget._parent, pattern, pathString, params, getFunction, getParams, paramsValues);
}
else {
return undefined;
}
}
}
}
......@@ -335,46 +396,42 @@ function getValue(scope, pattern, pathString, params, getFunction, getParams, pa
return path;
}
else {
if (getFunction) return path;
else return path.apply(null, paramsValues);
if (getFunction) {
return path;
}
else {
return path.apply(null, paramsValues);
}
}
return undefined;
}
}
function getExpressionPath(value) {
function getExpressionPath(value) {
var val = value.split('(')[0];
val = trimScopeDepth(val);
return val;
}
}
function getParamsFromString(value) {
function getParamsFromString(value) {
return trimArray(value.split(regex.params));
}
}
function getScopeDepth(value) {
function getScopeDepth(value) {
var val = value.split('(')[0];
var matches = val.match(regex.depth);
return !matches ? 0 : matches.length;
}
}
function getNodeFromElement(element, scope, isRepeaterDescendant) {
var node = new Node(element, scope);
node.previousSibling = element.previousSibling;
node.nextSibling = element.nextSibling;
var attributes = [];
var eventsArray = [];
for (var attr, name, value, attrs = element.attributes, j = 0, jj = attrs && attrs.length; j < jj; j++) {
attr = attrs[j];
if (attr.specified) {
name = attr.name;
value = attr.value;
function addAttribute(node, name, value) {
var attr;
node.attributes = node.attributes || [];
if (name === settings.attributes.skip) {
node.skip = (value === "" || value === "true");
node.skip = normalizeBoolean(value);
}
if (name === settings.attributes.html) {
node.html = (value === "" || value === "true");
node.html = normalizeBoolean(value);
}
if (name === settings.attributes.repeat && !isRepeaterDescendant) {
if (name === settings.attributes.repeat && !node.isRepeaterDescendant) {
node.repeater = value;
}
if (
......@@ -392,59 +449,88 @@ function getNodeFromElement(element, scope, isRepeaterDescendant) {
name === settings.attributes.selected ||
value.indexOf(settings.attributes.cloak) !== -1
) {
attributes.push(new Attribute(name, value, node));
attr = new Attribute(name, value, node);
node.attributes.push(attr);
}
if (events[name]) {
attr = new Attribute(name, value, node);
node.attributes.push(attr);
}
return attr;
}
function getNodeFromElement(element, scope) {
var node = new Node(element, scope);
node.previousSibling = element.previousSibling;
node.nextSibling = element.nextSibling;
var eventsArray = [];
for (var attr, attrs = element.attributes, j = 0, jj = attrs && attrs.length; j < jj; j++) {
attr = attrs[j];
if (attr.specified || attr.name === 'value') {
var newAttr = addAttribute(node, attr.name, attr.value);
if (events[attr.name]) {
if (events[attr.name] && !node.isRepeaterChild) {
eventsArray.push({name:events[attr.name], value:attr.value, attr: newAttr});
}
if (events[name] && !isRepeaterDescendant) {
eventsArray.push({name:events[name], value:value});
attributes.push(new Attribute(name, value, node));
}
}
}
node.attributes = attributes;
for (var i = 0, l = eventsArray.length; i < l; i++) {
node.addEvent(eventsArray[i].name, eventsArray[i].value);
for (var a=0, b=eventsArray.length; a<b; a++) {
node.addEvent(eventsArray[a].name, eventsArray[a].value, eventsArray[a].attr);
}
return node;
}
}
function hasInterpolation(value) {
function hasInterpolation(value) {
var matches = value.match(regex.token);
return matches && matches.length > 0;
}
}
function hasContent(value) {
return regex.content.test(value)
}
function hasContent(value) {
return regex.content.test(value);
}
function isElementValid(element) {
if (!element) return;
function isElementValid(element) {
if (!element) {
return;
}
var type = element.nodeType;
if (!element || !type) return false;
if (!element || !type) {
return false;
}
// comment
if (type === 8) return false;
if (type === 8) {
return false;
}
// empty text node
if (type === 3 && !hasContent(element.nodeValue) && !hasInterpolation(element.nodeValue)) return false;
if (type === 3 && !hasContent(element.nodeValue) && !hasInterpolation(element.nodeValue)) {
return false;
}
// result
return true;
}
}
function compile(template, element, parent, nodeTarget) {
if (!isElementValid(element)) return;
function compile(template, element, parent, nodeTarget) {
if (!isElementValid(element)) {
return;
}
// get node
var node;
if (!nodeTarget) {
node = getNodeFromElement(element, parent ? parent.scope : new Scope(helpersScopeObject)._createChild(), parent && (parent.repeater || parent.isRepeaterDescendant) );
node = getNodeFromElement(element, parent ? parent.scope : new Scope(helpersScopeObject)._createChild());
}
else {
node = nodeTarget;
node.parent = parent;
}
if (parent && (parent.repeater || parent.isRepeaterDescendant)) {
node.isRepeaterDescendant = true;
if (parent && (parent.repeater || parent.isRepeaterChild)) {
node.isRepeaterChild = true;
}
node.template = template;
// children
if (node.skip) return;
if (node.skip) {
return;
}
var child = element.firstChild;
while (child) {
var childNode = compile(template, child, node);
......@@ -455,39 +541,47 @@ function compile(template, element, parent, nodeTarget) {
child = child.nextSibling;
}
return node;
}
}
function updateScopeWithData(scope, data) {
function updateScopeWithData(scope, data) {
clearScope(scope);
for (var d in data) {
if (data.hasOwnProperty(d)) {
scope[d] = data[d];
}
}
}
}
function clearScope(scope) {
function clearScope(scope) {
for (var key in scope) {
if (scope.hasOwnProperty(key)) {
if (key.substr(0, 1) !== '_') {
scope[key] = null;
delete scope[key];
}
}
}
}
}
function updateNodeChildren(node) {
if (node.repeater || !node.children || childNodeIsTemplate(node)) return;
function updateNodeChildren(node) {
if (node.repeater || !node.children || childNodeIsTemplate(node)) {
return;
}
for (var i = 0, l = node.children.length; i < l; i++) {
node.children[i].update();
}
}
}
function renderNodeChildren(node) {
if (!node.children || childNodeIsTemplate(node)) return;
function renderNodeChildren(node) {
if (!node.children || childNodeIsTemplate(node)) {
return;
}
for (var i = 0, l = node.children.length; i < l; i++) {
node.children[i].render();
}
}
}
function renderNodeRepeater(node) {
function renderNodeRepeater(node) {
var data = getRepeaterData(node.repeater, node.scope);
var previousElement;
if (isArray(data)) {
......@@ -509,9 +603,11 @@ function renderNodeRepeater(node) {
// process object
var count = -1;
for (var o in data) {
if (data.hasOwnProperty(o)) {
count++;
previousElement = createRepeaterChild(node, count, data[o], vars.key, o, previousElement);
}
}
var size = count;
while (count++ < node.childrenRepeater.length-1) {
node.parent.element.removeChild(node.childrenRepeater[count].element);
......@@ -522,59 +618,88 @@ function renderNodeRepeater(node) {
if (node.element.parentNode) {
node.element.parentNode.removeChild(node.element);
}
}
}
function cloneRepeaterNode(element, node) {
var newNode = new Node(element, node.scope._createChild());
function compileClone(node, newNode) {
if (!isElementValid(newNode.element)) {
return;
}
// create attribute
if (node.attributes) {
var attrs = [];
for (var i = 0, l = node.attributes.length; i < l; i++) {
newNode.renderAsHtml = node.renderAsHtml;
if (node.attributes[i].name === settings.attributes.skip) {
newNode.skip = (node.attributes[i].value === "" || node.attributes[i].value === "true");
for (var i= 0, l=node.attributes.length; i<l; i++) {
var attr = node.attributes[i];
var newAttr = addAttribute(newNode, attr.name, attr.value);
if (events[attr.name]) {
newNode.addEvent(events[attr.name], attr.value, newAttr);
}
if (node.attributes[i].name === settings.attributes.html) {
newNode.html = (node.attributes[i].value === "" || node.attributes[i].value === "true");
}
if (node.attributes[i].name !== attributes.repeat) {
var attribute = new Attribute(node.attributes[i].name, node.attributes[i].value, newNode);
attrs.push(attribute);
}
if (events[node.attributes[i].name]) {
newNode.addEvent(events[node.attributes[i].name], node.attributes[i].value);
// children
var child = node.element.firstChild;
var newChild = newNode.element.firstChild;
// loop
while (child && newChild) {
var childNode = node.getNode(child);
var newChildNode = new Node(newChild, newNode.scope);
newNode.children.push(newChildNode);
newChildNode.parent = newNode;
newChildNode.template = newNode.template;
newChildNode.isRepeaterChild = true;
var compiledNode = compileClone(childNode, newChildNode);
if (compiledNode) {
compiledNode.parent = newChildNode;
compiledNode.template = newChildNode.template;
newChildNode.children.push(compiledNode);
}
child = child.nextSibling;
newChild = newChild.nextSibling;
}
newNode.attributes = attrs;
return newChildNode;
}
function cloneRepeaterNode(element, node) {
var newNode = new Node(element, node.scope._createChild());
newNode.template = node.template;
newNode.parent = node;
newNode.isRepeaterChild = true;
newNode.isRepeaterDescendant = true;
compileClone(node, newNode);
return newNode;
}
}
function appendRepeaterElement(previousElement, node, newElement) {
if (!previousElement) {
if (node.element.previousSibling) {
insertAfter(node.element.previousSibling, newElement);
}
else if (node.element.nextSibling) {
insertBefore(node.element.nextSibling, newElement);
}
else {
node.parent.element.appendChild(newElement);
}
}
else {
insertAfter(previousElement, newElement);
}
}
function createRepeaterChild(node, count, data, indexVar, indexVarValue, previousElement) {
function createRepeaterChild(node, count, data, indexVar, indexVarValue, previousElement) {
var existingChild = node.childrenRepeater[count];
if (!existingChild) {
// no existing node
var newElement = node.element.cloneNode(true);
// need to append the cloned element to the DOM
// before changing attributes or IE will crash
appendRepeaterElement(previousElement, node, newElement);
// can't recreate the node with a cloned element on IE7
// be cause the attributes are not specified annymore (attribute.specified)
// be cause the attributes are not specified anymore (attribute.specified)
//var newNode = getNodeFromElement(newElement, node.scope._createChild(), true);
var newNode = cloneRepeaterNode(newElement, node);
newNode.isRepeaterChild = true;
newNode.parent = node.parent;
newNode.template = node.template;
node.childrenRepeater[count] = newNode;
updateScopeWithRepeaterData(node.repeater, newNode.scope, data);
newNode.scope[indexVar] = indexVarValue;
compile(node.template, newElement, node.parent, newNode);
newNode.update();
newNode.render();
if (!previousElement) {
if (node.previousSibling) insertAfter(node.previousSibling, newElement);
else if (node.nextSibling) insertBefore(node.nextSibling, newElement);
else node.parent.element.appendChild(newElement);
}
else {
insertAfter(previousElement, newElement);
}
return newElement;
}
else {
......@@ -585,28 +710,29 @@ function createRepeaterChild(node, count, data, indexVar, indexVarValue, previou
existingChild.render();
return existingChild.element;
}
}
}
var Scope = function(data) {
var Scope = function(data) {
var self;
function createChild(data) {
var obj = createObject(data);
obj._parent = this;
this._children.push(obj);
obj._parent = self;
self._children.push(obj);
return obj;
}
function createObject(data) {
var obj = data || {};
obj._parent = null;
obj._children = [];
obj._createChild = function(data) {
obj._createChild = function() {
self = obj;
return createChild.apply(obj, arguments);
}
};
return obj;
}
return createObject(data);
};
var Node = function(element, scope) {
};
var Node = function(element, scope) {
this.element = element;
this.scope = scope;
this.attributes = null;
......@@ -631,8 +757,8 @@ var Node = function(element, scope) {
this.interpolation = new Interpolation(this.value, this, undefined);
}
};
Node.prototype = {
};
Node.prototype = {
toString: function() {
return '[object Node]';
},
......@@ -660,7 +786,6 @@ Node.prototype = {
this.element = null;
this.scope = null;
this.attributes = null;
this.attributesHashMap = null;
this.value = null;
this.interpolation = null;
this.repeater = null;
......@@ -674,17 +799,21 @@ Node.prototype = {
},
getNode: function(element) {
var node;
if (element === this.element) return this;
else if (this.childrenRepeater.length > 0) {
if (element === this.element) {
return this;
}
if (this.childrenRepeater.length > 0) {
for (var k = 0, kl = this.childrenRepeater.length; k < kl; k++) {
node = this.childrenRepeater[k].getNode(element);
if (node) return node;
if (node) {
return node;
}
}
}
else {
for (var i = 0, l = this.children.length; i < l; i++) {
node = this.children[i].getNode(element);
if (node) return node;
if (node) {
return node;
}
}
return null;
......@@ -700,7 +829,9 @@ Node.prototype = {
}
},
update: function() {
if (childNodeIsTemplate(this)) return;
if (childNodeIsTemplate(this)) {
return;
}
if (isDefined(this.interpolation)) {
this.interpolation.update();
}
......@@ -712,7 +843,9 @@ Node.prototype = {
updateNodeChildren(this);
},
invalidateData: function() {
if (childNodeIsTemplate(this)) return;
if (childNodeIsTemplate(this)) {
return;
}
this.invalidate = true;
var i, l;
if (this.attributes) {
......@@ -727,14 +860,17 @@ Node.prototype = {
this.children[i].invalidateData();
}
},
addEvent: function(type, pattern) {
if (this.repeater) return;
addEvent: function(type, pattern, attr) {
if (this.repeater) {
return;
}
if (this.eventHandlers[type]) {
this.removeEvent(type);
}
var scope = this.scope;
var node = this;
var handler = function(event) {
var exp = new Expression(pattern, this.node);
var exp = new Expression(pattern, node, attr);
var func = exp.getValue(scope, true);
var params = exp.getValue(scope, false, true);
params.unshift(event);
......@@ -753,7 +889,9 @@ Node.prototype = {
clearEvents: function() {
if (this.eventHandlers) {
for (var key in this.eventHandlers) {
this.removeEvent(key, this.eventHandlers[key]);
if (this.eventHandlers.hasOwnProperty(key)) {
this.removeEvent(key);
}
}
}
if (this.children) {
......@@ -768,7 +906,9 @@ Node.prototype = {
}
},
render: function() {
if (childNodeIsTemplate(this)) return;
if (childNodeIsTemplate(this)) {
return;
}
if (this.invalidate) {
this.invalidate = false;
if (isTextNode(this.element)) {
......@@ -792,22 +932,26 @@ Node.prototype = {
renderNodeChildren(this);
}
}
};
var Attribute = function(name, value, node) {
};
var Attribute = function(name, value, node) {
this.name = name;
this.value = value;
this.node = node;
this.interpolationName = new Interpolation(this.name, null, this);
this.interpolationValue = new Interpolation(this.value, null, this);
this.invalidate = false;
};
Attribute.prototype = {
};
Attribute.prototype = {
toString: function() {
return '[object Attribute]';
},
dispose: function() {
if (this.interpolationName) this.interpolationName.dispose();
if (this.interpolationValue) this.interpolationValue.dispose();
if (this.interpolationName) {
this.interpolationName.dispose();
}
if (this.interpolationValue) {
this.interpolationValue.dispose();
}
this.interpolationName = null;
this.interpolationValue = null;
this.node = null;
......@@ -816,47 +960,77 @@ Attribute.prototype = {
this.previousName = null;
},
update: function() {
if (this.node.repeater) {
return;
}
this.interpolationName.update();
this.interpolationValue.update();
},
render: function() {
if (this.node.repeater) return;
if (this.node.repeater) {
return;
}
// normal attribute
function renderAttribute(name, value, node) {
if (name === 'value' && node.element['value'] !== undefined) {
element.value = value;
}
else if (ie === 7 && name === 'class') {
element.className = value;
}
else {
element.setAttribute(name, value);
}
}
// boolean attribute
function renderBooleanAttribute(name, value) {
element.setAttribute(name, value);
}
// special attribute
function renderSpecialAttribute(value, attrName) {
if (normalizeBoolean(value)) {
element.setAttribute(attrName, attrName);
}
else {
element.removeAttribute(attrName);
}
}
// src attribute
function renderSrc(value) {
element.setAttribute('src', value);
}
// href attribute
function renderHref(value) {
element.setAttribute('href', value);
}
var element = this.node.element;
if (this.invalidate) {
this.invalidate = false;
this.previousName = this.name;
this.name = isDefined(this.interpolationName.render()) ? this.interpolationName.render() : this.name;
this.value = isDefined(this.interpolationValue.render()) ? this.interpolationValue.render() : this.value;
if (this.name === attributes.src) {
renderSrc(this.name, this.value);
renderSrc(this.value);
}
else if (this.name === attributes.href) {
renderHref(this.name, this.value);
}
else {
if (this.node.isRepeaterChild && ie === 7) {
// delete attributes on cloned elements crash IE7
renderHref(this.value);
}
else {
if (ie !== 7 || (ie === 7 && !this.node.isRepeaterChild)) {
this.node.element.removeAttribute(this.interpolationName.value);
}
if (this.previousName) {
if (ie === 7 && this.previousName === 'class') {
// iE
this.node.element.className = "";
}
else {
if (this.node.isRepeaterChild && ie === 7) {
// delete attributes on cloned elements crash IE7
this.node.element.className = '';
}
else {
if (ie !== 7 || (ie === 7 && !this.node.isRepeaterChild)) {
this.node.element.removeAttribute(this.previousName);
}
}
}
renderAttribute(this.name, this.value, this.previousName);
renderAttribute(this.name, this.value, this.node);
}
}
// cloak
......@@ -865,68 +1039,52 @@ Attribute.prototype = {
}
// hide
if (this.name === attributes.hide) {
element.style.display = isAttributeDefined(this.value) ? "none" : "block";
var bool = normalizeBoolean(this.value);
renderAttribute(this.name, bool, this.node);
element.style.display = bool ? 'none' : '';
}
// show
if (this.name === attributes.show) {
element.style.display = isAttributeDefined(this.value) ? "block" : "none";
var bool = normalizeBoolean(this.value);
renderAttribute(this.name, bool, this.node);
element.style.display = bool ? '' : 'none';
}
// checked
if (this.name === attributes.checked) {
renderSpecialAttribute(this.name, this.value, 'checked');
element.checked = isAttributeDefined(this.value) ? true : false;
renderSpecialAttribute(this.value, 'checked');
renderAttribute(this.name, normalizeBoolean(this.value) ? true : false, this.node);
element.checked = normalizeBoolean(this.value) ? true : false;
}
// disabled
if (this.name === attributes.disabled) {
renderSpecialAttribute(this.name, this.value, 'disabled');
renderSpecialAttribute(this.value, 'disabled');
renderAttribute(this.name, normalizeBoolean(this.value) ? true : false, this.node);
}
// multiple
if (this.name === attributes.multiple) {
renderSpecialAttribute(this.name, this.value, 'multiple');
renderSpecialAttribute(this.value, 'multiple');
renderAttribute(this.name, normalizeBoolean(this.value) ? true : false, this.node);
}
// readonly
if (this.name === attributes.readonly) {
var bool = normalizeBoolean(this.value);
if (ie === 7) {
element.readOnly = isAttributeDefined(this.value) ? true : false;
element.readOnly = bool ? true : false;
}
else {
renderSpecialAttribute(this.name, this.value, 'readonly');
renderSpecialAttribute(this.value, 'readonly');
}
renderAttribute(this.name, bool ? true : false, this.node);
}
// selected
if (this.name === attributes.selected) {
renderSpecialAttribute(this.name, this.value, 'selected');
}
// normal attribute
function renderAttribute(name, value) {
if (ie === 7 && name === "class") {
element.className = value;
}
else {
element.setAttribute(name, value);
renderSpecialAttribute(this.value, 'selected');
renderAttribute(this.name, normalizeBoolean(this.value) ? true : false, this.node);
}
}
// special attribute
function renderSpecialAttribute(name, value, attrName) {
if (isAttributeDefined(value)) {
element.setAttribute(attrName, attrName);
}
else {
element.removeAttribute(attrName);
}
}
// src attribute
function renderSrc(name, value) {
element.setAttribute('src', value);
}
// href attribute
function renderHref(name, value) {
element.setAttribute('href', value);
}
}
};
};
var Interpolation = function(value, node, attribute) {
var Interpolation = function(value, node, attribute) {
this.value = node && !isTextNode(node.element) ? trim(value) : value;
this.node = node;
this.attribute = attribute;
......@@ -946,8 +1104,8 @@ var Interpolation = function(value, node, attribute) {
}
trimArray(this.sequence);
}
};
Interpolation.prototype = {
};
Interpolation.prototype = {
toString: function() {
return '[object Interpolation]';
},
......@@ -970,22 +1128,30 @@ Interpolation.prototype = {
}
},
render: function() {
var rendered = "";
var rendered = '';
if (this.sequence) {
for (var i = 0, l = this.sequence.length; i < l; i++) {
var val = "";
if (isExpression(this.sequence[i])) val = this.sequence[i].value;
else val = this.sequence[i];
if (!isDefined(val)) val = "";
var val = '';
if (isExpression(this.sequence[i])) {
val = this.sequence[i].value;
}
else {
val = this.sequence[i];
}
if (!isDefined(val)) {
val = '';
}
rendered += val;
}
}
return rendered;
}
};
};
var Expression = function(pattern, node, attribute) {
if (!isDefined(pattern)) return;
var Expression = function(pattern, node, attribute) {
if (!isDefined(pattern)) {
return;
}
this.pattern = pattern;
this.isString = regex.string.test(pattern);
this.node = node;
......@@ -1003,8 +1169,8 @@ var Expression = function(pattern, node, attribute) {
this.path = getExpressionPath(this.pattern);
this.params = !this.isFunction ? null : getParamsFromString(this.pattern.match(regex.func)[2]);
}
};
Expression.prototype = {
};
Expression.prototype = {
toString: function() {
return '[object Expression]';
},
......@@ -1018,8 +1184,12 @@ Expression.prototype = {
},
update: function() {
var node = this.node;
if (!node && this.attribute) node = this.attribute.node;
if (!node && node.scope) return;
if (!node && this.attribute) {
node = this.attribute.node;
}
if (!node && node.scope) {
return;
}
var newValue = this.getValue(node.scope);
newValue = getWatcherValue(this, newValue);
if (this.value !== newValue) {
......@@ -1028,42 +1198,69 @@ Expression.prototype = {
}
},
getValue: function(scope, getFunction, getParams) {
return getValue(scope, this.pattern, this.path, this.params, getFunction, getParams);
var node = this.node;
if (!node && this.attribute) {
node = this.attribute.node;
}
var context = {};
if (node) {
context[vars.element] = node.element;
if (node.element) {
context[vars.parentElement] = node.element.parentNode;
}
}
};
context[vars.attribute] = this.attribute;
context[vars.scope] = scope;
return getValue(scope, this.pattern, this.path, this.params, getFunction, getParams, undefined, context);
}
};
var templates = new HashMap();
var templates = new HashMap('st');
var Template = function(element) {
this.watchers = new HashMap();
var Template = function(element) {
this.watchers = new HashMap('stw');
this.node = null;
this.scope = null;
this.compile(element);
};
Template.prototype = {
};
Template.prototype = {
toString: function() {
return '[object Template]';
},
compile: function(element) {
if (element) this.element = element;
if (this.node) this.node.dispose();
if (element) {
this.element = element;
}
if (this.node) {
this.node.dispose();
}
this.node = compile(this, this.element);
this.node.root = true;
this.scope = this.node.scope;
},
update: function(data) {
if (isDefined(data)) updateScopeWithData(this.node.scope, data);
if (this.node) this.node.update();
if (isDefined(data)) {
updateScopeWithData(this.node.scope, data);
}
if (this.node) {
this.node.update();
}
},
render: function(data) {
this.update(data);
if (this.node) this.node.render();
if (this.node) {
this.node.render();
}
},
invalidate: function() {
if (this.node) this.node.invalidateData();
if (this.node) {
this.node.invalidateData();
}
},
watch: function(target, watcher) {
if ( (!isString(target) && !isElement(target)) || !isFunction(watcher)) return;
if ( (!isString(target) && !isElement(target)) || !isFunction(watcher)) {
return;
}
this.watchers.put(target, watcher);
},
unwatch: function(target) {
......@@ -1090,47 +1287,36 @@ Template.prototype = {
this.watchers = null;
this.node = null;
}
};
};
// written by Dean Edwards, 2005
// with input from Tino Zijdel, Matthias Miller, Diego Perini
// http://dean.edwards.name/weblog/2005/10/add-event/
function addEvent(element, type, handler) {
// written by Dean Edwards, 2005
// with input from Tino Zijdel, Matthias Miller, Diego Perini
// http://dean.edwards.name/weblog/2005/10/add-event/
function addEvent(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else {
// assign each event handler a unique ID
if (!handler.$$guid) handler.$$guid = addEvent.guid++;
if (!handler.$$guid) {
handler.$$guid = addEvent.guid++;
}
// create a hash table of event types for the element
if (!element.events) element.events = {};
if (!element.events) {
element.events = {};
}
// create a hash table of event handlers for each element/event pair
var handlers = element.events[type];
if (!handlers) {
handlers = element.events[type] = {};
// store the existing event handler (if there is one)
if (element["on" + type]) {
handlers[0] = element["on" + type];
if (element['on' + type]) {
handlers[0] = element['on' + type];
}
}
// store the event handler in the hash table
handlers[handler.$$guid] = handler;
// assign a global event handler to do all the work
element["on" + type] = handleEvent;
}
};
// a counter used to create unique IDs
addEvent.guid = 1;
function removeEvent(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else {
// delete the event handler from the hash table
if (element.events && element.events[type]) {
delete element.events[type][handler.$$guid];
}
}
};
function handleEvent(event) {
element['on' + type] = function(event) {
var returnValue = true;
// grab the event object (IE uses a global event object)
event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event);
......@@ -1138,38 +1324,60 @@ function handleEvent(event) {
var handlers = this.events[event.type];
// execute each event handler
for (var i in handlers) {
if (handlers.hasOwnProperty(i)) {
this.$$handleEvent = handlers[i];
if (this.$$handleEvent(event) === false) {
returnValue = false;
}
}
}
return returnValue;
};
function fixEvent(event) {
};
}
}
// a counter used to create unique IDs
addEvent.guid = 1;
function removeEvent(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else {
// delete the event handler from the hash table
if (element.events && element.events[type]) {
delete element.events[type][handler.$$guid];
}
}
}
function fixEvent(event) {
// add W3C standard event methods
event.preventDefault = fixEvent.preventDefault;
event.stopPropagation = fixEvent.stopPropagation;
return event;
};
fixEvent.preventDefault = function() {
}
fixEvent.preventDefault = function() {
this.returnValue = false;
};
fixEvent.stopPropagation = function() {
};
fixEvent.stopPropagation = function() {
this.cancelBubble = true;
};
};
var maxDepth;
var eventStore = [];
var maxDepth;
var eventStore = [];
function parseEvents(element, object, depth) {
function parseEvents(element, object, depth) {
maxDepth = depth === undefined ? Number.MAX_VALUE : depth;
parseNode(element, object, 0, true);
}
}
function parseNode(element, object, depth, isRoot) {
if (!isElement(element)) throw new Error('Error in soma.template.parseEvents, only a DOM Element can be parsed.');
if (isRoot) parseAttributes(element, object);
if (maxDepth === 0) return;
function parseNode(element, object, depth, isRoot) {
if (!isElement(element)) {
throw new Error('Error in soma.template.parseEvents, only a DOM Element can be parsed.');
}
if (isRoot) {
parseAttributes(element, object);
}
if (maxDepth === 0) {
return;
}
var child = element.firstChild;
while (child) {
if (child.nodeType === 1) {
......@@ -1180,17 +1388,16 @@ function parseNode(element, object, depth, isRoot) {
}
child = child.nextSibling;
}
}
}
function parseAttributes(element, object) {
var attributes = [];
function parseAttributes(element, object) {
for (var attr, name, value, attrs = element.attributes, j = 0, jj = attrs && attrs.length; j < jj; j++) {
attr = attrs[j];
if (attr.specified) {
name = attr.name;
value = attr.value;
if (events[name]) {
var handler = getHandlerFromPattern(object, value, element);
var handler = getHandlerFromPattern(object, value);
if (handler && isFunction(handler)) {
addEvent(element, events[name], handler);
eventStore.push({element:element, type:events[name], handler:handler});
......@@ -1198,9 +1405,9 @@ function parseAttributes(element, object) {
}
}
}
}
}
function getHandlerFromPattern(object, pattern, child) {
function getHandlerFromPattern(object, pattern) {
var parts = pattern.match(regex.func);
if (parts) {
var func = parts[1];
......@@ -1208,9 +1415,9 @@ function getHandlerFromPattern(object, pattern, child) {
return object[func];
}
}
}
}
function clearEvents(element) {
function clearEvents(element) {
var i = eventStore.length, l = 0;
while (--i >= l) {
var item = eventStore[i];
......@@ -1219,12 +1426,16 @@ function clearEvents(element) {
eventStore.splice(i, 1);
}
}
}
}
if (settings.autocreate && typeof document === 'object') {
var ready;
if (typeof document === 'object') {
// https://github.com/ded/domready
var ready=function(){function l(b){for(k=1;b=a.shift();)b()}var b,a=[],c=!1,d=document,e=d.documentElement,f=e.doScroll,g="DOMContentLoaded",h="addEventListener",i="onreadystatechange",j="readyState",k=/^loade|c/.test(d[j]);return d[h]&&d[h](g,b=function(){d.removeEventListener(g,b,c),l()},c),f&&d.attachEvent(i,b=function(){/^c/.test(d[j])&&(d.detachEvent(i,b),l())}),f?function(b){self!=top?k?b():a.push(b):function(){try{e.doScroll("left")}catch(a){return setTimeout(function(){ready(b)},50)}b()}()}:function(b){k?b():a.push(b)}}();
if (settings.autocreate) {
var parse = function(element) {
var child = !element ? document.body : element.firstChild;
while (child) {
......@@ -1238,19 +1449,21 @@ if (settings.autocreate && typeof document === 'object') {
if (isFunction(f)) {
soma.template.bootstrap(attrValue, child, f);
}
} catch(err){};
} catch(err){}
}
}
child = child.nextSibling;
}
};
ready(parse);
}
function bootstrapTemplate(attrValue, element, func) {
}
}
function bootstrapTemplate(attrValue, element, func) {
var tpl = createTemplate(element);
func(tpl, tpl.scope, tpl.element, tpl.node);
}
function createTemplate(source, target) {
}
function createTemplate(source, target) {
var element;
if (isString(source)) {
// string template
......@@ -1283,19 +1496,22 @@ function createTemplate(source, target) {
var template = new Template(element);
templates.put(element, template);
return template;
}
}
function getTemplate(element) {
function getTemplate(element) {
return templates.get(element);
}
}
function renderAllTemplates() {
function renderAllTemplates() {
var data = templates.getData();
for (var key in templates.getData()) {
if (data.hasOwnProperty(key)) {
templates.get(key).render();
}
}
}
}
function appendHelpers(obj) {
function appendHelpers(obj) {
if (obj === null) {
helpersObject = {};
helpersScopeObject = {};
......@@ -1308,20 +1524,20 @@ function appendHelpers(obj) {
}
}
return helpersObject;
}
}
// set regex
tokens.start(tokenStart);
tokens.end(tokenEnd);
// set regex
tokens.start(tokenStart);
tokens.end(tokenEnd);
// plugins
// plugins
soma.plugins = soma.plugins || {};
soma.plugins = soma.plugins || {};
var TemplatePlugin = function(instance, injector) {
var TemplatePlugin = function(instance, injector) {
instance.constructor.prototype.createTemplate = function(cl, domElement) {
if (!cl || typeof cl !== "function") {
throw new Error("Error creating a template, the first parameter must be a function.");
if (!cl || typeof cl !== 'function') {
throw new Error('Error creating a template, the first parameter must be a function.');
}
if (domElement && isElement(domElement)) {
var template = soma.template.create(domElement);
......@@ -1332,46 +1548,46 @@ var TemplatePlugin = function(instance, injector) {
}
cl.prototype.render = template.render.bind(template);
var childInjector = injector.createChild();
childInjector.mapValue("template", template);
childInjector.mapValue("scope", template.scope);
childInjector.mapValue("element", template.element);
childInjector.mapValue('template', template);
childInjector.mapValue('scope', template.scope);
childInjector.mapValue('element', template.element);
return childInjector.createInstance(cl);
}
return null;
}
};
soma.template.bootstrap = function(attrValue, element, func) {
instance.createTemplate(func, element);
}
}
if (soma.plugins && soma.plugins.add) {
};
};
if (soma.plugins && soma.plugins.add) {
soma.plugins.add(TemplatePlugin);
}
soma.template.Plugin = TemplatePlugin;
// exports
soma.template.create = createTemplate;
soma.template.get = getTemplate;
soma.template.renderAll = renderAllTemplates;
soma.template.helpers = appendHelpers;
soma.template.bootstrap = bootstrapTemplate;
soma.template.addEvent = addEvent;
soma.template.removeEvent = removeEvent;
soma.template.parseEvents = parseEvents;
soma.template.clearEvents = clearEvents;
soma.template.ready = ready;
// register for AMD module
if (typeof define === 'function' && define.amd) {
define("soma-template", soma.template);
}
// export for node.js
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = soma.template;
}
soma.template.Plugin = TemplatePlugin;
// exports
soma.template.create = createTemplate;
soma.template.get = getTemplate;
soma.template.renderAll = renderAllTemplates;
soma.template.helpers = appendHelpers;
soma.template.bootstrap = bootstrapTemplate;
soma.template.addEvent = addEvent;
soma.template.removeEvent = removeEvent;
soma.template.parseEvents = parseEvents;
soma.template.clearEvents = clearEvents;
soma.template.ready = ready;
// register for AMD module
if (typeof define === 'function' && typeof define.amd !== 'undefined') {
define('soma-template', soma.template);
}
// export for node.js
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
module.exports = soma.template;
}
if (typeof exports !== 'undefined') {
exports = soma.template;
}
}
})(this['soma'] = this['soma'] || {});
\ No newline at end of file
/*
Copyright (c) | 2012 | infuse.js | Romuald Quantin | www.soundstep.com | romu@soundstep.com
Copyright (c) | 2013 | infuse.js | Romuald Quantin | www.soundstep.com | romu@soundstep.com
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without restriction,
......@@ -17,10 +17,11 @@ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
;(function(infuse, undefined) {
"use strict";
(function(infuse) {
infuse.version = "0.6.3";
'use strict';
infuse.version = '0.7.0';
// regex from angular JS (https://github.com/angular/angular.js)
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
......@@ -28,26 +29,26 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
if(!Array.prototype.contains) {
Array.prototype.contains = function(value) {
var i = this.length;
function contains(arr, value) {
var i = arr.length;
while (i--) {
if (this[i] === value) return true;
if (arr[i] === value) {
return true;
}
}
return false;
};
}
infuse.InjectorError = {
MAPPING_BAD_PROP: "[Error infuse.Injector.mapClass/mapValue] the first parameter is invalid, a string is expected",
MAPPING_BAD_VALUE: "[Error infuse.Injector.mapClass/mapValue] the second parameter is invalid, it can't null or undefined, with property: ",
MAPPING_BAD_CLASS: "[Error infuse.Injector.mapClass/mapValue] the second parameter is invalid, a function is expected, with property: ",
MAPPING_BAD_SINGLETON: "[Error infuse.Injector.mapClass] the third parameter is invalid, a boolean is expected, with property: ",
MAPPING_ALREADY_EXISTS: "[Error infuse.Injector.mapClass/mapValue] this mapping already exists, with property: ",
CREATE_INSTANCE_INVALID_PARAM: "[Error infuse.Injector.createInstance] invalid parameter, a function is expected",
NO_MAPPING_FOUND: "[Error infuse.Injector.getInstance] no mapping found",
INJECT_INSTANCE_IN_ITSELF_PROPERTY: "[Error infuse.Injector.getInjectedValue] A matching property has been found in the target, you can't inject an instance in itself",
INJECT_INSTANCE_IN_ITSELF_CONSTRUCTOR: "[Error infuse.Injector.getInjectedValue] A matching constructor parameter has been found in the target, you can't inject an instance in itself"
MAPPING_BAD_PROP: '[Error infuse.Injector.mapClass/mapValue] the first parameter is invalid, a string is expected',
MAPPING_BAD_VALUE: '[Error infuse.Injector.mapClass/mapValue] the second parameter is invalid, it can\'t null or undefined, with property: ',
MAPPING_BAD_CLASS: '[Error infuse.Injector.mapClass/mapValue] the second parameter is invalid, a function is expected, with property: ',
MAPPING_BAD_SINGLETON: '[Error infuse.Injector.mapClass] the third parameter is invalid, a boolean is expected, with property: ',
MAPPING_ALREADY_EXISTS: '[Error infuse.Injector.mapClass/mapValue] this mapping already exists, with property: ',
CREATE_INSTANCE_INVALID_PARAM: '[Error infuse.Injector.createInstance] invalid parameter, a function is expected',
NO_MAPPING_FOUND: '[Error infuse.Injector.getInstance] no mapping found',
INJECT_INSTANCE_IN_ITSELF_PROPERTY: '[Error infuse.Injector.getInjectedValue] A matching property has been found in the target, you can\'t inject an instance in itself',
INJECT_INSTANCE_IN_ITSELF_CONSTRUCTOR: '[Error infuse.Injector.getInjectedValue] A matching constructor parameter has been found in the target, you can\'t inject an instance in itself'
};
var MappingVO = function(prop, value, cl, singleton) {
......@@ -58,7 +59,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
};
var validateProp = function(prop) {
if (typeof prop !== "string") {
if (typeof prop !== 'string') {
throw new Error(infuse.InjectorError.MAPPING_BAD_PROP);
}
};
......@@ -70,20 +71,20 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
};
var validateClass = function(prop, val) {
if (typeof val !== "function") {
if (typeof val !== 'function') {
throw new Error(infuse.InjectorError.MAPPING_BAD_CLASS + prop);
}
};
var validateBooleanSingleton = function(prop, singleton) {
if (typeof singleton !== "boolean") {
if (typeof singleton !== 'boolean') {
throw new Error(infuse.InjectorError.MAPPING_BAD_SINGLETON + prop);
}
};
var validateConstructorInjectionLoop = function(name, cl) {
var params = infuse.getConstructorParams(cl);
if (params.contains(name)) {
if (contains(params, name)) {
throw new Error(infuse.InjectorError.INJECT_INSTANCE_IN_ITSELF_CONSTRUCTOR);
}
};
......@@ -94,33 +95,29 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}
};
var instantiateIgnoringConstructor = function() {
if (typeof arguments[0] !== "function") {
throw new Error(infuse.InjectorError.CREATE_INSTANCE_INVALID_PARAM);
}
var TargetClass = arguments[0];
var args = [null];
for (var i=1; i<arguments.length; i++) {
args.push(arguments[i]);
}
return new (Function.prototype.bind.apply(TargetClass, args));
};
infuse.Injector = function() {
this.mappings = {};
this.parent = null;
};
infuse.getConstructorParams = function(cl) {
var args = [];
var args = [],
inject;
function extractName(all, underscore, name) {
args.push(name);
}
// Override arg name with inject array values if present
if( cl.hasOwnProperty('inject') && toString.call(cl.inject) === '[object Array]' && cl.inject.length > 0)
inject = cl.inject;
var clStr = cl.toString().replace(STRIP_COMMENTS, '');
var argsFlat = clStr.match(FN_ARGS);
var spl = argsFlat[1].split(FN_ARG_SPLIT);
for (var i=0; i<spl.length; i++) {
var arg = spl[i];
arg.replace(FN_ARG, function(all, underscore, name){
args.push(name);
});
// Only override arg with non-falsey inject value at same key
var arg = (inject && inject[i]) ? inject[i] : spl[i];
arg.replace(FN_ARG, extractName);
}
return args;
};
......@@ -134,9 +131,15 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
},
getMappingVo: function(prop) {
if (!this.mappings) return null;
if (this.mappings[prop]) return this.mappings[prop];
if (this.parent) return this.parent.getMappingVo(prop);
if (!this.mappings) {
return null;
}
if (this.mappings[prop]) {
return this.mappings[prop];
}
if (this.parent) {
return this.parent.getMappingVo(prop);
}
return null;
},
......@@ -146,7 +149,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}
validateProp(prop);
validateValue(prop, val);
this.mappings[prop] = new MappingVO(prop, val);
this.mappings[prop] = new MappingVO(prop, val, undefined, undefined);
return this;
},
......@@ -156,7 +159,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}
validateProp(prop);
validateClass(prop, cl);
if (singleton) validateBooleanSingleton(prop, singleton);
if (singleton) {
validateBooleanSingleton(prop, singleton);
}
this.mappings[prop] = new MappingVO(prop, null, cl, singleton);
return this;
},
......@@ -177,22 +182,38 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
getMapping: function(value) {
for (var name in this.mappings) {
if (this.mappings.hasOwnProperty(name)) {
var vo = this.mappings[name];
if (vo.value === value || vo.cl === value) {
return vo.prop;
}
}
}
return undefined;
},
getValue: function(prop) {
var vo = this.mappings[prop];
if (!vo) {
if (this.parent) return this.parent.getValue.apply(this.parent, arguments);
else throw new Error(infuse.InjectorError.NO_MAPPING_FOUND);
if (this.parent) {
return this.parent.getValue.apply(this.parent, arguments);
}
else {
throw new Error(infuse.InjectorError.NO_MAPPING_FOUND);
}
}
if (vo.cl) {
arguments[0] = vo.cl;
return this.getValueFromClass.apply(this, arguments);
var args = Array.prototype.slice.call(arguments);
args[0] = vo.cl;
if (vo.singleton) {
if (!vo.value) {
vo.value = this.createInstance.apply(this, args);
}
return vo.value;
}
else {
return this.createInstance.apply(this, args);
}
}
return vo.value;
},
......@@ -200,20 +221,25 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
getClass: function(prop) {
var vo = this.mappings[prop];
if (!vo) {
if (this.parent) return this.parent.getClass(prop);
else return undefined;
if (this.parent) {
return this.parent.getClass(prop);
}
else {
return undefined;
}
}
if (vo.cl) {
return vo.cl;
}
if (vo.cl) return vo.cl;
return undefined;
},
instantiate: function(TargetClass) {
if (typeof TargetClass !== "function") {
if (typeof TargetClass !== 'function') {
throw new Error(infuse.InjectorError.CREATE_INSTANCE_INVALID_PARAM);
}
var TargetClass = arguments[0];
var args = [null];
var params = infuse.getConstructorParams(TargetClass, this.mappings);
var params = infuse.getConstructorParams(TargetClass);
for (var i=0; i<params.length; i++) {
if (arguments[i+1] !== undefined && arguments[i+1] !== null) {
// argument found
......@@ -234,7 +260,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}
}
}
return new (Function.prototype.bind.apply(TargetClass, args));
return new (Function.prototype.bind.apply(TargetClass, args))();
},
inject: function (target, isParent) {
......@@ -242,10 +268,11 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
this.parent.inject(target, true);
}
for (var name in this.mappings) {
if (this.mappings.hasOwnProperty(name)) {
var vo = this.getMappingVo(name);
if (target.hasOwnProperty(vo.prop)) {
var val = this.getInjectedValue(vo, name);
target[name] = val;
if (target.hasOwnProperty(vo.prop) || (target.constructor && target.constructor.prototype && target.constructor.prototype.hasOwnProperty(vo.prop)) ) {
target[name] = this.getInjectedValue(vo, name);
}
}
}
if (typeof target.postConstruct === 'function' && !isParent) {
......@@ -258,7 +285,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var val = vo.value;
var injectee;
if (vo.cl) {
var params = infuse.getConstructorParams(vo.cl);
if (vo.singleton) {
if (!vo.value) {
validateConstructorInjectionLoop(name, vo.cl);
......@@ -288,10 +314,13 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
getValueFromClass: function(cl) {
for (var name in this.mappings) {
if (this.mappings.hasOwnProperty(name)) {
var vo = this.mappings[name];
if (vo.cl == cl) {
if (vo.cl === cl) {
if (vo.singleton) {
if (!vo.value) vo.value = this.createInstance.apply(this, arguments);
if (!vo.value) {
vo.value = this.createInstance.apply(this, arguments);
}
return vo.value;
}
else {
......@@ -299,6 +328,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}
}
}
}
if (this.parent) {
return this.parent.getValueFromClass.apply(this.parent, arguments);
} else {
......@@ -315,15 +345,15 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
if (!Function.prototype.bind) {
Function.prototype.bind = function bind(that) {
var target = this;
if (typeof target != "function") {
throw new Error("Error, you must bind a function.");
if (typeof target !== 'function') {
throw new Error('Error, you must bind a function.');
}
var args = Array.prototype.slice.call(arguments, 1); // for normal call
var bound = function () {
if (this instanceof bound) {
var F = function(){};
F.prototype = target.prototype;
var self = new F;
var self = new F();
var result = target.apply(
self,
args.concat(Array.prototype.slice.call(arguments))
......@@ -344,55 +374,54 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}
// register for AMD module
if (typeof define === 'function' && define.amd) {
if (typeof define === 'function' && typeof define.amd !== 'undefined') {
define("infuse", infuse);
}
// export for node.js
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = infuse;
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
module.exports = infuse;
}
if (typeof exports !== 'undefined') {
exports = infuse;
}
})(this['infuse'] = this['infuse'] || {});
/*
Copyright (c) | 2012 | soma-events | Romuald Quantin | www.soundstep.com
Copyright (c) | 2013 | soma-events | Romuald Quantin | www.soundstep.com
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
(function (soma) {
;(function (soma, undefined) {
"use strict";
'use strict';
soma.events = {};
soma.events.version = "0.5.2";
soma.events.version = '0.5.6';
if (!Function.prototype.bind) {
Function.prototype.bind = function bind(that) {
var target = this;
if (typeof target != "function") {
throw new Error("Error, you must bind a function.");
if (typeof target !== 'function') {
throw new Error('Error, you must bind a function.');
}
var args = Array.prototype.slice.call(arguments, 1); // for normal call
var bound = function () {
if (this instanceof bound) {
var F = function(){};
F.prototype = target.prototype;
var self = new F;
var self = new F();
var result = target.apply(
self,
args.concat(Array.prototype.slice.call(arguments))
......@@ -410,7 +439,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
};
return bound;
};
};
}
soma.Event = function (type, params, bubbles, cancelable) {
var e = soma.Event.createGenericEvent(type, bubbles, cancelable);
......@@ -419,12 +448,14 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}
e.isCloned = false;
e.clone = this.clone.bind(e);
e.isIE9 = this.isIE9;
e.isIE9orIE10 = this.isIE9orIE10;
e.isDefaultPrevented = this.isDefaultPrevented;
if (this.isIE9() || !e.preventDefault || (e.getDefaultPrevented === undefined && e.defaultPrevented === undefined )) {
if (this.isIE9orIE10() || !e.preventDefault || (e.getDefaultPrevented === undefined && e.defaultPrevented === undefined )) {
e.preventDefault = this.preventDefault.bind(e);
}
if (this.isIE9()) e.IE9PreventDefault = false;
if (this.isIE9orIE10()) {
e.IE9or10PreventDefault = false;
}
return e;
};
......@@ -434,22 +465,32 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
e.isCloned = true;
e.clone = this.clone;
e.isDefaultPrevented = this.isDefaultPrevented;
e.isIE9 = this.isIE9;
if (this.isIE9()) e.IE9PreventDefault = this.IE9PreventDefault;
e.isIE9orIE10 = this.isIE9orIE10;
if (this.isIE9orIE10()) {
e.IE9or10PreventDefault = this.IE9or10PreventDefault;
}
return e;
};
soma.Event.prototype.preventDefault = function () {
if (!this.cancelable) return false;
if (!this.cancelable) {
return false;
}
if (this.isIE9orIE10()) {
this.IE9or10PreventDefault = true;
}
else {
this.defaultPrevented = true;
if (this.isIE9()) this.IE9PreventDefault = true;
}
return this;
};
soma.Event.prototype.isDefaultPrevented = function () {
if (!this.cancelable) return false;
if (this.isIE9()) {
return this.IE9PreventDefault;
if (!this.cancelable) {
return false;
}
if (this.isIE9orIE10()) {
return this.IE9or10PreventDefault;
}
if (this.defaultPrevented !== undefined) {
return this.defaultPrevented;
......@@ -462,10 +503,10 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
soma.Event.createGenericEvent = function (type, bubbles, cancelable) {
var event;
bubbles = bubbles !== undefined ? bubbles : true;
if (typeof document === "object" && document.createEvent) {
event = document.createEvent("Event");
if (typeof document === 'object' && document.createEvent) {
event = document.createEvent('Event');
event.initEvent(type, !!bubbles, !!cancelable);
} else if (typeof document === "object" && document.createEventObject) {
} else if (typeof document === 'object' && document.createEventObject) {
event = document.createEventObject();
event.type = type;
event.bubbles = !!bubbles;
......@@ -476,13 +517,15 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
return event;
};
soma.Event.prototype.isIE9 = function() {
if (typeof document !== "object") return false;
return document.body.style.scrollbar3dLightColor !== undefined && document.body.style.opacity !== undefined;
soma.Event.prototype.isIE9orIE10 = function() {
if (typeof document !== 'object') {
return false;
}
return (document.body.style.scrollbar3dLightColor !== undefined && document.body.style.opacity !== undefined) || document.body.style.msTouchAction !== undefined;
};
soma.Event.prototype.toString = function() {
return "[soma.Event]";
return '[soma.Event]';
};
var EventObject = function(type, bubbles, cancelable) {
......@@ -499,8 +542,12 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
};
soma.EventDispatcher.prototype.addEventListener = function(type, listener, priority) {
if (!this.listeners || !type || !listener) return;
if (isNaN(priority)) priority = 0;
if (!this.listeners || !type || !listener) {
return;
}
if (isNaN(priority)) {
priority = 0;
}
for (var i=0; i<this.listeners.length; i++) {
var eventObj = this.listeners[i];
if (eventObj.type === type && eventObj.listener === listener) {
......@@ -511,7 +558,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
};
soma.EventDispatcher.prototype.removeEventListener = function(type, listener) {
if (!this.listeners || !type || !listener) return;
if (!this.listeners || !type || !listener) {
return;
}
var i = this.listeners.length;
while(i-- > 0) {
var eventObj = this.listeners[i];
......@@ -522,7 +571,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
};
soma.EventDispatcher.prototype.hasEventListener = function(type) {
if (!this.listeners || !type) return false;
if (!this.listeners || !type) {
return false;
}
var i = 0;
var l = this.listeners.length;
for (; i < l; ++i) {
......@@ -535,7 +586,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
};
soma.EventDispatcher.prototype.dispatchEvent = function(event) {
if (!this.listeners || !event) throw new Error("Error in EventDispatcher (dispatchEvent), one of the parameters is null or undefined.");
if (!this.listeners || !event) {
throw new Error('Error in EventDispatcher (dispatchEvent), one of the parameters is null or undefined.');
}
var events = [];
var i;
for (i = 0; i < this.listeners.length; i++) {
......@@ -554,7 +607,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
};
soma.EventDispatcher.prototype.dispatch = function(type, params, bubbles, cancelable) {
if (!this.listeners || !type || type === "") throw new Error("Error in EventDispatcher (dispatch), one of the parameters is null or undefined.");
if (!this.listeners || !type || type === '') {
throw new Error('Error in EventDispatcher (dispatch), one of the parameters is null or undefined.');
}
var event = new soma.Event(type, params, bubbles, cancelable);
this.dispatchEvent(event);
return event;
......@@ -565,30 +620,30 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
};
soma.EventDispatcher.prototype.toString = function() {
return "[soma.EventDispatcher]";
return '[soma.EventDispatcher]';
};
// register for AMD module
if (typeof define === 'function' && define.amd) {
if (typeof define === 'function' && typeof define.amd !== 'undefined') {
define("soma-events", soma);
};
}
// export for node.js
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = soma;
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
module.exports = soma;
}
if (typeof exports !== 'undefined') {
exports = soma;
};
}
})(this['soma'] = this['soma'] || {});
;(function (soma, infuse, undefined) {
(function (soma, infuse) {
'use strict';
soma.version = "2.0.0";
soma.version = '2.1.0';
soma.applyProperties = function(target, extension, bindToExtension, list) {
if (Object.prototype.toString.apply(list) === '[object Array]') {
......@@ -651,7 +706,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Chain.prototype = parent.prototype;
Subclass.prototype = new Chain();
// add obj properties
if (obj) soma.applyProperties(Subclass.prototype, obj);
if (obj) {
soma.applyProperties(Subclass.prototype, obj);
}
// point constructor to the Subclass
Subclass.prototype.constructor = Subclass;
// set super class reference
......@@ -685,35 +742,38 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// framework
soma.Application = soma.extend({
constructor: function() {
setup.bind(this)();
this.init();
this.start();
var self = this;
function setup() {
// injector
this.injector = new infuse.Injector(this.dispatcher);
self.injector = new infuse.Injector(self.dispatcher);
// dispatcher
this.dispatcher = new soma.EventDispatcher();
self.dispatcher = new soma.EventDispatcher();
// mapping
this.injector.mapValue('injector', this.injector);
this.injector.mapValue('instance', this);
this.injector.mapValue('dispatcher', this.dispatcher);
self.injector.mapValue('injector', self.injector);
self.injector.mapValue('instance', self);
self.injector.mapValue('dispatcher', self.dispatcher);
// mediator
this.injector.mapClass('mediators', Mediators, true);
this.mediators = this.injector.getValue('mediators');
self.injector.mapClass('mediators', Mediators, true);
self.mediators = self.injector.getValue('mediators');
// commands
this.injector.mapClass('commands', Commands, true);
this.commands = this.injector.getValue('commands');
self.injector.mapClass('commands', Commands, true);
self.commands = self.injector.getValue('commands');
// plugins
for (var i = 0, l = plugins.length; i < l; i++) {
this.createPlugin(plugins[i]);
self.createPlugin(plugins[i]);
}
}
setup.bind(this)();
this.init();
this.start();
},
createPlugin: function() {
if (arguments.length == 0 || !arguments[0]) {
throw new Error("Error creating a plugin, plugin class is missing.");
if (arguments.length === 0 || !arguments[0]) {
throw new Error('Error creating a plugin, plugin class is missing.');
}
var params = infuse.getConstructorParams(arguments[0]);
var args = [arguments[0]];
......@@ -769,11 +829,11 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
this.dispatcher = null;
},
create: function(cl, target) {
if (!cl || typeof cl !== "function") {
throw new Error("Error creating a mediator, the first parameter must be a function.");
if (!cl || typeof cl !== 'function') {
throw new Error('Error creating a mediator, the first parameter must be a function.');
}
if (target === undefined || target === null) {
throw new Error("Error creating a mediator, the second parameter cannot be undefined or null.");
throw new Error('Error creating a mediator, the second parameter cannot be undefined or null.');
}
var targets = [];
var meds = [];
......@@ -785,11 +845,11 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}
for (var i= 0, l=targets.length; i<l; i++) {
var injector = this.injector.createChild();
injector.mapValue("target", targets[i]);
//var mediator = injector.createInstance.apply(this.injector, params);
injector.mapValue('target', targets[i]);
var mediator = injector.createInstance(cl);
// soma.applyProperties(mediator, this.dispatcher, true, ['dispatch', 'dispatchEvent', 'addEventListener', 'removeEventListener', 'hasEventListener']);
if (targets.length === 1) return mediator;
if (targets.length === 1) {
return mediator;
}
meds.push(mediator);
}
return meds;
......@@ -819,19 +879,21 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
getAll: function() {
var copy = {};
for (var cmd in this.list) {
if (this.list.hasOwnProperty(cmd)) {
copy[cmd] = this.list[cmd];
}
}
return copy;
},
add: function(commandName, command) {
if (typeof commandName !== 'string') {
throw new Error("Error adding a command, the first parameter must be a string.");
throw new Error('Error adding a command, the first parameter must be a string.');
}
if (typeof command !== 'function') {
throw new Error("Error adding a command with the name \"" + command + "\", the second parameter must be a function, and must contain an \"execute\" public method.");
throw new Error('Error adding a command with the name "' + command + '", the second parameter must be a function, and must contain an "execute" public method.');
}
if (this.has(commandName)) {
throw new Error("Error adding a command with the name: \"" + commandName + "\", already registered.");
throw new Error('Error adding a command with the name: "' + commandName + '", already registered.');
}
this.list[ commandName ] = command;
this.addInterceptor(commandName);
......@@ -860,16 +922,17 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
if (this.has(commandName)) {
var command = this.injector.createInstance(this.list[commandName]);
if (!command.hasOwnProperty('execute') && command['execute'] === 'function') {
throw new Error("Error in " + this + " Command \"" + command + "\" must contain an execute public method.");
throw new Error('Error in ' + this + ' Command ' + command + ' must contain an execute public method.');
}
// soma.applyProperties(command, this.dispatcher, true, ['dispatch', 'dispatchEvent', 'addEventListener', 'removeEventListener', 'hasEventListener']);
command.execute(event);
}
},
dispose: function() {
for (var cmd in this.list) {
if (this.list.hasOwnProperty(cmd)) {
this.remove(cmd);
}
}
this.boundHandler = undefined;
this.dispatcher = undefined;
this.injector = undefined;
......@@ -893,16 +956,17 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// register for AMD module
if (typeof define === 'function' && define.amd) {
define("soma", soma);
/* globals define:false */
if (typeof define === 'function' && typeof define.amd !== 'undefined') {
define('soma', soma);
}
// export for node.js
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = soma;
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
module.exports = soma;
}
exports = soma;
else {
window.soma = soma;
}
})(this['soma'] = this['soma'] || {}, this['infuse']);
\ No newline at end of file
......@@ -26,7 +26,7 @@
<label data-dblclick="edit(todo)">{{todo.title}}</label>
<button class="destroy" data-click="remove(todo)"></button>
</div>
<input class="edit" value="{{todo.title}}" data-keypress="update(todo)" data-blur="update(todo)">
<input class="edit" value="{{todo.title}}" data-keydown="update(todo)" data-blur="update(todo)">
</li>
</ul>
</section>
......
......@@ -8,12 +8,16 @@
var RouterModel = function (dispatcher) {
// create the router (director.js)
var router = new Router().init();
var router = new Router().init().configure({
notfound: render
});
// dispatch a custom event to render the template on a route change
router.on(/.*/, function () {
router.on(/.*/, render);
function render() {
dispatcher.dispatch('render');
});
}
return {
getRoute: function () {
......
......@@ -5,6 +5,7 @@
define([], function () {
var ENTER_KEY = 13;
var ESCAPE_KEY = 27;
var MainView = function (scope, template, model, router, dispatcher) {
......@@ -54,10 +55,14 @@
scope.edit = function (event, item) {
item.editing = 'editing';
template.render();
template.element.querySelector('.edit').focus();
};
// template function: during edit mode, changes the value of an item after an enter key press
scope.update = function (event, item) {
if (cancelEditing(event, item)) {
return;
}
var value = event.currentTarget.value.trim();
if (event.which === ENTER_KEY || event.type === 'blur') {
if (value) {
......@@ -72,6 +77,19 @@
}
};
// escape has been pressed, revert the value of the input
function cancelEditing(event, item) {
if (event.which === ESCAPE_KEY) {
event.currentTarget.value = item.title;
event.currentTarget.blur();
update();
return true;
}
else {
return false;
}
}
// save the changes to the model and dispatch a custom event to render the templates
function update() {
model.set(items);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment