wise-web-client
Version:
Based on Spine MVC framework
1,760 lines (1,648 loc) • 442 kB
JavaScript
/*
ractive.js v0.6.1
2014-10-25 - commit 3a576eb3
http://ractivejs.org
http://twitter.com/RactiveJS
Released under the MIT License.
*/
( function( global ) {
'use strict';
var noConflict = global.Ractive;
/* config/defaults/options.js */
var options = function() {
var defaultOptions = {
// render placement:
el: void 0,
append: false,
// template:
template: {
v: 1,
t: []
},
yield: null,
// parse:
preserveWhitespace: false,
sanitize: false,
stripComments: true,
// data & binding:
data: {},
computed: {},
magic: false,
modifyArrays: true,
adapt: [],
isolated: false,
twoway: true,
lazy: false,
// transitions:
noIntro: false,
transitionsEnabled: true,
complete: void 0,
// css:
noCssTransform: false,
// debug:
debug: false
};
return defaultOptions;
}();
/* config/defaults/easing.js */
var 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 );
}
};
/* circular.js */
var circular = [];
/* utils/hasOwnProperty.js */
var hasOwn = Object.prototype.hasOwnProperty;
/* utils/isArray.js */
var isArray = function() {
var toString = Object.prototype.toString;
// thanks, http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/
return function( thing ) {
return toString.call( thing ) === '[object Array]';
};
}();
/* utils/isObject.js */
var isObject = function() {
var toString = Object.prototype.toString;
return function( thing ) {
return thing && toString.call( thing ) === '[object Object]';
};
}();
/* utils/isNumeric.js */
var isNumeric = function( thing ) {
return !isNaN( parseFloat( thing ) ) && isFinite( thing );
};
/* config/defaults/interpolators.js */
var interpolators = function( circular, hasOwnProperty, isArray, isObject, isNumeric ) {
var interpolators, interpolate, cssLengthPattern;
circular.push( function() {
interpolate = circular.interpolate;
} );
cssLengthPattern = /^([+-]?[0-9]+\.?(?:[0-9]+)?)(px|em|ex|%|in|cm|mm|pt|pc)$/;
interpolators = {
number: function( from, to ) {
var delta;
if ( !isNumeric( from ) || !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 ] = 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 ( hasOwnProperty.call( from, prop ) ) {
if ( hasOwnProperty.call( to, prop ) ) {
properties.push( prop );
interpolators[ prop ] = interpolate( from[ prop ], to[ prop ] );
} else {
intermediate[ prop ] = from[ prop ];
}
}
}
for ( prop in to ) {
if ( hasOwnProperty.call( to, prop ) && !hasOwnProperty.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;
};
}
};
return interpolators;
}( circular, hasOwn, isArray, isObject, isNumeric );
/* config/svg.js */
var svg = function() {
var svg;
if ( typeof document === 'undefined' ) {
svg = false;
} else {
svg = document && document.implementation.hasFeature( 'http://www.w3.org/TR/SVG11/feature#BasicStructure', '1.1' );
}
return svg;
}();
/* utils/warn.js */
var warn = function() {
/* global console */
var warn, warned = {};
if ( typeof console !== 'undefined' && typeof console.warn === 'function' && typeof console.warn.apply === 'function' ) {
warn = function( message, allowDuplicates ) {
if ( !allowDuplicates ) {
if ( warned[ message ] ) {
return;
}
warned[ message ] = true;
}
console.warn( '%cRactive.js: %c' + message, 'color: rgb(114, 157, 52);', 'color: rgb(85, 85, 85);' );
};
} else {
warn = function() {};
}
return warn;
}();
/* config/errors.js */
var errors = {
missingParser: 'Missing Ractive.parse - cannot parse template. Either preparse or use the version that includes the parser',
mergeComparisonFail: 'Merge operation: comparison failed. Falling back to identity checking',
noComponentEventArguments: 'Components currently only support simple events - you cannot include arguments. Sorry!',
noTemplateForPartial: 'Could not find template for partial "{name}"',
noNestedPartials: 'Partials ({{>{name}}}) cannot contain nested inline partials',
evaluationError: 'Error evaluating "{uniqueString}": {err}',
badArguments: 'Bad arguments "{arguments}". I\'m not allowed to argue unless you\'ve paid.',
failedComputation: 'Failed to compute "{key}": {err}',
missingPlugin: 'Missing "{name}" {plugin} plugin. You may need to download a {plugin} via http://docs.ractivejs.org/latest/plugins#{plugin}s',
badRadioInputBinding: 'A radio input can have two-way binding on its name attribute, or its checked attribute - not both',
noRegistryFunctionReturn: 'A function was specified for "{name}" {registry}, but no {registry} was returned',
defaultElSpecified: 'The <{name}/> component has a default `el` property; it has been disregarded',
noElementProxyEventWildcards: 'Only component proxy-events may contain "*" wildcards, <{element} on-{event}/> is not valid.',
methodDeprecated: 'The method "{deprecated}" has been deprecated in favor of "{replacement}" and will likely be removed in a future release. See http://docs.ractivejs.org/latest/migrating for more information.'
};
/* utils/log.js */
var log = function( consolewarn, errors ) {
var log = {
warn: function( options, passthru ) {
if ( !options.debug && !passthru ) {
return;
}
this.warnAlways( options );
},
warnAlways: function( options ) {
this.logger( getMessage( options ), options.allowDuplicates );
},
error: function( options ) {
this.errorOnly( options );
if ( !options.debug ) {
this.warn( options, true );
}
},
errorOnly: function( options ) {
if ( options.debug ) {
this.critical( options );
}
},
critical: function( options ) {
var err = options.err || new Error( getMessage( options ) );
this.thrower( err );
},
logger: consolewarn,
thrower: function( err ) {
throw err;
}
};
function getMessage( options ) {
var message = errors[ options.message ] || options.message || '';
return interpolate( message, options.args );
}
// simple interpolation. probably quicker (and better) out there,
// but log is not in golden path of execution, only exceptions
function interpolate( message, args ) {
return message.replace( /{([^{}]*)}/g, function( a, b ) {
return args[ b ];
} );
}
return log;
}( warn, errors );
/* Ractive/prototype/shared/hooks/Hook.js */
var Ractive$shared_hooks_Hook = function( log ) {
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 ) ) {
log.warnAlways( {
debug: ractive.debug,
message: this.deprecate.message || 'methodDeprecated',
args: this.deprecate
} );
}
arg ? ractive.fire( this.event, arg ) : ractive.fire( this.event );
};
return Hook;
}( log );
/* utils/removeFromArray.js */
var removeFromArray = function( array, member ) {
var index = array.indexOf( member );
if ( index !== -1 ) {
array.splice( index, 1 );
}
};
/* utils/Promise.js */
var Promise = function() {
var __export;
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 );
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( i ) {
promises[ i ].then( function( value ) {
result[ i ] = value;
if ( !--pending ) {
fulfil( result );
}
}, reject );
};
pending = i = promises.length;
while ( i-- ) {
processPromise( i );
}
} );
};
_Promise.resolve = function( value ) {
return new _Promise( function( fulfil ) {
fulfil( value );
} );
};
_Promise.reject = function( reason ) {
return new _Promise( function( fulfil, reject ) {
reject( reason );
} );
};
}
__export = _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 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 );
} else if ( x && ( typeof x === 'object' || typeof x === 'function' ) ) {
try {
then = x.then;
} 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;
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 );
}
}
return __export;
}();
/* utils/normaliseRef.js */
var normaliseRef = function() {
var regex = /\[\s*(\*|[0-9]|[1-9][0-9]+)\s*\]/g;
return function normaliseRef( ref ) {
return ( ref || '' ).replace( regex, '.$1' );
};
}();
/* shared/getInnerContext.js */
var getInnerContext = function( fragment ) {
do {
if ( fragment.context !== undefined ) {
return fragment.context;
}
} while ( fragment = fragment.parent );
return '';
};
/* utils/isEqual.js */
var isEqual = function( a, b ) {
if ( a === null && b === null ) {
return true;
}
if ( typeof a === 'object' || typeof b === 'object' ) {
return false;
}
return a === b;
};
/* shared/createComponentBinding.js */
var createComponentBinding = function( circular, isEqual ) {
var runloop;
circular.push( function() {
return runloop = circular.runloop;
} );
var Binding = function( ractive, keypath, otherInstance, otherKeypath ) {
var this$0 = this;
this.root = ractive;
this.keypath = keypath;
this.otherInstance = otherInstance;
this.otherKeypath = otherKeypath;
this.lock = function() {
return this$0.updating = true;
};
this.unlock = function() {
return this$0.updating = false;
};
this.bind();
this.value = this.root.viewmodel.get( this.keypath );
};
Binding.prototype = {
isLocked: function() {
return this.updating || this.counterpart && this.counterpart.updating;
},
shuffle: function( newIndices, value ) {
this.propagateChange( value, newIndices );
},
setValue: function( value ) {
this.propagateChange( value );
},
propagateChange: function( value, newIndices ) {
var other;
// Only *you* can prevent infinite loops
if ( this.isLocked() ) {
this.value = value;
return;
}
if ( !isEqual( value, this.value ) ) {
this.lock();
// TODO maybe the case that `value === this.value` - should that result
// in an update rather than a set?
// if the other viewmodel is already locked up, need to do a deferred update
if ( !runloop.addViewmodel( other = this.otherInstance.viewmodel ) && this.counterpart.value !== value ) {
runloop.scheduleTask( function() {
return runloop.addViewmodel( other );
} );
}
if ( newIndices ) {
other.smartUpdate( this.otherKeypath, value, newIndices );
} else {
if ( isSettable( other, this.otherKeypath ) ) {
other.set( this.otherKeypath, value );
}
}
this.value = value;
// TODO will the counterpart update after this line, during
// the runloop end cycle? may be a problem...
runloop.scheduleTask( this.unlock );
}
},
refineValue: function( keypaths ) {
var this$0 = this;
var other;
if ( this.isLocked() ) {
return;
}
this.lock();
runloop.addViewmodel( other = this.otherInstance.viewmodel );
keypaths.map( function( keypath ) {
return this$0.otherKeypath + keypath.substr( this$0.keypath.length );
} ).forEach( function( keypath ) {
return other.mark( keypath );
} );
runloop.scheduleTask( this.unlock );
},
bind: function() {
this.root.viewmodel.register( this.keypath, this );
},
rebind: function( newKeypath ) {
this.unbind();
this.keypath = newKeypath;
this.counterpart.otherKeypath = newKeypath;
this.bind();
},
unbind: function() {
this.root.viewmodel.unregister( this.keypath, this );
}
};
function isSettable( viewmodel, keypath ) {
var computed = viewmodel.computations[ keypath ];
return !computed || computed.setter;
}
return function createComponentBinding( component, parentInstance, parentKeypath, childKeypath ) {
var hash, childInstance, bindings, parentToChildBinding, childToParentBinding;
hash = parentKeypath + '=' + childKeypath;
bindings = component.bindings;
if ( bindings[ hash ] ) {
// TODO does this ever happen?
return;
}
childInstance = component.instance;
parentToChildBinding = new Binding( parentInstance, parentKeypath, childInstance, childKeypath );
bindings.push( parentToChildBinding );
if ( childInstance.twoway ) {
childToParentBinding = new Binding( childInstance, childKeypath, parentInstance, parentKeypath );
bindings.push( childToParentBinding );
parentToChildBinding.counterpart = childToParentBinding;
childToParentBinding.counterpart = parentToChildBinding;
}
bindings[ hash ] = parentToChildBinding;
};
}( circular, isEqual );
/* shared/resolveRef.js */
var resolveRef = function( normaliseRef, getInnerContext, createComponentBinding ) {
var __export;
var ancestorErrorMessage, getOptions;
ancestorErrorMessage = 'Could not resolve reference - too many "../" prefixes';
getOptions = {
evaluateWrapped: true
};
__export = function resolveRef( ractive, ref, fragment, isParentLookup ) {
var context, key, index, keypath, parentValue, hasContextChain, parentKeys, childKeys, parentKeypath, childKeypath;
ref = normaliseRef( ref );
// If a reference begins '~/', it's a top-level reference
if ( ref.substr( 0, 2 ) === '~/' ) {
return ref.substring( 2 );
}
// If a reference begins with '.', it's either a restricted reference or
// an ancestor reference...
if ( ref.charAt( 0 ) === '.' ) {
return resolveAncestorReference( getInnerContext( fragment ), ref );
}
// ...otherwise we need to find the keypath
key = ref.split( '.' )[ 0 ];
// get() in viewmodel creation means no fragment (yet)
fragment = fragment || {};
do {
context = fragment.context;
if ( !context ) {
continue;
}
hasContextChain = true;
parentValue = ractive.viewmodel.get( context, getOptions );
if ( parentValue && ( typeof parentValue === 'object' || typeof parentValue === 'function' ) && key in parentValue ) {
return context + '.' + ref;
}
} while ( fragment = fragment.parent );
// Root/computed property?
if ( key in ractive.data || key in ractive.viewmodel.computations ) {
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;
// Special case - index refs
if ( fragment.indexRefs && ( index = fragment.indexRefs[ ref ] ) !== undefined ) {
// Create an index ref binding, so that it can be rebound letter if necessary.
// It doesn't have an alias since it's an implicit binding, hence `...[ ref ] = ref`
ractive.component.indexRefBindings[ ref ] = ref;
ractive.viewmodel.set( ref, index, true );
return;
}
keypath = resolveRef( ractive._parent, ref, fragment, true );
if ( keypath ) {
// We need to create an inter-component binding
// If parent keypath is 'one.foo' and child is 'two.foo', we bind
// 'one' to 'two' as it's more efficient and avoids edge cases
parentKeys = keypath.split( '.' );
childKeys = ref.split( '.' );
while ( parentKeys.length > 1 && childKeys.length > 1 && parentKeys[ parentKeys.length - 1 ] === childKeys[ childKeys.length - 1 ] ) {
parentKeys.pop();
childKeys.pop();
}
parentKeypath = parentKeys.join( '.' );
childKeypath = childKeys.join( '.' );
ractive.viewmodel.set( childKeypath, ractive._parent.viewmodel.get( parentKeypath ), true );
createComponentBinding( ractive.component, ractive._parent, parentKeypath, childKeypath );
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;
}
if ( ractive.viewmodel.get( ref ) !== undefined ) {
return ref;
}
};
function resolveAncestorReference( baseContext, ref ) {
var contextKeys;
// {{.}} means 'current context'
if ( ref === '.' )
return 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( ancestorErrorMessage );
}
contextKeys.pop();
ref = ref.substring( 3 );
}
contextKeys.push( ref );
return contextKeys.join( '.' );
}
// not an ancestor reference - must be a restricted reference (prepended with "." or "./")
if ( !baseContext ) {
return ref.replace( /^\.\/?/, '' );
}
return baseContext + ref.replace( /^\.\//, '.' );
}
return __export;
}( normaliseRef, getInnerContext, createComponentBinding );
/* global/TransitionManager.js */
var TransitionManager = function( removeFromArray ) {
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.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 );
},
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.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();
}
}
}
return TransitionManager;
}( removeFromArray );
/* global/runloop.js */
var runloop = function( circular, Hook, removeFromArray, Promise, resolveRef, TransitionManager ) {
var __export;
var batch, runloop, unresolved = [],
changeHook = new Hook( 'change' );
runloop = {
start: function( instance, returnPromise ) {
var promise, fulfilPromise;
if ( returnPromise ) {
promise = new Promise( function( f ) {
return fulfilPromise = f;
} );
}
batch = {
previousBatch: batch,
transitionManager: new TransitionManager( fulfilPromise, batch && batch.transitionManager ),
views: [],
tasks: [],
viewmodels: [],
instance: instance
};
if ( instance ) {
batch.viewmodels.push( instance.viewmodel );
}
return promise;
},
end: function() {
flushChanges();
batch.transitionManager.init();
if ( !batch.previousBatch && !!batch.instance )
batch.instance.viewmodel.changes = [];
batch = batch.previousBatch;
},
addViewmodel: function( viewmodel ) {
if ( batch ) {
if ( batch.viewmodels.indexOf( viewmodel ) === -1 ) {
batch.viewmodels.push( viewmodel );
return true;
} else {
return false;
}
} else {
viewmodel.applyChanges();
return false;
}
},
registerTransition: function( transition ) {
transition._manager = batch.transitionManager;
batch.transitionManager.add( transition );
},
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 );
}
}
};
circular.runloop = runloop;
__export = runloop;
function flushChanges() {
var i, thing, changeHash;
for ( i = 0; i < batch.viewmodels.length; i += 1 ) {
thing = batch.viewmodels[ i ];
changeHash = thing.applyChanges();
if ( changeHash ) {
changeHook.fire( thing.ractive, changeHash );
}
}
batch.viewmodels.length = 0;
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 <option> elements caused the binding on the <select>
// to update - then we start over
if ( batch.viewmodels.length )
return flushChanges();
}
function attemptKeypathResolution() {
var i, item, keypath, resolved;
i = unresolved.length;
// see if we can resolve any unresolved references
while ( i-- ) {
item = unresolved[ i ];
if ( item.keypath ) {
// it resolved some other way. TODO how? two-way binding? Seems
// weird that we'd still end up here
unresolved.splice( i, 1 );
}
if ( keypath = resolveRef( item.root, item.ref, item.parentFragment ) ) {
( resolved || ( resolved = [] ) ).push( {
item: item,
keypath: keypath
} );
unresolved.splice( i, 1 );
}
}
if ( resolved ) {
resolved.forEach( resolve );
}
}
function resolve( resolved ) {
resolved.item.resolve( resolved.keypath );
}
return __export;
}( circular, Ractive$shared_hooks_Hook, removeFromArray, Promise, resolveRef, TransitionManager );
/* utils/createBranch.js */
var createBranch = function() {
var numeric = /^\s*[0-9]+\s*$/;
return function( key ) {
return numeric.test( key ) ? [] : {};
};
}();
/* viewmodel/prototype/get/magicAdaptor.js */
var viewmodel$get_magicAdaptor = function( runloop, createBranch, isArray ) {
var __export;
var magicAdaptor, MagicWrapper;
try {
Object.defineProperty( {}, 'test', {
value: 0
} );
magicAdaptor = {
filter: function( object, keypath, ractive ) {
var keys, key, parentKeypath, parentWrapper, parentValue;
if ( !keypath ) {
return false;
}
keys = keypath.split( '.' );
key = keys.pop();
parentKeypath = keys.join( '.' );
// If the parent value is a wrapper, other than a magic wrapper,
// we shouldn't wrap this property
if ( ( parentWrapper = ractive.viewmodel.wrapped[ parentKeypath ] ) && !parentWrapper.magic ) {
return false;
}
parentValue = ractive.get( parentKeypath );
// if parentValue is an array that doesn't include this member,
// we should return false otherwise lengths will get messed up
if ( isArray( parentValue ) && /^[0-9]+$/.test( key ) ) {
return false;
}
return parentValue && ( typeof parentValue === 'object' || typeof parentValue === 'function' );
},
wrap: function( ractive, property, keypath ) {
return new MagicWrapper( ractive, property, keypath );
}
};
MagicWrapper = function( ractive, value, keypath ) {
var keys, objKeypath, template, siblings;
this.magic = true;
this.ractive = ractive;
this.keypath = keypath;
this.value = value;
keys = keypath.split( '.' );
this.prop = keys.pop();
objKeypath = keys.join( '.' );
this.obj = objKeypath ? ractive.get( objKeypath ) : ractive.data;
template = this.originalDescriptor = Object.getOwnPropertyDescriptor( this.obj, this.prop );
// Has this property already been wrapped?
if ( template && template.set && ( siblings = template.set._ractiveWrappers ) ) {
// Yes. Register this wrapper to this property, if it hasn't been already
if ( siblings.indexOf( this ) === -1 ) {
siblings.push( this );
}
return;
}
// No, it hasn't been wrapped
createAccessors( this, value, template );
};
MagicWrapper.prototype = {
get: function() {
return this.value;
},
reset: function( value ) {
if ( this.updating ) {
return;
}
this.updating = true;
this.obj[ this.prop ] = value;
// trigger set() accessor
runloop.addViewmodel( this.ractive.viewmodel );
this.ractive.viewmodel.mark( this.keypath );
this.updating = false;
},
set: function( key, value ) {
if ( this.updating ) {
return;
}
if ( !this.obj[ this.prop ] ) {
this.updating = true;
this.obj[ this.prop ] = createBranch( key );
this.updating = false;
}
this.obj[ this.prop ][ key ] = value;
},
teardown: function() {
var template, set, value, wrappers, index;
// If this method was called because the cache was being cleared as a
// result of a set()/update() call made by this wrapper, we return false
// so that it doesn't get torn down
if ( this.updating ) {
return false;
}
template = Object.getOwnPropertyDescriptor( this.obj, this.prop );
set = template && template.set;
if ( !set ) {
// most likely, this was an array member that was spliced out
return;
}
wrappers = set._ractiveWrappers;
index = wrappers.indexOf( this );
if ( index !== -1 ) {
wrappers.splice( index, 1 );
}
// Last one out, turn off the lights
if ( !wrappers.length ) {
value = this.obj[ this.prop ];
Object.defineProperty( this.obj, this.prop, this.originalDescriptor || {
writable: true,
enumerable: true,
configurable: true
} );
this.obj[ this.prop ] = value;
}
}
};
} catch ( err ) {
magicAdaptor = false;
}
__export = magicAdaptor;
function createAccessors( originalWrapper, value, template ) {
var object, property, oldGet, oldSet, get, set;
object = originalWrapper.obj;
property = originalWrapper.prop;
// Is this template configurable?
if ( template && !template.configurable ) {
// Special case - array length
if ( property === 'length' ) {
return;
}
throw new Error( 'Cannot use magic mode with property "' + property + '" - object is not configurable' );
}
// Time to wrap this property
if ( template ) {
oldGet = template.get;
oldSet = template.set;
}
get = oldGet || function() {
return value;
};
set = function( v ) {
if ( oldSet ) {
oldSet( v );
}
value = oldGet ? oldGet() : v;
set._ractiveWrappers.forEach( updateWrapper );
};
function updateWrapper( wrapper ) {
var keypath, ractive;
wrapper.value = value;
if ( wrapper.updating ) {
return;
}
ractive = wrapper.ractive;
keypath = wrapper.keypath;
wrapper.updating = true;
runloop.start( ractive );
ractive.viewmodel.mark( keypath );
runloop.end();
wrapper.updating = false;
}
// Create an array of wrappers, in case other keypaths/ractives depend on this property.
// Handily, we can store them as a property of the set function. Yay JavaScript.
set._ractiveWrappers = [ originalWrapper ];
Object.defineProperty( object, property, {
get: get,
set: set,
enumerable: true,
configurable: true
} );
}
return __export;
}( runloop, createBranch, isArray );
/* config/magic.js */
var magic = function( magicAdaptor ) {
return !!magicAdaptor;
}( viewmodel$get_magicAdaptor );
/* config/namespaces.js */
var 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/'
};
/* utils/createElement.js */
var createElement = function( svg, namespaces ) {
var createElement;
// 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 );
};
}
return createElement;
}( svg, namespaces );
/* config/isClient.js */
var isClient = function() {
var isClient = typeof document === 'object';
return isClient;
}();
/* utils/defineProperty.js */
var defineProperty = function( isClient ) {
var defineProperty;
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 the fuck were you smoking, MSFT?)
defineProperty = function( obj, prop, desc ) {
obj[ prop ] = desc.value;
};
}
return defineProperty;
}( isClient );
/* utils/defineProperties.js */
var defineProperties = function( createElement, defineProperty, isClient ) {
var defineProperties;
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 ] );
}
}
};
}
return defineProperties;
}( createElement, defineProperty, isClient );
/* Ractive/prototype/shared/add.js */
var Ractive$shared_add = function( isNumeric ) {
return function add( root, keypath, d ) {
var value;
if ( typeof keypath !== 'string' || !isNumeric( d ) ) {
throw new Error( 'Bad arguments' );
}
value = +root.get( keypath ) || 0;
if ( !isNumeric( value ) ) {
throw new Error( 'Cannot add to a non-numeric value' );
}
return root.set( keypath, value + d );
};
}( isNumeric );
/* Ractive/prototype/add.js */
var Ractive$add = function( add ) {
return function Ractive$add( keypath, d ) {
return add( this, keypath, d === undefined ? 1 : +d );
};
}( Ractive$shared_add );
/* utils/normaliseKeypath.js */
var normaliseKeypath = function( normaliseRef ) {
var leadingDot = /^\.+/;
return function normaliseKeypath( keypath ) {
return normaliseRef( keypath ).replace( leadingDot, '' );
};
}( normaliseRef );
/* config/vendors.js */
var vendors = [
'o',
'ms',
'moz',
'webkit'
];
/* utils/requestAnimationFrame.js */
var requestAnimationFrame = function( vendors ) {
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;
}
return requestAnimationFrame;
}( vendors );
/* utils/getTime.js */
var getTime = function() {
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();
};
}
return getTime;
}();
/* shared/animations.js */
var animations = function( rAF, getTime, runloop ) {
var queue = [];
var animations = {
tick: function() {
var i, animation, now;
now = getTime();
runloop.start();
for ( i = 0; i < queue.length; i += 1 ) {
animation = queue[ i ];
if ( !animation.tick( now ) ) {
// animation is complete, remove it from the stack, and decrement i so we don't miss one
queue.splice( i--, 1 );
}
}
runloop.end();
if ( queue.length ) {
rAF( animations.tick );
} else {
animations.running = false;
}
},
add: function( animation ) {
queue.push( animation );
if ( !animations.running ) {
animations.running = true;
rAF( animations.tick );
}
},
// TODO optimise this
abort: function( keypath, root ) {
var i = queue.length,
animation;
while ( i-- ) {
animation = queue[ i ];
if ( animation.root === root && animation.keypath === keypath ) {
animation.stop();
}
}
}
};
return animations;
}( requestAnimationFrame, getTime, runloop );
/* config/options/css/transform.js */
var transform = function() {
var __export;
var selectorsPattern = /(?:^|\})?\s*([^\{\}]+)\s*\{/g,
commentsPattern = /\/\*.*?\*\//g,
selectorUnitPattern = /((?:(?:\[[^\]+]\])|(?:[^\s\+\>\~:]))+)((?::[^\s\+\>\~]+)?\s*[\s\+\>\~]?)\s*/g,
mediaQueryPattern = /^@media/,
dataRvcGuidPattern = /\[data-rvcguid="[a-z0-9-]+"]/g;
__export = function transformCss( css, guid ) {
var transformed, addGuid;
addGuid = function( selector ) {
var selectorUnits, match, unit, dataAttr, base, prepended, appended, i, transformed = [];
selectorUnits = [];
while ( match = selectorUnitPattern.exec( selector ) ) {
selectorUnits.push( {
str: match[ 0 ],
base: match[ 1 ],
modifiers: match[ 2 ]
} );
}
// For each simple selector within the selector, we need to create a version
// that a) combines with the guid, and b) is inside the guid
dataAttr = '[data-rvcguid="' + guid + '"]';
base = selectorUnits.map( extractString );
i = selectorUnits.length;
while ( i-- ) {
appended = base.slice();
// Pseudo-selectors should go after the attribute selector
unit = selectorUnits[ i ];
appended[ i ] = unit.base + dataAttr + unit.modifiers || '';
prepended = base.slice();
prepended[ i ] = dataAttr + ' ' + prepended[ i ];
transformed.push( appended.join( ' ' ), prepended.join( ' ' ) );
}
return transformed.join( ', ' );
};
if ( dataRvcGuidPattern.test( css ) ) {
transformed = css.replace( dataRvcGuidPattern, '[data-rvcguid="' + guid + '"]' );
} else {
transformed = css.replace( commentsPattern, '' ).replace( selectorsPattern, function( match, $1 ) {
var selectors, transformed;
// don't transform media queries!
if ( mediaQueryPattern.test( $1 ) )
return match;
selectors = $1.split( ',' ).map( trim );
transformed = selectors.map( addGuid ).join( ', ' ) + ' ';
return match.replace( $1, transformed );
} );
}
return transformed;
};
function trim( str ) {
if ( str.trim ) {
return str.trim();
}
return str.replace( /^\s+/, '' ).replace( /\s+$/, '' );
}
function extractString( unit ) {
return unit.str;
}
return __export;
}();
/* config/options/css/css.js */
var css = function( transformCss ) {
var cssConfig = {
name: 'css',
extend: extend,
init: function() {}
};
function extend( Parent, proto, options ) {
var guid = proto.constructor._guid,
css;
if ( css = getCss( options.css, options, guid ) || getCss( Parent.css, Parent, guid ) ) {
proto.constructor.css = css;
}
}
function getCss( css, target, guid ) {
if ( !css ) {
return;
}
return target.noCssTransform ? css : transformCss( css, guid );
}
return cssConfig;
}( transform );
/* utils/wrapMethod.js */
var wrapMethod = function() {
var __export;
__export = function( method, superMethod, force ) {
if ( force || needsSuper( method, superMethod ) ) {
return function() {
var hasSuper = '_super' in this,
_super = this._super,
result;
this._super = superMethod;
result = method.apply( this, arguments );
if ( hasSuper ) {
this._super = _super;
}
return result;
};
} else {
return method;
}
};
function needsSuper( method, superMethod ) {
return typeof superMethod === 'function' && /_super/.test( method );
}
return __export;
}();
/* config/options/data.js */
var data = function( wrap ) {
var __export;
var dataConfig = {
name: 'data',
extend: extend,
init: init,
reset: reset
};
__export = dataConfig;
function combine( Parent, target, options ) {
var value = options.data || {},
parentValue = getAddedKeys( Parent.prototype.data );
if ( typeof value !== 'object' && typeof value !== 'function' ) {
throw new TypeError( 'data option must be an object or a function, "' + value + '" is not valid' );
}
return dispatch( parentValue, value );
}
function extend( Parent, proto, options ) {
proto.data = combine( Parent, proto, options );
}
function init( Parent, ractive, options ) {
var value = options.data,
result = combine( Parent, ractive, options );
if ( typeof result === 'function' ) {
result = result.call( ractive, value ) || value;
}
return ractive.data = result || {};
}
function reset( ractive ) {
var result = this.init( ractive.constructor, ractive, ractive );
if ( result ) {
ractive.data = result;
return true;
}
}
function getAddedKeys( parent ) {
// only for functions that had keys added
if ( typeof parent !== 'function' || !Object.keys( parent ).length ) {
return parent;
}
// copy the added keys to temp 'object', otherwise
// parent would be interpreted as 'function' by dispatch
var temp = {};
copy( parent, temp );
// roll in added keys
return dispatch( parent, temp );
}
function dispatch( parent, child ) {
if ( typeof child === 'function' ) {
return extendFn( child, parent );
} else if ( typeof parent === 'function' ) {
return fromFn( child, parent );
} else {
return fromProperties( child, parent );
}
}
function copy( from, to, fillOnly ) {
for ( var key in from ) {
if ( fillOnly && key in to ) {
continue;
}
to[ key ] = from[ key ];
}
}
function fromProperties( child, parent ) {
child = child || {};
if ( !parent ) {
return child;
}
copy( parent, child, true );
return child;
}
function fromFn( child, parentFn ) {
return function( data ) {
var keys;
if ( child ) {
// Track the keys that our on the child,
// but not on the data. We'll need to apply these
// after the parent function returns.
keys = [];
for ( var key in child ) {
if ( !data || !( key in data ) ) {
keys.push( key );
}
}
}
// call the parent fn, use data if no return value
data = parentFn.call( this, data ) || data;
// Copy child keys back onto data. The child keys
// should take precedence over whatever the
// parent did with the data.
if ( keys && keys.length ) {
data = data || {};
keys.forEach( function( key ) {
data[ key ] = child[ key ];
} );
}
return data;
};
}
function extendFn( childFn, parent ) {
var parentFn;
if ( typeof parent !== 'function' ) {
// copy props to data
parentFn = function( data ) {
fromProperties( data, parent );
};
} else {
parentFn = function( data ) {
// give parent function it's own this._super context,
// otherwise this._super is from child and
// causes infinite loop
parent = wrap( parent, function() {}, true );
return parent.call( this, data ) || data;
};
}
return wrap( childFn, parentFn );
}
return __export;
}( wrapMethod );
/* config/types.js */
var 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,
ATTRIBUTE: 13,
CLOSING_TAG: 14,
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,
SECTION_IF: 50,
SECTION_UNLESS: 51,
SECTION_EACH: 52,
SECTION_WITH: 53,
SECTION_IF_WITH: 54
};
/* utils/create.js */
var create = function() {
var create;
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;
};
}();
}
return create;
}();
/* parse/Parser/expressions/shared/errors.js */
var parse_Parser_expressions_shared_errors = {
expectedExpression: 'Expected a JavaScript expression',
expectedParen: 'Expected closing paren'
};
/* parse/Parser/expressions/primary/literal/numberLiteral.js */
var numberLiteral = function( types ) {
var numberPatter