37,6 → 37,7 |
var _getKeys = _jsx_object.getKeys; |
var _hasOwnProperty = _jsx_object._hasOwnProperty; |
var _isArray = _jsx_object.isArray; |
var _isObject = _jsx_object.isObject; |
var _isNativeObject = _jsx_object.isNativeObject; |
|
/* Constant-like variables */ |
908,6 → 909,37 |
} |
}); |
|
/** |
* Returns the indexes of an array-like object as an {@link Array} |
* |
* @param {Array} a |
* @param {boolean} bStrict = false |
* If <code>true</code>, properties are only considered |
* indexes if they meet the definition in the ECMAScript |
* Language Specification, 5.1 Edition. The default is |
* <code>false</code> which considers all integers. |
* @return {Array} |
*/ |
function _getIndexes (a, bStrict) |
{ |
var keys = _getKeys(a); |
var result = []; |
for (var i = 0, len = keys.length; i < len; ++i) |
{ |
var key = keys[i]; |
|
if (key % 1 == 0) |
{ |
if (!bStrict || (key > -1 && key < _MAX_ARRAY_LENGTH - 1)) |
{ |
result.push(key); |
} |
} |
} |
|
return result; |
} |
|
return { |
/** |
* @memberOf jsx.array |
1064,6 → 1096,8 |
* or <code>false</code>. If it returns <code>true</code> |
* for the element of <code>a</code>, that element is |
* included in the resulting array, otherwise it is not. |
* A function that filters on property values can be created |
* with {@link createFilter()}. |
* @param {Array} a (optional) |
* Array which should be filtered. Is used instead of the |
* <code>Array</code> object the function is applied to. |
1077,7 → 1111,7 |
{ |
if (_isArray(fCallback)) |
{ |
var tmp = a; |
var tmp = fCallback; |
fCallback = a; |
a = tmp; |
} |
1093,7 → 1127,7 |
} |
} |
|
var len = this.length; |
var len = a.length; |
|
if (typeof fCallback != "function") |
{ |
1104,10 → 1138,10 |
|
for (var i = 0; i < len; i++) |
{ |
if (i in this) |
if (i in a) |
{ |
/* mozilla.org: in case fCallback mutates `this'(?) */ |
var val = this[i]; |
var val = a[i]; |
|
if (fCallback.call(a, val, i, this)) |
{ |
1120,20 → 1154,158 |
}, |
|
/** |
* Creates an {@link Array} from the own enumerable properties |
* of an object. |
* |
* @param {Object} obj |
* @param {Object} options |
* <table> |
* <thead> |
* <tr> |
* <th>Option</th> |
* <th>Type</th> |
* <th>Meaning</th> |
* </tr> |
* <thead> |
* <tbody> |
* <tr> |
* <th>preserveKeys</th> |
* <td><code>boolean</code></th> |
* <td>If <code>true</code>, the return value is an |
* <code>Array</code> of <code>Object</code>s |
* whose elements have properties <code>key</code> |
* and <code>value</code>, for the original object's |
* property names and associated values, respectively.<br> |
* The default is <code>false</code>, so that the |
* referred <code>Array</code> only contains the |
* original property values.</td> |
* </tr> |
* <tr> |
* <th>depth</th> |
* <td><code>number</code></th> |
* <td>If not equal to <code>0</code> and the original |
* property value is a reference to an object, that |
* object's properties are turned into an array as well, |
* using this method, so are its properties, and so on. |
* If less than <code>0</code>, recursion is performed |
* as deep as possible; if greater than <code>0</code>, |
* recursion is performed until the specified depth |
* is reached. The default is <code>0</code>. |
* <em>Note that recursion is limited by the maximum |
* stack size.</em></td> |
* </tr> |
* </tbody> |
* </table> |
* @return {Array[Object]} that can be filtered with {@link #filter()}. |
*/ |
fromObject: function jsx_array_fromObject (obj, options) { |
var keys = _getKeys(obj); |
var result = []; |
|
for (var i = 0, len = keys.length; i < len; ++i) |
{ |
var key = keys[i]; |
var value = obj[key]; |
|
var item = value; |
|
if (options) |
{ |
if (typeof options.depth != "undefined") |
{ |
options.depth = Math.floor(options.depth); |
|
if (options.depth != 0 && _isObject(value)) |
{ |
--options.depth; |
value = jsx_array_fromObject(value, options); |
} |
} |
|
if (options.preserveKeys) |
{ |
item = { |
key: key, |
value: value |
}; |
} |
} |
|
result.push(item); |
} |
|
return result; |
}, |
|
getIndexes: _getIndexes, |
|
/** |
* Returns a function that can be used for filtering an {@link Array} |
* by the property values of its elements. |
* |
* @param {Object} filter |
* Object whose property names are the elements' property |
* names, and whose property values are the element's property |
* values to compare against |
* @param {boolean} bStrict = false |
* If <code>true</code>, perform strict comparison. |
* @return {Function} |
* The filter function |
* @see jsx.array.filter |
* Object whose property names (keys) are compared agains |
* the elements' property names, and whose property values |
* (key values) are compared against the elements' |
* corresponding property values. A filter key value of |
* <code>NaN</code> applies to <code>NaN</code> element |
* property values even though <code>NaN</code> usually |
* does not compare equal to anything. |
* @param {Object} options |
* <table> |
* <thead> |
* <tr> |
* <th>Key</th> |
* <th>Type</th> |
* <th>Meaning</th> |
* </tr> |
* </thead> |
* <tbody> |
* <tr> |
* <th>compareStructure</th> |
* <td><code>boolean</code></td> |
* <td>If <code>true</code> and the filter key value |
* is an object, perform structural comparison. |
* If it or a subordered entity is an <code>Array</code> |
* instance, use its elements to filter for |
* items that have the same value or structure: |
* Otherwise, filter for elements' properties whose |
* value is a reference to an object with the specified |
* properties. Examples: |
* <ol> |
* <li><pre><code>jsx.array.filter(jsx.array.createFilter({foo: {bar: "baz"}), <var>a</var>);</code></pre> |
* filters the array-like object referred to by |
* <code><var>a</var></code> for elements whose |
* values are references to objects whose |
* <code>foo</code> property value is a reference |
* to an object whose <code>bar</code> property |
* value is <code>"baz"</code>.</li> |
* <li><pre><code>jsx.array.filter(jsx.array.createFilter({foo: [, "bar"]}), <var>a</var>);</code></pre> |
* filters the array-like object referred to by |
* <code><var>a</var></code> for elements whose |
* values are references to an object whose |
* <code>foo</code> property value is a reference |
* to an <code>Aarray</code> instance whose second |
* element is <code>"bar"</code>.</li> |
* </ol> |
* The default is <code>false</code>.</td> |
* </tr> |
* </tbody> |
* <tr> |
* <th>strict</th> |
* <td><code>boolean</code></td> |
* <td>If <code>true</code> and <var>compareStructure</var> |
* is <code>false</code>, perform strict comparison. |
* The default is <code>false</code>.</td> |
* </tr> |
* </tbody> |
* </table> |
* @return {Function} that takes the element as first and only |
* argument and returns <code>true</code> if the element meets |
* all specified filter criteria, <code>false</code> otherwise. |
* @see jsx.array.filter() |
*/ |
createFilter: function (filter, bStrict) { |
createFilter: function (filter, options) { |
var keys = _getKeys(filter); |
|
/** |
1141,24 → 1313,133 |
* @return {boolean} |
*/ |
return function (element) { |
function _isNaN (value) |
{ |
return (typeof value == "number" && isNaN(value)); |
} |
|
/** |
* @param item |
* @param filter |
*/ |
function _structureCompare (item, filter, bStrict) |
{ |
if (_isArray(filter)) |
{ |
if (!_isArray(item)) |
{ |
return false; |
} |
|
var filter_keys = _getIndexes(filter); |
for (var i = 0, len = filter_keys.length; i < len; ++i) |
{ |
var array_key = filter_keys[i]; |
var array_value = item[array_key]; |
var filter_value = filter[array_key]; |
|
if (_isObject(filter_value)) |
{ |
if (!_structureCompare(array_value, filter_value, bStrict)) |
{ |
return false; |
} |
} |
else |
{ |
if (bStrict) |
{ |
if (array_value !== filter_value) |
{ |
return false; |
} |
} |
else if (array_value != filter_value) |
{ |
return false; |
} |
} |
} |
} |
else if (_isObject(filter)) |
{ |
if (!_isObject(item)) |
{ |
return false; |
} |
|
filter_keys = _getKeys(filter); |
for (var i = 0, len = filter_keys.length; i < len; ++i) |
{ |
var object_key = filter_keys[i]; |
var object_value = item[object_key]; |
filter_value = filter[object_key]; |
|
if (_isObject(filter_value)) |
{ |
if (!_structureCompare(object_value, filter_value, bStrict)) |
{ |
return false; |
} |
} |
else |
{ |
if (bStrict) |
{ |
if (object_value !== filter_value) |
{ |
return false; |
} |
} |
else if (object_value != filter_value) |
{ |
return false; |
} |
} |
} |
} |
|
return true; |
} |
|
for (var i = 0, len = keys.length; i < len; ++i) |
{ |
var key = keys[i]; |
if (bStrict) |
var element_property_value = element[key]; |
var filter_key_value = filter[key]; |
|
if (_isNaN(filter_key_value) && |
!_isNaN(element_property_value)) |
{ |
if (element[key] === filter[key]) |
return false; |
} |
|
if (options.compareStructure) |
{ |
if (!_structureCompare( |
element_property_value, filter_key_value, |
options && options.strict)) |
{ |
return true; |
return false; |
} |
} |
else |
{ |
if (element[key] == filter[key]) |
if (options && options.strict) |
{ |
return true; |
if (element_property_value !== filter_key_value) |
{ |
return false; |
} |
} |
else if (element_property_value != filter_key_value) |
{ |
return false; |
} |
} |
} |
|
return true; |
}; |
}, |
|
1695,212 → 1976,204 |
* Returns a function that can be used for sorting an {@link Array}. |
* |
* @author (C) 2013 Thomas 'PointedEars' Lahn <js@PointedEars.de> |
* @param {Array} aKeys |
* Array of keys that should be sorted by, in order. |
* A key may be a {@link string} value or a native object. |
* If it is a <code>string</code>, it specifies the property name |
* of the sort key. If it is another native object, the following |
* of its properties are used as options. See the <var>options</var> |
* parameter for the default values of these options. |
* <table> |
* <tr> |
* <th><code>key</code></th> |
* <td>The name of the property of the elements whose values |
* should be sorted by (sort values). If this option is |
* not present or a false-value, the element values are |
* used as sort values.</td> |
* </tr> |
* <tr> |
* <th><code>callback</code></th> |
* <td>A reference to the <code>Function</code> whose |
* return value, when passed the current sort value, |
* defines the new sort value.</td> |
* </tr> |
* <tr> |
* <th><code>constructor</code></th> |
* <td>A reference to the <code>Function</code> whose |
* return value when passed the current sort value |
* and called as a constructor, defines the new |
* sort value. This is useful if data can be converted |
* to an object whose <code>toString</code> or |
* <code>valueOf</code> methods can return a |
* valid sort value. If both <code>callback</code> |
* and <code>constructor</code> are specified, the |
* return value of the callback is passed to |
* the constructor.</td> |
* </tr> |
* <tr> |
* <th><code>comparator</code></th> |
* <td>A reference to the <code>Function</code> that |
* should be passed the first and second current |
* sort values and whose return value defines |
* the relation between the first and second sort |
* value. If the return value is not (loosely) equal |
* to 0 or if the key is the last key, its return |
* value is returned. Otherwise the subsequent |
* sort values are compared.</td> |
* </tr> |
* <tr> |
* <th><code>descending</code></th> |
* <td>If a true-value, the sort order for this key |
* is descending.</td> |
* </tr> |
* <tr> |
* <th><code>numeric</code></th> |
* <td>If a true-value, the sort values are compared as if |
* both of them were <code>Number</code> values.</td> |
* </tr> |
* <tr> |
* <th><code>strict</code></th> |
* <td>If a true-value, the sort values are sorted |
* using the <code>===</code> operator.</td> |
* </tr> |
* </table> |
* @param {Object} options (optional) |
* Default sort options. The following properties are used: |
* <table> |
* <tr> |
* <th><code>callback</code></th> |
* <td>A reference to the <code>Function</code> whose |
* return value, when passed the current sort value, |
* defines the new sort value. The factory default |
* is not to use a callback.</td> |
* </tr> |
* <tr> |
* <th><code>constructor</code></th> |
* <td>A reference to the <code>Function</code> whose |
* return value when passed the current sort value |
* and called as a constructor, defines the new |
* sort value. The factory default is not to use |
* a constructor.</td> |
* </tr> |
* <tr> |
* <th><code>comparator</code></th> |
* <td>A reference to the <code>Function</code> that |
* should be passed the first and second current |
* sort values and whose return value defines |
* the relation between the first and second sort |
* value. The factory default is not to use a |
* special sort value comparator.</td> |
* </tr> |
* <tr> |
* <th><code>descending</code></th> |
* <td>If a true-value, the default sort order is |
* descending. The factory default is ascending.</td> |
* </tr> |
* <tr> |
* <th><code>numeric</code></th> |
* <td>If a true-value, by default the sort values are compared |
* as if they were <code>Number</code> values. The factory |
* default is a generic comparison that uses the operators |
* <code>==</code> (non-strict) or <code>===</code> |
* (strict), and <code><</code>, and <code>></code>.</td> |
* </tr> |
* <tr> |
* <th><code>strict</code></th> |
* <td>If a true-value, use strict comparison by default. |
* The factory default is non-strict comparison.</td> |
* </tr> |
* </table> |
* @return {Function} |
*/ |
createComparator: (function () { |
var _isObject = _jsx_object.isObject; |
createComparator: function (aKeys, options) |
{ |
if (aKeys == null || !_isArray(aKeys)) |
{ |
aKeys = [aKeys]; |
} |
|
/** |
* @param {Array} aKeys |
* Array of keys that should be sorted by, in order. |
* A key may be a {@link string} value or a native object. |
* If it is a <code>string</code>, it specifies the property name |
* of the sort key. If it is another native object, the following |
* of its properties are used as options. See the <var>options</var> |
* parameter for the default values of these options. |
* <table> |
* <tr> |
* <th><code>key</code></th> |
* <td>The name of the property of the elements whose values |
* should be sorted by (sort values). If this option is |
* not present or a false-value, the element values are |
* used as sort values.</td> |
* </tr> |
* <tr> |
* <th><code>callback</code></th> |
* <td>A reference to the <code>Function</code> whose |
* return value, when passed the current sort value, |
* defines the new sort value.</td> |
* </tr> |
* <tr> |
* <th><code>constructor</code></th> |
* <td>A reference to the <code>Function</code> whose |
* return value when passed the current sort value |
* and called as a constructor, defines the new |
* sort value. This is useful if data can be converted |
* to an object whose <code>toString</code> or |
* <code>valueOf</code> methods can return a |
* valid sort value. If both <code>callback</code> |
* and <code>constructor</code> are specified, the |
* return value of the callback is passed to |
* the constructor.</td> |
* </tr> |
* <tr> |
* <th><code>comparator</code></th> |
* <td>A reference to the <code>Function</code> that |
* should be passed the first and second current |
* sort values and whose return value defines |
* the relation between the first and second sort |
* value. If the return value is not (loosely) equal |
* to 0 or if the key is the last key, its return |
* value is returned. Otherwise the subsequent |
* sort values are compared.</td> |
* </tr> |
* <tr> |
* <th><code>descending</code></th> |
* <td>If a true-value, the sort order for this key |
* is descending.</td> |
* </tr> |
* <tr> |
* <th><code>numeric</code></th> |
* <td>If a true-value, the sort values are compared as if |
* both of them were <code>Number</code> values.</td> |
* </tr> |
* <tr> |
* <th><code>strict</code></th> |
* <td>If a true-value, the sort values are sorted |
* using the <code>===</code> operator.</td> |
* </tr> |
* </table> |
* @param {Object} options (optional) |
* Default sort options. The following properties are used: |
* <table> |
* <tr> |
* <th><code>callback</code></th> |
* <td>A reference to the <code>Function</code> whose |
* return value, when passed the current sort value, |
* defines the new sort value. The factory default |
* is not to use a callback.</td> |
* </tr> |
* <tr> |
* <th><code>constructor</code></th> |
* <td>A reference to the <code>Function</code> whose |
* return value when passed the current sort value |
* and called as a constructor, defines the new |
* sort value. The factory default is not to use |
* a constructor.</td> |
* </tr> |
* <tr> |
* <th><code>comparator</code></th> |
* <td>A reference to the <code>Function</code> that |
* should be passed the first and second current |
* sort values and whose return value defines |
* the relation between the first and second sort |
* value. The factory default is not to use a |
* special sort value comparator.</td> |
* </tr> |
* <tr> |
* <th><code>descending</code></th> |
* <td>If a true-value, the default sort order is |
* descending. The factory default is ascending.</td> |
* </tr> |
* <tr> |
* <th><code>numeric</code></th> |
* <td>If a true-value, by default the sort values are compared |
* as if they were <code>Number</code> values. The factory |
* default is a generic comparison that uses the operators |
* <code>==</code> (non-strict) or <code>===</code> |
* (strict), and <code><</code>, and <code>></code>.</td> |
* </tr> |
* <tr> |
* <th><code>strict</code></th> |
* <td>If a true-value, use strict comparison by default. |
* The factory default is non-strict comparison.</td> |
* </tr> |
* </table> |
* @return {Function} |
*/ |
function _createComparator (aKeys, options) |
if (options == null || !_isObject(options)) |
{ |
if (aKeys == null || !_isArray(aKeys)) |
{ |
aKeys = [aKeys]; |
} |
options = {}; |
} |
|
if (options == null || !_isObject(options)) |
return function (el1, el2) { |
for (var i = 0, len = aKeys.length; i < len; ++i) |
{ |
options = {}; |
} |
var key = aKeys[i]; |
var propertyName = ((key == null || typeof key.valueOf() == "string") |
? key |
: key.key); |
|
return function (el1, el2) { |
for (var i = 0, len = aKeys.length; i < len; ++i) |
var el1Value = (propertyName != null ? el1[propertyName] : el1); |
var el2Value = (propertyName != null ? el2[propertyName] : el2); |
|
if (key && typeof key.callback == "function") |
{ |
var key = aKeys[i]; |
var propertyName = ((key == null || typeof key.valueOf() == "string") |
? key |
: key.key); |
el1Value = key.callback(el1Value); |
el2Value = key.callback(el2Value); |
} |
else if (typeof options.callback == "function") |
{ |
el1Value = options.callback(el1Value); |
el2Value = options.callback(el2Value); |
} |
|
var el1Value = (propertyName != null ? el1[propertyName] : el1); |
var el2Value = (propertyName != null ? el2[propertyName] : el2); |
if (key && _hasOwnProperty(key, "constructor")) |
{ |
el1Value = new key.constructor(el1Value); |
el2Value = new key.constructor(el2Value); |
} |
else if (_hasOwnProperty(options, "constructor")) |
{ |
el1Value = new options.constructor(el1Value); |
el2Value = new options.constructor(el2Value); |
} |
|
if (key && typeof key.callback == "function") |
{ |
el1Value = key.callback(el1Value); |
el2Value = key.callback(el2Value); |
} |
else if (typeof options.callback == "function") |
{ |
el1Value = options.callback(el1Value); |
el2Value = options.callback(el2Value); |
} |
var isLastKey = (i == len - 1); |
var hasKeySpecificComparator = (typeof key.comparator == "function"); |
if (hasKeySpecificComparator |
|| (typeof options.comparator == "function")) |
{ |
var comparatorResult = (hasKeySpecificComparator |
? key.comparator(el1Value, el2Value) |
: options.comparator(el1Value, el2Value)); |
|
if (key && _hasOwnProperty(key, "constructor")) |
if (isLastKey || comparatorResult != 0) |
{ |
el1Value = new key.constructor(el1Value); |
el2Value = new key.constructor(el2Value); |
return comparatorResult; |
} |
else if (_hasOwnProperty(options, "constructor")) |
{ |
el1Value = new options.constructor(el1Value); |
el2Value = new options.constructor(el2Value); |
} |
|
var isLastKey = (i == len - 1); |
var hasKeySpecificComparator = (typeof key.comparator == "function"); |
if (hasKeySpecificComparator |
|| (typeof options.comparator == "function")) |
{ |
var comparatorResult = (hasKeySpecificComparator |
? key.comparator(el1Value, el2Value) |
: options.comparator(el1Value, el2Value)); |
continue; |
} |
|
if (isLastKey || comparatorResult != 0) |
{ |
return comparatorResult; |
} |
var equals = ((key && key.strict) || (options.strict) |
? (el1Value === el2Value) |
: (el1Value == el2Value)); |
|
continue; |
} |
|
var equals = ((key && key.strict) || (options.strict) |
? (el1Value === el2Value) |
: (el1Value == el2Value)); |
|
if (equals) |
if (equals) |
{ |
if (isLastKey) |
{ |
if (isLastKey) |
{ |
/* last key, same value */ |
return 0; |
} |
/* last key, same value */ |
return 0; |
} |
else |
{ |
var descending = ((key && key.descending) || options.descending); |
} |
else |
{ |
var descending = ((key && key.descending) || options.descending); |
|
return ((key && key.numeric) || options.numeric |
? (descending |
? el2Value - el1Value |
: el1Value - el2Value) |
: (descending |
? (el1Value > el2Value ? -1 : 1) |
: (el1Value < el2Value ? -1 : 1))); |
} |
return ((key && key.numeric) || options.numeric |
? (descending |
? el2Value - el1Value |
: el1Value - el2Value) |
: (descending |
? (el1Value > el2Value ? -1 : 1) |
: (el1Value < el2Value ? -1 : 1))); |
} |
}; |
} |
|
return _createComparator; |
}()) |
} |
}; |
} |
}; |
}()); |
|