/**
* The `proact-core` module provides base utilties and common functionality for all the other
* modules of the lib.
*
* @module proact-core
* @main proact-core
*/
/**
* ProAct.js turns plain JavaScript objects into holders of reactive properties.
* You can define the dependencies between these objects and properties using the 'vanilla' js syntax.
* For example if an object should have a property 'x', that depends on its two fields 'a' and 'b', the only thing that's needed
* is to define a function 'x', that refers to 'this.a' and 'this.b'.
*
* So ProAct.js can turn every vanilla JavaScript value to a set of reactive properties, and this generates a dependency graph between them.
* The data flow in this oriented graph is determined by its edges. So if we should receive data from the outside of this dependency system we'll need
* a powerful but easy to use tool to turn every user or server generated action into a data event, common to the graph.
*
* ProAct.js can be used to define bindings, to separate views from models (mv*), for performance optimizations... It is a tool.
* A powerful tool for creating other, high level tools, or applications.
* Everything should be defined in this namespace. It can be used as P or Pro.
*
* ProAct is powerful Functional Reactive Programming (FRP) lib too. Its streams and events
*
* are integrated with the reactive properties mentioned above.
* Everything can be described using declarative expressions.
* All ProAct classes and functions are defined in this namespace.
* You can use `Pro` and `P` instead of `ProAct` too.
*
* @class ProAct
* @static
*/
var ProAct = Pro = P = {},
arrayProto = Array.prototype,
concat = arrayProto.concat,
every = arrayProto.every,
filter = arrayProto.filter,
forEach = arrayProto.forEach,
indexOf = arrayProto.indexOf,
join = arrayProto.join,
lastIndexOf = arrayProto.lastIndexOf,
map = arrayProto.map,
pop = arrayProto.pop,
push = arrayProto.push,
reduce = arrayProto.reduce,
reduceRight = arrayProto.reduceRight,
reverse = arrayProto.reverse,
shift = arrayProto.shift,
slice = arrayProto.slice,
some = arrayProto.some,
sort = arrayProto.sort,
splice = arrayProto.splice,
toLocaleString = arrayProto.toLocaleString,
toString = arrayProto.toString,
unshift = arrayProto.unshift,
pArray, pArrayOps, pArrayProto, pArrayLs,
rProto,
dsl, dslOps,
opStoreAll,
streamProvider, functionProvider,
attachers, attacherKeys,
ActorUtil;
/**
* @property VERSION
* @type String
* @static
* @for ProAct
*/
ProAct.VERSION = '1.3.1';
/**
* Defines the possible states of the {{#crossLink "ProAct.Actor"}}{{/crossLink}} instances.
*
* @class States
* @namespace ProAct
* @static
*/
ProAct.States = {
/**
* Initialized : It is not usable yet.
*
* For example a computed property (property depending on other properties/actors) is
* in `init` state when it's created and not read yet.
* When something reads its value it computes it for the the first time and becomes in `ready`
* state.
*
* @property init
* @type Number
* @final
* @for ProAct.States
*/
init: 1,
/**
* Ready for use.
*
* Active {{#crossLink "ProAct.Actor"}}Actors{{/crossLink}} have this state. It can be listened to, it
* can be updated and notify all of its dependencies.
*
* @property ready
* @type Number
* @final
* @for ProAct.States
*/
ready: 2,
/**
* Ended it's lifecycle.
*
* Every {{#crossLink "ProAct.Actor"}}{{/crossLink}} can be `destroyed`. All the resources it uses are freed.
* All the dependent objects don't depend on it anymore.
*
* For example if an application has states/routing, {{#crossLink "ProAct.Actor"}}Actors{{/crossLink}} that were active in one
* of the states should be `destroyed` before going into other route/state.
*
* @property destroyed
* @type Number
* @final
* @for ProAct.States
*/
destroyed: 3,
/**
* Error has occured in the {{#crossLink "ProAct.Actor"}}{{/crossLink}}'s lifecycle.
*
* For example, if there was an exception in the object's initialization.
*
* @property error
* @type Number
* @final
* @for ProAct.States
*/
error: 4,
/**
* A closed ProAct object.
*
* For example Streams that can emmit events anymore are closed streams.
*
* Properties which value can not be updated are closed (constants).
*
* @property closed
* @type Number
* @final
* @for ProAct.States
*/
closed: 5
};
/**
* Contains a set of utility functions to ease working with arrays and objects.
* Can be reffered by using `ProAct.U` too.
*
* This class is part of the `proact-core` module of ProAct.js.
*
* @namespace ProAct
* @class Utils
* @static
*/
ProAct.Utils = Pro.U = {
/**
* Generates an universally unique identifier.
*
* @method uuid
* @return {String} Unique string.
*/
uuid: function () {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0,
v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
},
/**
* Checks if the passed value is a Function or not.
*
* @method isFunction
* @param {Object} value The object/value to check.
* @return {Boolean} True if the passed value is a Function.
*/
isFunction: function (value) {
return typeof(value) === 'function';
},
/**
* Checks if the passed value is a String instance or not.
*
* @method isString
* @param {Object} value The object/value to check.
* @return {Boolean} True if the passed value is a String.
*/
isString: function (value) {
return typeof(value) === 'string';
},
/**
* Checks if the passed value is a JavaScript object or not.
*
* @method isObject
* @param {Object} value The value to check.
* @return {Boolean} True if the passed values is not primitive.
*/
isObject: function (value) {
return typeof(value) === 'object';
},
/**
* Checks if the passed value is {} or not.
*
* @method isEmptyObject
* @param {Object} value The value to check.
* @return {Boolean} True if the value is object that has no own fields.
*/
isEmptyObject: function (value) {
var property;
for (property in value) {
if (value.hasOwnProperty(property)) {
return false;
}
}
return true;
},
/**
* Checks if the passed value is a valid JavaScript Error instance or not.
*
* @method isError
* @param {Object} value The value to check.
* @return {Boolean} True if the passed `value` is instance of an Error.
*/
isError: function (value) {
return value !== null && value instanceof Error;
},
/**
* Checks if the passed value is a valid JavaScript Array instance or not.
*
* @method isArray
* @param {Object} value The value to check.
* @return {Boolean} True if the passed `value` is Array.
*/
isArray: function (value) {
return P.U.isObject(value) && Object.prototype.toString.call(value) === '[object Array]';
},
/**
* Clones the passed object. It creates a deep copy of it.
* For now it clones only arrays.
*
* TODO It is not fully implemented...
*
* @method clone
* @beta
* @param {Object} obj The object to clone.
* @return {Object} Clone of the passed object.
*/
clone: function (obj) {
if (P.U.isArray(obj)) {
var i, ln = obj.length, copy = [];
for (i = 0; i < ln; i++) {
copy.push(P.U.clone(obj[i]));
}
return copy;
}
return obj;
},
/**
* Extends the destination object with the properties and methods of the source object.
*
* ```
* var obj1 = {a: 3};
* var obj2 = {b: 4;}
* ProAct.Utils.ex(obj2, obj1);
*
* console.log(obj2);
* // This prints : {a: 3, b: 4}
*
* ```
*
* @method ex
* @param {Object} destination The object to be extended - it will be modified.
* @param {Object} source The source holding the properties and the functions to extend destination with.
* @return {Object} The changed destination object.
*/
ex: function(destination, source) {
var p;
for (p in source) {
if (source.hasOwnProperty(p)) {
destination[p] = P.U.clone(source[p]);
}
}
return destination;
},
/**
* Used for extending of classes.
* Example is:
* ```
*
* var Bar = ProAct.Utils.extendClass.call(Foo, {
* a: 1,
* b: 2,
* c: function () {}
* });
*
* ```
*
* @method extendClass
* @param {Object} data Data to add new properties to the new class or override old ones.
* @return {Object} Child class.
*/
extendClass: function (data) {
var parent = this,
child = function () {
parent.apply(this, slice.call(arguments));
};
P.U.ex(child, parent);
child.initData = {};
P.U.ex(child.initData, parent.initData);
P.U.ex(child.prototype, parent.prototype);
P.U.ex(child.initData, data);
child.uuid = P.U.uuid();
child.prototype.constructor = child;
return child;
},
/**
* Binds a `function` to an `object context`.
*
* Every time the `function` is called, `this` will point to the passed `object`.
*
* ```
*
* var context = {a: 3};
* var f = ProAct.Utils.bind(context, function () {
* return this;
* });
*
* var result = f();
* console.log(result === context); // prints 'true'
*
* ```
*
* @method bind
* @param {Object} ctx The `context` to bind the `this` of the function to.
* @param {Function} func The `function` to bind.
* @return {Function} The bound `function`.
*/
bind: function (ctx, func) {
return function () {
return func.apply(ctx, arguments);
};
},
/**
* Removes the first appearance of the passed `value` in the passed `array`.
* If the `value` is not present in the passed `array` does nothing.
*
* ```
*
* var array = [1, 2, 3];
* ProAct.Utils.remove(array, 2);
*
* console.log(array); // prints [1, 3]
*
* ```
*
* @method remove
* @param {Array} array The `array` to remove from.
* @param {Object} value The `value` to be removed.
*/
remove: function (array, value) {
var i = array.indexOf(value);
if (i > -1) {
array.splice(i, 1);
}
},
/**
* A powerful function that creates a diff object containing the differences between two arrays.
*
* @method diff
* @param {Array} array1
* @param {Array} array2
* @return {Object}
* <p>The object returned contains a property for every index there is a difference between the passed arrays.</p>
* <p>The object set on the index has two array properties : 'o' and 'n'.</p>
* <p>The 'o' property represents the owned elemetns of the first array that are different from the other's.</p>
* <p>The 'n' property contains all the elements that are not owned by the first array, but present in the other.</p>
* <p>Example:</p>
* ```
* var array1 = [1, 3, 4, 5],
* array2 = [1, 2, 7, 5, 6]
* diff;
*
* diff = ProAct.Utils.diff(array1, array2);
*
* console.log(diff[0]); // undefined - the arrays are the same at he index 0
* console.log(diff[1]); // {o: [3, 4], n: [2, 7]}
* console.log(diff[2]); // undefined the change began from index 1, so it is stored there
* console.log(diff[3]); // undefined - the arrays are the same at index 3
* console.log(diff[4]); // {o: [], n: [6]}
* ```
*/
diff: function (array1, array2) {
var i, e1, e2,
index = -1,
l1 = array1.length,
l2 = array2.length,
diff = {};
if (l1 >= l2) {
for (i = 0; i < l2; i++) {
e1 = array1[i];
e2 = array2[i];
if (e1 !== e2) {
if (index === -1) {
index = i;
}
diff[index] = diff[index] || {o: [], n: []};
diff[index].o.push(e1);
diff[index].n.push(e2);
} else {
index = -1;
}
}
if (index === -1) {
index = i;
}
diff[index] = diff[index] || {o: [], n: []};
for (; i < l1; i++) {
e1 = array1[i];
diff[index].o.push(e1);
}
} else {
diff = P.U.diff(array2, array1);
for (i in diff) {
el1 = diff[i];
el2 = el1.n;
el1.n = el1.o;
el1.o = el2;
}
}
return diff;
},
/**
* Defines a property to an object that contains a initial value.
*
* The property can be configured using the arguments passed if it is possible in the javascript implementation.
*
* @method defValProp
* @param {Object} obj The object to define a property in.
* @param {String} prop The name of the property to define.
* @param {Boolean} enumerable If the property should be enumerable.<br /> In other words visible when doing <pre>for (p in obj) {}</pre>
* @param {Boolean} configurable If the property should be configurable.<br /> In other words if the parameters of the property for example enumerable or writable can be changed in the future.
* @param {Boolean} writable If the property can be changed.
* @param {Object} val The initial value of the property.
*/
defValProp: function (obj, prop, enumerable, configurable, writable, val) {
try {
Object.defineProperty(obj, prop, {
enumerable: enumerable,
configurable: configurable,
writable: writable,
value: val
});
} catch (e) {
obj[prop] = val;
}
}
};
/**
* Contains various configuration settings for the ProAct.js library.
*
* @namespace ProAct
* @class Configuration
* @static
*/
ProAct.Configuration = {
/**
* If this option is set to true, when a ProAct.js object is created and has properties named
* as one or more of the properties listed in
* {{#crossLink "ProAct.Configuration.keypropList"}}{{/crossLink}} an `Error` will be thrown.
*
* In other words declares some of the properties of every ProAct objects as keyword properties.
*
* @property keyprops
* @type Boolean
* @static
* @for ProAct.Configuration
*/
keyprops: true,
/**
* Defines a list of the keyword properties that can not be used in ProAct.js objects.
* The {{#crossLink "ProAct.Configuration.keyprops"}}{{/crossLink}} option must be set to true in order for this list to be used.
*
* @property keypropList
* @type Array
* @static
* @for ProAct.Configuration
*/
keypropList: ['p']
};
/**
* No-action or emtpy function. Represent an action that does nothing.
*
* @method N
* @for ProAct
*/
ProAct.N = function () {};