UNPKG

ractive

Version:

Next-generation DOM manipulation

2,025 lines (1,642 loc) 517 kB
/* Ractive.js v1.4.4 Build: 3aeff251497ddb0b9da991576c91e05d37884fc9 Date: Wed May 22 2024 01:58:39 GMT-0400 (Eastern Daylight Time) Website: https://ractive.js.org License: MIT */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (function() { var current = global.Ractive; var exports = factory(); global.Ractive = exports; exports.noConflict = function() { global.Ractive = current; return exports; }; })(); }(this, (function () { 'use strict'; /* istanbul ignore if */ if (!Object.assign) { Object.assign = function(target) { var sources = [], len = arguments.length - 1; while ( len-- > 0 ) sources[ len ] = arguments[ len + 1 ]; if (target == null) { throw new TypeError('Cannot convert undefined or null to object'); } var to = Object(target); var sourcesLength = sources.length; for (var index = 0; index < sourcesLength; index++) { var nextSource = sources[index]; for (var nextKey in nextSource) { if (!Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { continue; } to[nextKey] = nextSource[nextKey]; } } return to; }; } function hasOwn(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } function fillGaps(target) { var sources = [], len = arguments.length - 1; while ( len-- > 0 ) sources[ len ] = arguments[ len + 1 ]; for (var i = 0; i < sources.length; i++) { var source = sources[i]; for (var key in source) { // Source can be a prototype-less object. if (key in target || !hasOwn(source, key)) { continue; } target[key] = source[key]; } } return target; } function toPairs(obj) { if ( obj === void 0 ) obj = {}; var pairs = []; for (var key in obj) { // Source can be a prototype-less object. if (!hasOwn(obj, key)) { continue; } pairs.push([key, obj[key]]); } return pairs; } var obj = Object; var assign = obj.assign; var create = obj.create; var defineProperty = obj.defineProperty; var defineProperties = obj.defineProperties; var keys = obj.keys; var toString = Object.prototype.toString; var isArray = Array.isArray; function isEqual(a, b) { if (a === null && b === null) { return true; } if (isObjectType(a) || isObjectType(b)) { return false; } return a === b; } // http://stackoverflow.com/questions/18082/validate-numbers-in-javascript-isnumeric function isNumeric(thing) { return !isNaN(parseFloat(thing)) && isFinite(thing); } function isObject(thing) { return thing && toString.call(thing) === '[object Object]'; } function isObjectLike(thing) { return !!(thing && (isObjectType(thing) || isFunction(thing))) && !isDate(thing); } function isDate(thing) { return thing instanceof Date; } function isObjectType(thing) { return typeof thing === 'object'; } function isFunction(thing) { return typeof thing === 'function'; } function isString(thing) { return typeof thing === 'string'; } function isNumber(thing) { return typeof thing === 'number'; } function isUndefined(thing) { return thing === undefined; } /* istanbul ignore if */ if (!Array.prototype.find) { defineProperty(Array.prototype, 'find', { value: function value(callback, thisArg) { if (this === null || isUndefined(this)) { throw new TypeError('Array.prototype.find called on null or undefined'); } if (!isFunction(callback)) { throw new TypeError((callback + " is not a function")); } var array = Object(this); var arrayLength = array.length >>> 0; for (var index = 0; index < arrayLength; index++) { if (!hasOwn(array, index)) { continue; } if (!callback.call(thisArg, array[index], index, array)) { continue; } return array[index]; } return undefined; }, configurable: true, writable: true }); } // NOTE: Node doesn't exist in IE8. Nothing can be done. /* istanbul ignore if */ if ( typeof window !== 'undefined' && window.Node && window.Node.prototype && !window.Node.prototype.contains ) { Node.prototype.contains = function(node) { var this$1 = this; if (!node) { throw new TypeError('node required'); } do { if (this$1 === node) { return true; } } while ((node = node && node.parentNode)); return false; }; } /* istanbul ignore if */ if (typeof window !== 'undefined' && window.performance && !window.performance.now) { window.performance = window.performance || {}; var nowOffset = Date.now(); window.performance.now = function() { return Date.now() - nowOffset; }; } /* eslint no-console:"off" */ var win = typeof window !== 'undefined' ? window : null; var doc = win ? document : null; var isClient = !!doc; var base = typeof global !== 'undefined' ? global : win; var hasConsole = typeof console !== 'undefined' && isFunction(console.warn) && isFunction(console.warn.apply); var svg = doc ? doc.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#BasicStructure', '1.1') : false; var vendors = ['o', 'ms', 'moz', 'webkit']; /* istanbul ignore if */ if (!base.Promise) { var PENDING = {}; var FULFILLED = {}; var REJECTED = {}; var Promise$1 = (base.Promise = function(callback) { var fulfilledHandlers = []; var rejectedHandlers = []; var state = PENDING; var result; var dispatchHandlers; var makeResolver = function (newState) { return function(value) { if (state !== PENDING) { return; } result = value; state = newState; dispatchHandlers = makeDispatcher( state === FULFILLED ? fulfilledHandlers : rejectedHandlers, result ); wait(dispatchHandlers); }; }; var fulfill = makeResolver(FULFILLED); var reject = makeResolver(REJECTED); try { callback(fulfill, reject); } catch (err) { reject(err); } return { // `then()` returns a Promise - 2.2.7 then: function then(onFulfilled, onRejected) { var promise2 = new Promise$1(function (fulfill, reject) { var processResolutionHandler = function (handler, handlers, forward) { if (isFunction(handler)) { handlers.push(function (p1result) { try { resolve$1(promise2, handler(p1result), fulfill, reject); } catch (err) { reject(err); } }); } else { handlers.push(forward); } }; processResolutionHandler(onFulfilled, fulfilledHandlers, fulfill); processResolutionHandler(onRejected, rejectedHandlers, reject); if (state !== PENDING) { wait(dispatchHandlers); } }); return promise2; }, catch: function catch$1(onRejected) { return this.then(null, onRejected); }, finally: function finally$1(callback) { return this.then( function (v) { callback(); return v; }, function (e) { callback(); throw e; } ); } }; }); Promise$1.all = function(promises) { return new Promise$1(function (fulfill, reject) { var result = []; var pending; var i; if (!promises.length) { fulfill(result); return; } var processPromise = function (promise, i) { if (promise && isFunction(promise.then)) { promise.then(function (value) { result[i] = value; --pending || fulfill(result); }, reject); } else { result[i] = promise; --pending || fulfill(result); } }; pending = i = promises.length; while (i--) { processPromise(promises[i], i); } }); }; Promise$1.race = function(promises) { return new Promise$1(function (fulfill, reject) { var pending = true; function ok(v) { if (!pending) { return; } pending = false; fulfill(v); } function fail(e) { if (!pending) { return; } pending = false; reject(e); } for (var i = 0; i < promises.length; i++) { if (promises[i] && isFunction(promises[i].then)) { promises[i].then(ok, fail); } } }); }; Promise$1.resolve = function(value) { if (value && isFunction(value.then)) { return value; } return new Promise$1(function (fulfill) { fulfill(value); }); }; Promise$1.reject = function(reason) { if (reason && isFunction(reason.then)) { return reason; } return new Promise$1(function (fulfill, reject) { reject(reason); }); }; // TODO use MutationObservers or something to simulate setImmediate var wait = function(callback) { setTimeout(callback, 0); }; var makeDispatcher = function(handlers, result) { return function() { for (var handler = (void 0); (handler = handlers.shift()); ) { handler(result); } }; }; var resolve$1 = function(promise, x, fulfil, reject) { var then; if (x === promise) { throw new TypeError("A promise's fulfillment handler cannot return the same promise"); } if (x instanceof Promise$1) { x.then(fulfil, reject); } else if (x && (isObjectType(x) || isFunction(x))) { try { then = x.then; } catch (e) { reject(e); return; } if (isFunction(then)) { var called; var resolvePromise = function(y) { if (called) { return; } called = true; resolve$1(promise, y, fulfil, reject); }; var rejectPromise = function(r) { if (called) { return; } called = true; reject(r); }; try { then.call(x, resolvePromise, rejectPromise); } catch (e) { if (!called) { reject(e); called = true; return; } } } else { fulfil(x); } } else { fulfil(x); } }; } /* istanbul ignore if */ if ( typeof window !== 'undefined' && !(window.requestAnimationFrame && window.cancelAnimationFrame) ) { var lastTime = 0; window.requestAnimationFrame = function(callback) { var currentTime = Date.now(); var timeToNextCall = Math.max(0, 16 - (currentTime - lastTime)); var id = window.setTimeout(function () { callback(currentTime + timeToNextCall); }, timeToNextCall); lastTime = currentTime + timeToNextCall; return id; }; window.cancelAnimationFrame = function(id) { clearTimeout(id); }; } var defaults = { // render placement: el: void 0, append: false, delegate: true, enhance: false, // template: template: null, // parse: allowExpressions: true, delimiters: ['{{', '}}'], tripleDelimiters: ['{{{', '}}}'], staticDelimiters: ['[[', ']]'], staticTripleDelimiters: ['[[[', ']]]'], csp: true, interpolate: false, preserveWhitespace: false, preserveStandaloneSections: false, sanitize: false, stripComments: true, contextLines: 0, // data & binding: data: create(null), helpers: create(null), computed: create(null), syncComputedChildren: false, resolveInstanceMembers: false, warnAboutAmbiguity: false, adapt: [], isolated: true, twoway: true, lazy: false, // transitions: noIntro: false, noOutro: false, transitionsEnabled: true, complete: void 0, nestedTransitions: true, // css: css: null, noCSSTransform: false }; // 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 easing = { linear: function linear(pos) { return pos; }, easeIn: function easeIn(pos) { /* istanbul ignore next */ return Math.pow(pos, 3); }, easeOut: function easeOut(pos) { return Math.pow(pos - 1, 3) + 1; }, easeInOut: function easeInOut(pos) { /* istanbul ignore next */ if ((pos /= 0.5) < 1) { return 0.5 * Math.pow(pos, 3); } /* istanbul ignore next */ return 0.5 * (Math.pow(pos - 2, 3) + 2); } }; function noop() {} /* global console */ /* eslint no-console:"off" */ var alreadyWarned = {}; var log; var printWarning; var welcome; if (hasConsole) { var welcomeIntro = [ "%cRactive.js %c1.4.4 %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 1.4.4 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://ractive.js.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 () { if (Ractive.WELCOME_MESSAGE === false) { welcome = noop; return; } var message = 'WELCOME_MESSAGE' in Ractive ? Ractive.WELCOME_MESSAGE : welcomeMessage; var hasGroup = !!console.groupCollapsed; if (hasGroup) { console.groupCollapsed.apply(console, welcomeIntro); } console.log(message); if (hasGroup) { console.groupEnd(welcomeIntro); } welcome = noop; }; printWarning = function (message, args) { welcome(); // extract information about the instance this message pertains to, if applicable if (isObjectType(args[args.length - 1])) { 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; if (ractive.component && (name = ractive.component.name)) { message = "<" + name + "> " + message; } var node; 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) { var args = [], len = arguments.length - 1; while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ]; message = format(message, args); throw new Error(message); } function logIfDebug() { if (Ractive.DEBUG) { log.apply(null, arguments); } } function warn(message) { var args = [], len = arguments.length - 1; while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ]; message = format(message, args); printWarning(message, args); } function warnOnce(message) { var args = [], len = arguments.length - 1; while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ]; 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://ractive.js.org/integrations/#" + 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; } } function interpolate(from, to, ractive, type) { if (from === to) { return null; } if (type) { var interpol = findInViewHierarchy('interpolators', ractive, type); if (interpol) { return interpol(from, to) || null; } fatal(missingPlugin(type, 'interpolator')); } return ( interpolators.number(from, to) || interpolators.array(from, to) || interpolators.object(from, to) || null ); } var interpolators = { number: function number(from, to) { if (!isNumeric(from) || !isNumeric(to)) { return null; } from = +from; to = +to; var delta = to - from; if (!delta) { return function() { return from; }; } return function(t) { return from + t * delta; }; }, array: function array(from, to) { var len, i; if (!isArray(from) || !isArray(to)) { return null; } var intermediate = []; var interpolators = []; i = len = Math.min(from.length, to.length); while (i--) { interpolators[i] = 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 object(from, to) { if (!isObject(from) || !isObject(to)) { return null; } var properties = []; var intermediate = {}; var interpolators = {}; var loop = function ( prop ) { if (hasOwn(from, prop)) { if (hasOwn(to, prop)) { properties.push(prop); interpolators[prop] = interpolate(from[prop], to[prop]) || (function () { return to[prop]; }); } else { intermediate[prop] = from[prop]; } } }; for (var prop in from) loop( prop ); for (var prop$1 in to) { if (hasOwn(to, prop$1) && !hasOwn(from, prop$1)) { intermediate[prop$1] = to[prop$1]; } } var len = properties.length; return function(t) { var i = len; while (i--) { var prop = properties[i]; intermediate[prop] = interpolators[prop](t); } return intermediate; }; } }; var refPattern = /\[\s*(\*|[0-9]|[1-9][0-9]+)\s*\]/g; var splitPattern = /([^\\](?:\\\\)*)\./; var escapeKeyPattern = /\\|\./g; var unescapeKeyPattern = /((?:\\)+)\1|\\(\.)/g; function escapeKey(key) { if (isString(key)) { return key.replace(escapeKeyPattern, '\\$&'); } return key; } function normalise(ref) { return ref ? ref.replace(refPattern, '.$1') : ''; } function splitKeypath(keypath) { var result = []; var match; keypath = normalise(keypath); while ((match = splitPattern.exec(keypath))) { var index = match.index + match[1].length; result.push(keypath.substr(0, index)); keypath = keypath.substr(index + 1); } result.push(keypath); return result; } function unescapeKey(key) { if (isString(key)) { return key.replace(unescapeKeyPattern, '$1$2'); } return key; } 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 (isString(x)) { return [x]; } if (isUndefined(x)) { return []; } return x; } function lastItem(array) { return array[array.length - 1]; } function removeFromArray(array, member) { if (!array) { return; } var index = array.indexOf(member); if (index !== -1) { array.splice(index, 1); } } function combine() { var arrays = [], len = arguments.length; while ( len-- ) arrays[ len ] = arguments[ len ]; var res = arrays.concat.apply([], arrays); var i = res.length; while (i--) { var idx = res.indexOf(res[i]); if (~idx && idx < i) { res.splice(i, 1); } } return res; } function toArray(arrayLike) { var array = []; var i = arrayLike.length; while (i--) { array[i] = arrayLike[i]; } return array; } function findMap(array, fn) { var len = array.length; for (var i = 0; i < len; i++) { var result = fn(array[i]); if (result) { return result; } } } function buildNewIndices(one, two, comparator) { var oldArray = one; var newArray = two; if (comparator) { oldArray = oldArray.map(comparator); newArray = newArray.map(comparator); } var oldLength = oldArray.length; var usedIndices = {}; var firstUnusedIndex = 0; var result = oldArray.map(function (item) { var index; var start = firstUnusedIndex; do { index = newArray.indexOf(item, start); if (index === -1) { return -1; } start = index + 1; } while (usedIndices[index] === true && start < oldLength); // keep track of the first unused index, so we don't search // the whole of newArray for each item in oldArray unnecessarily if (index === firstUnusedIndex) { firstUnusedIndex += 1; } // allow next instance of next "equal" to be found item usedIndices[index] = true; return index; }); var len = (result.oldLen = oldArray.length); result.newLen = newArray.length; if (len === result.newLen) { var i = 0; for (i; i < len; i++) { if (result[i] !== i) { break; } } if (i === len) { result.same = true; } } return result; } var fnBind = Function.prototype.bind; function bind(fn, context) { if (!/this/.test(fn.toString())) { return fn; } var bound = fnBind.call(fn, context); for (var prop in fn) { bound[prop] = fn[prop]; } return bound; } var shuffleTasks = { early: [], mark: [] }; var registerQueue = { early: [], mark: [] }; var noVirtual = { virtual: false }; var ModelBase = function ModelBase(parent) { this.deps = []; this.children = []; this.childByKey = {}; this.links = []; this.bindings = []; if (parent) { this.parent = parent; this.root = parent.root; } }; var ModelBase__proto__ = ModelBase.prototype; ModelBase__proto__.addShuffleTask = function addShuffleTask (task, stage) { if ( stage === void 0 ) stage = 'early'; shuffleTasks[stage].push(task); }; ModelBase__proto__.addShuffleRegister = function addShuffleRegister (item, stage) { if ( stage === void 0 ) stage = 'early'; registerQueue[stage].push({ model: this, item: item }); }; ModelBase__proto__.downstreamChanged = function downstreamChanged () {}; ModelBase__proto__.findMatches = function findMatches (keys$$1) { var len = keys$$1.length; var existingMatches = [this]; var matches; var i; var loop = function ( ) { var key = keys$$1[i]; if (key === '*') { matches = []; existingMatches.forEach(function (model) { matches.push.apply(matches, model.getValueChildren(model.get())); }); } else { matches = existingMatches.map(function (model) { return model.joinKey(key); }); } existingMatches = matches; }; for (i = 0; i < len; i += 1) loop( ); return matches; }; ModelBase__proto__.getKeypath = function getKeypath (ractive) { if (ractive !== this.ractive && this._link) { return this._link.target.getKeypath(ractive); } if (!this.keypath) { var parent = this.parent && this.parent.getKeypath(ractive); this.keypath = parent ? ((this.parent.getKeypath(ractive)) + "." + (escapeKey(this.key))) : escapeKey(this.key); } return this.keypath; }; ModelBase__proto__.getValueChildren = function getValueChildren (value) { var this$1 = this; var children; if (isArray(value)) { children = []; if ('length' in this && this.length !== value.length) { children.push(this.joinKey('length')); } value.forEach(function (m, i) { children.push(this$1.joinKey(i)); }); } else if (isObject(value) || isFunction(value)) { children = keys(value).map(function (key) { return this$1.joinKey(escapeKey(key)); }); } else if (value != null) { children = []; } var computed = this.computed; if (computed) { children.push.apply(children, keys(computed).map(function (k) { return this$1.joinKey(k); })); } return children; }; ModelBase__proto__.getVirtual = function getVirtual (shouldCapture) { var this$1 = this; var value = this.get(shouldCapture, { virtual: false }); if (isObjectLike(value)) { var result = isArray(value) ? [] : create(null); var keys$$1 = keys(value); var i = keys$$1.length; while (i--) { var child = this$1.childByKey[keys$$1[i]]; if (!child) { result[keys$$1[i]] = value[keys$$1[i]]; } else if (child._link) { result[keys$$1[i]] = child._link.getVirtual(); } else { result[keys$$1[i]] = child.getVirtual(); } } i = this.children.length; while (i--) { var child$1 = this$1.children[i]; if (!(child$1.key in result) && child$1._link) { result[child$1.key] = child$1._link.getVirtual(); } } if (this.computed) { keys$$1 = keys(this.computed); i = keys$$1.length; while (i--) { result[keys$$1[i]] = this$1.computed[keys$$1[i]].get(); } } return result; } else { return value; } }; ModelBase__proto__.has = function has (key) { var this$1 = this; if (this._link) { return this._link.has(key); } var value = this.get(false, noVirtual); if (!value) { return false; } key = unescapeKey(key); if ((isFunction(value) || isObject(value)) && key in value) { return true; } var computed = this.computed; if (computed && key in this.computed) { return true; } computed = this.root.ractive && this.root.ractive.computed; if (computed) { keys(computed).forEach(function (k) { if (computed[k].pattern && computed[k].pattern.test(this$1.getKeypath())) { return true; } }); } return false; }; ModelBase__proto__.joinAll = function joinAll (keys$$1, opts) { var model = this; for (var i = 0; i < keys$$1.length; i += 1) { if ( opts && opts.lastLink === false && i + 1 === keys$$1.length && model.childByKey[keys$$1[i]] && model.childByKey[keys$$1[i]]._link ) { return model.childByKey[keys$$1[i]]; } model = model.joinKey(keys$$1[i], opts); } return model; }; ModelBase__proto__.notifyUpstream = function notifyUpstream (startPath) { var this$1 = this; var parent = this.parent; var path = startPath || [this.key]; while (parent) { if (parent.patterns) { parent.patterns.forEach(function (o) { return o.notify(path.slice()); }); } path.unshift(parent.key); parent.links.forEach(function (l) { return l.notifiedUpstream(path, this$1.root); }); parent.deps.forEach(function (d) { return d.handleChange(path); }); parent.downstreamChanged(startPath); parent = parent.parent; } }; ModelBase__proto__.rebind = function rebind (next, previous, safe) { var this$1 = this; if (this._link) { this._link.rebind(next, previous, false); } if (next === this) { return; } // tell the deps to move to the new target var i = this.deps.length; while (i--) { if (this$1.deps[i].rebind) { this$1.deps[i].rebind(next, previous, safe); } } i = this.links.length; while (i--) { var link = this$1.links[i]; // only relink the root of the link tree if (link.owner && link.owner._link) { link.relinking(next, safe); } } i = this.children.length; while (i--) { var child = this$1.children[i]; child.rebind(next ? next.joinKey(child.key) : undefined, child._link || child, safe); if (this$1.dataModel) { this$1.addShuffleTask(function () { return checkDataLink(this$1, this$1.retrieve()); }, 'early'); } } i = this.bindings.length; while (i--) { this$1.bindings[i].rebind(next, previous, safe); } }; ModelBase__proto__.reference = function reference () { 'refs' in this ? this.refs++ : (this.refs = 1); }; ModelBase__proto__.register = function register (dep) { this.deps.push(dep); }; ModelBase__proto__.registerLink = function registerLink (link) { addToArray(this.links, link); }; ModelBase__proto__.registerPatternObserver = function registerPatternObserver (observer) { (this.patterns || (this.patterns = [])).push(observer); this.register(observer); }; ModelBase__proto__.registerTwowayBinding = function registerTwowayBinding (binding) { this.bindings.push(binding); }; ModelBase__proto__.unreference = function unreference () { if ('refs' in this) { this.refs--; } }; ModelBase__proto__.unregister = function unregister (dep) { removeFromArray(this.deps, dep); }; ModelBase__proto__.unregisterLink = function unregisterLink (link) { removeFromArray(this.links, link); }; ModelBase__proto__.unregisterPatternObserver = function unregisterPatternObserver (observer) { removeFromArray(this.patterns, observer); this.unregister(observer); }; ModelBase__proto__.unregisterTwowayBinding = function unregisterTwowayBinding (binding) { removeFromArray(this.bindings, binding); }; ModelBase__proto__.updateFromBindings = function updateFromBindings$1 (cascade) { var this$1 = this; var i = this.bindings.length; while (i--) { var value = this$1.bindings[i].getValue(); if (value !== this$1.value) { this$1.set(value); } } // check for one-way bindings if there are no two-ways if (!this.bindings.length) { var oneway = findBoundValue(this.deps); if (oneway && oneway.value !== this.value) { this.set(oneway.value); } } if (cascade) { this.children.forEach(updateFromBindings); this.links.forEach(updateFromBindings); if (this._link) { this._link.updateFromBindings(cascade); } } }; // TODO: this may be better handled by overriding `get` on models with a parent that isRoot function maybeBind(model, value, shouldBind) { if (shouldBind && isFunction(value) && model.parent && model.parent.isRoot) { if (!model.boundValue) { model.boundValue = bind(value._r_unbound || value, model.parent.ractive); } return model.boundValue; } return value; } function updateFromBindings(model) { model.updateFromBindings(true); } function findBoundValue(list) { var i = list.length; while (i--) { if (list[i].bound) { var owner = list[i].owner; if (owner) { var value = owner.name === 'checked' ? owner.node.checked : owner.node.value; return { value: value }; } } } } function fireShuffleTasks(stage) { if (!stage) { fireShuffleTasks('early'); fireShuffleTasks('mark'); } else { var tasks = shuffleTasks[stage]; shuffleTasks[stage] = []; var i = tasks.length; while (i--) { tasks[i](); } var register = registerQueue[stage]; registerQueue[stage] = []; i = register.length; while (i--) { register[i].model.register(register[i].item); } } } function shuffle(model, newIndices, link, unsafe) { model.shuffling = true; var upstream = model.source().length !== model.source().value.length; var i = newIndices.length; while (i--) { var idx = newIndices[i]; // nothing is actually changing, so move in the index and roll on if (i === idx) { continue; } upstream = true; // rebind the children on i to idx if (i in model.childByKey) { model.childByKey[i].rebind( !~idx ? undefined : model.joinKey(idx), model.childByKey[i], !unsafe ); } } model.links.forEach(function (l) { return l.shuffle(newIndices); }); if (!link) { fireShuffleTasks('early'); } i = model.deps.length; while (i--) { if (model.deps[i].shuffle) { model.deps[i].shuffle(newIndices); } } model[link ? 'marked' : 'mark'](); if (!link) { fireShuffleTasks('mark'); } if (upstream) { model.notifyUpstream(); } model.shuffling = false; } function checkDataLink(model, value) { if (value !== model.dataModel) { if (value && value.viewmodel && value.viewmodel.isRoot && model.childByKey.data) { model.childByKey.data.link(value.viewmodel, 'data'); model.dataModel = value; } else if (model.dataModel) { model.childByKey.data.unlink(); model.dataModel = true; } } } var stack = []; var captureGroup; function startCapturing() { stack.push((captureGroup = [])); } function stopCapturing() { var dependencies = stack.pop(); captureGroup = stack[stack.length - 1]; return dependencies; } function capture(model) { if (captureGroup) { addToArray(captureGroup, model); } } function bind$1(x) { x.bind(); } function cancel(x) { x.cancel(); } function destroyed(x) { x.destroyed(); } function handleChange(x) { x.handleChange(); } function mark(x) { x.mark(); } function markForce(x) { x.mark(true); } function marked(x) { x.marked(); } function markedAll(x) { x.markedAll(); } function render(x) { x.render(); } function shuffled(x) { x.shuffled(); } function teardown(x) { x.teardown(); } function unbind(x) { x.unbind(); } function unrender(x) { x.unrender(); } function update(x) { x.update(); } function toString$1(x) { return x.toString(); } function toEscapedString(x) { return x.toString(true); } // this is the dry method of checking to see if a rebind applies to // a particular keypath because in some cases, a dep may be bound // directly to a particular keypath e.g. foo.bars.0.baz and need // to avoid getting kicked to foo.bars.1.baz if foo.bars is unshifted function rebindMatch(template, next, previous, fragment) { var keypath = template.r || template; // no valid keypath, go with next if (!keypath || !isString(keypath)) { return next; } // completely contextual ref, go with next if ( keypath === '.' || keypath[0] === '@' || (next || previous).isKey || (next || previous).isKeypath ) { return next; } var parts = keypath.split('/'); var keys = splitKeypath(parts[parts.length - 1]); var last = keys[keys.length - 1]; // check the keypath against the model keypath to see if it matches var model = next || previous; // check to see if this was an alias if (model && keys.length === 1 && last !== model.key && fragment) { keys = findAlias(last, fragment) || keys; } var i = keys.length; var match = true; var shuffling = false; while (model && i--) { if (model.shuffling) { shuffling = true; } // non-strict comparison to account for indices in keypaths if (keys[i] != model.key) { match = false; } model = model.parent; } // next is undefined, but keypath is shuffling and previous matches if (!next && match && shuffling) { return previous; } else if (next && !match && shuffling) // next is defined, but doesn't match the keypath { return previous; } else { return next; } } function findAlias(name, fragment) { while (fragment) { var z = fragment.aliases; if (z && z[name]) { var aliases = (fragment.owner.iterations ? fragment.owner : fragment).owner.template.z; for (var i = 0; i < aliases.length; i++) { if (aliases[i].n === name) { var alias = aliases[i].x; if (!alias.r) { return false; } var parts = alias.r.split('/'); return splitKeypath(parts[parts.length - 1]); } } return; } fragment = fragment.componentParent || fragment.parent; } } // temporary placeholder target for detached implicit links var Missing = { key: '@missing', animate: noop, applyValue: noop, get: noop, getKeypath: function getKeypath() { return this.key; }, joinAll: function joinAll() { return this; }, joinKey: function joinKey() { return this; }, mark: noop, registerLink: noop, shufle: noop, set: noop, unregisterLink: noop }; Missing.parent = Missing; var LinkModel = (function (ModelBase) { function LinkModel(parent, owner, target, key) { ModelBase.call(this, parent); this.owner = owner; this.target = target; this.key = isUndefined(key) ? owner.key : key; if (owner && owner.isLink) { this.sourcePath = (owner.sourcePath) + "." + (this.key); } if (target) { target.registerLink(this); } if (parent) { this.isReadonly = parent.isReadonly; } this.isLink = true; } if ( ModelBase ) LinkModel.__proto__ = ModelBase; var LinkModel__proto__ = LinkModel.prototype = Object.create( ModelBase && ModelBase.prototype ); LinkModel__proto__.constructor = LinkModel; LinkModel__proto__.animate = function animate (from, to, options, interpolator) { return this.target.animate(from, to, options, interpolator); }; LinkModel__proto__.applyValue = function applyValue (value) { if (this.boundValue) { this.boundValue = null; } this.target.applyValue(value); }; LinkModel__proto__.attach = function attach (fragment) { var model = resolveReference(fragment, this.key); if (model) { this.relinking(model, false); } else { // if there is no link available, move everything here to real models this.owner.unlink(); } }; LinkModel__proto__.detach = function detach () { this.relinking(Missing, false); }; LinkModel__proto__.get = function get (shouldCapture, opts) { if ( opts === void 0 ) opts = {}; if (shouldCapture) { capture(this); // may need to tell the target to unwrap opts.unwrap = 'unwrap' in opts ? opts.unwrap : true; } var bind = 'shouldBind' in opts ? opts.shouldBind : true; opts.shouldBind = this.mapping && this.target.parent && this.target.parent.isRoot; return maybeBind(this, this.target.get(false, opts), bind); }; LinkModel__proto__.getKeypath = function getKeypath (ractive) { if (ractive && ractive !== this.root.ractive) { return this.target.getKeypath(ractive); } return ModelBase.prototype.getKeypath.call(this, ractive); }; LinkModel__proto__.handleChange = function handleChange$1 () { this.deps.forEach(handleChange); this.links.forEach(handleChange); this.notifyUpstream(); }; LinkModel__proto__.isDetached = function isDetached () { return this.virtual && this.target === Missing; }; LinkModel__proto__.joinKey = function joinKey (key) { // TODO: handle nested links if (isUndefined(key) || key === '') { return this; } if (!hasOwn(this.childByKey, key)) { var child = new LinkModel(this, this, this.target.joinKey(key), key); this.children.push(child); this.childByKey[key] = child; } return this.childByKey[key]; }; LinkModel__proto__.mark = function mark (force) { this.target.mark(force); }; LinkModel__proto__.marked = function marked$1 () { if (this.boundValue) { this.boundValue = null; } this.links.forEach(marked); this.deps.forEach(handleChange); }; LinkModel__proto__.markedAll = function markedAll$1 () { this.children.forEach(markedAll); this.marked(); }; LinkModel__proto__.notifiedUpstream = function notifiedUpstream (startPath, root) { var this$1 = this; this.links.forEach(function (l) { return l.notifiedUpstream(startPath, this$1.root); }); this.deps.forEach(handleChange); if (startPath && this.rootLink) { var parent = this.parent; if (this.root !== root) { var path = startPath.slice(1); path.unshift(this.key); this.notifyUpstream(path); } else if (parent && parent !== this.target) { var path$1 = [parent.key, this.key]; parent.links.forEach(function (l) { return l.notifiedUpstream(path$1, parent.root); }); parent.deps.forEach(function (d) { return d.handleChange(path$1); }); parent.notifyUpstream(path$1); } } }; LinkModel__proto__.relinked = function relinked () { this.target.registerLink(this); this.children.forEach(function (c) { return c.relinked(); }); }; LinkModel__proto__.relinking = function relinking (target, safe) { var this$1 = this; if (this.rootLink && this.sourcePath) { target = rebindMatch(this.sourcePath, target, this.target); } if (!target || this.target === target) { return; } this.target && this.target.unregisterLink(this); this.target = target; this.children.forEach(function (c) { c.relinking(target.joinKey(c.key), safe); }); if (!safe) { this.keypath = undefined; } if (this.rootLink) { this.addShuffleTask(function () { this$1.relinked(); if (!safe) { this$1.markedAll(); this$1.notifyUpstream(); } }); } }; LinkModel__proto__.set = function set (value) { if (this.boundValue) { this.boundValue = null; } this.target.set(value); }; LinkModel__proto__.shuffle = function shuffle$1 (newIndices) { // watch for extra shuffles caused by a shuffle in a downstream link if (this.shuffling) { return; } // let the real model handle firing off shuffles if (!this.target.shuffling) { if (this.target.shuffle) { this.target.shuffle(newIndices); } else { // the target is a computation, which can't shuffle this.target.mark(); } } else { shuffle(this, newIndices, true); } }; LinkModel__proto__.source = function source () { if (this.target.source) { return this.target.source(); } else { return this.target; } }; LinkModel__proto__.teardown = function teardown$3 () { if (this._link) { this._link.teardown(); } this.target.unregisterLink(this); this.children.forEach(teardown); }; return LinkModel; }(ModelBase)); ModelBase.prototype.link = function link(model, keypath, options) { var lnk = this._link || new LinkModel(this.parent, this, model, this.key); lnk.implicit = options && options.implicit; lnk.mapping = options && options.mapping; lnk.sourcePath = keypath; lnk.rootLink = true; if (this._link) { this._link.relinking(model, false); } this._link = lnk; this.rebind(lnk, this, false); fireShuffleTasks(); lnk.markedAll(); this.notifyUpstream(); return lnk; }; ModelBase.prototype.unlink = function unlink() { if (this._link) { var ln = this._link; this._link = undefined; ln.rebind(this, ln, false); fireShuffleTasks(); ln.teardown(); this.notifyUpstream(); } }; function fromExpression(body, length) { if ( length === void 0 ) length = 0; var args = new Array(length); while (length--) { args[length] = "_" + length; } // Functions created directly with new Function() look like this: // function anonymous (_0 /**/) { return _0*2 } // // With this workaround, we get a little more compact: // function (_0){return _0*2} return new Function([], ("return function (" + (args.join(',')) + "){return(" + body + ");};"))(); } var functions = create(null); function getFunction(str, i) { if (functions[str]) { return functions[str]; } return (functions[str] = createFunction(str, i)); } function addFunctions(template) { if (!template) { return; } var exp = template.e; if (!exp) { return; } keys(exp).forEach(function (str) { if (functions[str]) { return; } functions[str] = exp[str]; }); } var TEMPLATE_VERSION = 4; var leadingWhitespace = /^\s+/; var ParseError = function(message) { this.name = 'ParseError'; this.message = message; try { throw new Error(message); } catch (e) { this.stack = e.stack; } }; ParseError.prototype = Error.prototype; var Parser = function(str, options) { var item; var lineStart = 0; this.str = str; this.options = options || {}; this.pos = 0; this.lines = this.str.split('\n'); this.lineEnds = this.lines.map(function (line) { var lineEnd = lineStart + line.length + 1; // +1 for the newline lineStart = lineEnd; return lineEnd; }, 0); // Custom init logic if (this.init) { this.init(str, options); } var items = []; while (this.pos < this.str.length && (item = this.read())) { items.push(item); } this.leftover = this.remaining(); this.result = this.postProcess ? this.postProcess(items, options) : items; }; Parser.prototype = { read: function read(converters) { var this$1 = this; var i, item; if (!converters) { converters = this.converters; } var pos = this.pos; var len = converters.length; for (i = 0; i < len; i += 1) { this$1.pos = pos; // reset for each attempt if ((item = converters[i](this$1))) { return item; } } return null; }, getContextMessage: function getContextMessage(pos, message) { var ref = this.getLinePos(pos); var lineNum = ref[0]; var columnNum = ref[1]; if (this.options.contextLines === -1) { return [lineNum, columnNum, (message + " at line " + lineNum + " character " + columnNum)]; } var line = this.lines[lineNum - 1]; var contextUp = ''; var contextDown = ''; if (this.options.contextLines) { var start = lineNum - 1 - this.options.contextLines < 0 ? 0 : lineNum - 1 - this.options.contextLines; contextUp = this.lines .slice(start, lineNum - 1 - start) .join('\n') .replace(/\t/g, ' '); contextDown = this.lines .slice(lineNum, lineNum + this.options.contextLines) .join('\n') .replace(/\t/g, ' '); if (contextUp) { contextUp += '\n'; } if (contextDown) { contextDown = '\n' + contextDown; } } var numTabs = 0; var annotation = contextUp + line.replace(/\t/g, function (match, char) { if (char < columnNum) { numTabs += 1; } return ' '; }) + '\n' + new Array(columnNum + numTabs).join(' ') + '^----' + contextDown; return [ lineNum, columnNum, (message + " at line " + lineNum + " character " + columnNum + ":\n" + annotation) ]; }, getLinePos: function getLinePos(char) { var this$1 = this; var lineNum = 0; var lineStart = 0; while (char >= this.lineEnds[lineNum]) { lineStart = this$1.lineEnds[lineNum]; lineNum += 1; } var columnNum = char - lineStart; return [lineNum + 1, columnNum + 1, char]; // line/col should be one-based, not zero-based! }, error: function error(message) { var ref = this.getContextMessage(this.pos, message); var lineNum = ref[0]; var columnNum = ref[1]; var msg = ref[2]; var error = new ParseError(msg); error.line = lineNum; error.character = columnNum; error.shortMessage = message; throw error; }, matchString: function matchString(string) { if (this.str.substr(this.pos, string.length) === string) { this.pos += string.length; return string; } }, matchPattern: function matchPattern(pattern) { var match; if ((match = pattern.exec(this.remaining()))) { this.pos += match[0].length; return match[1] || match[0]; } }, sp: function sp() { this.matchPattern(leadingWhitespace); }, remaining: function remaining() { return this.str.substring(this.pos); }, nextChar: function nextChar() { return this.str.charAt(this.pos); }, warn: function warn(message) { var msg = this.getContextMessage(this.pos, message)[2]; warnIfDebug(msg); } }; Parser.extend = function(proto) { var Parent = this; var Child = function(str, options) { Parser.call(this, str, options); }; Child.prototype = create(Parent.prototype); for (var key in proto) { if (hasOwn(proto, key)) { Child.prototype[key] = proto[key]; } } Child.extend = Parser.extend; return Child; }; var TEXT = 1; var INTERPOLATOR = 2; var TRIPLE = 3; var SECTION = 4; var INVERTED = 5; var CLOSING = 6; var ELEMENT = 7; var PARTIAL = 8; var C