ion
Version:
ion language ========================
423 lines • 16.6 kB
JavaScript
void (function(){var _ion_runtime_Context_ = function(module,exports,require){'use strict';
var ion = require('../'), Factory = require('./Factory'), Literal = require('./Literal'), noop = function () {
};
var createObjectInserter = function (container) {
return {
isOrdered: function (value) {
return false;
},
convert: function (value) {
return value;
},
getLength: function () {
return 0;
},
add: function (value, index) {
var current = container[value];
var insert = (current != null ? current : 0) + 1;
container[value] = insert;
},
remove: function (index, value, moving) {
var current = container[value];
if (!(current != null)) {
throw new Error('Removing value \'' + value + '\' that was not present in container: ' + container);
}
var insert = current - 1;
if (insert === 0) {
delete container[value];
} else {
container[value] = insert;
}
}
};
};
var createMapInserter = function (container) {
var touch = function () {
container.touch = container.touch != null ? container.touch : 0;
container.touch += 1;
};
return {
isOrdered: function (value) {
return false;
},
convert: function (value) {
return value;
},
getLength: function () {
return container.size;
},
add: function (value, index) {
var current = container.get(value);
var insert = (current != null ? current : 0) + 1;
container.set(value, insert);
touch();
},
remove: function (index, value, moving) {
var current = container.get(value);
if (!(current != null)) {
throw new Error('Removing value \'' + value + '\' that was not present in container: ' + container);
}
var insert = current - 1;
if (insert === 0) {
container.delete(value);
} else {
container.set(value, insert);
}
touch();
}
};
};
var createArrayInserter = function (container) {
return {
isOrdered: function (value) {
if (container.sortCompareFunction != null) {
return false;
}
return container.unordered !== true;
},
convert: function (value) {
return value;
},
getLength: function () {
return container.length;
},
add: function (value, index) {
if (index != null) {
container.splice(index, 0, value);
} else {
container.push(value);
}
},
remove: function (index, value, moving) {
index = index != null ? index : container.indexOf(value);
container.splice(index, 1);
}
};
};
var isNode = function (value) {
return typeof (value != null ? value.nodeType : void 0) === 'number';
};
var isWebComponent = function (value) {
return (value != null ? value.nodeName != null ? value.nodeName.indexOf('-') : void 0 : void 0) > 0;
};
var createHtmlInserter = function (container) {
return {
isOrdered: function (value) {
if (typeof value === 'function') {
return false;
}
if (container.unordered) {
return false;
}
return true;
},
convert: function (value) {
if (typeof value === 'function') {
var name = value.id != null ? value.id : value.name;
if (!(name != null)) {
throw new Error('Functions added to an Element must be named');
}
var capture = false;
var captureSuffix = '_capture';
if (name.endsWith(captureSuffix)) {
capture = true;
name = name.substring(0, name.length - captureSuffix.length);
}
value.id = name;
value.capture = capture;
} else if (!isNode(value)) {
value = document.createTextNode(value);
}
return value;
},
getLength: function () {
return container.childNodes.length;
},
add: function (value, index, sourceNode) {
if (typeof value === 'function') {
if (value.toString().indexOf('ion.sync') < 0) {
value.wrapper = value.wrapper != null ? value.wrapper : function () {
value.apply(this, arguments);
ion.sync(value.id != null ? value.id : value.name);
};
}
container.addEventListener(value.id, value.wrapper != null ? value.wrapper : value, value.capture);
} else {
if (global.Polymer) {
var polymerContainer = Polymer.dom(container);
if (index != null) {
var after = polymerContainer.childNodes[index];
if (after != null) {
polymerContainer.insertBefore(value, after);
return;
}
}
polymerContainer.appendChild(value);
} else {
if (index != null) {
var after = container.childNodes[index];
if (after != null) {
container.insertBefore(value, after);
return;
}
}
container.appendChild(value);
}
}
},
remove: function (index, value, moving) {
if (typeof value === 'function') {
container.removeEventListener(value.id, value.wrapper != null ? value.wrapper : value);
} else if (!moving) {
if (global.Polymer) {
var polymerContainer = Polymer.dom(container);
try {
polymerContainer.removeChild(value);
} catch (e) {
if (!warnedOfRemovalBug) {
warnedOfRemovalBug = true;
console.log('TODO: FIX!!! Polymer error: Cannot remove child. It may not exist anymore/yet.');
}
}
} else {
if (value.parentElement === container) {
container.removeChild(value);
} else {
console.log('Context is trying to remove an element from a container that it is not in.');
}
}
}
}
};
};
var warnedOfRemovalBug = false;
function isDomAncestor(ancestor, child, debug) {
var realAncestor = child;
while (realAncestor.parentElement != null) {
realAncestor = realAncestor.parentElement;
if (realAncestor === ancestor) {
return true;
}
}
return false;
}
var createOrderManager = function (container) {
var inserter;
if (Array.isArray(container)) {
inserter = createArrayInserter(container);
} else if ((container != null ? container.constructor : void 0) === Map) {
inserter = createMapInserter(container);
} else if (isNode(container)) {
inserter = createHtmlInserter(container);
} else if ((container != null ? container.constructor : void 0) === Object) {
inserter = createObjectInserter(container);
} else {
return {
insert: function (value, order, fastInsert, sourceNode) {
return ion.add(container, value, sourceNode);
},
update: function (oldOrder, newOrder) {
}
};
}
var baseLength = inserter.getLength();
var insertionOrders = [];
var insertionValues = {};
var pendingOrderChanges = {};
var insertInternal = function (value, order, fastInsert, sourceNode) {
if (insertionValues[order] != null) {
throw new Error('Cannot add a new item with the same order as an existing item: ' + JSON.stringify({
order: order,
previousValue: insertionValues[order],
newValue: value
}));
}
if (inserter.isOrdered(value)) {
insertionValues[order] = value;
insertionOrders.push(order);
} else {
fastInsert = true;
}
if (fastInsert) {
inserter.add(value, null, sourceNode);
} else {
insertionOrders.sort();
var index = insertionOrders.indexOf(order);
inserter.add(value, baseLength + index, sourceNode);
}
};
var removeInternal = function (value, order, moving) {
if (!inserter.isOrdered(value)) {
inserter.remove(null, value);
} else {
if (insertionValues[order] !== value) {
order = null;
for (var key in insertionValues) {
var insertedValue = insertionValues[key];
if (insertedValue === value) {
order = key;
break;
}
}
if (order === null) {
throw new Error('Could not find value in insertionValues ' + value);
}
}
var index = insertionOrders.indexOf(order);
if (index < 0) {
throw new Error('Insertion order ' + JSON.stringify(order) + ' not found ' + JSON.stringify(insertionOrders));
}
insertionOrders.splice(index, 1);
inserter.remove(baseLength + index, value, moving);
delete insertionValues[order];
}
};
return {
insert: function (value, order, fastInsert, sourceNode) {
value = inserter.convert(value);
insertInternal(value, order, fastInsert, sourceNode);
return function () {
return removeInternal(value, order);
};
},
update: function (oldOrder, newOrder) {
if (oldOrder != null && newOrder != null) {
pendingOrderChanges[oldOrder] = newOrder;
} else {
var reinsertValues = {};
for (var i = insertionOrders.length - 1; i >= 0; i--) {
var order = insertionOrders[i];
for (var oldOrderValue in pendingOrderChanges) {
var newOrderValue = pendingOrderChanges[oldOrderValue];
if (order.startsWith(oldOrderValue)) {
var insertedValue = insertionValues[order];
reinsertValues[newOrderValue + order.substring(oldOrderValue.length)] = insertedValue;
removeInternal(insertedValue, order, true);
}
}
}
for (var order in reinsertValues) {
var value = reinsertValues[order];
insertInternal(value, order);
}
pendingOrderChanges = {};
}
}
};
};
var Context = ion.defineClass({
name: 'Context',
constructor: function Context(parent, output, order) {
this.output = output;
this.parent = parent;
this.depth = parent != null ? parent.depth + 1 : 0;
this.variables = {};
this.root = (parent != null ? parent.root : void 0) != null ? parent.root : this;
this._runtimes = {};
this.returnExpression = parent != null ? parent.returnExpression : void 0;
this.inserter = output === (parent != null ? parent.output : void 0) ? parent != null ? parent.inserter : void 0 : createOrderManager(output);
this.order = order;
},
properties: {
newContext: function (output, order) {
if (output == null)
output = this.output;
return new Context(this, output, order);
},
createRuntime: function (node) {
return Factory.createRuntime(this, node);
},
setFastInsert: function (value) {
if (this.inserter != null) {
this.inserter.fastInsert = value;
}
},
order: {
get: function () {
var value = this._order != null ? this._order : '';
if (this.output != null && this.output === (this.parent != null ? this.parent.output : void 0)) {
value = this.parent.order + value;
}
return value;
},
set: function (value) {
var _order = this._order;
var oldValue = this.order;
this._order = value != null ? value : '';
var newValue = this.order;
if (_order != null && newValue !== oldValue) {
this.inserter != null ? this.inserter.update(oldValue, newValue) : void 0;
}
}
},
insert: function (value, order, sourceNode) {
order = this.order + (order != null ? order : '');
return this.inserter.insert(value, order, this.inserter.fastInsert, sourceNode);
},
get: function (name) {
var variable = this.getVariable(name);
if (!(variable != null)) {
throw new Error('Variable not found: \'' + name + '\'');
}
return variable.value;
},
getVariable: function (ast) {
var name = typeof ast === 'string' ? ast : ast.name;
var context = this, value;
while (context != null) {
var variable = context.variables[name];
if (variable != null) {
return variable;
}
context = context.parent;
}
value = global[name];
if (value === void 0) {
var message = 'Variable not found: \'' + name + '\'';
if (typeof ast === 'object') {
message += ' at (' + ast.loc.start.source + ':' + ast.loc.start.line + ':' + (ast.loc.start.column + 1) + ')';
}
throw new Error(message);
}
var cachedGlobals = this.root.globals = this.root.globals != null ? this.root.globals : {};
return cachedGlobals[name] = cachedGlobals[name] != null ? cachedGlobals[name] : new Literal({
value: value,
mutable: true
});
},
setVariableFromAst: function (name, node) {
if (name != null) {
return this.setVariableExpression(name, this.createRuntime(node));
}
},
setVariableLiteral: function (name, value) {
if (name != null) {
return this.setVariableExpression(name, new Literal({
value: value,
mutable: true
}));
}
},
setVariableExpression: function (name, expression) {
if (name != null) {
if (this.variables[name] != null) {
throw new Error('Variable ' + name + ' is already defined');
}
this.variables[name] = expression;
return expression;
}
}
}
});
module.exports = exports = Context;
}
if (typeof require === 'function') {
if (require.register)
require.register('ion/runtime/Context',_ion_runtime_Context_);
else
_ion_runtime_Context_.call(this, module, exports, require);
}
else {
_ion_runtime_Context_.call(this);
}
}).call(this)