1// Array Extensions  v1.0.7
2// documentation: http://www.dithered.com/javascript/array/index.html
3// license: http://creativecommons.org/licenses/by/1.0/
4// code by Chris Nott (chris[at]dithered[dot]com)
5// code by Ilya Lebedev (ilya[at]lebedev[dot]net)
6
7
8// Array.concat() - Join two arrays
9if (isUndefined(Array.prototype.concat)) {
10  Array.prototype.concat = function (secondArray) {
11     var firstArray = this.copy();
12     for (var i = 0, saL = secondArray.length; i < saL; i++) {
13        firstArray[firstArray.length] = secondArray[i];
14     }
15     return firstArray;
16  };
17}
18
19// Array.copy() - Copy an array
20if (isUndefined(Array.prototype.copy)) {
21  Array.prototype.copy = function() {
22     var copy = new Array();
23     for (var i = 0, tL = this.length; i < tL; i++) {
24        copy[i] = this[i];
25     }
26     return copy;
27  };
28}
29
30// Array.pop() - Remove the last element of an array and return it
31if (isUndefined(Array.prototype.pop)) {
32  Array.prototype.pop = function() {
33    var lastItem = undefined;
34    if ( this.length > 0 ) {
35        lastItem = this[this.length - 1];
36        this.length--;
37    }
38    return lastItem;
39  };
40}
41
42// Array.push() - Add an element to the end of an array
43if (isUndefined(Array.prototype.push)) {
44  Array.prototype.push = function() {
45     var currentLength = this.length;
46     for (var i = 0; i < arguments.length; i++) {
47        this[currentLength + i] = arguments[i];
48     }
49     return this.length;
50  };
51}
52
53// Array.shift() - Remove the first element of an array and return it
54if (isUndefined(Array.prototype.shift)) {
55  Array.prototype.shift = function() {
56     var firstItem = this[0];
57     for (var i = 0, tL = this.length - 1; i < tL; i++) {
58        this[i] = this[i + 1];
59     }
60     this.length--;
61     return firstItem;
62  };
63}
64
65// Array.slice() - Copy several elements of an array and return them
66if (isUndefined(Array.prototype.slice)) {
67  Array.prototype.slice = function(start, end) {
68     var temp;
69
70     if (end == null || end == '') end = this.length;
71
72     // negative arguments measure from the end of the array
73     else if (end < 0) end = this.length + end;
74     if (start < 0) start = this.length + start;
75
76     // swap limits if they are backwards
77     if (end < start) {
78        temp  = end;
79        end   = start;
80        start = temp;
81     }
82
83     // copy elements from array to a new array and return the new array
84     var newArray = new Array();
85     for (var i = 0; i < end - start; i++) {
86        newArray[i] = this[start + i];
87     }
88     return newArray;
89  };
90}
91
92// Array.splice() - Splice out and / or replace several elements of an array and return any deleted elements
93if (isUndefined(Array.prototype.splice)) {
94  Array.prototype.splice = function(start, deleteCount) {
95     if (deleteCount == null || deleteCount == '') deleteCount = this.length - start;
96
97     // create a temporary copy of the array
98     var tempArray = this.copy();
99
100     // Copy new elements into array (over-writing old entries)
101     for (var i = start, aL = start + arguments.length - 2; i < aL; i++) {
102        this[i] = arguments[i - start + 2];
103     }
104
105     // Copy old entries after the end of the splice back into array and return
106     var dC = deleteCount - arguments.length + 2;
107     for (var i = start + arguments.length - 2, tL = this.length - deleteCount + arguments.length - 2; i < tL; i++) {
108        this[i] = tempArray[i + dC];
109     }
110     this.length = this.length - dC;
111     return tempArray.slice(start, start + deleteCount);
112  };
113}
114
115// Array.unshift - Add an element to the beginning of an array
116if (isUndefined(Array.prototype.unshift)) {
117  Array.prototype.unshift = function(the_item) {
118     for (var loop = this.length-1 ; loop >= 0; loop--) {
119        this[loop+1] = this[loop];
120     }
121     this[0] = the_item;
122     return this.length;
123  };
124}
125
126// Array.indexOf - return index of found element or -1 (similar to String.indexOf)
127// Don't do the check on 'undefined' because Mozilla does calculate index weirdly
128Array.prototype.indexOf = function(needle,begin) {
129   for (var i=(null==begin||isNaN(begin)||begin<0)?0:Math.round(begin),len = this.length, idx = -1; idx==-1 & i<len; i++) {
130     idx = (this[i]==needle)?i:idx;
131   }
132   return idx;
133};
134// Array.lastIndexOf - return index of found element or -1 (similar to String.lastIndexOf)
135// Don't do the check on 'undefined' because Mozilla does calculate index weirdly
136Array.prototype.lastIndexOf = function(needle,end) {
137   for (var i=(null==end||isNaN(end)||end>this.length)?this.length-1:Math.round(end), idx = -1; idx==-1 & i>-1; i--) {
138     idx = (this[i]==needle)?i:idx;
139   }
140   return idx;
141};
142// Array.map - maps a function on the array elements
143if (isUndefined(Array.prototype.map)) {
144  Array.prototype.map = function(func) {
145     if ('function' != typeof func) return this;
146     var tmp = [];
147     for (var loop = this.length-1 ; loop >= 0; loop--) {
148        tmp[loop] = func(this[loop]);
149     }
150     return tmp;
151  };
152}
153
154if (isUndefined(Array.prototype.unique)) {
155  /**
156   *  Method removes dumplicate entries
157   *
158   *  @return {Array}
159   *  @scope public
160   */
161  Array.prototype.unique = function() /* :Array */{
162    var tmp = [];
163    for(var i=0, tL=this.length; i<tL; i++ ) {
164      if( tmp.indexOf(this[i]) < 0 ) tmp[tmp.length] = this[i];
165    }
166    return tmp;
167  };
168}
169
170if (isUndefined(Array.prototype.flatten)) {
171  /**
172   *  Method flattens 2-dimensional array, when no cols supplied only the cols number from 0th row will be counted
173   *
174   *  @param {Number, Array} cols columns to insert to resulting array
175   *  @return {Array}
176   *  @scope public
177   */
178  Array.prototype.flatten = function(cols /* :Array */, cd) /* :Array */{
179    if (this.length<1) return [];
180    if (isNumeric(cols)) cols = [cols];
181    var idx = false;
182    if (isArray(cols)) {
183      idx = {};
184      for (var i=0,cL=cols.length;i<cL;i++) idx[cols[i]]=true;
185    }
186    var tmp = [];
187    for (var i=0, tL=this.length; i<tL; i++ ) {
188        if (isUndefined(this[i])) continue;
189        if (!isArray(this[i])) {
190            if (false===idx) tmp[tmp.length] = this[i];
191        } else {
192            for (var k=0, cL=this[i].length; k<cL; k++) {
193                if (false===idx || idx.hasOwnProperty(k)) tmp[tmp.length] = this[i][k];
194            }
195        }
196    }
197    return tmp;
198  };
199}
200//-----------------------------------------------------------------------------
201// STATIC METHODS
202//-----------------------------------------------------------------------------
203if (isUndefined(Array.range)) {
204  /**
205   *  Method creates the array with values in the specified range
206   *  1 argument: create array from min(0, end) to max(0, end) with increment 1
207   *  2 arguments: create array from min(start, end) to max(start, end) with increment 1
208   *  3 arguments: create array from min(start, end) to max(start, end) with increment inc
209   *
210   *  @param {Number} end end position
211   *  @param {Number} start start position
212   *  @param {Number} inc increment
213   *  @return {Array}
214   *  @scope public
215   */
216  Array.range = function(end /* :Number */, start /* :Number */, inc /* :Number */) /* :Array */{
217    if (!isNumber(end)) return null;
218    if (!isNumber(inc)) inc = 1;
219    if (!isNumber(start)) start = 0;
220    var tmp = []
221       ,mn = Math.min(start, end)
222       ,mx = Math.max(start, end)
223       ,i = Math.abs(inc)
224       ,cnt = -1;
225    do {
226        cnt++;
227        tmp[cnt] = mn;
228        mn += i;
229    } while (mn<=mx);
230    return inc>0?tmp:tmp.reverse();
231  };
232}
233