"); //-> "<div> </div>"
* ```
*/
esc: function (content) {
return convertBadValues(content)
.replace(/&/g, '&')
.replace(//g, '>')
.replace(strQuote, '"')
.replace(strSingleQuote, ''');
},
/**
* @function can-string.capitalize capitalize
* @signature `string.capitalize(s)`
* @param {String} s the string to capitalize
* @return {String} the supplied string with the first character uppercased if it is a letter
*
* ```js
* var string = require("can-string");
*
* console.log(string.capitalize("foo")); // -> "Foo"
* console.log(string.capitalize("123")); // -> "123"
* ```
*/
capitalize: function (s) {
// Used to make newId.
return s.charAt(0)
.toUpperCase() + s.slice(1);
},
/**
* @function can-string.camelize camelize
* @signature `string.camelize(s)`
* @param {String} str the string to camelCase
* @return {String} the supplied string with hyphens removed and following letters capitalized.
*
* ```js
* var string = require("can-string");
*
* console.log(string.camelize("foo-bar")); // -> "fooBar"
* console.log(string.camelize("-webkit-flex-flow")); // -> "WebkitFlexFlow"
* ```
*/
camelize: function (str) {
return convertBadValues(str)
.replace(strHyphenMatch, function (match, chr) {
return chr ? chr.toUpperCase() : '';
});
},
/**
* @function can-string.hyphenate hyphenate
* @signature `string.hyphenate(s)`
* @param {String} str a string in camelCase
* @return {String} the supplied string with camelCase converted to hyphen-lowercase digraphs
*
* ```js
* var string = require("can-string");
*
* console.log(string.hyphenate("fooBar")); // -> "foo-bar"
* console.log(string.hyphenate("WebkitFlexFlow")); // -> "Webkit-flex-flow"
* ```
*/
hyphenate: function (str) {
return convertBadValues(str)
.replace(strCamelMatch, function (str) {
return str.charAt(0) + '-' + str.charAt(1)
.toLowerCase();
});
},
/**
* @function can-string.pascalize pascalize
* @signature `string.pascalize(s)`
* @param {String} str the string in hyphen case | camelCase
* @return {String} the supplied string with hyphens | camelCase converted to PascalCase
*
* ```js
* var string = require("can-string");
*
* console.log(string.pascalize("fooBar")); // -> "FooBar"
* console.log(string.pascalize("baz-bar")); // -> "BazBar"
* ```
*/
pascalize: function (str) {
return string.capitalize(string.camelize(str));
},
/**
* @function can-string.underscore underscore
* @signature `string.underscore(s)`
* @param {String} str a string in camelCase
* @return {String} the supplied string with camelCase converted to underscore-lowercase digraphs
*
* ```js
* var string = require("can-string");
*
* console.log(string.underscore("fooBar")); // -> "foo_bar"
* console.log(string.underscore("HTMLElement")); // -> "html_element"
* ```
*/
underscore: function (s) {
return s.replace(strColons, '/')
.replace(strWords, '$1_$2')
.replace(strLowUp, '$1_$2')
.replace(strDash, '_')
.toLowerCase();
},
/**
* @property {RegExp} can-string.strUndHash strUndHash
*
* A regex which matches an underscore or hyphen character
*/
undHash: strUndHash
};
var canString_1_1_0_canString = string;
var inSetupSymbol = canSymbol_1_7_0_canSymbol.for("can.initializing");
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
var CanString = canString_1_1_0_canString;
var reservedWords = {
"abstract": true,
"boolean": true,
"break": true,
"byte": true,
"case": true,
"catch": true,
"char": true,
"class": true,
"const": true,
"continue": true,
"debugger": true,
"default": true,
"delete": true,
"do": true,
"double": true,
"else": true,
"enum": true,
"export": true,
"extends": true,
"false": true,
"final": true,
"finally": true,
"float": true,
"for": true,
"function": true,
"goto": true,
"if": true,
"implements": true,
"import": true,
"in": true,
"instanceof": true,
"int": true,
"interface": true,
"let": true,
"long": true,
"native": true,
"new": true,
"null": true,
"package": true,
"private": true,
"protected": true,
"public": true,
"return": true,
"short": true,
"static": true,
"super": true,
"switch": true,
"synchronized": true,
"this": true,
"throw": true,
"throws": true,
"transient": true,
"true": true,
"try": true,
"typeof": true,
"var": true,
"void": true,
"volatile": true,
"while": true,
"with": true
};
var constructorNameRegex = /[^A-Z0-9_]/gi;
}
//!steal-remove-end
// ## construct.js
// `Construct`
// _This is a modified version of
// [John Resig's class](http://ejohn.org/blog/simple-javascript-inheritance/).
// It provides class level inheritance and callbacks._
// A private flag used to initialize a new class instance without
// initializing it's bindings.
var initializing = 0;
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
var namedCtor = (function(cache){
return function(name, fn) {
return ((name in cache) ? cache[name] : cache[name] = new Function(
"__", "function "+name+"(){return __.apply(this,arguments)};return "+name
))( fn );
};
}({}));
}
//!steal-remove-end
/**
* @add can-construct
*/
var Construct = function () {
if (arguments.length) {
return Construct.extend.apply(Construct, arguments);
}
};
var canGetDescriptor;
try {
canGetDescriptor = true;
} catch(e) {
canGetDescriptor = false;
}
var getDescriptor = function(newProps, name) {
var descriptor = Object.getOwnPropertyDescriptor(newProps, name);
if(descriptor && (descriptor.get || descriptor.set)) {
return descriptor;
}
return null;
},
inheritGetterSetter = function(newProps, oldProps, addTo) {
addTo = addTo || newProps;
var descriptor;
for (var name in newProps) {
if( (descriptor = getDescriptor(newProps, name)) ) {
this._defineProperty(addTo, oldProps, name, descriptor);
} else {
Construct._overwrite(addTo, oldProps, name, newProps[name]);
}
}
},
simpleInherit = function (newProps, oldProps, addTo) {
addTo = addTo || newProps;
for (var name in newProps) {
Construct._overwrite(addTo, oldProps, name, newProps[name]);
}
},
defineNonEnumerable = function(obj, prop, value) {
Object.defineProperty(obj, prop, {
configurable: true,
writable: true,
enumerable: false,
value: value
});
};
/**
* @static
*/
canReflect_1_19_2_canReflect.assignMap(Construct, {
/**
* @property {Boolean} can-construct.constructorExtends constructorExtends
* @parent can-construct.static
*
* @description
* Toggles the behavior of a constructor function called
* without the `new` keyword to extend the constructor function or
* create a new instance.
*
* ```js
* var animal = Animal();
* // vs
* var animal = new Animal();
* ```
*
* @body
*
* If `constructorExtends` is:
*
* - `true` - the constructor extends
* - `false` - a new instance of the constructor is created
*
* This property defaults to false.
*
* Example of constructExtends as `true`:
*
* ```js
* var Animal = Construct.extend({
* constructorExtends: true // the constructor extends
* },{
* sayHi: function() {
* console.log("hai!");
* }
* });
*
* var Pony = Animal({
* gallop: function () {
* console.log("Galloping!!");
* }
* }); // Pony is now a constructor function extended from Animal
*
* var frank = new Animal(); // frank is a new instance of Animal
*
* var gertrude = new Pony(); // gertrude is a new instance of Pony
* gertrude.sayHi(); // "hai!" - sayHi is "inherited" from Animal
* gertrude.gallop(); // "Galloping!!" - gallop is unique to instances of Pony
*```
*
* The default behavior is shown in the example below:
*
* ```js
* var Animal = Construct.extend({
* constructorExtends: false // the constructor does NOT extend
* },{
* sayHi: function() {
* console.log("hai!");
* }
* });
*
* var pony = Animal(); // pony is a new instance of Animal
* var frank = new Animal(); // frank is a new instance of Animal
*
* pony.sayHi() // "hai!"
* frank.sayHi() // "hai!"
*```
* By default to extend a constructor, you must use [can-construct.extend extend].
*/
constructorExtends: true,
// This is a hook for adding legacy behaviors
_created: function(){},
/**
* @function can-construct.newInstance newInstance
* @parent can-construct.static
*
* @description Returns an instance of `Construct`. This method
* can be overridden to return a cached instance.
*
* @signature `Construct.newInstance([...args])`
*
* @param {*} [args] arguments that get passed to [can-construct::setup] and [can-construct::init]. Note
* that if [can-construct::setup] returns an array, those arguments will be passed to [can-construct::init]
* instead.
* @return {class} instance of the class
*
* @body
* Creates a new instance of the constructor function. This method is useful for creating new instances
* with arbitrary parameters. Typically, however, you will simply want to call the constructor with the
* __new__ operator.
*
* ## Example
*
* The following creates a `Person` Construct and overrides `newInstance` to cache all
* instances of Person to prevent duplication. If the properties of a new Person match an existing one it
* will return a reference to the previously created object, otherwise it returns a new object entirely.
*
* ```js
* // define and create the Person constructor
* var Person = Construct.extend({
* init : function(first, middle, last) {
* this.first = first;
* this.middle = middle;
* this.last = last;
* }
* });
*
* // store a reference to the original newInstance function
* var _newInstance = Person.newInstance;
*
* // override Person's newInstance function
* Person.newInstance = function() {
* // if cache does not exist make it an new object
* this.__cache = this.__cache || {};
* // id is a stingified version of the passed arguments
* var id = JSON.stringify(arguments);
*
* // look in the cache to see if the object already exists
* var cachedInst = this.__cache[id];
* if(cachedInst) {
* return cachedInst;
* }
*
* //otherwise call the original newInstance function and return a new instance of Person.
* var newInst = _newInstance.apply(this, arguments);
* this.__cache[id] = newInst;
* return newInst;
* };
*
* // create two instances with the same arguments
* var justin = new Person('Justin', 'Barry', 'Meyer'),
* brian = new Person('Justin', 'Barry', 'Meyer');
*
* console.log(justin === brian); // true - both are references to the same instance
* ```
*
*/
newInstance: function () {
// Get a raw instance object (`init` is not called).
var inst = this.instance(),
args;
// Call `setup` if there is a `setup`
if (inst.setup) {
Object.defineProperty(inst,"__inSetup",{
configurable: true,
enumerable: false,
value: true,
writable: true
});
Object.defineProperty(inst, inSetupSymbol, {
configurable: true,
enumerable: false,
value: true,
writable: true
});
args = inst.setup.apply(inst, arguments);
if (args instanceof Construct.ReturnValue){
return args.value;
}
inst.__inSetup = false;
inst[inSetupSymbol] = false;
}
// Call `init` if there is an `init`
// If `setup` returned `args`, use those as the arguments
if (inst.init) {
inst.init.apply(inst, args || arguments);
}
return inst;
},
// Overwrites an object with methods. Used in the `super` plugin.
// `newProps` - New properties to add.
// `oldProps` - Where the old properties might be (used with `super`).
// `addTo` - What we are adding to.
_inherit: canGetDescriptor ? inheritGetterSetter : simpleInherit,
// Adds a `defineProperty` with the given name and descriptor
// Will only ever be called if ES5 is supported
_defineProperty: function(what, oldProps, propName, descriptor) {
Object.defineProperty(what, propName, descriptor);
},
// used for overwriting a single property.
// this should be used for patching other objects
// the super plugin overwrites this
_overwrite: function (what, oldProps, propName, val) {
Object.defineProperty(what, propName, {value: val, configurable: true, enumerable: true, writable: true});
},
// Set `defaults` as the merger of the parent `defaults` and this
// object's `defaults`. If you overwrite this method, make sure to
// include option merging logic.
/**
* @function can-construct.setup setup
* @parent can-construct.static
*
* @description Perform initialization logic for a constructor function.
*
* @signature `Construct.setup(base, fullName, staticProps, protoProps)`
*
* A static `setup` method provides inheritable setup functionality
* for a Constructor function. The following example
* creates a Group constructor function. Any constructor
* functions that inherit from Group will be added to
* `Group.childGroups`.
*
* ```js
* Group = Construct.extend({
* setup: function(Construct, fullName, staticProps, protoProps){
* this.childGroups = [];
* if(Construct !== Construct){
* this.childGroups.push(Construct)
* }
* Construct.setup.apply(this, arguments)
* }
* },{})
* var Flock = Group.extend(...)
* Group.childGroups[0] //-> Flock
* ```
* @param {constructor} base The base constructor that is being inherited from.
* @param {String} fullName The name of the new constructor.
* @param {Object} staticProps The static properties of the new constructor.
* @param {Object} protoProps The prototype properties of the new constructor.
*
* @body
* The static `setup` method is called immediately after a constructor
* function is created and
* set to inherit from its base constructor. It is useful for setting up
* additional inheritance work.
* Do not confuse this with the prototype `[can-construct::setup]` method.
*
* ## Example
*
* This `Parent` class adds a reference to its base class to itself, and
* so do all the classes that inherit from it.
*
* ```js
* Parent = Construct.extend({
* setup : function(base, fullName, staticProps, protoProps){
* this.base = base;
*
* // call base functionality
* Construct.setup.apply(this, arguments)
* }
* },{});
*
* Parent.base; // Construct
*
* Child = Parent({});
*
* Child.base; // Parent
* ```
*/
setup: function (base) {
var defaults = base.defaults ? canReflect_1_19_2_canReflect.serialize(base.defaults) : {};
this.defaults = canReflect_1_19_2_canReflect.assignDeepMap(defaults,this.defaults);
},
// Create's a new `class` instance without initializing by setting the
// `initializing` flag.
instance: function () {
// Prevents running `init`.
initializing = 1;
var inst = new this();
// Allow running `init`.
initializing = 0;
return inst;
},
// Extends classes.
/**
* @function can-construct.extend extend
* @parent can-construct.static
*
* @signature `Construct.extend([name,] [staticProperties,] instanceProperties)`
*
* Extends `Construct`, or constructor functions derived from `Construct`,
* to create a new constructor function. Example:
*
* ```js
* var Animal = Construct.extend({
* sayHi: function(){
* console.log("hi")
* }
* });
*
* var animal = new Animal()
* animal.sayHi();
* ```
*
* @param {String} [name] Adds a name to the constructor function so
* it is nicely labeled in the developer tools. The following:
*
* Construct.extend("ConstructorName",{})
*
* returns a constructur function that will show up as `ConstructorName`
* in the developer tools.
* It also sets "ConstructorName" as [can-construct.shortName shortName].
*
* @param {Object} [staticProperties] Properties that are added the constructor
* function directly. For example:
*
* ```js
* var Animal = Construct.extend({
* findAll: function(){
* return can.ajax({url: "/animals"})
* }
* },{}); // need to pass an empty instanceProperties object
*
* Animal.findAll().then(function(json){ ... })
* ```
*
* The [can-construct.setup static setup] method can be used to
* specify inheritable behavior when a Constructor function is created.
*
* @param {Object} instanceProperties Properties that belong to
* instances made with the constructor. These properties are added to the
* constructor's `prototype` object. Example:
*
* var Animal = Construct.extend({
* findAll: function() {
* return can.ajax({url: "/animals"});
* }
* },{
* init: function(name) {
* this.name = name;
* },
* sayHi: function() {
* console.log(this.name," says hai!");
* }
* })
* var pony = new Animal("Gertrude");
* pony.sayHi(); // "Gertrude says hai!"
*
* The [can-construct::init init] and [can-construct::setup setup] properties
* are used for initialization.
*
* @return {function} The constructor function.
*
* ```js
* var Animal = Construct.extend(...);
* var pony = new Animal(); // Animal is a constructor function
* ```
* @body
* ## Inheritance
* Creating "subclasses" with `Construct` is simple. All you need to do is call the base constructor
* with the new function's static and instance properties. For example, we want our `Snake` to
* be an `Animal`, but there are some differences:
*
*
* var Snake = Animal.extend({
* legs: 0
* }, {
* init: function() {
* Animal.prototype.init.call(this, 'ssssss');
* },
* slither: function() {
* console.log('slithering...');
* }
* });
*
* var baslisk = new Snake();
* baslisk.speak(); // "ssssss"
* baslisk.slither(); // "slithering..."
* baslisk instanceof Snake; // true
* baslisk instanceof Animal; // true
*
*
* ## Static properties and inheritance
*
* If you pass all three arguments to Construct, the second one will be attached directy to the
* constructor, allowing you to imitate static properties and functions. You can access these
* properties through the `[can-construct::constructor this.constructor]` property.
*
* Static properties can get overridden through inheritance just like instance properties. In the example below,
* we override both the legs static property as well as the the init function for each instance:
*
* ```js
* var Animal = Construct.extend({
* legs: 4
* }, {
* init: function(sound) {
* this.sound = sound;
* },
* speak: function() {
* console.log(this.sound);
* }
* });
*
* var Snake = Animal.extend({
* legs: 0
* }, {
* init: function() {
* this.sound = 'ssssss';
* },
* slither: function() {
* console.log('slithering...');
* }
* });
*
* Animal.legs; // 4
* Snake.legs; // 0
* var dog = new Animal('woof');
* var blackMamba = new Snake();
* dog.speak(); // 'woof'
* blackMamba.speak(); // 'ssssss'
* ```
*
* ## Alternative value for a new instance
*
* Sometimes you may want to return some custom value instead of a new object when creating an instance of your class.
* For example, you want your class to act as a singleton, or check whether an item with the given id was already
* created and return an existing one from your cache store (e.g. using [can-connect/constructor/store/store]).
*
* To achieve this you can return [can-construct.ReturnValue] from `setup` method of your class.
*
* Lets say you have `myStore` to cache all newly created instances. And if an item already exists you want to merge
* the new data into the existing instance and return the updated instance.
*
* ```
* var myStore = {};
*
* var Item = Construct.extend({
* setup: function(params){
* if (myStore[params.id]){
* var item = myStore[params.id];
*
* // Merge new data to the existing instance:
* Object.assign(item, params);
*
* // Return the updated item:
* return new Construct.ReturnValue( item );
* } else {
* // Save to cache store:
* myStore[this.id] = this;
*
* return [params];
* }
* },
* init: function(params){
* Object.assign(this, params);
* }
* });
*
* var item_1 = new Item( {id: 1, name: "One"} );
* var item_1a = new Item( {id: 1, name: "OnePlus"} )
* ```
*/
extend: function (name, staticProperties, instanceProperties) {
var shortName = name,
klass = staticProperties,
proto = instanceProperties;
// Figure out what was passed and normalize it.
if (typeof shortName !== 'string') {
proto = klass;
klass = shortName;
name = shortName = null;
}
if (!proto) {
proto = klass;
klass = null;
}
proto = proto || {};
var _super_class = this,
_super = this.prototype,
Constructor, prototype;
// Instantiate a base class (but only create the instance,
// don't run the init constructor).
prototype = this.instance();
// Copy the properties over onto the new prototype.
Construct._inherit(proto, _super, prototype);
if(shortName) {
} else if(klass && klass.shortName) {
shortName = klass.shortName;
} else if(this.shortName) {
shortName = this.shortName;
}
// We want constructor.name to be the same as shortName, within
// the bounds of what the JS VM will allow (meaning no non-word characters).
// new Function() is significantly faster than eval() here.
// Strip semicolons
//!steal-remove-start
// wrapping this var will cause "used out of scope." when linting
var constructorName = shortName ? shortName.replace(constructorNameRegex, '_') : 'Constructor';
if(process.env.NODE_ENV !== 'production') {
if(reservedWords[constructorName]) {
constructorName = CanString.capitalize(constructorName);
}
}
//!steal-remove-end
// The dummy class constructor.
function init() {
/* jshint validthis: true */
// All construction is actually done in the init method.
if (!initializing) {
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
if(!this || (this.constructor !== Constructor) &&
// We are being called without `new` or we are extending.
arguments.length && Constructor.constructorExtends) {
dev.warn('can/construct/construct.js: extending a Construct without calling extend');
}
}
//!steal-remove-end
return (!this || this.constructor !== Constructor) &&
// We are being called without `new` or we are extending.
arguments.length && Constructor.constructorExtends ? Constructor.extend.apply(Constructor, arguments) :
// We are being called with `new`.
Constructor.newInstance.apply(Constructor, arguments);
}
}
Constructor = typeof namedCtor === "function" ?
namedCtor( constructorName, init ) :
function() { return init.apply(this, arguments); };
// Copy old stuff onto class (can probably be merged w/ inherit)
for (var propName in _super_class) {
if (_super_class.hasOwnProperty(propName)) {
Constructor[propName] = _super_class[propName];
}
}
// Copy new static properties on class.
Construct._inherit(klass, _super_class, Constructor);
// Set things that shouldn't be overwritten.
canReflect_1_19_2_canReflect.assignMap(Constructor, {
constructor: Constructor,
prototype: prototype
/**
* @property {String} can-construct.shortName shortName
* @parent can-construct.static
*
* If you pass a name when creating a Construct, the `shortName` property will be set to the
* name.
*
* ```js
* var MyConstructor = Construct.extend("MyConstructor",{},{});
* MyConstructor.shortName // "MyConstructor"
* ```
*/
});
if (shortName !== undefined) {
if (Object.getOwnPropertyDescriptor) {
var desc = Object.getOwnPropertyDescriptor(Constructor, 'name');
if (!desc || desc.configurable) {
Object.defineProperty(
Constructor,
'name',
{ writable: true, value: shortName, configurable: true }
);
}
}
Constructor.shortName = shortName;
}
// Make sure our prototype looks nice.
defineNonEnumerable(Constructor.prototype, "constructor", Constructor);
// Global callback for legacy behaviors
Construct._created(name, Constructor);
// Call the class `setup` and `init`
var t = [_super_class].concat(Array.prototype.slice.call(arguments)),
args = Constructor.setup.apply(Constructor, t);
if (Constructor.init) {
Constructor.init.apply(Constructor, args || t);
}
/**
* @prototype
*/
return Constructor; //
/**
* @property {Object} can-construct.prototype.constructor constructor
* @parent can-construct.prototype
*
* A reference to the constructor function that created the instance. This allows you to access
* the constructor's static properties from an instance.
*
* @body
* ## Example
*
* This Construct has a static counter that counts how many instances have been created:
*
* ```js
* var Counter = Construct.extend({
* count: 0
* }, {
* init: function() {
* this.constructor.count++;
* }
* });
*
* var childCounter = new Counter();
* console.log(childCounter.constructor.count); // 1
* console.log(Counter.count); // 1
* ```
*/
},
/**
* @function can-construct.ReturnValue ReturnValue
* @parent can-construct.static
*
* Use to overwrite the return value of new Construct(...).
*
* @signature `new Construct.ReturnValue( value )`
*
* This constructor function can be used for creating a return value of the `setup` method.
* [can-construct] will check if the return value is an instance of `Construct.ReturnValue`.
* If it is then its `value` will be used as the new instance.
*
* @param {Object} value A value to be used for a new instance instead of a new object.
*
* ```js
* var Student = function( name, school ){
* this.name = name;
* this.school = school;
* }
*
* var Person = Construct.extend({
* setup: function( options ){
* if (options.school){
* return new Constructor.ReturnValue( new Student( options.name, options.school ) );
* } else {
* return [options];
* }
* }
* });
*
* var myPerson = new Person( {name: "Ilya", school: "PetrSU"} );
*
* myPerson instanceof Student // => true
* ```
*/
ReturnValue: function(value){
this.value = value;
}
});
/**
* @function can-construct.prototype.setup setup
* @parent can-construct.prototype
*
* @signature `construct.setup(...args)`
*
* A setup function for the instantiation of a constructor function.
*
* @param {*} args The arguments passed to the constructor.
*
* @return {Array|undefined|can-construct.ReturnValue} If an array is returned, the array's items are passed as
* arguments to [can-construct::init init]. If a [can-construct.ReturnValue] instance is returned, the ReturnValue
* instance's value will be returned as the result of calling new Construct(). The following example always makes
* sure that init is called with a jQuery wrapped element:
*
* ```js
* WidgetFactory = Construct.extend({
* setup: function(element){
* return [$(element)]
* }
* });
*
* MyWidget = WidgetFactory.extend({
* init: function($el){
* $el.html("My Widget!!")
* }
* });
* ```
*
* Otherwise, the arguments to the
* constructor are passed to [can-construct::init] and the return value of `setup` is discarded.
*
* @body
*
* ## Deciding between `setup` and `init`
*
*
* Usually, you should use [can-construct::init init] to do your constructor function's initialization.
* You should, instead, use `setup` when:
*
* - there is initialization code that you want to run before the inheriting constructor's
* `init` method is called.
* - there is initialization code that should run whether or not inheriting constructors
* call their base's `init` methods.
* - you want to modify the arguments that will get passed to `init`.
*
*/
defineNonEnumerable(Construct.prototype, "setup", function () {});
/**
* @function can-construct.prototype.init init
* @parent can-construct.prototype
*
* @description Called when a new instance of a Construct is created.
*
* @signature `construct.init(...args)`
* @param {*} args the arguments passed to the constructor (or the items of the array returned from [can-construct::setup])
*
* @body
* If a prototype `init` method is provided, `init` is called when a new Construct is created---
* after [can-construct::setup]. The `init` method is where the bulk of your initialization code
* should go. A common thing to do in `init` is save the arguments passed into the constructor.
*
* ## Examples
*
* First, we'll make a Person constructor that has a first and last name:
*
* ```js
* var Person = Construct.extend({
* init: function(first, last) {
* this.first = first;
* this.last = last;
* }
* });
*
* var justin = new Person("Justin", "Meyer");
* justin.first; // "Justin"
* justin.last; // "Meyer"
* ```
*
* Then, we'll extend Person into Programmer, and add a favorite language:
*
* ```js
* var Programmer = Person.extend({
* init: function(first, last, language) {
* // call base's init
* Person.prototype.init.apply(this, arguments);
*
* // other initialization code
* this.language = language;
* },
* bio: function() {
* return "Hi! I'm " + this.first + " " + this.last +
* " and I write " + this.language + ".";
* }
* });
*
* var brian = new Programmer("Brian", "Moschel", 'ECMAScript');
* brian.bio(); // "Hi! I'm Brian Moschel and I write ECMAScript.";
* ```
*
* ## Modified Arguments
*
* [can-construct::setup] is able to modify the arguments passed to `init`.
* If you aren't receiving the arguments you passed to `new Construct(args)`,
* check that they aren't being changed by `setup` along
* the inheritance chain.
*/
defineNonEnumerable(Construct.prototype, "init", function () {});
var canConstruct_3_5_7_canConstruct = canNamespace_1_0_0_canNamespace.Construct = Construct;
function dispatch(key) {
// jshint -W040
var handlers = this.eventHandlers[key];
if (handlers) {
var handlersCopy = handlers.slice();
var value = this.getKeyValue(key);
for (var i = 0; i < handlersCopy.length; i++) {
handlersCopy[i](value);
}
}
}
function Globals() {
this.eventHandlers = {};
this.properties = {};
}
/**
* @function define
* @parent can-globals/methods
*
* Create a new global environment variable.
*
* @signature `globals.define(key, value[, cache])`
*
* Defines a new global called `key`, who's value defaults to `value`.
*
* The following example defines the `global` key's default value to the [`window`](https://developer.mozilla.org/en-US/docs/Web/API/Window) object:
* ```javascript
* globals.define('global', window);
* globals.getKeyValue('window') //-> window
* ```
*
* If a function is provided and `cache` is falsy, that function is run every time the key value is read:
* ```javascript
* globals.define('isBrowserWindow', function() {
* console.log('EVALUATING')
* return typeof window !== 'undefined' &&
* typeof document !== 'undefined' && typeof SimpleDOM === 'undefined'
* }, false);
* globals.get('isBrowserWindow') // logs 'EVALUATING'
* // -> true
* globals.get('isBrowserWindow') // logs 'EVALUATING' again
* // -> true
* ```
*
* If a function is provided and `cache` is truthy, that function is run only the first time the value is read:
* ```javascript
* globals.define('isWebkit', function() {
* console.log('EVALUATING')
* var div = document.createElement('div')
* return 'WebkitTransition' in div.style
* })
* globals.getKeyValue('isWebkit') // logs 'EVALUATING'
* // -> true
* globals.getKeyValue('isWebkit') // Does NOT log again!
* // -> true
* ```
*
* @param {String} key
* The key value to create.
*
* @param {*} value
* The default value. If this is a function, its return value will be used.
*
* @param {Boolean} [cache=true]
* Enable cache. If false the `value` function is run every time the key value is read.
*
* @return {can-globals}
* Returns the instance of `can-globals` for chaining.
*/
Globals.prototype.define = function (key, value, enableCache) {
if (enableCache === undefined) {
enableCache = true;
}
if (!this.properties[key]) {
this.properties[key] = {
default: value,
value: value,
enableCache: enableCache
};
}
return this;
};
/**
* @function getKeyValue
* @parent can-globals/methods
*
* Get a global environment variable by name.
*
* @signature `globals.getKeyValue(key)`
*
* Returns the current value at `key`. If no value has been set, it will return the default value (if it is not a function). If the default value is a function, it will return the output of the function. This execution is cached if the cache flag was set on initialization.
*
* ```javascript
* globals.define('foo', 'bar');
* globals.getKeyValue('foo'); //-> 'bar'
* ```
*
* @param {String} key
* The key value to access.
*
* @return {*}
* Returns the value of a given key.
*/
Globals.prototype.getKeyValue = function (key) {
var property = this.properties[key];
if (property) {
if (typeof property.value === 'function') {
if (property.cachedValue) {
return property.cachedValue;
}
if (property.enableCache) {
property.cachedValue = property.value();
return property.cachedValue;
} else {
return property.value();
}
}
return property.value;
}
};
Globals.prototype.makeExport = function (key) {
return function (value) {
if (arguments.length === 0) {
return this.getKeyValue(key);
}
if (typeof value === 'undefined' || value === null) {
this.deleteKeyValue(key);
} else {
if (typeof value === 'function') {
this.setKeyValue(key, function () {
return value;
});
} else {
this.setKeyValue(key, value);
}
return value;
}
}.bind(this);
};
/**
* @function offKeyValue
* @parent can-globals/methods
*
* Remove handler from event queue.
*
* @signature `globals.offKeyValue(key, handler)`
*
* Removes `handler` from future change events for `key`.
*
*
* ```javascript
* var handler = (value) => {
* value === 'baz' //-> true
* };
* globals.define('foo', 'bar');
* globals.onKeyValue('foo', handler);
* globals.setKeyValue('foo', 'baz');
* globals.offKeyValue('foo', handler);
* ```
*
* @param {String} key
* The key value to observe.
*
* @param {Function} handler([value])
* The observer callback.
*
* @return {can-globals}
* Returns the instance of `can-globals` for chaining.
*/
Globals.prototype.offKeyValue = function (key, handler) {
if (this.properties[key]) {
var handlers = this.eventHandlers[key];
if (handlers) {
var i = handlers.indexOf(handler);
handlers.splice(i, 1);
}
}
return this;
};
/**
* @function onKeyValue
* @parent can-globals/methods
*
* Add handler to event queue.
*
* @signature `globals.onKeyValue(key, handler)`
*
* Calls `handler` each time the value of `key` is set or reset.
*
* ```javascript
* globals.define('foo', 'bar');
* globals.onKeyValue('foo', (value) => {
* value === 'baz' //-> true
* });
* globals.setKeyValue('foo', 'baz');
* ```
*
* @param {String} key
* The key value to observe.
*
* @param {function(*)} handler([value])
* The observer callback.
*
* @return {can-globals}
* Returns the instance of `can-globals` for chaining.
*/
Globals.prototype.onKeyValue = function (key, handler) {
if (this.properties[key]) {
if (!this.eventHandlers[key]) {
this.eventHandlers[key] = [];
}
this.eventHandlers[key].push(handler);
}
return this;
};
/**
* @function deleteKeyValue
* @parent can-globals/methods
*
* Reset global environment variable.
*
* @signature `globals.deleteKeyValue(key)`
*
* Deletes the current value at `key`. Future `get`s will use the default value.
*
* ```javascript
* globals.define('global', window);
* globals.setKeyValue('global', {});
* globals.deleteKeyValue('global');
* globals.getKeyValue('global') === window; //-> true
* ```
*
* @param {String} key
* The key value to access.
*
* @return {can-globals}
* Returns the instance of `can-globals` for chaining.
*/
Globals.prototype.deleteKeyValue = function (key) {
var property = this.properties[key];
if (property !== undefined) {
property.value = property.default;
property.cachedValue = undefined;
dispatch.call(this, key);
}
return this;
};
/**
* @function setKeyValue
* @parent can-globals/methods
*
* Overwrite an existing global environment variable.
*
* @signature `globals.setKeyValue(key, value)`
*
* ```javascript
* globals.define('foo', 'bar');
* globals.setKeyValue('foo', 'baz');
* globals.getKeyValue('foo'); //-> 'baz'
* ```
*
* Sets the new value at `key`. Will override previously set values, but preserves the default (see `deleteKeyValue`).
*
* Setting a key which was not previously defined will call `define` with the key and value.
*
* @param {String} key
* The key value to access.
*
* @param {*} value
* The new value.
*
* @return {can-globals}
* Returns the instance of `can-globals` for chaining.
*/
Globals.prototype.setKeyValue = function (key, value) {
if (!this.properties[key]) {
return this.define(key, value);
}
var property = this.properties[key];
property.value = value;
property.cachedValue = undefined;
dispatch.call(this, key);
return this;
};
/**
* @function reset
* @parent can-globals/methods
*
* Reset all keys to their default value and clear their caches.
*
* @signature `globals.setKeyValue(key, value)`
*
* ```javascript
* globals.define('foo', 'bar');
* globals.setKeyValue('foo', 'baz');
* globals.getKeyValue('foo'); //-> 'baz'
* globals.reset();
* globals.getKeyValue('foo'); //-> 'bar'
* ```
*
* @return {can-globals}
* Returns the instance of `can-globals` for chaining.
*/
Globals.prototype.reset = function () {
for (var key in this.properties) {
if (this.properties.hasOwnProperty(key)) {
this.properties[key].value = this.properties[key].default;
this.properties[key].cachedValue = undefined;
dispatch.call(this, key);
}
}
return this;
};
canReflect_1_19_2_canReflect.assignSymbols(Globals.prototype, {
'can.getKeyValue': Globals.prototype.getKeyValue,
'can.setKeyValue': Globals.prototype.setKeyValue,
'can.deleteKeyValue': Globals.prototype.deleteKeyValue,
'can.onKeyValue': Globals.prototype.onKeyValue,
'can.offKeyValue': Globals.prototype.offKeyValue
});
var canGlobals_1_2_2_canGlobalsProto = Globals;
var canGlobals_1_2_2_canGlobalsInstance = createCommonjsModule(function (module) {
var globals = new canGlobals_1_2_2_canGlobalsProto();
if (canNamespace_1_0_0_canNamespace.globals) {
throw new Error("You can't have two versions of can-globals, check your dependencies");
} else {
module.exports = canNamespace_1_0_0_canNamespace.globals = globals;
}
});
/* global self */
/* global WorkerGlobalScope */
/**
* @module {function} can-globals/global/global global
* @parent can-globals/modules
*
* Get the global object for the current context.
*
* @signature `GLOBAL([newGlobal])`
*
* Optionally sets, and returns the global that this environment provides. It will be one of:
*
* ```js
* var GLOBAL = require('can-globals/global/global');
* var g = GLOBAL();
* // In a browser
* console.log(g === window); // -> true
* ```
*
* - **Browser**: [`window`](https://developer.mozilla.org/en-US/docs/Web/API/window)
* - **Web Worker**: [`self`](https://developer.mozilla.org/en-US/docs/Web/API/Window/self)
* - **Node.js**: [`global`](https://nodejs.org/api/globals.html#globals_global)
*
* @param {Object} [newGlobal] An optional global-like object to set as the context's global
*
* @return {Object} The global object for this JavaScript environment.
*/
canGlobals_1_2_2_canGlobalsInstance.define('global', function(){
// Web Worker
return (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) ? self :
// Node.js
typeof process === 'object' &&
{}.toString.call(process) === '[object process]' ? commonjsGlobal :
// Browser window
window;
});
var global_1 = canGlobals_1_2_2_canGlobalsInstance.makeExport('global');
/**
* @module {function} can-globals/document/document document
* @parent can-globals/modules
*
* Get the global [`document`](https://developer.mozilla.org/en-US/docs/Web/API/document) object for the current context.
*
* @signature `DOCUMENT([newDocument])`
*
* Optionally sets, and returns, the [`document`](https://developer.mozilla.org/en-US/docs/Web/API/document) object for the context.
*
* ```js
* var documentShim = { getElementById() {...} };
* var DOCUMENT = require('can-globals/document/document');
* DOCUMENT(documentShim); //-> document
* DOCUMENT().getElementById('foo');
* ```
*
* @param {Object} [newDocument] An optional document-like object to set as the context's document
*
* @return {Object} The window object for this JavaScript environment.
*/
canGlobals_1_2_2_canGlobalsInstance.define('document', function(){
return canGlobals_1_2_2_canGlobalsInstance.getKeyValue('global').document;
});
var document$1 = canGlobals_1_2_2_canGlobalsInstance.makeExport('document');
/**
* @module {function} can-globals/is-node/is-node is-node
* @parent can-globals/modules
* @description Determines if your code is running in [Node.js](https://nodejs.org).
* @signature `isNode()`
*
* ```js
* var isNode = require("can-globals/is-node/is-node");
* var GLOBAL = require("can-globals/global/global");
*
* if(isNode()) {
* console.log(GLOBAL() === global); // -> true
* }
* ```
*
* @return {Boolean} True if running in Node.js
*/
canGlobals_1_2_2_canGlobalsInstance.define('isNode', function(){
return typeof process === "object" &&
{}.toString.call(process) === "[object process]";
});
var isNode = canGlobals_1_2_2_canGlobalsInstance.makeExport('isNode');
// This module depends on isNode being defined
/**
* @module {function} can-globals/is-browser-window/is-browser-window is-browser-window
* @parent can-globals/modules
* @signature `isBrowserWindow()`
*
* Returns `true` if the code is running within a Browser window. Use this function if you need special code paths for when running in a Browser window, a Web Worker, or another environment (such as Node.js).
*
* ```js
* var isBrowserWindow = require("can-globals/is-browser-window/is-browser-window");
* var GLOBAL = require("can-globals/global/global");
*
* if(isBrowserWindow()) {
* console.log(GLOBAL() === window); // -> true
* }
* ```
*
* @return {Boolean} True if the environment is a Browser window.
*/
canGlobals_1_2_2_canGlobalsInstance.define('isBrowserWindow', function(){
var isNode = canGlobals_1_2_2_canGlobalsInstance.getKeyValue('isNode');
return typeof window !== "undefined" &&
typeof document !== "undefined" &&
isNode === false;
});
var isBrowserWindow = canGlobals_1_2_2_canGlobalsInstance.makeExport('isBrowserWindow');
function getTargetDocument (target) {
return target.ownerDocument || document$1();
}
function createEvent (target, eventData, bubbles, cancelable) {
var doc = getTargetDocument(target);
var event = doc.createEvent('HTMLEvents');
var eventType;
if (typeof eventData === 'string') {
eventType = eventData;
} else {
eventType = eventData.type;
for (var prop in eventData) {
if (event[prop] === undefined) {
event[prop] = eventData[prop];
}
}
}
if (bubbles === undefined) {
bubbles = true;
}
event.initEvent(eventType, bubbles, cancelable);
return event;
}
// We do not account for all EventTarget classes,
// only EventTarget DOM nodes, fragments, and the window.
function isDomEventTarget (obj) {
if (!(obj && obj.nodeName)) {
return obj === window;
}
var nodeType = obj.nodeType;
return (
nodeType === 1 || // Node.ELEMENT_NODE
nodeType === 9 || // Node.DOCUMENT_NODE
nodeType === 11 // Node.DOCUMENT_FRAGMENT_NODE
);
}
function addDomContext (context, args) {
if (isDomEventTarget(context)) {
args = Array.prototype.slice.call(args, 0);
args.unshift(context);
}
return args;
}
function removeDomContext (context, args) {
if (!isDomEventTarget(context)) {
args = Array.prototype.slice.call(args, 0);
context = args.shift();
}
return {
context: context,
args: args
};
}
var fixSyntheticEventsOnDisabled = false;
// In FireFox, dispatching a synthetic event on a disabled element throws an error.
// Other browsers, like IE 10 do not dispatch synthetic events on disabled elements at all.
// This determines if we have to work around that when dispatching events.
// https://bugzilla.mozilla.org/show_bug.cgi?id=329509
(function() {
if(!isBrowserWindow()) {
return;
}
var testEventName = 'fix_synthetic_events_on_disabled_test';
var input = document.createElement("input");
input.disabled = true;
var timer = setTimeout(function() {
fixSyntheticEventsOnDisabled = true;
}, 50);
var onTest = function onTest (){
clearTimeout(timer);
input.removeEventListener(testEventName, onTest);
};
input.addEventListener(testEventName, onTest);
try {
var event = document.create('HTMLEvents');
event.initEvent(testEventName, false);
input.dispatchEvent(event);
} catch(e) {
onTest();
fixSyntheticEventsOnDisabled = true;
}
})();
function isDispatchingOnDisabled(element, event) {
var eventType = event.type;
var isInsertedOrRemoved = eventType === 'inserted' || eventType === 'removed';
var isDisabled = !!element.disabled;
return isInsertedOrRemoved && isDisabled;
}
function forceEnabledForDispatch (element, event) {
return fixSyntheticEventsOnDisabled && isDispatchingOnDisabled(element, event);
}
var util = {
createEvent: createEvent,
addDomContext: addDomContext,
removeDomContext: removeDomContext,
isDomEventTarget: isDomEventTarget,
getTargetDocument: getTargetDocument,
forceEnabledForDispatch: forceEnabledForDispatch
};
function EventRegistry () {
this._registry = {};
}
/**
* @module can-dom-events/helpers/make-event-registry
* @parent can-dom-events.helpers
* @description Create an event registry.
* @signature `makeEventRegistry()`
* @return {can-dom-events/EventRegistry}
* @hide
*
* @body
*
* ```js
* var makeEventRegistry = require('can-dom-events/helpers/make-event-registry');
* var registry = makeEventRegistry();
*
* var radioChange = require('can-events-dom-radiochange');
* var removeRadioChange = registry.add(radioChange);
*
* registry.has('radiochange'); // => true
* registry.get('radiochange'); // => radioChange
*
* removeRadioChange();
* ```
*/
var makeEventRegistry = function makeEventRegistry () {
return new EventRegistry();
};
/**
* @function make-event-registry.has eventRegistry.has
*
* Check whether an event type has already been registered.
*
* @signature `eventRegistry.has( eventType )`
* @parent can-dom-events/EventRegistry
* @param {String} eventType The event type for which to check.
* @return {Boolean} Whether the event type is registered.
*/
EventRegistry.prototype.has = function (eventType) {
return !!this._registry[eventType];
};
/**
* @function make-event-registry.get eventRegistry.get
*
* Retrieve an event type which has already been registered.
*
* @signature `eventRegistry.get( eventType )`
* @parent can-dom-events/EventRegistry
* @param {String} eventType The event type for which to retrieve.
* @return {EventDefinition} The registered event definition, or undefined if unregistered.
*/
EventRegistry.prototype.get = function (eventType) {
return this._registry[eventType];
};
/**
* @function make-event-registry.add eventRegistry.add
*
* Add an event to the registry.
*
* @signature `eventRegistry.add( event [, eventType ] )`
* @parent can-dom-events/EventRegistry
* @param {EventDefinition} event The event definition to register.
* @param {String} eventType The event type with which to register the event.
* @return {function} The callback to remove the event from the registry.
*/
EventRegistry.prototype.add = function (event, eventType) {
if (!event) {
throw new Error('An EventDefinition must be provided');
}
if (typeof event.addEventListener !== 'function') {
throw new TypeError('EventDefinition addEventListener must be a function');
}
if (typeof event.removeEventListener !== 'function') {
throw new TypeError('EventDefinition removeEventListener must be a function');
}
eventType = eventType || event.defaultEventType;
if (typeof eventType !== 'string') {
throw new TypeError('Event type must be a string, not ' + eventType);
}
if (this.has(eventType)) {
if (process.env.NODE_ENV !== 'production') {
dev.warn('Event "' + eventType + '" is already registered');
return;
}
throw new Error('Event "' + eventType + '" is already registered');
}
this._registry[eventType] = event;
var self = this;
return function remove () {
self._registry[eventType] = undefined;
};
};
// Some events do not bubble, so delegating them requires registering the handler in the
// capturing phase.
// http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
var useCapture = function(eventType) {
return eventType === 'focus' || eventType === 'blur';
};
function makeDelegator (domEvents) {
var Delegator = function Delegator (parentKey){
this.element = parentKey; // HTMLElement
this.events = {}; // {[eventType: string]: Array<(event) -> void>}
this.delegated = {}; // {[eventType: string]: (event) -> void}
};
canReflect_1_19_2_canReflect.assignSymbols( Delegator.prototype, {
"can.setKeyValue": function(eventType, handlersBySelector){
var handler = this.delegated[eventType] = function(ev){
var cur = ev.target;
var propagate = true;
var origStopPropagation = ev.stopPropagation;
ev.stopPropagation = function() {
origStopPropagation.apply(this, arguments);
propagate = false;
};
var origStopImmediatePropagation = ev.stopImmediatePropagation;
ev.stopImmediatePropagation = function() {
origStopImmediatePropagation.apply(this, arguments);
propagate = false;
};
do {
// document does not implement `.matches` but documentElement does
var el = cur === document ? document.documentElement : cur;
var matches = el.matches || el.msMatchesSelector;
canReflect_1_19_2_canReflect.each(handlersBySelector, function(handlers, selector){
// Text and comment nodes may be included in mutation event targets
// but will never match selectors (and do not implement matches)
if (matches && matches.call(el, selector)) {
handlers.forEach(function(handler){
handler.call(el, ev);
});
}
});
// since `el` points to `documentElement` when `cur` === document,
// we need to continue using `cur` as the loop pointer, otherwhise
// it will never end as documentElement.parentNode === document
cur = cur.parentNode;
} while ((cur && cur !== ev.currentTarget) && propagate);
};
this.events[eventType] = handlersBySelector;
domEvents.addEventListener(this.element, eventType, handler, useCapture(eventType));
},
"can.getKeyValue": function(eventType) {
return this.events[eventType];
},
"can.deleteKeyValue": function(eventType) {
domEvents.removeEventListener(this.element, eventType, this.delegated[eventType], useCapture(eventType));
delete this.delegated[eventType];
delete this.events[eventType];
},
"can.getOwnEnumerableKeys": function() {
return Object.keys(this.events);
}
});
return Delegator;
}
var MakeDelegateEventTree = function makeDelegateEventTree (domEvents) {
var Delegator = makeDelegator(domEvents);
return new canKeyTree_1_2_2_canKeyTree([Map, Delegator, Object, Array]);
};
var domEvents = {
_eventRegistry: makeEventRegistry(),
/**
* @function can-dom-events.addEvent addEvent
* @parent can-dom-events.static
*
* Add a custom event to the global event registry.
*
* @signature `addEvent( event [, eventType ] )`
*
* ```js
* var removeReturnEvent = domEvents.addEvent(enterEvent, "return");
* ```
*
* @param {can-dom-events/EventDefinition} event The custom event definition.
* @param {String} eventType The event type to associated with the custom event.
* @return {function} The callback to remove the custom event from the registry.
*/
addEvent: function(event, eventType) {
return this._eventRegistry.add(event, eventType);
},
/**
* @function can-dom-events.addEventListener addEventListener
*
* Add an event listener for eventType to the target.
*
* @signature `addEventListener( target, eventType, ...eventArgs )`
* @parent can-dom-events.static
* @param {DomEventTarget} target The object to which to add the listener.
* @param {String} eventType The event type with which to register.
* @param {*} eventArgs The arguments which configure the associated event's behavior. This is usually a
* function event handler.
*/
addEventListener: function(target, eventType) {
var hasCustomEvent = domEvents._eventRegistry.has(eventType);
if (hasCustomEvent) {
var event = domEvents._eventRegistry.get(eventType);
return event.addEventListener.apply(domEvents, arguments);
}
var eventArgs = Array.prototype.slice.call(arguments, 1);
return target.addEventListener.apply(target, eventArgs);
},
/**
* @function can-dom-events.removeEventListener removeEventListener
*
* Remove an event listener for eventType from the target.
*
* @signature `removeEventListener( target, eventType, ...eventArgs )`
* @parent can-dom-events.static
* @param {DomEventTarget} target The object from which to remove the listener.
* @param {String} eventType The event type with which to unregister.
* @param {*} eventArgs The arguments which configure the associated event's behavior. This is usually a
* function event handler.
*/
removeEventListener: function(target, eventType) {
var hasCustomEvent = domEvents._eventRegistry.has(eventType);
if (hasCustomEvent) {
var event = domEvents._eventRegistry.get(eventType);
return event.removeEventListener.apply(domEvents, arguments);
}
var eventArgs = Array.prototype.slice.call(arguments, 1);
return target.removeEventListener.apply(target, eventArgs);
},
/**
* @function can-dom-events.addDelegateListener addDelegateListener
*
* Attach a handler for an event for all elements that match the selector,
* now or in the future, based on a root element.
*
* @signature `addDelegateListener( target, eventType, selector, handler )`
*
* ```js
* // Prevents all anchor elements from changing the page
* domEvents.addDelegateListener(document.body,"click", "a", function(event){
* event.preventDefault();
* })
* ```
* @parent can-dom-events.static
* @param {DomEventTarget} root The html element to listen to events that match selector within.
* @param {String} eventType The event name to listen to.
* @param {String} selector A selector to filter the elements that trigger the event.
* @param {function} handler A function to execute at the time the event is triggered.
*/
addDelegateListener: function(root, eventType, selector, handler) {
domEvents._eventTree.add([root, eventType, selector, handler]);
},
/**
* @function can-dom-events.removeDelegateListener removeDelegateListener
*
* Remove a handler for an event for all elements that match the selector.
*
* @signature `removeDelegateListener( target, eventType, selector, handler )`
*
* ```js
* // Prevents all anchor elements from changing the page
* function handler(event) {
* event.preventDefault();
* }
* domEvents.addDelegateListener(document.body,"click", "a", handler);
*
* domEvents.removeDelegateListener(document.body,"click", "a", handler);
* ```
* @parent can-dom-events.static
* @param {DomEventTarget} root The html element to listen to events that match selector within.
* @param {String} eventType The event name to listen to.
* @param {String} selector A selector to filter the elements that trigger the event.
* @param {function} handler A function that was previously passed to `addDelegateListener`.
*/
removeDelegateListener: function(target, eventType, selector, handler) {
domEvents._eventTree.delete([target, eventType, selector, handler]);
},
/**
* @function can-dom-events.dispatch dispatch
*
* Create and dispatch a configured event on the target.
*
* @signature `dispatch( target, eventData [, bubbles ][, cancelable ] )`
* @parent can-dom-events.static
* @param {DomEventTarget} target The object on which to dispatch the event.
* @param {Object | String} eventData The data to be assigned to the event. If it is a string, that will be the event type.
* @param {Boolean} bubbles Whether the event should bubble; defaults to true.
* @param {Boolean} cancelable Whether the event can be cancelled; defaults to false.
* @return {Boolean} notCancelled Whether the event dispatched without being cancelled.
*/
dispatch: function(target, eventData, bubbles, cancelable) {
var event = util.createEvent(target, eventData, bubbles, cancelable);
var enableForDispatch = util.forceEnabledForDispatch(target, event);
if(enableForDispatch) {
target.disabled = false;
}
var ret = target.dispatchEvent(event);
if(enableForDispatch) {
target.disabled = true;
}
return ret;
}
};
domEvents._eventTree = MakeDelegateEventTree(domEvents);
var canDomEvents_1_3_13_canDomEvents = canNamespace_1_0_0_canNamespace.domEvents = domEvents;
/**
* @module {function} can-event-queue/map/map
* @parent can-event-queue
* @templateRender true
*
* @description Mixin methods and symbols to make this object or prototype object
* behave like a key-value observable.
*
* @signature `mixinMapBindings( obj )`
*
* Adds symbols and methods that make `obj` or instances having `obj` on their prototype
* behave like key-value observables.
*
* When `mixinMapBindings` is called on an `obj` like:
*
* ```js
* var mixinMapBindings = require("can-event-queue/map/map");
*
* var observable = mixinValueBindings({});
*
* observable.on("prop",function(ev, newVal, oldVal){
* console.log(newVal);
* });
*
* observable[canSymbol.for("can.dispatch")]("prop",[2,1]);
* // Logs: 2
* ```
*
* `mixinMapBindings` adds the following properties and symbols to the object:
*
* {{#each (getChildren [can-event-queue/map/map])}}
* - [{{name}}] - {{description}}{{/each}}
*
* Furthermore, `mixinMapBindings` looks for the following symbols on the object's `.constructor`
* property:
*
* - `@can.dispatchInstanceBoundChange` - Called when the bind status of an instance changes.
* - `@can.dispatchInstanceOnPatches` - Called if [can-event-queue/map/map.dispatch] is called with `event.patches` as an array of
* patches.
*/
var isDomEventTarget$1 = util.isDomEventTarget;
var metaSymbol = canSymbol_1_7_0_canSymbol.for("can.meta"),
dispatchBoundChangeSymbol = canSymbol_1_7_0_canSymbol.for("can.dispatchInstanceBoundChange"),
dispatchInstanceOnPatchesSymbol = canSymbol_1_7_0_canSymbol.for("can.dispatchInstanceOnPatches"),
onKeyValueSymbol$1 = canSymbol_1_7_0_canSymbol.for("can.onKeyValue"),
offKeyValueSymbol = canSymbol_1_7_0_canSymbol.for("can.offKeyValue"),
onEventSymbol = canSymbol_1_7_0_canSymbol.for("can.onEvent"),
offEventSymbol = canSymbol_1_7_0_canSymbol.for("can.offEvent"),
onValueSymbol$1 = canSymbol_1_7_0_canSymbol.for("can.onValue"),
offValueSymbol = canSymbol_1_7_0_canSymbol.for("can.offValue"),
inSetupSymbol$1 = canSymbol_1_7_0_canSymbol.for("can.initializing");
var legacyMapBindings;
function addHandlers(obj, meta) {
if (!meta.handlers) {
// Handlers are organized by:
// event name - the type of event bound to
// binding type - "event" for things that expect an event object (legacy), "onKeyValue" for reflective bindings.
// queue name - mutate, queue, etc
// handlers - the handlers.
meta.handlers = new canKeyTree_1_2_2_canKeyTree([Object, Object, Object, Array], {
onFirst: function() {
if (obj._eventSetup !== undefined) {
obj._eventSetup();
}
var constructor = obj.constructor;
if(constructor[dispatchBoundChangeSymbol] !== undefined && obj instanceof constructor) {
constructor[dispatchBoundChangeSymbol](obj, true);
}
//queues.enqueueByQueue(getLifecycleHandlers(obj).getNode([]), obj, [true]);
},
onEmpty: function() {
if (obj._eventTeardown !== undefined) {
obj._eventTeardown();
}
var constructor = obj.constructor;
if(constructor[dispatchBoundChangeSymbol] !== undefined && obj instanceof constructor) {
constructor[dispatchBoundChangeSymbol](obj, false);
}
//queues.enqueueByQueue(getLifecycleHandlers(obj).getNode([]), obj, [false]);
}
});
}
if (!meta.listenHandlers) {
// context, eventName (might be undefined), queue, handlers
meta.listenHandlers = new canKeyTree_1_2_2_canKeyTree([Map, Map, Object, Array]);
}
}
// getHandlers returns a KeyTree used for event handling.
// `handlers` will be on the `can.meta` symbol on the object.
// Ensure the "obj" passed as an argument has an object on @@can.meta
var ensureMeta = function ensureMeta(obj) {
var meta = obj[metaSymbol];
if (!meta) {
meta = {};
canReflect_1_19_2_canReflect.setKeyValue(obj, metaSymbol, meta);
}
addHandlers(obj, meta);
return meta;
};
function stopListeningArgumentsToKeys(bindTarget, event, handler, queueName) {
if(arguments.length && canReflect_1_19_2_canReflect.isPrimitive(bindTarget)) {
queueName = handler;
handler = event;
event = bindTarget;
bindTarget = this.context;
}
if(typeof event === "function") {
queueName = handler;
handler = event;
event = undefined;
}
if(typeof handler === "string") {
queueName = handler;
handler = undefined;
}
var keys = [];
if(bindTarget) {
keys.push(bindTarget);
if(event || handler || queueName) {
keys.push(event);
if(queueName || handler) {
keys.push(queueName || this.defaultQueue);
if(handler) {
keys.push(handler);
}
}
}
}
return keys;
}
// These are the properties we are going to add to objects
var props = {
/**
* @function can-event-queue/map/map.dispatch dispatch
* @parent can-event-queue/map/map
*
* @description Dispatch event and key binding handlers.
*
* @signature `obj.dispatch(event, [args])`
*
* Dispatches registered [can-event-queue/map/map.addEventListener] and
* [can-event-queue/map/map.can.onKeyValue] value binding handlers.
*
* The following shows dispatching the `property` event and
* `keyValue` handlers:
*
*
* ```js
* var mixinMapBindings = require("can-event-queue/map/map");
*
* var obj = mixinMapBindings({});
*
* obj.addEventListener("property", function(event, newVal){
* event.type //-> "property"
* newVal //-> 5
* });
*
* canReflect.onKeyValue("property", function(newVal){
* newVal //-> 5
* })
*
* obj.dispatch("property", [5]);
* ```
*
* > NOTE: Event handlers have an additional `event` argument.
*
* @param {String|Object} event The event to dispatch. If a string is passed,
* it will be used as the `type` of the event that will be dispatched and dispatch matching
* [can-event-queue/map/map.can.onKeyValue] bindings:
*
* ```js
* obs.dispatch("key")
* ```
*
* If `event` is an object, it __MUST__ have a `type` property. The If a string is passed,
* it will be used as the `type` of the event that will be dispatched and dispatch matching
* [can-event-queue/map/map.can.onKeyValue] bindings:
*
* ```js
* obs.dispatch({type: "key"})
* ```
*
* The `event` object can also have the following properties and values:
* - __reasonLog__ `{Array}` - The reason this event happened. This will be passed to
* [can-queues.enqueueByQueue] for debugging purposes.
* - __makeMeta__ `{function}` - Details about the handler being called. This will be passed to
* [can-queues.enqueueByQueue] for debugging purposes.
* - __patches__ `{Array}` - The patch objects this event represents. The `.patches` value will be
* passed to the object's `.constructor`'s `@can.dispatchInstanceOnPatches` method.
*
* @param {Array} [args] Additional arguments to pass to event handlers.
* @return {Object} event The resulting event object.
*/
dispatch: function(event, args) {
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
if (arguments.length > 4) {
dev.warn('Arguments to dispatch should be an array, not multiple arguments.');
args = Array.prototype.slice.call(arguments, 1);
}
if (args && !Array.isArray(args)) {
dev.warn('Arguments to dispatch should be an array.');
args = [args];
}
}
//!steal-remove-end
// Don't send events if initalizing.
if (this.__inSetup !== true && this[inSetupSymbol$1] !== true) {
if (typeof event === 'string') {
event = {
type: event
};
}
var meta = ensureMeta(this);
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
if (!event.reasonLog) {
event.reasonLog = [canReflect_1_19_2_canReflect.getName(this), "dispatched", '"' + event.type + '"', "with"].concat(args);
}
}
if (typeof meta._log === "function") {
meta._log.call(this, event, args);
}
//!steal-remove-end
var handlers = meta.handlers;
var handlersByType = event.type !== undefined && handlers.getNode([event.type]);
var dispatchConstructorPatches = event.patches && this.constructor[dispatchInstanceOnPatchesSymbol];
var patchesNode = event.patches !== undefined && handlers.getNode(["can.patches","onKeyValue"]);
var keysNode = event.keyChanged !== undefined && handlers.getNode(["can.keys","onKeyValue"]);
var batch = dispatchConstructorPatches || handlersByType || patchesNode || keysNode;
if ( batch ) {
canQueues_1_3_2_canQueues.batch.start();
}
if(handlersByType) {
if (handlersByType.onKeyValue) {
canQueues_1_3_2_canQueues.enqueueByQueue(handlersByType.onKeyValue, this, args, event.makeMeta, event.reasonLog);
}
if (handlersByType.event) {
event.batchNum = canQueues_1_3_2_canQueues.batch.number();
var eventAndArgs = [event].concat(args);
canQueues_1_3_2_canQueues.enqueueByQueue(handlersByType.event, this, eventAndArgs, event.makeMeta, event.reasonLog);
}
}
if(keysNode) {
canQueues_1_3_2_canQueues.enqueueByQueue(keysNode, this, [event.keyChanged], event.makeMeta, event.reasonLog);
}
if(patchesNode) {
canQueues_1_3_2_canQueues.enqueueByQueue(patchesNode, this, [event.patches], event.makeMeta, event.reasonLog);
}
if(dispatchConstructorPatches) {
this.constructor[dispatchInstanceOnPatchesSymbol](this, event.patches);
}
if ( batch ) {
canQueues_1_3_2_canQueues.batch.stop();
}
}
return event;
},
/**
* @function can-event-queue/map/map.addEventListener addEventListener
* @parent can-event-queue/map/map
*
* @description Register an event handler to be called when an event is dispatched.
*
* @signature `obj.addEventListener(eventName, handler(event, ...) [,queueName] )`
*
* Add a event listener to an object. Handlers attached by `.addEventListener` get
* called back with the [can-event-queue/map/map.dispatch]
* `event` object and any arguments used to dispatch. [can-event-queue/map/map.can.onKeyValue] bindings do
* not get the event object.
*
* ```js
* var mixinMapBindings = require("can-event-queue/map/map");
*
* var obj = mixinMapBindings({});
*
* obj.addEventListener("foo", function(event){ ... });
* ```
*
* @param {String} eventName The name of the event to listen for.
* @param {Function} handler(event,arg...) The handler that will be executed to handle the event. The handler will be called
* with the dispatched `event` and `args`.
* @param {String} [queueName='mutate'] The name of the [can-queues] queue the handler will called
* back within. Defaults to `"mutate"`.
* @return {Object} Returns the object `.addEventListener` was called on.
*
*/
addEventListener: function(key, handler, queueName) {
ensureMeta(this).handlers.add([key, "event", queueName || "mutate", handler]);
return this;
},
/**
* @function can-event-queue/map/map.removeEventListener removeEventListener
* @parent can-event-queue/map/map
*
* @description Unregister an event handler to be called when an event is dispatched.
*
* @signature `obj.removeEventListener(eventName, [handler [,queueName]] )`
*
* Removes one or more handlers from being called when `eventName`
* is [can-event-queue/map/map.dispatch]ed.
*
* ```js
* // Removes `handler` if it is in the notify queue.
* obj.removeEventListener("closed", handler, "notify")
*
* // Removes `handler` if it is in the mutate queue.
* obj.removeEventListener("closed", handler)
*
* // Removes all "closed" handlers.
* obj.removeEventListener("closed")
* ```
*
* @param {String} eventName The name of the event to remove. If not specified, all events are removed.
* @param {Function} [handler] The handler that will be removed from the event. If not specified, all handlers for the event are removed.
* @param {String} [queueName='mutate'] The name of the [can-queues] queue the handler was registered on. Defaults to `"mutate"`.
* @return {Object} Returns the object `.removeEventListener` was called on.
*/
removeEventListener: function(key, handler, queueName) {
if(key === undefined) {
// This isn't super fast, but this pattern isn't used much.
// We could re-arrange the tree so it would be faster.
var handlers = ensureMeta(this).handlers;
var keyHandlers = handlers.getNode([]);
Object.keys(keyHandlers).forEach(function(key){
handlers.delete([key,"event"]);
});
} else if (!handler && !queueName) {
ensureMeta(this).handlers.delete([key, "event"]);
} else if (!handler) {
ensureMeta(this).handlers.delete([key, "event", queueName || "mutate"]);
} else {
ensureMeta(this).handlers.delete([key, "event", queueName || "mutate", handler]);
}
return this;
},
/**
* @function can-event-queue/map/map.one one
* @parent can-event-queue/map/map
*
* @description Register an event handler that gets called only once.
*
* @signature `obj.one(event, handler(event, args...) )`
*
* Adds a basic event listener that listens to an event once and only once.
*
* ```js
* obj.one("prop", function(){
* console.log("prop dispatched");
* })
*
* obj[canSymbol.for("prop")]("prop") //-> logs "prop dispatched"
* obj[canSymbol.for("prop")]("prop")
* ```
*
* @param {String} eventName The name of the event to listen to.
* @param {Function} handler(event, args...) The handler that will be run when the
* event is dispached.
* @return {Object} this
*/
one: function(event, handler) {
// Unbind the listener after it has been executed
var one = function() {
legacyMapBindings.off.call(this, event, one);
return handler.apply(this, arguments);
};
// Bind the altered listener
legacyMapBindings.on.call(this, event, one);
return this;
},
/**
* @function can-event-queue/map/map.listenTo listenTo
* @parent can-event-queue/map/map
*
* @description Listen to an event and register the binding for simplified unbinding.
*
* @signature `obj.listenTo([bindTarget,] event, handler)`
*
* `.listenTo` is useful for creating bindings that can can be torn down with
* [can-event-queue/map/map.stopListening]. This is useful when creating
* rich behaviors that can't be accomplished using computed values, or if you are trying to
* avoid streams.
*
* For example, the following creates an observable that counts how many times its
* `name` property has changed:
*
* ```js
* class Person {
* constructor(){
* this.nameChanged = 0;
* this.listenTo("name", function(){
* this.nameChanged++;
* })
* },
* setName(newVal) {
* this.name = newVal;
* this.dispatch("name",[newVal])
* }
* }
* mixinMapBindings(Person.prototype);
*
* var person = new Person();
* person.setName("Justin");
* person.setName("Ramiya");
* person.nameChanged //-> 2
* ```
*
* `.listenTo` event bindings are stored on an observable and MUST be unbound using
* [can-event-queue/map/map.stopListening]. `.stopListening` make it easy to unbind
* all of the `.listenTo` event bindings when the observable is no longer needed:
*
* ```js
* person.stopListening();
* ```
*
* If no `bindTarget` is passed, `.listenTo` binds to the current
* observable.
*
* [can-component]'s `connectedCallback` lifecyle hook is often used to call
* `.listenTo` to setup bindings that update viewmodel properties.
*
*
* @param {Object} [bindTarget] The object to listen for events on. If `bindTarget` is not provided,
* the observable `.listenTo` was called on will be the `bindTarget`.
* @param {String} event The name of the event to listen for.
* @param {Function} handler The handler that will be executed to handle the event.
* @return {Object} this
*/
listenTo: function (bindTarget, event, handler, queueName) {
if(canReflect_1_19_2_canReflect.isPrimitive(bindTarget)) {
queueName = handler;
handler = event;
event = bindTarget;
bindTarget = this;
}
if(typeof event === "function") {
queueName = handler;
handler = event;
event = undefined;
}
// Initialize event cache
ensureMeta(this).listenHandlers.add([bindTarget, event, queueName || "mutate", handler]);
legacyMapBindings.on.call(bindTarget, event, handler, queueName || "mutate");
return this;
},
/**
* @function can-event-queue/map/map.stopListening stopListening
* @parent can-event-queue/map/map
* @description Stops listening for registered event handlers.
*
* @signature `obj.stopListening( [bindTarget], [event,] handler]] )`
*
* `.stopListening` unbinds on event handlers registered through
* [can-event-queue/map/map.listenTo]. All event handlers
* that match the arguments will be unbound. For example:
*
* ```js
* // Unbinds all .listenTo registered handlers
* obj.stopListening()
*
* // Unbinds all .listenTo registered with `bindTarget`
* obj.stopListening(bindTarget)
*
* // Unbinds all .listenTo registered with `bindTarget`, `event`
* obj.stopListening(bindTarget, event)
*
* // Unbinds the handler registered with `bindTarget`, `event`, `handler`
* obj.stopListening(bindTarget, event, handler)
* ```
*
* `.listenTo` is often returned by [can-component]'s `connectedCallback` lifecyle hook.
*
* @param {Object} [bindTarget] The object we will stop listening to event on. If `bindTarget` is
* not provided, the observable `.stopListening` was called on will be the `bindTarget`.
* @param {String} [event] The name of the event to listen for.
* @param {Function} [handler] The handler that will be executed to handle the event.
* @return {Object} this
*
*/
stopListening: function () {
var keys = stopListeningArgumentsToKeys.apply({context: this, defaultQueue: "mutate"}, arguments);
var listenHandlers = ensureMeta(this).listenHandlers;
function deleteHandler(bindTarget, event, queue, handler){
legacyMapBindings.off.call(bindTarget, event, handler, queue);
}
listenHandlers.delete(keys, deleteHandler);
return this;
},
/**
* @function can-event-queue/map/map.on on
* @parent can-event-queue/map/map
*
* @description A shorthand method for listening to event.
*
* @signature `obj.on( event, handler [, queue] )`
*
* Listen to when `obj` dispatches an event, a [can-reflect/observe.onKeyValue]
* change, or a [can-reflect/observe.onValue] change in that order.
*
* As this is the __legacy__ `.on`, it will look for an `.addEventListener`
* method on the `obj` first, before looking for the [can-symbol/symbols/onKeyValue]
* and then [can-symbol/symbols/onValue] symbol.
*
* @param {String} eventName
* @param {Function} handler
* @param {String} [queue]
* @return {Any} The object `on` was called on.
*/
on: function(eventName, handler, queue) {
var listenWithDOM = isDomEventTarget$1(this);
if (listenWithDOM) {
if (typeof handler === 'string') {
canDomEvents_1_3_13_canDomEvents.addDelegateListener(this, eventName, handler, queue);
} else {
canDomEvents_1_3_13_canDomEvents.addEventListener(this, eventName, handler, queue);
}
} else {
if (this[onEventSymbol]) {
this[onEventSymbol](eventName, handler, queue);
} else if ("addEventListener" in this) {
this.addEventListener(eventName, handler, queue);
} else if (this[onKeyValueSymbol$1]) {
canReflect_1_19_2_canReflect.onKeyValue(this, eventName, handler, queue);
} else {
if (!eventName && this[onValueSymbol$1]) {
canReflect_1_19_2_canReflect.onValue(this, handler, queue);
} else {
throw new Error("can-event-queue: Unable to bind " + eventName);
}
}
}
return this;
},
/**
* @function can-event-queue/map/map.off off
* @parent can-event-queue/map/map
*
* @description A shorthand method for unbinding an event.
*
* @signature `obj.on( event, handler [, queue] )`
*
* Listen to when `obj` dispatches an event, a [can-reflect/observe.onKeyValue]
* change, or a [can-reflect/observe.onValue] change in that order.
*
* As this is the __legacy__ `.on`, it will look for an `.addEventListener`
* method on the `obj` first, before looking for the [can-symbol/symbols/onKeyValue]
* and then [can-symbol/symbols/onValue] symbol.
*
* @param {String} eventName
* @param {Function} handler
* @param {String} [queue]
* @return {Any} The object `on` was called on.
*/
off: function(eventName, handler, queue) {
var listenWithDOM = isDomEventTarget$1(this);
if (listenWithDOM) {
if (typeof handler === 'string') {
canDomEvents_1_3_13_canDomEvents.removeDelegateListener(this, eventName, handler, queue);
} else {
canDomEvents_1_3_13_canDomEvents.removeEventListener(this, eventName, handler, queue);
}
} else {
if (this[offEventSymbol]) {
this[offEventSymbol](eventName, handler, queue);
} else if ("removeEventListener" in this) {
this.removeEventListener(eventName, handler, queue);
} else if (this[offKeyValueSymbol]) {
canReflect_1_19_2_canReflect.offKeyValue(this, eventName, handler, queue);
} else {
if (!eventName && this[offValueSymbol]) {
canReflect_1_19_2_canReflect.offValue(this, handler, queue);
} else {
throw new Error("can-event-queue: Unable to unbind " + eventName);
}
}
}
return this;
}
};
// The symbols we'll add to objects
var symbols$1 = {
/**
* @function can-event-queue/map/map.can.onKeyValue @can.onKeyValue
* @parent can-event-queue/map/map
*
* @description Register an event handler to be called when a key value changes.
*
* @signature `canReflect.onKeyValue( obj, key, handler(newVal) [,queueName] )`
*
* Add a key change handler to an object. Handlers attached by `.onKeyValue` get
* called back with the new value of the `key`. Handlers attached with [can-event-queue/map/map.can.addEventListener]
* get the event object.
*
* ```js
* var mixinMapBindings = require("can-event-queue/map/map");
*
* var obj = mixinMapBindings({});
*
* canReflect.onKeyValue( obj, "prop", function(newPropValue){ ... });
* ```
*
* @param {String} key The name of property to listen to changes in values.
* @param {Function} handler(newVal, oldValue) The handler that will be called
* back with the new and old value of the key.
* @param {String} [queueName='mutate'] The name of the [can-queues] queue the handler will called
* back within. Defaults to `"mutate"`.
*/
"can.onKeyValue": function(key, handler, queueName) {
ensureMeta(this).handlers.add([key, "onKeyValue", queueName || "mutate", handler]);
},
/**
* @function can-event-queue/map/map.can.offKeyValue @can.offKeyValue
* @parent can-event-queue/map/map
*
* @description Unregister an event handler to be called when an event is dispatched.
*
* @signature `canReflect.offKeyValue( obj, key, handler, queueName )`
*
* Removes a handlers from being called when `key` changes are
* [can-event-queue/map/map.dispatch]ed.
*
* ```js
* // Removes `handler` if it is in the notify queue.
* canReflect.offKeyValue( obj, "prop", handler, "notify" )
* ```
*
* @param {String} eventName The name of the event to remove. If not specified, all events are removed.
* @param {Function} [handler] The handler that will be removed from the event. If not specified, all handlers for the event are removed.
* @param {String} [queueName='mutate'] The name of the [can-queues] queue the handler was registered on. Defaults to `"mutate"`.
*/
"can.offKeyValue": function(key, handler, queueName) {
ensureMeta(this).handlers.delete([key, "onKeyValue", queueName || "mutate", handler]);
},
/**
* @function can-event-queue/map/map.can.isBound @can.isBound
* @parent can-event-queue/map/map
*
* @description Return if the observable is bound to.
*
* @signature `canReflect.isBound(obj)`
*
* The `@can.isBound` symbol is added to make [can-reflect/observe.isBound]
* return if `obj` is bound or not.
*
* @return {Boolean} True if the observable has been bound to with `.onKeyValue` or `.addEventListener`.
*/
"can.isBound": function() {
return !ensureMeta(this).handlers.isEmpty();
},
/**
* @function can-event-queue/map/map.can.getWhatIChange @can.getWhatIChange
* @parent can-event-queue/map/map
*
* @description Return observables whose values are affected by attached event handlers
* @signature `@can.getWhatIChange(key)`
*
* The `@@can.getWhatIChange` symbol is added to make sure [can-debug] can report
* all the observables whose values are set by a given observable's key.
*
* This function iterates over the event handlers attached to a given `key` and
* collects the result of calling `@@can.getChangesDependencyRecord` on each handler;
* this symbol allows the caller to tell what observables are being mutated by
* the event handler when it is executed.
*
* In the following example a [can-simple-map] instance named `me` is created
* and when its `age` property changes, the value of a [can-simple-observable]
* instance is set. The event handler that causes the mutation is then decatorated
* with `@@can.getChangesDependencyRecord` to register the mutation dependency.
*
* ```js
* var obs = new SimpleObservable("a");
* var me = new SimpleMap({ age: 30 });
* var canReflect = require("can-reflect");
*
* var onAgeChange = function onAgeChange() {
* canReflect.setValue(obs, "b");
* };
*
* onAgeChange[canSymbol.for("can.getChangesDependencyRecord")] = function() {
* return {
* valueDependencies: new Set([ obs ]);
* }
* };
*
* canReflect.onKeyValue(me, "age", onAgeChange);
* me[canSymbol.for("can.getWhatIChange")]("age");
* ```
*
* The dependency records collected from the event handlers are divided into
* two categories:
*
* - mutate: Handlers in the mutate/domUI queues
* - derive: Handlers in the notify queue
*
* Since event handlers are added by default to the "mutate" queue, calling
* `@@can.getWhatIChange` on the `me` instance returns an object with a mutate
* property and the `valueDependencies` Set registered on the `onAgeChange`
* handler.
*
* Please check out the [can-reflect-dependencies] docs to learn more about
* how this symbol is used to keep track of custom observable dependencies.
*/
"can.getWhatIChange": function getWhatIChange(key) {
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
var whatIChange = {};
var meta = ensureMeta(this);
var notifyHandlers = [].concat(
meta.handlers.get([key, "event", "notify"]),
meta.handlers.get([key, "onKeyValue", "notify"])
);
var mutateHandlers = [].concat(
meta.handlers.get([key, "event", "mutate"]),
meta.handlers.get([key, "event", "domUI"]),
meta.handlers.get([key, "onKeyValue", "mutate"]),
meta.handlers.get([key, "onKeyValue", "domUI"])
);
if (notifyHandlers.length) {
notifyHandlers.forEach(function(handler) {
var changes = canReflect_1_19_2_canReflect.getChangesDependencyRecord(handler);
if (changes) {
var record = whatIChange.derive;
if (!record) {
record = (whatIChange.derive = {});
}
merge(record, changes);
}
});
}
if (mutateHandlers.length) {
mutateHandlers.forEach(function(handler) {
var changes = canReflect_1_19_2_canReflect.getChangesDependencyRecord(handler);
if (changes) {
var record = whatIChange.mutate;
if (!record) {
record = (whatIChange.mutate = {});
}
merge(record, changes);
}
});
}
return Object.keys(whatIChange).length ? whatIChange : undefined;
}
//!steal-remove-end
},
"can.onPatches": function(handler, queue) {
var handlers = ensureMeta(this).handlers;
handlers.add(["can.patches", "onKeyValue", queue || "notify", handler]);
},
"can.offPatches": function(handler, queue) {
var handlers = ensureMeta(this).handlers;
handlers.delete(["can.patches", "onKeyValue", queue || "notify", handler]);
}
};
// This can be removed in a future version.
function defineNonEnumerable$1(obj, prop, value) {
Object.defineProperty(obj, prop, {
enumerable: false,
value: value
});
}
// The actual legacyMapBindings mixin function
legacyMapBindings = function(obj) {
// add properties
canReflect_1_19_2_canReflect.assignMap(obj, props);
// add symbols
return canReflect_1_19_2_canReflect.assignSymbols(obj, symbols$1);
};
defineNonEnumerable$1(legacyMapBindings, "addHandlers", addHandlers);
defineNonEnumerable$1(legacyMapBindings, "stopListeningArgumentsToKeys", stopListeningArgumentsToKeys);
// ## LEGACY
// The following is for compatability with the old can-event
props.bind = props.addEventListener;
props.unbind = props.removeEventListener;
// Adds methods directly to method so it can be used like `can-event` used to be used.
canReflect_1_19_2_canReflect.assignMap(legacyMapBindings, props);
canReflect_1_19_2_canReflect.assignSymbols(legacyMapBindings, symbols$1);
defineNonEnumerable$1(legacyMapBindings, "start", function() {
console.warn("use can-queues.batch.start()");
canQueues_1_3_2_canQueues.batch.start();
});
defineNonEnumerable$1(legacyMapBindings, "stop", function() {
console.warn("use can-queues.batch.stop()");
canQueues_1_3_2_canQueues.batch.stop();
});
defineNonEnumerable$1(legacyMapBindings, "flush", function() {
console.warn("use can-queues.flush()");
canQueues_1_3_2_canQueues.flush();
});
defineNonEnumerable$1(legacyMapBindings, "afterPreviousEvents", function(handler) {
console.warn("don't use afterPreviousEvents");
canQueues_1_3_2_canQueues.mutateQueue.enqueue(function afterPreviousEvents() {
canQueues_1_3_2_canQueues.mutateQueue.enqueue(handler);
});
canQueues_1_3_2_canQueues.flush();
});
defineNonEnumerable$1(legacyMapBindings, "after", function(handler) {
console.warn("don't use after");
canQueues_1_3_2_canQueues.mutateQueue.enqueue(handler);
canQueues_1_3_2_canQueues.flush();
});
var map$1 = legacyMapBindings;
// Ensure the "obj" passed as an argument has an object on @@can.meta
var ensureMeta$1 = function ensureMeta(obj) {
var metaSymbol = canSymbol_1_7_0_canSymbol.for("can.meta");
var meta = obj[metaSymbol];
if (!meta) {
meta = {};
canReflect_1_19_2_canReflect.setKeyValue(obj, metaSymbol, meta);
}
return meta;
};
// this is a very simple can-map like object
var SimpleMap = canConstruct_3_5_7_canConstruct.extend("SimpleMap",
{
// ### setup
// A setup function for the instantiation of a simple-map.
setup: function(initialData){
this._data = {};
if(initialData && typeof initialData === "object") {
this.attr(initialData);
}
},
// ### attr
// The main get/set interface simple-map.
// Either sets or gets one or more properties depending on how it is called.
attr: function(prop, value) {
var self = this;
if(arguments.length === 0 ) {
canObservationRecorder_1_3_1_canObservationRecorder.add(this,"can.keys");
var data = {};
canReflect_1_19_2_canReflect.eachKey(this._data, function(value, prop){
canObservationRecorder_1_3_1_canObservationRecorder.add(this, prop);
data[prop] = value;
}, this);
return data;
}
else if(arguments.length > 1) {
var had = this._data.hasOwnProperty(prop);
var old = this._data[prop];
this._data[prop] = value;
if(old !== value) {
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
if (typeof this._log === "function") {
this._log(prop, value, old);
}
}
//!steal-remove-end
var dispatched = {
keyChanged: !had ? prop : undefined,
type: prop
};
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
dispatched = {
keyChanged: !had ? prop : undefined,
type: prop,
reasonLog: [ canReflect_1_19_2_canReflect.getName(this) + "'s", prop, "changed to", value, "from", old ],
};
}
//!steal-remove-end
this.dispatch(dispatched, [value, old]);
}
}
// 1 argument
else if(typeof prop === 'object') {
canQueues_1_3_2_canQueues.batch.start();
canReflect_1_19_2_canReflect.eachKey(prop, function(value, key) {
self.attr(key, value);
});
canQueues_1_3_2_canQueues.batch.stop();
}
else {
if(prop !== "constructor") {
canObservationRecorder_1_3_1_canObservationRecorder.add(this, prop);
return this._data[prop];
}
return this.constructor;
}
},
serialize: function(){
return canReflect_1_19_2_canReflect.serialize(this, Map);
},
get: function(){
return this.attr.apply(this, arguments);
},
set: function(){
return this.attr.apply(this, arguments);
},
// call `.log()` to log all property changes
// pass a single property to only get logs for said property, e.g: `.log("foo")`
log: function(key) {
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
var quoteString = function quoteString(x) {
return typeof x === "string" ? JSON.stringify(x) : x;
};
var meta = ensureMeta$1(this);
meta.allowedLogKeysSet = meta.allowedLogKeysSet || new Set();
if (key) {
meta.allowedLogKeysSet.add(key);
}
this._log = function(prop, current, previous, log) {
if (key && !meta.allowedLogKeysSet.has(prop)) {
return;
}
dev.log(
canReflect_1_19_2_canReflect.getName(this),
"\n key ", quoteString(prop),
"\n is ", quoteString(current),
"\n was ", quoteString(previous)
);
};
}
//!steal-remove-end
}
}
);
map$1(SimpleMap.prototype);
var simpleMapProto = {
// -type-
"can.isMapLike": true,
"can.isListLike": false,
"can.isValueLike": false,
// -get/set-
"can.getKeyValue": SimpleMap.prototype.get,
"can.setKeyValue": SimpleMap.prototype.set,
"can.deleteKeyValue": function(prop) {
var dispatched;
if( this._data.hasOwnProperty(prop) ) {
var old = this._data[prop];
delete this._data[prop];
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
if (typeof this._log === "function") {
this._log(prop, undefined, old);
}
}
//!steal-remove-end
dispatched = {
keyChanged: prop,
type: prop
};
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
dispatched = {
keyChanged: prop,
type: prop,
reasonLog: [ canReflect_1_19_2_canReflect.getName(this) + "'s", prop, "deleted", old ]
};
}
//!steal-remove-end
this.dispatch(dispatched, [undefined, old]);
}
},
// -shape
"can.getOwnEnumerableKeys": function(){
canObservationRecorder_1_3_1_canObservationRecorder.add(this, 'can.keys');
return Object.keys(this._data);
},
// -shape get/set-
"can.assignDeep": function(source){
canQueues_1_3_2_canQueues.batch.start();
// TODO: we should probably just throw an error instead of cleaning
canReflect_1_19_2_canReflect.assignMap(this, source);
canQueues_1_3_2_canQueues.batch.stop();
},
"can.updateDeep": function(source){
canQueues_1_3_2_canQueues.batch.start();
// TODO: we should probably just throw an error instead of cleaning
canReflect_1_19_2_canReflect.updateMap(this, source);
canQueues_1_3_2_canQueues.batch.stop();
},
"can.keyHasDependencies": function(key) {
return false;
},
"can.getKeyDependencies": function(key) {
return undefined;
},
"can.hasOwnKey": function(key){
return this._data.hasOwnProperty(key);
}
};
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
simpleMapProto["can.getName"] = function() {
return canReflect_1_19_2_canReflect.getName(this.constructor) + "{}";
};
}
//!steal-remove-end
canReflect_1_19_2_canReflect.assignSymbols(SimpleMap.prototype,simpleMapProto);
// Setup other symbols
var canSimpleMap_4_3_3_canSimpleMap = SimpleMap;
/**
* Creates a constructor function from an ES2015 class, this is a workaround
* needed to being able to extend a class from code that's transpiled by Babel.
* See https://github.com/babel/babel/pull/8656
* @param {*} Type The ES2015 base class used to create the constructor
* @param {*} Parent The object where the prototype chain walk to copy over
* symbols and static properties to the constructor stops. If not provided,
* the chain stops at Object.
* @returns {Function} Constructor function than can be safely subclassed from
* transpiled code.
*/
function createConstructorFunction(Type, Parent) {
if (typeof Parent === "undefined") {
Parent = Object.getPrototypeOf(Object);
}
function TypeConstructor() {
return Reflect.construct(Type, arguments, this.constructor);
}
TypeConstructor.prototype = Object.create(Type.prototype);
TypeConstructor.prototype.constructor = TypeConstructor;
/**
* Add `prop` to TypeConstructor from `source` if not defined already
* @param {{}} source The object that owns `prop`
* @param {string} prop The name of the property to be defined
*/
function copyIfMissing(source, prop) {
if (!TypeConstructor[prop]) {
Object.defineProperty(
TypeConstructor,
prop,
Object.getOwnPropertyDescriptor(source, prop)
);
}
}
// Walk up the prototype chain to copy over all Symbols and
// static properties to the constructor function
let Link = Type;
while (Link !== Parent && Link !== null) {
const props = Object.getOwnPropertyNames(Link);
props.forEach(function(prop) {
copyIfMissing(Link, prop);
});
const symbols = Object.getOwnPropertySymbols(Link);
symbols.forEach(function(symbol) {
copyIfMissing(Link, symbol);
});
Link = Object.getPrototypeOf(Link);
}
return TypeConstructor;
}
var createConstructorFunction_1 = createConstructorFunction;
// This is an observable that is like `settable`, but passed a `resolve`
// function that can resolve the value of this observable late.
function AsyncObservable(fn, context, initialValue) {
this.resolve = this.resolve.bind(this);
this.lastSetValue = new canSimpleObservable_2_5_0_canSimpleObservable(initialValue);
this.handler = this.handler.bind(this);
function observe() {
this.resolveCalled = false;
// set inGetter flag to avoid calling `resolve` redundantly if it is called
// synchronously in the getter
this.inGetter = true;
var newVal = fn.call(
context,
this.lastSetValue.get(),
this.bound === true ? this.resolve : undefined
);
this.inGetter = false;
// if the getter returned a value, resolve with the value
if (newVal !== undefined) {
this.resolve(newVal);
}
// otherwise, if `resolve` was called synchronously in the getter,
// resolve with the value passed to `resolve`
else if (this.resolveCalled) {
this.resolve(this._value);
}
// if bound, the handlers will be called by `resolve`
// returning here would cause a duplicate event
if (this.bound !== true) {
return newVal;
}
}
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
canReflect_1_19_2_canReflect.assignSymbols(this, {
"can.getName": function() {
return (
canReflect_1_19_2_canReflect.getName(this.constructor) +
"<" +
canReflect_1_19_2_canReflect.getName(fn) +
">"
);
}
});
Object.defineProperty(this.handler, "name", {
value: canReflect_1_19_2_canReflect.getName(this) + ".handler"
});
Object.defineProperty(observe, "name", {
value: canReflect_1_19_2_canReflect.getName(fn) + "::" + canReflect_1_19_2_canReflect.getName(this.constructor)
});
}
//!steal-remove-end
this.observation = new canObservation_4_2_0_canObservation(observe, this);
}
AsyncObservable.prototype = Object.create(settable.prototype);
AsyncObservable.prototype.constructor = AsyncObservable;
AsyncObservable.prototype.handler = function(newVal) {
if (newVal !== undefined) {
settable.prototype.handler.apply(this, arguments);
}
};
var peek$1 = canObservationRecorder_1_3_1_canObservationRecorder.ignore(canReflect_1_19_2_canReflect.getValue.bind(canReflect_1_19_2_canReflect));
AsyncObservable.prototype.activate = function() {
canReflect_1_19_2_canReflect.onValue(this.observation, this.handler, "notify");
if (!this.resolveCalled) {
this._value = peek$1(this.observation);
}
};
AsyncObservable.prototype.resolve = function resolve(newVal) {
this.resolveCalled = true;
var old = this._value;
this._value = newVal;
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
if (typeof this._log === "function") {
this._log(old, newVal);
}
}
//!steal-remove-end
// if resolve was called synchronously from the getter, do not enqueue changes
// the observation will handle calling resolve again if required
if (!this.inGetter) {
var queuesArgs = [
this.handlers.getNode([]),
this,
[newVal, old],
null
];
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
queuesArgs = [
this.handlers.getNode([]),
this,
[newVal, old],
null
/* jshint laxcomma: true */
, [canReflect_1_19_2_canReflect.getName(this), "resolved with", newVal]
/* jshint laxcomma: false */
];
}
//!steal-remove-end
// adds callback handlers to be called w/i their respective queue.
canQueues_1_3_2_canQueues.enqueueByQueue.apply(canQueues_1_3_2_canQueues, queuesArgs);
}
};
var async = AsyncObservable;
var getChangesSymbol$1 = canSymbol_1_7_0_canSymbol.for("can.getChangesDependencyRecord");
var metaSymbol$1 = canSymbol_1_7_0_canSymbol.for("can.meta");
function ResolverObservable(resolver, context, initialValue, options) {
// we don't want reads leaking out. We should be binding to all of this ourselves.
this.resolver = canObservationRecorder_1_3_1_canObservationRecorder.ignore(resolver);
this.context = context;
this._valueOptions = {
resolve: this.resolve.bind(this),
listenTo: this.listenTo.bind(this),
stopListening: this.stopListening.bind(this),
lastSet: new canSimpleObservable_2_5_0_canSimpleObservable(initialValue)
};
this.update = this.update.bind(this);
this.contextHandlers = new WeakMap();
this.teardown = null;
// a place holder for remembering where we bind
this.binder = {};
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
canReflect_1_19_2_canReflect.assignSymbols(this, {
"can.getName": function() {
return (
canReflect_1_19_2_canReflect.getName(this.constructor) +
"<" +
canReflect_1_19_2_canReflect.getName(resolver) +
">"
);
}
});
Object.defineProperty(this.update, "name", {
value: canReflect_1_19_2_canReflect.getName(this) + ".update"
});
canReflect_1_19_2_canReflect.assignSymbols(this._valueOptions.lastSet, {
"can.getName": function() {
return (
canReflect_1_19_2_canReflect.getName(this.constructor) +"::lastSet"+
"<" +
canReflect_1_19_2_canReflect.getName(resolver) +
">"
);
}
});
}
//!steal-remove-end
this[metaSymbol$1] = canReflect_1_19_2_canReflect.assignMap({}, options);
}
ResolverObservable.prototype = Object.create(settable.prototype);
function deleteHandler(bindTarget, event, queue, handler){
map$1.off.call(bindTarget, event, handler, queue);
}
canReflect_1_19_2_canReflect.assignMap(ResolverObservable.prototype, {
constructor: ResolverObservable,
listenTo: function(bindTarget, event, handler, queueName) {
//Object.defineProperty(this.handler, "name", {
// value: canReflect.getName(this) + ".handler"
//});
if(canReflect_1_19_2_canReflect.isPrimitive(bindTarget)) {
handler = event;
event = bindTarget;
bindTarget = this.context;
}
if(typeof event === "function") {
handler = event;
event = undefined;
}
var resolverInstance = this;
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
if(!handler.name) {
Object.defineProperty(handler, "name", {
value:
(bindTarget ?
canReflect_1_19_2_canReflect.getName(bindTarget) : "")+
(event ? ".on('"+event+"',handler)" : ".on(handler)")+
"::"+canReflect_1_19_2_canReflect.getName(this)
});
}
}
//!steal-remove-end
var contextHandler = handler.bind(this.context);
contextHandler[getChangesSymbol$1] = function getChangesDependencyRecord() {
var s = new Set();
s.add(resolverInstance);
return {
valueDependencies: s
};
};
this.contextHandlers.set(handler, contextHandler);
map$1.listenTo.call(this.binder, bindTarget, event, contextHandler, queueName || "notify");
},
stopListening: function(){
var meta = this.binder[canSymbol_1_7_0_canSymbol.for("can.meta")];
var listenHandlers = meta && meta.listenHandlers;
if(listenHandlers) {
var keys = map$1.stopListeningArgumentsToKeys.call({context: this.context, defaultQueue: "notify"});
listenHandlers.delete(keys, deleteHandler);
}
return this;
},
resolve: function(newVal) {
this._value = newVal;
// if we are setting up the initial binding and we get a resolved value
// do not emit events for it.
if(this.isBinding) {
this.lastValue = this._value;
return newVal;
}
if(this._value !== this.lastValue) {
var enqueueMeta = {};
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
/* jshint laxcomma: true */
enqueueMeta = {
log: [canReflect_1_19_2_canReflect.getName(this.update)],
reasonLog: [canReflect_1_19_2_canReflect.getName(this), "resolved with", newVal]
};
/* jshint laxcomma: false */
}
//!steal-remove-end
canQueues_1_3_2_canQueues.batch.start();
canQueues_1_3_2_canQueues.deriveQueue.enqueue(
this.update,
this,
[],
enqueueMeta
);
canQueues_1_3_2_canQueues.batch.stop();
}
return newVal;
},
update: function(){
if(this.lastValue !== this._value) {
var old = this.lastValue;
this.lastValue = this._value;
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
if (typeof this._log === "function") {
this._log(old, this._value);
}
}
//!steal-remove-end
// adds callback handlers to be called w/i their respective queue.
canQueues_1_3_2_canQueues.enqueueByQueue(
this.handlers.getNode([]),
this,
[this._value, old]
);
}
},
activate: function() {
this.isBinding = true;
this.teardown = this.resolver.call(this.context, this._valueOptions);
this.isBinding = false;
},
onUnbound: function() {
this.bound = false;
map$1.stopListening.call(this.binder);
if(this.teardown != null) {
this.teardown();
this.teardown = null;
}
},
set: function(value) {
this._valueOptions.lastSet.set(value);
/*if (newVal !== this.lastSetValue.get()) {
this.lastSetValue.set(newVal);
}*/
},
get: function() {
if (canObservationRecorder_1_3_1_canObservationRecorder.isRecording()) {
canObservationRecorder_1_3_1_canObservationRecorder.add(this);
if (!this.bound) {
this.onBound();
}
}
if (this.bound === true) {
return this._value;
} else {
if (this[metaSymbol$1].resetUnboundValueInGet) {
this._value = undefined;
}
var handler = function(){};
this.on(handler);
var val = this._value;
this.off(handler);
return val;
}
},
hasDependencies: function hasDependencies() {
var hasDependencies = false;
if (this.bound) {
var meta = this.binder[metaSymbol$1];
var listenHandlers = meta && meta.listenHandlers;
hasDependencies = !!listenHandlers.size();
}
return hasDependencies;
},
getValueDependencies: function getValueDependencies() {
if (this.bound) {
var meta = this.binder[canSymbol_1_7_0_canSymbol.for("can.meta")];
var listenHandlers = meta && meta.listenHandlers;
var keyDeps = new Map();
var valueDeps = new Set();
if (listenHandlers) {
canReflect_1_19_2_canReflect.each(listenHandlers.root, function(events, obj) {
canReflect_1_19_2_canReflect.each(events, function(queues, eventName) {
if (eventName === undefined) {
valueDeps.add(obj);
} else {
var entry = keyDeps.get(obj);
if (!entry) {
entry = new Set();
keyDeps.set(obj, entry);
}
entry.add(eventName);
}
});
});
if (valueDeps.size || keyDeps.size) {
var result = {};
if (keyDeps.size) {
result.keyDependencies = keyDeps;
}
if (valueDeps.size) {
result.valueDependencies = valueDeps;
}
return result;
}
}
}
}
});
canReflect_1_19_2_canReflect.assignSymbols(ResolverObservable.prototype, {
"can.getValue": ResolverObservable.prototype.get,
"can.setValue": ResolverObservable.prototype.set,
"can.isMapLike": false,
"can.getPriority": function() {
// TODO: the priority should come from any underlying values
return this.priority || 0;
},
"can.setPriority": function(newPriority) {
this.priority = newPriority;
},
"can.valueHasDependencies": ResolverObservable.prototype.hasDependencies,
"can.getValueDependencies": ResolverObservable.prototype.getValueDependencies
});
var resolver = ResolverObservable;
/**
* @module {function} can-event-queue/type/type
* @parent can-event-queue
*
* @description Mixin methods and symbols to make a type constructor function able to
* broadcast changes in its instances.
*
* @signature `mixinTypeBindings( type )`
*
* Adds symbols and methods that make `type` work with the following [can-reflect] APIs:
*
* - [can-reflect/observe.onInstanceBoundChange] - Observe when instances are bound.
* - [can-reflect/observe.onInstancePatches] - Observe patche events on all instances.
*
* When `mixinTypeBindings` is called on an `Person` _type_ like:
*
* ```js
* var mixinTypeBindings = require("can-event-queue/type/type");
* var mixinLegacyMapBindings = require("can-event-queue/map/map");
*
* class Person {
* constructor(data){
* this.data = data;
* }
* }
* mixinTypeBindings(Person);
* mixinLegacyMapBindings(Person.prototype);
*
* var me = new Person({first: "Justin", last: "Meyer"});
*
* // mixinTypeBindings allows you to listen to
* // when a person instance's bind stache changes
* canReflect.onInstanceBoundChange(Person, function(person, isBound){
* console.log("isBound");
* });
*
* // mixinTypeBindings allows you to listen to
* // when a patch change happens.
* canReflect.onInstancePatches(Person, function(person, patches){
* console.log(patches[0]);
* });
*
* me.on("name",function(ev, newVal, oldVal){}) //-> logs: "isBound"
*
* me.dispatch({
* type: "first",
* patches: [{type: "set", key: "first", value: "Ramiya"}]
* }, ["Ramiya","Justin"])
* //-> logs: {type: "set", key: "first", value: "Ramiya"}
* ```
*
*/
var metaSymbol$2 = canSymbol_1_7_0_canSymbol.for("can.meta");
function addHandlers$1(obj, meta) {
if (!meta.lifecycleHandlers) {
meta.lifecycleHandlers = new canKeyTree_1_2_2_canKeyTree([Object, Array]);
}
if (!meta.instancePatchesHandlers) {
meta.instancePatchesHandlers = new canKeyTree_1_2_2_canKeyTree([Object, Array]);
}
}
function ensureMeta$2(obj) {
var meta = obj[metaSymbol$2];
if (!meta) {
meta = {};
canReflect_1_19_2_canReflect.setKeyValue(obj, metaSymbol$2, meta);
}
addHandlers$1(obj, meta);
return meta;
}
var props$1 = {
/**
* @function can-event-queue/type/type.can.onInstanceBoundChange @can.onInstanceBoundChange
* @parent can-event-queue/type/type
* @description Listen to when any instance is bound for the first time or all handlers are removed.
*
* @signature `canReflect.onInstanceBoundChange(Type, handler(instance, isBound) )`
*
* ```js
* canReflect.onInstanceBoundChange(Person, function(person, isBound){
* console.log("isBound");
* });
* ```
*
* @param {function(Any,Boolean)} handler(instance,isBound) A function is called
* when an instance is bound or unbound. `isBound` will be `true` when the instance
* becomes bound and `false` when unbound.
*/
/**
* @function can-event-queue/type/type.can.offInstanceBoundChange @can.offInstanceBoundChange
* @parent can-event-queue/type/type
*
* @description Stop listening to when an instance's bound status changes.
*
* @signature `canReflect.offInstanceBoundChange(Type, handler )`
*
* Stop listening to a handler bound with
* [can-event-queue/type/type.can.onInstanceBoundChange].
*/
/**
* @function can-event-queue/type/type.can.onInstancePatches @can.onInstancePatches
* @parent can-event-queue/type/type
*
* @description Listen to patch changes on any instance.
*
* @signature `canReflect.onInstancePatches(Type, handler(instance, patches) )`
*
* Listen to patch changes on any instance of `Type`. This is used by
* [can-connect] to know when a potentially `unbound` instance's `id`
* changes. If the `id` changes, the instance can be moved into the store
* while it is being saved.
*
*/
/**
* @function can-event-queue/type/type.can.offInstancePatches @can.offInstancePatches
* @parent can-event-queue/type/type
*
* @description Stop listening to patch changes on any instance.
*
* @signature `canReflect.onInstancePatches(Type, handler )`
*
* Stop listening to a handler bound with [can-event-queue/type/type.can.onInstancePatches].
*/
};
function onOffAndDispatch(symbolName, dispatchName, handlersName){
props$1["can.on"+symbolName] = function(handler, queueName) {
ensureMeta$2(this)[handlersName].add([queueName || "mutate", handler]);
};
props$1["can.off"+symbolName] = function(handler, queueName) {
ensureMeta$2(this)[handlersName].delete([queueName || "mutate", handler]);
};
props$1["can."+dispatchName] = function(instance, arg){
canQueues_1_3_2_canQueues.enqueueByQueue(ensureMeta$2(this)[handlersName].getNode([]), this, [instance, arg]);
};
}
onOffAndDispatch("InstancePatches","dispatchInstanceOnPatches","instancePatchesHandlers");
onOffAndDispatch("InstanceBoundChange","dispatchInstanceBoundChange","lifecycleHandlers");
function mixinTypeBindings(obj){
return canReflect_1_19_2_canReflect.assignSymbols(obj,props$1);
}
Object.defineProperty(mixinTypeBindings, "addHandlers", {
enumerable: false,
value: addHandlers$1
});
var type$1 = mixinTypeBindings;
var canType_1_1_6_canType = createCommonjsModule(function (module, exports) {
var isMemberSymbol = canSymbol_1_7_0_canSymbol.for("can.isMember");
var newSymbol = canSymbol_1_7_0_canSymbol.for("can.new");
var getSchemaSymbol = canSymbol_1_7_0_canSymbol.for("can.getSchema");
var baseTypeSymbol = canSymbol_1_7_0_canSymbol.for("can.baseType");
var strictTypeOfSymbol = canSymbol_1_7_0_canSymbol.for("can.strictTypeOf");
var type = exports;
function makeSchema(values) {
return function(){
return {
type: "Or",
values: values
};
};
}
// Default "can.new"
function canNew(value) {
if(this[isMemberSymbol](value)) {
return value;
}
return canReflect_1_19_2_canReflect.convert(value, this[baseTypeSymbol]);
}
function strictNew(value) {
var isMember = this[isMemberSymbol](value);
if(!isMember) {
return check(this[baseTypeSymbol], value);
}
return value;
}
// "can.new" for Booleans
function booleanNew(value) {
if (value === "false" || value=== "0") {
return false;
}
return Boolean(value);
}
var maybeValues = Object.freeze([null, undefined]);
function check(Type, val) {
var valueType = canString_1_1_0_canString.capitalize(typeof val);
var error = new Error('Type value ' + typeof val === "string" ? '"' + val + '"' : val + ' (' + valueType + ') is not of type ' + canReflect_1_19_2_canReflect.getName(Type) + '.' );
error.type = 'can-type-error';
throw error;
}
function makeIsMember(Type) {
if(isMemberSymbol in Type) {
return Type[isMemberSymbol];
}
return function(value) {
return value instanceof Type;
};
}
function makeBaseType(Type) {
var typeObject = {};
typeObject[newSymbol] = canNew;
typeObject[isMemberSymbol] = makeIsMember(Type);
typeObject[baseTypeSymbol] = Type;
typeObject[getSchemaSymbol] = makeSchema([Type]);
Type[strictTypeOfSymbol] = typeObject[strictTypeOfSymbol] = typeObject;
return typeObject;
}
function makePrimitiveType(Type, typeString) {
var typeObject = makeBaseType(Type);
if(Type === Boolean) {
typeObject[newSymbol] = booleanNew;
typeObject[getSchemaSymbol] = makeSchema([true, false]);
}
typeObject[isMemberSymbol] = function(value) {
return typeof value === typeString;
};
return typeObject;
}
function getBaseType(Type) {
if(typeof Type === "function") {
if(canReflect_1_19_2_canReflect.hasOwnKey(Type, strictTypeOfSymbol)) {
return Type[strictTypeOfSymbol];
}
} else if(strictTypeOfSymbol in Type) {
return Type[strictTypeOfSymbol];
}
return makeBaseType(Type);
}
function makeMaybe(Type) {
var isMember = Type[isMemberSymbol];
return function(value) {
return value == null || isMember.call(this, value);
};
}
function makeMaybeSchema(baseType) {
var baseSchema = canReflect_1_19_2_canReflect.getSchema(baseType);
var allValues = baseSchema.values.concat(maybeValues);
return makeSchema(allValues);
}
function inheritFrom(o, Type, property) {
if(property in Type) {
o[property] = Type[property];
}
}
function wrapName(wrapper, Type) {
var baseName = canReflect_1_19_2_canReflect.getName(Type);
return "type." + wrapper + "(" + baseName + ")";
}
canReflect_1_19_2_canReflect.each({
"boolean": Boolean,
"number": Number,
"string": String
}, function(Type, typeString) {
makePrimitiveType(Type, typeString);
});
function isTypeObject(Type) {
if(canReflect_1_19_2_canReflect.isPrimitive(Type)) {
return false;
}
return (newSymbol in Type) && (isMemberSymbol in Type);
}
function normalize(Type) {
if(canReflect_1_19_2_canReflect.isPrimitive(Type)) {
throw new Error("can-type: Unable to normalize primitive values.");
} else if(isTypeObject(Type)) {
return Type;
} else {
return type.check(Type);
}
}
function late(fn) {
var lateType = {};
var underlyingType;
var unwrap = function() {
underlyingType = type.normalize(fn());
unwrap = function() { return underlyingType; };
return underlyingType;
};
return canReflect_1_19_2_canReflect.assignSymbols(lateType, {
"can.new": function(val) {
return canReflect_1_19_2_canReflect.new(unwrap(), val);
},
"can.isMember": function(val) {
return unwrap()[isMemberSymbol](val);
}
});
}
var Any = canReflect_1_19_2_canReflect.assignSymbols({}, {
"can.new": function(val) { return val; },
"can.isMember": function() { return true; }
});
function all(typeFn, Type) {
var typeObject = typeFn(Type);
typeObject[getSchemaSymbol] = function() {
var parentSchema = canReflect_1_19_2_canReflect.getSchema(Type);
var schema = canReflect_1_19_2_canReflect.assignMap({}, parentSchema);
schema.keys = {};
canReflect_1_19_2_canReflect.eachKey(parentSchema.keys, function(value, key) {
schema.keys[key] = typeFn(value);
});
return schema;
};
function Constructor(values) {
var schema = canReflect_1_19_2_canReflect.getSchema(this);
var keys = schema.keys;
var convertedValues = {};
canReflect_1_19_2_canReflect.eachKey(values || {}, function(value, key) {
convertedValues[key] = canReflect_1_19_2_canReflect.convert(value, keys[key]);
});
return canReflect_1_19_2_canReflect.new(Type, convertedValues);
}
canReflect_1_19_2_canReflect.setName(Constructor, "Converted<" + canReflect_1_19_2_canReflect.getName(Type) + ">");
Constructor.prototype = typeObject;
return Constructor;
}
var Integer = {};
Integer[newSymbol] = function(value) {
// parseInt(notANumber) returns NaN
// Since we always want an integer returned
// using |0 instead.
return value | 0;
};
Integer[isMemberSymbol] = function(value) {
// “polyfill” for Number.isInteger because it’s not supported in IE11
return typeof value === "number" && isFinite(value) &&
Math.floor(value) === value;
};
Integer[getSchemaSymbol] = makeSchema([Number]);
canReflect_1_19_2_canReflect.setName(Integer, "Integer");
function makeCache(fn) {
var cache = new WeakMap();
return function(Type) {
if(cache.has(Type)) {
return cache.get(Type);
}
var typeObject = fn.call(this, Type);
cache.set(Type, typeObject);
return typeObject;
};
}
exports.check = makeCache(function(Type) {
var o = Object.create(getBaseType(Type));
o[newSymbol] = strictNew;
inheritFrom(o, Type, isMemberSymbol);
inheritFrom(o, Type, getSchemaSymbol);
canReflect_1_19_2_canReflect.setName(o, wrapName("check", Type));
return o;
});
exports.convert = makeCache(function(Type) {
var o = Object.create(getBaseType(Type));
inheritFrom(o, Type, isMemberSymbol);
inheritFrom(o, Type, getSchemaSymbol);
canReflect_1_19_2_canReflect.setName(o, wrapName("convert", Type));
return o;
});
exports.maybe = makeCache(function(Type) {
var baseType = getBaseType(Type);
var desc = {};
desc[newSymbol] = {
value: strictNew
};
desc[isMemberSymbol] = {
value: makeMaybe(baseType)
};
desc[getSchemaSymbol] = {
value: makeMaybeSchema(baseType)
};
var o = Object.create(baseType, desc);
canReflect_1_19_2_canReflect.setName(o, wrapName("maybe", Type));
return o;
});
exports.maybeConvert = makeCache(function(Type) {
var baseType = getBaseType(Type);
var desc = {};
desc[isMemberSymbol] = {
value: makeMaybe(baseType)
};
desc[getSchemaSymbol] = {
value: makeMaybeSchema(baseType)
};
var o = Object.create(baseType, desc);
canReflect_1_19_2_canReflect.setName(o, wrapName("maybeConvert", Type));
return o;
});
//!steal-remove-start
// type checking should not throw in production
if(process.env.NODE_ENV === 'production') {
exports.check = exports.convert;
exports.maybe = exports.maybeConvert;
}
//!steal-remove-end
exports.Any = Any;
exports.Integer = Integer;
exports.late = late;
exports.isTypeObject = isTypeObject;
exports.normalize = normalize;
exports.all = all;
exports.convertAll = all.bind(null, exports.convert);
canNamespace_1_0_0_canNamespace.type = exports;
});
var canType_1_1_6_canType_1 = canType_1_1_6_canType.check;
var canType_1_1_6_canType_2 = canType_1_1_6_canType.convert;
var canType_1_1_6_canType_3 = canType_1_1_6_canType.maybe;
var canType_1_1_6_canType_4 = canType_1_1_6_canType.maybeConvert;
var canType_1_1_6_canType_5 = canType_1_1_6_canType.Any;
var canType_1_1_6_canType_6 = canType_1_1_6_canType.Integer;
var canType_1_1_6_canType_7 = canType_1_1_6_canType.late;
var canType_1_1_6_canType_8 = canType_1_1_6_canType.isTypeObject;
var canType_1_1_6_canType_9 = canType_1_1_6_canType.normalize;
var canType_1_1_6_canType_10 = canType_1_1_6_canType.all;
var canType_1_1_6_canType_11 = canType_1_1_6_canType.convertAll;
let define; //jshint ignore:line
const newSymbol$1 = Symbol.for("can.new"),
serializeSymbol = Symbol.for("can.serialize"),
inSetupSymbol$2 = Symbol.for("can.initializing"),
isMemberSymbol$1 = Symbol.for("can.isMember"),
hasBeenDefinedSymbol = Symbol.for("can.hasBeenDefined"),
canMetaSymbol = Symbol.for("can.meta"),
baseTypeSymbol = Symbol.for("can.baseType");
let eventsProto,
make, makeDefinition, getDefinitionsAndMethods, getDefinitionOrMethod;
// UTILITIES
function isDefineType(func){
return func && (func.canDefineType === true || func[newSymbol$1] );
}
function observableType() {
throw new Error("This is not currently implemented.");
}
let AsyncFunction;
const browserSupportsAsyncFunctions = (function() {
try {
AsyncFunction = (async function(){}).constructor;
return true;
} catch(e) {
return false;
}
}());
function isAsyncFunction(fn) {
if (!browserSupportsAsyncFunctions) {
return false;
}
return fn && fn instanceof AsyncFunction;
}
const peek$2 = canObservationRecorder_1_3_1_canObservationRecorder.ignore(canReflect_1_19_2_canReflect.getValue.bind(canReflect_1_19_2_canReflect));
let Object_defineNamedPrototypeProperty = Object.defineProperty;
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
Object_defineNamedPrototypeProperty = function(obj, prop, definition) {
if (definition.get) {
Object.defineProperty(definition.get, "name", {
value: "get "+canReflect_1_19_2_canReflect.getName(obj) + "."+prop,
writable: true,
configurable: true
});
}
if (definition.set) {
Object.defineProperty(definition.set, "name", {
value: "set "+canReflect_1_19_2_canReflect.getName(obj) + "."+prop,
configurable: true
});
}
return Object.defineProperty(obj, prop, definition);
};
}
//!steal-remove-end
function defineConfigurableAndNotEnumerable(obj, prop, value) {
Object.defineProperty(obj, prop, {
configurable: true,
enumerable: false,
writable: true,
value: value
});
}
function defineNotWritableAndNotEnumerable(obj, prop, value) {
Object.defineProperty(obj, prop, {
value: value,
enumerable: false,
writable: false
});
}
function eachPropertyDescriptor(map, cb, ...args){
for(const prop of Object.getOwnPropertyNames(map)) {
if(map.hasOwnProperty(prop)) {
cb.call(map, prop, Object.getOwnPropertyDescriptor(map, prop), ...args);
}
}
}
function getEveryPropertyAndSymbol(obj) {
const props = Object.getOwnPropertyNames(obj);
const symbols = ("getOwnPropertySymbols" in Object) ?
Object.getOwnPropertySymbols(obj) : [];
return props.concat(symbols);
}
var define_1 = define = function(typePrototype, defines, baseDefine, propertyDefaults = {}) {
// default property definitions on _data
let prop,
dataInitializers = Object.create(baseDefine ? baseDefine.dataInitializers : null),
// computed property definitions on _computed
computedInitializers = Object.create(baseDefine ? baseDefine.computedInitializers : null),
required = new Set();
const result = getDefinitionsAndMethods(defines, baseDefine, typePrototype, propertyDefaults);
result.dataInitializers = dataInitializers;
result.computedInitializers = computedInitializers;
result.required = required;
// Goes through each property definition and creates
// a `getter` and `setter` function for `Object.defineProperty`.
canReflect_1_19_2_canReflect.eachKey(result.definitions, function(definition, property){
// Add this as a required property
if(definition.required === true) {
required.add(property);
}
define.property(typePrototype, property, definition, dataInitializers, computedInitializers, result.defaultDefinition);
});
// Places a `_data` on the prototype that when first called replaces itself
// with a `_data` object local to the instance. It also defines getters
// for any value that has a default value.
if(typePrototype.hasOwnProperty("_data")) {
for (prop in dataInitializers) {
canDefineLazyValue_1_1_1_defineLazyValue(typePrototype._data, prop, dataInitializers[prop].bind(typePrototype), true);
}
} else {
canDefineLazyValue_1_1_1_defineLazyValue(typePrototype, "_data", function() {
const map = this;
const data = {};
for (const prop in dataInitializers) {
canDefineLazyValue_1_1_1_defineLazyValue(data, prop, dataInitializers[prop].bind(map), true);
}
return data;
});
}
// Places a `_computed` on the prototype that when first called replaces itself
// with a `_computed` object local to the instance. It also defines getters
// that will create the property's compute when read.
if(typePrototype.hasOwnProperty("_computed")) {
for (prop in computedInitializers) {
canDefineLazyValue_1_1_1_defineLazyValue(typePrototype._computed, prop, computedInitializers[prop].bind(typePrototype));
}
} else {
canDefineLazyValue_1_1_1_defineLazyValue(typePrototype, "_computed", function() {
const map = this;
const data = Object.create(null);
for (const prop in computedInitializers) {
canDefineLazyValue_1_1_1_defineLazyValue(data, prop, computedInitializers[prop].bind(map));
}
return data;
});
}
// Add necessary event methods to this object.
getEveryPropertyAndSymbol(eventsProto).forEach(function(prop){
Object.defineProperty(typePrototype, prop, {
enumerable: false,
value: eventsProto[prop],
configurable: true,
writable: true
});
});
// also add any symbols
// add so instance defs can be dynamically added
Object.defineProperty(typePrototype,"_define",{
enumerable: false,
value: result,
configurable: true,
writable: true
});
// Places Symbol.iterator or @@iterator on the prototype
// so that this can be iterated with for/of and canReflect.eachIndex
const iteratorSymbol = Symbol.iterator || Symbol.for("iterator");
if(!typePrototype[iteratorSymbol]) {
defineConfigurableAndNotEnumerable(typePrototype, iteratorSymbol, function(){
return new define.Iterator(this);
});
}
return result;
};
const onlyType = function(obj){
for(const prop in obj) {
if(prop !== "type") {
return false;
}
}
return true;
};
const callAsync = function(fn) {
return function asyncResolver(lastSet, resolve){
let newValue = fn.call(this, resolve, lastSet);
// This should really be happening in can-simple-observable/async/
// But that would be a breaking change so putting it here.
if(canReflect_1_19_2_canReflect.isPromise(newValue)) {
newValue.then(resolve);
return undefined;
}
return newValue;
};
};
define.extensions = function () {};
define.isEnumerable = function(definition) {
return typeof definition !== "object" ||
("serialize" in definition ?
!!definition.serialize :
(!definition.get && !definition.async && !definition.value));
};
// typePrototype - the prototype of the type we are defining `prop` on.
// `definition` - the user provided definition
define.property = function(typePrototype, prop, definition, dataInitializers, computedInitializers, defaultDefinition) {
const propertyDefinition = define.extensions.apply(this, arguments);
if (propertyDefinition) {
definition = makeDefinition(prop, propertyDefinition, defaultDefinition || {}, typePrototype);
}
const type = definition.type;
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
if(!definition.set && definition.get && definition.get.length === 0 && ( "default" in definition ) ) {
dev.warn("can-observable-object: default value for property " +
canReflect_1_19_2_canReflect.getName(typePrototype)+"."+ prop +
" ignored, as its definition has a zero-argument getter and no setter");
}
if(!definition.set && definition.get && definition.get.length === 0 && ( definition.type && definition.type !== defaultDefinition.type ) ) {
dev.warn("can-observable-object: type value for property " +
canReflect_1_19_2_canReflect.getName(typePrototype)+"."+ prop +
" ignored, as its definition has a zero-argument getter and no setter");
}
}
for (let defFuncProp of ['get', 'set', 'value']) {
const propType = definition[defFuncProp] && typeof definition[defFuncProp];
if (propType && propType !== 'function') {
dev.error(`can-observable-object: "${defFuncProp}" for property ${canReflect_1_19_2_canReflect.getName(typePrototype)}.${prop}` +
` is expected to be a function, but it's a ${propType}.`);
return;
}
}
//!steal-remove-end
// Special case definitions that have only `type: "*"`.
if (type && onlyType(definition) && type === type.Any) {
Object_defineNamedPrototypeProperty(typePrototype, prop, {
get: make.get.data(prop),
set: make.set.events(prop, make.get.data(prop), make.set.data(prop), make.eventType.data(prop)),
enumerable: true,
configurable: true
});
return;
}
definition.type = type;
// Where the value is stored. If there is a `get` the source of the value
// will be a compute in `this._computed[prop]`. If not, the source of the
// value will be in `this._data[prop]`.
let dataProperty = definition.get || definition.async || definition.value ? "computed" : "data",
// simple functions that all read/get/set to the right place.
// - reader - reads the value but does not observe.
// - getter - reads the value and notifies observers.
// - setter - sets the value.
reader = make.read[dataProperty](prop),
getter = make.get[dataProperty](prop),
setter = make.set[dataProperty](prop),
getInitialValue;
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
if (definition.get) {
Object.defineProperty(definition.get, "name", {
value: canReflect_1_19_2_canReflect.getName(typePrototype) + "'s " + prop + " getter",
configurable: true
});
}
if (definition.set) {
Object.defineProperty(definition.set, "name", {
value: canReflect_1_19_2_canReflect.getName(typePrototype) + "'s " + prop + " setter",
configurable: true
});
}
if(definition.value) {
Object.defineProperty(definition.value, "name", {
value: canReflect_1_19_2_canReflect.getName(typePrototype) + "'s " + prop + " value",
configurable: true
});
}
}
//!steal-remove-end
// Determine the type converter
let typeConvert = function(val) {
return val;
};
if (type) {
typeConvert = make.set.type(prop, type, typeConvert);
}
// make a setter that's going to fire of events
const eventsSetter = make.set.events(prop, reader, setter, make.eventType[dataProperty](prop));
if(definition.value) {
computedInitializers[prop] = make.resolver(prop, definition, typeConvert);
}
// Determine a function that will provide the initial property value.
else if (definition.default !== undefined) {
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
// If value is an object or array, give a warning
if (definition.default !== null && typeof definition.default === 'object') {
dev.warn("can-observable-object: The default value for " + canReflect_1_19_2_canReflect.getName(typePrototype)+"."+prop + " is set to an object. This will be shared by all instances of the DefineMap. Use a function that returns the object instead.");
}
// If value is a constructor, give a warning
if (definition.default && canReflect_1_19_2_canReflect.isConstructorLike(definition.default)) {
dev.warn("can-observable-object: The \"default\" for " + canReflect_1_19_2_canReflect.getName(typePrototype)+"."+prop + " is set to a constructor. Did you mean \"Default\" instead?");
}
}
//!steal-remove-end
getInitialValue = canObservationRecorder_1_3_1_canObservationRecorder.ignore(make.get.defaultValue(prop, definition, typeConvert, eventsSetter));
}
// If property has a getter, create the compute that stores its data.
if (definition.get) {
computedInitializers[prop] = make.compute(prop, definition.get, getInitialValue);
}
else if (definition.async) {
computedInitializers[prop] = make.compute(prop, callAsync(definition.async), getInitialValue);
}
// If the property isn't a getter, but has an initial value, setup a
// default value on `this._data[prop]`.
else if (getInitialValue) {
dataInitializers[prop] = getInitialValue;
}
// Define setter behavior.
// If there's a `get` and `set`, make the setter get the `lastSetValue` on the
// `get`'s compute.
if (definition.get && definition.set) {
// the compute will set off events, so we can use the basic setter
setter = make.set.setter(prop, definition.set, make.read.lastSet(prop), setter, true);
}
// If there's a `set` and no `get`,
else if (definition.set) {
// Add `set` functionality to the eventSetter.
setter = make.set.setter(prop, definition.set, reader, eventsSetter, false);
}
// If there's neither `set` or `get` or `value` (resolver)
else if (dataProperty === "data") {
// make a set that produces events.
setter = eventsSetter;
}
// If there's zero-arg `get` but not `set`, warn on all sets in dev mode
else if (definition.get && definition.get.length < 1) {
setter = function() {
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
dev.warn("can-observable-object: Set value for property " +
canReflect_1_19_2_canReflect.getName(typePrototype)+"."+ prop +
" ignored, as its definition has a zero-argument getter and no setter");
}
//!steal-remove-end
};
}
// Add type behavior to the setter.
if (type) {
setter = make.set.type(prop, type, setter);
}
// Define the property.
Object_defineNamedPrototypeProperty(typePrototype, prop, {
get: getter,
set: setter,
enumerable: define.isEnumerable(definition),
configurable: true
});
};
define.makeDefineInstanceKey = function(constructor) {
constructor[Symbol.for("can.defineInstanceKey")] = function(property, value) {
define.hooks.finalizeClass(this);
const defineResult = this.prototype._define;
if(value && typeof value.value !== "undefined") {
value.default = value.value;
value.type = canType_1_1_6_canType.Any;
delete value.value;
}
const definition = getDefinitionOrMethod(property, value, defineResult.defaultDefinition, this);
if(definition && typeof definition === "object") {
define.property(this.prototype, property, definition, defineResult.dataInitializers, defineResult.computedInitializers, defineResult.defaultDefinition);
defineResult.definitions[property] = definition;
} else {
defineResult.methods[property] = definition;
}
this.prototype.dispatch({
action: "can.keys",
type: "can.keys",
target: this.prototype
});
};
};
// Makes a simple constructor function.
define.Constructor = function(defines, sealed) {
const constructor = function DefineConstructor(props) {
Object.defineProperty(this, inSetupSymbol$2, {
configurable: true,
enumerable: false,
value: true,
writable: true
});
define.setup.call(this, props, sealed);
this[inSetupSymbol$2] = false;
};
const result = define(constructor.prototype, defines);
type$1(constructor);
define.makeDefineInstanceKey(constructor, result);
return constructor;
};
// A bunch of helper functions that are used to create various behaviors.
make = {
computeObj: function(map, prop, observable) {
const computeObj = {
oldValue: undefined,
compute: observable,
count: 0,
handler: function(newVal) {
let oldValue = computeObj.oldValue;
computeObj.oldValue = newVal;
map.dispatch({
action: "prop",
key: prop,
value: newVal,
oldValue: oldValue,
type: prop,
target: map
}, [newVal, oldValue]);
}
};
return computeObj;
},
resolver: function(prop, definition, typeConvert) {
const getDefault = make.get.defaultValue(prop, definition, typeConvert);
return function(){
const map = this;
const defaultValue = getDefault.call(this);
const computeObj = make.computeObj(map, prop, new resolver(definition.value, map, defaultValue, {
resetUnboundValueInGet: true
}));
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
Object.defineProperty(computeObj.handler, "name", {
value: canReflect_1_19_2_canReflect.getName(definition.value).replace('value', 'event emitter')
});
}
//!steal-remove-end
return computeObj;
};
},
// Returns a function that creates the `_computed` prop.
compute: function(prop, get, defaultValueFn) {
return function() {
const map = this;
const defaultValue = defaultValueFn && defaultValueFn.call(this);
let observable, computeObj;
if(get.length === 0) {
observable = new canObservation_4_2_0_canObservation(get, map);
} else if(get.length === 1) {
observable = new settable(get, map, defaultValue);
} else {
observable = new async(get, map, defaultValue);
}
computeObj = make.computeObj(map, prop, observable);
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
Object.defineProperty(computeObj.handler, "name", {
value: canReflect_1_19_2_canReflect.getName(get).replace('getter', 'event emitter')
});
}
//!steal-remove-end
return computeObj;
};
},
// Set related helpers.
set: {
data: function(prop) {
return function(newVal) {
this._data[prop] = newVal;
};
},
computed: function(prop) {
return function(val) {
canReflect_1_19_2_canReflect.setValue( this._computed[prop].compute, val );
};
},
events: function(prop, getCurrent, setData/*, eventType*/) {
return function(newVal) {
if (this[inSetupSymbol$2]) {
setData.call(this, newVal);
}
else {
const current = getCurrent.call(this);
if (newVal !== current) {
let dispatched;
setData.call(this, newVal);
dispatched = {
patches: [{type: "set", key: prop, value: newVal}],
action: "prop",
key: prop,
value: newVal,
oldValue: current,
type: prop,
target: this
};
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
dispatched.reasonLog = [ canReflect_1_19_2_canReflect.getName(this) + "'s", prop, "changed to", newVal, "from", current ];
}
//!steal-remove-end
this.dispatch(dispatched, [newVal, current]);
}
}
};
},
eventDispatcher: function(map, prop, current, newVal) {
if (map[inSetupSymbol$2]) {
return;
}
else {
if (newVal !== current) {
const dispatched = {
patches: [{type: "set", key: prop, value: newVal}],
action: "prop",
key: prop,
value: newVal,
oldValue: current,
type: prop,
target: map
};
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
dispatched.reasonLog = [ canReflect_1_19_2_canReflect.getName(this) + "'s", prop, "changed to", newVal, "from", current ];
}
//!steal-remove-end
map$1.dispatch.call(map, dispatched, [newVal, current]);
}
}
},
setter: function(prop, setter, getCurrent, setEvents, hasGetter) {
return function(value) {
//!steal-remove-start
var asyncTimer;
//!steal-remove-end
const self = this;
// call the setter, if returned value is undefined,
// this means the setter is async so we
// do not call update property and return right away
canQueues_1_3_2_canQueues.batch.start();
const setterCalled = false,
current = getCurrent.call(this),
setValue = setter.call(this, value, current);
if (setterCalled) {
canQueues_1_3_2_canQueues.batch.stop();
} else {
if (hasGetter) {
// we got a return value
if (setValue !== undefined) {
// if the current `set` value is returned, don't set
// because current might be the `lastSetVal` of the internal compute.
if (current !== setValue) {
setEvents.call(this, setValue);
}
canQueues_1_3_2_canQueues.batch.stop();
}
// this is a side effect, it didn't take a value
// so use the original set value
else if (setter.length === 0) {
setEvents.call(this, value);
canQueues_1_3_2_canQueues.batch.stop();
return;
}
// it took a value
else if (setter.length === 1) {
// if we have a getter, and undefined was returned,
// we should assume this is setting the getters properties
// and we shouldn't do anything.
canQueues_1_3_2_canQueues.batch.stop();
}
// we are expecting something
else {
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
asyncTimer = setTimeout(function() {
dev.warn('can-observable-object: Setter "' + canReflect_1_19_2_canReflect.getName(self)+"."+prop + '" did not return a value or call the setter callback.');
}, dev.warnTimeout);
}
//!steal-remove-end
canQueues_1_3_2_canQueues.batch.stop();
return;
}
} else {
// we got a return value
if (setValue !== undefined) {
// if the current `set` value is returned, don't set
// because current might be the `lastSetVal` of the internal compute.
setEvents.call(this, setValue);
canQueues_1_3_2_canQueues.batch.stop();
}
// this is a side effect, it didn't take a value
// so use the original set value
else if (setter.length === 0) {
setEvents.call(this, value);
canQueues_1_3_2_canQueues.batch.stop();
return;
}
// it took a value
else if (setter.length === 1) {
// if we don't have a getter, we should probably be setting the
// value to undefined
setEvents.call(this, undefined);
canQueues_1_3_2_canQueues.batch.stop();
}
// we are expecting something
else {
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
asyncTimer = setTimeout(function() {
dev.warn('can/map/setter.js: Setter "' + canReflect_1_19_2_canReflect.getName(self)+"."+prop + '" did not return a value or call the setter callback.');
}, dev.warnTimeout);
}
//!steal-remove-end
canQueues_1_3_2_canQueues.batch.stop();
return;
}
}
}
};
},
type: function(prop, type, set) {
function setter(newValue) {
return set.call(this, type.call(this, newValue, prop));
}
if(isDefineType(type)) {
// TODO: remove this `canDefineType` check in a future release.
if(type.canDefineType) {
return setter;
} else {
return function setter(newValue){
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
try {
return set.call(this, canReflect_1_19_2_canReflect.convert(newValue, type));
} catch (error) {
if (error.type === 'can-type-error') {
const typeName = canReflect_1_19_2_canReflect.getName(type[baseTypeSymbol]);
const valueType = typeof newValue;
let message = '"' + newValue + '"' + ' ('+ valueType + ') is not of type ' + typeName + '. Property ' + prop + ' is using "type: ' + typeName + '". ';
message += 'Use "' + prop + ': type.convert(' + typeName + ')" to automatically convert values to ' + typeName + 's when setting the "' + prop + '" property.';
error.message = message;
}
throw error;
}
}
//!steal-remove-end
return set.call(this, canReflect_1_19_2_canReflect.convert(newValue, type));
};
}
}
return setter;
}
},
// Helpes that indicate what the event type should be. These probably aren't needed.
eventType: {
data: function(prop) {
return function(newVal, oldVal) {
return oldVal !== undefined || this._data.hasOwnProperty(prop) ? "set" : "add";
};
},
computed: function() {
return function() {
return "set";
};
}
},
// Helpers that read the data in a non-observable way.
read: {
data: function(prop) {
return function() {
return this._data[prop];
};
},
computed: function(prop) {
// might want to protect this
return function() {
return canReflect_1_19_2_canReflect.getValue( this._computed[prop].compute );
};
},
lastSet: function(prop) {
return function() {
const observable = this._computed[prop].compute;
if(observable.lastSetValue) {
return canReflect_1_19_2_canReflect.getValue(observable.lastSetValue);
}
};
}
},
// Helpers that read the data in an observable way.
get: {
// uses the default value
defaultValue: function(prop, definition, typeConvert, callSetter) {
return function() {
let value = definition.default;
if (value !== undefined) {
// call `get default() { ... }` but not `default() { ... }`
if (typeof value === "function" && value.isAGetter) {
value = value.call(this);
}
value = typeConvert.call(this, value);
}
if(definition.set) {
// TODO: there's almost certainly a faster way of making this happen
// But this is maintainable.
let VALUE;
let sync = true;
const setter = make.set.setter(prop, definition.set, function(){}, function(value){
if(sync) {
VALUE = value;
} else {
callSetter.call(this, value);
}
}, definition.get);
setter.call(this,value);
sync = false;
// VALUE will be undefined if the callback is never called.
return VALUE;
}
return value;
};
},
data: function(prop) {
return function() {
if (!this[inSetupSymbol$2]) {
canObservationRecorder_1_3_1_canObservationRecorder.add(this, prop);
}
return this._data[prop];
};
},
computed: function(prop) {
return function(/*val*/) {
const compute = this._computed[prop].compute;
if (canObservationRecorder_1_3_1_canObservationRecorder.isRecording()) {
canObservationRecorder_1_3_1_canObservationRecorder.add(this, prop);
if (!canReflect_1_19_2_canReflect.isBound(compute)) {
canObservation_4_2_0_canObservation.temporarilyBind(compute);
}
}
return peek$2(compute);
};
}
}
};
define.behaviors = ["get", "set", "value", "type", "serialize"];
// This cleans up a particular behavior and adds it to the definition
const addBehaviorToDefinition = function(definition, behavior, descriptor, def, prop, typePrototype) {
if(behavior === "enumerable") {
// treat enumerable like serialize
definition.serialize = !!def[behavior];
}
else if(behavior === "type") {
const behaviorDef = def[behavior];
if (typeof behaviorDef !== 'undefined') {
definition[behavior] = behaviorDef;
}
}
else {
// This is a good place to do warnings? This gets called for every behavior
// Both by .define() and .property()
const value = descriptor.get || descriptor.value;
if (descriptor.get) {
value.isAGetter = true;
}
if(behavior === "async") {
if(value.length === 1 && isAsyncFunction(value)) {
dev.warn(`${canReflect_1_19_2_canReflect.getName(typePrototype)}: async property [${prop}] should not be an async function and also use the resolve() argument. Remove the argument and return a value from the async function instead.`);
}
}
definition[behavior] = value;
}
};
// This is called by `define.property` AND `getDefinitionOrMethod` (which is called by `define`)
// Currently, this is adding default behavior
// copying `type` over, and even cleaning up the final definition object
makeDefinition = function(prop, def, defaultDefinition, typePrototype) {
let definition = {};
eachPropertyDescriptor(def, function(behavior, descriptor) {
addBehaviorToDefinition(definition, behavior, descriptor, def, prop, typePrototype);
});
// only add default if it doesn't exist
canReflect_1_19_2_canReflect.eachKey(defaultDefinition, function(value, prop){
if(definition[prop] === undefined) {
if(prop !== "type") {
definition[prop] = value;
}
}
});
if (def.type) {
const value = def.type;
const serialize = value[serializeSymbol];
if(serialize) {
definition.serialize = function(val){
return serialize.call(val);
};
}
definition.type = canType_1_1_6_canType.normalize(value);
}
const noTypeDefined = !definition.type && (!defaultDefinition.type ||
defaultDefinition.type && defaultDefinition.typeSetByDefault);
if (definition.hasOwnProperty("default")) {
if (typeof definition.default === "function" && !definition.default.isAGetter && noTypeDefined) {
definition.type = canType_1_1_6_canType.normalize(Function);
}
if (canReflect_1_19_2_canReflect.isPrimitive(definition.default) && noTypeDefined) {
if (definition.default === null || typeof definition.default === 'undefined') {
definition.type = canType_1_1_6_canType.Any;
} else {
definition.type = canType_1_1_6_canType.normalize(definition.default.constructor);
}
}
}
// if there's no type definition, take it from the defaultDefinition
if(!definition.type) {
const defaultsCopy = canReflect_1_19_2_canReflect.assignMap({}, defaultDefinition);
definition = canReflect_1_19_2_canReflect.assignMap(defaultsCopy, definition);
}
if(canReflect_1_19_2_canReflect.size(definition) === 0) {
definition.type = canType_1_1_6_canType.Any;
// `setByDefault` indicates that the default type can be
// overridden by an inferred type
definition.typeSetByDefault = true;
}
return definition;
};
// called by `can.defineInstanceKey` and `getDefinitionsAndMethods`
// returns the value or the definition object.
// calls makeDefinition
// This is dealing with a string value
getDefinitionOrMethod = function(prop, value, defaultDefinition, typePrototype){
// Clean up the value to make it a definition-like object
let definition;
let definitionType;
if(canReflect_1_19_2_canReflect.isPrimitive(value)) {
if (value === null || typeof value === 'undefined') {
definitionType = canType_1_1_6_canType.Any;
} else {
// only include type from defaultDefininition
// if it came from propertyDefaults
definitionType = defaultDefinition.typeSetByDefault ?
canType_1_1_6_canType.normalize(value.constructor) :
defaultDefinition.type;
}
definition = {
default: value,
type: definitionType
};
}
// copies a `Type`'s methods over
else if(value && (value[serializeSymbol] || value[newSymbol$1]) ) {
if(value[isMemberSymbol$1]) {
definition = { type: value };
} else {
definition = { type: canType_1_1_6_canType.normalize(value) };
}
}
else if(typeof value === "function") {
if(canReflect_1_19_2_canReflect.isConstructorLike(value)) {
definition = { type: canType_1_1_6_canType.normalize(value) };
} else {
definition = { default: value, type: Function };
}
} else if( Array.isArray(value) ) {
definition = { type: canType_1_1_6_canType.normalize(Array) };
} else if( canReflect_1_19_2_canReflect.isPlainObject(value) ){
definition = value;
}
if(definition) {
return makeDefinition(prop, definition, defaultDefinition, typePrototype);
}
else {
return value;
}
};
// called by can.define
getDefinitionsAndMethods = function(defines, baseDefines, typePrototype, propertyDefaults) {
// make it so the definitions include base definitions on the proto
const definitions = Object.create(baseDefines ? baseDefines.definitions : null);
let methods = {};
// first lets get a default if it exists
let defaultDefinition;
if(propertyDefaults) {
defaultDefinition = getDefinitionOrMethod("*", propertyDefaults, {}, typePrototype);
} else {
defaultDefinition = Object.create(null);
}
function addDefinition(prop, propertyDescriptor, skipGetDefinitionForMethods) {
let value;
if(propertyDescriptor.get || propertyDescriptor.set) {
value = { get: propertyDescriptor.get, set: propertyDescriptor.set };
} else {
value = propertyDescriptor.value;
}
if(prop === "constructor" || skipGetDefinitionForMethods && typeof value === "function") {
methods[prop] = value;
return;
} else {
const result = getDefinitionOrMethod(prop, value, defaultDefinition, typePrototype);
const resultType = typeof result;
if(result && resultType === "object" && canReflect_1_19_2_canReflect.size(result) > 0) {
definitions[prop] = result;
}
else {
// Removed adding raw values that are not functions
if (resultType === "function") {
methods[prop] = result;
}
//!steal-remove-start
else if (resultType !== 'undefined') {
if(process.env.NODE_ENV !== 'production') {
// Ex: {prop: 0}
dev.error(canReflect_1_19_2_canReflect.getName(typePrototype)+"."+prop + " does not match a supported definitionObject. See: https://canjs.com/doc/can-observable-object/object.types.definitionObject.html");
}
}
//!steal-remove-end
}
}
}
eachPropertyDescriptor(typePrototype, addDefinition, true);
eachPropertyDescriptor(defines, addDefinition);
if(propertyDefaults) {
// we should move this property off the prototype.
defineConfigurableAndNotEnumerable(defines, "*", propertyDefaults);
}
return { definitions: definitions, methods: methods, defaultDefinition: defaultDefinition };
};
eventsProto = map$1({});
function setupComputed(instance, eventName) {
const computedBinding = instance._computed && instance._computed[eventName];
if (computedBinding && computedBinding.compute) {
if (!computedBinding.count) {
computedBinding.count = 1;
canReflect_1_19_2_canReflect.onValue(computedBinding.compute, computedBinding.handler, "notify");
computedBinding.oldValue = peek$2(computedBinding.compute);
} else {
computedBinding.count++;
}
}
}
function teardownComputed(instance, eventName){
const computedBinding = instance._computed && instance._computed[eventName];
if (computedBinding) {
if (computedBinding.count === 1) {
computedBinding.count = 0;
canReflect_1_19_2_canReflect.offValue(computedBinding.compute, computedBinding.handler,"notify");
} else {
computedBinding.count--;
}
}
}
canAssign_1_3_3_canAssign(eventsProto, {
_eventSetup: function() {},
_eventTeardown: function() {},
addEventListener: function(eventName/*, handler, queue*/) {
setupComputed(this, eventName);
return map$1.addEventListener.apply(this, arguments);
},
// ### unbind
// Stops listening to an event.
// If this is the last listener of a computed property,
// stop forwarding events of the computed property to this map.
removeEventListener: function(eventName/*, handler*/) {
teardownComputed(this, eventName);
return map$1.removeEventListener.apply(this, arguments);
}
});
eventsProto.on = eventsProto.bind = eventsProto.addEventListener;
eventsProto.off = eventsProto.unbind = eventsProto.removeEventListener;
const onKeyValueSymbol$2 = Symbol.for("can.onKeyValue");
const offKeyValueSymbol$1 = Symbol.for("can.offKeyValue");
canReflect_1_19_2_canReflect.assignSymbols(eventsProto,{
"can.onKeyValue": function(key){
setupComputed(this, key);
return map$1[onKeyValueSymbol$2].apply(this, arguments);
},
"can.offKeyValue": function(key){
teardownComputed(this, key);
return map$1[offKeyValueSymbol$1].apply(this, arguments);
}
});
delete eventsProto.one;
define.finalizeInstance = function() {
defineNotWritableAndNotEnumerable(this, "constructor", this.constructor);
defineNotWritableAndNotEnumerable(this, canMetaSymbol, Object.create(null));
};
define.setup = function(props, sealed) {
const requiredButNotProvided = new Set(this._define.required);
const definitions = this._define.definitions;
const instanceDefinitions = Object.create(null);
const map = this;
canReflect_1_19_2_canReflect.eachKey(props, function(value, prop){
if(requiredButNotProvided.has(prop)) {
requiredButNotProvided.delete(prop);
}
if(definitions[prop] !== undefined) {
map[prop] = value;
} else {
if(sealed) {
throw new Error(`The type ${canReflect_1_19_2_canReflect.getName(map.constructor)} is sealed, but the property [${prop}] has no definition.`);
}
define.expando(map, prop, value);
}
});
if(canReflect_1_19_2_canReflect.size(instanceDefinitions) > 0) {
defineConfigurableAndNotEnumerable(this, "_instanceDefinitions", instanceDefinitions);
}
if(requiredButNotProvided.size) {
let msg;
const missingProps = Array.from(requiredButNotProvided);
let thisName = canReflect_1_19_2_canReflect.getName(this);
if(requiredButNotProvided.size === 1) {
msg = `${thisName}: Missing required property [${missingProps[0]}].`;
} else {
msg = `${thisName}: Missing required properties [${missingProps.join(", ")}].`;
}
throw new Error(msg);
}
};
const returnFirstArg = function(arg){
return arg;
};
// TODO Why is this exported, does it need to be?
define.normalizeTypeDefinition = canType_1_1_6_canType.normalize;
define.expando = function(map, prop, value) {
if(define._specialKeys[prop]) {
// ignores _data and _computed
return true;
}
// first check if it's already a constructor define
const constructorDefines = map._define.definitions;
if(constructorDefines && constructorDefines[prop]) {
return;
}
// next if it's already on this instances
let instanceDefines = map._instanceDefinitions;
if(!instanceDefines) {
if(Object.isSealed(map)) {
let errorMessage = `Cannot set property [${prop}] on sealed instance of ${canReflect_1_19_2_canReflect.getName(map)}`;
throw new Error(errorMessage);
}
Object.defineProperty(map, "_instanceDefinitions", {
configurable: true,
enumerable: false,
writable: true,
value: {}
});
instanceDefines = map._instanceDefinitions;
}
if(!instanceDefines[prop]) {
const defaultDefinition = map._define.defaultDefinition || { type: observableType };
define.property(map, prop, defaultDefinition, {},{});
// possibly convert value to List or DefineMap
if(defaultDefinition.type) {
map._data[prop] = define.make.set.type(prop, defaultDefinition.type, returnFirstArg).call(map, value);
} else {
map._data[prop] = observableType(value);
}
instanceDefines[prop] = defaultDefinition;
if(!map[inSetupSymbol$2]) {
canQueues_1_3_2_canQueues.batch.start();
map.dispatch({
action: "can.keys",
type: "can.keys",
target: map
});
if(Object.prototype.hasOwnProperty.call(map._data, prop)) {
map.dispatch({
action: "add",
key: prop,
type: prop,
value: map._data[prop],
target: map,
patches: [{type: "add", key: prop, value: map._data[prop]}],
},[map._data[prop], undefined]);
} else {
map.dispatch({
action: "set",
type: "set",
value: map._data[prop],
target: map,
patches: [{type: "add", key: prop, value: map._data[prop]}],
},[map._data[prop], undefined]);
}
canQueues_1_3_2_canQueues.batch.stop();
}
return true;
}
};
define.replaceWith = canDefineLazyValue_1_1_1_defineLazyValue;
define.eventsProto = eventsProto;
define.defineConfigurableAndNotEnumerable = defineConfigurableAndNotEnumerable;
define.make = make;
define.getDefinitionOrMethod = getDefinitionOrMethod;
define._specialKeys = {_data: true, _computed: true};
let simpleGetterSetters = {};
define.makeSimpleGetterSetter = function(prop){
if(simpleGetterSetters[prop] === undefined) {
const setter = make.set.events(prop, make.get.data(prop), make.set.data(prop), make.eventType.data(prop) );
simpleGetterSetters[prop] = {
get: make.get.data(prop),
set: function(newVal){
return setter.call(this, observableType(newVal));
},
enumerable: true,
configurable: true
};
}
return simpleGetterSetters[prop];
};
define.Iterator = function(obj){
this.obj = obj;
this.definitions = Object.keys(obj._define.definitions);
this.instanceDefinitions = obj._instanceDefinitions ?
Object.keys(obj._instanceDefinitions) :
Object.keys(obj);
this.hasGet = typeof obj.get === "function";
};
define.Iterator.prototype.next = function(){
let key;
if(this.definitions.length) {
key = this.definitions.shift();
// Getters should not be enumerable
const def = this.obj._define.definitions[key];
if(def.get) {
return this.next();
}
} else if(this.instanceDefinitions.length) {
key = this.instanceDefinitions.shift();
} else {
return {
value: undefined,
done: true
};
}
return {
value: [
key,
this.hasGet ? this.obj.get(key) : this.obj[key]
],
done: false
};
};
define.updateSchemaKeys = function(schema, definitions) {
for(const prop in definitions) {
const definition = definitions[prop];
if(definition.serialize !== false ) {
if(definition.type) {
schema.keys[prop] = definition.type;
} else {
schema.keys[prop] = function(val){ return val; };
}
// some unknown type
if(definitions[prop].identity === true) {
schema.identity.push(prop);
}
}
}
return schema;
};
define.hooks = {
finalizeClass: function(Type) {
let hasBeenDefined = Type.hasOwnProperty(hasBeenDefinedSymbol);
if(!hasBeenDefined) {
let prototypeObject = Type.prototype;
// check for `static props = {}`
// fall back to `static define = {}` if `props` doesn't exist
let defines = typeof Type.props === "object" ?
Type.props :
typeof Type.define === "object" ?
Type.define :
{};
define(prototypeObject, defines, null, Type.propertyDefaults);
Type[hasBeenDefinedSymbol] = true;
}
},
initialize: function(instance, props) {
const firstInitialize = !instance.hasOwnProperty(canMetaSymbol);
const sealed = instance.constructor.seal;
if (firstInitialize) {
define.finalizeInstance.call(instance);
}
if (!instance[canMetaSymbol].initialized) {
defineConfigurableAndNotEnumerable(instance, inSetupSymbol$2, true);
define.setup.call(instance, props, sealed);
// set inSetup to false so events can be dispatched
instance[inSetupSymbol$2] = false;
// set instance as initialized so this is only called once
instance[canMetaSymbol].initialized = true;
}
// only seal in dev mode for performance reasons.
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
// only seal the first time initialize is called
// even if meta.initialized is reset to false
if (firstInitialize) {
/* jshint -W030 */
instance._data;
instance._computed;
if(sealed === true) {
Object.seal(instance);
}
}
}
//!steal-remove-end
},
expando: define.expando,
normalizeTypeDefinition: canType_1_1_6_canType.normalize //define.normalizeTypeDefinition
};
// Ensure the "obj" passed as an argument has an object on @@can.meta
var ensureMeta$3 = function ensureMeta(obj) {
const metaSymbol = Symbol.for("can.meta");
let meta = obj[metaSymbol];
if (!meta) {
meta = {};
canReflect_1_19_2_canReflect.setKeyValue(obj, metaSymbol, meta);
}
return meta;
};
/*jshint -W079 */
const defineHelpers = {
// returns `true` if the value was defined and set
defineExpando: define_1.expando,
reflectSerialize: function(unwrapped){
const constructorDefinitions = this._define.definitions;
const defaultDefinition = this._define.defaultDefinition;
this.forEach(function(val, name){
const propDef = constructorDefinitions[name];
if(propDef && typeof propDef.serialize === "function") {
val = propDef.serialize.call(this, val, name);
}
else if(defaultDefinition && typeof defaultDefinition.serialize === "function") {
val = defaultDefinition.serialize.call(this, val, name);
} else {
val = canReflect_1_19_2_canReflect.serialize(val);
}
if(val !== undefined) {
unwrapped[name] = val;
}
}, this);
return unwrapped;
},
reflectUnwrap: function(unwrapped){
this.forEach(function(value, key){
if(value !== undefined) {
unwrapped[key] = canReflect_1_19_2_canReflect.unwrap(value);
}
});
return unwrapped;
},
log: function(key) {
const instance = this;
const quoteString = function quoteString(x) {
return typeof x === "string" ? JSON.stringify(x) : x;
};
const meta = ensureMeta$3(instance);
const allowed = meta.allowedLogKeysSet || new Set();
meta.allowedLogKeysSet = allowed;
if (key) {
allowed.add(key);
}
meta._log = function(event, data) {
const type = event.type;
if (
type === "can.onPatches" || (key && !allowed.has(type)) ||
type === "can.keys" || (key && !allowed.has(type))
) {
return;
}
if (type === "add" || type === "remove") {
dev.log(
canReflect_1_19_2_canReflect.getName(instance),
"\n how ", quoteString(type),
"\n what ", quoteString(data[0]),
"\n index ", quoteString(data[1])
);
} else {
// log `length` and `propertyName` events
dev.log(
canReflect_1_19_2_canReflect.getName(instance),
"\n key ", quoteString(type),
"\n is ", quoteString(data[0]),
"\n was ", quoteString(data[1])
);
}
};
},
deleteKey: function(prop){
const instanceDefines = this._instanceDefinitions;
if(instanceDefines && Object.prototype.hasOwnProperty.call(instanceDefines, prop) && !Object.isSealed(this)) {
delete instanceDefines[prop];
delete this[prop];
canQueues_1_3_2_canQueues.batch.start();
this.dispatch({
action: "can.keys",
type: "can.keys",
target: this
});
const oldValue = this._data[prop];
if(oldValue !== undefined) {
delete this._data[prop];
//delete this[prop];
this.dispatch({
action: "delete",
key: prop,
oldValue: oldValue,
type: prop,
target: this,
patches: [{type: "delete", key: prop}],
},[undefined,oldValue]);
}
canQueues_1_3_2_canQueues.batch.stop();
} else {
this.set(prop, undefined);
}
return this;
}
};
var defineHelpers_1 = defineHelpers;
const { updateSchemaKeys, hooks, isEnumerable } = define_1;
const getSchemaSymbol$1 = Symbol.for("can.getSchema");
function keysForDefinition(definitions) {
const keys = [];
for(let prop in definitions) {
if(isEnumerable(definitions[prop])) {
keys.push(prop);
}
}
return keys;
}
function assign(source) {
canQueues_1_3_2_canQueues.batch.start();
canReflect_1_19_2_canReflect.assignMap(this, source || {});
canQueues_1_3_2_canQueues.batch.stop();
}
function update(source) {
canQueues_1_3_2_canQueues.batch.start();
if (canReflect_1_19_2_canReflect.isListLike(source)) {
canReflect_1_19_2_canReflect.updateList(this, source);
} else {
canReflect_1_19_2_canReflect.updateMap(this, source || {});
}
canQueues_1_3_2_canQueues.batch.stop();
}
function assignDeep(source){
canQueues_1_3_2_canQueues.batch.start();
// TODO: we should probably just throw an error instead of cleaning
canReflect_1_19_2_canReflect.assignDeepMap(this, source || {});
canQueues_1_3_2_canQueues.batch.stop();
}
function updateDeep(source){
canQueues_1_3_2_canQueues.batch.start();
if (canReflect_1_19_2_canReflect.isListLike(source)) {
canReflect_1_19_2_canReflect.updateDeepList(this, source);
} else {
// TODO: we should probably just throw an error instead of cleaning
canReflect_1_19_2_canReflect.updateDeepMap(this, source || {});
}
canQueues_1_3_2_canQueues.batch.stop();
}
function setKeyValue(key, value) {
const defined = defineHelpers_1.defineExpando(this, key, value);
if(!defined) {
this[key] = value;
}
}
function getKeyValue(key) {
const value = this[key];
if(value !== undefined || key in this || Object.isSealed(this)) {
return value;
} else {
canObservationRecorder_1_3_1_canObservationRecorder.add(this, key);
return this[key];
}
}
var mixinMapprops = function(Type) {
return class extends Type {
static [getSchemaSymbol$1]() {
hooks.finalizeClass(this);
let def = this.prototype._define;
let definitions = def ? def.definitions : {};
let schema = {
type: "map",
identity: [],
keys: {}
};
return updateSchemaKeys(schema, definitions);
}
get(prop){
if(prop) {
return getKeyValue.call(this, prop);
} else {
return canReflect_1_19_2_canReflect.unwrap(this, Map);
}
}
set(prop, value){
if(typeof prop === "object") {
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
dev.warn('can-define/map/map.prototype.set is deprecated; please use can-define/map/map.prototype.assign or can-define/map/map.prototype.update instead');
}
//!steal-remove-end
if(value === true) {
updateDeep.call(this, prop);
} else {
assignDeep.call(this, prop);
}
} else {
setKeyValue.call(this, prop, value);
}
return this;
}
assignDeep(prop) {
assignDeep.call(this, prop);
return this;
}
updateDeep(prop) {
updateDeep.call(this, prop);
return this;
}
assign(prop) {
assign.call(this, prop);
return this;
}
update(prop) {
update.call(this, prop);
return this;
}
serialize () {
return canReflect_1_19_2_canReflect.serialize(this, Map);
}
deleteKey() {
return defineHelpers_1.deleteKey.apply(this, arguments);
}
forEach(cb, thisarg, observe) {
function forEach(list, cb, thisarg){
return canReflect_1_19_2_canReflect.eachKey(list, cb, thisarg);
}
if(observe === false) {
canObservationRecorder_1_3_1_canObservationRecorder.ignore(forEach)(this, cb, thisarg);
} else {
return forEach(this, cb, thisarg);
}
}
static [Symbol.for("can.new")](...args) {
return new this(...args);
}
get [Symbol.for("can.isMapLike")]() {
return true;
}
get [Symbol.for("can.isListLike")]() {
return false;
}
get [Symbol.for("can.isValueLike")]() {
return false;
}
[Symbol.for("can.getKeyValue")](...args) {
return getKeyValue.apply(this, args);
}
[Symbol.for("can.deleteKeyValue")](...args) {
return defineHelpers_1.deleteKey.call(this, ...args);
}
[Symbol.for("can.getOwnKeys")]() {
const keys = canReflect_1_19_2_canReflect.getOwnEnumerableKeys(this);
if(this._computed) {
const computedKeys = canReflect_1_19_2_canReflect.getOwnKeys(this._computed);
let key;
for (let i=0; i= 0) {
return Reflect.defineProperty(target, prop, descriptor);
}
if (value) {
// do not create expando properties for properties that are described
// by `static props` or `static propertyDefaults`
if (props && props[prop] || target.constructor.propertyDefaults) {
target.set(prop, value);
return true;
}
// create expandos to make all other properties observable
return mixins$1.expando(target, prop, value);
}
// Prevent dispatching more than one event with canReflect.setKeyValue
return Reflect.defineProperty(target, prop, descriptor);
}
});
// Adding the instance to observable-mixin
// prevents additional event dispatching
// https://github.com/canjs/can-observable-object/issues/35
this.constructor.instances.add(proxiedInstance);
return proxiedInstance;
}
};
ObservableObject = mixinTypeEvents$1(mixinMapProps(ObservableObject));
makeDefineInstanceKey$2(ObservableObject);
// Export a constructor function to workaround an issue where ES2015 classes
// cannot be extended in code that's transpiled by Babel.
var canObservableObject = canNamespace_1_0_0_canNamespace.ObservableObject = createConstructorFunction$1(
ObservableObject
);
const { mixins: mixins$2 } = mixins;
const metaSymbol$3 = Symbol.for("can.meta");
const helpers$1 = {
assignNonEnumerable: function(obj, key, value) {
return Object.defineProperty(obj, key, {
enumerable: false,
writable: true,
configurable: true,
value: value
});
},
shouldRecordObservationOnAllKeysExceptFunctionsOnProto: function(keyInfo, meta){
return meta.preventSideEffects === 0 && !keyInfo.isAccessor && (
// it's on us
(// it's on our proto, but not a function
(keyInfo.targetHasOwnKey ) ||
// it's "missing", and we are not sealed
(!keyInfo.protoHasKey && !Object.isSealed(meta.target)) || keyInfo.protoHasKey && (typeof targetValue !== "function"))
);
},
/*
* dispatch an event when an index changes
*/
dispatchIndexEvent: function(attr, how, newVal, oldVal) {
var index = +attr;
// Make sure this is not nested and not an expando
if (!isNaN(index)) {
var itemsDefinition = this._define.definitions["#"];
if (how === 'set') {
this.dispatch({
type: index,
action: how,
key: index,
value: newVal,
oldValue: oldVal
}, [ newVal, oldVal ]);
// if event is being set through an ObservableArray.prototype method,
// do not dispatch length or patch events.
// This will be handled by ObservableArray.prototype method.
let meta = this[metaSymbol$3];
if (!("preventSideEffects" in meta) || meta.preventSideEffects === 0) {
let patches = [{
index: index,
deleteCount: 1,
insert: [ newVal ],
type: "splice"
}];
helpers$1.dispatchLengthPatch.call(this, how, patches, this.length, this.length);
}
} else if (how === 'add') {
if (itemsDefinition && typeof itemsDefinition.added === 'function') {
canObservationRecorder_1_3_1_canObservationRecorder.ignore(itemsDefinition.added).call(this, newVal, index);
}
this.dispatch({
type: index,
action: how,
key: index,
value: newVal,
oldValue: oldVal
}, [ newVal, oldVal ]);
// if event is being set through an ObservableArray.prototype method,
// do not dispatch length or patch events.
// This will be handled by ObservableArray.prototype method.
let meta = this[metaSymbol$3];
if (!("preventSideEffects" in meta) || meta.preventSideEffects === 0) {
let patches = [{
index: index,
deleteCount: 0,
insert: [ newVal ],
type: "splice"
}];
helpers$1.dispatchLengthPatch.call(this, how, patches, this.length, this.length - 1);
}
} else if (how === 'remove') {
if (itemsDefinition && typeof itemsDefinition.removed === 'function') {
canObservationRecorder_1_3_1_canObservationRecorder.ignore(itemsDefinition.removed).call(this, oldVal, index);
}
}
} else {
var key = "" + attr;
this.dispatch({
type: key,
key: key,
action: how,
value: newVal,
oldValue: oldVal,
target: this
}, [ newVal, oldVal ]);
}
},
/*
* Dispatch a `type: "splice"` patch and a `length` event
*/
dispatchLengthPatch: function(how, patches, newLength, oldLength) {
const dispatchArgs = {
type: "length",
key: "length",
action: how,
value: newLength,
oldValue: oldLength,
patches: patches
};
//!steal-remove-start
if(process.env.NODE_ENV !== "production") {
dispatchArgs.reasonLog = [canReflect_1_19_2_canReflect.getName(this) + "." + how + " called with", arguments];
}
//!steal-remove-end
map$1.dispatch.call(this, dispatchArgs, [newLength, oldLength]);
},
convertItem: function(Constructor, item) {
if(Constructor.items) {
const definition = mixins$2.normalizeTypeDefinition(Constructor.items.type || Constructor.items);
return canReflect_1_19_2_canReflect.convert(item, definition);
}
return item;
},
convertItems: function(Constructor, items) {
if(items.length) {
if(Constructor.items) {
for(let i = 0, len = items.length; i < len; i++) {
items[i] = helpers$1.convertItem(Constructor, items[i]);
}
}
}
return items;
}
};
var helpers_1$1 = helpers$1;
var canMeta = Symbol.for("can.meta");
const computedPropertyDefinitionSymbol = Symbol.for("can.computedPropertyDefinitions");
const onKeyValueSymbol$3 = Symbol.for("can.onKeyValue");
const offKeyValueSymbol$2 = Symbol.for("can.offKeyValue");
// ## ComputedObjectObservationData
// Instances of this are created to wrap the observation.
// The `.bind` and `.unbind` methods should be called when the
// instance's prop is bound or unbound.
function ComputedObjectObservationData(instance, prop, observation){
this.instance = instance;
this.prop = prop;
this.observation = observation;
this.forward = this.forward.bind(this);
}
ComputedObjectObservationData.prototype.bind = function(){
this.bindingCount++;
if(this.bindingCount === 1) {
this.observation.on(this.forward, "notify");
}
};
ComputedObjectObservationData.prototype.unbind = function(){
this.bindingCount--;
if(this.bindingCount === 0) {
this.observation.off(this.forward, "notify");
}
};
ComputedObjectObservationData.prototype.forward = function(newValue, oldValue){
map$1.dispatch.call(this.instance, {
type: this.prop,
key: this.prop,
target: this.instance,
value: newValue,
oldValue: oldValue
// patches: [{
// key: this.prop,
// type: "set",
// value: newValue
// }]
// keyChanged: undefined
}, [newValue, oldValue]);
};
ComputedObjectObservationData.prototype.bindingCount = 0;
function findComputed(instance, key) {
var meta = instance[canMeta];
var target = meta.target;
var computedPropertyDefinitions = target[computedPropertyDefinitionSymbol];
if (computedPropertyDefinitions === undefined) {
return;
}
var computedPropertyDefinition = computedPropertyDefinitions[key];
if (computedPropertyDefinition === undefined) {
return;
}
if (meta.computedKeys[key] === undefined) {
meta.computedKeys[key] = new ComputedObjectObservationData(
instance, key,
computedPropertyDefinition(instance, key)
);
}
return meta.computedKeys[key];
}
const computedHelpers = {
bind: function(instance, key) {
let computedObj = findComputed(instance, key);
if (computedObj === undefined) {
return;
}
computedObj.bind();
},
addKeyDependencies: function(proxyKeys) {
let onKeyValue = proxyKeys[onKeyValueSymbol$3];
let offKeyValue = proxyKeys[offKeyValueSymbol$2];
canReflect_1_19_2_canReflect.assignSymbols(proxyKeys, {
"can.onKeyValue": function(key) {
computedHelpers.bind(this, key);
return onKeyValue.apply(this, arguments);
},
"can.offKeyValue": function(key) {
computedHelpers.unbind(this, key);
return offKeyValue.apply(this, arguments);
},
"can.getKeyDependencies": function(key) {
var computedObj = findComputed(this, key);
if (computedObj === undefined) {
return;
}
return {
valueDependencies: new Set([ computedObj.observation ])
};
},
});
}
};
var computedHelpers_1 = computedHelpers;
const {
assignNonEnumerable,
convertItem,
dispatchIndexEvent,
shouldRecordObservationOnAllKeysExceptFunctionsOnProto
} = helpers_1$1;
const { mixins: mixins$3 } = mixins;
const hasOwn = Object.prototype.hasOwnProperty;
const { isSymbolLike: isSymbolLike$1 } = canReflect_1_19_2_canReflect;
const metaSymbol$4 = Symbol.for("can.meta");
const proxiedObjects = new WeakMap();
const proxies = new WeakSet();
const proxyKeys = Object.create(null);
Object.getOwnPropertySymbols(map$1).forEach(function(symbol){
assignNonEnumerable(proxyKeys, symbol, map$1[symbol]);
});
computedHelpers_1.addKeyDependencies(proxyKeys);
const mutateMethods = {
"push": function(arr, args) {
return [{
index: arr.length - args.length,
deleteCount: 0,
insert: args,
type: "splice"
}];
},
"pop": function(arr) {
return [{
index: arr.length,
deleteCount: 1,
insert: [],
type: "splice"
}];
},
"shift": function() {
return [{
index: 0,
deleteCount: 1,
insert: [],
type: "splice"
}];
},
"unshift": function(arr, args) {
return [{
index: 0,
deleteCount: 0,
insert: args,
type: "splice"
}];
},
"splice": function(arr, args) {
return [{
index: args[0],
deleteCount: args[1],
insert: args.slice(2),
type: "splice"
}];
},
"sort": function(arr) {
// The array replaced everything.
return [{
index: 0,
deleteCount: arr.length,
insert: arr,
type: "splice"
}];
},
"reverse": function(arr) {
// The array replaced everything.
return [{
index: 0,
deleteCount: arr.length,
insert: arr,
type: "splice"
}];
}
};
// Overwrite Array's methods that mutate to:
// - prevent other events from being fired off (index events and length events.)
// - dispatch patches events.
canReflect_1_19_2_canReflect.eachKey(mutateMethods, function(makePatches, prop){
var protoFn = Array.prototype[prop];
var mutateMethod = function() {
var meta = this[metaSymbol$4],
// Capture if this function should be making sideEffects
makeSideEffects = meta.preventSideEffects === 0,
oldLength = meta.target.length;
// Prevent proxy from calling ObservationRecorder and sending events.
meta.preventSideEffects++;
// Call the function -- note that *this* is the Proxy here, so
// accesses in the function still go through `get()` and `set()`.
var ret = protoFn.apply(meta.target, arguments);
var patches = makePatches(meta.target, Array.from(arguments), oldLength);
if (makeSideEffects === true) {
//!steal-remove-start
var reasonLog = [canReflect_1_19_2_canReflect.getName(meta.proxy)+"."+prop+" called with", arguments];
//!steal-remove-end
var dispatchArgs = {
type: "length",
key: "length",
value: meta.target.length,
oldValue: oldLength,
patches: patches
};
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
dispatchArgs.reasonLog = reasonLog;
}
//!steal-remove-end
map$1.dispatch.call( meta.proxy, dispatchArgs , [meta.target.length, oldLength]);
}
meta.preventSideEffects--;
return ret;
};
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
Object.defineProperty(mutateMethod, "name", {
value: prop
});
}
//!steal-remove-end
// Store the proxied method so it will be used instead of the
// prototype method.
proxiedObjects.set(protoFn, mutateMethod);
proxies.add(mutateMethod);
});
function setValueAndOnChange(key, value, target, proxy, onChange) {
let old, change;
let hadOwn = hasOwn.call(target, key);
let descriptor = Object.getOwnPropertyDescriptor(target, key);
// call the setter on the Proxy to properly do any side-effect sets (and run corresponding handlers)
// -- setters do not return values, so it is unnecessary to check for changes.
if (descriptor && descriptor.set) {
descriptor.set.call(proxy, value);
} else {
// otherwise check for a changed value
old = target[key];
change = old !== value;
if (change) {
let keyType = typeof key;
let keyIsString = keyType === "string";
// String keys added to the instance (and is not "length")
// Are newly defined properties and have propertyDefaults provided.
if(keyIsString && !(key in target)) {
mixins$3.expando(target, key, value);
} else {
// arr[0] = { foo: 'bar' } should convert to MyArray.items
if(keyType === "number") {
value = convertItem(target.constructor, value);
}
target[key] = value;
onChange(hadOwn, old);
}
}
}
}
const proxyHandlers = {
get(target, key, receiver) {
if (isSymbolLike$1(key)) {
return target[key];
}
let proxy = proxiedObjects.get(target);
canObservationRecorder_1_3_1_canObservationRecorder.add(proxy, key.toString());
const numberKey = !isSymbolLike$1(key) && +key;
if (Number.isInteger(numberKey)) {
canObservationRecorder_1_3_1_canObservationRecorder.add(proxy, "length");
}
let value = Reflect.get(target, key, receiver);
return value;
},
set(target, key, newValue, receiver) {
let proxy = proxiedObjects.get(target);
let numberKey = !isSymbolLike$1(key) && +key;
if (Number.isInteger(numberKey)) {
key = numberKey;
}
setValueAndOnChange(key, newValue, target, proxy, function onChange(hadOwn, oldValue) {
if (Number.isInteger(key)) {
dispatchIndexEvent.call(
receiver,
key,
hadOwn ? (typeof newValue !== 'undefined' ? "set" : "remove") : "add",
newValue,
oldValue
);
}
});
return true;
},
deleteProperty(target, key) {
let old = this.target[key];
let deleteSuccessful = delete this.target[key];
// Fire event handlers if we were able to delete and the value changed.
if (deleteSuccessful && this.preventSideEffects === 0 && old !== undefined) {
dispatchIndexEvent.call(
this.proxy,
key,
"remove",
undefined,
old
);
}
return deleteSuccessful;
},
ownKeys() {
canObservationRecorder_1_3_1_canObservationRecorder.add(this.proxy, "can.keys");
let keysSet = new Set(
Object.getOwnPropertyNames(this.target)
.concat(Object.getOwnPropertySymbols(this.target))
.concat(Object.getOwnPropertySymbols(this.proxyKeys))
);
return Array.from(keysSet);
}
};
function makeObservable(array, options) {
let meta = {
target: array,
proxyKeys: options.proxyKeys !== undefined ? options.proxyKeys : Object.create(proxyKeys),
computedKeys: Object.create(null),
options: options,
// `preventSideEffects` is a counter used to "turn off" the proxy. This is incremented when some
// function (like `Array.splice`) wants to handle event dispatching and/or calling
// `ObservationRecorder` itself for performance reasons.
preventSideEffects: 0
};
meta.proxyKeys[metaSymbol$4] = meta;
meta.proxy = new Proxy(array, {
get: proxyHandlers.get.bind(meta),
set: proxyHandlers.set.bind(meta),
ownKeys: proxyHandlers.ownKeys.bind(meta),
deleteProperty: proxyHandlers.deleteProperty.bind(meta),
meta: meta
});
map$1.addHandlers(meta.proxy, meta);
return meta.proxy;
}
function proxyArray() {
return class ProxyArray extends Array {
constructor(...items) {
super(...items);
let localProxyKeys = Object.create(proxyKeys);
localProxyKeys.constructor = this.constructor;
let observable = makeObservable(this, {
//observe: makeObserve.observe,
proxyKeys: localProxyKeys,
shouldRecordObservation: shouldRecordObservationOnAllKeysExceptFunctionsOnProto
});
proxiedObjects.set(this, observable);
proxies.add(observable);
return observable;
}
};
}
var proxyArray_1 = proxyArray;
const {
createConstructorFunction: createConstructorFunction$2,
makeDefineInstanceKey: makeDefineInstanceKey$3,
mixins: mixins$4,
mixinMapProps: mixinMapProps$1,
mixinTypeEvents: mixinTypeEvents$2
} = mixins;
const {
convertItem: convertItem$1,
convertItems,
dispatchLengthPatch
} = helpers_1$1;
const ProxyArray = proxyArray_1();
// symbols aren't enumerable ... we'd need a version of Object that treats them that way
const localOnPatchesSymbol = "can.patches";
const onKeyValueSymbol$4 = Symbol.for("can.onKeyValue");
const offKeyValueSymbol$3 = Symbol.for("can.offKeyValue");
const metaSymbol$5 = Symbol.for("can.meta");
function isListLike$1(items) {
return canReflect_1_19_2_canReflect.isListLike(items) && typeof items !== "string";
}
const MixedInArray = mixinTypeEvents$2(mixinMapProps$1(ProxyArray));
class ObservableArray extends MixedInArray {
// TODO define stuff here
constructor(items, props) {
// Arrays can be passed a length like `new Array(15)`
let isLengthArg = typeof items === "number";
if(isLengthArg) {
super(items);
} else if(arguments.length > 0 && !isListLike$1(items)) {
throw new Error("can-observable-array: Unexpected argument: " + typeof items);
} else {
super();
}
mixins$4.finalizeClass(this.constructor);
mixins$4.initialize(this, props || {});
for(let i = 0, len = items && items.length; i < len; i++) {
this[i] = convertItem$1(this.constructor, items[i]);
}
// Define class fields observables
//and return the proxy
return new Proxy(this, {
defineProperty(target, prop, descriptor) {
if ('items' === prop) {
throw new Error('ObservableArray does not support a class field named items. Try using a different name or using static items');
}
// do not create expando properties for special keys set by can-observable-mixin
if (prop === '_instanceDefinitions') {
return Reflect.defineProperty(target, prop, descriptor);
}
let value = descriptor.value;
// do not create expando properties for properties that are described
// by `static props` or `static propertyDefaults`
const props = target.constructor.props;
if (props && props[prop] || target.constructor.propertyDefaults) {
if (value) {
target.set(prop, value);
return true;
}
return Reflect.defineProperty(target, prop, descriptor);
}
// create expandos to make all other properties observable
return mixins$4.expando(target, prop, value);
}
});
}
static get [Symbol.species]() {
return this;
}
static [Symbol.for("can.new")](items) {
let array = items || [];
return new this(array);
}
push(...items) {
return super.push(...items);
}
unshift(...items) {
return super.unshift(...items);
}
filter(callback) {
if(typeof callback === "object") {
let props = callback;
callback = function(item) {
for (let prop in props) {
if (item[prop] !== props[prop]) {
return false;
}
}
return true;
};
}
return super.filter(callback);
}
forEach(...args) {
return Array.prototype.forEach.apply(this, args);
}
splice(...args) {
let index = args[0],
howMany = args[1],
added = [],
i, len, listIndex,
allSame = args.length > 2;
index = index || 0;
// converting the arguments to the right type
for (i = 0, len = args.length - 2; i < len; i++) {
listIndex = i + 2;
added.push(args[listIndex]);
// Now lets check if anything will change
if (this[i + index] !== args[listIndex]) {
allSame = false;
}
}
// if nothing has changed, then return
if (allSame && this.length <= added.length) {
return added;
}
// default howMany if not provided
if (howMany === undefined) {
howMany = args[1] = this.length - index;
}
canQueues_1_3_2_canQueues.batch.start();
var removed = super.splice.apply(this, args);
canQueues_1_3_2_canQueues.batch.stop();
return removed;
}
static convertsTo(Type) {
const ConvertedType = canType_1_1_6_canType.convert(Type);
const ArrayType = class extends this {
static get items() {
return ConvertedType;
}
};
const name = `ConvertedObservableArray<${canReflect_1_19_2_canReflect.getName(Type)}>`;
canReflect_1_19_2_canReflect.setName(ArrayType, name);
return ArrayType;
}
/* Symbols */
[Symbol.for("can.splice")](index, deleteCount, insert){
return this.splice(...[index, deleteCount].concat(insert));
}
[Symbol.for("can.onPatches")](handler, queue){
this[onKeyValueSymbol$4](localOnPatchesSymbol, handler,queue);
}
[Symbol.for("can.offPatches")](handler, queue) {
this[offKeyValueSymbol$3](localOnPatchesSymbol, handler, queue);
}
get [Symbol.for("can.isListLike")]() {
return true;
}
[Symbol.for("can.getOwnEnumerableKeys")]() {
let base = super[Symbol.for("can.getOwnEnumerableKeys")]();
let keysSet = new Set([...Object.keys(this), ...base]);
return Array.from(keysSet);
}
}
var mutateMethods$1 = {
"push": function(arr, args) {
return [{
index: arr.length - args.length,
deleteCount: 0,
insert: args,
type: "splice"
}];
},
"pop": function(arr, args, oldLength) {
return [{
index: arr.length,
deleteCount: oldLength > 0 ? 1 : 0,
type: "splice"
}];
},
"shift": function(arr, args, oldLength) {
return [{
index: 0,
deleteCount: oldLength > 0 ? 1 : 0,
type: "splice"
}];
},
"unshift": function(arr, args) {
return [{
index: 0,
deleteCount: 0,
insert: args,
type: "splice"
}];
},
"splice": function(arr, args, oldLength) {
const index = args[0] < 0 ?
Math.max(oldLength + args[0], 0) :
Math.min(oldLength, args[0]);
return [{
index,
deleteCount: Math.max(0, Math.min(args[1], oldLength - index)),
insert: args.slice(2),
type: "splice"
}];
},
"sort": function(arr) {
return [{
index: 0,
deleteCount: arr.length,
insert: arr,
type: "splice"
}];
},
"reverse": function(arr) {
return [{
index: 0,
deleteCount: arr.length,
insert: arr,
type: "splice"
}];
}
};
const convertArgs = {
"push": function(arr, args) {
return convertItems(arr.constructor, args);
},
"unshift": function(arr, args) {
return convertItems(arr.constructor, args);
},
"splice": function(arr, args) {
return args.slice(0, 2).concat(convertItems(arr.constructor, args.slice(2)));
}
};
canReflect_1_19_2_canReflect.eachKey(mutateMethods$1, function(makePatches, prop) {
const protoFn = ObservableArray.prototype[prop];
ObservableArray.prototype[prop] = function() {
const oldLength = this.length;
let args = Array.from(arguments);
if(convertArgs[prop]) {
args = convertArgs[prop](this, args);
}
// prevent `length` event from being dispatched by get/set proxy hooks
this[metaSymbol$5].preventSideEffects = (this[metaSymbol$5].preventSideEffects || 0) + 1;
const result = protoFn.apply(this, args);
this[metaSymbol$5].preventSideEffects--;
const patches = makePatches(this, args, oldLength);
dispatchLengthPatch.call(this, prop, patches, this.length, oldLength);
return result;
};
});
makeDefineInstanceKey$3(ObservableArray);
// Export a constructor function to workaround an issue where ES2015 classes
// cannot be extended in code that's transpiled by Babel.
var canObservableArray = canNamespace_1_0_0_canNamespace.ObservableArray = createConstructorFunction$2(
ObservableArray
);
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
var canLog = dev;
var canReflectDeps = canReflectDependencies_1_1_2_canReflectDependencies;
}
//!steal-remove-end
// Symbols
var getChangesSymbol$2 = canSymbol_1_7_0_canSymbol.for("can.getChangesDependencyRecord");
var getValueSymbol$1 = canSymbol_1_7_0_canSymbol.for("can.getValue");
var onValueSymbol$2 = canSymbol_1_7_0_canSymbol.for("can.onValue");
var onEmitSymbol = canSymbol_1_7_0_canSymbol.for("can.onEmit");
var offEmitSymbol = canSymbol_1_7_0_canSymbol.for("can.offEmit");
var setValueSymbol$2 = canSymbol_1_7_0_canSymbol.for("can.setValue");
var canElementSymbol$1 = canSymbol_1_7_0_canSymbol.for("can.element");
// Default implementations for setting the child and parent values
function defaultSetValue(newValue, observable) {
canReflect_1_19_2_canReflect.setValue(observable, newValue);
}
// onEmit function
function onEmit (listenToObservable, updateFunction, queue) {
return listenToObservable[onEmitSymbol](updateFunction, queue);
}
// offEmit function
function offEmit (listenToObservable, updateFunction, queue) {
return listenToObservable[offEmitSymbol](updateFunction, queue);
}
// Given an observable, stop listening to it and tear down the mutation dependencies
function turnOffListeningAndUpdate(listenToObservable, updateObservable, updateFunction, queue) {
var offValueOrOffEmitFn;
// Use either offValue or offEmit depending on which Symbols are on the `observable`
if (listenToObservable[onValueSymbol$2]) {
offValueOrOffEmitFn = canReflect_1_19_2_canReflect.offValue;
} else if (listenToObservable[onEmitSymbol]) {
offValueOrOffEmitFn = offEmit;
}
if (offValueOrOffEmitFn) {
offValueOrOffEmitFn(listenToObservable, updateFunction, queue);
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
// The updateObservable is no longer mutated by listenToObservable
canReflectDeps.deleteMutatedBy(updateObservable, listenToObservable);
// The updateFunction no longer mutates anything
updateFunction[getChangesSymbol$2] = function getChangesDependencyRecord() {
};
}
//!steal-remove-end
}
}
// Given an observable, start listening to it and set up the mutation dependencies
function turnOnListeningAndUpdate(listenToObservable, updateObservable, updateFunction, queue) {
var onValueOrOnEmitFn;
// Use either onValue or onEmit depending on which Symbols are on the `observable`
if (listenToObservable[onValueSymbol$2]) {
onValueOrOnEmitFn = canReflect_1_19_2_canReflect.onValue;
} else if (listenToObservable[onEmitSymbol]) {
onValueOrOnEmitFn = onEmit;
}
if (onValueOrOnEmitFn) {
onValueOrOnEmitFn(listenToObservable, updateFunction, queue);
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
// The updateObservable is mutated by listenToObservable
canReflectDeps.addMutatedBy(updateObservable, listenToObservable);
// The updateFunction mutates updateObservable
updateFunction[getChangesSymbol$2] = function getChangesDependencyRecord() {
var s = new Set();
s.add(updateObservable);
return {
valueDependencies: s
};
};
}
//!steal-remove-end
}
}
// Semaphores are used to keep track of updates to the child & parent
// For debugging purposes, Semaphore and Bind are highly coupled.
function Semaphore(binding, type) {
this.value = 0;
this._binding = binding;
this._type = type;
}
canAssign_1_3_3_canAssign(Semaphore.prototype, {
decrement: function() {
this.value -= 1;
},
increment: function(args) {
this._incremented = true;
this.value += 1;
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
if(this.value === 1) {
this._binding._debugSemaphores = [];
}
var semaphoreData = {
type: this._type,
action: "increment",
observable: args.observable,
newValue: args.newValue,
value: this.value,
lastTask: canQueues_1_3_2_canQueues.lastTask()
};
this._binding._debugSemaphores.push(semaphoreData);
}
//!steal-remove-end
}
});
function Bind(options) {
this._options = options;
// These parameters must be supplied
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
if (options.child === undefined) {
throw new TypeError("You must supply a child");
}
if (options.parent === undefined) {
throw new TypeError("You must supply a parent");
}
if (options.queue && ["notify", "derive", "domUI","dom"].indexOf(options.queue) === -1) {
throw new RangeError("Invalid queue; must be one of notify, derive, dom, or domUI");
}
}
//!steal-remove-end
// queue; by default, domUI
if (options.queue === undefined) {
if(options.element) {
options.queue = "dom";
} else {
options.queue = "domUI";
}
}
// cycles: when an observable is set in a two-way binding, it can update the
// other bound observable, which can then update the original observable the
// “cycles” number of times. For example, a child is set and updates the parent;
// with cycles: 0, the parent could not update the child;
// with cycles: 1, the parent could update the child, which can update the parent
// with cycles: 2, the parent can update the child again, and so on and so forth…
if (options.cycles > 0 === false) {
options.cycles = 0;
}
// onInitDoNotUpdateChild is false by default
options.onInitDoNotUpdateChild =
typeof options.onInitDoNotUpdateChild === "boolean" ?
options.onInitDoNotUpdateChild
: false;
// onInitDoNotUpdateParent is false by default
options.onInitDoNotUpdateParent =
typeof options.onInitDoNotUpdateParent === "boolean" ?
options.onInitDoNotUpdateParent
: false;
// onInitSetUndefinedParentIfChildIsDefined is true by default
options.onInitSetUndefinedParentIfChildIsDefined =
typeof options.onInitSetUndefinedParentIfChildIsDefined === "boolean" ?
options.onInitSetUndefinedParentIfChildIsDefined
: true;
// The way the cycles are tracked is through semaphores; currently, when
// either the child or parent is updated, we increase their respective
// semaphore so that if it’s two-way binding, then the “other” observable
// will only update if the total count for both semaphores is less than or
// equal to twice the number of cycles (because a cycle means two updates).
var childSemaphore = new Semaphore(this,"child");
var parentSemaphore = new Semaphore(this,"parent");
// Determine if this is a one-way or two-way binding; by default, accept
// whatever options are passed in, but if they’re not defined, then check for
// the getValue and setValue symbols on the child and parent values.
var childToParent = true;
if (typeof options.childToParent === "boolean") {
// Always let the option override any checks
childToParent = options.childToParent;
} else if (options.child[getValueSymbol$1] == null) {
// Child to parent won’t work if we can’t get the child’s value
childToParent = false;
} else if (options.setParent === undefined && options.parent[setValueSymbol$2] == null) {
// Child to parent won’t work if we can’t set the parent’s value
childToParent = false;
}
var parentToChild = true;
if (typeof options.parentToChild === "boolean") {
// Always let the option override any checks
parentToChild = options.parentToChild;
} else if (options.parent[getValueSymbol$1] == null) {
// Parent to child won’t work if we can’t get the parent’s value
parentToChild = false;
} else if (options.setChild === undefined && options.child[setValueSymbol$2] == null) {
// Parent to child won’t work if we can’t set the child’s value
parentToChild = false;
}
if (childToParent === false && parentToChild === false) {
throw new Error("Neither the child nor parent will be updated; this is a no-way binding");
}
this._childToParent = childToParent;
this._parentToChild = parentToChild;
// Custom child & parent setters can be supplied; if they aren’t provided,
// then create our own.
if (options.setChild === undefined) {
options.setChild = defaultSetValue;
}
if (options.setParent === undefined) {
options.setParent = defaultSetValue;
}
// Set the observables’ priority
if (options.priority !== undefined) {
canReflect_1_19_2_canReflect.setPriority(options.child, options.priority);
canReflect_1_19_2_canReflect.setPriority(options.parent, options.priority);
}
// These variables keep track of how many updates are allowed in a cycle.
// cycles is multipled by two because one update is allowed for each side of
// the binding, child and parent. One more update is allowed depending on the
// sticky option; if it’s sticky, then one more update needs to be allowed.
var allowedUpdates = options.cycles * 2;
var allowedChildUpdates = allowedUpdates + (options.sticky === "childSticksToParent" ? 1 : 0);
var allowedParentUpdates = allowedUpdates + (options.sticky === "parentSticksToChild" ? 1 : 0);
// This keeps track of whether we’re bound to the child and/or parent; this
// allows startParent() to be called first and on() can be called later to
// finish setting up the child binding. This is also checked when updating
// values; if stop() has been called but updateValue() is called, then we
// ignore the update.
this._bindingState = {
child: false,
parent: false
};
// This is the listener that’s called when the parent changes
this._updateChild = function(newValue) {
updateValue.call(this, {
bindingState: this._bindingState,
newValue: newValue,
// Some options used for debugging
debugObservableName: "child",
debugPartnerName: "parent",
// Main observable values
observable: options.child,
setValue: options.setChild,
semaphore: childSemaphore,
// If the sum of the semaphores is less than or equal to this number, then
// it’s ok to update the child with the new value.
allowedUpdates: allowedChildUpdates,
// If options.sticky === "parentSticksToChild", then after the parent sets
// the child, check to see if the child matches the parent; if not, then
// set the parent to the child’s value. This is used in cases where the
// child modifies its own value and the parent should be kept in sync with
// the child.
sticky: options.sticky === "parentSticksToChild",
// Partner observable values
partner: options.parent,
setPartner: options.setParent,
partnerSemaphore: parentSemaphore
});
}.bind(this);
// This is the listener that’s called when the child changes
this._updateParent = function(newValue) {
updateValue.call(this, {
bindingState: this._bindingState,
newValue: newValue,
// Some options used for debugging
debugObservableName: "parent",
debugPartnerName: "child",
// Main observable values
observable: options.parent,
setValue: options.setParent,
semaphore: parentSemaphore,
// If the sum of the semaphores is less than or equal to this number, then
// it’s ok to update the parent with the new value.
allowedUpdates: allowedParentUpdates,
// If options.sticky === "childSticksToParent", then after the child sets
// the parent, check to see if the parent matches the child; if not, then
// set the child to the parent’s value. This is used in cases where the
// parent modifies its own value and the child should be kept in sync with
// the parent.
sticky: options.sticky === "childSticksToParent",
// Partner observable values
partner: options.child,
setPartner: options.setChild,
partnerSemaphore: childSemaphore
});
}.bind(this);
if(options.element) {
this._updateChild[canElementSymbol$1] = this._updateParent[canElementSymbol$1] = options.element;
}
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
Object.defineProperty(this._updateChild, "name", {
value: options.updateChildName ? options.updateChildName : "update "+canReflect_1_19_2_canReflect.getName(options.child),
configurable: true
});
Object.defineProperty(this._updateParent, "name", {
value: options.updateParentName ? options.updateParentName : "update "+canReflect_1_19_2_canReflect.getName(options.parent),
configurable: true
});
}
//!steal-remove-end
}
Object.defineProperty(Bind.prototype, "parentValue", {
get: function() {
return canReflect_1_19_2_canReflect.getValue(this._options.parent);
}
});
canAssign_1_3_3_canAssign(Bind.prototype, {
// Turn on any bindings that haven’t already been enabled;
// also update the child or parent if need be.
start: function() {
var childValue;
var options = this._options;
var parentValue;
// The tests don’t show that it matters which is bound first, but we’ll
// bind to the parent first to stay consistent with how
// can-stache-bindings did things.
this.startParent();
this.startChild();
// Initialize the child & parent values
if (this._childToParent === true && this._parentToChild === true) {
// Two-way binding
parentValue = canReflect_1_19_2_canReflect.getValue(options.parent);
if (parentValue === undefined) {
childValue = canReflect_1_19_2_canReflect.getValue(options.child);
if (childValue === undefined) {
// Check if updating the child is allowed
if (options.onInitDoNotUpdateChild === false) {
this._updateChild(parentValue);
}
} else if (options.onInitDoNotUpdateParent === false && options.onInitSetUndefinedParentIfChildIsDefined === true) {
this._updateParent(childValue);
}
} else {
// Check if updating the child is allowed
if (options.onInitDoNotUpdateChild === false) {
this._updateChild(parentValue);
}
}
//!steal-remove-start
if(process.env.NODE_ENV !== 'production'){
// Here we want to do a dev-mode check to see whether the child does type conversions on
// any two-way bindings. This will be ignored and the child and parent will be desynched.
var parentContext = options.parent.observation && options.parent.observation.func || options.parent;
var childContext = options.child.observation && options.child.observation.func || options.child;
parentValue = canReflect_1_19_2_canReflect.getValue(options.parent);
childValue = canReflect_1_19_2_canReflect.getValue(options.child);
if (options.sticky && childValue !== parentValue) {
canLog.warn(
"can-bind: The " +
(options.sticky === "parentSticksToChild" ? "parent" : "child") +
" of the sticky two-way binding " +
(options.debugName || (canReflect_1_19_2_canReflect.getName(parentContext) + "<->" + canReflect_1_19_2_canReflect.getName(childContext))) +
" is changing or converting its value when set. Conversions should only be done on the binding " +
(options.sticky === "parentSticksToChild" ? "child" : "parent") +
" to preserve synchronization. " +
"See https://canjs.com/doc/can-stache-bindings.html#StickyBindings for more about sticky bindings"
);
}
}
//!steal-remove-end
} else if (this._childToParent === true) {
// One-way child -> parent, so update the parent
// Check if we are to initialize the parent
if (options.onInitDoNotUpdateParent === false) {
childValue = canReflect_1_19_2_canReflect.getValue(options.child);
this._updateParent(childValue);
}
} else if (this._parentToChild === true) {
// One-way parent -> child, so update the child
// Check if updating the child is allowed
if (options.onInitDoNotUpdateChild === false) {
parentValue = canReflect_1_19_2_canReflect.getValue(options.parent);
this._updateChild(parentValue);
}
}
},
// Listen for changes to the child observable and update the parent
startChild: function() {
if (this._bindingState.child === false && this._childToParent === true) {
var options = this._options;
this._bindingState.child = true;
turnOnListeningAndUpdate(options.child, options.parent, this._updateParent, options.queue);
}
},
// Listen for changes to the parent observable and update the child
startParent: function() {
if (this._bindingState.parent === false && this._parentToChild === true) {
var options = this._options;
this._bindingState.parent = true;
turnOnListeningAndUpdate(options.parent, options.child, this._updateChild, options.queue);
}
},
// Turn off all the bindings
stop: function() {
var bindingState = this._bindingState;
var options = this._options;
// Turn off the parent listener
if (bindingState.parent === true && this._parentToChild === true) {
bindingState.parent = false;
turnOffListeningAndUpdate(options.parent, options.child, this._updateChild, options.queue);
}
// Turn off the child listener
if (bindingState.child === true && this._childToParent === true) {
bindingState.child = false;
turnOffListeningAndUpdate(options.child, options.parent, this._updateParent, options.queue);
}
}
});
["parent", "child"].forEach(function(property){
Object.defineProperty(Bind.prototype, property, {
get: function(){
return this._options[property];
}
});
});
// updateValue is a helper function that’s used by updateChild and updateParent
function updateValue(args) {
/* jshint validthis: true */
// Check to see whether the binding is active; ignore updates if it isn’t active
var bindingState = args.bindingState;
if (bindingState.child === false && bindingState.parent === false) {
// We don’t warn the user about this because it’s a common occurrence in
// can-stache-bindings, e.g. {{#if value}}{{/if}}
return;
}
// Now check the semaphore; if this change is happening because the partner
// observable was just updated, we only want to update this observable again
// if the total count for both semaphores is less than or equal to the number
// of allowed updates.
var semaphore = args.semaphore;
if ((semaphore.value + args.partnerSemaphore.value) <= args.allowedUpdates) {
canQueues_1_3_2_canQueues.batch.start();
// Increase the semaphore so that when the batch ends, if an update to the
// partner observable’s value is made, then it won’t update this observable
// again unless cycles are allowed.
semaphore.increment(args);
// Update the observable’s value; this uses either a custom function passed
// in when the binding was initialized or canReflect.setValue.
args.setValue(args.newValue, args.observable);
// Decrease the semaphore after all other updates have occurred
canQueues_1_3_2_canQueues.mutateQueue.enqueue(semaphore.decrement, semaphore, []);
canQueues_1_3_2_canQueues.batch.stop();
// Stickiness is used in cases where the call to args.setValue above might
// have resulted in the observable being set to a different value than what
// was passed into this function (args.newValue). If sticky:true, then set
// the partner observable’s value so they’re kept in sync.
if (args.sticky) {
var observableValue = canReflect_1_19_2_canReflect.getValue(args.observable);
if (observableValue !== canReflect_1_19_2_canReflect.getValue(args.partner)) {
args.setPartner(observableValue, args.partner);
}
}
} else {
// It’s natural for this “else” block to be hit in two-way bindings; as an
// example, if a parent gets set and the child gets updated, the child’s
// listener to update the parent will be called, but it’ll be ignored if we
// don’t want cycles. HOWEVER, if this gets called and the parent is not the
// same value as the child, then their values are going to be out of sync,
// probably unintentionally. This is worth pointing out to developers
// because it can cause unexpected behavior… some people call those bugs. :)
//!steal-remove-start
if(process.env.NODE_ENV !== 'production'){
var currentValue = canReflect_1_19_2_canReflect.getValue(args.observable);
if (currentValue !== args.newValue) {
var warningParts = [
"can-bind: attempting to update " + args.debugObservableName + " " + canReflect_1_19_2_canReflect.getName(args.observable) + " to new value: %o",
"…but the " + args.debugObservableName + " semaphore is at " + semaphore.value + " and the " + args.debugPartnerName + " semaphore is at " + args.partnerSemaphore.value + ". The number of allowed updates is " + args.allowedUpdates + ".",
"The " + args.debugObservableName + " value will remain unchanged; it’s currently: %o. ",
"Read https://canjs.com/doc/can-bind.html#Warnings for more information. Printing mutation history:"
];
canLog.warn(warningParts.join("\n"), args.newValue, currentValue);
if(console.groupCollapsed) {
// stores the last stack we've seen so we only need to show what's happened since the
// last increment.
var lastStack = [];
var getFromLastStack = function(stack){
if(lastStack.length) {
// walk backwards
for(var i = lastStack.length - 1; i >= 0 ; i--) {
var index = stack.indexOf(lastStack[i]);
if(index !== - 1) {
return stack.slice(i+1);
}
}
}
return stack;
};
// Loop through all the debug information
// And print out what caused increments.
this._debugSemaphores.forEach(function(semaphoreMutation){
if(semaphoreMutation.action === "increment") {
console.groupCollapsed(semaphoreMutation.type+" "+canReflect_1_19_2_canReflect.getName(semaphoreMutation.observable)+" set.");
var stack = canQueues_1_3_2_canQueues.stack(semaphoreMutation.lastTask);
var printStack = getFromLastStack(stack);
lastStack = stack;
// This steals how `logStack` logs information.
canQueues_1_3_2_canQueues.logStack.call({
stack: function(){
return printStack;
}
});
console.log(semaphoreMutation.type+ " semaphore incremented to "+semaphoreMutation.value+".");
console.log(canReflect_1_19_2_canReflect.getName(semaphoreMutation.observable),semaphoreMutation.observable,"set to ", semaphoreMutation.newValue);
console.groupEnd();
}
});
console.groupCollapsed(args.debugObservableName+" "+canReflect_1_19_2_canReflect.getName(args.observable)+" NOT set.");
var stack = getFromLastStack(canQueues_1_3_2_canQueues.stack());
canQueues_1_3_2_canQueues.logStack.call({
stack: function(){
return stack;
}
});
console.log(args.debugObservableName+" semaphore ("+semaphore.value+
") + "+args.debugPartnerName+" semaphore ("+args.partnerSemaphore.value+ ") IS NOT <= allowed updates ("+
args.allowedUpdates+")");
console.log("Prevented from setting "+canReflect_1_19_2_canReflect.getName(args.observable), args.observable, "to", args.newValue);
console.groupEnd();
}
}
}
//!steal-remove-end
}
}
var canBind_1_5_1_canBind = canNamespace_1_0_0_canNamespace.Bind = Bind;
const value$1 = canValue_1_1_2_canValue;
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
var Observation$1 = canObservation_4_2_0_canObservation;
}
//!steal-remove-end
const metaSymbol$6 = Symbol.for("can.meta");
function isJSONLike (obj) {
return (canReflect_1_19_2_canReflect.isFunctionLike(obj.parse) &&
canReflect_1_19_2_canReflect.isFunctionLike(obj.stringify));
}
function initializeFromAttribute (propertyName, ctr, converter, attributeName) {
if (ctr[metaSymbol$6] === undefined) {
ctr[metaSymbol$6] = {};
}
// Create array for all attributes we want to listen to change events for
if (ctr[metaSymbol$6]._observedAttributes === undefined) {
ctr[metaSymbol$6]._observedAttributes = [];
}
// Create object for attributeChangedCallback for each prop
if (ctr[metaSymbol$6]._attributeChangedCallbackHandler === undefined) {
ctr[metaSymbol$6]._attributeChangedCallbackHandler = {};
}
if (attributeName === undefined) {
attributeName = propertyName;
}
// Ensure the attributeName is hyphen case
attributeName = canString_1_1_0_canString.hyphenate(attributeName);
// Modify the class prototype here
if (!ctr[metaSymbol$6]._hasInitializedAttributeBindings) {
// Set up the static getter for `observedAttributes`
Object.defineProperty(ctr, "observedAttributes", {
get() {
return ctr[metaSymbol$6]._observedAttributes;
}
});
ctr.prototype.attributeChangedCallback = function (prop) {
ctr[metaSymbol$6]._attributeChangedCallbackHandler[prop].apply(this, arguments);
};
ctr[metaSymbol$6]._hasInitializedAttributeBindings = true;
}
// Push into `_observedAttributes` for `observedAttributes` getter
ctr[metaSymbol$6]._observedAttributes.push(attributeName);
// Create the attributeChangedCallback handler
ctr[metaSymbol$6]._attributeChangedCallbackHandler[attributeName] = function (prop, oldVal, newVal) {
if (this[metaSymbol$6] && this[metaSymbol$6]._attributeBindings && newVal !== oldVal) {
canReflect_1_19_2_canReflect.setValue(this[metaSymbol$6]._attributeBindings[prop], newVal);
}
};
var lazyGetType = function() {
var Type;
var schema = canReflect_1_19_2_canReflect.getSchema(ctr);
if(schema) {
Type = schema.keys[propertyName];
}
if(!Type) {
Type = canType_1_1_6_canType.Any;
}
Type = canType_1_1_6_canType.convert(Type);
lazyGetType = function() { return Type; };
return Type;
};
function convertToValue(value) {
if (converter) {
value = converter.parse(value);
}
return canReflect_1_19_2_canReflect.convert(value, lazyGetType());
}
return function fromAttributeBind (instance) {
// Child binding used by `attributeChangedCallback` to update the value when an attribute change occurs
const childValue = value$1.to(instance, propertyName);
const intermediateValue = {};
canReflect_1_19_2_canReflect.assignSymbols(intermediateValue, {
"can.setValue": function(value) {
canReflect_1_19_2_canReflect.setValue(childValue, convertToValue(value) );
}
});
const parentValue = value$1.from(instance.hasAttribute(attributeName) ? convertToValue(instance.getAttribute(attributeName)) : undefined);
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
// Ensure pretty names for dep graph
canReflect_1_19_2_canReflect.assignSymbols(parentValue, {
"can.getName": function getName() {
return (
"FromAttribute<" +
instance.nodeName.toLowerCase() +
"." +
attributeName +
">"
);
}
});
canReflect_1_19_2_canReflect.assignSymbols(childValue, {
"can.getName": function getName() {
return (
"Observation<" +
canReflect_1_19_2_canReflect.getName(parentValue) +
">"
);
}
});
// Create temporary binding to initialize dep graph
Observation$1.temporarilyBind(childValue);
}
//!steal-remove-end
const bind = new canBind_1_5_1_canBind({
parent: parentValue,
child: intermediateValue,
queue: "dom",
// During initialization prevent update of child
onInitDoNotUpdateChild: true
});
if (instance[metaSymbol$6] === undefined) {
instance[metaSymbol$6] = {};
}
if (instance[metaSymbol$6]._attributeBindings === undefined) {
instance[metaSymbol$6]._attributeBindings = {};
}
// Push binding so it can be used within `attributeChangedCallback`
instance[metaSymbol$6]._attributeBindings[attributeName] = intermediateValue;
return bind;
};
}
var canObservableBindings_1_3_3_fromAttribute = function fromAttribute (attributeName, ctr) {
var converter;
// Handle the class constructor
if (arguments.length === 2 && canReflect_1_19_2_canReflect.isConstructorLike(ctr) && !isJSONLike(ctr)) {
return initializeFromAttribute(attributeName, ctr);
} else if (arguments.length === 1 && typeof attributeName === 'object') {
// Handle fromAttribute(JSON)
converter = attributeName;
attributeName = undefined;
} else if (typeof ctr === 'object' && isJSONLike(ctr)) {
// Handle the case where an attribute name
// and JSON like converter is passed
// fromAttribute('attr', JSON)
converter = ctr;
}
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
if (converter && !isJSONLike(converter)) {
throw new Error('The passed converter object is wrong! The object must have "parse" and "stringify" methods!');
}
}
//!steal-remove-end
return function (propertyName, ctr) {
return initializeFromAttribute(propertyName, ctr, converter, attributeName);
};
};
var setElementSymbol = canSymbol_1_7_0_canSymbol.for("can.setElement");
// SetterObservable's call a function when set. Their getter is backed up by an
// observation.
function SetterObservable(getter, setter) {
this.setter = setter;
this.observation = new canObservation_4_2_0_canObservation(getter);
this.handler = this.handler.bind(this);
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
canReflect_1_19_2_canReflect.assignSymbols(this, {
"can.getName": function() {
return (
canReflect_1_19_2_canReflect.getName(this.constructor) +
"<" +
canReflect_1_19_2_canReflect.getName(getter) +
">"
);
}
});
Object.defineProperty(this.handler, "name", {
value: canReflect_1_19_2_canReflect.getName(this) + ".handler"
});
}
//!steal-remove-end
}
SetterObservable.prototype = Object.create(settable.prototype);
SetterObservable.prototype.constructor = SetterObservable;
SetterObservable.prototype.set = function(newVal) {
this.setter(newVal);
};
SetterObservable.prototype.hasDependencies = function() {
return canReflect_1_19_2_canReflect.valueHasDependencies(this.observation);
};
canReflect_1_19_2_canReflect.assignSymbols(SetterObservable.prototype, {
"can.setValue": SetterObservable.prototype.set,
"can.valueHasDependencies": SetterObservable.prototype.hasDependencies,
"can.setElement": function(el) {
this.observation[setElementSymbol](el);
}
});
var setter = SetterObservable;
const lifecycleStatusSymbol = Symbol.for("can.lifecycleStatus");
const inSetupSymbol$4 = Symbol.for("can.initializing");
const teardownHandlersSymbol = Symbol.for("can.teardownHandlers");
function defineConfigurableNonEnumerable(obj, prop, value) {
Object.defineProperty(obj, prop, {
configurable: true,
enumerable: false,
writable: true,
value: value
});
}
var mixinLifecycleMethods = function mixinLifecycleMethods(BaseElement = HTMLElement) {
return class LifecycleElement extends BaseElement {
constructor() {
super();
if (arguments.length) {
throw new Error("can-stache-element: Do not pass arguments to the constructor. Initial property values should be passed to the `initialize` hook.");
}
// add inSetup symbol to prevent events being dispatched
defineConfigurableNonEnumerable(this, inSetupSymbol$4, true);
// add lifecycle status symbol
defineConfigurableNonEnumerable(this, lifecycleStatusSymbol, {
initialized: false,
rendered: false,
connected: false,
disconnected: false
});
// add a place to store additional teardownHandlers
defineConfigurableNonEnumerable(this, teardownHandlersSymbol, []);
}
// custom element lifecycle methods
connectedCallback(props) {
this.initialize(props);
this.render();
this.connect();
return this;
}
disconnectedCallback() {
this.disconnect();
return this;
}
// custom lifecycle methods
initialize(props) {
const lifecycleStatus = this[lifecycleStatusSymbol];
if (lifecycleStatus.initialized) {
return this;
}
// Overwrite ... this means that this initialize
// can't be inherited (super.initialize).
this[inSetupSymbol$4] = true;
if (super.initialize) {
super.initialize(props);
}
this[inSetupSymbol$4] = false;
lifecycleStatus.initialized = true;
return this;
}
render(props) {
const lifecycleStatus = this[lifecycleStatusSymbol];
if (lifecycleStatus.rendered) {
return this;
}
if (!lifecycleStatus.initialized) {
this.initialize(props);
}
if (super.render) {
super.render(props);
}
lifecycleStatus.rendered = true;
return this;
}
connect(props) {
const lifecycleStatus = this[lifecycleStatusSymbol];
if (lifecycleStatus.connected) {
return this;
}
if (!lifecycleStatus.initialized) {
this.initialize(props);
}
if (!lifecycleStatus.rendered) {
this.render(props);
}
if (super.connect) {
super.connect(props);
}
if (this.connected) {
let connectedTeardown = this.connected();
if (typeof connectedTeardown === "function") {
this[teardownHandlersSymbol].push(connectedTeardown);
}
}
lifecycleStatus.connected = true;
lifecycleStatus.disconnected = false;
return this;
}
disconnect() {
const lifecycleStatus = this[lifecycleStatusSymbol];
if (lifecycleStatus.disconnected) {
return this;
}
if (super.disconnect) {
super.disconnect();
}
if (this.stopListening) {
this.stopListening();
}
for (let handler of this[teardownHandlersSymbol]) {
handler.call(this);
}
if (this.disconnected) {
this.disconnected();
}
this[lifecycleStatusSymbol] = {
initialized: false,
rendered: false,
connected: false,
disconnected: true
};
return this;
}
};
};
const { mixinElement: mixinElement$1, mixins: mixins$5 } = mixins;
const eventTargetInstalledSymbol = Symbol.for("can.eventTargetInstalled");
var mixinProps = function mixinDefine(Base = HTMLElement) {
const realAddEventListener = Base.prototype.addEventListener;
const realRemoveEventListener = Base.prototype.removeEventListener;
function installEventTarget(Type) {
if(Type[eventTargetInstalledSymbol]) {
return;
}
const eventQueueAddEventListener = Type.prototype.addEventListener;
const eventQueueRemoveEventListener = Type.prototype.removeEventListener;
Type.prototype.addEventListener = function() {
eventQueueAddEventListener.apply(this, arguments);
return realAddEventListener.apply(this, arguments);
};
Type.prototype.removeEventListener = function() {
eventQueueRemoveEventListener.apply(this, arguments);
return realRemoveEventListener.apply(this, arguments);
};
Type[eventTargetInstalledSymbol] = true;
}
// Warn on special properties
//!steal-remove-start
function raisePropWarnings(Type, Base) {
if(process.env.NODE_ENV !== 'production') {
// look for `static props`and fall back to `static define` if `props` doesn't exist
let props = typeof Type.props === "object" ?
Type.props :
typeof Type.define === "object" ?
Type.define :
{};
Object.keys(props).forEach(function(key) {
if("on" + key in Type.prototype) {
dev.warn(`${canReflect_1_19_2_canReflect.getName(Type)}: The defined property [${key}] matches the name of a DOM event. This property could update unexpectedly. Consider renaming.`);
}
else if(key in Base.prototype) {
dev.warn(`${canReflect_1_19_2_canReflect.getName(Type)}: The defined property [${key}] matches the name of a property on the type being extended, ${canReflect_1_19_2_canReflect.getName(Base)}. This could lead to errors by changing the expected behaviour of that property. Consider renaming.`);
}
});
}
}
//!steal-remove-end
class DefinedClass extends mixinElement$1(Base) {
constructor() {
super();
//!steal-remove-start
raisePropWarnings(this.constructor, Base);
//!steal-remove-end
installEventTarget(this.constructor);
}
initialize(props) {
super.initialize(props);
let prop, staticProps;
if (this.constructor.props) {
staticProps = Object.keys(this.constructor.props);
}
for (prop in this) {
if (this.hasOwnProperty(prop)) {
if (staticProps && staticProps.includes(prop)) {
const val = this[prop];
delete this[prop];
this[prop] = val;
} else {
mixins$5.expando(this, prop, this[prop]);
}
}
}
}
}
return DefinedClass;
};
var canAttributeEncoder_1_1_4_canAttributeEncoder = createCommonjsModule(function (module) {
/**
* @module {{}} can-attribute-encoder can-attribute-encoder
* @parent can-dom-utilities
* @collection can-infrastructure
* @package ./package.json
*
* Encode and decode attribute names.
*
* @option {Object} An object with the methods:
* [can-attribute-encoder.encode] and [can-attribute-encoder.decode].
*
*/
function each(items, callback){
for ( var i = 0; i < items.length; i++ ) {
callback(items[i], i);
}
}
function makeMap(str){
var obj = {}, items = str.split(",");
each(items, function(name){
obj[name] = true;
});
return obj;
}
// Attributes for which the case matters - shouldn’t be lowercased.
var caseMattersAttributes = makeMap("allowReorder,attributeName,attributeType,autoReverse,baseFrequency,baseProfile,calcMode,clipPathUnits,contentScriptType,contentStyleType,diffuseConstant,edgeMode,externalResourcesRequired,filterRes,filterUnits,glyphRef,gradientTransform,gradientUnits,kernelMatrix,kernelUnitLength,keyPoints,keySplines,keyTimes,lengthAdjust,limitingConeAngle,markerHeight,markerUnits,markerWidth,maskContentUnits,maskUnits,patternContentUnits,patternTransform,patternUnits,pointsAtX,pointsAtY,pointsAtZ,preserveAlpha,preserveAspectRatio,primitiveUnits,repeatCount,repeatDur,requiredExtensions,requiredFeatures,specularConstant,specularExponent,spreadMethod,startOffset,stdDeviation,stitchTiles,surfaceScale,systemLanguage,tableValues,textLength,viewBox,viewTarget,xChannelSelector,yChannelSelector,controlsList");
function camelCaseToSpinalCase(match, lowerCaseChar, upperCaseChar) {
return lowerCaseChar + "-" + upperCaseChar.toLowerCase();
}
function startsWith(allOfIt, startsWith) {
return allOfIt.indexOf(startsWith) === 0;
}
function endsWith(allOfIt, endsWith) {
return (allOfIt.length - allOfIt.lastIndexOf(endsWith)) === endsWith.length;
}
var regexes = {
leftParens: /\(/g,
rightParens: /\)/g,
leftBrace: /\{/g,
rightBrace: /\}/g,
camelCase: /([a-z]|[0-9]|^)([A-Z])/g,
forwardSlash: /\//g,
space: /\s/g,
uppercase: /[A-Z]/g,
uppercaseDelimiterThenChar: /:u:([a-z])/g,
caret: /\^/g,
dollar: /\$/g,
at: /@/g
};
var delimiters = {
prependUppercase: ':u:',
replaceSpace: ':s:',
replaceForwardSlash: ':f:',
replaceLeftParens: ':lp:',
replaceRightParens: ':rp:',
replaceLeftBrace: ':lb:',
replaceRightBrace: ':rb:',
replaceCaret: ':c:',
replaceDollar: ':d:',
replaceAt: ':at:'
};
var encoder = {};
/**
* @function can-attribute-encoder.encode encode
* @parent can-attribute-encoder
* @description Encode an attribute name
*
* @signature `encoder.encode(attributeName)`
*
* Note: specific encoding may change, but encoded attributes
* can always be decoded using [can-attribute-encoder.decode].
*
* @body
*
* ```js
* var encodedAttributeName = encoder.encode("{(^$foo/bar baz)}");
* div.setAttribute(encodedAttributeName, "attribute value");
* ```
*
* @param {String} attributeName The attribute name.
* @return {String} The encoded attribute name.
*
*/
encoder.encode = function(name) {
var encoded = name;
// encode or convert camelCase attributes unless in list of attributes
// where case matters
if (!caseMattersAttributes[encoded] && encoded.match(regexes.camelCase)) {
// encode uppercase characters in new bindings
// - on:fooBar, fooBar:to, fooBar:from, fooBar:bind
if (
startsWith(encoded, 'on:') ||
endsWith(encoded, ':to') ||
endsWith(encoded, ':from') ||
endsWith(encoded, ':bind') ||
endsWith(encoded, ':raw')
) {
encoded = encoded
.replace(regexes.uppercase, function(char) {
return delimiters.prependUppercase + char.toLowerCase();
});
} else if(startsWith(encoded, '(') || startsWith(encoded, '{')) {
// convert uppercase characters in older bindings to kebab-case
// - {fooBar}, (fooBar), {(fooBar)}
encoded = encoded.replace(regexes.camelCase, camelCaseToSpinalCase);
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
dev.warn("can-attribute-encoder: Found attribute with name: " + name + ". Converting to: " + encoded + '.');
}
//!steal-remove-end
}
}
//encode spaces
encoded = encoded.replace(regexes.space, delimiters.replaceSpace)
//encode forward slashes
.replace(regexes.forwardSlash, delimiters.replaceForwardSlash)
// encode left parentheses
.replace(regexes.leftParens, delimiters.replaceLeftParens)
// encode right parentheses
.replace(regexes.rightParens, delimiters.replaceRightParens)
// encode left braces
.replace(regexes.leftBrace, delimiters.replaceLeftBrace)
// encode left braces
.replace(regexes.rightBrace, delimiters.replaceRightBrace)
// encode ^
.replace(regexes.caret, delimiters.replaceCaret)
// encode $
.replace(regexes.dollar, delimiters.replaceDollar)
// encode @
.replace(regexes.at, delimiters.replaceAt);
return encoded;
};
/**
* @function can-attribute-encoder.decode decode
* @parent can-attribute-encoder
* @description Decode an attribute name encoded by [can-attribute-encoder.encode]
* @signature `encoder.decode(attributeName)`
*
* @body
*
* ```js
* encoder.decode(attributeName); // -> "{(^$foo/bar baz)}"
*
* ```
*
* @param {String} attributeName The encoded attribute name.
* @return {String} The decoded attribute name.
*
*/
encoder.decode = function(name) {
var decoded = name;
// decode uppercase characters in new bindings
if (!caseMattersAttributes[decoded] && regexes.uppercaseDelimiterThenChar.test(decoded)) {
if (
startsWith(decoded, 'on:') ||
endsWith(decoded, ':to') ||
endsWith(decoded, ':from') ||
endsWith(decoded, ':bind') ||
endsWith(decoded, ':raw')
) {
decoded = decoded
.replace(regexes.uppercaseDelimiterThenChar, function(match, char) {
return char.toUpperCase();
});
}
}
// decode left parentheses
decoded = decoded.replace(delimiters.replaceLeftParens, '(')
// decode right parentheses
.replace(delimiters.replaceRightParens, ')')
// decode left braces
.replace(delimiters.replaceLeftBrace, '{')
// decode left braces
.replace(delimiters.replaceRightBrace, '}')
// decode forward slashes
.replace(delimiters.replaceForwardSlash, '/')
// decode spaces
.replace(delimiters.replaceSpace, ' ')
// decode ^
.replace(delimiters.replaceCaret, '^')
//decode $
.replace(delimiters.replaceDollar, '$')
//decode @
.replace(delimiters.replaceAt, '@');
return decoded;
};
if (canNamespace_1_0_0_canNamespace.encoder) {
throw new Error("You can't have two versions of can-attribute-encoder, check your dependencies");
} else {
module.exports = canNamespace_1_0_0_canNamespace.encoder = encoder;
}
});
/* jshint maxdepth:7,node:true, latedef:false */
function each(items, callback){
for ( var i = 0; i < items.length; i++ ) {
callback(items[i], i);
}
}
function makeMap$1(str){
var obj = {}, items = str.split(",");
each(items, function(name){
obj[name] = true;
});
return obj;
}
function handleIntermediate(intermediate, handler){
for(var i = 0, len = intermediate.length; i < len; i++) {
var item = intermediate[i];
handler[item.tokenType].apply(handler, item.args);
}
return intermediate;
}
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
//assign the function to a var to avoid jshint
//"Function declarations should not be placed in blocks"
var countLines = function countLines(input) {
// TODO: optimize?
return input.split('\n').length - 1;
};
}
//!steal-remove-end
var alphaNumeric = "A-Za-z0-9",
alphaNumericHU = "-:_"+alphaNumeric,
magicStart = "{{",
endTag = new RegExp("^<\\/(["+alphaNumericHU+"]+)[^>]*>"),
magicMatch = new RegExp("\\{\\{(![\\s\\S]*?!|[\\s\\S]*?)\\}\\}\\}?","g"),
space = /\s/,
alphaRegex = new RegExp('['+ alphaNumeric + ']'),
attributeRegexp = new RegExp("["+alphaNumericHU+"]+\s*=\s*(\"[^\"]*\"|'[^']*')");
// Empty Elements - HTML 5
var empty = makeMap$1("area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed");
// Elements for which tag case matters - shouldn't be lowercased.
var caseMattersElements = makeMap$1("altGlyph,altGlyphDef,altGlyphItem,animateColor,animateMotion,animateTransform,clipPath,feBlend,feColorMatrix,feComponentTransfer,feComposite,feConvolveMatrix,feDiffuseLighting,feDisplacementMap,feDistantLight,feFlood,feFuncA,feFuncB,feFuncG,feFuncR,feGaussianBlur,feImage,feMerge,feMergeNode,feMorphology,feOffset,fePointLight,feSpecularLighting,feSpotLight,feTile,feTurbulence,foreignObject,glyphRef,linearGradient,radialGradient,textPath");
// Elements that you can, intentionally, leave open
// (and which close themselves)
var closeSelf = makeMap$1("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr");
// Special Elements (can contain anything)
var special = makeMap$1("script");
// Callback names on `handler`.
var tokenTypes = "start,end,close,attrStart,attrEnd,attrValue,chars,comment,special,done".split(",");
//maps end characters to start characters
var startOppositesMap = {"{": "}", "(":")"};
var fn = function(){};
var HTMLParser = function (html, handler, returnIntermediate) {
if(typeof html === "object") {
return handleIntermediate(html, handler);
}
var intermediate = [];
handler = handler || {};
if(returnIntermediate) {
// overwrite handlers so they add to intermediate
each(tokenTypes, function(name){
var callback = handler[name] || fn;
handler[name] = function(){
if( callback.apply(this, arguments) !== false ) {
var end = arguments.length;
// the intermediate is stringified in the compiled stache templates
// so we want to trim the last item if it is the line number
if (arguments[end - 1] === undefined) {
end = arguments.length - 1;
}
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
// but restore line number in dev mode
end = arguments.length;
}
//!steal-remove-end
intermediate.push({
tokenType: name,
args: [].slice.call(arguments, 0, end),
});
}
};
});
}
function parseStartTag(tag, tagName, rest, unary) {
tagName = caseMattersElements[tagName] ? tagName : tagName.toLowerCase();
if (closeSelf[tagName] && stack.last() === tagName) {
parseEndTag("", tagName);
}
unary = empty[tagName] || !!unary;
handler.start(tagName, unary, lineNo);
if (!unary) {
stack.push(tagName);
}
// find attribute or special
HTMLParser.parseAttrs(rest, handler, lineNo);
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
lineNo += countLines(tag);
}
//!steal-remove-end
handler.end(tagName, unary, lineNo);
if(tagName === "html") {
skipChars = true;
}
}
function parseEndTag(tag, tagName) {
// If no tag name is provided, clean shop
var pos;
if (!tagName) {
pos = 0;
}
// Find the closest opened tag of the same type
else {
tagName = caseMattersElements[tagName] ? tagName : tagName.toLowerCase();
for (pos = stack.length - 1; pos >= 0; pos--) {
if (stack[pos] === tagName) {
break;
}
}
}
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
if (typeof tag === 'undefined') {
if (stack.length > 0) {
if (handler.filename) {
dev.warn(handler.filename + ": expected closing tag " + stack[pos] + ">");
}
else {
dev.warn("expected closing tag " + stack[pos] + ">");
}
}
} else if (pos < 0 || pos !== stack.length - 1) {
if (stack.length > 0) {
if (handler.filename) {
dev.warn(handler.filename + ":" + lineNo + ": unexpected closing tag " + tag + " expected " + stack[stack.length - 1] + ">");
}
else {
dev.warn(lineNo + ": unexpected closing tag " + tag + " expected " + stack[stack.length - 1] + ">");
}
} else {
if (handler.filename) {
dev.warn(handler.filename + ":" + lineNo + ": unexpected closing tag " + tag);
}
else {
dev.warn(lineNo + ": unexpected closing tag " + tag);
}
}
}
}
//!steal-remove-end
if (pos >= 0) {
// Close all the open elements, up the stack
for (var i = stack.length - 1; i >= pos; i--) {
if (handler.close) {
handler.close(stack[i], lineNo);
}
}
// Remove the open elements from the stack
stack.length = pos;
// Don't add TextNodes after the tag
if(tagName === "body") {
skipChars = true;
}
}
}
function parseMustache(mustache, inside){
if(handler.special){
handler.special(inside, lineNo);
}
}
var callChars = function(){
if(charsText && !skipChars) {
if(handler.chars) {
handler.chars(charsText, lineNo);
}
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
lineNo += countLines(charsText);
}
//!steal-remove-end
}
skipChars = false;
charsText = "";
};
var index,
chars,
skipChars,
match,
lineNo,
stack = [],
last = html,
// an accumulating text for the next .chars callback
charsText = "";
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
lineNo = 1;
}
//!steal-remove-end
stack.last = function () {
return this[this.length - 1];
};
while (html) {
chars = true;
// Make sure we're not in a script or style element
if (!stack.last() || !special[stack.last()]) {
// Comment
if (html.indexOf("");
if (index >= 0) {
callChars();
if (handler.comment) {
handler.comment(html.substring(4, index), lineNo);
}
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
lineNo += countLines(html.substring(0, index + 3));
}
//!steal-remove-end
html = html.substring(index + 3);
chars = false;
}
// end tag
} else if (html.indexOf("") === 0) {
match = html.match(endTag);
if (match) {
callChars();
match[0].replace(endTag, parseEndTag);
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
lineNo += countLines(html.substring(0, match[0].length));
}
//!steal-remove-end
html = html.substring(match[0].length);
chars = false;
}
// start tag
} else if (html.indexOf("<") === 0) {
var res = HTMLParser.searchStartTag(html);
if(res) {
callChars();
parseStartTag.apply(null, res.match);
html = res.html;
chars = false;
}
// magic tag
} else if (html.indexOf(magicStart) === 0 ) {
match = html.match(magicMatch);
if (match) {
callChars();
match[0].replace(magicMatch, parseMustache);
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
lineNo += countLines(html.substring(0, match[0].length));
}
//!steal-remove-end
html = html.substring(match[0].length);
}
}
if (chars) {
index = findBreak(html, magicStart);
if(index === 0 && html === last) {
charsText += html.charAt(0);
html = html.substr(1);
index = findBreak(html, magicStart);
}
var text = index < 0 ? html : html.substring(0, index);
html = index < 0 ? "" : html.substring(index);
if (text) {
charsText += text;
}
}
} else {
html = html.replace(new RegExp("([\\s\\S]*?)<\/" + stack.last() + "[^>]*>"), function (all, text) {
text = text.replace(/|/g, "$1$2");
if (handler.chars) {
handler.chars(text, lineNo);
}
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
lineNo += countLines(text);
}
//!steal-remove-end
return "";
});
parseEndTag("", stack.last());
}
if (html === last) {
throw new Error("Parse Error: " + html);
}
last = html;
}
callChars();
// Clean up any remaining tags
parseEndTag();
handler.done(lineNo);
return intermediate;
};
var callAttrStart = function(state, curIndex, handler, rest, lineNo){
var attrName = rest.substring(typeof state.nameStart === "number" ? state.nameStart : curIndex, curIndex),
newAttrName = canAttributeEncoder_1_1_4_canAttributeEncoder.encode(attrName);
state.attrStart = newAttrName;
handler.attrStart(state.attrStart, lineNo);
state.inName = false;
};
var callAttrEnd = function(state, curIndex, handler, rest, lineNo){
if(state.valueStart !== undefined && state.valueStart < curIndex) {
var val = rest.substring(state.valueStart, curIndex);
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
var quotedVal, closedQuote;
quotedVal = rest.substring(state.valueStart - 1, curIndex + 1);
quotedVal = quotedVal.trim();
closedQuote = quotedVal.charAt(quotedVal.length - 1);
if (state.inQuote !== closedQuote) {
if (handler.filename) {
dev.warn(handler.filename + ":" + lineNo + ": End quote is missing for " + val);
} else {
dev.warn(lineNo + ": End quote is missing for " + val);
}
}
}
//!steal-remove-end
handler.attrValue(val, lineNo);
}
// if this never got to be inValue, like `DISABLED` then send a attrValue
// else if(!state.inValue){
// handler.attrValue(state.attrStart, lineNo);
// }
handler.attrEnd(state.attrStart, lineNo);
state.attrStart = undefined;
state.valueStart = undefined;
state.inValue = false;
state.inName = false;
state.lookingForEq = false;
state.inQuote = false;
state.lookingForName = true;
};
var findBreak = function(str, magicStart) {
var magicLength = magicStart.length;
for(var i = 0, len = str.length; i < len; i++) {
if(str[i] === "<" || str.substr(i, magicLength) === magicStart) {
return i;
}
}
return -1;
};
HTMLParser.parseAttrs = function(rest, handler, lineNo){
if(!rest) {
return;
}
var i = 0;
var curIndex;
var state = {
inName: false,
nameStart: undefined,
inValue: false,
valueStart: undefined,
inQuote: false,
attrStart: undefined,
lookingForName: true,
lookingForValue: false,
lookingForEq : false
};
while(i < rest.length) {
curIndex = i;
var cur = rest.charAt(i);
i++;
if(magicStart === rest.substr(curIndex, magicStart.length) ) {
if(state.inValue && curIndex > state.valueStart) {
handler.attrValue(rest.substring(state.valueStart, curIndex), lineNo);
}
// `{{#foo}}DISABLED{{/foo}}`
else if(state.inName && state.nameStart < curIndex) {
callAttrStart(state, curIndex, handler, rest, lineNo);
callAttrEnd(state, curIndex, handler, rest, lineNo);
}
// foo={{bar}}
else if(state.lookingForValue){
state.inValue = true;
}
// a {{bar}}
else if(state.lookingForEq && state.attrStart) {
callAttrEnd(state, curIndex, handler, rest, lineNo);
}
magicMatch.lastIndex = curIndex;
var match = magicMatch.exec(rest);
if(match) {
handler.special(match[1], lineNo);
// i is already incremented
i = curIndex + (match[0].length);
if(state.inValue) {
state.valueStart = curIndex+match[0].length;
}
}
}
else if(state.inValue) {
if(state.inQuote) {
if(cur === state.inQuote) {
callAttrEnd(state, curIndex, handler, rest, lineNo);
}
}
else if(space.test(cur)) {
callAttrEnd(state, curIndex, handler, rest, lineNo);
}
}
// if we hit an = outside a value
else if(cur === "=" && (state.lookingForEq || state.lookingForName || state.inName)) {
// if we haven't yet started this attribute `{{}}=foo` case:
if(!state.attrStart) {
callAttrStart(state, curIndex, handler, rest, lineNo);
}
state.lookingForValue = true;
state.lookingForEq = false;
state.lookingForName = false;
}
// if we are currently in a name:
// when the name starts with `{` or `(`
// it isn't finished until the matching end character is found
// otherwise, a space finishes the name
else if(state.inName) {
var started = rest[ state.nameStart ],
otherStart, otherOpposite;
if(startOppositesMap[started] === cur) {
//handle mismatched brackets: `{(})` or `({)}`
otherStart = started === "{" ? "(" : "{";
otherOpposite = startOppositesMap[otherStart];
if(rest[curIndex+1] === otherOpposite){
callAttrStart(state, curIndex+2, handler, rest, lineNo);
i++;
}else{
callAttrStart(state, curIndex+1, handler, rest, lineNo);
}
state.lookingForEq = true;
}
else if(space.test(cur) && started !== "{" && started !== "(") {
callAttrStart(state, curIndex, handler, rest, lineNo);
state.lookingForEq = true;
}
}
else if(state.lookingForName) {
if(!space.test(cur)) {
// might have just started a name, we need to close it
if(state.attrStart) {
callAttrEnd(state, curIndex, handler, rest, lineNo);
}
state.nameStart = curIndex;
state.inName = true;
}
}
else if(state.lookingForValue) {
if(!space.test(cur)) {
state.lookingForValue = false;
state.inValue = true;
if(cur === "'" || cur === '"') {
state.inQuote = cur;
state.valueStart = curIndex+1;
} else {
state.valueStart = curIndex;
}
// if we are looking for a value
// at the end of the loop we need callAttrEnd
} else if (i === rest.length){
callAttrEnd(state, curIndex, handler, rest, lineNo);
}
}
}
if(state.inName) {
callAttrStart(state, curIndex+1, handler, rest, lineNo);
callAttrEnd(state, curIndex+1, handler, rest, lineNo);
} else if(state.lookingForEq || state.lookingForValue || state.inValue) {
callAttrEnd(state, curIndex+1, handler, rest, lineNo);
}
magicMatch.lastIndex = 0;
};
HTMLParser.searchStartTag = function (html) {
var closingIndex = html.indexOf('>');
// The first closing bracket we find might be in an attribute value.
// Move through the attributes by regexp.
var attributeRange = attributeRegexp.exec(html.substring(1));
var afterAttributeOffset = 1;
// if the closing index is after the next attribute...
while(attributeRange && closingIndex >= afterAttributeOffset + attributeRange.index) {
// prepare to move to the attribute after this one by increasing the offset
afterAttributeOffset += attributeRange.index + attributeRange[0].length;
// if the closing index is before the new offset, then this closing index is inside
// an attribute value and should be ignored. Find the *next* closing character.
while(closingIndex < afterAttributeOffset) {
closingIndex += html.substring(closingIndex + 1).indexOf('>') + 1;
}
// find the next attribute by starting from the new offset.
attributeRange = attributeRegexp.exec(html.substring(afterAttributeOffset));
}
// if there is no closing bracket
//
// it is not a startTag
if(closingIndex === -1 || !(alphaRegex.test(html[1]))){
return null;
}
var tagName, tagContent, match, rest = '', unary = '';
var startTag = html.substring(0, closingIndex + 1);
var isUnary = startTag[startTag.length-2] === '/';
var spaceIndex = startTag.search(space);
if(isUnary){
unary = '/';
tagContent = startTag.substring(1, startTag.length-2).trim();
} else {
tagContent = startTag.substring(1, startTag.length-1).trim();
}
if(spaceIndex === -1){
tagName = tagContent;
} else {
//spaceIndex needs to shift one to the left
spaceIndex--;
tagName = tagContent.substring(0, spaceIndex);
rest = tagContent.substring(spaceIndex);
}
match = [startTag, tagName, rest, unary];
return {
match: match,
html: html.substring(startTag.length),
};
};
var canViewParser_4_1_3_canViewParser = canNamespace_1_0_0_canNamespace.HTMLParser = HTMLParser;
/**
* @module {function} can-globals/location/location location
* @parent can-globals/modules
*
* Get the global [`location`](https://developer.mozilla.org/en-US/docs/Web/API/Window/location) object for the current context.
*
* @signature `LOCATION([newLocation])`
*
* Optionally sets, and returns, the [`location`](https://developer.mozilla.org/en-US/docs/Web/API/Window/location) object for the context.
*
* ```js
* var locationShim = { path: '/' };
* var LOCATION = require('can-globals/location/location');
* LOCATION(locationShim);
* LOCATION().path; // -> '/'
* ```
*
* @param {Object} location An optional location-like object to set as the context's location
*
* @return {Object} The location object for this JavaScript environment.
*/
canGlobals_1_2_2_canGlobalsInstance.define('location', function(){
return canGlobals_1_2_2_canGlobalsInstance.getKeyValue('global').location;
});
var location_1 = canGlobals_1_2_2_canGlobalsInstance.makeExport('location');
/**
* @module {function} can-globals/mutation-observer/mutation-observer mutation-observer
* @parent can-globals/modules
*
* Get the global [`MutationObserver`](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) object for the current context.
*
* @signature `MUTATIONOBSERVER([newMutationObserver])`
*
* Optionally sets, and returns, the [`MutationObserver`](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) object for the context.
*
* ```js
* var mutationObserverShim = require('can-globals/mutation-observer/mutation-observer');
* MUTATIONOBSERVER(mutationObserverShim);
* MUTATIONOBSERVER() //-> MutationObserver
* ```
*
* @param {Object} MutationObserver An optional MutationObserver-like object to set as the context's MutationObserver
*
* @return {Object} The MutationObserver object for this JavaScript environment.
*/
canGlobals_1_2_2_canGlobalsInstance.define('MutationObserver', function(){
var GLOBAL = canGlobals_1_2_2_canGlobalsInstance.getKeyValue('global');
return GLOBAL.MutationObserver || GLOBAL.WebKitMutationObserver || GLOBAL.MozMutationObserver;
});
var mutationObserver = canGlobals_1_2_2_canGlobalsInstance.makeExport('MutationObserver');
/**
* @module {function} can-globals/custom-elements/custom-elements custom-elements
* @parent can-globals/modules
*
* Get the global [`customElements`](https://developer.mozilla.org/en-US/docs/Web/API/Window/customElements) object for the current context.
*
* @signature `CUSTOMELEMENTS([newCustomElements])`
*
* Optionally sets, and returns, the [`customElements`](https://developer.mozilla.org/en-US/docs/Web/API/Window/customElements) object for the context.
*
* ```js
* var customElementsShim = require('some-custom-elements-shim');
* CUSTOMELEMENTS(customElementsShim);
* CUSTOMELEMENTS() //-> customElementsShim
* ```
*
* @param {Object} customElements An optional CustomElementRegistry-like object to set as the context's customElements
*
* @return {Object} The customElements object for this JavaScript environment.
*/
canGlobals_1_2_2_canGlobalsInstance.define('customElements', function(){
var GLOBAL = canGlobals_1_2_2_canGlobalsInstance.getKeyValue('global');
return GLOBAL.customElements;
});
var customElements = canGlobals_1_2_2_canGlobalsInstance.makeExport('customElements');
var canGlobals_1_2_2_canGlobals = canGlobals_1_2_2_canGlobalsInstance;
function eliminate(array, item) {
var index = array.indexOf(item);
if (index >= 0) {
array.splice(index, 1);
}
}
function wasNotInSet(item, set) {
var inSet = set.has(item);
if(inSet === false) {
set.add(item);
}
return !inSet;
}
function contains(parent, child){
if(child && child.nodeType === Node.TEXT_NODE) {
return contains(parent, child.parentNode);
}
if(parent.contains) {
return parent.contains(child);
}
if(parent.nodeType === Node.DOCUMENT_NODE && parent.documentElement) {
return contains(parent.documentElement, child);
} else {
child = child.parentNode;
if(child === parent) {
return true;
}
return false;
}
}
function isDocumentElement (node) {
return document$1().documentElement === node;
}
function isFragment (node) {
return !!(node && node.nodeType === 11);
}
function isElementNode (node) {
return !!(node && node.nodeType === 1);
}
function getChildren (parentNode) {
var nodes = [];
var node = parentNode.firstChild;
while (node) {
nodes.push(node);
node = node.nextSibling;
}
return nodes;
}
function getParents (node) {
var nodes;
if (isFragment(node)) {
nodes = getChildren(node);
} else {
nodes = [node];
}
return nodes;
}
function getNodesLegacyB(node) {
var skip, tmp;
var depth = 0;
var items = isFragment(node) ? [] : [node];
if(node.firstChild == null) {
return items;
}
// Always start with the initial element.
do {
if ( !skip && (tmp = node.firstChild) ) {
depth++;
items.push(tmp);
} else if ( tmp = node.nextSibling ) {
skip = false;
items.push(tmp);
} else {
// Skipped or no first child and no next sibling, so traverse upwards,
tmp = node.parentNode;
// and decrement the depth.
depth--;
// Enable skipping, so that in the next loop iteration, the children of
// the now-current node (parent node) aren't processed again.
skip = true;
}
// Instead of setting node explicitly in each conditional block, use the
// tmp var and set it here.
node = tmp;
// Stop if depth comes back to 0 (or goes below zero, in conditions where
// the passed node has neither children nore next siblings).
} while ( depth > 0 );
return items;
}
// IE11 requires a filter parameter for createTreeWalker
// it also must be an object with an `acceptNode` property
function treeWalkerFilterFunction() {
return NodeFilter.FILTER_ACCEPT;
}
var treeWalkerFilter = treeWalkerFilterFunction;
treeWalkerFilter.acceptNode = treeWalkerFilterFunction;
function getNodesWithTreeWalker(rootNode) {
var result = isFragment(rootNode) ? [] : [rootNode];
// IE11 throws if createTreeWalker is called on a non-ElementNode
var walker = isElementNode(rootNode) && document$1().createTreeWalker(
rootNode,
NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT,
treeWalkerFilter,
false
);
var node;
while(node = walker && walker.nextNode()) {
result.push(node);
}
return result;
}
function getAllNodes (node) {
if( document$1().createTreeWalker !== undefined ) {
return getNodesWithTreeWalker(node);
} else {
return getNodesLegacyB(node);
}
}
function subscription (fn) {
return function _subscription () {
var disposal = fn.apply(this, arguments);
var isDisposed = false;
return function _disposal () {
if (isDisposed) {
var fnName = fn.name || fn.displayName || 'an anonymous function';
var message = 'Disposal function returned by ' + fnName + ' called more than once.';
throw new Error(message);
}
disposal.apply(this, arguments);
isDisposed = true;
};
};
}
var canDomMutate_2_0_9_Util = {
eliminate: eliminate,
getDocument: document$1,
isDocumentElement: isDocumentElement,
isFragment: isFragment,
getParents: getParents,
getAllNodes: getAllNodes,
getChildren: getChildren,
subscription: subscription,
wasNotInSet: wasNotInSet,
contains: contains
};
var contains$1 = canDomMutate_2_0_9_Util.contains;
var mutate = {};
var isConnected;
function getIsConnectedFromNode(node) {
return node.isConnected;
}
function getIsConnectedFromDocument(node) {
var doc = node.ownerDocument;
// if node *is* the document, ownerDocument is null
// However, CanSimpleDom implements this incorrectly, and a document's ownerDocument is itself,
// so make both checks
return doc === null || doc === node || contains$1(doc, node);
}
function setIsConnected(doc) {
if(doc) {
var node = doc.createTextNode("");
isConnected = 'isConnected' in node.constructor.prototype ?
getIsConnectedFromNode :
getIsConnectedFromDocument;
if(mutate) {
mutate.isConnected = isConnected;
}
} else {
mutate.isConnected = getIsConnectedFromNode;
}
}
setIsConnected(canGlobals_1_2_2_canGlobals.getKeyValue("document"));
canGlobals_1_2_2_canGlobals.onKeyValue("document", setIsConnected);
var canDomMutate_2_0_9_IsConnected = mutate;
var eliminate$1 = canDomMutate_2_0_9_Util.eliminate;
var subscription$1 = canDomMutate_2_0_9_Util.subscription;
var isDocumentElement$1 = canDomMutate_2_0_9_Util.isDocumentElement;
var getAllNodes$1 = canDomMutate_2_0_9_Util.getAllNodes;
var domMutate,
dispatchNodeInserted,
dispatchNodeConnected,
dispatchGlobalConnected,
dispatchNodeRemoved,
dispatchNodeDisconnected,
dispatchGlobalDisconnected,
dispatchAttributeChange;
var dataStore = new WeakMap();
var queue;
function getRelatedData(node, key) {
var data = dataStore.get(node);
if (data) {
return data[key];
}
}
function setRelatedData(node, key, targetListenersMap) {
var data = dataStore.get(node);
if (!data) {
data = {};
dataStore.set(node, data);
}
data[key] = targetListenersMap;
}
function deleteRelatedData(node, key) {
var data = dataStore.get(node);
return delete data[key];
}
function toMutationEvent(node, mutation) {
return {target: node, sourceMutation: mutation};
}
function getDocumentListeners (target, key) {
// TODO: it's odd these functions read DOCUMENT() instead of
// target.ownerDocument. To change to ownerDocument, we might need a "is document"
// check.
var doc = document$1();
var data = getRelatedData(doc, key);
if (data) {
return data.listeners;
}
}
function getTargetListeners (target, key) {
var doc = document$1();
var targetListenersMap = getRelatedData(doc, key);
if (!targetListenersMap) {
return;
}
return targetListenersMap.get(target);
}
function addTargetListener (target, key, listener) {
var doc = document$1();
var targetListenersMap = getRelatedData(doc, key);
if (!targetListenersMap) {
targetListenersMap = new WeakMap();
setRelatedData(doc, key, targetListenersMap);
}
var targetListeners = targetListenersMap.get(target);
if (!targetListeners) {
targetListeners = [];
targetListenersMap.set(target, targetListeners);
}
targetListeners.push(listener);
}
function removeTargetListener (target, key, listener) {
var doc = document$1();
var targetListenersMap = getRelatedData(doc, key);
if (!targetListenersMap) {
return;
}
var targetListeners = targetListenersMap.get(target);
if (!targetListeners) {
return;
}
eliminate$1(targetListeners, listener);
if (targetListeners.length === 0) {
targetListenersMap['delete'](target);
if (targetListenersMap.size === 0) {
deleteRelatedData(doc, key);
}
}
}
var promise = Promise.resolve();
function nextTick(handler) {
promise.then(handler);
}
//var recordsAndCallbacks = null;
function flushCallbacks(callbacks, arg){
var callbacksCount = callbacks.length;
var safeCallbacks = callbacks.slice(0);
for(var c = 0; c < callbacksCount; c++){
safeCallbacks[c](arg);
}
}
function dispatch$1(getListeners, targetKey) {
return function dispatchEvents(event) {
var targetListeners = getListeners(event.target, targetKey);
if (targetListeners) {
flushCallbacks(targetListeners, event);
}
};
}
var count = 0;
function observeMutations(target, observerKey, config, handler) {
var observerData = getRelatedData(target, observerKey);
if (!observerData) {
observerData = {
observingCount: 0
};
setRelatedData(target, observerKey, observerData);
}
var setupObserver = function () {
// disconnect the old one
if (observerData.observer) {
observerData.observer.disconnect();
observerData.observer = null;
}
var MutationObserver = mutationObserver();
if (MutationObserver) {
var Node = global_1().Node;
var isRealNode = !!(Node && target instanceof Node);
if (isRealNode) {
var targetObserver = new MutationObserver(handler);
targetObserver.id = count++;
targetObserver.observe(target, config);
observerData.observer = targetObserver;
}
}
};
if (observerData.observingCount === 0) {
canGlobals_1_2_2_canGlobals.onKeyValue('MutationObserver', setupObserver);
setupObserver();
}
observerData.observingCount++;
return function stopObservingMutations() {
var observerData = getRelatedData(target, observerKey);
if (observerData) {
observerData.observingCount--;
if (observerData.observingCount <= 0) {
if (observerData.observer) {
observerData.observer.disconnect();
}
deleteRelatedData(target, observerKey);
canGlobals_1_2_2_canGlobals.offKeyValue('MutationObserver', setupObserver);
}
}
};
}
var treeMutationConfig = {
subtree: true,
childList: true
};
var attributeMutationConfig = {
attributes: true,
attributeOldValue: true
};
function addNodeListener(listenerKey, observerKey, isAttributes) {
return subscription$1(function _addNodeListener(target, listener) {
// DocumentFragment
if(target.nodeType === 11) {
// This returns a noop without actually doing anything.
// We should probably warn about passing a DocumentFragment here,
// but since can-stache does so currently we are ignoring until that is
// fixed.
return Function.prototype;
}
var stopObserving;
if (isAttributes) {
stopObserving = observeMutations(target, observerKey, attributeMutationConfig, queue.enqueueAndFlushMutations);
} else {
stopObserving = observeMutations(document$1(), observerKey, treeMutationConfig, queue.enqueueAndFlushMutations);
}
addTargetListener(target, listenerKey, listener);
return function removeNodeListener() {
if(stopObserving) {
stopObserving();
}
removeTargetListener(target, listenerKey, listener);
};
});
}
function addGlobalListener(globalDataKey, addNodeListener) {
return subscription$1(function addGlobalGroupListener(documentElement, listener) {
if (!isDocumentElement$1(documentElement)) {
throw new Error('Global mutation listeners must pass a documentElement');
}
var doc = document$1();
var documentData = getRelatedData(doc, globalDataKey);
if (!documentData) {
documentData = {listeners: []};
setRelatedData(doc, globalDataKey, documentData);
}
var listeners = documentData.listeners;
if (listeners.length === 0) {
// We need at least on listener for mutation events to propagate
documentData.removeListener = addNodeListener(doc, function () {});
}
listeners.push(listener);
return function removeGlobalGroupListener() {
var documentData = getRelatedData(doc, globalDataKey);
if (!documentData) {
return;
}
var listeners = documentData.listeners;
eliminate$1(listeners, listener);
if (listeners.length === 0) {
documentData.removeListener();
deleteRelatedData(doc, globalDataKey);
}
};
});
}
var domMutationPrefix = 'domMutation';
// target listener keys
var connectedDataKey = domMutationPrefix + 'ConnectedData';
var disconnectedDataKey = domMutationPrefix + 'DisconnectedData';
var insertedDataKey = domMutationPrefix + 'InsertedData';
var removedDataKey = domMutationPrefix + 'RemovedData';
var attributeChangeDataKey = domMutationPrefix + 'AttributeChangeData';
// document listener keys
var documentConnectedDataKey = domMutationPrefix + 'DocumentConnectedData';
var documentDisconnectedDataKey = domMutationPrefix + 'DocumentDisconnectedData';
var documentAttributeChangeDataKey = domMutationPrefix + 'DocumentAttributeChangeData';
// observer keys
var treeDataKey = domMutationPrefix + 'TreeData';
var attributeDataKey = domMutationPrefix + 'AttributeData';
dispatchNodeInserted = dispatch$1(getTargetListeners, insertedDataKey);
dispatchNodeConnected = dispatch$1(getTargetListeners, connectedDataKey);
dispatchGlobalConnected = dispatch$1(getDocumentListeners, documentConnectedDataKey);
dispatchNodeRemoved = dispatch$1(getTargetListeners, removedDataKey);
dispatchNodeDisconnected = dispatch$1(getTargetListeners, disconnectedDataKey);
dispatchGlobalDisconnected = dispatch$1(getDocumentListeners, documentDisconnectedDataKey);
dispatchAttributeChange = dispatch$1(getTargetListeners, attributeChangeDataKey);
// node listeners
var addNodeConnectedListener = addNodeListener(connectedDataKey, treeDataKey);
var addNodeDisconnectedListener = addNodeListener(disconnectedDataKey, treeDataKey);
var addNodeInsertedListener = addNodeListener(insertedDataKey, treeDataKey);
var addNodeRemovedListener = addNodeListener(removedDataKey, treeDataKey);
var addNodeAttributeChangeListener = addNodeListener(attributeChangeDataKey, attributeDataKey, true);
// global listeners
var addConnectedListener = addGlobalListener(
documentConnectedDataKey,
addNodeConnectedListener
);
var addDisconnectedListener = addGlobalListener(
documentDisconnectedDataKey,
addNodeDisconnectedListener
);
var addAttributeChangeListener = addGlobalListener(
documentAttributeChangeDataKey,
addNodeAttributeChangeListener
);
// ==========================================
function dispatchTreeMutation(mutation, processedState) {
// was the mutation connected
var wasConnected = mutation.isConnected === true || mutation.isConnected === undefined;
// there are
// - the global connected
// - individual connected
// - individual inserted
var removedCount = mutation.removedNodes.length;
for (var r = 0; r < removedCount; r++) {
// get what already isn't in `removed`
// see if "removed"
// if wasConnected .. dispatch disconnected
var removedNodes = getAllNodes$1(mutation.removedNodes[r]);
removedNodes.forEach(function(node){
var event = toMutationEvent(node, mutation);
if( canDomMutate_2_0_9_Util.wasNotInSet(node, processedState.removed) ) {
dispatchNodeRemoved( event );
}
if(wasConnected && canDomMutate_2_0_9_Util.wasNotInSet(node, processedState.disconnected) ) {
dispatchNodeDisconnected( event );
dispatchGlobalDisconnected( event );
}
});
}
var addedCount = mutation.addedNodes.length;
for (var a = 0; a < addedCount; a++) {
var insertedNodes = getAllNodes$1(mutation.addedNodes[a]);
insertedNodes.forEach(function(node){
var event = toMutationEvent(node, mutation);
if(canDomMutate_2_0_9_Util.wasNotInSet(node, processedState.inserted)) {
dispatchNodeInserted( event );
}
if(wasConnected && canDomMutate_2_0_9_Util.wasNotInSet(node, processedState.connected) ) {
dispatchNodeConnected( event );
dispatchGlobalConnected( event );
}
});
}
// run mutation
}
var FLUSHING_MUTATIONS = [];
var IS_FLUSHING = false;
var IS_FLUSH_PENDING = false;
var ENQUEUED_MUTATIONS = [];
queue = {
// This is used to dispatch mutations immediately.
// This is usually called by the result of a mutation observer.
enqueueAndFlushMutations: function(mutations) {
if(IS_FLUSH_PENDING) {
FLUSHING_MUTATIONS = FLUSHING_MUTATIONS.concat(ENQUEUED_MUTATIONS);
IS_FLUSH_PENDING = false;
ENQUEUED_MUTATIONS = [];
}
FLUSHING_MUTATIONS = FLUSHING_MUTATIONS.concat(mutations);
if(IS_FLUSHING) {
return;
}
IS_FLUSHING = true;
var index = 0;
var processedState = {
connected: new Set(),
disconnected: new Set(),
inserted: new Set(),
removed: new Set()
};
while(index < FLUSHING_MUTATIONS.length) {
var mutation = FLUSHING_MUTATIONS[index];
// process mutation
if(mutation.type === "childList") {
dispatchTreeMutation(mutation, processedState);
} else if(mutation.type === "attributes") {
dispatchAttributeChange(mutation);
}
index++;
}
FLUSHING_MUTATIONS = [];
IS_FLUSHING = false;
},
// called to dipatch later unless we are already dispatching.
enqueueMutationsAndFlushAsync: function(mutations){
ENQUEUED_MUTATIONS = ENQUEUED_MUTATIONS.concat(mutations);
// if there are currently dispatching mutations, this should happen sometime after
if(!IS_FLUSH_PENDING) {
IS_FLUSH_PENDING = true;
nextTick(function(){
if(IS_FLUSH_PENDING) {
IS_FLUSH_PENDING = false;
var pending = ENQUEUED_MUTATIONS;
ENQUEUED_MUTATIONS = [];
queue.enqueueAndFlushMutations(pending);
} else {
// Someone called enqueueAndFlushMutations before this finished.
}
});
}
}
};
// ==========================================
domMutate = {
/**
* @function can-dom-mutate.dispatchNodeInsertion dispatchNodeInsertion
* @hide
*
* Dispatch an insertion mutation on the given node.
*
* @signature `dispatchNodeInsertion( node [, callback ] )`
* @parent can-dom-mutate.static
* @param {Node} node The node on which to dispatch an insertion mutation.
*/
dispatchNodeInsertion: function (node, target) {
queue.enqueueMutationsAndFlushAsync(
[{
type: "childList",
target: target,
addedNodes: [node],
isConnected: canDomMutate_2_0_9_IsConnected.isConnected(target),
removedNodes: []
}]
);
/*
var nodes = new Set();
util.addToSet( getAllNodes(node), nodes);
var events = toMutationEvents( canReflect.toArray(nodes) );
// this is basically an array of every single child of node including node
dispatchInsertion(events, callback, dispatchConnected, flushAsync);*/
},
/**
* @function can-dom-mutate.dispatchNodeRemoval dispatchNodeRemoval
* @hide
*
* Dispatch a removal mutation on the given node.
*
* @signature `dispatchNodeRemoval( node [, callback ] )`
* @parent can-dom-mutate.static
* @param {Node} node The node on which to dispatch a removal mutation.
* @param {function} callback The optional callback called after the mutation is dispatched.
*/
dispatchNodeRemoval: function (node, target) {
queue.enqueueMutationsAndFlushAsync(
[{
type: "childList",
target: target,
addedNodes: [],
removedNodes: [node],
isConnected: canDomMutate_2_0_9_IsConnected.isConnected(target)
}]
);
/*
var nodes = new Set();
util.addToSet( getAllNodes(node), nodes);
var events = toMutationEvents( canReflect.toArray(nodes) );
dispatchRemoval(events, callback, dispatchConnected, flushAsync);*/
},
/**
* @function can-dom-mutate.dispatchNodeAttributeChange dispatchNodeAttributeChange
* @parent can-dom-mutate.static
* @hide
*
* Dispatch an attribute change mutation on the given node.
*
* @signature `dispatchNodeAttributeChange( node, attributeName, oldValue [, callback ] )`
*
* ```
* input.setAttribute("value", "newValue")
* domMutate.dispatchNodeAttributeChange(input, "value","oldValue")
* ```
*
*
* @param {Node} target The node on which to dispatch an attribute change mutation.
* @param {String} attributeName The attribute name whose value has changed.
* @param {String} oldValue The attribute value before the change.
*/
dispatchNodeAttributeChange: function (target, attributeName, oldValue) {
queue.enqueueMutationsAndFlushAsync(
[{
type: "attributes",
target: target,
attributeName: attributeName,
oldValue: oldValue
}]
);
},
/**
* @function can-dom-mutate.onNodeConnected onNodeConnected
*
* Listen for insertion mutations on the given node.
*
* @signature `onNodeConnected( node, callback )`
* @parent can-dom-mutate.static
* @param {Node} node The node on which to listen for insertion mutations.
* @param {function} callback The callback called when an insertion mutation is dispatched.
* @return {function} The callback to remove the mutation listener.
*/
onNodeConnected: addNodeConnectedListener,
onNodeInsertion: function(){
// TODO: remove in prod
console.warn("can-dom-mutate: Use onNodeConnected instead of onNodeInsertion");
return addNodeConnectedListener.apply(this, arguments);
},
/**
* @function can-dom-mutate.onNodeDisconnected onNodeDisconnected
*
* Listen for removal mutations on the given node.
*
* @signature `onNodeDisconnected( node, callback )`
* @parent can-dom-mutate.static
* @param {Node} node The node on which to listen for removal mutations.
* @param {function} callback The callback called when a removal mutation is dispatched.
* @return {function} The callback to remove the mutation listener.
*/
onNodeDisconnected: addNodeDisconnectedListener,
onNodeRemoval: function(){
// TODO: remove in prod
console.warn("can-dom-mutate: Use onNodeDisconnected instead of onNodeRemoval");
return addNodeDisconnectedListener.apply(this, arguments);
},
/**
* @function can-dom-mutate.onNodeAttributeChange onNodeAttributeChange
*
* Listen for attribute change mutations on the given node.
*
* @signature `onNodeAttributeChange( node, callback )`
* @parent can-dom-mutate.static
* @param {Node} node The node on which to listen for attribute change mutations.
* @param {function} callback The callback called when an attribute change mutation is dispatched.
* @return {function} The callback to remove the mutation listener.
*/
onNodeAttributeChange: addNodeAttributeChangeListener,
/**
* @function can-dom-mutate.onDisconnected onDisconnected
*
* Listen for removal mutations on any node within the documentElement.
*
* @signature `onDisconnected( documentElement, callback )`
* @parent can-dom-mutate.static
* @param {Node} documentElement The documentElement on which to listen for removal mutations.
* @param {function} callback The callback called when a removal mutation is dispatched.
* @return {function} The callback to remove the mutation listener.
*/
onDisconnected: addDisconnectedListener,
onRemoval: function(){
// TODO: remove in prod
console.warn("can-dom-mutate: Use onDisconnected instead of onRemoval");
return addDisconnectedListener.apply(this, arguments);
},
/**
* @function can-dom-mutate.onConnected onConnected
*
* Listen for insertion mutations on any node within the documentElement.
*
* @signature `onConnected( documentElement, callback )`
* @parent can-dom-mutate.static
* @param {Node} documentElement The documentElement on which to listen for removal mutations.
* @param {function} callback The callback called when a insertion mutation is dispatched.
* @return {function} The callback to remove the mutation listener.
*/
onConnected: addConnectedListener,
onInsertion: function(){
// TODO: remove in prod
console.warn("can-dom-mutate: Use onConnected instead of onInsertion");
return addConnectedListener.apply(this, arguments);
},
/**
* @function can-dom-mutate.onAttributeChange onAttributeChange
*
* Listen for attribute change mutations on any node within the documentElement.
*
* @signature `onAttributeChange( documentElement, callback )`
* @parent can-dom-mutate.static
* @param {Node} documentElement The documentElement on which to listen for removal mutations.
* @param {function} callback The callback called when an attribute change mutation is dispatched.
* @return {function} The callback to remove the mutation listener.
*/
onAttributeChange: addAttributeChangeListener,
flushRecords: function(doc){
doc = doc || document$1();
var data = dataStore.get(doc),
records = [];
if(data) {
if(data.domMutationTreeData && data.domMutationTreeData.observer) {
records = data.domMutationTreeData.observer.takeRecords();
}
}
queue.enqueueAndFlushMutations(records);
},
onNodeInserted: addNodeInsertedListener,
onNodeRemoved: addNodeRemovedListener
};
//!steal-remove-start
if(process.env.NODE_ENV !== "production") {
domMutate.dataStore = dataStore;
}
//!steal-remove-end
var canDomMutate_2_0_9_canDomMutate = canNamespace_1_0_0_canNamespace.domMutate = domMutate;
var getParents$1 = canDomMutate_2_0_9_Util.getParents;
var compat = {
replaceChild: function (newChild, oldChild) {
var newChildren = getParents$1(newChild);
var result = this.replaceChild(newChild, oldChild);
canDomMutate_2_0_9_canDomMutate.dispatchNodeRemoval(oldChild, this);
for (var i = 0; i < newChildren.length; i++) {
canDomMutate_2_0_9_canDomMutate.dispatchNodeInsertion(newChildren[i], this);
}
return result;
},
setAttribute: function (name, value) {
var oldAttributeValue = this.getAttribute(name);
var result = this.setAttribute(name, value);
var newAttributeValue = this.getAttribute(name);
if (oldAttributeValue !== newAttributeValue) {
canDomMutate_2_0_9_canDomMutate.dispatchNodeAttributeChange(this, name, oldAttributeValue);
}
return result;
},
setAttributeNS: function (namespace, name, value) {
var oldAttributeValue = this.getAttribute(name);
var result = this.setAttributeNS(namespace, name, value);
var newAttributeValue = this.getAttribute(name);
if (oldAttributeValue !== newAttributeValue) {
canDomMutate_2_0_9_canDomMutate.dispatchNodeAttributeChange(this, name, oldAttributeValue);
}
return result;
},
removeAttribute: function (name) {
var oldAttributeValue = this.getAttribute(name);
var result = this.removeAttribute(name);
if (oldAttributeValue) {
canDomMutate_2_0_9_canDomMutate.dispatchNodeAttributeChange(this, name, oldAttributeValue);
}
return result;
}
};
var compatData = [
['appendChild', 'Insertion'],
['insertBefore', 'Insertion'],
['removeChild', 'Removal']
];
compatData.forEach(function (pair) {
var nodeMethod = pair[0];
var dispatchMethod = 'dispatchNode' + pair[1];
compat[nodeMethod] = function (node) {
var nodes = getParents$1(node);
var result = this[nodeMethod].apply(this, arguments);
for (var i = 0; i < nodes.length; i++) {
canDomMutate_2_0_9_canDomMutate[dispatchMethod](nodes[i], this);
}
return result;
};
});
var normal = {};
var nodeMethods = ['appendChild', 'insertBefore', 'removeChild', 'replaceChild', 'setAttribute', 'setAttributeNS', 'removeAttribute'];
nodeMethods.forEach(function (methodName) {
normal[methodName] = function () {
if(canDomMutate_2_0_9_IsConnected.isConnected(this)) {
return this[methodName].apply(this, arguments);
} else {
return compat[methodName].apply(this, arguments);
}
};
});
/**
* @module {{}} can-dom-mutate/node node
* @parent can-dom-mutate/modules
*
* Append, insert, and remove DOM nodes. Also, change node attributes.
* This allows mutations to be dispatched in environments where MutationObserver is not supported.
* @signature `mutateNode`
*
* Exports an `Object` with methods that shouhld be used to mutate HTML.
*
* ```js
* var mutateNode = require('can-dom-mutate/node');
* var el = document.createElement('div');
*
* mutateNode.appendChild.call(document.body, el);
*
* ```
*/
var mutate$1 = {};
/**
* @function can-dom-mutate/node.appendChild appendChild
* @parent can-dom-mutate/node
*
* Append a node to an element, effectively `Node.prototype.appendChild`.
*
* @signature `mutate.appendChild.call(parent, child)`
*
* @param {Node} parent The parent into which the child is inserted.
* @param {Node} child The child which will be inserted into the parent.
* @return {Node} The appended child.
*/
/**
* @function can-dom-mutate/node.insertBefore insertBefore
* @parent can-dom-mutate/node
*
* Insert a node before a given reference node in an element, effectively `Node.prototype.insertBefore`.
*
* @signature `mutate.insertBefore.call(parent, child, reference)`
* @param {Node} parent The parent into which the child is inserted.
* @param {Node} child The child which will be inserted into the parent.
* @param {Node} reference The reference which the child will be placed before.
* @return {Node} The inserted child.
*/
/**
* @function can-dom-mutate/node.removeChild removeChild
* @parent can-dom-mutate/node
*
* Remove a node from an element, effectively `Node.prototype.removeChild`.
*
* @signature `mutate.removeChild.call(parent, child)`
*
* @param {Node} parent The parent from which the child is removed.
* @param {Node} child The child which will be removed from the parent.
* @return {Node} The removed child.
*/
/**
* @function can-dom-mutate/node.replaceChild replaceChild
* @parent can-dom-mutate/node
*
* Insert a node before a given reference node in an element, effectively `Node.prototype.replaceChild`.
*
* @signature `mutate.replaceChild.call(parent, newChild, oldChild)`
*
* @param {Node} parent The parent into which the newChild is inserted.
* @param {Node} newChild The child which is inserted into the parent.
* @param {Node} oldChild The child which is removed from the parent.
* @return {Node} The replaced child.
*/
/**
* @function can-dom-mutate/node.setAttribute setAttribute
* @parent can-dom-mutate/node
*
* Set an attribute value on an element, effectively `Element.prototype.setAttribute`.
*
* @signature `mutate.setAttribute.call(element, name, value)`
*
* @param {Element} element The element on which to set the attribute.
* @param {String} name The name of the attribute to set.
* @param {String} value The value to set on the attribute.
*/
/**
* @function can-dom-mutate/node.removeAttribute removeAttribute
* @parent can-dom-mutate/node
*
* Removes an attribute from an element, effectively `Element.prototype.removeAttribute`.
*
* @signature `mutate.removeAttribute.call(element, name, value)`
*
* @param {Element} element The element from which to remove the attribute.
* @param {String} name The name of the attribute to remove.
*/
function setMutateStrategy(observer) {
var strategy = observer ? normal : compat;
for (var key in strategy) {
mutate$1[key] = strategy[key];
}
}
var mutationObserverKey = 'MutationObserver';
setMutateStrategy(canGlobals_1_2_2_canGlobals.getKeyValue(mutationObserverKey));
canGlobals_1_2_2_canGlobals.onKeyValue(mutationObserverKey, setMutateStrategy);
var node = canNamespace_1_0_0_canNamespace.domMutateNode = canDomMutate_2_0_9_canDomMutate.node = mutate$1;
// backwards compatibility
var canDomMutate_2_0_9_node = canNamespace_1_0_0_canNamespace.node = node;
/**
* @module {function} can-child-nodes
* @parent can-dom-utilities
* @collection can-infrastructure
* @package ./package.json
*
* @signature `childNodes(node)`
*
* Get all of the childNodes of a given node.
*
* ```js
* var stache = require("can-stache");
* var childNodes = require("can-util/child-nodes/child-nodes");
*
* var html = "
";
* var frag = stache(html)();
*
* console.log(childNodes(frag)[0].nodeName); // -> DIV
* ```
*
* @param {Object} node The Node that you want child nodes for.
*/
function childNodes(node) {
var childNodes = node.childNodes;
if ("length" in childNodes) {
return childNodes;
} else {
var cur = node.firstChild;
var nodes = [];
while (cur) {
nodes.push(cur);
cur = cur.nextSibling;
}
return nodes;
}
}
var canChildNodes_1_2_1_canChildNodes = canNamespace_1_0_0_canNamespace.childNodes = childNodes;
/**
@module {function} can-fragment
@parent can-dom-utilities
@collection can-infrastructure
@package ./package.json
Convert a String, HTMLElement, documentFragment, contentArray, or object with a `can.toDOM` symbol into a documentFragment.
@signature `fragment(item, doc)`
@param {String|HTMLElement|documentFragment|contentArray} item
@param {Document} doc an optional DOM document in which to build the fragment
@return {documentFragment}
@body
## Use
ContentArrays can be used to combine multiple HTMLElements into a single document fragment. For example:
var fragment = require("can-fragment");
var p = document.createElement("p");
p.innerHTML = "Welcome to CanJS";
var contentArray = ["
Hi There
", p];
var fragment = fragment( contentArray )
`fragment` will be a documentFragment with the following elements:
Hi There
Welcome to CanJS
*/
// fragment.js
// ---------
// _DOM Fragment support._
var fragmentRE = /^\s*<(\w+)[^>]*>/,
toString = {}.toString,
toDOMSymbol = canSymbol_1_7_0_canSymbol.for("can.toDOM");
function makeFragment(html, name, doc) {
if (name === undefined) {
name = fragmentRE.test(html) && RegExp.$1;
}
if (html && toString.call(html.replace) === "[object Function]") {
// Fix "XHTML"-style tags in all browsers
html = html.replace(/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, '<$1>$2>');
}
var container = doc.createElement('div'),
temp = doc.createElement('div');
// IE's parser will strip any `
` tags when `innerHTML`
// is called on a `tbody`. To get around this, we construct a
// valid table with a `tbody` that has the `innerHTML` we want.
// Then the container is the `firstChild` of the `tbody`.
// [source](http://www.ericvasilik.com/2006/07/code-karma.html).
if (name === 'tbody' || name === 'tfoot' || name === 'thead' || name === 'colgroup') {
temp.innerHTML = '
';
container = temp.firstChild.nodeType === 3 ? temp.lastChild : temp.firstChild.firstChild.firstChild;
} else if (name === 'option') {
temp.innerHTML = '';
container = temp.firstChild.nodeType === 3 ? temp.lastChild : temp.firstChild;
} else {
container.innerHTML = '' + html;
}
return [].slice.call(canChildNodes_1_2_1_canChildNodes(container));
}
function fragment(html, doc) {
if (html && html.nodeType === 11) {
return html;
}
if (!doc) {
doc = document$1();
} else if (doc.length) {
doc = doc[0];
}
var parts = makeFragment(html, undefined, doc),
frag = (doc || document).createDocumentFragment();
for (var i = 0, length = parts.length; i < length; i++) {
frag.appendChild(parts[i]);
}
return frag;
}
var makeFrag = function(item, doc) {
var document = doc || document$1();
var frag;
if (!item || typeof item === "string") {
frag = fragment(item == null ? "" : "" + item, document);
// If we have an empty frag...
} else if(typeof item[toDOMSymbol] === "function") {
return makeFrag(item[toDOMSymbol]());
}
else if (item.nodeType === 11) {
return item;
} else if (typeof item.nodeType === "number") {
frag = document.createDocumentFragment();
frag.appendChild(item);
return frag;
} else if (canReflect_1_19_2_canReflect.isListLike(item)) {
frag = document.createDocumentFragment();
canReflect_1_19_2_canReflect.eachIndex(item, function(item) {
frag.appendChild(makeFrag(item));
});
} else {
frag = fragment("" + item, document);
}
if (!canChildNodes_1_2_1_canChildNodes(frag).length) {
frag.appendChild(document.createTextNode(''));
}
return frag;
};
var canFragment_1_3_1_canFragment = canNamespace_1_0_0_canNamespace.fragment = canNamespace_1_0_0_canNamespace.frag = makeFrag;
var canViewCallbacks_5_0_0_canViewCallbacks = createCommonjsModule(function (module) {
var callbackMapSymbol = canSymbol_1_7_0_canSymbol.for('can.callbackMap');
var initializeSymbol = canSymbol_1_7_0_canSymbol.for('can.initialize');
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
var requestedAttributes = {};
}
//!steal-remove-end
var tags = {};
// WeakSet containing elements that have been rendered already
// and therefore do not need to be rendered again
var automountEnabled = function(){
var document = canGlobals_1_2_2_canGlobals.getKeyValue("document");
if(document == null || document.documentElement == null) {
return false;
}
return document.documentElement.getAttribute("data-can-automount") !== "false";
};
var renderedElements = new WeakMap();
var mountElement = function (node) {
var tagName = node.tagName && node.tagName.toLowerCase();
var tagHandler = tags[tagName];
// skip elements that already have a viewmodel or elements whose tags don't match a registered tag
// or elements that have already been rendered
if (tagHandler) {
callbacks.tagHandler(node, tagName, {});
}
};
var mutationObserverEnabled = false;
var disableMutationObserver;
var enableMutationObserver = function() {
var docEl = document$1().documentElement;
if (mutationObserverEnabled) {
if (mutationObserverEnabled === docEl) {
return;
}
// if the document has changed, re-enable mutationObserver
disableMutationObserver();
}
var undoOnInsertionHandler = canDomMutate_2_0_9_canDomMutate.onConnected(docEl, function(mutation) {
mountElement(mutation.target);
});
mutationObserverEnabled = true;
disableMutationObserver = function() {
undoOnInsertionHandler();
mutationObserverEnabled = false;
};
};
var renderTagsInDocument = function(tagName) {
var nodes = document$1().getElementsByTagName(tagName);
for (var i=0, node; (node = nodes[i]) !== undefined; i++) {
mountElement(node);
}
};
var attr = function (attributeName, attrHandler) {
if(attrHandler) {
if (typeof attributeName === "string") {
attributes[attributeName] = attrHandler;
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
if(requestedAttributes[attributeName]) {
dev.warn("can-view-callbacks: " + attributeName+ " custom attribute behavior requested before it was defined. Make sure "+attributeName+" is defined before it is needed.");
}
}
//!steal-remove-end
} else {
regExpAttributes.push({
match: attributeName,
handler: attrHandler
});
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
Object.keys(requestedAttributes).forEach(function(requested){
if(attributeName.test(requested)) {
dev.warn("can-view-callbacks: " + requested+ " custom attribute behavior requested before it was defined. Make sure "+requested+" is defined before it is needed.");
}
});
}
//!steal-remove-end
}
} else {
var cb = attributes[attributeName];
if( !cb ) {
for( var i = 0, len = regExpAttributes.length; i < len; i++) {
var attrMatcher = regExpAttributes[i];
if(attrMatcher.match.test(attributeName)) {
return attrMatcher.handler;
}
}
}
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
requestedAttributes[attributeName] = true;
}
//!steal-remove-end
return cb;
}
};
var attrs = function(attrMap) {
var map = canReflect_1_19_2_canReflect.getKeyValue(attrMap, callbackMapSymbol) || attrMap;
// Only add bindings once.
if(attrMaps.has(map)) {
return;
} else {
// Would prefer to use WeakSet but IE11 doesn't support it.
attrMaps.set(map, true);
}
canReflect_1_19_2_canReflect.eachKey(map, function(callback, exp){
attr(exp, callback);
});
};
var attributes = {},
regExpAttributes = [],
attrMaps = new WeakMap(),
automaticCustomElementCharacters = /[-\:]/;
var defaultCallback = function () {};
var tag = function (tagName, tagHandler) {
if(tagHandler) {
var validCustomElementName = automaticCustomElementCharacters.test(tagName),
tagExists = typeof tags[tagName.toLowerCase()] !== 'undefined',
customElementExists;
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
if (tagExists) {
dev.warn("Custom tag: " + tagName.toLowerCase() + " is already defined");
}
if (!validCustomElementName && tagName !== "content") {
dev.warn("Custom tag: " + tagName.toLowerCase() + " hyphen missed");
}
}
//!steal-remove-end
tags[tagName.toLowerCase()] = tagHandler;
if(automountEnabled()) {
var customElements = canGlobals_1_2_2_canGlobals.getKeyValue("customElements");
// automatically render elements that have tagHandlers
// If browser supports customElements, register the tag as a custom element
if (customElements) {
customElementExists = customElements.get(tagName.toLowerCase());
if (validCustomElementName && !customElementExists) {
var CustomElement = function() {
return Reflect.construct(HTMLElement, [], CustomElement);
};
CustomElement.prototype = Object.create(HTMLElement.prototype);
CustomElement.prototype.constructor = CustomElement;
CustomElement.prototype.connectedCallback = function() {
callbacks.tagHandler(this, tagName.toLowerCase(), {});
};
customElements.define(tagName, CustomElement);
}
}
// If browser doesn't support customElements, set up MutationObserver for
// rendering elements when they are inserted in the page
// and rendering elements that are already in the page
else {
enableMutationObserver();
renderTagsInDocument(tagName);
}
} else if(mutationObserverEnabled) {
disableMutationObserver();
}
} else {
var cb;
// if null is passed as tagHandler, remove tag
if (tagHandler === null) {
delete tags[tagName.toLowerCase()];
} else {
cb = tags[tagName.toLowerCase()];
}
if(!cb && automaticCustomElementCharacters.test(tagName)) {
// empty callback for things that look like special tags
cb = defaultCallback;
}
return cb;
}
};
var callbacks = {
_tags: tags,
_attributes: attributes,
_regExpAttributes: regExpAttributes,
defaultCallback: defaultCallback,
tag: tag,
attr: attr,
attrs: attrs,
// handles calling back a tag callback
tagHandler: function(el, tagName, tagData){
// skip elements that have already been rendered
if (renderedElements.has(el)) {
return;
}
var scope = tagData.scope,
helperTagCallback = scope && scope.templateContext.tags.get(tagName),
tagCallback = helperTagCallback || tags[tagName] || el[initializeSymbol],
res;
// If this was an element like that doesn't have a component, just render its content
if(tagCallback) {
res = canObservationRecorder_1_3_1_canObservationRecorder.ignore(tagCallback)(el, tagData);
// add the element to the Set of elements that have had their handlers called
// this will prevent the handler from being called again when the element is inserted
renderedElements.set(el, true);
} else {
res = scope;
}
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
if (!tagCallback) {
var GLOBAL = global_1();
var ceConstructor = document$1().createElement(tagName).constructor;
// If not registered as a custom element, the browser will use default constructors
if (ceConstructor === GLOBAL.HTMLElement || ceConstructor === GLOBAL.HTMLUnknownElement) {
dev.warn('can-view-callbacks: No custom element found for ' + tagName);
}
}
}
//!steal-remove-end
// If the tagCallback gave us something to render with, and there is content within that element
// render it!
if (res && tagData.subtemplate) {
if (scope !== res) {
scope = scope.add(res);
}
//var nodeList = nodeLists.register([], undefined, tagData.parentNodeList || true, false);
//nodeList.expression = "<" + el.tagName + ">";
var result = tagData.subtemplate(scope, tagData.options);
var frag = typeof result === "string" ? canFragment_1_3_1_canFragment(result) : result;
canDomMutate_2_0_9_node.appendChild.call(el, frag);
}
}
};
canNamespace_1_0_0_canNamespace.view = canNamespace_1_0_0_canNamespace.view || {};
if (canNamespace_1_0_0_canNamespace.view.callbacks) {
throw new Error("You can't have two versions of can-view-callbacks, check your dependencies");
} else {
module.exports = canNamespace_1_0_0_canNamespace.view.callbacks = callbacks;
}
});
/* jshint maxdepth:7 */
/* jshint latedef:false */
// if an object or a function
// convert into what it should look like
// then the modification can happen in place
// but it has to have more than the current node
// blah!
var processNodes = function(nodes, paths, location, document){
var frag = document.createDocumentFragment();
for(var i = 0, len = nodes.length; i < len; i++) {
var node = nodes[i];
frag.appendChild( processNode(node,paths,location.concat(i), document) );
}
return frag;
},
keepsTextNodes = typeof document !== "undefined" && (function(){
var testFrag = document.createDocumentFragment();
var div = document.createElement("div");
div.appendChild(document.createTextNode(""));
div.appendChild(document.createTextNode(""));
testFrag.appendChild(div);
var cloned = testFrag.cloneNode(true);
return cloned.firstChild.childNodes.length === 2;
})(),
clonesWork = typeof document !== "undefined" && (function(){
// Since html5shiv is required to support custom elements, assume cloning
// works in any browser that doesn't have html5shiv
// Clone an element containing a custom tag to see if the innerHTML is what we
// expect it to be, or if not it probably was created outside of the document's
// namespace.
var el = document.createElement('a');
el.innerHTML = "";
var clone = el.cloneNode(true);
var works = clone.innerHTML === "";
var MO, observer;
if(works) {
// Cloning text nodes with dashes seems to create multiple nodes in IE11 when
// MutationObservers of subtree modifications are used on the documentElement.
// Since this is not what we expect we have to include detecting it here as well.
el = document.createDocumentFragment();
el.appendChild(document.createTextNode('foo-bar'));
MO = mutationObserver();
if (MO) {
observer = new MO(function() {});
observer.observe(document.documentElement, { childList: true, subtree: true });
clone = el.cloneNode(true);
observer.disconnect();
} else {
clone = el.cloneNode(true);
}
return clone.childNodes.length === 1;
}
return works;
})(),
namespacesWork = typeof document !== "undefined" && !!document.createElementNS;
/**
* @function cloneNode
* @hide
*
* A custom cloneNode function to be used in browsers that properly support cloning
* of custom tags (IE8 for example). Fixes it by doing some manual cloning that
* uses innerHTML instead, which has been shimmed.
*
* @param {DocumentFragment} frag A document fragment to clone
* @return {DocumentFragment} a new fragment that is a clone of the provided argument
*/
var cloneNode = clonesWork ?
function(el){
return el.cloneNode(true);
} :
function(node){
var document = node.ownerDocument;
var copy;
if(node.nodeType === 1) {
if(node.namespaceURI !== 'http://www.w3.org/1999/xhtml' && namespacesWork && document.createElementNS) {
copy = document.createElementNS(node.namespaceURI, node.nodeName);
}
else {
copy = document.createElement(node.nodeName);
}
} else if(node.nodeType === 3){
copy = document.createTextNode(node.nodeValue);
} else if(node.nodeType === 8) {
copy = document.createComment(node.nodeValue);
} else if(node.nodeType === 11) {
copy = document.createDocumentFragment();
}
if(node.attributes) {
var attributes = node.attributes;
for (var i = 0; i < attributes.length; i++) {
var attribute = attributes[i];
if (attribute && attribute.specified) {
// If the attribute has a namespace set the namespace
// otherwise it will be set to null
if (attribute.namespaceURI) {
copy.setAttributeNS(attribute.namespaceURI, attribute.nodeName || attribute.name, attribute.nodeValue || attribute.value);
} else {
copy.setAttribute(attribute.nodeName || attribute.name, attribute.nodeValue || attribute.value);
}
}
}
}
if(node && node.firstChild) {
var child = node.firstChild;
while(child) {
copy.appendChild( cloneNode(child) );
child = child.nextSibling;
}
}
return copy;
};
function processNode(node, paths, location, document){
var callback,
loc = location,
nodeType = typeof node,
el,
p,
i , len;
var getCallback = function(){
if(!callback) {
callback = {
path: location,
callbacks: []
};
paths.push(callback);
loc = [];
}
return callback;
};
if(nodeType === "object") {
if( node.tag ) {
if(namespacesWork && node.namespace) {
el = document.createElementNS(node.namespace, node.tag);
} else {
el = document.createElement(node.tag);
}
if(node.attrs) {
for(var attrName in node.attrs) {
var value = node.attrs[attrName];
if(typeof value === "function"){
getCallback().callbacks.push({
callback: value
});
} else if (value !== null && typeof value === "object" && value.namespaceURI) {
el.setAttributeNS(value.namespaceURI,attrName,value.value);
} else {
canDomMutate_2_0_9_node.setAttribute.call(el, attrName, value);
}
}
}
if(node.attributes) {
for(i = 0, len = node.attributes.length; i < len; i++ ) {
getCallback().callbacks.push({callback: node.attributes[i]});
}
}
if(node.children && node.children.length) {
// add paths
if(callback) {
p = callback.paths = [];
} else {
p = paths;
}
el.appendChild( processNodes(node.children, p, loc, document) );
}
} else if(node.comment) {
el = document.createComment(node.comment);
if(node.callbacks) {
for(i = 0, len = node.callbacks.length; i < len; i++ ) {
getCallback().callbacks.push({callback: node.callbacks[i]});
}
}
}
} else if(nodeType === "string"){
el = document.createTextNode(node);
} else if(nodeType === "function") {
if(keepsTextNodes) {
el = document.createTextNode("");
getCallback().callbacks.push({
callback: node
});
} else {
el = document.createComment("~");
getCallback().callbacks.push({
callback: function(){
var el = document.createTextNode("");
canDomMutate_2_0_9_node.replaceChild.call(this.parentNode, el, this);
return node.apply(el,arguments );
}
});
}
}
return el;
}
function getCallbacks(el, pathData, elementCallbacks){
var path = pathData.path,
callbacks = pathData.callbacks,
paths = pathData.paths,
child = el,
pathLength = path ? path.length : 0,
pathsLength = paths ? paths.length : 0;
for(var i = 0; i < pathLength; i++) {
child = child.childNodes.item(path[i]);
}
for( i= 0 ; i < pathsLength; i++) {
getCallbacks(child, paths[i], elementCallbacks);
}
elementCallbacks.push({element: child, callbacks: callbacks});
}
function hydrateCallbacks(callbacks, args) {
var len = callbacks.length,
callbacksLength,
callbackElement,
callbackData;
for(var i = 0; i < len; i++) {
callbackData = callbacks[i];
callbacksLength = callbackData.callbacks.length;
callbackElement = callbackData.element;
for(var c = 0; c < callbacksLength; c++) {
callbackData.callbacks[c].callback.apply(callbackElement, args);
}
}
}
function makeTarget(nodes, doc){
var paths = [];
var frag = processNodes(nodes, paths, [], doc || document$1());
return {
paths: paths,
clone: frag,
hydrate: function(){
var cloned = cloneNode(this.clone);
var args = [];
for (var a = 0, ref = args.length = arguments.length; a < ref; a++) {
args[a] = arguments[a];
} // see https://jsperf.com/nodelist-to-array
var callbacks = [];
for(var i = 0; i < paths.length; i++) {
getCallbacks(cloned, paths[i], callbacks);
}
hydrateCallbacks(callbacks, args);
return cloned;
}
};
}
makeTarget.keepsTextNodes = keepsTextNodes;
makeTarget.cloneNode = cloneNode;
canNamespace_1_0_0_canNamespace.view = canNamespace_1_0_0_canNamespace.view || {};
var canViewTarget_5_0_0_canViewTarget = canNamespace_1_0_0_canNamespace.view.target = makeTarget;
var getKeyValueSymbol$2 = canSymbol_1_7_0_canSymbol.for("can.getKeyValue"),
observeDataSymbol = canSymbol_1_7_0_canSymbol.for("can.meta");
var promiseDataPrototype = {
isPending: true,
state: "pending",
isResolved: false,
isRejected: false,
value: undefined,
reason: undefined
};
function setVirtualProp(promise, property, value) {
var observeData = promise[observeDataSymbol];
var old = observeData[property];
observeData[property] = value;
canQueues_1_3_2_canQueues.enqueueByQueue(observeData.handlers.getNode([property]), promise, [value,old], function() {
return {};
},["Promise", promise, "resolved with value", value, "and changed virtual property: "+property]);
}
function initPromise(promise) {
var observeData = promise[observeDataSymbol];
if(!observeData) {
Object.defineProperty(promise, observeDataSymbol, {
enumerable: false,
configurable: false,
writable: false,
value: Object.create(promiseDataPrototype)
});
observeData = promise[observeDataSymbol];
observeData.handlers = new canKeyTree_1_2_2_canKeyTree([Object, Object, Array]);
}
promise.then(function(value){
canQueues_1_3_2_canQueues.batch.start();
setVirtualProp(promise, "isPending", false);
setVirtualProp(promise, "isResolved", true);
setVirtualProp(promise, "value", value);
setVirtualProp(promise, "state", "resolved");
canQueues_1_3_2_canQueues.batch.stop();
}, function(reason){
canQueues_1_3_2_canQueues.batch.start();
setVirtualProp(promise, "isPending", false);
setVirtualProp(promise, "isRejected", true);
setVirtualProp(promise, "reason", reason);
setVirtualProp(promise, "state", "rejected");
canQueues_1_3_2_canQueues.batch.stop();
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
dev.error("Failed promise:", reason);
}
//!steal-remove-end
});
}
function setupPromise(value) {
var oldPromiseFn;
var proto = "getPrototypeOf" in Object ? Object.getPrototypeOf(value) : value.__proto__; //jshint ignore:line
if(value[getKeyValueSymbol$2] && value[observeDataSymbol]) {
// promise has already been set up. Don't overwrite.
return;
}
if(proto === null || proto === Object.prototype) {
// promise type is a plain object or dictionary. Set up object instead of proto.
proto = value;
if(typeof proto.promise === "function") {
// Duck-type identification as a jQuery.Deferred;
// In that case, the promise() function returns a new object
// that needs to be decorated.
oldPromiseFn = proto.promise;
proto.promise = function() {
var result = oldPromiseFn.call(proto);
setupPromise(result);
return result;
};
}
}
canReflect_1_19_2_canReflect.assignSymbols(proto, {
"can.getKeyValue": function(key) {
if(!this[observeDataSymbol]) {
initPromise(this);
}
canObservationRecorder_1_3_1_canObservationRecorder.add(this, key);
switch(key) {
case "state":
case "isPending":
case "isResolved":
case "isRejected":
case "value":
case "reason":
return this[observeDataSymbol][key];
default:
return this[key];
}
},
"can.getValue": function() {
return this[getKeyValueSymbol$2]("value");
},
"can.isValueLike": false,
"can.onKeyValue": function(key, handler, queue) {
if(!this[observeDataSymbol]) {
initPromise(this);
}
this[observeDataSymbol].handlers.add([key, queue || "mutate", handler]);
},
"can.offKeyValue": function(key, handler, queue) {
if(!this[observeDataSymbol]) {
initPromise(this);
}
this[observeDataSymbol].handlers.delete([key, queue || "mutate", handler]);
},
"can.hasOwnKey": function(key) {
if (!this[observeDataSymbol]) {
initPromise(this);
}
return (key in this[observeDataSymbol]);
}
});
}
var canReflectPromise_2_2_1_canReflectPromise = setupPromise;
var getValueSymbol$2 = canSymbol_1_7_0_canSymbol.for("can.getValue");
var setValueSymbol$3 = canSymbol_1_7_0_canSymbol.for("can.setValue");
var isValueLikeSymbol = canSymbol_1_7_0_canSymbol.for("can.isValueLike");
var peek$3 = canObservationRecorder_1_3_1_canObservationRecorder.ignore(canReflect_1_19_2_canReflect.getKeyValue.bind(canReflect_1_19_2_canReflect));
var observeReader;
var isPromiseLike = canObservationRecorder_1_3_1_canObservationRecorder.ignore(function isPromiseLike(value){
return typeof value === "object" && value && typeof value.then === "function";
});
var bindName = Function.prototype.bind;
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
bindName = function(source){
var fn = Function.prototype.bind.call(this, source);
Object.defineProperty(fn, "name", {
value: canReflect_1_19_2_canReflect.getName(source) + "."+canReflect_1_19_2_canReflect.getName(this)
});
return fn;
};
}
//!steal-remove-end
var isAt = function(index, reads) {
var prevRead = reads[index-1];
return prevRead && prevRead.at;
};
var readValue = function(value, index, reads, options, state, prev){
// if the previous read is AT false ... we shouldn't be doing this;
var usedValueReader;
do {
usedValueReader = false;
for(var i =0, len = observeReader.valueReaders.length; i < len; i++){
if( observeReader.valueReaders[i].test(value, index, reads, options) ) {
value = observeReader.valueReaders[i].read(value, index, reads, options, state, prev);
//usedValueReader = true;
}
}
} while(usedValueReader);
return value;
};
var specialRead = {index: true, key: true, event: true, element: true, viewModel: true};
var checkForObservableAndNotify = function(options, state, getObserves, value, index){
if(options.foundObservable && !state.foundObservable) {
if(canObservationRecorder_1_3_1_canObservationRecorder.trapsCount()) {
canObservationRecorder_1_3_1_canObservationRecorder.addMany( getObserves() );
options.foundObservable(value, index);
state.foundObservable = true;
}
}
};
var objHasKeyAtIndex = function(obj, reads, index) {
return !!(
reads && reads.length &&
canReflect_1_19_2_canReflect.hasKey(obj, reads[index].key)
);
};
observeReader = {
// there are things that you need to evaluate when you get them back as a property read
// for example a compute or a function you might need to call to get the next value to
// actually check
// - readCompute - can be set to `false` to prevent reading an ending compute. This is used by component to get a
// compute as a delegate. In 3.0, this should be removed and force people to write "{@prop} change"
// - callMethodsOnObservables - this is an overwrite ... so normal methods won't be called, but observable ones will.
// - executeAnonymousFunctions - call a function if it's found, defaults to true
// - proxyMethods - if the last read is a method, return a function so `this` will be correct.
// - args - arguments to call functions with.
//
// Callbacks
// - earlyExit - called if a value could not be found
// - foundObservable - called when an observable value is found
read: function (parent, reads, options) {
options = options || {};
var state = {
foundObservable: false
};
var getObserves;
if(options.foundObservable) {
getObserves = canObservationRecorder_1_3_1_canObservationRecorder.trap();
}
// `cur` is the current value.
var cur = readValue(parent, 0, reads, options, state),
// `prev` is the object we are reading from.
prev,
// `foundObs` did we find an observable.
readLength = reads.length,
i = 0,
parentHasKey;
checkForObservableAndNotify(options, state, getObserves, parent, 0);
while( i < readLength ) {
prev = cur;
// try to read the property
for(var r=0, readersLength = observeReader.propertyReaders.length; r < readersLength; r++) {
var reader = observeReader.propertyReaders[r];
if(reader.test(cur)) {
cur = reader.read(cur, reads[i], i, options, state);
break; // there can be only one reading of a property
}
}
checkForObservableAndNotify(options, state, getObserves, prev, i);
i = i+1;
// read the value if it is a compute or function
cur = readValue(cur, i, reads, options, state, prev);
checkForObservableAndNotify(options, state, getObserves, prev, i-1);
// early exit if need be
if (i < reads.length && (cur === null || cur === undefined )) {
parentHasKey = objHasKeyAtIndex(prev, reads, i - 1);
if (options.earlyExit && !parentHasKey) {
options.earlyExit(prev, i - 1, cur);
}
// return undefined so we know this isn't the right value
return {
value: undefined,
parent: prev,
parentHasKey: parentHasKey,
foundLastParent: false
};
}
}
parentHasKey = objHasKeyAtIndex(prev, reads, reads.length - 1);
// if we don't have a value, exit early.
if (cur === undefined && !parentHasKey) {
if (options.earlyExit) {
options.earlyExit(prev, i - 1);
}
}
return {
value: cur,
parent: prev,
parentHasKey: parentHasKey,
foundLastParent: true
};
},
get: function(parent, reads, options){
return observeReader.read(parent, observeReader.reads(reads), options || {}).value;
},
valueReadersMap: {},
// an array of types that might have a value inside them like functions
// value readers check the current value
// and get a new value from it
// ideally they would keep calling until
// none of these passed
valueReaders: [
{
name: "function",
// if this is a function before the last read and its not a constructor function
test: function(value){
return value && canReflect_1_19_2_canReflect.isFunctionLike(value) && !canReflect_1_19_2_canReflect.isConstructorLike(value);
},
read: function(value, i, reads, options, state, prev){
if(options.callMethodsOnObservables && canReflect_1_19_2_canReflect.isObservableLike(prev) && canReflect_1_19_2_canReflect.isMapLike(prev)) {
dev.warn("can-stache-key: read() called with `callMethodsOnObservables: true`.");
return value.apply(prev, options.args || []);
}
return options.proxyMethods !== false ? bindName.call(value, prev) : value;
}
},
{
name: "isValueLike",
// compute value reader
test: function(value, i, reads, options) {
return value && value[getValueSymbol$2] && value[isValueLikeSymbol] !== false && (options.foundAt || !isAt(i, reads) );
},
read: function(value, i, reads, options){
if(options.readCompute === false && i === reads.length ) {
return value;
}
return canReflect_1_19_2_canReflect.getValue(value);
},
write: function(base, newVal){
if(base[setValueSymbol$3]) {
base[setValueSymbol$3](newVal);
} else if(base.set) {
base.set(newVal);
} else {
base(newVal);
}
}
}],
propertyReadersMap: {},
// an array of things that might have a property
propertyReaders: [
{
name: "map",
test: function(value){
// the first time we try reading from a promise, set it up for
// special reflections.
if(canReflect_1_19_2_canReflect.isPromise(value) ||
isPromiseLike(value)) {
canReflectPromise_2_2_1_canReflectPromise(value);
}
return canReflect_1_19_2_canReflect.isObservableLike(value) && canReflect_1_19_2_canReflect.isMapLike(value);
},
read: function(value, prop){
var res = canReflect_1_19_2_canReflect.getKeyValue(value, prop.key);
if(res !== undefined) {
return res;
} else {
return value[prop.key];
}
},
write: canReflect_1_19_2_canReflect.setKeyValue
},
// read a normal object
{
name: "object",
// this is the default
test: function(){return true;},
read: function(value, prop, i, options){
if(value == null) {
return undefined;
} else {
if(typeof value === "object") {
if(prop.key in value) {
return value[prop.key];
}
// TODO: remove in 5.0.
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
if( prop.at && specialRead[prop.key] && ( ("@"+prop.key) in value)) {
options.foundAt = true;
dev.warn("Use %"+prop.key+" in place of @"+prop.key+".");
return undefined;
}
}
//!steal-remove-end
} else {
return value[prop.key];
}
}
},
write: function(base, prop, newVal){
var propValue = base[prop];
// if newVal is observable object, lets try to update
if(newVal != null && typeof newVal === "object" && canReflect_1_19_2_canReflect.isMapLike(propValue) ) {
dev.warn("can-stache-key: Merging data into \"" + prop + "\" because its parent is non-observable");
canReflect_1_19_2_canReflect.update(propValue, newVal);
} else if(propValue != null && propValue[setValueSymbol$3] !== undefined){
canReflect_1_19_2_canReflect.setValue(propValue, newVal);
} else {
base[prop] = newVal;
}
}
}
],
reads: function(keyArg) {
var key = ""+keyArg;
var keys = [];
var last = 0;
var at = false;
if( key.charAt(0) === "@" ) {
last = 1;
at = true;
}
var keyToAdd = "";
for(var i = last; i < key.length; i++) {
var character = key.charAt(i);
if(character === "." || character === "@") {
if( key.charAt(i -1) !== "\\" ) {
keys.push({
key: keyToAdd,
at: at
});
at = character === "@";
keyToAdd = "";
} else {
keyToAdd = keyToAdd.substr(0,keyToAdd.length - 1) + ".";
}
} else {
keyToAdd += character;
}
}
keys.push({
key: keyToAdd,
at: at
});
return keys;
},
// This should be able to set a property similar to how read works.
write: function(parent, key, value, options) {
var keys = typeof key === "string" ? observeReader.reads(key) : key;
var last;
options = options || {};
if(keys.length > 1) {
last = keys.pop();
parent = observeReader.read(parent, keys, options).value;
keys.push(last);
} else {
last = keys[0];
}
if(!parent) {
return;
}
var keyValue = peek$3(parent, last.key);
// here's where we need to figure out the best way to write
// if property being set points at a compute, set the compute
if( observeReader.valueReadersMap.isValueLike.test(keyValue, keys.length - 1, keys, options) ) {
observeReader.valueReadersMap.isValueLike.write(keyValue, value, options);
} else {
if(observeReader.valueReadersMap.isValueLike.test(parent, keys.length - 1, keys, options) ) {
parent = parent[getValueSymbol$2]();
}
if(observeReader.propertyReadersMap.map.test(parent)) {
observeReader.propertyReadersMap.map.write(parent, last.key, value, options);
}
else if(observeReader.propertyReadersMap.object.test(parent)) {
observeReader.propertyReadersMap.object.write(parent, last.key, value, options);
if(options.observation) {
options.observation.update();
}
}
}
}
};
observeReader.propertyReaders.forEach(function(reader){
observeReader.propertyReadersMap[reader.name] = reader;
});
observeReader.valueReaders.forEach(function(reader){
observeReader.valueReadersMap[reader.name] = reader;
});
observeReader.set = observeReader.write;
var canStacheKey_1_4_3_canStacheKey = observeReader;
var TemplateContext = function(options) {
options = options || {};
this.vars = new canSimpleMap_4_3_3_canSimpleMap(options.vars || {});
this.helpers = new canSimpleMap_4_3_3_canSimpleMap(options.helpers || {});
this.partials = new canSimpleMap_4_3_3_canSimpleMap(options.partials || {});
this.tags = new canSimpleMap_4_3_3_canSimpleMap(options.tags || {});
};
var canViewScope_4_13_7_templateContext = TemplateContext;
var canCid_1_3_1_canCid = createCommonjsModule(function (module) {
/**
* @module {function} can-cid
* @parent can-typed-data
* @collection can-infrastructure
* @package ./package.json
* @description Utility for getting a unique identifier for an object.
* @signature `cid(object, optionalObjectType)`
*
* Get a unique identifier for the object, optionally prefixed by a type name.
*
* Once set, the unique identifier does not change, even if the type name
* changes on subsequent calls.
*
* ```js
* var cid = require("can-cid");
* var x = {};
* var y = {};
*
* console.log(cid(x, "demo")); // -> "demo1"
* console.log(cid(x, "prod")); // -> "demo1"
* console.log(cid(y)); // -> "2"
* ```
*
* @param {Object} object The object to uniquely identify.
* @param {String} name An optional type name with which to prefix the identifier
*
* @return {String} Returns the unique identifier
*/
var _cid = 0;
// DOM nodes shouldn't all use the same property
var domExpando = "can" + new Date();
var cid = function (object, name) {
var propertyName = object.nodeName ? domExpando : "_cid";
if (!object[propertyName]) {
_cid++;
object[propertyName] = (name || '') + _cid;
}
return object[propertyName];
};
cid.domExpando = domExpando;
cid.get = function(object){
var type = typeof object;
var isObject = type !== null && (type === "object" || type === "function");
return isObject ? cid(object) : (type + ":" + object);
};
if (canNamespace_1_0_0_canNamespace.cid) {
throw new Error("You can't have two versions of can-cid, check your dependencies");
} else {
module.exports = canNamespace_1_0_0_canNamespace.cid = cid;
}
});
var singleReference;
function getKeyName(key, extraKey) {
var keyName = extraKey ? canCid_1_3_1_canCid(key) + ":" + extraKey : canCid_1_3_1_canCid(key);
return keyName || key;
}
// weak maps are slow
/* if(typeof WeakMap !== "undefined") {
var globalMap = new WeakMap();
singleReference = {
set: function(obj, key, value){
var localMap = globalMap.get(obj);
if( !localMap ) {
globalMap.set(obj, localMap = new WeakMap());
}
localMap.set(key, value);
},
getAndDelete: function(obj, key){
return globalMap.get(obj).get(key);
},
references: globalMap
};
} else {*/
singleReference = {
// obj is a function ... we need to place `value` on it so we can retreive it
// we can't use a global map
set: function(obj, key, value, extraKey){
// check if it has a single reference map
obj[getKeyName(key, extraKey)] = value;
},
getAndDelete: function(obj, key, extraKey){
var keyName = getKeyName(key, extraKey);
var value = obj[keyName];
delete obj[keyName];
return value;
}
};
/*}*/
var canSingleReference_1_3_0_canSingleReference = singleReference;
var Compute = function(newVal){
if(arguments.length) {
return canReflect_1_19_2_canReflect.setValue(this, newVal);
} else {
return canReflect_1_19_2_canReflect.getValue(this);
}
};
var canViewScope_4_13_7_makeComputeLike = function(observable) {
var compute = Compute.bind(observable);
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
Object.defineProperty(compute, "name", {
value: "Compute<"+canReflect_1_19_2_canReflect.getName(observable) + ">",
});
}
//!steal-remove-end
compute.on = compute.bind = compute.addEventListener = function(event, handler) {
var translationHandler = function(newVal, oldVal) {
handler.call(compute, {type:'change'}, newVal, oldVal);
};
canSingleReference_1_3_0_canSingleReference.set(handler, this, translationHandler);
observable.on(translationHandler);
};
compute.off = compute.unbind = compute.removeEventListener = function(event, handler) {
observable.off( canSingleReference_1_3_0_canSingleReference.getAndDelete(handler, this) );
};
canReflect_1_19_2_canReflect.assignSymbols(compute, {
"can.getValue": function(){
return canReflect_1_19_2_canReflect.getValue(observable);
},
"can.setValue": function(newVal){
return canReflect_1_19_2_canReflect.setValue(observable, newVal);
},
"can.onValue": function(handler, queue){
return canReflect_1_19_2_canReflect.onValue(observable, handler, queue);
},
"can.offValue": function(handler, queue){
return canReflect_1_19_2_canReflect.offValue(observable, handler, queue);
},
"can.valueHasDependencies": function(){
return canReflect_1_19_2_canReflect.valueHasDependencies(observable);
},
"can.getPriority": function(){
return canReflect_1_19_2_canReflect.getPriority( observable );
},
"can.setPriority": function(newPriority){
canReflect_1_19_2_canReflect.setPriority( observable, newPriority );
},
"can.isValueLike": true,
"can.isFunctionLike": false
});
compute.isComputed = true;
return compute;
};
var canStacheHelpers_1_2_0_canStacheHelpers = createCommonjsModule(function (module) {
if (canNamespace_1_0_0_canNamespace.stacheHelpers) {
throw new Error("You can't have two versions of can-stache-helpers, check your dependencies");
} else {
module.exports = canNamespace_1_0_0_canNamespace.stacheHelpers = {};
}
});
var dispatchSymbol$2 = canSymbol_1_7_0_canSymbol.for("can.dispatch");
var setElementSymbol$1 = canSymbol_1_7_0_canSymbol.for("can.setElement");
// The goal of this is to create a high-performance compute that represents a key value from can.view.Scope.
// If the key value is something like {{name}} and the context is a can.Map, a faster
// binding path will be used where new rebindings don't need to be looked for with every change of
// the observable property.
// However, if the property changes to a compute, then the slower `can.compute.read` method of
// observing values will be used.
// ideally, we would know the order things were read. If the last thing read
// was something we can observe, and the value of it matched the value of the observation,
// and the key matched the key of the observation
// it's a fair bet that we can just listen to that last object.
// If the `this` is not that object ... freak out. Though `this` is not necessarily part of it. can-observation could make
// this work.
var getFastPathRoot = canObservationRecorder_1_3_1_canObservationRecorder.ignore(function(computeData){
if( computeData.reads &&
// a single property read
computeData.reads.length === 1 ) {
var root = computeData.root;
if( root && root[canSymbol_1_7_0_canSymbol.for("can.getValue")] ) {
root = canReflect_1_19_2_canReflect.getValue(root);
}
// on a map
return root && canReflect_1_19_2_canReflect.isObservableLike(root) && canReflect_1_19_2_canReflect.isMapLike(root) &&
// that isn't calling a function
typeof root[computeData.reads[0].key] !== "function" && root;
}
return;
});
var isEventObject = function(obj){
return obj && typeof obj.batchNum === "number" && typeof obj.type === "string";
};
function getMutated(scopeKeyData){
// The _thisArg is the value before the last `.`. For example if the key was `foo.bar.zed`,
// _thisArg would be the value at foo.bar.
// This should be improved as `foo.bar` might not be observable.
var value$$1 = canObservationRecorder_1_3_1_canObservationRecorder.peekValue(scopeKeyData._thisArg);
// Something like `string@split` would provide a primitive which can't be a mutated subject
return !canReflect_1_19_2_canReflect.isPrimitive(value$$1) ? value$$1 : scopeKeyData.root;
}
function callMutateWithRightArgs(method, mutated, reads, mutator){
if(reads.length) {
method.call(canReflectDependencies_1_1_2_canReflectDependencies,mutated, reads[ reads.length - 1 ].key ,mutator);
} else {
method.call(canReflectDependencies_1_1_2_canReflectDependencies,mutated ,mutator);
}
}
var warnOnUndefinedProperty;
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
warnOnUndefinedProperty = function(options) {
if ( options.key !== "debugger" && !options.parentHasKey) {
var filename = options.scope.peek('scope.filename');
var lineNumber = options.scope.peek('scope.lineNumber');
var reads = canStacheKey_1_4_3_canStacheKey.reads(options.key);
var firstKey = reads[0].key;
var key = reads.map(function(read) {
return read.key + (read.at ? "()" : "");
}).join(".");
var pathsForKey = options.scope.getPathsForKey(firstKey);
var paths = Object.keys( pathsForKey );
var firstKeyValue = options.scope.get(firstKey);
var includeSuggestions = paths.length && (paths.indexOf(firstKey) < 0);
var warning = [
(filename ? filename + ':' : '') +
(lineNumber ? lineNumber + ': ' : '') +
'Unable to find key "' + key + '".'
];
if (includeSuggestions) {
warning[0] = warning[0] + ' Did you mean' + (paths.length > 1 ? ' one of these' : '') + '?\n';
paths.forEach(function(path) {
warning.push('\t"' + path + '" which will read from');
warning.push(pathsForKey[path]);
warning.push("\n");
});
} else if (firstKeyValue) {
warning[0] = warning[0] + ' Found "' + firstKey + '" with value: %o\n';
}
if (firstKeyValue) {
dev.warn.apply(dev, [warning.join("\n"), firstKeyValue]);
} else {
dev.warn.apply(dev,
warning
);
}
}
};
}
//!steal-remove-end
// could we make this an observation first ... and have a getter for the compute?
// This is a fast-path enabled Observation wrapper use many places in can-stache.
// The goal of this is to:
//
// 1. Make something that can be passed to can-view-live directly, hopefully
// avoiding creating expensive computes. Instead we will only be creating
// `ScopeKeyData` which are thin wrappers.
var ScopeKeyData = function(scope, key, options){
this.startingScope = scope;
this.key = key;
this.read = this.read.bind(this);
this.dispatch = this.dispatch.bind(this);
// special case debugger helper so that it is called with helperOtions
// when you do {{debugger}} as it already is with {{debugger()}}
if (key === "debugger") {
// prevent "Unable to find key" warning
this.startingScope = { _context: canStacheHelpers_1_2_0_canStacheHelpers };
this.read = function() {
var helperOptions = { scope: scope };
var debuggerHelper = canStacheHelpers_1_2_0_canStacheHelpers["debugger"];
return debuggerHelper(helperOptions);
};
}
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
Object.defineProperty(this.read, "name", {
value: canReflect_1_19_2_canReflect.getName(this) + ".read",
});
Object.defineProperty(this.dispatch, "name", {
value: canReflect_1_19_2_canReflect.getName(this) + ".dispatch",
});
}
//!steal-remove-end
var observation = this.observation = new canObservation_4_2_0_canObservation(this.read, this);
this.options = canAssign_1_3_3_canAssign({ observation: this.observation }, options);
// things added later
this.fastPath = undefined;
this.root = undefined;
this.reads = undefined;
this.setRoot = undefined;
// This is read by call expressions so it needs to be observable
this._thisArg = new canSimpleObservable_2_5_0_canSimpleObservable();
this.parentHasKey = undefined;
var valueDependencies = new Set();
valueDependencies.add(observation);
this.dependencies = {valueDependencies: valueDependencies};
// This is basically what .get() should give, but it
// isn't used to figure out the last value.
this._latestValue = undefined;
};
value(ScopeKeyData.prototype);
function fastOnBoundSet_Value() {
this._value = this.newVal;
}
function fastOnBoundSetValue() {
this.value = this.newVal;
}
canAssign_1_3_3_canAssign(ScopeKeyData.prototype, {
constructor: ScopeKeyData,
dispatch: function dispatch(newVal){
var old = this.value;
this._latestValue = this.value = newVal;
// call the base implementation in can-event-queue
this[dispatchSymbol$2].call(this, this.value, old);
},
onBound: function onBound(){
this.bound = true;
canReflect_1_19_2_canReflect.onValue(this.observation, this.dispatch, "notify");
// TODO: we should check this sometime in the background.
var fastPathRoot = getFastPathRoot(this);
if( fastPathRoot ) {
// rewrite the observation to call its event handlers
this.toFastPath(fastPathRoot);
}
this._latestValue = this.value = canObservationRecorder_1_3_1_canObservationRecorder.peekValue(this.observation);
},
onUnbound: function onUnbound() {
this.bound = false;
canReflect_1_19_2_canReflect.offValue(this.observation, this.dispatch, "notify");
this.toSlowPath();
},
set: function(newVal){
var root = this.root || this.setRoot;
if(root) {
if(this.reads.length) {
canStacheKey_1_4_3_canStacheKey.write(root, this.reads, newVal, this.options);
} else {
canReflect_1_19_2_canReflect.setValue(root,newVal);
}
} else {
this.startingScope.set(this.key, newVal, this.options);
}
},
get: function() {
if (canObservationRecorder_1_3_1_canObservationRecorder.isRecording()) {
canObservationRecorder_1_3_1_canObservationRecorder.add(this);
if (!this.bound) {
canObservation_4_2_0_canObservation.temporarilyBind(this);
}
}
if (this.bound === true && this.fastPath === true) {
return this._latestValue;
} else {
return canObservationRecorder_1_3_1_canObservationRecorder.peekValue(this.observation);
}
},
toFastPath: function(fastPathRoot){
var self = this,
observation = this.observation;
this.fastPath = true;
// there won't be an event in the future ...
observation.dependencyChange = function(target, newVal){
if(isEventObject(newVal)) {
throw "no event objects!";
}
// but I think we will be able to get at it b/c there should only be one
// dependency we are binding to ...
if(target === fastPathRoot && typeof newVal !== "function") {
self._latestValue = newVal;
this.newVal = newVal;
} else {
// restore
self.toSlowPath();
}
return canObservation_4_2_0_canObservation.prototype.dependencyChange.apply(this, arguments);
};
if (observation.hasOwnProperty("_value")) {// can-observation 4.1+
observation.onBound = fastOnBoundSet_Value;
} else {// can-observation < 4.1
observation.onBound = fastOnBoundSetValue;
}
},
toSlowPath: function(){
this.observation.dependencyChange = canObservation_4_2_0_canObservation.prototype.dependencyChange;
this.observation.onBound = canObservation_4_2_0_canObservation.prototype.onBound;
this.fastPath = false;
},
read: function(){
var data;
if (this.root) {
// if we've figured out a root observable, start reading from there
data = canStacheKey_1_4_3_canStacheKey.read(this.root, this.reads, this.options);
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
// remove old dependency
if(this.reads.length) {
callMutateWithRightArgs(canReflectDependencies_1_1_2_canReflectDependencies.deleteMutatedBy, getMutated(this), this.reads,this);
}
}
//!steal-remove-end
// update thisArg and add new dependency
this.thisArg = data.parent;
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
var valueDeps = new Set();
valueDeps.add(this);
callMutateWithRightArgs(canReflectDependencies_1_1_2_canReflectDependencies.addMutatedBy, data.parent || this.root, this.reads,{
valueDependencies: valueDeps
});
}
//!steal-remove-end
return data.value;
}
// If the key has not already been located in a observable then we need to search the scope for the
// key. Once we find the key then we need to return it's value and if it is found in an observable
// then we need to store the observable so the next time this compute is called it can grab the value
// directly from the observable.
data = this.startingScope.read(this.key, this.options);
this.scope = data.scope;
this.reads = data.reads;
this.root = data.rootObserve;
this.setRoot = data.setRoot;
this.thisArg = data.thisArg;
this.parentHasKey = data.parentHasKey;
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
if (data.rootObserve) {
var rootValueDeps = new Set();
rootValueDeps.add(this);
callMutateWithRightArgs(canReflectDependencies_1_1_2_canReflectDependencies.addMutatedBy, getMutated(this), data.reads,{
valueDependencies: rootValueDeps
});
}
if(data.value === undefined && this.options.warnOnMissingKey === true) {
warnOnUndefinedProperty({
scope: this.startingScope,
key: this.key,
parentHasKey: data.parentHasKey
});
}
}
//!steal-remove-end
return data.value;
},
hasDependencies: function(){
// ScopeKeyData is unique in that when these things are read, it will temporarily bind
// to make sure the right value is returned. This is for can-stache.
// Helpers warns about a missing helper.
if (!this.bound) {
canObservation_4_2_0_canObservation.temporarilyBind(this);
}
return canReflect_1_19_2_canReflect.valueHasDependencies( this.observation );
}
});
Object.defineProperty(ScopeKeyData.prototype, "thisArg", {
get: function(){
return this._thisArg.get();
},
set: function(newVal) {
this._thisArg.set(newVal);
}
});
var scopeKeyDataPrototype = {
"can.getValue": ScopeKeyData.prototype.get,
"can.setValue": ScopeKeyData.prototype.set,
"can.valueHasDependencies": ScopeKeyData.prototype.hasDependencies,
"can.getValueDependencies": function() {
return this.dependencies;
},
"can.getPriority": function(){
return canReflect_1_19_2_canReflect.getPriority( this.observation );
},
"can.setPriority": function(newPriority){
canReflect_1_19_2_canReflect.setPriority( this.observation, newPriority );
},
"can.setElement": function(element) {
this.observation[setElementSymbol$1](element);
}
};
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
scopeKeyDataPrototype["can.getName"] = function() {
return canReflect_1_19_2_canReflect.getName(this.constructor) + "{{" + this.key + "}}";
};
}
//!steal-remove-end
canReflect_1_19_2_canReflect.assignSymbols(ScopeKeyData.prototype, scopeKeyDataPrototype);
// Creates a compute-like for legacy reasons ...
Object.defineProperty(ScopeKeyData.prototype, "compute", {
get: function(){
var compute = canViewScope_4_13_7_makeComputeLike(this);
Object.defineProperty(this, "compute", {
value: compute,
writable: false,
configurable: false
});
return compute;
},
configurable: true
});
Object.defineProperty(ScopeKeyData.prototype, "initialValue", {
get: function(){
if (!this.bound) {
canObservation_4_2_0_canObservation.temporarilyBind(this);
}
return canObservationRecorder_1_3_1_canObservationRecorder.peekValue(this);
},
set: function(){
throw new Error("initialValue should not be set");
},
configurable: true
});
var canViewScope_4_13_7_scopeKeyData = ScopeKeyData;
var canViewScope_4_13_7_compute_data = function(scope, key, options){
return new canViewScope_4_13_7_scopeKeyData(scope, key, options || {
args: []
});
};
// ### LetContext
// Instances of this are used to create a `let` variable context.
// Like Object.create, but only keeps Symbols and properties in `propertiesToKeep`
function objectCreateWithSymbolsAndSpecificProperties(obj, propertiesToKeep) {
var newObj = {};
// copy over all Symbols from obj
if ("getOwnPropertySymbols" in Object) {
Object.getOwnPropertySymbols(obj).forEach(function(key) {
newObj[key] = obj[key];
});
}
// copy over specific properties from obj (also fake Symbols properties for IE support);
Object.getOwnPropertyNames(obj).forEach(function(key) {
if (propertiesToKeep.indexOf(key) >= 0 || key.indexOf("@@symbol") === 0) {
newObj[key] = obj[key];
}
});
return Object.create(newObj);
}
var LetContext = canSimpleMap_4_3_3_canSimpleMap.extend("LetContext", {});
LetContext.prototype = objectCreateWithSymbolsAndSpecificProperties(canSimpleMap_4_3_3_canSimpleMap.prototype, [
// SimpleMap properties
"setup",
"attr",
"serialize",
"get",
"set",
"log",
// required by SimpleMap properties
"dispatch",
// Construct properties (not added by can-event-queue)
"constructorExtends",
"newInstance",
"_inherit",
"_defineProperty",
"_overwrite",
"instance",
"extend",
"ReturnValue",
"setup",
"init"
]);
LetContext.prototype.constructor = LetContext;
var canViewScope_4_13_7_letContext = LetContext;
// # can-view-scope.js
//
// This provides the ability to lookup values across a higherarchy of objects. This is similar to
// how closures work in JavaScript.
//
// This is done with the `Scope` type. It works by having a `_context` reference to
// an object whose properties can be searched for values. It also has a `_parent` reference
// to the next Scope in which to check. In this way, `Scope` is used to form a tree-like
// structure. Leaves and Nodes in the tree only point to their parent.
// ## Helpers
function canHaveProperties(obj){
return obj != null;
}
function returnFalse(){
return false;
}
// ## Scope
// Represents a node in the scope tree.
function Scope(context, parent, meta) {
// The object that will be looked on for values.
// If the type of context is TemplateContext, there will be special rules for it.
this._context = context;
// The next Scope object whose context should be looked on for values.
this._parent = parent;
// If this is a special context, it can be labeled here.
// Options are:
// - `viewModel` - This is a viewModel. This is mostly used by can-component to make `scope.vm` work.
// - `notContext` - This can't be looked within using `./` and `../`. It will be skipped.
// This is for virtual contexts like those used by `%index`. This is very much like
// `variable`. Most things should switch to `variable` in the future.
// - `special` - This can't be looked within using `./` and `../`. It will be skipped.
// This is for reading properties on the scope {{scope.index}}. It's different from variable
// because it's never lookup up like {{key}}.
// - `variable` - This is used to define a variable (as opposed to "normal" context). These
// will also be skipped when using `./` and `../`.
this._meta = meta || {};
// A cache that can be used to store computes used to look up within this scope.
// For example if someone creates a compute to lookup `name`, another compute does not
// need to be created.
this.__cache = {};
}
var parentContextSearch = /(\.\.\/)|(\.\/)|(this[\.@])/g;
// ## Static Methods
// The following methods are exposed mostly for testing purposes.
canAssign_1_3_3_canAssign(Scope, {
// ### Scope.read
// Scope.read was moved to can-stache-key.read
// can-stache-key.read reads properties from a parent. A much more complex version of getObject.
read: canStacheKey_1_4_3_canStacheKey.read,
TemplateContext: canViewScope_4_13_7_templateContext,
// ### keyInfo(key)
// Returns an object that details what the `key` means with the following:
// ```js
// {
// remainingKey, // what would be read on a context (or this)
// isScope, // if the scope itself is being read
// inScope, // if a key on the scope is being read
// parentContextWalkCount, // how many ../
// isContextBased // if a "normal" context is explicitly being read
// }
// ```
keyInfo: function(attr){
if (attr === "./") {
attr = "this";
}
var info = {remainingKey: attr};
// handle scope stuff first
info.isScope = attr === "scope";
if(info.isScope) {
return info;
}
var firstSix = attr.substr(0, 6);
info.isInScope =
firstSix === "scope." ||
firstSix === "scope@";
if(info.isInScope) {
info.remainingKey = attr.substr(6);
return info;
} else if(firstSix === "scope/") {
info.walkScope = true;
info.remainingKey = attr.substr(6);
return info;
} else if(attr.substr(0, 7) === "@scope/") {
info.walkScope = true;
info.remainingKey = attr.substr(7);
return info;
}
info.parentContextWalkCount = 0;
// Searches for `../` and other context specifiers
info.remainingKey = attr.replace(parentContextSearch, function(token, parentContext, dotSlash, thisContext, index){
info.isContextBased = true;
if(parentContext !== undefined) {
info.parentContextWalkCount++;
}
return "";
});
// ../..
if(info.remainingKey === "..") {
info.parentContextWalkCount++;
info.remainingKey = "this";
}
else if(info.remainingKey === "." || info.remainingKey === "") {
info.remainingKey = "this";
}
if(info.remainingKey === "this") {
info.isContextBased = true;
}
return info;
},
// ### isTemplateContextOrCanNotHaveProperties
// Returns `true` if a template context or a `null` or `undefined`
// context.
isTemplateContextOrCanNotHaveProperties: function(currentScope){
var currentContext = currentScope._context;
if(currentContext instanceof canViewScope_4_13_7_templateContext) {
return true;
} else if( !canHaveProperties(currentContext) ) {
return true;
}
return false;
},
// ### shouldSkipIfSpecial
// Return `true` if special.
shouldSkipIfSpecial: function(currentScope){
var isSpecialContext = currentScope._meta.special === true;
if (isSpecialContext === true) {
return true;
}
if( Scope.isTemplateContextOrCanNotHaveProperties(currentScope) ) {
return true;
}
return false;
},
// ### shouldSkipEverythingButSpecial
// Return `true` if not special.
shouldSkipEverythingButSpecial: function(currentScope){
var isSpecialContext = currentScope._meta.special === true;
if (isSpecialContext === false) {
return true;
}
if( Scope.isTemplateContextOrCanNotHaveProperties(currentScope) ) {
return true;
}
return false;
},
// ### makeShouldExitOnSecondNormalContext
// This will keep checking until we hit a second "normal" context.
makeShouldExitOnSecondNormalContext: function(){
var foundNormalContext = false;
return function shouldExitOnSecondNormalContext(currentScope){
var isNormalContext = !currentScope.isSpecial();
var shouldExit = isNormalContext && foundNormalContext;
// leaks some state
if(isNormalContext) {
foundNormalContext = true;
}
return shouldExit;
};
},
// ### makeShouldExitAfterFirstNormalContext
// This will not check anything after the first normal context.
makeShouldExitAfterFirstNormalContext: function(){
var foundNormalContext = false;
return function shouldExitAfterFirstNormalContext(currentScope){
if(foundNormalContext) {
return true;
}
var isNormalContext = !currentScope.isSpecial();
// leaks some state
if(isNormalContext) {
foundNormalContext = true;
}
return false;
};
},
// ### makeShouldSkipSpecialContexts
// Skips `parentContextWalkCount` contexts. This is used to
// walk past scopes when `../` is used.
makeShouldSkipSpecialContexts: function(parentContextWalkCount){
var walkCount = parentContextWalkCount || 0;
return function shouldSkipSpecialContexts(currentScope){
// after walking past the correct number of contexts,
// should not skip notContext scopes
// so that ../foo can be used to read from a notContext scope
if (walkCount < 0 && currentScope._meta.notContext) {
return false;
}
if(currentScope.isSpecial()) {
return true;
}
walkCount--;
if(walkCount < 0) {
return false;
}
return true;
};
}
});
// ## Prototype methods
canAssign_1_3_3_canAssign(Scope.prototype, {
// ### scope.add
// Creates a new scope and sets the current scope to be the parent.
// ```
// var scope = new can.view.Scope([
// {name:"Chris"},
// {name: "Justin"}
// ]).add({name: "Brian"});
// scope.attr("name") //-> "Brian"
// ```
add: function(context, meta) {
if (context !== this._context) {
return new this.constructor(context, this, meta);
} else {
return this;
}
},
// ### scope.find
// This is the equivalent of Can 3's scope walking.
find: function(attr, options) {
var keyReads = canStacheKey_1_4_3_canStacheKey.reads(attr);
var howToRead = {
shouldExit: returnFalse,
shouldSkip: Scope.shouldSkipIfSpecial,
shouldLookForHelper: true,
read: canStacheKey_1_4_3_canStacheKey.read
};
var result = this._walk(keyReads, options, howToRead);
return result.value;
},
// ### scope.readFromSpecialContext
readFromSpecialContext: function(key) {
return this._walk(
[{key: key, at: false }],
{ special: true },
{
shouldExit: returnFalse,
shouldSkip: Scope.shouldSkipEverythingButSpecial,
shouldLookForHelper: false,
read: canStacheKey_1_4_3_canStacheKey.read
}
);
},
// ### scope.readFromTemplateContext
readFromTemplateContext: function(key, readOptions) {
var keyReads = canStacheKey_1_4_3_canStacheKey.reads(key);
return canStacheKey_1_4_3_canStacheKey.read(this.templateContext, keyReads, readOptions);
},
// ### Scope.prototype.read
// Reads from the scope chain and returns the first non-`undefined` value.
// `read` deals mostly with setting up "context based" keys to start reading
// from the right scope. Once the right scope is located, `_walk` is called.
/**
* @hide
* @param {can.stache.key} attr A dot-separated path. Use `"\."` if you have a property name that includes a dot.
* @param {can.view.Scope.readOptions} options that configure how this gets read.
* @return {{}}
* @option {Object} parent the value's immediate parent
* @option {can.Map|can.compute} rootObserve the first observable to read from.
* @option {Array} reads An array of properties that can be used to read from the rootObserve to get the value.
* @option {*} value the found value
*/
read: function(attr, options) {
options = options || {};
return this.readKeyInfo(Scope.keyInfo(attr), options || {});
},
readKeyInfo: function(keyInfo, options){
// Identify context based keys. Context based keys try to
// specify a particular context a key should be within.
var readValue,
keyReads,
howToRead = {
read: options.read || canStacheKey_1_4_3_canStacheKey.read
};
// 1.A. Handle reading the scope itself
if (keyInfo.isScope) {
return { value: this };
}
// 1.B. Handle reading something on the scope
else if (keyInfo.isInScope) {
keyReads = canStacheKey_1_4_3_canStacheKey.reads(keyInfo.remainingKey);
// check for a value on Scope.prototype
readValue = canStacheKey_1_4_3_canStacheKey.read(this, keyReads, options);
// otherwise, check the templateContext
if (typeof readValue.value === 'undefined' && !readValue.parentHasKey) {
readValue = this.readFromTemplateContext(keyInfo.remainingKey, options);
}
return canAssign_1_3_3_canAssign(readValue, {
thisArg: keyReads.length > 0 ? readValue.parent : undefined
});
}
// 1.C. Handle context-based reads. They should skip over special stuff.
// this.key, ../.., .././foo
else if (keyInfo.isContextBased) {
// TODO: REMOVE
// options && options.special === true && console.warn("SPECIAL!!!!");
if(keyInfo.remainingKey !== "this") {
keyReads = canStacheKey_1_4_3_canStacheKey.reads(keyInfo.remainingKey);
} else {
keyReads = [];
}
howToRead.shouldExit = Scope.makeShouldExitOnSecondNormalContext();
howToRead.shouldSkip = Scope.makeShouldSkipSpecialContexts(keyInfo.parentContextWalkCount);
howToRead.shouldLookForHelper = true;
return this._walk(keyReads, options, howToRead);
}
// 1.D. Handle scope walking with scope/key
else if(keyInfo.walkScope) {
howToRead.shouldExit = returnFalse;
howToRead.shouldSkip = Scope.shouldSkipIfSpecial;
howToRead.shouldLookForHelper = true;
keyReads = canStacheKey_1_4_3_canStacheKey.reads(keyInfo.remainingKey);
return this._walk(keyReads, options, howToRead);
}
// 1.E. Handle reading without context clues
// {{foo}}
else {
keyReads = canStacheKey_1_4_3_canStacheKey.reads(keyInfo.remainingKey);
var isSpecialRead = options && options.special === true;
// TODO: remove
// options && options.special === true && console.warn("SPECIAL!!!!");
howToRead.shouldExit = Scope.makeShouldExitOnSecondNormalContext();
howToRead.shouldSkip = isSpecialRead ? Scope.shouldSkipEverythingButSpecial : Scope.shouldSkipIfSpecial;
howToRead.shouldLookForHelper = isSpecialRead ? false : true;
return this._walk(keyReads, options, howToRead);
}
},
// ### scope._walk
// This is used to walk up the scope chain.
_walk: function(keyReads, options, howToRead) {
// The current scope and context we are trying to find "keyReads" within.
var currentScope = this,
currentContext,
// If no value can be found, this is a list of of every observed
// object and property name to observe.
undefinedObserves = [],
// Tracks the first found observe.
currentObserve,
// Tracks the reads to get the value from `currentObserve`.
currentReads,
// Tracks the most likely observable to use as a setter.
setObserveDepth = -1,
currentSetReads,
currentSetObserve,
readOptions = canAssign_1_3_3_canAssign({
/* Store found observable, incase we want to set it as the rootObserve. */
foundObservable: function(observe, nameIndex) {
currentObserve = observe;
currentReads = keyReads.slice(nameIndex);
},
earlyExit: function(parentValue, nameIndex) {
var isVariableScope = currentScope._meta.variable === true,
updateSetObservable = false;
if(isVariableScope === true && nameIndex === 0) {
// we MUST have pre-defined the key in a variable scope
updateSetObservable = canReflect_1_19_2_canReflect.hasKey( parentValue, keyReads[nameIndex].key);
} else {
updateSetObservable =
// Has more matches
nameIndex > setObserveDepth ||
// The same number of matches but it has the key
nameIndex === setObserveDepth && (typeof parentValue === "object" && canReflect_1_19_2_canReflect.hasOwnKey( parentValue, keyReads[nameIndex].key));
}
if ( updateSetObservable ) {
currentSetObserve = currentObserve;
currentSetReads = currentReads;
setObserveDepth = nameIndex;
}
}
}, options);
var isRecording = canObservationRecorder_1_3_1_canObservationRecorder.isRecording(),
readAContext = false;
// Goes through each scope context provided until it finds the key (attr). Once the key is found
// then it's value is returned along with an observe, the current scope and reads.
// While going through each scope context searching for the key, each observable found is returned and
// saved so that either the observable the key is found in can be returned, or in the case the key is not
// found in an observable the closest observable can be returned.
while (currentScope) {
if(howToRead.shouldSkip(currentScope) === true) {
currentScope = currentScope._parent;
continue;
}
if(howToRead.shouldExit(currentScope) === true) {
break;
}
readAContext = true;
currentContext = currentScope._context;
// Prevent computes from temporarily observing the reading of observables.
var getObserves = canObservationRecorder_1_3_1_canObservationRecorder.trap();
var data = howToRead.read(currentContext, keyReads, readOptions);
// Retrieve the observes that were read.
var observes = getObserves();
// If a **value was was found**, return value and location data.
if (data.value !== undefined || data.parentHasKey) {
if(!observes.length && isRecording) {
// if we didn't actually observe anything
// the reads and currentObserve don't mean anything
// we just point to the current object so setting is fast
currentObserve = data.parent;
currentReads = keyReads.slice(keyReads.length - 1);
} else {
canObservationRecorder_1_3_1_canObservationRecorder.addMany(observes);
}
return {
scope: currentScope,
rootObserve: currentObserve,
value: data.value,
reads: currentReads,
thisArg: data.parent,
parentHasKey: data.parentHasKey
};
}
// Otherwise, save all observables that were read. If no value
// is found, we will observe on all of them.
else {
undefinedObserves.push.apply(undefinedObserves, observes);
}
currentScope = currentScope._parent;
}
// The **value was not found** in the scope
// if not looking for a "special" key, check in can-stache-helpers
if (howToRead.shouldLookForHelper) {
var helper = this.getHelperOrPartial(keyReads);
if (helper) {
// Don't return parent so `.bind` is not used.
return {value: helper};
}
}
// The **value was not found**, return `undefined` for the value.
// Make sure we listen to everything we checked for when the value becomes defined.
// Once it becomes defined, we won't have to listen to so many things.
canObservationRecorder_1_3_1_canObservationRecorder.addMany(undefinedObserves);
return {
setRoot: currentSetObserve,
reads: currentSetReads,
value: undefined,
noContextAvailable: !readAContext
};
},
// ### scope.getDataForScopeSet
// Returns an object with data needed by `.set` to figure out what to set,
// and how.
// {
// parent: what is being set
// key: try setting a key value
// how: "setValue" | "set" | "updateDeep" | "write" | "setKeyValue"
// }
// This works by changing how `readKeyInfo` will read individual scopes.
// Specifically, with something like `{{foo.bar}}` it will read `{{foo}}` and
// only check if a `bar` property exists.
getDataForScopeSet: function getDataForScopeSet(key, options) {
var keyInfo = Scope.keyInfo(key);
var firstSearchedContext;
// Overwrite the options to use this read.
var opts = canAssign_1_3_3_canAssign({
// This read is used by `._walk` to read from the scope.
// This will use `hasKey` on the last property instead of reading it.
read: function(context, keys){
// If nothing can be found with the keys we are looking for, save the
// first possible match. This is where we will write to.
if(firstSearchedContext === undefined && !(context instanceof canViewScope_4_13_7_letContext)) {
firstSearchedContext = context;
}
// If we have multiple keys ...
if(keys.length > 1) {
// see if we can find the parent ...
var parentKeys = keys.slice(0, keys.length-1);
var parent = canStacheKey_1_4_3_canStacheKey.read(context, parentKeys, options).value;
// If there is a parent, see if it has the last key
if( parent != null && canReflect_1_19_2_canReflect.hasKey(parent, keys[keys.length-1].key ) ) {
return {
parent: parent,
parentHasKey: true,
value: undefined
};
} else {
return {};
}
}
// If we have only one key, try to find a context with this key
else if(keys.length === 1) {
if( canReflect_1_19_2_canReflect.hasKey(context, keys[0].key ) ) {
return {
parent: context,
parentHasKey: true,
value: undefined
};
} else {
return {};
}
}
// If we have no keys, we are reading `this`.
else {
return {
value: context
};
}
}
},options);
// Use the read above to figure out what we are probably writing to.
var readData = this.readKeyInfo(keyInfo, opts);
if(keyInfo.remainingKey === "this") {
// If we are setting a context, then return that context
return { parent: readData.value, how: "setValue" };
}
// Now we are trying to set a property on something. Parent will
// be the something we are setting a property on.
var parent;
var props = keyInfo.remainingKey.split(".");
var propName = props.pop();
// If we got a `thisArg`, that's the parent.
if(readData.thisArg) {
parent = readData.thisArg;
}
// Otherwise, we didn't find anything, use the first searched context.
// TODO: there is likely a bug here when trying to set foo.bar where nothing in the scope
// has a foo.
else if(firstSearchedContext) {
parent = firstSearchedContext;
}
if (parent === undefined) {
return {
error: "Attempting to set a value at " +
key + " where the context is undefined."
};
}
// Now we need to figure out how we would update this value. The following does that.
if(!canReflect_1_19_2_canReflect.isObservableLike(parent) && canReflect_1_19_2_canReflect.isObservableLike(parent[propName])) {
if(canReflect_1_19_2_canReflect.isMapLike(parent[propName])) {
return {
parent: parent,
key: propName,
how: "updateDeep",
warn: "can-view-scope: Merging data into \"" +
propName + "\" because its parent is non-observable"
};
}
else if(canReflect_1_19_2_canReflect.isValueLike(parent[propName])){
return { parent: parent, key: propName, how: "setValue" };
} else {
return { parent: parent, how: "write", key: propName, passOptions: true };
}
} else {
return { parent: parent, how: "write", key: propName, passOptions: true };
}
},
// ### scope.getHelper
// read a helper from the templateContext or global helpers list
getHelper: function(keyReads) {
console.warn(".getHelper is deprecated, use .getHelperOrPartial");
return this.getHelperOrPartial(keyReads);
},
getHelperOrPartial: function(keyReads) {
// try every template context
var scope = this, context, helper;
while (scope) {
context = scope._context;
if (context instanceof canViewScope_4_13_7_templateContext) {
helper = canStacheKey_1_4_3_canStacheKey.read(context.helpers, keyReads, { proxyMethods: false });
if(helper.value !== undefined) {
return helper.value;
}
helper = canStacheKey_1_4_3_canStacheKey.read(context.partials, keyReads, { proxyMethods: false });
if(helper.value !== undefined) {
return helper.value;
}
}
scope = scope._parent;
}
return canStacheKey_1_4_3_canStacheKey.read(canStacheHelpers_1_2_0_canStacheHelpers, keyReads, { proxyMethods: false }).value;
},
// ### scope.get
// Gets a value from the scope without being observable.
get: function(key, options) {
options = canAssign_1_3_3_canAssign({
isArgument: true
}, options);
var res = this.read(key, options);
return res.value;
},
peek: canObservationRecorder_1_3_1_canObservationRecorder.ignore(function(key, options) {
return this.get(key, options);
}),
// TODO: Remove in 6.0
peak: canObservationRecorder_1_3_1_canObservationRecorder.ignore(function(key, options) {
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
dev.warn('peak is deprecated, please use peek instead');
}
//!steal-remove-end
return this.peek(key, options);
}),
// ### scope.getScope
// Returns the first scope that passes the `tester` function.
getScope: function(tester) {
var scope = this;
while (scope) {
if (tester(scope)) {
return scope;
}
scope = scope._parent;
}
},
// ### scope.getContext
// Returns the first context whose scope passes the `tester` function.
getContext: function(tester) {
var res = this.getScope(tester);
return res && res._context;
},
// ### scope.getTemplateContext
// Returns the template context scope
// This function isn't named right.
getTemplateContext: function() {
var lastScope;
// find the first reference scope
var templateContext = this.getScope(function(scope) {
lastScope = scope;
return scope._context instanceof canViewScope_4_13_7_templateContext;
});
// if there is no reference scope, add one as the root
if(!templateContext) {
templateContext = new Scope(new canViewScope_4_13_7_templateContext());
// add templateContext to root of the scope chain so it
// can be found using `getScope` next time it is looked up
lastScope._parent = templateContext;
}
return templateContext;
},
addTemplateContext: function(){
return this.add(new canViewScope_4_13_7_templateContext());
},
addLetContext: function(values){
return this.add(new canViewScope_4_13_7_letContext(values || {}), {variable: true});
},
// ### scope.getRoot
// Returns the top most context that is not a references scope.
// Used by `.read` to provide `%root`.
getRoot: function() {
var cur = this,
child = this;
while (cur._parent) {
child = cur;
cur = cur._parent;
}
if (cur._context instanceof canViewScope_4_13_7_templateContext) {
cur = child;
}
return cur._context;
},
// first viewModel scope
getViewModel: function() {
var vmScope = this.getScope(function(scope) {
return scope._meta.viewModel;
});
return vmScope && vmScope._context;
},
// _top_ viewModel scope
getTop: function() {
var top;
this.getScope(function(scope) {
if (scope._meta.viewModel) {
top = scope;
}
// walk entire scope tree
return false;
});
return top && top._context;
},
// ### scope.getPathsForKey
// Finds all paths that will return a value for a specific key
// NOTE: this is for development purposes only and is removed in production
getPathsForKey: function getPathsForKey(key) {
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
var paths = {};
var getKeyDefinition = function(obj, key) {
if (!obj || typeof obj !== "object") {
return {};
}
var keyExistsOnObj = key in obj;
var objHasKey = canReflect_1_19_2_canReflect.hasKey(obj, key);
return {
isDefined: keyExistsOnObj || objHasKey,
isFunction: keyExistsOnObj && typeof obj[key] === "function"
};
};
// scope.foo@bar -> bar
var reads = canStacheKey_1_4_3_canStacheKey.reads(key);
var keyParts = reads.map(function(read) {
return read.key;
});
var scopeIndex = keyParts.indexOf("scope");
if (scopeIndex > -1) {
keyParts.splice(scopeIndex, 2);
}
var normalizedKey = keyParts.join(".");
// check scope.vm.
var vm = this.getViewModel();
var vmKeyDefinition = getKeyDefinition(vm, normalizedKey);
if (vmKeyDefinition.isDefined) {
paths["scope.vm." + normalizedKey + (vmKeyDefinition.isFunction ? "()" : "")] = vm;
}
// check scope.top.
var top = this.getTop();
var topKeyDefinition = getKeyDefinition(top, normalizedKey);
if (topKeyDefinition.isDefined) {
paths["scope.top." + normalizedKey + (topKeyDefinition.isFunction ? "()" : "")] = top;
}
// find specific paths (like ../key)
var cur = "";
this.getScope(function(scope) {
// `notContext` and `special` contexts can't be read using `../`
var canBeRead = !scope.isSpecial();
if (canBeRead) {
var contextKeyDefinition = getKeyDefinition(scope._context, normalizedKey);
if (contextKeyDefinition.isDefined) {
paths[cur + normalizedKey + (contextKeyDefinition.isFunction ? "()" : "")] = scope._context;
}
cur += "../";
}
// walk entire scope tree
return false;
});
return paths;
}
//!steal-remove-end
},
// ### scope.hasKey
// returns whether or not this scope has the key
hasKey: function hasKey(key) {
var reads = canStacheKey_1_4_3_canStacheKey.reads(key);
var readValue;
if (reads[0].key === "scope") {
// read properties like `scope.vm.foo` directly from the scope
readValue = canStacheKey_1_4_3_canStacheKey.read(this, reads.slice(1), key);
} else {
// read normal properties from the scope's context
readValue = canStacheKey_1_4_3_canStacheKey.read(this._context, reads, key);
}
return readValue.foundLastParent && readValue.parentHasKey;
},
set: function(key, value, options) {
options = options || {};
var data = this.getDataForScopeSet(key, options);
var parent = data.parent;
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
if (data.error) {
return dev.error(data.error);
}
}
//!steal-remove-end
if (data.warn) {
dev.warn(data.warn);
}
switch (data.how) {
case "set":
parent.set(data.key, value, data.passOptions ? options : undefined);
break;
case "write":
canStacheKey_1_4_3_canStacheKey.write(parent, data.key, value, options);
break;
case "setValue":
canReflect_1_19_2_canReflect.setValue("key" in data ? parent[data.key] : parent, value);
break;
case "setKeyValue":
canReflect_1_19_2_canReflect.setKeyValue(parent, data.key, value);
break;
case "updateDeep":
canReflect_1_19_2_canReflect.updateDeep(parent[data.key], value);
break;
}
},
// ### scope.attr
// Gets or sets a value in the scope without being observable.
attr: canObservationRecorder_1_3_1_canObservationRecorder.ignore(function(key, value, options) {
dev.warn("can-view-scope::attr is deprecated, please use peek, get or set");
options = canAssign_1_3_3_canAssign({
isArgument: true
}, options);
// Allow setting a value on the context
if (arguments.length === 2) {
return this.set(key, value, options);
} else {
return this.get(key, options);
}
}),
// ### scope.computeData
// Finds the first location of the key in the scope and then provides a get-set compute that represents the key's value
// and other information about where the value was found.
computeData: function(key, options) {
return canViewScope_4_13_7_compute_data(this, key, options);
},
// ### scope.compute
// Provides a get-set compute that represents a key's value.
compute: function(key, options) {
return this.computeData(key, options)
.compute;
},
// ### scope.cloneFromRef
//
// This takes a scope and essentially copies its chain from
// right before the last TemplateContext. And it does not include the ref.
// this is a helper function to provide lexical semantics for refs.
// This will not be needed for leakScope: false.
cloneFromRef: function() {
var scopes = [];
var scope = this,
context,
parent;
while (scope) {
context = scope._context;
if (context instanceof canViewScope_4_13_7_templateContext) {
parent = scope._parent;
break;
}
scopes.unshift(scope);
scope = scope._parent;
}
if (parent) {
scopes.forEach(function(scope) {
// For performance, re-use _meta, don't copy it.
parent = parent.add(scope._context, scope._meta);
});
return parent;
} else {
return this;
}
},
isSpecial: function(){
return this._meta.notContext || this._meta.special || (this._context instanceof canViewScope_4_13_7_templateContext) || this._meta.variable;
}
});
// Legacy name for _walk.
Scope.prototype._read = Scope.prototype._walk;
canReflect_1_19_2_canReflect.assignSymbols(Scope.prototype, {
"can.hasKey": Scope.prototype.hasKey,
"can.isScopeLike": true
});
var templateContextPrimitives = [
"filename", "lineNumber"
];
// create getters/setters for primitives on the templateContext
// scope.filename -> scope.readFromTemplateContext("filename")
templateContextPrimitives.forEach(function(key) {
Object.defineProperty(Scope.prototype, key, {
get: function() {
return this.readFromTemplateContext(key).value;
},
set: function(val) {
this.templateContext[key] = val;
}
});
});
canDefineLazyValue_1_1_1_defineLazyValue(Scope.prototype, 'templateContext', function() {
return this.getTemplateContext()._context;
});
canDefineLazyValue_1_1_1_defineLazyValue(Scope.prototype, 'root', function() {
dev.warn('`scope.root` is deprecated. Use either `scope.top`: https://canjs.com/doc/can-stache/keys/scope.html#scope_top or `scope.vm`: https://canjs.com/doc/can-stache/keys/scope.html#scope_vm instead.');
return this.getRoot();
});
canDefineLazyValue_1_1_1_defineLazyValue(Scope.prototype, 'vm', function() {
return this.getViewModel();
});
canDefineLazyValue_1_1_1_defineLazyValue(Scope.prototype, 'top', function() {
return this.getTop();
});
canDefineLazyValue_1_1_1_defineLazyValue(Scope.prototype, 'helpers', function() {
return canStacheHelpers_1_2_0_canStacheHelpers;
});
var specialKeywords = [
'index', 'key', 'element',
'event', 'viewModel','arguments',
'helperOptions', 'args'
];
// create getters for "special" keys
// scope.index -> scope.readFromSpecialContext("index")
specialKeywords.forEach(function(key) {
Object.defineProperty(Scope.prototype, key, {
get: function() {
return this.readFromSpecialContext(key).value;
}
});
});
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
Scope.prototype.log = function() {
var scope = this;
var indent = "";
var contextType = "";
while(scope) {
contextType = scope._meta.notContext ? " (notContext)" :
scope._meta.special ? " (special)" : "";
console.log(indent, canReflect_1_19_2_canReflect.getName(scope._context) + contextType, scope._context);
scope = scope._parent;
indent += " ";
}
};
}
//!steal-remove-end
canNamespace_1_0_0_canNamespace.view = canNamespace_1_0_0_canNamespace.view || {};
var canViewScope_4_13_7_canViewScope = canNamespace_1_0_0_canNamespace.view.Scope = Scope;
function KeyObservable(root, key){
key = ""+key;
this.key = key;
this.root = root;
settable.call(this, function(){
return canStacheKey_1_4_3_canStacheKey.get(this,key);
}, root);
}
KeyObservable.prototype = Object.create(settable.prototype);
KeyObservable.prototype.set = function(newVal) {
canStacheKey_1_4_3_canStacheKey.set(this.root,this.key, newVal);
};
var keyObservable = KeyObservable;
var isViewSymbol = canSymbol_1_7_0_canSymbol.for("can.isView");
// this creates a noop that marks that a renderer was called
// this is for situations where a helper function calls a renderer
// that was not provided such as
// {{#if false}} ... {{/if}}
// with no {{else}}
var createNoOpRenderer = function (metadata) {
return function noop() {
if (metadata) {
metadata.rendered = true;
}
};
};
var utils$1 = {
last: function(arr){
return arr !=null && arr[arr.length-1];
},
// A generic empty function
emptyHandler: function(){},
// Converts a string like "1" into 1. "null" into null, etc.
// This doesn't have to do full JSON, so removing eval would be good.
jsonParse: function(str){
// if it starts with a quote, assume a string.
if(str[0] === "'") {
return str.substr(1, str.length -2);
} else if(str === "undefined") {
return undefined;
} else {
return JSON.parse(str);
}
},
mixins: {
last: function(){
return this.stack[this.stack.length - 1];
},
add: function(chars){
this.last().add(chars);
},
subSectionDepth: function(){
return this.stack.length - 1;
}
},
// Sets .fn and .inverse on a helperOptions object and makes sure
// they can reference the current scope and options.
createRenderers: function(helperOptions, scope, truthyRenderer, falseyRenderer, isStringOnly){
helperOptions.fn = truthyRenderer ? this.makeRendererConvertScopes(truthyRenderer, scope, isStringOnly, helperOptions.metadata) : createNoOpRenderer(helperOptions.metadata);
helperOptions.inverse = falseyRenderer ? this.makeRendererConvertScopes(falseyRenderer, scope, isStringOnly, helperOptions.metadata) : createNoOpRenderer(helperOptions.metadata);
helperOptions.isSection = !!(truthyRenderer || falseyRenderer);
},
// Returns a new renderer function that makes sure any data or helpers passed
// to it are converted to a can.view.Scope and a can.view.Options.
makeRendererConvertScopes: function (renderer, parentScope, observeObservables, metadata) {
var convertedRenderer = function (newScope, newOptions) {
// prevent binding on fn.
// If a non-scope value is passed, add that to the parent scope.
if (newScope !== undefined && !(newScope instanceof canViewScope_4_13_7_canViewScope)) {
if (parentScope) {
newScope = parentScope.add(newScope);
}
else {
newScope = new canViewScope_4_13_7_canViewScope(newScope || {});
}
}
if (metadata) {
metadata.rendered = true;
}
var result = renderer(newScope || parentScope );
return result;
};
return observeObservables ? convertedRenderer :
canObservationRecorder_1_3_1_canObservationRecorder.ignore(convertedRenderer);
},
makeView: function(renderer){
var view = canObservationRecorder_1_3_1_canObservationRecorder.ignore(function(scope){
if(!(scope instanceof canViewScope_4_13_7_canViewScope)) {
scope = new canViewScope_4_13_7_canViewScope(scope);
}
return renderer(scope);
});
view[isViewSymbol] = true;
return view;
},
// Calls the truthy subsection for each item in a list and returning them in a string.
getItemsStringContent: function(items, isObserveList, helperOptions){
var txt = "",
len = canStacheKey_1_4_3_canStacheKey.get(items, 'length'),
isObservable = canReflect_1_19_2_canReflect.isObservableLike(items);
for (var i = 0; i < len; i++) {
var item = isObservable ? new keyObservable(items, i) :items[i];
txt += helperOptions.fn(item);
}
return txt;
},
// Calls the truthy subsection for each item in a list and returns them in a document Fragment.
getItemsFragContent: function(items, helperOptions, scope) {
var result = [],
len = canStacheKey_1_4_3_canStacheKey.get(items, 'length'),
isObservable = canReflect_1_19_2_canReflect.isObservableLike(items),
hashExprs = helperOptions.exprData && helperOptions.exprData.hashExprs,
hashOptions;
// Check if using hash
if (canReflect_1_19_2_canReflect.size(hashExprs) > 0) {
hashOptions = {};
canReflect_1_19_2_canReflect.eachKey(hashExprs, function (exprs, key) {
hashOptions[exprs.key] = key;
});
}
for (var i = 0; i < len; i++) {
var aliases = {};
var item = isObservable ? new keyObservable(items, i) :items[i];
if (canReflect_1_19_2_canReflect.size(hashOptions) > 0) {
if (hashOptions.value) {
aliases[hashOptions.value] = item;
}
if (hashOptions.index) {
aliases[hashOptions.index] = i;
}
}
result.push(helperOptions.fn(
scope
.add(aliases, { notContext: true })
.add({ index: i }, { special: true })
.add(item))
);
}
return result;
}
};
var last = utils$1.last;
var decodeHTML = typeof document !== "undefined" && (function(){
var el = document$1().createElement('div');
return function(html){
if(html.indexOf("&") === -1) {
return html.replace(/\r\n/g,"\n");
}
el.innerHTML = html;
return el.childNodes.length === 0 ? "" : el.childNodes.item(0).nodeValue;
};
})();
// ## HTMLSectionBuilder
//
// Contains a stack of HTMLSections.
// An HTMLSection is created everytime a subsection is found. For example:
//
// {{#if(items)}} {{#items}} X
//
// At the point X was being processed, there would be 2 HTMLSections in the
// stack. One for the content of `{{#if(items)}}` and the other for the
// content of `{{#items}}`
var HTMLSectionBuilder = function(filename){
if (filename) {
this.filename = filename;
}
this.stack = [new HTMLSection()];
};
canAssign_1_3_3_canAssign(HTMLSectionBuilder.prototype,utils$1.mixins);
canAssign_1_3_3_canAssign(HTMLSectionBuilder.prototype,{
startSubSection: function(process){
var newSection = new HTMLSection(process);
this.stack.push(newSection);
return newSection;
},
// Ends the current section and returns a renderer.
// But only returns a renderer if there is a template.
endSubSectionAndReturnRenderer: function(){
if(this.last().isEmpty()) {
this.stack.pop();
return null;
} else {
var htmlSection = this.endSection();
return utils$1.makeView(htmlSection.compiled.hydrate.bind(htmlSection.compiled));
}
},
startSection: function( process, commentName ) {
var newSection = new HTMLSection(process);
this.last().add({
comment: commentName || "#section",
callbacks: [newSection.targetCallback]
});
this.last().add({
comment: "can-end-placeholder"
});
// adding a section within a section ...
// the stack has section ...
this.stack.push(newSection);
},
endSection: function(){
this.last().compile();
return this.stack.pop();
},
inverse: function(){
this.last().inverse();
},
compile: function(){
var compiled = this.stack.pop().compile();
// ignore observations here. the render fn
// itself doesn't need to be observable.
return utils$1.makeView( compiled.hydrate.bind(compiled) );
},
push: function(chars){
this.last().push(chars);
},
pop: function(){
return this.last().pop();
},
removeCurrentNode: function() {
this.last().removeCurrentNode();
}
});
var HTMLSection = function(process){
this.data = "targetData";
this.targetData = [];
// A record of what targetData element we are within.
this.targetStack = [];
var self = this;
this.targetCallback = function(scope){
process.call(this,
scope,
self.compiled.hydrate.bind(self.compiled),
self.inverseCompiled && self.inverseCompiled.hydrate.bind(self.inverseCompiled) ) ;
};
};
canAssign_1_3_3_canAssign(HTMLSection.prototype,{
inverse: function(){
this.inverseData = [];
this.data = "inverseData";
},
// Adds a DOM node.
push: function(data){
this.add(data);
this.targetStack.push(data);
},
pop: function(){
return this.targetStack.pop();
},
add: function(data){
if(typeof data === "string"){
data = decodeHTML(data);
}
if(this.targetStack.length) {
last(this.targetStack).children.push(data);
} else {
this[this.data].push(data);
}
},
compile: function(){
this.compiled = canViewTarget_5_0_0_canViewTarget(this.targetData, document$1());
if(this.inverseData) {
this.inverseCompiled = canViewTarget_5_0_0_canViewTarget(this.inverseData, document$1());
delete this.inverseData;
}
this.targetStack = this.targetData = null;
return this.compiled;
},
removeCurrentNode: function() {
var children = this.children();
return children.pop();
},
children: function(){
if(this.targetStack.length) {
return last(this.targetStack).children;
} else {
return this[this.data];
}
},
// Returns if a section is empty
isEmpty: function(){
return !this.targetData.length;
}
});
HTMLSectionBuilder.HTMLSection = HTMLSection;
var html_section = HTMLSectionBuilder;
var canDomData_1_0_3_canDomData = createCommonjsModule(function (module) {
var isEmptyObject = function(obj){
/* jshint -W098 */
for(var prop in obj) {
return false;
}
return true;
};
var data = new WeakMap();
// delete this node's `data`
// returns true if the node was deleted.
var deleteNode = function(node) {
var nodeDeleted = false;
if (data.has(node)) {
nodeDeleted = true;
data.delete(node);
}
return nodeDeleted;
};
var setData = function(node, name, value) {
var store = data.get(node);
if (store === undefined) {
store = {};
data.set(node, store);
}
if (name !== undefined) {
store[name] = value;
}
return store;
};
/*
* Core of domData that does not depend on mutationDocument
* This is separated in order to prevent circular dependencies
*/
var domData = {
_data: data,
get: function(node, key) {
var store = data.get(node);
return key === undefined ? store : store && store[key];
},
set: setData,
clean: function(node, prop) {
var itemData = data.get(node);
if (itemData && itemData[prop]) {
delete itemData[prop];
}
if (isEmptyObject(itemData)) {
deleteNode(node);
}
},
delete: deleteNode
};
if (canNamespace_1_0_0_canNamespace.domData) {
throw new Error("You can't have two versions of can-dom-data, check your dependencies");
} else {
module.exports = canNamespace_1_0_0_canNamespace.domData = domData;
}
});
var slice$1 = [].slice;
// a b c
// a b c d
// [[2,0, d]]
function defaultIdentity(a, b){
return a === b;
}
function makeIdentityFromMapSchema(typeSchema) {
if(typeSchema.identity && typeSchema.identity.length) {
return function identityCheck(a, b) {
var aId = canReflect_1_19_2_canReflect.getIdentity(a, typeSchema),
bId = canReflect_1_19_2_canReflect.getIdentity(b, typeSchema);
return aId === bId;
};
} else {
return defaultIdentity;
}
}
function makeIdentityFromListSchema(listSchema) {
return listSchema.values != null ?
makeIdentityFromMapSchema( canReflect_1_19_2_canReflect.getSchema(listSchema.values) ) :
defaultIdentity;
}
function makeIdentity(oldList, oldListLength) {
var listSchema = canReflect_1_19_2_canReflect.getSchema(oldList),
typeSchema;
if(listSchema != null) {
if(listSchema.values != null) {
typeSchema = canReflect_1_19_2_canReflect.getSchema(listSchema.values);
} else {
return defaultIdentity;
}
}
if(typeSchema == null && oldListLength > 0) {
typeSchema = canReflect_1_19_2_canReflect.getSchema( canReflect_1_19_2_canReflect.getKeyValue(oldList, 0) );
}
if(typeSchema) {
return makeIdentityFromMapSchema(typeSchema);
} else {
return defaultIdentity;
}
}
function reverseDiff(oldDiffStopIndex, newDiffStopIndex, oldList, newList, identity) {
var oldIndex = oldList.length - 1,
newIndex = newList.length - 1;
while( oldIndex > oldDiffStopIndex && newIndex > newDiffStopIndex) {
var oldItem = oldList[oldIndex],
newItem = newList[newIndex];
if( identity( oldItem, newItem, oldIndex ) ) {
oldIndex--;
newIndex--;
continue;
} else {
// use newIndex because it reflects any deletions
return [{
type: "splice",
index: newDiffStopIndex,
deleteCount: (oldIndex-oldDiffStopIndex+1),
insert: slice$1.call(newList, newDiffStopIndex,newIndex+1)
}];
}
}
// if we've reached of either the new or old list
// we simply return
return [{
type: "splice",
index: newDiffStopIndex,
deleteCount: (oldIndex-oldDiffStopIndex+1),
insert: slice$1.call(newList, newDiffStopIndex,newIndex+1)
}];
}
/**
* @module {function} can-diff/list/list
* @parent can-diff
*
* @description Return a difference of two lists.
*
* @signature `diffList( oldList, newList, [identity] )`
*
* Compares two lists and produces a sequence of patches that can be applied to make `oldList` take
* the shape of `newList`.
*
* ```js
* var diffList = require("can-diff/list/list");
*
* console.log(diff([1], [1, 2])); // -> [{type: "splice", index: 1, deleteCount: 0, insert: [2]}]
* console.log(diff([1, 2], [1])); // -> [{type: "splice", index: 1, deleteCount: 1, insert: []}]
*
* // with an optional identity function:
* diffList(
* [{id:1},{id:2}],
* [{id:1},{id:3}],
* (a,b) => a.id === b.id
* ); // -> [{type: "splice", index: 1, deleteCount: 1, insert: [{id:3}]}]
* ```
*
* The patch algorithm is linear with respect to the length of the lists and therefore does not produce a
* [perfect edit distance](https://en.wikipedia.org/wiki/Edit_distance) (which would be at least quadratic).
*
* It is designed to work with most common list change scenarios, when items are inserted or removed
* to a list (as opposed to moved with in the last).
*
* For example, it is able to produce the following patches:
*
* ```js
* diffList(
* ["a","b","c","d"],
* ["a","b","X","Y","c","d"]
* ); // -> [{type: "splice", index: 2, deleteCount: 0, insert: ["X","Y"]}]
* ```
*
* @param {ArrayLike} oldList The source array or list to diff from.
* @param {ArrayLike} newList The array or list to diff to.
* @param {function|can-reflect.getSchema} schemaOrIdentity An optional identity function or a schema with
* an identity property for comparing elements. If a `schemaOrIdentity` is not provided, the schema of
* the `oldList` will be used. If a schema can not be found, items a default identity function will be created
* that checks if the two values are strictly equal `===`.
* @return {Array} An array of [can-symbol/types/Patch] objects representing the differences
*
* Returns the difference between two ArrayLike objects (that have nonnegative
* integer keys and the `length` property) as an array of patch objects.
*
* A patch object returned by this function has the following properties:
* - **type**: the type of patch (`"splice"`).
* - **index**: the index of newList where the patch begins
* - **deleteCount**: the number of items deleted from that index in newList
* - **insert**: an Array of items newly inserted at that index in newList
*
* Patches should be applied in the order they are returned.
*/
var list = function(oldList, newList, schemaOrIdentity){
var oldIndex = 0,
newIndex = 0,
oldLength = canReflect_1_19_2_canReflect.size( oldList ),
newLength = canReflect_1_19_2_canReflect.size( newList ),
patches = [];
var schemaType = typeof schemaOrIdentity,
identity;
if(schemaType === "function") {
identity = schemaOrIdentity;
} else if(schemaOrIdentity != null) {
if(schemaOrIdentity.type === "map") {
identity = makeIdentityFromMapSchema(schemaOrIdentity);
} else {
identity = makeIdentityFromListSchema(schemaOrIdentity);
}
} else {
identity = makeIdentity(oldList, oldLength);
}
while(oldIndex < oldLength && newIndex < newLength) {
var oldItem = oldList[oldIndex],
newItem = newList[newIndex];
if( identity( oldItem, newItem, oldIndex ) ) {
oldIndex++;
newIndex++;
continue;
}
// look for single insert, does the next newList item equal the current oldList.
// 1 2 3
// 1 2 4 3
if( newIndex+1 < newLength && identity( oldItem, newList[newIndex+1], oldIndex ) ) {
patches.push({index: newIndex, deleteCount: 0, insert: [ newList[newIndex] ], type: "splice"});
oldIndex++;
newIndex += 2;
continue;
}
// look for single removal, does the next item in the oldList equal the current newList item.
// 1 2 3
// 1 3
else if( oldIndex+1 < oldLength && identity( oldList[oldIndex+1], newItem, oldIndex+1 ) ) {
patches.push({index: newIndex, deleteCount: 1, insert: [], type: "splice"});
oldIndex += 2;
newIndex++;
continue;
}
// just clean up the rest and exit
// 1 2 3
// 1 2 5 6 7
else {
// iterate backwards to `newIndex`
// "a", "b", "c", "d", "e"
// "a", "x", "y", "z", "e"
// -> {}
patches.push.apply(patches, reverseDiff(oldIndex, newIndex , oldList, newList, identity) );
return patches;
}
}
if( (newIndex === newLength) && (oldIndex === oldLength) ) {
return patches;
}
// a b
// a b c d e
patches.push(
{type: "splice", index: newIndex,
deleteCount: oldLength-oldIndex,
insert: slice$1.call(newList, newIndex) } );
return patches;
};
var global$1 = global_1();
var xmlnsAttrNamespaceURI = "http://www.w3.org/2000/xmlns/";
var xlinkHrefAttrNamespaceURI = "http://www.w3.org/1999/xlink";
var attrsNamespacesURI = {
'xmlns': xmlnsAttrNamespaceURI,
'xlink:href': xlinkHrefAttrNamespaceURI
};
var formElements = {"INPUT": true, "TEXTAREA": true, "SELECT": true, "BUTTON": true},
// Used to convert values to strings.
toString$1 = function(value){
if(value == null) {
return "";
} else {
return ""+value;
}
},
isSVG = function(el){
return el.namespaceURI === "http://www.w3.org/2000/svg";
},
truthy = function() { return true; },
getSpecialTest = function(special){
return (special && special.test) || truthy;
},
propProp = function(prop, obj){
obj = obj || {};
obj.get = function(){
return this[prop];
};
obj.set = function(value){
if(this[prop] !== value) {
this[prop] = value;
}
};
return obj;
},
booleanProp = function(prop){
return {
isBoolean: true,
set: function(value){
if(prop in this) {
this[prop] = value;
} else {
canDomMutate_2_0_9_node.setAttribute.call(this, prop, "");
}
},
remove: function(){
this[prop] = false;
}
};
},
setupMO = function(el, callback){
var attrMO = canDomData_1_0_3_canDomData.get(el, "attrMO");
if(!attrMO) {
var onMutation = function(){
callback.call(el);
};
var MO = mutationObserver();
if(MO) {
var observer = new MO(onMutation);
observer.observe(el, {
childList: true,
subtree: true
});
canDomData_1_0_3_canDomData.set(el, "attrMO", observer);
} else {
canDomData_1_0_3_canDomData.set(el, "attrMO", true);
canDomData_1_0_3_canDomData.set(el, "canBindingCallback", {onMutation: onMutation});
}
}
},
_findOptionToSelect = function (parent, value) {
var child = parent.firstChild;
while (child) {
if (child.nodeName === "OPTION" && value === child.value) {
return child;
}
if (child.nodeName === "OPTGROUP") {
var groupChild = _findOptionToSelect(child, value);
if (groupChild) {
return groupChild;
}
}
child = child.nextSibling;
}
},
setChildOptions = function(el, value){
var option;
if (value != null) {
option = _findOptionToSelect(el, value);
}
if (option) {
option.selected = true;
} else {
el.selectedIndex = -1;
}
},
forEachOption = function (parent, fn) {
var child = parent.firstChild;
while (child) {
if (child.nodeName === "OPTION") {
fn(child);
}
if (child.nodeName === "OPTGROUP") {
forEachOption(child, fn);
}
child = child.nextSibling;
}
},
collectSelectedOptions = function (parent) {
var selectedValues = [];
forEachOption(parent, function (option) {
if (option.selected) {
selectedValues.push(option.value);
}
});
return selectedValues;
},
markSelectedOptions = function (parent, values) {
forEachOption(parent, function (option) {
option.selected = values.indexOf(option.value) !== -1;
});
},
// Create a handler, only once, that will set the child options any time
// the select's value changes.
setChildOptionsOnChange = function(select, aEL){
var handler = canDomData_1_0_3_canDomData.get(select, "attrSetChildOptions");
if(handler) {
return Function.prototype;
}
handler = function(){
setChildOptions(select, select.value);
};
canDomData_1_0_3_canDomData.set(select, "attrSetChildOptions", handler);
aEL.call(select, "change", handler);
return function(rEL){
canDomData_1_0_3_canDomData.clean(select, "attrSetChildOptions");
rEL.call(select, "change", handler);
};
},
// cache of rules already calculated by `attr.getRule`
behaviorRules = new Map(),
// # isPropWritable
// check if a property is writable on an element by finding its property descriptor
// on the element or its prototype chain
isPropWritable = function(el, prop) {
var desc = Object.getOwnPropertyDescriptor(el, prop);
if (desc) {
return desc.writable || desc.set;
} else {
var proto = Object.getPrototypeOf(el);
if (proto) {
return isPropWritable(proto, prop);
}
}
return false;
},
// # cacheRule
// add a rule to the rules Map so it does not need to be calculated more than once
cacheRule = function(el, attrOrPropName, rule) {
var rulesForElementType;
rulesForElementType = behaviorRules.get(el.prototype);
if (!rulesForElementType) {
rulesForElementType = {};
behaviorRules.set(el.constructor, rulesForElementType);
}
rulesForElementType[attrOrPropName] = rule;
return rule;
};
var specialAttributes = {
checked: {
get: function(){
return this.checked;
},
set: function(val){
// - `set( truthy )` => TRUE
// - `set( "" )` => TRUE
// - `set()` => TRUE
// - `set(undefined)` => false.
var notFalse = !!val || val === "" || arguments.length === 0;
this.checked = notFalse;
if(notFalse && this.type === "radio") {
this.defaultChecked = true;
}
},
remove: function(){
this.checked = false;
},
test: function(){
return this.nodeName === "INPUT";
}
},
"class": {
get: function(){
if(isSVG(this)) {
return this.getAttribute("class");
}
return this.className;
},
set: function(val){
val = val || "";
if(isSVG(this)) {
canDomMutate_2_0_9_node.setAttribute.call(this, "class", "" + val);
} else {
this.className = val;
}
}
},
disabled: booleanProp("disabled"),
focused: {
get: function(){
return this === document.activeElement;
},
set: function(val){
var cur = attr.get(this, "focused");
var docEl = this.ownerDocument.documentElement;
var element = this;
function focusTask() {
if (val) {
element.focus();
} else {
element.blur();
}
}
if (cur !== val) {
if (!docEl.contains(element)) {
var connectionDisposal = canDomMutate_2_0_9_canDomMutate.onNodeConnected(element, function () {
connectionDisposal();
focusTask();
});
} else {
// THIS MIGHT NEED TO BE PUT IN THE MUTATE QUEUE
canQueues_1_3_2_canQueues.enqueueByQueue({
mutate: [focusTask]
}, null, []);
}
}
return true;
},
addEventListener: function(eventName, handler, aEL){
aEL.call(this, "focus", handler);
aEL.call(this, "blur", handler);
return function(rEL){
rEL.call(this, "focus", handler);
rEL.call(this, "blur", handler);
};
},
test: function(){
return this.nodeName === "INPUT";
}
},
"for": propProp("htmlFor"),
innertext: propProp("innerText"),
innerhtml: propProp("innerHTML"),
innerHTML: propProp("innerHTML", {
addEventListener: function(eventName, handler, aEL){
var handlers = [];
var el = this;
["change", "blur"].forEach(function(eventName){
var localHandler = function(){
handler.apply(this, arguments);
};
canDomEvents_1_3_13_canDomEvents.addEventListener(el, eventName, localHandler);
handlers.push([eventName, localHandler]);
});
return function(rEL){
handlers.forEach( function(info){
rEL.call(el, info[0], info[1]);
});
};
}
}),
required: booleanProp("required"),
readonly: booleanProp("readOnly"),
selected: {
get: function(){
return this.selected;
},
set: function(val){
val = !!val;
canDomData_1_0_3_canDomData.set(this, "lastSetValue", val);
this.selected = val;
},
addEventListener: function(eventName, handler, aEL){
var option = this;
var select = this.parentNode;
var lastVal = option.selected;
var localHandler = function(changeEvent){
var curVal = option.selected;
lastVal = canDomData_1_0_3_canDomData.get(option, "lastSetValue") || lastVal;
if(curVal !== lastVal) {
lastVal = curVal;
canDomEvents_1_3_13_canDomEvents.dispatch(option, eventName);
}
};
var removeChangeHandler = setChildOptionsOnChange(select, aEL);
canDomEvents_1_3_13_canDomEvents.addEventListener(select, "change", localHandler);
aEL.call(option, eventName, handler);
return function(rEL){
removeChangeHandler(rEL);
canDomEvents_1_3_13_canDomEvents.removeEventListener(select, "change", localHandler);
rEL.call(option, eventName, handler);
};
},
test: function(){
return this.nodeName === "OPTION" && this.parentNode &&
this.parentNode.nodeName === "SELECT";
}
},
style: {
set: (function () {
var el = global$1.document && document$1().createElement("div");
if ( el && el.style && ("cssText" in el.style) ) {
return function (val) {
this.style.cssText = (val || "");
};
} else {
return function (val) {
canDomMutate_2_0_9_node.setAttribute.call(this, "style", val);
};
}
})()
},
textcontent: propProp("textContent"),
value: {
get: function(){
var value = this.value;
if(this.nodeName === "SELECT") {
if(("selectedIndex" in this) && this.selectedIndex === -1) {
value = undefined;
}
}
return value;
},
set: function(value){
var providedValue = value;
var nodeName = this.nodeName.toLowerCase();
if(nodeName === "input" || nodeName === "textarea") {
// Do some input types support non string values?
value = toString$1(value);
}
if(this.value !== value || nodeName === "option") {
this.value = value;
}
if (nodeName === "input" || nodeName === "textarea") {
this.defaultValue = value;
}
if(nodeName === "select") {
canDomData_1_0_3_canDomData.set(this, "attrValueLastVal", value);
//If it's null then special case
setChildOptions(this, value === null ? value : this.value);
// If not in the document reset the value when inserted.
var docEl = this.ownerDocument.documentElement;
if(!docEl.contains(this)) {
var select = this;
var connectionDisposal = canDomMutate_2_0_9_canDomMutate.onNodeConnected(select, function () {
connectionDisposal();
setChildOptions(select, value === null ? value : select.value);
});
}
// MO handler is only set up **ONCE**
setupMO(this, function(){
var value = canDomData_1_0_3_canDomData.get(this, "attrValueLastVal");
attr.set(this, "value", value);
canDomEvents_1_3_13_canDomEvents.dispatch(this, "change");
});
}
// Warnings area
//!steal-remove-start
if(process.env.NODE_ENV !== "production") {
var settingADateInputToADate = nodeName === "input" && this.type === "date" && (providedValue instanceof Date);
if(settingADateInputToADate) {
dev.warn("Binding a Date to the \"value\" property on an will not work as expected. Use valueAsDate:bind instead. See https://canjs.com/doc/guides/forms.html#Dateinput for more information.");
}
}
//!steal-remove-end
},
test: function(){
return formElements[this.nodeName];
}
},
values: {
get: function(){
return collectSelectedOptions(this);
},
set: function(values){
values = values || [];
// set new DOM state
markSelectedOptions(this, values);
// store new DOM state
canDomData_1_0_3_canDomData.set(this, "stickyValues", attr.get(this,"values") );
// MO handler is only set up **ONCE**
// TODO: should this be moved into addEventListener?
setupMO(this, function(){
// Get the previous sticky state
var previousValues = canDomData_1_0_3_canDomData.get(this,
"stickyValues");
// Set DOM to previous sticky state
attr.set(this, "values", previousValues);
// Get the new result after trying to maintain the sticky state
var currentValues = canDomData_1_0_3_canDomData.get(this,
"stickyValues");
// If there are changes, trigger a `values` event.
var changes = list(previousValues.slice().sort(),
currentValues.slice().sort());
if (changes.length) {
canDomEvents_1_3_13_canDomEvents.dispatch(this, "values");
}
});
},
addEventListener: function(eventName, handler, aEL){
var localHandler = function(){
canDomEvents_1_3_13_canDomEvents.dispatch(this, "values");
};
canDomEvents_1_3_13_canDomEvents.addEventListener(this, "change", localHandler);
aEL.call(this, eventName, handler);
return function(rEL){
canDomEvents_1_3_13_canDomEvents.removeEventListener(this, "change", localHandler);
rEL.call(this, eventName, handler);
};
}
}
};
var attr = {
// cached rules (stored on `attr` for testing purposes)
rules: behaviorRules,
// special attribute behaviors (stored on `attr` for testing purposes)
specialAttributes: specialAttributes,
// # attr.getRule
//
// get the behavior rule for an attribute or property on an element
//
// Rule precendence:
// 1. "special" behaviors - use the special behavior getter/setter
// 2. writable properties - read and write as a property
// 3. all others - read and write as an attribute
//
// Once rule is determined it will be cached for all elements of the same type
// so that it does not need to be calculated again
getRule: function(el, attrOrPropName) {
var special = specialAttributes[attrOrPropName];
// always use "special" if available
// these are not cached since they would have to be cached separately
// for each element type and it is faster to just look up in the
// specialAttributes object
if (special) {
return special;
}
// next use rules cached in a previous call to getRule
var rulesForElementType = behaviorRules.get(el.constructor);
var cached = rulesForElementType && rulesForElementType[attrOrPropName];
if (cached) {
return cached;
}
// if the element doesn't have a property of this name, it must be an attribute
if (!(attrOrPropName in el)) {
return this.attribute(attrOrPropName);
}
// if there is a property, check if it is writable
var newRule = isPropWritable(el, attrOrPropName) ?
this.property(attrOrPropName) :
this.attribute(attrOrPropName);
// cache the new rule and return it
return cacheRule(el, attrOrPropName, newRule);
},
attribute: function(attrName) {
return {
get: function() {
return this.getAttribute(attrName);
},
set: function(val) {
if (attrsNamespacesURI[attrName]) {
canDomMutate_2_0_9_node.setAttributeNS.call(this, attrsNamespacesURI[attrName], attrName, val);
} else {
canDomMutate_2_0_9_node.setAttribute.call(this, attrName, val);
}
}
};
},
property: function(propName) {
return {
get: function() {
return this[propName];
},
set: function(val) {
this[propName] = val;
}
};
},
findSpecialListener: function(attributeName) {
return specialAttributes[attributeName] && specialAttributes[attributeName].addEventListener;
},
setAttrOrProp: function(el, attrName, val){
return this.set(el, attrName, val);
},
// ## attr.set
// Set the value an attribute on an element.
set: function (el, attrName, val) {
var rule = this.getRule(el, attrName);
var setter = rule && rule.set;
if (setter) {
return setter.call(el, val);
}
},
// ## attr.get
// Gets the value of an attribute or property.
// First checks if the property is an `specialAttributes` and if so calls the special getter.
// Then checks if the attribute or property is a property on the element.
// Otherwise uses `getAttribute` to retrieve the value.
get: function (el, attrName) {
var rule = this.getRule(el, attrName);
var getter = rule && rule.get;
if (getter) {
return rule.test ?
rule.test.call(el) && getter.call(el) :
getter.call(el);
}
},
// ## attr.remove
// Removes an attribute from an element. First checks specialAttributes to see if the attribute is special and has a setter. If so calls the setter with `undefined`. Otherwise `removeAttribute` is used.
// If the attribute previously had a value and the browser doesn't support MutationObservers we then trigger an "attributes" event.
remove: function (el, attrName) {
attrName = attrName.toLowerCase();
var special = specialAttributes[attrName];
var setter = special && special.set;
var remover = special && special.remove;
var test = getSpecialTest(special);
if(typeof remover === "function" && test.call(el)) {
remover.call(el);
} else if(typeof setter === "function" && test.call(el)) {
setter.call(el, undefined);
} else {
canDomMutate_2_0_9_node.removeAttribute.call(el, attrName);
}
}
};
var canAttributeObservable_2_0_2_behaviors = attr;
var setElementSymbol$2 = canSymbol_1_7_0_canSymbol.for("can.setElement");
var elementSymbol = canSymbol_1_7_0_canSymbol.for("can.element");
function ListenUntilRemovedAndInitialize(
observable,
handler,
placeholder,
queueName,
handlerName
) {
this.observable = observable;
this.handler = handler;
this.placeholder = placeholder;
this.queueName = queueName;
this.handler[elementSymbol] = placeholder;
if( observable[setElementSymbol$2] ) {
observable[setElementSymbol$2](placeholder);
} else {
console.warn("no can.setElement symbol on observable", observable);
}
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
// register that the handler changes the parent element
canReflect_1_19_2_canReflect.assignSymbols(handler, {
"can.getChangesDependencyRecord": function() {
var s = new Set();
s.add(placeholder);
return {
valueDependencies: s
};
}
});
Object.defineProperty(handler, "name", {
value: handlerName,
});
}
//!steal-remove-end
this.setup();
}
ListenUntilRemovedAndInitialize.prototype.setup = function() {
// reinsertion case, not applicable during initial setup
if(this.setupNodeReinserted) {
// do not set up again if disconnected
if(!canDomMutate_2_0_9_IsConnected.isConnected(this.placeholder)) {
return;
}
this.setupNodeReinserted();
}
this.teardownNodeRemoved = canDomMutate_2_0_9_canDomMutate.onNodeRemoved(this.placeholder,
this.teardown.bind(this));
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
canReflectDependencies_1_1_2_canReflectDependencies.addMutatedBy(this.placeholder, this.observable);
}
//!steal-remove-end
canReflect_1_19_2_canReflect.onValue(this.observable, this.handler, this.queueName);
this.handler( canReflect_1_19_2_canReflect.getValue(this.observable) );
};
ListenUntilRemovedAndInitialize.prototype.teardown = function(){
// do not teardown if still connected.
if(canDomMutate_2_0_9_IsConnected.isConnected(this.placeholder)) {
return;
}
this.teardownNodeRemoved();
this.setupNodeReinserted = canDomMutate_2_0_9_canDomMutate.onNodeInserted(this.placeholder,
this.setup.bind(this));
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
canReflectDependencies_1_1_2_canReflectDependencies.deleteMutatedBy(this.placeholder, this.observable);
}
//!steal-remove-end
canReflect_1_19_2_canReflect.offValue(this.observable, this.handler, this.queueName);
};
var helpers$2 = {
range: {
create: function(el, rangeName){
var start, end, next;
if(el.nodeType === Node.COMMENT_NODE) {
start = el;
next = el.nextSibling;
if(next && next.nodeType === Node.COMMENT_NODE && next.nodeValue === "can-end-placeholder") {
end = next;
end.nodeValue = "/" + (start.nodeValue = rangeName);
} else {
dev.warn("can-view-live: creating an end comment for ", rangeName, el);
}
} else {
dev.warn("can-view-live: forcing a comment range for ", rangeName, el);
start = el.ownerDocument.createComment( rangeName );
el.parentNode.replaceChild( start, el );
}
if(!end) {
end = el.ownerDocument.createComment( "/" + rangeName );
start.parentNode.insertBefore(end, start.nextSibling);
}
return {start: start, end: end};
},
remove: function ( range ) {
// TODO: Ideally this would be able to remove from the end, but
// dispatch in the right order.
// For now, we might want to remove nodes in the right order.
var parentNode = range.start.parentNode,
cur = range.end.previousSibling,
remove;
while(cur && cur !== range.start) {
remove = cur;
cur = cur.previousSibling;
canDomMutate_2_0_9_node.removeChild.call(parentNode, remove );
}
canDomMutate_2_0_9_canDomMutate.flushRecords();
},
update: function ( range, frag ) {
var parentNode = range.start.parentNode;
if(parentNode) {
canDomMutate_2_0_9_node.insertBefore.call(parentNode, frag, range.end);
// this makes it so `connected` events will be called immediately
canDomMutate_2_0_9_canDomMutate.flushRecords();
}
}
},
ListenUntilRemovedAndInitialize: ListenUntilRemovedAndInitialize,
getAttributeParts: function(newVal) {
var attrs = {},
attr;
canViewParser_4_1_3_canViewParser.parseAttrs(newVal, {
attrStart: function(name) {
attrs[name] = "";
attr = name;
},
attrValue: function(value) {
attrs[attr] += value;
},
attrEnd: function() {}
});
return attrs;
},
// #### addTextNodeIfNoChildren
// Append an empty text node to a parent with no children;
// do nothing if the parent already has children.
addTextNodeIfNoChildren: function(frag) {
if (!frag.firstChild) {
frag.appendChild(frag.ownerDocument.createTextNode(""));
}
},
// #### makeString
// any -> string converter (including nullish)
makeString: function(txt) {
return txt == null ? "" : "" + txt;
}
};
/**
* @function can-view-live.attr attr
* @parent can-view-live
*
* @signature `live.attr(el, attributeName, observable)`
*
* Keep an attribute live to a [can-reflect]-ed observable.
*
* ```js
* var div = document.createElement('div');
* var value = new SimpleObservable("foo bar");
* live.attr(div,"class", value);
* ```
*
* @param {HTMLElement} el The element whos attribute will be kept live.
* @param {String} attributeName The attribute name.
* @param {Object} observable An observable value.
*
* @body
*
* ## How it works
*
* This listens for the changes in the observable and uses those changes to
* set the specified attribute.
*/
var attr_1 = function(el, attributeName, compute) {
var handlerName = "";
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
// register that the handler changes the parent element
handlerName = "live.attr update::"+canReflect_1_19_2_canReflect.getName(compute);
}
//!steal-remove-end
new helpers$2.ListenUntilRemovedAndInitialize(compute,
function liveUpdateAttr(newVal) {
canAttributeObservable_2_0_2_behaviors.set(el,attributeName, newVal);
},
el,
"dom",
handlerName
);
};
// This provides live binding for stache attributes.
var attrs = function(el, compute, scope, options) {
var handlerName = "";
if (!canReflect_1_19_2_canReflect.isObservableLike(compute)) {
// Non-live case (`compute` was not a compute):
// set all attributes on the element and don't
// worry about setting up live binding since there
// is not compute to bind on.
var attrs = helpers$2.getAttributeParts(compute);
for (var name in attrs) {
canDomMutate_2_0_9_node.setAttribute.call(el, name, attrs[name]);
}
return;
}
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
handlerName = "live.attrs update::"+canReflect_1_19_2_canReflect.getName(compute);
}
//!steal-remove-end
// last set of attributes
var oldAttrs = {};
new helpers$2.ListenUntilRemovedAndInitialize(compute,
function canViewLive_updateAttributes(newVal) {
var newAttrs = helpers$2.getAttributeParts(newVal),
name;
for (name in newAttrs) {
var newValue = newAttrs[name],
// `oldAttrs` was set on the last run of setAttrs in this context
// (for this element and compute)
oldValue = oldAttrs[name];
// Only fire a callback
// if the value of the attribute has changed
if (newValue !== oldValue) {
// set on DOM attributes (dispatches an "attributes" event as well)
canDomMutate_2_0_9_node.setAttribute.call(el, name, newValue);
// get registered callback for attribute name and fire
var callback = canViewCallbacks_5_0_0_canViewCallbacks.attr(name);
if (callback) {
callback(el, {
attributeName: name,
scope: scope,
options: options
});
}
}
// remove key found in new attrs from old attrs
delete oldAttrs[name];
}
// any attrs left at this point are not set on the element now,
// so remove them.
for (name in oldAttrs) {
canDomMutate_2_0_9_node.removeAttribute.call(el, name);
}
oldAttrs = newAttrs;
},
el,
"dom",
handlerName);
};
var viewInsertSymbol = canSymbol_1_7_0_canSymbol.for("can.viewInsert");
function makeCommentFragment(comment) {
var doc = document$1();
return canFragment_1_3_1_canFragment([
doc.createComment(comment),
doc.createComment("can-end-placeholder")
]);
}
/**
* @function can-view-live.html html
* @parent can-view-live
* @release 2.0.4
*
* Live binds a compute's value to a collection of elements.
*
* @signature `live.html(el, compute, [parentNode])`
*
* `live.html` is used to setup incremental live-binding on a block of html.
*
* ```js
* // a compute that changes its list
* var greeting = compute(function(){
* return "Welcome "+me.attr("name")+""
* });
*
* var placeholder = document.createTextNode(" ");
* $("#greeting").append(placeholder);
*
* live.html(placeholder, greeting);
* ```
*
* @param {HTMLElement} el An html element to replace with the live-section.
*
* @param {can.compute} compute A [can.compute] whose value is HTML.
*
* @param {HTMLElement} [parentNode] An overwritable parentNode if `el`'s parent is
* a documentFragment.
*
*
*/
var html = function(el, compute, viewInsertSymbolOptions) {
var observableName = "";
var updateRange = helpers$2.range.update;
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
// register that the handler changes the parent element
updateRange = helpers$2.range.update.bind(null);
observableName = canReflect_1_19_2_canReflect.getName(compute);
Object.defineProperty(updateRange, "name", {
value: "live.html update::"+observableName,
});
}
//!steal-remove-end
if (el.nodeType !== Node.COMMENT_NODE) {
var commentFrag = makeCommentFragment(observableName);
var startCommentNode = commentFrag.firstChild;
el.parentNode.replaceChild(commentFrag, el);
el = startCommentNode;
}
// replace element with a comment node
var range = helpers$2.range.create(el, observableName);
var useQueue = false;
new helpers$2.ListenUntilRemovedAndInitialize(compute,
function canViewLive_updateHTML(val) {
// If val has the can.viewInsert symbol, call it and get something usable for val back
if (val && typeof val[viewInsertSymbol] === "function") {
val = val[viewInsertSymbol](viewInsertSymbolOptions);
}
var isFunction = typeof val === "function";
// translate val into a document fragment if it's DOM-like
var frag = isFunction ?
makeCommentFragment(observableName) :
canFragment_1_3_1_canFragment(val);
if(isFunction) {
val(frag.firstChild);
}
if(useQueue === true) {
helpers$2.range.remove(range);
updateRange(range, frag);
} else {
helpers$2.range.update(range, frag);
useQueue = true;
}
},
range.start,
"dom",
"live.html replace::" + observableName);
};
var onValueSymbol$3 = canSymbol_1_7_0_canSymbol.for("can.onValue");
var offValueSymbol$1 = canSymbol_1_7_0_canSymbol.for("can.offValue");
var onPatchesSymbol$1 = canSymbol_1_7_0_canSymbol.for("can.onPatches");
var offPatchesSymbol = canSymbol_1_7_0_canSymbol.for("can.offPatches");
// Patcher takes a observable that might wrap a list type.
// When the observable changes, it will diff, and emit patches,
// and if the list emits patches, it will emit those too.
// It is expected that only `domUI` handlers are registered.
/*
var observable = new SimpleObservable( new DefineList([ "a", "b", "c" ]) )
var patcher = new Patcher(observable)
canReflect.onPatches( patcher,function(patches){
console.log(patches) // a patch removing c, then a
})
var newList = new DefineList(["a","b"]);
observable.set(newList);
newList.unshift("X");
[
{type: "splice", index: 2, deleteCount: 1}
]
var patches2 = [
{type: "splice", index: 0, deleteCount: 0, inserted: ["X"]}
]
*/
var Patcher = function(observableOrList, priority) {
// stores listeners for this patcher
this.handlers = new canKeyTree_1_2_2_canKeyTree([Object, Array], {
// call setup when the first handler is bound
onFirst: this.setup.bind(this),
// call teardown when the last handler is removed
onEmpty: this.teardown.bind(this)
});
// save this value observable or patch emitter (list)
this.observableOrList = observableOrList;
// if we were passed an observable value that we need to read its array for changes
this.isObservableValue = canReflect_1_19_2_canReflect.isValueLike(this.observableOrList) || canReflect_1_19_2_canReflect.isObservableLike(this.observableOrList);
if(this.isObservableValue) {
this.priority = canReflect_1_19_2_canReflect.getPriority(observableOrList);
} else {
this.priority = priority || 0;
}
this.onList = this.onList.bind(this);
this.onPatchesNotify = this.onPatchesNotify.bind(this);
// needs to be unique so the derive queue doesn't only add one.
this.onPatchesDerive = this.onPatchesDerive.bind(this);
// stores patches that have happened between notification and
// when we queue the `onPatches` handlers in the `domUI` queue
this.patches = [];
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
Object.defineProperty(this.onList, "name", {
value: "live.list new list::"+canReflect_1_19_2_canReflect.getName(observableOrList),
});
Object.defineProperty(this.onPatchesNotify, "name", {
value: "live.list notify::"+canReflect_1_19_2_canReflect.getName(observableOrList),
});
Object.defineProperty(this.onPatchesDerive, "name", {
value: "live.list derive::"+canReflect_1_19_2_canReflect.getName(observableOrList),
});
}
//!steal-remove-end
};
Patcher.prototype = {
constructor: Patcher,
setup: function() {
if (this.observableOrList[onValueSymbol$3]) {
// if we have an observable value, listen to when it changes to get a
// new list.
canReflect_1_19_2_canReflect.onValue(this.observableOrList, this.onList, "notify");
// listen on the current value (which shoudl be a list) if there is one
this.setupList(canReflect_1_19_2_canReflect.getValue(this.observableOrList));
} else {
this.setupList(this.observableOrList);
}
},
teardown: function() {
if (this.observableOrList[offValueSymbol$1]) {
canReflect_1_19_2_canReflect.offValue(this.observableOrList, this.onList, "notify");
}
if (this.currentList && this.currentList[offPatchesSymbol]) {
this.currentList[offPatchesSymbol](this.onPatchesNotify, "notify");
}
},
// listen to the list for patches
setupList: function(list$$1) {
this.currentList = list$$1;
if (list$$1 && list$$1[onPatchesSymbol$1]) {
// If observable, set up bindings on list changes
list$$1[onPatchesSymbol$1](this.onPatchesNotify, "notify");
}
},
// when the list changes, teardown the old list bindings
// and setup the new list
onList: function onList(newList) {
var current = this.currentList || [];
newList = newList || [];
if (current[offPatchesSymbol]) {
current[offPatchesSymbol](this.onPatchesNotify, "notify");
}
var patches = list(current, newList);
this.currentList = newList;
this.onPatchesNotify(patches);
if (newList[onPatchesSymbol$1]) {
// If observable, set up bindings on list changes
newList[onPatchesSymbol$1](this.onPatchesNotify, "notify");
}
},
// This is when we get notified of patches on the underlying list.
// Save the patches and queue up a `derive` task that will
// call `domUI` updates.
onPatchesNotify: function onPatchesNotify(patches) {
// we are going to collect all patches
this.patches.push.apply(this.patches, patches);
// TODO: share priority
canQueues_1_3_2_canQueues.deriveQueue.enqueue(this.onPatchesDerive, this, [], {
priority: this.priority
});
},
// Let handlers (which should only be registered in `domUI`) know about patches
// that they can apply.
onPatchesDerive: function onPatchesDerive() {
var patches = this.patches;
this.patches = [];
canQueues_1_3_2_canQueues.enqueueByQueue(this.handlers.getNode([]), this.currentList, [patches, this.currentList], null,["Apply patches", patches]);
}
};
canReflect_1_19_2_canReflect.assignSymbols(Patcher.prototype, {
"can.onPatches": function(handler, queue) {
this.handlers.add([queue || "mutate", handler]);
},
"can.offPatches": function(handler, queue) {
this.handlers.delete([queue || "mutate", handler]);
}
});
var patcher = Patcher;
var patchSort = function(patches) {
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
var deletes =[],
inserts = [],
moves = [];
patches.forEach(function(patch){
if (patch.type === "move") {
moves.push(patch);
} else {
if (patch.deleteCount) {
deletes.push(patch);
}
if (patch.insert && patch.insert.length) {
inserts.push(inserts);
}
}
});
if(deletes.length + inserts.length > 2) {
console.error("unable to group patches",patches);
throw new Error("unable to group patches");
}
if(moves.length &&(deletes.length || inserts.length)) {
console.error("unable to sort a move with a delete or insert");
throw new Error("unable to sort a move with a delete or insert");
}
}
//!steal-remove-end
var splitPatches = [];
patches.forEach(function(patch){
if (patch.type === "move") {
splitPatches.push( {patch: patch, kind: "move"} );
} else {
if (patch.deleteCount) {
splitPatches.push({
type: "splice",
index: patch.index,
deleteCount: patch.deleteCount,
insert: [],
});
}
if (patch.insert && patch.insert.length) {
splitPatches.push({
type: "splice",
index: patch.index,
deleteCount: 0,
insert: patch.insert
});
}
}
});
if(patches.length !== 2) {
return patches;
}
var first = splitPatches[0],
second = splitPatches[1];
// if insert before a delete
if(first.insert && first.insert.length && second.deleteCount) {
// lets swap the order.
var insert = first,
remove = second;
if(insert.index < remove.index) {
remove.index = remove.index - insert.insert.length;
} else if(insert.index > remove.index) {
insert.index = insert.index - remove.deleteCount;
} else {
throw "indexes the same!"
}
return [remove, insert];
}
return patches;
};
function SetObservable(initialValue, setter) {
this.setter = setter;
canSimpleObservable_2_5_0_canSimpleObservable.call(this, initialValue);
}
SetObservable.prototype = Object.create(canSimpleObservable_2_5_0_canSimpleObservable.prototype);
SetObservable.prototype.constructor = SetObservable;
SetObservable.prototype.set = function(newVal) {
this.setter(newVal);
};
canReflect_1_19_2_canReflect.assignSymbols(SetObservable.prototype, {
"can.setValue": SetObservable.prototype.set
});
var setObservable = SetObservable;
var splice = [].splice;
// #### renderAndAddRangeNode
// a helper function that renders something and adds its nodeLists to newNodeLists
// in the right way for stache.
var renderAndAddRangeNode = function(render, context, args, document) {
// call the renderer, passing in the new nodeList as the last argument
var itemHTML = render.apply(context, args.concat()),
// and put the output into a document fragment
itemFrag = canFragment_1_3_1_canFragment(itemHTML);
var rangeNode = document.createTextNode("");
itemFrag.appendChild(rangeNode);
return itemFrag;
};
function getFrag(first, last){
var frag = first.ownerDocument.createDocumentFragment();
var current,
lastInserted;
// hopefully this doesn't dispatch removed?
while(last !== first) {
current = last;
last = current.previousSibling;
frag.insertBefore(current, lastInserted);
lastInserted = current;
}
frag.insertBefore(last, lastInserted);
return frag;
}
var onPatchesSymbol$2 = canSymbol_1_7_0_canSymbol.for("can.onPatches");
var offPatchesSymbol$1 = canSymbol_1_7_0_canSymbol.for("can.offPatches");
function ListDOMPatcher(el, compute, render, context, falseyRender) {
this.patcher = new patcher(compute);
var observableName = canReflect_1_19_2_canReflect.getName(compute);
// argument cleanup
// function callback binding
// argument saving -----
this.value = compute;
this.render = render;
this.context = context;
this.falseyRender = falseyRender;
this.range = helpers$2.range.create(el, observableName);
// A mapping of indices to observables holding that index.
this.indexMap = [];
// A mapping of each item's end node
this.itemEndNode = [];
// A mapping of each item to its pending patches.
this.domQueue = [];
this.isValueLike = canReflect_1_19_2_canReflect.isValueLike(this.value);
this.isObservableLike = canReflect_1_19_2_canReflect.isObservableLike(this.value);
// Setup binding and teardown to add and remove events
this.onPatches = this.onPatches.bind(this);
this.processDomQueue = this.processDomQueue.bind(this);
this.teardownValueBinding = this.teardownValueBinding.bind(this);
this.meta = {reasonLog: "live.html add::"+observableName, element: this.range.start};
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
Object.defineProperty(this.onPatches, "name", {
value: "live.list update::"+canReflect_1_19_2_canReflect.getName(compute),
});
}
//!steal-remove-end
this.setupValueBinding();
}
var onPatchesSymbol$2 = canSymbol_1_7_0_canSymbol.for("can.onPatches");
var offPatchesSymbol$1 = canSymbol_1_7_0_canSymbol.for("can.offPatches");
ListDOMPatcher.prototype = {
setupValueBinding: function() {
// Teardown when the placeholder element is removed.
this.teardownNodeRemoved = canDomMutate_2_0_9_canDomMutate.onNodeRemoved(this.range.start, this.teardownValueBinding);
// Listen to when the patcher produces patches.
this.patcher[onPatchesSymbol$2](this.onPatches, "notify");
// Initialize with the patcher's value
if (this.patcher.currentList && this.patcher.currentList.length) {
this.add(this.patcher.currentList, 0);
} else {
this.addFalseyIfEmpty();
}
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
canReflectDependencies_1_1_2_canReflectDependencies.addMutatedBy(this.range.start, this.patcher.observableOrList);
}
//!steal-remove-end
},
teardownValueBinding: function() {
this.exit = true;
// Stop listening for teardowns
this.teardownNodeRemoved();
this.patcher[offPatchesSymbol$1](this.onPatches, "notify");
// Todo: I bet this is no longer necessary?
//this.remove({
// length: this.patcher.currentList ? this.patcher.currentList.length : 0
//}, 0, true);
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
canReflectDependencies_1_1_2_canReflectDependencies.deleteMutatedBy(this.range.start, this.patcher.observableOrList);
}
//!steal-remove-end
},
onPatches: function ListDOMPatcher_onPatches(patches) {
if (this.exit) {
return;
}
var sortedPatches = [];
patches.forEach(function(patch) {
sortedPatches.push.apply(sortedPatches, patchSort([patch]));
});
// adjust so things can happen
for (var i = 0, patchLen = sortedPatches.length; i < patchLen; i++) {
var patch = sortedPatches[i];
if (patch.type === "move") {
this.addToDomQueue(
this.move,
[patch.toIndex, patch.fromIndex]
);
} else if (patch.type === "splice") {
if (patch.deleteCount) {
// Remove any items scheduled for deletion from the patch.
this.addToDomQueue(this.remove, [{
length: patch.deleteCount
}, patch.index]);
}
if (patch.insert && patch.insert.length) {
// Insert any new items at the index
this.addToDomQueue(this.add, [patch.insert, patch.index]);
}
} else {
// all other patch types are ignored
continue;
}
}
},
addToDomQueue: function(fn, args) {
this.domQueue.push({
fn: fn,
args: args
});
canQueues_1_3_2_canQueues.domQueue.enqueue(this.processDomQueue, this, [this.domQueue], this.meta);
},
processDomQueue: function() {
this.domQueue.forEach(function(queueItem) {
var fn = queueItem.fn;
var args = queueItem.args;
fn.apply(this, args);
}.bind(this));
this.domQueue = [];
},
add: function(items, index) {
//if (!afterPreviousEvents) {
// return;
//}
// Collect new html and mappings
var ownerDocument = this.range.start.ownerDocument,
frag = ownerDocument.createDocumentFragment(),
newEndNodes = [],
newIndicies = [],
render = this.render,
context = this.context;
// For each new item,
items.forEach( function(item, key) {
var itemIndex = new canSimpleObservable_2_5_0_canSimpleObservable(key + index),
itemCompute = new setObservable(item, function(newVal) {
canReflect_1_19_2_canReflect.setKeyValue(this.patcher.currentList, itemIndex.get(), newVal );
}.bind(this)),
itemFrag = renderAndAddRangeNode(render, context, [itemCompute, itemIndex], ownerDocument);
newEndNodes.push(itemFrag.lastChild);
// Hookup the fragment (which sets up child live-bindings) and
// add it to the collection of all added elements.
frag.appendChild(itemFrag);
// track indicies;
newIndicies.push(itemIndex);
}, this);
// The position of elements is always after the initial text placeholder node
// TODO: this should probably happen earlier.
// remove falsey if there's something there
if (!this.indexMap.length) {
// remove all leftover things
helpers$2.range.remove(this.range);
this.itemEndNode = [];
}
// figure out where we are placing things.
var placeholder,
endNodesLength = this.itemEndNode.length;
if(index === endNodesLength ) {
placeholder = this.range.end;
} else if(index === 0) {
placeholder = this.range.start.nextSibling;
} else if(index < endNodesLength) {
placeholder = this.itemEndNode[index - 1].nextSibling;
} else {
throw new Error("Unable to place item");
}
canDomMutate_2_0_9_node.insertBefore.call(placeholder.parentNode,frag,placeholder);
splice.apply(this.itemEndNode, [
index,
0
].concat(newEndNodes));
// update indices after insert point
splice.apply(this.indexMap, [
index,
0
].concat(newIndicies));
for (var i = index + newIndicies.length, len = this.indexMap.length; i < len; i++) {
this.indexMap[i].set(i);
}
},
remove: function(items, index) {
//if (!afterPreviousEvents) {
// return;
//}
// If this is because an element was removed, we should
// check to make sure the live elements are still in the page.
// If we did this during a teardown, it would cause an infinite loop.
//if (!duringTeardown && this.data.teardownCheck(this.placeholder.parentNode)) {
// return;
//}
if (index < 0) {
index = this.indexMap.length + index;
}
var removeStart;
var removeEnd;
var removeCount = items.length;
var endIndex = index + removeCount - 1;
if(index === 0) {
removeStart = this.range.start;
} else {
removeStart = this.itemEndNode[index - 1];
}
removeEnd = this.itemEndNode[endIndex].nextSibling;
this.itemEndNode.splice(index, items.length);
if (removeStart && removeEnd) {
helpers$2.range.remove({start: removeStart, end: removeEnd});
}
var indexMap = this.indexMap;
// update indices after remove point
indexMap.splice(index, items.length);
for (var i = index, len = indexMap.length; i < len; i++) {
indexMap[i].set(i);
}
// don't remove elements during teardown. Something else will probably be doing that.
if (!this.exit) {
// adds the falsey section if the list is empty
this.addFalseyIfEmpty();
} else {
// This probably isn't needed anymore as element removal will be propagated
// nodeLists.unregister(this.masterNodeList);
}
},
// #### addFalseyIfEmpty
// Add the results of redering the "falsey" or inverse case render to the
// master nodeList and the DOM if the live list is empty
addFalseyIfEmpty: function() {
if (this.falseyRender && this.indexMap.length === 0) {
// If there are no items ... we should render the falsey template
var falseyFrag = renderAndAddRangeNode(this.falseyRender, this.currentList, [this.currentList], this.range.start.ownerDocument);
helpers$2.range.update(this.range, falseyFrag);
}
},
move: function move(newIndex, currentIndex) {
//if (!afterPreviousEvents) {
// return;
//}
// The position of elements is always after the initial text
// placeholder node
var currentFirstNode,
currentEndNode = this.itemEndNode[currentIndex];
if( currentIndex > 0 ) {
currentFirstNode = this.itemEndNode[currentIndex - 1].nextSibling;
} else {
currentFirstNode = this.range.start.nextSibling;
}
var newIndexFirstNode;
if (currentIndex < newIndex) {
// we need to advance one spot, because removing at
// current index will shift everything left
newIndexFirstNode = this.itemEndNode[newIndex].nextSibling;
} else {
if( newIndex > 0 ) {
newIndexFirstNode = this.itemEndNode[newIndex - 1].nextSibling;
} else {
newIndexFirstNode = this.range.start.nextSibling;
}
}
// need to put this at the newIndex
var frag = getFrag(currentFirstNode, currentEndNode);
newIndexFirstNode.parentNode.insertBefore(frag, newIndexFirstNode);
// update endNodes
this.itemEndNode.splice(currentIndex, 1);
this.itemEndNode.splice(newIndex, 0,currentEndNode);
// Update indexMap
newIndex = newIndex + 1;
currentIndex = currentIndex + 1;
var indexMap = this.indexMap;
// Convert back to a zero-based array index
newIndex = newIndex - 1;
currentIndex = currentIndex - 1;
// Grab the index compute from the `indexMap`
var indexCompute = indexMap[currentIndex];
// Remove the index compute from the `indexMap`
[].splice.apply(indexMap, [currentIndex, 1]);
// Move the index compute to the correct index in the `indexMap`
[].splice.apply(indexMap, [newIndex, 0, indexCompute]);
var i = Math.min(currentIndex, newIndex);
var len = indexMap.length;
for (len; i < len; i++) {
// set each compute to have its current index in the map as its value
indexMap[i].set(i);
}
}
};
/**
* @function can-view-live.list list
* @parent can-view-live
* @release 2.0.4
*
* @signature `live.list(el, list, render, context)`
*
* Live binds a compute's list incrementally.
*
* ```js
* // a compute that change's it's list
* var todos = compute(function(){
* return new Todo.List({page: can.route.attr("page")})
* })
*
* var placeholder = document.createTextNode(" ");
* $("ul#todos").append(placeholder);
*
* can.view.live.list(
* placeholder,
* todos,
* function(todo, index){
* return "
"+todo.attr("name")+"
"
* });
* ```
*
* @param {HTMLElement} el An html element to replace with the live-section.
*
* @param {Object} list An observable value or list type. If an observable value, it should contain
* a falsey value or a list type.
*
* @param {function(this:*,*,index):String} render(index, index) A function that when called with
* the incremental item to render and the index of the item in the list.
*
* @param {Object} context The `this` the `render` function will be called with.
*
* @body
*
* ## How it works
*
* If `list` is an observable value, `live.list` listens to changes in in that
* observable value. It will generally change from one list type (often a list type that implements `onPatches`)
* to another. When the value changes, a diff will be performed and the DOM updated. Also, `live.list`
* will listen to `.onPatches` on the new list and apply any patches emitted from it.
*
*
*/
var list$1 = function(el, list, render, context, falseyRender) {
new ListDOMPatcher(el, list, render, context, falseyRender);
};
/**
* @function can-view-live.text text
* @parent can-view-live
* @release 2.0.4
*
* @signature `live.text(el, compute)`
*
* Replaces one element with some content while keeping [can-view-live.nodeLists nodeLists] data correct.
*/
var text = function(el, compute) {
var handlerName = "";
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
if(arguments.length > 2) {
// TODO: remove
throw new Error("too many arguments");
}
handlerName = "live.text update::"+canReflect_1_19_2_canReflect.getName(compute);
}
//!steal-remove-end
// TODO: we can remove this at some point
if (el.nodeType !== Node.TEXT_NODE) {
var textNode;
textNode = document.createTextNode("");
el.parentNode.replaceChild(textNode, el);
el = textNode;
}
new helpers$2.ListenUntilRemovedAndInitialize(compute, function liveTextUpdateTextNode(newVal) {
el.nodeValue = helpers$2.makeString(newVal);
},
el,
"dom", // TODO: should this still be domUI?
handlerName);
};
/**
* @module {{}} can-view-live can-view-live
* @parent can-views
* @collection can-infrastructure
* @package ./package.json
*
* Setup live-binding between the DOM and a compute manually.
*
* @option {Object} An object with the live-binding methods:
* [can-view-live.html], [can-view-live.list], [can-view-live.text], and
* [can-view-live.attr].
*
*
* @body
*
* ## Use
*
* [can-view-live] is an object with utility methods for setting up
* live-binding in relation to different parts of the DOM and DOM elements. For
* example, to make an `
`'s text stay live with
* a compute:
*
* ```js
* var live = require("can-view-live");
* var text = canCompute("Hello World");
* var textNode = $("h2").text(" ")[0].childNodes[0];
* live.text(textNode, text);
* ```
*
*/
var live = {};
live.attr = attr_1;
live.attrs = attrs;
live.html = html;
live.list = list$1;
live.text = text;
var canViewLive_5_0_5_canViewLive = live;
var noop = function(){};
var TextSectionBuilder = function(filename){
if (filename) {
this.filename = filename;
}
this.stack = [new TextSection()];
};
canAssign_1_3_3_canAssign(TextSectionBuilder.prototype,utils$1.mixins);
canAssign_1_3_3_canAssign(TextSectionBuilder.prototype,{
// Adds a subsection.
startSection: function(process){
var subSection = new TextSection();
this.last().add({process: process, truthy: subSection});
this.stack.push(subSection);
},
endSection: function(){
this.stack.pop();
},
inverse: function(){
this.stack.pop();
var falseySection = new TextSection();
this.last().last().falsey = falseySection;
this.stack.push(falseySection);
},
compile: function(state){
var renderer = this.stack[0].compile();
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
Object.defineProperty(renderer,"name",{
value: "textSectionRenderer<"+state.tag+"."+state.attr+">"
});
}
//!steal-remove-end
return function(scope){
function textSectionRender(){
return renderer(scope);
}
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
Object.defineProperty(textSectionRender,"name",{
value: "textSectionRender<"+state.tag+"."+state.attr+">"
});
}
//!steal-remove-end
var observation = new canObservation_4_2_0_canObservation(textSectionRender, null, {isObservable: false});
canReflect_1_19_2_canReflect.onValue(observation, noop);
var value = canReflect_1_19_2_canReflect.getValue(observation);
if( canReflect_1_19_2_canReflect.valueHasDependencies( observation ) ) {
if(state.textContentOnly) {
canViewLive_5_0_5_canViewLive.text(this, observation);
}
else if(state.attr) {
canViewLive_5_0_5_canViewLive.attr(this, state.attr, observation);
}
else {
canViewLive_5_0_5_canViewLive.attrs(this, observation, scope);
}
canReflect_1_19_2_canReflect.offValue(observation, noop);
} else {
if(state.textContentOnly) {
this.nodeValue = value;
}
else if(state.attr) {
canDomMutate_2_0_9_node.setAttribute.call(this, state.attr, value);
}
else {
canViewLive_5_0_5_canViewLive.attrs(this, value);
}
}
};
}
});
var passTruthyFalsey = function(process, truthy, falsey){
return function(scope){
return process.call(this, scope, truthy, falsey);
};
};
var TextSection = function(){
this.values = [];
};
canAssign_1_3_3_canAssign( TextSection.prototype, {
add: function(data){
this.values.push(data);
},
last: function(){
return this.values[this.values.length - 1];
},
compile: function(){
var values = this.values,
len = values.length;
for(var i = 0 ; i < len; i++) {
var value = this.values[i];
if(typeof value === "object") {
values[i] = passTruthyFalsey( value.process,
value.truthy && value.truthy.compile(),
value.falsey && value.falsey.compile());
}
}
return function(scope){
var txt = "",
value;
for(var i = 0; i < len; i++){
value = values[i];
txt += typeof value === "string" ? value : value.call(this, scope);
}
return txt;
};
}
});
var text_section = TextSectionBuilder;
// ### Arg
// `new Arg(Expression [,modifierOptions] )`
// Used to identify an expression that should return a value.
var Arg = function(expression, modifiers){
this.expr = expression;
this.modifiers = modifiers || {};
this.isCompute = false;
};
Arg.prototype.value = function(){
return this.expr.value.apply(this.expr, arguments);
};
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
Arg.prototype.sourceText = function(){
return (this.modifiers.compute ? "~" : "")+ this.expr.sourceText();
};
}
//!steal-remove-end
var arg = Arg;
// ### Literal
// For inline static values like `{{"Hello World"}}`
var Literal = function(value){
this._value = value;
};
Literal.prototype.value = function(){
return this._value;
};
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
Literal.prototype.sourceText = function(){
return JSON.stringify(this._value);
};
}
//!steal-remove-end
var literal = Literal;
// ## Helpers
function getObservableValue_fromDynamicKey_fromObservable(key, root, helperOptions, readOptions) {
// This needs to return something similar to a ScopeKeyData with intialValue and parentHasKey
var getKeys = function(){
return canStacheKey_1_4_3_canStacheKey.reads(("" + canReflect_1_19_2_canReflect.getValue(key)).replace(/\./g, "\\."));
};
var parentHasKey;
var computeValue = new setter(function getDynamicKey() {
var readData = canStacheKey_1_4_3_canStacheKey.read( canReflect_1_19_2_canReflect.getValue(root) , getKeys());
parentHasKey = readData.parentHasKey;
return readData.value;
}, function setDynamicKey(newVal){
canStacheKey_1_4_3_canStacheKey.write(canReflect_1_19_2_canReflect.getValue(root), getKeys(), newVal);
});
// This prevents lazy evalutaion
canObservation_4_2_0_canObservation.temporarilyBind(computeValue);
// peek so no observable that might call getObservableValue_fromDynamicKey_fromObservable will re-evaluate if computeValue changes.
computeValue.initialValue = canObservationRecorder_1_3_1_canObservationRecorder.peekValue(computeValue);
computeValue.parentHasKey = parentHasKey;
// Todo:
// 1. We should warn here if `initialValue` is undefined. We can expose the warning function
// in can-view-scope and call it here.
// 2. We should make this lazy if possible. We can do that by making getter/setters for
// initialValue and parentHasKey (and possibly @@can.valueHasDependencies)
return computeValue;
}
// If not a Literal or an Arg, convert to an arg for caching.
function convertToArgExpression(expr) {
if(!(expr instanceof arg) && !(expr instanceof literal)) {
return new arg(expr);
} else {
return expr;
}
}
function toComputeOrValue(value) {
// convert to non observable value
if(canReflect_1_19_2_canReflect.isObservableLike(value)) {
// we only want to do this for things that `should` have dependencies, but dont.
if(canReflect_1_19_2_canReflect.isValueLike(value) && canReflect_1_19_2_canReflect.valueHasDependencies(value) === false) {
return canReflect_1_19_2_canReflect.getValue(value);
}
// if compute data
if(value.compute) {
return value.compute;
} else {
return canViewScope_4_13_7_makeComputeLike(value);
}
}
return value;
}
// try to make it a compute no matter what. This is useful for
// ~ operator.
function toCompute(value) {
if(value) {
if(value.isComputed) {
return value;
}
if(value.compute) {
return value.compute;
} else {
return canViewScope_4_13_7_makeComputeLike(value);
}
}
return value;
}
var expressionHelpers = {
getObservableValue_fromDynamicKey_fromObservable: getObservableValue_fromDynamicKey_fromObservable,
convertToArgExpression: convertToArgExpression,
toComputeOrValue: toComputeOrValue,
toCompute: toCompute
};
var Hashes = function(hashes){
this.hashExprs = hashes;
};
Hashes.prototype.value = function(scope, helperOptions){
var hash = {};
for(var prop in this.hashExprs) {
var val = expressionHelpers.convertToArgExpression(this.hashExprs[prop]),
value = val.value.apply(val, arguments);
hash[prop] = {
call: !val.modifiers || !val.modifiers.compute,
value: value
};
}
return new canObservation_4_2_0_canObservation(function(){
var finalHash = {};
for(var prop in hash) {
finalHash[prop] = hash[prop].call ? canReflect_1_19_2_canReflect.getValue( hash[prop].value ) : expressionHelpers.toComputeOrValue( hash[prop].value );
}
return finalHash;
});
};
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
Hashes.prototype.sourceText = function(){
var hashes = [];
canReflect_1_19_2_canReflect.eachKey(this.hashExprs, function(expr, prop){
hashes.push( prop+"="+expr.sourceText() );
});
return hashes.join(" ");
};
}
//!steal-remove-end
var hashes = Hashes;
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
var canSymbol = canSymbol_1_7_0_canSymbol;
}
//!steal-remove-end
// ### Bracket
// For accessing properties using bracket notation like `foo[bar]`
var Bracket = function (key, root, originalKey) {
this.root = root;
this.key = key;
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
this[canSymbol.for("can-stache.originalKey")] = originalKey;
}
//!steal-remove-end
};
Bracket.prototype.value = function (scope, helpers) {
var root = this.root ? this.root.value(scope, helpers) : scope.peek("this");
return expressionHelpers.getObservableValue_fromDynamicKey_fromObservable(this.key.value(scope, helpers), root, scope, helpers, {});
};
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
Bracket.prototype.sourceText = function(){
if(this.rootExpr) {
return this.rootExpr.sourceText()+"["+this.key+"]";
} else {
return "["+this.key+"]";
}
};
}
//!steal-remove-end
Bracket.prototype.closingTag = function() {
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
return this[canSymbol.for('can-stache.originalKey')] || '';
}
//!steal-remove-end
};
var bracket = Bracket;
var setIdentifier = function SetIdentifier(value){
this.value = value;
};
var sourceTextSymbol = canSymbol_1_7_0_canSymbol.for("can-stache.sourceText");
var isViewSymbol$1 = canSymbol_1_7_0_canSymbol.for("can.isView");
// ### Call
// `new Call( new Lookup("method"), [new ScopeExpr("name")], {})`
// A call expression like `method(arg1, arg2)` that, by default,
// calls `method` with non compute values.
var Call = function(methodExpression, argExpressions){
this.methodExpr = methodExpression;
this.argExprs = argExpressions.map(expressionHelpers.convertToArgExpression);
};
Call.prototype.args = function(scope, ignoreArgLookup) {
var hashExprs = {};
var args = [];
var gotIgnoreFunction = typeof ignoreArgLookup === "function";
for (var i = 0, len = this.argExprs.length; i < len; i++) {
var arg = this.argExprs[i];
if(arg.expr instanceof hashes){
canAssign_1_3_3_canAssign(hashExprs, arg.expr.hashExprs);
}
if (!gotIgnoreFunction || !ignoreArgLookup(i)) {
var value = arg.value.apply(arg, arguments);
args.push({
// always do getValue unless compute is false
call: !arg.modifiers || !arg.modifiers.compute,
value: value
});
}
}
return function(doNotWrapArguments){
var finalArgs = [];
if(canReflect_1_19_2_canReflect.size(hashExprs) > 0){
finalArgs.hashExprs = hashExprs;
}
for(var i = 0, len = args.length; i < len; i++) {
if (doNotWrapArguments) {
finalArgs[i] = args[i].value;
} else {
finalArgs[i] = args[i].call ?
canReflect_1_19_2_canReflect.getValue( args[i].value ) :
expressionHelpers.toCompute( args[i].value );
}
}
return finalArgs;
};
};
Call.prototype.value = function(scope, helperOptions){
var callExpression = this;
// proxyMethods must be false so that the `requiresOptionsArgument` and any
// other flags stored on the function are preserved
var method = this.methodExpr.value(scope, { proxyMethods: false });
canObservation_4_2_0_canObservation.temporarilyBind(method);
var func = canReflect_1_19_2_canReflect.getValue( method );
var getArgs = callExpression.args(scope , func && func.ignoreArgLookup);
var computeFn = function(newVal){
var func = canReflect_1_19_2_canReflect.getValue( method );
if(typeof func === "function") {
if (canReflect_1_19_2_canReflect.isObservableLike(func)) {
func = canReflect_1_19_2_canReflect.getValue(func);
}
var args = getArgs(
func.isLiveBound
);
if (func.requiresOptionsArgument) {
if(args.hashExprs && helperOptions && helperOptions.exprData){
helperOptions.exprData.hashExprs = args.hashExprs;
}
// For #581
if(helperOptions !== undefined) {
args.push(helperOptions);
}
}
// we are calling a view!
if(func[isViewSymbol$1] === true) {
// if not a scope, we should create a scope that
// includes the template scope
if(!(args[0] instanceof canViewScope_4_13_7_canViewScope)){
args[0] = scope.getTemplateContext().add(args[0]);
}
}
if(arguments.length) {
args.unshift(new setIdentifier(newVal));
}
// if this is a call like `foo.bar()` the method.thisArg will be set to `foo`
// for a call like `foo()`, method.thisArg will not be set and we will default
// to setting the scope as the context of the function
return func.apply(method.thisArg || scope.peek("this"), args);
}
};
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
Object.defineProperty(computeFn, "name", {
value: "{{" + this.sourceText() + "}}"
});
}
//!steal-remove-end
if (helperOptions && helperOptions.doNotWrapInObservation) {
return computeFn();
} else {
var computeValue = new setter(computeFn, computeFn);
return computeValue;
}
};
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
Call.prototype.sourceText = function(){
var args = this.argExprs.map(function(arg){
return arg.sourceText();
});
return this.methodExpr.sourceText()+"("+args.join(",")+")";
};
}
//!steal-remove-end
Call.prototype.closingTag = function() {
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
if(this.methodExpr[sourceTextSymbol]) {
return this.methodExpr[sourceTextSymbol];
}
}
//!steal-remove-end
return this.methodExpr.key;
};
var call$1 = Call;
var Helper = function(methodExpression, argExpressions, hashExpressions){
this.methodExpr = methodExpression;
this.argExprs = argExpressions;
this.hashExprs = hashExpressions;
this.mode = null;
};
Helper.prototype.args = function(scope){
var args = [];
for(var i = 0, len = this.argExprs.length; i < len; i++) {
var arg = this.argExprs[i];
// TODO: once we know the helper, we should be able to avoid compute conversion
args.push( expressionHelpers.toComputeOrValue( arg.value.apply(arg, arguments) ) );
}
return args;
};
Helper.prototype.hash = function(scope){
var hash = {};
for(var prop in this.hashExprs) {
var val = this.hashExprs[prop];
// TODO: once we know the helper, we should be able to avoid compute conversion
hash[prop] = expressionHelpers.toComputeOrValue( val.value.apply(val, arguments) );
}
return hash;
};
Helper.prototype.value = function(scope, helperOptions){
// If a literal, this means it should be treated as a key. But helpers work this way for some reason.
// TODO: fix parsing so numbers will also be assumed to be keys.
var methodKey = this.methodExpr instanceof literal ?
"" + this.methodExpr._value :
this.methodExpr.key,
helperInstance = this,
// proxyMethods must be false so that the `requiresOptionsArgument` and any
// other flags stored on the function are preserved
helperFn = scope.computeData(methodKey, { proxyMethods: false }),
initialValue = helperFn && helperFn.initialValue,
thisArg = helperFn && helperFn.thisArg;
if (typeof initialValue === "function") {
helperFn = function helperFn() {
var args = helperInstance.args(scope),
helperOptionArg = canAssign_1_3_3_canAssign(canAssign_1_3_3_canAssign({}, helperOptions), {
hash: helperInstance.hash(scope),
exprData: helperInstance
});
args.push(helperOptionArg);
return initialValue.apply(thisArg || scope.peek("this"), args);
};
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
Object.defineProperty(helperFn, "name", {
configurable: true,
value: canReflect_1_19_2_canReflect.getName(this)
});
}
//!steal-remove-end
}
//!steal-remove-start
else if (process.env.NODE_ENV !== 'production') {
var filename = scope.peek('scope.filename');
var lineNumber = scope.peek('scope.lineNumber');
dev.warn(
(filename ? filename + ':' : '') +
(lineNumber ? lineNumber + ': ' : '') +
'Unable to find helper "' + methodKey + '".');
}
//!steal-remove-end
return helperFn;
};
Helper.prototype.closingTag = function() {
return this.methodExpr.key;
};
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
Helper.prototype.sourceText = function(){
var text = [this.methodExpr.sourceText()];
if(this.argExprs.length) {
text.push( this.argExprs.map(function(arg){
return arg.sourceText();
}).join(" ") );
}
if(canReflect_1_19_2_canReflect.size(this.hashExprs) > 0){
text.push( hashes.prototype.sourceText.call(this) );
}
return text.join(" ");
};
canReflect_1_19_2_canReflect.assignSymbols(Helper.prototype,{
"can.getName": function() {
return canReflect_1_19_2_canReflect.getName(this.constructor) + "{{" + (this.sourceText()) + "}}";
}
});
}
//!steal-remove-end
var helper = Helper;
var sourceTextSymbol$1 = canSymbol_1_7_0_canSymbol.for("can-stache.sourceText");
// ### Lookup
// `new Lookup(String, [Expression])`
// Finds a value in the scope or a helper.
var Lookup = function(key, root, sourceText) {
this.key = key;
this.rootExpr = root;
canReflect_1_19_2_canReflect.setKeyValue(this, sourceTextSymbol$1, sourceText);
};
Lookup.prototype.value = function(scope, readOptions){
if (this.rootExpr) {
return expressionHelpers.getObservableValue_fromDynamicKey_fromObservable(this.key, this.rootExpr.value(scope), scope, {}, {});
} else {
return scope.computeData(this.key, canAssign_1_3_3_canAssign({
warnOnMissingKey: true
},readOptions));
}
};
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
Lookup.prototype.sourceText = function(){
if(this[sourceTextSymbol$1]) {
return this[sourceTextSymbol$1];
} else if(this.rootExpr) {
return this.rootExpr.sourceText()+"."+this.key;
} else {
return this.key;
}
};
}
//!steal-remove-end
var lookup = Lookup;
// ## Expression Types
//
// These expression types return a value. They are assembled by `expression.parse`.
var last$1 = utils$1.last;
var sourceTextSymbol$2 = canSymbol_1_7_0_canSymbol.for("can-stache.sourceText");
// ### Hash
// A placeholder. This isn't actually used.
var Hash = function(){ }; // jshint ignore:line
// NAME - \w
// KEY - foo, foo.bar, foo@bar, %foo (special), &foo (references), ../foo, ./foo
// ARG - ~KEY, KEY, CALLEXPRESSION, PRIMITIVE
// CALLEXPRESSION = KEY(ARG,ARG, NAME=ARG)
// HELPEREXPRESSION = KEY ARG ARG NAME=ARG
// DOT .NAME
// AT @NAME
//
var keyRegExp = /[\w\.\\\-_@\/\&%]+/,
tokensRegExp = /('.*?'|".*?"|=|[\w\.\\\-_@\/*%\$]+|[\(\)]|,|\~|\[|\]\s*|\s*(?=\[))/g,
bracketSpaceRegExp = /\]\s+/,
literalRegExp = /^('.*?'|".*?"|-?[0-9]+\.?[0-9]*|true|false|null|undefined)$/;
var isTokenKey = function(token){
return keyRegExp.test(token);
};
var testDot = /^[\.@]\w/;
var isAddingToExpression = function(token) {
return isTokenKey(token) && testDot.test(token);
};
var ensureChildren = function(type) {
if(!type.children) {
type.children = [];
}
return type;
};
var Stack = function(){
this.root = {children: [], type: "Root"};
this.current = this.root;
this.stack = [this.root];
};
canAssign_1_3_3_canAssign(Stack.prototype,{
top: function(){
return last$1(this.stack);
},
isRootTop: function(){
return this.top() === this.root;
},
popTo: function(types){
this.popUntil(types);
this.pop();
},
pop: function() {
if(!this.isRootTop()) {
this.stack.pop();
}
},
first: function(types){
var curIndex = this.stack.length - 1;
while( curIndex > 0 && types.indexOf(this.stack[curIndex].type) === -1 ) {
curIndex--;
}
return this.stack[curIndex];
},
firstParent: function(types){
var curIndex = this.stack.length - 2;
while( curIndex > 0 && types.indexOf(this.stack[curIndex].type) === -1 ) {
curIndex--;
}
return this.stack[curIndex];
},
popUntil: function(types){
while( types.indexOf(this.top().type) === -1 && !this.isRootTop() ) {
this.stack.pop();
}
return this.top();
},
addTo: function(types, type){
var cur = this.popUntil(types);
ensureChildren(cur).children.push(type);
},
addToAndPush: function(types, type){
this.addTo(types, type);
this.stack.push(type);
},
push: function(type) {
this.stack.push(type);
},
topLastChild: function(){
return last$1(this.top().children);
},
replaceTopLastChild: function(type){
var children = ensureChildren(this.top()).children;
children.pop();
children.push(type);
return type;
},
replaceTopLastChildAndPush: function(type) {
this.replaceTopLastChild(type);
this.stack.push(type);
},
replaceTopAndPush: function(type){
var children;
if(this.top() === this.root) {
children = ensureChildren(this.top()).children;
} else {
this.stack.pop();
// get parent and clean
children = ensureChildren(this.top()).children;
}
children.pop();
children.push(type);
this.stack.push(type);
return type;
}
});
// converts
// - "../foo" -> "../@foo",
// - "foo" -> "@foo",
// - ".foo" -> "@foo",
// - "./foo" -> "./@foo"
// - "foo.bar" -> "foo@bar"
var convertKeyToLookup = function(key){
var lastPath = key.lastIndexOf("./");
var lastDot = key.lastIndexOf(".");
if(lastDot > lastPath) {
return key.substr(0, lastDot)+"@"+key.substr(lastDot+1);
}
var firstNonPathCharIndex = lastPath === -1 ? 0 : lastPath+2;
var firstNonPathChar = key.charAt(firstNonPathCharIndex);
if(firstNonPathChar === "." || firstNonPathChar === "@" ) {
return key.substr(0, firstNonPathCharIndex)+"@"+key.substr(firstNonPathCharIndex+1);
} else {
return key.substr(0, firstNonPathCharIndex)+"@"+key.substr(firstNonPathCharIndex);
}
};
var convertToAtLookup = function(ast){
if(ast.type === "Lookup") {
canReflect_1_19_2_canReflect.setKeyValue(ast, sourceTextSymbol$2, ast.key);
ast.key = convertKeyToLookup(ast.key);
}
return ast;
};
var convertToHelperIfTopIsLookup = function(stack){
var top = stack.top();
// if two scopes, that means a helper
if(top && top.type === "Lookup") {
var base = stack.stack[stack.stack.length - 2];
// That lookup shouldn't be part of a Helper already or
if(base.type !== "Helper" && base) {
stack.replaceTopAndPush({
type: "Helper",
method: top
});
}
}
};
var expression = {
toComputeOrValue: expressionHelpers.toComputeOrValue,
convertKeyToLookup: convertKeyToLookup,
Literal: literal,
Lookup: lookup,
Arg: arg,
Hash: Hash,
Hashes: hashes,
Call: call$1,
Helper: helper,
Bracket: bracket,
SetIdentifier: setIdentifier,
tokenize: function(expression){
var tokens = [];
(expression.trim() + ' ').replace(tokensRegExp, function (whole, arg$$1) {
if (bracketSpaceRegExp.test(arg$$1)) {
tokens.push(arg$$1[0]);
tokens.push(arg$$1.slice(1));
} else {
tokens.push(arg$$1);
}
});
return tokens;
},
lookupRules: {
"default": function(ast, methodType, isArg){
return ast.type === "Helper" ? helper : lookup;
},
"method": function(ast, methodType, isArg){
return lookup;
}
},
methodRules: {
"default": function(ast){
return ast.type === "Call" ? call$1 : helper;
},
"call": function(ast){
return call$1;
}
},
// ## expression.parse
//
// - {String} expressionString - A stache expression like "abc foo()"
// - {Object} options
// - baseMethodType - Treat this like a Helper or Call. Default to "Helper"
// - lookupRule - "default" or "method"
// - methodRule - "default" or "call"
parse: function(expressionString, options){
options = options || {};
var ast = this.ast(expressionString);
if(!options.lookupRule) {
options.lookupRule = "default";
}
if(typeof options.lookupRule === "string") {
options.lookupRule = expression.lookupRules[options.lookupRule];
}
if(!options.methodRule) {
options.methodRule = "default";
}
if(typeof options.methodRule === "string") {
options.methodRule = expression.methodRules[options.methodRule];
}
var expr = this.hydrateAst(ast, options, options.baseMethodType || "Helper");
return expr;
},
hydrateAst: function(ast, options, methodType, isArg){
var hashes$$1;
if(ast.type === "Lookup") {
var LookupRule = options.lookupRule(ast, methodType, isArg);
var lookup$$1 = new LookupRule(ast.key, ast.root && this.hydrateAst(ast.root, options, methodType), ast[sourceTextSymbol$2] );
return lookup$$1;
}
else if(ast.type === "Literal") {
return new literal(ast.value);
}
else if(ast.type === "Arg") {
return new arg(this.hydrateAst(ast.children[0], options, methodType, isArg),{compute: true});
}
else if(ast.type === "Hash") {
throw new Error("");
}
else if(ast.type === "Hashes") {
hashes$$1 = {};
ast.children.forEach(function(hash){
hashes$$1[hash.prop] = this.hydrateAst( hash.children[0], options, methodType, true );
}, this);
return new hashes(hashes$$1);
}
else if(ast.type === "Call" || ast.type === "Helper") {
//get all arguments and hashes
hashes$$1 = {};
var args = [],
children = ast.children,
ExpressionType = options.methodRule(ast);
if(children) {
for(var i = 0 ; i 0)) {
stack.addTo(["Helper", "Call", "Bracket"], {type: "Literal", value: utils$1.jsonParse( token )});
} else if(firstParent.type === "Bracket" && (firstParent.children && firstParent.children.length > 0)) {
stack.addTo(["Helper", "Call", "Hash"], {type: "Literal", value: utils$1.jsonParse( token )});
} else {
stack.addTo(["Helper", "Call", "Hash", "Bracket"], {type: "Literal", value: utils$1.jsonParse( token )});
}
}
// Lookup
else if(keyRegExp.test(token)) {
lastToken = stack.topLastChild();
firstParent = stack.first(["Helper", "Call", "Hash", "Bracket"]);
// if we had `foo().bar`, we need to change to a Lookup that looks up from lastToken.
if(lastToken && (lastToken.type === "Call" || lastToken.type === "Bracket" ) && isAddingToExpression(token)) {
stack.replaceTopLastChildAndPush({
type: "Lookup",
root: lastToken,
key: token.slice(1) // remove leading `.`
});
}
else if(firstParent.type === 'Bracket') {
// a Bracket expression without children means we have
// parsed `foo[` of an expression like `foo[bar]`
// so we know to add the Lookup as a child of the Bracket expression
if (!(firstParent.children && firstParent.children.length > 0)) {
stack.addToAndPush(["Bracket"], {type: "Lookup", key: token});
} else {
// check if we are adding to a helper like `eq foo[bar] baz`
// but not at the `.baz` of `eq foo[bar].baz xyz`
if(stack.first(["Helper", "Call", "Hash", "Arg"]).type === 'Helper' && token[0] !== '.') {
stack.addToAndPush(["Helper"], {type: "Lookup", key: token});
} else {
// otherwise, handle the `.baz` in expressions like `foo[bar].baz`
stack.replaceTopAndPush({
type: "Lookup",
key: token.slice(1),
root: firstParent
});
}
}
}
else {
// if two scopes, that means a helper
convertToHelperIfTopIsLookup(stack);
stack.addToAndPush(["Helper", "Call", "Hash", "Arg", "Bracket"], {type: "Lookup", key: token});
}
}
// Arg
else if(token === "~") {
convertToHelperIfTopIsLookup(stack);
stack.addToAndPush(["Helper", "Call", "Hash"], {type: "Arg", key: token});
}
// Call
// foo[bar()]
else if(token === "(") {
top = stack.top();
lastToken = stack.topLastChild();
if(top.type === "Lookup") {
stack.replaceTopAndPush({
type: "Call",
method: convertToAtLookup(top)
});
// Nested Call
// foo()()
} else if (lastToken && lastToken.type === "Call") {
stack.replaceTopAndPush({
type: "Call",
method: lastToken
});
} else {
throw new Error("Unable to understand expression "+tokens.join(''));
}
}
// End Call
else if(token === ")") {
stack.popTo(["Call"]);
}
// End Call argument
else if(token === ",") {
// The {{let foo=zed, bar=car}} helper is not in a call
// expression.
var call = stack.first(["Call"]);
if(call.type !== "Call") {
stack.popUntil(["Hash"]);
} else {
stack.popUntil(["Call"]);
}
}
// Bracket
else if(token === "[") {
top = stack.top();
lastToken = stack.topLastChild();
// foo()[bar] => top -> root, lastToken -> {t: call, m: "@foo"}
// foo()[bar()] => same as above last thing we see was a call expression "rotate"
// test['foo'][0] => lastToken => {root: test, t: Bracket, c: 'foo' }
// log(thing['prop'][0]) =>
//
// top -> {Call, children|args: [Bracket(Lookup(thing), c: ['[prop]'])]}
// last-> Bracket(Lookup(thing), c: ['[prop]'])
if (lastToken && (lastToken.type === "Call" || lastToken.type === "Bracket" ) ) {
// must be on top of the stack as it recieves new stuff ...
// however, what we really want is to
stack.replaceTopLastChildAndPush({type: "Bracket", root: lastToken});
} else if (top.type === "Lookup" || top.type === "Bracket") {
var bracket$$1 = {type: "Bracket", root: top};
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
canReflect_1_19_2_canReflect.setKeyValue(bracket$$1, canSymbol_1_7_0_canSymbol.for("can-stache.originalKey"), top.key);
}
//!steal-remove-end
stack.replaceTopAndPush(bracket$$1);
} else if (top.type === "Call") {
stack.addToAndPush(["Call"], { type: "Bracket" });
} else if (top === " ") {
stack.popUntil(["Lookup", "Call"]);
convertToHelperIfTopIsLookup(stack);
stack.addToAndPush(["Helper", "Call", "Hash"], {type: "Bracket"});
} else {
stack.replaceTopAndPush({type: "Bracket"});
}
}
// End Bracket
else if(token === "]") {
stack.pop();
}
else if(token === " ") {
stack.push(token);
}
}
return stack.root.children[0];
}
};
var expression_1 = expression;
//
// This provides helper utilities for Mustache processing. Currently,
// only stache uses these helpers. Ideally, these utilities could be used
// in other libraries implementing Mustache-like features.
var expression$1 = expression_1;
var toDOMSymbol$1 = canSymbol_1_7_0_canSymbol.for("can.toDOM");
// Lazily lookup the context only if it's needed.
function HelperOptions(scope, exprData, stringOnly) {
this.metadata = { rendered: false };
this.stringOnly = stringOnly;
this.scope = scope;
this.exprData = exprData;
}
canDefineLazyValue_1_1_1_defineLazyValue(HelperOptions.prototype,"context", function(){
return this.scope.peek("this");
});
// ## Helpers
var mustacheLineBreakRegExp = /(?:(^|\r?\n)(\s*)(\{\{([\s\S]*)\}\}\}?)([^\S\n\r]*)($|\r?\n))|(\{\{([\s\S]*)\}\}\}?)/g,
mustacheWhitespaceRegExp = /\s*\{\{--\}\}\s*|\s*(\{\{\{?)-|-(\}\}\}?)\s*/g,
k = function(){};
var viewInsertSymbol$1 = canSymbol_1_7_0_canSymbol.for("can.viewInsert");
// DOM, safeString or the insertSymbol can opt-out of updating as text
function valueShouldBeInsertedAsHTML(value) {
return value !== null && typeof value === "object" && (
typeof value[toDOMSymbol$1] === "function" ||
typeof value[viewInsertSymbol$1] === "function" ||
typeof value.nodeType === "number" );
}
var core = {
expression: expression$1,
// ## mustacheCore.makeEvaluator
// Given a scope and expression, returns a function that evaluates that expression in the scope.
//
// This function first reads lookup values in the args and hash. Then it tries to figure out
// if a helper is being called or a value is being read. Finally, depending on
// if it's a helper, or not, and which mode the expression is in, it returns
// a function that can quickly evaluate the expression.
/**
* @hide
* Given a mode and expression data, returns a function that evaluates that expression.
* @param {can-view-scope} The scope in which the expression is evaluated.
* @param {can.view.Options} The option helpers in which the expression is evaluated.
* @param {String} mode Either null, #, ^. > is handled elsewhere
* @param {Object} exprData Data about what was in the mustache expression
* @param {renderer} [truthyRenderer] Used to render a subsection
* @param {renderer} [falseyRenderer] Used to render the inverse subsection
* @param {String} [stringOnly] A flag to indicate that only strings will be returned by subsections.
* @return {Function} An 'evaluator' function that evaluates the expression.
*/
makeEvaluator: function (scope, mode, exprData, truthyRenderer, falseyRenderer, stringOnly) {
if(mode === "^") {
var temp = truthyRenderer;
truthyRenderer = falseyRenderer;
falseyRenderer = temp;
}
var value,
helperOptions = new HelperOptions(scope , exprData, stringOnly);
// set up renderers
utils$1.createRenderers(helperOptions, scope ,truthyRenderer, falseyRenderer, stringOnly);
if(exprData instanceof expression$1.Call) {
value = exprData.value(scope, helperOptions);
} else if (exprData instanceof expression$1.Bracket) {
value = exprData.value(scope);
} else if (exprData instanceof expression$1.Lookup) {
value = exprData.value(scope);
} else if (exprData instanceof expression$1.Literal) {
value = exprData.value.bind(exprData);
} else if (exprData instanceof expression$1.Helper && exprData.methodExpr instanceof expression$1.Bracket) {
// Brackets get wrapped in Helpers when used in attributes
// like ``
value = exprData.methodExpr.value(scope, helperOptions);
} else {
value = exprData.value(scope, helperOptions);
if (typeof value === "function") {
return value;
}
}
// {{#something()}}foo{{/something}}
// return evaluator for no mode or rendered value if a renderer was called
if(!mode || helperOptions.metadata.rendered) {
return value;
} else if( mode === "#" || mode === "^" ) {
return function(){
// Get the value
var finalValue = canReflect_1_19_2_canReflect.getValue(value);
var result;
// if options.fn or options.inverse was called, we take the observable's return value
// as what should be put in the DOM.
if(helperOptions.metadata.rendered) {
result = finalValue;
}
// If it's an array, render.
else if ( typeof finalValue !== "string" && canReflect_1_19_2_canReflect.isListLike(finalValue) ) {
var isObserveList = canReflect_1_19_2_canReflect.isObservableLike(finalValue) &&
canReflect_1_19_2_canReflect.isListLike(finalValue);
if(canReflect_1_19_2_canReflect.getKeyValue(finalValue, "length")) {
if (stringOnly) {
result = utils$1.getItemsStringContent(finalValue, isObserveList, helperOptions);
} else {
result = canFragment_1_3_1_canFragment(utils$1.getItemsFragContent(finalValue, helperOptions, scope));
}
} else {
result = helperOptions.inverse(scope);
}
}
else {
result = finalValue ? helperOptions.fn(finalValue || scope) : helperOptions.inverse(scope);
}
// We always set the rendered result back to false.
// - Future calls might change from returning a value to calling `.fn`
// - We are calling `.fn` and `.inverse` ourselves.
helperOptions.metadata.rendered = false;
return result;
};
} else {
// not supported!
}
},
// ## mustacheCore.makeLiveBindingPartialRenderer
// Returns a renderer function that live binds a partial.
/**
* @hide
* Returns a renderer function that live binds a partial.
* @param {String} expressionString
* @param {Object} state The html state of where the expression was found.
* @return {function(this:HTMLElement,can-view-scope,can.view.Options)} A renderer function
* live binds a partial.
*/
makeLiveBindingPartialRenderer: function(expressionString, state){
expressionString = expressionString.trim();
var exprData,
partialName = expressionString.split(/\s+/).shift();
if(partialName !== expressionString) {
exprData = core.expression.parse(expressionString);
}
return function(scope){
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
scope.set('scope.filename', state.filename);
scope.set('scope.lineNumber', state.lineNo);
}
//!steal-remove-end
var partialFrag = new canObservation_4_2_0_canObservation(function(){
var localPartialName = partialName;
var partialScope = scope;
// If the second parameter of a partial is a custom context
if(exprData && exprData.argExprs.length === 1) {
var newContext = canReflect_1_19_2_canReflect.getValue( exprData.argExprs[0].value(scope) );
if(typeof newContext === "undefined") {
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
dev.warn('The context ('+ exprData.argExprs[0].key +') you passed into the' +
'partial ('+ partialName +') is not defined in the scope!');
}
//!steal-remove-end
}else{
partialScope = scope.add(newContext);
}
}
// Look up partials in templateContext first
var partial = canReflect_1_19_2_canReflect.getKeyValue(partialScope.templateContext.partials, localPartialName);
var renderer;
if (partial) {
renderer = function() {
return partial.render ? partial.render(partialScope)
: partial(partialScope);
};
}
// Use can.view to get and render the partial.
else {
var scopePartialName = partialScope.read(localPartialName, {
isArgument: true
}).value;
if (scopePartialName === null || !scopePartialName && localPartialName[0] === '*') {
return canFragment_1_3_1_canFragment("");
}
if (scopePartialName) {
localPartialName = scopePartialName;
}
renderer = function() {
if(typeof localPartialName === "function"){
return localPartialName(partialScope, {});
} else {
var domRenderer = core.getTemplateById(localPartialName);
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
if (!domRenderer) {
dev.warn(
(state.filename ? state.filename + ':' : '') +
(state.lineNo ? state.lineNo + ': ' : '') +
'Unable to find partial "' + localPartialName + '".');
}
}
//!steal-remove-end
return domRenderer ? domRenderer(partialScope, {}) : document$1().createDocumentFragment();
}
};
}
var res = canObservationRecorder_1_3_1_canObservationRecorder.ignore(renderer)();
return canFragment_1_3_1_canFragment(res);
});
canViewLive_5_0_5_canViewLive.html(this, partialFrag);
};
},
// ## mustacheCore.makeStringBranchRenderer
// Return a renderer function that evalutes to a string and caches
// the evaluator on the scope.
/**
* @hide
* Return a renderer function that evaluates to a string.
* @param {String} mode
* @param {can.stache.Expression} expression
* @param {Object} state The html state of where the expression was found.
* @return {function(can.view.Scope,can.view.Options, can-stache.view, can.view.renderer)}
*/
makeStringBranchRenderer: function(mode, expressionString, state){
var exprData = core.expression.parse(expressionString),
// Use the full mustache expression as the cache key.
fullExpression = mode+expressionString;
// A branching renderer takes truthy and falsey renderer.
var branchRenderer = function branchRenderer(scope, truthyRenderer, falseyRenderer){
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
scope.set('scope.filename', state.filename);
scope.set('scope.lineNumber', state.lineNo);
}
//!steal-remove-end
// Check the scope's cache if the evaluator already exists for performance.
var evaluator = scope.__cache[fullExpression];
if(mode || !evaluator) {
evaluator = makeEvaluator( scope, mode, exprData, truthyRenderer, falseyRenderer, true);
if(!mode) {
scope.__cache[fullExpression] = evaluator;
}
}
var gotObservableValue = evaluator[canSymbol_1_7_0_canSymbol.for("can.onValue")],
res;
// Run the evaluator and return the result.
if(gotObservableValue) {
res = canReflect_1_19_2_canReflect.getValue(evaluator);
} else {
res = evaluator();
}
if (res == null) {
return "";
}
return res.nodeType === 11 ? res.textContent : ""+res;
};
branchRenderer.exprData = exprData;
return branchRenderer;
},
// ## mustacheCore.makeLiveBindingBranchRenderer
// Return a renderer function that evaluates the mustache expression and
// sets up live binding if a compute with dependencies is found. Otherwise,
// the element's value is set.
//
// This function works by creating a `can.compute` from the mustache expression.
// If the compute has dependent observables, it passes the compute to `can.view.live`; otherwise,
// it updates the element's property based on the compute's value.
/**
* @hide
* Returns a renderer function that evaluates the mustache expression.
* @param {String} mode
* @param {can.stache.Expression} expression
* @param {Object} state The html state of where the expression was found.
*/
makeLiveBindingBranchRenderer: function(mode, expressionString, state){
// Pre-process the expression.
var exprData = core.expression.parse(expressionString);
// A branching renderer takes truthy and falsey renderer.
var branchRenderer = function branchRenderer(scope, truthyRenderer, falseyRenderer){
// If this is within a tag, make sure we only get string values.
var stringOnly = state.tag;
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
scope.set('scope.filename', state.filename);
scope.set('scope.lineNumber', state.lineNo);
}
//!steal-remove-end
// Get the evaluator. This does not need to be cached (probably) because if there
// an observable value, it will be handled by `can.view.live`.
var evaluator = makeEvaluator( scope, mode, exprData, truthyRenderer, falseyRenderer, stringOnly );
// Create a compute that can not be observed by other
// computes. This is important because this renderer is likely called by
// parent expressions. If this value changes, the parent expressions should
// not re-evaluate. We prevent that by making sure this compute is ignored by
// everyone else.
//var compute = can.compute(evaluator, null, false);
var gotObservableValue = evaluator[canSymbol_1_7_0_canSymbol.for("can.onValue")];
var observable;
if(gotObservableValue) {
observable = evaluator;
} else {
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
Object.defineProperty(evaluator,"name",{
value: "{{"+(mode || "")+expressionString+"}}"
});
}
//!steal-remove-end
observable = new canObservation_4_2_0_canObservation(evaluator,null,{isObservable: false});
}
// Bind on the computeValue to set the cached value. This helps performance
// so live binding can read a cached value instead of re-calculating.
canReflect_1_19_2_canReflect.onValue(observable, k);
var value = canReflect_1_19_2_canReflect.getValue(observable);
// If value is a function and not a Lookup ({{foo}}),
// it's a helper that returned a function and should be called.
if(typeof value === "function" && !(exprData instanceof expression$1.Lookup)) {
// A helper function should do it's own binding. Similar to how
// we prevented this function's compute from being noticed by parent expressions,
// we hide any observables read in the function by saving any observables that
// have been read and then setting them back which overwrites any `can.__observe` calls
// performed in value.
canObservationRecorder_1_3_1_canObservationRecorder.ignore(value)(this);
}
// If the computeValue has observable dependencies, setup live binding.
else if( canReflect_1_19_2_canReflect.valueHasDependencies(observable) ) {
// Depending on where the template is, setup live-binding differently.
if(state.attr) {
canViewLive_5_0_5_canViewLive.attr(this, state.attr, observable);
}
else if( state.tag ) {
canViewLive_5_0_5_canViewLive.attrs( this, observable );
}
else if(state.text && !valueShouldBeInsertedAsHTML(value)) {
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
if(value !== null && typeof value === "object") {
dev.warn("Previously, the result of "+
expressionString+" in "+state.filename+":"+state.lineNo+
", was being inserted as HTML instead of TEXT. Please use stache.safeString(obj) "+
"if you would like the object to be treated as HTML.");
}
}
//!steal-remove-end
canViewLive_5_0_5_canViewLive.text(this, observable);
} else {
canViewLive_5_0_5_canViewLive.html(this, observable);
}
}
// If the computeValue has no observable dependencies, just set the value on the element.
else {
if(state.attr) {
canDomMutate_2_0_9_canDomMutate.setAttribute(this, state.attr, value);
}
else if(state.tag) {
canViewLive_5_0_5_canViewLive.attrs(this, value);
}
else if(state.text && !valueShouldBeInsertedAsHTML(value)) {
this.nodeValue = helpers$2.makeString(value);
}
else if( value != null ){
if (typeof value[viewInsertSymbol$1] === "function") {
var insert = value[viewInsertSymbol$1]({});
this.parentNode.replaceChild( insert, this );
} else {
this.parentNode.replaceChild(canFragment_1_3_1_canFragment(value, this.ownerDocument), this);
//domMutateNode.replaceChild.call(this.parentNode, frag(value, this.ownerDocument), this);
}
}
}
// Unbind the compute.
canReflect_1_19_2_canReflect.offValue(observable, k);
};
branchRenderer.exprData = exprData;
return branchRenderer;
},
// ## mustacheCore.splitModeFromExpression
// Returns the mustache mode split from the rest of the expression.
/**
* @hide
* Returns the mustache mode split from the rest of the expression.
* @param {can.stache.Expression} expression
* @param {Object} state The state of HTML where the expression was found.
*/
splitModeFromExpression: function(expression, state){
expression = expression.trim();
var mode = expression.charAt(0);
if( "#/{&^>!<".indexOf(mode) >= 0 ) {
expression = expression.substr(1).trim();
} else {
mode = null;
}
// Triple braces do nothing within a tag.
if(mode === "{" && state.node) {
mode = null;
}
return {
mode: mode,
expression: expression
};
},
// ## mustacheCore.cleanLineEndings
// Removes line breaks accoding to the mustache specification.
/**
* @hide
* Prunes line breaks accoding to the mustache specification.
* @param {String} template
* @return {String}
*/
cleanLineEndings: function(template){
// Finds mustache tags with space around them or no space around them.
return template.replace( mustacheLineBreakRegExp,
function(whole,
returnBefore,
spaceBefore,
special,
expression,
spaceAfter,
returnAfter,
// A mustache magic tag that has no space around it.
spaceLessSpecial,
spaceLessExpression,
matchIndex){
// IE 8 will provide undefined
spaceAfter = (spaceAfter || "");
returnBefore = (returnBefore || "");
spaceBefore = (spaceBefore || "");
var modeAndExpression = splitModeFromExpression(expression || spaceLessExpression,{});
// If it's a partial or tripple stache, leave in place.
if(spaceLessSpecial || ">{".indexOf( modeAndExpression.mode) >= 0) {
return whole;
} else if( "^#!/".indexOf( modeAndExpression.mode ) >= 0 ) {
// Return the magic tag and a trailing linebreak if this did not
// start a new line and there was an end line.
// Add a normalized leading space, if there was any leading space, in case this abuts a tag name
spaceBefore = (returnBefore + spaceBefore) && " ";
return spaceBefore+special+( matchIndex !== 0 && returnAfter.length ? returnBefore+"\n" :"");
} else {
// There is no mode, return special with spaces around it.
return spaceBefore+special+spaceAfter+(spaceBefore.length || matchIndex !== 0 ? returnBefore+"\n" : "");
}
});
},
// ## mustacheCore.cleanWhitespaceControl
// Removes whitespace according to the whitespace control.
/**
* @hide
* Prunes whitespace according to the whitespace control.
* @param {String} template
* @return {String}
*/
cleanWhitespaceControl: function(template) {
return template.replace(mustacheWhitespaceRegExp, "$1$2");
},
getTemplateById: function(){}
};
// ## Local Variable Cache
//
// The following creates slightly more quickly accessible references of the following
// core functions.
var makeEvaluator = core.makeEvaluator,
splitModeFromExpression = core.splitModeFromExpression;
var mustache_core = core;
/**
* @module {function} can-globals/base-url/base-url base-url
* @parent can-globals/modules
*
* @signature `baseUrl(optionalBaseUrlToSet)`
*
* Get and/or set the "base" (containing path) of the document.
*
* ```js
* var baseUrl = require("can-globals/base-url/base-url");
*
* console.log(baseUrl()); // -> "http://localhost:8080"
* console.log(baseUrl(baseUrl() + "/foo/bar")); // -> "http://localhost:8080/foo/bar"
* console.log(baseUrl()); // -> "http://localhost:8080/foo/bar"
* ```
*
* @param {String} setUrl An optional base url to override reading the base URL from the known path.
*
* @return {String} Returns the set or computed base URL
*/
canGlobals_1_2_2_canGlobalsInstance.define('base-url', function(){
var global = canGlobals_1_2_2_canGlobalsInstance.getKeyValue('global');
var domDocument = canGlobals_1_2_2_canGlobalsInstance.getKeyValue('document');
if (domDocument && 'baseURI' in domDocument) {
return domDocument.baseURI;
} else if(global.location) {
var href = global.location.href;
var lastSlash = href.lastIndexOf("/");
return lastSlash !== -1 ? href.substr(0, lastSlash) : href;
} else if(typeof process !== "undefined") {
return process.cwd();
}
});
var baseUrl = canGlobals_1_2_2_canGlobalsInstance.makeExport('base-url');
/**
* @module {function} can-parse-uri can-parse-uri
* @parent can-js-utilities
* @collection can-infrastructure
* @package ./package.json
* @signature `parseURI(url)`
*
* Parse a URI into its components.
*
* ```js
* import {parseURI} from "can"
* parseURI("http://foo:8080/bar.html?query#change")
* //-> {
* // authority: "//foo:8080",
* // hash: "#change",
* // host: "foo:8080",
* // hostname: "foo",
* // href: "http://foo:8080/bar.html?query#change",
* // pathname: "/bar.html",
* // port: "8080",
* // protocol: "http:",
* // search: "?query"
* // }
* ```
*
* @param {String} url The URL you want to parse.
*
* @return {Object} Returns an object with properties for each part of the URL. `null`
* is returned if the url can not be parsed.
*/
var canParseUri_1_2_2_canParseUri = canNamespace_1_0_0_canNamespace.parseURI = function(url){
var m = String(url).replace(/^\s+|\s+$/g, '').match(/^([^:\/?#]+:)?(\/\/(?:[^:@]*(?::[^:@]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/);
// authority = '//' + user + ':' + pass '@' + hostname + ':' port
return (m ? {
href : m[0] || '',
protocol : m[1] || '',
authority: m[2] || '',
host : m[3] || '',
hostname : m[4] || '',
port : m[5] || '',
pathname : m[6] || '',
search : m[7] || '',
hash : m[8] || ''
} : null);
};
var canJoinUris_1_2_0_canJoinUris = canNamespace_1_0_0_canNamespace.joinURIs = function(base, href) {
function removeDotSegments(input) {
var output = [];
input.replace(/^(\.\.?(\/|$))+/, '')
.replace(/\/(\.(\/|$))+/g, '/')
.replace(/\/\.\.$/, '/../')
.replace(/\/?[^\/]*/g, function (p) {
if (p === '/..') {
output.pop();
} else {
output.push(p);
}
});
return output.join('').replace(/^\//, input.charAt(0) === '/' ? '/' : '');
}
href = canParseUri_1_2_2_canParseUri(href || '');
base = canParseUri_1_2_2_canParseUri(base || '');
return !href || !base ? null : (href.protocol || base.protocol) +
(href.protocol || href.authority ? href.authority : base.authority) +
removeDotSegments(href.protocol || href.authority || href.pathname.charAt(0) === '/' ? href.pathname : (href.pathname ? ((base.authority && !base.pathname ? '/' : '') + base.pathname.slice(0, base.pathname.lastIndexOf('/') + 1) + href.pathname) : base.pathname)) +
(href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) +
href.hash;
};
function noop$1 () {}
var resolveValue = noop$1;
var evaluateArgs = noop$1;
var __testing = {};
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
var canReflect = canReflect_1_19_2_canReflect;
var canSymbol$1 = canSymbol_1_7_0_canSymbol;
__testing = {
allowDebugger: true
};
resolveValue = function (value) {
if (value && value[canSymbol$1.for("can.getValue")]) {
return canReflect.getValue(value);
}
return value;
};
evaluateArgs = function (left, right) {
switch (arguments.length) {
case 0: return true;
case 1: return !!resolveValue(left);
case 2: return resolveValue(left) === resolveValue(right);
default:
canLog_1_0_2_canLog.log([
'Usage:',
' {{debugger}}: break any time this helper is evaluated',
' {{debugger condition}}: break when `condition` is truthy',
' {{debugger left right}}: break when `left` === `right`'
].join('\n'));
throw new Error('{{debugger}} must have less than three arguments');
}
};
}
//!steal-remove-end
function debuggerHelper (left, right) {
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
var shouldBreak = evaluateArgs.apply(null, Array.prototype.slice.call(arguments, 0, -1));
if (!shouldBreak) {
return;
}
var options = arguments[arguments.length - 1],
scope = options && options.scope;
var get = function (path) {
return scope.get(path);
};
// This makes sure `get`, `options` and `scope` are available
debuggerHelper._lastGet = get;
canLog_1_0_2_canLog.log('Use `get()` to debug this template');
var allowDebugger = __testing.allowDebugger;
// forgotten debugger
// jshint -W087
if (allowDebugger) {
debugger;
return;
}
// jshint +W087
}
//!steal-remove-end
canLog_1_0_2_canLog.warn('Forgotten {{debugger}} helper');
}
debuggerHelper.requiresOptionsArgument = true;
var Debugger = {
helper: debuggerHelper,
evaluateArgs: evaluateArgs,
resolveValue: resolveValue,
// used only for testing purposes
__testing: __testing
};
var truthyObservable = function(observable){
return new canObservation_4_2_0_canObservation(function truthyObservation(){
var val = canReflect_1_19_2_canReflect.getValue(observable);
return !!val;
});
};
function makeConverter(getterSetter){
getterSetter = getterSetter || {};
return function(newVal, source) {
var args = canReflect_1_19_2_canReflect.toArray(arguments);
if(newVal instanceof setIdentifier) {
return typeof getterSetter.set === "function" ?
getterSetter.set.apply(this, [newVal.value].concat(args.slice(1))) :
source(newVal.value);
} else {
return typeof getterSetter.get === "function" ?
getterSetter.get.apply(this, args) :
args[0];
}
};
}
var converter = makeConverter;
var bindAndRead = function (value) {
if ( value && canReflect_1_19_2_canReflect.isValueLike(value) ) {
canObservation_4_2_0_canObservation.temporarilyBind(value);
return canReflect_1_19_2_canReflect.getValue(value);
} else {
return value;
}
};
function forOfInteger(integer, variableName, options) {
var result = [];
for (var i = 0; i < integer; i++) {
var variableScope = {};
if(variableName !== undefined){
variableScope[variableName] = i;
}
result.push(
options.fn( options.scope
.add({ index: i }, { special: true })
.addLetContext(variableScope) )
);
}
return options.stringOnly ? result.join('') : result;
}
function forOfObject(object, variableName, options){
var result = [];
canReflect_1_19_2_canReflect.each(object, function(val, key){
// Allow key to contain a dot, for example: "My.key.has.dot"
var value = new keyObservable(object, key.replace(/\./g, "\\."));
var variableScope = {};
if(variableName !== undefined){
variableScope[variableName] = value;
}
result.push(
options.fn( options.scope
.add({ key: key }, { special: true })
.addLetContext(variableScope) )
);
});
return options.stringOnly ? result.join('') : result;
}
// this is called with the ast ... we are going to use that to our advantage.
var forHelper = function(helperOptions) {
// lookup
// TODO: remove in prod
// make sure we got called with the right stuff
if(helperOptions.exprData.argExprs.length !== 1) {
throw new Error("for(of) broken syntax");
}
// TODO: check if an instance of helper;
var helperExpr = helperOptions.exprData.argExprs[0].expr;
var variableName, valueLookup, valueObservable;
if(helperExpr instanceof expression_1.Lookup) {
valueObservable = helperExpr.value(helperOptions.scope);
} else if(helperExpr instanceof expression_1.Helper) {
// TODO: remove in prod
var inLookup = helperExpr.argExprs[0];
if(inLookup.key !== "of") {
throw new Error("for(of) broken syntax");
}
variableName = helperExpr.methodExpr.key;
valueLookup = helperExpr.argExprs[1];
valueObservable = valueLookup.value(helperOptions.scope);
}
var items = valueObservable;
var args = [].slice.call(arguments),
options = args.pop(),
resolved = bindAndRead(items);
if(resolved && resolved === Math.floor(resolved)) {
return forOfInteger(resolved, variableName, helperOptions);
}
if(resolved && !canReflect_1_19_2_canReflect.isListLike(resolved)) {
return forOfObject(resolved,variableName, helperOptions);
}
if(options.stringOnly) {
var parts = [];
canReflect_1_19_2_canReflect.eachIndex(resolved, function(value, index){
var variableScope = {};
if(variableName !== undefined){
variableScope[variableName] = value;
}
parts.push(
helperOptions.fn( options.scope
.add({ index: index }, { special: true })
.addLetContext(variableScope) )
);
});
return parts.join("");
} else {
// Tells that a helper has been called, this function should be returned through
// checking its value.
options.metadata.rendered = true;
return function(el){
var cb = function (item, index) {
var variableScope = {};
if(variableName !== undefined){
variableScope[variableName] = item;
}
return options.fn(
options.scope
.add({ index: index }, { special: true })
.addLetContext(variableScope),
options.options
);
};
canViewLive_5_0_5_canViewLive.list(el, items, cb, options.context, function(list){
return options.inverse(options.scope, options.options);
});
};
}
};
forHelper.isLiveBound = true;
forHelper.requiresOptionsArgument = true;
forHelper.ignoreArgLookup = function ignoreArgLookup(index) {
return index === 0;
};
var ForOf = forHelper;
function isVariable(scope) {
return scope._meta.variable === true;
}
// This sets variables so it needs to not causes changes.
var letHelper = canObservationRecorder_1_3_1_canObservationRecorder.ignore(function(options){
if(options.isSection){
return options.fn( options.scope.addLetContext( options.hash ) );
}
var variableScope = options.scope.getScope(isVariable);
if(!variableScope) {
throw new Error("There is no variable scope!");
}
canReflect_1_19_2_canReflect.assignMap(variableScope._context, options.hash);
return document.createTextNode("");
});
var Let = letHelper;
var keepNodeSymbol = canSymbol_1_7_0_canSymbol.for("done.keepNode");
function portalHelper(elementObservable, options){
var debugName = "portal(" + canReflect_1_19_2_canReflect.getName(elementObservable) + ")";
function portalContents() {
var frag = options.fn(
options.scope
.addLetContext({}),
options.options
);
var child = frag.firstChild;
while(child) {
// makes sure DoneJS does not remove these nodes
child[keepNodeSymbol] = true;
child = child.nextSibling;
}
return frag;
}
//!steal-remove-start
if(process.env.NODE_ENV !== 'production') {
Object.defineProperty(portalContents,"name",{
value: debugName+" contents"
});
}
//!steal-remove-end
// Where we are portalling
var portalElement,
startPortalledPlaceholder,
endPortalledPlaceholder,
commentPlaceholderDispose;
function teardownPortalledContent() {
if(portalElement) {
canReflect_1_19_2_canReflect.offValue(elementObservable, getElementAndRender);
portalElement = null;
}
if(startPortalledPlaceholder && endPortalledPlaceholder) {
var parentNode = startPortalledPlaceholder.parentNode;
if(parentNode) {
helpers$2.range.remove({start: startPortalledPlaceholder, end: endPortalledPlaceholder});
canDomMutate_2_0_9_node.removeChild.call(parentNode, startPortalledPlaceholder );
canDomMutate_2_0_9_node.removeChild.call(parentNode, endPortalledPlaceholder );
startPortalledPlaceholder = endPortalledPlaceholder = null;
}
}
}
function teardownEverything(){
if(commentPlaceholderDispose) {
commentPlaceholderDispose();
}
teardownPortalledContent();
}
// The element has changed
function getElementAndRender() {
// remove the old rendered content and unbind if we've bound before
teardownPortalledContent();
canReflect_1_19_2_canReflect.onValue(elementObservable, getElementAndRender);
portalElement = canReflect_1_19_2_canReflect.getValue(elementObservable);
if(portalElement) {
startPortalledPlaceholder = portalElement.ownerDocument.createComment(debugName+" contents");
endPortalledPlaceholder = portalElement.ownerDocument.createComment("can-end-placeholder");
startPortalledPlaceholder[keepNodeSymbol] = true;
endPortalledPlaceholder[keepNodeSymbol] = true;
portalElement.appendChild(startPortalledPlaceholder);
portalElement.appendChild(endPortalledPlaceholder);
var observable = new canObservation_4_2_0_canObservation(portalContents, null, {isObservable: false});
canViewLive_5_0_5_canViewLive.html(startPortalledPlaceholder, observable);
} else {
options.metadata.rendered = true;
}
}
getElementAndRender();
return function(placeholderElement) {
var commentPlaceholder = placeholderElement.ownerDocument.createComment(debugName);
placeholderElement.parentNode.replaceChild(commentPlaceholder, placeholderElement);
commentPlaceholderDispose = canDomMutate_2_0_9_canDomMutate.onNodeRemoved(commentPlaceholder, teardownEverything);
return commentPlaceholder;
};
}
portalHelper.isLiveBound = true;
portalHelper.requiresOptionsArgument = true;
var Portal = portalHelper;
var debuggerHelper$1 = Debugger.helper;
var builtInHelpers = {};
var builtInConverters = {};
var converterPackages = new WeakMap();
// ## Helpers
var helpersCore = {
looksLikeOptions: function(options){
return options && typeof options.fn === "function" && typeof options.inverse === "function";
},
resolve: function(value) {
if (value && canReflect_1_19_2_canReflect.isValueLike(value)) {
return canReflect_1_19_2_canReflect.getValue(value);
} else {
return value;
}
},
resolveHash: function(hash){
var params = {};
for(var prop in hash) {
params[prop] = helpersCore.resolve(hash[prop]);
}
return params;
},
bindAndRead: function (value) {
if ( value && canReflect_1_19_2_canReflect.isValueLike(value) ) {
canObservation_4_2_0_canObservation.temporarilyBind(value);
return canReflect_1_19_2_canReflect.getValue(value);
} else {
return value;
}
},
registerHelper: function(name, callback){
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
if (canStacheHelpers_1_2_0_canStacheHelpers[name]) {
dev.warn('The helper ' + name + ' has already been registered.');
}
}
//!steal-remove-end
// mark passed in helper so it will be automatically passed
// helperOptions (.fn, .inverse, etc) when called as Call Expressions
callback.requiresOptionsArgument = true;
// store on global helpers list
canStacheHelpers_1_2_0_canStacheHelpers[name] = callback;
},
registerHelpers: function(helpers) {
var name, callback;
for(name in helpers) {
callback = helpers[name];
helpersCore.registerHelper(name, helpersCore.makeSimpleHelper(callback));
}
},
registerConverter: function(name, getterSetter) {
helpersCore.registerHelper(name, converter(getterSetter));
},
makeSimpleHelper: function(fn) {
return function() {
var realArgs = [];
canReflect_1_19_2_canReflect.eachIndex(arguments, function(val) {
realArgs.push(helpersCore.resolve(val));
});
return fn.apply(this, realArgs);
};
},
addHelper: function(name, callback) {
if(typeof name === "object") {
return helpersCore.registerHelpers(name);
}
return helpersCore.registerHelper(name, helpersCore.makeSimpleHelper(callback));
},
addConverter: function(name, getterSetter) {
if(typeof name === "object") {
if(!converterPackages.has(name)) {
converterPackages.set(name, true);
canReflect_1_19_2_canReflect.eachKey(name, function(getterSetter, name) {
helpersCore.addConverter(name, getterSetter);
});
}
return;
}
var helper = converter(getterSetter);
helper.isLiveBound = true;
helpersCore.registerHelper(name, helper);
},
// add helpers that set up their own internal live-binding
// these helpers will not be wrapped in computes and will
// receive observable arguments when called with Call Expressions
addLiveHelper: function(name, callback) {
callback.isLiveBound = true;
return helpersCore.registerHelper(name, callback);
},
getHelper: function(name, scope) {
var helper = scope && scope.getHelper(name);
if (!helper) {
helper = canStacheHelpers_1_2_0_canStacheHelpers[name];
}
return helper;
},
__resetHelpers: function() {
// remove all helpers from can-stache-helpers object
for (var helper in canStacheHelpers_1_2_0_canStacheHelpers) {
delete canStacheHelpers_1_2_0_canStacheHelpers[helper];
}
// Clear converterPackages map before re-adding converters
converterPackages.delete(builtInConverters);
helpersCore.addBuiltInHelpers();
helpersCore.addBuiltInConverters();
},
addBuiltInHelpers: function() {
canReflect_1_19_2_canReflect.each(builtInHelpers, function(helper, helperName) {
canStacheHelpers_1_2_0_canStacheHelpers[helperName] = helper;
});
},
addBuiltInConverters: function () {
helpersCore.addConverter(builtInConverters);
},
_makeLogicHelper: function(name, logic){
var logicHelper = canAssign_1_3_3_canAssign(function() {
var args = Array.prototype.slice.call(arguments, 0),
options;
if( helpersCore.looksLikeOptions(args[args.length - 1]) ){
options = args.pop();
}
function callLogic(){
// if there are options, we want to prevent re-rendering if values are still truthy
if(options) {
return logic(args) ? true: false;
} else {
return logic(args);
}
}
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
Object.defineProperty(callLogic, "name", {
value: name+"("+args.map(function(arg){
return canReflect_1_19_2_canReflect.getName(arg);
}).join(",")+")",
configurable: true
});
}
//!steal-remove-end
var callFn = new canObservation_4_2_0_canObservation(callLogic);
if(options) {
return callFn.get() ? options.fn() : options.inverse();
} else {
return callFn.get();
}
},{requiresOptionsArgument: true, isLiveBound: true});
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
Object.defineProperty(logicHelper, "name", {
value: name,
configurable: true
});
}
//!steal-remove-end
return logicHelper;
}
};
// ## IF HELPER
var ifHelper = canAssign_1_3_3_canAssign(function ifHelper(expr, options) {
var value;
// if it's a function, wrap its value in a compute
// that will only change values from true to false
if (expr && canReflect_1_19_2_canReflect.isValueLike(expr)) {
value = canReflect_1_19_2_canReflect.getValue(new truthyObservable(expr));
} else {
value = !! helpersCore.resolve(expr);
}
if (options) {
return value ? options.fn(options.scope || this) : options.inverse(options.scope || this);
}
return !!value;
}, {requiresOptionsArgument: true, isLiveBound: true});
//## EQ/IS HELPER
var isHelper = helpersCore._makeLogicHelper("eq", function eqHelper(args){
var curValue, lastValue;
for (var i = 0; i < args.length; i++) {
curValue = helpersCore.resolve(args[i]);
curValue = typeof curValue === "function" ? curValue() : curValue;
if (i > 0) {
if (curValue !== lastValue) {
return false;
}
}
lastValue = curValue;
}
return true;
});
var andHelper = helpersCore._makeLogicHelper("and", function andHelper(args){
if(args.length === 0 ) {
return false;
}
var last;
for (var i = 0, len = args.length; i < len; i++) {
last = helpersCore.resolve(args[i]);
if( !last ) {
return last;
}
}
return last;
});
var orHelper = helpersCore._makeLogicHelper("or", function orHelper(args){
if(args.length === 0 ) {
return false;
}
var last;
for (var i = 0, len = args.length; i < len; i++) {
last = helpersCore.resolve(args[i]);
if( last ) {
return last;
}
}
return last;
});
var switchHelper = function(expression, options){
helpersCore.resolve(expression);
var found = false;
var caseHelper = function(value, options) {
if(!found && helpersCore.resolve(expression) === helpersCore.resolve(value)) {
found = true;
return options.fn(options.scope);
}
};
caseHelper.requiresOptionsArgument = true;
// create default helper as a value-like function
// so that either {{#default}} or {{#default()}} will work
var defaultHelper = function(options) {
if (!found) {
return options ? options.scope.peek('this') : true;
}
};
defaultHelper.requiresOptionsArgument = true;
canReflect_1_19_2_canReflect.assignSymbols(defaultHelper, {
"can.isValueLike": true,
"can.isFunctionLike": false,
"can.getValue": function() {
// pass the helperOptions passed to {{#switch}}
return this(options);
}
});
var newScope = options.scope.add({
case: caseHelper,
default: defaultHelper
}, { notContext: true });
return options.fn(newScope, options);
};
switchHelper.requiresOptionsArgument = true;
// ## ODD HELPERS
var domDataHelper = function(attr, value) {
var data = (helpersCore.looksLikeOptions(value) ? value.context : value) || this;
return function setDomData(el) {
canDomData_1_0_3_canDomData.set( el, attr, data );
};
};
var joinBaseHelper = function(firstExpr/* , expr... */){
var args = [].slice.call(arguments);
var options = args.pop();
var moduleReference = args.map( function(expr){
var value = helpersCore.resolve(expr);
return typeof value === "function" ? value() : value;
}).join("");
var templateModule = canReflect_1_19_2_canReflect.getKeyValue(options.scope.templateContext.helpers, 'module');
var parentAddress = templateModule ? templateModule.uri: undefined;
var isRelative = moduleReference[0] === ".";
if(isRelative && parentAddress) {
return canJoinUris_1_2_0_canJoinUris(parentAddress, moduleReference);
} else {
var baseURL = (typeof System !== "undefined" &&
(System.renderingBaseURL || System.baseURL)) || baseUrl();
// Make sure one of them has a needed /
if(moduleReference[0] !== "/" && baseURL[baseURL.length - 1] !== "/") {
baseURL += "/";
}
return canJoinUris_1_2_0_canJoinUris(baseURL, moduleReference);
}
};
joinBaseHelper.requiresOptionsArgument = true;
// ## LEGACY HELPERS
// ### each
var eachHelper = function(items) {
var args = [].slice.call(arguments),
options = args.pop(),
hashExprs = options.exprData.hashExprs,
resolved = helpersCore.bindAndRead(items),
hashOptions,
aliases;
// Check if using hash
if (canReflect_1_19_2_canReflect.size(hashExprs) > 0) {
hashOptions = {};
canReflect_1_19_2_canReflect.eachKey(hashExprs, function (exprs, key) {
hashOptions[exprs.key] = key;
});
}
if ((
canReflect_1_19_2_canReflect.isObservableLike(resolved) && canReflect_1_19_2_canReflect.isListLike(resolved) ||
( canReflect_1_19_2_canReflect.isListLike(resolved) && canReflect_1_19_2_canReflect.isValueLike(items) )
) && !options.stringOnly) {
// Tells that a helper has been called, this function should be returned through
// checking its value.
options.metadata.rendered = true;
return function(el){
var cb = function (item, index) {
var aliases = {};
if (canReflect_1_19_2_canReflect.size(hashOptions) > 0) {
if (hashOptions.value) {
aliases[hashOptions.value] = item;
}
if (hashOptions.index) {
aliases[hashOptions.index] = index;
}
}
return options.fn(
options.scope
.add(aliases, { notContext: true })
.add({ index: index }, { special: true })
.add(item),
options.options
);
};
canViewLive_5_0_5_canViewLive.list(el, items, cb, options.context , function(list){
return options.inverse(options.scope.add(list), options.options);
});
};
}
var expr = helpersCore.resolve(items),
result;
if (!!expr && canReflect_1_19_2_canReflect.isListLike(expr)) {
result = utils$1.getItemsFragContent(expr, options, options.scope);
return options.stringOnly ? result.join('') : result;
} else if (canReflect_1_19_2_canReflect.isObservableLike(expr) && canReflect_1_19_2_canReflect.isMapLike(expr) || expr instanceof Object) {
result = [];
canReflect_1_19_2_canReflect.each(expr, function(val, key){
var value = new keyObservable(expr, key);
aliases = {};
if (canReflect_1_19_2_canReflect.size(hashOptions) > 0) {
if (hashOptions.value) {
aliases[hashOptions.value] = value;
}
if (hashOptions.key) {
aliases[hashOptions.key] = key;
}
}
result.push(options.fn(
options.scope
.add(aliases, { notContext: true })
.add({ key: key }, { special: true })
.add(value)
));
});
return options.stringOnly ? result.join('') : result;
}
};
eachHelper.isLiveBound = true;
eachHelper.requiresOptionsArgument = true;
eachHelper.ignoreArgLookup = function ignoreArgLookup(index) {
return index === 1;
};
// ### index
// This is legacy for `{{index(5)}}`
var indexHelper = canAssign_1_3_3_canAssign(function indexHelper(offset, options) {
if (!options) {
options = offset;
offset = 0;
}
var index = options.scope.peek("scope.index");
return ""+((typeof(index) === "function" ? index() : index) + offset);
}, {requiresOptionsArgument: true});
// ### WITH HELPER
var withHelper = function (expr, options) {
var ctx = expr;
if(!options) {
// hash-only case if no current context expression
options = expr;
expr = true;
ctx = options.hash;
} else {
expr = helpersCore.resolve(expr);
if(options.hash && canReflect_1_19_2_canReflect.size(options.hash) > 0) {
// presumably rare case of both a context object AND hash keys
// Leaving it undocumented for now, but no reason not to support it.
ctx = options.scope.add(options.hash, { notContext: true }).add(ctx);
}
}
return options.fn(ctx || {});
};
withHelper.requiresOptionsArgument = true;
// ### data helper
var dataHelper = function(attr, value) {
var data = (helpersCore.looksLikeOptions(value) ? value.context : value) || this;
return function setData(el) {
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
dev.warn('The {{data}} helper has been deprecated; use {{domData}} instead: https://canjs.com/doc/can-stache.helpers.domData.html');
}
//!steal-remove-end
canDomData_1_0_3_canDomData.set( el, attr, data );
};
};
// ## UNLESS HELPER
var unlessHelper = function (expr, options) {
if(!options) {
return !ifHelper.apply(this, [expr]);
}
return ifHelper.apply(this, [expr, canAssign_1_3_3_canAssign(canAssign_1_3_3_canAssign({}, options), {
fn: options.inverse,
inverse: options.fn
})]);
};
unlessHelper.requiresOptionsArgument = true;
unlessHelper.isLiveBound = true;
// ## Converters
// ## NOT converter
var notConverter = {
get: function(obs, options){
if(helpersCore.looksLikeOptions(options)) {
return canReflect_1_19_2_canReflect.getValue(obs) ? options.inverse() : options.fn();
} else {
return !canReflect_1_19_2_canReflect.getValue(obs);
}
},
set: function(newVal, obs){
canReflect_1_19_2_canReflect.setValue(obs, !newVal);
}
};
// ## Register as defaults
canAssign_1_3_3_canAssign(builtInHelpers, {
'debugger': debuggerHelper$1,
each: eachHelper,
eachOf: eachHelper,
index: indexHelper,
'if': ifHelper,
is: isHelper,
eq: isHelper,
unless: unlessHelper,
'with': withHelper,
console: console,
data: dataHelper,
domData: domDataHelper,
'switch': switchHelper,
joinBase: joinBaseHelper,
and: andHelper,
or: orHelper,
'let': Let,
'for': ForOf,
portal: Portal
});
canAssign_1_3_3_canAssign(builtInConverters, {
'not': notConverter
});
// add all the built-in helpers when stache is loaded
helpersCore.addBuiltInHelpers();
helpersCore.addBuiltInConverters();
var core$1 = helpersCore;
var mustacheLineBreakRegExp$1 = /(?:(^|\r?\n)(\s*)(\{\{([\s\S]*)\}\}\}?)([^\S\n\r]*)($|\r?\n))|(\{\{([\s\S]*)\}\}\}?)/g,
mustacheWhitespaceRegExp$1 = /(\s*)(\{\{\{?)(-?)([\s\S]*?)(-?)(\}\}\}?)(\s*)/g;
function splitModeFromExpression$1(expression, state){
expression = expression.trim();
var mode = expression.charAt(0);
if( "#/{&^>!<".indexOf(mode) >= 0 ) {
expression = expression.substr(1).trim();
} else {
mode = null;
}
// Triple braces do nothing within a tag.
if(mode === "{" && state.node) {
mode = null;
}
return {
mode: mode,
expression: expression
};
}
function cleanLineEndings(template) {
// Finds mustache tags with space around them or no space around them.
return template.replace( mustacheLineBreakRegExp$1,
function(whole,
returnBefore,
spaceBefore,
special,
expression,
spaceAfter,
returnAfter,
// A mustache magic tag that has no space around it.
spaceLessSpecial,
spaceLessExpression,
matchIndex){
// IE 8 will provide undefined
spaceAfter = (spaceAfter || "");
returnBefore = (returnBefore || "");
spaceBefore = (spaceBefore || "");
var modeAndExpression = splitModeFromExpression$1(expression || spaceLessExpression,{});
// If it's a partial or tripple stache, leave in place.
if(spaceLessSpecial || ">{".indexOf( modeAndExpression.mode) >= 0) {
return whole;
} else if( "^#!/".indexOf( modeAndExpression.mode ) >= 0 ) {
// Return the magic tag and a trailing linebreak if this did not
// start a new line and there was an end line.
// Add a normalized leading space, if there was any leading space, in case this abuts a tag name
spaceBefore = (returnBefore + spaceBefore) && " ";
return spaceBefore+special+( matchIndex !== 0 && returnAfter.length ? returnBefore+"\n" :"");
} else {
// There is no mode, return special with spaces around it.
return spaceBefore+special+spaceAfter+(spaceBefore.length || matchIndex !== 0 ? returnBefore+"\n" : "");
}
});
}
function whiteSpaceReplacement(
whole,
spaceBefore,
bracketBefore,
controlBefore,
expression,
controlAfter,
bracketAfter,
spaceAfter
) {
if (controlBefore === '-') {
spaceBefore = '';
}
if (controlAfter === '-') {
spaceAfter = '';
}
return spaceBefore + bracketBefore + expression + bracketAfter + spaceAfter;
}
function cleanWhitespaceControl(template) {
return template.replace(mustacheWhitespaceRegExp$1, whiteSpaceReplacement);
}
var cleanLineEndings_1 = cleanLineEndings;
var cleanWhitespaceControl_1 = cleanWhitespaceControl;
var canStacheAst_1_1_0_controls = {
cleanLineEndings: cleanLineEndings_1,
cleanWhitespaceControl: cleanWhitespaceControl_1
};
var parse = function(filename, source){
if (arguments.length === 1) {
source = arguments[0];
filename = undefined;
}
var template = source;
template = canStacheAst_1_1_0_controls.cleanWhitespaceControl(template);
template = canStacheAst_1_1_0_controls.cleanLineEndings(template);
var imports = [],
dynamicImports = [],
importDeclarations = [],
ases = {},
attributes = new Map(),
inImport = false,
inFrom = false,
inAs = false,
isUnary = false,
importIsDynamic = false,
currentAs = "",
currentFrom = "",
currentAttrName = null;
function processImport(line) {
if(currentAs) {
ases[currentAs] = currentFrom;
currentAs = "";
}
if(importIsDynamic) {
dynamicImports.push(currentFrom);
} else {
imports.push(currentFrom);
}
importDeclarations.push({
specifier: currentFrom,
loc: {
line: line
},
attributes: attributes
});
// Reset this scope value so that the next import gets new attributes.
attributes = new Map();
}
var program = canViewParser_4_1_3_canViewParser(template, {
filename: filename,
start: function( tagName, unary ){
if(tagName === "can-import") {
isUnary = unary;
importIsDynamic = false; // assume static import unless there is content (chars/tags/special).
inImport = true;
} else if(tagName === "can-dynamic-import") {
isUnary = unary;
importIsDynamic = true;
inImport = true;
} else if(inImport) {
importIsDynamic = true; // found content inside can-import tag.
inImport = false;
}
},
attrStart: function( attrName ){
currentAttrName = attrName;
// Default to a boolean attribute, the attrValue hook will replace that.
attributes.set(currentAttrName, true);
if(attrName === "from") {
inFrom = true;
} else if(attrName === "as" || attrName === "export-as") {
inAs = true;
}
},
attrEnd: function( attrName ){
if(attrName === "from") {
inFrom = false;
} else if(attrName === "as" || attrName === "export-as") {
inAs = false;
}
},
attrValue: function( value ){
if(inImport) {
attributes.set(currentAttrName, value);
}
if(inFrom && inImport) {
currentFrom = value;
} else if(inAs && inImport) {
currentAs = value;
}
},
end: function(tagName, unary, line){
if((tagName === "can-import" || tagName === "can-dynamic-import") && isUnary) {
processImport(line);
}
},
close: function(tagName, unary, line){
if((tagName === "can-import" || tagName === "can-dynamic-import")) {
processImport(line);
}
},
chars: function(text) {
if(text.trim().length > 0) {
importIsDynamic = true;
}
},
special: function() {
importIsDynamic = true;
}
}, true);
return {
intermediate: program,
program: program,
imports: imports,
dynamicImports: dynamicImports,
importDeclarations: importDeclarations,
ases: ases,
exports: ases
};
};
var canStacheAst_1_1_0_canStacheAst = {
parse: parse
};
var global$2 = global_1();
var stealOptimized = function(moduleName, parentName){
if (typeof global$2.stealRequire !== "undefined") {
return steal.import(moduleName, { name: parentName });
}
};
var global$3 = global_1();
function isFunction$1(fn) {
return typeof fn === "function";
}
// since stealJS uses a SystemJS fork and SystemJS is exposed globally we can use this loader for SystemJS or stealJS
var system = function(moduleName, parentName) {
if(typeof global$3.System === "object" && isFunction$1(global$3.System["import"])) {
return global$3.System["import"](moduleName, {
name: parentName
});
}
};
var es6 = createCommonjsModule(function (module) {
// check for `noModule` in HTMLScriptElement. if its present, then the browser can handle dynamic loading because if
// HTMLScriptElement.noModule is `true` the browser used to run fallback scripts in older browsers that do not support JavaScript modules
if ("HTMLScriptElement" in global_1() && "noModule" in HTMLScriptElement.prototype) {
// "import()" is a syntax error on some platforms and will cause issues if this module is bundled
// into a larger script bundle, so only eval it to code if the platform is known to support it.
module.exports = new Function(
"moduleName",
// if moduleName has no extension, treat it as a javascript file and add .js extension
"if (!(moduleName.match(/[^\\\\\\/]\\.([^.\\\\\\/]+)$/) || [null]).pop()) {\n" +
"moduleName += '.js';\n" +
"}\n" +
"return import(moduleName.replace(/['\"]+/g, ''));\n"
);
} else {
module.exports = function() {};
}
});
var node$1 = function(moduleName) {
if (isNode()) {
return Promise.resolve(commonjsRequire(moduleName));
}
};
var global$4 = global_1();
// AMD loader
var require = function(moduleName){
if(global$4.define && global$4.define.amd){
return new Promise(function(resolve, reject) {
global$4.require([moduleName], function(value){
resolve(value);
});
});
}
};
/**
* @module {function} can-util/js/import/import import
* @parent can-util/js
* @signature `importModule(moduleName, parentName)`
* @hide
*
* ```js
* var importModule = require("can-util/js/import/import");
*
* importModule("foo.stache").then(function(){
* // module was imported
* });
* ```
*
* @param {String} moduleName The module to be imported.
* @param {String} [parentName] A parent module that will be used as a reference for resolving relative module imports.
* @return {Promise} A Promise that will resolve when the module has been imported.
*/
// array of loader functions, last in first out
var loader = [];
/**
* add a loader-function to the list of loader
* the function should return a promise that resolves when the module has been loaded
* otherwise the loader function should return null or undefined
*
* @signature `import.addLoader(loader)`
* @param fn callable
*/
function addLoader(fn){
if(typeof fn === "function"){
loader.push(fn);
}
}
/**
* clear the list of loaders
*/
function flushLoader(){
loader = [];
}
/**
* a bunch of presets that can be used in a certain environment
*
* @param preset string
*/
function preset(preset){
flushLoader();
switch (preset){
case "stealjs":
addLoader(stealOptimized);
addLoader(system);
break;
case "ES2020":
case "es2020":
case "dynamic-import":
addLoader(es6);
break;
case "node":
addLoader(node$1);
break;
case "all":
default:
addLoader(stealOptimized);
addLoader(es6);
addLoader(node$1);
addLoader(require);
addLoader(system);
break;
}
}
// by default, add all available loaders to the list
preset('all');
var canImportModule_1_3_2_canImportModule = canNamespace_1_0_0_canNamespace.import = function(moduleName, parentName) {
return new Promise(function(resolve, reject) {
try {
var loaderPromise;
// last added loader will be called first
for (var i = loader.length - 1; i >= 0; i--) {
loaderPromise = loader[i](moduleName, parentName);
if (loaderPromise) {
break;
}
}
if(loaderPromise){
loaderPromise.then(resolve, reject);
}else{
reject("no proper module-loader available");
}
} catch(err) {
reject(err);
}
});
};
var addLoader_1 = addLoader;
var flushLoader_1 = flushLoader;
var preset_1 = preset;
canImportModule_1_3_2_canImportModule.addLoader = addLoader_1;
canImportModule_1_3_2_canImportModule.flushLoader = flushLoader_1;
canImportModule_1_3_2_canImportModule.preset = preset_1;
/* jshint undef: false */
var getIntermediateAndImports = canStacheAst_1_1_0_canStacheAst.parse;
var makeRendererConvertScopes = utils$1.makeRendererConvertScopes;
var last$2 = utils$1.last;
// Make sure that we can also use our modules with Stache as a plugin
if(!canViewCallbacks_5_0_0_canViewCallbacks.tag("content")) {
// This was moved from the legacy view/scanner.js to here.
// This makes sure content elements will be able to have a callback.
canViewCallbacks_5_0_0_canViewCallbacks.tag("content", function(el, tagData) {
return tagData.scope;
});
}
var isViewSymbol$2 = canSymbol_1_7_0_canSymbol.for("can.isView");
var wrappedAttrPattern = /[{(].*[)}]/;
var colonWrappedAttrPattern = /^on:|(:to|:from|:bind)$|.*:to:on:.*/;
var svgNamespace = "http://www.w3.org/2000/svg",
xmlnsAttrNamespaceURI$1 = "http://www.w3.org/2000/xmlns/",
xlinkHrefAttrNamespaceURI$1 = "http://www.w3.org/1999/xlink";
var namespaces = {
"svg": svgNamespace,
// this allows a partial to start with g.
"g": svgNamespace,
"defs": svgNamespace,
"path": svgNamespace,
"filter": svgNamespace,
"feMorphology": svgNamespace,
"feGaussianBlur": svgNamespace,
"feOffset": svgNamespace,
"feComposite": svgNamespace,
"feColorMatrix": svgNamespace,
"use": svgNamespace
},
attrsNamespacesURI$1 = {
'xmlns': xmlnsAttrNamespaceURI$1,
'xlink:href': xlinkHrefAttrNamespaceURI$1
},
textContentOnlyTag = {style: true, script: true};
function stache (filename, template) {
if (arguments.length === 1) {
template = arguments[0];
filename = undefined;
}
var inlinePartials = {};
// Remove line breaks according to mustache's specs.
if(typeof template === "string") {
template = mustache_core.cleanWhitespaceControl(template);
template = mustache_core.cleanLineEndings(template);
}
// The HTML section that is the root section for the entire template.
var section = new html_section(filename),
// Tracks the state of the parser.
state = {
node: null,
attr: null,
// A stack of which node / section we are in.
// There is probably a better way of doing this.
sectionElementStack: [],
// If text should be inserted and HTML escaped
text: false,
// which namespace we are in
namespaceStack: [],
// for style and script tags
// we create a special TextSectionBuilder and add things to that
// when the element is done, we compile the text section and
// add it as a callback to `section`.
textContentOnly: null
},
// This function is a catch all for taking a section and figuring out
// how to create a "renderer" that handles the functionality for a
// given section and modify the section to use that renderer.
// For example, if an HTMLSection is passed with mode `#` it knows to
// create a liveBindingBranchRenderer and pass that to section.add.
// jshint maxdepth:5
makeRendererAndUpdateSection = function(section, mode, stache, lineNo){
if(mode === ">") {
// Partials use liveBindingPartialRenderers
section.add(mustache_core.makeLiveBindingPartialRenderer(stache, copyState({ filename: section.filename, lineNo: lineNo })));
} else if(mode === "/") {
var createdSection = section.last();
if ( createdSection.startedWith === "<" ) {
inlinePartials[ stache ] = section.endSubSectionAndReturnRenderer();
// Remove *TWO* nodes because we now have a start and an end comment for the section....
section.removeCurrentNode();
section.removeCurrentNode();
} else {
section.endSection();
}
// to avoid "Blocks are nested too deeply" when linting
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
if(section instanceof html_section) {
var last = state.sectionElementStack[state.sectionElementStack.length - 1];
if (last.tag && last.type === "section" && stache !== "" && stache !== last.tag) {
if (filename) {
dev.warn(filename + ":" + lineNo + ": unexpected closing tag {{/" + stache + "}} expected {{/" + last.tag + "}}");
}
else {
dev.warn(lineNo + ": unexpected closing tag {{/" + stache + "}} expected {{/" + last.tag + "}}");
}
}
}
}
//!steal-remove-end
if(section instanceof html_section) {
state.sectionElementStack.pop();
}
} else if(mode === "else") {
section.inverse();
} else {
// If we are an HTMLSection, we will generate a
// a LiveBindingBranchRenderer; otherwise, a StringBranchRenderer.
// A LiveBindingBranchRenderer function processes
// the mustache text, and sets up live binding if an observable is read.
// A StringBranchRenderer function processes the mustache text and returns a
// text value.
var makeRenderer = section instanceof html_section ?
mustache_core.makeLiveBindingBranchRenderer:
mustache_core.makeStringBranchRenderer;
if(mode === "{" || mode === "&") {
// Adds a renderer function that just reads a value or calls a helper.
section.add(makeRenderer(null,stache, copyState({ filename: section.filename, lineNo: lineNo })));
} else if(mode === "#" || mode === "^" || mode === "<") {
// Adds a renderer function and starts a section.
var renderer = makeRenderer(mode, stache, copyState({ filename: section.filename, lineNo: lineNo }));
var sectionItem = {
type: "section"
};
section.startSection(renderer, stache);
section.last().startedWith = mode;
// If we are a directly nested section, count how many we are within
if(section instanceof html_section) {
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
var tag = typeof renderer.exprData.closingTag === 'function' ?
renderer.exprData.closingTag() : stache;
sectionItem.tag = tag;
}
//!steal-remove-end
state.sectionElementStack.push(sectionItem);
}
} else {
// Adds a renderer function that only updates text.
section.add(makeRenderer(null, stache, copyState({text: true, filename: section.filename, lineNo: lineNo })));
}
}
},
isDirectlyNested = function() {
var lastElement = state.sectionElementStack[state.sectionElementStack.length - 1];
return state.sectionElementStack.length ?
lastElement.type === "section" || lastElement.type === "custom": true;
},
// Copys the state object for use in renderers.
copyState = function(overwrites){
var cur = {
tag: state.node && state.node.tag,
attr: state.attr && state.attr.name,
// elements should be considered direclty nested
directlyNested: isDirectlyNested(),
textContentOnly: !!state.textContentOnly
};
return overwrites ? canAssign_1_3_3_canAssign(cur, overwrites) : cur;
},
addAttributesCallback = function(node, callback){
if( !node.attributes ) {
node.attributes = [];
}
node.attributes.unshift(callback);
};
canViewParser_4_1_3_canViewParser(template, {
filename: filename,
start: function(tagName, unary, lineNo){
var matchedNamespace = namespaces[tagName];
if (matchedNamespace && !unary ) {
state.namespaceStack.push(matchedNamespace);
}
// either add templates: {} here or check below and decorate
// walk up the stack/targetStack until you find the first node
// with a templates property, and add the popped renderer
state.node = {
tag: tagName,
children: [],
namespace: matchedNamespace || last$2(state.namespaceStack)
};
},
end: function(tagName, unary, lineNo){
var isCustomTag = canViewCallbacks_5_0_0_canViewCallbacks.tag(tagName);
var directlyNested = isDirectlyNested();
if(unary){
// If it's a custom tag with content, we need a section renderer.
section.add(state.node);
if(isCustomTag) {
// Call directlyNested now as it's stateful.
addAttributesCallback(state.node, function(scope){
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
scope.set('scope.lineNumber', lineNo);
}
//!steal-remove-end
canViewCallbacks_5_0_0_canViewCallbacks.tagHandler(this,tagName, {
scope: scope,
subtemplate: null,
templateType: "stache",
directlyNested: directlyNested
});
});
}
} else {
section.push(state.node);
state.sectionElementStack.push({
type: isCustomTag ? "custom" : null,
tag: isCustomTag ? null : tagName,
templates: {},
directlyNested: directlyNested
});
// If it's a custom tag with content, we need a section renderer.
if( isCustomTag ) {
section.startSubSection();
} else if(textContentOnlyTag[tagName]) {
state.textContentOnly = new text_section(filename);
}
}
state.node =null;
},
close: function(tagName, lineNo) {
var matchedNamespace = namespaces[tagName];
if (matchedNamespace ) {
state.namespaceStack.pop();
}
var isCustomTag = canViewCallbacks_5_0_0_canViewCallbacks.tag(tagName),
renderer;
if( isCustomTag ) {
renderer = section.endSubSectionAndReturnRenderer();
}
if(textContentOnlyTag[tagName]) {
section.last().add(state.textContentOnly.compile(copyState()));
state.textContentOnly = null;
}
var oldNode = section.pop();
if( isCustomTag ) {
if (tagName === "can-template") {
// If we find a can-template we want to go back 2 in the stack to get it's inner content
// rather than the element itself
var parent = state.sectionElementStack[state.sectionElementStack.length - 2];
if (renderer) {// Only add the renderer if the template has content
parent.templates[oldNode.attrs.name] = makeRendererConvertScopes(renderer);
}
section.removeCurrentNode();
} else {
// Get the last element in the stack
var current = state.sectionElementStack[state.sectionElementStack.length - 1];
addAttributesCallback(oldNode, function(scope){
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
scope.set('scope.lineNumber', lineNo);
}
//!steal-remove-end
canViewCallbacks_5_0_0_canViewCallbacks.tagHandler(this,tagName, {
scope: scope,
subtemplate: renderer ? makeRendererConvertScopes(renderer) : renderer,
templateType: "stache",
templates: current.templates,
directlyNested: current.directlyNested
});
});
}
}
state.sectionElementStack.pop();
},
attrStart: function(attrName, lineNo){
if(state.node.section) {
state.node.section.add(attrName+"=\"");
} else {
state.attr = {
name: attrName,
value: ""
};
}
},
attrEnd: function(attrName, lineNo){
var matchedAttrNamespacesURI = attrsNamespacesURI$1[attrName];
if(state.node.section) {
state.node.section.add("\" ");
} else {
if(!state.node.attrs) {
state.node.attrs = {};
}
if (state.attr.section) {
state.node.attrs[state.attr.name] = state.attr.section.compile(copyState());
} else if (matchedAttrNamespacesURI) {
state.node.attrs[state.attr.name] = {
value: state.attr.value,
namespaceURI: attrsNamespacesURI$1[attrName]
};
} else {
state.node.attrs[state.attr.name] = state.attr.value;
}
var attrCallback = canViewCallbacks_5_0_0_canViewCallbacks.attr(attrName);
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
var decodedAttrName = canAttributeEncoder_1_1_4_canAttributeEncoder.decode(attrName);
var weirdAttribute = !!wrappedAttrPattern.test(decodedAttrName) || !!colonWrappedAttrPattern.test(decodedAttrName);
if (weirdAttribute && !attrCallback) {
dev.warn("unknown attribute binding " + decodedAttrName + ". Is can-stache-bindings imported?");
}
}
//!steal-remove-end
if(attrCallback) {
if( !state.node.attributes ) {
state.node.attributes = [];
}
state.node.attributes.push(function(scope){
//!steal-remove-start
if (process.env.NODE_ENV !== 'production') {
scope.set('scope.lineNumber', lineNo);
}
//!steal-remove-end
attrCallback(this,{
attributeName: attrName,
scope: scope
});
});
}
state.attr = null;
}
},
attrValue: function(value, lineNo){
var section = state.node.section || state.attr.section;
if(section){
section.add(value);
} else {
state.attr.value += value;
}
},
chars: function(text, lineNo) {
(state.textContentOnly || section).add(text);
},
special: function(text, lineNo){
var firstAndText = mustache_core.splitModeFromExpression(text, state),
mode = firstAndText.mode,
expression = firstAndText.expression;
if(expression === "else") {
var inverseSection;
if(state.attr && state.attr.section) {
inverseSection = state.attr.section;
} else if(state.node && state.node.section ) {
inverseSection = state.node.section;
} else {
inverseSection = state.textContentOnly || section;
}
inverseSection.inverse();
return;
}
if(mode === "!") {
return;
}
if(state.node && state.node.section) {
makeRendererAndUpdateSection(state.node.section, mode, expression, lineNo);
if(state.node.section.subSectionDepth() === 0){
state.node.attributes.push( state.node.section.compile(copyState()) );
delete state.node.section;
}
}
// `{{}}` in an attribute like `class="{{}}"`
else if(state.attr) {
if(!state.attr.section) {
state.attr.section = new text_section(filename);
if(state.attr.value) {
state.attr.section.add(state.attr.value);
}
}
makeRendererAndUpdateSection(state.attr.section, mode, expression, lineNo);
}
// `{{}}` in a tag like `