1 /* See license.txt for terms of usage */ 2 3 define([ 4 "firebug/lib/trace", 5 "firebug/lib/deprecated", 6 ], 7 function(FBTrace, Deprecated) { 8 "use strict"; 9 // ********************************************************************************************* // 10 // Constants 11 12 const Ci = Components.interfaces; 13 14 /** 15 * @name Arr 16 * @lib Utility for Arrays 17 */ 18 var Arr = {}; 19 20 21 // Array Generic methods 22 // use them to call Array methods with Array-Like objects (arguments, String, NodeList...) 23 // example: var firstArg = Array.forEach(nodeList, func); 24 // 25 // 1. xxxFlorent: should be deprecated as soon Array generics are standardized in ES5 or ES6 26 // 2. xxxFlorent: BTW, can we consider Array generic methods as safe to be used?? What would happen if it is eventually abandoned? 27 var ArrayGen = {}; 28 (function() 29 { 30 var methods = [ 31 'join', 'reverse', 'sort', 'push', 'pop', 'shift', 'unshift', 32 'splice', 'concat', 'slice', 'indexOf', 'lastIndexOf', 33 'forEach', 'map', 'reduce', 'reduceRight', 'filter', 34 'some', 'every' 35 ]; 36 37 methods.forEach(function(methodName) 38 { 39 // xxxFlorent: TODO: [REST] 40 ArrayGen[methodName] = function(thisObj/*, ...args*/) 41 { 42 var args = Array.prototype.slice.call(arguments, 1); 43 return Array.prototype[methodName].apply(thisObj, args); 44 }; 45 }); 46 })(); 47 48 Object.seal(ArrayGen); 49 Object.freeze(ArrayGen); 50 51 Arr.ArrayGen = ArrayGen; 52 53 // ********************************************************************************************* // 54 // Arrays 55 56 /** 57 * @deprecated use Array.isArray instead 58 */ 59 Arr.isArray = Deprecated.deprecated("Use Array.isArray instead", Array.isArray); 60 /** 61 * Returns true if the given object is an Array or an Array-Like object 62 * 63 * @param {*} obj The object 64 * @return true if it is an array-like object or false otherwise 65 */ 66 Arr.isArrayLike = function(obj) 67 { 68 try 69 { 70 if (typeof obj !== "object") 71 return false; 72 if (!isFinite(obj.length)) 73 return false; 74 if (Array.isArray(obj)) 75 return true; 76 if (typeof obj.callee === "function") // arguments 77 return true; 78 if (typeof obj.splice === "function") // jQuery etc. 79 return true; 80 if (obj instanceof Ci.nsIDOMHTMLCollection) 81 return true; 82 if (obj instanceof Ci.nsIDOMNodeList) 83 return true; 84 if (obj instanceof Ci.nsIDOMDOMTokenList) 85 return true; 86 } 87 catch (exc) {} 88 return false; 89 }; 90 91 /** 92 * @deprecated Use Object.keys instead 93 * see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys 94 */ 95 Arr.keys = Deprecated.deprecated("Use Object.keys instead", function(map) 96 { 97 var keys = []; 98 try 99 { 100 for (var name in map) // enumeration is safe 101 keys.push(name); // name is string, safe 102 } 103 catch (exc) 104 { 105 // Sometimes we get exceptions trying to iterate properties 106 } 107 108 return keys; // return is safe 109 }); 110 111 /** 112 * Returns the values of an object 113 * 114 * @param {*} map The object 115 * 116 * @return {Array} the values 117 */ 118 Arr.values = function(map) 119 { 120 var values = []; 121 try 122 { 123 for (var name in map) 124 { 125 try 126 { 127 values.push(map[name]); 128 } 129 catch (exc) 130 { 131 // Sometimes we get exceptions trying to access properties 132 if (FBTrace.DBG_ERRORS) 133 FBTrace.dumpPropreties("lib.values FAILED ", exc); 134 } 135 } 136 } 137 catch (exc) 138 { 139 // Sometimes we get exceptions trying to iterate properties 140 if (FBTrace.DBG_ERRORS) 141 FBTrace.dumpPropreties("lib.values FAILED ", exc); 142 } 143 144 return values; 145 }; 146 147 /** 148 * Removes an item from an array or an array-like object 149 * 150 * @param {Array or Array-Like object} list The array 151 * @param {*} item The item to remove from the object 152 * 153 * @return true if an item as been removed, false otherwise 154 */ 155 Arr.remove = function(list, item) 156 { 157 var index = ArrayGen.indexOf(list, item); 158 if (index >= 0) 159 { 160 ArrayGen.splice(list, index, 1); 161 return true; 162 } 163 return false; 164 }; 165 /** 166 * Same as Arr.remove but removes all the occurences of item 167 * 168 * @param {Array or Array-Like object} list The array 169 * @param {*} item The item to remove from the object 170 * 171 * @return true if an item as been removed, false otherwise 172 */ 173 Arr.removeAll = function(list, item) 174 { 175 var iter = 0; 176 177 while (Arr.remove(list, item)) 178 iter++; 179 180 return (iter > 0); 181 } 182 183 /** 184 * Returns a shallow copy of a portion of an array. 185 * @deprecated use Array.prototype.slice instead 186 */ 187 Arr.sliceArray = Deprecated.deprecated("use Array.prototype.slice instead", 188 function(array, index) 189 { 190 var slice = []; 191 for (var i = index; i < array.length; ++i) 192 slice.push(array[i]); 193 194 return slice; 195 }); 196 197 /** 198 * Clone an array. If a function is given as second parameter, the function is called for each 199 * elements of the passed array and the results are put in the new one. 200 * 201 * @param {Array or Array-Like object} [array] The array 202 * @param {function} [fn] The function 203 * 204 * @deprecated Use either Array.slice(array) or Array.map(array, fn) instead. 205 * see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array 206 * 207 */ 208 Arr.cloneArray = Deprecated.deprecated("use either Array.slice or Array.map instead", 209 function(array, fn) 210 { 211 if (fn) 212 return ArrayGen.map(array, fn); 213 else 214 return ArrayGen.slice(array); 215 }); 216 217 /** 218 * @deprecated Use Array.concat(array, array2) or array.concat(array2) instead 219 */ 220 Arr.extendArray = Deprecated.deprecated("use Array.prototype.concat or Array.concat instead", 221 function(array, array2) 222 { 223 return array.concat(array2); 224 }); 225 226 /** 227 * insert elements at a specific index 228 * NOTE: that method modifies the array passed as the first parameter 229 * 230 * @param {Array or Array-Like object} array The array in which we insert elements 231 * @param {Integer} index The index 232 * @param {Array or Array-Like object} other The elements to insert 233 * 234 * @return the updated array 235 */ 236 Arr.arrayInsert = function(array, index, other) 237 { 238 var splice = ArrayGen.splice.bind(Array, array, index, 0); 239 splice.apply(null, other); 240 return array; 241 } 242 243 /** 244 * Filters out unique values of an array, saving only the first occurrence of 245 * every value. In case the array is sorted, a faster path is taken. 246 * 247 * @param {Array or Array-Like object} arr The array 248 * @param {Boolean} sorted If set to true, use the faster path 249 * 250 * @return {Array} the array deprived of duplication 251 */ 252 Arr.unique = function(arr, sorted) 253 { 254 var ret = [], len = arr.length; 255 if (sorted) 256 { 257 for (var i = 0; i < len; ++i) 258 { 259 // Skip duplicated entries 260 if (i && arr[i-1] === arr[i]) 261 continue; 262 ret.push(arr[i]); 263 } 264 } 265 else 266 { 267 // Keep a map whose ","-prefixed keys represent the values that have 268 // occurred so far in the array (this avoids overwriting e.g. __proto__). 269 var map = {}; 270 for (var i = 0; i < len; ++i) 271 { 272 if (!map.hasOwnProperty("," + arr[i])) 273 { 274 ret.push(arr[i]); 275 map["," + arr[i]] = 1; 276 } 277 } 278 } 279 return ret; 280 }; 281 282 /** 283 * Sorts an array and eliminate duplicates from it. 284 * 285 * @param {Array or Array-Like object} arr The array 286 * @param {function} sortFunc The function used to sort the array (optional) 287 * 288 * @return {Array} the sorted array 289 */ 290 Arr.sortUnique = function(arr, sortFunc) 291 { 292 // make a clone of the array so the original one is preserved 293 var arrCopy = ArrayGen.slice(arr); 294 return Arr.unique(arrCopy.sort(sortFunc), true); 295 }; 296 297 /** 298 * Merge together two arrays, sort the result, and eliminate any duplicates. 299 * 300 * @deprecated use Arr.sortUnique and/or Array.prototype.concat instead 301 */ 302 Arr.merge = Deprecated.deprecated("use Arr.sortUnique and/or Array.prototype.concat instead", 303 function(arr1, arr2, sortFunc) 304 { 305 return Arr.sortUnique(arr1.concat(arr2), sortFunc); 306 }); 307 308 // ********************************************************************************************* // 309 310 return Arr; 311 312 // ********************************************************************************************* // 313 }); 314