/**
* @module proact-arrays
*/
/**
* Creates a wrapper around a plain JavaScript array that is capable of tracking changes on the array and notifying listeners.
* <p>
* It has a {{#crossLink "ProAct.ArrayCore"}}{{/crossLink}} which it uses to observe the array for changes or to update the array on changes.
* </p>
* <p>
* `ProAct.Array` is array-like object, it has all the methods defined in the JavaScript Array class, length property and indices.
* </p>
* <p>
* `ProAct.Array` is part of the `proact-arrays` module of ProAct.js.
* </p>
*
* @class ProAct.Array
* @constructor
* @extends Array
* @param [...]
* I can take an array as a parameter and it becomes reactive wrapper around it.
* It can take a list of arguments which become the wrapped array.
* If nothing is passed it becomes wrapper arround an empty array.
*/
ProAct.Array = P.A = pArray = function () {
var self = this,
getLength, setLength, oldLength,
arr, core;
// Setup _array:
if (arguments.length === 0) {
arr = [];
} else if (arguments.length === 1 && P.U.isArray(arguments[0])) {
arr = arguments[0];
} else {
arr = slice.call(arguments);
}
P.U.defValProp(this, '_array', false, false, true, arr);
// Setup core:
core = new P.AC(this);
P.U.defValProp(this, '__pro__', false, false, false, core);
P.U.defValProp(this, 'core', false, false, false, core);
core.prob();
};
P.U.ex(P.A, {
/**
* Defines a set of the possible operations over an array.
*
* @class Operations
* @namespace ProAct.Array
* @static
*/
Operations: {
/**
* Represents setting a value to an index of an array.
* <pre>
* array[3] = 12;
* </pre>
*
* @property set
* @type Number
* @final
* @for ProAct.Array.Operations
*/
set: 0,
/**
* Represents adding values to array.
* <pre>
* array.push(12);
* array.unshift(12);
* </pre>
*
* @property add
* @type Number
* @final
* @for ProAct.Array.Operations
*/
add: 1,
/**
* Represents removing values from array.
* <pre>
* array.pop();
* array.shift();
* </pre>
*
* @property remove
* @type Number
* @final
* @for ProAct.Array.Operations
*/
remove: 2,
/**
* Represents setting the length of an array.
* <pre>
* array.length = 5;
* </pre>
*
* @property setLength
* @type Number
* @final
* @for ProAct.Array.Operations
*/
setLength: 3,
/**
* Represents reversing the element order in an array.
* <pre>
* array.reverse();
* </pre>
*
* @property reverse
* @type Number
* @final
* @for ProAct.Array.Operations
*/
reverse: 4,
/**
* Represents sorting the elements in an array.
* <pre>
* array.sort();
* </pre>
*
* @property sort
* @type Number
* @final
* @for ProAct.Array.Operations
*/
sort: 5,
/**
* Represents the powerful <i>splice</i> operation.
* <pre>
* array.splice(2, 3, 4, 15, 6);
* </pre>
*
* @property splice
* @type Number
* @final
* @for ProAct.Array.Operations
*/
splice: 6,
},
/**
* A helper method for filtering an array and notifying the right listeners of the filtered result.
* <p>
* This is used if there is an `ProAct.Array` created by filtering another `ProAct.Array`.
* If the original is changed, the filtered array should be changed in some cases.
* So refilter does this - changes the dependent filtered array, using
* {{#crossLink "ProAct.ArrayCore/updateByDiff:method"}}{{/crossLink}}.
* </p>
*
* @for ProAct.Array
* @static
* @param {ProAct.Array} original
* The original array to filter by.
* @param {ProAct.Array} filtered
* The array to be filtered - changed by a filter function, applied on the original.
* @param {Array} filterArgs
* Arguments of the filtering - filtering function and data.
*/
reFilter: function (original, filtered, filterArgs) {
var oarr = filtered._array;
filtered._array = filter.apply(original._array, filterArgs);
filtered.core.updateByDiff(oarr);
}
});
pArrayOps = pArray.Operations;
ProAct.Array.prototype = pArrayProto = P.U.ex(Object.create(arrayProto), {
/**
* Reference to the constructor of this object.
*
* @property constructor
* @type ProAct.Array
* @final
* @for ProAct.Array
*/
constructor: ProAct.Array,
/**
* The <b>concat()</b> method returns a new array comprised of this array joined with other array(s) and/or value(s).
* <p>
* The result `ProAct.Array` is dependent on <i>this</i>, so if <i>this</i> changes, the concatenation resut will be updated.
* </p>
* <p>
* If the argument passed is another `ProAct.Array` the result array is dependent on it too.
* </p>
*
* @for ProAct.Array
* @instance
* @method concat
* @param [...]
* Arrays and/or values to concatenate to the resulting array.
* @return {ProAct.Array}
* A new `ProAct.Array` consisting of the elements in the <i>this</i> object on which it is called, followed in order by,
* for each argument, the elements of that argument (if the argument is an array) or the argument itself (if the argument is not an array).
*/
concat: function () {
var res, rightProArray;
if (arguments.length === 1 && P.AU.isProArray(arguments[0])) {
rightProArray = arguments[0];
arguments[0] = rightProArray._array;
}
res = new P.A(concat.apply(this._array, arguments));
if (rightProArray) {
this.core.on(pArrayLs.leftConcat(res, this, rightProArray));
rightProArray.core.on(pArrayLs.rightConcat(res, this, rightProArray));
} else {
this.core.on(pArrayLs.leftConcat(res, this, slice.call(arguments, 0)));
}
return res;
},
/**
* The <b>every()</b> method tests whether all elements in the `ProAct.Array` pass the test implemented by the provided function.
* <p>
* This method adds the {{#crossLink "ProAct/currentCaller:property"}}{{/crossLink}} as a listener to both 'index' type and 'length' type of changes.
* </p>
*
* @for ProAct.Array
* @instance
* @method every
* @param {Function} callback
* Function to test for each element.
* @param {Object} thisArg
* Value to use as this when executing <i>callback</i>.
* @return {Boolean}
* True if all the elements in the <i>this</i> ProAct.Array pass the test implemented by the <i>callback</i>, false otherwise.
*/
every: function (fun, thisArg) {
this.core.addCaller();
if (this.core.isComplex) {
fun = this.core.actionFunction(fun);
}
return every.call(this._array, fun, thisArg);
},
/**
* Does the same as the {{#crossLink "ProAct.Array/every:method"}}{{/crossLink}} method, but the result is a {{#crossLink "ProAct.Property"}}{{/crossLink}} depending on changes on the array.
*
* @for ProAct.Array
* @instance
* @method pevery
* @param {Function} fun
* Function to test for each element.
* @param {Object} thisArg
* Value to use as this when executing <i>callback</i>.
* @return {ProAct.Property}
* {{#crossLink "ProAct.Property"}}{{/crossLink}} with value of true if all the elements in <i>this</i> `ProAct.Array` pass the test implemented by the <i>fun</i>, false otherwise.
*/
pevery: function (fun, thisArg) {
var val = P.P.lazyValue(every.apply(this._array, arguments));
this.core.on(pArrayLs.every(val, this, arguments));
return val;
},
/**
* The <b>some()</b> method tests whether some element in the array passes the test implemented by the provided function.
* <p>
* This method adds the {{#crossLink "ProAct/currentCaller:property"}}{{/crossLink}} as a listener to both 'index' type and 'length' type of changes.
* </p>
*
* @for ProAct.Array
* @instance
* @method some
* @param {Function} callback
* Function to test for each element.
* @param {Object} thisArg
* Value to use as this when executing <i>callback</i>.
* @return {Boolean}
* True if one or more of the elements in <i>this</i> `ProAct.Array` pass the test implemented by the <i>callback</i>, false otherwise.
*/
some: function () {
this.core.addCaller();
return some.apply(this._array, arguments);
},
/**
* Does the same as the {{#crossLink "ProAct.Array/some:method"}}{{/crossLink}} method, but the result is a {{#crossLink "ProAct.Property"}}{{/crossLink}} depending on changes on the array.
*
* @for ProAct.Array
* @instance
* @method psome
* @param {Function} fun
* Function to test for each element.
* @param {Object} thisArg
* Value to use as this when executing <i>callback</i>.
* @return {ProAct.Property}
* {{#crossLink "ProAct.Property"}}{{/crossLink}} with value of true if one or more of the elements in <i>this</i> `ProAct.Array` pass the test implemented by the <i>fun</i>, false otherwise.
*/
psome: function (fun, thisArg) {
var val = P.P.lazyValue(some.apply(this._array, arguments));
this.core.on(pArrayLs.some(val, this, arguments));
return val;
},
/**
* The <b>forEach()</b> method executes a provided function once per array element.
* <p>
* This method adds the {{#crossLink "ProAct/currentCaller:property"}}{{/crossLink}} as a listener to both 'index' type and 'length' type of changes.
* </p>
*
* @for ProAct.Array
* @instance
* @method forEach
* @param {Function} fun
* Function to execute for each element.
* @param {Object} thisArg
* Value to use as <i>this</i> when executing <i>callback</i>.
*/
forEach: function (fun /*, thisArg */) {
this.core.addCaller();
return forEach.apply(this._array, arguments);
},
/**
* The <b>filter()</b> method creates a new `ProAct.Array` with all elements that pass the test implemented by the provided function.
* <p>
* The result `ProAct.Array` is dependent on <i>this</i>, so if <i>this</i> changes, the filtered resut will be updated.
* </p>
*
* @for ProAct.Array
* @instance
* @method filter
* @param {Function} fun
* Function to test for each element.
* @param {Object} thisArg
* Value to use as this when executing <i>fun</i>.
* @return {ProAct.Array}
* A new `ProAct.Array` consisting of the elements in <i>this</i> `ProAct.Array` that pass the test implemented by <i>fun</i>.
*/
filter: function (fun, thisArg, isComplex) {
if (this.core.isComplex || isComplex) {
fun = this.core.actionFunction(fun);
}
var filtered = new P.A(filter.apply(this._array, arguments)),
listener = pArrayLs.filter(filtered, this, arguments);
this.core.on(listener);
filtered.core.filteringListener = listener;
return filtered;
},
/**
* The <b>map()</b> method creates a new `ProAct.Array` with the results of calling a provided function on every element in <i>this</i> `ProAct.Array`.
* <p>
* The result `ProAct.Array` is dependent on <i>this</i>, so if <i>this</i> changes, the mapped resut will be updated.
* </p>
*
* @for ProAct.Array
* @instance
* @method map
* @param {Function} fun
* Function that produces an element of the new `ProAct.Array`, taking three arguments:
* <ol>
* <li><b>currentValue</b> : The current element being processed in the array.</li>
* <li><b>index</b> : The index of the current element being processed in the array.</li>
* <li><b>array</b> : The array map was called upon.</li>
* </ol>
* @param {Object} thisArg
* Value to use as this when executing <i>fun</i>.
* @return {ProAct.Array}
* A new `ProAct.Array` consisting of the elements in <i>this</i> `ProAct.Array` transformed by <i>fun</i>.
*/
map: function (fun, thisArg) {
var mapped = new P.A(map.apply(this._array, arguments));
this.core.on(pArrayLs.map(mapped, this, arguments));
return mapped;
},
/**
* The <b>reduce()</b> method applies a function against an accumulator and each value of the `ProAct.Array` (from left-to-right) has to reduce it to a single value.
* <p>
* This method adds the {{#crossLink "ProAct/currentCaller:property"}}{{/crossLink}} as a listener to both 'index' type and 'length' type of changes.
* </p>
*
* @for ProAct.Array
* @instance
* @method reduce
* @param {Function} fun
* Function to execute on each value in the array, taking four arguments:
* <ol>
* <li><b>previousValue</b> : The value previously returned in the last invocation of the <i>fun</i>, or <i>initialValue</i>, if supplied.</li>
* <li><b>currentValue</b> : The current element being processed in the `ProAct.Array`.</li>
* <li><b>index</b> : The index of the current element being processed in the `ProAct.Array`.</li>
* <li><b>array</b> : The array reduce was called upon.</li>
* </ol>
* @param {Object} initialValue
* Object to use as the first argument to the first call of the <i>fun</i> .
* @return {Object}
* The value of the last <i>fun</i> invocation.
*/
reduce: function (fun /*, initialValue */) {
this.core.addCaller();
return reduce.apply(this._array, arguments);
},
/**
* Does the same as the {{#crossLink "ProAct.Array/reduce:method"}}{{/crossLink}} method, but the result is a {{#crossLink "ProAct.Property"}}{{/crossLink}} depending on changes on <i>this</i> `ProAct.Array`.
*
* @for ProAct.Array
* @instance
* @method preduce
* @param {Function} fun
* Function to execute on each value in the array, taking four arguments:
* <ol>
* <li><b>previousValue</b> : The value previously returned in the last invocation of the <i>fun</i>, or <i>initialValue</i>, if supplied.</li>
* <li><b>currentValue</b> : The current element being processed in the `ProAct.Array`.</li>
* <li><b>index</b> : The index of the current element being processed in the `ProAct.Array`.</li>
* <li><b>array</b> : The array reduce was called upon.</li>
* </ol>
* @param {Object} initialValue
* Object to use as the first argument to the first call of the <i>fun</i> .
* @return {ProAct.Property}
* {{#crossLink "ProAct.Property"}}{{/crossLink}} with value of the last <i>fun</i> invocation.
*/
preduce: function (fun /*, initialValue */) {
var val = P.P.lazyValue(reduce.apply(this._array, arguments));
this.core.on(pArrayLs.reduce(val, this, arguments));
return val;
},
/**
* The <b>reduceRight()</b> method applies a function against an accumulator and each value of the `ProAct.Array` (from right-to-left) as to reduce it to a single value.
* <p>
* This method adds the {{#crossLink "ProAct/currentCaller:property"}}{{/crossLink}} as a listener to both 'index' type and 'length' type of changes.
* </p>
*
* @for ProAct.Array
* @instance
* @method reduceRight
* @param {Function} fun
* Function to execute on each value in the array, taking four arguments:
* <ol>
* <li><b>previousValue</b> : The value previously returned in the last invocation of the <i>fun</i>, or <i>initialValue</i>, if supplied.</li>
* <li><b>currentValue</b> : The current element being processed in the `ProAct.Array`.</li>
* <li><b>index</b> : The index of the current element being processed in the `ProAct.Array`.</li>
* <li><b>array</b> : The array reduce was called upon.</li>
* </ol>
* @param {Object} initialValue
* Object to use as the first argument to the first call of the <i>fun</i> .
* @return {Object}
* The value of the last <i>fun</i> invocation.
*/
reduceRight: function (fun /*, initialValue */) {
this.core.addCaller();
return reduceRight.apply(this._array, arguments);
},
/**
* Does the same as the {{#crossLink "ProAct.Array/reduceRight:method"}}{{/crossLink}} method, but the result is a {{#crossLink "ProAct.Property"}}{{/crossLink}} depending on changes on <i>this</i> `ProAct.Array`.
*
* @for ProAct.Array
* @instance
* @method preduceRight
* @param {Function} fun
* Function to execute on each value in the array, taking four arguments:
* <ol>
* <li><b>previousValue</b> : The value previously returned in the last invocation of the <i>fun</i>, or <i>initialValue</i>, if supplied.</li>
* <li><b>currentValue</b> : The current element being processed in the `ProAct.Array`.</li>
* <li><b>index</b> : The index of the current element being processed in the `ProAct.Array`.</li>
* <li><b>array</b> : The array reduce was called upon.</li>
* </ol>
* @param {Object} initialValue
* Object to use as the first argument to the first call of the <i>fun</i> .
* @return {ProAct.Property}
* {{#crossLink "ProAct.Property"}}{{/crossLink}} with value of the last <i>fun</i> invocation.
*/
preduceRight: function (fun /*, initialValue */) {
var val = P.P.lazyValue(reduceRight.apply(this._array, arguments));
this.core.on(pArrayLs.reduceRight(val, this, arguments));
return val;
},
/**
* The <b>indexOf()</b> method returns the first index at which a given element can be found in the ProAct.Array, or -1 if it is not present.
* <p>
* This method adds the {{#crossLink "ProAct/currentCaller:property"}}{{/crossLink}} as a listener to both 'index' type and 'length' type of changes.
* </p>
*
* @for ProAct.Array
* @instance
* @method indexOf
* @param {Object} searchElement
* Element to locate in the ProAct.Array.
* @param {Number} fromIndex
* Default: 0 (Entire array is searched)
* <p>
* The index to start the search at.
* If the index is greater than or equal to the `ProAct.Array`'s length, -1 is returned,
* which means the array will not be searched.
* If the provided index value is a negative number,
* it is taken as the offset from the end of the `ProAct.Array`.
* </p>
* <p>
* Note: if the provided index is negative, the `ProAct.Array` is still searched from front to back.
* If the calculated index is less than 0, then the whole `ProAct.Array` will be searched.
* </p>
* @return {Number}
* The index of the searched element or '-1' if it is not found in <i>this</i> `ProAct.Array`.
*/
indexOf: function () {
this.core.addCaller();
return indexOf.apply(this._array, arguments);
},
/**
* Does the same as the {{#crossLink "ProAct.Array/indexOf:method"}}{{/crossLink}} method, but the result is a {{#crossLink "ProAct.Property"}}{{/crossLink}} depending on changes on <i>this</i> `ProAct.Array`.
*
* @for ProAct.Array
* @instance
* @method pindexOf
* @param {Object} searchElement
* Element to locate in the `ProAct.Array`.
* @param {Number} fromIndex
* Default: 0 (Entire array is searched)
* <p>
* The index to start the search at.
* If the index is greater than or equal to the `ProAct.Array`'s length, -1 is returned,
* which means the array will not be searched.
* If the provided index value is a negative number,
* it is taken as the offset from the end of the `ProAct.Array`.
* </p>
* <p>
* Note: if the provided index is negative, the `ProAct.Array` is still searched from front to back.
* If the calculated index is less than 0, then the whole ProAct.Array will be searched.
* </p>
* @return {ProAct.Property}
* A {{#crossLink "ProAct.Property"}}{{/crossLink}} instance with value, the index of the searched element or '-1' if it is not found in <i>this</i> `ProAct.Array`.
*/
pindexOf: function () {
var val = P.P.lazyValue(indexOf.apply(this._array, arguments));
this.core.on(pArrayLs.indexOf(val, this, arguments));
return val;
},
/**
* The <b>lastIndexOf()</b> method returns the last index at which a given element can be found in the `ProAct.Array`, or -1 if it is not present.
* The ProAct.Array is searched backwards, starting at <i>fromIndex</i>.
* <p>
* This method adds the {{#crossLink "ProAct/currentCaller:property"}}{{/crossLink}} as a listener to both 'index' type and 'length' type of changes.
* </p>
*
* @for ProAct.Array
* @instance
* @method lastIndexOf
* @param {Object} searchElement
* Element to locate in the ProAct.Array.
* @param {Number} fromIndex
* <p>
* The index at which to start searching backwards.
* Defaults to the ProAct.Array's length, i.e. the whole array will be searched.
* If the index is greater than or equal to the length of the `ProAct.Array`, the whole `ProAct.Array` will be searched.
* If negative, it is taken as the offset from the end of the `ProAct.Array`.
* </p>
* <p>
* Note that even when the index is negative,
* the ProAct.Array is still searched from back to front.
* If the calculated index is less than 0, -1 is returned, i.e. the `ProAct.Array` will not be searched.
* </p>
* @return {Number}
* The index of the searched backwards element or '-1' if it is not found in <i>this</i> `ProAct.Array`.
*/
lastIndexOf: function () {
this.core.addCaller();
return lastIndexOf.apply(this._array, arguments);
},
/**
* Does the same as the {{#crossLink "ProAct.Array/lastIndexOf:method"}}{{/crossLink}} method, but the result is a {{#crossLink "ProAct.Property"}}{{/crossLink}} depending on changes on <i>this</i> `ProAct.Array`.
*
* @for ProAct.Array
* @instance
* @method plastindexOf
* @param {Object} searchElement
* Element to locate in the `ProAct.Array`.
* @param {Number} fromIndex
* <p>
* The index at which to start searching backwards.
* Defaults to the `ProAct.Array`'s length, i.e. the whole array will be searched.
* If the index is greater than or equal to the length of the `ProAct.Array`, the whole ProAct.Array will be searched.
* If negative, it is taken as the offset from the end of the` ProAct.Array`.
* </p>
* <p>
* Note that even when the index is negative,
* the ProAct.Array is still searched from back to front.
* If the calculated index is less than 0, -1 is returned, i.e. the `ProAct.Array` will not be searched.
* </p>
* @return {ProAct.Property}
* A {{#crossLink "ProAct.Property"}}{{/crossLink}} instance with value, the index of the backwards searched element or '-1' if it is not found in <i>this</i> `ProAct.Array`.
*/
plastindexOf: function () {
var val = P.P.lazyValue(lastIndexOf.apply(this._array, arguments));
this.core.on(pArrayLs.lastIndexOf(val, this, arguments));
return val;
},
/**
* The <b>join()</b> method joins all elements of an `ProAct.Array` into a string.
* <p>
* This method adds the {{#crossLink "ProAct/currentCaller:property"}}{{/crossLink}} as a listener to both 'index' type and 'length' type of changes.
* </p>
*
* @for ProAct.Array
* @instance
* @method join
* @param {String} separator
* Specifies a string to separate each element of the `ProAct`.
* The separator is converted to a string if necessary.
* <p>
* If omitted, the ProAct.Array elements are separated with a comma.
* </p>
* @return {String}
* A string representation of all the elements in <i>this</i> `ProAct.Array`, separated by the provided <i>separator</i>.
*/
join: function () {
this.core.addCaller();
return join.apply(this._array, arguments);
},
/**
* Does the same as the {{#crossLink "ProAct.Array/join:method"}}{{/crossLink}} method, but the result is a {{#crossLink "ProAct.Property"}}{{/crossLink}} depending on changes on <i>this</i> `ProAct.Array`.
*
* @for ProAct.Array
* @instance
* @method pjoin
* @param {String} separator
* Specifies a string to separate each element of the `ProAct`.
* The separator is converted to a string if necessary.
* <p>
* If omitted, the ProAct.Array elements are separated with a comma.
* </p>
* @return {ProAct.Property}
* A {{#crossLink "ProAct.Property"}}{{/crossLink}} instance with value : string representation of all the elements in <i>this</i> `ProAct.Array`, separated by the provided <i>separator</i>.
*/
pjoin: function (separator) {
var reduced = this.preduce(function (i, el) {
return i + separator + el;
}, ''), res = P.P.lazyValue(function () {
if (!reduced.v) {
return '';
}
return reduced.v.substring(1);
});
return res;
},
/**
* The <b>toLocaleString()</b> method returns a string representing the elements of the ProAct.Array.
* The elements are converted to Strings using their toLocaleString methods and these Strings are separated by a locale-specific String (such as a comma ",").
* <p>
* This method adds the {{#crossLink "ProAct/currentCaller:property"}}{{/crossLink}} as a listener to both 'index' type and 'length' type of changes.
* </p>
*
* @for ProAct.Array
* @instance
* @method toLocaleString
* @return {String}
* Locale-specific string representing the elements of <i>this</i> ProAct.Array.
*/
toLocaleString: function () {
this.core.addCaller();
return toLocaleString.apply(this._array, arguments);
},
/**
* The <b>toString()</b> method returns a string representing the specified `ProAct.Array` and its elements.
* The elements are converted to Strings using their toLocaleString methods and these Strings are separated by a locale-specific String (such as a comma ",").
* <p>
* This method adds the {{#crossLink "ProAct/currentCaller:property"}}{{/crossLink}} as a listener to both 'index' type and 'length' type of changes.
* </p>
*
* @for ProAct.Array
* @instance
* @method toString
* @return {String}
* A string representing the elements of <i>this</i> `ProAct.Array`.
*/
toString: function () {
this.core.addCaller();
return toString.apply(this._array, arguments);
},
/**
* Returns the result of {{#crossLink "ProAct.Array/toArray:method"}}{{/crossLink}}.
*
* @for ProAct.Array
* @instance
* @method valueOf
* @return {Array}
* This ProAct.Array converted to plain JavaScript array.
*/
valueOf: function () {
return this.toArray();
},
/**
* The <b>slice()</b> method returns a shallow copy of a portion of <i>this</i> `ProAct.Array` into a new `ProAct.Array` object.
* <p>
* The result `ProAct.Array` is dependent on <i>this</i>, so if <i>this</i> changes, the slice resut will be updated.
* </p>
*
* @for ProAct.Array
* @instance
* @method slice
* @param {Number} begin
* Zero-based index at which to begin extraction.
* As a negative index, begin indicates an offset from the end of the sequence. slice(-2) extracts the last two elements in the sequence.
* If begin is omitted, slice begins from index 0.
* @param {Number} end
* Zero-based index at which to end extraction. slice extracts up to but not including end.
* slice(1,4) extracts the second element up to the fourth element (elements indexed 1, 2, and 3).
* As a negative index, end indicates an offset from the end of the sequence. slice(2,-1) extracts the third element through the second-to-last element in the sequence.
* If end is omitted, slice extracts to the end of the sequence.
* @return {ProAct.Array}
* A portion of <i>this</i> `ProAct.Array`, dependent on it.
*/
slice: function () {
var sliced = new P.A(slice.apply(this._array, arguments));
this.core.on(pArrayLs.slice(sliced, this, arguments));
return sliced;
},
/**
* The <b>reverse()</b> method reverses an `ProAct.Array` in place. The first array element becomes the last and the last becomes the first.
* <p>
* This method notifies the 'index' listeners attached to <i>this</i>' {{#crossLink "ProAct.ArrayCore"}}{{/crossLink}}.
* </p>
*
* @for ProAct.Array
* @instance
* @method reverse
*/
reverse: function () {
if (this._array.length === 0) {
return;
}
var reversed = reverse.apply(this._array, arguments);
ActorUtil.update.call(this.core, null, 'index', [pArrayOps.reverse, -1, null, null]);
return reversed;
},
/**
* The <b>sort()</b> method sorts the elements of <i>this</i> `ProAct.Array` in place and returns the <i>this</i>. The sort is not necessarily stable.
* The default sort order is according to string Unicode code points.
* <p>
* This method notifies the 'index' listeners attached to <i>this</i>' {{#crossLink "ProAct.ArrayCore"}}{{/crossLink}}.
* </p>
*
* @for ProAct.Array
* @instance
* @method sort
* @return {ProAct.Array}
* <i>this</i>
*/
sort: function () {
if (this._array.length === 0) {
return;
}
var sorted = sort.apply(this._array, arguments),
args = arguments;
ActorUtil.update.call(this.core, null, 'index', [pArrayOps.sort, -1, null, args]);
return this;
},
/**
* The <b>splice()</b> method changes the content of <i>this</i> `ProAct.Array`, adding new elements while removing old elements.
* <p>
* This method may notify the 'index' listeners or the 'length' listeners, or even the both types of listeners, attached to <i>this</i>' {{#crossLink "ProAct.ArrayCore"}}{{/crossLink}}, depending
* on what the splicing does - removing, adding or changing elements (removing and adding).
* </p>
*
* @for ProAct.Array
* @instance
* @method splice
* @param {Number} index
* Index at which to start changing the `ProAct.Array`.
* If greater than the length of the `ProAct.Array`, actual starting index will be set to the length of the <i>this</i>.
* If negative, will begin that many elements from the end.
* @param {Number} howMany
* An integer indicating the number of old `ProAct.Array` elements to remove.
* If howMany is 0, no elements are removed. In this case, you should specify at least one new element.
* If howMany is greater than the number of elements left in the ProAct.Array starting at index,
* then all of the elements through the end of the ProAct.Array will be deleted.
* @param [...]
* <b>element1, ..., elementN</b>:
* <p>
* The elements to add to the `ProAct.Array`. If you don't specify any elements, splice simply removes elements from the `ProAct.Array`.
* </p>
* @return {ProAct.Array}
* An `ProAct.Array` containing the removed elements.
* If only one element is removed, an `ProAct.Array` of one element is returned.
* If no elements are removed, an empty `ProAct.Array` is returned.
*/
splice: function (index, howMany) {
var oldLn = this._array.length,
spliced = splice.apply(this._array, arguments),
ln = this._array.length, delta,
newItems = slice.call(arguments, 2);
index = !~index ? ln - index : index
howMany = (howMany == null ? ln - index : howMany) || 0;
if (newItems.length > howMany) {
delta = newItems.length - howMany;
while (delta--) {
this.core.defineIndexProp(oldLn++);
}
} else if (howMany > newItems.length) {
delta = howMany - newItems.length;
while (delta--) {
delete this[--oldLn];
}
}
this.core.updateSplice(index, spliced, newItems);
return new P.A(spliced);
},
/**
* The <b>pop()</b> method removes the last element from an `ProAct.Array` and returns that element.
* <p>
* This method notifies the 'length' listeners, attached to <i>this</i>' {{#crossLink "ProAct.ArrayCore"}}{{/crossLink}}.
* </p>
* <p>
* This method removes the special index accessor of the deleted element's index - the last index.
* </p>
*
* @for ProAct.Array
* @instance
* @method pop
* @return {Object}
* The removed element. If <i>this</i> `ProAct.Array` is empty the result is undefined.
*/
pop: function () {
if (this._array.length === 0) {
return;
}
var popped = pop.apply(this._array, arguments),
index = this._array.length;
delete this[index];
ActorUtil.update.call(this.core, null, 'length', [pArrayOps.remove, this._array.length, popped, null]);
return popped;
},
/**
* The <b>push()</b> method adds one or more elements to the end of an `ProAct.Array` and returns the new length of the `ProAct.Array`.
* <p>
* This method notifies the 'length' listeners, attached to <i>this</i>' {{#crossLink "ProAct.ArrayCore"}}{{/crossLink}}.
* </p>
* <p>
* This method defines new index accessors for the elements on the new indexes. So these indexes can be set and read, and
* will attatch listeners to the {{#crossLink "ProAct.ArrayCore"}}{{/crossLink}} or update them.
* </p>
*
* @for ProAct.Array
* @instance
* @method push
* @param [...]
* <b>element1, ..., elementN</b> : The elements to add to the end of the array.
* @return {Object}
* The new length property of the <i>this</i>.
*/
push: function () {
var vals = arguments, i, ln = arguments.length, index;
for (i = 0; i < ln; i++) {
index = this._array.length;
push.call(this._array, arguments[i]);
this.core.defineIndexProp(index);
}
ActorUtil.update.call(this.core, null, 'length', [pArrayOps.add, this._array.length - 1, null, slice.call(vals, 0)]);
return this._array.length;
},
/**
* The <b>shift()</b> method removes the first element from an `ProAct.Array` and returns that element. This method changes the length of the `ProAct.Array`.
* <p>
* This method notifies the 'length' listeners, attached to <i>this</i>' {{#crossLink "ProAct.ArrayCore"}}{{/crossLink}}.
* </p>
* <p>
* This method removes the special index accessor of the deleted element's index - the zero index.
* </p>
*
* @for ProAct.Array
* @instance
* @method shift
* @return {Object}
* The removed element. If <i>this</i> `ProAct.Array` is empty the result is undefined.
*/
shift: function () {
if (this._array.length === 0) {
return;
}
var shifted = shift.apply(this._array, arguments),
index = this._array.length;
delete this[index];
ActorUtil.update.call(this.core, null, 'length', [pArrayOps.remove, 0, shifted, null]);
return shifted;
},
/**
* The <b>unshift()</b> method adds one or more elements to the beginning of an `ProAct.Array` and returns the new length of the `ProAct.Array`.
* <p>
* This method notifies the 'length' listeners, attached to <i>this</i>' {{#crossLink "ProAct.ArrayCore"}}{{/crossLink}}.
* </p>
* <p>
* This method defines new index accessors for the elements on the new indexes. So these indexes can be set and read, and
* will attatch listeners to the {{#crossLink "ProAct.ArrayCore"}}{{/crossLink}} or update them.
* </p>
*
* @for ProAct.Array
* @instance
* @method unshift
* @param [...]
* <b>element1, ..., elementN</b> : The elements to add to the front of the array.
* @return {Object}
* The new length property of the <i>this</i>.
*/
unshift: function () {
var vals = slice.call(arguments, 0), i, ln = arguments.length,
array = this._array;
for (var i = 0; i < ln; i++) {
array.splice(i, 0, arguments[i]);
this.core.defineIndexProp(array.length - 1);
}
ActorUtil.update.call(this.core, null, 'length', [pArrayOps.add, 0, null, vals]);
return array.length;
},
/**
* Generates an plain array representation of <i>this</i>.
* <p>
* The returned array is shallow copy of <i>this</i>' content, so if modified with methods like 'push' or 'pop',
* <i>this</i> content will not be modified
* </p>
*
* @for ProAct.Array
* @instance
* @method toArray
* @return {Array}
* An plain JavaScript array representation of <i>this</i>.
*/
toArray: function () {
var result = [], i, ar = this._array, ln = ar.length, el,
isPA = P.AU.isProArray;
for (i = 0; i < ln; i++) {
el = ar[i];
if (isPA(el)) {
el = el.toArray();
}
result.push(el);
}
return result;
},
/**
* Generates a JSON representation of <i>this</i>.
*
* @for ProAct.Array
* @instance
* @method toJSON
* @return {String}
* A JSON array representing <i>this</i>.
*/
toJSON: function () {
return JSON.stringify(this._array);
}
});
P.U.ex(P.Actor.prototype, {
/**
* Creates and returns a {{#crossLink "ProAct.Array"}}{{/crossLink}} instance, which tracks the changes of this.
* Uses the current queue for queueing changes.
*
* @for ProAct.Actor
* @instance
* @method toProArray
* @return {ProAct.Array}
* A `ProAct.Array` instance tracking the changes of `this`.
*/
toProArray: function () {
var array = new P.A();
array.core.queueName = this.queueName;
array.core.into(this);
return array;
}
});
function ArrayProbProvider () {
};
ArrayProbProvider.prototype = P.U.ex(Object.create(P.ProbProvider.prototype), {
constructor: ArrayProbProvider,
filter: function (data, meta) {
return P.U.isArray(data);
},
provide: function (data, meta) {
var array = new P.A(data);
if (meta && meta.p && meta.p.queueName && P.U.isString(meta.p.queueName)) {
array.core.queueName = meta.p.queueName;
}
return array;
}
});
P.ProbProvider.register(new ArrayProbProvider());