/*
Ractive.js v0.7.3
Sat Apr 25 2015 13:52:38 GMT-0400 (EDT) - commit da40f81c660ba2f09c45a09a9c20fdd34ee36d80
http://ractivejs.org
http://twitter.com/RactiveJS
Released under the MIT License.
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
global.Ractive = factory()
}(this, function () { 'use strict';
var TEMPLATE_VERSION = 3;
var defaultOptions = {
// render placement:
el: void 0,
append: false,
// template:
template: { v: TEMPLATE_VERSION, t: [] },
// parse: // TODO static delimiters?
preserveWhitespace: false,
sanitize: false,
stripComments: true,
delimiters: ["{{", "}}"],
tripleDelimiters: ["{{{", "}}}"],
interpolate: false,
// data & binding:
data: {},
computed: {},
magic: false,
modifyArrays: true,
adapt: [],
isolated: false,
twoway: true,
lazy: false,
// transitions:
noIntro: false,
transitionsEnabled: true,
complete: void 0,
// css:
css: null,
noCssTransform: false
};
var config_defaults = defaultOptions;
// These are a subset of the easing equations found at
// https://raw.github.com/danro/easing-js - license info
// follows:
// --------------------------------------------------
// easing.js v0.5.4
// Generic set of easing functions with AMD support
// https://github.com/danro/easing-js
// This code may be freely distributed under the MIT license
// http://danro.mit-license.org/
// --------------------------------------------------
// All functions adapted from Thomas Fuchs & Jeremy Kahn
// Easing Equations (c) 2003 Robert Penner, BSD license
// https://raw.github.com/danro/easing-js/master/LICENSE
// --------------------------------------------------
// In that library, the functions named easeIn, easeOut, and
// easeInOut below are named easeInCubic, easeOutCubic, and
// (you guessed it) easeInOutCubic.
//
// You can add additional easing functions to this list, and they
// will be globally available.
var static_easing = {
linear: function (pos) {
return pos;
},
easeIn: function (pos) {
return Math.pow(pos, 3);
},
easeOut: function (pos) {
return Math.pow(pos - 1, 3) + 1;
},
easeInOut: function (pos) {
if ((pos /= 0.5) < 1) {
return 0.5 * Math.pow(pos, 3);
}
return 0.5 * (Math.pow(pos - 2, 3) + 2);
}
};
/*global console, navigator */
var isClient, isJsdom, hasConsole, environment__magic, namespaces, svg, vendors;
isClient = typeof document === "object";
isJsdom = typeof navigator !== "undefined" && /jsDom/.test(navigator.appName);
hasConsole = typeof console !== "undefined" && typeof console.warn === "function" && typeof console.warn.apply === "function";
try {
Object.defineProperty({}, "test", { value: 0 });
environment__magic = true;
} catch (e) {
environment__magic = false;
}
namespaces = {
html: "http://www.w3.org/1999/xhtml",
mathml: "http://www.w3.org/1998/Math/MathML",
svg: "http://www.w3.org/2000/svg",
xlink: "http://www.w3.org/1999/xlink",
xml: "http://www.w3.org/XML/1998/namespace",
xmlns: "http://www.w3.org/2000/xmlns/"
};
if (typeof document === "undefined") {
svg = false;
} else {
svg = document && document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1");
}
vendors = ["o", "ms", "moz", "webkit"];
var createElement, matches, dom__div, methodNames, unprefixed, prefixed, dom__i, j, makeFunction;
// Test for SVG support
if (!svg) {
createElement = function (type, ns) {
if (ns && ns !== namespaces.html) {
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 http://docs.ractivejs.org/latest/svg-and-older-browsers for more information";
}
return document.createElement(type);
};
} else {
createElement = function (type, ns) {
if (!ns || ns === namespaces.html) {
return document.createElement(type);
}
return document.createElementNS(ns, type);
};
}
function getElement(input) {
var output;
if (!input || typeof input === "boolean") {
return;
}
if (typeof window === "undefined" || !document || !input) {
return null;
}
// We already have a DOM node - no work to do. (Duck typing alert!)
if (input.nodeType) {
return input;
}
// Get node from string
if (typeof input === "string") {
// try ID first
output = document.getElementById(input);
// then as selector, if possible
if (!output && document.querySelector) {
output = document.querySelector(input);
}
// did it work?
if (output && output.nodeType) {
return output;
}
}
// If we've been given a collection (jQuery, Zepto etc), extract the first item
if (input[0] && input[0].nodeType) {
return input[0];
}
return null;
}
if (!isClient) {
matches = null;
} else {
dom__div = createElement("div");
methodNames = ["matches", "matchesSelector"];
makeFunction = function (methodName) {
return function (node, selector) {
return node[methodName](selector);
};
};
dom__i = methodNames.length;
while (dom__i-- && !matches) {
unprefixed = methodNames[dom__i];
if (dom__div[unprefixed]) {
matches = makeFunction(unprefixed);
} else {
j = vendors.length;
while (j--) {
prefixed = vendors[dom__i] + unprefixed.substr(0, 1).toUpperCase() + unprefixed.substring(1);
if (dom__div[prefixed]) {
matches = makeFunction(prefixed);
break;
}
}
}
}
// IE8...
if (!matches) {
matches = function (node, selector) {
var nodes, parentNode, i;
parentNode = node.parentNode;
if (!parentNode) {
// empty dummy
dom__div.innerHTML = "";
parentNode = dom__div;
node = node.cloneNode();
dom__div.appendChild(node);
}
nodes = parentNode.querySelectorAll(selector);
i = nodes.length;
while (i--) {
if (nodes[i] === node) {
return true;
}
}
return false;
};
}
}
function detachNode(node) {
if (node && typeof node.parentNode !== "unknown" && node.parentNode) {
node.parentNode.removeChild(node);
}
return node;
}
function safeToStringValue(value) {
return value == null || !value.toString ? "" : value;
}
var legacy = null;
var create, defineProperty, defineProperties;
try {
Object.defineProperty({}, "test", { value: 0 });
if (isClient) {
Object.defineProperty(document.createElement("div"), "test", { value: 0 });
}
defineProperty = Object.defineProperty;
} catch (err) {
// Object.defineProperty doesn't exist, or we're in IE8 where you can
// only use it with DOM objects (what were you smoking, MSFT?)
defineProperty = function (obj, prop, desc) {
obj[prop] = desc.value;
};
}
try {
try {
Object.defineProperties({}, { test: { value: 0 } });
} catch (err) {
// TODO how do we account for this? noMagic = true;
throw err;
}
if (isClient) {
Object.defineProperties(createElement("div"), { test: { value: 0 } });
}
defineProperties = Object.defineProperties;
} catch (err) {
defineProperties = function (obj, props) {
var prop;
for (prop in props) {
if (props.hasOwnProperty(prop)) {
defineProperty(obj, prop, props[prop]);
}
}
};
}
try {
Object.create(null);
create = Object.create;
} catch (err) {
// sigh
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;
};
})();
}
function utils_object__extend(target) {
for (var _len = arguments.length, sources = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
sources[_key - 1] = arguments[_key];
}
var prop, source;
while (source = sources.shift()) {
for (prop in source) {
if (hasOwn.call(source, prop)) {
target[prop] = source[prop];
}
}
}
return target;
}
function fillGaps(target) {
for (var _len = arguments.length, sources = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
sources[_key - 1] = arguments[_key];
}
sources.forEach(function (s) {
for (var key in s) {
if (s.hasOwnProperty(key) && !(key in target)) {
target[key] = s[key];
}
}
});
return target;
}
var hasOwn = Object.prototype.hasOwnProperty;
// thanks, http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/
var is__toString = Object.prototype.toString,
arrayLikePattern = /^\[object (?:Array|FileList)\]$/;
function isArray(thing) {
return is__toString.call(thing) === "[object Array]";
}
function isArrayLike(obj) {
return arrayLikePattern.test(is__toString.call(obj));
}
function isEqual(a, b) {
if (a === null && b === null) {
return true;
}
if (typeof a === "object" || typeof b === "object") {
return false;
}
return a === b;
}
function is__isNumeric(thing) {
return !isNaN(parseFloat(thing)) && isFinite(thing);
}
function isObject(thing) {
return thing && is__toString.call(thing) === "[object Object]";
}
var noop = function () {};
/* global console */
var alreadyWarned = {},
log,
printWarning,
welcome;
if (hasConsole) {
(function () {
var welcomeIntro = ["%cRactive.js %c0.7.3 %cin debug mode, %cmore...", "color: rgb(114, 157, 52); font-weight: normal;", "color: rgb(85, 85, 85); font-weight: normal;", "color: rgb(85, 85, 85); font-weight: normal;", "color: rgb(82, 140, 224); font-weight: normal; text-decoration: underline;"];
var welcomeMessage = "You're running Ractive 0.7.3 in debug mode - messages will be printed to the console to help you fix problems and optimise your application.\n\nTo disable debug mode, add this line at the start of your app:\n Ractive.DEBUG = false;\n\nTo disable debug mode when your app is minified, add this snippet:\n Ractive.DEBUG = /unminified/.test(function(){/*unminified*/});\n\nGet help and support:\n http://docs.ractivejs.org\n http://stackoverflow.com/questions/tagged/ractivejs\n http://groups.google.com/forum/#!forum/ractive-js\n http://twitter.com/ractivejs\n\nFound a bug? Raise an issue:\n https://github.com/ractivejs/ractive/issues\n\n";
welcome = function () {
var hasGroup = !!console.groupCollapsed;
console[hasGroup ? "groupCollapsed" : "log"].apply(console, welcomeIntro);
console.log(welcomeMessage);
if (hasGroup) {
console.groupEnd(welcomeIntro);
}
welcome = noop;
};
printWarning = function (message, args) {
welcome();
// extract information about the instance this message pertains to, if applicable
if (typeof args[args.length - 1] === "object") {
var options = args.pop();
var ractive = options ? options.ractive : null;
if (ractive) {
// if this is an instance of a component that we know the name of, add
// it to the message
var _name = undefined;
if (ractive.component && (_name = ractive.component.name)) {
message = "<" + _name + "> " + message;
}
var node = undefined;
if (node = options.node || ractive.fragment && ractive.fragment.rendered && ractive.find("*")) {
args.push(node);
}
}
}
console.warn.apply(console, ["%cRactive.js: %c" + message, "color: rgb(114, 157, 52);", "color: rgb(85, 85, 85);"].concat(args));
};
log = function () {
console.log.apply(console, arguments);
};
})();
} else {
printWarning = log = welcome = noop;
}
function format(message, args) {
return message.replace(/%s/g, function () {
return args.shift();
});
}
function fatal(message) {
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
message = format(message, args);
throw new Error(message);
}
function logIfDebug() {
if (_Ractive.DEBUG) {
log.apply(null, arguments);
}
}
function warn(message) {
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
message = format(message, args);
printWarning(message, args);
}
function warnOnce(message) {
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
message = format(message, args);
if (alreadyWarned[message]) {
return;
}
alreadyWarned[message] = true;
printWarning(message, args);
}
function warnIfDebug() {
if (_Ractive.DEBUG) {
warn.apply(null, arguments);
}
}
function warnOnceIfDebug() {
if (_Ractive.DEBUG) {
warnOnce.apply(null, arguments);
}
}
// Error messages that are used (or could be) in multiple places
var badArguments = "Bad arguments";
var noRegistryFunctionReturn = "A function was specified for \"%s\" %s, but no %s was returned";
var missingPlugin = function (name, type) {
return "Missing \"" + name + "\" " + type + " plugin. You may need to download a plugin via http://docs.ractivejs.org/latest/plugins#" + type + "s";
};
function findInViewHierarchy(registryName, ractive, name) {
var instance = findInstance(registryName, ractive, name);
return instance ? instance[registryName][name] : null;
}
function findInstance(registryName, ractive, name) {
while (ractive) {
if (name in ractive[registryName]) {
return ractive;
}
if (ractive.isolated) {
return null;
}
ractive = ractive.parent;
}
}
var interpolate = function (from, to, ractive, type) {
if (from === to) {
return snap(to);
}
if (type) {
var interpol = findInViewHierarchy("interpolators", ractive, type);
if (interpol) {
return interpol(from, to) || snap(to);
}
fatal(missingPlugin(type, "interpolator"));
}
return static_interpolators.number(from, to) || static_interpolators.array(from, to) || static_interpolators.object(from, to) || snap(to);
};
var shared_interpolate = interpolate;
function snap(to) {
return function () {
return to;
};
}
var interpolators = {
number: function (from, to) {
var delta;
if (!is__isNumeric(from) || !is__isNumeric(to)) {
return null;
}
from = +from;
to = +to;
delta = to - from;
if (!delta) {
return function () {
return from;
};
}
return function (t) {
return from + t * delta;
};
},
array: function (from, to) {
var intermediate, interpolators, len, i;
if (!isArray(from) || !isArray(to)) {
return null;
}
intermediate = [];
interpolators = [];
i = len = Math.min(from.length, to.length);
while (i--) {
interpolators[i] = shared_interpolate(from[i], to[i]);
}
// surplus values - don't interpolate, but don't exclude them either
for (i = len; i < from.length; i += 1) {
intermediate[i] = from[i];
}
for (i = len; i < to.length; i += 1) {
intermediate[i] = to[i];
}
return function (t) {
var i = len;
while (i--) {
intermediate[i] = interpolators[i](t);
}
return intermediate;
};
},
object: function (from, to) {
var properties, len, interpolators, intermediate, prop;
if (!isObject(from) || !isObject(to)) {
return null;
}
properties = [];
intermediate = {};
interpolators = {};
for (prop in from) {
if (hasOwn.call(from, prop)) {
if (hasOwn.call(to, prop)) {
properties.push(prop);
interpolators[prop] = shared_interpolate(from[prop], to[prop]);
} else {
intermediate[prop] = from[prop];
}
}
}
for (prop in to) {
if (hasOwn.call(to, prop) && !hasOwn.call(from, prop)) {
intermediate[prop] = to[prop];
}
}
len = properties.length;
return function (t) {
var i = len,
prop;
while (i--) {
prop = properties[i];
intermediate[prop] = interpolators[prop](t);
}
return intermediate;
};
}
};
var static_interpolators = interpolators;
// This function takes a keypath such as 'foo.bar.baz', and returns
// all the variants of that keypath that include a wildcard in place
// of a key, such as 'foo.bar.*', 'foo.*.baz', 'foo.*.*' and so on.
// These are then checked against the dependants map (ractive.viewmodel.depsMap)
// to see if any pattern observers are downstream of one or more of
// these wildcard keypaths (e.g. 'foo.bar.*.status')
var utils_getPotentialWildcardMatches = getPotentialWildcardMatches;
var starMaps = {};
function getPotentialWildcardMatches(keypath) {
var keys, starMap, mapper, i, result, wildcardKeypath;
keys = keypath.split(".");
if (!(starMap = starMaps[keys.length])) {
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.hasOwnProperty(wildcardKeypath)) {
result.push(wildcardKeypath);
result[wildcardKeypath] = true;
}
}
return result;
}
// This function returns all the possible true/false combinations for
// a given number - e.g. for two, the possible combinations are
// [ true, true ], [ true, false ], [ false, true ], [ false, false ].
// It does so by getting all the binary values between 0 and e.g. 11
function getStarMap(num) {
var ones = "",
max,
binary,
starMap,
mapper,
i,
j,
l,
map;
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;
}
map = [];
l = binary.length;
for (j = 0; j < l; j++) {
map.push(mapper(binary[j]));
}
starMap[i] = map;
}
starMaps[num] = starMap;
}
return starMaps[num];
}
var refPattern = /\[\s*(\*|[0-9]|[1-9][0-9]+)\s*\]/g;
var patternPattern = /\*/;
var keypathCache = {};
var Keypath = function (str) {
var keys = str.split(".");
this.str = str;
if (str[0] === "@") {
this.isSpecial = true;
this.value = decodeKeypath(str);
}
this.firstKey = keys[0];
this.lastKey = keys.pop();
this.isPattern = patternPattern.test(str);
this.parent = str === "" ? null : getKeypath(keys.join("."));
this.isRoot = !str;
};
Keypath.prototype = {
equalsOrStartsWith: function (keypath) {
return keypath === this || this.startsWith(keypath);
},
join: function (str) {
return getKeypath(this.isRoot ? String(str) : this.str + "." + str);
},
replace: function (oldKeypath, newKeypath) {
if (this === oldKeypath) {
return newKeypath;
}
if (this.startsWith(oldKeypath)) {
return newKeypath === null ? newKeypath : getKeypath(this.str.replace(oldKeypath.str + ".", newKeypath.str + "."));
}
},
startsWith: function (keypath) {
if (!keypath) {
// TODO under what circumstances does this happen?
return false;
}
return keypath && this.str.substr(0, keypath.str.length + 1) === keypath.str + ".";
},
toString: function () {
throw new Error("Bad coercion");
},
valueOf: function () {
throw new Error("Bad coercion");
},
wildcardMatches: function () {
return this._wildcardMatches || (this._wildcardMatches = utils_getPotentialWildcardMatches(this.str));
}
};
function assignNewKeypath(target, property, oldKeypath, newKeypath) {
var existingKeypath = target[property];
if (existingKeypath && (existingKeypath.equalsOrStartsWith(newKeypath) || !existingKeypath.equalsOrStartsWith(oldKeypath))) {
return;
}
target[property] = existingKeypath ? existingKeypath.replace(oldKeypath, newKeypath) : newKeypath;
return true;
}
function decodeKeypath(keypath) {
var value = keypath.slice(2);
if (keypath[1] === "i") {
return is__isNumeric(value) ? +value : value;
} else {
return value;
}
}
function getKeypath(str) {
if (str == null) {
return str;
}
// TODO it *may* be worth having two versions of this function - one where
// keypathCache inherits from null, and one for IE8. Depends on how
// much of an overhead hasOwnProperty is - probably negligible
if (!keypathCache.hasOwnProperty(str)) {
keypathCache[str] = new Keypath(str);
}
return keypathCache[str];
}
function getMatchingKeypaths(ractive, keypath) {
var keys, key, matchingKeypaths;
keys = keypath.str.split(".");
matchingKeypaths = [rootKeypath];
while (key = keys.shift()) {
if (key === "*") {
// expand to find all valid child keypaths
matchingKeypaths = matchingKeypaths.reduce(expand, []);
} else {
if (matchingKeypaths[0] === rootKeypath) {
// first key
matchingKeypaths[0] = getKeypath(key);
} else {
matchingKeypaths = matchingKeypaths.map(concatenate(key));
}
}
}
return matchingKeypaths;
function expand(matchingKeypaths, keypath) {
var wrapper, value, keys;
if (keypath.isRoot) {
keys = [].concat(Object.keys(ractive.viewmodel.data), Object.keys(ractive.viewmodel.mappings), Object.keys(ractive.viewmodel.computations));
} else {
wrapper = ractive.viewmodel.wrapped[keypath.str];
value = wrapper ? wrapper.get() : ractive.viewmodel.get(keypath);
keys = value ? Object.keys(value) : null;
}
if (keys) {
keys.forEach(function (key) {
if (key !== "_ractive" || !isArray(value)) {
matchingKeypaths.push(keypath.join(key));
}
});
}
return matchingKeypaths;
}
}
function concatenate(key) {
return function (keypath) {
return keypath.join(key);
};
}
function normalise(ref) {
return ref ? ref.replace(refPattern, ".$1") : "";
}
var rootKeypath = getKeypath("");
var shared_add = add;
var shared_add__errorMessage = "Cannot add to a non-numeric value";
function add(root, keypath, d) {
if (typeof keypath !== "string" || !is__isNumeric(d)) {
throw new Error("Bad arguments");
}
var value = undefined,
changes = undefined;
if (/\*/.test(keypath)) {
changes = {};
getMatchingKeypaths(root, getKeypath(normalise(keypath))).forEach(function (keypath) {
var value = root.viewmodel.get(keypath);
if (!is__isNumeric(value)) {
throw new Error(shared_add__errorMessage);
}
changes[keypath.str] = value + d;
});
return root.set(changes);
}
value = root.get(keypath);
if (!is__isNumeric(value)) {
throw new Error(shared_add__errorMessage);
}
return root.set(keypath, +value + d);
}
var prototype_add = Ractive$add;
function Ractive$add(keypath, d) {
return shared_add(this, keypath, d === undefined ? 1 : +d);
}
var requestAnimationFrame;
// If window doesn't exist, we don't need requestAnimationFrame
if (typeof window === "undefined") {
requestAnimationFrame = null;
} else {
// https://gist.github.com/paulirish/1579671
(function (vendors, lastTime, window) {
var x, setTimeout;
if (window.requestAnimationFrame) {
return;
}
for (x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x] + "RequestAnimationFrame"];
}
if (!window.requestAnimationFrame) {
setTimeout = window.setTimeout;
window.requestAnimationFrame = function (callback) {
var currTime, timeToCall, id;
currTime = Date.now();
timeToCall = Math.max(0, 16 - (currTime - lastTime));
id = setTimeout(function () {
callback(currTime + timeToCall);
}, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
})(vendors, 0, window);
requestAnimationFrame = window.requestAnimationFrame;
}
var rAF = requestAnimationFrame;
var getTime;
if (typeof window !== "undefined" && window.performance && typeof window.performance.now === "function") {
getTime = function () {
return window.performance.now();
};
} else {
getTime = function () {
return Date.now();
};
}
var utils_getTime = getTime;
var deprecations = {
construct: {
deprecated: "beforeInit",
replacement: "onconstruct"
},
render: {
deprecated: "init",
message: "The \"init\" method has been deprecated " + "and will likely be removed in a future release. " + "You can either use the \"oninit\" method which will fire " + "only once prior to, and regardless of, any eventual ractive " + "instance being rendered, or if you need to access the " + "rendered DOM, use \"onrender\" instead. " + "See http://docs.ractivejs.org/latest/migrating for more information."
},
complete: {
deprecated: "complete",
replacement: "oncomplete"
}
};
function Hook(event) {
this.event = event;
this.method = "on" + event;
this.deprecate = deprecations[event];
}
Hook.prototype.fire = function (ractive, arg) {
function call(method) {
if (ractive[method]) {
arg ? ractive[method](arg) : ractive[method]();
return true;
}
}
call(this.method);
if (!ractive[this.method] && this.deprecate && call(this.deprecate.deprecated)) {
if (this.deprecate.message) {
warnIfDebug(this.deprecate.message);
} else {
warnIfDebug("The method \"%s\" has been deprecated in favor of \"%s\" and will likely be removed in a future release. See http://docs.ractivejs.org/latest/migrating for more information.", this.deprecate.deprecated, this.deprecate.replacement);
}
}
arg ? ractive.fire(this.event, arg) : ractive.fire(this.event);
};
var hooks_Hook = Hook;
function addToArray(array, value) {
var index = array.indexOf(value);
if (index === -1) {
array.push(value);
}
}
function arrayContains(array, value) {
for (var i = 0, c = array.length; i < c; i++) {
if (array[i] == value) {
return true;
}
}
return false;
}
function arrayContentsMatch(a, b) {
var i;
if (!isArray(a) || !isArray(b)) {
return false;
}
if (a.length !== b.length) {
return false;
}
i = a.length;
while (i--) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}
function ensureArray(x) {
if (typeof x === "string") {
return [x];
}
if (x === undefined) {
return [];
}
return x;
}
function lastItem(array) {
return array[array.length - 1];
}
function removeFromArray(array, member) {
var index = array.indexOf(member);
if (index !== -1) {
array.splice(index, 1);
}
}
function toArray(arrayLike) {
var array = [],
i = arrayLike.length;
while (i--) {
array[i] = arrayLike[i];
}
return array;
}
var _Promise,
PENDING = {},
FULFILLED = {},
REJECTED = {};
if (typeof Promise === "function") {
// use native Promise
_Promise = Promise;
} else {
_Promise = function (callback) {
var fulfilledHandlers = [],
rejectedHandlers = [],
state = PENDING,
result,
dispatchHandlers,
makeResolver,
fulfil,
reject,
promise;
makeResolver = function (newState) {
return function (value) {
if (state !== PENDING) {
return;
}
result = value;
state = newState;
dispatchHandlers = makeDispatcher(state === FULFILLED ? fulfilledHandlers : rejectedHandlers, result);
// dispatch onFulfilled and onRejected handlers asynchronously
wait(dispatchHandlers);
};
};
fulfil = makeResolver(FULFILLED);
reject = makeResolver(REJECTED);
try {
callback(fulfil, reject);
} catch (err) {
reject(err);
}
promise = {
// `then()` returns a Promise - 2.2.7
then: function (onFulfilled, onRejected) {
var promise2 = new _Promise(function (fulfil, reject) {
var processResolutionHandler = function (handler, handlers, forward) {
// 2.2.1.1
if (typeof handler === "function") {
handlers.push(function (p1result) {
var x;
try {
x = handler(p1result);
utils_Promise__resolve(promise2, x, fulfil, reject);
} catch (err) {
reject(err);
}
});
} else {
// Forward the result of promise1 to promise2, if resolution handlers
// are not given
handlers.push(forward);
}
};
// 2.2
processResolutionHandler(onFulfilled, fulfilledHandlers, fulfil);
processResolutionHandler(onRejected, rejectedHandlers, reject);
if (state !== PENDING) {
// If the promise has resolved already, dispatch the appropriate handlers asynchronously
wait(dispatchHandlers);
}
});
return promise2;
}
};
promise["catch"] = function (onRejected) {
return this.then(null, onRejected);
};
return promise;
};
_Promise.all = function (promises) {
return new _Promise(function (fulfil, reject) {
var result = [],
pending,
i,
processPromise;
if (!promises.length) {
fulfil(result);
return;
}
processPromise = function (promise, i) {
if (promise && typeof promise.then === "function") {
promise.then(function (value) {
result[i] = value;
--pending || fulfil(result);
}, reject);
} else {
result[i] = promise;
--pending || fulfil(result);
}
};
pending = i = promises.length;
while (i--) {
processPromise(promises[i], i);
}
});
};
_Promise.resolve = function (value) {
return new _Promise(function (fulfil) {
fulfil(value);
});
};
_Promise.reject = function (reason) {
return new _Promise(function (fulfil, reject) {
reject(reason);
});
};
}
var utils_Promise = _Promise;
// TODO use MutationObservers or something to simulate setImmediate
function wait(callback) {
setTimeout(callback, 0);
}
function makeDispatcher(handlers, result) {
return function () {
var handler;
while (handler = handlers.shift()) {
handler(result);
}
};
}
function utils_Promise__resolve(promise, x, fulfil, reject) {
// Promise Resolution Procedure
var then;
// 2.3.1
if (x === promise) {
throw new TypeError("A promise's fulfillment handler cannot return the same promise");
}
// 2.3.2
if (x instanceof _Promise) {
x.then(fulfil, reject);
}
// 2.3.3
else if (x && (typeof x === "object" || typeof x === "function")) {
try {
then = x.then; // 2.3.3.1
} catch (e) {
reject(e); // 2.3.3.2
return;
}
// 2.3.3.3
if (typeof then === "function") {
var called, resolvePromise, rejectPromise;
resolvePromise = function (y) {
if (called) {
return;
}
called = true;
utils_Promise__resolve(promise, y, fulfil, reject);
};
rejectPromise = function (r) {
if (called) {
return;
}
called = true;
reject(r);
};
try {
then.call(x, resolvePromise, rejectPromise);
} catch (e) {
if (!called) {
// 2.3.3.3.4.1
reject(e); // 2.3.3.3.4.2
called = true;
return;
}
}
} else {
fulfil(x);
}
} else {
fulfil(x);
}
}
var getInnerContext = function (fragment) {
do {
if (fragment.context !== undefined) {
return fragment.context;
}
} while (fragment = fragment.parent);
return rootKeypath;
};
var shared_resolveRef = resolveRef;
function resolveRef(ractive, ref, fragment) {
var keypath;
ref = normalise(ref);
// If a reference begins '~/', it's a top-level reference
if (ref.substr(0, 2) === "~/") {
keypath = getKeypath(ref.substring(2));
createMappingIfNecessary(ractive, keypath.firstKey, fragment);
}
// If a reference begins with '.', it's either a restricted reference or
// an ancestor reference...
else if (ref[0] === ".") {
keypath = resolveAncestorRef(getInnerContext(fragment), ref);
if (keypath) {
createMappingIfNecessary(ractive, keypath.firstKey, fragment);
}
}
// ...otherwise we need to figure out the keypath based on context
else {
keypath = resolveAmbiguousReference(ractive, getKeypath(ref), fragment);
}
return keypath;
}
function resolveAncestorRef(baseContext, ref) {
var contextKeys;
// TODO...
if (baseContext != undefined && typeof baseContext !== "string") {
baseContext = baseContext.str;
}
// {{.}} means 'current context'
if (ref === ".") return getKeypath(baseContext);
contextKeys = baseContext ? baseContext.split(".") : [];
// ancestor references (starting "../") go up the tree
if (ref.substr(0, 3) === "../") {
while (ref.substr(0, 3) === "../") {
if (!contextKeys.length) {
throw new Error("Could not resolve reference - too many \"../\" prefixes");
}
contextKeys.pop();
ref = ref.substring(3);
}
contextKeys.push(ref);
return getKeypath(contextKeys.join("."));
}
// not an ancestor reference - must be a restricted reference (prepended with "." or "./")
if (!baseContext) {
return getKeypath(ref.replace(/^\.\/?/, ""));
}
return getKeypath(baseContext + ref.replace(/^\.\//, "."));
}
function resolveAmbiguousReference(ractive, ref, fragment, isParentLookup) {
var context, key, parentValue, hasContextChain, parentKeypath;
if (ref.isRoot) {
return ref;
}
key = ref.firstKey;
while (fragment) {
context = fragment.context;
fragment = fragment.parent;
if (!context) {
continue;
}
hasContextChain = true;
parentValue = ractive.viewmodel.get(context);
if (parentValue && (typeof parentValue === "object" || typeof parentValue === "function") && key in parentValue) {
return context.join(ref.str);
}
}
// Root/computed/mapped property?
if (isRootProperty(ractive.viewmodel, key)) {
return ref;
}
// If this is an inline component, and it's not isolated, we
// can try going up the scope chain
if (ractive.parent && !ractive.isolated) {
hasContextChain = true;
fragment = ractive.component.parentFragment;
key = getKeypath(key);
if (parentKeypath = resolveAmbiguousReference(ractive.parent, key, fragment, true)) {
// We need to create an inter-component binding
ractive.viewmodel.map(key, {
origin: ractive.parent.viewmodel,
keypath: parentKeypath
});
return ref;
}
}
// If there's no context chain, and the instance is either a) isolated or
// b) an orphan, then we know that the keypath is identical to the reference
if (!isParentLookup && !hasContextChain) {
// the data object needs to have a property by this name,
// to prevent future failed lookups
ractive.viewmodel.set(ref, undefined);
return ref;
}
}
function createMappingIfNecessary(ractive, key) {
var parentKeypath;
if (!ractive.parent || ractive.isolated || isRootProperty(ractive.viewmodel, key)) {
return;
}
key = getKeypath(key);
if (parentKeypath = resolveAmbiguousReference(ractive.parent, key, ractive.component.parentFragment, true)) {
ractive.viewmodel.map(key, {
origin: ractive.parent.viewmodel,
keypath: parentKeypath
});
}
}
function isRootProperty(viewmodel, key) {
// special case for reference to root
return key === "" || key in viewmodel.data || key in viewmodel.computations || key in viewmodel.mappings;
}
function teardown(x) {
x.teardown();
}
function methodCallers__unbind(x) {
x.unbind();
}
function methodCallers__unrender(x) {
x.unrender();
}
function cancel(x) {
x.cancel();
}
var TransitionManager = function (callback, parent) {
this.callback = callback;
this.parent = parent;
this.intros = [];
this.outros = [];
this.children = [];
this.totalChildren = this.outroChildren = 0;
this.detachQueue = [];
this.decoratorQueue = [];
this.outrosComplete = false;
if (parent) {
parent.addChild(this);
}
};
TransitionManager.prototype = {
addChild: function (child) {
this.children.push(child);
this.totalChildren += 1;
this.outroChildren += 1;
},
decrementOutros: function () {
this.outroChildren -= 1;
check(this);
},
decrementTotal: function () {
this.totalChildren -= 1;
check(this);
},
add: function (transition) {
var list = transition.isIntro ? this.intros : this.outros;
list.push(transition);
},
addDecorator: function (decorator) {
this.decoratorQueue.push(decorator);
},
remove: function (transition) {
var list = transition.isIntro ? this.intros : this.outros;
removeFromArray(list, transition);
check(this);
},
init: function () {
this.ready = true;
check(this);
},
detachNodes: function () {
this.decoratorQueue.forEach(teardown);
this.detachQueue.forEach(detach);
this.children.forEach(detachNodes);
}
};
function detach(element) {
element.detach();
}
function detachNodes(tm) {
tm.detachNodes();
}
function check(tm) {
if (!tm.ready || tm.outros.length || tm.outroChildren) return;
// If all outros are complete, and we haven't already done this,
// we notify the parent if there is one, otherwise
// start detaching nodes
if (!tm.outrosComplete) {
if (tm.parent) {
tm.parent.decrementOutros(tm);
} else {
tm.detachNodes();
}
tm.outrosComplete = true;
}
// Once everything is done, we can notify parent transition
// manager and call the callback
if (!tm.intros.length && !tm.totalChildren) {
if (typeof tm.callback === "function") {
tm.callback();
}
if (tm.parent) {
tm.parent.decrementTotal();
}
}
}
var global_TransitionManager = TransitionManager;
var batch,
runloop,
unresolved = [],
changeHook = new hooks_Hook("change");
runloop = {
start: function (instance, returnPromise) {
var promise, fulfilPromise;
if (returnPromise) {
promise = new utils_Promise(function (f) {
return fulfilPromise = f;
});
}
batch = {
previousBatch: batch,
transitionManager: new global_TransitionManager(fulfilPromise, batch && batch.transitionManager),
views: [],
tasks: [],
ractives: [],
instance: instance
};
if (instance) {
batch.ractives.push(instance);
}
return promise;
},
end: function () {
flushChanges();
batch.transitionManager.init();
if (!batch.previousBatch && !!batch.instance) batch.instance.viewmodel.changes = [];
batch = batch.previousBatch;
},
addRactive: function (ractive) {
if (batch) {
addToArray(batch.ractives, ractive);
}
},
registerTransition: function (transition) {
transition._manager = batch.transitionManager;
batch.transitionManager.add(transition);
},
registerDecorator: function (decorator) {
batch.transitionManager.addDecorator(decorator);
},
addView: function (view) {
batch.views.push(view);
},
addUnresolved: function (thing) {
unresolved.push(thing);
},
removeUnresolved: function (thing) {
removeFromArray(unresolved, thing);
},
// synchronise node detachments with transition ends
detachWhenReady: function (thing) {
batch.transitionManager.detachQueue.push(thing);
},
scheduleTask: function (task, postRender) {
var _batch;
if (!batch) {
task();
} else {
_batch = batch;
while (postRender && _batch.previousBatch) {
// this can't happen until the DOM has been fully updated
// otherwise in some situations (with components inside elements)
// transitions and decorators will initialise prematurely
_batch = _batch.previousBatch;
}
_batch.tasks.push(task);
}
}
};
var global_runloop = runloop;
function flushChanges() {
var i, thing, changeHash;
while (batch.ractives.length) {
thing = batch.ractives.pop();
changeHash = thing.viewmodel.applyChanges();
if (changeHash) {
changeHook.fire(thing, changeHash);
}
}
attemptKeypathResolution();
// Now that changes have been fully propagated, we can update the DOM
// and complete other tasks
for (i = 0; i < batch.views.length; i += 1) {
batch.views[i].update();
}
batch.views.length = 0;
for (i = 0; i < batch.tasks.length; i += 1) {
batch.tasks[i]();
}
batch.tasks.length = 0;
// If updating the view caused some model blowback - e.g. a triple
// containing