/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */ /*global Query, RSVP, deepClone */ /** * Escapes regexp special chars from a string. * * @param {String} string The string to escape * @return {String} The escaped string */ function stringEscapeRegexpCharacters(string) { if (typeof string === "string") { return string.replace(/([\\\.\$\[\]\(\)\{\}\^\?\*\+\-])/g, "\\$1"); } throw new TypeError("Query.stringEscapeRegexpCharacters(): " + "Argument no 1 is not of type 'string'"); } Query.stringEscapeRegexpCharacters = stringEscapeRegexpCharacters; /** * Convert metadata values to array of strings. ex: * * "a" -> ["a"], * {"content": "a"} -> ["a"] * * @param {Any} value The metadata value * @return {Array} The value in string array format */ function metadataValueToStringArray(value) { var i, new_value = []; if (value === undefined) { return undefined; } if (!Array.isArray(value)) { value = [value]; } for (i = 0; i < value.length; i += 1) { if (typeof value[i] === 'object') { new_value[i] = value[i].content; } else { new_value[i] = value[i]; } } return new_value; } /** * A sort function to sort items by key * * @param {String} key The key to sort on * @param {String} [way="ascending"] 'ascending' or 'descending' * @return {Function} The sort function */ function sortFunction(key, way) { var result; if (way === 'descending') { result = 1; } else if (way === 'ascending') { result = -1; } else { throw new TypeError("Query.sortFunction(): " + "Argument 2 must be 'ascending' or 'descending'"); } return function (a, b) { // this comparison is 5 times faster than json comparison var i, l; a = metadataValueToStringArray(a[key]) || []; b = metadataValueToStringArray(b[key]) || []; l = a.length > b.length ? a.length : b.length; for (i = 0; i < l; i += 1) { if (a[i] === undefined) { return result; } if (b[i] === undefined) { return -result; } if (a[i] > b[i]) { return -result; } if (a[i] < b[i]) { return result; } } return 0; }; } /** * Inherits the prototype methods from one constructor into another. The * prototype of `constructor` will be set to a new object created from * `superConstructor`. * * @param {Function} constructor The constructor which inherits the super one * @param {Function} superConstructor The super constructor */ function inherits(constructor, superConstructor) { constructor.super_ = superConstructor; constructor.prototype = Object.create(superConstructor.prototype, { "constructor": { "configurable": true, "enumerable": false, "writable": true, "value": constructor } }); } /** * Does nothing */ function emptyFunction() { return; } /** * Filter a list of items, modifying them to select only wanted keys. If * `clone` is true, then the method will act on a cloned list. * * @param {Array} select_option Key list to keep * @param {Array} list The item list to filter * @param {Boolean} [clone=false] If true, modifies a clone of the list * @return {Array} The filtered list */ function select(select_option, list, clone) { var i, j, new_item; if (!Array.isArray(select_option)) { throw new TypeError("jioquery.select(): " + "Argument 1 is not of type Array"); } if (!Array.isArray(list)) { throw new TypeError("jioquery.select(): " + "Argument 2 is not of type Array"); } if (clone === true) { list = deepClone(list); } for (i = 0; i < list.length; i += 1) { new_item = {}; for (j = 0; j < select_option.length; j += 1) { if (list[i].hasOwnProperty([select_option[j]])) { new_item[select_option[j]] = list[i][select_option[j]]; } } for (j in new_item) { if (new_item.hasOwnProperty(j)) { list[i] = new_item; break; } } } return list; } Query.select = select; /** * Sort a list of items, according to keys and directions. If `clone` is true, * then the method will act on a cloned list. * * @param {Array} sort_on_option List of couples [key, direction] * @param {Array} list The item list to sort * @param {Boolean} [clone=false] If true, modifies a clone of the list * @return {Array} The filtered list */ function sortOn(sort_on_option, list, clone) { var sort_index; if (!Array.isArray(sort_on_option)) { throw new TypeError("jioquery.sortOn(): " + "Argument 1 is not of type 'array'"); } if (clone) { list = deepClone(list); } for (sort_index = sort_on_option.length - 1; sort_index >= 0; sort_index -= 1) { list.sort(sortFunction( sort_on_option[sort_index][0], sort_on_option[sort_index][1] )); } return list; } Query.sortOn = sortOn; /** * Limit a list of items, according to index and length. If `clone` is true, * then the method will act on a cloned list. * * @param {Array} limit_option A couple [from, length] * @param {Array} list The item list to limit * @param {Boolean} [clone=false] If true, modifies a clone of the list * @return {Array} The filtered list */ function limit(limit_option, list, clone) { if (!Array.isArray(limit_option)) { throw new TypeError("jioquery.limit(): " + "Argument 1 is not of type 'array'"); } if (!Array.isArray(list)) { throw new TypeError("jioquery.limit(): " + "Argument 2 is not of type 'array'"); } if (clone) { list = deepClone(list); } list.splice(0, limit_option[0]); if (limit_option[1]) { list.splice(limit_option[1]); } return list; } Query.limit = limit; /** * Convert a search text to a regexp. * * @param {String} string The string to convert * @param {Boolean} [use_wildcard_character=true] Use wildcard "%" and "_" * @return {RegExp} The search text regexp */ function searchTextToRegExp(string, use_wildcard_characters) { if (typeof string !== 'string') { throw new TypeError("jioquery.searchTextToRegExp(): " + "Argument 1 is not of type 'string'"); } if (use_wildcard_characters === false) { return new RegExp("^" + stringEscapeRegexpCharacters(string) + "$"); } return new RegExp("^" + stringEscapeRegexpCharacters(string).replace( /%/g, ".*" ).replace( /_/g, "." ) + "$"); } Query.searchTextToRegExp = searchTextToRegExp;