ractive
Version:
Next-generation DOM manipulation
1,367 lines (1,265 loc) • 353 kB
JavaScript
/*
Ractive - v0.3.8 - 2013-12-21
==============================================================
Next-generation DOM manipulation - http://ractivejs.org
Follow @RactiveJS for updates
--------------------------------------------------------------
Copyright 2013 2013 Rich Harris and contributors
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 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 ( win ) {
'use strict';
var doc = win.document;
if ( !doc ) {
return;
}
// Shims for older browsers
if ( !Date.now ) {
Date.now = function () { return +new Date(); };
}
if ( !doc.createElementNS ) {
doc.createElementNS = function ( ns, type ) {
if ( ns && ns !== 'http://www.w3.org/1999/xhtml' ) {
throw 'This browser does not support namespaces other than http://www.w3.org/1999/xhtml. The most likely cause of this error is that you\'re trying to render SVG in an older browser. See https://github.com/RactiveJS/Ractive/wiki/SVG-and-older-browsers for more information';
}
return doc.createElement( type );
};
}
if ( !String.prototype.trim ) {
String.prototype.trim = function () {
return this.replace(/^\s+/, '').replace(/\s+$/, '');
};
}
// Polyfill for Object.keys
// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys
if ( !Object.keys ) {
Object.keys = (function () {
var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
dontEnums = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor'
],
dontEnumsLength = dontEnums.length;
return function ( obj ) {
if ( typeof obj !== 'object' && typeof obj !== 'function' || obj === null ) {
throw new TypeError( 'Object.keys called on non-object' );
}
var result = [];
for ( var prop in obj ) {
if ( hasOwnProperty.call( obj, prop ) ){
result.push( prop );
}
}
if ( hasDontEnumBug ) {
for ( var i=0; i < dontEnumsLength; i++ ) {
if ( hasOwnProperty.call( obj, dontEnums[i] ) ){
result.push( dontEnums[i] );
}
}
}
return result;
};
}());
}
// Array extras
if ( !Array.prototype.indexOf ) {
Array.prototype.indexOf = function ( needle, i ) {
var len;
if ( i === undefined ) {
i = 0;
}
if ( i < 0 ) {
i+= this.length;
}
if ( i < 0 ) {
i = 0;
}
for ( len = this.length; i<len; i++ ) {
if ( this.hasOwnProperty( i ) && this[i] === needle ) {
return i;
}
}
return -1;
};
}
if ( !Array.prototype.forEach ) {
Array.prototype.forEach = function ( callback, context ) {
var i, len;
for ( i=0, len=this.length; i<len; i+=1 ) {
if ( this.hasOwnProperty( i ) ) {
callback.call( context, this[i], i, this );
}
}
};
}
if ( !Array.prototype.map ) {
Array.prototype.map = function ( mapper, context ) {
var i, len, mapped = [];
for ( i=0, len=this.length; i<len; i+=1 ) {
if ( this.hasOwnProperty( i ) ) {
mapped[i] = mapper.call( context, this[i], i, this );
}
}
return mapped;
};
}
if ( !Array.prototype.filter ) {
Array.prototype.filter = function ( filter, context ) {
var i, len, filtered = [];
for ( i=0, len=this.length; i<len; i+=1 ) {
if ( this.hasOwnProperty( i ) && filter.call( context, this[i], i, this ) ) {
filtered[ filtered.length ] = this[i];
}
}
return filtered;
};
}
// https://gist.github.com/Rich-Harris/6010282 via https://gist.github.com/jonathantneal/2869388
// addEventListener polyfill IE6+
if ( !win.addEventListener ) {
(function ( win, doc ) {
var Event, addEventListener, removeEventListener, head, style, origCreateElement;
Event = function ( e, element ) {
var property, instance = this;
for ( property in e ) {
instance[ property ] = e[ property ];
}
instance.currentTarget = element;
instance.target = e.srcElement || element;
instance.timeStamp = +new Date();
instance.preventDefault = function () {
e.returnValue = false;
};
instance.stopPropagation = function () {
e.cancelBubble = true;
};
};
addEventListener = function ( type, listener ) {
var element = this, listeners, i;
listeners = element.listeners || ( element.listeners = [] );
i = listeners.length;
listeners[i] = [ listener, function (e) {
listener.call( element, new Event( e, element ) );
}];
element.attachEvent( 'on' + type, listeners[i][1] );
};
removeEventListener = function ( type, listener ) {
var element = this, listeners, i;
if ( !element.listeners ) {
return;
}
listeners = element.listeners;
i = listeners.length;
while ( i-- ) {
if (listeners[i][0] === listener) {
element.detachEvent( 'on' + type, listeners[i][1] );
}
}
};
win.addEventListener = doc.addEventListener = addEventListener;
win.removeEventListener = doc.removeEventListener = removeEventListener;
if ( 'Element' in win ) {
Element.prototype.addEventListener = addEventListener;
Element.prototype.removeEventListener = removeEventListener;
} else {
// First, intercept any calls to document.createElement - this is necessary
// because the CSS hack (see below) doesn't come into play until after a
// node is added to the DOM, which is too late for a lot of Ractive setup work
origCreateElement = doc.createElement;
doc.createElement = function ( tagName ) {
var el = origCreateElement( tagName );
el.addEventListener = addEventListener;
el.removeEventListener = removeEventListener;
return el;
};
// Then, mop up any additional elements that weren't created via
// document.createElement (i.e. with innerHTML).
head = doc.getElementsByTagName('head')[0];
style = doc.createElement('style');
head.insertBefore( style, head.firstChild );
//style.styleSheet.cssText = '*{-ms-event-prototype:expression(!this.addEventListener&&(this.addEventListener=addEventListener)&&(this.removeEventListener=removeEventListener))}';
}
}( win, doc ));
}
// https://github.com/jonathantneal/Polyfills-for-IE8/blob/master/getComputedStyle.js
if ( !win.getComputedStyle ) {
win.getComputedStyle = (function () {
function getPixelSize(element, style, property, fontSize) {
var
sizeWithSuffix = style[property],
size = parseFloat(sizeWithSuffix),
suffix = sizeWithSuffix.split(/\d/)[0],
rootSize;
fontSize = fontSize != null ? fontSize : /%|em/.test(suffix) && element.parentElement ? getPixelSize(element.parentElement, element.parentElement.currentStyle, 'fontSize', null) : 16;
rootSize = property == 'fontSize' ? fontSize : /width/i.test(property) ? element.clientWidth : element.clientHeight;
return (suffix == 'em') ? size * fontSize : (suffix == 'in') ? size * 96 : (suffix == 'pt') ? size * 96 / 72 : (suffix == '%') ? size / 100 * rootSize : size;
}
function setShortStyleProperty(style, property) {
var
borderSuffix = property == 'border' ? 'Width' : '',
t = property + 'Top' + borderSuffix,
r = property + 'Right' + borderSuffix,
b = property + 'Bottom' + borderSuffix,
l = property + 'Left' + borderSuffix;
style[property] = (style[t] == style[r] == style[b] == style[l] ? [style[t]]
: style[t] == style[b] && style[l] == style[r] ? [style[t], style[r]]
: style[l] == style[r] ? [style[t], style[r], style[b]]
: [style[t], style[r], style[b], style[l]]).join(' ');
}
function CSSStyleDeclaration(element) {
var currentStyle, style, fontSize, property;
currentStyle = element.currentStyle;
style = this;
fontSize = getPixelSize(element, currentStyle, 'fontSize', null);
for (property in currentStyle) {
if (/width|height|margin.|padding.|border.+W/.test(property) && style[property] !== 'auto') {
style[property] = getPixelSize(element, currentStyle, property, fontSize) + 'px';
} else if (property === 'styleFloat') {
style.float = currentStyle[property];
} else {
style[property] = currentStyle[property];
}
}
setShortStyleProperty(style, 'margin');
setShortStyleProperty(style, 'padding');
setShortStyleProperty(style, 'border');
style.fontSize = fontSize + 'px';
return style;
}
CSSStyleDeclaration.prototype = {
constructor: CSSStyleDeclaration,
getPropertyPriority: function () {},
getPropertyValue: function ( prop ) {
return this[prop] || '';
},
item: function () {},
removeProperty: function () {},
setProperty: function () {},
getPropertyCSSValue: function () {}
};
function getComputedStyle(element) {
return new CSSStyleDeclaration(element);
}
return getComputedStyle;
}());
}
}( typeof window !== 'undefined' ? window : this ));
(function ( global ) {
var utils_create = function () {
var create;
try {
Object.create(null);
create = Object.create;
} catch (err) {
create = function () {
var F = function () {
};
return function (proto, props) {
var obj;
if (proto === null) {
return {};
}
F.prototype = proto;
obj = new F();
if (props) {
Object.defineProperties(obj, props);
}
return obj;
};
}();
}
return create;
}();
var config_isClient = function () {
if (typeof document === 'object') {
return true;
}
return false;
}();
var utils_defineProperty = function (isClient) {
try {
Object.defineProperty({}, 'test', { value: 0 });
if (isClient) {
Object.defineProperty(document.createElement('div'), 'test', { value: 0 });
}
return Object.defineProperty;
} catch (err) {
return function (obj, prop, desc) {
obj[prop] = desc.value;
};
}
}(config_isClient);
var utils_defineProperties = function (defineProperty, isClient) {
try {
try {
Object.defineProperties({}, { test: { value: 0 } });
} catch (err) {
throw err;
}
if (isClient) {
Object.defineProperties(document.createElement('div'), { test: { value: 0 } });
}
return Object.defineProperties;
} catch (err) {
return function (obj, props) {
var prop;
for (prop in props) {
if (props.hasOwnProperty(prop)) {
defineProperty(obj, prop, props[prop]);
}
}
};
}
}(utils_defineProperty, config_isClient);
var utils_normaliseKeypath = function () {
var regex = /\[\s*(\*|[0-9]|[1-9][0-9]+)\s*\]/g;
return function (keypath) {
return keypath.replace(regex, '.$1');
};
}();
var registries_adaptors = {};
var config_types = {
TEXT: 1,
INTERPOLATOR: 2,
TRIPLE: 3,
SECTION: 4,
INVERTED: 5,
CLOSING: 6,
ELEMENT: 7,
PARTIAL: 8,
COMMENT: 9,
DELIMCHANGE: 10,
MUSTACHE: 11,
TAG: 12,
COMPONENT: 15,
NUMBER_LITERAL: 20,
STRING_LITERAL: 21,
ARRAY_LITERAL: 22,
OBJECT_LITERAL: 23,
BOOLEAN_LITERAL: 24,
GLOBAL: 26,
KEY_VALUE_PAIR: 27,
REFERENCE: 30,
REFINEMENT: 31,
MEMBER: 32,
PREFIX_OPERATOR: 33,
BRACKETED: 34,
CONDITIONAL: 35,
INFIX_OPERATOR: 36,
INVOCATION: 40
};
var utils_isArray = function () {
var toString = Object.prototype.toString;
return function (thing) {
return toString.call(thing) === '[object Array]';
};
}();
var shared_clearCache = function () {
return function clearCache(ractive, keypath) {
var cacheMap, wrappedProperty;
if (wrappedProperty = ractive._wrapped[keypath]) {
if (wrappedProperty.teardown() !== false) {
ractive._wrapped[keypath] = null;
}
}
ractive._cache[keypath] = undefined;
if (cacheMap = ractive._cacheMap[keypath]) {
while (cacheMap.length) {
clearCache(ractive, cacheMap.pop());
}
}
};
}();
var shared_getValueFromCheckboxes = function () {
return function (ractive, keypath) {
var value, checkboxes, checkbox, len, i, rootEl;
value = [];
rootEl = ractive.rendered ? ractive.el : ractive.fragment.docFrag;
checkboxes = rootEl.querySelectorAll('input[type="checkbox"][name="{{' + keypath + '}}"]');
len = checkboxes.length;
for (i = 0; i < len; i += 1) {
checkbox = checkboxes[i];
if (checkbox.hasAttribute('checked') || checkbox.checked) {
value[value.length] = checkbox._ractive.value;
}
}
return value;
};
}();
var shared_preDomUpdate = function (getValueFromCheckboxes) {
return function (ractive) {
var deferred, evaluator, selectValue, attribute, keypath, radio;
deferred = ractive._deferred;
while (evaluator = deferred.evals.pop()) {
evaluator.update().deferred = false;
}
while (selectValue = deferred.selectValues.pop()) {
selectValue.deferredUpdate();
}
while (attribute = deferred.attrs.pop()) {
attribute.update().deferred = false;
}
while (keypath = deferred.checkboxes.pop()) {
ractive.set(keypath, getValueFromCheckboxes(ractive, keypath));
}
while (radio = deferred.radios.pop()) {
radio.update();
}
};
}(shared_getValueFromCheckboxes);
var shared_postDomUpdate = function () {
return function (ractive) {
var deferred, focusable, query, decorator, transition, observer;
deferred = ractive._deferred;
if (focusable = deferred.focusable) {
focusable.focus();
deferred.focusable = null;
}
while (query = deferred.liveQueries.pop()) {
query._sort();
}
while (decorator = deferred.decorators.pop()) {
decorator.init();
}
while (transition = deferred.transitions.pop()) {
transition.init();
}
while (observer = deferred.observers.pop()) {
observer.update();
}
};
}();
var shared_makeTransitionManager = function () {
var makeTransitionManager = function (root, callback) {
var transitionManager, elementsToDetach, detachNodes, nodeHasNoTransitioningChildren;
elementsToDetach = [];
detachNodes = function () {
var i, element;
i = elementsToDetach.length;
while (i--) {
element = elementsToDetach[i];
if (nodeHasNoTransitioningChildren(element.node)) {
element.detach();
elementsToDetach.splice(i, 1);
}
}
};
nodeHasNoTransitioningChildren = function (node) {
var i, candidate;
i = transitionManager.active.length;
while (i--) {
candidate = transitionManager.active[i];
if (node.contains(candidate)) {
return false;
}
}
return true;
};
transitionManager = {
active: [],
push: function (node) {
transitionManager.active[transitionManager.active.length] = node;
},
pop: function (node) {
var index;
index = transitionManager.active.indexOf(node);
if (index === -1) {
return;
}
transitionManager.active.splice(index, 1);
detachNodes();
if (!transitionManager.active.length && transitionManager._ready) {
transitionManager.complete();
}
},
complete: function () {
if (callback) {
callback.call(root);
}
},
ready: function () {
detachNodes();
transitionManager._ready = true;
if (!transitionManager.active.length) {
transitionManager.complete();
}
},
detachWhenReady: function (element) {
elementsToDetach[elementsToDetach.length] = element;
}
};
return transitionManager;
};
return makeTransitionManager;
}();
var shared_notifyDependants = function () {
var notifyDependants, lastKey, starMaps = {};
lastKey = /[^\.]+$/;
notifyDependants = function (ractive, keypath, onlyDirect) {
var i;
if (ractive._patternObservers.length) {
notifyPatternObservers(ractive, keypath, keypath, onlyDirect, true);
}
for (i = 0; i < ractive._deps.length; i += 1) {
notifyDependantsAtPriority(ractive, keypath, i, onlyDirect);
}
};
notifyDependants.multiple = function (ractive, keypaths, onlyDirect) {
var i, j, len;
len = keypaths.length;
if (ractive._patternObservers.length) {
i = len;
while (i--) {
notifyPatternObservers(ractive, keypaths[i], keypaths[i], onlyDirect, true);
}
}
for (i = 0; i < ractive._deps.length; i += 1) {
if (ractive._deps[i]) {
j = len;
while (j--) {
notifyDependantsAtPriority(ractive, keypaths[j], i, onlyDirect);
}
}
}
};
return notifyDependants;
function notifyDependantsAtPriority(ractive, keypath, priority, onlyDirect) {
var depsByKeypath = ractive._deps[priority];
if (!depsByKeypath) {
return;
}
updateAll(depsByKeypath[keypath]);
if (onlyDirect) {
return;
}
cascade(ractive._depsMap[keypath], ractive, priority);
}
function updateAll(deps) {
var i, len;
if (deps) {
len = deps.length;
for (i = 0; i < len; i += 1) {
deps[i].update();
}
}
}
function cascade(childDeps, ractive, priority, onlyDirect) {
var i;
if (childDeps) {
i = childDeps.length;
while (i--) {
notifyDependantsAtPriority(ractive, childDeps[i], priority, onlyDirect);
}
}
}
function notifyPatternObservers(ractive, registeredKeypath, actualKeypath, isParentOfChangedKeypath, isTopLevelCall) {
var i, patternObserver, children, child, key, childActualKeypath, potentialWildcardMatches, cascade;
i = ractive._patternObservers.length;
while (i--) {
patternObserver = ractive._patternObservers[i];
if (patternObserver.regex.test(actualKeypath)) {
patternObserver.update(actualKeypath);
}
}
if (isParentOfChangedKeypath) {
return;
}
cascade = function (keypath) {
if (children = ractive._depsMap[keypath]) {
i = children.length;
while (i--) {
child = children[i];
key = lastKey.exec(child)[0];
childActualKeypath = actualKeypath + '.' + key;
notifyPatternObservers(ractive, child, childActualKeypath);
}
}
};
if (isTopLevelCall) {
potentialWildcardMatches = getPotentialWildcardMatches(actualKeypath);
potentialWildcardMatches.forEach(cascade);
} else {
cascade(registeredKeypath);
}
}
function getPotentialWildcardMatches(keypath) {
var keys, starMap, mapper, i, result, wildcardKeypath;
keys = keypath.split('.');
starMap = getStarMap(keys.length);
result = [];
mapper = function (star, i) {
return star ? '*' : keys[i];
};
i = starMap.length;
while (i--) {
wildcardKeypath = starMap[i].map(mapper).join('.');
if (!result[wildcardKeypath]) {
result[result.length] = wildcardKeypath;
result[wildcardKeypath] = true;
}
}
return result;
}
function getStarMap(num) {
var ones = '', max, binary, starMap, mapper, i;
if (!starMaps[num]) {
starMap = [];
while (ones.length < num) {
ones += 1;
}
max = parseInt(ones, 2);
mapper = function (digit) {
return digit === '1';
};
for (i = 0; i <= max; i += 1) {
binary = i.toString(2);
while (binary.length < num) {
binary = '0' + binary;
}
starMap[i] = Array.prototype.map.call(binary, mapper);
}
starMaps[num] = starMap;
}
return starMaps[num];
}
}();
var Ractive_prototype_get_arrayAdaptor = function (types, defineProperty, isArray, clearCache, preDomUpdate, postDomUpdate, makeTransitionManager, notifyDependants) {
var arrayAdaptor, notifyArrayDependants, ArrayWrapper, patchArrayMethods, unpatchArrayMethods, patchedArrayProto, testObj, mutatorMethods, noop, errorMessage;
arrayAdaptor = {
filter: function (ractive, object, keypath) {
return keypath.charAt(0) !== '(' && isArray(object) && (!object._ractive || !object._ractive.setting);
},
wrap: function (ractive, array, keypath) {
return new ArrayWrapper(ractive, array, keypath);
}
};
ArrayWrapper = function (ractive, array, keypath) {
this.root = ractive;
this.value = array;
this.keypath = keypath;
if (!array._ractive) {
defineProperty(array, '_ractive', {
value: {
wrappers: [],
instances: [],
setting: false
},
configurable: true
});
patchArrayMethods(array);
}
if (!array._ractive.instances[ractive._guid]) {
array._ractive.instances[ractive._guid] = 0;
array._ractive.instances.push(ractive);
}
array._ractive.instances[ractive._guid] += 1;
array._ractive.wrappers.push(this);
};
ArrayWrapper.prototype = {
get: function () {
return this.value;
},
teardown: function () {
var array, storage, wrappers, instances, index;
array = this.value;
storage = array._ractive;
wrappers = storage.wrappers;
instances = storage.instances;
if (storage.setting) {
return false;
}
index = wrappers.indexOf(this);
if (index === -1) {
throw new Error(errorMessage);
}
wrappers.splice(index, 1);
if (!wrappers.length) {
delete array._ractive;
unpatchArrayMethods(this.value);
} else {
instances[this.root._guid] -= 1;
if (!instances[this.root._guid]) {
index = instances.indexOf(this.root);
if (index === -1) {
throw new Error(errorMessage);
}
instances.splice(index, 1);
}
}
}
};
notifyArrayDependants = function (array, methodName, args) {
var notifyKeypathDependants, queueDependants, wrappers, wrapper, i;
notifyKeypathDependants = function (root, keypath) {
var depsByKeypath, deps, keys, upstreamQueue, smartUpdateQueue, dumbUpdateQueue, i, changed, start, end, childKeypath, lengthUnchanged;
if (methodName === 'sort' || methodName === 'reverse') {
root.set(keypath, array);
return;
}
clearCache(root, keypath);
smartUpdateQueue = [];
dumbUpdateQueue = [];
for (i = 0; i < root._deps.length; i += 1) {
depsByKeypath = root._deps[i];
if (!depsByKeypath) {
continue;
}
deps = depsByKeypath[keypath];
if (deps) {
queueDependants(keypath, deps, smartUpdateQueue, dumbUpdateQueue);
preDomUpdate(root);
while (smartUpdateQueue.length) {
smartUpdateQueue.pop().smartUpdate(methodName, args);
}
while (dumbUpdateQueue.length) {
dumbUpdateQueue.pop().update();
}
}
}
if (methodName === 'splice' && args.length > 2 && args[1]) {
changed = Math.min(args[1], args.length - 2);
start = args[0];
end = start + changed;
if (args[1] === args.length - 2) {
lengthUnchanged = true;
}
for (i = start; i < end; i += 1) {
childKeypath = keypath + '.' + i;
notifyDependants(root, childKeypath);
}
}
preDomUpdate(root);
upstreamQueue = [];
keys = keypath.split('.');
while (keys.length) {
keys.pop();
upstreamQueue[upstreamQueue.length] = keys.join('.');
}
notifyDependants.multiple(root, upstreamQueue, true);
if (!lengthUnchanged) {
notifyDependants(root, keypath + '.length', true);
}
};
queueDependants = function (keypath, deps, smartUpdateQueue, dumbUpdateQueue) {
var k, dependant;
k = deps.length;
while (k--) {
dependant = deps[k];
if (dependant.type === types.REFERENCE) {
dependant.update();
} else if (dependant.keypath === keypath && dependant.type === types.SECTION && !dependant.inverted && dependant.pNode) {
smartUpdateQueue[smartUpdateQueue.length] = dependant;
} else {
dumbUpdateQueue[dumbUpdateQueue.length] = dependant;
}
}
};
wrappers = array._ractive.wrappers;
i = wrappers.length;
while (i--) {
wrapper = wrappers[i];
notifyKeypathDependants(wrapper.root, wrapper.keypath);
}
};
patchedArrayProto = [];
mutatorMethods = [
'pop',
'push',
'reverse',
'shift',
'sort',
'splice',
'unshift'
];
noop = function () {
};
mutatorMethods.forEach(function (methodName) {
var method = function () {
var result, instances, instance, i, previousTransitionManagers = {}, transitionManagers = {};
result = Array.prototype[methodName].apply(this, arguments);
instances = this._ractive.instances;
i = instances.length;
while (i--) {
instance = instances[i];
previousTransitionManagers[instance._guid] = instance._transitionManager;
instance._transitionManager = transitionManagers[instance._guid] = makeTransitionManager(instance, noop);
}
this._ractive.setting = true;
notifyArrayDependants(this, methodName, arguments);
this._ractive.setting = false;
i = instances.length;
while (i--) {
instance = instances[i];
instance._transitionManager = previousTransitionManagers[instance._guid];
transitionManagers[instance._guid].ready();
preDomUpdate(instance);
postDomUpdate(instance);
}
return result;
};
defineProperty(patchedArrayProto, methodName, { value: method });
});
testObj = {};
if (testObj.__proto__) {
patchArrayMethods = function (array) {
array.__proto__ = patchedArrayProto;
};
unpatchArrayMethods = function (array) {
array.__proto__ = Array.prototype;
};
} else {
patchArrayMethods = function (array) {
var i, methodName;
i = mutatorMethods.length;
while (i--) {
methodName = mutatorMethods[i];
defineProperty(array, methodName, {
value: patchedArrayProto[methodName],
configurable: true
});
}
};
unpatchArrayMethods = function (array) {
var i;
i = mutatorMethods.length;
while (i--) {
delete array[mutatorMethods[i]];
}
};
}
errorMessage = 'Something went wrong in a rather interesting way';
return arrayAdaptor;
}(config_types, utils_defineProperty, utils_isArray, shared_clearCache, shared_preDomUpdate, shared_postDomUpdate, shared_makeTransitionManager, shared_notifyDependants);
var Ractive_prototype_get_magicAdaptor = function () {
var magicAdaptor, MagicWrapper;
try {
Object.defineProperty({}, 'test', { value: 0 });
} catch (err) {
return false;
}
magicAdaptor = {
wrap: function (ractive, object, keypath) {
return new MagicWrapper(ractive, object, keypath);
}
};
MagicWrapper = function (ractive, object, keypath) {
var wrapper = this, keys, prop, objKeypath, descriptor, wrappers, oldGet, oldSet, get, set;
this.ractive = ractive;
this.keypath = keypath;
keys = keypath.split('.');
this.prop = keys.pop();
objKeypath = keys.join('.');
this.obj = ractive.get(objKeypath);
descriptor = this.originalDescriptor = Object.getOwnPropertyDescriptor(this.obj, this.prop);
if (descriptor && descriptor.set && (wrappers = descriptor.set._ractiveWrappers)) {
if (wrappers.indexOf(this) === -1) {
wrappers[wrappers.length] = this;
}
return;
}
if (descriptor && !descriptor.configurable) {
throw new Error('Cannot use magic mode with property "' + prop + '" - object is not configurable');
}
if (descriptor) {
this.value = descriptor.value;
oldGet = descriptor.get;
oldSet = descriptor.set;
}
get = oldGet || function () {
return wrapper.value;
};
set = function (value) {
var wrappers, wrapper, i;
if (oldSet) {
oldSet(value);
}
wrappers = set._ractiveWrappers;
i = wrappers.length;
while (i--) {
wrapper = wrappers[i];
if (!wrapper.resetting) {
wrapper.ractive.set(wrapper.keypath, value);
}
}
};
set._ractiveWrappers = [this];
Object.defineProperty(this.obj, this.prop, {
get: get,
set: set,
enumerable: true,
configurable: true
});
};
MagicWrapper.prototype = {
get: function () {
return this.value;
},
reset: function (value) {
this.resetting = true;
this.value = value;
this.obj[this.prop] = value;
this.resetting = false;
},
teardown: function () {
var descriptor, set, value, wrappers;
descriptor = Object.getOwnPropertyDescriptor(this.obj, this.prop);
set = descriptor.set;
wrappers = set._ractiveWrappers;
wrappers.splice(wrappers.indexOf(this), 1);
if (!wrappers.length) {
value = this.obj[this.prop];
Object.defineProperty(this.obj, this.prop, this.originalDescriptor);
this.obj[this.prop] = value;
}
}
};
return magicAdaptor;
}();
var Ractive_prototype_get__get = function (normaliseKeypath, adaptorRegistry, arrayAdaptor, magicAdaptor) {
var get, _get, retrieve, prefix, getPrefixer, prefixers = {}, adaptIfNecessary;
get = function (keypath) {
return _get(this, keypath);
};
_get = function (ractive, keypath) {
var cache, cached, value, wrapped, evaluator;
keypath = normaliseKeypath(keypath || '');
cache = ractive._cache;
if ((cached = cache[keypath]) !== undefined) {
return cached;
}
if (wrapped = ractive._wrapped[keypath]) {
value = wrapped.value;
} else if (!keypath) {
adaptIfNecessary(ractive, '', ractive.data);
value = ractive.data;
} else if (evaluator = ractive._evaluators[keypath]) {
value = evaluator.value;
} else {
value = retrieve(ractive, keypath);
}
cache[keypath] = value;
return value;
};
retrieve = function (ractive, keypath) {
var keys, key, parentKeypath, parentValue, cacheMap, value, wrapped;
keys = keypath.split('.');
key = keys.pop();
parentKeypath = keys.join('.');
parentValue = _get(ractive, parentKeypath);
if (wrapped = ractive._wrapped[parentKeypath]) {
parentValue = wrapped.get();
}
if (parentValue === null || parentValue === undefined) {
return;
}
if (!(cacheMap = ractive._cacheMap[parentKeypath])) {
ractive._cacheMap[parentKeypath] = [keypath];
} else {
if (cacheMap.indexOf(keypath) === -1) {
cacheMap[cacheMap.length] = keypath;
}
}
value = parentValue[key];
if (adaptIfNecessary(ractive, keypath, value)) {
return value;
}
if (ractive.magic) {
ractive._wrapped[keypath] = magicAdaptor.wrap(ractive, value, keypath);
}
if (ractive.modifyArrays) {
if (arrayAdaptor.filter(ractive, value, keypath)) {
ractive._wrapped[keypath] = arrayAdaptor.wrap(ractive, value, keypath);
}
}
ractive._cache[keypath] = value;
return value;
};
prefix = function (obj, prefix) {
var prefixed = {}, key;
if (!prefix) {
return obj;
}
prefix += '.';
for (key in obj) {
if (obj.hasOwnProperty(key)) {
prefixed[prefix + key] = obj[key];
}
}
return prefixed;
};
getPrefixer = function (rootKeypath) {
var rootDot;
if (!prefixers[rootKeypath]) {
rootDot = rootKeypath ? rootKeypath + '.' : '';
prefixers[rootKeypath] = function (relativeKeypath, value) {
var obj;
if (typeof relativeKeypath === 'string') {
obj = {};
obj[rootDot + relativeKeypath] = value;
return obj;
}
if (typeof relativeKeypath === 'object') {
return rootDot ? prefix(relativeKeypath, rootKeypath) : relativeKeypath;
}
};
}
return prefixers[rootKeypath];
};
adaptIfNecessary = function (ractive, keypath, value) {
var i, adaptor, wrapped;
i = ractive.adaptors.length;
while (i--) {
adaptor = ractive.adaptors[i];
if (typeof adaptor === 'string') {
if (!adaptorRegistry[adaptor]) {
throw new Error('Missing adaptor "' + adaptor + '"');
}
adaptor = ractive.adaptors[i] = adaptorRegistry[adaptor];
}
if (adaptor.filter(value, keypath, ractive)) {
wrapped = ractive._wrapped[keypath] = adaptor.wrap(ractive, value, keypath, getPrefixer(keypath));
ractive._cache[keypath] = value;
return true;
}
}
};
return get;
}(utils_normaliseKeypath, registries_adaptors, Ractive_prototype_get_arrayAdaptor, Ractive_prototype_get_magicAdaptor);
var utils_isObject = function () {
var toString = Object.prototype.toString;
return function (thing) {
return typeof thing === 'object' && toString.call(thing) === '[object Object]';
};
}();
var utils_isEqual = function () {
return function (a, b) {
if (a === null && b === null) {
return true;
}
if (typeof a === 'object' || typeof b === 'object') {
return false;
}
return a === b;
};
}();
var shared_resolveRef = function () {
var resolveRef;
resolveRef = function (ractive, ref, contextStack) {
var keys, lastKey, contextKeys, innerMostContext, postfix, parentKeypath, parentValue, wrapped, keypath, context, ancestorErrorMessage;
ancestorErrorMessage = 'Could not resolve reference - too many "../" prefixes';
if (ref === '.') {
if (!contextStack.length) {
return '';
}
return contextStack[contextStack.length - 1];
}
if (ref.charAt(0) === '.') {
context = contextStack[contextStack.length - 1];
contextKeys = context ? context.split('.') : [];
if (ref.substr(0, 3) === '../') {
while (ref.substr(0, 3) === '../') {
if (!contextKeys.length) {
throw new Error(ancestorErrorMessage);
}
contextKeys.pop();
ref = ref.substring(3);
}
contextKeys.push(ref);
return contextKeys.join('.');
}
if (!context) {
return ref.substring(1);
}
return context + ref;
}
keys = ref.split('.');
lastKey = keys.pop();
postfix = keys.length ? '.' + keys.join('.') : '';
contextStack = contextStack.concat();
while (contextStack.length) {
innerMostContext = contextStack.pop();
parentKeypath = innerMostContext + postfix;
parentValue = ractive.get(parentKeypath);
if (wrapped = ractive._wrapped[parentKeypath]) {
parentValue = wrapped.get();
}
if (typeof parentValue === 'object' && parentValue !== null && parentValue.hasOwnProperty(lastKey)) {
keypath = innerMostContext + '.' + ref;
break;
}
}
if (!keypath && ractive.get(ref) !== undefined) {
keypath = ref;
}
return keypath;
};
return resolveRef;
}();
var shared_attemptKeypathResolution = function (resolveRef) {
var push = Array.prototype.push;
return function (ractive) {
var unresolved, keypath, leftover;
while (unresolved = ractive._pendingResolution.pop()) {
keypath = resolveRef(ractive, unresolved.ref, unresolved.contextStack);
if (keypath !== undefined) {
unresolved.resolve(keypath);
} else {
(leftover || (leftover = [])).push(unresolved);
}
}
if (leftover) {
push.apply(ractive._pendingResolution, leftover);
}
};
}(shared_resolveRef);
var shared_processDeferredUpdates = function (preDomUpdate, postDomUpdate) {
return function (ractive) {
preDomUpdate(ractive);
postDomUpdate(ractive);
};
}(shared_preDomUpdate, shared_postDomUpdate);
var Ractive_prototype_shared_replaceData = function () {
return function (ractive, keypath, value) {
var keys, accumulated, wrapped, obj, key, currentKeypath, keypathToClear;
keys = keypath.split('.');
accumulated = [];
if (wrapped = ractive._wrapped['']) {
if (wrapped.set) {
wrapped.set(keys.join('.'), value);
}
obj = wrapped.get();
} else {
obj = ractive.data;
}
while (keys.length > 1) {
key = accumulated[accumulated.length] = keys.shift();
currentKeypath = accumulated.join('.');
if (wrapped = ractive._wrapped[currentKeypath]) {
if (wrapped.set) {
wrapped.set(keys.join('.'), value);
}
obj = wrapped.get();
} else {
if (!obj[key]) {
if (!keypathToClear) {
keypathToClear = currentKeypath;
}
obj[key] = /^\s*[0-9]+\s*$/.test(keys[0]) ? [] : {};
}
obj = obj[key];
}
}
key = keys[0];
obj[key] = value;
return keypathToClear;
};
}();
var Ractive_prototype_set = function (isObject, isEqual, normaliseKeypath, clearCache, notifyDependants, attemptKeypathResolution, makeTransitionManager, processDeferredUpdates, replaceData) {
var set, updateModel, getUpstreamChanges, resetWrapped;
set = function (keypath, value, complete) {
var map, changes, upstreamChanges, previousTransitionManager, transitionManager, i, changeHash;
changes = [];
if (isObject(keypath)) {
map = keypath;
complete = value;
}
if (map) {
for (keypath in map) {
if (map.hasOwnProperty(keypath)) {
value = map[keypath];
keypath = normaliseKeypath(keypath);
updateModel(this, keypath, value, changes);
}
}
} else {
keypath = normaliseKeypath(keypath);
updateModel(this, keypath, value, changes);
}
if (!changes.length) {
return;
}
previousTransitionManager = this._transitionManager;
this._transitionManager = transitionManager = makeTransitionManager(this, complete);
upstreamChanges = getUpstreamChanges(changes);
if (upstreamChanges.length) {
notifyDependants.multiple(this, upstreamChanges, true);
}
notifyDependants.multiple(this, changes);
if (this._pendingResolution.length) {
attemptKeypathResolution(this);
}
processDeferredUpdates(this);
this._transitionManager = previousTransitionManager;
transitionManager.ready();
if (!this.firingChangeEvent) {
this.firingChangeEvent = true;
changeHash = {};
i = changes.length;
while (i--) {
changeHash[changes[i]] = this.get(changes[i]);
}
this.fire('change', changeHash);
this.firingChangeEvent = false;
}
return this;
};
updateModel = function (ractive, keypath, value, changes) {
var cached, previous, wrapped, keypathToClear;
if ((wrapped = ractive._wrapped[keypath]) && wrapped.reset) {
if (resetWrapped(ractive, keypath, value, wrapped, changes) !== false) {
return;
}
}
cached = ractive._cache[keypath];
previous = ractive.get(keypath);
if (previous !== value) {
keypathToClear = replaceData(ractive, keypath, value);
} else {
if (value === cached && typeof value !== 'object') {
return;
}
}
clearCache(ractive, keypathToClear || keypath);
changes[changes.length] = keypath;
};
getUpstreamChanges = function (changes) {
var upstreamChanges = [''], i, keypath, keys, upstreamKeypath;
i = changes.length;
while (i--) {
keypath = changes[i];
keys = keypath.split('.');
while (keys.length > 1) {
keys.pop();
upstreamKeypath = keys.join('.');
if (!upstreamChanges[upstreamKeypath]) {
upstreamChanges[upstreamChanges.length] = upstreamKeypath;
upstreamChanges[upstreamKeypath] = true;
}
}
}
return upstreamChanges;
};
resetWrapped = function (ra