cordova.define("cordova-plugin-googlemaps.BaseArrayClass", function(require, exports, module) { var utils = require('cordova/utils'), BaseClass = require('./BaseClass'); var ARRAY_FIELD = typeof Symbol === 'undefined' ? '__array' + Date.now() : Symbol('array'); var nextTick = function(fn) { Promise.resolve().then(fn); }; /** * Create a BaseArrayClass. * @class */ function BaseArrayClass(array) { BaseClass.apply(this); var self = this; self[ARRAY_FIELD] = []; if (array && (array instanceof Array || Array.isArray(array))) { for (var i = 0; i < array.length; i++) { self[ARRAY_FIELD].push(array[i]); } } } utils.extend(BaseArrayClass, BaseClass); /** * The same as `Array.map` but runs a single async operation at a time. * * @name mapSeries * @param {Function} iteratee - An async function to apply to each item in array. * @param {Function} [callback] - A callback which is called when all `iteratee` functions * have finished. Results is an array of the transformed items from holding array. * Invoked with (results); * @return {Promise} a promise, if no calback if passed. */ BaseArrayClass.prototype.mapSeries = function(iteratee, callback) { if (typeof iteratee !== 'function') { var error = new Error('iteratee must be a function'); if (typeof callback === 'function') { throw error; } else { return Promise.reject(error); } } var self = this; var results = []; var _arrayLength = self[ARRAY_FIELD].length; var currentCnt = 0; if (_arrayLength === 0) { if (typeof callback === 'function') { callback.call(self, []); return; } else { return Promise.resolve([]); } } var _looper = function(currentIdx, resolve) { iteratee.call(self, self[ARRAY_FIELD][currentIdx], function(value) { results[currentIdx] = value; currentCnt++; if (_arrayLength === currentCnt) { resolve(results); } else { nextTick(function() { _looper(currentIdx + 1, resolve); }); } }); }; return new Promise(function(resolve) { nextTick(function() { _looper(0, resolve); }); }).then(function(results) { if (typeof callback === 'function') { return callback.call(self, results); } else { return Promise.resolve(results); } }); }; /** * The same as `Array.map` but runs async all `iteratee` function at the same time. * * ``` * baseArray.mapAsync(function(item, idx, callback) { * ... * callback(value); * }).then(function(values) { * * }); * ``` * * @name mapAsync * @param {Function} iteratee - An async function to apply to each item in array. * @param {Function} [callback] - A callback which is called when all `iteratee` functions * have finished. Results is an array of the transformed items from holding array. * Invoked with (results); * @return {Promise} a promise, if no calback if passed. */ BaseArrayClass.prototype.mapAsync = function(iteratee, callback) { if (typeof iteratee !== 'function') { var error = new Error('iteratee must be a function'); if (typeof callback === 'function') { throw error; } else { return Promise.reject(error); } } var self = this; var results = []; for (var i = 0; i < self[ARRAY_FIELD].length; i++) { results.push(null); } var _arrayLength = self[ARRAY_FIELD].length; var finishCnt = 0; if (_arrayLength === 0) { if (typeof callback === 'function') { callback.call(self, []); return; } else { return Promise.resolve([]); } } return new Promise(function(resolve) { for (i = 0; i < self[ARRAY_FIELD].length; i++) { (function(item, idx) { nextTick(function() { iteratee.call(self, item, function(value) { results[idx] = value; finishCnt++; if (finishCnt === _arrayLength) { resolve(results); } }); }); })(self[ARRAY_FIELD][i], i); } }).then(function(results) { if (typeof callback === 'function') { return callback.call(self, results); } else { return Promise.resolve(results); } }); }; /** * If you provide `iteratee` and `callback`, work as `mapAsync()`. * If you provide `iteratee`, but omit `callback`, work as `Array.map()`. * * @deprecated * @name map * @param {Function} iteratee - An async function to apply to each item in array. * @param {Function} [callback] - A callback which is called when all `iteratee` functions * have finished. Results is an array of the transformed items from holding array. * Invoked with (results); * @return {Promise|any[]} a promise, if no calback if passed. If you omit `callback`, return transformed items. */ BaseArrayClass.prototype.map = function(iteratee, callback) { var self = this; if (typeof iteratee !== 'function') { var error = new Error('iteratee must be a function'); if (typeof callback === 'function') { throw error; } else { return Promise.reject(error); } } if (typeof callback !== 'function') { //------------------------ // example: // var values = baseArray.map(function(item, idx) { // ... // return someValue; // }); //------------------------ return self[ARRAY_FIELD].map(iteratee.bind(self)); } return self.mapAsync(iteratee, callback); }; /** * The same as `Array.forEach` but runs async all `iteratee` function at the same time. * * @name forEachAsync * @param {Function} iteratee - An async function to apply to each item in array. * @param {Function} [callback] - A callback which is called when all `iteratee` functions * have finished. * @return {Promise} a promise, if no calback if passed. */ BaseArrayClass.prototype.forEachAsync = function(iteratee, callback) { if (typeof iteratee !== 'function') { var error = new Error('iteratee must be a function'); if (typeof callback === 'function') { throw error; } else { return Promise.reject(error); } } var self = this; //------------------------ // example: // baseArray.forEach(function(item, callback) { // ... // callback(); // }, function() { // // }); //------------------------ var finishCnt = 0; var _arrayLength = self[ARRAY_FIELD].length; if (_arrayLength === 0) { if (typeof callback === 'function') { callback.call(self); return; } else { return Promise.resolve(); } } return new Promise(function(resolve) { self[ARRAY_FIELD].forEach(function(item) { iteratee.call(self, item, function() { finishCnt++; if (finishCnt === _arrayLength) { resolve(self); } }); }); }) .then(function() { if (typeof callback === 'function') { callback.call(self); return; } else { return Promise.resolve(); } }); }; /** * If you provide `iteratee` and `callback`, work as `forEachAsync()`. * If you provide `iteratee`, but you omit `callback`, work as `Array.forEach()` * * @deprecated * @name forEach * @param {Function} iteratee - An async function to apply to each item in array. * @param {Function} [callback] - A callback which is called when all `iteratee` functions * have finished. * Invoked with (results); * @return {Promise} a promise, if no calback if passed. */ BaseArrayClass.prototype.forEach = function(iteratee, callback) { var self = this; if (typeof iteratee !== 'function') { var error = new Error('iteratee must be a function'); if (typeof callback === 'function') { throw error; } else { return Promise.reject(error); } } if (typeof callback !== 'function') { //------------------------ // example: // baseArray.forEach(function(item, idx) { // ... // }); //------------------------ self[ARRAY_FIELD].forEach(iteratee.bind(self)); return Promise.resolve(); } return self.forEachAsync(iteratee, callback); }; /** * The same as `Array.filter` but runs async all `iteratee` function at the same time. * * @name filterAsync * @param {Function} iteratee - An async function to apply to each item in array. * @param {Function} [callback] - A callback which is called when all `iteratee` functions * have finished. Results is an array of the filtered items from holding array. * Invoked with (results); * @return {Promise} a promise, if no calback if passed. */ BaseArrayClass.prototype.filterAsync = function(iteratee, callback) { var self = this; if (typeof iteratee !== 'function') { var error = new Error('iteratee must be a function'); if (typeof callback === 'function') { throw error; } else { return Promise.reject(error); } } //------------------------ // example: // baseArray.filter(function(item, callback) { // ... // callback(true or false); // }, function(filteredItems) { // // }); //------------------------ var finishCnt = 0; var _arrayLength = self[ARRAY_FIELD].length; if (_arrayLength === 0) { if (typeof callback === 'function') { callback.call(self, []); return; } else { return Promise.resolve([]); } } return (new Promise(function(resolve) { var results = []; self[ARRAY_FIELD].forEach(function(item, idx) { iteratee.call(self, item, function(isOk) { results[idx] = isOk; finishCnt++; if (finishCnt === _arrayLength) { resolve(self[ARRAY_FIELD].filter(function(item, j) { return results[j]; })); } }); }); })) .then(function(results) { if (typeof callback === 'function') { callback.call(self, results); return; } else { return Promise.resolve(results); } }); }; /** * If you provide `iteratee` and `callback`, work as `filterAsync()`. * If you provide `iteratee`, but you omit `callback`, work as `Array.filter()` * * @deprecated * @name filter * @param {Function} iteratee - An async function to apply to each item in array. * @param {Function} [callback] - A callback which is called when all `iteratee` functions * have finished. * @return {Promise} a promise, if no calback if passed. */ BaseArrayClass.prototype.filter = function(iteratee, callback) { var self = this; if (typeof iteratee !== 'function') { var error = new Error('iteratee must be a function'); if (typeof callback === 'function') { throw error; } else { return Promise.reject(error); } } if (typeof callback !== 'function') { //------------------------ // example: // baseArray.filter(function(item, idx) { // ... // return true or false // }); //------------------------ return self[ARRAY_FIELD].filter(iteratee); } return self.filterAsync(iteratee, callback); }; /** * Returns the first index at which a given element can be found in the array, or -1 if it is not present. * * @name indexOf * @param {any} searchElement - Element to locate in the array. * @param {number} [searchElement] - The index to start the search at. * If the index is greater than or equal to the 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 array. * Note: if the provided index is negative, the array is still searched from front to back. * If the provided index is 0, then the whole array will be searched. Default: 0 (entire array is searched). * @return The first index of the element in the array; -1 if not found. */ BaseArrayClass.prototype.indexOf = function(item, searchElement) { searchElement = searchElement === undefined || searchElement === null ? 0 : searchElement; if (typeof searchElement !== 'number') { throw new Error('searchElement must be a number'); } if (searchElement < 0) { throw new Error('searchElement must be over number than 0'); } return this[ARRAY_FIELD].indexOf(item, searchElement); }; /** * Removes all elements. Fire `remove_at` event for each element. * * @name empty * @param {boolean} [noNotify] - Sets `true` if you don't want to fire `remove_at` event. */ BaseArrayClass.prototype.empty = function(noNotify) { var self = this; var cnt = self[ARRAY_FIELD].length; for (var i = cnt - 1; i >= 0; i--) { self.removeAt(i, noNotify); } }; /** * Adds one element to the end of an array and returns the new length of the array. * Fire `insert_at` event if `noNotify` is `false`. * * @name push * @param {any} value - The element to add to the end of the array. * @param {boolean} [noNotify] - Sets `true` if you don't want to fire `insert_at` event. * @return {number} The new length property of the object upon which the method was called. */ BaseArrayClass.prototype.push = function(value, noNotify) { var self = this; self[ARRAY_FIELD].push(value); if (noNotify !== true) { self.trigger('insert_at', self[ARRAY_FIELD].length - 1); } return self[ARRAY_FIELD].length; }; /** * Adds one element to the end of an array and returns the new length of the array. * Fire `insert_at` event if `noNotify` is `false`. * * @name insertAt * @param {number} index - The position of the array you want to insert new element. * @param {any} value - The element to add to the end of the array. * @param {boolean} [noNotify] - Sets `true` if you don't want to fire `insert_at` event. * @return {number} The new length property of the object upon which the method was called. */ BaseArrayClass.prototype.insertAt = function(index, value, noNotify) { var self = this; if (typeof index !== 'number') { throw new Error('index must be a number'); } if (index < 0) { throw new Error('index must be over number than 0'); } self[ARRAY_FIELD].splice(index, 0, value); if (noNotify !== true) { self.trigger('insert_at', index); } return self[ARRAY_FIELD].length; }; /** * Returns a new array that is the clone of internal array. * * @name getArray * @return {Array} New array */ BaseArrayClass.prototype.getArray = function() { //return _array.slice(0); <-- Android browser keeps the same instance of original array return JSON.parse(JSON.stringify(this[ARRAY_FIELD])); }; /** * Returns item of specified position. * * @name getAt * @param {number} index - The position of the array you want to get. * @return {any} item */ BaseArrayClass.prototype.getAt = function(index) { var self = this; if (typeof index !== 'number') { throw new Error('index must be a number'); } if (index < 0) { throw new Error('index must be over number than 0'); } if (index >= self[ARRAY_FIELD].length) { throw new Error('index must be lower number than ' + self[ARRAY_FIELD].length); } return this[ARRAY_FIELD][index]; }; /** * Replaces item of specified position. * * @name setAt * @param {number} index - The position of the array you want to get. * @param {any} value - New element * @param {boolean} [noNotify] - Sets `true` if you don't want to fire `set_at` event. * @return {any} previous item */ BaseArrayClass.prototype.setAt = function(index, value, noNotify) { var self = this; if (typeof index !== 'number') { throw new Error('index must be a number'); } if (index < 0) { throw new Error('index must be over number than 0'); } if (index > self[ARRAY_FIELD].length) { for (var i = self[ARRAY_FIELD].length; i <= index; i++) { self[ARRAY_FIELD][i] = undefined; } } var prev = self[ARRAY_FIELD][index]; self[ARRAY_FIELD][index] = value; if (noNotify !== true) { self.trigger('set_at', index, prev); } return prev; }; /** * Removes item of specified position. * * @name removeAt * @param {number} index - The position of the array you want to get. * @param {boolean} [noNotify] - Sets `true` if you don't want to fire `remove_at` event. * @return {any} removed item */ BaseArrayClass.prototype.removeAt = function(index, noNotify) { var self = this; if (typeof index !== 'number') { throw new Error('index must be a number'); } if (index < 0) { throw new Error('index must be over number than 0'); } if (index >= self[ARRAY_FIELD].length) { throw new Error('index must be lower number than ' + self[ARRAY_FIELD].length); } var value = self[ARRAY_FIELD][index]; self[ARRAY_FIELD].splice(index, 1); if (noNotify !== true) { self.trigger('remove_at', index, value); } return value; }; /** * Removes item of the last array item. * * @name pop * @param {boolean} [noNotify] - Sets `true` if you don't want to fire `remove_at` event. * @return {any} removed item */ BaseArrayClass.prototype.pop = function(noNotify) { var self = this; var index = self[ARRAY_FIELD].length - 1; var value = self[ARRAY_FIELD].pop(); if (noNotify !== true) { self.trigger('remove_at', index, value); } return value; }; /** * Returns the length of array. * * @name getLength * @return {any} Number of items */ BaseArrayClass.prototype.getLength = function() { return parseInt(this[ARRAY_FIELD].length, 10); // In order to prevent manupulating through `length` property, conver to number mandatory using `parseInt`. }; /** * Reverses an array in place. The first array element becomes the last, and the last array element becomes the first. * * @name reverse */ BaseArrayClass.prototype.reverse = function() { this[ARRAY_FIELD].reverse(); }; /** * The `sort()` method sorts the elements of an array in place and returns the array. * The same as `array.sort()`. * * @name sort * @param {Function} [compareFunction] - Specifies a function that defines the sort order. * If omitted, the array is sorted according to each character's Unicode code point value, * according to the string conversion of each element. */ BaseArrayClass.prototype.sort = function(compareFunction) { if (typeof compareFunction === 'function') { this[ARRAY_FIELD].sort(compareFunction); } else { this[ARRAY_FIELD].sort(); } }; module.exports = BaseArrayClass; });