| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| 'use strict'; |
| |
| /** @module odatajs/utils */ |
| |
| |
| function inBrowser() { |
| return typeof window !== 'undefined'; |
| } |
| |
| /** Creates a new ActiveXObject from the given progId. |
| * @param {String} progId - ProgId string of the desired ActiveXObject. |
| * @returns {Object} The ActiveXObject instance. Null if ActiveX is not supported by the browser. |
| * This function throws whatever exception might occur during the creation |
| * of the ActiveXObject. |
| */ |
| var activeXObject = function (progId) { |
| |
| if (window.ActiveXObject) { |
| return new window.ActiveXObject(progId); |
| } |
| return null; |
| }; |
| |
| /** Checks whether the specified value is different from null and undefined. |
| * @param [value] Value to check ( may be null) |
| * @returns {Boolean} true if the value is assigned; false otherwise. |
| */ |
| function assigned(value) { |
| return value !== null && value !== undefined; |
| } |
| |
| /** Checks whether the specified item is in the array. |
| * @param {Array} [arr] Array to check in. |
| * @param item - Item to look for. |
| * @returns {Boolean} true if the item is contained, false otherwise. |
| */ |
| function contains(arr, item) { |
| var i, len; |
| for (i = 0, len = arr.length; i < len; i++) { |
| if (arr[i] === item) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** Given two values, picks the first one that is not undefined. |
| * @param a - First value. |
| * @param b - Second value. |
| * @returns a if it's a defined value; else b. |
| */ |
| function defined(a, b) { |
| return (a !== undefined) ? a : b; |
| } |
| |
| /** Delays the invocation of the specified function until execution unwinds. |
| * @param {Function} callback - Callback function. |
| */ |
| function delay(callback) { |
| |
| if (arguments.length === 1) { |
| window.setTimeout(callback, 0); |
| return; |
| } |
| |
| var args = Array.prototype.slice.call(arguments, 1); |
| window.setTimeout(function () { |
| callback.apply(this, args); |
| }, 0); |
| } |
| |
| /** Throws an exception in case that a condition evaluates to false. |
| * @param {Boolean} condition - Condition to evaluate. |
| * @param {String} message - Message explaining the assertion. |
| * @param {Object} data - Additional data to be included in the exception. |
| */ |
| function djsassert(condition, message, data) { |
| |
| |
| if (!condition) { |
| throw { message: "Assert fired: " + message, data: data }; |
| } |
| } |
| |
| /** Extends the target with the specified values. |
| * @param {Object} target - Object to add properties to. |
| * @param {Object} values - Object with properties to add into target. |
| * @returns {Object} The target object. |
| */ |
| function extend(target, values) { |
| for (var name in values) { |
| target[name] = values[name]; |
| } |
| |
| return target; |
| } |
| |
| function find(arr, callback) { |
| /** Returns the first item in the array that makes the callback function true. |
| * @param {Array} [arr] Array to check in. ( may be null) |
| * @param {Function} callback - Callback function to invoke once per item in the array. |
| * @returns The first item that makes the callback return true; null otherwise or if the array is null. |
| */ |
| |
| if (arr) { |
| var i, len; |
| for (i = 0, len = arr.length; i < len; i++) { |
| if (callback(arr[i])) { |
| return arr[i]; |
| } |
| } |
| } |
| return null; |
| } |
| |
| function isArray(value) { |
| /** Checks whether the specified value is an array object. |
| * @param value - Value to check. |
| * @returns {Boolean} true if the value is an array object; false otherwise. |
| */ |
| |
| return Object.prototype.toString.call(value) === "[object Array]"; |
| } |
| |
| /** Checks whether the specified value is a Date object. |
| * @param value - Value to check. |
| * @returns {Boolean} true if the value is a Date object; false otherwise. |
| */ |
| function isDate(value) { |
| return Object.prototype.toString.call(value) === "[object Date]"; |
| } |
| |
| /** Tests whether a value is an object. |
| * @param value - Value to test. |
| * @returns {Boolean} True is the value is an object; false otherwise. |
| * Per javascript rules, null and array values are objects and will cause this function to return true. |
| */ |
| function isObject(value) { |
| return typeof value === "object"; |
| } |
| |
| /** Parses a value in base 10. |
| * @param {String} value - String value to parse. |
| * @returns {Number} The parsed value, NaN if not a valid value. |
| */ |
| function parseInt10(value) { |
| return parseInt(value, 10); |
| } |
| |
| /** Renames a property in an object. |
| * @param {Object} obj - Object in which the property will be renamed. |
| * @param {String} oldName - Name of the property that will be renamed. |
| * @param {String} newName - New name of the property. |
| * This function will not do anything if the object doesn't own a property with the specified old name. |
| */ |
| function renameProperty(obj, oldName, newName) { |
| if (obj.hasOwnProperty(oldName)) { |
| obj[newName] = obj[oldName]; |
| delete obj[oldName]; |
| } |
| } |
| |
| /** Default error handler. |
| * @param {Object} error - Error to handle. |
| */ |
| function throwErrorCallback(error) { |
| throw error; |
| } |
| |
| /** Removes leading and trailing whitespaces from a string. |
| * @param {String} str String to trim |
| * @returns {String} The string with no leading or trailing whitespace. |
| */ |
| function trimString(str) { |
| if (str.trim) { |
| return str.trim(); |
| } |
| |
| return str.replace(/^\s+|\s+$/g, ''); |
| } |
| |
| /** Returns a default value in place of undefined. |
| * @param [value] Value to check (may be null) |
| * @param defaultValue - Value to return if value is undefined. |
| * @returns value if it's defined; defaultValue otherwise. |
| * This should only be used for cases where falsy values are valid; |
| * otherwise the pattern should be 'x = (value) ? value : defaultValue;'. |
| */ |
| function undefinedDefault(value, defaultValue) { |
| return (value !== undefined) ? value : defaultValue; |
| } |
| |
| // Regular expression that splits a uri into its components: |
| // 0 - is the matched string. |
| // 1 - is the scheme. |
| // 2 - is the authority. |
| // 3 - is the path. |
| // 4 - is the query. |
| // 5 - is the fragment. |
| var uriRegEx = /^([^:\/?#]+:)?(\/\/[^\/?#]*)?([^?#:]+)?(\?[^#]*)?(#.*)?/; |
| var uriPartNames = ["scheme", "authority", "path", "query", "fragment"]; |
| |
| /** Gets information about the components of the specified URI. |
| * @param {String} uri - URI to get information from. |
| * @return {Object} An object with an isAbsolute flag and part names (scheme, authority, etc.) if available. |
| */ |
| function getURIInfo(uri) { |
| var result = { isAbsolute: false }; |
| |
| if (uri) { |
| var matches = uriRegEx.exec(uri); |
| if (matches) { |
| var i, len; |
| for (i = 0, len = uriPartNames.length; i < len; i++) { |
| if (matches[i + 1]) { |
| result[uriPartNames[i]] = matches[i + 1]; |
| } |
| } |
| } |
| if (result.scheme) { |
| result.isAbsolute = true; |
| } |
| } |
| |
| return result; |
| } |
| |
| /** Builds a URI string from its components. |
| * @param {Object} uriInfo - An object with uri parts (scheme, authority, etc.). |
| * @returns {String} URI string. |
| */ |
| function getURIFromInfo(uriInfo) { |
| return "".concat( |
| uriInfo.scheme || "", |
| uriInfo.authority || "", |
| uriInfo.path || "", |
| uriInfo.query || "", |
| uriInfo.fragment || ""); |
| } |
| |
| // Regular expression that splits a uri authority into its subcomponents: |
| // 0 - is the matched string. |
| // 1 - is the userinfo subcomponent. |
| // 2 - is the host subcomponent. |
| // 3 - is the port component. |
| var uriAuthorityRegEx = /^\/{0,2}(?:([^@]*)@)?([^:]+)(?::{1}(\d+))?/; |
| |
| // Regular expression that matches percentage enconded octects (i.e %20 or %3A); |
| var pctEncodingRegEx = /%[0-9A-F]{2}/ig; |
| |
| /** Normalizes the casing of a URI. |
| * @param {String} uri - URI to normalize, absolute or relative. |
| * @returns {String} The URI normalized to lower case. |
| */ |
| function normalizeURICase(uri) { |
| var uriInfo = getURIInfo(uri); |
| var scheme = uriInfo.scheme; |
| var authority = uriInfo.authority; |
| |
| if (scheme) { |
| uriInfo.scheme = scheme.toLowerCase(); |
| if (authority) { |
| var matches = uriAuthorityRegEx.exec(authority); |
| if (matches) { |
| uriInfo.authority = "//" + |
| (matches[1] ? matches[1] + "@" : "") + |
| (matches[2].toLowerCase()) + |
| (matches[3] ? ":" + matches[3] : ""); |
| } |
| } |
| } |
| |
| uri = getURIFromInfo(uriInfo); |
| |
| return uri.replace(pctEncodingRegEx, function (str) { |
| return str.toLowerCase(); |
| }); |
| } |
| |
| /** Normalizes a possibly relative URI with a base URI. |
| * @param {String} uri - URI to normalize, absolute or relative |
| * @param {String} base - Base URI to compose with (may be null) |
| * @returns {String} The composed URI if relative; the original one if absolute. |
| */ |
| function normalizeURI(uri, base) { |
| if (!base) { |
| return uri; |
| } |
| |
| var uriInfo = getURIInfo(uri); |
| if (uriInfo.isAbsolute) { |
| return uri; |
| } |
| |
| var baseInfo = getURIInfo(base); |
| var normInfo = {}; |
| var path; |
| |
| if (uriInfo.authority) { |
| normInfo.authority = uriInfo.authority; |
| path = uriInfo.path; |
| normInfo.query = uriInfo.query; |
| } else { |
| if (!uriInfo.path) { |
| path = baseInfo.path; |
| normInfo.query = uriInfo.query || baseInfo.query; |
| } else { |
| if (uriInfo.path.charAt(0) === '/') { |
| path = uriInfo.path; |
| } else { |
| path = mergeUriPathWithBase(uriInfo.path, baseInfo.path); |
| } |
| normInfo.query = uriInfo.query; |
| } |
| normInfo.authority = baseInfo.authority; |
| } |
| |
| normInfo.path = removeDotsFromPath(path); |
| |
| normInfo.scheme = baseInfo.scheme; |
| normInfo.fragment = uriInfo.fragment; |
| |
| return getURIFromInfo(normInfo); |
| } |
| |
| /** Merges the path of a relative URI and a base URI. |
| * @param {String} uriPath - Relative URI path. |
| * @param {String} basePath - Base URI path. |
| * @returns {String} A string with the merged path. |
| */ |
| function mergeUriPathWithBase(uriPath, basePath) { |
| var path = "/"; |
| var end; |
| |
| if (basePath) { |
| end = basePath.lastIndexOf("/"); |
| path = basePath.substring(0, end); |
| |
| if (path.charAt(path.length - 1) !== "/") { |
| path = path + "/"; |
| } |
| } |
| |
| return path + uriPath; |
| } |
| |
| /** Removes the special folders . and .. from a URI's path. |
| * @param {string} path - URI path component. |
| * @returns {String} Path without any . and .. folders. |
| */ |
| function removeDotsFromPath(path) { |
| var result = ""; |
| var segment = ""; |
| var end; |
| |
| while (path) { |
| if (path.indexOf("..") === 0 || path.indexOf(".") === 0) { |
| path = path.replace(/^\.\.?\/?/g, ""); |
| } else if (path.indexOf("/..") === 0) { |
| path = path.replace(/^\/\..\/?/g, "/"); |
| end = result.lastIndexOf("/"); |
| if (end === -1) { |
| result = ""; |
| } else { |
| result = result.substring(0, end); |
| } |
| } else if (path.indexOf("/.") === 0) { |
| path = path.replace(/^\/\.\/?/g, "/"); |
| } else { |
| segment = path; |
| end = path.indexOf("/", 1); |
| if (end !== -1) { |
| segment = path.substring(0, end); |
| } |
| result = result + segment; |
| path = path.replace(segment, ""); |
| } |
| } |
| return result; |
| } |
| |
| function convertByteArrayToHexString(str) { |
| var arr = []; |
| if (window.atob === undefined) { |
| arr = decodeBase64(str); |
| } else { |
| var binaryStr = window.atob(str); |
| for (var i = 0; i < binaryStr.length; i++) { |
| arr.push(binaryStr.charCodeAt(i)); |
| } |
| } |
| var hexValue = ""; |
| var hexValues = "0123456789ABCDEF"; |
| for (var j = 0; j < arr.length; j++) { |
| var t = arr[j]; |
| hexValue += hexValues[t >> 4]; |
| hexValue += hexValues[t & 0x0F]; |
| } |
| return hexValue; |
| } |
| |
| function decodeBase64(str) { |
| var binaryString = ""; |
| for (var i = 0; i < str.length; i++) { |
| var base65IndexValue = getBase64IndexValue(str[i]); |
| var binaryValue = ""; |
| if (base65IndexValue !== null) { |
| binaryValue = base65IndexValue.toString(2); |
| binaryString += addBase64Padding(binaryValue); |
| } |
| } |
| var byteArray = []; |
| var numberOfBytes = parseInt(binaryString.length / 8, 10); |
| for (i = 0; i < numberOfBytes; i++) { |
| var intValue = parseInt(binaryString.substring(i * 8, (i + 1) * 8), 2); |
| byteArray.push(intValue); |
| } |
| return byteArray; |
| } |
| |
| function getBase64IndexValue(character) { |
| var asciiCode = character.charCodeAt(0); |
| var asciiOfA = 65; |
| var differenceBetweenZanda = 6; |
| if (asciiCode >= 65 && asciiCode <= 90) { // between "A" and "Z" inclusive |
| return asciiCode - asciiOfA; |
| } else if (asciiCode >= 97 && asciiCode <= 122) { // between 'a' and 'z' inclusive |
| return asciiCode - asciiOfA - differenceBetweenZanda; |
| } else if (asciiCode >= 48 && asciiCode <= 57) { // between '0' and '9' inclusive |
| return asciiCode + 4; |
| } else if (character == "+") { |
| return 62; |
| } else if (character == "/") { |
| return 63; |
| } else { |
| return null; |
| } |
| } |
| |
| function addBase64Padding(binaryString) { |
| while (binaryString.length < 6) { |
| binaryString = "0" + binaryString; |
| } |
| return binaryString; |
| |
| } |
| |
| function getJsonValueArraryLength(data) { |
| if (data && data.value) { |
| return data.value.length; |
| } |
| |
| return 0; |
| } |
| |
| function sliceJsonValueArray(data, start, end) { |
| if (data === undefined || data.value === undefined) { |
| return data; |
| } |
| |
| if (start < 0) { |
| start = 0; |
| } |
| |
| var length = getJsonValueArraryLength(data); |
| if (length < end) { |
| end = length; |
| } |
| |
| var newdata = {}; |
| for (var property in data) { |
| if (property == "value") { |
| newdata[property] = data[property].slice(start, end); |
| } else { |
| newdata[property] = data[property]; |
| } |
| } |
| |
| return newdata; |
| } |
| |
| function concatJsonValueArray(data, concatData) { |
| if (concatData === undefined || concatData.value === undefined) { |
| return data; |
| } |
| |
| if (data === undefined || Object.keys(data).length === 0) { |
| return concatData; |
| } |
| |
| if (data.value === undefined) { |
| data.value = concatData.value; |
| return data; |
| } |
| |
| data.value = data.value.concat(concatData.value); |
| |
| return data; |
| } |
| |
| function endsWith(input, search) { |
| return input.indexOf(search, input.length - search.length) !== -1; |
| } |
| |
| function startsWith (input, search) { |
| return input.indexOf(search) === 0; |
| } |
| |
| function getFormatKind(format, defaultFormatKind) { |
| var formatKind = defaultFormatKind; |
| if (!assigned(format)) { |
| return formatKind; |
| } |
| |
| var normalizedFormat = format.toLowerCase(); |
| switch (normalizedFormat) { |
| case "none": |
| formatKind = 0; |
| break; |
| case "minimal": |
| formatKind = 1; |
| break; |
| case "full": |
| formatKind = 2; |
| break; |
| default: |
| break; |
| } |
| |
| return formatKind; |
| } |
| |
| |
| |
| |
| exports.inBrowser = inBrowser; |
| exports.activeXObject = activeXObject; |
| exports.assigned = assigned; |
| exports.contains = contains; |
| exports.defined = defined; |
| exports.delay = delay; |
| exports.djsassert = djsassert; |
| exports.extend = extend; |
| exports.find = find; |
| exports.getURIInfo = getURIInfo; |
| exports.isArray = isArray; |
| exports.isDate = isDate; |
| exports.isObject = isObject; |
| exports.normalizeURI = normalizeURI; |
| exports.normalizeURICase = normalizeURICase; |
| exports.parseInt10 = parseInt10; |
| exports.renameProperty = renameProperty; |
| exports.throwErrorCallback = throwErrorCallback; |
| exports.trimString = trimString; |
| exports.undefinedDefault = undefinedDefault; |
| exports.decodeBase64 = decodeBase64; |
| exports.convertByteArrayToHexString = convertByteArrayToHexString; |
| exports.getJsonValueArraryLength = getJsonValueArraryLength; |
| exports.sliceJsonValueArray = sliceJsonValueArray; |
| exports.concatJsonValueArray = concatJsonValueArray; |
| exports.startsWith = startsWith; |
| exports.endsWith = endsWith; |
| exports.getFormatKind = getFormatKind; |