From ccf76e430b7703db028966a845a966f50956f490 Mon Sep 17 00:00:00 2001 From: xue <> Date: Mon, 5 Dec 2005 01:00:16 +0000 Subject: --- framework/Web/Javascripts/extended/array.js | 465 ++++++++++++++++++++++++++++ 1 file changed, 465 insertions(+) create mode 100644 framework/Web/Javascripts/extended/array.js (limited to 'framework/Web/Javascripts/extended/array.js') diff --git a/framework/Web/Javascripts/extended/array.js b/framework/Web/Javascripts/extended/array.js new file mode 100644 index 00000000..2aeb9084 --- /dev/null +++ b/framework/Web/Javascripts/extended/array.js @@ -0,0 +1,465 @@ +/** +ARRAY EXTENSIONS +by Caio Chassot (http://v2studio.com/k/code/) +*/ + +//function v2studio_com_code() +//{ + + +/** + * Searches Array for value. + * returns the index of the first item + * which matches value, or -1 if not found. + * searching starts at index 0, or at start, if specified. + * + * Here are the rules for an item to match value + * if strict is false or not specified (default): + * if value is a: + * # function -> value(item) must be true + * # RegExp -> value.test(item) must be true + * # anything else -> item == value must be true + * @param value the value (function, regexp) to search + * @param start where to start the search + * @param strict use strict comparison (===) for everything + */ +Array.prototype.indexOf = function(value, start, strict) { + start = start || 0; + for (var i=start; ivalue returns the first matched item, or null if not found + * Parameters work the same as indexOf + * @see #indexOf + */ +Array.prototype.find = function(value, start, strict) { + var i = this.indexOf(value, start, strict); + if (i != -1) return this[i]; + return null +} + + + +/* A.contains(value [, strict]) +/** + * aliases: has, include + * returns true if value is found in Array, otherwise false; + * relies on indexOf, see its doc for details on value and strict + * @see #indexOf + */ +Array.prototype.contains = function(value,strict) { + return this.indexOf(value,0,strict) !== -1; +} + + +Array.prototype.has = Array.prototype.contains; + +Array.prototype.include = Array.prototype.contains; + + +/** + * counts occurences of value in Array + * relies on indexOf, see its doc for details on value and strict + * @see #indexOf + */ +Array.prototype.count = function(value, strict) { + var pos, start = 0, count = 0; + while ((pos = this.indexOf(value, start, strict)) !== -1) { + start = pos + 1; + count++; + } + return count; +} + + +/** + * if all is false or not provied: + * removes first occurence of value from Array + * if all is provided and true: + * removes all occurences of value from Array + * returns the array + * relies on indexOf, see its doc for details on value and strict + * @see #indexOf + */ +Array.prototype.remove = function(value,all,strict) { + while (this.contains(value,strict)) { + this.splice(this.indexOf(value,0,strict),1); + if (!all) break + } + return this; +} + + + +/* A.merge(a [, a]*) + Append the contents of provided arrays into the current + takes: one or more arrays + returns: current array (modified) +*/ +Array.prototype.merge = function() { + var a = []; + for (var i=0; i +*/ +Array.prototype.min = function() { + if (!this.length) return; + var n = this[0]; + for (var i=1; ithis[i]) n=this[i]; + return n; +} + + + +/* A.min() + returns the graetest item in array by comparing them with < +*/ +Array.prototype.max = function() { + if (!this.length) return; + var n = this[0]; + for (var i=1; i 0; +} + + + +/* A.each(fn) + method form of each function +*/ +Array.prototype.each = function(fn) { return each(this, fn) } + + + +/* A.map([fn]) + method form of map function +*/ +Array.prototype.map = function(fn) { return map(this, fn) } + + + +/* A.filter([fn]) + method form of filter function +*/ +Array.prototype.filter = function(fn) { return filter(this, fn) } + + +Array.prototype.select = Array.prototype.filter + + +/* A.reduce([initial,] fn) + method form of filter function +*/ +Array.prototype.reduce = function() { + var args = map(arguments); + fn = args.pop(); + d = args.pop(); + return reduce(this, d, fn); +} + + +Array.prototype.inject = Array.prototype.reduce + + + +/* A.reject(fn) + deletes items in A *in place* for which fn(item) is true + returns a +*/ +Array.prototype.reject = function(fn) { + if (typeof(fn)=='string') fn = __strfn('item,idx,list', fn); + var self = this; + var itemsToRemove = []; + fn = fn || function(v) {return v}; + map(self, function(item,idx,list) { if (fn(item,idx,list)) itemsToRemove.push(idx) } ); + itemsToRemove.reverse().each(function(idx) { self.splice(idx,1) }); + return self; +} + + + +/* __strfn(args, fn) + this is used internally by each, map, combine, filter and reduce to accept + strings as functions. + + takes: + `args` -> a string of comma separated names of the function arguments + `fn` -> the function body + + if `fn` does not contain a return statement, a return keyword will be added + before the last statement. the last statement is determined by removing the + trailing semicolon (';') (if it exists) and then searching for the last + semicolon, hence, caveats may apply (i.e. if the last statement has a + string or regex containing the ';' character things will go wrong) +*/ +function __strfn(args, fn) { + function quote(s) { return '"' + s.replace(/"/g,'\\"') + '"' } + if (!/\breturn\b/.test(fn)) { + fn = fn.replace(/;\s*$/, ''); + fn = fn.insert(fn.lastIndexOf(';')+1, ' return '); + } + return eval('new Function(' + + map(args.split(/\s*,\s*/), quote).join() + + ',' + + quote(fn) + + ')' + ); +} + + + +/* each(list, fn) + traverses `list`, applying `fn` to each item of `list` + takes: + `list` -> anything that can be indexed and has a `length` property. + usually an array. + `fn` -> either a function, or a string containing a function body, + in which case the name of the paremeters passed to it will be + 'item', 'idx' and 'list'. + se doc for `__strfn` for peculiarities about passing strings + for `fn` + + `each` provides a safe way for traversing only an array's indexed items, + ignoring its other properties. (as opposed to how for-in works) +*/ +function each(list, fn) { + if (typeof(fn)=='string') return each(list, __strfn('item,idx,list', fn)); + for (var i=0; i < list.length; i++) fn(list[i], i, list); +} + + +/* map(list [, fn]) + traverses `list`, applying `fn` to each item of `list`, returning an array + of values returned by `fn` + + parameters work the same as for `each`, same `__strfn` caveats apply + + if `fn` is not provided, the list item is returned itself. this is an easy + way to transform fake arrays (e.g. the arguments object of a function or + nodeList objects) into real javascript arrays. + e.g.: args = map(arguments) + + If you don't care about map's return value, you should use `each` + + this is a simplified version of python's map. parameter order is different, + only a single list (array) is accepted, and the parameters passed to [fn] + are different: + [fn] takes the current item, then, optionally, the current index and a + reference to the list (so that [fn] can modify list) + see `combine` if you want to pass multiple lists +*/ +function map(list, fn) { + if (typeof(fn)=='string') return map(list, __strfn('item,idx,list', fn)); + + var result = []; + fn = fn || function(v) {return v}; + for (var i=0; i < list.length; i++) result.push(fn(list[i], i, list)); + return result; +} + + +/* combine(list [, list]* [, fn]) + + takes: + `list`s -> one or more lists (see `each` for definition of a list) + `fn` -> Similar s `each` or `map`, a function or a string containing + a function body. + if a string is used, the name of parameters passed to the + created function will be the lowercase alphabet letters, in + order: a,b,c... + same `__strfn` caveats apply + + combine will traverse all lists concurrently, passing each row if items as + parameters to `fn` + if `fn` is not provided, a function that returns a list containing each + item in the row is used. + if a list is smaller than the other, `null` is used in place of its missing + items + + returns: + an array of the values returned by calling `fn` for each row of items +*/ +function combine() { + var args = map(arguments); + var lists = map(args.slice(0,-1),'map(item)'); + var fn = args.last(); + var toplen = map(lists, "item.length").max(); + var vals = []; + + if (!fn) fn = function(){return map(arguments)}; + if (typeof fn == 'string') { + if (lists.length > 26) throw 'string functions can take at most 26 lists'; + var a = 'a'.charCodeAt(0); + fn = __strfn(map(range(a, a+lists.length),'String.fromCharCode(item)').join(','), fn); + } + + map(lists, function(li) { + while (li.length < toplen) li.push(null); + map(li, function(item,ix){ + if (ix < vals.length) vals[ix].push(item); + else vals.push([item]); + }); + }); + + return map(vals, function(val) { return fn.apply(fn, val) }); +} + + + +/* filter(list [, fn]) + returns an array of items in `list` for which `fn(item)` is true + + parameters work the same as for `each`, same `__strfn` caveats apply + + if `fn` is not specified the items are evaluated themselves, that is, + filter will return an array of the items in `list` which evaluate to true + + this is a similar to python's filter, but parameter order is inverted +*/ +function filter(list, fn) { + if (typeof(fn)=='string') return filter(list, __strfn('item,idx,list', fn)); + + var result = []; + fn = fn || function(v) {return v}; + map(list, function(item,idx,list) { if (fn(item,idx,list)) result.push(item) } ); + return result; +} + + + +/* reduce(list [, initial], fn) + similar to python's reduce. paremeter onder inverted... + + TODO: document this properly + + takes: + `list` -> see doc for `each` to learn more about it + `inirial -> TODO: doc` + `fn` -> similar to `each` too, but in the case where it's a string, + the name of the paremeters passed to it will be 'a' and 'b' + same `__strfn` caveats apply + +*/ +function reduce(list, initial, fn) { + if (undef(fn)) { + fn = initial; + initial = window.undefined; // explicit `window` object so browsers that do not have an `undefined` keyword will evaluate to the (hopefully) undefined parameter `undefined` of `window` + } + if (typeof(fn)=='string') return reduce(list, initial, __strfn('a,b', fn)); + if (isdef(initial)) list.splice(0,0,initial); + if (list.length===0) return false; + if (list.length===1) return list[0]; + var result = list[0]; + var i = 1; + while(i