You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ko...@apache.org on 2014/04/23 10:10:50 UTC
[01/15] [OLINGO-238] Build infrastructure for datajs I
Repository: olingo-odata4-js
Updated Branches:
refs/heads/OLINGO-238-browserify [created] f1cfcbc50
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/store-memory.js
----------------------------------------------------------------------
diff --git a/datajs/src/store-memory.js b/datajs/src/store-memory.js
deleted file mode 100644
index 4f35090..0000000
--- a/datajs/src/store-memory.js
+++ /dev/null
@@ -1,231 +0,0 @@
-// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
-// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// store-memory.js
-
-(function (window, undefined) {
-
- var datajs = window.datajs || {};
-
- // Imports.
- var throwErrorCallback = datajs.throwErrorCallback;
- var delay = datajs.delay;
-
- // CONTENT START
-
- var MemoryStore = function (name) {
- /// <summary>Constructor for store objects that use a sorted array as the underlying mechanism.</summary>
- /// <param name="name" type="String">Store name.</param>
-
- var holes = [];
- var items = [];
- var keys = {};
-
- this.name = name;
-
- var getErrorCallback = function (error) {
- return error || this.defaultError;
- };
-
- var validateKeyInput = function (key, error) {
- /// <summary>Validates that the specified key is not undefined, not null, and not an array</summary>
- /// <param name="key">Key value.</param>
- /// <param name="error" type="Function">Error callback.</param>
- /// <returns type="Boolean">True if the key is valid. False if the key is invalid and the error callback has been queued for execution.</returns>
-
- var messageString;
-
- if (key instanceof Array) {
- messageString = "Array of keys not supported";
- }
-
- if (key === undefined || key === null) {
- messageString = "Invalid key";
- }
-
- if (messageString) {
- delay(error, { message: messageString });
- return false;
- }
- return true;
- };
-
- this.add = function (key, value, success, error) {
- /// <summary>Adds a new value identified by a key to the store.</summary>
- /// <param name="key" type="String">Key string.</param>
- /// <param name="value">Value that is going to be added to the store.</param>
- /// <param name="success" type="Function" optional="no">Callback for a successful add operation.</param>
- /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
- /// <remarks>
- /// This method errors out if the store already contains the specified key.
- /// </remarks>
-
- error = getErrorCallback(error);
-
- if (validateKeyInput(key, error)) {
- if (!keys.hasOwnProperty(key)) {
- this.addOrUpdate(key, value, success, error);
- } else {
- error({ message: "key already exists", key: key });
- }
- }
- };
-
- this.addOrUpdate = function (key, value, success, error) {
- /// <summary>Adds or updates a value identified by a key to the store.</summary>
- /// <param name="key" type="String">Key string.</param>
- /// <param name="value">Value that is going to be added or updated to the store.</param>
- /// <param name="success" type="Function" optional="no">Callback for a successful add or update operation.</param>
- /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
- /// <remarks>
- /// This method will overwrite the key's current value if it already exists in the store; otherwise it simply adds the new key and value.
- /// </remarks>
-
- error = getErrorCallback(error);
-
- if (validateKeyInput(key, error)) {
- var index = keys[key];
- if (index === undefined) {
- if (holes.length > 0) {
- index = holes.splice(0, 1);
- } else {
- index = items.length;
- }
- }
- items[index] = value;
- keys[key] = index;
- delay(success, key, value);
- }
- };
-
- this.clear = function (success) {
- /// <summary>Removes all the data associated with this store object.</summary>
- /// <param name="success" type="Function" optional="no">Callback for a successful clear operation.</param>
-
- items = [];
- keys = {};
- holes = [];
-
- delay(success);
- };
-
- this.contains = function (key, success) {
- /// <summary>Checks whether a key exists in the store.</summary>
- /// <param name="key" type="String">Key string.</param>
- /// <param name="success" type="Function" optional="no">Callback indicating whether the store contains the key or not.</param>
-
- var contained = keys.hasOwnProperty(key);
- delay(success, contained);
- };
-
- this.getAllKeys = function (success) {
- /// <summary>Gets all the keys that exist in the store.</summary>
- /// <param name="success" type="Function" optional="no">Callback for a successful get operation.</param>
-
- var results = [];
- for (var name in keys) {
- results.push(name);
- }
- delay(success, results);
- };
-
- this.read = function (key, success, error) {
- /// <summary>Reads the value associated to a key in the store.</summary>
- /// <param name="key" type="String">Key string.</param>
- /// <param name="success" type="Function" optional="no">Callback for a successful reads operation.</param>
- /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
- error = getErrorCallback(error);
-
- if (validateKeyInput(key, error)) {
- var index = keys[key];
- delay(success, key, items[index]);
- }
- };
-
- this.remove = function (key, success, error) {
- /// <summary>Removes a key and its value from the store.</summary>
- /// <param name="key" type="String">Key string.</param>
- /// <param name="success" type="Function" optional="no">Callback for a successful remove operation.</param>
- /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
- error = getErrorCallback(error);
-
- if (validateKeyInput(key, error)) {
- var index = keys[key];
- if (index !== undefined) {
- if (index === items.length - 1) {
- items.pop();
- } else {
- items[index] = undefined;
- holes.push(index);
- }
- delete keys[key];
-
- // The last item was removed, no need to keep track of any holes in the array.
- if (items.length === 0) {
- holes = [];
- }
- }
-
- delay(success);
- }
- };
-
- this.update = function (key, value, success, error) {
- /// <summary>Updates the value associated to a key in the store.</summary>
- /// <param name="key" type="String">Key string.</param>
- /// <param name="value">New value.</param>
- /// <param name="success" type="Function" optional="no">Callback for a successful update operation.</param>
- /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
- /// <remarks>
- /// This method errors out if the specified key is not found in the store.
- /// </remarks>
-
- error = getErrorCallback(error);
- if (validateKeyInput(key, error)) {
- if (keys.hasOwnProperty(key)) {
- this.addOrUpdate(key, value, success, error);
- } else {
- error({ message: "key not found", key: key });
- }
- }
- };
- };
-
- MemoryStore.create = function (name) {
- /// <summary>Creates a store object that uses memory storage as its underlying mechanism.</summary>
- /// <param name="name" type="String">Store name.</param>
- /// <returns type="Object">Store object.</returns>
- return new MemoryStore(name);
- };
-
- MemoryStore.isSupported = function () {
- /// <summary>Checks whether the underlying mechanism for this kind of store objects is supported by the browser.</summary>
- /// <returns type="Boolean">True if the mechanism is supported by the browser; otherwise false.</returns>
- return true;
- };
-
- MemoryStore.prototype.close = function () {
- /// <summary>This function does nothing in MemoryStore as it does not have a connection model.</summary>
- };
-
- MemoryStore.prototype.defaultError = throwErrorCallback;
-
- /// <summary>Identifies the underlying mechanism used by the store.</summary>
- MemoryStore.prototype.mechanism = "memory";
-
- // DATAJS INTERNAL START
- datajs.MemoryStore = MemoryStore;
- // DATAJS INTERNAL END
-
- // CONTENT END
-})(this);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/store.js
----------------------------------------------------------------------
diff --git a/datajs/src/store.js b/datajs/src/store.js
deleted file mode 100644
index 688e88e..0000000
--- a/datajs/src/store.js
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
-// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// store.js
-
-(function (window, undefined) {
-
- var datajs = window.datajs || {};
-
- var DomStore = datajs.DomStore;
- var IndexedDBStore = datajs.IndexedDBStore;
- var MemoryStore = datajs.MemoryStore;
-
- // CONTENT START
-
- var mechanisms = {
- indexeddb: IndexedDBStore,
- dom: DomStore,
- memory: MemoryStore
- };
-
- datajs.defaultStoreMechanism = "best";
-
- datajs.createStore = function (name, mechanism) {
- /// <summary>Creates a new store object.</summary>
- /// <param name="name" type="String">Store name.</param>
- /// <param name="mechanism" type="String" optional="true">A specific mechanism to use (defaults to best, can be "best", "dom", "indexeddb", "webdb").</param>
- /// <returns type="Object">Store object.</returns>
-
- if (!mechanism) {
- mechanism = datajs.defaultStoreMechanism;
- }
-
- if (mechanism === "best") {
- mechanism = (DomStore.isSupported()) ? "dom" : "memory";
- }
-
- var factory = mechanisms[mechanism];
- if (factory) {
- return factory.create(name);
- }
-
- throw { message: "Failed to create store", name: name, mechanism: mechanism };
- };
-
- // DATAJS INTERNAL START
- datajs.mechanisms = mechanisms;
- // DATAJS INTERNAL END
-
- // CONTENT END
-})(this);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/utils.js
----------------------------------------------------------------------
diff --git a/datajs/src/utils.js b/datajs/src/utils.js
deleted file mode 100644
index 3dd3a49..0000000
--- a/datajs/src/utils.js
+++ /dev/null
@@ -1,490 +0,0 @@
-// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
-// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// utils.js
-
-(function (window, undefined) {
-
- var datajs = window.datajs || {};
-
- // CONTENT START
-
- var activeXObject = function (progId) {
- /// <summary>Creates a new ActiveXObject from the given progId.</summary>
- /// <param name="progId" type="String" mayBeNull="false" optional="false">
- /// ProgId string of the desired ActiveXObject.
- /// </param>
- /// <remarks>
- /// This function throws whatever exception might occur during the creation
- /// of the ActiveXObject.
- /// </remarks>
- /// <returns type="Object">
- /// The ActiveXObject instance. Null if ActiveX is not supported by the
- /// browser.
- /// </returns>
- if (window.ActiveXObject) {
- return new window.ActiveXObject(progId);
- }
- return null;
- };
-
- var assigned = function (value) {
- /// <summary>Checks whether the specified value is different from null and undefined.</summary>
- /// <param name="value" mayBeNull="true" optional="true">Value to check.</param>
- /// <returns type="Boolean">true if the value is assigned; false otherwise.</returns>
- return value !== null && value !== undefined;
- };
-
- var contains = function (arr, item) {
- /// <summary>Checks whether the specified item is in the array.</summary>
- /// <param name="arr" type="Array" optional="false" mayBeNull="false">Array to check in.</param>
- /// <param name="item">Item to look for.</param>
- /// <returns type="Boolean">true if the item is contained, false otherwise.</returns>
-
- var i, len;
- for (i = 0, len = arr.length; i < len; i++) {
- if (arr[i] === item) {
- return true;
- }
- }
-
- return false;
- };
-
- var defined = function (a, b) {
- /// <summary>Given two values, picks the first one that is not undefined.</summary>
- /// <param name="a">First value.</param>
- /// <param name="b">Second value.</param>
- /// <returns>a if it's a defined value; else b.</returns>
- return (a !== undefined) ? a : b;
- };
-
- var delay = function (callback) {
- /// <summary>Delays the invocation of the specified function until execution unwinds.</summary>
- /// <param name="callback" type="Function">Callback function.</param>
- 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);
- };
-
- // DATAJS INTERNAL START
- var djsassert = function (condition, message, data) {
- /// <summary>Throws an exception in case that a condition evaluates to false.</summary>
- /// <param name="condition" type="Boolean">Condition to evaluate.</param>
- /// <param name="message" type="String">Message explaining the assertion.</param>
- /// <param name="data" type="Object">Additional data to be included in the exception.</param>
-
- if (!condition) {
- throw { message: "Assert fired: " + message, data: data };
- };
- };
- // DATAJS INTERNAL END
-
- var extend = function (target, values) {
- /// <summary>Extends the target with the specified values.</summary>
- /// <param name="target" type="Object">Object to add properties to.</param>
- /// <param name="values" type="Object">Object with properties to add into target.</param>
- /// <returns type="Object">The target object.</returns>
-
- for (var name in values) {
- target[name] = values[name];
- }
-
- return target;
- };
-
- var find = function (arr, callback) {
- /// <summary>Returns the first item in the array that makes the callback function true.</summary>
- /// <param name="arr" type="Array" optional="false" mayBeNull="true">Array to check in.</param>
- /// <param name="callback" type="Function">Callback function to invoke once per item in the array.</param>
- /// <returns>The first item that makes the callback return true; null otherwise or if the array is null.</returns>
-
- if (arr) {
- var i, len;
- for (i = 0, len = arr.length; i < len; i++) {
- if (callback(arr[i])) {
- return arr[i];
- }
- }
- }
- return null;
- };
-
- var isArray = function (value) {
- /// <summary>Checks whether the specified value is an array object.</summary>
- /// <param name="value">Value to check.</param>
- /// <returns type="Boolean">true if the value is an array object; false otherwise.</returns>
-
- return Object.prototype.toString.call(value) === "[object Array]";
- };
-
- var isDate = function (value) {
- /// <summary>Checks whether the specified value is a Date object.</summary>
- /// <param name="value">Value to check.</param>
- /// <returns type="Boolean">true if the value is a Date object; false otherwise.</returns>
-
- return Object.prototype.toString.call(value) === "[object Date]";
- };
-
- var isObject = function (value) {
- /// <summary>Tests whether a value is an object.</summary>
- /// <param name="value">Value to test.</param>
- /// <remarks>
- /// Per javascript rules, null and array values are objects and will cause this function to return true.
- /// </remarks>
- /// <returns type="Boolean">True is the value is an object; false otherwise.</returns>
-
- return typeof value === "object";
- };
-
- var parseInt10 = function (value) {
- /// <summary>Parses a value in base 10.</summary>
- /// <param name="value" type="String">String value to parse.</param>
- /// <returns type="Number">The parsed value, NaN if not a valid value.</returns>
-
- return parseInt(value, 10);
- };
-
- var renameProperty = function (obj, oldName, newName) {
- /// <summary>Renames a property in an object.</summary>
- /// <param name="obj" type="Object">Object in which the property will be renamed.</param>
- /// <param name="oldName" type="String">Name of the property that will be renamed.</param>
- /// <param name="newName" type="String">New name of the property.</param>
- /// <remarks>
- /// This function will not do anything if the object doesn't own a property with the specified old name.
- /// </remarks>
-
- if (obj.hasOwnProperty(oldName)) {
- obj[newName] = obj[oldName];
- delete obj[oldName];
- }
- };
-
- var throwErrorCallback = function (error) {
- /// <summary>Default error handler.</summary>
- /// <param name="error" type="Object">Error to handle.</param>
- throw error;
- };
-
- var trimString = function (str) {
- /// <summary>Removes leading and trailing whitespaces from a string.</summary>
- /// <param name="str" type="String" optional="false" mayBeNull="false">String to trim</param>
- /// <returns type="String">The string with no leading or trailing whitespace.</returns>
-
- if (str.trim) {
- return str.trim();
- }
-
- return str.replace(/^\s+|\s+$/g, '');
- };
-
- var undefinedDefault = function (value, defaultValue) {
- /// <summary>Returns a default value in place of undefined.</summary>
- /// <param name="value" mayBeNull="true" optional="true">Value to check.</param>
- /// <param name="defaultValue">Value to return if value is undefined.</param>
- /// <returns>value if it's defined; defaultValue otherwise.</returns>
- /// <remarks>
- /// This should only be used for cases where falsy values are valid;
- /// otherwise the pattern should be 'x = (value) ? value : defaultValue;'.
- /// </remarks>
- 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"];
-
- var getURIInfo = function (uri) {
- /// <summary>Gets information about the components of the specified URI.</summary>
- /// <param name="uri" type="String">URI to get information from.</param>
- /// <returns type="Object">
- /// An object with an isAbsolute flag and part names (scheme, authority, etc.) if available.
- /// </returns>
-
- 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;
- };
-
- var getURIFromInfo = function (uriInfo) {
- /// <summary>Builds a URI string from its components.</summary>
- /// <param name="uriInfo" type="Object"> An object with uri parts (scheme, authority, etc.).</param>
- /// <returns type="String">URI string.</returns>
-
- 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;
-
- var normalizeURICase = function (uri) {
- /// <summary>Normalizes the casing of a URI.</summary>
- /// <param name="uri" type="String">URI to normalize, absolute or relative.</param>
- /// <returns type="String">The URI normalized to lower case.</returns>
-
- 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();
- });
- };
-
- var normalizeURI = function (uri, base) {
- /// <summary>Normalizes a possibly relative URI with a base URI.</summary>
- /// <param name="uri" type="String">URI to normalize, absolute or relative.</param>
- /// <param name="base" type="String" mayBeNull="true">Base URI to compose with.</param>
- /// <returns type="String">The composed URI if relative; the original one if absolute.</returns>
-
- 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);
- };
-
- var mergeUriPathWithBase = function (uriPath, basePath) {
- /// <summary>Merges the path of a relative URI and a base URI.</summary>
- /// <param name="uriPath" type="String>Relative URI path.</param>
- /// <param name="basePath" type="String">Base URI path.</param>
- /// <returns type="String">A string with the merged path.</returns>
-
- 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;
- };
-
- var removeDotsFromPath = function (path) {
- /// <summary>Removes the special folders . and .. from a URI's path.</summary>
- /// <param name="path" type="string">URI path component.</param>
- /// <returns type="String">Path without any . and .. folders.</returns>
-
- 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;
- };
-
- var convertByteArrayToHexString = function (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;
- };
-
- var decodeBase64 = function (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;
- };
-
- var getBase64IndexValue = function (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;
- }
- };
-
- var addBase64Padding = function (binaryString) {
- while (binaryString.length < 6) {
- binaryString = "0" + binaryString;
- }
- return binaryString;
- };
- // DATAJS INTERNAL START
-
- datajs.activeXObject = activeXObject;
- datajs.assigned = assigned;
- datajs.contains = contains;
- datajs.defined = defined;
- datajs.delay = delay;
- datajs.djsassert = djsassert;
- datajs.extend = extend;
- datajs.find = find;
- datajs.getURIInfo = getURIInfo;
- datajs.isArray = isArray;
- datajs.isDate = isDate;
- datajs.isObject = isObject;
- datajs.normalizeURI = normalizeURI;
- datajs.normalizeURICase = normalizeURICase;
- datajs.parseInt10 = parseInt10;
- datajs.renameProperty = renameProperty;
- datajs.throwErrorCallback = throwErrorCallback;
- datajs.trimString = trimString;
- datajs.undefinedDefault = undefinedDefault;
- datajs.decodeBase64 = decodeBase64;
- datajs.convertByteArrayToHexString = convertByteArrayToHexString;
- // DATAJS INTERNAL END
-
- // CONTENT END
-})(this);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/xml.js
----------------------------------------------------------------------
diff --git a/datajs/src/xml.js b/datajs/src/xml.js
deleted file mode 100644
index 895a4c7..0000000
--- a/datajs/src/xml.js
+++ /dev/null
@@ -1,824 +0,0 @@
-// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
-// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// xml.js
-
-(function (window, undefined) {
-
- var datajs = window.datajs;
-
- var activeXObject = datajs.activeXObject;
- var djsassert = datajs.djsassert;
- var extend = datajs.extend;
- var isArray = datajs.isArray;
- var isObject = datajs.isObject;
- var normalizeURI = datajs.normalizeURI;
-
- // CONTENT START
-
- // URI prefixes to generate smaller code.
- var http = "http://";
- var w3org = http + "www.w3.org/"; // http://www.w3.org/
-
- var xhtmlNS = w3org + "1999/xhtml"; // http://www.w3.org/1999/xhtml
- var xmlnsNS = w3org + "2000/xmlns/"; // http://www.w3.org/2000/xmlns/
- var xmlNS = w3org + "XML/1998/namespace"; // http://www.w3.org/XML/1998/namespace
-
- var mozillaParserErroNS = http + "www.mozilla.org/newlayout/xml/parsererror.xml";
-
- var hasLeadingOrTrailingWhitespace = function (text) {
- /// <summary>Checks whether the specified string has leading or trailing spaces.</summary>
- /// <param name="text" type="String">String to check.</param>
- /// <returns type="Boolean">true if text has any leading or trailing whitespace; false otherwise.</returns>
-
- var re = /(^\s)|(\s$)/;
- return re.test(text);
- };
-
- var isWhitespace = function (text) {
- /// <summary>Determines whether the specified text is empty or whitespace.</summary>
- /// <param name="text" type="String">Value to inspect.</param>
- /// <returns type="Boolean">true if the text value is empty or all whitespace; false otherwise.</returns>
-
- var ws = /^\s*$/;
- return text === null || ws.test(text);
- };
-
- var isWhitespacePreserveContext = function (domElement) {
- /// <summary>Determines whether the specified element has xml:space='preserve' applied.</summary>
- /// <param name="domElement">Element to inspect.</param>
- /// <returns type="Boolean">Whether xml:space='preserve' is in effect.</returns>
-
- while (domElement !== null && domElement.nodeType === 1) {
- var val = xmlAttributeValue(domElement, "space", xmlNS);
- if (val === "preserve") {
- return true;
- } else if (val === "default") {
- break;
- } else {
- domElement = domElement.parentNode;
- }
- }
-
- return false;
- };
-
- var isXmlNSDeclaration = function (domAttribute) {
- /// <summary>Determines whether the attribute is a XML namespace declaration.</summary>
- /// <param name="domAttribute">Element to inspect.</param>
- /// <returns type="Boolean">
- /// True if the attribute is a namespace declaration (its name is 'xmlns' or starts with 'xmlns:'; false otherwise.
- /// </returns>
-
- var nodeName = domAttribute.nodeName;
- return nodeName == "xmlns" || nodeName.indexOf("xmlns:") === 0;
- };
-
- var safeSetProperty = function (obj, name, value) {
- /// <summary>Safely set as property in an object by invoking obj.setProperty.</summary>
- /// <param name="obj">Object that exposes a setProperty method.</param>
- /// <param name="name" type="String" mayBeNull="false">Property name.</param>
- /// <param name="value">Property value.</param>
-
- try {
- obj.setProperty(name, value);
- } catch (_) { }
- };
-
- var msXmlDom3 = function () {
- /// <summary>Creates an configures new MSXML 3.0 ActiveX object.</summary>
- /// <remakrs>
- /// This function throws any exception that occurs during the creation
- /// of the MSXML 3.0 ActiveX object.
- /// <returns type="Object">New MSXML 3.0 ActiveX object.</returns>
-
- var msxml3 = activeXObject("Msxml2.DOMDocument.3.0");
- if (msxml3) {
- safeSetProperty(msxml3, "ProhibitDTD", true);
- safeSetProperty(msxml3, "MaxElementDepth", 256);
- safeSetProperty(msxml3, "AllowDocumentFunction", false);
- safeSetProperty(msxml3, "AllowXsltScript", false);
- }
- return msxml3;
- };
-
- var msXmlDom = function () {
- /// <summary>Creates an configures new MSXML 6.0 or MSXML 3.0 ActiveX object.</summary>
- /// <remakrs>
- /// This function will try to create a new MSXML 6.0 ActiveX object. If it fails then
- /// it will fallback to create a new MSXML 3.0 ActiveX object. Any exception that
- /// happens during the creation of the MSXML 6.0 will be handled by the function while
- /// the ones that happend during the creation of the MSXML 3.0 will be thrown.
- /// <returns type="Object">New MSXML 3.0 ActiveX object.</returns>
-
- try {
- var msxml = activeXObject("Msxml2.DOMDocument.6.0");
- if (msxml) {
- msxml.async = true;
- }
- return msxml;
- } catch (_) {
- return msXmlDom3();
- }
- };
-
- var msXmlParse = function (text) {
- /// <summary>Parses an XML string using the MSXML DOM.</summary>
- /// <remakrs>
- /// This function throws any exception that occurs during the creation
- /// of the MSXML ActiveX object. It also will throw an exception
- /// in case of a parsing error.
- /// <returns type="Object">New MSXML DOMDocument node representing the parsed XML string.</returns>
-
- var dom = msXmlDom();
- if (!dom) {
- return null;
- }
-
- dom.loadXML(text);
- var parseError = dom.parseError;
- if (parseError.errorCode !== 0) {
- xmlThrowParserError(parseError.reason, parseError.srcText, text);
- }
- return dom;
- };
-
- var xmlThrowParserError = function (exceptionOrReason, srcText, errorXmlText) {
- /// <summary>Throws a new exception containing XML parsing error information.</summary>
- /// <param name="exceptionOrReason">
- /// String indicatin the reason of the parsing failure or
- /// Object detailing the parsing error.
- /// </param>
- /// <param name="srcText" type="String">
- /// String indicating the part of the XML string that caused the parsing error.
- /// </param>
- /// <param name="errorXmlText" type="String">XML string for wich the parsing failed.</param>
-
- if (typeof exceptionOrReason === "string") {
- exceptionOrReason = { message: exceptionOrReason };
- }
- throw extend(exceptionOrReason, { srcText: srcText || "", errorXmlText: errorXmlText || "" });
- };
-
- var xmlParse = function (text) {
- /// <summary>Returns an XML DOM document from the specified text.</summary>
- /// <param name="text" type="String">Document text.</param>
- /// <returns>XML DOM document.</returns>
- /// <remarks>This function will throw an exception in case of a parse error.</remarks>
-
- var domParser = window.DOMParser && new window.DOMParser();
- var dom;
-
- if (!domParser) {
- dom = msXmlParse(text);
- if (!dom) {
- xmlThrowParserError("XML DOM parser not supported");
- }
- return dom;
- }
-
- try {
- dom = domParser.parseFromString(text, "text/xml");
- } catch (e) {
- xmlThrowParserError(e, "", text);
- }
-
- var element = dom.documentElement;
- var nsURI = element.namespaceURI;
- var localName = xmlLocalName(element);
-
- // Firefox reports errors by returing the DOM for an xml document describing the problem.
- if (localName === "parsererror" && nsURI === mozillaParserErroNS) {
- var srcTextElement = xmlFirstChildElement(element, mozillaParserErroNS, "sourcetext");
- var srcText = srcTextElement ? xmlNodeValue(srcTextElement) : "";
- xmlThrowParserError(xmlInnerText(element) || "", srcText, text);
- }
-
- // Chrome (and maybe other webkit based browsers) report errors by injecting a header with an error message.
- // The error may be localized, so instead we simply check for a header as the
- // top element or descendant child of the document.
- if (localName === "h3" && nsURI === xhtmlNS || xmlFirstDescendantElement(element, xhtmlNS, "h3")) {
- var reason = "";
- var siblings = [];
- var cursor = element.firstChild;
- while (cursor) {
- if (cursor.nodeType === 1) {
- reason += xmlInnerText(cursor) || "";
- }
- siblings.push(cursor.nextSibling);
- cursor = cursor.firstChild || siblings.shift();
- }
- reason += xmlInnerText(element) || "";
- xmlThrowParserError(reason, "", text);
- }
-
- return dom;
- };
-
- var xmlQualifiedName = function (prefix, name) {
- /// <summary>Builds a XML qualified name string in the form of "prefix:name".</summary>
- /// <param name="prefix" type="String" maybeNull="true">Prefix string.</param>
- /// <param name="name" type="String">Name string to qualify with the prefix.</param>
- /// <returns type="String">Qualified name.</returns>
-
- return prefix ? prefix + ":" + name : name;
- };
-
- var xmlAppendText = function (domNode, textNode) {
- /// <summary>Appends a text node into the specified DOM element node.</summary>
- /// <param name="domNode">DOM node for the element.</param>
- /// <param name="text" type="String" mayBeNull="false">Text to append as a child of element.</param>
- if (hasLeadingOrTrailingWhitespace(textNode.data)) {
- var attr = xmlAttributeNode(domNode, xmlNS, "space");
- if (!attr) {
- attr = xmlNewAttribute(domNode.ownerDocument, xmlNS, xmlQualifiedName("xml", "space"));
- xmlAppendChild(domNode, attr);
- }
- attr.value = "preserve";
- }
- domNode.appendChild(textNode);
- return domNode;
- };
-
- var xmlAttributes = function (element, onAttributeCallback) {
- /// <summary>Iterates through the XML element's attributes and invokes the callback function for each one.</summary>
- /// <param name="element">Wrapped element to iterate over.</param>
- /// <param name="onAttributeCallback" type="Function">Callback function to invoke with wrapped attribute nodes.</param>
-
- var attributes = element.attributes;
- var i, len;
- for (i = 0, len = attributes.length; i < len; i++) {
- onAttributeCallback(attributes.item(i));
- }
- };
-
- var xmlAttributeValue = function (domNode, localName, nsURI) {
- /// <summary>Returns the value of a DOM element's attribute.</summary>
- /// <param name="domNode">DOM node for the owning element.</param>
- /// <param name="localName" type="String">Local name of the attribute.</param>
- /// <param name="nsURI" type="String">Namespace URI of the attribute.</param>
- /// <returns type="String" maybeNull="true">The attribute value, null if not found.</returns>
-
- var attribute = xmlAttributeNode(domNode, localName, nsURI);
- return attribute ? xmlNodeValue(attribute) : null;
- };
-
- var xmlAttributeNode = function (domNode, localName, nsURI) {
- /// <summary>Gets an attribute node from a DOM element.</summary>
- /// <param name="domNode">DOM node for the owning element.</param>
- /// <param name="localName" type="String">Local name of the attribute.</param>
- /// <param name="nsURI" type="String">Namespace URI of the attribute.</param>
- /// <returns>The attribute node, null if not found.</returns>
-
- var attributes = domNode.attributes;
- if (attributes.getNamedItemNS) {
- return attributes.getNamedItemNS(nsURI || null, localName);
- }
-
- return attributes.getQualifiedItem(localName, nsURI) || null;
- };
-
- var xmlBaseURI = function (domNode, baseURI) {
- /// <summary>Gets the value of the xml:base attribute on the specified element.</summary>
- /// <param name="domNode">Element to get xml:base attribute value from.</param>
- /// <param name="baseURI" mayBeNull="true" optional="true">Base URI used to normalize the value of the xml:base attribute.</param>
- /// <returns type="String">Value of the xml:base attribute if found; the baseURI or null otherwise.</returns>
-
- var base = xmlAttributeNode(domNode, "base", xmlNS);
- return (base ? normalizeURI(base.value, baseURI) : baseURI) || null;
- };
-
-
- var xmlChildElements = function (domNode, onElementCallback) {
- /// <summary>Iterates through the XML element's child DOM elements and invokes the callback function for each one.</summary>
- /// <param name="element">DOM Node containing the DOM elements to iterate over.</param>
- /// <param name="onElementCallback" type="Function">Callback function to invoke for each child DOM element.</param>
-
- xmlTraverse(domNode, /*recursive*/false, function (child) {
- if (child.nodeType === 1) {
- onElementCallback(child);
- }
- // continue traversing.
- return true;
- });
- };
-
- var xmlFindElementByPath = function (root, namespaceURI, path) {
- /// <summary>Gets the descendant element under root that corresponds to the specified path and namespace URI.</summary>
- /// <param name="root">DOM element node from which to get the descendant element.</param>
- /// <param name="namespaceURI" type="String">The namespace URI of the element to match.</param>
- /// <param name="path" type="String">Path to the desired descendant element.</param>
- /// <returns>The element specified by path and namespace URI.</returns>
- /// <remarks>
- /// All the elements in the path are matched against namespaceURI.
- /// The function will stop searching on the first element that doesn't match the namespace and the path.
- /// </remarks>
-
- var parts = path.split("/");
- var i, len;
- for (i = 0, len = parts.length; i < len; i++) {
- root = root && xmlFirstChildElement(root, namespaceURI, parts[i]);
- }
- return root || null;
- };
-
- var xmlFindNodeByPath = function (root, namespaceURI, path) {
- /// <summary>Gets the DOM element or DOM attribute node under root that corresponds to the specified path and namespace URI.</summary>
- /// <param name="root">DOM element node from which to get the descendant node.</param>
- /// <param name="namespaceURI" type="String">The namespace URI of the node to match.</param>
- /// <param name="path" type="String">Path to the desired descendant node.</param>
- /// <returns>The node specified by path and namespace URI.</returns>
- /// <remarks>
- /// This function will traverse the path and match each node associated to a path segement against the namespace URI.
- /// The traversal stops when the whole path has been exahusted or a node that doesn't belogong the specified namespace is encountered.
- ///
- /// The last segment of the path may be decorated with a starting @ character to indicate that the desired node is a DOM attribute.
- /// </remarks>
-
- var lastSegmentStart = path.lastIndexOf("/");
- var nodePath = path.substring(lastSegmentStart + 1);
- var parentPath = path.substring(0, lastSegmentStart);
-
- var node = parentPath ? xmlFindElementByPath(root, namespaceURI, parentPath) : root;
- if (node) {
- if (nodePath.charAt(0) === "@") {
- return xmlAttributeNode(node, nodePath.substring(1), namespaceURI);
- }
- return xmlFirstChildElement(node, namespaceURI, nodePath);
- }
- return null;
- };
-
- var xmlFirstChildElement = function (domNode, namespaceURI, localName) {
- /// <summary>Returns the first child DOM element under the specified DOM node that matches the specified namespace URI and local name.</summary>
- /// <param name="domNode">DOM node from which the child DOM element is going to be retrieved.</param>
- /// <param name="namespaceURI" type="String" optional="true">The namespace URI of the element to match.</param>
- /// <param name="localName" type="String" optional="true">Name of the element to match.</param>
- /// <returns>The node's first child DOM element that matches the specified namespace URI and local name; null otherwise.</returns>
-
- return xmlFirstElementMaybeRecursive(domNode, namespaceURI, localName, /*recursive*/false);
- };
-
- var xmlFirstDescendantElement = function (domNode, namespaceURI, localName) {
- /// <summary>Returns the first descendant DOM element under the specified DOM node that matches the specified namespace URI and local name.</summary>
- /// <param name="domNode">DOM node from which the descendant DOM element is going to be retrieved.</param>
- /// <param name="namespaceURI" type="String" optional="true">The namespace URI of the element to match.</param>
- /// <param name="localName" type="String" optional="true">Name of the element to match.</param>
- /// <returns>The node's first descendant DOM element that matches the specified namespace URI and local name; null otherwise.</returns>
-
- if (domNode.getElementsByTagNameNS) {
- var result = domNode.getElementsByTagNameNS(namespaceURI, localName);
- return result.length > 0 ? result[0] : null;
- }
- return xmlFirstElementMaybeRecursive(domNode, namespaceURI, localName, /*recursive*/true);
- };
-
- var xmlFirstElementMaybeRecursive = function (domNode, namespaceURI, localName, recursive) {
- /// <summary>Returns the first descendant DOM element under the specified DOM node that matches the specified namespace URI and local name.</summary>
- /// <param name="domNode">DOM node from which the descendant DOM element is going to be retrieved.</param>
- /// <param name="namespaceURI" type="String" optional="true">The namespace URI of the element to match.</param>
- /// <param name="localName" type="String" optional="true">Name of the element to match.</param>
- /// <param name="recursive" type="Boolean">
- /// True if the search should include all the descendants of the DOM node.
- /// False if the search should be scoped only to the direct children of the DOM node.
- /// </param>
- /// <returns>The node's first descendant DOM element that matches the specified namespace URI and local name; null otherwise.</returns>
-
- var firstElement = null;
- xmlTraverse(domNode, recursive, function (child) {
- if (child.nodeType === 1) {
- var isExpectedNamespace = !namespaceURI || xmlNamespaceURI(child) === namespaceURI;
- var isExpectedNodeName = !localName || xmlLocalName(child) === localName;
-
- if (isExpectedNamespace && isExpectedNodeName) {
- firstElement = child;
- }
- }
- return firstElement === null;
- });
- return firstElement;
- };
-
- var xmlInnerText = function (xmlElement) {
- /// <summary>Gets the concatenated value of all immediate child text and CDATA nodes for the specified element.</summary>
- /// <param name="domElement">Element to get values for.</param>
- /// <returns type="String">Text for all direct children.</returns>
-
- var result = null;
- var root = (xmlElement.nodeType === 9 && xmlElement.documentElement) ? xmlElement.documentElement : xmlElement;
- var whitespaceAlreadyRemoved = root.ownerDocument.preserveWhiteSpace === false;
- var whitespacePreserveContext;
-
- xmlTraverse(root, false, function (child) {
- if (child.nodeType === 3 || child.nodeType === 4) {
- // isElementContentWhitespace indicates that this is 'ignorable whitespace',
- // but it's not defined by all browsers, and does not honor xml:space='preserve'
- // in some implementations.
- //
- // If we can't tell either way, we walk up the tree to figure out whether
- // xml:space is set to preserve; otherwise we discard pure-whitespace.
- //
- // For example <a> <b>1</b></a>. The space between <a> and <b> is usually 'ignorable'.
- var text = xmlNodeValue(child);
- var shouldInclude = whitespaceAlreadyRemoved || !isWhitespace(text);
- if (!shouldInclude) {
- // Walk up the tree to figure out whether we are in xml:space='preserve' context
- // for the cursor (needs to happen only once).
- if (whitespacePreserveContext === undefined) {
- whitespacePreserveContext = isWhitespacePreserveContext(root);
- }
-
- shouldInclude = whitespacePreserveContext;
- }
-
- if (shouldInclude) {
- if (!result) {
- result = text;
- } else {
- result += text;
- }
- }
- }
- // Continue traversing?
- return true;
- });
- return result;
- };
-
- var xmlLocalName = function (domNode) {
- /// <summary>Returns the localName of a XML node.</summary>
- /// <param name="domNode">DOM node to get the value from.</param>
- /// <returns type="String">localName of domNode.</returns>
-
- return domNode.localName || domNode.baseName;
- };
-
- var xmlNamespaceURI = function (domNode) {
- /// <summary>Returns the namespace URI of a XML node.</summary>
- /// <param name="node">DOM node to get the value from.</param>
- /// <returns type="String">Namespace URI of domNode.</returns>
-
- return domNode.namespaceURI || null;
- };
-
- var xmlNodeValue = function (domNode) {
- /// <summary>Returns the value or the inner text of a XML node.</summary>
- /// <param name="node">DOM node to get the value from.</param>
- /// <returns>Value of the domNode or the inner text if domNode represents a DOM element node.</returns>
-
- if (domNode.nodeType === 1) {
- return xmlInnerText(domNode);
- }
- return domNode.nodeValue;
- };
-
- var xmlTraverse = function (domNode, recursive, onChildCallback) {
- /// <summary>Walks through the descendants of the domNode and invokes a callback for each node.</summary>
- /// <param name="domNode">DOM node whose descendants are going to be traversed.</param>
- /// <param name="recursive" type="Boolean">
- /// True if the traversal should include all the descenants of the DOM node.
- /// False if the traversal should be scoped only to the direct children of the DOM node.
- /// </param>
- /// <returns type="String">Namespace URI of node.</returns>
-
- var subtrees = [];
- var child = domNode.firstChild;
- var proceed = true;
- while (child && proceed) {
- proceed = onChildCallback(child);
- if (proceed) {
- if (recursive && child.firstChild) {
- subtrees.push(child.firstChild);
- }
- child = child.nextSibling || subtrees.shift();
- }
- }
- };
-
- var xmlSiblingElement = function (domNode, namespaceURI, localName) {
- /// <summary>Returns the next sibling DOM element of the specified DOM node.</summary>
- /// <param name="domNode">DOM node from which the next sibling is going to be retrieved.</param>
- /// <param name="namespaceURI" type="String" optional="true">The namespace URI of the element to match.</param>
- /// <param name="localName" type="String" optional="true">Name of the element to match.</param>
- /// <returns>The node's next sibling DOM element, null if there is none.</returns>
-
- var sibling = domNode.nextSibling;
- while (sibling) {
- if (sibling.nodeType === 1) {
- var isExpectedNamespace = !namespaceURI || xmlNamespaceURI(sibling) === namespaceURI;
- var isExpectedNodeName = !localName || xmlLocalName(sibling) === localName;
-
- if (isExpectedNamespace && isExpectedNodeName) {
- return sibling;
- }
- }
- sibling = sibling.nextSibling;
- }
- return null;
- };
-
- var xmlDom = function () {
- /// <summary>Creates a new empty DOM document node.</summary>
- /// <returns>New DOM document node.</returns>
- /// <remarks>
- /// This function will first try to create a native DOM document using
- /// the browsers createDocument function. If the browser doesn't
- /// support this but supports ActiveXObject, then an attempt to create
- /// an MSXML 6.0 DOM will be made. If this attempt fails too, then an attempt
- /// for creating an MXSML 3.0 DOM will be made. If this last attemp fails or
- /// the browser doesn't support ActiveXObject then an exception will be thrown.
- /// </remarks>
-
- var implementation = window.document.implementation;
- return (implementation && implementation.createDocument) ?
- implementation.createDocument(null, null, null) :
- msXmlDom();
- };
-
- var xmlAppendChildren = function (parent, children) {
- /// <summary>Appends a collection of child nodes or string values to a parent DOM node.</summary>
- /// <param name="parent">DOM node to which the children will be appended.</param>
- /// <param name="children" type="Array">Array containing DOM nodes or string values that will be appended to the parent.</param>
- /// <returns>The parent with the appended children or string values.</returns>
- /// <remarks>
- /// If a value in the children collection is a string, then a new DOM text node is going to be created
- /// for it and then appended to the parent.
- /// </remarks>
-
- if (!isArray(children)) {
- return xmlAppendChild(parent, children);
- }
-
- var i, len;
- for (i = 0, len = children.length; i < len; i++) {
- children[i] && xmlAppendChild(parent, children[i]);
- }
- return parent;
- };
-
- var xmlAppendChild = function (parent, child) {
- /// <summary>Appends a child node or a string value to a parent DOM node.</summary>
- /// <param name="parent">DOM node to which the child will be appended.</param>
- /// <param name="child">Child DOM node or string value to append to the parent.</param>
- /// <returns>The parent with the appended child or string value.</returns>
- /// <remarks>
- /// If child is a string value, then a new DOM text node is going to be created
- /// for it and then appended to the parent.
- /// </remarks>
-
- djsassert(parent !== child, "xmlAppendChild() - parent and child are one and the same!");
- if (child) {
- if (typeof child === "string") {
- return xmlAppendText(parent, xmlNewText(parent.ownerDocument, child));
- }
- if (child.nodeType === 2) {
- parent.setAttributeNodeNS ? parent.setAttributeNodeNS(child) : parent.setAttributeNode(child);
- } else {
- parent.appendChild(child);
- }
- }
- return parent;
- };
-
- var xmlNewAttribute = function (dom, namespaceURI, qualifiedName, value) {
- /// <summary>Creates a new DOM attribute node.</summary>
- /// <param name="dom">DOM document used to create the attribute.</param>
- /// <param name="prefix" type="String">Namespace prefix.</param>
- /// <param name="namespaceURI" type="String">Namespace URI.</param>
- /// <returns>DOM attribute node for the namespace declaration.</returns>
-
- var attribute =
- dom.createAttributeNS && dom.createAttributeNS(namespaceURI, qualifiedName) ||
- dom.createNode(2, qualifiedName, namespaceURI || undefined);
-
- attribute.value = value || "";
- return attribute;
- };
-
- var xmlNewElement = function (dom, nampespaceURI, qualifiedName, children) {
- /// <summary>Creates a new DOM element node.</summary>
- /// <param name="dom">DOM document used to create the DOM element.</param>
- /// <param name="namespaceURI" type="String">Namespace URI of the new DOM element.</param>
- /// <param name="qualifiedName" type="String">Qualified name in the form of "prefix:name" of the new DOM element.</param>
- /// <param name="children" type="Array" optional="true">
- /// Collection of child DOM nodes or string values that are going to be appended to the new DOM element.
- /// </param>
- /// <returns>New DOM element.</returns>
- /// <remarks>
- /// If a value in the children collection is a string, then a new DOM text node is going to be created
- /// for it and then appended to the new DOM element.
- /// </remarks>
-
- var element =
- dom.createElementNS && dom.createElementNS(nampespaceURI, qualifiedName) ||
- dom.createNode(1, qualifiedName, nampespaceURI || undefined);
-
- return xmlAppendChildren(element, children || []);
- };
-
- var xmlNewNSDeclaration = function (dom, namespaceURI, prefix) {
- /// <summary>Creates a namespace declaration attribute.</summary>
- /// <param name="dom">DOM document used to create the attribute.</param>
- /// <param name="namespaceURI" type="String">Namespace URI.</param>
- /// <param name="prefix" type="String">Namespace prefix.</param>
- /// <returns>DOM attribute node for the namespace declaration.</returns>
-
- return xmlNewAttribute(dom, xmlnsNS, xmlQualifiedName("xmlns", prefix), namespaceURI);
- };
-
- var xmlNewFragment = function (dom, text) {
- /// <summary>Creates a new DOM document fragment node for the specified xml text.</summary>
- /// <param name="dom">DOM document from which the fragment node is going to be created.</param>
- /// <param name="text" type="String" mayBeNull="false">XML text to be represented by the XmlFragment.</param>
- /// <returns>New DOM document fragment object.</returns>
-
- var value = "<c>" + text + "</c>";
- var tempDom = xmlParse(value);
- var tempRoot = tempDom.documentElement;
- var imported = ("importNode" in dom) ? dom.importNode(tempRoot, true) : tempRoot;
- var fragment = dom.createDocumentFragment();
-
- var importedChild = imported.firstChild;
- while (importedChild) {
- fragment.appendChild(importedChild);
- importedChild = importedChild.nextSibling;
- }
- return fragment;
- };
-
- var xmlNewText = function (dom, text) {
- /// <summary>Creates new DOM text node.</summary>
- /// <param name="dom">DOM document used to create the text node.</param>
- /// <param name="text" type="String">Text value for the DOM text node.</param>
- /// <returns>DOM text node.</returns>
-
- return dom.createTextNode(text);
- };
-
- var xmlNewNodeByPath = function (dom, root, namespaceURI, prefix, path) {
- /// <summary>Creates a new DOM element or DOM attribute node as specified by path and appends it to the DOM tree pointed by root.</summary>
- /// <param name="dom">DOM document used to create the new node.</param>
- /// <param name="root">DOM element node used as root of the subtree on which the new nodes are going to be created.</param>
- /// <param name="namespaceURI" type="String">Namespace URI of the new DOM element or attribute.</param>
- /// <param name="namespacePrefix" type="String">Prefix used to qualify the name of the new DOM element or attribute.</param>
- /// <param name="Path" type="String">Path string describing the location of the new DOM element or attribute from the root element.</param>
- /// <returns>DOM element or attribute node for the last segment of the path.</returns>
- /// <remarks>
- /// This function will traverse the path and will create a new DOM element with the specified namespace URI and prefix
- /// for each segment that doesn't have a matching element under root.
- ///
- /// The last segment of the path may be decorated with a starting @ character. In this case a new DOM attribute node
- /// will be created.
- /// </remarks>
-
- var name = "";
- var parts = path.split("/");
- var xmlFindNode = xmlFirstChildElement;
- var xmlNewNode = xmlNewElement;
- var xmlNode = root;
-
- var i, len;
- for (i = 0, len = parts.length; i < len; i++) {
- name = parts[i];
- if (name.charAt(0) === "@") {
- name = name.substring(1);
- xmlFindNode = xmlAttributeNode;
- xmlNewNode = xmlNewAttribute;
- }
-
- var childNode = xmlFindNode(xmlNode, namespaceURI, name);
- if (!childNode) {
- childNode = xmlNewNode(dom, namespaceURI, xmlQualifiedName(prefix, name));
- xmlAppendChild(xmlNode, childNode);
- }
- xmlNode = childNode;
- }
- return xmlNode;
- };
-
- var xmlSerialize = function (domNode) {
- /// <summary>
- /// Returns the text representation of the document to which the specified node belongs.
- /// </summary>
- /// <param name="root">Wrapped element in the document to serialize.</param>
- /// <returns type="String">Serialized document.</returns>
-
- var xmlSerializer = window.XMLSerializer;
- if (xmlSerializer) {
- var serializer = new xmlSerializer();
- return serializer.serializeToString(domNode);
- }
-
- if (domNode.xml) {
- return domNode.xml;
- }
-
- throw { message: "XML serialization unsupported" };
- };
-
- var xmlSerializeDescendants = function (domNode) {
- /// <summary>Returns the XML representation of the all the descendants of the node.</summary>
- /// <param name="domNode" optional="false" mayBeNull="false">Node to serialize.</param>
- /// <returns type="String">The XML representation of all the descendants of the node.</returns>
-
- var children = domNode.childNodes;
- var i, len = children.length;
- if (len === 0) {
- return "";
- }
-
- // Some implementations of the XMLSerializer don't deal very well with fragments that
- // don't have a DOMElement as their first child. The work around is to wrap all the
- // nodes in a dummy root node named "c", serialize it and then just extract the text between
- // the <c> and the </c> substrings.
-
- var dom = domNode.ownerDocument;
- var fragment = dom.createDocumentFragment();
- var fragmentRoot = dom.createElement("c");
-
- fragment.appendChild(fragmentRoot);
- // Move the children to the fragment tree.
- for (i = 0; i < len; i++) {
- fragmentRoot.appendChild(children[i]);
- }
-
- var xml = xmlSerialize(fragment);
- xml = xml.substr(3, xml.length - 7);
-
- // Move the children back to the original dom tree.
- for (i = 0; i < len; i++) {
- domNode.appendChild(fragmentRoot.childNodes[i]);
- }
-
- return xml;
- };
-
- var xmlSerializeNode = function (domNode) {
- /// <summary>Returns the XML representation of the node and all its descendants.</summary>
- /// <param name="domNode" optional="false" mayBeNull="false">Node to serialize.</param>
- /// <returns type="String">The XML representation of the node and all its descendants.</returns>
-
- var xml = domNode.xml;
- if (xml !== undefined) {
- return xml;
- }
-
- if (window.XMLSerializer) {
- var serializer = new window.XMLSerializer();
- return serializer.serializeToString(domNode);
- }
-
- throw { message: "XML serialization unsupported" };
- };
-
- // DATAJS INTERNAL START
-
- datajs.http = http;
- datajs.w3org = w3org;
- datajs.xmlNS = xmlNS;
- datajs.xmlnsNS = xmlnsNS;
-
- datajs.hasLeadingOrTrailingWhitespace = hasLeadingOrTrailingWhitespace;
- datajs.isXmlNSDeclaration = isXmlNSDeclaration;
- datajs.xmlAppendChild = xmlAppendChild;
- datajs.xmlAppendChildren = xmlAppendChildren;
- datajs.xmlAttributeNode = xmlAttributeNode;
- datajs.xmlAttributes = xmlAttributes;
- datajs.xmlAttributeValue = xmlAttributeValue;
- datajs.xmlBaseURI = xmlBaseURI;
- datajs.xmlChildElements = xmlChildElements;
- datajs.xmlFindElementByPath = xmlFindElementByPath;
- datajs.xmlFindNodeByPath = xmlFindNodeByPath;
- datajs.xmlFirstChildElement = xmlFirstChildElement;
- datajs.xmlFirstDescendantElement = xmlFirstDescendantElement;
- datajs.xmlInnerText = xmlInnerText;
- datajs.xmlLocalName = xmlLocalName;
- datajs.xmlNamespaceURI = xmlNamespaceURI;
- datajs.xmlNodeValue = xmlNodeValue;
- datajs.xmlDom = xmlDom;
- datajs.xmlNewAttribute = xmlNewAttribute;
- datajs.xmlNewElement = xmlNewElement;
- datajs.xmlNewFragment = xmlNewFragment;
- datajs.xmlNewNodeByPath = xmlNewNodeByPath;
- datajs.xmlNewNSDeclaration = xmlNewNSDeclaration;
- datajs.xmlNewText = xmlNewText;
- datajs.xmlParse = xmlParse;
- datajs.xmlQualifiedName = xmlQualifiedName;
- datajs.xmlSerialize = xmlSerialize;
- datajs.xmlSerializeDescendants = xmlSerializeDescendants;
- datajs.xmlSiblingElement = xmlSiblingElement;
-
- // DATAJS INTERNAL END
-
- // CONTENT END
-})(this);
\ No newline at end of file
[11/15] [OLINGO-238] Build infrastructure for datajs I
Posted by ko...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/lib/odata/gml.js
----------------------------------------------------------------------
diff --git a/datajs/src/lib/odata/gml.js b/datajs/src/lib/odata/gml.js
new file mode 100644
index 0000000..68788b0
--- /dev/null
+++ b/datajs/src/lib/odata/gml.js
@@ -0,0 +1,833 @@
+//SK name /odata/odata-gml.js
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// odata-gml.js
+
+// Imports.
+
+var utils = require('./../datajs.js').utils;
+var xml = require('./../datajs.js').xml;
+var odataUtils = require('./utils.js');
+
+
+
+var contains = utils.contains;
+var djsassert = utils.djsassert;
+var http = utils.http;
+var isArray = utils.isArray;
+
+var xmlAppendChild = xml.xmlAppendChild;
+var xmlAttributeValue = xml.xmlAttributeValue;
+var xmlChildElements = xml.xmlChildElements;
+var xmlFirstChildElement = xml.xmlFirstChildElement;
+var xmlInnerText = xml.xmlInnerText;
+var xmlLocalName = xml.xmlLocalName;
+var xmlNamespaceURI = xml.xmlNamespaceURI;
+var xmlNewElement = xml.xmlNewElement;
+var xmlQualifiedName = xml.xmlQualifiedName;
+
+var GEOJSON_POINT = odataUtils.GEOJSON_POINT;
+var GEOJSON_LINESTRING = odataUtils.GEOJSON_LINESTRING;
+var GEOJSON_POLYGON = odataUtils.GEOJSON_POLYGON;
+var GEOJSON_MULTIPOINT = odataUtils.GEOJSON_MULTIPOINT;
+var GEOJSON_MULTILINESTRING = odataUtils.GEOJSON_MULTILINESTRING;
+var GEOJSON_MULTIPOLYGON = odataUtils.GEOJSON_MULTIPOLYGON;
+var GEOJSON_GEOMETRYCOLLECTION = odataUtils.GEOJSON_GEOMETRYCOLLECTION;
+
+// CONTENT START
+var gmlOpenGis = http + "www.opengis.net"; // http://www.opengis.net
+var gmlXmlNs = gmlOpenGis + "/gml"; // http://www.opengis.net/gml
+var gmlSrsPrefix = gmlOpenGis + "/def/crs/EPSG/0/"; // http://www.opengis.net/def/crs/EPSG/0/
+
+var gmlPrefix = "gml";
+
+var gmlCreateGeoJSONOBject = function (type, member, data) {
+ /// <summary>Creates a GeoJSON object with the specified type, member and value.</summary>
+ /// <param name="type" type="String">GeoJSON object type.</param>
+ /// <param name="member" type="String">Name for the data member in the GeoJSON object.</param>
+ /// <param name="data">Data to be contained by the GeoJSON object.</param>
+ /// <returns type="Object">GeoJSON object.</returns>
+
+ var result = { type: type };
+ result[member] = data;
+ return result;
+};
+
+var gmlSwapLatLong = function (coordinates) {
+ /// <summary>Swaps the longitude and latitude in the coordinates array.</summary>
+ /// <param name="coordinates" type="Array">Array of doubles descrbing a set of coordinates.</param>
+ /// <returns type="Array">Array of doubles with the latitude and longitude components swapped.</returns>
+
+ if (isArray(coordinates) && coordinates.length >= 2) {
+ var tmp = coordinates[0];
+ coordinates[0] = coordinates[1];
+ coordinates[1] = tmp;
+ }
+ return coordinates;
+};
+
+var gmlReadODataMultiItem = function (domElement, type, member, members, valueReader, isGeography) {
+ /// <summary>
+ /// Reads a GML DOM element that represents a composite structure like a multi-point or a
+ /// multi-geometry returnig its GeoJSON representation.
+ /// </summary>
+ /// <param name="domElement">GML DOM element.</param>
+ /// <param name="type" type="String">GeoJSON object type.</param>
+ /// <param name="member" type="String">Name for the child element representing a single item in the composite structure.</param>
+ /// <param name="members" type="String">Name for the child element representing a collection of items in the composite structure.</param>
+ /// <param name="valueReader" type="Function">Callback function invoked to get the coordinates of each item in the comoposite structure.</param>
+ /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+ /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns type="Object">GeoJSON object.</returns>
+
+ var coordinates = gmlReadODataMultiItemValue(domElement, member, members, valueReader, isGeography);
+ return gmlCreateGeoJSONOBject(type, "coordinates", coordinates);
+};
+
+var gmlReadODataMultiItemValue = function (domElement, member, members, valueReader, isGeography) {
+ /// <summary>
+ /// Reads the value of a GML DOM element that represents a composite structure like a multi-point or a
+ /// multi-geometry returnig its items.
+ /// </summary>
+ /// <param name="domElement">GML DOM element.</param>
+ /// <param name="type" type="String">GeoJSON object type.</param>
+ /// <param name="member" type="String">Name for the child element representing a single item in the composite structure.</param>
+ /// <param name="members" type="String">Name for the child element representing a collection of items in the composite structure.</param>
+ /// <param name="valueReader" type="Function">Callback function invoked to get the transformed value of each item in the comoposite structure.</param>
+ /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+ /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns type="Array">Array containing the transformed value of each item in the multi-item.</returns>
+
+ var items = [];
+
+ xmlChildElements(domElement, function (child) {
+ if (xmlNamespaceURI(child) !== gmlXmlNs) {
+ return;
+ }
+
+ var localName = xmlLocalName(child);
+
+ if (localName === member) {
+ var valueElement = xmlFirstChildElement(child, gmlXmlNs);
+ if (valueElement) {
+ var value = valueReader(valueElement, isGeography);
+ if (value) {
+ items.push(value);
+ }
+ }
+ return;
+ }
+
+ if (localName === members) {
+ xmlChildElements(child, function (valueElement) {
+ if (xmlNamespaceURI(valueElement) !== gmlXmlNs) {
+ return;
+ }
+
+ var value = valueReader(valueElement, isGeography);
+ if (value) {
+ items.push(value);
+ }
+ });
+ }
+ });
+ return items;
+};
+
+var gmlReadODataCollection = function (domElement, isGeography) {
+ /// <summary>Reads a GML DOM element representing a multi-geometry returning its GeoJSON representation.</summary>
+ /// <param name="domElement">DOM element.</param>
+ /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+ /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns type="Object">MultiGeometry object in GeoJSON format.</returns>
+
+ var geometries = gmlReadODataMultiItemValue(domElement, "geometryMember", "geometryMembers", gmlReadODataSpatialValue, isGeography);
+ return gmlCreateGeoJSONOBject(GEOJSON_GEOMETRYCOLLECTION, "geometries", geometries);
+};
+
+var gmlReadODataLineString = function (domElement, isGeography) {
+ /// <summary>Reads a GML DOM element representing a line string returning its GeoJSON representation.</summary>
+ /// <param name="domElement">DOM element.</param>
+ /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+ /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns type="Object">LineString object in GeoJSON format.</returns>
+
+ return gmlCreateGeoJSONOBject(GEOJSON_LINESTRING, "coordinates", gmlReadODataLineValue(domElement, isGeography));
+};
+
+var gmlReadODataMultiLineString = function (domElement, isGeography) {
+ /// <summary>Reads a GML DOM element representing a multi-line string returning its GeoJSON representation.</summary>
+ /// <param name="domElement">DOM element.</param>
+ /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+ /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns type="Object">MultiLineString object in GeoJSON format.</returns>
+
+ return gmlReadODataMultiItem(domElement, GEOJSON_MULTILINESTRING, "curveMember", "curveMembers", gmlReadODataLineValue, isGeography);
+};
+
+var gmlReadODataMultiPoint = function (domElement, isGeography) {
+ /// <summary>Reads a GML DOM element representing a multi-point returning its GeoJSON representation.</summary>
+ /// <param name="domElement">DOM element.</param>
+ /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+ /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns type="Object">MultiPoint object in GeoJSON format.</returns>
+
+ return gmlReadODataMultiItem(domElement, GEOJSON_MULTIPOINT, "pointMember", "pointMembers", gmlReadODataPointValue, isGeography);
+};
+
+var gmlReadODataMultiPolygon = function (domElement, isGeography) {
+ /// <summary>Reads a GML DOM element representing a multi-polygon returning its GeoJSON representation.</summary>
+ /// <param name="domElement">DOM element.</param>
+ /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+ /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns type="Object">MultiPolygon object in GeoJSON format.</returns>
+
+ return gmlReadODataMultiItem(domElement, GEOJSON_MULTIPOLYGON, "surfaceMember", "surfaceMembers", gmlReadODataPolygonValue, isGeography);
+};
+
+var gmlReadODataPoint = function (domElement, isGeography) {
+ /// <summary>Reads a GML DOM element representing a point returning its GeoJSON representation.</summary>
+ /// <param name="domElement">DOM element.</param>
+ /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+ /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns type="Object">Point object in GeoJSON format.</returns>
+
+ return gmlCreateGeoJSONOBject(GEOJSON_POINT, "coordinates", gmlReadODataPointValue(domElement, isGeography));
+};
+
+var gmlReadODataPolygon = function (domElement, isGeography) {
+ /// <summary>Reads a GML DOM element representing a polygon returning its GeoJSON representation.</summary>
+ /// <param name="domElement">DOM element.</param>
+ /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+ /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns type="Object">Polygon object in GeoJSON format.</returns>
+
+ return gmlCreateGeoJSONOBject(GEOJSON_POLYGON, "coordinates", gmlReadODataPolygonValue(domElement, isGeography));
+};
+
+var gmlReadODataLineValue = function (domElement, isGeography) {
+ /// <summary>Reads the value of a GML DOM element representing a line returning its set of coordinates.</summary>
+ /// <param name="domElement">DOM element.</param>
+ /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+ /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns type="Array">Array containing an array of doubles for each coordinate of the line.</returns>
+
+ var coordinates = [];
+
+ xmlChildElements(domElement, function (child) {
+ var nsURI = xmlNamespaceURI(child);
+
+ if (nsURI !== gmlXmlNs) {
+ return;
+ }
+
+ var localName = xmlLocalName(child);
+
+ if (localName === "posList") {
+ coordinates = gmlReadODataPosListValue(child, isGeography);
+ return;
+ }
+ if (localName === "pointProperty") {
+ coordinates.push(gmlReadODataPointWrapperValue(child, isGeography));
+ return;
+ }
+ if (localName === "pos") {
+ coordinates.push(gmlReadODataPosValue(child, isGeography));
+ return;
+ }
+ });
+
+ return coordinates;
+};
+
+var gmlReadODataPointValue = function (domElement, isGeography) {
+ /// <summary>Reads the value of a GML DOM element representing a point returning its coordinates.</summary>
+ /// <param name="domElement">DOM element.</param>
+ /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+ /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns type="Array">Array of doubles containing the point coordinates.</returns>
+
+ var pos = xmlFirstChildElement(domElement, gmlXmlNs, "pos");
+ return pos ? gmlReadODataPosValue(pos, isGeography) : [];
+};
+
+var gmlReadODataPointWrapperValue = function (domElement, isGeography) {
+ /// <summary>Reads the value of a GML DOM element wrapping an element representing a point returning its coordinates.</summary>
+ /// <param name="domElement">DOM element.</param>
+ /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+ /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns type="Array">Array of doubles containing the point coordinates.</returns>
+
+ var point = xmlFirstChildElement(domElement, gmlXmlNs, "Point");
+ return point ? gmlReadODataPointValue(point, isGeography) : [];
+};
+
+var gmlReadODataPolygonValue = function (domElement, isGeography) {
+ /// <summary>Reads the value of a GML DOM element representing a polygon returning its set of coordinates.</summary>
+ /// <param name="domElement">DOM element.</param>
+ /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+ /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns type="Array">Array containing an array of array of doubles for each ring of the polygon.</returns>
+
+ var coordinates = [];
+ var exteriorFound = false;
+ xmlChildElements(domElement, function (child) {
+ if (xmlNamespaceURI(child) !== gmlXmlNs) {
+ return;
+ }
+
+ // Only the exterior and the interior rings are interesting
+ var localName = xmlLocalName(child);
+ if (localName === "exterior") {
+ exteriorFound = true;
+ coordinates.unshift(gmlReadODataPolygonRingValue(child, isGeography));
+ return;
+ }
+ if (localName === "interior") {
+ coordinates.push(gmlReadODataPolygonRingValue(child, isGeography));
+ return;
+ }
+ });
+
+ if (!exteriorFound && coordinates.length > 0) {
+ // Push an empty exterior ring.
+ coordinates.unshift([[]]);
+ }
+
+ return coordinates;
+};
+
+var gmlReadODataPolygonRingValue = function (domElement, isGeography) {
+ /// <summary>Reads the value of a GML DOM element representing a linear ring in a GML Polygon element.</summary>
+ /// <param name="domElement">DOM element.</param>
+ /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+ /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns type="Array">Array containing an array of doubles for each coordinate of the linear ring.</returns>
+
+ var value = [];
+ xmlChildElements(domElement, function (child) {
+ if (xmlNamespaceURI(child) !== gmlXmlNs || xmlLocalName(child) !== "LinearRing") {
+ return;
+ }
+ value = gmlReadODataLineValue(child, isGeography);
+ });
+ return value;
+};
+
+var gmlReadODataPosListValue = function (domElement, isGeography) {
+ /// <summary>Reads the value of a GML DOM element representing a list of positions retruning its set of coordinates.</summary>
+ /// <param name="domElement">DOM element.</param>
+ /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+ /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
+ ///
+ /// The positions described by the list are assumed to be 2D, so
+ /// an exception will be thrown if the list has an odd number elements.
+ /// </remarks>
+ /// <returns type="Array">Array containing an array of doubles for each coordinate in the list.</returns>
+
+ var coordinates = gmlReadODataPosValue(domElement, false);
+ var len = coordinates.length;
+
+ if (len % 2 !== 0) {
+ throw { message: "GML posList element has an uneven number of numeric values" };
+ }
+
+ var value = [];
+ for (var i = 0; i < len; i += 2) {
+ var pos = coordinates.slice(i, i + 2);
+ value.push(isGeography ? gmlSwapLatLong(pos) : pos);
+ }
+ return value;
+};
+
+var gmlReadODataPosValue = function (domElement, isGeography) {
+ /// <summary>Reads the value of a GML element describing a position or a set of coordinates in an OData spatial property value.</summary>
+ /// <param name="property">DOM element for the GML element.</param>
+ /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+ /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns type="Array">Array of doubles containing the coordinates.</returns>
+
+ var value = [];
+ var delims = " \t\r\n";
+ var text = xmlInnerText(domElement);
+
+ if (text) {
+ var len = text.length;
+ var start = 0;
+ var end = 0;
+
+ while (end <= len) {
+ if (delims.indexOf(text.charAt(end)) !== -1) {
+ var coord = text.substring(start, end);
+ if (coord) {
+ value.push(parseFloat(coord));
+ }
+ start = end + 1;
+ }
+ end++;
+ }
+ }
+
+ return isGeography ? gmlSwapLatLong(value) : value;
+};
+
+var gmlReadODataSpatialValue = function (domElement, isGeography) {
+ /// <summary>Reads the value of a GML DOM element a spatial value in an OData XML document.</summary>
+ /// <param name="domElement">DOM element.</param>
+ /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+ /// will be deserialized as the second component of each position coordinates in the resulting GeoJSON object.
+ /// </remarks>
+ /// <returns type="Array">Array containing an array of doubles for each coordinate of the polygon.</returns>
+
+ var localName = xmlLocalName(domElement);
+ var reader;
+
+ switch (localName) {
+ case "Point":
+ reader = gmlReadODataPoint;
+ break;
+ case "Polygon":
+ reader = gmlReadODataPolygon;
+ break;
+ case "LineString":
+ reader = gmlReadODataLineString;
+ break;
+ case "MultiPoint":
+ reader = gmlReadODataMultiPoint;
+ break;
+ case "MultiCurve":
+ reader = gmlReadODataMultiLineString;
+ break;
+ case "MultiSurface":
+ reader = gmlReadODataMultiPolygon;
+ break;
+ case "MultiGeometry":
+ reader = gmlReadODataCollection;
+ break;
+ default:
+ throw { message: "Unsupported element: " + localName, element: domElement };
+ }
+
+ var value = reader(domElement, isGeography);
+ // Read the CRS
+ // WCF Data Services qualifies the srsName attribute withing the GML namespace; however
+ // other end points might no do this as per the standard.
+
+ var srsName = xmlAttributeValue(domElement, "srsName", gmlXmlNs) ||
+ xmlAttributeValue(domElement, "srsName");
+
+ if (srsName) {
+ if (srsName.indexOf(gmlSrsPrefix) !== 0) {
+ throw { message: "Unsupported srs name: " + srsName, element: domElement };
+ }
+
+ var crsId = srsName.substring(gmlSrsPrefix.length);
+ if (crsId) {
+ value.crs = {
+ type: "name",
+ properties: {
+ name: "EPSG:" + crsId
+ }
+ };
+ }
+ }
+ return value;
+};
+
+var gmlNewODataSpatialValue = function (dom, value, type, isGeography) {
+ /// <summary>Creates a new GML DOM element for the value of an OData spatial property or GeoJSON object.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="value" type="Object">Spatial property value in GeoJSON format.</param>
+ /// <param name="type" type="String">String indicating the GeoJSON type of the value to serialize.</param>
+ /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
+ /// will be serialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns>New DOM element in the GML namespace for the spatial value. </returns>
+
+ var gmlWriter;
+
+ switch (type) {
+ case GEOJSON_POINT:
+ gmlWriter = gmlNewODataPoint;
+ break;
+ case GEOJSON_LINESTRING:
+ gmlWriter = gmlNewODataLineString;
+ break;
+ case GEOJSON_POLYGON:
+ gmlWriter = gmlNewODataPolygon;
+ break;
+ case GEOJSON_MULTIPOINT:
+ gmlWriter = gmlNewODataMultiPoint;
+ break;
+ case GEOJSON_MULTILINESTRING:
+ gmlWriter = gmlNewODataMultiLineString;
+ break;
+ case GEOJSON_MULTIPOLYGON:
+ gmlWriter = gmlNewODataMultiPolygon;
+ break;
+ case GEOJSON_GEOMETRYCOLLECTION:
+ gmlWriter = gmlNewODataGeometryCollection;
+ break;
+ default:
+ djsassert(false, "gmlNewODataSpatialValue - Unknown GeoJSON type <" + type + ">!!");
+ return null;
+ }
+
+ var gml = gmlWriter(dom, value, isGeography);
+
+ // Set the srsName attribute if applicable.
+ var crs = value.crs;
+ if (crs) {
+ if (crs.type === "name") {
+ var properties = crs.properties;
+ var name = properties && properties.name;
+ if (name && name.indexOf("ESPG:") === 0 && name.length > 5) {
+ var crsId = name.substring(5);
+ var srsName = xmlNewAttribute(dom, null, "srsName", gmlPrefix + crsId);
+ xmlAppendChild(gml, srsName);
+ }
+ }
+ }
+
+ return gml;
+};
+
+var gmlNewODataElement = function (dom, name, children) {
+ /// <summary>Creates a new DOM element in the GML namespace.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="name" type="String">Local name of the GML element to create.</param>
+ /// <param name="children" type="Array">Array containing DOM nodes or string values that will be added as children of the new DOM element.</param>
+ /// <returns>New DOM element in the GML namespace.</returns>
+ /// <remarks>
+ /// If a value in the children collection is a string, then a new DOM text node is going to be created
+ /// for it and then appended as a child of the new DOM Element.
+ /// </remarks>
+
+ return xmlNewElement(dom, gmlXmlNs, xmlQualifiedName(gmlPrefix, name), children);
+};
+
+var gmlNewODataPosElement = function (dom, coordinates, isGeography) {
+ /// <summary>Creates a new GML pos DOM element.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="coordinates" type="Array">Array of doubles describing the coordinates of the pos element.</param>
+ /// <param name="isGeography" type="Boolean">Flag indicating if the coordinates use a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first coordinate is the Longitude and
+ /// will be serialized as the second component of the <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns>New pos DOM element in the GML namespace.</returns>
+
+ var posValue = isArray(coordinates) ? coordinates : [];
+
+ // If using a geographic reference system, then the first coordinate is the longitude and it has to
+ // swapped with the latitude.
+ posValue = isGeography ? gmlSwapLatLong(posValue) : posValue;
+
+ return gmlNewODataElement(dom, "pos", posValue.join(" "));
+};
+
+var gmlNewODataLineElement = function (dom, name, coordinates, isGeography) {
+ /// <summary>Creates a new GML DOM element representing a line.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="name" type="String">Name of the element to create.</param>
+ /// <param name="coordinates" type="Array">Array of array of doubles describing the coordinates of the line element.</param>
+ /// <param name="isGeography" type="Boolean">Flag indicating if the coordinates use a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates is the Longitude and
+ /// will be serialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns>New DOM element in the GML namespace.</returns>
+
+ var element = gmlNewODataElement(dom, name);
+ if (isArray(coordinates)) {
+ var i, len;
+ for (i = 0, len = coordinates.length; i < len; i++) {
+ xmlAppendChild(element, gmlNewODataPosElement(dom, coordinates[i], isGeography));
+ }
+
+ if (len === 0) {
+ xmlAppendChild(element, gmlNewODataElement(dom, "posList"));
+ }
+ }
+ return element;
+};
+
+var gmlNewODataPointElement = function (dom, coordinates, isGeography) {
+ /// <summary>Creates a new GML Point DOM element.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="value" type="Object">GeoJSON Point object.</param>
+ /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
+ /// will be serialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns>New DOM element in the GML namespace for the GeoJSON Point.</returns>
+
+ return gmlNewODataElement(dom, "Point", gmlNewODataPosElement(dom, coordinates, isGeography));
+};
+
+var gmlNewODataLineStringElement = function (dom, coordinates, isGeography) {
+ /// <summary>Creates a new GML LineString DOM element.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="coordinates" type="Array">Array of array of doubles describing the coordinates of the line element.</param>
+ /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
+ /// will be serialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns>New DOM element in the GML namespace for the GeoJSON LineString.</returns>
+
+ return gmlNewODataLineElement(dom, "LineString", coordinates, isGeography);
+};
+
+var gmlNewODataPolygonRingElement = function (dom, name, coordinates, isGeography) {
+ /// <summary>Creates a new GML DOM element representing a polygon ring.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="name" type="String">Name of the element to create.</param>
+ /// <param name="coordinates" type="Array">Array of array of doubles describing the coordinates of the polygon ring.</param>
+ /// <param name="isGeography" type="Boolean">Flag indicating if the coordinates use a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates is the Longitude and
+ /// will be serialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns>New DOM element in the GML namespace.</returns>
+
+ var ringElement = gmlNewODataElement(dom, name);
+ if (isArray(coordinates) && coordinates.length > 0) {
+ var linearRing = gmlNewODataLineElement(dom, "LinearRing", coordinates, isGeography);
+ xmlAppendChild(ringElement, linearRing);
+ }
+ return ringElement;
+};
+
+var gmlNewODataPolygonElement = function (dom, coordinates, isGeography) {
+ /// <summary>Creates a new GML Polygon DOM element for a GeoJSON Polygon object.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="coordinates" type="Array">Array of array of array of doubles describing the coordinates of the polygon.</param>
+ /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
+ /// will be serialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns>New DOM element in the GML namespace.</returns>
+
+ var len = coordinates && coordinates.length;
+ var element = gmlNewODataElement(dom, "Polygon");
+
+ if (isArray(coordinates) && len > 0) {
+ xmlAppendChild(element, gmlNewODataPolygonRingElement(dom, "exterior", coordinates[0], isGeography));
+
+ var i;
+ for (i = 1; i < len; i++) {
+ xmlAppendChild(element, gmlNewODataPolygonRingElement(dom, "interior", coordinates[i], isGeography));
+ }
+ }
+ return element;
+};
+
+var gmlNewODataPoint = function (dom, value, isGeography) {
+ /// <summary>Creates a new GML Point DOM element for a GeoJSON Point object.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="value" type="Object">GeoJSON Point object.</param>
+ /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
+ /// will be serialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns>New DOM element in the GML namespace for the GeoJSON Point.</returns>
+
+ return gmlNewODataPointElement(dom, value.coordinates, isGeography);
+};
+
+var gmlNewODataLineString = function (dom, value, isGeography) {
+ /// <summary>Creates a new GML LineString DOM element for a GeoJSON LineString object.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="value" type="Object">GeoJSON LineString object.</param>
+ /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
+ /// will be serialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns>New DOM element in the GML namespace for the GeoJSON LineString.</returns>
+
+ return gmlNewODataLineStringElement(dom, value.coordinates, isGeography);
+};
+
+var gmlNewODataPolygon = function (dom, value, isGeography) {
+ /// <summary>Creates a new GML Polygon DOM element for a GeoJSON Polygon object.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="value" type="Object">GeoJSON Polygon object.</param>
+ /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
+ /// will be serialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns>New DOM element in the GML namespace for the GeoJSON Polygon.</returns>
+
+ return gmlNewODataPolygonElement(dom, value.coordinates, isGeography);
+};
+
+var gmlNewODataMultiItem = function (dom, name, members, items, itemWriter, isGeography) {
+ /// <summary>Creates a new GML DOM element for a composite structure like a multi-point or a multi-geometry.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="name" type="String">Name of the element to create.</param>
+ /// <param name="items" type="Array">Array of items in the composite structure.</param>
+ /// <param name="isGeography" type="Boolean">Flag indicating if the multi-item uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in each of the items is the Longitude and
+ /// will be serialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns>New DOM element in the GML namespace.</returns>
+
+ var len = items && items.length;
+ var element = gmlNewODataElement(dom, name);
+
+ if (isArray(items) && len > 0) {
+ var membersElement = gmlNewODataElement(dom, members);
+ var i;
+ for (i = 0; i < len; i++) {
+ xmlAppendChild(membersElement, itemWriter(dom, items[i], isGeography));
+ }
+ xmlAppendChild(element, membersElement);
+ }
+ return element;
+};
+
+var gmlNewODataMultiPoint = function (dom, value, isGeography) {
+ /// <summary>Creates a new GML MultiPoint DOM element for a GeoJSON MultiPoint object.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="value" type="Object">GeoJSON MultiPoint object.</param>
+ /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
+ /// will be serialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns>New DOM element in the GML namespace for the GeoJSON MultiPoint.</returns>
+
+ return gmlNewODataMultiItem(dom, "MultiPoint", "pointMembers", value.coordinates, gmlNewODataPointElement, isGeography);
+};
+
+var gmlNewODataMultiLineString = function (dom, value, isGeography) {
+ /// <summary>Creates a new GML MultiCurve DOM element for a GeoJSON MultiLineString object.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="value" type="Object">GeoJSON MultiLineString object.</param>
+ /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
+ /// will be serialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns>New DOM element in the GML namespace for the GeoJSON MultiLineString.</returns>
+
+ return gmlNewODataMultiItem(dom, "MultiCurve", "curveMembers", value.coordinates, gmlNewODataLineStringElement, isGeography);
+};
+
+var gmlNewODataMultiPolygon = function (dom, value, isGeography) {
+ /// <summary>Creates a new GML MultiSurface DOM element for a GeoJSON MultiPolygon object.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="value" type="Object">GeoJSON MultiPolygon object.</param>
+ /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
+ /// will be serialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns>New DOM element in the GML namespace for the GeoJSON MultiPolygon.</returns>
+
+ return gmlNewODataMultiItem(dom, "MultiSurface", "surfaceMembers", value.coordinates, gmlNewODataPolygonElement, isGeography);
+};
+
+var gmlNewODataGeometryCollectionItem = function (dom, value, isGeography) {
+ /// <summary>Creates a new GML element for an item in a geometry collection object.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="item" type="Object">GeoJSON object in the geometry collection.</param>
+ /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
+ /// will be serialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns>New DOM element in the GML namespace.</returns>
+
+ return gmlNewODataSpatialValue(dom, value, value.type, isGeography);
+};
+
+var gmlNewODataGeometryCollection = function (dom, value, isGeography) {
+ /// <summary>Creates a new GML MultiGeometry DOM element for a GeoJSON GeometryCollection object.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="value" type="Object">GeoJSON GeometryCollection object.</param>
+ /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
+ /// will be serialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns>New DOM element in the GML namespace for the GeoJSON GeometryCollection.</returns>
+
+ return gmlNewODataMultiItem(dom, "MultiGeometry", "geometryMembers", value.geometries, gmlNewODataGeometryCollectionItem, isGeography);
+};
+
+// DATAJS INTERNAL START
+exports.gmlNewODataSpatialValue = gmlNewODataSpatialValue;
+exports.gmlReadODataSpatialValue = gmlReadODataSpatialValue;
+exports.gmlXmlNs = gmlXmlNs;
+// DATAJS INTERNAL END
+
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/lib/odata/handler.js
----------------------------------------------------------------------
diff --git a/datajs/src/lib/odata/handler.js b/datajs/src/lib/odata/handler.js
new file mode 100644
index 0000000..f26a35a
--- /dev/null
+++ b/datajs/src/lib/odata/handler.js
@@ -0,0 +1,273 @@
+//SK name /odata/odata-handler.js
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// odata-handler.js
+
+var utils = require('./../datajs.js').utils;
+var oDataUtils = require('./utils.js');
+
+
+// Imports.
+var assigned = utils.assigned;
+var extend = utils.extend;
+var trimString = utils.trimString;
+
+var maxVersion = oDataUtils.maxVersion;
+
+// CONTENT START
+
+var MAX_DATA_SERVICE_VERSION = "3.0";
+
+var contentType = function (str) {
+ /// <summary>Parses a string into an object with media type and properties.</summary>
+ /// <param name="str" type="String">String with media type to parse.</param>
+ /// <returns>null if the string is empty; an object with 'mediaType' and a 'properties' dictionary otherwise.</returns>
+
+ if (!str) {
+ return null;
+ }
+
+ var contentTypeParts = str.split(";");
+ var properties = {};
+
+ var i, len;
+ for (i = 1, len = contentTypeParts.length; i < len; i++) {
+ var contentTypeParams = contentTypeParts[i].split("=");
+ properties[trimString(contentTypeParams[0])] = contentTypeParams[1];
+ }
+
+ return { mediaType: trimString(contentTypeParts[0]), properties: properties };
+};
+
+var contentTypeToString = function (contentType) {
+ /// <summary>Serializes an object with media type and properties dictionary into a string.</summary>
+ /// <param name="contentType">Object with media type and properties dictionary to serialize.</param>
+ /// <returns>String representation of the media type object; undefined if contentType is null or undefined.</returns>
+
+ if (!contentType) {
+ return undefined;
+ }
+
+ var result = contentType.mediaType;
+ var property;
+ for (property in contentType.properties) {
+ result += ";" + property + "=" + contentType.properties[property];
+ }
+ return result;
+};
+
+var createReadWriteContext = function (contentType, dataServiceVersion, context, handler) {
+ /// <summary>Creates an object that is going to be used as the context for the handler's parser and serializer.</summary>
+ /// <param name="contentType">Object with media type and properties dictionary.</param>
+ /// <param name="dataServiceVersion" type="String">String indicating the version of the protocol to use.</param>
+ /// <param name="context">Operation context.</param>
+ /// <param name="handler">Handler object that is processing a resquest or response.</param>
+ /// <returns>Context object.</returns>
+
+ var rwContext = {};
+ extend(rwContext, context);
+ extend(rwContext, {
+ contentType: contentType,
+ dataServiceVersion: dataServiceVersion,
+ handler: handler
+ });
+
+ return rwContext;
+};
+
+var fixRequestHeader = function (request, name, value) {
+ /// <summary>Sets a request header's value. If the header has already a value other than undefined, null or empty string, then this method does nothing.</summary>
+ /// <param name="request">Request object on which the header will be set.</param>
+ /// <param name="name" type="String">Header name.</param>
+ /// <param name="value" type="String">Header value.</param>
+ if (!request) {
+ return;
+ }
+
+ var headers = request.headers;
+ if (!headers[name]) {
+ headers[name] = value;
+ }
+};
+
+var fixDataServiceVersionHeader = function (request, version) {
+ /// <summary>Sets the DataServiceVersion header of the request if its value is not yet defined or of a lower version.</summary>
+ /// <param name="request">Request object on which the header will be set.</param>
+ /// <param name="version" type="String">Version value.</param>
+ /// <remarks>
+ /// If the request has already a version value higher than the one supplied the this function does nothing.
+ /// </remarks>
+
+ if (request) {
+ var headers = request.headers;
+ var dsv = headers["DataServiceVersion"];
+ headers["DataServiceVersion"] = dsv ? maxVersion(dsv, version) : version;
+ }
+};
+
+var getRequestOrResponseHeader = function (requestOrResponse, name) {
+ /// <summary>Gets the value of a request or response header.</summary>
+ /// <param name="requestOrResponse">Object representing a request or a response.</param>
+ /// <param name="name" type="String">Name of the header to retrieve.</param>
+ /// <returns type="String">String value of the header; undefined if the header cannot be found.</returns>
+
+ var headers = requestOrResponse.headers;
+ return (headers && headers[name]) || undefined;
+};
+
+var getContentType = function (requestOrResponse) {
+ /// <summary>Gets the value of the Content-Type header from a request or response.</summary>
+ /// <param name="requestOrResponse">Object representing a request or a response.</param>
+ /// <returns type="Object">Object with 'mediaType' and a 'properties' dictionary; null in case that the header is not found or doesn't have a value.</returns>
+
+ return contentType(getRequestOrResponseHeader(requestOrResponse, "Content-Type"));
+};
+
+var versionRE = /^\s?(\d+\.\d+);?.*$/;
+var getDataServiceVersion = function (requestOrResponse) {
+ /// <summary>Gets the value of the DataServiceVersion header from a request or response.</summary>
+ /// <param name="requestOrResponse">Object representing a request or a response.</param>
+ /// <returns type="String">Data service version; undefined if the header cannot be found.</returns>
+
+ var value = getRequestOrResponseHeader(requestOrResponse, "DataServiceVersion");
+ if (value) {
+ var matches = versionRE.exec(value);
+ if (matches && matches.length) {
+ return matches[1];
+ }
+ }
+
+ // Fall through and return undefined.
+};
+
+var handlerAccepts = function (handler, cType) {
+ /// <summary>Checks that a handler can process a particular mime type.</summary>
+ /// <param name="handler">Handler object that is processing a resquest or response.</param>
+ /// <param name="cType">Object with 'mediaType' and a 'properties' dictionary.</param>
+ /// <returns type="Boolean">True if the handler can process the mime type; false otherwise.</returns>
+
+ // The following check isn't as strict because if cType.mediaType = application/; it will match an accept value of "application/xml";
+ // however in practice we don't not expect to see such "suffixed" mimeTypes for the handlers.
+ return handler.accept.indexOf(cType.mediaType) >= 0;
+};
+
+var handlerRead = function (handler, parseCallback, response, context) {
+ /// <summary>Invokes the parser associated with a handler for reading the payload of a HTTP response.</summary>
+ /// <param name="handler">Handler object that is processing the response.</param>
+ /// <param name="parseCallback" type="Function">Parser function that will process the response payload.</param>
+ /// <param name="response">HTTP response whose payload is going to be processed.</param>
+ /// <param name="context">Object used as the context for processing the response.</param>
+ /// <returns type="Boolean">True if the handler processed the response payload and the response.data property was set; false otherwise.</returns>
+
+ if (!response || !response.headers) {
+ return false;
+ }
+
+ var cType = getContentType(response);
+ var version = getDataServiceVersion(response) || "";
+ var body = response.body;
+
+ if (!assigned(body)) {
+ return false;
+ }
+
+ if (handlerAccepts(handler, cType)) {
+ var readContext = createReadWriteContext(cType, version, context, handler);
+ readContext.response = response;
+ response.data = parseCallback(handler, body, readContext);
+ return response.data !== undefined;
+ }
+
+ return false;
+};
+
+var handlerWrite = function (handler, serializeCallback, request, context) {
+ /// <summary>Invokes the serializer associated with a handler for generating the payload of a HTTP request.</summary>
+ /// <param name="handler">Handler object that is processing the request.</param>
+ /// <param name="serializeCallback" type="Function">Serializer function that will generate the request payload.</param>
+ /// <param name="response">HTTP request whose payload is going to be generated.</param>
+ /// <param name="context">Object used as the context for serializing the request.</param>
+ /// <returns type="Boolean">True if the handler serialized the request payload and the request.body property was set; false otherwise.</returns>
+ if (!request || !request.headers) {
+ return false;
+ }
+
+ var cType = getContentType(request);
+ var version = getDataServiceVersion(request);
+
+ if (!cType || handlerAccepts(handler, cType)) {
+ var writeContext = createReadWriteContext(cType, version, context, handler);
+ writeContext.request = request;
+
+ request.body = serializeCallback(handler, request.data, writeContext);
+
+ if (request.body !== undefined) {
+ fixDataServiceVersionHeader(request, writeContext.dataServiceVersion || "1.0");
+
+ fixRequestHeader(request, "Content-Type", contentTypeToString(writeContext.contentType));
+ fixRequestHeader(request, "MaxDataServiceVersion", handler.maxDataServiceVersion);
+ return true;
+ }
+ }
+
+ return false;
+};
+
+var handler = function (parseCallback, serializeCallback, accept, maxDataServiceVersion) {
+ /// <summary>Creates a handler object for processing HTTP requests and responses.</summary>
+ /// <param name="parseCallback" type="Function">Parser function that will process the response payload.</param>
+ /// <param name="serializeCallback" type="Function">Serializer function that will generate the request payload.</param>
+ /// <param name="accept" type="String">String containing a comma separated list of the mime types that this handler can work with.</param>
+ /// <param name="maxDataServiceVersion" type="String">String indicating the highest version of the protocol that this handler can work with.</param>
+ /// <returns type="Object">Handler object.</returns>
+
+ return {
+ accept: accept,
+ maxDataServiceVersion: maxDataServiceVersion,
+
+ read: function (response, context) {
+ return handlerRead(this, parseCallback, response, context);
+ },
+
+ write: function (request, context) {
+ return handlerWrite(this, serializeCallback, request, context);
+ }
+ };
+};
+
+var textParse = function (handler, body /*, context */) {
+ return body;
+};
+
+var textSerialize = function (handler, data /*, context */) {
+ if (assigned(data)) {
+ return data.toString();
+ } else {
+ return undefined;
+ }
+};
+
+exports.textHandler = handler(textParse, textSerialize, "text/plain", MAX_DATA_SERVICE_VERSION);
+
+// DATAJS INTERNAL START
+exports.contentType = contentType;
+exports.contentTypeToString = contentTypeToString;
+exports.handler = handler;
+exports.createReadWriteContext = createReadWriteContext;
+exports.fixRequestHeader = fixRequestHeader;
+exports.getRequestOrResponseHeader = getRequestOrResponseHeader;
+exports.getContentType = getContentType;
+exports.getDataServiceVersion = getDataServiceVersion;
+exports.MAX_DATA_SERVICE_VERSION = MAX_DATA_SERVICE_VERSION;
+// DATAJS INTERNAL END
[05/15] [OLINGO-238] Build infrastructure for datajs I
Posted by ko...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/odata-json-light.js
----------------------------------------------------------------------
diff --git a/datajs/src/odata-json-light.js b/datajs/src/odata-json-light.js
deleted file mode 100644
index 9a10601..0000000
--- a/datajs/src/odata-json-light.js
+++ /dev/null
@@ -1,1391 +0,0 @@
-// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
-// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// odata-json-light.js
-
-(function (window, undefined) {
-
- var datajs = window.datajs || {};
- var odata = window.OData || {};
-
- // Imports
-
- var assigned = datajs.assigned;
- var djsassert = datajs.djsassert;
- var extend = datajs.extend;
- var getURIInfo = datajs.getURIInfo;
- var isArray = datajs.isArray;
- var isDate = datajs.isDate;
- var normalizeURI = datajs.normalizeURI;
- var renameProperty = datajs.renameProperty;
- var undefinedDefault = datajs.undefinedDefault;
- var convertByteArrayToHexString = datajs.convertByteArrayToHexString;
-
- var dataItemTypeName = odata.dataItemTypeName;
- var EDM_DATETIME = odata.EDM_DATETIME;
- var EDM_DATETIMEOFFSET = odata.EDM_DATETIMEOFFSET;
- var EDM_TIME = odata.EDM_TIME;
- var getCollectionType = odata.getCollectionType;
- var isCollection = odata.isCollection;
- var isCollectionType = odata.isCollectionType;
- var isComplex = odata.isComplex;
- var isDeferred = odata.isDeferred;
- var isFeed = odata.isFeed;
- var isEntry = odata.isEntry;
- var isGeographyEdmType = odata.isGeographyEdmType;
- var isGeometryEdmType = odata.isGeometryEdmType;
- var isPrimitiveEdmType = odata.isPrimitiveEdmType;
- var isPrimitive = odata.isPrimitive;
- var lookupComplexType = odata.lookupComplexType;
- var lookupDefaultEntityContainer = odata.lookupDefaultEntityContainer;
- var lookupEntityContainer = odata.lookupEntityContainer;
- var lookupEntitySet = odata.lookupEntitySet;
- var lookupEntityType = odata.lookupEntityType;
- var lookupFunctionImport = odata.lookupFunctionImport;
- var lookupNavigationPropertyType = odata.lookupNavigationPropertyType;
- var getEntitySetInfo = odata.getEntitySetInfo;
- var lookupNavigationPropertyEntitySet = odata.lookupNavigationPropertyEntitySet;
- var lookupProperty = odata.lookupProperty;
- var parseBool = odata.parseBool;
- var parseDateTime = odata.parseDateTime;
- var parseDateTimeOffset = odata.parseDateTimeOffset;
- var parseDuration = odata.parseDuration;
-
- // CONTENT START
-
- var PAYLOADTYPE_OBJECT = "o";
- var PAYLOADTYPE_FEED = "f";
- var PAYLOADTYPE_PRIMITIVE = "p";
- var PAYLOADTYPE_COLLECTION = "c";
- var PAYLOADTYPE_SVCDOC = "s";
- var PAYLOADTYPE_LINKS = "l";
-
- var odataNs = "odata";
- var odataAnnotationPrefix = odataNs + ".";
-
- var bindAnnotation = "@" + odataAnnotationPrefix + "bind";
- var metadataAnnotation = odataAnnotationPrefix + "metadata";
- var navUrlAnnotation = odataAnnotationPrefix + "navigationLinkUrl";
- var typeAnnotation = odataAnnotationPrefix + "type";
-
- var jsonLightNameMap = {
- readLink: "self",
- editLink: "edit",
- nextLink: "__next",
- mediaReadLink: "media_src",
- mediaEditLink: "edit_media",
- mediaContentType: "content_type",
- mediaETag: "media_etag",
- count: "__count",
- media_src: "mediaReadLink",
- edit_media: "mediaEditLink",
- content_type: "mediaContentType",
- media_etag: "mediaETag",
- url: "uri"
- };
-
- var jsonLightAnnotations = {
- metadata: "odata.metadata",
- count: "odata.count",
- next: "odata.nextLink",
- id: "odata.id",
- etag: "odata.etag",
- read: "odata.readLink",
- edit: "odata.editLink",
- mediaRead: "odata.mediaReadLink",
- mediaEdit: "odata.mediaEditLink",
- mediaEtag: "odata.mediaETag",
- mediaContentType: "odata.mediaContentType",
- actions: "odata.actions",
- functions: "odata.functions",
- navigationUrl: "odata.navigationLinkUrl",
- associationUrl: "odata.associationLinkUrl",
- type: "odata.type"
- };
-
- var jsonLightAnnotationInfo = function (annotation) {
- /// <summary>Gets the name and target of an annotation in a JSON light payload.</summary>
- /// <param name="annotation" type="String">JSON light payload annotation.</param>
- /// <returns type="Object">Object containing the annotation name and the target property name.</param>
-
- if (annotation.indexOf(".") > 0) {
- var targetEnd = annotation.indexOf("@");
- var target = targetEnd > -1 ? annotation.substring(0, targetEnd) : null;
- var name = annotation.substring(targetEnd + 1);
-
- return {
- target: target,
- name: name,
- isOData: name.indexOf(odataAnnotationPrefix) === 0
- };
- }
- return null;
- };
-
- var jsonLightDataItemType = function (name, value, container, dataItemModel, model) {
- /// <summary>Gets the type name of a JSON light data item that belongs to a feed, an entry, a complex type property, or a collection property.</summary>
- /// <param name="name" type="String">Name of the data item for which the type name is going to be retrieved.</param>
- /// <param name="value">Value of the data item.</param>
- /// <param name="container" type="Object">JSON light object that owns the data item.</param>
- /// <param name="dataItemModel" type="Object" optional="true">Object describing the data item in an OData conceptual schema.</param>
- /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
- /// <remarks>
- /// This function will first try to get the type name from the data item's value itself if it is a JSON light object; otherwise
- /// it will try to get it from the odata.type annotation applied to the data item in the container. Then, it will fallback to the data item model.
- /// If all attempts fail, it will return null.
- /// </remarks>
- /// <returns type="String">Data item type name; null if the type name cannot be found.</returns>
-
- return (isComplex(value) && value[typeAnnotation]) ||
- (container && container[name + "@" + typeAnnotation]) ||
- (dataItemModel && dataItemModel.type) ||
- (lookupNavigationPropertyType(dataItemModel, model)) ||
- null;
- };
-
- var jsonLightDataItemModel = function (name, containerModel) {
- /// <summary>Gets an object describing a data item in an OData conceptual schema.</summary>
- /// <param name="name" type="String">Name of the data item for which the model is going to be retrieved.</param>
- /// <param name="containerModel" type="Object">Object describing the owner of the data item in an OData conceptual schema.</param>
- /// <returns type="Object">Object describing the data item; null if it cannot be found.</returns>
-
- if (containerModel) {
- return lookupProperty(containerModel.property, name) ||
- lookupProperty(containerModel.navigationProperty, name);
- }
- return null;
- };
-
- var jsonLightIsEntry = function (data) {
- /// <summary>Determines whether data represents a JSON light entry object.</summary>
- /// <param name="data" type="Object">JSON light object to test.</param>
- /// <returns type="Boolean">True if the data is JSON light entry object; false otherwise.</returns>
-
- return isComplex(data) && ((odataAnnotationPrefix + "id") in data);
- };
-
- var jsonLightIsNavigationProperty = function (name, data, dataItemModel) {
- /// <summary>Determines whether a data item in a JSON light object is a navigation property.</summary>
- /// <param name="name" type="String">Name of the data item to test.</param>
- /// <param name="data" type="Object">JSON light object that owns the data item.</param>
- /// <param name="dataItemModel" type="Object">Object describing the data item in an OData conceptual schema.</param>
- /// <returns type="Boolean">True if the data item is a navigation property; false otherwise.</returns>
-
- djsassert(isComplex(data), "jsonLightIsNavProp - data is not an object!!");
- if (!!data[name + "@" + navUrlAnnotation] || (dataItemModel && dataItemModel.relationship)) {
- return true;
- }
-
- // Sniff the property value.
- var value = isArray(data[name]) ? data[name][0] : data[name];
- return jsonLightIsEntry(value);
- };
-
- var jsonLightIsPrimitiveType = function (typeName) {
- /// <summary>Determines whether a type name is a primitive type in a JSON light payload.</summary>
- /// <param name="typeName" type="String">Type name to test.</param>
- /// <returns type="Boolean">True if the type name an EDM primitive type or an OData spatial type; false otherwise.</returns>
-
- return isPrimitiveEdmType(typeName) || isGeographyEdmType(typeName) || isGeometryEdmType(typeName);
- };
-
- var jsonLightReadDataAnnotations = function (data, obj, baseURI, dataModel, model) {
- /// <summary>Converts annotations found in a JSON light payload object to either properties or metadata.</summary>
- /// <param name="data" type="Object">JSON light payload object containing the annotations to convert.</param>
- /// <param name="obj" type="Object">Object that will store the converted annotations.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
- /// <param name="dataModel" type="Object">Object describing the JSON light payload in an OData conceptual schema.</param>
- /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
- /// <returns>JSON light payload object with its annotations converted to either properties or metadata.</param>
-
- for (var name in data) {
- if (name.indexOf(".") > 0 && name.charAt(0) !== "#") {
- var annotationInfo = jsonLightAnnotationInfo(name);
- if (annotationInfo) {
- var annotationName = annotationInfo.name;
- var target = annotationInfo.target;
- var targetModel = null;
- var targetType = null;
-
- if (target) {
- targetModel = jsonLightDataItemModel(target, dataModel);
- targetType = jsonLightDataItemType(target, data[target], data, targetModel, model);
- }
-
- if (annotationInfo.isOData) {
- jsonLightApplyPayloadODataAnnotation(annotationName, target, targetType, data[name], data, obj, baseURI);
- } else {
- obj[name] = data[name];
- }
- }
- }
- }
- return obj;
- };
-
- var jsonLightApplyPayloadODataAnnotation = function (name, target, targetType, value, data, obj, baseURI) {
- /// <summary>
- /// Processes a JSON Light payload OData annotation producing either a property, payload metadata, or property metadata on its owner object.
- /// </summary>
- /// <param name="name" type="String">Annotation name.</param>
- /// <param name="target" type="String">Name of the property that is being targeted by the annotation.</param>
- /// <param name="targetType" type="String">Type name of the target property.</param>
- /// <param name="data" type="Object">JSON light object containing the annotation.</param>
- /// <param name="obj" type="Object">Object that will hold properties produced by the annotation.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
-
- var annotation = name.substring(odataAnnotationPrefix.length);
-
- switch (annotation) {
- case "navigationLinkUrl":
- jsonLightApplyNavigationUrlAnnotation(annotation, target, targetType, value, data, obj, baseURI);
- return;
- case "nextLink":
- case "count":
- jsonLightApplyFeedAnnotation(annotation, target, value, obj, baseURI);
- return;
- case "mediaReadLink":
- case "mediaEditLink":
- case "mediaContentType":
- case "mediaETag":
- jsonLightApplyMediaAnnotation(annotation, target, targetType, value, obj, baseURI);
- return;
- default:
- jsonLightApplyMetadataAnnotation(annotation, target, value, obj, baseURI);
- return;
- }
- };
-
- var jsonLightApplyMetadataAnnotation = function (name, target, value, obj, baseURI) {
- /// <summary>
- /// Converts a JSON light annotation that applies to entry metadata only (i.e. odata.editLink or odata.readLink) and its value
- /// into their library's internal representation and saves it back to data.
- /// </summary>
- /// <param name="name" type="String">Annotation name.</param>
- /// <param name="target" type="String">Name of the property on which the annotation should be applied.</param>
- /// <param name="value" type="Object">Annotation value.</param>
- /// <param name="obj" type="Object">Object that will hold properties produced by the annotation.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
-
- var metadata = obj.__metadata = obj.__metadata || {};
- var mappedName = jsonLightNameMap[name] || name;
-
- if (name === "editLink") {
- metadata.uri = normalizeURI(value, baseURI);
- metadata[mappedName] = metadata.uri;
- return;
- }
-
- if (name === "readLink" || name === "associationLinkUrl") {
- value = normalizeURI(value, baseURI);
- }
-
- if (target) {
- var propertiesMetadata = metadata.properties = metadata.properties || {};
- var propertyMetadata = propertiesMetadata[target] = propertiesMetadata[target] || {};
-
- if (name === "type") {
- propertyMetadata[mappedName] = propertyMetadata[mappedName] || value;
- return;
- }
- propertyMetadata[mappedName] = value;
- return;
- }
- metadata[mappedName] = value;
- };
-
- var jsonLightApplyFeedAnnotation = function (name, target, value, obj, baseURI) {
- /// <summary>
- /// Converts a JSON light annotation that applies to feeds only (i.e. odata.count or odata.nextlink) and its value
- /// into their library's internal representation and saves it back to data.
- /// </summary>
- /// <param name="name" type="String">Annotation name.</param>
- /// <param name="target" type="String">Name of the property on which the annotation should be applied.</param>
- /// <param name="value" type="Object">Annotation value.</param>
- /// <param name="obj" type="Object">Object that will hold properties produced by the annotation.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
-
- var mappedName = jsonLightNameMap[name];
- var feed = target ? obj[target] : obj;
- feed[mappedName] = (name === "nextLink") ? normalizeURI(value, baseURI) : value;
- };
-
- var jsonLightApplyMediaAnnotation = function (name, target, targetType, value, obj, baseURI) {
- /// <summary>
- /// Converts a JSON light media annotation in and its value into their library's internal representation
- /// and saves it back to data or metadata.
- /// </summary>
- /// <param name="name" type="String">Annotation name.</param>
- /// <param name="target" type="String">Name of the property on which the annotation should be applied.</param>
- /// <param name="targetType" type="String">Type name of the target property.</param>
- /// <param name="value" type="Object">Annotation value.</param>
- /// <param name="obj" type="Object">Object that will hold properties produced by the annotation.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
-
- var metadata = obj.__metadata = obj.__metadata || {};
- var mappedName = jsonLightNameMap[name];
-
- if (name === "mediaReadLink" || name === "mediaEditLink") {
- value = normalizeURI(value, baseURI);
- }
-
- if (target) {
- var propertiesMetadata = metadata.properties = metadata.properties || {};
- var propertyMetadata = propertiesMetadata[target] = propertiesMetadata[target] || {};
- propertyMetadata.type = propertyMetadata.type || targetType;
-
- obj.__metadata = metadata;
- obj[target] = obj[target] || { __mediaresource: {} };
- obj[target].__mediaresource[mappedName] = value;
- return;
- }
-
- metadata[mappedName] = value;
- };
-
- var jsonLightApplyNavigationUrlAnnotation = function (name, target, targetType, value, data, obj, baseURI) {
- /// <summary>
- /// Converts a JSON light navigation property annotation and its value into their library's internal representation
- /// and saves it back to data o metadata.
- /// </summary>
- /// <param name="name" type="String">Annotation name.</param>
- /// <param name="target" type="String">Name of the property on which the annotation should be applied.</param>
- /// <param name="targetType" type="String">Type name of the target property.</param>
- /// <param name="value" type="Object">Annotation value.</param>
- /// <param name="data" type="Object">JSON light object containing the annotation.</param>
- /// <param name="obj" type="Object">Object that will hold properties produced by the annotation.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
-
- var metadata = obj.__metadata = obj.__metadata || {};
- var propertiesMetadata = metadata.properties = metadata.properties || {};
- var propertyMetadata = propertiesMetadata[target] = propertiesMetadata[target] || {};
- var uri = normalizeURI(value, baseURI);
-
- if (data.hasOwnProperty(target)) {
- // The navigation property is inlined in the payload,
- // so the navigation link url should be pushed to the object's
- // property metadata instead.
- propertyMetadata.navigationLinkUrl = uri;
- return;
- }
- obj[target] = { __deferred: { uri: uri} };
- propertyMetadata.type = propertyMetadata.type || targetType;
- };
-
-
- var jsonLightReadDataItemValue = function (value, typeName, dataItemMetadata, baseURI, dataItemModel, model, recognizeDates) {
- /// <summary>Converts the value of a data item in a JSON light object to its library representation.</summary>
- /// <param name="value">Data item value to convert.</param>
- /// <param name="typeName" type="String">Type name of the data item.</param>
- /// <param name="dataItemMetadata" type="Object">Object containing metadata about the data item.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
- /// <param name="dataItemModel" type="Object" optional="true">Object describing the data item in an OData conceptual schema.</param>
- /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
- /// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
- /// <returns>Data item value in its library representation.</param>
-
- if (typeof value === "string") {
- return jsonLightReadStringPropertyValue(value, typeName, recognizeDates);
- }
-
- if (!jsonLightIsPrimitiveType(typeName)) {
- if (isArray(value)) {
- return jsonLightReadCollectionPropertyValue(value, typeName, dataItemMetadata, baseURI, model, recognizeDates);
- }
-
- if (isComplex(value)) {
- return jsonLightReadComplexPropertyValue(value, typeName, dataItemMetadata, baseURI, model, recognizeDates);
- }
- }
- return value;
- };
-
- var jsonLightReadStringPropertyValue = function (value, propertyType, recognizeDates) {
- /// <summary>Convertes the value of a string property in a JSON light object to its library representation.</summary>
- /// <param name="value" type="String">String value to convert.</param>
- /// <param name="propertyType" type="String">Type name of the property.</param>
- /// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
- /// <returns>String property value in its library representation.</returns>
-
- switch (propertyType) {
- case EDM_TIME:
- return parseDuration(value);
- case EDM_DATETIME:
- return parseDateTime(value, /*nullOnError*/false);
- case EDM_DATETIMEOFFSET:
- return parseDateTimeOffset(value, /*nullOnError*/false);
- }
-
- if (recognizeDates) {
- return parseDateTime(value, /*nullOnError*/true) ||
- parseDateTimeOffset(value, /*nullOnError*/true) ||
- value;
- }
- return value;
- };
-
- var jsonLightReadCollectionPropertyValue = function (value, propertyType, propertyMetadata, baseURI, model, recognizeDates) {
- /// <summary>Converts the value of a collection property in a JSON light object into its library representation.</summary>
- /// <param name="value" type="Array">Collection property value to convert.</param>
- /// <param name="propertyType" type="String">Property type name.</param>
- /// <param name="propertyMetadata" type="Object">Object containing metadata about the collection property.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
- /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
- /// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
- /// <returns type="Object">Collection property value in its library representation.</returns>
-
- var collectionType = getCollectionType(propertyType);
- var itemsMetadata = [];
- var items = [];
-
- var i, len;
- for (i = 0, len = value.length; i < len; i++) {
- var itemType = jsonLightDataItemType(null, value[i]) || collectionType;
- var itemMetadata = { type: itemType };
- var item = jsonLightReadDataItemValue(value[i], itemType, itemMetadata, baseURI, null, model, recognizeDates);
-
- if (!jsonLightIsPrimitiveType(itemType) && !isPrimitive(value[i])) {
- itemsMetadata.push(itemMetadata);
- }
- items.push(item);
- }
-
- if (itemsMetadata.length > 0) {
- propertyMetadata.elements = itemsMetadata;
- }
-
- return { __metadata: { type: propertyType }, results: items };
- };
-
- var jsonLightReadComplexPropertyValue = function (value, propertyType, propertyMetadata, baseURI, model, recognizeDates) {
- /// <summary>Converts the value of a comples property in a JSON light object into its library representation.</summary>
- /// <param name="value" type="Object">Complex property value to convert.</param>
- /// <param name="propertyType" type="String">Property type name.</param>
- /// <param name="propertyMetadata" type="Object">Object containing metadata about the complx type property.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
- /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
- /// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
- /// <returns type="Object">Complex property value in its library representation.</returns>
-
- var complexValue = jsonLightReadObject(value, { type: propertyType }, baseURI, model, recognizeDates);
- var complexMetadata = complexValue.__metadata;
- var complexPropertiesMetadata = complexMetadata.properties;
-
- if (complexPropertiesMetadata) {
- propertyMetadata.properties = complexPropertiesMetadata;
- delete complexMetadata.properties;
- }
- return complexValue;
- };
-
- var jsonLightReadNavigationPropertyValue = function (value, propertyInfo, baseURI, model, recognizeDates) {
- /// <summary>Converts the value of a navigation property in a JSON light object into its library representation.</summary>
- /// <param name="value">Navigation property property value to convert.</param>
- /// <param name="propertyInfo" type="String">Information about the property whether it's an entry, feed or complex type.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
- /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
- /// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
- /// <returns type="Object">Collection property value in its library representation.</returns>
-
- if (isArray(value)) {
- return jsonLightReadFeed(value, propertyInfo, baseURI, model, recognizeDates);
- }
-
- if (isComplex(value)) {
- return jsonLightReadObject(value, propertyInfo, baseURI, model, recognizeDates);
- }
- return null;
- };
-
- var jsonLightReadObject = function (data, objectInfo, baseURI, model, recognizeDates) {
- /// <summary>Converts a JSON light entry or complex type object into its library representation.</summary>
- /// <param name="data" type="Object">JSON light entry or complex type object to convert.</param>
- /// <param name="objectInfo" type="Object">Information about the entry or complex.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
- /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
- /// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
- /// <returns type="Object">Entry or complex type object.</param>
-
- objectInfo = objectInfo || {};
- var actualType = data[typeAnnotation] || objectInfo.type || null;
- var dataModel = lookupEntityType(actualType, model);
- var isEntry = true;
- if (!dataModel) {
- isEntry = false;
- dataModel = lookupComplexType(actualType, model);
- }
-
- var metadata = { type: actualType };
- var obj = { __metadata: metadata };
- var propertiesMetadata = {};
- var baseTypeModel;
- if (isEntry && dataModel && objectInfo.entitySet && objectInfo.contentTypeOdata == "minimalmetadata") {
- var serviceURI = baseURI.substring(0, baseURI.lastIndexOf("$metadata"));
- baseTypeModel = null; // check if the key model is in a parent type.
- if (!dataModel.key) {
- baseTypeModel = dataModel;
- }
- while (!!baseTypeModel && !baseTypeModel.key && baseTypeModel.baseType) {
- baseTypeModel = lookupEntityType(baseTypeModel.baseType, model);
- }
-
- if (dataModel.key || (!!baseTypeModel && baseTypeModel.key)) {
- var entryKey;
- if (dataModel.key) {
- entryKey = jsonLightGetEntryKey(data, dataModel);
- } else {
- entryKey = jsonLightGetEntryKey(data, baseTypeModel);
- }
- if (entryKey) {
- var entryInfo = {
- key: entryKey,
- entitySet: objectInfo.entitySet,
- functionImport: objectInfo.functionImport,
- containerName: objectInfo.containerName
- };
- jsonLightComputeUrisIfMissing(data, entryInfo, actualType, serviceURI, dataModel, baseTypeModel);
- }
- }
- }
-
- for (var name in data) {
- if (name.indexOf("#") === 0) {
- // This is an advertised function or action.
- jsonLightReadAdvertisedFunctionOrAction(name.substring(1), data[name], obj, baseURI, model);
- } else {
- // Is name NOT an annotation?
- if (name.indexOf(".") === -1) {
- if (!metadata.properties) {
- metadata.properties = propertiesMetadata;
- }
-
- var propertyValue = data[name];
- var propertyModel = propertyModel = jsonLightDataItemModel(name, dataModel);
- baseTypeModel = dataModel;
- while (!!dataModel && propertyModel === null && baseTypeModel.baseType) {
- baseTypeModel = lookupEntityType(baseTypeModel.baseType, model);
- propertyModel = propertyModel = jsonLightDataItemModel(name, baseTypeModel);
- }
- var isNavigationProperty = jsonLightIsNavigationProperty(name, data, propertyModel);
- var propertyType = jsonLightDataItemType(name, propertyValue, data, propertyModel, model);
- var propertyMetadata = propertiesMetadata[name] = propertiesMetadata[name] || { type: propertyType };
- if (isNavigationProperty) {
- var propertyInfo = {};
- if (objectInfo.entitySet !== undefined) {
- var navigationPropertyEntitySetName = lookupNavigationPropertyEntitySet(propertyModel, objectInfo.entitySet.name, model);
- propertyInfo = getEntitySetInfo(navigationPropertyEntitySetName, model);
- }
- propertyInfo.contentTypeOdata = objectInfo.contentTypeOdata;
- propertyInfo.kind = objectInfo.kind;
- propertyInfo.type = propertyType;
- obj[name] = jsonLightReadNavigationPropertyValue(propertyValue, propertyInfo, baseURI, model, recognizeDates);
- } else {
- obj[name] = jsonLightReadDataItemValue(propertyValue, propertyType, propertyMetadata, baseURI, propertyModel, model, recognizeDates);
- }
- }
- }
- }
-
- return jsonLightReadDataAnnotations(data, obj, baseURI, dataModel, model);
- };
-
- var jsonLightReadAdvertisedFunctionOrAction = function (name, value, obj, baseURI, model) {
- /// <summary>Converts a JSON light advertised action or function object into its library representation.</summary>
- /// <param name="name" type="String">Advertised action or function name.</param>
- /// <param name="value">Advertised action or function value.</param>
- /// <param name="obj" type="Object">Object that will the converted value of the advertised action or function.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing the action's or function's relative URIs.</param>
- /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
- /// <remarks>
- /// Actions and functions have the same representation in json light, so to disambiguate them the function uses
- /// the model object. If available, the function will look for the functionImport object that describes the
- /// the action or the function. If for whatever reason the functionImport can't be retrieved from the model (like
- /// there is no model available or there is no functionImport within the model), then the value is going to be treated
- /// as an advertised action and stored under obj.__metadata.actions.
- /// </remarks>
-
- if (!name || !isArray(value) && !isComplex(value)) {
- return;
- }
-
- var isFunction = false;
- var nsEnd = name.lastIndexOf(".");
- var simpleName = name.substring(nsEnd + 1);
- var containerName = (nsEnd > -1) ? name.substring(0, nsEnd) : "";
-
- var container = (simpleName === name || containerName.indexOf(".") === -1) ?
- lookupDefaultEntityContainer(model) :
- lookupEntityContainer(containerName, model);
-
- if (container) {
- var functionImport = lookupFunctionImport(container.functionImport, simpleName);
- if (functionImport && !!functionImport.isSideEffecting) {
- isFunction = !parseBool(functionImport.isSideEffecting);
- }
- }
-
- var metadata = obj.__metadata;
- var targetName = isFunction ? "functions" : "actions";
- var metadataURI = normalizeURI(name, baseURI);
- var items = (isArray(value)) ? value : [value];
-
- var i, len;
- for (i = 0, len = items.length; i < len; i++) {
- var item = items[i];
- if (item) {
- var targetCollection = metadata[targetName] = metadata[targetName] || [];
- var actionOrFunction = { metadata: metadataURI, title: item.title, target: normalizeURI(item.target, baseURI) };
- targetCollection.push(actionOrFunction);
- }
- }
- };
-
- var jsonLightReadFeed = function (data, feedInfo, baseURI, model, recognizeDates) {
- /// <summary>Converts a JSON light feed or top level collection property object into its library representation.</summary>
- /// <param name="data" type="Object">JSON light feed object to convert.</param>
- /// <param name="typeName" type="String">Type name of the feed or collection items.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
- /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
- /// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
- /// <returns type="Object">Feed or top level collection object.</param>
-
- var items = isArray(data) ? data : data.value;
- var entries = [];
- var i, len, entry;
- for (i = 0, len = items.length; i < len; i++) {
- entry = jsonLightReadObject(items[i], feedInfo, baseURI, model, recognizeDates);
- entries.push(entry);
- }
-
- var feed = { results: entries };
-
- if (isComplex(data)) {
- for (var name in data) {
- if (name.indexOf("#") === 0) {
- // This is an advertised function or action.
- feed.__metadata = feed.__metadata || {};
- jsonLightReadAdvertisedFunctionOrAction(name.substring(1), data[name], feed, baseURI, model);
- }
- }
- feed = jsonLightReadDataAnnotations(data, feed, baseURI);
- }
- return feed;
- };
-
- var jsonLightGetEntryKey = function (data, entityModel) {
- /// <summary>Gets the key of an entry.</summary>
- /// <param name="data" type="Object">JSON light entry.</param>
- /// <param name="entityModel" type="String">Object describing the entry Model</param>
- /// <returns type="string">Entry instance key.</returns>
-
- var entityInstanceKey;
- var entityKeys = entityModel.key.propertyRef;
- var type;
- entityInstanceKey = "(";
- if (entityKeys.length == 1) {
- type = lookupProperty(entityModel.property, entityKeys[0].name).type;
- entityInstanceKey += formatLiteral(data[entityKeys[0].name], type);
- } else {
- var first = true;
- for (var i = 0; i < entityKeys.length; i++) {
- if (!first) {
- entityInstanceKey += ",";
- } else {
- first = false;
- }
- type = lookupProperty(entityModel.property, entityKeys[i].name).type;
- entityInstanceKey += entityKeys[i].name + "=" + formatLiteral(data[entityKeys[i].name], type);
- }
- }
- entityInstanceKey += ")";
- return entityInstanceKey;
- };
-
-
- var jsonLightComputeUrisIfMissing = function (data, entryInfo, actualType, serviceURI, entityModel, baseTypeModel) {
- /// <summary>Compute the URI according to OData conventions if it doesn't exist</summary>
- /// <param name="data" type="Object">JSON light entry.</param>
- /// <param name="entryInfo" type="Object">Information about the entry includes type, key, entitySet and entityContainerName.</param>
- /// <param name="actualType" type="String">Type of the entry</param>
- /// <param name="serviceURI" type="String">Base URI the service.</param>
- /// <param name="entityModel" type="Object">Object describing an OData conceptual schema of the entry.</param>
- /// <param name="baseTypeModel" type="Object" optional="true">Object escribing an OData conceptual schema of the baseType if it exists.</param>
-
- var lastIdSegment = data[jsonLightAnnotations.id] || data[jsonLightAnnotations.read] || data[jsonLightAnnotations.edit] || entryInfo.entitySet.name + entryInfo.key;
- data[jsonLightAnnotations.id] = serviceURI + lastIdSegment;
- if (!data[jsonLightAnnotations.edit]) {
- data[jsonLightAnnotations.edit] = entryInfo.entitySet.name + entryInfo.key;
- if (entryInfo.entitySet.entityType != actualType) {
- data[jsonLightAnnotations.edit] += "/" + actualType;
- }
- }
- data[jsonLightAnnotations.read] = data[jsonLightAnnotations.read] || data[jsonLightAnnotations.edit];
- if (!data[jsonLightAnnotations.etag]) {
- var etag = jsonLightComputeETag(data, entityModel, baseTypeModel);
- if (!!etag) {
- data[jsonLightAnnotations.etag] = etag;
- }
- }
-
- jsonLightComputeStreamLinks(data, entityModel, baseTypeModel);
- jsonLightComputeNavigationAndAssociationProperties(data, entityModel, baseTypeModel);
- jsonLightComputeFunctionImports(data, entryInfo);
- };
-
- var jsonLightComputeETag = function (data, entityModel, baseTypeModel) {
- /// <summary>Computes the etag of an entry</summary>
- /// <param name="data" type="Object">JSON light entry.</param>
- /// <param name="entryInfo" type="Object">Object describing the entry model.</param>
- /// <param name="baseTypeModel" type="Object" optional="true">Object describing an OData conceptual schema of the baseType if it exists.</param>
- /// <returns type="string">Etag value</returns>
- var etag = "";
- var propertyModel;
- for (var i = 0; entityModel.property && i < entityModel.property.length; i++) {
- propertyModel = entityModel.property[i];
- etag = jsonLightAppendValueToEtag(data, etag, propertyModel);
-
- }
- if (baseTypeModel) {
- for (i = 0; baseTypeModel.property && i < baseTypeModel.property.length; i++) {
- propertyModel = baseTypeModel.property[i];
- etag = jsonLightAppendValueToEtag(data, etag, propertyModel);
- }
- }
- if (etag.length > 0) {
- return etag + "\"";
- }
- return null;
- };
-
- var jsonLightAppendValueToEtag = function (data, etag, propertyModel) {
- /// <summary>Adds a propery value to the etag after formatting.</summary>
- /// <param name="data" type="Object">JSON light entry.</param>
- /// <param name="etag" type="Object">value of the etag.</param>
- /// <param name="propertyModel" type="Object">Object describing an OData conceptual schema of the property.</param>
- /// <returns type="string">Etag value</returns>
-
- if (propertyModel.concurrencyMode == "Fixed") {
- if (etag.length > 0) {
- etag += ",";
- } else {
- etag += "W/\"";
- }
- if (data[propertyModel.name] !== null) {
- etag += formatLiteral(data[propertyModel.name], propertyModel.type);
- } else {
- etag += "null";
- }
- }
- return etag;
- };
-
- var jsonLightComputeNavigationAndAssociationProperties = function (data, entityModel, baseTypeModel) {
- /// <summary>Adds navigation links to the entry metadata</summary>
- /// <param name="data" type="Object">JSON light entry.</param>
- /// <param name="entityModel" type="Object">Object describing the entry model.</param>
- /// <param name="baseTypeModel" type="Object" optional="true">Object describing an OData conceptual schema of the baseType if it exists.</param>
-
- var navigationLinkAnnotation = "@odata.navigationLinkUrl";
- var associationLinkAnnotation = "@odata.associationLinkUrl";
- var navigationPropertyName, navigationPropertyAnnotation, associationPropertyAnnotation;
- for (var i = 0; entityModel.navigationProperty && i < entityModel.navigationProperty.length; i++) {
- navigationPropertyName = entityModel.navigationProperty[i].name;
- navigationPropertyAnnotation = navigationPropertyName + navigationLinkAnnotation;
- if (data[navigationPropertyAnnotation] === undefined) {
- data[navigationPropertyAnnotation] = data[jsonLightAnnotations.edit] + "/" + encodeURIComponent(navigationPropertyName);
- }
- associationPropertyAnnotation = navigationPropertyName + associationLinkAnnotation;
- if (data[associationPropertyAnnotation] === undefined) {
- data[associationPropertyAnnotation] = data[jsonLightAnnotations.edit] + "/$links/" + encodeURIComponent(navigationPropertyName);
- }
- }
-
- if (baseTypeModel && baseTypeModel.navigationProperty) {
- for (i = 0; i < baseTypeModel.navigationProperty.length; i++) {
- navigationPropertyName = baseTypeModel.navigationProperty[i].name;
- navigationPropertyAnnotation = navigationPropertyName + navigationLinkAnnotation;
- if (data[navigationPropertyAnnotation] === undefined) {
- data[navigationPropertyAnnotation] = data[jsonLightAnnotations.edit] + "/" + encodeURIComponent(navigationPropertyName);
- }
- associationPropertyAnnotation = navigationPropertyName + associationLinkAnnotation;
- if (data[associationPropertyAnnotation] === undefined) {
- data[associationPropertyAnnotation] = data[jsonLightAnnotations.edit] + "/$links/" + encodeURIComponent(navigationPropertyName);
- }
- }
- }
- };
-
- var formatLiteral = function (value, type) {
- /// <summary>Formats a value according to Uri literal format</summary>
- /// <param name="value">Value to be formatted.</param>
- /// <param name="type">Edm type of the value</param>
- /// <returns type="string">Value after formatting</returns>
-
- value = "" + formatRowLiteral(value, type);
- value = encodeURIComponent(value.replace("'", "''"));
- switch ((type)) {
- case "Edm.Binary":
- return "X'" + value + "'";
- case "Edm.DateTime":
- return "datetime" + "'" + value + "'";
- case "Edm.DateTimeOffset":
- return "datetimeoffset" + "'" + value + "'";
- case "Edm.Decimal":
- return value + "M";
- case "Edm.Guid":
- return "guid" + "'" + value + "'";
- case "Edm.Int64":
- return value + "L";
- case "Edm.Float":
- return value + "f";
- case "Edm.Double":
- return value + "D";
- case "Edm.Geography":
- return "geography" + "'" + value + "'";
- case "Edm.Geometry":
- return "geometry" + "'" + value + "'";
- case "Edm.Time":
- return "time" + "'" + value + "'";
- case "Edm.String":
- return "'" + value + "'";
- default:
- return value;
- }
- };
-
-
- var formatRowLiteral = function (value, type) {
- switch (type) {
- case "Edm.Binary":
- return convertByteArrayToHexString(value);
- default:
- return value;
- }
- };
-
- var jsonLightComputeFunctionImports = function (data, entryInfo) {
- /// <summary>Adds functions and actions links to the entry metadata</summary>
- /// <param name="entry" type="Object">JSON light entry.</param>
- /// <param name="entityInfo" type="Object">Object describing the entry</param>
-
- var functionImport = entryInfo.functionImport || [];
- for (var i = 0; i < functionImport.length; i++) {
- if (functionImport[i].isBindable && functionImport[i].parameter[0] && functionImport[i].parameter[0].type == entryInfo.entitySet.entityType) {
- var functionImportAnnotation = "#" + entryInfo.containerName + "." + functionImport[i].name;
- if (data[functionImportAnnotation] == undefined) {
- data[functionImportAnnotation] = {
- title: functionImport[i].name,
- target: data[jsonLightAnnotations.edit] + "/" + functionImport[i].name
- };
- }
- }
- }
- };
-
- var jsonLightComputeStreamLinks = function (data, entityModel, baseTypeModel) {
- /// <summary>Adds stream links to the entry metadata</summary>
- /// <param name="data" type="Object">JSON light entry.</param>
- /// <param name="entityModel" type="Object">Object describing the entry model.</param>
- /// <param name="baseTypeModel" type="Object" optional="true">Object describing an OData conceptual schema of the baseType if it exists.</param>
-
- if (entityModel.hasStream || (baseTypeModel && baseTypeModel.hasStream)) {
- data[jsonLightAnnotations.mediaEdit] = data[jsonLightAnnotations.mediaEdit] || data[jsonLightAnnotations.mediaEdit] + "/$value";
- data[jsonLightAnnotations.mediaRead] = data[jsonLightAnnotations.mediaRead] || data[jsonLightAnnotations.mediaEdit];
- }
- };
-
- var jsonLightReadTopPrimitiveProperty = function (data, typeName, baseURI, recognizeDates) {
- /// <summary>Converts a JSON light top level primitive property object into its library representation.</summary>
- /// <param name="data" type="Object">JSON light feed object to convert.</param>
- /// <param name="typeName" type="String">Type name of the primitive property.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
- /// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
- /// <returns type="Object">Top level primitive property object.</param>
-
- var metadata = { type: typeName };
- var value = jsonLightReadDataItemValue(data.value, typeName, metadata, baseURI, null, null, recognizeDates);
- return jsonLightReadDataAnnotations(data, { __metadata: metadata, value: value }, baseURI);
- };
-
- var jsonLightReadTopCollectionProperty = function (data, typeName, baseURI, model, recognizeDates) {
- /// <summary>Converts a JSON light top level collection property object into its library representation.</summary>
- /// <param name="data" type="Object">JSON light feed object to convert.</param>
- /// <param name="typeName" type="String">Type name of the collection property.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
- /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
- /// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
- /// <returns type="Object">Top level collection property object.</param>
-
- var propertyMetadata = {};
- var value = jsonLightReadCollectionPropertyValue(data.value, typeName, propertyMetadata, baseURI, model, recognizeDates);
- extend(value.__metadata, propertyMetadata);
- return jsonLightReadDataAnnotations(data, value, baseURI);
- };
-
- var jsonLightReadLinksDocument = function (data, baseURI) {
- /// <summary>Converts a JSON light links collection object to its library representation.</summary>
- /// <param name="data" type="Object">JSON light link object to convert.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
- /// <returns type="Object">Links collection object.</param>
-
- var items = data.value;
- if (!isArray(items)) {
- return jsonLightReadLink(data, baseURI);
- }
-
- var results = [];
- var i, len;
- for (i = 0, len = items.length; i < len; i++) {
- results.push(jsonLightReadLink(items[i], baseURI));
- }
-
- var links = { results: results };
- return jsonLightReadDataAnnotations(data, links, baseURI);
- };
-
- var jsonLightReadLink = function (data, baseURI) {
- /// <summary>Converts a JSON light link object to its library representation.</summary>
- /// <param name="data" type="Object">JSON light link object to convert.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
- /// <returns type="Object">Link object.</param>
-
- var link = { uri: normalizeURI(data.url, baseURI) };
-
- link = jsonLightReadDataAnnotations(data, link, baseURI);
- var metadata = link.__metadata || {};
- var metadataProperties = metadata.properties || {};
-
- jsonLightRemoveTypePropertyMetadata(metadataProperties.url);
- renameProperty(metadataProperties, "url", "uri");
-
- return link;
- };
-
- var jsonLightRemoveTypePropertyMetadata = function (propertyMetadata) {
- /// <summary>Removes the type property from a property metadata object.</summary>
- /// <param name="propertyMetadata" type="Object">Property metadata object.</param>
-
- if (propertyMetadata) {
- delete propertyMetadata.type;
- }
- };
-
- var jsonLightReadSvcDocument = function (data, baseURI) {
- /// <summary>Converts a JSON light service document object to its library representation.</summary>
- /// <param name="data" type="Object">JSON light service document object to convert.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
- /// <returns type="Object">Link object.</param>
-
- var items = data.value;
- var collections = [];
- var workspace = jsonLightReadDataAnnotations(data, { collections: collections }, baseURI);
-
- var metadata = workspace.__metadata || {};
- var metadataProperties = metadata.properties || {};
-
- jsonLightRemoveTypePropertyMetadata(metadataProperties.value);
- renameProperty(metadataProperties, "value", "collections");
-
- var i, len;
- for (i = 0, len = items.length; i < len; i++) {
- var item = items[i];
- var collection = { title: item.name, href: normalizeURI(item.url, baseURI) };
-
- collection = jsonLightReadDataAnnotations(item, collection, baseURI);
- metadata = collection.__metadata || {};
- metadataProperties = metadata.properties || {};
-
- jsonLightRemoveTypePropertyMetadata(metadataProperties.name);
- jsonLightRemoveTypePropertyMetadata(metadataProperties.url);
-
- renameProperty(metadataProperties, "name", "title");
- renameProperty(metadataProperties, "url", "href");
-
- collections.push(collection);
- }
-
- return { workspaces: [workspace] };
- };
-
- var jsonLightMakePayloadInfo = function (kind, type) {
- /// <summary>Creates an object containing information for the json light payload.</summary>
- /// <param name="kind" type="String">JSON light payload kind, one of the PAYLOADTYPE_XXX constant values.</param>
- /// <param name="typeName" type="String">Type name of the JSON light payload.</param>
- /// <returns type="Object">Object with kind and type fields.</returns>
-
- /// <field name="kind" type="String">Kind of the JSON light payload. One of the PAYLOADTYPE_XXX constant values.</field>
- /// <field name="type" type="String">Data type of the JSON light payload.</field>
-
- return { kind: kind, type: type || null };
- };
-
- var jsonLightPayloadInfo = function (data, model, inferFeedAsComplexType) {
- /// <summary>Infers the information describing the JSON light payload from its metadata annotation, structure, and data model.</summary>
- /// <param name="data" type="Object">Json light response payload object.</param>
- /// <param name="model" type="Object">Object describing an OData conceptual schema.</param>
- /// <param name="inferFeedAsComplexType" type="Boolean">True if a JSON light payload that looks like a feed should be treated as a complex type property instead.</param>
- /// <remarks>
- /// If the arguments passed to the function don't convey enough information about the payload to determine without doubt that the payload is a feed then it
- /// will try to use the payload object structure instead. If the payload looks like a feed (has value property that is an array or non-primitive values) then
- /// the function will report its kind as PAYLOADTYPE_FEED unless the inferFeedAsComplexType flag is set to true. This flag comes from the user request
- /// and allows the user to control how the library behaves with an ambigous JSON light payload.
- /// </remarks>
- /// <returns type="Object">
- /// Object with kind and type fields. Null if there is no metadata annotation or the payload info cannot be obtained..
- /// </returns>
-
- var metadataUri = data[metadataAnnotation];
- if (!metadataUri || typeof metadataUri !== "string") {
- return null;
- }
-
- var fragmentStart = metadataUri.lastIndexOf("#");
- if (fragmentStart === -1) {
- return jsonLightMakePayloadInfo(PAYLOADTYPE_SVCDOC);
- }
-
- var elementStart = metadataUri.indexOf("@Element", fragmentStart);
- var fragmentEnd = elementStart - 1;
-
- if (fragmentEnd < 0) {
- fragmentEnd = metadataUri.indexOf("?", fragmentStart);
- if (fragmentEnd === -1) {
- fragmentEnd = metadataUri.length;
- }
- }
-
- var fragment = metadataUri.substring(fragmentStart + 1, fragmentEnd);
- if (fragment.indexOf("/$links/") > 0) {
- return jsonLightMakePayloadInfo(PAYLOADTYPE_LINKS);
- }
-
- var fragmentParts = fragment.split("/");
- if (fragmentParts.length >= 0) {
- var qualifiedName = fragmentParts[0];
- var typeCast = fragmentParts[1];
-
- if (jsonLightIsPrimitiveType(qualifiedName)) {
- return jsonLightMakePayloadInfo(PAYLOADTYPE_PRIMITIVE, qualifiedName);
- }
-
- if (isCollectionType(qualifiedName)) {
- return jsonLightMakePayloadInfo(PAYLOADTYPE_COLLECTION, qualifiedName);
- }
-
- var entityType = typeCast;
- var entitySet, functionImport, containerName;
- if (!typeCast) {
- var nsEnd = qualifiedName.lastIndexOf(".");
- var simpleName = qualifiedName.substring(nsEnd + 1);
- var container = (simpleName === qualifiedName) ?
- lookupDefaultEntityContainer(model) :
- lookupEntityContainer(qualifiedName.substring(0, nsEnd), model);
-
- if (container) {
- entitySet = lookupEntitySet(container.entitySet, simpleName);
- functionImport = container.functionImport;
- containerName = container.name;
- entityType = !!entitySet ? entitySet.entityType : null;
- }
- }
-
- var info;
- if (elementStart > 0) {
- info = jsonLightMakePayloadInfo(PAYLOADTYPE_OBJECT, entityType);
- info.entitySet = entitySet;
- info.functionImport = functionImport;
- info.containerName = containerName;
- return info;
- }
-
- if (entityType) {
- info = jsonLightMakePayloadInfo(PAYLOADTYPE_FEED, entityType);
- info.entitySet = entitySet;
- info.functionImport = functionImport;
- info.containerName = containerName;
- return info;
- }
-
- if (isArray(data.value) && !lookupComplexType(qualifiedName, model)) {
- var item = data.value[0];
- if (!isPrimitive(item)) {
- if (jsonLightIsEntry(item) || !inferFeedAsComplexType) {
- return jsonLightMakePayloadInfo(PAYLOADTYPE_FEED, null);
- }
- }
- }
-
- return jsonLightMakePayloadInfo(PAYLOADTYPE_OBJECT, qualifiedName);
- }
-
- return null;
- };
-
- var jsonLightReadPayload = function (data, model, recognizeDates, inferFeedAsComplexType, contentTypeOdata) {
- /// <summary>Converts a JSON light response payload object into its library's internal representation.</summary>
- /// <param name="data" type="Object">Json light response payload object.</param>
- /// <param name="model" type="Object">Object describing an OData conceptual schema.</param>
- /// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
- /// <param name="inferFeedAsComplexType" type="Boolean">True if a JSON light payload that looks like a feed should be reported as a complex type property instead.</param>
- /// <param name="contentTypeOdata" type="string">Includes the type of json ( minimalmetadata, fullmetadata .. etc )</param>
- /// <returns type="Object">Object in the library's representation.</returns>
-
- if (!isComplex(data)) {
- return data;
- }
-
- contentTypeOdata = contentTypeOdata || "minimalmetadata";
- var baseURI = data[metadataAnnotation];
- var payloadInfo = jsonLightPayloadInfo(data, model, inferFeedAsComplexType);
- if (assigned(payloadInfo)) {
- payloadInfo.contentTypeOdata = contentTypeOdata;
- }
- var typeName = null;
- if (payloadInfo) {
- delete data[metadataAnnotation];
-
- typeName = payloadInfo.type;
- switch (payloadInfo.kind) {
- case PAYLOADTYPE_FEED:
- return jsonLightReadFeed(data, payloadInfo, baseURI, model, recognizeDates);
- case PAYLOADTYPE_COLLECTION:
- return jsonLightReadTopCollectionProperty(data, typeName, baseURI, model, recognizeDates);
- case PAYLOADTYPE_PRIMITIVE:
- return jsonLightReadTopPrimitiveProperty(data, typeName, baseURI, recognizeDates);
- case PAYLOADTYPE_SVCDOC:
- return jsonLightReadSvcDocument(data, baseURI);
- case PAYLOADTYPE_LINKS:
- return jsonLightReadLinksDocument(data, baseURI);
- }
- }
- return jsonLightReadObject(data, payloadInfo, baseURI, model, recognizeDates);
- };
-
- var jsonLightSerializableMetadata = ["type", "etag", "media_src", "edit_media", "content_type", "media_etag"];
-
- var formatJsonLight = function (obj, context) {
- /// <summary>Converts an object in the library's internal representation to its json light representation.</summary>
- /// <param name="obj" type="Object">Object the library's internal representation.</param>
- /// <param name="context" type="Object">Object with the serialization context.</param>
- /// <returns type="Object">Object in its json light representation.</returns>
-
- // Regular expression used to test that the uri is for a $links document.
- var linksUriRE = /\/\$links\//;
- var data = {};
- var metadata = obj.__metadata;
-
- var islinks = context && linksUriRE.test(context.request.requestUri);
- formatJsonLightData(obj, (metadata && metadata.properties), data, islinks);
- return data;
- };
-
- var formatJsonLightMetadata = function (metadata, data) {
- /// <summary>Formats an object's metadata into the appropriate json light annotations and saves them to data.</summary>
- /// <param name="obj" type="Object">Object whose metadata is going to be formatted as annotations.</param>
- /// <param name="data" type="Object">Object on which the annotations are going to be stored.</param>
-
- if (metadata) {
- var i, len;
- for (i = 0, len = jsonLightSerializableMetadata.length; i < len; i++) {
- // There is only a subset of metadata values that are interesting during update requests.
- var name = jsonLightSerializableMetadata[i];
- var qName = odataAnnotationPrefix + (jsonLightNameMap[name] || name);
- formatJsonLightAnnotation(qName, null, metadata[name], data);
- }
- }
- };
-
- var formatJsonLightData = function (obj, pMetadata, data, isLinks) {
- /// <summary>Formats an object's data into the appropriate json light values and saves them to data.</summary>
- /// <param name="obj" type="Object">Object whose data is going to be formatted.</param>
- /// <param name="pMetadata" type="Object">Object that contains metadata for the properties that are being formatted.</param>
- /// <param name="data" type="Object">Object on which the formatted values are going to be stored.</param>
- /// <param name="isLinks" type="Boolean">True if a links document is being formatted. False otherwise.</param>
-
- for (var key in obj) {
- var value = obj[key];
- if (key === "__metadata") {
- // key is the object metadata.
- formatJsonLightMetadata(value, data);
- } else if (key.indexOf(".") === -1) {
- // key is an regular property or array element.
- if (isLinks && key === "uri") {
- formatJsonLightEntityLink(value, data);
- } else {
- formatJsonLightProperty(key, value, pMetadata, data, isLinks);
- }
- } else {
- data[key] = value;
- }
- }
- };
-
- var formatJsonLightProperty = function (name, value, pMetadata, data) {
- /// <summary>Formats an object's value identified by name to its json light representation and saves it to data.</summary>
- /// <param name="name" type="String">Property name.</param>
- /// <param name="value">Property value.</param>
- /// <param name="pMetadata" type="Object">Object that contains metadata for the property that is being formatted.</param>
- /// <param name="data" type="Object">Object on which the formatted value is going to be stored.</param>
-
- // Get property type from property metadata
- var propertyMetadata = pMetadata && pMetadata[name] || { properties: undefined, type: undefined };
- var typeName = dataItemTypeName(value, propertyMetadata);
-
- if (isPrimitive(value) || !value) {
- // It is a primitive value then.
- formatJsonLightAnnotation(typeAnnotation, name, typeName, data);
- data[name] = value;
- return;
- }
-
- if (isFeed(value, typeName) || isEntry(value)) {
- formatJsonLightInlineProperty(name, value, data);
- return;
- }
-
- if (!typeName && isDeferred(value)) {
- // It is really a deferred property.
- formatJsonLightDeferredProperty(name, value, data);
- return;
- }
-
- if (isCollection(value, typeName)) {
- // The thing is a collection, format it as one.
- if (getCollectionType(typeName)) {
- formatJsonLightAnnotation(typeAnnotation, name, typeName, data);
- }
- formatJsonLightCollectionProperty(name, value, data);
- return;
- }
-
- djsassert(isComplex(value), "formatJsonLightProperty - Value is not a complex type value");
-
- // Format the complex property value in a new object in data[name].
- data[name] = {};
- formatJsonLightAnnotation(typeAnnotation, null, typeName, data[name]);
- formatJsonLightData(value, propertyMetadata.properties, data[name]);
- };
-
- var formatJsonLightEntityLink = function (value, data) {
- /// <summary>Formats an entity link in a $links document and saves it into data.</summary>
- /// <param name="value" type="String">Entity link value.</summary>
- /// <param name="data" type="Object">Object on which the formatted value is going to be stored.</param>
- data.url = value;
- };
-
- var formatJsonLightDeferredProperty = function (name, value, data) {
- /// <summary>Formats the object value's identified by name as an odata.navigalinkurl annotation and saves it to data.</summary>
- /// <param name="name" type="String">Name of the deferred property to be formatted.</param>
- /// <param name="value" type="Object">Deferred property value to be formatted.</param>
- /// <param name="data" type="Object">Object on which the formatted value is going to be stored.</param>
-
- formatJsonLightAnnotation(navUrlAnnotation, name, value.__deferred.uri, data);
- };
-
- var formatJsonLightCollectionProperty = function (name, value, data) {
- /// <summary>Formats a collection property in obj identified by name as a json light collection property and saves it to data.</summary>
- /// <param name="name" type="String">Name of the collection property to be formatted.</param>
- /// <param name="value" type="Object">Collection property value to be formatted.</param>
- /// <param name="data" type="Object">Object on which the formatted value is going to be stored.</param>
-
- data[name] = [];
- var items = isArray(value) ? value : value.results;
- formatJsonLightData(items, null, data[name]);
- };
-
- var formatJsonLightInlineProperty = function (name, value, data) {
- /// <summary>Formats an inline feed or entry property in obj identified by name as a json light value and saves it to data.</summary>
- /// <param name="name" type="String">Name of the inline feed or entry property to be formatted.</param>
- /// <param name="value" type="Object or Array">Value of the inline feed or entry property.</param>
- /// <param name="data" type="Object">Object on which the formatted value is going to be stored.</param>
-
- if (isFeed(value)) {
- data[name] = [];
- // Format each of the inline feed entries
- var entries = isArray(value) ? value : value.results;
- var i, len;
- for (i = 0, len = entries.length; i < len; i++) {
- formatJsonLightInlineEntry(name, entries[i], true, data);
- }
- return;
- }
- formatJsonLightInlineEntry(name, value, false, data);
- };
-
- var formatJsonLightInlineEntry = function (name, value, inFeed, data) {
- /// <summary>Formats an inline entry value in the property identified by name as a json light value and saves it to data.</summary>
- /// <param name="name" type="String">Name of the inline feed or entry property that owns the entry formatted.</param>
- /// <param name="value" type="Object">Inline entry value to be formatted.</param>
- /// <param name="inFeed" type="Boolean">True if the entry is in an inline feed; false otherwise.
- /// <param name="data" type="Object">Object on which the formatted value is going to be stored.</param>
-
- // This might be a bind instead of a deep insert.
- var uri = value.__metadata && value.__metadata.uri;
- if (uri) {
- formatJsonLightBinding(name, uri, inFeed, data);
- return;
- }
-
- var entry = formatJsonLight(value);
- if (inFeed) {
- data[name].push(entry);
- return;
- }
- data[name] = entry;
- };
-
- var formatJsonLightBinding = function (name, uri, inFeed, data) {
- /// <summary>Formats an entry binding in the inline property in obj identified by name as an odata.bind annotation and saves it to data.</summary>
- /// <param name="name" type="String">Name of the inline property that has the binding to be formated.</param>
- /// <param name="uri" type="String">Uri to the bound entry.</param>
- /// <param name="inFeed" type="Boolean">True if the binding is in an inline feed; false otherwise.
- /// <param name="data" type="Object">Object on which the formatted value is going to be stored.</param>
-
- var bindingName = name + bindAnnotation;
- if (inFeed) {
- // The binding is inside an inline feed, so merge it with whatever other bindings already exist in data.
- data[bindingName] = data[bindingName] || [];
- data[bindingName].push(uri);
- return;
- }
- // The binding is on an inline entry; it can be safely overwritten.
- data[bindingName] = uri;
- };
-
- var formatJsonLightAnnotation = function (qName, target, value, data) {
- /// <summary>Formats a value as a json light annotation and stores it in data</summary>
- /// <param name="qName" type="String">Qualified name of the annotation.</param>
- /// <param name="target" type="String">Name of the property that the metadata value targets.</param>
- /// <param name="value">Annotation value.</param>
- /// <param name="data" type="Object">Object on which the annotation is going to be stored.</param>
-
- if (value !== undefined) {
- if(target) {
- data[target + "@" + qName] = value;
- }
- else {
- data[qName] = value;
- }
- }
- };
-
- // DATAJS INTERNAL START
- odata.jsonLightReadPayload = jsonLightReadPayload;
- odata.formatJsonLight = formatJsonLight;
- // DATAJS INTERNAL END
-
- // CONTENT END
-})(this);
-
-
-
[04/15] [OLINGO-238] Build infrastructure for datajs I
Posted by ko...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/odata-json.js
----------------------------------------------------------------------
diff --git a/datajs/src/odata-json.js b/datajs/src/odata-json.js
deleted file mode 100644
index 8f11857..0000000
--- a/datajs/src/odata-json.js
+++ /dev/null
@@ -1,379 +0,0 @@
-// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
-// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// odata-json.js
-
-(function (window, undefined) {
-
- var datajs = window.datajs || {};
- var odata = window.OData || {};
-
- // Imports
-
- var defined = datajs.defined;
- var extend = datajs.extend;
- var isArray = datajs.isArray;
- var isDate = datajs.isDate;
- var normalizeURI = datajs.normalizeURI;
- var parseInt10 = datajs.parseInt10;
-
- var contentType = odata.contentType;
- var jsonLightReadPayload = odata.jsonLightReadPayload;
- var formatDateTimeOffset = odata.formatDateTimeOffset;
- var formatDuration = odata.formatDuration;
- var formatJsonLight = odata.formatJsonLight;
- var formatNumberWidth = odata.formatNumberWidth;
- var getCanonicalTimezone = odata.getCanonicalTimezone;
- var handler = odata.handler;
- var isComplex = odata.isComplex;
- var lookupComplexType = odata.lookupComplexType;
- var lookupEntityType = odata.lookupEntityType;
- var MAX_DATA_SERVICE_VERSION = odata.MAX_DATA_SERVICE_VERSION;
- var maxVersion = odata.maxVersion;
- var parseDateTime = odata.parseDateTime;
- var parseDuration = odata.parseDuration;
- var parseTimezone = odata.parseTimezone;
- var payloadTypeOf = odata.payloadTypeOf;
- var traverse = odata.traverse;
-
- // CONTENT START
-
- var jsonMediaType = "application/json";
- var jsonContentType = contentType(jsonMediaType);
-
- var jsonReadAdvertisedActionsOrFunctions = function (value) {
- /// <summary>Reads and object containing action or function metadata and maps them into a single array of objects.</summary>
- /// <param name="value" type="Object">Object containing action or function metadata.</param>
- /// <returns type="Array">Array of objects containing metadata for the actions or functions specified in value.</returns>
-
- var result = [];
- for (var name in value) {
- var i, len;
- for (i = 0, len = value[name].length; i < len; i++) {
- result.push(extend({ metadata: name }, value[name][i]));
- }
- }
- return result;
- };
-
- var jsonApplyMetadata = function (value, metadata, dateParser, recognizeDates) {
- /// <summary>Applies metadata coming from both the payload and the metadata object to the value.</summary>
- /// <param name="value" type="Object">Data on which the metada is going to be applied.</param>
- /// <param name="metadata">Metadata store; one of edmx, schema, or an array of any of them.</param>
- /// <param name="dateParser" type="function">Function used for parsing datetime values.</param>
- /// <param name="recognizeDates" type="Boolean">
- /// True if strings formatted as datetime values should be treated as datetime values. False otherwise.
- /// </param>
- /// <returns type="Object">Transformed data.</returns>
-
- if (value && typeof value === "object") {
- var dataTypeName;
- var valueMetadata = value.__metadata;
-
- if (valueMetadata) {
- if (valueMetadata.actions) {
- valueMetadata.actions = jsonReadAdvertisedActionsOrFunctions(valueMetadata.actions);
- }
- if (valueMetadata.functions) {
- valueMetadata.functions = jsonReadAdvertisedActionsOrFunctions(valueMetadata.functions);
- }
- dataTypeName = valueMetadata && valueMetadata.type;
- }
-
- var dataType = lookupEntityType(dataTypeName, metadata) || lookupComplexType(dataTypeName, metadata);
- var propertyValue;
- if (dataType) {
- var properties = dataType.property;
- if (properties) {
- var i, len;
- for (i = 0, len = properties.length; i < len; i++) {
- var property = properties[i];
- var propertyName = property.name;
- propertyValue = value[propertyName];
-
- if (property.type === "Edm.DateTime" || property.type === "Edm.DateTimeOffset") {
- if (propertyValue) {
- propertyValue = dateParser(propertyValue);
- if (!propertyValue) {
- throw { message: "Invalid date/time value" };
- }
- value[propertyName] = propertyValue;
- }
- } else if (property.type === "Edm.Time") {
- value[propertyName] = parseDuration(propertyValue);
- }
- }
- }
- } else if (recognizeDates) {
- for (var name in value) {
- propertyValue = value[name];
- if (typeof propertyValue === "string") {
- value[name] = dateParser(propertyValue) || propertyValue;
- }
- }
- }
- }
- return value;
- };
-
- var isJsonLight = function (contentType) {
- /// <summary>Tests where the content type indicates a json light payload.</summary>
- /// <param name="contentType">Object with media type and properties dictionary.</param>
- /// <returns type="Boolean">True is the content type indicates a json light payload. False otherwise.</returns>
-
- if (contentType) {
- var odata = contentType.properties.odata;
- return odata === "nometadata" || odata === "minimalmetadata" || odata === "fullmetadata";
- }
- return false;
- };
-
- var normalizeServiceDocument = function (data, baseURI) {
- /// <summary>Normalizes a JSON service document to look like an ATOM service document.</summary>
- /// <param name="data" type="Object">Object representation of service documents as deserialized.</param>
- /// <param name="baseURI" type="String">Base URI to resolve relative URIs.</param>
- /// <returns type="Object">An object representation of the service document.</returns>
- var workspace = { collections: [] };
-
- var i, len;
- for (i = 0, len = data.EntitySets.length; i < len; i++) {
- var title = data.EntitySets[i];
- var collection = {
- title: title,
- href: normalizeURI(title, baseURI)
- };
-
- workspace.collections.push(collection);
- }
-
- return { workspaces: [workspace] };
- };
-
- // The regular expression corresponds to something like this:
- // /Date(123+60)/
- //
- // This first number is date ticks, the + may be a - and is optional,
- // with the second number indicating a timezone offset in minutes.
- //
- // On the wire, the leading and trailing forward slashes are
- // escaped without being required to so the chance of collisions is reduced;
- // however, by the time we see the objects, the characters already
- // look like regular forward slashes.
- var jsonDateRE = /^\/Date\((-?\d+)(\+|-)?(\d+)?\)\/$/;
-
- var minutesToOffset = function (minutes) {
- /// <summary>Formats the given minutes into (+/-)hh:mm format.</summary>
- /// <param name="minutes" type="Number">Number of minutes to format.</param>
- /// <returns type="String">The minutes in (+/-)hh:mm format.</returns>
-
- var sign;
- if (minutes < 0) {
- sign = "-";
- minutes = -minutes;
- } else {
- sign = "+";
- }
-
- var hours = Math.floor(minutes / 60);
- minutes = minutes - (60 * hours);
-
- return sign + formatNumberWidth(hours, 2) + ":" + formatNumberWidth(minutes, 2);
- };
-
- var parseJsonDateString = function (value) {
- /// <summary>Parses the JSON Date representation into a Date object.</summary>
- /// <param name="value" type="String">String value.</param>
- /// <returns type="Date">A Date object if the value matches one; falsy otherwise.</returns>
-
- var arr = value && jsonDateRE.exec(value);
- if (arr) {
- // 0 - complete results; 1 - ticks; 2 - sign; 3 - minutes
- var result = new Date(parseInt10(arr[1]));
- if (arr[2]) {
- var mins = parseInt10(arr[3]);
- if (arr[2] === "-") {
- mins = -mins;
- }
-
- // The offset is reversed to get back the UTC date, which is
- // what the API will eventually have.
- var current = result.getUTCMinutes();
- result.setUTCMinutes(current - mins);
- result.__edmType = "Edm.DateTimeOffset";
- result.__offset = minutesToOffset(mins);
- }
- if (!isNaN(result.valueOf())) {
- return result;
- }
- }
-
- // Allow undefined to be returned.
- };
-
- // Some JSON implementations cannot produce the character sequence \/
- // which is needed to format DateTime and DateTimeOffset into the
- // JSON string representation defined by the OData protocol.
- // See the history of this file for a candidate implementation of
- // a 'formatJsonDateString' function.
-
- var jsonParser = function (handler, text, context) {
- /// <summary>Parses a JSON OData payload.</summary>
- /// <param name="handler">This handler.</param>
- /// <param name="text">Payload text (this parser also handles pre-parsed objects).</param>
- /// <param name="context" type="Object">Object with parsing context.</param>
- /// <returns>An object representation of the OData payload.</returns>
-
- var recognizeDates = defined(context.recognizeDates, handler.recognizeDates);
- var inferJsonLightFeedAsObject = defined(context.inferJsonLightFeedAsObject, handler.inferJsonLightFeedAsObject);
- var model = context.metadata;
- var dataServiceVersion = context.dataServiceVersion;
- var dateParser = parseJsonDateString;
- var json = (typeof text === "string") ? window.JSON.parse(text) : text;
-
- if ((maxVersion("3.0", dataServiceVersion) === dataServiceVersion)) {
- if (isJsonLight(context.contentType)) {
- return jsonLightReadPayload(json, model, recognizeDates, inferJsonLightFeedAsObject, context.contentType.properties.odata);
- }
- dateParser = parseDateTime;
- }
-
- json = traverse(json.d, function (key, value) {
- return jsonApplyMetadata(value, model, dateParser, recognizeDates);
- });
-
- json = jsonUpdateDataFromVersion(json, context.dataServiceVersion);
- return jsonNormalizeData(json, context.response.requestUri);
- };
-
- var jsonToString = function (data) {
- /// <summary>Converts the data into a JSON string.</summary>
- /// <param name="data">Data to serialize.</param>
- /// <returns type="String">The JSON string representation of data.</returns>
-
- var result; // = undefined;
- // Save the current date.toJSON function
- var dateToJSON = Date.prototype.toJSON;
- try {
- // Set our own date.toJSON function
- Date.prototype.toJSON = function () {
- return formatDateTimeOffset(this);
- };
- result = window.JSON.stringify(data, jsonReplacer);
- } finally {
- // Restore the original toJSON function
- Date.prototype.toJSON = dateToJSON;
- }
- return result;
- };
-
- var jsonSerializer = function (handler, data, context) {
- /// <summary>Serializes the data by returning its string representation.</summary>
- /// <param name="handler">This handler.</param>
- /// <param name="data">Data to serialize.</param>
- /// <param name="context" type="Object">Object with serialization context.</param>
- /// <returns type="String">The string representation of data.</returns>
-
- var dataServiceVersion = context.dataServiceVersion || "1.0";
- var useJsonLight = defined(context.useJsonLight, handler.useJsonLight);
- var cType = context.contentType = context.contentType || jsonContentType;
-
- if (cType && cType.mediaType === jsonContentType.mediaType) {
- var json = data;
- if (useJsonLight || isJsonLight(cType)) {
- context.dataServiceVersion = maxVersion(dataServiceVersion, "3.0");
- json = formatJsonLight(data, context);
- return jsonToString(json);
- }
- if (maxVersion("3.0", dataServiceVersion) === dataServiceVersion) {
- cType.properties.odata = "verbose";
- context.contentType = cType;
- }
- return jsonToString(json);
- }
- return undefined;
- };
-
- var jsonReplacer = function (_, value) {
- /// <summary>JSON replacer function for converting a value to its JSON representation.</summary>
- /// <param value type="Object">Value to convert.</param>
- /// <returns type="String">JSON representation of the input value.</returns>
- /// <remarks>
- /// This method is used during JSON serialization and invoked only by the JSON.stringify function.
- /// It should never be called directly.
- /// </remarks>
-
- if (value && value.__edmType === "Edm.Time") {
- return formatDuration(value);
- } else {
- return value;
- }
- };
-
- var jsonNormalizeData = function (data, baseURI) {
- /// <summary>
- /// Normalizes the specified data into an intermediate representation.
- /// like the latest supported version.
- /// </summary>
- /// <param name="data" optional="false">Data to update.</param>
- /// <param name="baseURI" optional="false">URI to use as the base for normalizing references.</param>
-
- var isSvcDoc = isComplex(data) && !data.__metadata && isArray(data.EntitySets);
- return isSvcDoc ? normalizeServiceDocument(data, baseURI) : data;
- };
-
- var jsonUpdateDataFromVersion = function (data, dataVersion) {
- /// <summary>
- /// Updates the specified data in the specified version to look
- /// like the latest supported version.
- /// </summary>
- /// <param name="data" optional="false">Data to update.</param>
- /// <param name="dataVersion" optional="true" type="String">Version the data is in (possibly unknown).</param>
-
- // Strip the trailing comma if there.
- if (dataVersion && dataVersion.lastIndexOf(";") === dataVersion.length - 1) {
- dataVersion = dataVersion.substr(0, dataVersion.length - 1);
- }
-
- if (!dataVersion || dataVersion === "1.0") {
- if (isArray(data)) {
- data = { results: data };
- }
- }
-
- return data;
- };
-
- var jsonHandler = handler(jsonParser, jsonSerializer, jsonMediaType, MAX_DATA_SERVICE_VERSION);
- jsonHandler.recognizeDates = false;
- jsonHandler.useJsonLight = false;
- jsonHandler.inferJsonLightFeedAsObject = false;
-
- odata.jsonHandler = jsonHandler;
-
-
-
- // DATAJS INTERNAL START
- odata.jsonParser = jsonParser;
- odata.jsonSerializer = jsonSerializer;
- odata.jsonNormalizeData = jsonNormalizeData;
- odata.jsonUpdateDataFromVersion = jsonUpdateDataFromVersion;
- odata.normalizeServiceDocument = normalizeServiceDocument;
- odata.parseJsonDateString = parseJsonDateString;
- // DATAJS INTERNAL END
-
- // CONTENT END
-})(this);
-
-
-
-
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/odata-metadata.js
----------------------------------------------------------------------
diff --git a/datajs/src/odata-metadata.js b/datajs/src/odata-metadata.js
deleted file mode 100644
index a7ca00a..0000000
--- a/datajs/src/odata-metadata.js
+++ /dev/null
@@ -1,500 +0,0 @@
-// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
-// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// odata-metadata.js
-
-(function (window, undefined) {
-
- var datajs = window.datajs || {};
- var odata = window.OData || {};
-
- // imports
-
- var contains = datajs.contains;
- var normalizeURI = datajs.normalizeURI;
- var xmlAttributes = datajs.xmlAttributes;
- var xmlChildElements = datajs.xmlChildElements;
- var xmlFirstChildElement = datajs.xmlFirstChildElement;
- var xmlInnerText = datajs.xmlInnerText;
- var xmlLocalName = datajs.xmlLocalName;
- var xmlNamespaceURI = datajs.xmlNamespaceURI;
- var xmlNS = datajs.xmlNS;
- var xmlnsNS = datajs.xmlnsNS;
- var xmlParse = datajs.xmlParse;
-
- var createAttributeExtension = odata.createAttributeExtension;
- var createElementExtension = odata.createElementExtension;
- var edmxNs = odata.edmxNs;
- var edmNs1 = odata.edmNs1;
- var edmNs1_1 = odata.edmNs1_1;
- var edmNs1_2 = odata.edmNs1_2;
- var edmNs2a = odata.edmNs2a;
- var edmNs2b = odata.edmNs2b;
- var edmNs3 = odata.edmNs3;
- var handler = odata.handler;
- var MAX_DATA_SERVICE_VERSION = odata.MAX_DATA_SERVICE_VERSION;
- var odataMetaXmlNs = odata.odataMetaXmlNs;
-
-
- var xmlMediaType = "application/xml";
-
- // CONTENT START
-
- var schemaElement = function (attributes, elements, text, ns) {
- /// <summary>Creates an object that describes an element in an schema.</summary>
- /// <param name="attributes" type="Array">List containing the names of the attributes allowed for this element.</param>
- /// <param name="elements" type="Array">List containing the names of the child elements allowed for this element.</param>
- /// <param name="text" type="Boolean">Flag indicating if the element's text value is of interest or not.</param>
- /// <param name="ns" type="String">Namespace to which the element belongs to.</param>
- /// <remarks>
- /// If a child element name ends with * then it is understood by the schema that that child element can appear 0 or more times.
- /// </remarks>
- /// <returns type="Object">Object with attributes, elements, text, and ns fields.</returns>
-
- return {
- attributes: attributes,
- elements: elements,
- text: text || false,
- ns: ns
- };
- };
-
- // It's assumed that all elements may have Documentation children and Annotation elements.
- // See http://msdn.microsoft.com/en-us/library/bb399292.aspx for a CSDL reference.
- var schema = {
- elements: {
- Annotations: schemaElement(
- /*attributes*/["Target", "Qualifier"],
- /*elements*/["TypeAnnotation*", "ValueAnnotation*"]
- ),
- Association: schemaElement(
- /*attributes*/["Name"],
- /*elements*/["End*", "ReferentialConstraint", "TypeAnnotation*", "ValueAnnotation*"]
- ),
- AssociationSet: schemaElement(
- /*attributes*/["Name", "Association"],
- /*elements*/["End*", "TypeAnnotation*", "ValueAnnotation*"]
- ),
- Binary: schemaElement(
- /*attributes*/null,
- /*elements*/null,
- /*text*/true
- ),
- Bool: schemaElement(
- /*attributes*/null,
- /*elements*/null,
- /*text*/true
- ),
- Collection: schemaElement(
- /*attributes*/null,
- /*elements*/["String*", "Int*", "Float*", "Decimal*", "Bool*", "DateTime*", "DateTimeOffset*", "Guid*", "Binary*", "Time*", "Collection*", "Record*"]
- ),
- CollectionType: schemaElement(
- /*attributes*/["ElementType", "Nullable", "DefaultValue", "MaxLength", "FixedLength", "Precision", "Scale", "Unicode", "Collation", "SRID"],
- /*elements*/["CollectionType", "ReferenceType", "RowType", "TypeRef"]
- ),
- ComplexType: schemaElement(
- /*attributes*/["Name", "BaseType", "Abstract"],
- /*elements*/["Property*", "TypeAnnotation*", "ValueAnnotation*"]
- ),
- DateTime: schemaElement(
- /*attributes*/null,
- /*elements*/null,
- /*text*/true
- ),
- DateTimeOffset: schemaElement(
- /*attributes*/null,
- /*elements*/null,
- /*text*/true
- ),
- Decimal: schemaElement(
- /*attributes*/null,
- /*elements*/null,
- /*text*/true
- ),
- DefiningExpression: schemaElement(
- /*attributes*/null,
- /*elements*/null,
- /*text*/true
- ),
- Dependent: schemaElement(
- /*attributes*/["Role"],
- /*elements*/["PropertyRef*"]
- ),
- Documentation: schemaElement(
- /*attributes*/null,
- /*elements*/null,
- /*text*/true
- ),
- End: schemaElement(
- /*attributes*/["Type", "Role", "Multiplicity", "EntitySet"],
- /*elements*/["OnDelete"]
- ),
- EntityContainer: schemaElement(
- /*attributes*/["Name", "Extends"],
- /*elements*/["EntitySet*", "AssociationSet*", "FunctionImport*", "TypeAnnotation*", "ValueAnnotation*"]
- ),
- EntitySet: schemaElement(
- /*attributes*/["Name", "EntityType"],
- /*elements*/["TypeAnnotation*", "ValueAnnotation*"]
- ),
- EntityType: schemaElement(
- /*attributes*/["Name", "BaseType", "Abstract", "OpenType"],
- /*elements*/["Key", "Property*", "NavigationProperty*", "TypeAnnotation*", "ValueAnnotation*"]
- ),
- EnumType: schemaElement(
- /*attributes*/["Name", "UnderlyingType", "IsFlags"],
- /*elements*/["Member*"]
- ),
- Float: schemaElement(
- /*attributes*/null,
- /*elements*/null,
- /*text*/true
- ),
- Function: schemaElement(
- /*attributes*/["Name", "ReturnType"],
- /*elements*/["Parameter*", "DefiningExpression", "ReturnType", "TypeAnnotation*", "ValueAnnotation*"]
- ),
- FunctionImport: schemaElement(
- /*attributes*/["Name", "ReturnType", "EntitySet", "IsSideEffecting", "IsComposable", "IsBindable", "EntitySetPath"],
- /*elements*/["Parameter*", "ReturnType", "TypeAnnotation*", "ValueAnnotation*"]
- ),
- Guid: schemaElement(
- /*attributes*/null,
- /*elements*/null,
- /*text*/true
- ),
- Int: schemaElement(
- /*attributes*/null,
- /*elements*/null,
- /*text*/true
- ),
- Key: schemaElement(
- /*attributes*/null,
- /*elements*/["PropertyRef*"]
- ),
- LabeledElement: schemaElement(
- /*attributes*/["Name"],
- /*elements*/["Path", "String", "Int", "Float", "Decimal", "Bool", "DateTime", "DateTimeOffset", "Guid", "Binary", "Time", "Collection", "Record", "LabeledElement", "Null"]
- ),
- Member: schemaElement(
- /*attributes*/["Name", "Value"]
- ),
- NavigationProperty: schemaElement(
- /*attributes*/["Name", "Relationship", "ToRole", "FromRole", "ContainsTarget"],
- /*elements*/["TypeAnnotation*", "ValueAnnotation*"]
- ),
- Null: schemaElement(
- /*attributes*/null,
- /*elements*/null
- ),
- OnDelete: schemaElement(
- /*attributes*/["Action"]
- ),
- Path: schemaElement(
- /*attributes*/null,
- /*elements*/null,
- /*text*/true
- ),
- Parameter: schemaElement(
- /*attributes*/["Name", "Type", "Mode", "Nullable", "DefaultValue", "MaxLength", "FixedLength", "Precision", "Scale", "Unicode", "Collation", "ConcurrencyMode", "SRID"],
- /*elements*/["CollectionType", "ReferenceType", "RowType", "TypeRef", "TypeAnnotation*", "ValueAnnotation*"]
- ),
- Principal: schemaElement(
- /*attributes*/["Role"],
- /*elements*/["PropertyRef*"]
- ),
- Property: schemaElement(
- /*attributes*/["Name", "Type", "Nullable", "DefaultValue", "MaxLength", "FixedLength", "Precision", "Scale", "Unicode", "Collation", "ConcurrencyMode", "CollectionKind", "SRID"],
- /*elements*/["CollectionType", "ReferenceType", "RowType", "TypeAnnotation*", "ValueAnnotation*"]
- ),
- PropertyRef: schemaElement(
- /*attributes*/["Name"]
- ),
- PropertyValue: schemaElement(
- /*attributes*/["Property", "Path", "String", "Int", "Float", "Decimal", "Bool", "DateTime", "DateTimeOffset", "Guid", "Binary", "Time"],
- /*Elements*/["Path", "String", "Int", "Float", "Decimal", "Bool", "DateTime", "DateTimeOffset", "Guid", "Binary", "Time", "Collection", "Record", "LabeledElement", "Null"]
- ),
- ReferenceType: schemaElement(
- /*attributes*/["Type"]
- ),
- ReferentialConstraint: schemaElement(
- /*attributes*/null,
- /*elements*/["Principal", "Dependent"]
- ),
- ReturnType: schemaElement(
- /*attributes*/["ReturnType", "Type", "EntitySet"],
- /*elements*/["CollectionType", "ReferenceType", "RowType"]
- ),
- RowType: schemaElement(
- /*elements*/["Property*"]
- ),
- String: schemaElement(
- /*attributes*/null,
- /*elements*/null,
- /*text*/true
- ),
- Schema: schemaElement(
- /*attributes*/["Namespace", "Alias"],
- /*elements*/["Using*", "EntityContainer*", "EntityType*", "Association*", "ComplexType*", "Function*", "ValueTerm*", "Annotations*"]
- ),
- Time: schemaElement(
- /*attributes*/null,
- /*elements*/null,
- /*text*/true
- ),
- TypeAnnotation: schemaElement(
- /*attributes*/["Term", "Qualifier"],
- /*elements*/["PropertyValue*"]
- ),
- TypeRef: schemaElement(
- /*attributes*/["Type", "Nullable", "DefaultValue", "MaxLength", "FixedLength", "Precision", "Scale", "Unicode", "Collation", "SRID"]
- ),
- Using: schemaElement(
- /*attributes*/["Namespace", "Alias"]
- ),
- ValueAnnotation: schemaElement(
- /*attributes*/["Term", "Qualifier", "Path", "String", "Int", "Float", "Decimal", "Bool", "DateTime", "DateTimeOffset", "Guid", "Binary", "Time"],
- /*Elements*/["Path", "String", "Int", "Float", "Decimal", "Bool", "DateTime", "DateTimeOffset", "Guid", "Binary", "Time", "Collection", "Record", "LabeledElement", "Null"]
- ),
- ValueTerm: schemaElement(
- /*attributes*/["Name", "Type"],
- /*elements*/["TypeAnnotation*", "ValueAnnotation*"]
- ),
-
- // See http://msdn.microsoft.com/en-us/library/dd541238(v=prot.10) for an EDMX reference.
- Edmx: schemaElement(
- /*attributes*/["Version"],
- /*elements*/["DataServices", "Reference*", "AnnotationsReference*"],
- /*text*/false,
- /*ns*/edmxNs
- ),
- DataServices: schemaElement(
- /*attributes*/null,
- /*elements*/["Schema*"],
- /*text*/false,
- /*ns*/edmxNs
- )
- }
- };
-
- // See http://msdn.microsoft.com/en-us/library/ee373839.aspx for a feed customization reference.
- var customizationAttributes = ["m:FC_ContentKind", "m:FC_KeepInContent", "m:FC_NsPrefix", "m:FC_NsUri", "m:FC_SourcePath", "m:FC_TargetPath"];
- schema.elements.Property.attributes = schema.elements.Property.attributes.concat(customizationAttributes);
- schema.elements.EntityType.attributes = schema.elements.EntityType.attributes.concat(customizationAttributes);
-
- // See http://msdn.microsoft.com/en-us/library/dd541284(PROT.10).aspx for an EDMX reference.
- schema.elements.Edmx = { attributes: ["Version"], elements: ["DataServices"], ns: edmxNs };
- schema.elements.DataServices = { elements: ["Schema*"], ns: edmxNs };
-
- // See http://msdn.microsoft.com/en-us/library/dd541233(v=PROT.10) for Conceptual Schema Definition Language Document for Data Services.
- schema.elements.EntityContainer.attributes.push("m:IsDefaultEntityContainer");
- schema.elements.Property.attributes.push("m:MimeType");
- schema.elements.FunctionImport.attributes.push("m:HttpMethod");
- schema.elements.FunctionImport.attributes.push("m:IsAlwaysBindable");
- schema.elements.EntityType.attributes.push("m:HasStream");
- schema.elements.DataServices.attributes = ["m:DataServiceVersion", "m:MaxDataServiceVersion"];
-
- var scriptCase = function (text) {
- /// <summary>Converts a Pascal-case identifier into a camel-case identifier.</summary>
- /// <param name="text" type="String">Text to convert.</param>
- /// <returns type="String">Converted text.</returns>
- /// <remarks>If the text starts with multiple uppercase characters, it is left as-is.</remarks>
-
- if (!text) {
- return text;
- }
-
- if (text.length > 1) {
- var firstTwo = text.substr(0, 2);
- if (firstTwo === firstTwo.toUpperCase()) {
- return text;
- }
-
- return text.charAt(0).toLowerCase() + text.substr(1);
- }
-
- return text.charAt(0).toLowerCase();
- };
-
- var getChildSchema = function (parentSchema, candidateName) {
- /// <summary>Gets the schema node for the specified element.</summary>
- /// <param name="parentSchema" type="Object">Schema of the parent XML node of 'element'.</param>
- /// <param name="candidateName">XML element name to consider.</param>
- /// <returns type="Object">The schema that describes the specified element; null if not found.</returns>
-
- if (candidateName === "Documentation") {
- return { isArray: true, propertyName: "documentation" };
- }
-
- var elements = parentSchema.elements;
- if (!elements) {
- return null;
- }
-
- var i, len;
- for (i = 0, len = elements.length; i < len; i++) {
- var elementName = elements[i];
- var multipleElements = false;
- if (elementName.charAt(elementName.length - 1) === "*") {
- multipleElements = true;
- elementName = elementName.substr(0, elementName.length - 1);
- }
-
- if (candidateName === elementName) {
- var propertyName = scriptCase(elementName);
- return { isArray: multipleElements, propertyName: propertyName };
- }
- }
-
- return null;
- };
-
- // This regular expression is used to detect a feed customization element
- // after we've normalized it into the 'm' prefix. It starts with m:FC_,
- // followed by other characters, and ends with _ and a number.
- // The captures are 0 - whole string, 1 - name as it appears in internal table.
- var isFeedCustomizationNameRE = /^(m:FC_.*)_[0-9]+$/;
-
- var isEdmNamespace = function (nsURI) {
- /// <summary>Checks whether the specifies namespace URI is one of the known CSDL namespace URIs.</summary>
- /// <param name="nsURI" type="String">Namespace URI to check.</param>
- /// <returns type="Boolean">true if nsURI is a known CSDL namespace; false otherwise.</returns>
-
- return nsURI === edmNs1 ||
- nsURI === edmNs1_1 ||
- nsURI === edmNs1_2 ||
- nsURI === edmNs2a ||
- nsURI === edmNs2b ||
- nsURI === edmNs3;
- };
-
- var parseConceptualModelElement = function (element) {
- /// <summary>Parses a CSDL document.</summary>
- /// <param name="element">DOM element to parse.</param>
- /// <returns type="Object">An object describing the parsed element.</returns>
-
- var localName = xmlLocalName(element);
- var nsURI = xmlNamespaceURI(element);
- var elementSchema = schema.elements[localName];
- if (!elementSchema) {
- return null;
- }
-
- if (elementSchema.ns) {
- if (nsURI !== elementSchema.ns) {
- return null;
- }
- } else if (!isEdmNamespace(nsURI)) {
- return null;
- }
-
- var item = {};
- var extensions = [];
- var attributes = elementSchema.attributes || [];
- xmlAttributes(element, function (attribute) {
-
- var localName = xmlLocalName(attribute);
- var nsURI = xmlNamespaceURI(attribute);
- var value = attribute.value;
-
- // Don't do anything with xmlns attributes.
- if (nsURI === xmlnsNS) {
- return;
- }
-
- // Currently, only m: for metadata is supported as a prefix in the internal schema table,
- // un-prefixed element names imply one a CSDL element.
- var schemaName = null;
- var handled = false;
- if (isEdmNamespace(nsURI) || nsURI === null) {
- schemaName = "";
- } else if (nsURI === odataMetaXmlNs) {
- schemaName = "m:";
- }
-
- if (schemaName !== null) {
- schemaName += localName;
-
- // Feed customizations for complex types have additional
- // attributes with a suffixed counter starting at '1', so
- // take that into account when doing the lookup.
- var match = isFeedCustomizationNameRE.exec(schemaName);
- if (match) {
- schemaName = match[1];
- }
-
- if (contains(attributes, schemaName)) {
- handled = true;
- item[scriptCase(localName)] = value;
- }
- }
-
- if (!handled) {
- extensions.push(createAttributeExtension(attribute));
- }
- });
-
- xmlChildElements(element, function (child) {
- var localName = xmlLocalName(child);
- var childSchema = getChildSchema(elementSchema, localName);
- if (childSchema) {
- if (childSchema.isArray) {
- var arr = item[childSchema.propertyName];
- if (!arr) {
- arr = [];
- item[childSchema.propertyName] = arr;
- }
- arr.push(parseConceptualModelElement(child));
- } else {
- item[childSchema.propertyName] = parseConceptualModelElement(child);
- }
- } else {
- extensions.push(createElementExtension(child));
- }
- });
-
- if (elementSchema.text) {
- item.text = xmlInnerText(element);
- }
-
- if (extensions.length) {
- item.extensions = extensions;
- }
-
- return item;
- };
-
- var metadataParser = function (handler, text) {
- /// <summary>Parses a metadata document.</summary>
- /// <param name="handler">This handler.</param>
- /// <param name="text" type="String">Metadata text.</param>
- /// <returns>An object representation of the conceptual model.</returns>
-
- var doc = xmlParse(text);
- var root = xmlFirstChildElement(doc);
- return parseConceptualModelElement(root) || undefined;
- };
-
- odata.metadataHandler = handler(metadataParser, null, xmlMediaType, MAX_DATA_SERVICE_VERSION);
-
- // DATAJS INTERNAL START
- odata.schema = schema;
- odata.scriptCase = scriptCase;
- odata.getChildSchema = getChildSchema;
- odata.parseConceptualModelElement = parseConceptualModelElement;
- odata.metadataParser = metadataParser;
- // DATAJS INTERNAL END
-
- // CONTENT END
-})(this);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/odata-net.js
----------------------------------------------------------------------
diff --git a/datajs/src/odata-net.js b/datajs/src/odata-net.js
deleted file mode 100644
index ad9b8dd..0000000
--- a/datajs/src/odata-net.js
+++ /dev/null
@@ -1,330 +0,0 @@
-// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
-// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// odata-net.js
-
-(function (window, undefined) {
-
- var datajs = window.datajs || {};
- var odata = window.OData || {};
-
- // Imports.
-
- var defined = datajs.defined;
- var delay = datajs.delay;
-
- // CONTENT START
- var ticks = 0;
-
- var canUseJSONP = function (request) {
- /// <summary>
- /// Checks whether the specified request can be satisfied with a JSONP request.
- /// </summary>
- /// <param name="request">Request object to check.</param>
- /// <returns type="Boolean">true if the request can be satisfied; false otherwise.</returns>
-
- // Requests that 'degrade' without changing their meaning by going through JSONP
- // are considered usable.
- //
- // We allow data to come in a different format, as the servers SHOULD honor the Accept
- // request but may in practice return content with a different MIME type.
- if (request.method && request.method !== "GET") {
- return false;
- }
-
- return true;
- };
-
- var createIFrame = function (url) {
- /// <summary>Creates an IFRAME tag for loading the JSONP script</summary>
- /// <param name="url" type="String">The source URL of the script</param>
- /// <returns type="HTMLElement">The IFRAME tag</returns>
- var iframe = window.document.createElement("IFRAME");
- iframe.style.display = "none";
-
- var attributeEncodedUrl = url.replace(/&/g, "&").replace(/"/g, """).replace(/\</g, "<");
- var html = "<html><head><script type=\"text/javascript\" src=\"" + attributeEncodedUrl + "\"><\/script><\/head><body><\/body><\/html>";
-
- var body = window.document.getElementsByTagName("BODY")[0];
- body.appendChild(iframe);
-
- writeHtmlToIFrame(iframe, html);
- return iframe;
- };
-
- var createXmlHttpRequest = function () {
- /// <summary>Creates a XmlHttpRequest object.</summary>
- /// <returns type="XmlHttpRequest">XmlHttpRequest object.</returns>
- if (window.XMLHttpRequest) {
- return new window.XMLHttpRequest();
- }
- var exception;
- if (window.ActiveXObject) {
- try {
- return new window.ActiveXObject("Msxml2.XMLHTTP.6.0");
- } catch (_) {
- try {
- return new window.ActiveXObject("Msxml2.XMLHTTP.3.0");
- } catch (e) {
- exception = e;
- }
- }
- } else {
- exception = { message: "XMLHttpRequest not supported" };
- }
- throw exception;
- };
-
- var isAbsoluteUrl = function (url) {
- /// <summary>Checks whether the specified URL is an absolute URL.</summary>
- /// <param name="url" type="String">URL to check.</param>
- /// <returns type="Boolean">true if the url is an absolute URL; false otherwise.</returns>
-
- return url.indexOf("http://") === 0 ||
- url.indexOf("https://") === 0 ||
- url.indexOf("file://") === 0;
- };
-
- var isLocalUrl = function (url) {
- /// <summary>Checks whether the specified URL is local to the current context.</summary>
- /// <param name="url" type="String">URL to check.</param>
- /// <returns type="Boolean">true if the url is a local URL; false otherwise.</returns>
-
- if (!isAbsoluteUrl(url)) {
- return true;
- }
-
- // URL-embedded username and password will not be recognized as same-origin URLs.
- var location = window.location;
- var locationDomain = location.protocol + "//" + location.host + "/";
- return (url.indexOf(locationDomain) === 0);
- };
-
- var removeCallback = function (name, tick) {
- /// <summary>Removes a callback used for a JSONP request.</summary>
- /// <param name="name" type="String">Function name to remove.</param>
- /// <param name="tick" type="Number">Tick count used on the callback.</param>
- try {
- delete window[name];
- } catch (err) {
- window[name] = undefined;
- if (tick === ticks - 1) {
- ticks -= 1;
- }
- }
- };
-
- var removeIFrame = function (iframe) {
- /// <summary>Removes an iframe.</summary>
- /// <param name="iframe" type="Object">The iframe to remove.</param>
- /// <returns type="Object">Null value to be assigned to iframe reference.</returns>
- if (iframe) {
- writeHtmlToIFrame(iframe, "");
- iframe.parentNode.removeChild(iframe);
- }
-
- return null;
- };
-
- var readResponseHeaders = function (xhr, headers) {
- /// <summary>Reads response headers into array.</summary>
- /// <param name="xhr" type="XMLHttpRequest">HTTP request with response available.</param>
- /// <param name="headers" type="Array">Target array to fill with name/value pairs.</param>
-
- var responseHeaders = xhr.getAllResponseHeaders().split(/\r?\n/);
- var i, len;
- for (i = 0, len = responseHeaders.length; i < len; i++) {
- if (responseHeaders[i]) {
- var header = responseHeaders[i].split(": ");
- headers[header[0]] = header[1];
- }
- }
- };
-
- var writeHtmlToIFrame = function (iframe, html) {
- /// <summary>Writes HTML to an IFRAME document.</summary>
- /// <param name="iframe" type="HTMLElement">The IFRAME element to write to.</param>
- /// <param name="html" type="String">The HTML to write.</param>
- var frameDocument = (iframe.contentWindow) ? iframe.contentWindow.document : iframe.contentDocument.document;
- frameDocument.open();
- frameDocument.write(html);
- frameDocument.close();
- };
-
- odata.defaultHttpClient = {
- callbackParameterName: "$callback",
-
- formatQueryString: "$format=json",
-
- enableJsonpCallback: false,
-
- request: function (request, success, error) {
- /// <summary>Performs a network request.</summary>
- /// <param name="request" type="Object">Request description.</request>
- /// <param name="success" type="Function">Success callback with the response object.</param>
- /// <param name="error" type="Function">Error callback with an error object.</param>
- /// <returns type="Object">Object with an 'abort' method for the operation.</returns>
-
- var result = {};
- var xhr = null;
- var done = false;
- var iframe;
-
- result.abort = function () {
- iframe = removeIFrame(iframe);
- if (done) {
- return;
- }
-
- done = true;
- if (xhr) {
- xhr.abort();
- xhr = null;
- }
-
- error({ message: "Request aborted" });
- };
-
- var handleTimeout = function () {
- iframe = removeIFrame(iframe);
- if (!done) {
- done = true;
- xhr = null;
- error({ message: "Request timed out" });
- }
- };
-
- var name;
- var url = request.requestUri;
- var enableJsonpCallback = defined(request.enableJsonpCallback, this.enableJsonpCallback);
- var callbackParameterName = defined(request.callbackParameterName, this.callbackParameterName);
- var formatQueryString = defined(request.formatQueryString, this.formatQueryString);
- if (!enableJsonpCallback || isLocalUrl(url)) {
-
- xhr = createXmlHttpRequest();
- xhr.onreadystatechange = function () {
- if (done || xhr === null || xhr.readyState !== 4) {
- return;
- }
-
- // Workaround for XHR behavior on IE.
- var statusText = xhr.statusText;
- var statusCode = xhr.status;
- if (statusCode === 1223) {
- statusCode = 204;
- statusText = "No Content";
- }
-
- var headers = [];
- readResponseHeaders(xhr, headers);
-
- var response = { requestUri: url, statusCode: statusCode, statusText: statusText, headers: headers, body: xhr.responseText };
-
- done = true;
- xhr = null;
- if (statusCode >= 200 && statusCode <= 299) {
- success(response);
- } else {
- error({ message: "HTTP request failed", request: request, response: response });
- }
- };
-
- xhr.open(request.method || "GET", url, true, request.user, request.password);
-
- // Set the name/value pairs.
- if (request.headers) {
- for (name in request.headers) {
- xhr.setRequestHeader(name, request.headers[name]);
- }
- }
-
- // Set the timeout if available.
- if (request.timeoutMS) {
- xhr.timeout = request.timeoutMS;
- xhr.ontimeout = handleTimeout;
- }
-
- xhr.send(request.body);
- } else {
- if (!canUseJSONP(request)) {
- throw { message: "Request is not local and cannot be done through JSONP." };
- }
-
- var tick = ticks;
- ticks += 1;
- var tickText = tick.toString();
- var succeeded = false;
- var timeoutId;
- name = "handleJSONP_" + tickText;
- window[name] = function (data) {
- iframe = removeIFrame(iframe);
- if (!done) {
- succeeded = true;
- window.clearTimeout(timeoutId);
- removeCallback(name, tick);
-
- // Workaround for IE8 and IE10 below where trying to access data.constructor after the IFRAME has been removed
- // throws an "unknown exception"
- if (window.ActiveXObject) {
- data = window.JSON.parse(window.JSON.stringify(data));
- }
-
-
- var headers;
- // Adding dataServiceVersion in case of json light ( data.d doesn't exist )
- if (data.d === undefined) {
- headers = { "Content-Type": "application/json;odata=minimalmetadata", dataServiceVersion: "3.0" };
- } else {
- headers = { "Content-Type": "application/json" };
- }
- // Call the success callback in the context of the parent window, instead of the IFRAME
- delay(function () {
- removeIFrame(iframe);
- success({ body: data, statusCode: 200, headers: headers });
- });
- }
- };
-
- // Default to two minutes before timing out, 1000 ms * 60 * 2 = 120000.
- var timeoutMS = (request.timeoutMS) ? request.timeoutMS : 120000;
- timeoutId = window.setTimeout(handleTimeout, timeoutMS);
-
- var queryStringParams = callbackParameterName + "=parent." + name;
- if (this.formatQueryString) {
- queryStringParams += "&" + formatQueryString;
- }
-
- var qIndex = url.indexOf("?");
- if (qIndex === -1) {
- url = url + "?" + queryStringParams;
- } else if (qIndex === url.length - 1) {
- url = url + queryStringParams;
- } else {
- url = url + "&" + queryStringParams;
- }
-
- iframe = createIFrame(url);
- }
-
- return result;
- }
- };
-
- // DATAJS INTERNAL START
- odata.canUseJSONP = canUseJSONP;
- odata.isAbsoluteUrl = isAbsoluteUrl;
- odata.isLocalUrl = isLocalUrl;
- // DATAJS INTERNAL END
-
- // CONTENT END
-})(this);
\ No newline at end of file
[03/15] [OLINGO-238] Build infrastructure for datajs I
Posted by ko...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/odata-utils.js
----------------------------------------------------------------------
diff --git a/datajs/src/odata-utils.js b/datajs/src/odata-utils.js
deleted file mode 100644
index ad2cf00..0000000
--- a/datajs/src/odata-utils.js
+++ /dev/null
@@ -1,1117 +0,0 @@
-// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
-// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// odata-utils.js
-
-(function (window, undefined) {
-
- var datajs = window.datajs || {};
- var odata = window.OData || {};
-
- // Imports
- var assigned = datajs.assigned;
- var contains = datajs.contains;
- var find = datajs.find;
- var isArray = datajs.isArray;
- var isDate = datajs.isDate;
- var isObject = datajs.isObject;
- var parseInt10 = datajs.parseInt10;
-
- // CONTENT START
-
- var dataItemTypeName = function (value, metadata) {
- /// <summary>Gets the type name of a data item value that belongs to a feed, an entry, a complex type property, or a collection property.</summary>
- /// <param name="value">Value of the data item from which the type name is going to be retrieved.</param>
- /// <param name="metadata" type="object" optional="true">Object containing metadata about the data tiem.</param>
- /// <remarks>
- /// This function will first try to get the type name from the data item's value itself if it is an object with a __metadata property; otherwise
- /// it will try to recover it from the metadata. If both attempts fail, it will return null.
- /// </remarks>
- /// <returns type="String">Data item type name; null if the type name cannot be found within the value or the metadata</returns>
-
- var valueTypeName = ((value && value.__metadata) || {}).type;
- return valueTypeName || (metadata ? metadata.type : null);
- };
-
- var EDM = "Edm.";
- var EDM_BINARY = EDM + "Binary";
- var EDM_BOOLEAN = EDM + "Boolean";
- var EDM_BYTE = EDM + "Byte";
- var EDM_DATETIME = EDM + "DateTime";
- var EDM_DATETIMEOFFSET = EDM + "DateTimeOffset";
- var EDM_DECIMAL = EDM + "Decimal";
- var EDM_DOUBLE = EDM + "Double";
- var EDM_GUID = EDM + "Guid";
- var EDM_INT16 = EDM + "Int16";
- var EDM_INT32 = EDM + "Int32";
- var EDM_INT64 = EDM + "Int64";
- var EDM_SBYTE = EDM + "SByte";
- var EDM_SINGLE = EDM + "Single";
- var EDM_STRING = EDM + "String";
- var EDM_TIME = EDM + "Time";
-
- var EDM_GEOGRAPHY = EDM + "Geography";
- var EDM_GEOGRAPHY_POINT = EDM_GEOGRAPHY + "Point";
- var EDM_GEOGRAPHY_LINESTRING = EDM_GEOGRAPHY + "LineString";
- var EDM_GEOGRAPHY_POLYGON = EDM_GEOGRAPHY + "Polygon";
- var EDM_GEOGRAPHY_COLLECTION = EDM_GEOGRAPHY + "Collection";
- var EDM_GEOGRAPHY_MULTIPOLYGON = EDM_GEOGRAPHY + "MultiPolygon";
- var EDM_GEOGRAPHY_MULTILINESTRING = EDM_GEOGRAPHY + "MultiLineString";
- var EDM_GEOGRAPHY_MULTIPOINT = EDM_GEOGRAPHY + "MultiPoint";
-
- var EDM_GEOMETRY = EDM + "Geometry";
- var EDM_GEOMETRY_POINT = EDM_GEOMETRY + "Point";
- var EDM_GEOMETRY_LINESTRING = EDM_GEOMETRY + "LineString";
- var EDM_GEOMETRY_POLYGON = EDM_GEOMETRY + "Polygon";
- var EDM_GEOMETRY_COLLECTION = EDM_GEOMETRY + "Collection";
- var EDM_GEOMETRY_MULTIPOLYGON = EDM_GEOMETRY + "MultiPolygon";
- var EDM_GEOMETRY_MULTILINESTRING = EDM_GEOMETRY + "MultiLineString";
- var EDM_GEOMETRY_MULTIPOINT = EDM_GEOMETRY + "MultiPoint";
-
- var GEOJSON_POINT = "Point";
- var GEOJSON_LINESTRING = "LineString";
- var GEOJSON_POLYGON = "Polygon";
- var GEOJSON_MULTIPOINT = "MultiPoint";
- var GEOJSON_MULTILINESTRING = "MultiLineString";
- var GEOJSON_MULTIPOLYGON = "MultiPolygon";
- var GEOJSON_GEOMETRYCOLLECTION = "GeometryCollection";
-
- var primitiveEdmTypes = [
- EDM_STRING,
- EDM_INT32,
- EDM_INT64,
- EDM_BOOLEAN,
- EDM_DOUBLE,
- EDM_SINGLE,
- EDM_DATETIME,
- EDM_DATETIMEOFFSET,
- EDM_TIME,
- EDM_DECIMAL,
- EDM_GUID,
- EDM_BYTE,
- EDM_INT16,
- EDM_SBYTE,
- EDM_BINARY
- ];
-
- var geometryEdmTypes = [
- EDM_GEOMETRY,
- EDM_GEOMETRY_POINT,
- EDM_GEOMETRY_LINESTRING,
- EDM_GEOMETRY_POLYGON,
- EDM_GEOMETRY_COLLECTION,
- EDM_GEOMETRY_MULTIPOLYGON,
- EDM_GEOMETRY_MULTILINESTRING,
- EDM_GEOMETRY_MULTIPOINT
- ];
-
- var geographyEdmTypes = [
- EDM_GEOGRAPHY,
- EDM_GEOGRAPHY_POINT,
- EDM_GEOGRAPHY_LINESTRING,
- EDM_GEOGRAPHY_POLYGON,
- EDM_GEOGRAPHY_COLLECTION,
- EDM_GEOGRAPHY_MULTIPOLYGON,
- EDM_GEOGRAPHY_MULTILINESTRING,
- EDM_GEOGRAPHY_MULTIPOINT
- ];
-
- var forEachSchema = function (metadata, callback) {
- /// <summary>Invokes a function once per schema in metadata.</summary>
- /// <param name="metadata">Metadata store; one of edmx, schema, or an array of any of them.</param>
- /// <param name="callback" type="Function">Callback function to invoke once per schema.</param>
- /// <returns>
- /// The first truthy value to be returned from the callback; null or the last falsy value otherwise.
- /// </returns>
-
- if (!metadata) {
- return null;
- }
-
- if (isArray(metadata)) {
- var i, len, result;
- for (i = 0, len = metadata.length; i < len; i++) {
- result = forEachSchema(metadata[i], callback);
- if (result) {
- return result;
- }
- }
-
- return null;
- } else {
- if (metadata.dataServices) {
- return forEachSchema(metadata.dataServices.schema, callback);
- }
-
- return callback(metadata);
- }
- };
-
- var formatMilliseconds = function (ms, ns) {
- /// <summary>Formats a millisecond and a nanosecond value into a single string.</summary>
- /// <param name="ms" type="Number" mayBeNull="false">Number of milliseconds to format.</param>
- /// <param name="ns" type="Number" mayBeNull="false">Number of nanoseconds to format.</param>
- /// <returns type="String">Formatted text.</returns>
- /// <remarks>If the value is already as string it's returned as-is.</remarks>
-
- // Avoid generating milliseconds if not necessary.
- if (ms === 0) {
- ms = "";
- } else {
- ms = "." + formatNumberWidth(ms.toString(), 3);
- }
- if (ns > 0) {
- if (ms === "") {
- ms = ".000";
- }
- ms += formatNumberWidth(ns.toString(), 4);
- }
- return ms;
- };
-
- var formatDateTimeOffset = function (value) {
- /// <summary>Formats a DateTime or DateTimeOffset value a string.</summary>
- /// <param name="value" type="Date" mayBeNull="false">Value to format.</param>
- /// <returns type="String">Formatted text.</returns>
- /// <remarks>If the value is already as string it's returned as-is.</remarks>
-
- if (typeof value === "string") {
- return value;
- }
-
- var hasOffset = isDateTimeOffset(value);
- var offset = getCanonicalTimezone(value.__offset);
- if (hasOffset && offset !== "Z") {
- // We're about to change the value, so make a copy.
- value = new Date(value.valueOf());
-
- var timezone = parseTimezone(offset);
- var hours = value.getUTCHours() + (timezone.d * timezone.h);
- var minutes = value.getUTCMinutes() + (timezone.d * timezone.m);
-
- value.setUTCHours(hours, minutes);
- } else if (!hasOffset) {
- // Don't suffix a 'Z' for Edm.DateTime values.
- offset = "";
- }
-
- var year = value.getUTCFullYear();
- var month = value.getUTCMonth() + 1;
- var sign = "";
- if (year <= 0) {
- year = -(year - 1);
- sign = "-";
- }
-
- var ms = formatMilliseconds(value.getUTCMilliseconds(), value.__ns);
-
- return sign +
- formatNumberWidth(year, 4) + "-" +
- formatNumberWidth(month, 2) + "-" +
- formatNumberWidth(value.getUTCDate(), 2) + "T" +
- formatNumberWidth(value.getUTCHours(), 2) + ":" +
- formatNumberWidth(value.getUTCMinutes(), 2) + ":" +
- formatNumberWidth(value.getUTCSeconds(), 2) +
- ms + offset;
- };
-
- var formatDuration = function (value) {
- /// <summary>Converts a duration to a string in xsd:duration format.</summary>
- /// <param name="value" type="Object">Object with ms and __edmType properties.</param>
- /// <returns type="String">String representation of the time object in xsd:duration format.</returns>
-
- var ms = value.ms;
-
- var sign = "";
- if (ms < 0) {
- sign = "-";
- ms = -ms;
- }
-
- var days = Math.floor(ms / 86400000);
- ms -= 86400000 * days;
- var hours = Math.floor(ms / 3600000);
- ms -= 3600000 * hours;
- var minutes = Math.floor(ms / 60000);
- ms -= 60000 * minutes;
- var seconds = Math.floor(ms / 1000);
- ms -= seconds * 1000;
-
- return sign + "P" +
- formatNumberWidth(days, 2) + "DT" +
- formatNumberWidth(hours, 2) + "H" +
- formatNumberWidth(minutes, 2) + "M" +
- formatNumberWidth(seconds, 2) +
- formatMilliseconds(ms, value.ns) + "S";
- };
-
- var formatNumberWidth = function (value, width, append) {
- /// <summary>Formats the specified value to the given width.</summary>
- /// <param name="value" type="Number">Number to format (non-negative).</param>
- /// <param name="width" type="Number">Minimum width for number.</param>
- /// <param name="append" type="Boolean">Flag indicating if the value is padded at the beginning (false) or at the end (true).</param>
- /// <returns type="String">Text representation.</returns>
- var result = value.toString(10);
- while (result.length < width) {
- if (append) {
- result += "0";
- } else {
- result = "0" + result;
- }
- }
-
- return result;
- };
-
- var getCanonicalTimezone = function (timezone) {
- /// <summary>Gets the canonical timezone representation.</summary>
- /// <param name="timezone" type="String">Timezone representation.</param>
- /// <returns type="String">An 'Z' string if the timezone is absent or 0; the timezone otherwise.</returns>
-
- return (!timezone || timezone === "Z" || timezone === "+00:00" || timezone === "-00:00") ? "Z" : timezone;
- };
-
- var getCollectionType = function (typeName) {
- /// <summary>Gets the type of a collection type name.</summary>
- /// <param name="typeName" type="String">Type name of the collection.</param>
- /// <returns type="String">Type of the collection; null if the type name is not a collection type.</returns>
-
- if (typeof typeName === "string") {
- var end = typeName.indexOf(")", 10);
- if (typeName.indexOf("Collection(") === 0 && end > 0) {
- return typeName.substring(11, end);
- }
- }
- return null;
- };
-
- var invokeRequest = function (request, success, error, handler, httpClient, context) {
- /// <summary>Sends a request containing OData payload to a server.</summary>
- /// <param name="request">Object that represents the request to be sent..</param>
- /// <param name="success">Callback for a successful read operation.</param>
- /// <param name="error">Callback for handling errors.</param>
- /// <param name="handler">Handler for data serialization.</param>
- /// <param name="httpClient">HTTP client layer.</param>
- /// <param name="context">Context used for processing the request</param>
-
- return httpClient.request(request, function (response) {
- try {
- if (response.headers) {
- normalizeHeaders(response.headers);
- }
-
- if (response.data === undefined && response.statusCode !== 204) {
- handler.read(response, context);
- }
- } catch (err) {
- if (err.request === undefined) {
- err.request = request;
- }
- if (err.response === undefined) {
- err.response = response;
- }
- error(err);
- return;
- }
-
- success(response.data, response);
- }, error);
- };
-
- var isBatch = function (value) {
- /// <summary>Tests whether a value is a batch object in the library's internal representation.</summary>
- /// <param name="value">Value to test.</param>
- /// <returns type="Boolean">True is the value is a batch object; false otherwise.</returns>
-
- return isComplex(value) && isArray(value.__batchRequests);
- };
-
- // Regular expression used for testing and parsing for a collection type.
- var collectionTypeRE = /Collection\((.*)\)/;
-
- var isCollection = function (value, typeName) {
- /// <summary>Tests whether a value is a collection value in the library's internal representation.</summary>
- /// <param name="value">Value to test.</param>
- /// <param name="typeName" type="Sting">Type name of the value. This is used to disambiguate from a collection property value.</param>
- /// <returns type="Boolean">True is the value is a feed value; false otherwise.</returns>
-
- var colData = value && value.results || value;
- return !!colData &&
- (isCollectionType(typeName)) ||
- (!typeName && isArray(colData) && !isComplex(colData[0]));
- };
-
- var isCollectionType = function (typeName) {
- /// <summary>Checks whether the specified type name is a collection type.</summary>
- /// <param name="typeName" type="String">Name of type to check.</param>
- /// <returns type="Boolean">True if the type is the name of a collection type; false otherwise.</returns>
- return collectionTypeRE.test(typeName);
- };
-
- var isComplex = function (value) {
- /// <summary>Tests whether a value is a complex type value in the library's internal representation.</summary>
- /// <param name="value">Value to test.</param>
- /// <returns type="Boolean">True is the value is a complex type value; false otherwise.</returns>
-
- return !!value &&
- isObject(value) &&
- !isArray(value) &&
- !isDate(value);
- };
-
- var isDateTimeOffset = function (value) {
- /// <summary>Checks whether a Date object is DateTimeOffset value</summary>
- /// <param name="value" type="Date" mayBeNull="false">Value to check.</param>
- /// <returns type="Boolean">true if the value is a DateTimeOffset, false otherwise.</returns>
- return (value.__edmType === "Edm.DateTimeOffset" || (!value.__edmType && value.__offset));
- };
-
- var isDeferred = function (value) {
- /// <summary>Tests whether a value is a deferred navigation property in the library's internal representation.</summary>
- /// <param name="value">Value to test.</param>
- /// <returns type="Boolean">True is the value is a deferred navigation property; false otherwise.</returns>
-
- if (!value && !isComplex(value)) {
- return false;
- }
- var metadata = value.__metadata || {};
- var deferred = value.__deferred || {};
- return !metadata.type && !!deferred.uri;
- };
-
- var isEntry = function (value) {
- /// <summary>Tests whether a value is an entry object in the library's internal representation.</summary>
- /// <param name="value">Value to test.</param>
- /// <returns type="Boolean">True is the value is an entry object; false otherwise.</returns>
-
- return isComplex(value) && value.__metadata && "uri" in value.__metadata;
- };
-
- var isFeed = function (value, typeName) {
- /// <summary>Tests whether a value is a feed value in the library's internal representation.</summary>
- /// <param name="value">Value to test.</param>
- /// <param name="typeName" type="Sting">Type name of the value. This is used to disambiguate from a collection property value.</param>
- /// <returns type="Boolean">True is the value is a feed value; false otherwise.</returns>
-
- var feedData = value && value.results || value;
- return isArray(feedData) && (
- (!isCollectionType(typeName)) &&
- (isComplex(feedData[0]))
- );
- };
-
- var isGeographyEdmType = function (typeName) {
- /// <summary>Checks whether the specified type name is a geography EDM type.</summary>
- /// <param name="typeName" type="String">Name of type to check.</param>
- /// <returns type="Boolean">True if the type is a geography EDM type; false otherwise.</returns>
-
- return contains(geographyEdmTypes, typeName);
- };
-
- var isGeometryEdmType = function (typeName) {
- /// <summary>Checks whether the specified type name is a geometry EDM type.</summary>
- /// <param name="typeName" type="String">Name of type to check.</param>
- /// <returns type="Boolean">True if the type is a geometry EDM type; false otherwise.</returns>
-
- return contains(geometryEdmTypes, typeName);
- };
-
- var isNamedStream = function (value) {
- /// <summary>Tests whether a value is a named stream value in the library's internal representation.</summary>
- /// <param name="value">Value to test.</param>
- /// <returns type="Boolean">True is the value is a named stream; false otherwise.</returns>
-
- if (!value && !isComplex(value)) {
- return false;
- }
- var metadata = value.__metadata;
- var mediaResource = value.__mediaresource;
- return !metadata && !!mediaResource && !!mediaResource.media_src;
- };
-
- var isPrimitive = function (value) {
- /// <summary>Tests whether a value is a primitive type value in the library's internal representation.</summary>
- /// <param name="value">Value to test.</param>
- /// <remarks>
- /// Date objects are considered primitive types by the library.
- /// </remarks>
- /// <returns type="Boolean">True is the value is a primitive type value.</returns>
-
- return isDate(value) ||
- typeof value === "string" ||
- typeof value === "number" ||
- typeof value === "boolean";
- };
-
- var isPrimitiveEdmType = function (typeName) {
- /// <summary>Checks whether the specified type name is a primitive EDM type.</summary>
- /// <param name="typeName" type="String">Name of type to check.</param>
- /// <returns type="Boolean">True if the type is a primitive EDM type; false otherwise.</returns>
-
- return contains(primitiveEdmTypes, typeName);
- };
-
- var navigationPropertyKind = function (value, propertyModel) {
- /// <summary>Gets the kind of a navigation property value.</summary>
- /// <param name="value">Value of the navigation property.</param>
- /// <param name="propertyModel" type="Object" optional="true">
- /// Object that describes the navigation property in an OData conceptual schema.
- /// </param>
- /// <remarks>
- /// The returned string is as follows
- /// </remarks>
- /// <returns type="String">String value describing the kind of the navigation property; null if the kind cannot be determined.</returns>
-
- if (isDeferred(value)) {
- return "deferred";
- }
- if (isEntry(value)) {
- return "entry";
- }
- if (isFeed(value)) {
- return "feed";
- }
- if (propertyModel && propertyModel.relationship) {
- if (value === null || value === undefined || !isFeed(value)) {
- return "entry";
- }
- return "feed";
- }
- return null;
- };
-
- var lookupProperty = function (properties, name) {
- /// <summary>Looks up a property by name.</summary>
- /// <param name="properties" type="Array" mayBeNull="true">Array of property objects as per EDM metadata.</param>
- /// <param name="name" type="String">Name to look for.</param>
- /// <returns type="Object">The property object; null if not found.</returns>
-
- return find(properties, function (property) {
- return property.name === name;
- });
- };
-
- var lookupInMetadata = function (name, metadata, kind) {
- /// <summary>Looks up a type object by name.</summary>
- /// <param name="name" type="String">Name, possibly null or empty.</param>
- /// <param name="metadata">Metadata store; one of edmx, schema, or an array of any of them.</param>
- /// <param name="kind" type="String">Kind of object to look for as per EDM metadata.</param>
- /// <returns>An type description if the name is found; null otherwise.</returns>
-
- return (name) ? forEachSchema(metadata, function (schema) {
- return lookupInSchema(name, schema, kind);
- }) : null;
- };
-
- var lookupEntitySet = function (entitySets, name) {
- /// <summary>Looks up a entity set by name.</summary>
- /// <param name="properties" type="Array" mayBeNull="true">Array of entity set objects as per EDM metadata.</param>
- /// <param name="name" type="String">Name to look for.</param>
- /// <returns type="Object">The entity set object; null if not found.</returns>
-
- return find(entitySets, function (entitySet) {
- return entitySet.name === name;
- });
- };
-
- var lookupComplexType = function (name, metadata) {
- /// <summary>Looks up a complex type object by name.</summary>
- /// <param name="name" type="String">Name, possibly null or empty.</param>
- /// <param name="metadata">Metadata store; one of edmx, schema, or an array of any of them.</param>
- /// <returns>A complex type description if the name is found; null otherwise.</returns>
-
- return lookupInMetadata(name, metadata, "complexType");
- };
-
- var lookupEntityType = function (name, metadata) {
- /// <summary>Looks up an entity type object by name.</summary>
- /// <param name="name" type="String">Name, possibly null or empty.</param>
- /// <param name="metadata">Metadata store; one of edmx, schema, or an array of any of them.</param>
- /// <returns>An entity type description if the name is found; null otherwise.</returns>
-
- return lookupInMetadata(name, metadata, "entityType");
- };
-
- var lookupDefaultEntityContainer = function (metadata) {
- /// <summary>Looks up an</summary>
- /// <param name="name" type="String">Name, possibly null or empty.</param>
- /// <param name="metadata">Metadata store; one of edmx, schema, or an array of any of them.</param>
- /// <returns>An entity container description if the name is found; null otherwise.</returns>
-
- return forEachSchema(metadata, function (schema) {
- return find(schema.entityContainer, function (container) {
- return parseBool(container.isDefaultEntityContainer);
- });
- });
- };
-
- var lookupEntityContainer = function (name, metadata) {
- /// <summary>Looks up an entity container object by name.</summary>
- /// <param name="name" type="String">Name, possibly null or empty.</param>
- /// <param name="metadata">Metadata store; one of edmx, schema, or an array of any of them.</param>
- /// <returns>An entity container description if the name is found; null otherwise.</returns>
-
- return lookupInMetadata(name, metadata, "entityContainer");
- };
-
- var lookupFunctionImport = function (functionImports, name) {
- /// <summary>Looks up a function import by name.</summary>
- /// <param name="properties" type="Array" mayBeNull="true">Array of function import objects as per EDM metadata.</param>
- /// <param name="name" type="String">Name to look for.</param>
- /// <returns type="Object">The entity set object; null if not found.</returns>
-
- return find(functionImports, function (functionImport) {
- return functionImport.name === name;
- });
- };
-
- var lookupNavigationPropertyType = function (navigationProperty, metadata) {
- /// <summary>Looks up the target entity type for a navigation property.</summary>
- /// <param name="navigationProperty" type="Object"></param>
- /// <param name="metadata" type="Object"></param>
- /// <returns type="String">The entity type name for the specified property, null if not found.</returns>
-
- var result = null;
- if (navigationProperty) {
- var rel = navigationProperty.relationship;
- var association = forEachSchema(metadata, function (schema) {
- // The name should be the namespace qualified name in 'ns'.'type' format.
- var nameOnly = removeNamespace(schema["namespace"], rel);
- var associations = schema.association;
- if (nameOnly && associations) {
- var i, len;
- for (i = 0, len = associations.length; i < len; i++) {
- if (associations[i].name === nameOnly) {
- return associations[i];
- }
- }
- }
- return null;
- });
-
- if (association) {
- var end = association.end[0];
- if (end.role !== navigationProperty.toRole) {
- end = association.end[1];
- // For metadata to be valid, end.role === navigationProperty.toRole now.
- }
- result = end.type;
- }
- }
- return result;
- };
-
- var lookupNavigationPropertyEntitySet = function (navigationProperty, sourceEntitySetName, metadata) {
- /// <summary>Looks up the target entityset name for a navigation property.</summary>
- /// <param name="navigationProperty" type="Object"></param>
- /// <param name="metadata" type="Object"></param>
- /// <returns type="String">The entityset name for the specified property, null if not found.</returns>
-
- if (navigationProperty) {
- var rel = navigationProperty.relationship;
- var associationSet = forEachSchema(metadata, function (schema) {
- var containers = schema.entityContainer;
- for (var i = 0; i < containers.length; i++) {
- var associationSets = containers[i].associationSet;
- if (associationSets) {
- for (var j = 0; j < associationSets.length; j++) {
- if (associationSets[j].association == rel) {
- return associationSets[j];
- }
- }
- }
- }
- return null;
- });
- if (associationSet && associationSet.end[0] && associationSet.end[1]) {
- return (associationSet.end[0].entitySet == sourceEntitySetName) ? associationSet.end[1].entitySet : associationSet.end[0].entitySet;
- }
- }
- return null;
- };
-
- var getEntitySetInfo = function (entitySetName, metadata) {
- /// <summary>Gets the entitySet info, container name and functionImports for an entitySet</summary>
- /// <param name="navigationProperty" type="Object"></param>
- /// <param name="metadata" type="Object"></param>
- /// <returns type="Object">The info about the entitySet.</returns>
-
- var info = forEachSchema(metadata, function (schema) {
- var containers = schema.entityContainer;
- for (var i = 0; i < containers.length; i++) {
- var entitySets = containers[i].entitySet;
- if (entitySets) {
- for (var j = 0; j < entitySets.length; j++) {
- if (entitySets[j].name == entitySetName) {
- return { entitySet: entitySets[j], containerName: containers[i].name, functionImport: containers[i].functionImport };
- }
- }
- }
- }
- return null;
- });
-
- return info;
- };
-
- var removeNamespace = function (ns, fullName) {
- /// <summary>Given an expected namespace prefix, removes it from a full name.</summary>
- /// <param name="ns" type="String">Expected namespace.</param>
- /// <param name="fullName" type="String">Full name in 'ns'.'name' form.</param>
- /// <returns type="String">The local name, null if it isn't found in the expected namespace.</returns>
-
- if (fullName.indexOf(ns) === 0 && fullName.charAt(ns.length) === ".") {
- return fullName.substr(ns.length + 1);
- }
-
- return null;
- };
-
- var lookupInSchema = function (name, schema, kind) {
- /// <summary>Looks up a schema object by name.</summary>
- /// <param name="name" type="String">Name (assigned).</param>
- /// <param name="schema">Schema object as per EDM metadata.</param>
- /// <param name="kind" type="String">Kind of object to look for as per EDM metadata.</param>
- /// <returns>An entity type description if the name is found; null otherwise.</returns>
-
- if (name && schema) {
- // The name should be the namespace qualified name in 'ns'.'type' format.
- var nameOnly = removeNamespace(schema["namespace"], name);
- if (nameOnly) {
- return find(schema[kind], function (item) {
- return item.name === nameOnly;
- });
- }
- }
- return null;
- };
-
- var maxVersion = function (left, right) {
- /// <summary>Compares to version strings and returns the higher one.</summary>
- /// <param name="left" type="String">Version string in the form "major.minor.rev"</param>
- /// <param name="right" type="String">Version string in the form "major.minor.rev"</param>
- /// <returns type="String">The higher version string.</returns>
-
- if (left === right) {
- return left;
- }
-
- var leftParts = left.split(".");
- var rightParts = right.split(".");
-
- var len = (leftParts.length >= rightParts.length) ?
- leftParts.length :
- rightParts.length;
-
- for (var i = 0; i < len; i++) {
- var leftVersion = leftParts[i] && parseInt10(leftParts[i]);
- var rightVersion = rightParts[i] && parseInt10(rightParts[i]);
- if (leftVersion > rightVersion) {
- return left;
- }
- if (leftVersion < rightVersion) {
- return right;
- }
- }
- };
-
- var normalHeaders = {
- "accept": "Accept",
- "content-type": "Content-Type",
- "dataserviceversion": "DataServiceVersion",
- "maxdataserviceversion": "MaxDataServiceVersion"
- };
-
- var normalizeHeaders = function (headers) {
- /// <summary>Normalizes headers so they can be found with consistent casing.</summary>
- /// <param name="headers" type="Object">Dictionary of name/value pairs.</param>
-
- for (var name in headers) {
- var lowerName = name.toLowerCase();
- var normalName = normalHeaders[lowerName];
- if (normalName && name !== normalName) {
- var val = headers[name];
- delete headers[name];
- headers[normalName] = val;
- }
- }
- };
-
- var parseBool = function (propertyValue) {
- /// <summary>Parses a string into a boolean value.</summary>
- /// <param name="propertyValue">Value to parse.</param>
- /// <returns type="Boolean">true if the property value is 'true'; false otherwise.</returns>
-
- if (typeof propertyValue === "boolean") {
- return propertyValue;
- }
-
- return typeof propertyValue === "string" && propertyValue.toLowerCase() === "true";
- };
-
-
- // The captured indices for this expression are:
- // 0 - complete input
- // 1,2,3 - year with optional minus sign, month, day
- // 4,5,6 - hours, minutes, seconds
- // 7 - optional milliseconds
- // 8 - everything else (presumably offset information)
- var parseDateTimeRE = /^(-?\d{4,})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2}))?(?:\.(\d+))?(.*)$/;
-
- var parseDateTimeMaybeOffset = function (value, withOffset, nullOnError) {
- /// <summary>Parses a string into a DateTime value.</summary>
- /// <param name="value" type="String">Value to parse.</param>
- /// <param name="withOffset" type="Boolean">Whether offset is expected.</param>
- /// <returns type="Date">The parsed value.</returns>
-
- // We cannot parse this in cases of failure to match or if offset information is specified.
- var parts = parseDateTimeRE.exec(value);
- var offset = (parts) ? getCanonicalTimezone(parts[8]) : null;
-
- if (!parts || (!withOffset && offset !== "Z")) {
- if (nullOnError) {
- return null;
- }
- throw { message: "Invalid date/time value" };
- }
-
- // Pre-parse years, account for year '0' being invalid in dateTime.
- var year = parseInt10(parts[1]);
- if (year <= 0) {
- year++;
- }
-
- // Pre-parse optional milliseconds, fill in default. Fail if value is too precise.
- var ms = parts[7];
- var ns = 0;
- if (!ms) {
- ms = 0;
- } else {
- if (ms.length > 7) {
- if (nullOnError) {
- return null;
- }
- throw { message: "Cannot parse date/time value to given precision." };
- }
-
- ns = formatNumberWidth(ms.substring(3), 4, true);
- ms = formatNumberWidth(ms.substring(0, 3), 3, true);
-
- ms = parseInt10(ms);
- ns = parseInt10(ns);
- }
-
- // Pre-parse other time components and offset them if necessary.
- var hours = parseInt10(parts[4]);
- var minutes = parseInt10(parts[5]);
- var seconds = parseInt10(parts[6]) || 0;
- if (offset !== "Z") {
- // The offset is reversed to get back the UTC date, which is
- // what the API will eventually have.
- var timezone = parseTimezone(offset);
- var direction = -(timezone.d);
- hours += timezone.h * direction;
- minutes += timezone.m * direction;
- }
-
- // Set the date and time separately with setFullYear, so years 0-99 aren't biased like in Date.UTC.
- var result = new Date();
- result.setUTCFullYear(
- year, // Year.
- parseInt10(parts[2]) - 1, // Month (zero-based for Date.UTC and setFullYear).
- parseInt10(parts[3]) // Date.
- );
- result.setUTCHours(hours, minutes, seconds, ms);
-
- if (isNaN(result.valueOf())) {
- if (nullOnError) {
- return null;
- }
- throw { message: "Invalid date/time value" };
- }
-
- if (withOffset) {
- result.__edmType = "Edm.DateTimeOffset";
- result.__offset = offset;
- }
-
- if (ns) {
- result.__ns = ns;
- }
-
- return result;
- };
-
- var parseDateTime = function (propertyValue, nullOnError) {
- /// <summary>Parses a string into a DateTime value.</summary>
- /// <param name="propertyValue" type="String">Value to parse.</param>
- /// <returns type="Date">The parsed value.</returns>
-
- return parseDateTimeMaybeOffset(propertyValue, false, nullOnError);
- };
-
- var parseDateTimeOffset = function (propertyValue, nullOnError) {
- /// <summary>Parses a string into a DateTimeOffset value.</summary>
- /// <param name="propertyValue" type="String">Value to parse.</param>
- /// <returns type="Date">The parsed value.</returns>
- /// <remarks>
- /// The resulting object is annotated with an __edmType property and
- /// an __offset property reflecting the original intended offset of
- /// the value. The time is adjusted for UTC time, as the current
- /// timezone-aware Date APIs will only work with the local timezone.
- /// </remarks>
-
- return parseDateTimeMaybeOffset(propertyValue, true, nullOnError);
- };
-
- // The captured indices for this expression are:
- // 0 - complete input
- // 1 - direction
- // 2,3,4 - years, months, days
- // 5,6,7,8 - hours, minutes, seconds, miliseconds
-
- var parseTimeRE = /^([+-])?P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)(?:\.(\d+))?S)?)?/;
-
- var isEdmDurationValue = function(value) {
- parseTimeRE.test(value);
- };
-
- var parseDuration = function (duration) {
- /// <summary>Parses a string in xsd:duration format.</summary>
- /// <param name="duration" type="String">Duration value.</param>
- /// <remarks>
- /// This method will throw an exception if the input string has a year or a month component.
- /// </remarks>
- /// <returns type="Object">Object representing the time</returns>
-
- var parts = parseTimeRE.exec(duration);
-
- if (parts === null) {
- throw { message: "Invalid duration value." };
- }
-
- var years = parts[2] || "0";
- var months = parts[3] || "0";
- var days = parseInt10(parts[4] || 0);
- var hours = parseInt10(parts[5] || 0);
- var minutes = parseInt10(parts[6] || 0);
- var seconds = parseFloat(parts[7] || 0);
-
- if (years !== "0" || months !== "0") {
- throw { message: "Unsupported duration value." };
- }
-
- var ms = parts[8];
- var ns = 0;
- if (!ms) {
- ms = 0;
- } else {
- if (ms.length > 7) {
- throw { message: "Cannot parse duration value to given precision." };
- }
-
- ns = formatNumberWidth(ms.substring(3), 4, true);
- ms = formatNumberWidth(ms.substring(0, 3), 3, true);
-
- ms = parseInt10(ms);
- ns = parseInt10(ns);
- }
-
- ms += seconds * 1000 + minutes * 60000 + hours * 3600000 + days * 86400000;
-
- if (parts[1] === "-") {
- ms = -ms;
- }
-
- var result = { ms: ms, __edmType: "Edm.Time" };
-
- if (ns) {
- result.ns = ns;
- }
- return result;
- };
-
- var parseTimezone = function (timezone) {
- /// <summary>Parses a timezone description in (+|-)nn:nn format.</summary>
- /// <param name="timezone" type="String">Timezone offset.</param>
- /// <returns type="Object">
- /// An object with a (d)irection property of 1 for + and -1 for -,
- /// offset (h)ours and offset (m)inutes.
- /// </returns>
-
- var direction = timezone.substring(0, 1);
- direction = (direction === "+") ? 1 : -1;
-
- var offsetHours = parseInt10(timezone.substring(1));
- var offsetMinutes = parseInt10(timezone.substring(timezone.indexOf(":") + 1));
- return { d: direction, h: offsetHours, m: offsetMinutes };
- };
-
- var prepareRequest = function (request, handler, context) {
- /// <summary>Prepares a request object so that it can be sent through the network.</summary>
- /// <param name="request">Object that represents the request to be sent.</param>
- /// <param name="handler">Handler for data serialization</param>
- /// <param name="context">Context used for preparing the request</param>
-
- // Default to GET if no method has been specified.
- if (!request.method) {
- request.method = "GET";
- }
-
- if (!request.headers) {
- request.headers = {};
- } else {
- normalizeHeaders(request.headers);
- }
-
- if (request.headers.Accept === undefined) {
- request.headers.Accept = handler.accept;
- }
-
- if (assigned(request.data) && request.body === undefined) {
- handler.write(request, context);
- }
-
- if (!assigned(request.headers.MaxDataServiceVersion)) {
- request.headers.MaxDataServiceVersion = handler.maxDataServiceVersion || "1.0";
- }
- };
-
- var traverseInternal = function (item, owner, callback) {
- /// <summary>Traverses a tree of objects invoking callback for every value.</summary>
- /// <param name="item" type="Object">Object or array to traverse.</param>
- /// <param name="callback" type="Function">
- /// Callback function with key and value, similar to JSON.parse reviver.
- /// </param>
- /// <returns type="Object">The object with traversed properties.</returns>
- /// <remarks>Unlike the JSON reviver, this won't delete null members.</remarks>
-
- if (item && typeof item === "object") {
- for (var name in item) {
- var value = item[name];
- var result = traverseInternal(value, name, callback);
- result = callback(name, result, owner);
- if (result !== value) {
- if (value === undefined) {
- delete item[name];
- } else {
- item[name] = result;
- }
- }
- }
- }
-
- return item;
- };
-
- var traverse = function (item, callback) {
- /// <summary>Traverses a tree of objects invoking callback for every value.</summary>
- /// <param name="item" type="Object">Object or array to traverse.</param>
- /// <param name="callback" type="Function">
- /// Callback function with key and value, similar to JSON.parse reviver.
- /// </param>
- /// <returns type="Object">The traversed object.</returns>
- /// <remarks>Unlike the JSON reviver, this won't delete null members.</remarks>
-
- return callback("", traverseInternal(item, "", callback));
- };
-
- // DATAJS INTERNAL START
- odata.dataItemTypeName = dataItemTypeName;
- odata.EDM_BINARY = EDM_BINARY;
- odata.EDM_BOOLEAN = EDM_BOOLEAN;
- odata.EDM_BYTE = EDM_BYTE;
- odata.EDM_DATETIME = EDM_DATETIME;
- odata.EDM_DATETIMEOFFSET = EDM_DATETIMEOFFSET;
- odata.EDM_DECIMAL = EDM_DECIMAL;
- odata.EDM_DOUBLE = EDM_DOUBLE;
- odata.EDM_GEOGRAPHY = EDM_GEOGRAPHY;
- odata.EDM_GEOGRAPHY_POINT = EDM_GEOGRAPHY_POINT;
- odata.EDM_GEOGRAPHY_LINESTRING = EDM_GEOGRAPHY_LINESTRING;
- odata.EDM_GEOGRAPHY_POLYGON = EDM_GEOGRAPHY_POLYGON;
- odata.EDM_GEOGRAPHY_COLLECTION = EDM_GEOGRAPHY_COLLECTION;
- odata.EDM_GEOGRAPHY_MULTIPOLYGON = EDM_GEOGRAPHY_MULTIPOLYGON;
- odata.EDM_GEOGRAPHY_MULTILINESTRING = EDM_GEOGRAPHY_MULTILINESTRING;
- odata.EDM_GEOGRAPHY_MULTIPOINT = EDM_GEOGRAPHY_MULTIPOINT;
- odata.EDM_GEOMETRY = EDM_GEOMETRY;
- odata.EDM_GEOMETRY_POINT = EDM_GEOMETRY_POINT;
- odata.EDM_GEOMETRY_LINESTRING = EDM_GEOMETRY_LINESTRING;
- odata.EDM_GEOMETRY_POLYGON = EDM_GEOMETRY_POLYGON;
- odata.EDM_GEOMETRY_COLLECTION = EDM_GEOMETRY_COLLECTION;
- odata.EDM_GEOMETRY_MULTIPOLYGON = EDM_GEOMETRY_MULTIPOLYGON;
- odata.EDM_GEOMETRY_MULTILINESTRING = EDM_GEOMETRY_MULTILINESTRING;
- odata.EDM_GEOMETRY_MULTIPOINT = EDM_GEOMETRY_MULTIPOINT;
- odata.EDM_GUID = EDM_GUID;
- odata.EDM_INT16 = EDM_INT16;
- odata.EDM_INT32 = EDM_INT32;
- odata.EDM_INT64 = EDM_INT64;
- odata.EDM_SBYTE = EDM_SBYTE;
- odata.EDM_SINGLE = EDM_SINGLE;
- odata.EDM_STRING = EDM_STRING;
- odata.EDM_TIME = EDM_TIME;
- odata.GEOJSON_POINT = GEOJSON_POINT;
- odata.GEOJSON_LINESTRING = GEOJSON_LINESTRING;
- odata.GEOJSON_POLYGON = GEOJSON_POLYGON;
- odata.GEOJSON_MULTIPOINT = GEOJSON_MULTIPOINT;
- odata.GEOJSON_MULTILINESTRING = GEOJSON_MULTILINESTRING;
- odata.GEOJSON_MULTIPOLYGON = GEOJSON_MULTIPOLYGON;
- odata.GEOJSON_GEOMETRYCOLLECTION = GEOJSON_GEOMETRYCOLLECTION;
- odata.forEachSchema = forEachSchema;
- odata.formatDateTimeOffset = formatDateTimeOffset;
- odata.formatDuration = formatDuration;
- odata.formatNumberWidth = formatNumberWidth;
- odata.getCanonicalTimezone = getCanonicalTimezone;
- odata.getCollectionType = getCollectionType;
- odata.invokeRequest = invokeRequest;
- odata.isBatch = isBatch;
- odata.isCollection = isCollection;
- odata.isCollectionType = isCollectionType;
- odata.isComplex = isComplex;
- odata.isDateTimeOffset = isDateTimeOffset;
- odata.isDeferred = isDeferred;
- odata.isEntry = isEntry;
- odata.isFeed = isFeed;
- odata.isGeographyEdmType = isGeographyEdmType;
- odata.isGeometryEdmType = isGeometryEdmType;
- odata.isNamedStream = isNamedStream;
- odata.isPrimitive = isPrimitive;
- odata.isPrimitiveEdmType = isPrimitiveEdmType;
- odata.lookupComplexType = lookupComplexType;
- odata.lookupDefaultEntityContainer = lookupDefaultEntityContainer;
- odata.lookupEntityContainer = lookupEntityContainer;
- odata.lookupEntitySet = lookupEntitySet;
- odata.lookupEntityType = lookupEntityType;
- odata.lookupFunctionImport = lookupFunctionImport;
- odata.lookupNavigationPropertyType = lookupNavigationPropertyType;
- odata.lookupNavigationPropertyEntitySet = lookupNavigationPropertyEntitySet;
- odata.lookupInSchema = lookupInSchema;
- odata.lookupProperty = lookupProperty;
- odata.lookupInMetadata = lookupInMetadata;
- odata.getEntitySetInfo = getEntitySetInfo;
- odata.maxVersion = maxVersion;
- odata.navigationPropertyKind = navigationPropertyKind;
- odata.normalizeHeaders = normalizeHeaders;
- odata.parseBool = parseBool;
- odata.parseDateTime = parseDateTime;
- odata.parseDateTimeOffset = parseDateTimeOffset;
- odata.parseDuration = parseDuration;
- odata.parseTimezone = parseTimezone;
- odata.parseInt10 = parseInt10;
- odata.prepareRequest = prepareRequest;
- odata.removeNamespace = removeNamespace;
- odata.traverse = traverse;
-
- // DATAJS INTERNAL END
-
- // CONTENT END
-})(this);
\ No newline at end of file
[02/15] [OLINGO-238] Build infrastructure for datajs I
Posted by ko...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/odata-xml.js
----------------------------------------------------------------------
diff --git a/datajs/src/odata-xml.js b/datajs/src/odata-xml.js
deleted file mode 100644
index b2d00f6..0000000
--- a/datajs/src/odata-xml.js
+++ /dev/null
@@ -1,850 +0,0 @@
-// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
-// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// odata-xml.js
-
-(function (window, undefined) {
-
- var datajs = window.datajs || {};
- var odata = window.OData || {};
-
- // Imports.
-
- var djsassert = datajs.djsassert;
- var http = datajs.http;
- var isArray = datajs.isArray;
- var isDate = datajs.isDate;
- var isObject = datajs.isObject;
- var normalizeURI = datajs.normalizeURI;
- var parseInt10 = datajs.parseInt10;
- var xmlAppendChild = datajs.xmlAppendChild;
- var xmlAppendChildren = datajs.xmlAppendChildren;
- var xmlAttributes = datajs.xmlAttributes;
- var xmlBaseURI = datajs.xmlBaseURI;
- var xmlChildElements = datajs.xmlChildElements;
- var xmlDom = datajs.xmlDom;
- var xmlFirstChildElement = datajs.xmlFirstChildElement;
- var xmlInnerText = datajs.xmlInnerText;
- var xmlLocalName = datajs.xmlLocalName;
- var xmlNamespaceURI = datajs.xmlNamespaceURI;
- var xmlNewAttribute = datajs.xmlNewAttribute;
- var xmlNewElement = datajs.xmlNewElement;
- var xmlNodeValue = datajs.xmlNodeValue;
- var xmlNS = datajs.xmlNS;
- var xmlnsNS = datajs.xmlnsNS;
- var xmlParse = datajs.xmlParse;
- var xmlQualifiedName = datajs.xmlQualifiedName;
- var xmlSerialize = datajs.xmlSerialize;
- var xmlSiblingElement = datajs.xmlSiblingElement;
- var w3org = datajs.w3org;
-
- var dataItemTypeName = odata.dataItemTypeName;
- var EDM_BINARY = odata.EDM_BINARY;
- var EDM_BOOLEAN = odata.EDM_BOOLEAN;
- var EDM_BYTE = odata.EDM_BYTE;
- var EDM_DATETIME = odata.EDM_DATETIME;
- var EDM_DATETIMEOFFSET = odata.EDM_DATETIMEOFFSET;
- var EDM_DECIMAL = odata.EDM_DECIMAL;
- var EDM_DOUBLE = odata.EDM_DOUBLE;
- var EDM_GEOGRAPHY = odata.EDM_GEOGRAPHY;
- var EDM_GEOGRAPHY_POINT = odata.EDM_GEOGRAPHY_POINT;
- var EDM_GEOGRAPHY_LINESTRING = odata.EDM_GEOGRAPHY_LINESTRING;
- var EDM_GEOGRAPHY_POLYGON = odata.EDM_GEOGRAPHY_POLYGON;
- var EDM_GEOGRAPHY_COLLECTION = odata.EDM_GEOGRAPHY_COLLECTION;
- var EDM_GEOGRAPHY_MULTIPOLYGON = odata.EDM_GEOGRAPHY_MULTIPOLYGON;
- var EDM_GEOGRAPHY_MULTILINESTRING = odata.EDM_GEOGRAPHY_MULTILINESTRING;
- var EDM_GEOGRAPHY_MULTIPOINT = odata.EDM_GEOGRAPHY_MULTIPOINT;
- var EDM_GEOMETRY = odata.EDM_GEOMETRY;
- var EDM_GEOMETRY_POINT = odata.EDM_GEOMETRY_POINT;
- var EDM_GEOMETRY_LINESTRING = odata.EDM_GEOMETRY_LINESTRING;
- var EDM_GEOMETRY_POLYGON = odata.EDM_GEOMETRY_POLYGON;
- var EDM_GEOMETRY_COLLECTION = odata.EDM_GEOMETRY_COLLECTION;
- var EDM_GEOMETRY_MULTIPOLYGON = odata.EDM_GEOMETRY_MULTIPOLYGON;
- var EDM_GEOMETRY_MULTILINESTRING = odata.EDM_GEOMETRY_MULTILINESTRING;
- var EDM_GEOMETRY_MULTIPOINT = odata.EDM_GEOMETRY_MULTIPOINT;
- var EDM_GUID = odata.EDM_GUID;
- var EDM_INT16 = odata.EDM_INT16;
- var EDM_INT32 = odata.EDM_INT32;
- var EDM_INT64 = odata.EDM_INT64;
- var EDM_SBYTE = odata.EDM_SBYTE;
- var EDM_SINGLE = odata.EDM_SINGLE;
- var EDM_STRING = odata.EDM_STRING;
- var EDM_TIME = odata.EDM_TIME;
- var GEOJSON_POINT = odata.GEOJSON_POINT;
- var GEOJSON_LINESTRING = odata.GEOJSON_LINESTRING;
- var GEOJSON_POLYGON = odata.GEOJSON_POLYGON;
- var GEOJSON_MULTIPOINT = odata.GEOJSON_MULTIPOINT;
- var GEOJSON_MULTILINESTRING = odata.GEOJSON_MULTILINESTRING;
- var GEOJSON_MULTIPOLYGON = odata.GEOJSON_MULTIPOLYGON;
- var GEOJSON_GEOMETRYCOLLECTION = odata.GEOJSON_GEOMETRYCOLLECTION;
- var formatDateTimeOffset = odata.formatDateTimeOffset;
- var formatDuration = odata.formatDuration;
- var getCollectionType = odata.getCollectionType;
- var gmlNewODataSpatialValue = odata.gmlNewODataSpatialValue;
- var gmlReadODataSpatialValue = odata.gmlReadODataSpatialValue;
- var gmlXmlNs = odata.gmlXmlNs;
- var handler = odata.handler;
- var isCollection = odata.isCollection;
- var isCollectionType = odata.isCollectionType;
- var isDeferred = odata.isDeferred;
- var isNamedStream = odata.isNamedStream;
- var isGeographyEdmType = odata.isGeographyEdmType;
- var isGeometryEdmType = odata.isGeometryEdmType;
- var isPrimitive = odata.isPrimitive;
- var isPrimitiveEdmType = odata.isPrimitiveEdmType;
- var lookupComplexType = odata.lookupComplexType;
- var lookupProperty = odata.lookupProperty;
- var maxVersion = odata.maxVersion;
- var navigationPropertyKind = odata.navigationPropertyKind;
- var MAX_DATA_SERVICE_VERSION = odata.MAX_DATA_SERVICE_VERSION;
- var parseBool = odata.parseBool;
- var parseDateTime = odata.parseDateTime;
- var parseDateTimeOffset = odata.parseDateTimeOffset;
- var parseDuration = odata.parseDuration;
- var parseTimezone = odata.parseTimezone;
-
- // CONTENT START
-
- var xmlMediaType = "application/xml";
-
- var ado = http + "schemas.microsoft.com/ado/"; // http://schemas.microsoft.com/ado/
- var adoDs = ado + "2007/08/dataservices"; // http://schemas.microsoft.com/ado/2007/08/dataservices
-
- var edmxNs = ado + "2007/06/edmx"; // http://schemas.microsoft.com/ado/2007/06/edmx
- var edmNs1 = ado + "2006/04/edm"; // http://schemas.microsoft.com/ado/2006/04/edm
- var edmNs1_1 = ado + "2007/05/edm"; // http://schemas.microsoft.com/ado/2007/05/edm
- var edmNs1_2 = ado + "2008/01/edm"; // http://schemas.microsoft.com/ado/2008/01/edm
-
- // There are two valid namespaces for Edm 2.0
- var edmNs2a = ado + "2008/09/edm"; // http://schemas.microsoft.com/ado/2008/09/edm
- var edmNs2b = ado + "2009/08/edm"; // http://schemas.microsoft.com/ado/2009/08/edm
-
- var edmNs3 = ado + "2009/11/edm"; // http://schemas.microsoft.com/ado/2009/11/edm
-
- var odataXmlNs = adoDs; // http://schemas.microsoft.com/ado/2007/08/dataservices
- var odataMetaXmlNs = adoDs + "/metadata"; // http://schemas.microsoft.com/ado/2007/08/dataservices/metadata
- var odataRelatedPrefix = adoDs + "/related/"; // http://schemas.microsoft.com/ado/2007/08/dataservices/related
- var odataScheme = adoDs + "/scheme"; // http://schemas.microsoft.com/ado/2007/08/dataservices/scheme
-
- var odataPrefix = "d";
- var odataMetaPrefix = "m";
-
- var createAttributeExtension = function (domNode, useNamespaceURI) {
- /// <summary>Creates an extension object for the specified attribute.</summary>
- /// <param name="domNode">DOM node for the attribute.</param>
- /// <param name="useNamespaceURI" type="Boolean">Flag indicating if the namespaceURI property should be added to the extension object instead of the namespace property.</param>
- /// <remarks>
- /// The useNamespaceURI flag is used to prevent a breaking change from older versions of datajs in which extension
- /// objects created for Atom extension attributes have the namespaceURI property instead of the namespace one.
- ///
- /// This flag and the namespaceURI property should be deprecated in future major versions of the library.
- /// </remarks>
- /// <returns type="Object">The new extension object.</returns>
-
- djsassert(domNode.nodeType === 2, "createAttributeExtension - domNode is not an attribute node!!");
- var extension = { name: xmlLocalName(domNode), value: domNode.value };
- extension[useNamespaceURI ? "namespaceURI" : "namespace"] = xmlNamespaceURI(domNode);
-
- return extension;
- };
-
- var createElementExtension = function (domNode, useNamespaceURI) {
- /// <summary>Creates an extension object for the specified element.</summary>
- /// <param name="domNode">DOM node for the element.</param>
- /// <param name="useNamespaceURI" type="Boolean">Flag indicating if the namespaceURI property should be added to the extension object instead of the namespace property.</param>
- /// <remarks>
- /// The useNamespaceURI flag is used to prevent a breaking change from older versions of datajs in which extension
- /// objects created for Atom extension attributes have the namespaceURI property instead of the namespace one.
- ///
- /// This flag and the namespaceURI property should be deprecated in future major versions of the library.
- /// </remarks>
- /// <returns type="Object">The new extension object.</returns>
-
- djsassert(domNode.nodeType === 1, "createAttributeExtension - domNode is not an element node!!");
-
- var attributeExtensions = [];
- var childrenExtensions = [];
-
- var i, len;
- var attributes = domNode.attributes;
- for (i = 0, len = attributes.length; i < len; i++) {
- var attr = attributes[i];
- if (xmlNamespaceURI(attr) !== xmlnsNS) {
- attributeExtensions.push(createAttributeExtension(attr, useNamespaceURI));
- }
- }
-
- var child = domNode.firstChild;
- while (child != null) {
- if (child.nodeType === 1) {
- childrenExtensions.push(createElementExtension(child, useNamespaceURI));
- }
- child = child.nextSibling;
- }
-
- var extension = {
- name: xmlLocalName(domNode),
- value: xmlInnerText(domNode),
- attributes: attributeExtensions,
- children: childrenExtensions
- };
-
- extension[useNamespaceURI ? "namespaceURI" : "namespace"] = xmlNamespaceURI(domNode);
- return extension;
- };
-
- var isCollectionItemElement = function (domElement) {
- /// <summary>Checks whether the domElement is a collection item.</summary>
- /// <param name="domElement">DOM element possibliy represnting a collection item.</param>
- /// <returns type="Boolean">True if the domeElement belongs to the OData metadata namespace and its local name is "element"; false otherwise.</returns>
-
- return xmlNamespaceURI(domElement) === odataXmlNs && xmlLocalName(domElement) === "element";
- };
-
- var makePropertyMetadata = function (type, extensions) {
- /// <summary>Creates an object containing property metadata.</summary>
- /// <param type="String" name="type">Property type name.</param>
- /// <param type="Array" name="extensions">Array of attribute extension objects.</param>
- /// <returns type="Object">Property metadata object cotaining type and extensions fields.</returns>
-
- return { type: type, extensions: extensions };
- };
-
- var odataInferTypeFromPropertyXmlDom = function (domElement) {
- /// <summary>Infers type of a property based on its xml DOM tree.</summary>
- /// <param name="domElement">DOM element for the property.</param>
- /// <returns type="String">Inferred type name; null if the type cannot be determined.</returns>
-
- if (xmlFirstChildElement(domElement, gmlXmlNs)) {
- return EDM_GEOMETRY;
- }
-
- var firstChild = xmlFirstChildElement(domElement, odataXmlNs);
- if (!firstChild) {
- return EDM_STRING;
- }
-
- if (isCollectionItemElement(firstChild)) {
- var sibling = xmlSiblingElement(firstChild, odataXmlNs);
- if (sibling && isCollectionItemElement(sibling)) {
- // More than one <element> tag have been found, it can be safely assumed that this is a collection property.
- return "Collection()";
- }
- }
-
- return null;
- };
-
- var xmlReadODataPropertyAttributes = function (domElement) {
- /// <summary>Reads the attributes of a property DOM element in an OData XML document.</summary>
- /// <param name="domElement">DOM element for the property.</param>
- /// <returns type="Object">Object containing the property type, if it is null, and its attribute extensions.</returns>
-
- var type = null;
- var isNull = false;
- var extensions = [];
-
- xmlAttributes(domElement, function (attribute) {
- var nsURI = xmlNamespaceURI(attribute);
- var localName = xmlLocalName(attribute);
- var value = xmlNodeValue(attribute);
-
- if (nsURI === odataMetaXmlNs) {
- if (localName === "null") {
- isNull = (value.toLowerCase() === "true");
- return;
- }
-
- if (localName === "type") {
- type = value;
- return;
- }
- }
-
- if (nsURI !== xmlNS && nsURI !== xmlnsNS) {
- extensions.push(createAttributeExtension(attribute, true));
- return;
- }
- });
-
- return { type: (!type && isNull ? EDM_STRING : type), isNull: isNull, extensions: extensions };
- };
-
- var xmlReadODataProperty = function (domElement) {
- /// <summary>Reads a property DOM element in an OData XML document.</summary>
- /// <param name="domElement">DOM element for the property.</param>
- /// <returns type="Object">Object with name, value, and metadata for the property.</returns>
-
- if (xmlNamespaceURI(domElement) !== odataXmlNs) {
- // domElement is not a proprety element because it is not in the odata xml namespace.
- return null;
- }
-
- var propertyName = xmlLocalName(domElement);
- var propertyAttributes = xmlReadODataPropertyAttributes(domElement);
-
- var propertyIsNull = propertyAttributes.isNull;
- var propertyType = propertyAttributes.type;
-
- var propertyMetadata = makePropertyMetadata(propertyType, propertyAttributes.extensions);
- var propertyValue = propertyIsNull ? null : xmlReadODataPropertyValue(domElement, propertyType, propertyMetadata);
-
- return { name: propertyName, value: propertyValue, metadata: propertyMetadata };
- };
-
- var xmlReadODataPropertyValue = function (domElement, propertyType, propertyMetadata) {
- /// <summary>Reads the value of a property in an OData XML document.</summary>
- /// <param name="domElement">DOM element for the property.</param>
- /// <param name="propertyType" type="String">Property type name.</param>
- /// <param name="propertyMetadata" type="Object">Object that will store metadata about the property.</param>
- /// <returns>Property value.</returns>
-
- if (!propertyType) {
- propertyType = odataInferTypeFromPropertyXmlDom(domElement);
- propertyMetadata.type = propertyType;
- }
-
- var isGeograhpyType = isGeographyEdmType(propertyType);
- if (isGeograhpyType || isGeometryEdmType(propertyType)) {
- return xmlReadODataSpatialPropertyValue(domElement, propertyType, isGeograhpyType);
- }
-
- if (isPrimitiveEdmType(propertyType)) {
- return xmlReadODataEdmPropertyValue(domElement, propertyType);
- }
-
- if (isCollectionType(propertyType)) {
- return xmlReadODataCollectionPropertyValue(domElement, propertyType, propertyMetadata);
- }
-
- return xmlReadODataComplexPropertyValue(domElement, propertyType, propertyMetadata);
- };
-
- var xmlReadODataSpatialPropertyValue = function (domElement, propertyType, isGeography) {
- /// <summary>Reads the value of an spatial property in an OData XML document.</summary>
- /// <param name="property">DOM element for the spatial property.</param>
- /// <param name="propertyType" type="String">Property type name.</param>
- /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
- /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns>Spatial property value in GeoJSON format.</returns>
-
- var gmlRoot = xmlFirstChildElement(domElement, gmlXmlNs);
- djsassert(gmlRoot, "xmlReadODataSpatialPropertyValue - domElement doesn't have a child element that belongs to the gml namespace!!");
-
- var value = gmlReadODataSpatialValue(gmlRoot, isGeography);
- value.__metadata = { type: propertyType };
- return value;
- };
-
- var xmlReadODataEdmPropertyValue = function (domNode, propertyType) {
- /// <summary>Reads the value of an EDM property in an OData XML document.</summary>
- /// <param name="donNode">DOM node for the EDM property.</param>
- /// <param name="propertyType" type="String">Property type name.</param>
- /// <returns>EDM property value.</returns>
-
- var propertyValue = xmlNodeValue(domNode) || "";
-
- switch (propertyType) {
- case EDM_BOOLEAN:
- return parseBool(propertyValue);
- case EDM_BINARY:
- case EDM_DECIMAL:
- case EDM_GUID:
- case EDM_INT64:
- case EDM_STRING:
- return propertyValue;
- case EDM_BYTE:
- case EDM_INT16:
- case EDM_INT32:
- case EDM_SBYTE:
- return parseInt10(propertyValue);
- case EDM_DOUBLE:
- case EDM_SINGLE:
- return parseFloat(propertyValue);
- case EDM_TIME:
- return parseDuration(propertyValue);
- case EDM_DATETIME:
- return parseDateTime(propertyValue);
- case EDM_DATETIMEOFFSET:
- return parseDateTimeOffset(propertyValue);
- }
-
- return propertyValue;
- };
-
- var xmlReadODataComplexPropertyValue = function(domElement, propertyType, propertyMetadata) {
- /// <summary>Reads the value of a complex type property in an OData XML document.</summary>
- /// <param name="property">DOM element for the complex type property.</param>
- /// <param name="propertyType" type="String">Property type name.</param>
- /// <param name="propertyMetadata" type="Object">Object that will store metadata about the property.</param>
- /// <returns type="Object">Complex type property value.</returns>
-
- var propertyValue = { __metadata: { type: propertyType } };
- xmlChildElements(domElement, function(child) {
- var childProperty = xmlReadODataProperty(child);
- var childPropertyName = childProperty.name;
-
- propertyMetadata.properties = propertyMetadata.properties || {};
- propertyMetadata.properties[childPropertyName] = childProperty.metadata;
- propertyValue[childPropertyName] = childProperty.value;
- });
-
- return propertyValue;
- };
-
- var xmlReadODataCollectionPropertyValue = function (domElement, propertyType, propertyMetadata) {
- /// <summary>Reads the value of a collection property in an OData XML document.</summary>
- /// <param name="property">DOM element for the collection property.</param>
- /// <param name="propertyType" type="String">Property type name.</param>
- /// <param name="propertyMetadata" type="Object">Object that will store metadata about the property.</param>
- /// <returns type="Object">Collection property value.</returns>
-
- var items = [];
- var itemsMetadata = propertyMetadata.elements = [];
- var collectionType = getCollectionType(propertyType);
-
- xmlChildElements(domElement, function (child) {
- if (isCollectionItemElement(child)) {
- var itemAttributes = xmlReadODataPropertyAttributes(child);
- var itemExtensions = itemAttributes.extensions;
- var itemType = itemAttributes.type || collectionType;
- var itemMetadata = makePropertyMetadata(itemType, itemExtensions);
-
- var item = xmlReadODataPropertyValue(child, itemType, itemMetadata);
-
- items.push(item);
- itemsMetadata.push(itemMetadata);
- }
- });
-
- return { __metadata: { type: propertyType === "Collection()" ? null : propertyType }, results: items };
- };
-
- var readODataXmlDocument = function (xmlRoot, baseURI) {
- /// <summary>Reads an OData link(s) producing an object model in return.</summary>
- /// <param name="xmlRoot">Top-level element to read.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the XML payload.</param>
- /// <returns type="Object">The object model representing the specified element.</returns>
-
- if (xmlNamespaceURI(xmlRoot) === odataXmlNs) {
- baseURI = xmlBaseURI(xmlRoot, baseURI);
- var localName = xmlLocalName(xmlRoot);
-
- if (localName === "links") {
- return readLinks(xmlRoot, baseURI);
- }
- if (localName === "uri") {
- return readUri(xmlRoot, baseURI);
- }
- }
- return undefined;
- };
-
- var readLinks = function (linksElement, baseURI) {
- /// <summary>Deserializes an OData XML links element.</summary>
- /// <param name="linksElement">XML links element.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the XML payload.</param>
- /// <returns type="Object">A new object representing the links collection.</returns>
-
- var uris = [];
-
- xmlChildElements(linksElement, function (child) {
- if (xmlLocalName(child) === "uri" && xmlNamespaceURI(child) === odataXmlNs) {
- uris.push(readUri(child, baseURI));
- }
- });
-
- return { results: uris };
- };
-
- var readUri = function (uriElement, baseURI) {
- /// <summary>Deserializes an OData XML uri element.</summary>
- /// <param name="uriElement">XML uri element.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the XML payload.</param>
- /// <returns type="Object">A new object representing the uri.</returns>
-
- var uri = xmlInnerText(uriElement) || "";
- return { uri: normalizeURI(uri, baseURI) };
- };
-
- var xmlODataInferSpatialValueGeoJsonType = function (value, edmType) {
- /// <summary>Infers the GeoJSON type from the spatial property value and the edm type name.</summary>
- /// <param name="value" type="Object">Spatial property value in GeoJSON format.</param>
- /// <param name="edmType" type="String" mayBeNull="true" optional="true">Spatial property edm type.<param>
- /// <remarks>
- /// If the edmType parameter is null, undefined, "Edm.Geometry" or "Edm.Geography", then the function returns
- /// the GeoJSON type indicated by the value's type property.
- ///
- /// If the edmType parameter is specified or is not one of the base spatial types, then it is used to
- /// determine the GeoJSON type and the value's type property is ignored.
- /// </remarks>
- /// <returns>New DOM element in the GML namespace for the spatial value. </returns>
-
- if (edmType === EDM_GEOMETRY || edmType === EDM_GEOGRAPHY) {
- return value && value.type;
- }
-
- if (edmType === EDM_GEOMETRY_POINT || edmType === EDM_GEOGRAPHY_POINT) {
- return GEOJSON_POINT;
- }
-
- if (edmType === EDM_GEOMETRY_LINESTRING || edmType === EDM_GEOGRAPHY_LINESTRING) {
- return GEOJSON_LINESTRING;
- }
-
- if (edmType === EDM_GEOMETRY_POLYGON || edmType === EDM_GEOGRAPHY_POLYGON) {
- return GEOJSON_POLYGON;
- }
-
- if (edmType === EDM_GEOMETRY_COLLECTION || edmType === EDM_GEOGRAPHY_COLLECTION) {
- return GEOJSON_GEOMETRYCOLLECTION;
- }
-
- if (edmType === EDM_GEOMETRY_MULTIPOLYGON || edmType === EDM_GEOGRAPHY_MULTIPOLYGON) {
- return GEOJSON_MULTIPOLYGON;
- }
-
- if (edmType === EDM_GEOMETRY_MULTILINESTRING || edmType === EDM_GEOGRAPHY_MULTILINESTRING) {
- return GEOJSON_MULTILINESTRING;
- }
-
- if (edmType === EDM_GEOMETRY_MULTIPOINT || edmType === EDM_GEOGRAPHY_MULTIPOINT) {
- return GEOJSON_MULTIPOINT;
- }
-
- djsassert(false, "gmlInferGeoJsonType - edm type <" + edmType + "> was unexpected!!");
- return null;
- };
-
- var xmlNewODataMetaElement = function (dom, name, children) {
- /// <summary>Creates a new DOM element in the OData metadata namespace.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="name" type="String">Local name of the OData metadata element to create.</param>
- /// <param name="children" type="Array">Array containing DOM nodes or string values that will be added as children of the new DOM element.</param>
- /// <returns>New DOM element in the OData metadata namespace.</returns>
- /// <remarks>
- /// If a value in the children collection is a string, then a new DOM text node is going to be created
- /// for it and then appended as a child of the new DOM Element.
- /// </remarks>
-
- return xmlNewElement(dom, odataMetaXmlNs, xmlQualifiedName(odataMetaPrefix, name), children);
- };
-
- var xmlNewODataMetaAttribute = function (dom, name, value) {
- /// <summary>Creates a new DOM attribute in the odata namespace.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="name" type="String">Local name of the OData attribute to create.</param>
- /// <param name="value">Attribute value.</param>
- /// <returns>New DOM attribute in the odata namespace.</returns>
-
- return xmlNewAttribute(dom, odataMetaXmlNs, xmlQualifiedName(odataMetaPrefix, name), value);
- };
-
- var xmlNewODataElement = function (dom, name, children) {
- /// <summary>Creates a new DOM element in the OData namespace.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="name" type="String">Local name of the OData element to create.</param>
- /// <param name="children" type="Array">Array containing DOM nodes or string values that will be added as children of the new DOM element.</param>
- /// <returns>New DOM element in the OData namespace.</returns>
- /// <remarks>
- /// If a value in the children collection is a string, then a new DOM text node is going to be created
- /// for it and then appended as a child of the new DOM Element.
- /// </remarks>
-
- return xmlNewElement(dom, odataXmlNs, xmlQualifiedName(odataPrefix, name), children);
- };
-
- var xmlNewODataPrimitiveValue = function (value, typeName) {
- /// <summary>Returns the string representation of primitive value for an OData XML document.</summary>
- /// <param name="value">Primivite value to format.</param>
- /// <param name="typeName" type="String" optional="true">Type name of the primitive value.</param>
- /// <returns type="String">Formatted primitive value.</returns>
-
- if (typeName === EDM_DATETIME || typeName === EDM_DATETIMEOFFSET || isDate(value)) {
- return formatDateTimeOffset(value);
- }
- if (typeName === EDM_TIME) {
- return formatDuration(value);
- }
- return value.toString();
- };
-
- var xmlNewODataElementInfo = function (domElement, dataServiceVersion) {
- /// <summary>Creates an object that represents a new DOM element for an OData XML document and the data service version it requires.</summary>
- /// <param name="domElement">New DOM element for an OData XML document.</param>
- /// <param name="dataServiceVersion" type="String">Required data service version by the new DOM element.</param>
- /// <returns type="Object">Object containing new DOM element and its required data service version.</returns>
-
- return { element: domElement, dsv: dataServiceVersion };
- };
-
- var xmlNewODataProperty = function (dom, name, typeName, children) {
- /// <summary>Creates a new DOM element for an entry property in an OData XML document.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="name" type="String">Property name.</param>
- /// <param name="typeName" type="String" optional="true">Property type name.</param>
- /// <param name="children" type="Array">Array containing DOM nodes or string values that will be added as children of the new DOM element.</param>
- /// <remarks>
- /// If a value in the children collection is a string, then a new DOM text node is going to be created
- /// for it and then appended as a child of the new DOM Element.
- /// </remarks>
- /// <returns>New DOM element in the OData namespace for the entry property.</returns>
-
- var typeAttribute = typeName ? xmlNewODataMetaAttribute(dom, "type", typeName) : null;
- var property = xmlNewODataElement(dom, name, typeAttribute);
- return xmlAppendChildren(property, children);
- };
-
- var xmlNewODataEdmProperty = function (dom, name, value, typeName) {
- /// <summary>Creates a new DOM element for an EDM property in an OData XML document.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="name" type="String">Property name.</param>
- /// <param name="value">Property value.</param>
- /// <param name="typeName" type="String" optional="true">Property type name.</param>
- /// <returns type="Object">
- /// Object containing the new DOM element in the OData namespace for the EDM property and the
- /// required data service version for this property.
- /// </returns>
-
- var propertyValue = xmlNewODataPrimitiveValue(value, typeName);
- var property = xmlNewODataProperty(dom, name, typeName, propertyValue);
- return xmlNewODataElementInfo(property, /*dataServiceVersion*/"1.0");
- };
-
- var xmlNewODataNullProperty = function (dom, name, typeName, model) {
- /// <summary>Creates a new DOM element for a null property in an OData XML document.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="name" type="String">Property name.</param>
- /// <param name="typeName" type="String" optional="true">Property type name.</param>
- /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
- /// <remarks>
- /// If no typeName is specified, then it will be assumed that this is a primitive type property.
- /// </remarks>
- /// <returns type="Object">
- /// Object containing the new DOM element in the OData namespace for the null property and the
- /// required data service version for this property.
- /// </returns>
-
- var nullAttribute = xmlNewODataMetaAttribute(dom, "null", "true");
- var property = xmlNewODataProperty(dom, name, typeName, nullAttribute);
- var dataServiceVersion = lookupComplexType(typeName, model) ? "2.0" : "1.0";
-
- return xmlNewODataElementInfo(property, dataServiceVersion);
- };
-
- var xmlNewODataCollectionProperty = function (dom, name, value, typeName, collectionMetadata, collectionModel, model) {
- /// <summary>Creates a new DOM element for a collection property in an OData XML document.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="name" type="String">Property name.</param>
- /// <param name="value">Property value either as an array or an object representing a collection in the library's internal representation.</param>
- /// <param name="typeName" type="String" optional="true">Property type name.</param>
- /// <param name="collectionMetadata" type="Object" optional="true">Object containing metadata about the collection property.</param>
- /// <param name="collectionModel" type="Object" optional="true">Object describing the collection property in an OData conceptual schema.</param>
- /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
- /// <returns type="Object">
- /// Object containing the new DOM element in the OData namespace for the collection property and the
- /// required data service version for this property.
- /// </returns>
-
- var itemTypeName = getCollectionType(typeName);
- var items = isArray(value) ? value : value.results;
- var itemMetadata = typeName ? { type: itemTypeName} : {};
- itemMetadata.properties = collectionMetadata.properties;
-
- var xmlProperty = xmlNewODataProperty(dom, name, itemTypeName ? typeName : null);
-
- var i, len;
- for (i = 0, len = items.length; i < len; i++) {
- var itemValue = items[i];
- var item = xmlNewODataDataElement(dom, "element", itemValue, itemMetadata, collectionModel, model);
-
- xmlAppendChild(xmlProperty, item.element);
- }
- return xmlNewODataElementInfo(xmlProperty, /*dataServiceVersion*/"3.0");
- };
-
- var xmlNewODataComplexProperty = function (dom, name, value, typeName, propertyMetadata, propertyModel, model) {
- /// <summary>Creates a new DOM element for a complex type property in an OData XML document.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="name" type="String">Property name.</param>
- /// <param name="value">Property value as an object in the library's internal representation.</param>
- /// <param name="typeName" type="String" optional="true">Property type name.</param>
- /// <param name="propertyMetadata" type="Object" optional="true">Object containing metadata about the complex type property.</param>
- /// <param name="propertyModel" type="Object" optional="true">Object describing the complex type property in an OData conceptual schema.</param>
- /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
- /// <returns type="Object">
- /// Object containing the new DOM element in the OData namespace for the complex type property and the
- /// required data service version for this property.
- /// </returns>
-
- var xmlProperty = xmlNewODataProperty(dom, name, typeName);
- var complexTypePropertiesMetadata = propertyMetadata.properties || {};
- var complexTypeModel = lookupComplexType(typeName, model) || {};
-
- var dataServiceVersion = "1.0";
-
- for (var key in value) {
- if (key !== "__metadata") {
- var memberValue = value[key];
- var memberModel = lookupProperty(complexTypeModel.property, key);
- var memberMetadata = complexTypePropertiesMetadata[key] || {};
- var member = xmlNewODataDataElement(dom, key, memberValue, memberMetadata, memberModel, model);
-
- dataServiceVersion = maxVersion(dataServiceVersion, member.dsv);
- xmlAppendChild(xmlProperty, member.element);
- }
- }
- return xmlNewODataElementInfo(xmlProperty, dataServiceVersion);
- };
-
- var xmlNewODataSpatialProperty = function (dom, name, value, typeName, isGeography) {
- /// <summary>Creates a new DOM element for an EDM spatial property in an OData XML document.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="name" type="String">Property name.</param>
- /// <param name="value" type="Object">GeoJSON object containing the property value.</param>
- /// <param name="typeName" type="String" optional="true">Property type name.</param>
- /// <returns type="Object">
- /// Object containing the new DOM element in the OData namespace for the EDM property and the
- /// required data service version for this property.
- /// </returns>
-
- var geoJsonType = xmlODataInferSpatialValueGeoJsonType(value, typeName);
-
- var gmlRoot = gmlNewODataSpatialValue(dom, value, geoJsonType, isGeography);
- var xmlProperty = xmlNewODataProperty(dom, name, typeName, gmlRoot);
-
- return xmlNewODataElementInfo(xmlProperty, "3.0");
- };
-
- var xmlNewODataDataElement = function (dom, name, value, dataItemMetadata, dataItemModel, model) {
- /// <summary>Creates a new DOM element for a data item in an entry, complex property, or collection property.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="name" type="String">Data item name.</param>
- /// <param name="value" optional="true" mayBeNull="true">Value of the data item, if any.</param>
- /// <param name="dataItemMetadata" type="Object" optional="true">Object containing metadata about the data item.</param>
- /// <param name="dataItemModel" type="Object" optional="true">Object describing the data item in an OData conceptual schema.</param>
- /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
- /// <returns type="Object">
- /// Object containing the new DOM element in the appropriate namespace for the data item and the
- /// required data service version for it.
- /// </returns>
-
- var typeName = dataItemTypeName(value, dataItemMetadata, dataItemModel);
- if (isPrimitive(value)) {
- return xmlNewODataEdmProperty(dom, name, value, typeName || EDM_STRING);
- }
-
- var isGeography = isGeographyEdmType(typeName);
- if (isGeography || isGeometryEdmType(typeName)) {
- return xmlNewODataSpatialProperty(dom, name, value, typeName, isGeography);
- }
-
- if (isCollection(value, typeName)) {
- return xmlNewODataCollectionProperty(dom, name, value, typeName, dataItemMetadata, dataItemModel, model);
- }
-
- if (isNamedStream(value)) {
- return null;
- }
-
- // This may be a navigation property.
- var navPropKind = navigationPropertyKind(value, dataItemModel);
- if (navPropKind !== null) {
- return null;
- }
-
- if (value === null) {
- return xmlNewODataNullProperty(dom, name, typeName);
- }
-
- djsassert(isObject(value), "xmlNewODataEntryProperty - property '" + name + "' is not an object");
- return xmlNewODataComplexProperty(dom, name, value, typeName, dataItemMetadata, dataItemModel, model);
- };
-
- var odataNewLinkDocument = function (data) {
- /// <summary>Writes the specified data into an OData XML document.</summary>
- /// <param name="data">Data to write.</param>
- /// <returns>The root of the DOM tree built.</returns>
-
- if (data && isObject(data)) {
- var dom = xmlDom();
- return xmlAppendChild(dom, xmlNewODataElement(dom, "uri", data.uri));
- }
- // Allow for undefined to be returned.
- };
-
- var xmlParser = function (handler, text) {
- /// <summary>Parses an OData XML document.</summary>
- /// <param name="handler">This handler.</param>
- /// <param name="text" type="String">Document text.</param>
- /// <returns>An object representation of the document; undefined if not applicable.</returns>
-
- if (text) {
- var doc = xmlParse(text);
- var root = xmlFirstChildElement(doc);
- if (root) {
- return readODataXmlDocument(root);
- }
- }
-
- // Allow for undefined to be returned.
- };
-
- var xmlSerializer = function (handler, data, context) {
- /// <summary>Serializes an OData XML object into a document.</summary>
- /// <param name="handler">This handler.</param>
- /// <param name="data" type="Object">Representation of feed or entry.</param>
- /// <param name="context" type="Object">Object with parsing context.</param>
- /// <returns>A text representation of the data object; undefined if not applicable.</returns>
-
- var cType = context.contentType = context.contentType || contentType(xmlMediaType);
- if (cType && cType.mediaType === xmlMediaType) {
- return xmlSerialize(odataNewLinkDocument(data));
- }
- return undefined;
- };
-
- odata.xmlHandler = handler(xmlParser, xmlSerializer, xmlMediaType, MAX_DATA_SERVICE_VERSION);
-
- // DATAJS INTERNAL START
- odata.adoDs = adoDs;
- odata.createAttributeExtension = createAttributeExtension;
- odata.createElementExtension = createElementExtension;
- odata.edmxNs = edmxNs;
- odata.edmNs1 = edmNs1;
- odata.edmNs1_1 = edmNs1_1;
- odata.edmNs1_2 = edmNs1_2
- odata.edmNs2a = edmNs2a;
- odata.edmNs2b = edmNs2b;
- odata.edmNs3 = edmNs3;
- odata.odataMetaXmlNs = odataMetaXmlNs;
- odata.odataMetaPrefix = odataMetaPrefix;
- odata.odataXmlNs = odataXmlNs;
- odata.odataPrefix = odataPrefix;
- odata.odataScheme = odataScheme;
- odata.odataRelatedPrefix = odataRelatedPrefix;
- odata.xmlNewODataElement = xmlNewODataElement;
- odata.xmlNewODataElementInfo = xmlNewODataElementInfo;
- odata.xmlNewODataMetaAttribute = xmlNewODataMetaAttribute;
- odata.xmlNewODataMetaElement = xmlNewODataMetaElement;
- odata.xmlNewODataDataElement = xmlNewODataDataElement;
- odata.xmlReadODataEdmPropertyValue = xmlReadODataEdmPropertyValue;
- odata.xmlReadODataProperty = xmlReadODataProperty;
-
- // DATAJS INTERNAL END
-
- // CONTENT END
-})(this);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/odata.js
----------------------------------------------------------------------
diff --git a/datajs/src/odata.js b/datajs/src/odata.js
deleted file mode 100644
index 98b80e2..0000000
--- a/datajs/src/odata.js
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
-// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// odata.js
-
-(function (window, undefined) {
-
- var datajs = window.datajs || {};
- var odata = window.OData || {};
-
- // Imports
-
- var assigned = datajs.assigned;
- var defined = datajs.defined;
- var throwErrorCallback = datajs.throwErrorCallback;
-
- var invokeRequest = odata.invokeRequest;
- var MAX_DATA_SERVICE_VERSION = odata.MAX_DATA_SERVICE_VERSION;
- var prepareRequest = odata.prepareRequest;
- var metadataParser = odata.metadataParser;
-
- // CONTENT START
-
- var handlers = [odata.jsonHandler, odata.atomHandler, odata.xmlHandler, odata.textHandler];
-
- var dispatchHandler = function (handlerMethod, requestOrResponse, context) {
- /// <summary>Dispatches an operation to handlers.</summary>
- /// <param name="handlerMethod" type="String">Name of handler method to invoke.</param>
- /// <param name="requestOrResponse" type="Object">request/response argument for delegated call.</param>
- /// <param name="context" type="Object">context argument for delegated call.</param>
-
- var i, len;
- for (i = 0, len = handlers.length; i < len && !handlers[i][handlerMethod](requestOrResponse, context); i++) {
- }
-
- if (i === len) {
- throw { message: "no handler for data" };
- }
- };
-
- odata.defaultSuccess = function (data) {
- /// <summary>Default success handler for OData.</summary>
- /// <param name="data">Data to process.</param>
-
- window.alert(window.JSON.stringify(data));
- };
-
- odata.defaultError = throwErrorCallback;
-
- odata.defaultHandler = {
- read: function (response, context) {
- /// <summary>Reads the body of the specified response by delegating to JSON and ATOM handlers.</summary>
- /// <param name="response">Response object.</param>
- /// <param name="context">Operation context.</param>
-
- if (response && assigned(response.body) && response.headers["Content-Type"]) {
- dispatchHandler("read", response, context);
- }
- },
-
- write: function (request, context) {
- /// <summary>Write the body of the specified request by delegating to JSON and ATOM handlers.</summary>
- /// <param name="request">Reques tobject.</param>
- /// <param name="context">Operation context.</param>
-
- dispatchHandler("write", request, context);
- },
-
- maxDataServiceVersion: MAX_DATA_SERVICE_VERSION,
- accept: "application/atomsvc+xml;q=0.8, application/json;odata=fullmetadata;q=0.7, application/json;q=0.5, */*;q=0.1"
- };
-
- odata.defaultMetadata = [];
-
- odata.read = function (urlOrRequest, success, error, handler, httpClient, metadata) {
- /// <summary>Reads data from the specified URL.</summary>
- /// <param name="urlOrRequest">URL to read data from.</param>
- /// <param name="success" type="Function" optional="true">Callback for a successful read operation.</param>
- /// <param name="error" type="Function" optional="true">Callback for handling errors.</param>
- /// <param name="handler" type="Object" optional="true">Handler for data serialization.</param>
- /// <param name="httpClient" type="Object" optional="true">HTTP client layer.</param>
- /// <param name="metadata" type="Object" optional="true">Conceptual metadata for this request.</param>
-
- var request;
- if (urlOrRequest instanceof String || typeof urlOrRequest === "string") {
- request = { requestUri: urlOrRequest };
- } else {
- request = urlOrRequest;
- }
-
- return odata.request(request, success, error, handler, httpClient, metadata);
- };
-
- odata.request = function (request, success, error, handler, httpClient, metadata) {
- /// <summary>Sends a request containing OData payload to a server.</summary>
- /// <param name="request" type="Object">Object that represents the request to be sent.</param>
- /// <param name="success" type="Function" optional="true">Callback for a successful read operation.</param>
- /// <param name="error" type="Function" optional="true">Callback for handling errors.</param>
- /// <param name="handler" type="Object" optional="true">Handler for data serialization.</param>
- /// <param name="httpClient" type="Object" optional="true">HTTP client layer.</param>
- /// <param name="metadata" type="Object" optional="true">Conceptual metadata for this request.</param>
-
- success = success || odata.defaultSuccess;
- error = error || odata.defaultError;
- handler = handler || odata.defaultHandler;
- httpClient = httpClient || odata.defaultHttpClient;
- metadata = metadata || odata.defaultMetadata;
-
- // Augment the request with additional defaults.
- request.recognizeDates = defined(request.recognizeDates, odata.jsonHandler.recognizeDates);
- request.callbackParameterName = defined(request.callbackParameterName, odata.defaultHttpClient.callbackParameterName);
- request.formatQueryString = defined(request.formatQueryString, odata.defaultHttpClient.formatQueryString);
- request.enableJsonpCallback = defined(request.enableJsonpCallback, odata.defaultHttpClient.enableJsonpCallback);
- request.useJsonLight = defined(request.useJsonLight, odata.jsonHandler.enableJsonpCallback);
- request.inferJsonLightFeedAsObject = defined(request.inferJsonLightFeedAsObject, odata.jsonHandler.inferJsonLightFeedAsObject);
-
- // Create the base context for read/write operations, also specifying complete settings.
- var context = {
- metadata: metadata,
- recognizeDates: request.recognizeDates,
- callbackParameterName: request.callbackParameterName,
- formatQueryString: request.formatQueryString,
- enableJsonpCallback: request.enableJsonpCallback,
- useJsonLight: request.useJsonLight,
- inferJsonLightFeedAsObject: request.inferJsonLightFeedAsObject
- };
-
- try {
- prepareRequest(request, handler, context);
- return invokeRequest(request, success, error, handler, httpClient, context);
- } catch (err) {
- error(err);
- }
- };
-
- odata.parseMetadata = function (csdlMetadataDocument) {
- /// <summary>Parses the csdl metadata to DataJS metatdata format. This method can be used when the metadata is retrieved using something other than DataJS</summary>
- /// <param name="atomMetadata" type="string">A string that represents the entire csdl metadata.</param>
- /// <returns type="Object">An object that has the representation of the metadata in Datajs format.</returns>
-
- return metadataParser(null, csdlMetadataDocument);
- };
-
- // Configure the batch handler to use the default handler for the batch parts.
- odata.batchHandler.partHandler = odata.defaultHandler;
-
- // CONTENT END
-})(this);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/store-dom.js
----------------------------------------------------------------------
diff --git a/datajs/src/store-dom.js b/datajs/src/store-dom.js
deleted file mode 100644
index bf8a887..0000000
--- a/datajs/src/store-dom.js
+++ /dev/null
@@ -1,320 +0,0 @@
-// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
-// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// store-dom.js
-
-(function (window, undefined) {
-
- var datajs = window.datajs || {};
-
- // Imports.
- var throwErrorCallback = datajs.throwErrorCallback;
- var delay = datajs.delay;
-
- // CONTENT START
-
- var localStorage = null;
-
- var domStoreDateToJSON = function () {
- /// <summary>Converts a Date object into an object representation friendly to JSON serialization.</summary>
- /// <returns type="Object">Object that represents the Date.</returns>
- /// <remarks>
- /// This method is used to override the Date.toJSON method and is called only by
- /// JSON.stringify. It should never be called directly.
- /// </remarks>
-
- var newValue = { v: this.valueOf(), t: "[object Date]" };
- // Date objects might have extra properties on them so we save them.
- for (var name in this) {
- newValue[name] = this[name];
- }
- return newValue;
- };
-
- var domStoreJSONToDate = function (_, value) {
- /// <summary>JSON reviver function for converting an object representing a Date in a JSON stream to a Date object</summary>
- /// <param value="Object">Object to convert.</param>
- /// <returns type="Date">Date object.</returns>
- /// <remarks>
- /// This method is used during JSON parsing and invoked only by the reviver function.
- /// It should never be called directly.
- /// </remarks>
-
- if (value && value.t === "[object Date]") {
- var newValue = new Date(value.v);
- for (var name in value) {
- if (name !== "t" && name !== "v") {
- newValue[name] = value[name];
- }
- }
- value = newValue;
- }
- return value;
- };
-
- var qualifyDomStoreKey = function (store, key) {
- /// <summary>Qualifies the key with the name of the store.</summary>
- /// <param name="store" type="Object">Store object whose name will be used for qualifying the key.</param>
- /// <param name="key" type="String">Key string.</param>
- /// <returns type="String">Fully qualified key string.</returns>
-
- return store.name + "#!#" + key;
- };
-
- var unqualifyDomStoreKey = function (store, key) {
- /// <summary>Gets the key part of a fully qualified key string.</summary>
- /// <param name="store" type="Object">Store object whose name will be used for qualifying the key.</param>
- /// <param name="key" type="String">Fully qualified key string.</param>
- /// <returns type="String">Key part string</returns>
-
- return key.replace(store.name + "#!#", "");
- };
-
- var DomStore = function (name) {
- /// <summary>Constructor for store objects that use DOM storage as the underlying mechanism.</summary>
- /// <param name="name" type="String">Store name.</param>
- this.name = name;
- };
-
- DomStore.create = function (name) {
- /// <summary>Creates a store object that uses DOM Storage as its underlying mechanism.</summary>
- /// <param name="name" type="String">Store name.</param>
- /// <returns type="Object">Store object.</returns>
-
- if (DomStore.isSupported()) {
- localStorage = localStorage || window.localStorage;
- return new DomStore(name);
- }
-
- throw { message: "Web Storage not supported by the browser" };
- };
-
- DomStore.isSupported = function () {
- /// <summary>Checks whether the underlying mechanism for this kind of store objects is supported by the browser.</summary>
- /// <returns type="Boolean">True if the mechanism is supported by the browser; otherwise false.</summary>
- return !!window.localStorage;
- };
-
- DomStore.prototype.add = function (key, value, success, error) {
- /// <summary>Adds a new value identified by a key to the store.</summary>
- /// <param name="key" type="String">Key string.</param>
- /// <param name="value">Value that is going to be added to the store.</param>
- /// <param name="success" type="Function" optional="no">Callback for a successful add operation.</param>
- /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
- /// <remarks>
- /// This method errors out if the store already contains the specified key.
- /// </remarks>
-
- error = error || this.defaultError;
- var store = this;
- this.contains(key, function (contained) {
- if (!contained) {
- store.addOrUpdate(key, value, success, error);
- } else {
- delay(error, { message: "key already exists", key: key });
- }
- }, error);
- };
-
- DomStore.prototype.addOrUpdate = function (key, value, success, error) {
- /// <summary>Adds or updates a value identified by a key to the store.</summary>
- /// <param name="key" type="String">Key string.</param>
- /// <param name="value">Value that is going to be added or updated to the store.</param>
- /// <param name="success" type="Function" optional="no">Callback for a successful add or update operation.</param>
- /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
- /// <remarks>
- /// This method will overwrite the key's current value if it already exists in the store; otherwise it simply adds the new key and value.
- /// </remarks>
-
- error = error || this.defaultError;
-
- if (key instanceof Array) {
- error({ message: "Array of keys not supported" });
- } else {
- var fullKey = qualifyDomStoreKey(this, key);
- var oldDateToJSON = Date.prototype.toJSON;
- try {
- var storedValue = value;
- if (storedValue !== undefined) {
- // Dehydrate using json
- Date.prototype.toJSON = domStoreDateToJSON;
- storedValue = window.JSON.stringify(value);
- }
- // Save the json string.
- localStorage.setItem(fullKey, storedValue);
- delay(success, key, value);
- }
- catch (e) {
- if (e.code === 22 || e.number === 0x8007000E) {
- delay(error, { name: "QUOTA_EXCEEDED_ERR", error: e });
- } else {
- delay(error, e);
- }
- }
- finally {
- Date.prototype.toJSON = oldDateToJSON;
- }
- }
- };
-
- DomStore.prototype.clear = function (success, error) {
- /// <summary>Removes all the data associated with this store object.</summary>
- /// <param name="success" type="Function" optional="no">Callback for a successful clear operation.</param>
- /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
- /// <remarks>
- /// In case of an error, this method will not restore any keys that might have been deleted at that point.
- /// </remarks>
-
- error = error || this.defaultError;
- try {
- var i = 0, len = localStorage.length;
- while (len > 0 && i < len) {
- var fullKey = localStorage.key(i);
- var key = unqualifyDomStoreKey(this, fullKey);
- if (fullKey !== key) {
- localStorage.removeItem(fullKey);
- len = localStorage.length;
- } else {
- i++;
- }
- }
- delay(success);
- }
- catch (e) {
- delay(error, e);
- }
- };
-
- DomStore.prototype.close = function () {
- /// <summary>This function does nothing in DomStore as it does not have a connection model</summary>
- };
-
- DomStore.prototype.contains = function (key, success, error) {
- /// <summary>Checks whether a key exists in the store.</summary>
- /// <param name="key" type="String">Key string.</param>
- /// <param name="success" type="Function" optional="no">Callback indicating whether the store contains the key or not.</param>
- /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
- error = error || this.defaultError;
- try {
- var fullKey = qualifyDomStoreKey(this, key);
- var value = localStorage.getItem(fullKey);
- delay(success, value !== null);
- } catch (e) {
- delay(error, e);
- }
- };
-
- DomStore.prototype.defaultError = throwErrorCallback;
-
- DomStore.prototype.getAllKeys = function (success, error) {
- /// <summary>Gets all the keys that exist in the store.</summary>
- /// <param name="success" type="Function" optional="no">Callback for a successful get operation.</param>
- /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
-
- error = error || this.defaultError;
-
- var results = [];
- var i, len;
-
- try {
- for (i = 0, len = localStorage.length; i < len; i++) {
- var fullKey = localStorage.key(i);
- var key = unqualifyDomStoreKey(this, fullKey);
- if (fullKey !== key) {
- results.push(key);
- }
- }
- delay(success, results);
- }
- catch (e) {
- delay(error, e);
- }
- };
-
- /// <summary>Identifies the underlying mechanism used by the store.</summary>
- DomStore.prototype.mechanism = "dom";
-
- DomStore.prototype.read = function (key, success, error) {
- /// <summary>Reads the value associated to a key in the store.</summary>
- /// <param name="key" type="String">Key string.</param>
- /// <param name="success" type="Function" optional="no">Callback for a successful reads operation.</param>
- /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
- error = error || this.defaultError;
-
- if (key instanceof Array) {
- error({ message: "Array of keys not supported" });
- } else {
- try {
- var fullKey = qualifyDomStoreKey(this, key);
- var value = localStorage.getItem(fullKey);
- if (value !== null && value !== "undefined") {
- // Hydrate using json
- value = window.JSON.parse(value, domStoreJSONToDate);
- }
- else {
- value = undefined;
- }
- delay(success, key, value);
- } catch (e) {
- delay(error, e);
- }
- }
- };
-
- DomStore.prototype.remove = function (key, success, error) {
- /// <summary>Removes a key and its value from the store.</summary>
- /// <param name="key" type="String">Key string.</param>
- /// <param name="success" type="Function" optional="no">Callback for a successful remove operation.</param>
- /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
- error = error || this.defaultError;
-
- if (key instanceof Array) {
- error({ message: "Batches not supported" });
- } else {
- try {
- var fullKey = qualifyDomStoreKey(this, key);
- localStorage.removeItem(fullKey);
- delay(success);
- } catch (e) {
- delay(error, e);
- }
- }
- };
-
- DomStore.prototype.update = function (key, value, success, error) {
- /// <summary>Updates the value associated to a key in the store.</summary>
- /// <param name="key" type="String">Key string.</param>
- /// <param name="value">New value.</param>
- /// <param name="success" type="Function" optional="no">Callback for a successful update operation.</param>
- /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
- /// <remarks>
- /// This method errors out if the specified key is not found in the store.
- /// </remarks>
-
- error = error || this.defaultError;
- var store = this;
- this.contains(key, function (contained) {
- if (contained) {
- store.addOrUpdate(key, value, success, error);
- } else {
- delay(error, { message: "key not found", key: key });
- }
- }, error);
- };
-
- // DATAJS INTERNAL START
- datajs.DomStore = DomStore;
- // DATAJS INTERNAL END
-
- // CONTENT END
-})(this);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/store-indexeddb.js
----------------------------------------------------------------------
diff --git a/datajs/src/store-indexeddb.js b/datajs/src/store-indexeddb.js
deleted file mode 100644
index b56828f..0000000
--- a/datajs/src/store-indexeddb.js
+++ /dev/null
@@ -1,417 +0,0 @@
-// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
-// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// store-indexeddb.js
-
-(function (window, undefined) {
-
- var datajs = window.datajs || {};
-
- // Imports.
- var throwErrorCallback = datajs.throwErrorCallback;
- var delay = datajs.delay;
-
- // CONTENT START
-
- var indexedDB = window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB || window.indexedDB;
- var IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange;
- var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || {};
-
- var IDBT_READ_ONLY = IDBTransaction.READ_ONLY || "readonly";
- var IDBT_READ_WRITE = IDBTransaction.READ_WRITE || "readwrite";
-
- var getError = function (error, defaultError) {
- /// <summary>Returns either a specific error handler or the default error handler</summary>
- /// <param name="error" type="Function">The specific error handler</param>
- /// <param name="defaultError" type="Function">The default error handler</param>
- /// <returns type="Function">The error callback</returns>
-
- return function (e) {
- var errorFunc = error || defaultError;
- if (!errorFunc) {
- return;
- }
-
- // Old api quota exceeded error support.
- if (Object.prototype.toString.call(e) === "[object IDBDatabaseException]") {
- if (e.code === 11 /* IndexedDb disk quota exceeded */) {
- errorFunc({ name: "QuotaExceededError", error: e });
- return;
- }
- errorFunc(e);
- return;
- }
-
- var errName;
- try {
- var errObj = e.target.error || e;
- errName = errObj.name;
- } catch (ex) {
- errName = (e.type === "blocked") ? "IndexedDBBlocked" : "UnknownError";
- }
- errorFunc({ name: errName, error: e });
- };
- };
-
- var openStoreDb = function (store, success, error) {
- /// <summary>Opens the store object's indexed db database.</summary>
- /// <param name="store" type="IndexedDBStore">The store object</param>
- /// <param name="success" type="Function">The success callback</param>
- /// <param name="error" type="Function">The error callback</param>
-
- var storeName = store.name;
- var dbName = "_datajs_" + storeName;
-
- var request = indexedDB.open(dbName);
- request.onblocked = error;
- request.onerror = error;
-
- request.onupgradeneeded = function () {
- var db = request.result;
- if (!db.objectStoreNames.contains(storeName)) {
- db.createObjectStore(storeName);
- }
- };
-
- request.onsuccess = function (event) {
- var db = request.result;
- if (!db.objectStoreNames.contains(storeName)) {
- // Should we use the old style api to define the database schema?
- if ("setVersion" in db) {
- var versionRequest = db.setVersion("1.0");
- versionRequest.onsuccess = function () {
- var transaction = versionRequest.transaction;
- transaction.oncomplete = function () {
- success(db);
- };
- db.createObjectStore(storeName, null, false);
- };
- versionRequest.onerror = error;
- versionRequest.onblocked = error;
- return;
- }
-
- // The database doesn't have the expected store.
- // Fabricate an error object for the event for the schema mismatch
- // and error out.
- event.target.error = { name: "DBSchemaMismatch" };
- error(event);
- return;
- }
-
- db.onversionchange = function(event) {
- event.target.close();
- };
- success(db);
- };
- };
-
- var openTransaction = function (store, mode, success, error) {
- /// <summary>Opens a new transaction to the store</summary>
- /// <param name="store" type="IndexedDBStore">The store object</param>
- /// <param name="mode" type="Short">The read/write mode of the transaction (constants from IDBTransaction)</param>
- /// <param name="success" type="Function">The success callback</param>
- /// <param name="error" type="Function">The error callback</param>
-
- var storeName = store.name;
- var storeDb = store.db;
- var errorCallback = getError(error, store.defaultError);
-
- if (storeDb) {
- success(storeDb.transaction(storeName, mode));
- return;
- }
-
- openStoreDb(store, function (db) {
- store.db = db;
- success(db.transaction(storeName, mode));
- }, errorCallback);
- };
-
- var IndexedDBStore = function (name) {
- /// <summary>Creates a new IndexedDBStore.</summary>
- /// <param name="name" type="String">The name of the store.</param>
- /// <returns type="Object">The new IndexedDBStore.</returns>
- this.name = name;
- };
-
- IndexedDBStore.create = function (name) {
- /// <summary>Creates a new IndexedDBStore.</summary>
- /// <param name="name" type="String">The name of the store.</param>
- /// <returns type="Object">The new IndexedDBStore.</returns>
- if (IndexedDBStore.isSupported()) {
- return new IndexedDBStore(name);
- }
-
- throw { message: "IndexedDB is not supported on this browser" };
- };
-
- IndexedDBStore.isSupported = function () {
- /// <summary>Returns whether IndexedDB is supported.</summary>
- /// <returns type="Boolean">True if IndexedDB is supported, false otherwise.</returns>
- return !!indexedDB;
- };
-
- IndexedDBStore.prototype.add = function (key, value, success, error) {
- /// <summary>Adds a key/value pair to the store</summary>
- /// <param name="key" type="String">The key</param>
- /// <param name="value" type="Object">The value</param>
- /// <param name="success" type="Function">The success callback</param>
- /// <param name="error" type="Function">The error callback</param>
- var name = this.name;
- var defaultError = this.defaultError;
- var keys = [];
- var values = [];
-
- if (key instanceof Array) {
- keys = key;
- values = value;
- } else {
- keys = [key];
- values = [value];
- }
-
- openTransaction(this, IDBT_READ_WRITE, function (transaction) {
- transaction.onabort = getError(error, defaultError, key, "add");
- transaction.oncomplete = function () {
- if (key instanceof Array) {
- success(keys, values);
- } else {
- success(key, value);
- }
- };
-
- for (var i = 0; i < keys.length && i < values.length; i++) {
- transaction.objectStore(name).add({ v: values[i] }, keys[i]);
- }
- }, error);
- };
-
- IndexedDBStore.prototype.addOrUpdate = function (key, value, success, error) {
- /// <summary>Adds or updates a key/value pair in the store</summary>
- /// <param name="key" type="String">The key</param>
- /// <param name="value" type="Object">The value</param>
- /// <param name="success" type="Function">The success callback</param>
- /// <param name="error" type="Function">The error callback</param>
- var name = this.name;
- var defaultError = this.defaultError;
- var keys = [];
- var values = [];
-
- if (key instanceof Array) {
- keys = key;
- values = value;
- } else {
- keys = [key];
- values = [value];
- }
-
- openTransaction(this, IDBT_READ_WRITE, function (transaction) {
- transaction.onabort = getError(error, defaultError);
- transaction.oncomplete = function () {
- if (key instanceof Array) {
- success(keys, values);
- } else {
- success(key, value);
- }
- };
-
- for (var i = 0; i < keys.length && i < values.length; i++) {
- var record = { v: values[i] };
- transaction.objectStore(name).put(record, keys[i]);
- }
- }, error);
- };
-
- IndexedDBStore.prototype.clear = function (success, error) {
- /// <summary>Clears the store</summary>
- /// <param name="success" type="Function">The success callback</param>
- /// <param name="error" type="Function">The error callback</param>
- var name = this.name;
- var defaultError = this.defaultError;
- openTransaction(this, IDBT_READ_WRITE, function (transaction) {
- transaction.onerror = getError(error, defaultError);
- transaction.oncomplete = function () {
- success();
- };
-
- transaction.objectStore(name).clear();
- }, error);
- };
-
- IndexedDBStore.prototype.close = function () {
- /// <summary>Closes the connection to the database</summary>
- if (this.db) {
- this.db.close();
- this.db = null;
- }
- };
-
- IndexedDBStore.prototype.contains = function (key, success, error) {
- /// <summary>Returns whether the store contains a key</summary>
- /// <param name="key" type="String">The key</param>
- /// <param name="success" type="Function">The success callback</param>
- /// <param name="error" type="Function">The error callback</param>
- var name = this.name;
- var defaultError = this.defaultError;
- openTransaction(this, IDBT_READ_ONLY, function (transaction) {
- var objectStore = transaction.objectStore(name);
- var request = objectStore["get"](key);
-
- transaction.oncomplete = function () {
- success(!!request.result);
- };
- transaction.onerror = getError(error, defaultError);
- }, error);
- };
-
- IndexedDBStore.prototype.defaultError = throwErrorCallback;
-
- IndexedDBStore.prototype.getAllKeys = function (success, error) {
- /// <summary>Gets all the keys from the store</summary>
- /// <param name="success" type="Function">The success callback</param>
- /// <param name="error" type="Function">The error callback</param>
- var name = this.name;
- var defaultError = this.defaultError;
- openTransaction(this, IDBT_READ_WRITE, function (transaction) {
- var results = [];
-
- transaction.oncomplete = function () {
- success(results);
- };
-
- var request = transaction.objectStore(name).openCursor();
-
- request.onerror = getError(error, defaultError);
- request.onsuccess = function (event) {
- var cursor = event.target.result;
- if (cursor) {
- results.push(cursor.key);
- // Some tools have issues because continue is a javascript reserved word.
- cursor["continue"].call(cursor);
- }
- };
- }, error);
- };
-
- /// <summary>Identifies the underlying mechanism used by the store.</summary>
- IndexedDBStore.prototype.mechanism = "indexeddb";
-
- IndexedDBStore.prototype.read = function (key, success, error) {
- /// <summary>Reads the value for the specified key</summary>
- /// <param name="key" type="String">The key</param>
- /// <param name="success" type="Function">The success callback</param>
- /// <param name="error" type="Function">The error callback</param>
- /// <remarks>If the key does not exist, the success handler will be called with value = undefined</remarks>
- var name = this.name;
- var defaultError = this.defaultError;
- var keys = (key instanceof Array) ? key : [key];
-
- openTransaction(this, IDBT_READ_ONLY, function (transaction) {
- var values = [];
-
- transaction.onerror = getError(error, defaultError, key, "read");
- transaction.oncomplete = function () {
- if (key instanceof Array) {
- success(keys, values);
- } else {
- success(keys[0], values[0]);
- }
- };
-
- for (var i = 0; i < keys.length; i++) {
- // Some tools have issues because get is a javascript reserved word.
- var objectStore = transaction.objectStore(name);
- var request = objectStore["get"].call(objectStore, keys[i]);
- request.onsuccess = function (event) {
- var record = event.target.result;
- values.push(record ? record.v : undefined);
- };
- }
- }, error);
- };
-
- IndexedDBStore.prototype.remove = function (key, success, error) {
- /// <summary>Removes the specified key from the store</summary>
- /// <param name="key" type="String">The key</param>
- /// <param name="success" type="Function">The success callback</param>
- /// <param name="error" type="Function">The error callback</param>
- var name = this.name;
- var defaultError = this.defaultError;
- var keys = (key instanceof Array) ? key : [key];
-
- openTransaction(this, IDBT_READ_WRITE, function (transaction) {
- transaction.onerror = getError(error, defaultError);
- transaction.oncomplete = function () {
- success();
- };
-
- for (var i = 0; i < keys.length; i++) {
- // Some tools have issues because continue is a javascript reserved word.
- var objectStore = transaction.objectStore(name);
- objectStore["delete"].call(objectStore, keys[i]);
- }
- }, error);
- };
-
- IndexedDBStore.prototype.update = function (key, value, success, error) {
- /// <summary>Updates a key/value pair in the store</summary>
- /// <param name="key" type="String">The key</param>
- /// <param name="value" type="Object">The value</param>
- /// <param name="success" type="Function">The success callback</param>
- /// <param name="error" type="Function">The error callback</param>
- var name = this.name;
- var defaultError = this.defaultError;
- var keys = [];
- var values = [];
-
- if (key instanceof Array) {
- keys = key;
- values = value;
- } else {
- keys = [key];
- values = [value];
- }
-
- openTransaction(this, IDBT_READ_WRITE, function (transaction) {
- transaction.onabort = getError(error, defaultError);
- transaction.oncomplete = function () {
- if (key instanceof Array) {
- success(keys, values);
- } else {
- success(key, value);
- }
- };
-
- for (var i = 0; i < keys.length && i < values.length; i++) {
- var request = transaction.objectStore(name).openCursor(IDBKeyRange.only(keys[i]));
- var record = { v: values[i] };
- request.pair = { key: keys[i], value: record };
- request.onsuccess = function (event) {
- var cursor = event.target.result;
- if (cursor) {
- cursor.update(event.target.pair.value);
- } else {
- transaction.abort();
- }
- };
- }
- }, error);
- };
-
- // DATAJS INTERNAL START
- datajs.IndexedDBStore = IndexedDBStore;
- // DATAJS INTERNAL END
-
- // CONTENT END
-})(this);
\ No newline at end of file
[13/15] [OLINGO-238] Build infrastructure for datajs I
Posted by ko...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/lib/datajs/utils.js
----------------------------------------------------------------------
diff --git a/datajs/src/lib/datajs/utils.js b/datajs/src/lib/datajs/utils.js
new file mode 100644
index 0000000..9c44b07
--- /dev/null
+++ b/datajs/src/lib/datajs/utils.js
@@ -0,0 +1,487 @@
+//SK name /datajs/utils.js
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// utils.js
+
+
+
+var activeXObject = function (progId) {
+ /// <summary>Creates a new ActiveXObject from the given progId.</summary>
+ /// <param name="progId" type="String" mayBeNull="false" optional="false">
+ /// ProgId string of the desired ActiveXObject.
+ /// </param>
+ /// <remarks>
+ /// This function throws whatever exception might occur during the creation
+ /// of the ActiveXObject.
+ /// </remarks>
+ /// <returns type="Object">
+ /// The ActiveXObject instance. Null if ActiveX is not supported by the
+ /// browser.
+ /// </returns>
+ if (window.ActiveXObject) {
+ return new window.ActiveXObject(progId);
+ }
+ return null;
+};
+
+var assigned = function (value) {
+ /// <summary>Checks whether the specified value is different from null and undefined.</summary>
+ /// <param name="value" mayBeNull="true" optional="true">Value to check.</param>
+ /// <returns type="Boolean">true if the value is assigned; false otherwise.</returns>
+ return value !== null && value !== undefined;
+};
+
+var contains = function (arr, item) {
+ /// <summary>Checks whether the specified item is in the array.</summary>
+ /// <param name="arr" type="Array" optional="false" mayBeNull="false">Array to check in.</param>
+ /// <param name="item">Item to look for.</param>
+ /// <returns type="Boolean">true if the item is contained, false otherwise.</returns>
+
+ var i, len;
+ for (i = 0, len = arr.length; i < len; i++) {
+ if (arr[i] === item) {
+ return true;
+ }
+ }
+
+ return false;
+};
+
+var defined = function (a, b) {
+ /// <summary>Given two values, picks the first one that is not undefined.</summary>
+ /// <param name="a">First value.</param>
+ /// <param name="b">Second value.</param>
+ /// <returns>a if it's a defined value; else b.</returns>
+ return (a !== undefined) ? a : b;
+};
+
+var delay = function (callback) {
+ /// <summary>Delays the invocation of the specified function until execution unwinds.</summary>
+ /// <param name="callback" type="Function">Callback function.</param>
+ 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);
+};
+
+// DATAJS INTERNAL START
+var djsassert = function (condition, message, data) {
+ /// <summary>Throws an exception in case that a condition evaluates to false.</summary>
+ /// <param name="condition" type="Boolean">Condition to evaluate.</param>
+ /// <param name="message" type="String">Message explaining the assertion.</param>
+ /// <param name="data" type="Object">Additional data to be included in the exception.</param>
+
+ if (!condition) {
+ throw { message: "Assert fired: " + message, data: data };
+ };
+};
+// DATAJS INTERNAL END
+
+var extend = function (target, values) {
+ /// <summary>Extends the target with the specified values.</summary>
+ /// <param name="target" type="Object">Object to add properties to.</param>
+ /// <param name="values" type="Object">Object with properties to add into target.</param>
+ /// <returns type="Object">The target object.</returns>
+
+ for (var name in values) {
+ target[name] = values[name];
+ }
+
+ return target;
+};
+
+var find = function (arr, callback) {
+ /// <summary>Returns the first item in the array that makes the callback function true.</summary>
+ /// <param name="arr" type="Array" optional="false" mayBeNull="true">Array to check in.</param>
+ /// <param name="callback" type="Function">Callback function to invoke once per item in the array.</param>
+ /// <returns>The first item that makes the callback return true; null otherwise or if the array is null.</returns>
+
+ if (arr) {
+ var i, len;
+ for (i = 0, len = arr.length; i < len; i++) {
+ if (callback(arr[i])) {
+ return arr[i];
+ }
+ }
+ }
+ return null;
+};
+
+var isArray = function (value) {
+ /// <summary>Checks whether the specified value is an array object.</summary>
+ /// <param name="value">Value to check.</param>
+ /// <returns type="Boolean">true if the value is an array object; false otherwise.</returns>
+
+ return Object.prototype.toString.call(value) === "[object Array]";
+};
+
+var isDate = function (value) {
+ /// <summary>Checks whether the specified value is a Date object.</summary>
+ /// <param name="value">Value to check.</param>
+ /// <returns type="Boolean">true if the value is a Date object; false otherwise.</returns>
+
+ return Object.prototype.toString.call(value) === "[object Date]";
+};
+
+var isObject = function (value) {
+ /// <summary>Tests whether a value is an object.</summary>
+ /// <param name="value">Value to test.</param>
+ /// <remarks>
+ /// Per javascript rules, null and array values are objects and will cause this function to return true.
+ /// </remarks>
+ /// <returns type="Boolean">True is the value is an object; false otherwise.</returns>
+
+ return typeof value === "object";
+};
+
+var parseInt10 = function (value) {
+ /// <summary>Parses a value in base 10.</summary>
+ /// <param name="value" type="String">String value to parse.</param>
+ /// <returns type="Number">The parsed value, NaN if not a valid value.</returns>
+
+ return parseInt(value, 10);
+};
+
+var renameProperty = function (obj, oldName, newName) {
+ /// <summary>Renames a property in an object.</summary>
+ /// <param name="obj" type="Object">Object in which the property will be renamed.</param>
+ /// <param name="oldName" type="String">Name of the property that will be renamed.</param>
+ /// <param name="newName" type="String">New name of the property.</param>
+ /// <remarks>
+ /// This function will not do anything if the object doesn't own a property with the specified old name.
+ /// </remarks>
+
+ if (obj.hasOwnProperty(oldName)) {
+ obj[newName] = obj[oldName];
+ delete obj[oldName];
+ }
+};
+
+var throwErrorCallback = function (error) {
+ /// <summary>Default error handler.</summary>
+ /// <param name="error" type="Object">Error to handle.</param>
+ throw error;
+};
+
+var trimString = function (str) {
+ /// <summary>Removes leading and trailing whitespaces from a string.</summary>
+ /// <param name="str" type="String" optional="false" mayBeNull="false">String to trim</param>
+ /// <returns type="String">The string with no leading or trailing whitespace.</returns>
+
+ if (str.trim) {
+ return str.trim();
+ }
+
+ return str.replace(/^\s+|\s+$/g, '');
+};
+
+var undefinedDefault = function (value, defaultValue) {
+ /// <summary>Returns a default value in place of undefined.</summary>
+ /// <param name="value" mayBeNull="true" optional="true">Value to check.</param>
+ /// <param name="defaultValue">Value to return if value is undefined.</param>
+ /// <returns>value if it's defined; defaultValue otherwise.</returns>
+ /// <remarks>
+ /// This should only be used for cases where falsy values are valid;
+ /// otherwise the pattern should be 'x = (value) ? value : defaultValue;'.
+ /// </remarks>
+ 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"];
+
+var getURIInfo = function (uri) {
+ /// <summary>Gets information about the components of the specified URI.</summary>
+ /// <param name="uri" type="String">URI to get information from.</param>
+ /// <returns type="Object">
+ /// An object with an isAbsolute flag and part names (scheme, authority, etc.) if available.
+ /// </returns>
+
+ 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;
+};
+
+var getURIFromInfo = function (uriInfo) {
+ /// <summary>Builds a URI string from its components.</summary>
+ /// <param name="uriInfo" type="Object"> An object with uri parts (scheme, authority, etc.).</param>
+ /// <returns type="String">URI string.</returns>
+
+ 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;
+
+var normalizeURICase = function (uri) {
+ /// <summary>Normalizes the casing of a URI.</summary>
+ /// <param name="uri" type="String">URI to normalize, absolute or relative.</param>
+ /// <returns type="String">The URI normalized to lower case.</returns>
+
+ 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();
+ });
+};
+
+var normalizeURI = function (uri, base) {
+ /// <summary>Normalizes a possibly relative URI with a base URI.</summary>
+ /// <param name="uri" type="String">URI to normalize, absolute or relative.</param>
+ /// <param name="base" type="String" mayBeNull="true">Base URI to compose with.</param>
+ /// <returns type="String">The composed URI if relative; the original one if absolute.</returns>
+
+ 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);
+};
+
+var mergeUriPathWithBase = function (uriPath, basePath) {
+ /// <summary>Merges the path of a relative URI and a base URI.</summary>
+ /// <param name="uriPath" type="String>Relative URI path.</param>
+ /// <param name="basePath" type="String">Base URI path.</param>
+ /// <returns type="String">A string with the merged path.</returns>
+
+ 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;
+};
+
+var removeDotsFromPath = function (path) {
+ /// <summary>Removes the special folders . and .. from a URI's path.</summary>
+ /// <param name="path" type="string">URI path component.</param>
+ /// <returns type="String">Path without any . and .. folders.</returns>
+
+ 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;
+};
+
+var convertByteArrayToHexString = function (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;
+};
+
+var decodeBase64 = function (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;
+};
+
+var getBase64IndexValue = function (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;
+ }
+};
+
+var addBase64Padding = function (binaryString) {
+ while (binaryString.length < 6) {
+ binaryString = "0" + binaryString;
+ }
+ return binaryString;
+
+};
+
+// DATAJS INTERNAL START
+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;
+// DATAJS INTERNAL END
+
+
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/lib/datajs/xml.js
----------------------------------------------------------------------
diff --git a/datajs/src/lib/datajs/xml.js b/datajs/src/lib/datajs/xml.js
new file mode 100644
index 0000000..1475525
--- /dev/null
+++ b/datajs/src/lib/datajs/xml.js
@@ -0,0 +1,818 @@
+//SK name /datajs/xml.js
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// xml.js
+
+var utils = require('./utils.js');
+
+var activeXObject = utils.activeXObject;
+var djsassert = utils.djsassert;
+var extend = utils.extend;
+var isArray = utils.isArray;
+var isObject = utils.isObject;
+var normalizeURI = utils.normalizeURI;
+
+// CONTENT START
+
+// URI prefixes to generate smaller code.
+var http = "http://";
+var w3org = http + "www.w3.org/"; // http://www.w3.org/
+
+var xhtmlNS = w3org + "1999/xhtml"; // http://www.w3.org/1999/xhtml
+var xmlnsNS = w3org + "2000/xmlns/"; // http://www.w3.org/2000/xmlns/
+var xmlNS = w3org + "XML/1998/namespace"; // http://www.w3.org/XML/1998/namespace
+
+var mozillaParserErroNS = http + "www.mozilla.org/newlayout/xml/parsererror.xml";
+
+var hasLeadingOrTrailingWhitespace = function (text) {
+ /// <summary>Checks whether the specified string has leading or trailing spaces.</summary>
+ /// <param name="text" type="String">String to check.</param>
+ /// <returns type="Boolean">true if text has any leading or trailing whitespace; false otherwise.</returns>
+
+ var re = /(^\s)|(\s$)/;
+ return re.test(text);
+};
+
+var isWhitespace = function (text) {
+ /// <summary>Determines whether the specified text is empty or whitespace.</summary>
+ /// <param name="text" type="String">Value to inspect.</param>
+ /// <returns type="Boolean">true if the text value is empty or all whitespace; false otherwise.</returns>
+
+ var ws = /^\s*$/;
+ return text === null || ws.test(text);
+};
+
+var isWhitespacePreserveContext = function (domElement) {
+ /// <summary>Determines whether the specified element has xml:space='preserve' applied.</summary>
+ /// <param name="domElement">Element to inspect.</param>
+ /// <returns type="Boolean">Whether xml:space='preserve' is in effect.</returns>
+
+ while (domElement !== null && domElement.nodeType === 1) {
+ var val = xmlAttributeValue(domElement, "space", xmlNS);
+ if (val === "preserve") {
+ return true;
+ } else if (val === "default") {
+ break;
+ } else {
+ domElement = domElement.parentNode;
+ }
+ }
+
+ return false;
+};
+
+var isXmlNSDeclaration = function (domAttribute) {
+ /// <summary>Determines whether the attribute is a XML namespace declaration.</summary>
+ /// <param name="domAttribute">Element to inspect.</param>
+ /// <returns type="Boolean">
+ /// True if the attribute is a namespace declaration (its name is 'xmlns' or starts with 'xmlns:'; false otherwise.
+ /// </returns>
+
+ var nodeName = domAttribute.nodeName;
+ return nodeName == "xmlns" || nodeName.indexOf("xmlns:") === 0;
+};
+
+var safeSetProperty = function (obj, name, value) {
+ /// <summary>Safely set as property in an object by invoking obj.setProperty.</summary>
+ /// <param name="obj">Object that exposes a setProperty method.</param>
+ /// <param name="name" type="String" mayBeNull="false">Property name.</param>
+ /// <param name="value">Property value.</param>
+
+ try {
+ obj.setProperty(name, value);
+ } catch (_) { }
+};
+
+var msXmlDom3 = function () {
+ /// <summary>Creates an configures new MSXML 3.0 ActiveX object.</summary>
+ /// <remakrs>
+ /// This function throws any exception that occurs during the creation
+ /// of the MSXML 3.0 ActiveX object.
+ /// <returns type="Object">New MSXML 3.0 ActiveX object.</returns>
+
+ var msxml3 = activeXObject("Msxml2.DOMDocument.3.0");
+ if (msxml3) {
+ safeSetProperty(msxml3, "ProhibitDTD", true);
+ safeSetProperty(msxml3, "MaxElementDepth", 256);
+ safeSetProperty(msxml3, "AllowDocumentFunction", false);
+ safeSetProperty(msxml3, "AllowXsltScript", false);
+ }
+ return msxml3;
+};
+
+var msXmlDom = function () {
+ /// <summary>Creates an configures new MSXML 6.0 or MSXML 3.0 ActiveX object.</summary>
+ /// <remakrs>
+ /// This function will try to create a new MSXML 6.0 ActiveX object. If it fails then
+ /// it will fallback to create a new MSXML 3.0 ActiveX object. Any exception that
+ /// happens during the creation of the MSXML 6.0 will be handled by the function while
+ /// the ones that happend during the creation of the MSXML 3.0 will be thrown.
+ /// <returns type="Object">New MSXML 3.0 ActiveX object.</returns>
+
+ try {
+ var msxml = activeXObject("Msxml2.DOMDocument.6.0");
+ if (msxml) {
+ msxml.async = true;
+ }
+ return msxml;
+ } catch (_) {
+ return msXmlDom3();
+ }
+};
+
+var msXmlParse = function (text) {
+ /// <summary>Parses an XML string using the MSXML DOM.</summary>
+ /// <remakrs>
+ /// This function throws any exception that occurs during the creation
+ /// of the MSXML ActiveX object. It also will throw an exception
+ /// in case of a parsing error.
+ /// <returns type="Object">New MSXML DOMDocument node representing the parsed XML string.</returns>
+
+ var dom = msXmlDom();
+ if (!dom) {
+ return null;
+ }
+
+ dom.loadXML(text);
+ var parseError = dom.parseError;
+ if (parseError.errorCode !== 0) {
+ xmlThrowParserError(parseError.reason, parseError.srcText, text);
+ }
+ return dom;
+};
+
+var xmlThrowParserError = function (exceptionOrReason, srcText, errorXmlText) {
+ /// <summary>Throws a new exception containing XML parsing error information.</summary>
+ /// <param name="exceptionOrReason">
+ /// String indicatin the reason of the parsing failure or
+ /// Object detailing the parsing error.
+ /// </param>
+ /// <param name="srcText" type="String">
+ /// String indicating the part of the XML string that caused the parsing error.
+ /// </param>
+ /// <param name="errorXmlText" type="String">XML string for wich the parsing failed.</param>
+
+ if (typeof exceptionOrReason === "string") {
+ exceptionOrReason = { message: exceptionOrReason };
+ }
+ throw extend(exceptionOrReason, { srcText: srcText || "", errorXmlText: errorXmlText || "" });
+};
+
+var xmlParse = function (text) {
+ /// <summary>Returns an XML DOM document from the specified text.</summary>
+ /// <param name="text" type="String">Document text.</param>
+ /// <returns>XML DOM document.</returns>
+ /// <remarks>This function will throw an exception in case of a parse error.</remarks>
+
+ var domParser = window.DOMParser && new window.DOMParser();
+ var dom;
+
+ if (!domParser) {
+ dom = msXmlParse(text);
+ if (!dom) {
+ xmlThrowParserError("XML DOM parser not supported");
+ }
+ return dom;
+ }
+
+ try {
+ dom = domParser.parseFromString(text, "text/xml");
+ } catch (e) {
+ xmlThrowParserError(e, "", text);
+ }
+
+ var element = dom.documentElement;
+ var nsURI = element.namespaceURI;
+ var localName = xmlLocalName(element);
+
+ // Firefox reports errors by returing the DOM for an xml document describing the problem.
+ if (localName === "parsererror" && nsURI === mozillaParserErroNS) {
+ var srcTextElement = xmlFirstChildElement(element, mozillaParserErroNS, "sourcetext");
+ var srcText = srcTextElement ? xmlNodeValue(srcTextElement) : "";
+ xmlThrowParserError(xmlInnerText(element) || "", srcText, text);
+ }
+
+ // Chrome (and maybe other webkit based browsers) report errors by injecting a header with an error message.
+ // The error may be localized, so instead we simply check for a header as the
+ // top element or descendant child of the document.
+ if (localName === "h3" && nsURI === xhtmlNS || xmlFirstDescendantElement(element, xhtmlNS, "h3")) {
+ var reason = "";
+ var siblings = [];
+ var cursor = element.firstChild;
+ while (cursor) {
+ if (cursor.nodeType === 1) {
+ reason += xmlInnerText(cursor) || "";
+ }
+ siblings.push(cursor.nextSibling);
+ cursor = cursor.firstChild || siblings.shift();
+ }
+ reason += xmlInnerText(element) || "";
+ xmlThrowParserError(reason, "", text);
+ }
+
+ return dom;
+};
+
+var xmlQualifiedName = function (prefix, name) {
+ /// <summary>Builds a XML qualified name string in the form of "prefix:name".</summary>
+ /// <param name="prefix" type="String" maybeNull="true">Prefix string.</param>
+ /// <param name="name" type="String">Name string to qualify with the prefix.</param>
+ /// <returns type="String">Qualified name.</returns>
+
+ return prefix ? prefix + ":" + name : name;
+};
+
+var xmlAppendText = function (domNode, textNode) {
+ /// <summary>Appends a text node into the specified DOM element node.</summary>
+ /// <param name="domNode">DOM node for the element.</param>
+ /// <param name="text" type="String" mayBeNull="false">Text to append as a child of element.</param>
+ if (hasLeadingOrTrailingWhitespace(textNode.data)) {
+ var attr = xmlAttributeNode(domNode, xmlNS, "space");
+ if (!attr) {
+ attr = xmlNewAttribute(domNode.ownerDocument, xmlNS, xmlQualifiedName("xml", "space"));
+ xmlAppendChild(domNode, attr);
+ }
+ attr.value = "preserve";
+ }
+ domNode.appendChild(textNode);
+ return domNode;
+};
+
+var xmlAttributes = function (element, onAttributeCallback) {
+ /// <summary>Iterates through the XML element's attributes and invokes the callback function for each one.</summary>
+ /// <param name="element">Wrapped element to iterate over.</param>
+ /// <param name="onAttributeCallback" type="Function">Callback function to invoke with wrapped attribute nodes.</param>
+
+ var attributes = element.attributes;
+ var i, len;
+ for (i = 0, len = attributes.length; i < len; i++) {
+ onAttributeCallback(attributes.item(i));
+ }
+};
+
+var xmlAttributeValue = function (domNode, localName, nsURI) {
+ /// <summary>Returns the value of a DOM element's attribute.</summary>
+ /// <param name="domNode">DOM node for the owning element.</param>
+ /// <param name="localName" type="String">Local name of the attribute.</param>
+ /// <param name="nsURI" type="String">Namespace URI of the attribute.</param>
+ /// <returns type="String" maybeNull="true">The attribute value, null if not found.</returns>
+
+ var attribute = xmlAttributeNode(domNode, localName, nsURI);
+ return attribute ? xmlNodeValue(attribute) : null;
+};
+
+var xmlAttributeNode = function (domNode, localName, nsURI) {
+ /// <summary>Gets an attribute node from a DOM element.</summary>
+ /// <param name="domNode">DOM node for the owning element.</param>
+ /// <param name="localName" type="String">Local name of the attribute.</param>
+ /// <param name="nsURI" type="String">Namespace URI of the attribute.</param>
+ /// <returns>The attribute node, null if not found.</returns>
+
+ var attributes = domNode.attributes;
+ if (attributes.getNamedItemNS) {
+ return attributes.getNamedItemNS(nsURI || null, localName);
+ }
+
+ return attributes.getQualifiedItem(localName, nsURI) || null;
+};
+
+var xmlBaseURI = function (domNode, baseURI) {
+ /// <summary>Gets the value of the xml:base attribute on the specified element.</summary>
+ /// <param name="domNode">Element to get xml:base attribute value from.</param>
+ /// <param name="baseURI" mayBeNull="true" optional="true">Base URI used to normalize the value of the xml:base attribute.</param>
+ /// <returns type="String">Value of the xml:base attribute if found; the baseURI or null otherwise.</returns>
+
+ var base = xmlAttributeNode(domNode, "base", xmlNS);
+ return (base ? normalizeURI(base.value, baseURI) : baseURI) || null;
+};
+
+
+var xmlChildElements = function (domNode, onElementCallback) {
+ /// <summary>Iterates through the XML element's child DOM elements and invokes the callback function for each one.</summary>
+ /// <param name="element">DOM Node containing the DOM elements to iterate over.</param>
+ /// <param name="onElementCallback" type="Function">Callback function to invoke for each child DOM element.</param>
+
+ xmlTraverse(domNode, /*recursive*/false, function (child) {
+ if (child.nodeType === 1) {
+ onElementCallback(child);
+ }
+ // continue traversing.
+ return true;
+ });
+};
+
+var xmlFindElementByPath = function (root, namespaceURI, path) {
+ /// <summary>Gets the descendant element under root that corresponds to the specified path and namespace URI.</summary>
+ /// <param name="root">DOM element node from which to get the descendant element.</param>
+ /// <param name="namespaceURI" type="String">The namespace URI of the element to match.</param>
+ /// <param name="path" type="String">Path to the desired descendant element.</param>
+ /// <returns>The element specified by path and namespace URI.</returns>
+ /// <remarks>
+ /// All the elements in the path are matched against namespaceURI.
+ /// The function will stop searching on the first element that doesn't match the namespace and the path.
+ /// </remarks>
+
+ var parts = path.split("/");
+ var i, len;
+ for (i = 0, len = parts.length; i < len; i++) {
+ root = root && xmlFirstChildElement(root, namespaceURI, parts[i]);
+ }
+ return root || null;
+};
+
+var xmlFindNodeByPath = function (root, namespaceURI, path) {
+ /// <summary>Gets the DOM element or DOM attribute node under root that corresponds to the specified path and namespace URI.</summary>
+ /// <param name="root">DOM element node from which to get the descendant node.</param>
+ /// <param name="namespaceURI" type="String">The namespace URI of the node to match.</param>
+ /// <param name="path" type="String">Path to the desired descendant node.</param>
+ /// <returns>The node specified by path and namespace URI.</returns>
+ /// <remarks>
+ /// This function will traverse the path and match each node associated to a path segement against the namespace URI.
+ /// The traversal stops when the whole path has been exahusted or a node that doesn't belogong the specified namespace is encountered.
+ ///
+ /// The last segment of the path may be decorated with a starting @ character to indicate that the desired node is a DOM attribute.
+ /// </remarks>
+
+ var lastSegmentStart = path.lastIndexOf("/");
+ var nodePath = path.substring(lastSegmentStart + 1);
+ var parentPath = path.substring(0, lastSegmentStart);
+
+ var node = parentPath ? xmlFindElementByPath(root, namespaceURI, parentPath) : root;
+ if (node) {
+ if (nodePath.charAt(0) === "@") {
+ return xmlAttributeNode(node, nodePath.substring(1), namespaceURI);
+ }
+ return xmlFirstChildElement(node, namespaceURI, nodePath);
+ }
+ return null;
+};
+
+var xmlFirstChildElement = function (domNode, namespaceURI, localName) {
+ /// <summary>Returns the first child DOM element under the specified DOM node that matches the specified namespace URI and local name.</summary>
+ /// <param name="domNode">DOM node from which the child DOM element is going to be retrieved.</param>
+ /// <param name="namespaceURI" type="String" optional="true">The namespace URI of the element to match.</param>
+ /// <param name="localName" type="String" optional="true">Name of the element to match.</param>
+ /// <returns>The node's first child DOM element that matches the specified namespace URI and local name; null otherwise.</returns>
+
+ return xmlFirstElementMaybeRecursive(domNode, namespaceURI, localName, /*recursive*/false);
+};
+
+var xmlFirstDescendantElement = function (domNode, namespaceURI, localName) {
+ /// <summary>Returns the first descendant DOM element under the specified DOM node that matches the specified namespace URI and local name.</summary>
+ /// <param name="domNode">DOM node from which the descendant DOM element is going to be retrieved.</param>
+ /// <param name="namespaceURI" type="String" optional="true">The namespace URI of the element to match.</param>
+ /// <param name="localName" type="String" optional="true">Name of the element to match.</param>
+ /// <returns>The node's first descendant DOM element that matches the specified namespace URI and local name; null otherwise.</returns>
+
+ if (domNode.getElementsByTagNameNS) {
+ var result = domNode.getElementsByTagNameNS(namespaceURI, localName);
+ return result.length > 0 ? result[0] : null;
+ }
+ return xmlFirstElementMaybeRecursive(domNode, namespaceURI, localName, /*recursive*/true);
+};
+
+var xmlFirstElementMaybeRecursive = function (domNode, namespaceURI, localName, recursive) {
+ /// <summary>Returns the first descendant DOM element under the specified DOM node that matches the specified namespace URI and local name.</summary>
+ /// <param name="domNode">DOM node from which the descendant DOM element is going to be retrieved.</param>
+ /// <param name="namespaceURI" type="String" optional="true">The namespace URI of the element to match.</param>
+ /// <param name="localName" type="String" optional="true">Name of the element to match.</param>
+ /// <param name="recursive" type="Boolean">
+ /// True if the search should include all the descendants of the DOM node.
+ /// False if the search should be scoped only to the direct children of the DOM node.
+ /// </param>
+ /// <returns>The node's first descendant DOM element that matches the specified namespace URI and local name; null otherwise.</returns>
+
+ var firstElement = null;
+ xmlTraverse(domNode, recursive, function (child) {
+ if (child.nodeType === 1) {
+ var isExpectedNamespace = !namespaceURI || xmlNamespaceURI(child) === namespaceURI;
+ var isExpectedNodeName = !localName || xmlLocalName(child) === localName;
+
+ if (isExpectedNamespace && isExpectedNodeName) {
+ firstElement = child;
+ }
+ }
+ return firstElement === null;
+ });
+ return firstElement;
+};
+
+var xmlInnerText = function (xmlElement) {
+ /// <summary>Gets the concatenated value of all immediate child text and CDATA nodes for the specified element.</summary>
+ /// <param name="domElement">Element to get values for.</param>
+ /// <returns type="String">Text for all direct children.</returns>
+
+ var result = null;
+ var root = (xmlElement.nodeType === 9 && xmlElement.documentElement) ? xmlElement.documentElement : xmlElement;
+ var whitespaceAlreadyRemoved = root.ownerDocument.preserveWhiteSpace === false;
+ var whitespacePreserveContext;
+
+ xmlTraverse(root, false, function (child) {
+ if (child.nodeType === 3 || child.nodeType === 4) {
+ // isElementContentWhitespace indicates that this is 'ignorable whitespace',
+ // but it's not defined by all browsers, and does not honor xml:space='preserve'
+ // in some implementations.
+ //
+ // If we can't tell either way, we walk up the tree to figure out whether
+ // xml:space is set to preserve; otherwise we discard pure-whitespace.
+ //
+ // For example <a> <b>1</b></a>. The space between <a> and <b> is usually 'ignorable'.
+ var text = xmlNodeValue(child);
+ var shouldInclude = whitespaceAlreadyRemoved || !isWhitespace(text);
+ if (!shouldInclude) {
+ // Walk up the tree to figure out whether we are in xml:space='preserve' context
+ // for the cursor (needs to happen only once).
+ if (whitespacePreserveContext === undefined) {
+ whitespacePreserveContext = isWhitespacePreserveContext(root);
+ }
+
+ shouldInclude = whitespacePreserveContext;
+ }
+
+ if (shouldInclude) {
+ if (!result) {
+ result = text;
+ } else {
+ result += text;
+ }
+ }
+ }
+ // Continue traversing?
+ return true;
+ });
+ return result;
+};
+
+var xmlLocalName = function (domNode) {
+ /// <summary>Returns the localName of a XML node.</summary>
+ /// <param name="domNode">DOM node to get the value from.</param>
+ /// <returns type="String">localName of domNode.</returns>
+
+ return domNode.localName || domNode.baseName;
+};
+
+var xmlNamespaceURI = function (domNode) {
+ /// <summary>Returns the namespace URI of a XML node.</summary>
+ /// <param name="node">DOM node to get the value from.</param>
+ /// <returns type="String">Namespace URI of domNode.</returns>
+
+ return domNode.namespaceURI || null;
+};
+
+var xmlNodeValue = function (domNode) {
+ /// <summary>Returns the value or the inner text of a XML node.</summary>
+ /// <param name="node">DOM node to get the value from.</param>
+ /// <returns>Value of the domNode or the inner text if domNode represents a DOM element node.</returns>
+
+ if (domNode.nodeType === 1) {
+ return xmlInnerText(domNode);
+ }
+ return domNode.nodeValue;
+};
+
+var xmlTraverse = function (domNode, recursive, onChildCallback) {
+ /// <summary>Walks through the descendants of the domNode and invokes a callback for each node.</summary>
+ /// <param name="domNode">DOM node whose descendants are going to be traversed.</param>
+ /// <param name="recursive" type="Boolean">
+ /// True if the traversal should include all the descenants of the DOM node.
+ /// False if the traversal should be scoped only to the direct children of the DOM node.
+ /// </param>
+ /// <returns type="String">Namespace URI of node.</returns>
+
+ var subtrees = [];
+ var child = domNode.firstChild;
+ var proceed = true;
+ while (child && proceed) {
+ proceed = onChildCallback(child);
+ if (proceed) {
+ if (recursive && child.firstChild) {
+ subtrees.push(child.firstChild);
+ }
+ child = child.nextSibling || subtrees.shift();
+ }
+ }
+};
+
+var xmlSiblingElement = function (domNode, namespaceURI, localName) {
+ /// <summary>Returns the next sibling DOM element of the specified DOM node.</summary>
+ /// <param name="domNode">DOM node from which the next sibling is going to be retrieved.</param>
+ /// <param name="namespaceURI" type="String" optional="true">The namespace URI of the element to match.</param>
+ /// <param name="localName" type="String" optional="true">Name of the element to match.</param>
+ /// <returns>The node's next sibling DOM element, null if there is none.</returns>
+
+ var sibling = domNode.nextSibling;
+ while (sibling) {
+ if (sibling.nodeType === 1) {
+ var isExpectedNamespace = !namespaceURI || xmlNamespaceURI(sibling) === namespaceURI;
+ var isExpectedNodeName = !localName || xmlLocalName(sibling) === localName;
+
+ if (isExpectedNamespace && isExpectedNodeName) {
+ return sibling;
+ }
+ }
+ sibling = sibling.nextSibling;
+ }
+ return null;
+};
+
+var xmlDom = function () {
+ /// <summary>Creates a new empty DOM document node.</summary>
+ /// <returns>New DOM document node.</returns>
+ /// <remarks>
+ /// This function will first try to create a native DOM document using
+ /// the browsers createDocument function. If the browser doesn't
+ /// support this but supports ActiveXObject, then an attempt to create
+ /// an MSXML 6.0 DOM will be made. If this attempt fails too, then an attempt
+ /// for creating an MXSML 3.0 DOM will be made. If this last attemp fails or
+ /// the browser doesn't support ActiveXObject then an exception will be thrown.
+ /// </remarks>
+
+ var implementation = window.document.implementation;
+ return (implementation && implementation.createDocument) ?
+ implementation.createDocument(null, null, null) :
+ msXmlDom();
+};
+
+var xmlAppendChildren = function (parent, children) {
+ /// <summary>Appends a collection of child nodes or string values to a parent DOM node.</summary>
+ /// <param name="parent">DOM node to which the children will be appended.</param>
+ /// <param name="children" type="Array">Array containing DOM nodes or string values that will be appended to the parent.</param>
+ /// <returns>The parent with the appended children or string values.</returns>
+ /// <remarks>
+ /// If a value in the children collection is a string, then a new DOM text node is going to be created
+ /// for it and then appended to the parent.
+ /// </remarks>
+
+ if (!isArray(children)) {
+ return xmlAppendChild(parent, children);
+ }
+
+ var i, len;
+ for (i = 0, len = children.length; i < len; i++) {
+ children[i] && xmlAppendChild(parent, children[i]);
+ }
+ return parent;
+};
+
+var xmlAppendChild = function (parent, child) {
+ /// <summary>Appends a child node or a string value to a parent DOM node.</summary>
+ /// <param name="parent">DOM node to which the child will be appended.</param>
+ /// <param name="child">Child DOM node or string value to append to the parent.</param>
+ /// <returns>The parent with the appended child or string value.</returns>
+ /// <remarks>
+ /// If child is a string value, then a new DOM text node is going to be created
+ /// for it and then appended to the parent.
+ /// </remarks>
+
+ djsassert(parent !== child, "xmlAppendChild() - parent and child are one and the same!");
+ if (child) {
+ if (typeof child === "string") {
+ return xmlAppendText(parent, xmlNewText(parent.ownerDocument, child));
+ }
+ if (child.nodeType === 2) {
+ parent.setAttributeNodeNS ? parent.setAttributeNodeNS(child) : parent.setAttributeNode(child);
+ } else {
+ parent.appendChild(child);
+ }
+ }
+ return parent;
+};
+
+var xmlNewAttribute = function (dom, namespaceURI, qualifiedName, value) {
+ /// <summary>Creates a new DOM attribute node.</summary>
+ /// <param name="dom">DOM document used to create the attribute.</param>
+ /// <param name="prefix" type="String">Namespace prefix.</param>
+ /// <param name="namespaceURI" type="String">Namespace URI.</param>
+ /// <returns>DOM attribute node for the namespace declaration.</returns>
+
+ var attribute =
+ dom.createAttributeNS && dom.createAttributeNS(namespaceURI, qualifiedName) ||
+ dom.createNode(2, qualifiedName, namespaceURI || undefined);
+
+ attribute.value = value || "";
+ return attribute;
+};
+
+var xmlNewElement = function (dom, nampespaceURI, qualifiedName, children) {
+ /// <summary>Creates a new DOM element node.</summary>
+ /// <param name="dom">DOM document used to create the DOM element.</param>
+ /// <param name="namespaceURI" type="String">Namespace URI of the new DOM element.</param>
+ /// <param name="qualifiedName" type="String">Qualified name in the form of "prefix:name" of the new DOM element.</param>
+ /// <param name="children" type="Array" optional="true">
+ /// Collection of child DOM nodes or string values that are going to be appended to the new DOM element.
+ /// </param>
+ /// <returns>New DOM element.</returns>
+ /// <remarks>
+ /// If a value in the children collection is a string, then a new DOM text node is going to be created
+ /// for it and then appended to the new DOM element.
+ /// </remarks>
+
+ var element =
+ dom.createElementNS && dom.createElementNS(nampespaceURI, qualifiedName) ||
+ dom.createNode(1, qualifiedName, nampespaceURI || undefined);
+
+ return xmlAppendChildren(element, children || []);
+};
+
+var xmlNewNSDeclaration = function (dom, namespaceURI, prefix) {
+ /// <summary>Creates a namespace declaration attribute.</summary>
+ /// <param name="dom">DOM document used to create the attribute.</param>
+ /// <param name="namespaceURI" type="String">Namespace URI.</param>
+ /// <param name="prefix" type="String">Namespace prefix.</param>
+ /// <returns>DOM attribute node for the namespace declaration.</returns>
+
+ return xmlNewAttribute(dom, xmlnsNS, xmlQualifiedName("xmlns", prefix), namespaceURI);
+};
+
+var xmlNewFragment = function (dom, text) {
+ /// <summary>Creates a new DOM document fragment node for the specified xml text.</summary>
+ /// <param name="dom">DOM document from which the fragment node is going to be created.</param>
+ /// <param name="text" type="String" mayBeNull="false">XML text to be represented by the XmlFragment.</param>
+ /// <returns>New DOM document fragment object.</returns>
+
+ var value = "<c>" + text + "</c>";
+ var tempDom = xmlParse(value);
+ var tempRoot = tempDom.documentElement;
+ var imported = ("importNode" in dom) ? dom.importNode(tempRoot, true) : tempRoot;
+ var fragment = dom.createDocumentFragment();
+
+ var importedChild = imported.firstChild;
+ while (importedChild) {
+ fragment.appendChild(importedChild);
+ importedChild = importedChild.nextSibling;
+ }
+ return fragment;
+};
+
+var xmlNewText = function (dom, text) {
+ /// <summary>Creates new DOM text node.</summary>
+ /// <param name="dom">DOM document used to create the text node.</param>
+ /// <param name="text" type="String">Text value for the DOM text node.</param>
+ /// <returns>DOM text node.</returns>
+
+ return dom.createTextNode(text);
+};
+
+var xmlNewNodeByPath = function (dom, root, namespaceURI, prefix, path) {
+ /// <summary>Creates a new DOM element or DOM attribute node as specified by path and appends it to the DOM tree pointed by root.</summary>
+ /// <param name="dom">DOM document used to create the new node.</param>
+ /// <param name="root">DOM element node used as root of the subtree on which the new nodes are going to be created.</param>
+ /// <param name="namespaceURI" type="String">Namespace URI of the new DOM element or attribute.</param>
+ /// <param name="namespacePrefix" type="String">Prefix used to qualify the name of the new DOM element or attribute.</param>
+ /// <param name="Path" type="String">Path string describing the location of the new DOM element or attribute from the root element.</param>
+ /// <returns>DOM element or attribute node for the last segment of the path.</returns>
+ /// <remarks>
+ /// This function will traverse the path and will create a new DOM element with the specified namespace URI and prefix
+ /// for each segment that doesn't have a matching element under root.
+ ///
+ /// The last segment of the path may be decorated with a starting @ character. In this case a new DOM attribute node
+ /// will be created.
+ /// </remarks>
+
+ var name = "";
+ var parts = path.split("/");
+ var xmlFindNode = xmlFirstChildElement;
+ var xmlNewNode = xmlNewElement;
+ var xmlNode = root;
+
+ var i, len;
+ for (i = 0, len = parts.length; i < len; i++) {
+ name = parts[i];
+ if (name.charAt(0) === "@") {
+ name = name.substring(1);
+ xmlFindNode = xmlAttributeNode;
+ xmlNewNode = xmlNewAttribute;
+ }
+
+ var childNode = xmlFindNode(xmlNode, namespaceURI, name);
+ if (!childNode) {
+ childNode = xmlNewNode(dom, namespaceURI, xmlQualifiedName(prefix, name));
+ xmlAppendChild(xmlNode, childNode);
+ }
+ xmlNode = childNode;
+ }
+ return xmlNode;
+};
+
+var xmlSerialize = function (domNode) {
+ /// <summary>
+ /// Returns the text representation of the document to which the specified node belongs.
+ /// </summary>
+ /// <param name="root">Wrapped element in the document to serialize.</param>
+ /// <returns type="String">Serialized document.</returns>
+
+ var xmlSerializer = window.XMLSerializer;
+ if (xmlSerializer) {
+ var serializer = new xmlSerializer();
+ return serializer.serializeToString(domNode);
+ }
+
+ if (domNode.xml) {
+ return domNode.xml;
+ }
+
+ throw { message: "XML serialization unsupported" };
+};
+
+var xmlSerializeDescendants = function (domNode) {
+ /// <summary>Returns the XML representation of the all the descendants of the node.</summary>
+ /// <param name="domNode" optional="false" mayBeNull="false">Node to serialize.</param>
+ /// <returns type="String">The XML representation of all the descendants of the node.</returns>
+
+ var children = domNode.childNodes;
+ var i, len = children.length;
+ if (len === 0) {
+ return "";
+ }
+
+ // Some implementations of the XMLSerializer don't deal very well with fragments that
+ // don't have a DOMElement as their first child. The work around is to wrap all the
+ // nodes in a dummy root node named "c", serialize it and then just extract the text between
+ // the <c> and the </c> substrings.
+
+ var dom = domNode.ownerDocument;
+ var fragment = dom.createDocumentFragment();
+ var fragmentRoot = dom.createElement("c");
+
+ fragment.appendChild(fragmentRoot);
+ // Move the children to the fragment tree.
+ for (i = 0; i < len; i++) {
+ fragmentRoot.appendChild(children[i]);
+ }
+
+ var xml = xmlSerialize(fragment);
+ xml = xml.substr(3, xml.length - 7);
+
+ // Move the children back to the original dom tree.
+ for (i = 0; i < len; i++) {
+ domNode.appendChild(fragmentRoot.childNodes[i]);
+ }
+
+ return xml;
+};
+
+var xmlSerializeNode = function (domNode) {
+ /// <summary>Returns the XML representation of the node and all its descendants.</summary>
+ /// <param name="domNode" optional="false" mayBeNull="false">Node to serialize.</param>
+ /// <returns type="String">The XML representation of the node and all its descendants.</returns>
+
+ var xml = domNode.xml;
+ if (xml !== undefined) {
+ return xml;
+ }
+
+ if (window.XMLSerializer) {
+ var serializer = new window.XMLSerializer();
+ return serializer.serializeToString(domNode);
+ }
+
+ throw { message: "XML serialization unsupported" };
+};
+
+// DATAJS INTERNAL START
+exports.http = http;
+exports.w3org = w3org;
+exports.xmlNS = xmlNS;
+exports.xmlnsNS = xmlnsNS;
+
+exports.hasLeadingOrTrailingWhitespace = hasLeadingOrTrailingWhitespace;
+exports.isXmlNSDeclaration = isXmlNSDeclaration;
+exports.xmlAppendChild = xmlAppendChild;
+exports.xmlAppendChildren = xmlAppendChildren;
+exports.xmlAttributeNode = xmlAttributeNode;
+exports.xmlAttributes = xmlAttributes;
+exports.xmlAttributeValue = xmlAttributeValue;
+exports.xmlBaseURI = xmlBaseURI;
+exports.xmlChildElements = xmlChildElements;
+exports.xmlFindElementByPath = xmlFindElementByPath;
+exports.xmlFindNodeByPath = xmlFindNodeByPath;
+exports.xmlFirstChildElement = xmlFirstChildElement;
+exports.xmlFirstDescendantElement = xmlFirstDescendantElement;
+exports.xmlInnerText = xmlInnerText;
+exports.xmlLocalName = xmlLocalName;
+exports.xmlNamespaceURI = xmlNamespaceURI;
+exports.xmlNodeValue = xmlNodeValue;
+exports.xmlDom = xmlDom;
+exports.xmlNewAttribute = xmlNewAttribute;
+exports.xmlNewElement = xmlNewElement;
+exports.xmlNewFragment = xmlNewFragment;
+exports.xmlNewNodeByPath = xmlNewNodeByPath;
+exports.xmlNewNSDeclaration = xmlNewNSDeclaration;
+exports.xmlNewText = xmlNewText;
+exports.xmlParse = xmlParse;
+exports.xmlQualifiedName = xmlQualifiedName;
+exports.xmlSerialize = xmlSerialize;
+exports.xmlSerializeDescendants = xmlSerializeDescendants;
+exports.xmlSiblingElement = xmlSiblingElement;
+// DATAJS INTERNAL END
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/lib/odata.js
----------------------------------------------------------------------
diff --git a/datajs/src/lib/odata.js b/datajs/src/lib/odata.js
new file mode 100644
index 0000000..caea1fa
--- /dev/null
+++ b/datajs/src/lib/odata.js
@@ -0,0 +1,93 @@
+//SK name odata.js
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// odata.js
+
+// Imports
+exports.utils = odataUtils = require('./odata/utils.js');
+exports.handler = odataHandler = require('./odata/handler.js');
+exports.metadata = odataMetadata = require('./odata/metadata.js');
+exports.net = require('./odata/net.js');
+exports.gml = require('./odata/gml.js');
+exports.jsonLight = require('./odata/json-light.js');
+exports.request = odataRequest = require('./odata/request.js');
+exports.json = odataJson = require('./odata/json.js');
+exports.atom = odataAtom = require('./odata/atom.js');
+exports.xml = odataXml = require('./odata/xml.js');
+exports.batchHandler = require('./odata/batch.js');
+
+// Configure the batch handler to use the default handler for the batch parts.
+exports.batchHandler.partHandler = odataRequest.defaultHandler;
+
+var utils = require('./datajs/utils.js');
+
+var assigned = utils.assigned;
+var defined = utils.defined;
+var throwErrorCallback = utils.throwErrorCallback;
+
+var invokeRequest = odataUtils.invokeRequest;
+var MAX_DATA_SERVICE_VERSION = odataHandler.MAX_DATA_SERVICE_VERSION;
+var prepareRequest = odataUtils.prepareRequest;
+var metadataParser = odataMetadata.metadataParser;
+
+// CONTENT START
+
+var handlers = [odataJson.jsonHandler, odataAtom.atomHandler, odataXml.xmlHandler, odataHandler.textHandler];
+
+var dispatchHandler = function (handlerMethod, requestOrResponse, context) {
+ /// <summary>Dispatches an operation to handlers.</summary>
+ /// <param name="handlerMethod" type="String">Name of handler method to invoke.</param>
+ /// <param name="requestOrResponse" type="Object">request/response argument for delegated call.</param>
+ /// <param name="context" type="Object">context argument for delegated call.</param>
+
+ var i, len;
+ for (i = 0, len = handlers.length; i < len && !handlers[i][handlerMethod](requestOrResponse, context); i++) {
+ }
+
+ if (i === len) {
+ throw { message: "no handler for data" };
+ }
+};
+
+
+
+exports.read = function (urlOrRequest, success, error, handler, httpClient, metadata) {
+ /// <summary>Reads data from the specified URL.</summary>
+ /// <param name="urlOrRequest">URL to read data from.</param>
+ /// <param name="success" type="Function" optional="true">Callback for a successful read operation.</param>
+ /// <param name="error" type="Function" optional="true">Callback for handling errors.</param>
+ /// <param name="handler" type="Object" optional="true">Handler for data serialization.</param>
+ /// <param name="httpClient" type="Object" optional="true">HTTP client layer.</param>
+ /// <param name="metadata" type="Object" optional="true">Conceptual metadata for this request.</param>
+
+ var request;
+ if (urlOrRequest instanceof String || typeof urlOrRequest === "string") {
+ request = { requestUri: urlOrRequest };
+ } else {
+ request = urlOrRequest;
+ }
+
+ return odataRequest.request(request, success, error, handler, httpClient, metadata);
+};
+
+
+
+exports.parseMetadata = function (csdlMetadataDocument) {
+ /// <summary>Parses the csdl metadata to DataJS metatdata format. This method can be used when the metadata is retrieved using something other than DataJS</summary>
+ /// <param name="atomMetadata" type="string">A string that represents the entire csdl metadata.</param>
+ /// <returns type="Object">An object that has the representation of the metadata in Datajs format.</returns>
+
+ return metadataParser(null, csdlMetadataDocument);
+};
+
[09/15] [OLINGO-238] Build infrastructure for datajs I
Posted by ko...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/lib/odata/metadata.js
----------------------------------------------------------------------
diff --git a/datajs/src/lib/odata/metadata.js b/datajs/src/lib/odata/metadata.js
new file mode 100644
index 0000000..59b880a
--- /dev/null
+++ b/datajs/src/lib/odata/metadata.js
@@ -0,0 +1,498 @@
+//SK name /odata/odata-metadata.js
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// odata-metadata.js
+
+
+var utils = require('./../datajs.js').utils;
+var oDataXML = require('./xml.js');
+var odataHandler = require('./handler.js');
+
+// imports
+
+var contains = utils.contains;
+var normalizeURI = utils.normalizeURI;
+var xmlAttributes = utils.xmlAttributes;
+var xmlChildElements = utils.xmlChildElements;
+var xmlFirstChildElement = utils.xmlFirstChildElement;
+var xmlInnerText = utils.xmlInnerText;
+var xmlLocalName = utils.xmlLocalName;
+var xmlNamespaceURI = utils.xmlNamespaceURI;
+var xmlNS = utils.xmlNS;
+var xmlnsNS = utils.xmlnsNS;
+var xmlParse = utils.xmlParse;
+
+var createAttributeExtension = oDataXML.createAttributeExtension;
+var createElementExtension = oDataXML.createElementExtension;
+var edmxNs = oDataXML.edmxNs;
+var edmNs1 = oDataXML.edmNs1;
+var edmNs1_1 = oDataXML.edmNs1_1;
+var edmNs1_2 = oDataXML.edmNs1_2;
+var edmNs2a = oDataXML.edmNs2a;
+var edmNs2b = oDataXML.edmNs2b;
+var edmNs3 = oDataXML.edmNs3;
+var handler = oDataXML.handler;
+var MAX_DATA_SERVICE_VERSION = oDataXML.MAX_DATA_SERVICE_VERSION;
+var odataMetaXmlNs = oDataXML.odataMetaXmlNs;
+
+
+var xmlMediaType = "application/xml";
+
+// CONTENT START
+
+var schemaElement = function (attributes, elements, text, ns) {
+ /// <summary>Creates an object that describes an element in an schema.</summary>
+ /// <param name="attributes" type="Array">List containing the names of the attributes allowed for this element.</param>
+ /// <param name="elements" type="Array">List containing the names of the child elements allowed for this element.</param>
+ /// <param name="text" type="Boolean">Flag indicating if the element's text value is of interest or not.</param>
+ /// <param name="ns" type="String">Namespace to which the element belongs to.</param>
+ /// <remarks>
+ /// If a child element name ends with * then it is understood by the schema that that child element can appear 0 or more times.
+ /// </remarks>
+ /// <returns type="Object">Object with attributes, elements, text, and ns fields.</returns>
+
+ return {
+ attributes: attributes,
+ elements: elements,
+ text: text || false,
+ ns: ns
+ };
+};
+
+// It's assumed that all elements may have Documentation children and Annotation elements.
+// See http://msdn.microsoft.com/en-us/library/bb399292.aspx for a CSDL reference.
+var schema = {
+ elements: {
+ Annotations: schemaElement(
+ /*attributes*/["Target", "Qualifier"],
+ /*elements*/["TypeAnnotation*", "ValueAnnotation*"]
+ ),
+ Association: schemaElement(
+ /*attributes*/["Name"],
+ /*elements*/["End*", "ReferentialConstraint", "TypeAnnotation*", "ValueAnnotation*"]
+ ),
+ AssociationSet: schemaElement(
+ /*attributes*/["Name", "Association"],
+ /*elements*/["End*", "TypeAnnotation*", "ValueAnnotation*"]
+ ),
+ Binary: schemaElement(
+ /*attributes*/null,
+ /*elements*/null,
+ /*text*/true
+ ),
+ Bool: schemaElement(
+ /*attributes*/null,
+ /*elements*/null,
+ /*text*/true
+ ),
+ Collection: schemaElement(
+ /*attributes*/null,
+ /*elements*/["String*", "Int*", "Float*", "Decimal*", "Bool*", "DateTime*", "DateTimeOffset*", "Guid*", "Binary*", "Time*", "Collection*", "Record*"]
+ ),
+ CollectionType: schemaElement(
+ /*attributes*/["ElementType", "Nullable", "DefaultValue", "MaxLength", "FixedLength", "Precision", "Scale", "Unicode", "Collation", "SRID"],
+ /*elements*/["CollectionType", "ReferenceType", "RowType", "TypeRef"]
+ ),
+ ComplexType: schemaElement(
+ /*attributes*/["Name", "BaseType", "Abstract"],
+ /*elements*/["Property*", "TypeAnnotation*", "ValueAnnotation*"]
+ ),
+ DateTime: schemaElement(
+ /*attributes*/null,
+ /*elements*/null,
+ /*text*/true
+ ),
+ DateTimeOffset: schemaElement(
+ /*attributes*/null,
+ /*elements*/null,
+ /*text*/true
+ ),
+ Decimal: schemaElement(
+ /*attributes*/null,
+ /*elements*/null,
+ /*text*/true
+ ),
+ DefiningExpression: schemaElement(
+ /*attributes*/null,
+ /*elements*/null,
+ /*text*/true
+ ),
+ Dependent: schemaElement(
+ /*attributes*/["Role"],
+ /*elements*/["PropertyRef*"]
+ ),
+ Documentation: schemaElement(
+ /*attributes*/null,
+ /*elements*/null,
+ /*text*/true
+ ),
+ End: schemaElement(
+ /*attributes*/["Type", "Role", "Multiplicity", "EntitySet"],
+ /*elements*/["OnDelete"]
+ ),
+ EntityContainer: schemaElement(
+ /*attributes*/["Name", "Extends"],
+ /*elements*/["EntitySet*", "AssociationSet*", "FunctionImport*", "TypeAnnotation*", "ValueAnnotation*"]
+ ),
+ EntitySet: schemaElement(
+ /*attributes*/["Name", "EntityType"],
+ /*elements*/["TypeAnnotation*", "ValueAnnotation*"]
+ ),
+ EntityType: schemaElement(
+ /*attributes*/["Name", "BaseType", "Abstract", "OpenType"],
+ /*elements*/["Key", "Property*", "NavigationProperty*", "TypeAnnotation*", "ValueAnnotation*"]
+ ),
+ EnumType: schemaElement(
+ /*attributes*/["Name", "UnderlyingType", "IsFlags"],
+ /*elements*/["Member*"]
+ ),
+ Float: schemaElement(
+ /*attributes*/null,
+ /*elements*/null,
+ /*text*/true
+ ),
+ Function: schemaElement(
+ /*attributes*/["Name", "ReturnType"],
+ /*elements*/["Parameter*", "DefiningExpression", "ReturnType", "TypeAnnotation*", "ValueAnnotation*"]
+ ),
+ FunctionImport: schemaElement(
+ /*attributes*/["Name", "ReturnType", "EntitySet", "IsSideEffecting", "IsComposable", "IsBindable", "EntitySetPath"],
+ /*elements*/["Parameter*", "ReturnType", "TypeAnnotation*", "ValueAnnotation*"]
+ ),
+ Guid: schemaElement(
+ /*attributes*/null,
+ /*elements*/null,
+ /*text*/true
+ ),
+ Int: schemaElement(
+ /*attributes*/null,
+ /*elements*/null,
+ /*text*/true
+ ),
+ Key: schemaElement(
+ /*attributes*/null,
+ /*elements*/["PropertyRef*"]
+ ),
+ LabeledElement: schemaElement(
+ /*attributes*/["Name"],
+ /*elements*/["Path", "String", "Int", "Float", "Decimal", "Bool", "DateTime", "DateTimeOffset", "Guid", "Binary", "Time", "Collection", "Record", "LabeledElement", "Null"]
+ ),
+ Member: schemaElement(
+ /*attributes*/["Name", "Value"]
+ ),
+ NavigationProperty: schemaElement(
+ /*attributes*/["Name", "Relationship", "ToRole", "FromRole", "ContainsTarget"],
+ /*elements*/["TypeAnnotation*", "ValueAnnotation*"]
+ ),
+ Null: schemaElement(
+ /*attributes*/null,
+ /*elements*/null
+ ),
+ OnDelete: schemaElement(
+ /*attributes*/["Action"]
+ ),
+ Path: schemaElement(
+ /*attributes*/null,
+ /*elements*/null,
+ /*text*/true
+ ),
+ Parameter: schemaElement(
+ /*attributes*/["Name", "Type", "Mode", "Nullable", "DefaultValue", "MaxLength", "FixedLength", "Precision", "Scale", "Unicode", "Collation", "ConcurrencyMode", "SRID"],
+ /*elements*/["CollectionType", "ReferenceType", "RowType", "TypeRef", "TypeAnnotation*", "ValueAnnotation*"]
+ ),
+ Principal: schemaElement(
+ /*attributes*/["Role"],
+ /*elements*/["PropertyRef*"]
+ ),
+ Property: schemaElement(
+ /*attributes*/["Name", "Type", "Nullable", "DefaultValue", "MaxLength", "FixedLength", "Precision", "Scale", "Unicode", "Collation", "ConcurrencyMode", "CollectionKind", "SRID"],
+ /*elements*/["CollectionType", "ReferenceType", "RowType", "TypeAnnotation*", "ValueAnnotation*"]
+ ),
+ PropertyRef: schemaElement(
+ /*attributes*/["Name"]
+ ),
+ PropertyValue: schemaElement(
+ /*attributes*/["Property", "Path", "String", "Int", "Float", "Decimal", "Bool", "DateTime", "DateTimeOffset", "Guid", "Binary", "Time"],
+ /*Elements*/["Path", "String", "Int", "Float", "Decimal", "Bool", "DateTime", "DateTimeOffset", "Guid", "Binary", "Time", "Collection", "Record", "LabeledElement", "Null"]
+ ),
+ ReferenceType: schemaElement(
+ /*attributes*/["Type"]
+ ),
+ ReferentialConstraint: schemaElement(
+ /*attributes*/null,
+ /*elements*/["Principal", "Dependent"]
+ ),
+ ReturnType: schemaElement(
+ /*attributes*/["ReturnType", "Type", "EntitySet"],
+ /*elements*/["CollectionType", "ReferenceType", "RowType"]
+ ),
+ RowType: schemaElement(
+ /*elements*/["Property*"]
+ ),
+ String: schemaElement(
+ /*attributes*/null,
+ /*elements*/null,
+ /*text*/true
+ ),
+ Schema: schemaElement(
+ /*attributes*/["Namespace", "Alias"],
+ /*elements*/["Using*", "EntityContainer*", "EntityType*", "Association*", "ComplexType*", "Function*", "ValueTerm*", "Annotations*"]
+ ),
+ Time: schemaElement(
+ /*attributes*/null,
+ /*elements*/null,
+ /*text*/true
+ ),
+ TypeAnnotation: schemaElement(
+ /*attributes*/["Term", "Qualifier"],
+ /*elements*/["PropertyValue*"]
+ ),
+ TypeRef: schemaElement(
+ /*attributes*/["Type", "Nullable", "DefaultValue", "MaxLength", "FixedLength", "Precision", "Scale", "Unicode", "Collation", "SRID"]
+ ),
+ Using: schemaElement(
+ /*attributes*/["Namespace", "Alias"]
+ ),
+ ValueAnnotation: schemaElement(
+ /*attributes*/["Term", "Qualifier", "Path", "String", "Int", "Float", "Decimal", "Bool", "DateTime", "DateTimeOffset", "Guid", "Binary", "Time"],
+ /*Elements*/["Path", "String", "Int", "Float", "Decimal", "Bool", "DateTime", "DateTimeOffset", "Guid", "Binary", "Time", "Collection", "Record", "LabeledElement", "Null"]
+ ),
+ ValueTerm: schemaElement(
+ /*attributes*/["Name", "Type"],
+ /*elements*/["TypeAnnotation*", "ValueAnnotation*"]
+ ),
+
+ // See http://msdn.microsoft.com/en-us/library/dd541238(v=prot.10) for an EDMX reference.
+ Edmx: schemaElement(
+ /*attributes*/["Version"],
+ /*elements*/["DataServices", "Reference*", "AnnotationsReference*"],
+ /*text*/false,
+ /*ns*/edmxNs
+ ),
+ DataServices: schemaElement(
+ /*attributes*/null,
+ /*elements*/["Schema*"],
+ /*text*/false,
+ /*ns*/edmxNs
+ )
+ }
+};
+
+// See http://msdn.microsoft.com/en-us/library/ee373839.aspx for a feed customization reference.
+var customizationAttributes = ["m:FC_ContentKind", "m:FC_KeepInContent", "m:FC_NsPrefix", "m:FC_NsUri", "m:FC_SourcePath", "m:FC_TargetPath"];
+schema.elements.Property.attributes = schema.elements.Property.attributes.concat(customizationAttributes);
+schema.elements.EntityType.attributes = schema.elements.EntityType.attributes.concat(customizationAttributes);
+
+// See http://msdn.microsoft.com/en-us/library/dd541284(PROT.10).aspx for an EDMX reference.
+schema.elements.Edmx = { attributes: ["Version"], elements: ["DataServices"], ns: edmxNs };
+schema.elements.DataServices = { elements: ["Schema*"], ns: edmxNs };
+
+// See http://msdn.microsoft.com/en-us/library/dd541233(v=PROT.10) for Conceptual Schema Definition Language Document for Data Services.
+schema.elements.EntityContainer.attributes.push("m:IsDefaultEntityContainer");
+schema.elements.Property.attributes.push("m:MimeType");
+schema.elements.FunctionImport.attributes.push("m:HttpMethod");
+schema.elements.FunctionImport.attributes.push("m:IsAlwaysBindable");
+schema.elements.EntityType.attributes.push("m:HasStream");
+schema.elements.DataServices.attributes = ["m:DataServiceVersion", "m:MaxDataServiceVersion"];
+
+var scriptCase = function (text) {
+ /// <summary>Converts a Pascal-case identifier into a camel-case identifier.</summary>
+ /// <param name="text" type="String">Text to convert.</param>
+ /// <returns type="String">Converted text.</returns>
+ /// <remarks>If the text starts with multiple uppercase characters, it is left as-is.</remarks>
+
+ if (!text) {
+ return text;
+ }
+
+ if (text.length > 1) {
+ var firstTwo = text.substr(0, 2);
+ if (firstTwo === firstTwo.toUpperCase()) {
+ return text;
+ }
+
+ return text.charAt(0).toLowerCase() + text.substr(1);
+ }
+
+ return text.charAt(0).toLowerCase();
+};
+
+var getChildSchema = function (parentSchema, candidateName) {
+ /// <summary>Gets the schema node for the specified element.</summary>
+ /// <param name="parentSchema" type="Object">Schema of the parent XML node of 'element'.</param>
+ /// <param name="candidateName">XML element name to consider.</param>
+ /// <returns type="Object">The schema that describes the specified element; null if not found.</returns>
+
+ if (candidateName === "Documentation") {
+ return { isArray: true, propertyName: "documentation" };
+ }
+
+ var elements = parentSchema.elements;
+ if (!elements) {
+ return null;
+ }
+
+ var i, len;
+ for (i = 0, len = elements.length; i < len; i++) {
+ var elementName = elements[i];
+ var multipleElements = false;
+ if (elementName.charAt(elementName.length - 1) === "*") {
+ multipleElements = true;
+ elementName = elementName.substr(0, elementName.length - 1);
+ }
+
+ if (candidateName === elementName) {
+ var propertyName = scriptCase(elementName);
+ return { isArray: multipleElements, propertyName: propertyName };
+ }
+ }
+
+ return null;
+};
+
+// This regular expression is used to detect a feed customization element
+// after we've normalized it into the 'm' prefix. It starts with m:FC_,
+// followed by other characters, and ends with _ and a number.
+// The captures are 0 - whole string, 1 - name as it appears in internal table.
+var isFeedCustomizationNameRE = /^(m:FC_.*)_[0-9]+$/;
+
+var isEdmNamespace = function (nsURI) {
+ /// <summary>Checks whether the specifies namespace URI is one of the known CSDL namespace URIs.</summary>
+ /// <param name="nsURI" type="String">Namespace URI to check.</param>
+ /// <returns type="Boolean">true if nsURI is a known CSDL namespace; false otherwise.</returns>
+
+ return nsURI === edmNs1 ||
+ nsURI === edmNs1_1 ||
+ nsURI === edmNs1_2 ||
+ nsURI === edmNs2a ||
+ nsURI === edmNs2b ||
+ nsURI === edmNs3;
+};
+
+var parseConceptualModelElement = function (element) {
+ /// <summary>Parses a CSDL document.</summary>
+ /// <param name="element">DOM element to parse.</param>
+ /// <returns type="Object">An object describing the parsed element.</returns>
+
+ var localName = xmlLocalName(element);
+ var nsURI = xmlNamespaceURI(element);
+ var elementSchema = schema.elements[localName];
+ if (!elementSchema) {
+ return null;
+ }
+
+ if (elementSchema.ns) {
+ if (nsURI !== elementSchema.ns) {
+ return null;
+ }
+ } else if (!isEdmNamespace(nsURI)) {
+ return null;
+ }
+
+ var item = {};
+ var extensions = [];
+ var attributes = elementSchema.attributes || [];
+ xmlAttributes(element, function (attribute) {
+
+ var localName = xmlLocalName(attribute);
+ var nsURI = xmlNamespaceURI(attribute);
+ var value = attribute.value;
+
+ // Don't do anything with xmlns attributes.
+ if (nsURI === xmlnsNS) {
+ return;
+ }
+
+ // Currently, only m: for metadata is supported as a prefix in the internal schema table,
+ // un-prefixed element names imply one a CSDL element.
+ var schemaName = null;
+ var handled = false;
+ if (isEdmNamespace(nsURI) || nsURI === null) {
+ schemaName = "";
+ } else if (nsURI === odataMetaXmlNs) {
+ schemaName = "m:";
+ }
+
+ if (schemaName !== null) {
+ schemaName += localName;
+
+ // Feed customizations for complex types have additional
+ // attributes with a suffixed counter starting at '1', so
+ // take that into account when doing the lookup.
+ var match = isFeedCustomizationNameRE.exec(schemaName);
+ if (match) {
+ schemaName = match[1];
+ }
+
+ if (contains(attributes, schemaName)) {
+ handled = true;
+ item[scriptCase(localName)] = value;
+ }
+ }
+
+ if (!handled) {
+ extensions.push(createAttributeExtension(attribute));
+ }
+ });
+
+ xmlChildElements(element, function (child) {
+ var localName = xmlLocalName(child);
+ var childSchema = getChildSchema(elementSchema, localName);
+ if (childSchema) {
+ if (childSchema.isArray) {
+ var arr = item[childSchema.propertyName];
+ if (!arr) {
+ arr = [];
+ item[childSchema.propertyName] = arr;
+ }
+ arr.push(parseConceptualModelElement(child));
+ } else {
+ item[childSchema.propertyName] = parseConceptualModelElement(child);
+ }
+ } else {
+ extensions.push(createElementExtension(child));
+ }
+ });
+
+ if (elementSchema.text) {
+ item.text = xmlInnerText(element);
+ }
+
+ if (extensions.length) {
+ item.extensions = extensions;
+ }
+
+ return item;
+};
+
+var metadataParser = function (handler, text) {
+ /// <summary>Parses a metadata document.</summary>
+ /// <param name="handler">This handler.</param>
+ /// <param name="text" type="String">Metadata text.</param>
+ /// <returns>An object representation of the conceptual model.</returns>
+
+ var doc = xmlParse(text);
+ var root = xmlFirstChildElement(doc);
+ return parseConceptualModelElement(root) || undefined;
+};
+
+exports.metadataHandler = odataHandler.handler(metadataParser, null, xmlMediaType, MAX_DATA_SERVICE_VERSION);
+
+// DATAJS INTERNAL START
+exports.schema = schema;
+exports.scriptCase = scriptCase;
+exports.getChildSchema = getChildSchema;
+exports.parseConceptualModelElement = parseConceptualModelElement;
+exports.metadataParser = metadataParser;
+// DATAJS INTERNAL END
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/lib/odata/net.js
----------------------------------------------------------------------
diff --git a/datajs/src/lib/odata/net.js b/datajs/src/lib/odata/net.js
new file mode 100644
index 0000000..850d148
--- /dev/null
+++ b/datajs/src/lib/odata/net.js
@@ -0,0 +1,324 @@
+//SK name /odata/odata-net.js
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// odata-net.js
+
+var utils = require('./../datajs.js').utils;
+ // Imports.
+
+var defined = utils.defined;
+var delay = utils.delay;
+
+// CONTENT START
+var ticks = 0;
+
+var canUseJSONP = function (request) {
+ /// <summary>
+ /// Checks whether the specified request can be satisfied with a JSONP request.
+ /// </summary>
+ /// <param name="request">Request object to check.</param>
+ /// <returns type="Boolean">true if the request can be satisfied; false otherwise.</returns>
+
+ // Requests that 'degrade' without changing their meaning by going through JSONP
+ // are considered usable.
+ //
+ // We allow data to come in a different format, as the servers SHOULD honor the Accept
+ // request but may in practice return content with a different MIME type.
+ if (request.method && request.method !== "GET") {
+ return false;
+ }
+
+ return true;
+};
+
+var createIFrame = function (url) {
+ /// <summary>Creates an IFRAME tag for loading the JSONP script</summary>
+ /// <param name="url" type="String">The source URL of the script</param>
+ /// <returns type="HTMLElement">The IFRAME tag</returns>
+ var iframe = window.document.createElement("IFRAME");
+ iframe.style.display = "none";
+
+ var attributeEncodedUrl = url.replace(/&/g, "&").replace(/"/g, """).replace(/\</g, "<");
+ var html = "<html><head><script type=\"text/javascript\" src=\"" + attributeEncodedUrl + "\"><\/script><\/head><body><\/body><\/html>";
+
+ var body = window.document.getElementsByTagName("BODY")[0];
+ body.appendChild(iframe);
+
+ writeHtmlToIFrame(iframe, html);
+ return iframe;
+};
+
+var createXmlHttpRequest = function () {
+ /// <summary>Creates a XmlHttpRequest object.</summary>
+ /// <returns type="XmlHttpRequest">XmlHttpRequest object.</returns>
+ if (window.XMLHttpRequest) {
+ return new window.XMLHttpRequest();
+ }
+ var exception;
+ if (window.ActiveXObject) {
+ try {
+ return new window.ActiveXObject("Msxml2.XMLHTTP.6.0");
+ } catch (_) {
+ try {
+ return new window.ActiveXObject("Msxml2.XMLHTTP.3.0");
+ } catch (e) {
+ exception = e;
+ }
+ }
+ } else {
+ exception = { message: "XMLHttpRequest not supported" };
+ }
+ throw exception;
+};
+
+var isAbsoluteUrl = function (url) {
+ /// <summary>Checks whether the specified URL is an absolute URL.</summary>
+ /// <param name="url" type="String">URL to check.</param>
+ /// <returns type="Boolean">true if the url is an absolute URL; false otherwise.</returns>
+
+ return url.indexOf("http://") === 0 ||
+ url.indexOf("https://") === 0 ||
+ url.indexOf("file://") === 0;
+};
+
+var isLocalUrl = function (url) {
+ /// <summary>Checks whether the specified URL is local to the current context.</summary>
+ /// <param name="url" type="String">URL to check.</param>
+ /// <returns type="Boolean">true if the url is a local URL; false otherwise.</returns>
+
+ if (!isAbsoluteUrl(url)) {
+ return true;
+ }
+
+ // URL-embedded username and password will not be recognized as same-origin URLs.
+ var location = window.location;
+ var locationDomain = location.protocol + "//" + location.host + "/";
+ return (url.indexOf(locationDomain) === 0);
+};
+
+var removeCallback = function (name, tick) {
+ /// <summary>Removes a callback used for a JSONP request.</summary>
+ /// <param name="name" type="String">Function name to remove.</param>
+ /// <param name="tick" type="Number">Tick count used on the callback.</param>
+ try {
+ delete window[name];
+ } catch (err) {
+ window[name] = undefined;
+ if (tick === ticks - 1) {
+ ticks -= 1;
+ }
+ }
+};
+
+var removeIFrame = function (iframe) {
+ /// <summary>Removes an iframe.</summary>
+ /// <param name="iframe" type="Object">The iframe to remove.</param>
+ /// <returns type="Object">Null value to be assigned to iframe reference.</returns>
+ if (iframe) {
+ writeHtmlToIFrame(iframe, "");
+ iframe.parentNode.removeChild(iframe);
+ }
+
+ return null;
+};
+
+var readResponseHeaders = function (xhr, headers) {
+ /// <summary>Reads response headers into array.</summary>
+ /// <param name="xhr" type="XMLHttpRequest">HTTP request with response available.</param>
+ /// <param name="headers" type="Array">Target array to fill with name/value pairs.</param>
+
+ var responseHeaders = xhr.getAllResponseHeaders().split(/\r?\n/);
+ var i, len;
+ for (i = 0, len = responseHeaders.length; i < len; i++) {
+ if (responseHeaders[i]) {
+ var header = responseHeaders[i].split(": ");
+ headers[header[0]] = header[1];
+ }
+ }
+};
+
+var writeHtmlToIFrame = function (iframe, html) {
+ /// <summary>Writes HTML to an IFRAME document.</summary>
+ /// <param name="iframe" type="HTMLElement">The IFRAME element to write to.</param>
+ /// <param name="html" type="String">The HTML to write.</param>
+ var frameDocument = (iframe.contentWindow) ? iframe.contentWindow.document : iframe.contentDocument.document;
+ frameDocument.open();
+ frameDocument.write(html);
+ frameDocument.close();
+};
+
+exports.defaultHttpClient = {
+ callbackParameterName: "$callback",
+
+ formatQueryString: "$format=json",
+
+ enableJsonpCallback: false,
+
+ request: function (request, success, error) {
+ /// <summary>Performs a network request.</summary>
+ /// <param name="request" type="Object">Request description.</request>
+ /// <param name="success" type="Function">Success callback with the response object.</param>
+ /// <param name="error" type="Function">Error callback with an error object.</param>
+ /// <returns type="Object">Object with an 'abort' method for the operation.</returns>
+
+ var result = {};
+ var xhr = null;
+ var done = false;
+ var iframe;
+
+ result.abort = function () {
+ iframe = removeIFrame(iframe);
+ if (done) {
+ return;
+ }
+
+ done = true;
+ if (xhr) {
+ xhr.abort();
+ xhr = null;
+ }
+
+ error({ message: "Request aborted" });
+ };
+
+ var handleTimeout = function () {
+ iframe = removeIFrame(iframe);
+ if (!done) {
+ done = true;
+ xhr = null;
+ error({ message: "Request timed out" });
+ }
+ };
+
+ var name;
+ var url = request.requestUri;
+ var enableJsonpCallback = defined(request.enableJsonpCallback, this.enableJsonpCallback);
+ var callbackParameterName = defined(request.callbackParameterName, this.callbackParameterName);
+ var formatQueryString = defined(request.formatQueryString, this.formatQueryString);
+ if (!enableJsonpCallback || isLocalUrl(url)) {
+
+ xhr = createXmlHttpRequest();
+ xhr.onreadystatechange = function () {
+ if (done || xhr === null || xhr.readyState !== 4) {
+ return;
+ }
+
+ // Workaround for XHR behavior on IE.
+ var statusText = xhr.statusText;
+ var statusCode = xhr.status;
+ if (statusCode === 1223) {
+ statusCode = 204;
+ statusText = "No Content";
+ }
+
+ var headers = [];
+ readResponseHeaders(xhr, headers);
+
+ var response = { requestUri: url, statusCode: statusCode, statusText: statusText, headers: headers, body: xhr.responseText };
+
+ done = true;
+ xhr = null;
+ if (statusCode >= 200 && statusCode <= 299) {
+ success(response);
+ } else {
+ error({ message: "HTTP request failed", request: request, response: response });
+ }
+ };
+
+ xhr.open(request.method || "GET", url, true, request.user, request.password);
+
+ // Set the name/value pairs.
+ if (request.headers) {
+ for (name in request.headers) {
+ xhr.setRequestHeader(name, request.headers[name]);
+ }
+ }
+
+ // Set the timeout if available.
+ if (request.timeoutMS) {
+ xhr.timeout = request.timeoutMS;
+ xhr.ontimeout = handleTimeout;
+ }
+
+ xhr.send(request.body);
+ } else {
+ if (!canUseJSONP(request)) {
+ throw { message: "Request is not local and cannot be done through JSONP." };
+ }
+
+ var tick = ticks;
+ ticks += 1;
+ var tickText = tick.toString();
+ var succeeded = false;
+ var timeoutId;
+ name = "handleJSONP_" + tickText;
+ window[name] = function (data) {
+ iframe = removeIFrame(iframe);
+ if (!done) {
+ succeeded = true;
+ window.clearTimeout(timeoutId);
+ removeCallback(name, tick);
+
+ // Workaround for IE8 and IE10 below where trying to access data.constructor after the IFRAME has been removed
+ // throws an "unknown exception"
+ if (window.ActiveXObject) {
+ data = window.JSON.parse(window.JSON.stringify(data));
+ }
+
+
+ var headers;
+ // Adding dataServiceVersion in case of json light ( data.d doesn't exist )
+ if (data.d === undefined) {
+ headers = { "Content-Type": "application/json;odata=minimalmetadata", dataServiceVersion: "3.0" };
+ } else {
+ headers = { "Content-Type": "application/json" };
+ }
+ // Call the success callback in the context of the parent window, instead of the IFRAME
+ delay(function () {
+ removeIFrame(iframe);
+ success({ body: data, statusCode: 200, headers: headers });
+ });
+ }
+ };
+
+ // Default to two minutes before timing out, 1000 ms * 60 * 2 = 120000.
+ var timeoutMS = (request.timeoutMS) ? request.timeoutMS : 120000;
+ timeoutId = window.setTimeout(handleTimeout, timeoutMS);
+
+ var queryStringParams = callbackParameterName + "=parent." + name;
+ if (this.formatQueryString) {
+ queryStringParams += "&" + formatQueryString;
+ }
+
+ var qIndex = url.indexOf("?");
+ if (qIndex === -1) {
+ url = url + "?" + queryStringParams;
+ } else if (qIndex === url.length - 1) {
+ url = url + queryStringParams;
+ } else {
+ url = url + "&" + queryStringParams;
+ }
+
+ iframe = createIFrame(url);
+ }
+
+ return result;
+ }
+};
+
+// DATAJS INTERNAL START
+exports.canUseJSONP = canUseJSONP;
+exports.isAbsoluteUrl = isAbsoluteUrl;
+exports.isLocalUrl = isLocalUrl;
+// DATAJS INTERNAL END
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/lib/odata/request.js
----------------------------------------------------------------------
diff --git a/datajs/src/lib/odata/request.js b/datajs/src/lib/odata/request.js
new file mode 100644
index 0000000..fc6483a
--- /dev/null
+++ b/datajs/src/lib/odata/request.js
@@ -0,0 +1,84 @@
+
+var odataJson = require('./json.js');
+var odataNet = require('./net.js');
+var odataUtils = require('./utils.js');
+var odataHandler = require('./handler.js');
+var utils = require('./../datajs.js').utils;
+
+
+exports.defaultSuccess = function (data) {
+ /// <summary>Default success handler for OData.</summary>
+ /// <param name="data">Data to process.</param>
+
+ window.alert(window.JSON.stringify(data));
+};
+
+exports.defaultError = utils.throwErrorCallback;
+
+exports.defaultHandler = {
+ read: function (response, context) {
+ /// <summary>Reads the body of the specified response by delegating to JSON and ATOM handlers.</summary>
+ /// <param name="response">Response object.</param>
+ /// <param name="context">Operation context.</param>
+
+ if (response && assigned(response.body) && response.headers["Content-Type"]) {
+ dispatchHandler("read", response, context);
+ }
+ },
+
+ write: function (request, context) {
+ /// <summary>Write the body of the specified request by delegating to JSON and ATOM handlers.</summary>
+ /// <param name="request">Reques tobject.</param>
+ /// <param name="context">Operation context.</param>
+
+ dispatchHandler("write", request, context);
+ },
+
+ maxDataServiceVersion: odataHandler.MAX_DATA_SERVICE_VERSION,
+ accept: "application/atomsvc+xml;q=0.8, application/json;odata=fullmetadata;q=0.7, application/json;q=0.5, */*;q=0.1"
+};
+
+exports.defaultMetadata = [];
+
+
+exports.request = function (request, success, error, handler, httpClient, metadata) {
+ /// <summary>Sends a request containing OData payload to a server.</summary>
+ /// <param name="request" type="Object">Object that represents the request to be sent.</param>
+ /// <param name="success" type="Function" optional="true">Callback for a successful read operation.</param>
+ /// <param name="error" type="Function" optional="true">Callback for handling errors.</param>
+ /// <param name="handler" type="Object" optional="true">Handler for data serialization.</param>
+ /// <param name="httpClient" type="Object" optional="true">HTTP client layer.</param>
+ /// <param name="metadata" type="Object" optional="true">Conceptual metadata for this request.</param>
+
+ success = success || exports.defaultSuccess;
+ error = error || exports.defaultError;
+ handler = handler || exports.defaultHandler;
+ httpClient = httpClient || odataNet.defaultHttpClient;
+ metadata = metadata || exports.defaultMetadata;
+
+ // Augment the request with additional defaults.
+ request.recognizeDates = utils.defined(request.recognizeDates, odataJson.jsonHandler.recognizeDates);
+ request.callbackParameterName = utils.defined(request.callbackParameterName, odataNet.defaultHttpClient.callbackParameterName);
+ request.formatQueryString = utils.defined(request.formatQueryString, odataNet.defaultHttpClient.formatQueryString);
+ request.enableJsonpCallback = utils.defined(request.enableJsonpCallback, odataNet.defaultHttpClient.enableJsonpCallback);
+ request.useJsonLight = utils.defined(request.useJsonLight, odataJson.jsonHandler.useJsonLight);
+ request.inferJsonLightFeedAsObject = utils.defined(request.inferJsonLightFeedAsObject, odataJson.jsonHandler.inferJsonLightFeedAsObject);
+
+ // Create the base context for read/write operations, also specifying complete settings.
+ var context = {
+ metadata: metadata,
+ recognizeDates: request.recognizeDates,
+ callbackParameterName: request.callbackParameterName,
+ formatQueryString: request.formatQueryString,
+ enableJsonpCallback: request.enableJsonpCallback,
+ useJsonLight: request.useJsonLight,
+ inferJsonLightFeedAsObject: request.inferJsonLightFeedAsObject
+ };
+
+ try {
+ odataUtils.prepareRequest(request, handler, context);
+ return odataUtils.invokeRequest(request, success, error, handler, httpClient, context);
+ } catch (err) {
+ error(err);
+ }
+};
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/lib/odata/utils.js
----------------------------------------------------------------------
diff --git a/datajs/src/lib/odata/utils.js b/datajs/src/lib/odata/utils.js
new file mode 100644
index 0000000..2de078d
--- /dev/null
+++ b/datajs/src/lib/odata/utils.js
@@ -0,0 +1,1110 @@
+//SK name /odata/odata-utils.js
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// odata-utils.js
+var utils = require('./../datajs.js').utils;
+
+// Imports
+var assigned = utils.assigned;
+var contains = utils.contains;
+var find = utils.find;
+var isArray = utils.isArray;
+var isDate = utils.isDate;
+var isObject = utils.isObject;
+var parseInt10 = utils.parseInt10;
+
+// CONTENT START
+
+var dataItemTypeName = function (value, metadata) {
+ /// <summary>Gets the type name of a data item value that belongs to a feed, an entry, a complex type property, or a collection property.</summary>
+ /// <param name="value">Value of the data item from which the type name is going to be retrieved.</param>
+ /// <param name="metadata" type="object" optional="true">Object containing metadata about the data tiem.</param>
+ /// <remarks>
+ /// This function will first try to get the type name from the data item's value itself if it is an object with a __metadata property; otherwise
+ /// it will try to recover it from the metadata. If both attempts fail, it will return null.
+ /// </remarks>
+ /// <returns type="String">Data item type name; null if the type name cannot be found within the value or the metadata</returns>
+
+ var valueTypeName = ((value && value.__metadata) || {}).type;
+ return valueTypeName || (metadata ? metadata.type : null);
+};
+
+var EDM = "Edm.";
+var EDM_BINARY = EDM + "Binary";
+var EDM_BOOLEAN = EDM + "Boolean";
+var EDM_BYTE = EDM + "Byte";
+var EDM_DATETIME = EDM + "DateTime";
+var EDM_DATETIMEOFFSET = EDM + "DateTimeOffset";
+var EDM_DECIMAL = EDM + "Decimal";
+var EDM_DOUBLE = EDM + "Double";
+var EDM_GUID = EDM + "Guid";
+var EDM_INT16 = EDM + "Int16";
+var EDM_INT32 = EDM + "Int32";
+var EDM_INT64 = EDM + "Int64";
+var EDM_SBYTE = EDM + "SByte";
+var EDM_SINGLE = EDM + "Single";
+var EDM_STRING = EDM + "String";
+var EDM_TIME = EDM + "Time";
+
+var EDM_GEOGRAPHY = EDM + "Geography";
+var EDM_GEOGRAPHY_POINT = EDM_GEOGRAPHY + "Point";
+var EDM_GEOGRAPHY_LINESTRING = EDM_GEOGRAPHY + "LineString";
+var EDM_GEOGRAPHY_POLYGON = EDM_GEOGRAPHY + "Polygon";
+var EDM_GEOGRAPHY_COLLECTION = EDM_GEOGRAPHY + "Collection";
+var EDM_GEOGRAPHY_MULTIPOLYGON = EDM_GEOGRAPHY + "MultiPolygon";
+var EDM_GEOGRAPHY_MULTILINESTRING = EDM_GEOGRAPHY + "MultiLineString";
+var EDM_GEOGRAPHY_MULTIPOINT = EDM_GEOGRAPHY + "MultiPoint";
+
+var EDM_GEOMETRY = EDM + "Geometry";
+var EDM_GEOMETRY_POINT = EDM_GEOMETRY + "Point";
+var EDM_GEOMETRY_LINESTRING = EDM_GEOMETRY + "LineString";
+var EDM_GEOMETRY_POLYGON = EDM_GEOMETRY + "Polygon";
+var EDM_GEOMETRY_COLLECTION = EDM_GEOMETRY + "Collection";
+var EDM_GEOMETRY_MULTIPOLYGON = EDM_GEOMETRY + "MultiPolygon";
+var EDM_GEOMETRY_MULTILINESTRING = EDM_GEOMETRY + "MultiLineString";
+var EDM_GEOMETRY_MULTIPOINT = EDM_GEOMETRY + "MultiPoint";
+
+var GEOJSON_POINT = "Point";
+var GEOJSON_LINESTRING = "LineString";
+var GEOJSON_POLYGON = "Polygon";
+var GEOJSON_MULTIPOINT = "MultiPoint";
+var GEOJSON_MULTILINESTRING = "MultiLineString";
+var GEOJSON_MULTIPOLYGON = "MultiPolygon";
+var GEOJSON_GEOMETRYCOLLECTION = "GeometryCollection";
+
+var primitiveEdmTypes = [
+ EDM_STRING,
+ EDM_INT32,
+ EDM_INT64,
+ EDM_BOOLEAN,
+ EDM_DOUBLE,
+ EDM_SINGLE,
+ EDM_DATETIME,
+ EDM_DATETIMEOFFSET,
+ EDM_TIME,
+ EDM_DECIMAL,
+ EDM_GUID,
+ EDM_BYTE,
+ EDM_INT16,
+ EDM_SBYTE,
+ EDM_BINARY
+];
+
+var geometryEdmTypes = [
+ EDM_GEOMETRY,
+ EDM_GEOMETRY_POINT,
+ EDM_GEOMETRY_LINESTRING,
+ EDM_GEOMETRY_POLYGON,
+ EDM_GEOMETRY_COLLECTION,
+ EDM_GEOMETRY_MULTIPOLYGON,
+ EDM_GEOMETRY_MULTILINESTRING,
+ EDM_GEOMETRY_MULTIPOINT
+];
+
+var geographyEdmTypes = [
+ EDM_GEOGRAPHY,
+ EDM_GEOGRAPHY_POINT,
+ EDM_GEOGRAPHY_LINESTRING,
+ EDM_GEOGRAPHY_POLYGON,
+ EDM_GEOGRAPHY_COLLECTION,
+ EDM_GEOGRAPHY_MULTIPOLYGON,
+ EDM_GEOGRAPHY_MULTILINESTRING,
+ EDM_GEOGRAPHY_MULTIPOINT
+];
+
+var forEachSchema = function (metadata, callback) {
+ /// <summary>Invokes a function once per schema in metadata.</summary>
+ /// <param name="metadata">Metadata store; one of edmx, schema, or an array of any of them.</param>
+ /// <param name="callback" type="Function">Callback function to invoke once per schema.</param>
+ /// <returns>
+ /// The first truthy value to be returned from the callback; null or the last falsy value otherwise.
+ /// </returns>
+
+ if (!metadata) {
+ return null;
+ }
+
+ if (isArray(metadata)) {
+ var i, len, result;
+ for (i = 0, len = metadata.length; i < len; i++) {
+ result = forEachSchema(metadata[i], callback);
+ if (result) {
+ return result;
+ }
+ }
+
+ return null;
+ } else {
+ if (metadata.dataServices) {
+ return forEachSchema(metadata.dataServices.schema, callback);
+ }
+
+ return callback(metadata);
+ }
+};
+
+var formatMilliseconds = function (ms, ns) {
+ /// <summary>Formats a millisecond and a nanosecond value into a single string.</summary>
+ /// <param name="ms" type="Number" mayBeNull="false">Number of milliseconds to format.</param>
+ /// <param name="ns" type="Number" mayBeNull="false">Number of nanoseconds to format.</param>
+ /// <returns type="String">Formatted text.</returns>
+ /// <remarks>If the value is already as string it's returned as-is.</remarks>
+
+ // Avoid generating milliseconds if not necessary.
+ if (ms === 0) {
+ ms = "";
+ } else {
+ ms = "." + formatNumberWidth(ms.toString(), 3);
+ }
+ if (ns > 0) {
+ if (ms === "") {
+ ms = ".000";
+ }
+ ms += formatNumberWidth(ns.toString(), 4);
+ }
+ return ms;
+};
+
+var formatDateTimeOffset = function (value) {
+ /// <summary>Formats a DateTime or DateTimeOffset value a string.</summary>
+ /// <param name="value" type="Date" mayBeNull="false">Value to format.</param>
+ /// <returns type="String">Formatted text.</returns>
+ /// <remarks>If the value is already as string it's returned as-is.</remarks>
+
+ if (typeof value === "string") {
+ return value;
+ }
+
+ var hasOffset = isDateTimeOffset(value);
+ var offset = getCanonicalTimezone(value.__offset);
+ if (hasOffset && offset !== "Z") {
+ // We're about to change the value, so make a copy.
+ value = new Date(value.valueOf());
+
+ var timezone = parseTimezone(offset);
+ var hours = value.getUTCHours() + (timezone.d * timezone.h);
+ var minutes = value.getUTCMinutes() + (timezone.d * timezone.m);
+
+ value.setUTCHours(hours, minutes);
+ } else if (!hasOffset) {
+ // Don't suffix a 'Z' for Edm.DateTime values.
+ offset = "";
+ }
+
+ var year = value.getUTCFullYear();
+ var month = value.getUTCMonth() + 1;
+ var sign = "";
+ if (year <= 0) {
+ year = -(year - 1);
+ sign = "-";
+ }
+
+ var ms = formatMilliseconds(value.getUTCMilliseconds(), value.__ns);
+
+ return sign +
+ formatNumberWidth(year, 4) + "-" +
+ formatNumberWidth(month, 2) + "-" +
+ formatNumberWidth(value.getUTCDate(), 2) + "T" +
+ formatNumberWidth(value.getUTCHours(), 2) + ":" +
+ formatNumberWidth(value.getUTCMinutes(), 2) + ":" +
+ formatNumberWidth(value.getUTCSeconds(), 2) +
+ ms + offset;
+};
+
+var formatDuration = function (value) {
+ /// <summary>Converts a duration to a string in xsd:duration format.</summary>
+ /// <param name="value" type="Object">Object with ms and __edmType properties.</param>
+ /// <returns type="String">String representation of the time object in xsd:duration format.</returns>
+
+ var ms = value.ms;
+
+ var sign = "";
+ if (ms < 0) {
+ sign = "-";
+ ms = -ms;
+ }
+
+ var days = Math.floor(ms / 86400000);
+ ms -= 86400000 * days;
+ var hours = Math.floor(ms / 3600000);
+ ms -= 3600000 * hours;
+ var minutes = Math.floor(ms / 60000);
+ ms -= 60000 * minutes;
+ var seconds = Math.floor(ms / 1000);
+ ms -= seconds * 1000;
+
+ return sign + "P" +
+ formatNumberWidth(days, 2) + "DT" +
+ formatNumberWidth(hours, 2) + "H" +
+ formatNumberWidth(minutes, 2) + "M" +
+ formatNumberWidth(seconds, 2) +
+ formatMilliseconds(ms, value.ns) + "S";
+};
+
+var formatNumberWidth = function (value, width, append) {
+ /// <summary>Formats the specified value to the given width.</summary>
+ /// <param name="value" type="Number">Number to format (non-negative).</param>
+ /// <param name="width" type="Number">Minimum width for number.</param>
+ /// <param name="append" type="Boolean">Flag indicating if the value is padded at the beginning (false) or at the end (true).</param>
+ /// <returns type="String">Text representation.</returns>
+ var result = value.toString(10);
+ while (result.length < width) {
+ if (append) {
+ result += "0";
+ } else {
+ result = "0" + result;
+ }
+ }
+
+ return result;
+};
+
+var getCanonicalTimezone = function (timezone) {
+ /// <summary>Gets the canonical timezone representation.</summary>
+ /// <param name="timezone" type="String">Timezone representation.</param>
+ /// <returns type="String">An 'Z' string if the timezone is absent or 0; the timezone otherwise.</returns>
+
+ return (!timezone || timezone === "Z" || timezone === "+00:00" || timezone === "-00:00") ? "Z" : timezone;
+};
+
+var getCollectionType = function (typeName) {
+ /// <summary>Gets the type of a collection type name.</summary>
+ /// <param name="typeName" type="String">Type name of the collection.</param>
+ /// <returns type="String">Type of the collection; null if the type name is not a collection type.</returns>
+
+ if (typeof typeName === "string") {
+ var end = typeName.indexOf(")", 10);
+ if (typeName.indexOf("Collection(") === 0 && end > 0) {
+ return typeName.substring(11, end);
+ }
+ }
+ return null;
+};
+
+var invokeRequest = function (request, success, error, handler, httpClient, context) {
+ /// <summary>Sends a request containing OData payload to a server.</summary>
+ /// <param name="request">Object that represents the request to be sent..</param>
+ /// <param name="success">Callback for a successful read operation.</param>
+ /// <param name="error">Callback for handling errors.</param>
+ /// <param name="handler">Handler for data serialization.</param>
+ /// <param name="httpClient">HTTP client layer.</param>
+ /// <param name="context">Context used for processing the request</param>
+
+ return httpClient.request(request, function (response) {
+ try {
+ if (response.headers) {
+ normalizeHeaders(response.headers);
+ }
+
+ if (response.data === undefined && response.statusCode !== 204) {
+ handler.read(response, context);
+ }
+ } catch (err) {
+ if (err.request === undefined) {
+ err.request = request;
+ }
+ if (err.response === undefined) {
+ err.response = response;
+ }
+ error(err);
+ return;
+ }
+
+ success(response.data, response);
+ }, error);
+};
+
+var isBatch = function (value) {
+ /// <summary>Tests whether a value is a batch object in the library's internal representation.</summary>
+ /// <param name="value">Value to test.</param>
+ /// <returns type="Boolean">True is the value is a batch object; false otherwise.</returns>
+
+ return isComplex(value) && isArray(value.__batchRequests);
+};
+
+// Regular expression used for testing and parsing for a collection type.
+var collectionTypeRE = /Collection\((.*)\)/;
+
+var isCollection = function (value, typeName) {
+ /// <summary>Tests whether a value is a collection value in the library's internal representation.</summary>
+ /// <param name="value">Value to test.</param>
+ /// <param name="typeName" type="Sting">Type name of the value. This is used to disambiguate from a collection property value.</param>
+ /// <returns type="Boolean">True is the value is a feed value; false otherwise.</returns>
+
+ var colData = value && value.results || value;
+ return !!colData &&
+ (isCollectionType(typeName)) ||
+ (!typeName && isArray(colData) && !isComplex(colData[0]));
+};
+
+var isCollectionType = function (typeName) {
+ /// <summary>Checks whether the specified type name is a collection type.</summary>
+ /// <param name="typeName" type="String">Name of type to check.</param>
+ /// <returns type="Boolean">True if the type is the name of a collection type; false otherwise.</returns>
+ return collectionTypeRE.test(typeName);
+};
+
+var isComplex = function (value) {
+ /// <summary>Tests whether a value is a complex type value in the library's internal representation.</summary>
+ /// <param name="value">Value to test.</param>
+ /// <returns type="Boolean">True is the value is a complex type value; false otherwise.</returns>
+
+ return !!value &&
+ isObject(value) &&
+ !isArray(value) &&
+ !isDate(value);
+};
+
+var isDateTimeOffset = function (value) {
+ /// <summary>Checks whether a Date object is DateTimeOffset value</summary>
+ /// <param name="value" type="Date" mayBeNull="false">Value to check.</param>
+ /// <returns type="Boolean">true if the value is a DateTimeOffset, false otherwise.</returns>
+ return (value.__edmType === "Edm.DateTimeOffset" || (!value.__edmType && value.__offset));
+};
+
+var isDeferred = function (value) {
+ /// <summary>Tests whether a value is a deferred navigation property in the library's internal representation.</summary>
+ /// <param name="value">Value to test.</param>
+ /// <returns type="Boolean">True is the value is a deferred navigation property; false otherwise.</returns>
+
+ if (!value && !isComplex(value)) {
+ return false;
+ }
+ var metadata = value.__metadata || {};
+ var deferred = value.__deferred || {};
+ return !metadata.type && !!deferred.uri;
+};
+
+var isEntry = function (value) {
+ /// <summary>Tests whether a value is an entry object in the library's internal representation.</summary>
+ /// <param name="value">Value to test.</param>
+ /// <returns type="Boolean">True is the value is an entry object; false otherwise.</returns>
+
+ return isComplex(value) && value.__metadata && "uri" in value.__metadata;
+};
+
+var isFeed = function (value, typeName) {
+ /// <summary>Tests whether a value is a feed value in the library's internal representation.</summary>
+ /// <param name="value">Value to test.</param>
+ /// <param name="typeName" type="Sting">Type name of the value. This is used to disambiguate from a collection property value.</param>
+ /// <returns type="Boolean">True is the value is a feed value; false otherwise.</returns>
+
+ var feedData = value && value.results || value;
+ return isArray(feedData) && (
+ (!isCollectionType(typeName)) &&
+ (isComplex(feedData[0]))
+ );
+};
+
+var isGeographyEdmType = function (typeName) {
+ /// <summary>Checks whether the specified type name is a geography EDM type.</summary>
+ /// <param name="typeName" type="String">Name of type to check.</param>
+ /// <returns type="Boolean">True if the type is a geography EDM type; false otherwise.</returns>
+
+ return contains(geographyEdmTypes, typeName);
+};
+
+var isGeometryEdmType = function (typeName) {
+ /// <summary>Checks whether the specified type name is a geometry EDM type.</summary>
+ /// <param name="typeName" type="String">Name of type to check.</param>
+ /// <returns type="Boolean">True if the type is a geometry EDM type; false otherwise.</returns>
+
+ return contains(geometryEdmTypes, typeName);
+};
+
+var isNamedStream = function (value) {
+ /// <summary>Tests whether a value is a named stream value in the library's internal representation.</summary>
+ /// <param name="value">Value to test.</param>
+ /// <returns type="Boolean">True is the value is a named stream; false otherwise.</returns>
+
+ if (!value && !isComplex(value)) {
+ return false;
+ }
+ var metadata = value.__metadata;
+ var mediaResource = value.__mediaresource;
+ return !metadata && !!mediaResource && !!mediaResource.media_src;
+};
+
+var isPrimitive = function (value) {
+ /// <summary>Tests whether a value is a primitive type value in the library's internal representation.</summary>
+ /// <param name="value">Value to test.</param>
+ /// <remarks>
+ /// Date objects are considered primitive types by the library.
+ /// </remarks>
+ /// <returns type="Boolean">True is the value is a primitive type value.</returns>
+
+ return isDate(value) ||
+ typeof value === "string" ||
+ typeof value === "number" ||
+ typeof value === "boolean";
+};
+
+var isPrimitiveEdmType = function (typeName) {
+ /// <summary>Checks whether the specified type name is a primitive EDM type.</summary>
+ /// <param name="typeName" type="String">Name of type to check.</param>
+ /// <returns type="Boolean">True if the type is a primitive EDM type; false otherwise.</returns>
+
+ return contains(primitiveEdmTypes, typeName);
+};
+
+var navigationPropertyKind = function (value, propertyModel) {
+ /// <summary>Gets the kind of a navigation property value.</summary>
+ /// <param name="value">Value of the navigation property.</param>
+ /// <param name="propertyModel" type="Object" optional="true">
+ /// Object that describes the navigation property in an OData conceptual schema.
+ /// </param>
+ /// <remarks>
+ /// The returned string is as follows
+ /// </remarks>
+ /// <returns type="String">String value describing the kind of the navigation property; null if the kind cannot be determined.</returns>
+
+ if (isDeferred(value)) {
+ return "deferred";
+ }
+ if (isEntry(value)) {
+ return "entry";
+ }
+ if (isFeed(value)) {
+ return "feed";
+ }
+ if (propertyModel && propertyModel.relationship) {
+ if (value === null || value === undefined || !isFeed(value)) {
+ return "entry";
+ }
+ return "feed";
+ }
+ return null;
+};
+
+var lookupProperty = function (properties, name) {
+ /// <summary>Looks up a property by name.</summary>
+ /// <param name="properties" type="Array" mayBeNull="true">Array of property objects as per EDM metadata.</param>
+ /// <param name="name" type="String">Name to look for.</param>
+ /// <returns type="Object">The property object; null if not found.</returns>
+
+ return find(properties, function (property) {
+ return property.name === name;
+ });
+};
+
+var lookupInMetadata = function (name, metadata, kind) {
+ /// <summary>Looks up a type object by name.</summary>
+ /// <param name="name" type="String">Name, possibly null or empty.</param>
+ /// <param name="metadata">Metadata store; one of edmx, schema, or an array of any of them.</param>
+ /// <param name="kind" type="String">Kind of object to look for as per EDM metadata.</param>
+ /// <returns>An type description if the name is found; null otherwise.</returns>
+
+ return (name) ? forEachSchema(metadata, function (schema) {
+ return lookupInSchema(name, schema, kind);
+ }) : null;
+};
+
+var lookupEntitySet = function (entitySets, name) {
+ /// <summary>Looks up a entity set by name.</summary>
+ /// <param name="properties" type="Array" mayBeNull="true">Array of entity set objects as per EDM metadata.</param>
+ /// <param name="name" type="String">Name to look for.</param>
+ /// <returns type="Object">The entity set object; null if not found.</returns>
+
+ return find(entitySets, function (entitySet) {
+ return entitySet.name === name;
+ });
+};
+
+var lookupComplexType = function (name, metadata) {
+ /// <summary>Looks up a complex type object by name.</summary>
+ /// <param name="name" type="String">Name, possibly null or empty.</param>
+ /// <param name="metadata">Metadata store; one of edmx, schema, or an array of any of them.</param>
+ /// <returns>A complex type description if the name is found; null otherwise.</returns>
+
+ return lookupInMetadata(name, metadata, "complexType");
+};
+
+var lookupEntityType = function (name, metadata) {
+ /// <summary>Looks up an entity type object by name.</summary>
+ /// <param name="name" type="String">Name, possibly null or empty.</param>
+ /// <param name="metadata">Metadata store; one of edmx, schema, or an array of any of them.</param>
+ /// <returns>An entity type description if the name is found; null otherwise.</returns>
+
+ return lookupInMetadata(name, metadata, "entityType");
+};
+
+var lookupDefaultEntityContainer = function (metadata) {
+ /// <summary>Looks up an</summary>
+ /// <param name="name" type="String">Name, possibly null or empty.</param>
+ /// <param name="metadata">Metadata store; one of edmx, schema, or an array of any of them.</param>
+ /// <returns>An entity container description if the name is found; null otherwise.</returns>
+
+ return forEachSchema(metadata, function (schema) {
+ return find(schema.entityContainer, function (container) {
+ return parseBool(container.isDefaultEntityContainer);
+ });
+ });
+};
+
+var lookupEntityContainer = function (name, metadata) {
+ /// <summary>Looks up an entity container object by name.</summary>
+ /// <param name="name" type="String">Name, possibly null or empty.</param>
+ /// <param name="metadata">Metadata store; one of edmx, schema, or an array of any of them.</param>
+ /// <returns>An entity container description if the name is found; null otherwise.</returns>
+
+ return lookupInMetadata(name, metadata, "entityContainer");
+};
+
+var lookupFunctionImport = function (functionImports, name) {
+ /// <summary>Looks up a function import by name.</summary>
+ /// <param name="properties" type="Array" mayBeNull="true">Array of function import objects as per EDM metadata.</param>
+ /// <param name="name" type="String">Name to look for.</param>
+ /// <returns type="Object">The entity set object; null if not found.</returns>
+
+ return find(functionImports, function (functionImport) {
+ return functionImport.name === name;
+ });
+};
+
+var lookupNavigationPropertyType = function (navigationProperty, metadata) {
+ /// <summary>Looks up the target entity type for a navigation property.</summary>
+ /// <param name="navigationProperty" type="Object"></param>
+ /// <param name="metadata" type="Object"></param>
+ /// <returns type="String">The entity type name for the specified property, null if not found.</returns>
+
+ var result = null;
+ if (navigationProperty) {
+ var rel = navigationProperty.relationship;
+ var association = forEachSchema(metadata, function (schema) {
+ // The name should be the namespace qualified name in 'ns'.'type' format.
+ var nameOnly = removeNamespace(schema["namespace"], rel);
+ var associations = schema.association;
+ if (nameOnly && associations) {
+ var i, len;
+ for (i = 0, len = associations.length; i < len; i++) {
+ if (associations[i].name === nameOnly) {
+ return associations[i];
+ }
+ }
+ }
+ return null;
+ });
+
+ if (association) {
+ var end = association.end[0];
+ if (end.role !== navigationProperty.toRole) {
+ end = association.end[1];
+ // For metadata to be valid, end.role === navigationProperty.toRole now.
+ }
+ result = end.type;
+ }
+ }
+ return result;
+};
+
+var lookupNavigationPropertyEntitySet = function (navigationProperty, sourceEntitySetName, metadata) {
+ /// <summary>Looks up the target entityset name for a navigation property.</summary>
+ /// <param name="navigationProperty" type="Object"></param>
+ /// <param name="metadata" type="Object"></param>
+ /// <returns type="String">The entityset name for the specified property, null if not found.</returns>
+
+ if (navigationProperty) {
+ var rel = navigationProperty.relationship;
+ var associationSet = forEachSchema(metadata, function (schema) {
+ var containers = schema.entityContainer;
+ for (var i = 0; i < containers.length; i++) {
+ var associationSets = containers[i].associationSet;
+ if (associationSets) {
+ for (var j = 0; j < associationSets.length; j++) {
+ if (associationSets[j].association == rel) {
+ return associationSets[j];
+ }
+ }
+ }
+ }
+ return null;
+ });
+ if (associationSet && associationSet.end[0] && associationSet.end[1]) {
+ return (associationSet.end[0].entitySet == sourceEntitySetName) ? associationSet.end[1].entitySet : associationSet.end[0].entitySet;
+ }
+ }
+ return null;
+};
+
+var getEntitySetInfo = function (entitySetName, metadata) {
+ /// <summary>Gets the entitySet info, container name and functionImports for an entitySet</summary>
+ /// <param name="navigationProperty" type="Object"></param>
+ /// <param name="metadata" type="Object"></param>
+ /// <returns type="Object">The info about the entitySet.</returns>
+
+ var info = forEachSchema(metadata, function (schema) {
+ var containers = schema.entityContainer;
+ for (var i = 0; i < containers.length; i++) {
+ var entitySets = containers[i].entitySet;
+ if (entitySets) {
+ for (var j = 0; j < entitySets.length; j++) {
+ if (entitySets[j].name == entitySetName) {
+ return { entitySet: entitySets[j], containerName: containers[i].name, functionImport: containers[i].functionImport };
+ }
+ }
+ }
+ }
+ return null;
+ });
+
+ return info;
+};
+
+var removeNamespace = function (ns, fullName) {
+ /// <summary>Given an expected namespace prefix, removes it from a full name.</summary>
+ /// <param name="ns" type="String">Expected namespace.</param>
+ /// <param name="fullName" type="String">Full name in 'ns'.'name' form.</param>
+ /// <returns type="String">The local name, null if it isn't found in the expected namespace.</returns>
+
+ if (fullName.indexOf(ns) === 0 && fullName.charAt(ns.length) === ".") {
+ return fullName.substr(ns.length + 1);
+ }
+
+ return null;
+};
+
+var lookupInSchema = function (name, schema, kind) {
+ /// <summary>Looks up a schema object by name.</summary>
+ /// <param name="name" type="String">Name (assigned).</param>
+ /// <param name="schema">Schema object as per EDM metadata.</param>
+ /// <param name="kind" type="String">Kind of object to look for as per EDM metadata.</param>
+ /// <returns>An entity type description if the name is found; null otherwise.</returns>
+
+ if (name && schema) {
+ // The name should be the namespace qualified name in 'ns'.'type' format.
+ var nameOnly = removeNamespace(schema["namespace"], name);
+ if (nameOnly) {
+ return find(schema[kind], function (item) {
+ return item.name === nameOnly;
+ });
+ }
+ }
+ return null;
+};
+
+var maxVersion = function (left, right) {
+ /// <summary>Compares to version strings and returns the higher one.</summary>
+ /// <param name="left" type="String">Version string in the form "major.minor.rev"</param>
+ /// <param name="right" type="String">Version string in the form "major.minor.rev"</param>
+ /// <returns type="String">The higher version string.</returns>
+
+ if (left === right) {
+ return left;
+ }
+
+ var leftParts = left.split(".");
+ var rightParts = right.split(".");
+
+ var len = (leftParts.length >= rightParts.length) ?
+ leftParts.length :
+ rightParts.length;
+
+ for (var i = 0; i < len; i++) {
+ var leftVersion = leftParts[i] && parseInt10(leftParts[i]);
+ var rightVersion = rightParts[i] && parseInt10(rightParts[i]);
+ if (leftVersion > rightVersion) {
+ return left;
+ }
+ if (leftVersion < rightVersion) {
+ return right;
+ }
+ }
+};
+
+var normalHeaders = {
+ "accept": "Accept",
+ "content-type": "Content-Type",
+ "dataserviceversion": "DataServiceVersion",
+ "maxdataserviceversion": "MaxDataServiceVersion"
+};
+
+var normalizeHeaders = function (headers) {
+ /// <summary>Normalizes headers so they can be found with consistent casing.</summary>
+ /// <param name="headers" type="Object">Dictionary of name/value pairs.</param>
+
+ for (var name in headers) {
+ var lowerName = name.toLowerCase();
+ var normalName = normalHeaders[lowerName];
+ if (normalName && name !== normalName) {
+ var val = headers[name];
+ delete headers[name];
+ headers[normalName] = val;
+ }
+ }
+};
+
+var parseBool = function (propertyValue) {
+ /// <summary>Parses a string into a boolean value.</summary>
+ /// <param name="propertyValue">Value to parse.</param>
+ /// <returns type="Boolean">true if the property value is 'true'; false otherwise.</returns>
+
+ if (typeof propertyValue === "boolean") {
+ return propertyValue;
+ }
+
+ return typeof propertyValue === "string" && propertyValue.toLowerCase() === "true";
+};
+
+
+// The captured indices for this expression are:
+// 0 - complete input
+// 1,2,3 - year with optional minus sign, month, day
+// 4,5,6 - hours, minutes, seconds
+// 7 - optional milliseconds
+// 8 - everything else (presumably offset information)
+var parseDateTimeRE = /^(-?\d{4,})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2}))?(?:\.(\d+))?(.*)$/;
+
+var parseDateTimeMaybeOffset = function (value, withOffset, nullOnError) {
+ /// <summary>Parses a string into a DateTime value.</summary>
+ /// <param name="value" type="String">Value to parse.</param>
+ /// <param name="withOffset" type="Boolean">Whether offset is expected.</param>
+ /// <returns type="Date">The parsed value.</returns>
+
+ // We cannot parse this in cases of failure to match or if offset information is specified.
+ var parts = parseDateTimeRE.exec(value);
+ var offset = (parts) ? getCanonicalTimezone(parts[8]) : null;
+
+ if (!parts || (!withOffset && offset !== "Z")) {
+ if (nullOnError) {
+ return null;
+ }
+ throw { message: "Invalid date/time value" };
+ }
+
+ // Pre-parse years, account for year '0' being invalid in dateTime.
+ var year = parseInt10(parts[1]);
+ if (year <= 0) {
+ year++;
+ }
+
+ // Pre-parse optional milliseconds, fill in default. Fail if value is too precise.
+ var ms = parts[7];
+ var ns = 0;
+ if (!ms) {
+ ms = 0;
+ } else {
+ if (ms.length > 7) {
+ if (nullOnError) {
+ return null;
+ }
+ throw { message: "Cannot parse date/time value to given precision." };
+ }
+
+ ns = formatNumberWidth(ms.substring(3), 4, true);
+ ms = formatNumberWidth(ms.substring(0, 3), 3, true);
+
+ ms = parseInt10(ms);
+ ns = parseInt10(ns);
+ }
+
+ // Pre-parse other time components and offset them if necessary.
+ var hours = parseInt10(parts[4]);
+ var minutes = parseInt10(parts[5]);
+ var seconds = parseInt10(parts[6]) || 0;
+ if (offset !== "Z") {
+ // The offset is reversed to get back the UTC date, which is
+ // what the API will eventually have.
+ var timezone = parseTimezone(offset);
+ var direction = -(timezone.d);
+ hours += timezone.h * direction;
+ minutes += timezone.m * direction;
+ }
+
+ // Set the date and time separately with setFullYear, so years 0-99 aren't biased like in Date.UTC.
+ var result = new Date();
+ result.setUTCFullYear(
+ year, // Year.
+ parseInt10(parts[2]) - 1, // Month (zero-based for Date.UTC and setFullYear).
+ parseInt10(parts[3]) // Date.
+ );
+ result.setUTCHours(hours, minutes, seconds, ms);
+
+ if (isNaN(result.valueOf())) {
+ if (nullOnError) {
+ return null;
+ }
+ throw { message: "Invalid date/time value" };
+ }
+
+ if (withOffset) {
+ result.__edmType = "Edm.DateTimeOffset";
+ result.__offset = offset;
+ }
+
+ if (ns) {
+ result.__ns = ns;
+ }
+
+ return result;
+};
+
+var parseDateTime = function (propertyValue, nullOnError) {
+ /// <summary>Parses a string into a DateTime value.</summary>
+ /// <param name="propertyValue" type="String">Value to parse.</param>
+ /// <returns type="Date">The parsed value.</returns>
+
+ return parseDateTimeMaybeOffset(propertyValue, false, nullOnError);
+};
+
+var parseDateTimeOffset = function (propertyValue, nullOnError) {
+ /// <summary>Parses a string into a DateTimeOffset value.</summary>
+ /// <param name="propertyValue" type="String">Value to parse.</param>
+ /// <returns type="Date">The parsed value.</returns>
+ /// <remarks>
+ /// The resulting object is annotated with an __edmType property and
+ /// an __offset property reflecting the original intended offset of
+ /// the value. The time is adjusted for UTC time, as the current
+ /// timezone-aware Date APIs will only work with the local timezone.
+ /// </remarks>
+
+ return parseDateTimeMaybeOffset(propertyValue, true, nullOnError);
+};
+
+// The captured indices for this expression are:
+// 0 - complete input
+// 1 - direction
+// 2,3,4 - years, months, days
+// 5,6,7,8 - hours, minutes, seconds, miliseconds
+
+var parseTimeRE = /^([+-])?P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)(?:\.(\d+))?S)?)?/;
+
+var isEdmDurationValue = function(value) {
+ parseTimeRE.test(value);
+};
+
+var parseDuration = function (duration) {
+ /// <summary>Parses a string in xsd:duration format.</summary>
+ /// <param name="duration" type="String">Duration value.</param>
+ /// <remarks>
+ /// This method will throw an exception if the input string has a year or a month component.
+ /// </remarks>
+ /// <returns type="Object">Object representing the time</returns>
+
+ var parts = parseTimeRE.exec(duration);
+
+ if (parts === null) {
+ throw { message: "Invalid duration value." };
+ }
+
+ var years = parts[2] || "0";
+ var months = parts[3] || "0";
+ var days = parseInt10(parts[4] || 0);
+ var hours = parseInt10(parts[5] || 0);
+ var minutes = parseInt10(parts[6] || 0);
+ var seconds = parseFloat(parts[7] || 0);
+
+ if (years !== "0" || months !== "0") {
+ throw { message: "Unsupported duration value." };
+ }
+
+ var ms = parts[8];
+ var ns = 0;
+ if (!ms) {
+ ms = 0;
+ } else {
+ if (ms.length > 7) {
+ throw { message: "Cannot parse duration value to given precision." };
+ }
+
+ ns = formatNumberWidth(ms.substring(3), 4, true);
+ ms = formatNumberWidth(ms.substring(0, 3), 3, true);
+
+ ms = parseInt10(ms);
+ ns = parseInt10(ns);
+ }
+
+ ms += seconds * 1000 + minutes * 60000 + hours * 3600000 + days * 86400000;
+
+ if (parts[1] === "-") {
+ ms = -ms;
+ }
+
+ var result = { ms: ms, __edmType: "Edm.Time" };
+
+ if (ns) {
+ result.ns = ns;
+ }
+ return result;
+};
+
+var parseTimezone = function (timezone) {
+ /// <summary>Parses a timezone description in (+|-)nn:nn format.</summary>
+ /// <param name="timezone" type="String">Timezone offset.</param>
+ /// <returns type="Object">
+ /// An object with a (d)irection property of 1 for + and -1 for -,
+ /// offset (h)ours and offset (m)inutes.
+ /// </returns>
+
+ var direction = timezone.substring(0, 1);
+ direction = (direction === "+") ? 1 : -1;
+
+ var offsetHours = parseInt10(timezone.substring(1));
+ var offsetMinutes = parseInt10(timezone.substring(timezone.indexOf(":") + 1));
+ return { d: direction, h: offsetHours, m: offsetMinutes };
+};
+
+var prepareRequest = function (request, handler, context) {
+ /// <summary>Prepares a request object so that it can be sent through the network.</summary>
+ /// <param name="request">Object that represents the request to be sent.</param>
+ /// <param name="handler">Handler for data serialization</param>
+ /// <param name="context">Context used for preparing the request</param>
+
+ // Default to GET if no method has been specified.
+ if (!request.method) {
+ request.method = "GET";
+ }
+
+ if (!request.headers) {
+ request.headers = {};
+ } else {
+ normalizeHeaders(request.headers);
+ }
+
+ if (request.headers.Accept === undefined) {
+ request.headers.Accept = handler.accept;
+ }
+
+ if (assigned(request.data) && request.body === undefined) {
+ handler.write(request, context);
+ }
+
+ if (!assigned(request.headers.MaxDataServiceVersion)) {
+ request.headers.MaxDataServiceVersion = handler.maxDataServiceVersion || "1.0";
+ }
+};
+
+var traverseInternal = function (item, owner, callback) {
+ /// <summary>Traverses a tree of objects invoking callback for every value.</summary>
+ /// <param name="item" type="Object">Object or array to traverse.</param>
+ /// <param name="callback" type="Function">
+ /// Callback function with key and value, similar to JSON.parse reviver.
+ /// </param>
+ /// <returns type="Object">The object with traversed properties.</returns>
+ /// <remarks>Unlike the JSON reviver, this won't delete null members.</remarks>
+
+ if (item && typeof item === "object") {
+ for (var name in item) {
+ var value = item[name];
+ var result = traverseInternal(value, name, callback);
+ result = callback(name, result, owner);
+ if (result !== value) {
+ if (value === undefined) {
+ delete item[name];
+ } else {
+ item[name] = result;
+ }
+ }
+ }
+ }
+
+ return item;
+};
+
+var traverse = function (item, callback) {
+ /// <summary>Traverses a tree of objects invoking callback for every value.</summary>
+ /// <param name="item" type="Object">Object or array to traverse.</param>
+ /// <param name="callback" type="Function">
+ /// Callback function with key and value, similar to JSON.parse reviver.
+ /// </param>
+ /// <returns type="Object">The traversed object.</returns>
+ /// <remarks>Unlike the JSON reviver, this won't delete null members.</remarks>
+
+ return callback("", traverseInternal(item, "", callback));
+};
+
+// DATAJS INTERNAL START
+exports.dataItemTypeName = dataItemTypeName;
+exports.EDM_BINARY = EDM_BINARY;
+exports.EDM_BOOLEAN = EDM_BOOLEAN;
+exports.EDM_BYTE = EDM_BYTE;
+exports.EDM_DATETIME = EDM_DATETIME;
+exports.EDM_DATETIMEOFFSET = EDM_DATETIMEOFFSET;
+exports.EDM_DECIMAL = EDM_DECIMAL;
+exports.EDM_DOUBLE = EDM_DOUBLE;
+exports.EDM_GEOGRAPHY = EDM_GEOGRAPHY;
+exports.EDM_GEOGRAPHY_POINT = EDM_GEOGRAPHY_POINT;
+exports.EDM_GEOGRAPHY_LINESTRING = EDM_GEOGRAPHY_LINESTRING;
+exports.EDM_GEOGRAPHY_POLYGON = EDM_GEOGRAPHY_POLYGON;
+exports.EDM_GEOGRAPHY_COLLECTION = EDM_GEOGRAPHY_COLLECTION;
+exports.EDM_GEOGRAPHY_MULTIPOLYGON = EDM_GEOGRAPHY_MULTIPOLYGON;
+exports.EDM_GEOGRAPHY_MULTILINESTRING = EDM_GEOGRAPHY_MULTILINESTRING;
+exports.EDM_GEOGRAPHY_MULTIPOINT = EDM_GEOGRAPHY_MULTIPOINT;
+exports.EDM_GEOMETRY = EDM_GEOMETRY;
+exports.EDM_GEOMETRY_POINT = EDM_GEOMETRY_POINT;
+exports.EDM_GEOMETRY_LINESTRING = EDM_GEOMETRY_LINESTRING;
+exports.EDM_GEOMETRY_POLYGON = EDM_GEOMETRY_POLYGON;
+exports.EDM_GEOMETRY_COLLECTION = EDM_GEOMETRY_COLLECTION;
+exports.EDM_GEOMETRY_MULTIPOLYGON = EDM_GEOMETRY_MULTIPOLYGON;
+exports.EDM_GEOMETRY_MULTILINESTRING = EDM_GEOMETRY_MULTILINESTRING;
+exports.EDM_GEOMETRY_MULTIPOINT = EDM_GEOMETRY_MULTIPOINT;
+exports.EDM_GUID = EDM_GUID;
+exports.EDM_INT16 = EDM_INT16;
+exports.EDM_INT32 = EDM_INT32;
+exports.EDM_INT64 = EDM_INT64;
+exports.EDM_SBYTE = EDM_SBYTE;
+exports.EDM_SINGLE = EDM_SINGLE;
+exports.EDM_STRING = EDM_STRING;
+exports.EDM_TIME = EDM_TIME;
+exports.GEOJSON_POINT = GEOJSON_POINT;
+exports.GEOJSON_LINESTRING = GEOJSON_LINESTRING;
+exports.GEOJSON_POLYGON = GEOJSON_POLYGON;
+exports.GEOJSON_MULTIPOINT = GEOJSON_MULTIPOINT;
+exports.GEOJSON_MULTILINESTRING = GEOJSON_MULTILINESTRING;
+exports.GEOJSON_MULTIPOLYGON = GEOJSON_MULTIPOLYGON;
+exports.GEOJSON_GEOMETRYCOLLECTION = GEOJSON_GEOMETRYCOLLECTION;
+exports.forEachSchema = forEachSchema;
+exports.formatDateTimeOffset = formatDateTimeOffset;
+exports.formatDuration = formatDuration;
+exports.formatNumberWidth = formatNumberWidth;
+exports.getCanonicalTimezone = getCanonicalTimezone;
+exports.getCollectionType = getCollectionType;
+exports.invokeRequest = invokeRequest;
+exports.isBatch = isBatch;
+exports.isCollection = isCollection;
+exports.isCollectionType = isCollectionType;
+exports.isComplex = isComplex;
+exports.isDateTimeOffset = isDateTimeOffset;
+exports.isDeferred = isDeferred;
+exports.isEntry = isEntry;
+exports.isFeed = isFeed;
+exports.isGeographyEdmType = isGeographyEdmType;
+exports.isGeometryEdmType = isGeometryEdmType;
+exports.isNamedStream = isNamedStream;
+exports.isPrimitive = isPrimitive;
+exports.isPrimitiveEdmType = isPrimitiveEdmType;
+exports.lookupComplexType = lookupComplexType;
+exports.lookupDefaultEntityContainer = lookupDefaultEntityContainer;
+exports.lookupEntityContainer = lookupEntityContainer;
+exports.lookupEntitySet = lookupEntitySet;
+exports.lookupEntityType = lookupEntityType;
+exports.lookupFunctionImport = lookupFunctionImport;
+exports.lookupNavigationPropertyType = lookupNavigationPropertyType;
+exports.lookupNavigationPropertyEntitySet = lookupNavigationPropertyEntitySet;
+exports.lookupInSchema = lookupInSchema;
+exports.lookupProperty = lookupProperty;
+exports.lookupInMetadata = lookupInMetadata;
+exports.getEntitySetInfo = getEntitySetInfo;
+exports.maxVersion = maxVersion;
+exports.navigationPropertyKind = navigationPropertyKind;
+exports.normalizeHeaders = normalizeHeaders;
+exports.parseBool = parseBool;
+exports.parseDateTime = parseDateTime;
+exports.parseDateTimeOffset = parseDateTimeOffset;
+exports.parseDuration = parseDuration;
+exports.parseTimezone = parseTimezone;
+exports.parseInt10 = parseInt10;
+exports.prepareRequest = prepareRequest;
+exports.removeNamespace = removeNamespace;
+exports.traverse = traverse;
+// DATAJS INTERNAL END
[12/15] [OLINGO-238] Build infrastructure for datajs I
Posted by ko...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/lib/odata/atom.js
----------------------------------------------------------------------
diff --git a/datajs/src/lib/odata/atom.js b/datajs/src/lib/odata/atom.js
new file mode 100644
index 0000000..1a8f01d
--- /dev/null
+++ b/datajs/src/lib/odata/atom.js
@@ -0,0 +1,1416 @@
+//SK name /odata/odata-atom.js
+/// <reference path="odata-utils.js" />
+/// <reference path="odata-handler.js" />
+/// <reference path="odata-xml.js" />
+
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// odata-atom.js
+
+var utils = require('./../datajs.js').utils;
+var xml = require('./../datajs.js').xml;
+var odataXML = require('./xml.js');
+var odataUtils = require('./utils.js');
+var odataHandler = require('./handler.js');
+
+
+// imports
+var contains = utils.contains;
+var djsassert = utils.djsassert;
+var isArray = utils.isArray;
+var isObject = utils.isObject;
+
+var normalizeURI = utils.normalizeURI;
+var parseInt10 = utils.parseInt10;
+
+var isXmlNSDeclaration = xml.isXmlNSDeclaration;
+var xmlAppendChild = xml.xmlAppendChild;
+var xmlAppendChildren = xml.xmlAppendChildren
+var xmlAttributes = xml.xmlAttributes;
+var xmlAttributeNode = xml.xmlAttributeNode;
+var xmlAttributeValue = xml.xmlAttributeValue;
+var xmlBaseURI = xml.xmlBaseURI;
+var xmlChildElements = xml.xmlChildElements;
+var xmlDom = xml.xmlDom;
+var xmlFirstChildElement = xml.xmlFirstChildElement;
+var xmlFindElementByPath = xml.xmlFindElementByPath;
+var xmlFindNodeByPath = xml.xmlFindNodeByPath;
+var xmlInnerText = xml.xmlInnerText;
+var xmlLocalName = xml.xmlLocalName;
+var xmlNamespaceURI = xml.xmlNamespaceURI;
+var xmlNewAttribute = xml.xmlNewAttribute;
+var xmlNewElement = xml.xmlNewElement;
+var xmlNewFragment = xml.xmlNewFragment;
+var xmlNewNodeByPath = xml.xmlNewNodeByPath;
+var xmlNewNSDeclaration = xml.xmlNewNSDeclaration;
+var xmlNewText = xml.xmlNewText;
+var xmlNodeValue = xml.xmlNodeValue;
+var xmlNS = xml.xmlNS;
+var xmlnsNS = xml.xmlnsNS;
+var xmlQualifiedName = xml.xmlQualifiedName;
+var xmlParse = xml.xmlParse;
+var xmlSerialize = xml.xmlSerialize;
+var xmlSerializeDescendants = xml.xmlSerializeDescendants;
+var xmlSibling = xml.xmlSibling;
+
+
+var w3org = xml.w3org;
+
+var adoDs = odataXML.adoDs;
+var contentType = odataXML.contentType;
+var createAttributeExtension = odataXML.createAttributeExtension;
+var createElementExtension = odataXML.createElementExtension;
+var handler = odataHandler.handler;
+var isPrimitiveEdmType = odataUtils.isPrimitiveEdmType;
+var isFeed = odataUtils.isFeed;
+var isNamedStream = odataUtils.isNamedStream;
+var lookupEntityType = odataUtils.lookupEntityType;
+var lookupComplexType = odataUtils.lookupComplexType;
+var lookupProperty = odataUtils.lookupProperty;
+var navigationPropertyKind = odataUtils.navigationPropertyKind;
+
+var MAX_DATA_SERVICE_VERSION = odataHandler.MAX_DATA_SERVICE_VERSION;
+var maxVersion = odataXML.maxVersion;
+var odataXmlNs = odataXML.odataXmlNs;
+var odataMetaXmlNs = odataXML.odataMetaXmlNs;
+var odataMetaPrefix = odataXML.odataMetaPrefix;
+var odataPrefix = odataXML.odataPrefix;
+var odataRelatedPrefix = odataXML.odataRelatedPrefix;
+var odataScheme = odataXML.odataScheme;
+var parseBool = odataXML.parseBool;
+var parseDateTime = odataXML.parseDateTime;
+var parseDateTimeOffset = odataXML.parseDateTimeOffset;
+var parseDuration = odataXML.parseDuration;
+var parseTimezone = odataXML.parseTimezone;
+var xmlNewODataElement = odataXML.xmlNewODataElement;
+var xmlNewODataElementInfo = odataXML.xmlNewODataElementInfo;
+var xmlNewODataMetaAttribute = odataXML.xmlNewODataMetaAttribute;
+var xmlNewODataMetaElement = odataXML.xmlNewODataMetaElement;
+var xmlNewODataDataElement = odataXML.xmlNewODataDataElement;
+var xmlReadODataEdmPropertyValue = odataXML.xmlReadODataEdmPropertyValue;
+var xmlReadODataProperty = odataXML.xmlReadODataProperty;
+
+// CONTENT START
+
+var atomPrefix = "a";
+
+var atomXmlNs = w3org + "2005/Atom"; // http://www.w3.org/2005/Atom
+var appXmlNs = w3org + "2007/app"; // http://www.w3.org/2007/app
+
+var odataEditMediaPrefix = adoDs + "/edit-media/"; // http://schemas.microsoft.com/ado/2007/08/dataservices/edit-media
+var odataMediaResourcePrefix = adoDs + "/mediaresource/"; // http://schemas.microsoft.com/ado/2007/08/dataservices/mediaresource
+var odataRelatedLinksPrefix = adoDs + "/relatedlinks/"; // http://schemas.microsoft.com/ado/2007/08/dataservices/relatedlinks
+
+var atomAcceptTypes = ["application/atom+xml", "application/atomsvc+xml", "application/xml"];
+var atomMediaType = atomAcceptTypes[0];
+
+// These are the namespaces that are not considered ATOM extension namespaces.
+var nonExtensionNamepaces = [atomXmlNs, appXmlNs, xmlNS, xmlnsNS];
+
+// These are entity property mapping paths that have well-known paths.
+var knownCustomizationPaths = {
+ SyndicationAuthorEmail: "author/email",
+ SyndicationAuthorName: "author/name",
+ SyndicationAuthorUri: "author/uri",
+ SyndicationContributorEmail: "contributor/email",
+ SyndicationContributorName: "contributor/name",
+ SyndicationContributorUri: "contributor/uri",
+ SyndicationPublished: "published",
+ SyndicationRights: "rights",
+ SyndicationSummary: "summary",
+ SyndicationTitle: "title",
+ SyndicationUpdated: "updated"
+};
+
+var expandedFeedCustomizationPath = function (path) {
+ /// <summary>Returns an expanded customization path if it's well-known.</summary>
+ /// <param name="path" type="String">Path to expand.</param>
+ /// <returns type="String">Expanded path or just 'path' otherwise.</returns>
+
+ return knownCustomizationPaths[path] || path;
+};
+
+var isExtensionNs = function (nsURI) {
+ /// <summary>Checks whether the specified namespace is an extension namespace to ATOM.</summary>
+ /// <param type="String" name="nsURI">Namespace to check.</param>
+ /// <returns type="Boolean">true if nsURI is an extension namespace to ATOM; false otherwise.</returns>
+
+ return !(contains(nonExtensionNamepaces, nsURI));
+};
+
+var atomFeedCustomization = function (customizationModel, entityType, model, propertyName, suffix) {
+ /// <summary>Creates an object describing a feed customization that was delcared in an OData conceptual schema.</summary>
+ /// <param name="customizationModel" type="Object">Object describing the customization delcared in the conceptual schema.</param>
+ /// <param name="entityType" type="Object">Object describing the entity type that owns the customization in an OData conceputal schema.</param>
+ /// <param name="model" type="Object">Object describing an OData conceptual schema.</param>
+ /// <param name="propertyName" type="String" optional="true">Name of the property to which this customization applies.</param>
+ /// <param name="suffix" type="String" optional="true">Suffix to feed customization properties in the conceptual schema.</param>
+ /// <returns type="Object">Object that describes an applicable feed customization.</returns>
+
+ suffix = suffix || "";
+ var targetPath = customizationModel["FC_TargetPath" + suffix];
+ if (!targetPath) {
+ return null;
+ }
+
+ var sourcePath = customizationModel["FC_SourcePath" + suffix];
+ var targetXmlPath = expandedFeedCustomizationPath(targetPath);
+
+ var propertyPath = propertyName ? propertyName + (sourcePath ? "/" + sourcePath : "") : sourcePath;
+ var propertyType = propertyPath && lookupPropertyType(model, entityType, propertyPath);
+ var nsURI = customizationModel["FC_NsUri" + suffix] || null;
+ var nsPrefix = customizationModel["FC_NsPrefix" + suffix] || null;
+ var keepinContent = customizationModel["FC_KeepInContent" + suffix] || "";
+
+ if (targetPath !== targetXmlPath) {
+ nsURI = atomXmlNs;
+ nsPrefix = atomPrefix;
+ }
+
+ return {
+ contentKind: customizationModel["FC_ContentKind" + suffix],
+ keepInContent: keepinContent.toLowerCase() === "true",
+ nsPrefix: nsPrefix,
+ nsURI: nsURI,
+ propertyPath: propertyPath,
+ propertyType: propertyType,
+ entryPath: targetXmlPath
+ };
+};
+
+var atomApplyAllFeedCustomizations = function (entityType, model, callback) {
+ /// <summary>Gets all the feed customizations that have to be applied to an entry as per the enity type declared in an OData conceptual schema.</summary>
+ /// <param name="entityType" type="Object">Object describing an entity type in a conceptual schema.</param>
+ /// <param name="model" type="Object">Object describing an OData conceptual schema.</param>
+ /// <param name="callback" type="Function">Callback function to be invoked for each feed customization that needs to be applied.</param>
+
+ var customizations = [];
+ while (entityType) {
+ var sourcePath = entityType.FC_SourcePath;
+ var customization = atomFeedCustomization(entityType, entityType, model);
+ if (customization) {
+ callback(customization);
+ }
+
+ var properties = entityType.property || [];
+ var i, len;
+ for (i = 0, len = properties.length; i < len; i++) {
+ var property = properties[i];
+ var suffixCounter = 0;
+ var suffix = "";
+
+ while (customization = atomFeedCustomization(property, entityType, model, property.name, suffix)) {
+ callback(customization);
+ suffixCounter++;
+ suffix = "_" + suffixCounter;
+ }
+ }
+ entityType = lookupEntityType(entityType.baseType, model);
+ }
+ return customizations;
+};
+
+var atomReadExtensionAttributes = function (domElement) {
+ /// <summary>Reads ATOM extension attributes (any attribute not in the Atom namespace) from a DOM element.</summary>
+ /// <param name="domElement">DOM element with zero or more extension attributes.</param>
+ /// <returns type="Array">An array of extension attribute representations.</returns>
+
+ var extensions = [];
+ xmlAttributes(domElement, function (attribute) {
+ var nsURI = xmlNamespaceURI(attribute);
+ if (isExtensionNs(nsURI)) {
+ extensions.push(createAttributeExtension(attribute, true));
+ }
+ });
+ return extensions;
+};
+
+var atomReadExtensionElement = function (domElement) {
+ /// <summary>Reads an ATOM extension element (an element not in the ATOM namespaces).</summary>
+ /// <param name="domElement">DOM element not part of the atom namespace.</param>
+ /// <returns type="Object">Object representing the extension element.</returns>
+
+ return createElementExtension(domElement, /*addNamespaceURI*/true);
+};
+
+var atomReadDocument = function (domElement, baseURI, model) {
+ /// <summary>Reads an ATOM entry, feed or service document, producing an object model in return.</summary>
+ /// <param name="domElement">Top-level ATOM DOM element to read.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the ATOM document.</param>
+ /// <param name="model" type="Object">Object that describes the conceptual schema.</param>
+ /// <returns type="Object">The object model representing the specified element, undefined if the top-level element is not part of the ATOM specification.</returns>
+
+ var nsURI = xmlNamespaceURI(domElement);
+ var localName = xmlLocalName(domElement);
+
+ // Handle service documents.
+ if (nsURI === appXmlNs && localName === "service") {
+ return atomReadServiceDocument(domElement, baseURI);
+ }
+
+ // Handle feed and entry elements.
+ if (nsURI === atomXmlNs) {
+ if (localName === "feed") {
+ return atomReadFeed(domElement, baseURI, model);
+ }
+ if (localName === "entry") {
+ return atomReadEntry(domElement, baseURI, model);
+ }
+ }
+
+ // Allow undefined to be returned.
+};
+
+var atomReadAdvertisedActionOrFunction = function (domElement, baseURI) {
+ /// <summary>Reads the DOM element for an action or a function in an OData Atom document.</summary>
+ /// <param name="domElement">DOM element to read.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing the action or function target url.</param>
+ /// <returns type="Object">Object with title, target, and metadata fields.</returns>
+
+ var extensions = [];
+ var result = { extensions: extensions };
+ xmlAttributes(domElement, function (attribute) {
+ var localName = xmlLocalName(attribute);
+ var nsURI = xmlNamespaceURI(attribute);
+ var value = xmlNodeValue(attribute);
+
+ if (nsURI === null) {
+ if (localName === "title" || localName === "metadata") {
+ result[localName] = value;
+ return;
+ }
+ if (localName === "target") {
+ result.target = normalizeURI(value, xmlBaseURI(domElement, baseURI));
+ return;
+ }
+ }
+
+ if (isExtensionNs(nsURI)) {
+ extensions.push(createAttributeExtension(attribute, true));
+ }
+ });
+ return result;
+};
+
+var atomReadAdvertisedAction = function (domElement, baseURI, parentMetadata) {
+ /// <summary>Reads the DOM element for an action in an OData Atom document.</summary>
+ /// <param name="domElement">DOM element to read.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing the action or target url.</param>
+ /// <param name="parentMetadata" type="Object">Object to update with the action metadata.</param>
+
+ var actions = parentMetadata.actions = parentMetadata.actions || [];
+ actions.push(atomReadAdvertisedActionOrFunction(domElement, baseURI));
+};
+
+var atomReadAdvertisedFunction = function (domElement, baseURI, parentMetadata) {
+ /// <summary>Reads the DOM element for an action in an OData Atom document.</summary>
+ /// <param name="domElement">DOM element to read.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing the action or target url.</param>
+ /// <param name="parentMetadata" type="Object">Object to update with the action metadata.</param>
+
+ var functions = parentMetadata.functions = parentMetadata.functions || [];
+ functions.push(atomReadAdvertisedActionOrFunction(domElement, baseURI));
+};
+
+var atomReadFeed = function (domElement, baseURI, model) {
+ /// <summary>Reads a DOM element for an ATOM feed, producing an object model in return.</summary>
+ /// <param name="domElement">ATOM feed DOM element.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the ATOM feed.</param>
+ /// <param name="model">Metadata that describes the conceptual schema.</param>
+ /// <returns type="Object">A new object representing the feed.</returns>
+
+ var extensions = atomReadExtensionAttributes(domElement);
+ var feedMetadata = { feed_extensions: extensions };
+ var results = [];
+
+ var feed = { __metadata: feedMetadata, results: results };
+
+ baseURI = xmlBaseURI(domElement, baseURI);
+
+ xmlChildElements(domElement, function (child) {
+ var nsURI = xmlNamespaceURI(child);
+ var localName = xmlLocalName(child);
+
+ if (nsURI === odataMetaXmlNs) {
+ if (localName === "count") {
+ feed.__count = parseInt(xmlInnerText(child), 10);
+ return;
+ }
+ if (localName === "action") {
+ atomReadAdvertisedAction(child, baseURI, feedMetadata);
+ return;
+ }
+ if (localName === "function") {
+ atomReadAdvertisedFunction(child, baseURI, feedMetadata);
+ return;
+ }
+ }
+
+ if (isExtensionNs(nsURI)) {
+ extensions.push(createElementExtension(child));
+ return;
+ }
+
+ // The element should belong to the ATOM namespace.
+ djsassert(nsURI === atomXmlNs, "atomReadFeed - child feed element is not in the atom namespace!!");
+
+ if (localName === "entry") {
+ results.push(atomReadEntry(child, baseURI, model));
+ return;
+ }
+ if (localName === "link") {
+ atomReadFeedLink(child, feed, baseURI);
+ return;
+ }
+ if (localName === "id") {
+ feedMetadata.uri = normalizeURI(xmlInnerText(child), baseURI);
+ feedMetadata.uri_extensions = atomReadExtensionAttributes(child);
+ return;
+ }
+ if (localName === "title") {
+ feedMetadata.title = xmlInnerText(child) || "";
+ feedMetadata.title_extensions = atomReadExtensionAttributes(child);
+ return;
+ }
+ });
+
+ return feed;
+};
+
+var atomReadFeedLink = function (domElement, feed, baseURI) {
+ /// <summary>Reads an ATOM link DOM element for a feed.</summary>
+ /// <param name="domElement">ATOM link DOM element.</param>
+ /// <param name="feed">Feed object to be annotated with the link data.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
+
+ var link = atomReadLink(domElement, baseURI);
+ var href = link.href;
+ var rel = link.rel;
+ var extensions = link.extensions;
+ var metadata = feed.__metadata;
+
+ if (rel === "next") {
+ feed.__next = href;
+ metadata.next_extensions = extensions;
+ return;
+ }
+ if (rel === "self") {
+ metadata.self = href;
+ metadata.self_extensions = extensions;
+ return;
+ }
+};
+
+var atomReadLink = function (domElement, baseURI) {
+ /// <summary>Reads an ATOM link DOM element.</summary>
+ /// <param name="linkElement">DOM element to read.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing the link href.</param>
+ /// <returns type="Object">A link element representation.</returns>
+
+ baseURI = xmlBaseURI(domElement, baseURI);
+
+ var extensions = [];
+ var link = { extensions: extensions, baseURI: baseURI };
+
+ xmlAttributes(domElement, function (attribute) {
+ var nsURI = xmlNamespaceURI(attribute);
+ var localName = xmlLocalName(attribute);
+ var value = attribute.value;
+
+ if (localName === "href") {
+ link.href = normalizeURI(value, baseURI);
+ return;
+ }
+ if (localName === "type" || localName === "rel") {
+ link[localName] = value;
+ return;
+ }
+
+ if (isExtensionNs(nsURI)) {
+ extensions.push(createAttributeExtension(attribute, true));
+ }
+ });
+
+ if (!link.href) {
+ throw { error: "href attribute missing on link element", element: domElement };
+ }
+
+ return link;
+};
+
+var atomGetObjectValueByPath = function (path, item) {
+ /// <summary>Gets a slashed path value from the specified item.</summary>
+ /// <param name="path" type="String">Property path to read ('/'-separated).</param>
+ /// <param name="item" type="Object">Object to get value from.</param>
+ /// <returns>The property value, possibly undefined if any path segment is missing.</returns>
+
+ // Fast path.
+ if (path.indexOf('/') === -1) {
+ return item[path];
+ } else {
+ var parts = path.split('/');
+ var i, len;
+ for (i = 0, len = parts.length; i < len; i++) {
+ // Avoid traversing a null object.
+ if (item === null) {
+ return undefined;
+ }
+
+ item = item[parts[i]];
+ if (item === undefined) {
+ return item;
+ }
+ }
+
+ return item;
+ }
+};
+
+var atomSetEntryValueByPath = function (path, target, value, propertyType) {
+ /// <summary>Sets a slashed path value on the specified target.</summary>
+ /// <param name="path" type="String">Property path to set ('/'-separated).</param>
+ /// <param name="target" type="Object">Object to set value on.</param>
+ /// <param name="value">Value to set.</param>
+ /// <param name="propertyType" type="String" optional="true">Property type to set in metadata.</param>
+
+ var propertyName;
+ if (path.indexOf('/') === -1) {
+ target[path] = value;
+ propertyName = path;
+ } else {
+ var parts = path.split('/');
+ var i, len;
+ for (i = 0, len = (parts.length - 1); i < len; i++) {
+ // We construct each step of the way if the property is missing;
+ // if it's already initialized to null, we stop further processing.
+ var next = target[parts[i]];
+ if (next === undefined) {
+ next = {};
+ target[parts[i]] = next;
+ } else if (next === null) {
+ return;
+ }
+ target = next;
+ }
+ propertyName = parts[i];
+ target[propertyName] = value;
+ }
+
+ if (propertyType) {
+ var metadata = target.__metadata = target.__metadata || {};
+ var properties = metadata.properties = metadata.properties || {};
+ var property = properties[propertyName] = properties[propertyName] || {};
+ property.type = propertyType;
+ }
+};
+
+var atomApplyCustomizationToEntryObject = function (customization, domElement, entry) {
+ /// <summary>Applies a specific feed customization item to an object.</summary>
+ /// <param name="customization">Object with customization description.</param>
+ /// <param name="sourcePath">Property path to set ('source' in the description).</param>
+ /// <param name="entryElement">XML element for the entry that corresponds to the object being read.</param>
+ /// <param name="entryObject">Object being read.</param>
+ /// <param name="propertyType" type="String">Name of property type to set.</param>
+ /// <param name="suffix" type="String">Suffix to feed customization properties.</param>
+
+ var propertyPath = customization.propertyPath;
+ // If keepInConent equals true or the property value is null we do nothing as this overrides any other customization.
+ if (customization.keepInContent || atomGetObjectValueByPath(propertyPath, entry) === null) {
+ return;
+ }
+
+ var xmlNode = xmlFindNodeByPath(domElement, customization.nsURI, customization.entryPath);
+
+ // If the XML tree does not contain the necessary elements to read the value,
+ // then it shouldn't be considered null, but rather ignored at all. This prevents
+ // the customization from generating the object path down to the property.
+ if (!xmlNode) {
+ return;
+ }
+
+ var propertyType = customization.propertyType;
+ var propertyValue;
+
+ if (customization.contentKind === "xhtml") {
+ // Treat per XHTML in http://tools.ietf.org/html/rfc4287#section-3.1.1, including the DIV
+ // in the content.
+ propertyValue = xmlSerializeDescendants(xmlNode);
+ } else {
+ propertyValue = xmlReadODataEdmPropertyValue(xmlNode, propertyType || "Edm.String");
+ }
+ // Set the value on the entry.
+ atomSetEntryValueByPath(propertyPath, entry, propertyValue, propertyType);
+};
+
+var lookupPropertyType = function (metadata, owningType, path) {
+ /// <summary>Looks up the type of a property given its path in an entity type.</summary>
+ /// <param name="metadata">Metadata in which to search for base and complex types.</param>
+ /// <param name="owningType">Type to which property belongs.</param>
+ /// <param name="path" type="String" mayBeNull="false">Property path to look at.</param>
+ /// <returns type="String">The name of the property type; possibly null.</returns>
+
+ var parts = path.split("/");
+ var i, len;
+ while (owningType) {
+ // Keep track of the type being traversed, necessary for complex types.
+ var traversedType = owningType;
+
+ for (i = 0, len = parts.length; i < len; i++) {
+ // Traverse down the structure as necessary.
+ var properties = traversedType.property;
+ if (!properties) {
+ break;
+ }
+
+ // Find the property by scanning the property list (might be worth pre-processing).
+ var propertyFound = lookupProperty(properties, parts[i]);
+ if (!propertyFound) {
+ break;
+ }
+
+ var propertyType = propertyFound.type;
+
+ // We could in theory still be missing types, but that would
+ // be caused by a malformed path.
+ if (!propertyType || isPrimitiveEdmType(propertyType)) {
+ return propertyType || null;
+ }
+
+ traversedType = lookupComplexType(propertyType, metadata);
+ if (!traversedType) {
+ return null;
+ }
+ }
+
+ // Traverse up the inheritance chain.
+ owningType = lookupEntityType(owningType.baseType, metadata);
+ }
+
+ return null;
+};
+
+var atomReadEntry = function (domElement, baseURI, model) {
+ /// <summary>Reads a DOM element for an ATOM entry, producing an object model in return.</summary>
+ /// <param name="domElement">ATOM entry DOM element.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the ATOM entry.</param>
+ /// <param name="model">Metadata that describes the conceptual schema.</param>
+ /// <returns type="Object">A new object representing the entry.</returns>
+
+ var entryMetadata = {};
+ var entry = { __metadata: entryMetadata };
+
+ var etag = xmlAttributeValue(domElement, "etag", odataMetaXmlNs);
+ if (etag) {
+ entryMetadata.etag = etag;
+ }
+
+ baseURI = xmlBaseURI(domElement, baseURI);
+
+ xmlChildElements(domElement, function (child) {
+ var nsURI = xmlNamespaceURI(child);
+ var localName = xmlLocalName(child);
+
+ if (nsURI === atomXmlNs) {
+ if (localName === "id") {
+ atomReadEntryId(child, entryMetadata, baseURI);
+ return;
+ }
+ if (localName === "category") {
+ atomReadEntryType(child, entryMetadata);
+ return;
+ }
+ if (localName === "content") {
+ atomReadEntryContent(child, entry, entryMetadata, baseURI);
+ return;
+ }
+ if (localName === "link") {
+ atomReadEntryLink(child, entry, entryMetadata, baseURI, model);
+ return;
+ }
+ return;
+ }
+
+ if (nsURI === odataMetaXmlNs) {
+ if (localName === "properties") {
+ atomReadEntryStructuralObject(child, entry, entryMetadata);
+ return;
+ }
+ if (localName === "action") {
+ atomReadAdvertisedAction(child, baseURI, entryMetadata);
+ return;
+ }
+ if (localName === "function") {
+ atomReadAdvertisedFunction(child, baseURI, entryMetadata);
+ return;
+ }
+ }
+ });
+
+ // Apply feed customizations if applicable
+ var entityType = lookupEntityType(entryMetadata.type, model);
+ atomApplyAllFeedCustomizations(entityType, model, function (customization) {
+ atomApplyCustomizationToEntryObject(customization, domElement, entry);
+ });
+
+ return entry;
+};
+
+var atomReadEntryId = function (domElement, entryMetadata, baseURI) {
+ /// <summary>Reads an ATOM entry id DOM element.</summary>
+ /// <param name="domElement">ATOM id DOM element.</param>
+ /// <param name="entryMetadata">Entry metadata object to update with the id information.</param>
+
+ entryMetadata.uri = normalizeURI(xmlInnerText(domElement), xmlBaseURI(domElement, baseURI));
+ entryMetadata.uri_extensions = atomReadExtensionAttributes(domElement);
+};
+
+var atomReadEntryType = function (domElement, entryMetadata) {
+ /// <summary>Reads type information from an ATOM category DOM element.</summary>
+ /// <param name="domElement">ATOM category DOM element.</param>
+ /// <param name="entryMetadata">Entry metadata object to update with the type information.</param>
+
+ if (xmlAttributeValue(domElement, "scheme") === odataScheme) {
+ if (entryMetadata.type) {
+ throw { message: "Invalid AtomPub document: multiple category elements defining the entry type were encounterd withing an entry", element: domElement };
+ }
+
+ var typeExtensions = [];
+ xmlAttributes(domElement, function (attribute) {
+ var nsURI = xmlNamespaceURI(attribute);
+ var localName = xmlLocalName(attribute);
+
+ if (!nsURI) {
+ if (localName !== "scheme" && localName !== "term") {
+ typeExtensions.push(createAttributeExtension(attribute, true));
+ }
+ return;
+ }
+
+ if (isExtensionNs(nsURI)) {
+ typeExtensions.push(createAttributeExtension(attribute, true));
+ }
+ });
+
+ entryMetadata.type = xmlAttributeValue(domElement, "term");
+ entryMetadata.type_extensions = typeExtensions;
+ }
+};
+
+var atomReadEntryContent = function (domElement, entry, entryMetadata, baseURI) {
+ /// <summary>Reads an ATOM content DOM element.</summary>
+ /// <param name="domElement">ATOM content DOM element.</param>
+ /// <param name="entry">Entry object to update with information.</param>
+ /// <param name="entryMetadata">Entry metadata object to update with the content information.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the Atom entry content.</param>
+
+ var src = xmlAttributeValue(domElement, "src");
+ var type = xmlAttributeValue(domElement, "type");
+
+ if (src) {
+ if (!type) {
+ throw {
+ message: "Invalid AtomPub document: content element must specify the type attribute if the src attribute is also specified",
+ element: domElement
+ };
+ }
+
+ entryMetadata.media_src = normalizeURI(src, xmlBaseURI(domElement, baseURI));
+ entryMetadata.content_type = type;
+ }
+
+ xmlChildElements(domElement, function (child) {
+ if (src) {
+ throw { message: "Invalid AtomPub document: content element must not have child elements if the src attribute is specified", element: domElement };
+ }
+
+ if (xmlNamespaceURI(child) === odataMetaXmlNs && xmlLocalName(child) === "properties") {
+ atomReadEntryStructuralObject(child, entry, entryMetadata);
+ }
+ });
+};
+
+var atomReadEntryLink = function (domElement, entry, entryMetadata, baseURI, model) {
+ /// <summary>Reads a link element on an entry.</summary>
+ /// <param name="atomEntryLink">'link' element on the entry.</param>
+ /// <param name="entry" type="Object">Entry object to update with the link data.</param>
+ /// <param name="entryMetadata">Entry metadata object to update with the link metadata.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing the link href.</param>
+ /// <param name="model" type="Object">Metadata that describes the conceptual schema.</param>
+
+ var link = atomReadLink(domElement, baseURI);
+
+ var rel = link.rel;
+ var href = link.href;
+ var extensions = link.extensions;
+
+ if (rel === "self") {
+ entryMetadata.self = href;
+ entryMetadata.self_link_extensions = extensions;
+ return;
+ }
+
+ if (rel === "edit") {
+ entryMetadata.edit = href;
+ entryMetadata.edit_link_extensions = extensions;
+ return;
+ }
+
+ if (rel === "edit-media") {
+ entryMetadata.edit_media = link.href;
+ entryMetadata.edit_media_extensions = extensions;
+ atomReadLinkMediaEtag(link, entryMetadata);
+ return;
+ }
+
+ // This might be a named stream edit link
+ if (rel.indexOf(odataEditMediaPrefix) === 0) {
+ atomReadNamedStreamEditLink(link, entry, entryMetadata);
+ return;
+ }
+
+ // This might be a named stram media resource (read) link
+ if (rel.indexOf(odataMediaResourcePrefix) === 0) {
+ atomReadNamedStreamSelfLink(link, entry, entryMetadata);
+ return;
+ }
+
+ // This might be a navigation property
+ if (rel.indexOf(odataRelatedPrefix) === 0) {
+ atomReadNavPropLink(domElement, link, entry, entryMetadata, model);
+ return;
+ }
+
+ if (rel.indexOf(odataRelatedLinksPrefix) === 0) {
+ atomReadNavPropRelatedLink(link, entryMetadata);
+ return;
+ }
+};
+
+var atomReadNavPropRelatedLink = function (link, entryMetadata) {
+ /// <summary>Reads a link represnting the links related to a navigation property in an OData Atom document.</summary>
+ /// <param name="link" type="Object">Object representing the parsed link DOM element.</param>
+ /// <param name="entryMetadata" type="Object">Entry metadata object to update with the related links information.</param>
+
+ var propertyName = link.rel.substring(odataRelatedLinksPrefix.length);
+ djsassert(propertyName, "atomReadNavPropRelatedLink - property name is null, empty or undefined!");
+
+ // Set the extra property information on the entry object metadata.
+ entryMetadata.properties = entryMetadata.properties || {};
+ var propertyMetadata = entryMetadata.properties[propertyName] = entryMetadata.properties[propertyName] || {};
+
+ propertyMetadata.associationuri = link.href;
+ propertyMetadata.associationuri_extensions = link.extensions;
+};
+
+var atomReadNavPropLink = function (domElement, link, entry, entryMetadata, model) {
+ /// <summary>Reads a link representing a navigation property in an OData Atom document.</summary>
+ /// <param name="domElement">DOM element for a navigation property in an OData Atom document.</summary>
+ /// <param name="link" type="Object">Object representing the parsed link DOM element.</param>
+ /// <param name="entry" type="Object">Entry object to update with the navigation property.</param>
+ /// <param name="entryMetadata">Entry metadata object to update with the navigation property metadata.</param>
+ /// <param name="model" type="Object">Metadata that describes the conceptual schema.</param>
+
+ // Get any inline data.
+ var inlineData;
+ var inlineElement = xmlFirstChildElement(domElement, odataMetaXmlNs, "inline");
+ if (inlineElement) {
+ var inlineDocRoot = xmlFirstChildElement(inlineElement);
+ var inlineBaseURI = xmlBaseURI(inlineElement, link.baseURI);
+ inlineData = inlineDocRoot ? atomReadDocument(inlineDocRoot, inlineBaseURI, model) : null;
+ } else {
+ // If the link has no inline content, we consider it deferred.
+ inlineData = { __deferred: { uri: link.href} };
+ }
+
+ var propertyName = link.rel.substring(odataRelatedPrefix.length);
+
+ // Set the property value on the entry object.
+ entry[propertyName] = inlineData;
+
+ // Set the extra property information on the entry object metadata.
+ entryMetadata.properties = entryMetadata.properties || {};
+ var propertyMetadata = entryMetadata.properties[propertyName] = entryMetadata.properties[propertyName] || {};
+
+ propertyMetadata.extensions = link.extensions;
+};
+
+var atomReadNamedStreamEditLink = function (link, entry, entryMetadata) {
+ /// <summary>Reads a link representing the edit-media url of a named stream in an OData Atom document.</summary>
+ /// <param name="link" type="Object">Object representing the parsed link DOM element.</param>
+ /// <param name="entry" type="Object">Entry object to update with the named stream data.</param>
+ /// <param name="entryMetadata">Entry metadata object to update with the named stream metadata.</param>
+
+ var propertyName = link.rel.substring(odataEditMediaPrefix.length);
+ djsassert(propertyName, "atomReadNamedStreamEditLink - property name is null, empty or undefined!");
+
+ var namedStreamMediaResource = atomGetEntryNamedStreamMediaResource(propertyName, entry, entryMetadata);
+ var mediaResource = namedStreamMediaResource.value;
+ var mediaResourceMetadata = namedStreamMediaResource.metadata;
+
+ var editMedia = link.href;
+
+ mediaResource.edit_media = editMedia;
+ mediaResource.content_type = link.type;
+ mediaResourceMetadata.edit_media_extensions = link.extensions;
+
+ // If there is only the edit link, make it the media self link as well.
+ mediaResource.media_src = mediaResource.media_src || editMedia;
+ mediaResourceMetadata.media_src_extensions = mediaResourceMetadata.media_src_extensions || [];
+
+ atomReadLinkMediaEtag(link, mediaResource);
+};
+
+var atomReadNamedStreamSelfLink = function (link, entry, entryMetadata) {
+ /// <summary>Reads a link representing the self url of a named stream in an OData Atom document.</summary>
+ /// <param name="link" type="Object">Object representing the parsed link DOM element.</param>
+ /// <param name="entry" type="Object">Entry object to update with the named stream data.</param>
+ /// <param name="entryMetadata">Entry metadata object to update with the named stream metadata.</param>
+
+ var propertyName = link.rel.substring(odataMediaResourcePrefix.length);
+ djsassert(propertyName, "atomReadNamedStreamEditLink - property name is null, empty or undefined!");
+
+ var namedStreamMediaResource = atomGetEntryNamedStreamMediaResource(propertyName, entry, entryMetadata);
+ var mediaResource = namedStreamMediaResource.value;
+ var mediaResourceMetadata = namedStreamMediaResource.metadata;
+
+ mediaResource.media_src = link.href;
+ mediaResourceMetadata.media_src_extensions = link.extensions;
+ mediaResource.content_type = link.type;
+};
+
+var atomGetEntryNamedStreamMediaResource = function (name, entry, entryMetadata) {
+ /// <summary>Gets the media resource object and metadata object for a named stream in an entry object.</summary>
+ /// <param name="link" type="Object">Object representing the parsed link DOM element.</param>
+ /// <param name="entry" type="Object">Entry object from which the media resource object will be obtained.</param>
+ /// <param name="entryMetadata" type="Object">Entry metadata object from which the media resource metadata object will be obtained.</param>
+ /// <remarks>
+ /// If the entry doest' have a media resource for the named stream indicated by the name argument, then this function will create a new
+ /// one along with its metadata object.
+ /// <remarks>
+ /// <returns type="Object"> Object containing the value and metadata of the named stream's media resource. <returns>
+
+ entryMetadata.properties = entryMetadata.properties || {};
+
+ var mediaResourceMetadata = entryMetadata.properties[name];
+ var mediaResource = entry[name] && entry[name].__mediaresource;
+
+ if (!mediaResource) {
+ mediaResource = {};
+ entry[name] = { __mediaresource: mediaResource };
+ entryMetadata.properties[name] = mediaResourceMetadata = {};
+ }
+ return { value: mediaResource, metadata: mediaResourceMetadata };
+};
+
+var atomReadLinkMediaEtag = function (link, mediaResource) {
+ /// <summary>Gets the media etag from the link extensions and updates the media resource object with it.</summary>
+ /// <param name="link" type="Object">Object representing the parsed link DOM element.</param>
+ /// <param name="mediaResource" type="Object">Object containing media information for an OData Atom entry.</param>
+ /// <remarks>
+ /// The function will remove the extension object for the etag if it finds it in the link extensions and will set
+ /// its value under the media_etag property of the mediaResource object.
+ /// <remarks>
+ /// <returns type="Object"> Object containing the value and metadata of the named stream's media resource. <returns>
+
+ var extensions = link.extensions;
+ var i, len;
+ for (i = 0, len = extensions.length; i < len; i++) {
+ if (extensions[i].namespaceURI === odataMetaXmlNs && extensions[i].name === "etag") {
+ mediaResource.media_etag = extensions[i].value;
+ extensions.splice(i, 1);
+ return;
+ }
+ }
+};
+
+var atomReadEntryStructuralObject = function (domElement, parent, parentMetadata) {
+ /// <summary>Reads an atom entry's property as a structural object and sets its value in the parent and the metadata in the parentMetadata objects.</summary>
+ /// <param name="propertiesElement">XML element for the 'properties' node.</param>
+ /// <param name="parent">
+ /// Object that will contain the property value. It can be either an antom entry or
+ /// an atom complex property object.
+ /// </param>
+ /// <param name="parentMetadata">Object that will contain the property metadata. It can be either an atom entry metadata or a complex property metadata object</param>
+
+ xmlChildElements(domElement, function (child) {
+ var property = xmlReadODataProperty(child);
+ if (property) {
+ var propertyName = property.name;
+ var propertiesMetadata = parentMetadata.properties = parentMetadata.properties || {};
+ propertiesMetadata[propertyName] = property.metadata;
+ parent[propertyName] = property.value;
+ }
+ });
+};
+
+var atomReadServiceDocument = function (domElement, baseURI) {
+ /// <summary>Reads an AtomPub service document</summary>
+ /// <param name="atomServiceDoc">DOM element for the root of an AtomPub service document</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the AtomPub service document.</param>
+ /// <returns type="Object">An object that contains the properties of the service document</returns>
+
+ var workspaces = [];
+ var extensions = [];
+
+ baseURI = xmlBaseURI(domElement, baseURI);
+ // Find all the workspace elements.
+ xmlChildElements(domElement, function (child) {
+ if (xmlNamespaceURI(child) === appXmlNs && xmlLocalName(child) === "workspace") {
+ workspaces.push(atomReadServiceDocumentWorkspace(child, baseURI));
+ return;
+ }
+ extensions.push(createElementExtension(child));
+ });
+
+ // AtomPub (RFC 5023 Section 8.3.1) says a service document MUST contain one or
+ // more workspaces. Throw if we don't find any.
+ if (workspaces.length === 0) {
+ throw { message: "Invalid AtomPub service document: No workspace element found.", element: domElement };
+ }
+
+ return { workspaces: workspaces, extensions: extensions };
+};
+
+var atomReadServiceDocumentWorkspace = function (domElement, baseURI) {
+ /// <summary>Reads a single workspace element from an AtomPub service document</summary>
+ /// <param name="domElement">DOM element that represents a workspace of an AtomPub service document</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the AtomPub service document workspace.</param>
+ /// <returns type="Object">An object that contains the properties of the workspace</returns>
+
+ var collections = [];
+ var extensions = [];
+ var title; // = undefined;
+
+ baseURI = xmlBaseURI(domElement, baseURI);
+
+ xmlChildElements(domElement, function (child) {
+ var nsURI = xmlNamespaceURI(child);
+ var localName = xmlLocalName(child);
+
+ if (nsURI === atomXmlNs) {
+ if (localName === "title") {
+ if (title !== undefined) {
+ throw { message: "Invalid AtomPub service document: workspace has more than one child title element", element: child };
+ }
+
+ title = xmlInnerText(child);
+ return;
+ }
+ }
+
+ if (nsURI === appXmlNs) {
+ if (localName === "collection") {
+ collections.push(atomReadServiceDocumentCollection(child, baseURI));
+ }
+ return;
+ }
+ extensions.push(atomReadExtensionElement(child));
+ });
+
+ return { title: title || "", collections: collections, extensions: extensions };
+};
+
+var atomReadServiceDocumentCollection = function (domElement, baseURI) {
+ /// <summary>Reads a service document collection element into an object.</summary>
+ /// <param name="domElement">DOM element that represents a collection of an AtomPub service document.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the AtomPub service document collection.</param>
+ /// <returns type="Object">An object that contains the properties of the collection.</returns>
+
+
+ var href = xmlAttributeValue(domElement, "href");
+
+ if (!href) {
+ throw { message: "Invalid AtomPub service document: collection has no href attribute", element: domElement };
+ }
+
+ baseURI = xmlBaseURI(domElement, baseURI);
+ href = normalizeURI(href, xmlBaseURI(domElement, baseURI));
+ var extensions = [];
+ var title; // = undefined;
+
+ xmlChildElements(domElement, function (child) {
+ var nsURI = xmlNamespaceURI(child);
+ var localName = xmlLocalName(child);
+
+ if (nsURI === atomXmlNs) {
+ if (localName === "title") {
+ if (title !== undefined) {
+ throw { message: "Invalid AtomPub service document: collection has more than one child title element", element: child };
+ }
+ title = xmlInnerText(child);
+ }
+ return;
+ }
+
+ if (nsURI !== appXmlNs) {
+ extensions.push(atomReadExtensionElement(domElement));
+ }
+ });
+
+ // AtomPub (RFC 5023 Section 8.3.3) says the collection element MUST contain
+ // a title element. It's likely to be problematic if the service doc doesn't
+ // have one so here we throw.
+ if (!title) {
+ throw { message: "Invalid AtomPub service document: collection has no title element", element: domElement };
+ }
+
+ return { title: title, href: href, extensions: extensions };
+};
+
+var atomNewElement = function (dom, name, children) {
+ /// <summary>Creates a new DOM element in the Atom namespace.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="name" type="String">Local name of the Atom element to create.</param>
+ /// <param name="children" type="Array">Array containing DOM nodes or string values that will be added as children of the new DOM element.</param>
+ /// <returns>New DOM element in the Atom namespace.</returns>
+ /// <remarks>
+ /// If a value in the children collection is a string, then a new DOM text node is going to be created
+ /// for it and then appended as a child of the new DOM Element.
+ /// </remarks>
+
+ return xmlNewElement(dom, atomXmlNs, xmlQualifiedName(atomPrefix, name), children);
+};
+
+var atomNewAttribute = function (dom, name, value) {
+ /// <summary>Creates a new DOM attribute for an Atom element in the default namespace.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="name" type="String">Local name of the OData attribute to create.</param>
+ /// <param name="value">Attribute value.</param>
+ /// <returns>New DOM attribute in the default namespace.</returns>
+
+ return xmlNewAttribute(dom, null, name, value);
+};
+
+var atomCanRemoveProperty = function (propertyElement) {
+ /// <summary>Checks whether the property represented by domElement can be removed from the atom document DOM tree.</summary>
+ /// <param name="propertyElement">DOM element for the property to test.</param>
+ /// <remarks>
+ /// The property can only be removed if it doens't have any children and only has namespace or type declaration attributes.
+ /// </remarks>
+ /// <returns type="Boolean">True is the property can be removed; false otherwise.</returns>
+
+ if (propertyElement.childNodes.length > 0) {
+ return false;
+ }
+
+ var isEmpty = true;
+ var attributes = propertyElement.attributes;
+ var i, len;
+ for (i = 0, len = attributes.length; i < len && isEmpty; i++) {
+ var attribute = attributes[i];
+
+ isEmpty = isEmpty && isXmlNSDeclaration(attribute) ||
+ (xmlNamespaceURI(attribute) == odataMetaXmlNs && xmlLocalName(attribute) === "type");
+ }
+ return isEmpty;
+};
+
+var atomNewODataNavigationProperty = function (dom, name, kind, value, model) {
+ /// <summary>Creates a new Atom link DOM element for a navigation property in an OData Atom document.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="name" type="String">Property name.</param>
+ /// <param name="kind" type="String">Navigation property kind. Expected values are "deferred", "entry", or "feed".</param>
+ /// <param name="value" optional="true" mayBeNull="true">Value of the navigation property, if any.</param>
+ /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
+ /// <returns type="Object">
+ /// Object containing the new Atom link DOM element for the navigation property and the
+ /// required data service version for this property.
+ /// </returns>
+
+ var linkType = null;
+ var linkContent = null;
+ var linkContentBodyData = null;
+ var href = "";
+
+ if (kind !== "deferred") {
+ linkType = atomNewAttribute(dom, "type", "application/atom+xml;type=" + kind);
+ linkContent = xmlNewODataMetaElement(dom, "inline");
+
+ if (value) {
+ href = value.__metadata && value.__metadata.uri || "";
+ linkContentBodyData =
+ atomNewODataFeed(dom, value, model) ||
+ atomNewODataEntry(dom, value, model);
+ xmlAppendChild(linkContent, linkContentBodyData.element);
+ }
+ } else {
+ href = value.__deferred.uri;
+ }
+
+ var navProp = atomNewElement(dom, "link", [
+ atomNewAttribute(dom, "href", href),
+ atomNewAttribute(dom, "rel", normalizeURI(name, odataRelatedPrefix)),
+ linkType,
+ linkContent
+ ]);
+
+ return xmlNewODataElementInfo(navProp, linkContentBodyData ? linkContentBodyData.dsv : "1.0");
+};
+
+var atomNewODataEntryDataItem = function (dom, name, value, dataItemMetadata, dataItemModel, model) {
+ /// <summary>Creates a new DOM element for a data item in an entry, complex property, or collection property.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="name" type="String">Data item name.</param>
+ /// <param name="value" optional="true" mayBeNull="true">Value of the data item, if any.</param>
+ /// <param name="dataItemMetadata" type="Object" optional="true">Object containing metadata about the data item.</param>
+ /// <param name="dataItemModel" type="Object" optional="true">Object describing the data item in an OData conceptual schema.</param>
+ /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
+ /// <returns type="Object">
+ /// Object containing the new DOM element in the appropriate namespace for the data item and the
+ /// required data service version for it.
+ /// </returns>
+
+ if (isNamedStream(value)) {
+ return null;
+ }
+
+ var dataElement = xmlNewODataDataElement(dom, name, value, dataItemMetadata, dataItemModel, model);
+ if (!dataElement) {
+ // This may be a navigation property.
+ var navPropKind = navigationPropertyKind(value, dataItemModel);
+ djsassert(navPropKind !== null, "atomNewODataEntryDataItem - navigation property kind is null for property " + name);
+
+ dataElement = atomNewODataNavigationProperty(dom, name, navPropKind, value, model);
+ }
+ return dataElement;
+};
+
+var atomEntryCustomization = function (dom, entry, entryProperties, customization) {
+ /// <summary>Applies a feed customization by transforming an Atom entry DOM element as needed.</summary>
+ /// <param name="dom">DOM document used for creating any new DOM nodes required by the customization.</param>
+ /// <param name="entry">DOM element for the Atom entry to which the customization is going to be applied.</param>
+ /// <param name="entryProperties">DOM element containing the properties of the Atom entry.</param>
+ /// <param name="customization" type="Object">Object describing an applicable feed customization.</param>
+ /// <remarks>
+ /// Look into the atomfeedCustomization function for a description of the customization object.
+ /// </remarks>
+ /// <returns type="String">Data service version required by the applied customization</returns>
+
+ var atomProperty = xmlFindElementByPath(entryProperties, odataXmlNs, customization.propertyPath);
+ var atomPropertyNullAttribute = atomProperty && xmlAttributeNode(atomProperty, "null", odataMetaXmlNs);
+ var atomPropertyValue;
+ var dataServiceVersion = "1.0";
+
+ if (atomPropertyNullAttribute && atomPropertyNullAttribute.value === "true") {
+ return dataServiceVersion;
+ }
+
+ if (atomProperty) {
+ atomPropertyValue = xmlInnerText(atomProperty) || "";
+ if (!customization.keepInContent) {
+ dataServiceVersion = "2.0";
+ var parent = atomProperty.parentNode;
+ var candidate = parent;
+
+ parent.removeChild(atomProperty);
+ while (candidate !== entryProperties && atomCanRemoveProperty(candidate)) {
+ parent = candidate.parentNode;
+ parent.removeChild(candidate);
+ candidate = parent;
+ }
+ }
+ }
+
+ var targetNode = xmlNewNodeByPath(dom, entry,
+ customization.nsURI, customization.nsPrefix, customization.entryPath);
+
+ if (targetNode.nodeType === 2) {
+ targetNode.value = atomPropertyValue;
+ return dataServiceVersion;
+ }
+
+ var contentKind = customization.contentKind;
+ xmlAppendChildren(targetNode, [
+ contentKind && xmlNewAttribute(dom, null, "type", contentKind),
+ contentKind === "xhtml" ? xmlNewFragment(dom, atomPropertyValue) : atomPropertyValue
+ ]);
+
+ return dataServiceVersion;
+};
+
+var atomNewODataEntry = function (dom, data, model) {
+ /// <summary>Creates a new DOM element for an Atom entry.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="data" type="Object">Entry object in the library's internal representation.</param>
+ /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
+ /// <returns type="Object">
+ /// Object containing the new DOM element for the Atom entry and the required data service version for it.
+ /// </returns>
+
+ var payloadMetadata = data.__metadata || {};
+ var propertiesMetadata = payloadMetadata.properties || {};
+
+ var etag = payloadMetadata.etag;
+ var uri = payloadMetadata.uri;
+ var typeName = payloadMetadata.type;
+ var entityType = lookupEntityType(typeName, model);
+
+ var properties = xmlNewODataMetaElement(dom, "properties");
+ var entry = atomNewElement(dom, "entry", [
+ atomNewElement(dom, "author",
+ atomNewElement(dom, "name")
+ ),
+ etag && xmlNewODataMetaAttribute(dom, "etag", etag),
+ uri && atomNewElement(dom, "id", uri),
+ typeName && atomNewElement(dom, "category", [
+ atomNewAttribute(dom, "term", typeName),
+ atomNewAttribute(dom, "scheme", odataScheme)
+ ]),
+ // TODO: MLE support goes here.
+ atomNewElement(dom, "content", [
+ atomNewAttribute(dom, "type", "application/xml"),
+ properties
+ ])
+ ]);
+
+ var dataServiceVersion = "1.0";
+ for (var name in data) {
+ if (name !== "__metadata") {
+ var entryDataItemMetadata = propertiesMetadata[name] || {};
+ var entryDataItemModel = entityType && (
+ lookupProperty(entityType.property, name) ||
+ lookupProperty(entityType.navigationProperty, name));
+
+ var entryDataItem = atomNewODataEntryDataItem(dom, name, data[name], entryDataItemMetadata, entryDataItemModel, model);
+ if (entryDataItem) {
+ var entryElement = entryDataItem.element;
+ var entryElementParent = (xmlNamespaceURI(entryElement) === atomXmlNs) ? entry : properties;
+
+ xmlAppendChild(entryElementParent, entryElement);
+ dataServiceVersion = maxVersion(dataServiceVersion, entryDataItem.dsv);
+ }
+ }
+ }
+
+ atomApplyAllFeedCustomizations(entityType, model, function (customization) {
+ var customizationDsv = atomEntryCustomization(dom, entry, properties, customization);
+ dataServiceVersion = maxVersion(dataServiceVersion, customizationDsv);
+ });
+
+ return xmlNewODataElementInfo(entry, dataServiceVersion);
+};
+
+var atomNewODataFeed = function (dom, data, model) {
+ /// <summary>Creates a new DOM element for an Atom feed.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="data" type="Object">Feed object in the library's internal representation.</param>
+ /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
+ /// <returns type="Object">
+ /// Object containing the new DOM element for the Atom feed and the required data service version for it.
+ /// </returns>
+
+ var entries = isArray(data) ? data : data.results;
+
+ if (!entries) {
+ return null;
+ }
+
+ var dataServiceVersion = "1.0";
+ var atomFeed = atomNewElement(dom, "feed");
+
+ var i, len;
+ for (i = 0, len = entries.length; i < len; i++) {
+ var atomEntryData = atomNewODataEntry(dom, entries[i], model);
+ xmlAppendChild(atomFeed, atomEntryData.element);
+ dataServiceVersion = maxVersion(dataServiceVersion, atomEntryData.dsv);
+ }
+ return xmlNewODataElementInfo(atomFeed, dataServiceVersion);
+};
+
+var atomNewODataDocument = function (data, model) {
+ /// <summary>Creates a new OData Atom document.</summary>
+ /// <param name="data" type="Object">Feed or entry object in the libary's internal representaion.</param>
+ /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
+ /// <returns type="Object">
+ /// Object containing the new DOM document for the Atom document and the required data service version for it.
+ /// </returns>
+
+ if (data) {
+ var atomRootWriter = isFeed(data) && atomNewODataFeed ||
+ isObject(data) && atomNewODataEntry;
+
+ if (atomRootWriter) {
+ var dom = xmlDom();
+ var atomRootData = atomRootWriter(dom, data, model);
+
+ if (atomRootData) {
+ var atomRootElement = atomRootData.element;
+ xmlAppendChildren(atomRootElement, [
+ xmlNewNSDeclaration(dom, odataMetaXmlNs, odataMetaPrefix),
+ xmlNewNSDeclaration(dom, odataXmlNs, odataPrefix)
+ ]);
+ return xmlNewODataElementInfo(xmlAppendChild(dom, atomRootElement), atomRootData.dsv);
+ }
+ }
+ }
+ return null;
+};
+
+var atomParser = function (handler, text, context) {
+ /// <summary>Parses an ATOM document (feed, entry or service document).</summary>
+ /// <param name="handler">This handler.</param>
+ /// <param name="text" type="String">Document text.</param>
+ /// <param name="context" type="Object">Object with parsing context.</param>
+ /// <returns>An object representation of the document; undefined if not applicable.</returns>
+
+ if (text) {
+ var atomDoc = xmlParse(text);
+ var atomRoot = xmlFirstChildElement(atomDoc);
+ if (atomRoot) {
+ return atomReadDocument(atomRoot, null, context.metadata);
+ }
+ }
+};
+
+var atomSerializer = function (handler, data, context) {
+ /// <summary>Serializes an ATOM object into a document (feed or entry).</summary>
+ /// <param name="handler">This handler.</param>
+ /// <param name="data" type="Object">Representation of feed or entry.</param>
+ /// <param name="context" type="Object">Object with parsing context.</param>
+ /// <returns>An text representation of the data object; undefined if not applicable.</returns>
+
+ var cType = context.contentType = context.contentType || contentType(atomMediaType);
+ if (cType && cType.mediaType === atomMediaType) {
+ var atomDoc = atomNewODataDocument(data, context.metadata);
+ if (atomDoc) {
+ context.dataServiceVersion = maxVersion(context.dataServiceVersion || "1.0", atomDoc.dsv);
+ return xmlSerialize(atomDoc.element);
+ }
+ }
+ // Allow undefined to be returned.
+};
+
+exports.atomHandler = handler(atomParser, atomSerializer, atomAcceptTypes.join(","), MAX_DATA_SERVICE_VERSION);
+
+// DATAJS INTERNAL START
+exports.atomParser = atomParser;
+exports.atomSerializer = atomSerializer;
+exports.atomReadDocument = atomReadDocument;
+exports.atomReadFeed = atomReadFeed;
+exports.atomReadFeedLink = atomReadFeedLink;
+exports.atomReadLink = atomReadLink;
+exports.atomReadExtensionElement = atomReadExtensionElement;
+exports.atomReadExtensionAttributes = atomReadExtensionAttributes;
+exports.atomReadEntry = atomReadEntry;
+exports.atomReadEntryType = atomReadEntryType;
+exports.atomReadEntryContent = atomReadEntryContent;
+exports.atomReadEntryLink = atomReadEntryLink;
+exports.atomReadEntryStructuralObject = atomReadEntryStructuralObject;
+exports.atomReadServiceDocument = atomReadServiceDocument;
+exports.atomReadServiceDocumentWorkspace = atomReadServiceDocumentWorkspace;
+exports.atomReadServiceDocumentCollection = atomReadServiceDocumentCollection;
+exports.expandedFeedCustomizationPath = expandedFeedCustomizationPath;
+exports.lookupPropertyType = lookupPropertyType;
+exports.atomSetEntryValueByPath = atomSetEntryValueByPath;
+// DATAJS INTERNAL END
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/lib/odata/batch.js
----------------------------------------------------------------------
diff --git a/datajs/src/lib/odata/batch.js b/datajs/src/lib/odata/batch.js
new file mode 100644
index 0000000..a81cf13
--- /dev/null
+++ b/datajs/src/lib/odata/batch.js
@@ -0,0 +1,390 @@
+//SK name /odata/odata-batch.js
+/// <reference path="odata-utils.js" />
+
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// odata-batch.js
+
+var utils = require('./../datajs.js').utils;
+var odataUtils = require('./utils.js');
+var odataHandler = require('./handler.js');
+
+// Imports
+
+var extend = utils.extend;
+var isArray = utils.isArray;
+var trimString = utils.trimString;
+
+var contentType = odataHandler.contentType;
+var handler = odataHandler.handler;
+var isBatch = odataUtils.isBatch;
+var MAX_DATA_SERVICE_VERSION = odataUtils.MAX_DATA_SERVICE_VERSION;
+var normalizeHeaders = odataUtils.normalizeHeaders;
+//TODO var payloadTypeOf = odata.payloadTypeOf;
+var prepareRequest = odataUtils.prepareRequest;
+
+// CONTENT START
+var batchMediaType = "multipart/mixed";
+var responseStatusRegex = /^HTTP\/1\.\d (\d{3}) (.*)$/i;
+var responseHeaderRegex = /^([^()<>@,;:\\"\/[\]?={} \t]+)\s?:\s?(.*)/;
+
+var hex16 = function () {
+ /// <summary>
+ /// Calculates a random 16 bit number and returns it in hexadecimal format.
+ /// </summary>
+ /// <returns type="String">A 16-bit number in hex format.</returns>
+
+ return Math.floor((1 + Math.random()) * 0x10000).toString(16).substr(1);
+};
+
+var createBoundary = function (prefix) {
+ /// <summary>
+ /// Creates a string that can be used as a multipart request boundary.
+ /// </summary>
+ /// <param name="prefix" type="String" optional="true">String to use as the start of the boundary string</param>
+ /// <returns type="String">Boundary string of the format: <prefix><hex16>-<hex16>-<hex16></returns>
+
+ return prefix + hex16() + "-" + hex16() + "-" + hex16();
+};
+
+var partHandler = function (context) {
+ /// <summary>
+ /// Gets the handler for data serialization of individual requests / responses in a batch.
+ /// </summary>
+ /// <param name="context">Context used for data serialization.</param>
+ /// <returns>Handler object.</returns>
+
+ return context.handler.partHandler;
+};
+
+var currentBoundary = function (context) {
+ /// <summary>
+ /// Gets the current boundary used for parsing the body of a multipart response.
+ /// </summary>
+ /// <param name="context">Context used for parsing a multipart response.</param>
+ /// <returns type="String">Boundary string.</returns>
+
+ var boundaries = context.boundaries;
+ return boundaries[boundaries.length - 1];
+};
+
+var batchParser = function (handler, text, context) {
+ /// <summary>Parses a batch response.</summary>
+ /// <param name="handler">This handler.</param>
+ /// <param name="text" type="String">Batch text.</param>
+ /// <param name="context" type="Object">Object with parsing context.</param>
+ /// <returns>An object representation of the batch.</returns>
+
+ var boundary = context.contentType.properties["boundary"];
+ return { __batchResponses: readBatch(text, { boundaries: [boundary], handlerContext: context }) };
+};
+
+var batchSerializer = function (handler, data, context) {
+ /// <summary>Serializes a batch object representation into text.</summary>
+ /// <param name="handler">This handler.</param>
+ /// <param name="data" type="Object">Representation of a batch.</param>
+ /// <param name="context" type="Object">Object with parsing context.</param>
+ /// <returns>An text representation of the batch object; undefined if not applicable.</returns>
+
+ var cType = context.contentType = context.contentType || contentType(batchMediaType);
+ if (cType.mediaType === batchMediaType) {
+ return writeBatch(data, context);
+ }
+};
+
+var readBatch = function (text, context) {
+ /// <summary>
+ /// Parses a multipart/mixed response body from from the position defined by the context.
+ /// </summary>
+ /// <param name="text" type="String" optional="false">Body of the multipart/mixed response.</param>
+ /// <param name="context">Context used for parsing.</param>
+ /// <returns>Array of objects representing the individual responses.</returns>
+
+ var delimiter = "--" + currentBoundary(context);
+
+ // Move beyond the delimiter and read the complete batch
+ readTo(text, context, delimiter);
+
+ // Ignore the incoming line
+ readLine(text, context);
+
+ // Read the batch parts
+ var responses = [];
+ var partEnd;
+
+ while (partEnd !== "--" && context.position < text.length) {
+ var partHeaders = readHeaders(text, context);
+ var partContentType = contentType(partHeaders["Content-Type"]);
+
+ var changeResponses;
+ if (partContentType && partContentType.mediaType === batchMediaType) {
+ context.boundaries.push(partContentType.properties["boundary"]);
+ try {
+ changeResponses = readBatch(text, context);
+ } catch (e) {
+ e.response = readResponse(text, context, delimiter);
+ changeResponses = [e];
+ }
+ responses.push({ __changeResponses: changeResponses });
+ context.boundaries.pop();
+ readTo(text, context, "--" + currentBoundary(context));
+ } else {
+ if (!partContentType || partContentType.mediaType !== "application/http") {
+ throw { message: "invalid MIME part type " };
+ }
+ // Skip empty line
+ readLine(text, context);
+ // Read the response
+ var response = readResponse(text, context, delimiter);
+ try {
+ if (response.statusCode >= 200 && response.statusCode <= 299) {
+ partHandler(context.handlerContext).read(response, context.handlerContext);
+ } else {
+ // Keep track of failed responses and continue processing the batch.
+ response = { message: "HTTP request failed", response: response };
+ }
+ } catch (e) {
+ response = e;
+ }
+
+ responses.push(response);
+ }
+
+ partEnd = text.substr(context.position, 2);
+
+ // Ignore the incoming line.
+ readLine(text, context);
+ }
+ return responses;
+};
+
+var readHeaders = function (text, context) {
+ /// <summary>
+ /// Parses the http headers in the text from the position defined by the context.
+ /// </summary>
+ /// <param name="text" type="String" optional="false">Text containing an http response's headers</param>
+ /// <param name="context">Context used for parsing.</param>
+ /// <returns>Object containing the headers as key value pairs.</returns>
+ /// <remarks>
+ /// This function doesn't support split headers and it will stop reading when it hits two consecutive line breaks.
+ /// </remarks>
+
+ var headers = {};
+ var parts;
+ var line;
+ var pos;
+
+ do {
+ pos = context.position;
+ line = readLine(text, context);
+ parts = responseHeaderRegex.exec(line);
+ if (parts !== null) {
+ headers[parts[1]] = parts[2];
+ } else {
+ // Whatever was found is not a header, so reset the context position.
+ context.position = pos;
+ }
+ } while (line && parts);
+
+ normalizeHeaders(headers);
+
+ return headers;
+};
+
+var readResponse = function (text, context, delimiter) {
+ /// <summary>
+ /// Parses an HTTP response.
+ /// </summary>
+ /// <param name="text" type="String" optional="false">Text representing the http response.</param>
+ /// <param name="context" optional="false">Context used for parsing.</param>
+ /// <param name="delimiter" type="String" optional="false">String used as delimiter of the multipart response parts.</param>
+ /// <returns>Object representing the http response.</returns>
+
+ // Read the status line.
+ var pos = context.position;
+ var match = responseStatusRegex.exec(readLine(text, context));
+
+ var statusCode;
+ var statusText;
+ var headers;
+
+ if (match) {
+ statusCode = match[1];
+ statusText = match[2];
+ headers = readHeaders(text, context);
+ readLine(text, context);
+ } else {
+ context.position = pos;
+ }
+
+ return {
+ statusCode: statusCode,
+ statusText: statusText,
+ headers: headers,
+ body: readTo(text, context, "\r\n" + delimiter)
+ };
+};
+
+var readLine = function (text, context) {
+ /// <summary>
+ /// Returns a substring from the position defined by the context up to the next line break (CRLF).
+ /// </summary>
+ /// <param name="text" type="String" optional="false">Input string.</param>
+ /// <param name="context" optional="false">Context used for reading the input string.</param>
+ /// <returns type="String">Substring to the first ocurrence of a line break or null if none can be found. </returns>
+
+ return readTo(text, context, "\r\n");
+};
+
+var readTo = function (text, context, str) {
+ /// <summary>
+ /// Returns a substring from the position given by the context up to value defined by the str parameter and increments the position in the context.
+ /// </summary>
+ /// <param name="text" type="String" optional="false">Input string.</param>
+ /// <param name="context" type="Object" optional="false">Context used for reading the input string.</param>
+ /// <param name="str" type="String" optional="true">Substring to read up to.</param>
+ /// <returns type="String">Substring to the first ocurrence of str or the end of the input string if str is not specified. Null if the marker is not found.</returns>
+
+ var start = context.position || 0;
+ var end = text.length;
+ if (str) {
+ end = text.indexOf(str, start);
+ if (end === -1) {
+ return null;
+ }
+ context.position = end + str.length;
+ } else {
+ context.position = end;
+ }
+
+ return text.substring(start, end);
+};
+
+var writeBatch = function (data, context) {
+ /// <summary>
+ /// Serializes a batch request object to a string.
+ /// </summary>
+ /// <param name="data" optional="false">Batch request object in payload representation format</param>
+ /// <param name="context" optional="false">Context used for the serialization</param>
+ /// <returns type="String">String representing the batch request</returns>
+
+ if (!isBatch(data)) {
+ throw { message: "Data is not a batch object." };
+ }
+
+ var batchBoundary = createBoundary("batch_");
+ var batchParts = data.__batchRequests;
+ var batch = "";
+ var i, len;
+ for (i = 0, len = batchParts.length; i < len; i++) {
+ batch += writeBatchPartDelimiter(batchBoundary, false) +
+ writeBatchPart(batchParts[i], context);
+ }
+ batch += writeBatchPartDelimiter(batchBoundary, true);
+
+ // Register the boundary with the request content type.
+ var contentTypeProperties = context.contentType.properties;
+ contentTypeProperties.boundary = batchBoundary;
+
+ return batch;
+};
+
+var writeBatchPartDelimiter = function (boundary, close) {
+ /// <summary>
+ /// Creates the delimiter that indicates that start or end of an individual request.
+ /// </summary>
+ /// <param name="boundary" type="String" optional="false">Boundary string used to indicate the start of the request</param>
+ /// <param name="close" type="Boolean">Flag indicating that a close delimiter string should be generated</param>
+ /// <returns type="String">Delimiter string</returns>
+
+ var result = "\r\n--" + boundary;
+ if (close) {
+ result += "--";
+ }
+
+ return result + "\r\n";
+};
+
+var writeBatchPart = function (part, context, nested) {
+ /// <summary>
+ /// Serializes a part of a batch request to a string. A part can be either a GET request or
+ /// a change set grouping several CUD (create, update, delete) requests.
+ /// </summary>
+ /// <param name="part" optional="false">Request or change set object in payload representation format</param>
+ /// <param name="context" optional="false">Object containing context information used for the serialization</param>
+ /// <param name="nested" type="boolean" optional="true">Flag indicating that the part is nested inside a change set</param>
+ /// <returns type="String">String representing the serialized part</returns>
+ /// <remarks>
+ /// A change set is an array of request objects and they cannot be nested inside other change sets.
+ /// </remarks>
+
+ var changeSet = part.__changeRequests;
+ var result;
+ if (isArray(changeSet)) {
+ if (nested) {
+ throw { message: "Not Supported: change set nested in other change set" };
+ }
+
+ var changeSetBoundary = createBoundary("changeset_");
+ result = "Content-Type: " + batchMediaType + "; boundary=" + changeSetBoundary + "\r\n";
+ var i, len;
+ for (i = 0, len = changeSet.length; i < len; i++) {
+ result += writeBatchPartDelimiter(changeSetBoundary, false) +
+ writeBatchPart(changeSet[i], context, true);
+ }
+
+ result += writeBatchPartDelimiter(changeSetBoundary, true);
+ } else {
+ result = "Content-Type: application/http\r\nContent-Transfer-Encoding: binary\r\n\r\n";
+ var partContext = extend({}, context);
+ partContext.handler = handler;
+ partContext.request = part;
+ partContext.contentType = null;
+
+ prepareRequest(part, partHandler(context), partContext);
+ result += writeRequest(part);
+ }
+
+ return result;
+};
+
+var writeRequest = function (request) {
+ /// <summary>
+ /// Serializes a request object to a string.
+ /// </summary>
+ /// <param name="request" optional="false">Request object to serialize</param>
+ /// <returns type="String">String representing the serialized request</returns>
+
+ var result = (request.method ? request.method : "GET") + " " + request.requestUri + " HTTP/1.1\r\n";
+ for (var name in request.headers) {
+ if (request.headers[name]) {
+ result = result + name + ": " + request.headers[name] + "\r\n";
+ }
+ }
+
+ result += "\r\n";
+
+ if (request.body) {
+ result += request.body;
+ }
+
+ return result;
+};
+
+exports.batchHandler = handler(batchParser, batchSerializer, batchMediaType, MAX_DATA_SERVICE_VERSION);
+
+// DATAJS INTERNAL START
+exports.batchSerializer = batchSerializer;
+exports.writeRequest = writeRequest;
+// DATAJS INTERNAL END
[15/15] git commit: [OLINGO-238] Build infrastructure for datajs I
Posted by ko...@apache.org.
[OLINGO-238] Build infrastructure for datajs I
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/commit/f1cfcbc5
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/tree/f1cfcbc5
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/diff/f1cfcbc5
Branch: refs/heads/OLINGO-238-browserify
Commit: f1cfcbc5051ce1a8e96bee7a31c45dd076ed033e
Parents: e29bbd8
Author: Sven Kobler <sv...@sap.com>
Authored: Wed Apr 23 10:09:54 2014 +0200
Committer: Sven Kobler <sv...@sap.com>
Committed: Wed Apr 23 10:09:54 2014 +0200
----------------------------------------------------------------------
.gitignore | 1 +
datajs/.gitignore | 1 +
datajs/Gruntfile.js | 161 ++--
datajs/package.json | 13 +-
datajs/src/cache-source.js | 183 ----
datajs/src/cache.js | 1349 -----------------------------
datajs/src/datajs.js | 61 --
datajs/src/deferred.js | 179 ----
datajs/src/index.js | 22 +
datajs/src/lib/cache.js | 1351 +++++++++++++++++++++++++++++
datajs/src/lib/cache/source.js | 182 ++++
datajs/src/lib/datajs.js | 95 +++
datajs/src/lib/datajs/deferred.js | 178 ++++
datajs/src/lib/datajs/utils.js | 487 +++++++++++
datajs/src/lib/datajs/xml.js | 818 ++++++++++++++++++
datajs/src/lib/odata.js | 93 ++
datajs/src/lib/odata/atom.js | 1416 +++++++++++++++++++++++++++++++
datajs/src/lib/odata/batch.js | 390 +++++++++
datajs/src/lib/odata/gml.js | 833 ++++++++++++++++++
datajs/src/lib/odata/handler.js | 273 ++++++
datajs/src/lib/odata/json-light.js | 1384 ++++++++++++++++++++++++++++++
datajs/src/lib/odata/json.js | 374 ++++++++
datajs/src/lib/odata/metadata.js | 498 +++++++++++
datajs/src/lib/odata/net.js | 324 +++++++
datajs/src/lib/odata/request.js | 84 ++
datajs/src/lib/odata/utils.js | 1110 ++++++++++++++++++++++++
datajs/src/lib/odata/xml.js | 853 +++++++++++++++++++
datajs/src/lib/store.js | 59 ++
datajs/src/lib/store/dom.js | 316 +++++++
datajs/src/lib/store/indexeddb.js | 416 +++++++++
datajs/src/lib/store/memory.js | 230 +++++
datajs/src/odata-atom.js | 1411 ------------------------------
datajs/src/odata-batch.js | 393 ---------
datajs/src/odata-gml.js | 831 ------------------
datajs/src/odata-handler.js | 276 ------
datajs/src/odata-json-light.js | 1391 ------------------------------
datajs/src/odata-json.js | 379 ---------
datajs/src/odata-metadata.js | 500 -----------
datajs/src/odata-net.js | 330 -------
datajs/src/odata-utils.js | 1117 ------------------------
datajs/src/odata-xml.js | 850 -------------------
datajs/src/odata.js | 158 ----
datajs/src/store-dom.js | 320 -------
datajs/src/store-indexeddb.js | 417 ---------
datajs/src/store-memory.js | 231 -----
datajs/src/store.js | 61 --
datajs/src/utils.js | 490 -----------
datajs/src/xml.js | 824 ------------------
48 files changed, 11903 insertions(+), 11810 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..292c1b0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+info.txt
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/.gitignore
----------------------------------------------------------------------
diff --git a/datajs/.gitignore b/datajs/.gitignore
index b0a5c34..0fb4f6f 100644
--- a/datajs/.gitignore
+++ b/datajs/.gitignore
@@ -1,2 +1,3 @@
/node_modules/
/dist/
+/demo/
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/Gruntfile.js
----------------------------------------------------------------------
diff --git a/datajs/Gruntfile.js b/datajs/Gruntfile.js
index 621db4a..36d24cb 100644
--- a/datajs/Gruntfile.js
+++ b/datajs/Gruntfile.js
@@ -1,77 +1,130 @@
-/*global module:false*/
module.exports = function(grunt) {
-
- // Project configuration.
+ 'use strict';
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
banner: grunt.file.read('src/banner.txt'),
- concat: {
- options: {
- banner: '<%= banner %>',
- // strips comments
- stripBanners: true
- },
+ filename : '<%= pkg.name %>-<%= pkg.version %>',
+
+ browserify: {
+ dist: {
+ files: {
+ 'dist/<%= filename %>.js': ['src/index.js'],
+ },
+ options: {
+ browserifyOptions: {
+ //none
+ } ,
+ bundleOptions: {
+ debug: false
+ },
+ }
+ }
+ },
+ exorcise: {
+ dist: {
+ files: {
+ 'demo/jscripts/<%= filename %>.splitt_map.js': ['demo/jscripts/<%= filename %>.js'],
+ },
+ options: {},
+ }
+ },
+ exorcise111: {
dist: {
- src: ['src/datajs.js', //order matters, so no whildcards
- 'src/utils.js',
- 'src/xml.js',
- 'src/deferred.js',
- 'src/odata-utils.js',
- 'src/odata-net.js',
- 'src/odata-handler.js',
- 'src/odata-gml.js',
- 'src/odata-xml.js',
- 'src/odata-atom.js',
- 'src/odata-metadata.js',
- 'src/odata-json-light.js',
- 'src/odata-json.js',
- 'src/odata-batch.js',
- 'src/odata.js',
- 'src/store-dom.js',
- 'src/store-indexeddb.js',
- 'src/store-memory.js',
- 'src/store.js',
- 'src/cache-source.js',
- 'src/cache.js'],
- dest: 'dist/<%= pkg.name %>-<%= pkg.version %>.js'
+ files: {
+ 'dist/<%= filename %>.split_map': ['dist/<%= filename %>.js'],
+ },
+ options: {},
}
},
uglify: {
options: {
banner: '<%= banner %>',
- sourceMap : 'dist/<%= pkg.name %>-<%= pkg.version %>.map',
+ sourceMap : true,
+ sourceMapName : 'dist/<%= filename %>.map',
+ sourceMapIncludeSources :true,
+ /*sourceMapIn : 'dist/<%= filename %>.split_map',*/
},
dist: {
- src: '<%= concat.dist.dest %>',
- dest: 'dist/<%= pkg.name %>-<%= pkg.version %>.min.js'
+ src: 'dist/<%= filename %>.js',
+ dest: 'dist/<%= filename %>.min.js'
}
},
- qunit: {
- all: ['tests/**/*.html'],
- options: {
- timeout: 300000
+ copy: {
+ saveOrig : {
+ files: [
+ // includes files within path
+ {expand: false, flatten: true,src: './dist/<%= filename %>.js', dest: 'demo/jscripts/<%= filename %>.bu_js'},
+ ]
+ },
+ toDemo: {
+ files: [
+ // includes files within path
+ {expand: false, flatten: true,src: './dist/<%= filename %>.js', dest: 'demo/jscripts/<%= filename %>.js'},
+ {expand: false, flatten: true,src: './dist/<%= filename %>.min.js', dest: 'demo/jscripts/<%= filename %>.min.js'},
+ {expand: false, flatten: true,src: './dist/<%= filename %>.map', dest: 'demo/jscripts/<%= filename %>.map'},
+ {expand: false, flatten: true,src: './dist/<%= filename %>.split_map', dest: 'demo/jscripts/<%= filename %>.split_map'},
+ ]
+ }
+ },
+ connect: {
+ proxies: [{
+ context: "/sap/bc/ds/odata/v2/", // When the url contains this...
+ host: "ldcigmd.wdf.sap.corp",
+ changeOrigin: true,
+ https: true,
+ port: 44355,
+ rejectUnauthorized: false,
+ }],
+ demo: {
+ options: {
+ port: 4001 ,
+ hostname: "localhost",
+ base: "demo",
+ keepalive : true,
+ middleware: function (connect, options) {
+ return [
+ require("grunt-connect-proxy/lib/utils").proxyRequest ,
+ // Serve static files.
+ connect.static(options.base),
+ // Make empty directories browsable.
+ connect.directory(options.base)
+ ];
+ },
+ open1 : {
+ target: 'http://<%= connect.demo.options.hostname %>:<%= connect.demo.options.port %>/demo.html',
+ appName: '', //default browser
+ callback: function() {},
+ }
+ }
+ },
+ },
+ open: {
+ demo: {
+ path: "http://<%= connect.demo.options.hostname %>:<%= connect.demo.options.port %>/demo.html",
+ options: {
+ delay : 500,
+ }
}
- }
+ },
});
// These plugins provide necessary tasks.
+ grunt.loadNpmTasks('grunt-browserify');
+ grunt.loadNpmTasks('grunt-exorcise');
grunt.loadNpmTasks('grunt-contrib-uglify');
- grunt.loadNpmTasks('grunt-contrib-qunit');
- grunt.loadNpmTasks('grunt-contrib-concat');
+ grunt.loadNpmTasks('grunt-contrib-copy');
+ grunt.loadNpmTasks("grunt-connect-proxy");
+ grunt.loadNpmTasks("grunt-contrib-connect");
+
+
// Default task.
- grunt.registerTask('default', ['concat','uglify']);
- grunt.registerTask('test', ['qunit']);
- /*
- grunt.registerTask('serv', function() {
- grunt.task.run([
- "configureProxies:server",
- "connect:server",
- "open"
- ]);
- }
- );
- */
+ grunt.registerTask('build', ['browserify', 'uglify','copy:toDemo']);
+ grunt.registerTask('run', ['configureProxies', 'connect:demo']);
+ grunt.registerTask("demo", [ 'build','run' ]);
+ grunt.registerTask("xx", [ 'exorcise' ]);
+};
+var customTaks = function() {
-};
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/package.json
----------------------------------------------------------------------
diff --git a/datajs/package.json b/datajs/package.json
index e4aa286..2d36c00 100644
--- a/datajs/package.json
+++ b/datajs/package.json
@@ -6,12 +6,15 @@
"node": ">= 0.10.0"
},
"devDependencies": {
+ "browserify": "^3.40.0",
"grunt": "^0.4.4",
- "grunt-contrib-concat": "~0.3.0",
- "grunt-contrib-qunit": "^0.4.0",
- "grunt-contrib-uglify": "~0.2.7",
- "grunt-contrib-watch": "~0.5.3",
+ "grunt-browserify": "^2.0.3",
+ "grunt-connect-proxy": "^0.1.10",
+ "grunt-contrib-connect": "^0.7.1",
+ "grunt-contrib-copy": "^0.5.0",
+ "grunt-contrib-uglify": "^0.4.0",
+ "grunt-exorcise": "^0.1.0",
"grunt-open": "^0.2.3",
- "qunitjs": "^1.14.0"
+ "uglifyify": "^2.1.1"
}
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/cache-source.js
----------------------------------------------------------------------
diff --git a/datajs/src/cache-source.js b/datajs/src/cache-source.js
deleted file mode 100644
index 3616b84..0000000
--- a/datajs/src/cache-source.js
+++ /dev/null
@@ -1,183 +0,0 @@
-/// <reference path="odata-utils.js" />
-
-// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
-// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// cache-source.js
-
-(function (window, undefined) {
-
- var datajs = window.datajs || {};
- var odata = window.OData || {};
-
- var parseInt10 = datajs.parseInt10;
- var normalizeURICase = datajs.normalizeURICase;
-
- // CONTENT START
-
- var appendQueryOption = function (uri, queryOption) {
- /// <summary>Appends the specified escaped query option to the specified URI.</summary>
- /// <param name="uri" type="String">URI to append option to.</param>
- /// <param name="queryOption" type="String">Escaped query option to append.</param>
- var separator = (uri.indexOf("?") >= 0) ? "&" : "?";
- return uri + separator + queryOption;
- };
-
- var appendSegment = function (uri, segment) {
- /// <summary>Appends the specified segment to the given URI.</summary>
- /// <param name="uri" type="String">URI to append a segment to.</param>
- /// <param name="segment" type="String">Segment to append.</param>
- /// <returns type="String">The original URI with a new segment appended.</returns>
-
- var index = uri.indexOf("?");
- var queryPortion = "";
- if (index >= 0) {
- queryPortion = uri.substr(index);
- uri = uri.substr(0, index);
- }
-
- if (uri[uri.length - 1] !== "/") {
- uri += "/";
- }
- return uri + segment + queryPortion;
- };
-
- var buildODataRequest = function (uri, options) {
- /// <summary>Builds a request object to GET the specified URI.</summary>
- /// <param name="uri" type="String">URI for request.</param>
- /// <param name="options" type="Object">Additional options.</param>
-
- return {
- method: "GET",
- requestUri: uri,
- user: options.user,
- password: options.password,
- enableJsonpCallback: options.enableJsonpCallback,
- callbackParameterName: options.callbackParameterName,
- formatQueryString: options.formatQueryString
- };
- };
-
- var findQueryOptionStart = function (uri, name) {
- /// <summary>Finds the index where the value of a query option starts.</summary>
- /// <param name="uri" type="String">URI to search in.</param>
- /// <param name="name" type="String">Name to look for.</param>
- /// <returns type="Number">The index where the query option starts.</returns>
-
- var result = -1;
- var queryIndex = uri.indexOf("?");
- if (queryIndex !== -1) {
- var start = uri.indexOf("?" + name + "=", queryIndex);
- if (start === -1) {
- start = uri.indexOf("&" + name + "=", queryIndex);
- }
- if (start !== -1) {
- result = start + name.length + 2;
- }
- }
- return result;
- };
-
- var queryForData = function (uri, options, success, error) {
- /// <summary>Gets data from an OData service.</summary>
- /// <param name="uri" type="String">URI to the OData service.</param>
- /// <param name="options" type="Object">Object with additional well-known request options.</param>
- /// <param name="success" type="Function">Success callback.</param>
- /// <param name="error" type="Function">Error callback.</param>
- /// <returns type="Object">Object with an abort method.</returns>
-
- var request = queryForDataInternal(uri, options, [], success, error);
- return request;
- };
-
- var queryForDataInternal = function (uri, options, data, success, error) {
- /// <summary>Gets data from an OData service taking into consideration server side paging.</summary>
- /// <param name="uri" type="String">URI to the OData service.</param>
- /// <param name="options" type="Object">Object with additional well-known request options.</param>
- /// <param name="data" type="Array">Array that stores the data provided by the OData service.</param>
- /// <param name="success" type="Function">Success callback.</param>
- /// <param name="error" type="Function">Error callback.</param>
- /// <returns type="Object">Object with an abort method.</returns>
-
- var request = buildODataRequest(uri, options);
- var currentRequest = odata.request(request, function (newData) {
- var next = newData.__next;
- var results = newData.results;
-
- data = data.concat(results);
-
- if (next) {
- currentRequest = queryForDataInternal(next, options, data, success, error);
- } else {
- success(data);
- }
- }, error, undefined, options.httpClient, options.metadata);
-
- return {
- abort: function () {
- currentRequest.abort();
- }
- };
- };
-
- var ODataCacheSource = function (options) {
- /// <summary>Creates a data cache source object for requesting data from an OData service.</summary>
- /// <param name="options">Options for the cache data source.</param>
- /// <returns type="ODataCacheSource">A new data cache source instance.</returns>
-
- var that = this;
- var uri = options.source;
-
- that.identifier = normalizeURICase(encodeURI(decodeURI(uri)));
- that.options = options;
-
- that.count = function (success, error) {
- /// <summary>Gets the number of items in the collection.</summary>
- /// <param name="success" type="Function">Success callback with the item count.</param>
- /// <param name="error" type="Function">Error callback.</param>
- /// <returns type="Object">Request object with an abort method./<param>
-
- var options = that.options;
- return odata.request(
- buildODataRequest(appendSegment(uri, "$count"), options),
- function (data) {
- var count = parseInt10(data.toString());
- if (isNaN(count)) {
- error({ message: "Count is NaN", count: count });
- } else {
- success(count);
- }
- }, error, undefined, options.httpClient, options.metadata);
- };
-
- that.read = function (index, count, success, error) {
- /// <summary>Gets a number of consecutive items from the collection.</summary>
- /// <param name="index" type="Number">Zero-based index of the items to retrieve.</param>
- /// <param name="count" type="Number">Number of items to retrieve.</param>
- /// <param name="success" type="Function">Success callback with the requested items.</param>
- /// <param name="error" type="Function">Error callback.</param>
- /// <returns type="Object">Request object with an abort method./<param>
-
- var queryOptions = "$skip=" + index + "&$top=" + count;
- return queryForData(appendQueryOption(uri, queryOptions), that.options, success, error);
- };
-
- return that;
- };
-
- // DATAJS INTERNAL START
- window.datajs.ODataCacheSource = ODataCacheSource;
- // DATAJS INTERNAL END
-
- // CONTENT END
-})(this);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/cache.js
----------------------------------------------------------------------
diff --git a/datajs/src/cache.js b/datajs/src/cache.js
deleted file mode 100644
index b3a3a01..0000000
--- a/datajs/src/cache.js
+++ /dev/null
@@ -1,1349 +0,0 @@
-/// <reference path="odata-utils.js" />
-
-// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
-// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// cache.js
-
-(function (window, undefined) {
-
- var datajs = window.datajs || {};
-
- var assigned = datajs.assigned;
- var delay = datajs.delay;
- var extend = datajs.extend;
- var djsassert = datajs.djsassert;
- var isArray = datajs.isArray;
- var normalizeURI = datajs.normalizeURI;
- var parseInt10 = datajs.parseInt10;
- var undefinedDefault = datajs.undefinedDefault;
-
- var createDeferred = datajs.createDeferred;
- var DjsDeferred = datajs.DjsDeferred;
- var ODataCacheSource = datajs.ODataCacheSource;
-
- // CONTENT START
-
- var appendPage = function (operation, page) {
- /// <summary>Appends a page's data to the operation data.</summary>
- /// <param name="operation" type="Object">Operation with (i)ndex, (c)ount and (d)ata.</param>
- /// <param name="page" type="Object">Page with (i)ndex, (c)ount and (d)ata.</param>
-
- var intersection = intersectRanges(operation, page);
- if (intersection) {
- var start = intersection.i - page.i;
- var end = start + (operation.c - operation.d.length);
- operation.d = operation.d.concat(page.d.slice(start, end));
- }
- };
-
- var intersectRanges = function (x, y) {
- /// <summary>Returns the {(i)ndex, (c)ount} range for the intersection of x and y.</summary>
- /// <param name="x" type="Object">Range with (i)ndex and (c)ount members.</param>
- /// <param name="y" type="Object">Range with (i)ndex and (c)ount members.</param>
- /// <returns type="Object">The intersection (i)ndex and (c)ount; undefined if there is no intersection.</returns>
-
- var xLast = x.i + x.c;
- var yLast = y.i + y.c;
- var resultIndex = (x.i > y.i) ? x.i : y.i;
- var resultLast = (xLast < yLast) ? xLast : yLast;
- var result;
- if (resultLast >= resultIndex) {
- result = { i: resultIndex, c: resultLast - resultIndex };
- }
-
- return result;
- };
-
- var checkZeroGreater = function (val, name) {
- /// <summary>Checks whether val is a defined number with value zero or greater.</summary>
- /// <param name="val" type="Number">Value to check.</param>
- /// <param name="name" type="String">Parameter name to use in exception.</param>
-
- if (val === undefined || typeof val !== "number") {
- throw { message: "'" + name + "' must be a number." };
- }
-
- if (isNaN(val) || val < 0 || !isFinite(val)) {
- throw { message: "'" + name + "' must be greater than or equal to zero." };
- }
- };
-
- var checkUndefinedGreaterThanZero = function (val, name) {
- /// <summary>Checks whether val is undefined or a number with value greater than zero.</summary>
- /// <param name="val" type="Number">Value to check.</param>
- /// <param name="name" type="String">Parameter name to use in exception.</param>
-
- if (val !== undefined) {
- if (typeof val !== "number") {
- throw { message: "'" + name + "' must be a number." };
- }
-
- if (isNaN(val) || val <= 0 || !isFinite(val)) {
- throw { message: "'" + name + "' must be greater than zero." };
- }
- }
- };
-
- var checkUndefinedOrNumber = function (val, name) {
- /// <summary>Checks whether val is undefined or a number</summary>
- /// <param name="val" type="Number">Value to check.</param>
- /// <param name="name" type="String">Parameter name to use in exception.</param>
- if (val !== undefined && (typeof val !== "number" || isNaN(val) || !isFinite(val))) {
- throw { message: "'" + name + "' must be a number." };
- }
- };
-
- var removeFromArray = function (arr, item) {
- /// <summary>Performs a linear search on the specified array and removes the first instance of 'item'.</summary>
- /// <param name="arr" type="Array">Array to search.</param>
- /// <param name="item">Item being sought.</param>
- /// <returns type="Boolean">Whether the item was removed.</returns>
-
- var i, len;
- for (i = 0, len = arr.length; i < len; i++) {
- if (arr[i] === item) {
- arr.splice(i, 1);
- return true;
- }
- }
-
- return false;
- };
-
- var estimateSize = function (obj) {
- /// <summary>Estimates the size of an object in bytes.</summary>
- /// <param name="obj" type="Object">Object to determine the size of.</param>
- /// <returns type="Integer">Estimated size of the object in bytes.</returns>
- var size = 0;
- var type = typeof obj;
-
- if (type === "object" && obj) {
- for (var name in obj) {
- size += name.length * 2 + estimateSize(obj[name]);
- }
- } else if (type === "string") {
- size = obj.length * 2;
- } else {
- size = 8;
- }
- return size;
- };
-
- var snapToPageBoundaries = function (lowIndex, highIndex, pageSize) {
- /// <summary>Snaps low and high indices into page sizes and returns a range.</summary>
- /// <param name="lowIndex" type="Number">Low index to snap to a lower value.</param>
- /// <param name="highIndex" type="Number">High index to snap to a higher value.</param>
- /// <param name="pageSize" type="Number">Page size to snap to.</param>
- /// <returns type="Object">A range with (i)ndex and (c)ount of elements.</returns>
-
- lowIndex = Math.floor(lowIndex / pageSize) * pageSize;
- highIndex = Math.ceil((highIndex + 1) / pageSize) * pageSize;
- return { i: lowIndex, c: highIndex - lowIndex };
- };
-
- // The DataCache is implemented using state machines. The following constants are used to properly
- // identify and label the states that these machines transition to.
-
- // DataCache state constants
-
- var CACHE_STATE_DESTROY = "destroy";
- var CACHE_STATE_IDLE = "idle";
- var CACHE_STATE_INIT = "init";
- var CACHE_STATE_READ = "read";
- var CACHE_STATE_PREFETCH = "prefetch";
- var CACHE_STATE_WRITE = "write";
-
- // DataCacheOperation state machine states.
- // Transitions on operations also depend on the cache current of the cache.
-
- var OPERATION_STATE_CANCEL = "cancel";
- var OPERATION_STATE_END = "end";
- var OPERATION_STATE_ERROR = "error";
- var OPERATION_STATE_START = "start";
- var OPERATION_STATE_WAIT = "wait";
-
- // Destroy state machine states
-
- var DESTROY_STATE_CLEAR = "clear";
-
- // Read / Prefetch state machine states
-
- var READ_STATE_DONE = "done";
- var READ_STATE_LOCAL = "local";
- var READ_STATE_SAVE = "save";
- var READ_STATE_SOURCE = "source";
-
- var DataCacheOperation = function (stateMachine, promise, isCancelable, index, count, data, pending) {
- /// <summary>Creates a new operation object.</summary>
- /// <param name="stateMachine" type="Function">State machine that describes the specific behavior of the operation.</param>
- /// <param name="promise" type ="DjsDeferred">Promise for requested values.</param>
- /// <param name="isCancelable" type ="Boolean">Whether this operation can be canceled or not.</param>
- /// <param name="index" type="Number">Index of first item requested.</param>
- /// <param name="count" type="Number">Count of items requested.</param>
- /// <param name="data" type="Array">Array with the items requested by the operation.</param>
- /// <param name="pending" type="Number">Total number of pending prefetch records.</param>
- /// <returns type="DataCacheOperation">A new data cache operation instance.</returns>
-
- /// <field name="p" type="DjsDeferred">Promise for requested values.</field>
- /// <field name="i" type="Number">Index of first item requested.</field>
- /// <field name="c" type="Number">Count of items requested.</field>
- /// <field name="d" type="Array">Array with the items requested by the operation.</field>
- /// <field name="s" type="Array">Current state of the operation.</field>
- /// <field name="canceled" type="Boolean">Whether the operation has been canceled.</field>
- /// <field name="pending" type="Number">Total number of pending prefetch records.</field>
- /// <field name="oncomplete" type="Function">Callback executed when the operation reaches the end state.</field>
-
- var stateData;
- var cacheState;
- var that = this;
-
- that.p = promise;
- that.i = index;
- that.c = count;
- that.d = data;
- that.s = OPERATION_STATE_START;
-
- that.canceled = false;
- that.pending = pending;
- that.oncomplete = null;
-
- that.cancel = function () {
- /// <summary>Transitions this operation to the cancel state and sets the canceled flag to true.</summary>
- /// <remarks>The function is a no-op if the operation is non-cancelable.</summary>
-
- if (!isCancelable) {
- return;
- }
-
- var state = that.s;
- if (state !== OPERATION_STATE_ERROR && state !== OPERATION_STATE_END && state !== OPERATION_STATE_CANCEL) {
- that.canceled = true;
- transition(OPERATION_STATE_CANCEL, stateData);
- }
- };
-
- that.complete = function () {
- /// <summary>Transitions this operation to the end state.</summary>
-
- djsassert(that.s !== OPERATION_STATE_END, "DataCacheOperation.complete() - operation is in the end state", that);
- transition(OPERATION_STATE_END, stateData);
- };
-
- that.error = function (err) {
- /// <summary>Transitions this operation to the error state.</summary>
- if (!that.canceled) {
- djsassert(that.s !== OPERATION_STATE_END, "DataCacheOperation.error() - operation is in the end state", that);
- djsassert(that.s !== OPERATION_STATE_ERROR, "DataCacheOperation.error() - operation is in the error state", that);
- transition(OPERATION_STATE_ERROR, err);
- }
- };
-
- that.run = function (state) {
- /// <summary>Executes the operation's current state in the context of a new cache state.</summary>
- /// <param name="state" type="Object">New cache state.</param>
-
- cacheState = state;
- that.transition(that.s, stateData);
- };
-
- that.wait = function (data) {
- /// <summary>Transitions this operation to the wait state.</summary>
-
- djsassert(that.s !== OPERATION_STATE_END, "DataCacheOperation.wait() - operation is in the end state", that);
- transition(OPERATION_STATE_WAIT, data);
- };
-
- var operationStateMachine = function (opTargetState, cacheState, data) {
- /// <summary>State machine that describes all operations common behavior.</summary>
- /// <param name="opTargetState" type="Object">Operation state to transition to.</param>
- /// <param name="cacheState" type="Object">Current cache state.</param>
- /// <param name="data" type="Object" optional="true">Additional data passed to the state.</param>
-
- switch (opTargetState) {
- case OPERATION_STATE_START:
- // Initial state of the operation. The operation will remain in this state until the cache has been fully initialized.
- if (cacheState !== CACHE_STATE_INIT) {
- stateMachine(that, opTargetState, cacheState, data);
- }
- break;
-
- case OPERATION_STATE_WAIT:
- // Wait state indicating that the operation is active but waiting for an asynchronous operation to complete.
- stateMachine(that, opTargetState, cacheState, data);
- break;
-
- case OPERATION_STATE_CANCEL:
- // Cancel state.
- stateMachine(that, opTargetState, cacheState, data);
- that.fireCanceled();
- transition(OPERATION_STATE_END);
- break;
-
- case OPERATION_STATE_ERROR:
- // Error state. Data is expected to be an object detailing the error condition.
- stateMachine(that, opTargetState, cacheState, data);
- that.canceled = true;
- that.fireRejected(data);
- transition(OPERATION_STATE_END);
- break;
-
- case OPERATION_STATE_END:
- // Final state of the operation.
- if (that.oncomplete) {
- that.oncomplete(that);
- }
- if (!that.canceled) {
- that.fireResolved();
- }
- stateMachine(that, opTargetState, cacheState, data);
- break;
-
- default:
- // Any other state is passed down to the state machine describing the operation's specific behavior.
- // DATAJS INTERNAL START
- if (true) {
- // Check that the state machine actually handled the sate.
- var handled = stateMachine(that, opTargetState, cacheState, data);
- djsassert(handled, "Bad operation state: " + opTargetState + " cacheState: " + cacheState, this);
- } else {
- // DATAJS INTERNAL END
- stateMachine(that, opTargetState, cacheState, data);
- // DATAJS INTERNAL START
- }
- // DATAJS INTERNAL END
- break;
- }
- };
-
- var transition = function (state, data) {
- /// <summary>Transitions this operation to a new state.</summary>
- /// <param name="state" type="Object">State to transition the operation to.</param>
- /// <param name="data" type="Object" optional="true">Additional data passed to the state.</param>
-
- that.s = state;
- stateData = data;
- operationStateMachine(state, cacheState, data);
- };
-
- that.transition = transition;
-
- return that;
- };
-
- DataCacheOperation.prototype.fireResolved = function () {
- /// <summary>Fires a resolved notification as necessary.</summary>
-
- // Fire the resolve just once.
- var p = this.p;
- if (p) {
- this.p = null;
- p.resolve(this.d);
- }
- };
-
- DataCacheOperation.prototype.fireRejected = function (reason) {
- /// <summary>Fires a rejected notification as necessary.</summary>
-
- // Fire the rejection just once.
- var p = this.p;
- if (p) {
- this.p = null;
- p.reject(reason);
- }
- };
-
- DataCacheOperation.prototype.fireCanceled = function () {
- /// <summary>Fires a canceled notification as necessary.</summary>
-
- this.fireRejected({ canceled: true, message: "Operation canceled" });
- };
-
-
- var DataCache = function (options) {
- /// <summary>Creates a data cache for a collection that is efficiently loaded on-demand.</summary>
- /// <param name="options">
- /// Options for the data cache, including name, source, pageSize,
- /// prefetchSize, cacheSize, storage mechanism, and initial prefetch and local-data handler.
- /// </param>
- /// <returns type="DataCache">A new data cache instance.</returns>
-
- var state = CACHE_STATE_INIT;
- var stats = { counts: 0, netReads: 0, prefetches: 0, cacheReads: 0 };
-
- var clearOperations = [];
- var readOperations = [];
- var prefetchOperations = [];
-
- var actualCacheSize = 0; // Actual cache size in bytes.
- var allDataLocal = false; // Whether all data is local.
- var cacheSize = undefinedDefault(options.cacheSize, 1048576); // Requested cache size in bytes, default 1 MB.
- var collectionCount = 0; // Number of elements in the server collection.
- var highestSavedPage = 0; // Highest index of all the saved pages.
- var highestSavedPageSize = 0; // Item count of the saved page with the highest index.
- var overflowed = cacheSize === 0; // If the cache has overflowed (actualCacheSize > cacheSize or cacheSize == 0);
- var pageSize = undefinedDefault(options.pageSize, 50); // Number of elements to store per page.
- var prefetchSize = undefinedDefault(options.prefetchSize, pageSize); // Number of elements to prefetch from the source when the cache is idling.
- var version = "1.0";
- var cacheFailure;
-
- var pendingOperations = 0;
-
- var source = options.source;
- if (typeof source === "string") {
- // Create a new cache source.
- source = new ODataCacheSource(options);
- }
- source.options = options;
-
- // Create a cache local store.
- var store = datajs.createStore(options.name, options.mechanism);
-
- var that = this;
-
- that.onidle = options.idle;
- that.stats = stats;
-
- that.count = function () {
- /// <summary>Counts the number of items in the collection.</summary>
- /// <returns type="Object">A promise with the number of items.</returns>
-
- if (cacheFailure) {
- throw cacheFailure;
- }
-
- var deferred = createDeferred();
- var canceled = false;
-
- if (allDataLocal) {
- delay(function () {
- deferred.resolve(collectionCount);
- });
-
- return deferred.promise();
- }
-
- // TODO: Consider returning the local data count instead once allDataLocal flag is set to true.
- var request = source.count(function (count) {
- request = null;
- stats.counts++;
- deferred.resolve(count);
- }, function (err) {
- request = null;
- deferred.reject(extend(err, { canceled: canceled }));
- });
-
- return extend(deferred.promise(), {
- cancel: function () {
- /// <summary>Aborts the count operation.</summary>
- if (request) {
- canceled = true;
- request.abort();
- request = null;
- }
- }
- });
- };
-
- that.clear = function () {
- /// <summary>Cancels all running operations and clears all local data associated with this cache.</summary>
- /// <remarks>
- /// New read requests made while a clear operation is in progress will not be canceled.
- /// Instead they will be queued for execution once the operation is completed.
- /// </remarks>
- /// <returns type="Object">A promise that has no value and can't be canceled.</returns>
-
- if (cacheFailure) {
- throw cacheFailure;
- }
-
- if (clearOperations.length === 0) {
- var deferred = createDeferred();
- var op = new DataCacheOperation(destroyStateMachine, deferred, false);
- queueAndStart(op, clearOperations);
- return deferred.promise();
- }
- return clearOperations[0].p;
- };
-
- that.filterForward = function (index, count, predicate) {
- /// <summary>Filters the cache data based a predicate.</summary>
- /// <param name="index" type="Number">The index of the item to start filtering forward from.</param>
- /// <param name="count" type="Number">Maximum number of items to include in the result.</param>
- /// <param name="predicate" type="Function">Callback function returning a boolean that determines whether an item should be included in the result or not.</param>
- /// <remarks>
- /// Specifying a negative count value will yield all the items in the cache that satisfy the predicate.
- /// </remarks>
- /// <returns type="DjsDeferred">A promise for an array of results.</returns>
- return filter(index, count, predicate, false);
- };
-
- that.filterBack = function (index, count, predicate) {
- /// <summary>Filters the cache data based a predicate.</summary>
- /// <param name="index" type="Number">The index of the item to start filtering backward from.</param>
- /// <param name="count" type="Number">Maximum number of items to include in the result.</param>
- /// <param name="predicate" type="Function">Callback function returning a boolean that determines whether an item should be included in the result or not.</param>
- /// <remarks>
- /// Specifying a negative count value will yield all the items in the cache that satisfy the predicate.
- /// </remarks>
- /// <returns type="DjsDeferred">A promise for an array of results.</returns>
- return filter(index, count, predicate, true);
- };
-
- that.readRange = function (index, count) {
- /// <summary>Reads a range of adjacent records.</summary>
- /// <param name="index" type="Number">Zero-based index of record range to read.</param>
- /// <param name="count" type="Number">Number of records in the range.</param>
- /// <remarks>
- /// New read requests made while a clear operation is in progress will not be canceled.
- /// Instead they will be queued for execution once the operation is completed.
- /// </remarks>
- /// <returns type="DjsDeferred">
- /// A promise for an array of records; less records may be returned if the
- /// end of the collection is found.
- /// </returns>
-
- checkZeroGreater(index, "index");
- checkZeroGreater(count, "count");
-
- if (cacheFailure) {
- throw cacheFailure;
- }
-
- var deferred = createDeferred();
-
- // Merging read operations would be a nice optimization here.
- var op = new DataCacheOperation(readStateMachine, deferred, true, index, count, [], 0);
- queueAndStart(op, readOperations);
-
- return extend(deferred.promise(), {
- cancel: function () {
- /// <summary>Aborts the readRange operation.</summary>
- op.cancel();
- }
- });
- };
-
- that.ToObservable = that.toObservable = function () {
- /// <summary>Creates an Observable object that enumerates all the cache contents.</summary>
- /// <returns>A new Observable object that enumerates all the cache contents.</returns>
- if (!window.Rx || !window.Rx.Observable) {
- throw { message: "Rx library not available - include rx.js" };
- }
-
- if (cacheFailure) {
- throw cacheFailure;
- }
-
- return window.Rx.Observable.CreateWithDisposable(function (obs) {
- var disposed = false;
- var index = 0;
-
- var errorCallback = function (error) {
- if (!disposed) {
- obs.OnError(error);
- }
- };
-
- var successCallback = function (data) {
- if (!disposed) {
- var i, len;
- for (i = 0, len = data.length; i < len; i++) {
- // The wrapper automatically checks for Dispose
- // on the observer, so we don't need to check it here.
- obs.OnNext(data[i]);
- }
-
- if (data.length < pageSize) {
- obs.OnCompleted();
- } else {
- index += pageSize;
- that.readRange(index, pageSize).then(successCallback, errorCallback);
- }
- }
- };
-
- that.readRange(index, pageSize).then(successCallback, errorCallback);
-
- return { Dispose: function () { disposed = true; } };
- });
- };
-
- var cacheFailureCallback = function (message) {
- /// <summary>Creates a function that handles a callback by setting the cache into failure mode.</summary>
- /// <param name="message" type="String">Message text.</param>
- /// <returns type="Function">Function to use as error callback.</returns>
- /// <remarks>
- /// This function will specifically handle problems with critical store resources
- /// during cache initialization.
- /// </remarks>
-
- return function (error) {
- cacheFailure = { message: message, error: error };
-
- // Destroy any pending clear or read operations.
- // At this point there should be no prefetch operations.
- // Count operations will go through but are benign because they
- // won't interact with the store.
- djsassert(prefetchOperations.length === 0, "prefetchOperations.length === 0");
- var i, len;
- for (i = 0, len = readOperations.length; i < len; i++) {
- readOperations[i].fireRejected(cacheFailure);
- }
- for (i = 0, len = clearOperations.length; i < len; i++) {
- clearOperations[i].fireRejected(cacheFailure);
- }
-
- // Null out the operation arrays.
- readOperations = clearOperations = null;
- };
- };
-
- var changeState = function (newState) {
- /// <summary>Updates the cache's state and signals all pending operations of the change.</summary>
- /// <param name="newState" type="Object">New cache state.</param>
- /// <remarks>This method is a no-op if the cache's current state and the new state are the same.</remarks>
-
- if (newState !== state) {
- state = newState;
- var operations = clearOperations.concat(readOperations, prefetchOperations);
- var i, len;
- for (i = 0, len = operations.length; i < len; i++) {
- operations[i].run(state);
- }
- }
- };
-
- var clearStore = function () {
- /// <summary>Removes all the data stored in the cache.</summary>
- /// <returns type="DjsDeferred">A promise with no value.</returns>
- djsassert(state === CACHE_STATE_DESTROY || state === CACHE_STATE_INIT, "DataCache.clearStore() - cache is not on the destroy or initialize state, current sate = " + state);
-
- var deferred = new DjsDeferred();
- store.clear(function () {
-
- // Reset the cache settings.
- actualCacheSize = 0;
- allDataLocal = false;
- collectionCount = 0;
- highestSavedPage = 0;
- highestSavedPageSize = 0;
- overflowed = cacheSize === 0;
-
- // version is not reset, in case there is other state in eg V1.1 that is still around.
-
- // Reset the cache stats.
- stats = { counts: 0, netReads: 0, prefetches: 0, cacheReads: 0 };
- that.stats = stats;
-
- store.close();
- deferred.resolve();
- }, function (err) {
- deferred.reject(err);
- });
- return deferred;
- };
-
- var dequeueOperation = function (operation) {
- /// <summary>Removes an operation from the caches queues and changes the cache state to idle.</summary>
- /// <param name="operation" type="DataCacheOperation">Operation to dequeue.</param>
- /// <remarks>This method is used as a handler for the operation's oncomplete event.</remarks>
-
- var removed = removeFromArray(clearOperations, operation);
- if (!removed) {
- removed = removeFromArray(readOperations, operation);
- if (!removed) {
- removeFromArray(prefetchOperations, operation);
- }
- }
-
- pendingOperations--;
- changeState(CACHE_STATE_IDLE);
- };
-
- var fetchPage = function (start) {
- /// <summary>Requests data from the cache source.</summary>
- /// <param name="start" type="Number">Zero-based index of items to request.</param>
- /// <returns type="DjsDeferred">A promise for a page object with (i)ndex, (c)ount, (d)ata.</returns>
-
- djsassert(state !== CACHE_STATE_DESTROY, "DataCache.fetchPage() - cache is on the destroy state");
- djsassert(state !== CACHE_STATE_IDLE, "DataCache.fetchPage() - cache is on the idle state");
-
- var deferred = new DjsDeferred();
- var canceled = false;
-
- var request = source.read(start, pageSize, function (data) {
- var page = { i: start, c: data.length, d: data };
- deferred.resolve(page);
- }, function (err) {
- deferred.reject(err);
- });
-
- return extend(deferred, {
- cancel: function () {
- if (request) {
- request.abort();
- canceled = true;
- request = null;
- }
- }
- });
- };
-
- var filter = function (index, count, predicate, backwards) {
- /// <summary>Filters the cache data based a predicate.</summary>
- /// <param name="index" type="Number">The index of the item to start filtering from.</param>
- /// <param name="count" type="Number">Maximum number of items to include in the result.</param>
- /// <param name="predicate" type="Function">Callback function returning a boolean that determines whether an item should be included in the result or not.</param>
- /// <param name="backwards" type="Boolean">True if the filtering should move backward from the specified index, falsey otherwise.</param>
- /// <remarks>
- /// Specifying a negative count value will yield all the items in the cache that satisfy the predicate.
- /// </remarks>
- /// <returns type="DjsDeferred">A promise for an array of results.</returns>
- index = parseInt10(index);
- count = parseInt10(count);
-
- if (isNaN(index)) {
- throw { message: "'index' must be a valid number.", index: index };
- }
- if (isNaN(count)) {
- throw { message: "'count' must be a valid number.", count: count };
- }
-
- if (cacheFailure) {
- throw cacheFailure;
- }
-
- index = Math.max(index, 0);
-
- var deferred = createDeferred();
- var arr = [];
- var canceled = false;
- var pendingReadRange = null;
-
- var readMore = function (readIndex, readCount) {
- if (!canceled) {
- if (count >= 0 && arr.length >= count) {
- deferred.resolve(arr);
- } else {
- pendingReadRange = that.readRange(readIndex, readCount).then(function (data) {
- for (var i = 0, length = data.length; i < length && (count < 0 || arr.length < count); i++) {
- var dataIndex = backwards ? length - i - 1 : i;
- var item = data[dataIndex];
- if (predicate(item)) {
- var element = {
- index: readIndex + dataIndex,
- item: item
- };
-
- backwards ? arr.unshift(element) : arr.push(element);
- }
- }
-
- // Have we reached the end of the collection?
- if ((!backwards && data.length < readCount) || (backwards && readIndex <= 0)) {
- deferred.resolve(arr);
- } else {
- var nextIndex = backwards ? Math.max(readIndex - pageSize, 0) : readIndex + readCount;
- readMore(nextIndex, pageSize);
- }
- }, function (err) {
- deferred.reject(err);
- });
- }
- }
- };
-
- // Initially, we read from the given starting index to the next/previous page boundary
- var initialPage = snapToPageBoundaries(index, index, pageSize);
- var initialIndex = backwards ? initialPage.i : index;
- var initialCount = backwards ? index - initialPage.i + 1 : initialPage.i + initialPage.c - index;
- readMore(initialIndex, initialCount);
-
- return extend(deferred.promise(), {
- cancel: function () {
- /// <summary>Aborts the filter operation</summary>
- if (pendingReadRange) {
- pendingReadRange.cancel();
- }
- canceled = true;
- }
- });
- };
-
- var fireOnIdle = function () {
- /// <summary>Fires an onidle event if any functions are assigned.</summary>
-
- if (that.onidle && pendingOperations === 0) {
- that.onidle();
- }
- };
-
- var prefetch = function (start) {
- /// <summary>Creates and starts a new prefetch operation.</summary>
- /// <param name="start" type="Number">Zero-based index of the items to prefetch.</param>
- /// <remarks>
- /// This method is a no-op if any of the following conditions is true:
- /// 1.- prefetchSize is 0
- /// 2.- All data has been read and stored locally in the cache.
- /// 3.- There is already an all data prefetch operation queued.
- /// 4.- The cache has run out of available space (overflowed).
- /// <remarks>
-
- if (allDataLocal || prefetchSize === 0 || overflowed) {
- return;
- }
-
- djsassert(state === CACHE_STATE_READ, "DataCache.prefetch() - cache is not on the read state, current state: " + state);
-
- if (prefetchOperations.length === 0 || (prefetchOperations[0] && prefetchOperations[0].c !== -1)) {
- // Merging prefetch operations would be a nice optimization here.
- var op = new DataCacheOperation(prefetchStateMachine, null, true, start, prefetchSize, null, prefetchSize);
- queueAndStart(op, prefetchOperations);
- }
- };
-
- var queueAndStart = function (op, queue) {
- /// <summary>Queues an operation and runs it.</summary>
- /// <param name="op" type="DataCacheOperation">Operation to queue.</param>
- /// <param name="queue" type="Array">Array that will store the operation.</param>
-
- op.oncomplete = dequeueOperation;
- queue.push(op);
- pendingOperations++;
- op.run(state);
- };
-
- var readPage = function (key) {
- /// <summary>Requests a page from the cache local store.</summary>
- /// <param name="key" type="Number">Zero-based index of the reuqested page.</param>
- /// <returns type="DjsDeferred">A promise for a found flag and page object with (i)ndex, (c)ount, (d)ata, and (t)icks.</returns>
-
- djsassert(state !== CACHE_STATE_DESTROY, "DataCache.readPage() - cache is on the destroy state");
-
- var canceled = false;
- var deferred = extend(new DjsDeferred(), {
- cancel: function () {
- /// <summary>Aborts the readPage operation.</summary>
- canceled = true;
- }
- });
-
- var error = storeFailureCallback(deferred, "Read page from store failure");
-
- store.contains(key, function (contained) {
- if (canceled) {
- return;
- }
- if (contained) {
- store.read(key, function (_, data) {
- if (!canceled) {
- deferred.resolve(data !== undefined, data);
- }
- }, error);
- return;
- }
- deferred.resolve(false);
- }, error);
- return deferred;
- };
-
- var savePage = function (key, page) {
- /// <summary>Saves a page to the cache local store.</summary>
- /// <param name="key" type="Number">Zero-based index of the requested page.</param>
- /// <param name="page" type="Object">Object with (i)ndex, (c)ount, (d)ata, and (t)icks.</param>
- /// <returns type="DjsDeferred">A promise with no value.</returns>
-
- djsassert(state !== CACHE_STATE_DESTROY, "DataCache.savePage() - cache is on the destroy state");
- djsassert(state !== CACHE_STATE_IDLE, "DataCache.savePage() - cache is on the idle state");
-
- var canceled = false;
-
- var deferred = extend(new DjsDeferred(), {
- cancel: function () {
- /// <summary>Aborts the readPage operation.</summary>
- canceled = true;
- }
- });
-
- var error = storeFailureCallback(deferred, "Save page to store failure");
-
- var resolve = function () {
- deferred.resolve(true);
- };
-
- if (page.c > 0) {
- var pageBytes = estimateSize(page);
- overflowed = cacheSize >= 0 && cacheSize < actualCacheSize + pageBytes;
-
- if (!overflowed) {
- store.addOrUpdate(key, page, function () {
- updateSettings(page, pageBytes);
- saveSettings(resolve, error);
- }, error);
- } else {
- resolve();
- }
- } else {
- updateSettings(page, 0);
- saveSettings(resolve, error);
- }
- return deferred;
- };
-
- var saveSettings = function (success, error) {
- /// <summary>Saves the cache's current settings to the local store.</summary>
- /// <param name="success" type="Function">Success callback.</param>
- /// <param name="error" type="Function">Errror callback.</param>
-
- var settings = {
- actualCacheSize: actualCacheSize,
- allDataLocal: allDataLocal,
- cacheSize: cacheSize,
- collectionCount: collectionCount,
- highestSavedPage: highestSavedPage,
- highestSavedPageSize: highestSavedPageSize,
- pageSize: pageSize,
- sourceId: source.identifier,
- version: version
- };
-
- store.addOrUpdate("__settings", settings, success, error);
- };
-
- var storeFailureCallback = function (deferred/*, message*/) {
- /// <summary>Creates a function that handles a store error.</summary>
- /// <param name="deferred" type="DjsDeferred">Deferred object to resolve.</param>
- /// <param name="message" type="String">Message text.</param>
- /// <returns type="Function">Function to use as error callback.</returns>
- /// <remarks>
- /// This function will specifically handle problems when interacting with the store.
- /// </remarks>
-
- return function (/*error*/) {
- // var console = window.console;
- // if (console && console.log) {
- // console.log(message);
- // console.dir(error);
- // }
- deferred.resolve(false);
- };
- };
-
- var updateSettings = function (page, pageBytes) {
- /// <summary>Updates the cache's settings based on a page object.</summary>
- /// <param name="page" type="Object">Object with (i)ndex, (c)ount, (d)ata.</param>
- /// <param name="pageBytes" type="Number">Size of the page in bytes.</param>
-
- var pageCount = page.c;
- var pageIndex = page.i;
-
- // Detect the collection size.
- if (pageCount === 0) {
- if (highestSavedPage === pageIndex - pageSize) {
- collectionCount = highestSavedPage + highestSavedPageSize;
- }
- } else {
- highestSavedPage = Math.max(highestSavedPage, pageIndex);
- if (highestSavedPage === pageIndex) {
- highestSavedPageSize = pageCount;
- }
- actualCacheSize += pageBytes;
- if (pageCount < pageSize && !collectionCount) {
- collectionCount = pageIndex + pageCount;
- }
- }
-
- // Detect the end of the collection.
- if (!allDataLocal && collectionCount === highestSavedPage + highestSavedPageSize) {
- allDataLocal = true;
- }
- };
-
- var cancelStateMachine = function (operation, opTargetState, cacheState, data) {
- /// <summary>State machine describing the behavior for cancelling a read or prefetch operation.</summary>
- /// <param name="operation" type="DataCacheOperation">Operation being run.</param>
- /// <param name="opTargetState" type="Object">Operation state to transition to.</param>
- /// <param name="cacheState" type="Object">Current cache state.</param>
- /// <param name="data" type="Object" optional="true">Additional data passed to the state.</param>
- /// <remarks>
- /// This state machine contains behavior common to read and prefetch operations.
- /// </remarks>
-
- var canceled = operation.canceled && opTargetState !== OPERATION_STATE_END;
- if (canceled) {
- if (opTargetState === OPERATION_STATE_CANCEL) {
- // Cancel state.
- // Data is expected to be any pending request made to the cache.
- if (data && data.cancel) {
- data.cancel();
- }
- }
- }
- return canceled;
- };
-
- var destroyStateMachine = function (operation, opTargetState, cacheState) {
- /// <summary>State machine describing the behavior of a clear operation.</summary>
- /// <param name="operation" type="DataCacheOperation">Operation being run.</param>
- /// <param name="opTargetState" type="Object">Operation state to transition to.</param>
- /// <param name="cacheState" type="Object">Current cache state.</param>
- /// <remarks>
- /// Clear operations have the highest priority and can't be interrupted by other operations; however,
- /// they will preempt any other operation currently executing.
- /// </remarks>
-
- var transition = operation.transition;
-
- // Signal the cache that a clear operation is running.
- if (cacheState !== CACHE_STATE_DESTROY) {
- changeState(CACHE_STATE_DESTROY);
- return true;
- }
-
- switch (opTargetState) {
- case OPERATION_STATE_START:
- // Initial state of the operation.
- transition(DESTROY_STATE_CLEAR);
- break;
-
- case OPERATION_STATE_END:
- // State that signals the operation is done.
- fireOnIdle();
- break;
-
- case DESTROY_STATE_CLEAR:
- // State that clears all the local data of the cache.
- clearStore().then(function () {
- // Terminate the operation once the local store has been cleared.
- operation.complete();
- });
- // Wait until the clear request completes.
- operation.wait();
- break;
-
- default:
- return false;
- }
- return true;
- };
-
- var prefetchStateMachine = function (operation, opTargetState, cacheState, data) {
- /// <summary>State machine describing the behavior of a prefetch operation.</summary>
- /// <param name="operation" type="DataCacheOperation">Operation being run.</param>
- /// <param name="opTargetState" type="Object">Operation state to transition to.</param>
- /// <param name="cacheState" type="Object">Current cache state.</param>
- /// <param name="data" type="Object" optional="true">Additional data passed to the state.</param>
- /// <remarks>
- /// Prefetch operations have the lowest priority and will be interrupted by operations of
- /// other kinds. A preempted prefetch operation will resume its execution only when the state
- /// of the cache returns to idle.
- ///
- /// If a clear operation starts executing then all the prefetch operations are canceled,
- /// even if they haven't started executing yet.
- /// </remarks>
-
- // Handle cancelation
- if (!cancelStateMachine(operation, opTargetState, cacheState, data)) {
-
- var transition = operation.transition;
-
- // Handle preemption
- if (cacheState !== CACHE_STATE_PREFETCH) {
- if (cacheState === CACHE_STATE_DESTROY) {
- if (opTargetState !== OPERATION_STATE_CANCEL) {
- operation.cancel();
- }
- } else if (cacheState === CACHE_STATE_IDLE) {
- // Signal the cache that a prefetch operation is running.
- changeState(CACHE_STATE_PREFETCH);
- }
- return true;
- }
-
- switch (opTargetState) {
- case OPERATION_STATE_START:
- // Initial state of the operation.
- if (prefetchOperations[0] === operation) {
- transition(READ_STATE_LOCAL, operation.i);
- }
- break;
-
- case READ_STATE_DONE:
- // State that determines if the operation can be resolved or has to
- // continue processing.
- // Data is expected to be the read page.
- var pending = operation.pending;
-
- if (pending > 0) {
- pending -= Math.min(pending, data.c);
- }
-
- // Are we done, or has all the data been stored?
- if (allDataLocal || pending === 0 || data.c < pageSize || overflowed) {
- operation.complete();
- } else {
- // Continue processing the operation.
- operation.pending = pending;
- transition(READ_STATE_LOCAL, data.i + pageSize);
- }
- break;
-
- default:
- return readSaveStateMachine(operation, opTargetState, cacheState, data, true);
- }
- }
- return true;
- };
-
- var readStateMachine = function (operation, opTargetState, cacheState, data) {
- /// <summary>State machine describing the behavior of a read operation.</summary>
- /// <param name="operation" type="DataCacheOperation">Operation being run.</param>
- /// <param name="opTargetState" type="Object">Operation state to transition to.</param>
- /// <param name="cacheState" type="Object">Current cache state.</param>
- /// <param name="data" type="Object" optional="true">Additional data passed to the state.</param>
- /// <remarks>
- /// Read operations have a higher priority than prefetch operations, but lower than
- /// clear operations. They will preempt any prefetch operation currently running
- /// but will be interrupted by a clear operation.
- ///
- /// If a clear operation starts executing then all the currently running
- /// read operations are canceled. Read operations that haven't started yet will
- /// wait in the start state until the destory operation finishes.
- /// </remarks>
-
- // Handle cancelation
- if (!cancelStateMachine(operation, opTargetState, cacheState, data)) {
-
- var transition = operation.transition;
-
- // Handle preemption
- if (cacheState !== CACHE_STATE_READ && opTargetState !== OPERATION_STATE_START) {
- if (cacheState === CACHE_STATE_DESTROY) {
- if (opTargetState !== OPERATION_STATE_START) {
- operation.cancel();
- }
- } else if (cacheState !== CACHE_STATE_WRITE) {
- // Signal the cache that a read operation is running.
- djsassert(state == CACHE_STATE_IDLE || state === CACHE_STATE_PREFETCH, "DataCache.readStateMachine() - cache is not on the read or idle state.");
- changeState(CACHE_STATE_READ);
- }
-
- return true;
- }
-
- switch (opTargetState) {
- case OPERATION_STATE_START:
- // Initial state of the operation.
- // Wait until the cache is idle or prefetching.
- if (cacheState === CACHE_STATE_IDLE || cacheState === CACHE_STATE_PREFETCH) {
- // Signal the cache that a read operation is running.
- changeState(CACHE_STATE_READ);
- if (operation.c > 0) {
- // Snap the requested range to a page boundary.
- var range = snapToPageBoundaries(operation.i, operation.c, pageSize);
- transition(READ_STATE_LOCAL, range.i);
- } else {
- transition(READ_STATE_DONE, operation);
- }
- }
- break;
-
- case READ_STATE_DONE:
- // State that determines if the operation can be resolved or has to
- // continue processing.
- // Data is expected to be the read page.
- appendPage(operation, data);
- var len = operation.d.length;
- // Are we done?
- if (operation.c === len || data.c < pageSize) {
- // Update the stats, request for a prefetch operation.
- stats.cacheReads++;
- prefetch(data.i + data.c);
- // Terminate the operation.
- operation.complete();
- } else {
- // Continue processing the operation.
- transition(READ_STATE_LOCAL, data.i + pageSize);
- }
- break;
-
- default:
- return readSaveStateMachine(operation, opTargetState, cacheState, data, false);
- }
- }
-
- return true;
- };
-
- var readSaveStateMachine = function (operation, opTargetState, cacheState, data, isPrefetch) {
- /// <summary>State machine describing the behavior for reading and saving data into the cache.</summary>
- /// <param name="operation" type="DataCacheOperation">Operation being run.</param>
- /// <param name="opTargetState" type="Object">Operation state to transition to.</param>
- /// <param name="cacheState" type="Object">Current cache state.</param>
- /// <param name="data" type="Object" optional="true">Additional data passed to the state.</param>
- /// <param name="isPrefetch" type="Boolean">Flag indicating whether a read (false) or prefetch (true) operation is running.
- /// <remarks>
- /// This state machine contains behavior common to read and prefetch operations.
- /// </remarks>
-
- var error = operation.error;
- var transition = operation.transition;
- var wait = operation.wait;
- var request;
-
- switch (opTargetState) {
- case OPERATION_STATE_END:
- // State that signals the operation is done.
- fireOnIdle();
- break;
-
- case READ_STATE_LOCAL:
- // State that requests for a page from the local store.
- // Data is expected to be the index of the page to request.
- request = readPage(data).then(function (found, page) {
- // Signal the cache that a read operation is running.
- if (!operation.canceled) {
- if (found) {
- // The page is in the local store, check if the operation can be resolved.
- transition(READ_STATE_DONE, page);
- } else {
- // The page is not in the local store, request it from the source.
- transition(READ_STATE_SOURCE, data);
- }
- }
- });
- break;
-
- case READ_STATE_SOURCE:
- // State that requests for a page from the cache source.
- // Data is expected to be the index of the page to request.
- request = fetchPage(data).then(function (page) {
- // Signal the cache that a read operation is running.
- if (!operation.canceled) {
- // Update the stats and save the page to the local store.
- if (isPrefetch) {
- stats.prefetches++;
- } else {
- stats.netReads++;
- }
- transition(READ_STATE_SAVE, page);
- }
- }, error);
- break;
-
- case READ_STATE_SAVE:
- // State that saves a page to the local store.
- // Data is expected to be the page to save.
- // Write access to the store is exclusive.
- if (cacheState !== CACHE_STATE_WRITE) {
- changeState(CACHE_STATE_WRITE);
- request = savePage(data.i, data).then(function (saved) {
- if (!operation.canceled) {
- if (!saved && isPrefetch) {
- operation.pending = 0;
- }
- // Check if the operation can be resolved.
- transition(READ_STATE_DONE, data);
- }
- changeState(CACHE_STATE_IDLE);
- });
- }
- break;
-
- default:
- // Unknown state that can't be handled by this state machine.
- return false;
- }
-
- if (request) {
- // The operation might have been canceled between stack frames do to the async calls.
- if (operation.canceled) {
- request.cancel();
- } else if (operation.s === opTargetState) {
- // Wait for the request to complete.
- wait(request);
- }
- }
-
- return true;
- };
-
- // Initialize the cache.
- store.read("__settings", function (_, settings) {
- if (assigned(settings)) {
- var settingsVersion = settings.version;
- if (!settingsVersion || settingsVersion.indexOf("1.") !== 0) {
- cacheFailureCallback("Unsupported cache store version " + settingsVersion)();
- return;
- }
-
- if (pageSize !== settings.pageSize || source.identifier !== settings.sourceId) {
- // The shape or the source of the data was changed so invalidate the store.
- clearStore().then(function () {
- // Signal the cache is fully initialized.
- changeState(CACHE_STATE_IDLE);
- }, cacheFailureCallback("Unable to clear store during initialization"));
- } else {
- // Restore the saved settings.
- actualCacheSize = settings.actualCacheSize;
- allDataLocal = settings.allDataLocal;
- cacheSize = settings.cacheSize;
- collectionCount = settings.collectionCount;
- highestSavedPage = settings.highestSavedPage;
- highestSavedPageSize = settings.highestSavedPageSize;
- version = settingsVersion;
-
- // Signal the cache is fully initialized.
- changeState(CACHE_STATE_IDLE);
- }
- } else {
- // This is a brand new cache.
- saveSettings(function () {
- // Signal the cache is fully initialized.
- changeState(CACHE_STATE_IDLE);
- }, cacheFailureCallback("Unable to write settings during initialization."));
- }
- }, cacheFailureCallback("Unable to read settings from store."));
-
- return that;
- };
-
- datajs.createDataCache = function (options) {
- /// <summary>Creates a data cache for a collection that is efficiently loaded on-demand.</summary>
- /// <param name="options">
- /// Options for the data cache, including name, source, pageSize,
- /// prefetchSize, cacheSize, storage mechanism, and initial prefetch and local-data handler.
- /// </param>
- /// <returns type="DataCache">A new data cache instance.</returns>
- checkUndefinedGreaterThanZero(options.pageSize, "pageSize");
- checkUndefinedOrNumber(options.cacheSize, "cacheSize");
- checkUndefinedOrNumber(options.prefetchSize, "prefetchSize");
-
- if (!assigned(options.name)) {
- throw { message: "Undefined or null name", options: options };
- }
-
- if (!assigned(options.source)) {
- throw { message: "Undefined source", options: options };
- }
-
- return new DataCache(options);
- };
-
- // DATAJS INTERNAL START
- window.datajs.estimateSize = estimateSize;
- // DATAJS INTERNAL END
-
- // CONTENT END
-})(this);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/datajs.js
----------------------------------------------------------------------
diff --git a/datajs/src/datajs.js b/datajs/src/datajs.js
deleted file mode 100644
index fc5bb62..0000000
--- a/datajs/src/datajs.js
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
-// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// datajs.js
-
-(function (window, undefined) {
-
- var datajs = window.datajs || {};
- var odata = window.OData || {};
-
- // AMD support
- if (typeof define === 'function' && define.amd) {
- define('datajs', datajs);
- define('OData', odata);
- } else {
- window.datajs = datajs;
- window.OData = odata;
- }
-
- datajs.version = {
- major: 1,
- minor: 1,
- build: 1
- };
-
- // INCLUDE: utils.js
- // INCLUDE: xml.js
-
- // INCLUDE: deferred.js
-
- // INCLUDE: odata-utils.js
- // INCLUDE: odata-net.js
- // INCLUDE: odata-handler.js
- // INCLUDE: odata-gml.js
- // INCLUDE: odata-xml.js
- // INCLUDE: odata-atom.js
- // INCLUDE: odata-metadata.js
- // INCLUDE: odata-json-light.js
- // INCLUDE: odata-json.js
- // INCLUDE: odata-batch.js
- // INCLUDE: odata.js
-
- // INCLUDE: store-dom.js
- // INCLUDE: store-indexeddb.js
- // INCLUDE: store-memory.js
- // INCLUDE: store.js
-
- // INCLUDE: cache-source.js
- // INCLUDE: cache.js
-
-})(this);
\ No newline at end of file
[10/15] [OLINGO-238] Build infrastructure for datajs I
Posted by ko...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/lib/odata/json-light.js
----------------------------------------------------------------------
diff --git a/datajs/src/lib/odata/json-light.js b/datajs/src/lib/odata/json-light.js
new file mode 100644
index 0000000..2094d69
--- /dev/null
+++ b/datajs/src/lib/odata/json-light.js
@@ -0,0 +1,1384 @@
+//SK name /odata/odata-json-light.js
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// odata-json-light.js
+
+// Imports
+
+var utils = require('./../datajs.js').utils;
+var oDataUtils = require('./utils.js');
+
+var assigned = utils.assigned;
+var djsassert = utils.djsassert;
+var extend = utils.extend;
+var getURIInfo = utils.getURIInfo;
+var isArray = utils.isArray;
+var isDate = utils.isDate;
+var normalizeURI = utils.normalizeURI;
+var renameProperty = utils.renameProperty;
+var undefinedDefault = utils.undefinedDefault;
+var convertByteArrayToHexString = utils.convertByteArrayToHexString;
+
+var dataItemTypeName = oDataUtils.dataItemTypeName;
+var EDM_DATETIME = oDataUtils.EDM_DATETIME;
+var EDM_DATETIMEOFFSET = oDataUtils.EDM_DATETIMEOFFSET;
+var EDM_TIME = oDataUtils.EDM_TIME;
+var getCollectionType = oDataUtils.getCollectionType;
+var isCollection = oDataUtils.isCollection;
+var isCollectionType = oDataUtils.isCollectionType;
+var isComplex = oDataUtils.isComplex;
+var isDeferred = oDataUtils.isDeferred;
+var isFeed = oDataUtils.isFeed;
+var isEntry = oDataUtils.isEntry;
+var isGeographyEdmType = oDataUtils.isGeographyEdmType;
+var isGeometryEdmType = oDataUtils.isGeometryEdmType;
+var isPrimitiveEdmType = oDataUtils.isPrimitiveEdmType;
+var isPrimitive = oDataUtils.isPrimitive;
+var lookupComplexType = oDataUtils.lookupComplexType;
+var lookupDefaultEntityContainer = oDataUtils.lookupDefaultEntityContainer;
+var lookupEntityContainer = oDataUtils.lookupEntityContainer;
+var lookupEntitySet = oDataUtils.lookupEntitySet;
+var lookupEntityType = oDataUtils.lookupEntityType;
+var lookupFunctionImport = oDataUtils.lookupFunctionImport;
+var lookupNavigationPropertyType = oDataUtils.lookupNavigationPropertyType;
+var getEntitySetInfo = oDataUtils.getEntitySetInfo;
+var lookupNavigationPropertyEntitySet = oDataUtils.lookupNavigationPropertyEntitySet;
+var lookupProperty = oDataUtils.lookupProperty;
+var parseBool = oDataUtils.parseBool;
+var parseDateTime = oDataUtils.parseDateTime;
+var parseDateTimeOffset = oDataUtils.parseDateTimeOffset;
+var parseDuration = oDataUtils.parseDuration;
+
+// CONTENT START
+
+var PAYLOADTYPE_OBJECT = "o";
+var PAYLOADTYPE_FEED = "f";
+var PAYLOADTYPE_PRIMITIVE = "p";
+var PAYLOADTYPE_COLLECTION = "c";
+var PAYLOADTYPE_SVCDOC = "s";
+var PAYLOADTYPE_LINKS = "l";
+
+var odataNs = "odata";
+var odataAnnotationPrefix = odataNs + ".";
+
+var bindAnnotation = "@" + odataAnnotationPrefix + "bind";
+var metadataAnnotation = odataAnnotationPrefix + "metadata";
+var navUrlAnnotation = odataAnnotationPrefix + "navigationLinkUrl";
+var typeAnnotation = odataAnnotationPrefix + "type";
+
+var jsonLightNameMap = {
+ readLink: "self",
+ editLink: "edit",
+ nextLink: "__next",
+ mediaReadLink: "media_src",
+ mediaEditLink: "edit_media",
+ mediaContentType: "content_type",
+ mediaETag: "media_etag",
+ count: "__count",
+ media_src: "mediaReadLink",
+ edit_media: "mediaEditLink",
+ content_type: "mediaContentType",
+ media_etag: "mediaETag",
+ url: "uri"
+};
+
+var jsonLightAnnotations = {
+ metadata: "odata.metadata",
+ count: "odata.count",
+ next: "odata.nextLink",
+ id: "odata.id",
+ etag: "odata.etag",
+ read: "odata.readLink",
+ edit: "odata.editLink",
+ mediaRead: "odata.mediaReadLink",
+ mediaEdit: "odata.mediaEditLink",
+ mediaEtag: "odata.mediaETag",
+ mediaContentType: "odata.mediaContentType",
+ actions: "odata.actions",
+ functions: "odata.functions",
+ navigationUrl: "odata.navigationLinkUrl",
+ associationUrl: "odata.associationLinkUrl",
+ type: "odata.type"
+};
+
+var jsonLightAnnotationInfo = function (annotation) {
+ /// <summary>Gets the name and target of an annotation in a JSON light payload.</summary>
+ /// <param name="annotation" type="String">JSON light payload annotation.</param>
+ /// <returns type="Object">Object containing the annotation name and the target property name.</param>
+
+ if (annotation.indexOf(".") > 0) {
+ var targetEnd = annotation.indexOf("@");
+ var target = targetEnd > -1 ? annotation.substring(0, targetEnd) : null;
+ var name = annotation.substring(targetEnd + 1);
+
+ return {
+ target: target,
+ name: name,
+ isOData: name.indexOf(odataAnnotationPrefix) === 0
+ };
+ }
+ return null;
+};
+
+var jsonLightDataItemType = function (name, value, container, dataItemModel, model) {
+ /// <summary>Gets the type name of a JSON light data item that belongs to a feed, an entry, a complex type property, or a collection property.</summary>
+ /// <param name="name" type="String">Name of the data item for which the type name is going to be retrieved.</param>
+ /// <param name="value">Value of the data item.</param>
+ /// <param name="container" type="Object">JSON light object that owns the data item.</param>
+ /// <param name="dataItemModel" type="Object" optional="true">Object describing the data item in an OData conceptual schema.</param>
+ /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
+ /// <remarks>
+ /// This function will first try to get the type name from the data item's value itself if it is a JSON light object; otherwise
+ /// it will try to get it from the odata.type annotation applied to the data item in the container. Then, it will fallback to the data item model.
+ /// If all attempts fail, it will return null.
+ /// </remarks>
+ /// <returns type="String">Data item type name; null if the type name cannot be found.</returns>
+
+ return (isComplex(value) && value[typeAnnotation]) ||
+ (container && container[name + "@" + typeAnnotation]) ||
+ (dataItemModel && dataItemModel.type) ||
+ (lookupNavigationPropertyType(dataItemModel, model)) ||
+ null;
+};
+
+var jsonLightDataItemModel = function (name, containerModel) {
+ /// <summary>Gets an object describing a data item in an OData conceptual schema.</summary>
+ /// <param name="name" type="String">Name of the data item for which the model is going to be retrieved.</param>
+ /// <param name="containerModel" type="Object">Object describing the owner of the data item in an OData conceptual schema.</param>
+ /// <returns type="Object">Object describing the data item; null if it cannot be found.</returns>
+
+ if (containerModel) {
+ return lookupProperty(containerModel.property, name) ||
+ lookupProperty(containerModel.navigationProperty, name);
+ }
+ return null;
+};
+
+var jsonLightIsEntry = function (data) {
+ /// <summary>Determines whether data represents a JSON light entry object.</summary>
+ /// <param name="data" type="Object">JSON light object to test.</param>
+ /// <returns type="Boolean">True if the data is JSON light entry object; false otherwise.</returns>
+
+ return isComplex(data) && ((odataAnnotationPrefix + "id") in data);
+};
+
+var jsonLightIsNavigationProperty = function (name, data, dataItemModel) {
+ /// <summary>Determines whether a data item in a JSON light object is a navigation property.</summary>
+ /// <param name="name" type="String">Name of the data item to test.</param>
+ /// <param name="data" type="Object">JSON light object that owns the data item.</param>
+ /// <param name="dataItemModel" type="Object">Object describing the data item in an OData conceptual schema.</param>
+ /// <returns type="Boolean">True if the data item is a navigation property; false otherwise.</returns>
+
+ djsassert(isComplex(data), "jsonLightIsNavProp - data is not an object!!");
+ if (!!data[name + "@" + navUrlAnnotation] || (dataItemModel && dataItemModel.relationship)) {
+ return true;
+ }
+
+ // Sniff the property value.
+ var value = isArray(data[name]) ? data[name][0] : data[name];
+ return jsonLightIsEntry(value);
+};
+
+var jsonLightIsPrimitiveType = function (typeName) {
+ /// <summary>Determines whether a type name is a primitive type in a JSON light payload.</summary>
+ /// <param name="typeName" type="String">Type name to test.</param>
+ /// <returns type="Boolean">True if the type name an EDM primitive type or an OData spatial type; false otherwise.</returns>
+
+ return isPrimitiveEdmType(typeName) || isGeographyEdmType(typeName) || isGeometryEdmType(typeName);
+};
+
+var jsonLightReadDataAnnotations = function (data, obj, baseURI, dataModel, model) {
+ /// <summary>Converts annotations found in a JSON light payload object to either properties or metadata.</summary>
+ /// <param name="data" type="Object">JSON light payload object containing the annotations to convert.</param>
+ /// <param name="obj" type="Object">Object that will store the converted annotations.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
+ /// <param name="dataModel" type="Object">Object describing the JSON light payload in an OData conceptual schema.</param>
+ /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
+ /// <returns>JSON light payload object with its annotations converted to either properties or metadata.</param>
+
+ for (var name in data) {
+ if (name.indexOf(".") > 0 && name.charAt(0) !== "#") {
+ var annotationInfo = jsonLightAnnotationInfo(name);
+ if (annotationInfo) {
+ var annotationName = annotationInfo.name;
+ var target = annotationInfo.target;
+ var targetModel = null;
+ var targetType = null;
+
+ if (target) {
+ targetModel = jsonLightDataItemModel(target, dataModel);
+ targetType = jsonLightDataItemType(target, data[target], data, targetModel, model);
+ }
+
+ if (annotationInfo.isOData) {
+ jsonLightApplyPayloadODataAnnotation(annotationName, target, targetType, data[name], data, obj, baseURI);
+ } else {
+ obj[name] = data[name];
+ }
+ }
+ }
+ }
+ return obj;
+};
+
+var jsonLightApplyPayloadODataAnnotation = function (name, target, targetType, value, data, obj, baseURI) {
+ /// <summary>
+ /// Processes a JSON Light payload OData annotation producing either a property, payload metadata, or property metadata on its owner object.
+ /// </summary>
+ /// <param name="name" type="String">Annotation name.</param>
+ /// <param name="target" type="String">Name of the property that is being targeted by the annotation.</param>
+ /// <param name="targetType" type="String">Type name of the target property.</param>
+ /// <param name="data" type="Object">JSON light object containing the annotation.</param>
+ /// <param name="obj" type="Object">Object that will hold properties produced by the annotation.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
+
+ var annotation = name.substring(odataAnnotationPrefix.length);
+
+ switch (annotation) {
+ case "navigationLinkUrl":
+ jsonLightApplyNavigationUrlAnnotation(annotation, target, targetType, value, data, obj, baseURI);
+ return;
+ case "nextLink":
+ case "count":
+ jsonLightApplyFeedAnnotation(annotation, target, value, obj, baseURI);
+ return;
+ case "mediaReadLink":
+ case "mediaEditLink":
+ case "mediaContentType":
+ case "mediaETag":
+ jsonLightApplyMediaAnnotation(annotation, target, targetType, value, obj, baseURI);
+ return;
+ default:
+ jsonLightApplyMetadataAnnotation(annotation, target, value, obj, baseURI);
+ return;
+ }
+};
+
+var jsonLightApplyMetadataAnnotation = function (name, target, value, obj, baseURI) {
+ /// <summary>
+ /// Converts a JSON light annotation that applies to entry metadata only (i.e. odata.editLink or odata.readLink) and its value
+ /// into their library's internal representation and saves it back to data.
+ /// </summary>
+ /// <param name="name" type="String">Annotation name.</param>
+ /// <param name="target" type="String">Name of the property on which the annotation should be applied.</param>
+ /// <param name="value" type="Object">Annotation value.</param>
+ /// <param name="obj" type="Object">Object that will hold properties produced by the annotation.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
+
+ var metadata = obj.__metadata = obj.__metadata || {};
+ var mappedName = jsonLightNameMap[name] || name;
+
+ if (name === "editLink") {
+ metadata.uri = normalizeURI(value, baseURI);
+ metadata[mappedName] = metadata.uri;
+ return;
+ }
+
+ if (name === "readLink" || name === "associationLinkUrl") {
+ value = normalizeURI(value, baseURI);
+ }
+
+ if (target) {
+ var propertiesMetadata = metadata.properties = metadata.properties || {};
+ var propertyMetadata = propertiesMetadata[target] = propertiesMetadata[target] || {};
+
+ if (name === "type") {
+ propertyMetadata[mappedName] = propertyMetadata[mappedName] || value;
+ return;
+ }
+ propertyMetadata[mappedName] = value;
+ return;
+ }
+ metadata[mappedName] = value;
+};
+
+var jsonLightApplyFeedAnnotation = function (name, target, value, obj, baseURI) {
+ /// <summary>
+ /// Converts a JSON light annotation that applies to feeds only (i.e. odata.count or odata.nextlink) and its value
+ /// into their library's internal representation and saves it back to data.
+ /// </summary>
+ /// <param name="name" type="String">Annotation name.</param>
+ /// <param name="target" type="String">Name of the property on which the annotation should be applied.</param>
+ /// <param name="value" type="Object">Annotation value.</param>
+ /// <param name="obj" type="Object">Object that will hold properties produced by the annotation.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
+
+ var mappedName = jsonLightNameMap[name];
+ var feed = target ? obj[target] : obj;
+ feed[mappedName] = (name === "nextLink") ? normalizeURI(value, baseURI) : value;
+};
+
+var jsonLightApplyMediaAnnotation = function (name, target, targetType, value, obj, baseURI) {
+ /// <summary>
+ /// Converts a JSON light media annotation in and its value into their library's internal representation
+ /// and saves it back to data or metadata.
+ /// </summary>
+ /// <param name="name" type="String">Annotation name.</param>
+ /// <param name="target" type="String">Name of the property on which the annotation should be applied.</param>
+ /// <param name="targetType" type="String">Type name of the target property.</param>
+ /// <param name="value" type="Object">Annotation value.</param>
+ /// <param name="obj" type="Object">Object that will hold properties produced by the annotation.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
+
+ var metadata = obj.__metadata = obj.__metadata || {};
+ var mappedName = jsonLightNameMap[name];
+
+ if (name === "mediaReadLink" || name === "mediaEditLink") {
+ value = normalizeURI(value, baseURI);
+ }
+
+ if (target) {
+ var propertiesMetadata = metadata.properties = metadata.properties || {};
+ var propertyMetadata = propertiesMetadata[target] = propertiesMetadata[target] || {};
+ propertyMetadata.type = propertyMetadata.type || targetType;
+
+ obj.__metadata = metadata;
+ obj[target] = obj[target] || { __mediaresource: {} };
+ obj[target].__mediaresource[mappedName] = value;
+ return;
+ }
+
+ metadata[mappedName] = value;
+};
+
+var jsonLightApplyNavigationUrlAnnotation = function (name, target, targetType, value, data, obj, baseURI) {
+ /// <summary>
+ /// Converts a JSON light navigation property annotation and its value into their library's internal representation
+ /// and saves it back to data o metadata.
+ /// </summary>
+ /// <param name="name" type="String">Annotation name.</param>
+ /// <param name="target" type="String">Name of the property on which the annotation should be applied.</param>
+ /// <param name="targetType" type="String">Type name of the target property.</param>
+ /// <param name="value" type="Object">Annotation value.</param>
+ /// <param name="data" type="Object">JSON light object containing the annotation.</param>
+ /// <param name="obj" type="Object">Object that will hold properties produced by the annotation.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
+
+ var metadata = obj.__metadata = obj.__metadata || {};
+ var propertiesMetadata = metadata.properties = metadata.properties || {};
+ var propertyMetadata = propertiesMetadata[target] = propertiesMetadata[target] || {};
+ var uri = normalizeURI(value, baseURI);
+
+ if (data.hasOwnProperty(target)) {
+ // The navigation property is inlined in the payload,
+ // so the navigation link url should be pushed to the object's
+ // property metadata instead.
+ propertyMetadata.navigationLinkUrl = uri;
+ return;
+ }
+ obj[target] = { __deferred: { uri: uri} };
+ propertyMetadata.type = propertyMetadata.type || targetType;
+};
+
+
+var jsonLightReadDataItemValue = function (value, typeName, dataItemMetadata, baseURI, dataItemModel, model, recognizeDates) {
+ /// <summary>Converts the value of a data item in a JSON light object to its library representation.</summary>
+ /// <param name="value">Data item value to convert.</param>
+ /// <param name="typeName" type="String">Type name of the data item.</param>
+ /// <param name="dataItemMetadata" type="Object">Object containing metadata about the data item.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
+ /// <param name="dataItemModel" type="Object" optional="true">Object describing the data item in an OData conceptual schema.</param>
+ /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
+ /// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
+ /// <returns>Data item value in its library representation.</param>
+
+ if (typeof value === "string") {
+ return jsonLightReadStringPropertyValue(value, typeName, recognizeDates);
+ }
+
+ if (!jsonLightIsPrimitiveType(typeName)) {
+ if (isArray(value)) {
+ return jsonLightReadCollectionPropertyValue(value, typeName, dataItemMetadata, baseURI, model, recognizeDates);
+ }
+
+ if (isComplex(value)) {
+ return jsonLightReadComplexPropertyValue(value, typeName, dataItemMetadata, baseURI, model, recognizeDates);
+ }
+ }
+ return value;
+};
+
+var jsonLightReadStringPropertyValue = function (value, propertyType, recognizeDates) {
+ /// <summary>Convertes the value of a string property in a JSON light object to its library representation.</summary>
+ /// <param name="value" type="String">String value to convert.</param>
+ /// <param name="propertyType" type="String">Type name of the property.</param>
+ /// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
+ /// <returns>String property value in its library representation.</returns>
+
+ switch (propertyType) {
+ case EDM_TIME:
+ return parseDuration(value);
+ case EDM_DATETIME:
+ return parseDateTime(value, /*nullOnError*/false);
+ case EDM_DATETIMEOFFSET:
+ return parseDateTimeOffset(value, /*nullOnError*/false);
+ }
+
+ if (recognizeDates) {
+ return parseDateTime(value, /*nullOnError*/true) ||
+ parseDateTimeOffset(value, /*nullOnError*/true) ||
+ value;
+ }
+ return value;
+};
+
+var jsonLightReadCollectionPropertyValue = function (value, propertyType, propertyMetadata, baseURI, model, recognizeDates) {
+ /// <summary>Converts the value of a collection property in a JSON light object into its library representation.</summary>
+ /// <param name="value" type="Array">Collection property value to convert.</param>
+ /// <param name="propertyType" type="String">Property type name.</param>
+ /// <param name="propertyMetadata" type="Object">Object containing metadata about the collection property.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
+ /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
+ /// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
+ /// <returns type="Object">Collection property value in its library representation.</returns>
+
+ var collectionType = getCollectionType(propertyType);
+ var itemsMetadata = [];
+ var items = [];
+
+ var i, len;
+ for (i = 0, len = value.length; i < len; i++) {
+ var itemType = jsonLightDataItemType(null, value[i]) || collectionType;
+ var itemMetadata = { type: itemType };
+ var item = jsonLightReadDataItemValue(value[i], itemType, itemMetadata, baseURI, null, model, recognizeDates);
+
+ if (!jsonLightIsPrimitiveType(itemType) && !isPrimitive(value[i])) {
+ itemsMetadata.push(itemMetadata);
+ }
+ items.push(item);
+ }
+
+ if (itemsMetadata.length > 0) {
+ propertyMetadata.elements = itemsMetadata;
+ }
+
+ return { __metadata: { type: propertyType }, results: items };
+};
+
+var jsonLightReadComplexPropertyValue = function (value, propertyType, propertyMetadata, baseURI, model, recognizeDates) {
+ /// <summary>Converts the value of a comples property in a JSON light object into its library representation.</summary>
+ /// <param name="value" type="Object">Complex property value to convert.</param>
+ /// <param name="propertyType" type="String">Property type name.</param>
+ /// <param name="propertyMetadata" type="Object">Object containing metadata about the complx type property.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
+ /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
+ /// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
+ /// <returns type="Object">Complex property value in its library representation.</returns>
+
+ var complexValue = jsonLightReadObject(value, { type: propertyType }, baseURI, model, recognizeDates);
+ var complexMetadata = complexValue.__metadata;
+ var complexPropertiesMetadata = complexMetadata.properties;
+
+ if (complexPropertiesMetadata) {
+ propertyMetadata.properties = complexPropertiesMetadata;
+ delete complexMetadata.properties;
+ }
+ return complexValue;
+};
+
+var jsonLightReadNavigationPropertyValue = function (value, propertyInfo, baseURI, model, recognizeDates) {
+ /// <summary>Converts the value of a navigation property in a JSON light object into its library representation.</summary>
+ /// <param name="value">Navigation property property value to convert.</param>
+ /// <param name="propertyInfo" type="String">Information about the property whether it's an entry, feed or complex type.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
+ /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
+ /// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
+ /// <returns type="Object">Collection property value in its library representation.</returns>
+
+ if (isArray(value)) {
+ return jsonLightReadFeed(value, propertyInfo, baseURI, model, recognizeDates);
+ }
+
+ if (isComplex(value)) {
+ return jsonLightReadObject(value, propertyInfo, baseURI, model, recognizeDates);
+ }
+ return null;
+};
+
+var jsonLightReadObject = function (data, objectInfo, baseURI, model, recognizeDates) {
+ /// <summary>Converts a JSON light entry or complex type object into its library representation.</summary>
+ /// <param name="data" type="Object">JSON light entry or complex type object to convert.</param>
+ /// <param name="objectInfo" type="Object">Information about the entry or complex.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
+ /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
+ /// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
+ /// <returns type="Object">Entry or complex type object.</param>
+
+ objectInfo = objectInfo || {};
+ var actualType = data[typeAnnotation] || objectInfo.type || null;
+ var dataModel = lookupEntityType(actualType, model);
+ var isEntry = true;
+ if (!dataModel) {
+ isEntry = false;
+ dataModel = lookupComplexType(actualType, model);
+ }
+
+ var metadata = { type: actualType };
+ var obj = { __metadata: metadata };
+ var propertiesMetadata = {};
+ var baseTypeModel;
+ if (isEntry && dataModel && objectInfo.entitySet && objectInfo.contentTypeOdata == "minimalmetadata") {
+ var serviceURI = baseURI.substring(0, baseURI.lastIndexOf("$metadata"));
+ baseTypeModel = null; // check if the key model is in a parent type.
+ if (!dataModel.key) {
+ baseTypeModel = dataModel;
+ }
+ while (!!baseTypeModel && !baseTypeModel.key && baseTypeModel.baseType) {
+ baseTypeModel = lookupEntityType(baseTypeModel.baseType, model);
+ }
+
+ if (dataModel.key || (!!baseTypeModel && baseTypeModel.key)) {
+ var entryKey;
+ if (dataModel.key) {
+ entryKey = jsonLightGetEntryKey(data, dataModel);
+ } else {
+ entryKey = jsonLightGetEntryKey(data, baseTypeModel);
+ }
+ if (entryKey) {
+ var entryInfo = {
+ key: entryKey,
+ entitySet: objectInfo.entitySet,
+ functionImport: objectInfo.functionImport,
+ containerName: objectInfo.containerName
+ };
+ jsonLightComputeUrisIfMissing(data, entryInfo, actualType, serviceURI, dataModel, baseTypeModel);
+ }
+ }
+ }
+
+ for (var name in data) {
+ if (name.indexOf("#") === 0) {
+ // This is an advertised function or action.
+ jsonLightReadAdvertisedFunctionOrAction(name.substring(1), data[name], obj, baseURI, model);
+ } else {
+ // Is name NOT an annotation?
+ if (name.indexOf(".") === -1) {
+ if (!metadata.properties) {
+ metadata.properties = propertiesMetadata;
+ }
+
+ var propertyValue = data[name];
+ var propertyModel = propertyModel = jsonLightDataItemModel(name, dataModel);
+ baseTypeModel = dataModel;
+ while (!!dataModel && propertyModel === null && baseTypeModel.baseType) {
+ baseTypeModel = lookupEntityType(baseTypeModel.baseType, model);
+ propertyModel = propertyModel = jsonLightDataItemModel(name, baseTypeModel);
+ }
+ var isNavigationProperty = jsonLightIsNavigationProperty(name, data, propertyModel);
+ var propertyType = jsonLightDataItemType(name, propertyValue, data, propertyModel, model);
+ var propertyMetadata = propertiesMetadata[name] = propertiesMetadata[name] || { type: propertyType };
+ if (isNavigationProperty) {
+ var propertyInfo = {};
+ if (objectInfo.entitySet !== undefined) {
+ var navigationPropertyEntitySetName = lookupNavigationPropertyEntitySet(propertyModel, objectInfo.entitySet.name, model);
+ propertyInfo = getEntitySetInfo(navigationPropertyEntitySetName, model);
+ }
+ propertyInfo.contentTypeOdata = objectInfo.contentTypeOdata;
+ propertyInfo.kind = objectInfo.kind;
+ propertyInfo.type = propertyType;
+ obj[name] = jsonLightReadNavigationPropertyValue(propertyValue, propertyInfo, baseURI, model, recognizeDates);
+ } else {
+ obj[name] = jsonLightReadDataItemValue(propertyValue, propertyType, propertyMetadata, baseURI, propertyModel, model, recognizeDates);
+ }
+ }
+ }
+ }
+
+ return jsonLightReadDataAnnotations(data, obj, baseURI, dataModel, model);
+};
+
+var jsonLightReadAdvertisedFunctionOrAction = function (name, value, obj, baseURI, model) {
+ /// <summary>Converts a JSON light advertised action or function object into its library representation.</summary>
+ /// <param name="name" type="String">Advertised action or function name.</param>
+ /// <param name="value">Advertised action or function value.</param>
+ /// <param name="obj" type="Object">Object that will the converted value of the advertised action or function.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing the action's or function's relative URIs.</param>
+ /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
+ /// <remarks>
+ /// Actions and functions have the same representation in json light, so to disambiguate them the function uses
+ /// the model object. If available, the function will look for the functionImport object that describes the
+ /// the action or the function. If for whatever reason the functionImport can't be retrieved from the model (like
+ /// there is no model available or there is no functionImport within the model), then the value is going to be treated
+ /// as an advertised action and stored under obj.__metadata.actions.
+ /// </remarks>
+
+ if (!name || !isArray(value) && !isComplex(value)) {
+ return;
+ }
+
+ var isFunction = false;
+ var nsEnd = name.lastIndexOf(".");
+ var simpleName = name.substring(nsEnd + 1);
+ var containerName = (nsEnd > -1) ? name.substring(0, nsEnd) : "";
+
+ var container = (simpleName === name || containerName.indexOf(".") === -1) ?
+ lookupDefaultEntityContainer(model) :
+ lookupEntityContainer(containerName, model);
+
+ if (container) {
+ var functionImport = lookupFunctionImport(container.functionImport, simpleName);
+ if (functionImport && !!functionImport.isSideEffecting) {
+ isFunction = !parseBool(functionImport.isSideEffecting);
+ }
+ }
+
+ var metadata = obj.__metadata;
+ var targetName = isFunction ? "functions" : "actions";
+ var metadataURI = normalizeURI(name, baseURI);
+ var items = (isArray(value)) ? value : [value];
+
+ var i, len;
+ for (i = 0, len = items.length; i < len; i++) {
+ var item = items[i];
+ if (item) {
+ var targetCollection = metadata[targetName] = metadata[targetName] || [];
+ var actionOrFunction = { metadata: metadataURI, title: item.title, target: normalizeURI(item.target, baseURI) };
+ targetCollection.push(actionOrFunction);
+ }
+ }
+};
+
+var jsonLightReadFeed = function (data, feedInfo, baseURI, model, recognizeDates) {
+ /// <summary>Converts a JSON light feed or top level collection property object into its library representation.</summary>
+ /// <param name="data" type="Object">JSON light feed object to convert.</param>
+ /// <param name="typeName" type="String">Type name of the feed or collection items.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
+ /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
+ /// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
+ /// <returns type="Object">Feed or top level collection object.</param>
+
+ var items = isArray(data) ? data : data.value;
+ var entries = [];
+ var i, len, entry;
+ for (i = 0, len = items.length; i < len; i++) {
+ entry = jsonLightReadObject(items[i], feedInfo, baseURI, model, recognizeDates);
+ entries.push(entry);
+ }
+
+ var feed = { results: entries };
+
+ if (isComplex(data)) {
+ for (var name in data) {
+ if (name.indexOf("#") === 0) {
+ // This is an advertised function or action.
+ feed.__metadata = feed.__metadata || {};
+ jsonLightReadAdvertisedFunctionOrAction(name.substring(1), data[name], feed, baseURI, model);
+ }
+ }
+ feed = jsonLightReadDataAnnotations(data, feed, baseURI);
+ }
+ return feed;
+};
+
+var jsonLightGetEntryKey = function (data, entityModel) {
+ /// <summary>Gets the key of an entry.</summary>
+ /// <param name="data" type="Object">JSON light entry.</param>
+ /// <param name="entityModel" type="String">Object describing the entry Model</param>
+ /// <returns type="string">Entry instance key.</returns>
+
+ var entityInstanceKey;
+ var entityKeys = entityModel.key.propertyRef;
+ var type;
+ entityInstanceKey = "(";
+ if (entityKeys.length == 1) {
+ type = lookupProperty(entityModel.property, entityKeys[0].name).type;
+ entityInstanceKey += formatLiteral(data[entityKeys[0].name], type);
+ } else {
+ var first = true;
+ for (var i = 0; i < entityKeys.length; i++) {
+ if (!first) {
+ entityInstanceKey += ",";
+ } else {
+ first = false;
+ }
+ type = lookupProperty(entityModel.property, entityKeys[i].name).type;
+ entityInstanceKey += entityKeys[i].name + "=" + formatLiteral(data[entityKeys[i].name], type);
+ }
+ }
+ entityInstanceKey += ")";
+ return entityInstanceKey;
+};
+
+
+var jsonLightComputeUrisIfMissing = function (data, entryInfo, actualType, serviceURI, entityModel, baseTypeModel) {
+ /// <summary>Compute the URI according to OData conventions if it doesn't exist</summary>
+ /// <param name="data" type="Object">JSON light entry.</param>
+ /// <param name="entryInfo" type="Object">Information about the entry includes type, key, entitySet and entityContainerName.</param>
+ /// <param name="actualType" type="String">Type of the entry</param>
+ /// <param name="serviceURI" type="String">Base URI the service.</param>
+ /// <param name="entityModel" type="Object">Object describing an OData conceptual schema of the entry.</param>
+ /// <param name="baseTypeModel" type="Object" optional="true">Object escribing an OData conceptual schema of the baseType if it exists.</param>
+
+ var lastIdSegment = data[jsonLightAnnotations.id] || data[jsonLightAnnotations.read] || data[jsonLightAnnotations.edit] || entryInfo.entitySet.name + entryInfo.key;
+ data[jsonLightAnnotations.id] = serviceURI + lastIdSegment;
+ if (!data[jsonLightAnnotations.edit]) {
+ data[jsonLightAnnotations.edit] = entryInfo.entitySet.name + entryInfo.key;
+ if (entryInfo.entitySet.entityType != actualType) {
+ data[jsonLightAnnotations.edit] += "/" + actualType;
+ }
+ }
+ data[jsonLightAnnotations.read] = data[jsonLightAnnotations.read] || data[jsonLightAnnotations.edit];
+ if (!data[jsonLightAnnotations.etag]) {
+ var etag = jsonLightComputeETag(data, entityModel, baseTypeModel);
+ if (!!etag) {
+ data[jsonLightAnnotations.etag] = etag;
+ }
+ }
+
+ jsonLightComputeStreamLinks(data, entityModel, baseTypeModel);
+ jsonLightComputeNavigationAndAssociationProperties(data, entityModel, baseTypeModel);
+ jsonLightComputeFunctionImports(data, entryInfo);
+};
+
+var jsonLightComputeETag = function (data, entityModel, baseTypeModel) {
+ /// <summary>Computes the etag of an entry</summary>
+ /// <param name="data" type="Object">JSON light entry.</param>
+ /// <param name="entryInfo" type="Object">Object describing the entry model.</param>
+ /// <param name="baseTypeModel" type="Object" optional="true">Object describing an OData conceptual schema of the baseType if it exists.</param>
+ /// <returns type="string">Etag value</returns>
+ var etag = "";
+ var propertyModel;
+ for (var i = 0; entityModel.property && i < entityModel.property.length; i++) {
+ propertyModel = entityModel.property[i];
+ etag = jsonLightAppendValueToEtag(data, etag, propertyModel);
+
+ }
+ if (baseTypeModel) {
+ for (i = 0; baseTypeModel.property && i < baseTypeModel.property.length; i++) {
+ propertyModel = baseTypeModel.property[i];
+ etag = jsonLightAppendValueToEtag(data, etag, propertyModel);
+ }
+ }
+ if (etag.length > 0) {
+ return etag + "\"";
+ }
+ return null;
+};
+
+var jsonLightAppendValueToEtag = function (data, etag, propertyModel) {
+ /// <summary>Adds a propery value to the etag after formatting.</summary>
+ /// <param name="data" type="Object">JSON light entry.</param>
+ /// <param name="etag" type="Object">value of the etag.</param>
+ /// <param name="propertyModel" type="Object">Object describing an OData conceptual schema of the property.</param>
+ /// <returns type="string">Etag value</returns>
+
+ if (propertyModel.concurrencyMode == "Fixed") {
+ if (etag.length > 0) {
+ etag += ",";
+ } else {
+ etag += "W/\"";
+ }
+ if (data[propertyModel.name] !== null) {
+ etag += formatLiteral(data[propertyModel.name], propertyModel.type);
+ } else {
+ etag += "null";
+ }
+ }
+ return etag;
+};
+
+var jsonLightComputeNavigationAndAssociationProperties = function (data, entityModel, baseTypeModel) {
+ /// <summary>Adds navigation links to the entry metadata</summary>
+ /// <param name="data" type="Object">JSON light entry.</param>
+ /// <param name="entityModel" type="Object">Object describing the entry model.</param>
+ /// <param name="baseTypeModel" type="Object" optional="true">Object describing an OData conceptual schema of the baseType if it exists.</param>
+
+ var navigationLinkAnnotation = "@odata.navigationLinkUrl";
+ var associationLinkAnnotation = "@odata.associationLinkUrl";
+ var navigationPropertyName, navigationPropertyAnnotation, associationPropertyAnnotation;
+ for (var i = 0; entityModel.navigationProperty && i < entityModel.navigationProperty.length; i++) {
+ navigationPropertyName = entityModel.navigationProperty[i].name;
+ navigationPropertyAnnotation = navigationPropertyName + navigationLinkAnnotation;
+ if (data[navigationPropertyAnnotation] === undefined) {
+ data[navigationPropertyAnnotation] = data[jsonLightAnnotations.edit] + "/" + encodeURIComponent(navigationPropertyName);
+ }
+ associationPropertyAnnotation = navigationPropertyName + associationLinkAnnotation;
+ if (data[associationPropertyAnnotation] === undefined) {
+ data[associationPropertyAnnotation] = data[jsonLightAnnotations.edit] + "/$links/" + encodeURIComponent(navigationPropertyName);
+ }
+ }
+
+ if (baseTypeModel && baseTypeModel.navigationProperty) {
+ for (i = 0; i < baseTypeModel.navigationProperty.length; i++) {
+ navigationPropertyName = baseTypeModel.navigationProperty[i].name;
+ navigationPropertyAnnotation = navigationPropertyName + navigationLinkAnnotation;
+ if (data[navigationPropertyAnnotation] === undefined) {
+ data[navigationPropertyAnnotation] = data[jsonLightAnnotations.edit] + "/" + encodeURIComponent(navigationPropertyName);
+ }
+ associationPropertyAnnotation = navigationPropertyName + associationLinkAnnotation;
+ if (data[associationPropertyAnnotation] === undefined) {
+ data[associationPropertyAnnotation] = data[jsonLightAnnotations.edit] + "/$links/" + encodeURIComponent(navigationPropertyName);
+ }
+ }
+ }
+};
+
+var formatLiteral = function (value, type) {
+ /// <summary>Formats a value according to Uri literal format</summary>
+ /// <param name="value">Value to be formatted.</param>
+ /// <param name="type">Edm type of the value</param>
+ /// <returns type="string">Value after formatting</returns>
+
+ value = "" + formatRowLiteral(value, type);
+ value = encodeURIComponent(value.replace("'", "''"));
+ switch ((type)) {
+ case "Edm.Binary":
+ return "X'" + value + "'";
+ case "Edm.DateTime":
+ return "datetime" + "'" + value + "'";
+ case "Edm.DateTimeOffset":
+ return "datetimeoffset" + "'" + value + "'";
+ case "Edm.Decimal":
+ return value + "M";
+ case "Edm.Guid":
+ return "guid" + "'" + value + "'";
+ case "Edm.Int64":
+ return value + "L";
+ case "Edm.Float":
+ return value + "f";
+ case "Edm.Double":
+ return value + "D";
+ case "Edm.Geography":
+ return "geography" + "'" + value + "'";
+ case "Edm.Geometry":
+ return "geometry" + "'" + value + "'";
+ case "Edm.Time":
+ return "time" + "'" + value + "'";
+ case "Edm.String":
+ return "'" + value + "'";
+ default:
+ return value;
+ }
+};
+
+
+var formatRowLiteral = function (value, type) {
+ switch (type) {
+ case "Edm.Binary":
+ return convertByteArrayToHexString(value);
+ default:
+ return value;
+ }
+};
+
+var jsonLightComputeFunctionImports = function (data, entryInfo) {
+ /// <summary>Adds functions and actions links to the entry metadata</summary>
+ /// <param name="entry" type="Object">JSON light entry.</param>
+ /// <param name="entityInfo" type="Object">Object describing the entry</param>
+
+ var functionImport = entryInfo.functionImport || [];
+ for (var i = 0; i < functionImport.length; i++) {
+ if (functionImport[i].isBindable && functionImport[i].parameter[0] && functionImport[i].parameter[0].type == entryInfo.entitySet.entityType) {
+ var functionImportAnnotation = "#" + entryInfo.containerName + "." + functionImport[i].name;
+ if (data[functionImportAnnotation] == undefined) {
+ data[functionImportAnnotation] = {
+ title: functionImport[i].name,
+ target: data[jsonLightAnnotations.edit] + "/" + functionImport[i].name
+ };
+ }
+ }
+ }
+};
+
+var jsonLightComputeStreamLinks = function (data, entityModel, baseTypeModel) {
+ /// <summary>Adds stream links to the entry metadata</summary>
+ /// <param name="data" type="Object">JSON light entry.</param>
+ /// <param name="entityModel" type="Object">Object describing the entry model.</param>
+ /// <param name="baseTypeModel" type="Object" optional="true">Object describing an OData conceptual schema of the baseType if it exists.</param>
+
+ if (entityModel.hasStream || (baseTypeModel && baseTypeModel.hasStream)) {
+ data[jsonLightAnnotations.mediaEdit] = data[jsonLightAnnotations.mediaEdit] || data[jsonLightAnnotations.mediaEdit] + "/$value";
+ data[jsonLightAnnotations.mediaRead] = data[jsonLightAnnotations.mediaRead] || data[jsonLightAnnotations.mediaEdit];
+ }
+};
+
+var jsonLightReadTopPrimitiveProperty = function (data, typeName, baseURI, recognizeDates) {
+ /// <summary>Converts a JSON light top level primitive property object into its library representation.</summary>
+ /// <param name="data" type="Object">JSON light feed object to convert.</param>
+ /// <param name="typeName" type="String">Type name of the primitive property.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
+ /// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
+ /// <returns type="Object">Top level primitive property object.</param>
+
+ var metadata = { type: typeName };
+ var value = jsonLightReadDataItemValue(data.value, typeName, metadata, baseURI, null, null, recognizeDates);
+ return jsonLightReadDataAnnotations(data, { __metadata: metadata, value: value }, baseURI);
+};
+
+var jsonLightReadTopCollectionProperty = function (data, typeName, baseURI, model, recognizeDates) {
+ /// <summary>Converts a JSON light top level collection property object into its library representation.</summary>
+ /// <param name="data" type="Object">JSON light feed object to convert.</param>
+ /// <param name="typeName" type="String">Type name of the collection property.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
+ /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
+ /// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
+ /// <returns type="Object">Top level collection property object.</param>
+
+ var propertyMetadata = {};
+ var value = jsonLightReadCollectionPropertyValue(data.value, typeName, propertyMetadata, baseURI, model, recognizeDates);
+ extend(value.__metadata, propertyMetadata);
+ return jsonLightReadDataAnnotations(data, value, baseURI);
+};
+
+var jsonLightReadLinksDocument = function (data, baseURI) {
+ /// <summary>Converts a JSON light links collection object to its library representation.</summary>
+ /// <param name="data" type="Object">JSON light link object to convert.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
+ /// <returns type="Object">Links collection object.</param>
+
+ var items = data.value;
+ if (!isArray(items)) {
+ return jsonLightReadLink(data, baseURI);
+ }
+
+ var results = [];
+ var i, len;
+ for (i = 0, len = items.length; i < len; i++) {
+ results.push(jsonLightReadLink(items[i], baseURI));
+ }
+
+ var links = { results: results };
+ return jsonLightReadDataAnnotations(data, links, baseURI);
+};
+
+var jsonLightReadLink = function (data, baseURI) {
+ /// <summary>Converts a JSON light link object to its library representation.</summary>
+ /// <param name="data" type="Object">JSON light link object to convert.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
+ /// <returns type="Object">Link object.</param>
+
+ var link = { uri: normalizeURI(data.url, baseURI) };
+
+ link = jsonLightReadDataAnnotations(data, link, baseURI);
+ var metadata = link.__metadata || {};
+ var metadataProperties = metadata.properties || {};
+
+ jsonLightRemoveTypePropertyMetadata(metadataProperties.url);
+ renameProperty(metadataProperties, "url", "uri");
+
+ return link;
+};
+
+var jsonLightRemoveTypePropertyMetadata = function (propertyMetadata) {
+ /// <summary>Removes the type property from a property metadata object.</summary>
+ /// <param name="propertyMetadata" type="Object">Property metadata object.</param>
+
+ if (propertyMetadata) {
+ delete propertyMetadata.type;
+ }
+};
+
+var jsonLightReadSvcDocument = function (data, baseURI) {
+ /// <summary>Converts a JSON light service document object to its library representation.</summary>
+ /// <param name="data" type="Object">JSON light service document object to convert.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
+ /// <returns type="Object">Link object.</param>
+
+ var items = data.value;
+ var collections = [];
+ var workspace = jsonLightReadDataAnnotations(data, { collections: collections }, baseURI);
+
+ var metadata = workspace.__metadata || {};
+ var metadataProperties = metadata.properties || {};
+
+ jsonLightRemoveTypePropertyMetadata(metadataProperties.value);
+ renameProperty(metadataProperties, "value", "collections");
+
+ var i, len;
+ for (i = 0, len = items.length; i < len; i++) {
+ var item = items[i];
+ var collection = { title: item.name, href: normalizeURI(item.url, baseURI) };
+
+ collection = jsonLightReadDataAnnotations(item, collection, baseURI);
+ metadata = collection.__metadata || {};
+ metadataProperties = metadata.properties || {};
+
+ jsonLightRemoveTypePropertyMetadata(metadataProperties.name);
+ jsonLightRemoveTypePropertyMetadata(metadataProperties.url);
+
+ renameProperty(metadataProperties, "name", "title");
+ renameProperty(metadataProperties, "url", "href");
+
+ collections.push(collection);
+ }
+
+ return { workspaces: [workspace] };
+};
+
+var jsonLightMakePayloadInfo = function (kind, type) {
+ /// <summary>Creates an object containing information for the json light payload.</summary>
+ /// <param name="kind" type="String">JSON light payload kind, one of the PAYLOADTYPE_XXX constant values.</param>
+ /// <param name="typeName" type="String">Type name of the JSON light payload.</param>
+ /// <returns type="Object">Object with kind and type fields.</returns>
+
+ /// <field name="kind" type="String">Kind of the JSON light payload. One of the PAYLOADTYPE_XXX constant values.</field>
+ /// <field name="type" type="String">Data type of the JSON light payload.</field>
+
+ return { kind: kind, type: type || null };
+};
+
+var jsonLightPayloadInfo = function (data, model, inferFeedAsComplexType) {
+ /// <summary>Infers the information describing the JSON light payload from its metadata annotation, structure, and data model.</summary>
+ /// <param name="data" type="Object">Json light response payload object.</param>
+ /// <param name="model" type="Object">Object describing an OData conceptual schema.</param>
+ /// <param name="inferFeedAsComplexType" type="Boolean">True if a JSON light payload that looks like a feed should be treated as a complex type property instead.</param>
+ /// <remarks>
+ /// If the arguments passed to the function don't convey enough information about the payload to determine without doubt that the payload is a feed then it
+ /// will try to use the payload object structure instead. If the payload looks like a feed (has value property that is an array or non-primitive values) then
+ /// the function will report its kind as PAYLOADTYPE_FEED unless the inferFeedAsComplexType flag is set to true. This flag comes from the user request
+ /// and allows the user to control how the library behaves with an ambigous JSON light payload.
+ /// </remarks>
+ /// <returns type="Object">
+ /// Object with kind and type fields. Null if there is no metadata annotation or the payload info cannot be obtained..
+ /// </returns>
+
+ var metadataUri = data[metadataAnnotation];
+ if (!metadataUri || typeof metadataUri !== "string") {
+ return null;
+ }
+
+ var fragmentStart = metadataUri.lastIndexOf("#");
+ if (fragmentStart === -1) {
+ return jsonLightMakePayloadInfo(PAYLOADTYPE_SVCDOC);
+ }
+
+ var elementStart = metadataUri.indexOf("@Element", fragmentStart);
+ var fragmentEnd = elementStart - 1;
+
+ if (fragmentEnd < 0) {
+ fragmentEnd = metadataUri.indexOf("?", fragmentStart);
+ if (fragmentEnd === -1) {
+ fragmentEnd = metadataUri.length;
+ }
+ }
+
+ var fragment = metadataUri.substring(fragmentStart + 1, fragmentEnd);
+ if (fragment.indexOf("/$links/") > 0) {
+ return jsonLightMakePayloadInfo(PAYLOADTYPE_LINKS);
+ }
+
+ var fragmentParts = fragment.split("/");
+ if (fragmentParts.length >= 0) {
+ var qualifiedName = fragmentParts[0];
+ var typeCast = fragmentParts[1];
+
+ if (jsonLightIsPrimitiveType(qualifiedName)) {
+ return jsonLightMakePayloadInfo(PAYLOADTYPE_PRIMITIVE, qualifiedName);
+ }
+
+ if (isCollectionType(qualifiedName)) {
+ return jsonLightMakePayloadInfo(PAYLOADTYPE_COLLECTION, qualifiedName);
+ }
+
+ var entityType = typeCast;
+ var entitySet, functionImport, containerName;
+ if (!typeCast) {
+ var nsEnd = qualifiedName.lastIndexOf(".");
+ var simpleName = qualifiedName.substring(nsEnd + 1);
+ var container = (simpleName === qualifiedName) ?
+ lookupDefaultEntityContainer(model) :
+ lookupEntityContainer(qualifiedName.substring(0, nsEnd), model);
+
+ if (container) {
+ entitySet = lookupEntitySet(container.entitySet, simpleName);
+ functionImport = container.functionImport;
+ containerName = container.name;
+ entityType = !!entitySet ? entitySet.entityType : null;
+ }
+ }
+
+ var info;
+ if (elementStart > 0) {
+ info = jsonLightMakePayloadInfo(PAYLOADTYPE_OBJECT, entityType);
+ info.entitySet = entitySet;
+ info.functionImport = functionImport;
+ info.containerName = containerName;
+ return info;
+ }
+
+ if (entityType) {
+ info = jsonLightMakePayloadInfo(PAYLOADTYPE_FEED, entityType);
+ info.entitySet = entitySet;
+ info.functionImport = functionImport;
+ info.containerName = containerName;
+ return info;
+ }
+
+ if (isArray(data.value) && !lookupComplexType(qualifiedName, model)) {
+ var item = data.value[0];
+ if (!isPrimitive(item)) {
+ if (jsonLightIsEntry(item) || !inferFeedAsComplexType) {
+ return jsonLightMakePayloadInfo(PAYLOADTYPE_FEED, null);
+ }
+ }
+ }
+
+ return jsonLightMakePayloadInfo(PAYLOADTYPE_OBJECT, qualifiedName);
+ }
+
+ return null;
+};
+
+var jsonLightReadPayload = function (data, model, recognizeDates, inferFeedAsComplexType, contentTypeOdata) {
+ /// <summary>Converts a JSON light response payload object into its library's internal representation.</summary>
+ /// <param name="data" type="Object">Json light response payload object.</param>
+ /// <param name="model" type="Object">Object describing an OData conceptual schema.</param>
+ /// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
+ /// <param name="inferFeedAsComplexType" type="Boolean">True if a JSON light payload that looks like a feed should be reported as a complex type property instead.</param>
+ /// <param name="contentTypeOdata" type="string">Includes the type of json ( minimalmetadata, fullmetadata .. etc )</param>
+ /// <returns type="Object">Object in the library's representation.</returns>
+
+ if (!isComplex(data)) {
+ return data;
+ }
+
+ contentTypeOdata = contentTypeOdata || "minimalmetadata";
+ var baseURI = data[metadataAnnotation];
+ var payloadInfo = jsonLightPayloadInfo(data, model, inferFeedAsComplexType);
+ if (assigned(payloadInfo)) {
+ payloadInfo.contentTypeOdata = contentTypeOdata;
+ }
+ var typeName = null;
+ if (payloadInfo) {
+ delete data[metadataAnnotation];
+
+ typeName = payloadInfo.type;
+ switch (payloadInfo.kind) {
+ case PAYLOADTYPE_FEED:
+ return jsonLightReadFeed(data, payloadInfo, baseURI, model, recognizeDates);
+ case PAYLOADTYPE_COLLECTION:
+ return jsonLightReadTopCollectionProperty(data, typeName, baseURI, model, recognizeDates);
+ case PAYLOADTYPE_PRIMITIVE:
+ return jsonLightReadTopPrimitiveProperty(data, typeName, baseURI, recognizeDates);
+ case PAYLOADTYPE_SVCDOC:
+ return jsonLightReadSvcDocument(data, baseURI);
+ case PAYLOADTYPE_LINKS:
+ return jsonLightReadLinksDocument(data, baseURI);
+ }
+ }
+ return jsonLightReadObject(data, payloadInfo, baseURI, model, recognizeDates);
+};
+
+var jsonLightSerializableMetadata = ["type", "etag", "media_src", "edit_media", "content_type", "media_etag"];
+
+var formatJsonLight = function (obj, context) {
+ /// <summary>Converts an object in the library's internal representation to its json light representation.</summary>
+ /// <param name="obj" type="Object">Object the library's internal representation.</param>
+ /// <param name="context" type="Object">Object with the serialization context.</param>
+ /// <returns type="Object">Object in its json light representation.</returns>
+
+ // Regular expression used to test that the uri is for a $links document.
+ var linksUriRE = /\/\$links\//;
+ var data = {};
+ var metadata = obj.__metadata;
+
+ var islinks = context && linksUriRE.test(context.request.requestUri);
+ formatJsonLightData(obj, (metadata && metadata.properties), data, islinks);
+ return data;
+};
+
+var formatJsonLightMetadata = function (metadata, data) {
+ /// <summary>Formats an object's metadata into the appropriate json light annotations and saves them to data.</summary>
+ /// <param name="obj" type="Object">Object whose metadata is going to be formatted as annotations.</param>
+ /// <param name="data" type="Object">Object on which the annotations are going to be stored.</param>
+
+ if (metadata) {
+ var i, len;
+ for (i = 0, len = jsonLightSerializableMetadata.length; i < len; i++) {
+ // There is only a subset of metadata values that are interesting during update requests.
+ var name = jsonLightSerializableMetadata[i];
+ var qName = odataAnnotationPrefix + (jsonLightNameMap[name] || name);
+ formatJsonLightAnnotation(qName, null, metadata[name], data);
+ }
+ }
+};
+
+var formatJsonLightData = function (obj, pMetadata, data, isLinks) {
+ /// <summary>Formats an object's data into the appropriate json light values and saves them to data.</summary>
+ /// <param name="obj" type="Object">Object whose data is going to be formatted.</param>
+ /// <param name="pMetadata" type="Object">Object that contains metadata for the properties that are being formatted.</param>
+ /// <param name="data" type="Object">Object on which the formatted values are going to be stored.</param>
+ /// <param name="isLinks" type="Boolean">True if a links document is being formatted. False otherwise.</param>
+
+ for (var key in obj) {
+ var value = obj[key];
+ if (key === "__metadata") {
+ // key is the object metadata.
+ formatJsonLightMetadata(value, data);
+ } else if (key.indexOf(".") === -1) {
+ // key is an regular property or array element.
+ if (isLinks && key === "uri") {
+ formatJsonLightEntityLink(value, data);
+ } else {
+ formatJsonLightProperty(key, value, pMetadata, data, isLinks);
+ }
+ } else {
+ data[key] = value;
+ }
+ }
+};
+
+var formatJsonLightProperty = function (name, value, pMetadata, data) {
+ /// <summary>Formats an object's value identified by name to its json light representation and saves it to data.</summary>
+ /// <param name="name" type="String">Property name.</param>
+ /// <param name="value">Property value.</param>
+ /// <param name="pMetadata" type="Object">Object that contains metadata for the property that is being formatted.</param>
+ /// <param name="data" type="Object">Object on which the formatted value is going to be stored.</param>
+
+ // Get property type from property metadata
+ var propertyMetadata = pMetadata && pMetadata[name] || { properties: undefined, type: undefined };
+ var typeName = dataItemTypeName(value, propertyMetadata);
+
+ if (isPrimitive(value) || !value) {
+ // It is a primitive value then.
+ formatJsonLightAnnotation(typeAnnotation, name, typeName, data);
+ data[name] = value;
+ return;
+ }
+
+ if (isFeed(value, typeName) || isEntry(value)) {
+ formatJsonLightInlineProperty(name, value, data);
+ return;
+ }
+
+ if (!typeName && isDeferred(value)) {
+ // It is really a deferred property.
+ formatJsonLightDeferredProperty(name, value, data);
+ return;
+ }
+
+ if (isCollection(value, typeName)) {
+ // The thing is a collection, format it as one.
+ if (getCollectionType(typeName)) {
+ formatJsonLightAnnotation(typeAnnotation, name, typeName, data);
+ }
+ formatJsonLightCollectionProperty(name, value, data);
+ return;
+ }
+
+ djsassert(isComplex(value), "formatJsonLightProperty - Value is not a complex type value");
+
+ // Format the complex property value in a new object in data[name].
+ data[name] = {};
+ formatJsonLightAnnotation(typeAnnotation, null, typeName, data[name]);
+ formatJsonLightData(value, propertyMetadata.properties, data[name]);
+};
+
+var formatJsonLightEntityLink = function (value, data) {
+ /// <summary>Formats an entity link in a $links document and saves it into data.</summary>
+ /// <param name="value" type="String">Entity link value.</summary>
+ /// <param name="data" type="Object">Object on which the formatted value is going to be stored.</param>
+ data.url = value;
+};
+
+var formatJsonLightDeferredProperty = function (name, value, data) {
+ /// <summary>Formats the object value's identified by name as an odata.navigalinkurl annotation and saves it to data.</summary>
+ /// <param name="name" type="String">Name of the deferred property to be formatted.</param>
+ /// <param name="value" type="Object">Deferred property value to be formatted.</param>
+ /// <param name="data" type="Object">Object on which the formatted value is going to be stored.</param>
+
+ formatJsonLightAnnotation(navUrlAnnotation, name, value.__deferred.uri, data);
+};
+
+var formatJsonLightCollectionProperty = function (name, value, data) {
+ /// <summary>Formats a collection property in obj identified by name as a json light collection property and saves it to data.</summary>
+ /// <param name="name" type="String">Name of the collection property to be formatted.</param>
+ /// <param name="value" type="Object">Collection property value to be formatted.</param>
+ /// <param name="data" type="Object">Object on which the formatted value is going to be stored.</param>
+
+ data[name] = [];
+ var items = isArray(value) ? value : value.results;
+ formatJsonLightData(items, null, data[name]);
+};
+
+var formatJsonLightInlineProperty = function (name, value, data) {
+ /// <summary>Formats an inline feed or entry property in obj identified by name as a json light value and saves it to data.</summary>
+ /// <param name="name" type="String">Name of the inline feed or entry property to be formatted.</param>
+ /// <param name="value" type="Object or Array">Value of the inline feed or entry property.</param>
+ /// <param name="data" type="Object">Object on which the formatted value is going to be stored.</param>
+
+ if (isFeed(value)) {
+ data[name] = [];
+ // Format each of the inline feed entries
+ var entries = isArray(value) ? value : value.results;
+ var i, len;
+ for (i = 0, len = entries.length; i < len; i++) {
+ formatJsonLightInlineEntry(name, entries[i], true, data);
+ }
+ return;
+ }
+ formatJsonLightInlineEntry(name, value, false, data);
+};
+
+var formatJsonLightInlineEntry = function (name, value, inFeed, data) {
+ /// <summary>Formats an inline entry value in the property identified by name as a json light value and saves it to data.</summary>
+ /// <param name="name" type="String">Name of the inline feed or entry property that owns the entry formatted.</param>
+ /// <param name="value" type="Object">Inline entry value to be formatted.</param>
+ /// <param name="inFeed" type="Boolean">True if the entry is in an inline feed; false otherwise.
+ /// <param name="data" type="Object">Object on which the formatted value is going to be stored.</param>
+
+ // This might be a bind instead of a deep insert.
+ var uri = value.__metadata && value.__metadata.uri;
+ if (uri) {
+ formatJsonLightBinding(name, uri, inFeed, data);
+ return;
+ }
+
+ var entry = formatJsonLight(value);
+ if (inFeed) {
+ data[name].push(entry);
+ return;
+ }
+ data[name] = entry;
+};
+
+var formatJsonLightBinding = function (name, uri, inFeed, data) {
+ /// <summary>Formats an entry binding in the inline property in obj identified by name as an odata.bind annotation and saves it to data.</summary>
+ /// <param name="name" type="String">Name of the inline property that has the binding to be formated.</param>
+ /// <param name="uri" type="String">Uri to the bound entry.</param>
+ /// <param name="inFeed" type="Boolean">True if the binding is in an inline feed; false otherwise.
+ /// <param name="data" type="Object">Object on which the formatted value is going to be stored.</param>
+
+ var bindingName = name + bindAnnotation;
+ if (inFeed) {
+ // The binding is inside an inline feed, so merge it with whatever other bindings already exist in data.
+ data[bindingName] = data[bindingName] || [];
+ data[bindingName].push(uri);
+ return;
+ }
+ // The binding is on an inline entry; it can be safely overwritten.
+ data[bindingName] = uri;
+};
+
+var formatJsonLightAnnotation = function (qName, target, value, data) {
+ /// <summary>Formats a value as a json light annotation and stores it in data</summary>
+ /// <param name="qName" type="String">Qualified name of the annotation.</param>
+ /// <param name="target" type="String">Name of the property that the metadata value targets.</param>
+ /// <param name="value">Annotation value.</param>
+ /// <param name="data" type="Object">Object on which the annotation is going to be stored.</param>
+
+ if (value !== undefined) {
+ if(target) {
+ data[target + "@" + qName] = value;
+ }
+ else {
+ data[qName] = value;
+ }
+ }
+};
+
+// DATAJS INTERNAL START
+exports.jsonLightReadPayload = jsonLightReadPayload;
+exports.formatJsonLight = formatJsonLight;
+// DATAJS INTERNAL END
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/lib/odata/json.js
----------------------------------------------------------------------
diff --git a/datajs/src/lib/odata/json.js b/datajs/src/lib/odata/json.js
new file mode 100644
index 0000000..cb5dcfc
--- /dev/null
+++ b/datajs/src/lib/odata/json.js
@@ -0,0 +1,374 @@
+//SK name /odata/odata-json.js
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// odata-json.js
+
+ // Imports
+var utils = require('./../datajs.js').utils;
+var oDataUtils = require('./utils.js');
+var oDataHandler = require('./handler.js');
+
+
+var defined = utils.defined;
+var extend = utils.extend;
+var isArray = utils.isArray;
+var isDate = utils.isDate;
+var normalizeURI = utils.normalizeURI;
+var parseInt10 = utils.parseInt10;
+
+var contentType = oDataUtils.contentType;
+var jsonLightReadPayload = oDataUtils.jsonLightReadPayload;
+var formatDateTimeOffset = oDataUtils.formatDateTimeOffset;
+var formatDuration = oDataUtils.formatDuration;
+var formatJsonLight = oDataUtils.formatJsonLight;
+var formatNumberWidth = oDataUtils.formatNumberWidth;
+var getCanonicalTimezone = oDataUtils.getCanonicalTimezone;
+var handler = oDataUtils.handler;
+var isComplex = oDataUtils.isComplex;
+var lookupComplexType = oDataUtils.lookupComplexType;
+var lookupEntityType = oDataUtils.lookupEntityType;
+var MAX_DATA_SERVICE_VERSION = oDataUtils.MAX_DATA_SERVICE_VERSION;
+var maxVersion = oDataUtils.maxVersion;
+var parseDateTime = oDataUtils.parseDateTime;
+var parseDuration = oDataUtils.parseDuration;
+var parseTimezone = oDataUtils.parseTimezone;
+var payloadTypeOf = oDataUtils.payloadTypeOf;
+var traverse = oDataUtils.traverse;
+
+// CONTENT START
+
+var jsonMediaType = "application/json";
+var jsonContentType = oDataHandler.contentType(jsonMediaType);
+
+var jsonReadAdvertisedActionsOrFunctions = function (value) {
+ /// <summary>Reads and object containing action or function metadata and maps them into a single array of objects.</summary>
+ /// <param name="value" type="Object">Object containing action or function metadata.</param>
+ /// <returns type="Array">Array of objects containing metadata for the actions or functions specified in value.</returns>
+
+ var result = [];
+ for (var name in value) {
+ var i, len;
+ for (i = 0, len = value[name].length; i < len; i++) {
+ result.push(extend({ metadata: name }, value[name][i]));
+ }
+ }
+ return result;
+};
+
+var jsonApplyMetadata = function (value, metadata, dateParser, recognizeDates) {
+ /// <summary>Applies metadata coming from both the payload and the metadata object to the value.</summary>
+ /// <param name="value" type="Object">Data on which the metada is going to be applied.</param>
+ /// <param name="metadata">Metadata store; one of edmx, schema, or an array of any of them.</param>
+ /// <param name="dateParser" type="function">Function used for parsing datetime values.</param>
+ /// <param name="recognizeDates" type="Boolean">
+ /// True if strings formatted as datetime values should be treated as datetime values. False otherwise.
+ /// </param>
+ /// <returns type="Object">Transformed data.</returns>
+
+ if (value && typeof value === "object") {
+ var dataTypeName;
+ var valueMetadata = value.__metadata;
+
+ if (valueMetadata) {
+ if (valueMetadata.actions) {
+ valueMetadata.actions = jsonReadAdvertisedActionsOrFunctions(valueMetadata.actions);
+ }
+ if (valueMetadata.functions) {
+ valueMetadata.functions = jsonReadAdvertisedActionsOrFunctions(valueMetadata.functions);
+ }
+ dataTypeName = valueMetadata && valueMetadata.type;
+ }
+
+ var dataType = lookupEntityType(dataTypeName, metadata) || lookupComplexType(dataTypeName, metadata);
+ var propertyValue;
+ if (dataType) {
+ var properties = dataType.property;
+ if (properties) {
+ var i, len;
+ for (i = 0, len = properties.length; i < len; i++) {
+ var property = properties[i];
+ var propertyName = property.name;
+ propertyValue = value[propertyName];
+
+ if (property.type === "Edm.DateTime" || property.type === "Edm.DateTimeOffset") {
+ if (propertyValue) {
+ propertyValue = dateParser(propertyValue);
+ if (!propertyValue) {
+ throw { message: "Invalid date/time value" };
+ }
+ value[propertyName] = propertyValue;
+ }
+ } else if (property.type === "Edm.Time") {
+ value[propertyName] = parseDuration(propertyValue);
+ }
+ }
+ }
+ } else if (recognizeDates) {
+ for (var name in value) {
+ propertyValue = value[name];
+ if (typeof propertyValue === "string") {
+ value[name] = dateParser(propertyValue) || propertyValue;
+ }
+ }
+ }
+ }
+ return value;
+};
+
+var isJsonLight = function (contentType) {
+ /// <summary>Tests where the content type indicates a json light payload.</summary>
+ /// <param name="contentType">Object with media type and properties dictionary.</param>
+ /// <returns type="Boolean">True is the content type indicates a json light payload. False otherwise.</returns>
+
+ if (contentType) {
+ var odata = contentType.properties.odata;
+ return odata === "nometadata" || odata === "minimalmetadata" || odata === "fullmetadata";
+ }
+ return false;
+};
+
+var normalizeServiceDocument = function (data, baseURI) {
+ /// <summary>Normalizes a JSON service document to look like an ATOM service document.</summary>
+ /// <param name="data" type="Object">Object representation of service documents as deserialized.</param>
+ /// <param name="baseURI" type="String">Base URI to resolve relative URIs.</param>
+ /// <returns type="Object">An object representation of the service document.</returns>
+ var workspace = { collections: [] };
+
+ var i, len;
+ for (i = 0, len = data.EntitySets.length; i < len; i++) {
+ var title = data.EntitySets[i];
+ var collection = {
+ title: title,
+ href: normalizeURI(title, baseURI)
+ };
+
+ workspace.collections.push(collection);
+ }
+
+ return { workspaces: [workspace] };
+};
+
+// The regular expression corresponds to something like this:
+// /Date(123+60)/
+//
+// This first number is date ticks, the + may be a - and is optional,
+// with the second number indicating a timezone offset in minutes.
+//
+// On the wire, the leading and trailing forward slashes are
+// escaped without being required to so the chance of collisions is reduced;
+// however, by the time we see the objects, the characters already
+// look like regular forward slashes.
+var jsonDateRE = /^\/Date\((-?\d+)(\+|-)?(\d+)?\)\/$/;
+
+var minutesToOffset = function (minutes) {
+ /// <summary>Formats the given minutes into (+/-)hh:mm format.</summary>
+ /// <param name="minutes" type="Number">Number of minutes to format.</param>
+ /// <returns type="String">The minutes in (+/-)hh:mm format.</returns>
+
+ var sign;
+ if (minutes < 0) {
+ sign = "-";
+ minutes = -minutes;
+ } else {
+ sign = "+";
+ }
+
+ var hours = Math.floor(minutes / 60);
+ minutes = minutes - (60 * hours);
+
+ return sign + formatNumberWidth(hours, 2) + ":" + formatNumberWidth(minutes, 2);
+};
+
+var parseJsonDateString = function (value) {
+ /// <summary>Parses the JSON Date representation into a Date object.</summary>
+ /// <param name="value" type="String">String value.</param>
+ /// <returns type="Date">A Date object if the value matches one; falsy otherwise.</returns>
+
+ var arr = value && jsonDateRE.exec(value);
+ if (arr) {
+ // 0 - complete results; 1 - ticks; 2 - sign; 3 - minutes
+ var result = new Date(parseInt10(arr[1]));
+ if (arr[2]) {
+ var mins = parseInt10(arr[3]);
+ if (arr[2] === "-") {
+ mins = -mins;
+ }
+
+ // The offset is reversed to get back the UTC date, which is
+ // what the API will eventually have.
+ var current = result.getUTCMinutes();
+ result.setUTCMinutes(current - mins);
+ result.__edmType = "Edm.DateTimeOffset";
+ result.__offset = minutesToOffset(mins);
+ }
+ if (!isNaN(result.valueOf())) {
+ return result;
+ }
+ }
+
+ // Allow undefined to be returned.
+};
+
+// Some JSON implementations cannot produce the character sequence \/
+// which is needed to format DateTime and DateTimeOffset into the
+// JSON string representation defined by the OData protocol.
+// See the history of this file for a candidate implementation of
+// a 'formatJsonDateString' function.
+
+var jsonParser = function (handler, text, context) {
+ /// <summary>Parses a JSON OData payload.</summary>
+ /// <param name="handler">This handler.</param>
+ /// <param name="text">Payload text (this parser also handles pre-parsed objects).</param>
+ /// <param name="context" type="Object">Object with parsing context.</param>
+ /// <returns>An object representation of the OData payload.</returns>
+
+ var recognizeDates = defined(context.recognizeDates, handler.recognizeDates);
+ var inferJsonLightFeedAsObject = defined(context.inferJsonLightFeedAsObject, handler.inferJsonLightFeedAsObject);
+ var model = context.metadata;
+ var dataServiceVersion = context.dataServiceVersion;
+ var dateParser = parseJsonDateString;
+ var json = (typeof text === "string") ? window.JSON.parse(text) : text;
+
+ if ((maxVersion("3.0", dataServiceVersion) === dataServiceVersion)) {
+ if (isJsonLight(context.contentType)) {
+ return jsonLightReadPayload(json, model, recognizeDates, inferJsonLightFeedAsObject, context.contentType.properties.odata);
+ }
+ dateParser = parseDateTime;
+ }
+
+ json = traverse(json.d, function (key, value) {
+ return jsonApplyMetadata(value, model, dateParser, recognizeDates);
+ });
+
+ json = jsonUpdateDataFromVersion(json, context.dataServiceVersion);
+ return jsonNormalizeData(json, context.response.requestUri);
+};
+
+var jsonToString = function (data) {
+ /// <summary>Converts the data into a JSON string.</summary>
+ /// <param name="data">Data to serialize.</param>
+ /// <returns type="String">The JSON string representation of data.</returns>
+
+ var result; // = undefined;
+ // Save the current date.toJSON function
+ var dateToJSON = Date.prototype.toJSON;
+ try {
+ // Set our own date.toJSON function
+ Date.prototype.toJSON = function () {
+ return formatDateTimeOffset(this);
+ };
+ result = window.JSON.stringify(data, jsonReplacer);
+ } finally {
+ // Restore the original toJSON function
+ Date.prototype.toJSON = dateToJSON;
+ }
+ return result;
+};
+
+var jsonSerializer = function (handler, data, context) {
+ /// <summary>Serializes the data by returning its string representation.</summary>
+ /// <param name="handler">This handler.</param>
+ /// <param name="data">Data to serialize.</param>
+ /// <param name="context" type="Object">Object with serialization context.</param>
+ /// <returns type="String">The string representation of data.</returns>
+
+ var dataServiceVersion = context.dataServiceVersion || "1.0";
+ var useJsonLight = defined(context.useJsonLight, handler.useJsonLight);
+ var cType = context.contentType = context.contentType || jsonContentType;
+
+ if (cType && cType.mediaType === jsonContentType.mediaType) {
+ var json = data;
+ if (useJsonLight || isJsonLight(cType)) {
+ context.dataServiceVersion = maxVersion(dataServiceVersion, "3.0");
+ json = formatJsonLight(data, context);
+ return jsonToString(json);
+ }
+ if (maxVersion("3.0", dataServiceVersion) === dataServiceVersion) {
+ cType.properties.odata = "verbose";
+ context.contentType = cType;
+ }
+ return jsonToString(json);
+ }
+ return undefined;
+};
+
+var jsonReplacer = function (_, value) {
+ /// <summary>JSON replacer function for converting a value to its JSON representation.</summary>
+ /// <param value type="Object">Value to convert.</param>
+ /// <returns type="String">JSON representation of the input value.</returns>
+ /// <remarks>
+ /// This method is used during JSON serialization and invoked only by the JSON.stringify function.
+ /// It should never be called directly.
+ /// </remarks>
+
+ if (value && value.__edmType === "Edm.Time") {
+ return formatDuration(value);
+ } else {
+ return value;
+ }
+};
+
+var jsonNormalizeData = function (data, baseURI) {
+ /// <summary>
+ /// Normalizes the specified data into an intermediate representation.
+ /// like the latest supported version.
+ /// </summary>
+ /// <param name="data" optional="false">Data to update.</param>
+ /// <param name="baseURI" optional="false">URI to use as the base for normalizing references.</param>
+
+ var isSvcDoc = isComplex(data) && !data.__metadata && isArray(data.EntitySets);
+ return isSvcDoc ? normalizeServiceDocument(data, baseURI) : data;
+};
+
+var jsonUpdateDataFromVersion = function (data, dataVersion) {
+ /// <summary>
+ /// Updates the specified data in the specified version to look
+ /// like the latest supported version.
+ /// </summary>
+ /// <param name="data" optional="false">Data to update.</param>
+ /// <param name="dataVersion" optional="true" type="String">Version the data is in (possibly unknown).</param>
+
+ // Strip the trailing comma if there.
+ if (dataVersion && dataVersion.lastIndexOf(";") === dataVersion.length - 1) {
+ dataVersion = dataVersion.substr(0, dataVersion.length - 1);
+ }
+
+ if (!dataVersion || dataVersion === "1.0") {
+ if (isArray(data)) {
+ data = { results: data };
+ }
+ }
+
+ return data;
+};
+
+var jsonHandler = oDataHandler.handler(jsonParser, jsonSerializer, jsonMediaType, MAX_DATA_SERVICE_VERSION);
+jsonHandler.recognizeDates = false;
+jsonHandler.useJsonLight = false;
+jsonHandler.inferJsonLightFeedAsObject = false;
+
+exports.jsonHandler = jsonHandler;
+
+
+
+// DATAJS INTERNAL START
+exports.jsonParser = jsonParser;
+exports.jsonSerializer = jsonSerializer;
+exports.jsonNormalizeData = jsonNormalizeData;
+exports.jsonUpdateDataFromVersion = jsonUpdateDataFromVersion;
+exports.normalizeServiceDocument = normalizeServiceDocument;
+exports.parseJsonDateString = parseJsonDateString;
+// DATAJS INTERNAL END
+
+
[08/15] [OLINGO-238] Build infrastructure for datajs I
Posted by ko...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/lib/odata/xml.js
----------------------------------------------------------------------
diff --git a/datajs/src/lib/odata/xml.js b/datajs/src/lib/odata/xml.js
new file mode 100644
index 0000000..7a21775
--- /dev/null
+++ b/datajs/src/lib/odata/xml.js
@@ -0,0 +1,853 @@
+//SK name /odata/odata-xml.js
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// odata-xml.js
+
+var xml = require('./../datajs.js').xml;
+var utils = require('./../datajs.js').utils;
+var odata_utils = require('./utils.js');
+var odataHandler = require('./handler.js');
+
+// Imports.
+
+var djsassert = utils.djsassert;
+
+var isArray = utils.isArray;
+var isDate = utils.isDate;
+var isObject = utils.isObject;
+var normalizeURI = utils.normalizeURI;
+var parseInt10 = utils.parseInt10;
+
+var xmlAppendChild = xml.xmlAppendChild;
+var xmlAppendChildren = xml.xmlAppendChildren;
+var xmlAttributes = xml.xmlAttributes;
+var xmlBaseURI = xml.xmlBaseURI;
+var xmlChildElements = xml.xmlChildElements;
+var xmlDom = xml.xmlDom;
+var xmlFirstChildElement = xml.xmlFirstChildElement;
+var xmlInnerText = xml.xmlInnerText;
+var xmlLocalName = xml.xmlLocalName;
+var xmlNamespaceURI = xml.xmlNamespaceURI;
+var xmlNewAttribute = xml.xmlNewAttribute;
+var xmlNewElement = xml.xmlNewElement;
+var xmlNodeValue = xml.xmlNodeValue;
+var xmlNS = xml.xmlNS;
+var xmlnsNS = xml.xmlnsNS;
+var xmlParse = xml.xmlParse;
+var xmlQualifiedName = xml.xmlQualifiedName;
+var xmlSerialize = xml.xmlSerialize;
+var xmlSiblingElement = xml.xmlSiblingElement;
+var http = xml.http;
+var w3org = xml.w3org;
+
+var dataItemTypeName = odata_utils.dataItemTypeName;
+var EDM_BINARY = odata_utils.EDM_BINARY;
+var EDM_BOOLEAN = odata_utils.EDM_BOOLEAN;
+var EDM_BYTE = odata_utils.EDM_BYTE;
+var EDM_DATETIME = odata_utils.EDM_DATETIME;
+var EDM_DATETIMEOFFSET = odata_utils.EDM_DATETIMEOFFSET;
+var EDM_DECIMAL = odata_utils.EDM_DECIMAL;
+var EDM_DOUBLE = odata_utils.EDM_DOUBLE;
+var EDM_GEOGRAPHY = odata_utils.EDM_GEOGRAPHY;
+var EDM_GEOGRAPHY_POINT = odata_utils.EDM_GEOGRAPHY_POINT;
+var EDM_GEOGRAPHY_LINESTRING = odata_utils.EDM_GEOGRAPHY_LINESTRING;
+var EDM_GEOGRAPHY_POLYGON = odata_utils.EDM_GEOGRAPHY_POLYGON;
+var EDM_GEOGRAPHY_COLLECTION = odata_utils.EDM_GEOGRAPHY_COLLECTION;
+var EDM_GEOGRAPHY_MULTIPOLYGON = odata_utils.EDM_GEOGRAPHY_MULTIPOLYGON;
+var EDM_GEOGRAPHY_MULTILINESTRING = odata_utils.EDM_GEOGRAPHY_MULTILINESTRING;
+var EDM_GEOGRAPHY_MULTIPOINT = odata_utils.EDM_GEOGRAPHY_MULTIPOINT;
+var EDM_GEOMETRY = odata_utils.EDM_GEOMETRY;
+var EDM_GEOMETRY_POINT = odata_utils.EDM_GEOMETRY_POINT;
+var EDM_GEOMETRY_LINESTRING = odata_utils.EDM_GEOMETRY_LINESTRING;
+var EDM_GEOMETRY_POLYGON = odata_utils.EDM_GEOMETRY_POLYGON;
+var EDM_GEOMETRY_COLLECTION = odata_utils.EDM_GEOMETRY_COLLECTION;
+var EDM_GEOMETRY_MULTIPOLYGON = odata_utils.EDM_GEOMETRY_MULTIPOLYGON;
+var EDM_GEOMETRY_MULTILINESTRING = odata_utils.EDM_GEOMETRY_MULTILINESTRING;
+var EDM_GEOMETRY_MULTIPOINT = odata_utils.EDM_GEOMETRY_MULTIPOINT;
+var EDM_GUID = odata_utils.EDM_GUID;
+var EDM_INT16 = odata_utils.EDM_INT16;
+var EDM_INT32 = odata_utils.EDM_INT32;
+var EDM_INT64 = odata_utils.EDM_INT64;
+var EDM_SBYTE = odata_utils.EDM_SBYTE;
+var EDM_SINGLE = odata_utils.EDM_SINGLE;
+var EDM_STRING = odata_utils.EDM_STRING;
+var EDM_TIME = odata_utils.EDM_TIME;
+var GEOJSON_POINT = odata_utils.GEOJSON_POINT;
+var GEOJSON_LINESTRING = odata_utils.GEOJSON_LINESTRING;
+var GEOJSON_POLYGON = odata_utils.GEOJSON_POLYGON;
+var GEOJSON_MULTIPOINT = odata_utils.GEOJSON_MULTIPOINT;
+var GEOJSON_MULTILINESTRING = odata_utils.GEOJSON_MULTILINESTRING;
+var GEOJSON_MULTIPOLYGON = odata_utils.GEOJSON_MULTIPOLYGON;
+var GEOJSON_GEOMETRYCOLLECTION = odata_utils.GEOJSON_GEOMETRYCOLLECTION;
+
+var formatDateTimeOffset = odata_utils.formatDateTimeOffset;
+var formatDuration = odata_utils.formatDuration;
+var getCollectionType = odata_utils.getCollectionType;
+var gmlNewODataSpatialValue = odata_utils.gmlNewODataSpatialValue;
+var gmlReadODataSpatialValue = odata_utils.gmlReadODataSpatialValue;
+var gmlXmlNs = odata_utils.gmlXmlNs;
+var handler = odata_utils.handler;
+var isCollection = odata_utils.isodata_utilsCollection;
+var isCollectionType = odata_utils.isCollectionType;
+var isDeferred = odata_utils.isDeferred;
+var isNamedStream = odata_utils.isNamedStream;
+var isGeographyEdmType = odata_utils.isGeographyEdmType;
+var isGeometryEdmType = odata_utils.isGeometryEdmType;
+var isPrimitive = odata_utils.isPrimitive;
+var isPrimitiveEdmType = odata_utils.isPrimitiveEdmType;
+var lookupComplexType = odata_utils.lookupComplexType;
+var lookupProperty = odata_utils.lookupProperty;
+var maxVersion = odata_utils.maxVersion;
+var navigationPropertyKind = odata_utils.navigationPropertyKind;
+
+
+var parseBool = odata_utils.parseBool;
+var parseDateTime = odata_utils.parseDateTime;
+var parseDateTimeOffset = odata_utils.parseDateTimeOffset;
+var parseDuration = odata_utils.parseDuration;
+var parseTimezone = odata_utils.parseTimezone;
+
+var MAX_DATA_SERVICE_VERSION = odataHandler.MAX_DATA_SERVICE_VERSION;
+
+// CONTENT START
+
+var xmlMediaType = "application/xml";
+
+var ado = http + "schemas.microsoft.com/ado/"; // http://schemas.microsoft.com/ado/
+var adoDs = ado + "2007/08/dataservices"; // http://schemas.microsoft.com/ado/2007/08/dataservices
+
+var edmxNs = ado + "2007/06/edmx"; // http://schemas.microsoft.com/ado/2007/06/edmx
+var edmNs1 = ado + "2006/04/edm"; // http://schemas.microsoft.com/ado/2006/04/edm
+var edmNs1_1 = ado + "2007/05/edm"; // http://schemas.microsoft.com/ado/2007/05/edm
+var edmNs1_2 = ado + "2008/01/edm"; // http://schemas.microsoft.com/ado/2008/01/edm
+
+// There are two valid namespaces for Edm 2.0
+var edmNs2a = ado + "2008/09/edm"; // http://schemas.microsoft.com/ado/2008/09/edm
+var edmNs2b = ado + "2009/08/edm"; // http://schemas.microsoft.com/ado/2009/08/edm
+
+var edmNs3 = ado + "2009/11/edm"; // http://schemas.microsoft.com/ado/2009/11/edm
+
+var odataXmlNs = adoDs; // http://schemas.microsoft.com/ado/2007/08/dataservices
+var odataMetaXmlNs = adoDs + "/metadata"; // http://schemas.microsoft.com/ado/2007/08/dataservices/metadata
+var odataRelatedPrefix = adoDs + "/related/"; // http://schemas.microsoft.com/ado/2007/08/dataservices/related
+var odataScheme = adoDs + "/scheme"; // http://schemas.microsoft.com/ado/2007/08/dataservices/scheme
+
+var odataPrefix = "d";
+var odataMetaPrefix = "m";
+
+var createAttributeExtension = function (domNode, useNamespaceURI) {
+ /// <summary>Creates an extension object for the specified attribute.</summary>
+ /// <param name="domNode">DOM node for the attribute.</param>
+ /// <param name="useNamespaceURI" type="Boolean">Flag indicating if the namespaceURI property should be added to the extension object instead of the namespace property.</param>
+ /// <remarks>
+ /// The useNamespaceURI flag is used to prevent a breaking change from older versions of datajs in which extension
+ /// objects created for Atom extension attributes have the namespaceURI property instead of the namespace one.
+ ///
+ /// This flag and the namespaceURI property should be deprecated in future major versions of the library.
+ /// </remarks>
+ /// <returns type="Object">The new extension object.</returns>
+
+ djsassert(domNode.nodeType === 2, "createAttributeExtension - domNode is not an attribute node!!");
+ var extension = { name: xmlLocalName(domNode), value: domNode.value };
+ extension[useNamespaceURI ? "namespaceURI" : "namespace"] = xmlNamespaceURI(domNode);
+
+ return extension;
+};
+
+var createElementExtension = function (domNode, useNamespaceURI) {
+ /// <summary>Creates an extension object for the specified element.</summary>
+ /// <param name="domNode">DOM node for the element.</param>
+ /// <param name="useNamespaceURI" type="Boolean">Flag indicating if the namespaceURI property should be added to the extension object instead of the namespace property.</param>
+ /// <remarks>
+ /// The useNamespaceURI flag is used to prevent a breaking change from older versions of datajs in which extension
+ /// objects created for Atom extension attributes have the namespaceURI property instead of the namespace one.
+ ///
+ /// This flag and the namespaceURI property should be deprecated in future major versions of the library.
+ /// </remarks>
+ /// <returns type="Object">The new extension object.</returns>
+
+ djsassert(domNode.nodeType === 1, "createAttributeExtension - domNode is not an element node!!");
+
+ var attributeExtensions = [];
+ var childrenExtensions = [];
+
+ var i, len;
+ var attributes = domNode.attributes;
+ for (i = 0, len = attributes.length; i < len; i++) {
+ var attr = attributes[i];
+ if (xmlNamespaceURI(attr) !== xmlnsNS) {
+ attributeExtensions.push(createAttributeExtension(attr, useNamespaceURI));
+ }
+ }
+
+ var child = domNode.firstChild;
+ while (child != null) {
+ if (child.nodeType === 1) {
+ childrenExtensions.push(createElementExtension(child, useNamespaceURI));
+ }
+ child = child.nextSibling;
+ }
+
+ var extension = {
+ name: xmlLocalName(domNode),
+ value: xmlInnerText(domNode),
+ attributes: attributeExtensions,
+ children: childrenExtensions
+ };
+
+ extension[useNamespaceURI ? "namespaceURI" : "namespace"] = xmlNamespaceURI(domNode);
+ return extension;
+};
+
+var isCollectionItemElement = function (domElement) {
+ /// <summary>Checks whether the domElement is a collection item.</summary>
+ /// <param name="domElement">DOM element possibliy represnting a collection item.</param>
+ /// <returns type="Boolean">True if the domeElement belongs to the OData metadata namespace and its local name is "element"; false otherwise.</returns>
+
+ return xmlNamespaceURI(domElement) === odataXmlNs && xmlLocalName(domElement) === "element";
+};
+
+var makePropertyMetadata = function (type, extensions) {
+ /// <summary>Creates an object containing property metadata.</summary>
+ /// <param type="String" name="type">Property type name.</param>
+ /// <param type="Array" name="extensions">Array of attribute extension objects.</param>
+ /// <returns type="Object">Property metadata object cotaining type and extensions fields.</returns>
+
+ return { type: type, extensions: extensions };
+};
+
+var odataInferTypeFromPropertyXmlDom = function (domElement) {
+ /// <summary>Infers type of a property based on its xml DOM tree.</summary>
+ /// <param name="domElement">DOM element for the property.</param>
+ /// <returns type="String">Inferred type name; null if the type cannot be determined.</returns>
+
+ if (xmlFirstChildElement(domElement, gmlXmlNs)) {
+ return EDM_GEOMETRY;
+ }
+
+ var firstChild = xmlFirstChildElement(domElement, odataXmlNs);
+ if (!firstChild) {
+ return EDM_STRING;
+ }
+
+ if (isCollectionItemElement(firstChild)) {
+ var sibling = xmlSiblingElement(firstChild, odataXmlNs);
+ if (sibling && isCollectionItemElement(sibling)) {
+ // More than one <element> tag have been found, it can be safely assumed that this is a collection property.
+ return "Collection()";
+ }
+ }
+
+ return null;
+};
+
+var xmlReadODataPropertyAttributes = function (domElement) {
+ /// <summary>Reads the attributes of a property DOM element in an OData XML document.</summary>
+ /// <param name="domElement">DOM element for the property.</param>
+ /// <returns type="Object">Object containing the property type, if it is null, and its attribute extensions.</returns>
+
+ var type = null;
+ var isNull = false;
+ var extensions = [];
+
+ xmlAttributes(domElement, function (attribute) {
+ var nsURI = xmlNamespaceURI(attribute);
+ var localName = xmlLocalName(attribute);
+ var value = xmlNodeValue(attribute);
+
+ if (nsURI === odataMetaXmlNs) {
+ if (localName === "null") {
+ isNull = (value.toLowerCase() === "true");
+ return;
+ }
+
+ if (localName === "type") {
+ type = value;
+ return;
+ }
+ }
+
+ if (nsURI !== xmlNS && nsURI !== xmlnsNS) {
+ extensions.push(createAttributeExtension(attribute, true));
+ return;
+ }
+ });
+
+ return { type: (!type && isNull ? EDM_STRING : type), isNull: isNull, extensions: extensions };
+};
+
+var xmlReadODataProperty = function (domElement) {
+ /// <summary>Reads a property DOM element in an OData XML document.</summary>
+ /// <param name="domElement">DOM element for the property.</param>
+ /// <returns type="Object">Object with name, value, and metadata for the property.</returns>
+
+ if (xmlNamespaceURI(domElement) !== odataXmlNs) {
+ // domElement is not a proprety element because it is not in the odata xml namespace.
+ return null;
+ }
+
+ var propertyName = xmlLocalName(domElement);
+ var propertyAttributes = xmlReadODataPropertyAttributes(domElement);
+
+ var propertyIsNull = propertyAttributes.isNull;
+ var propertyType = propertyAttributes.type;
+
+ var propertyMetadata = makePropertyMetadata(propertyType, propertyAttributes.extensions);
+ var propertyValue = propertyIsNull ? null : xmlReadODataPropertyValue(domElement, propertyType, propertyMetadata);
+
+ return { name: propertyName, value: propertyValue, metadata: propertyMetadata };
+};
+
+var xmlReadODataPropertyValue = function (domElement, propertyType, propertyMetadata) {
+ /// <summary>Reads the value of a property in an OData XML document.</summary>
+ /// <param name="domElement">DOM element for the property.</param>
+ /// <param name="propertyType" type="String">Property type name.</param>
+ /// <param name="propertyMetadata" type="Object">Object that will store metadata about the property.</param>
+ /// <returns>Property value.</returns>
+
+ if (!propertyType) {
+ propertyType = odataInferTypeFromPropertyXmlDom(domElement);
+ propertyMetadata.type = propertyType;
+ }
+
+ var isGeograhpyType = isGeographyEdmType(propertyType);
+ if (isGeograhpyType || isGeometryEdmType(propertyType)) {
+ return xmlReadODataSpatialPropertyValue(domElement, propertyType, isGeograhpyType);
+ }
+
+ if (isPrimitiveEdmType(propertyType)) {
+ return xmlReadODataEdmPropertyValue(domElement, propertyType);
+ }
+
+ if (isCollectionType(propertyType)) {
+ return xmlReadODataCollectionPropertyValue(domElement, propertyType, propertyMetadata);
+ }
+
+ return xmlReadODataComplexPropertyValue(domElement, propertyType, propertyMetadata);
+};
+
+var xmlReadODataSpatialPropertyValue = function (domElement, propertyType, isGeography) {
+ /// <summary>Reads the value of an spatial property in an OData XML document.</summary>
+ /// <param name="property">DOM element for the spatial property.</param>
+ /// <param name="propertyType" type="String">Property type name.</param>
+ /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+ /// <remarks>
+ /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+ /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
+ /// </remarks>
+ /// <returns>Spatial property value in GeoJSON format.</returns>
+
+ var gmlRoot = xmlFirstChildElement(domElement, gmlXmlNs);
+ djsassert(gmlRoot, "xmlReadODataSpatialPropertyValue - domElement doesn't have a child element that belongs to the gml namespace!!");
+
+ var value = gmlReadODataSpatialValue(gmlRoot, isGeography);
+ value.__metadata = { type: propertyType };
+ return value;
+};
+
+var xmlReadODataEdmPropertyValue = function (domNode, propertyType) {
+ /// <summary>Reads the value of an EDM property in an OData XML document.</summary>
+ /// <param name="donNode">DOM node for the EDM property.</param>
+ /// <param name="propertyType" type="String">Property type name.</param>
+ /// <returns>EDM property value.</returns>
+
+ var propertyValue = xmlNodeValue(domNode) || "";
+
+ switch (propertyType) {
+ case EDM_BOOLEAN:
+ return parseBool(propertyValue);
+ case EDM_BINARY:
+ case EDM_DECIMAL:
+ case EDM_GUID:
+ case EDM_INT64:
+ case EDM_STRING:
+ return propertyValue;
+ case EDM_BYTE:
+ case EDM_INT16:
+ case EDM_INT32:
+ case EDM_SBYTE:
+ return parseInt10(propertyValue);
+ case EDM_DOUBLE:
+ case EDM_SINGLE:
+ return parseFloat(propertyValue);
+ case EDM_TIME:
+ return parseDuration(propertyValue);
+ case EDM_DATETIME:
+ return parseDateTime(propertyValue);
+ case EDM_DATETIMEOFFSET:
+ return parseDateTimeOffset(propertyValue);
+ }
+
+ return propertyValue;
+};
+
+var xmlReadODataComplexPropertyValue = function(domElement, propertyType, propertyMetadata) {
+ /// <summary>Reads the value of a complex type property in an OData XML document.</summary>
+ /// <param name="property">DOM element for the complex type property.</param>
+ /// <param name="propertyType" type="String">Property type name.</param>
+ /// <param name="propertyMetadata" type="Object">Object that will store metadata about the property.</param>
+ /// <returns type="Object">Complex type property value.</returns>
+
+ var propertyValue = { __metadata: { type: propertyType } };
+ xmlChildElements(domElement, function(child) {
+ var childProperty = xmlReadODataProperty(child);
+ var childPropertyName = childProperty.name;
+
+ propertyMetadata.properties = propertyMetadata.properties || {};
+ propertyMetadata.properties[childPropertyName] = childProperty.metadata;
+ propertyValue[childPropertyName] = childProperty.value;
+ });
+
+ return propertyValue;
+};
+
+var xmlReadODataCollectionPropertyValue = function (domElement, propertyType, propertyMetadata) {
+ /// <summary>Reads the value of a collection property in an OData XML document.</summary>
+ /// <param name="property">DOM element for the collection property.</param>
+ /// <param name="propertyType" type="String">Property type name.</param>
+ /// <param name="propertyMetadata" type="Object">Object that will store metadata about the property.</param>
+ /// <returns type="Object">Collection property value.</returns>
+
+ var items = [];
+ var itemsMetadata = propertyMetadata.elements = [];
+ var collectionType = getCollectionType(propertyType);
+
+ xmlChildElements(domElement, function (child) {
+ if (isCollectionItemElement(child)) {
+ var itemAttributes = xmlReadODataPropertyAttributes(child);
+ var itemExtensions = itemAttributes.extensions;
+ var itemType = itemAttributes.type || collectionType;
+ var itemMetadata = makePropertyMetadata(itemType, itemExtensions);
+
+ var item = xmlReadODataPropertyValue(child, itemType, itemMetadata);
+
+ items.push(item);
+ itemsMetadata.push(itemMetadata);
+ }
+ });
+
+ return { __metadata: { type: propertyType === "Collection()" ? null : propertyType }, results: items };
+};
+
+var readODataXmlDocument = function (xmlRoot, baseURI) {
+ /// <summary>Reads an OData link(s) producing an object model in return.</summary>
+ /// <param name="xmlRoot">Top-level element to read.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the XML payload.</param>
+ /// <returns type="Object">The object model representing the specified element.</returns>
+
+ if (xmlNamespaceURI(xmlRoot) === odataXmlNs) {
+ baseURI = xmlBaseURI(xmlRoot, baseURI);
+ var localName = xmlLocalName(xmlRoot);
+
+ if (localName === "links") {
+ return readLinks(xmlRoot, baseURI);
+ }
+ if (localName === "uri") {
+ return readUri(xmlRoot, baseURI);
+ }
+ }
+ return undefined;
+};
+
+var readLinks = function (linksElement, baseURI) {
+ /// <summary>Deserializes an OData XML links element.</summary>
+ /// <param name="linksElement">XML links element.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the XML payload.</param>
+ /// <returns type="Object">A new object representing the links collection.</returns>
+
+ var uris = [];
+
+ xmlChildElements(linksElement, function (child) {
+ if (xmlLocalName(child) === "uri" && xmlNamespaceURI(child) === odataXmlNs) {
+ uris.push(readUri(child, baseURI));
+ }
+ });
+
+ return { results: uris };
+};
+
+var readUri = function (uriElement, baseURI) {
+ /// <summary>Deserializes an OData XML uri element.</summary>
+ /// <param name="uriElement">XML uri element.</param>
+ /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the XML payload.</param>
+ /// <returns type="Object">A new object representing the uri.</returns>
+
+ var uri = xmlInnerText(uriElement) || "";
+ return { uri: normalizeURI(uri, baseURI) };
+};
+
+var xmlODataInferSpatialValueGeoJsonType = function (value, edmType) {
+ /// <summary>Infers the GeoJSON type from the spatial property value and the edm type name.</summary>
+ /// <param name="value" type="Object">Spatial property value in GeoJSON format.</param>
+ /// <param name="edmType" type="String" mayBeNull="true" optional="true">Spatial property edm type.<param>
+ /// <remarks>
+ /// If the edmType parameter is null, undefined, "Edm.Geometry" or "Edm.Geography", then the function returns
+ /// the GeoJSON type indicated by the value's type property.
+ ///
+ /// If the edmType parameter is specified or is not one of the base spatial types, then it is used to
+ /// determine the GeoJSON type and the value's type property is ignored.
+ /// </remarks>
+ /// <returns>New DOM element in the GML namespace for the spatial value. </returns>
+
+ if (edmType === EDM_GEOMETRY || edmType === EDM_GEOGRAPHY) {
+ return value && value.type;
+ }
+
+ if (edmType === EDM_GEOMETRY_POINT || edmType === EDM_GEOGRAPHY_POINT) {
+ return GEOJSON_POINT;
+ }
+
+ if (edmType === EDM_GEOMETRY_LINESTRING || edmType === EDM_GEOGRAPHY_LINESTRING) {
+ return GEOJSON_LINESTRING;
+ }
+
+ if (edmType === EDM_GEOMETRY_POLYGON || edmType === EDM_GEOGRAPHY_POLYGON) {
+ return GEOJSON_POLYGON;
+ }
+
+ if (edmType === EDM_GEOMETRY_COLLECTION || edmType === EDM_GEOGRAPHY_COLLECTION) {
+ return GEOJSON_GEOMETRYCOLLECTION;
+ }
+
+ if (edmType === EDM_GEOMETRY_MULTIPOLYGON || edmType === EDM_GEOGRAPHY_MULTIPOLYGON) {
+ return GEOJSON_MULTIPOLYGON;
+ }
+
+ if (edmType === EDM_GEOMETRY_MULTILINESTRING || edmType === EDM_GEOGRAPHY_MULTILINESTRING) {
+ return GEOJSON_MULTILINESTRING;
+ }
+
+ if (edmType === EDM_GEOMETRY_MULTIPOINT || edmType === EDM_GEOGRAPHY_MULTIPOINT) {
+ return GEOJSON_MULTIPOINT;
+ }
+
+ djsassert(false, "gmlInferGeoJsonType - edm type <" + edmType + "> was unexpected!!");
+ return null;
+};
+
+var xmlNewODataMetaElement = function (dom, name, children) {
+ /// <summary>Creates a new DOM element in the OData metadata namespace.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="name" type="String">Local name of the OData metadata element to create.</param>
+ /// <param name="children" type="Array">Array containing DOM nodes or string values that will be added as children of the new DOM element.</param>
+ /// <returns>New DOM element in the OData metadata namespace.</returns>
+ /// <remarks>
+ /// If a value in the children collection is a string, then a new DOM text node is going to be created
+ /// for it and then appended as a child of the new DOM Element.
+ /// </remarks>
+
+ return xmlNewElement(dom, odataMetaXmlNs, xmlQualifiedName(odataMetaPrefix, name), children);
+};
+
+var xmlNewODataMetaAttribute = function (dom, name, value) {
+ /// <summary>Creates a new DOM attribute in the odata namespace.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="name" type="String">Local name of the OData attribute to create.</param>
+ /// <param name="value">Attribute value.</param>
+ /// <returns>New DOM attribute in the odata namespace.</returns>
+
+ return xmlNewAttribute(dom, odataMetaXmlNs, xmlQualifiedName(odataMetaPrefix, name), value);
+};
+
+var xmlNewODataElement = function (dom, name, children) {
+ /// <summary>Creates a new DOM element in the OData namespace.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="name" type="String">Local name of the OData element to create.</param>
+ /// <param name="children" type="Array">Array containing DOM nodes or string values that will be added as children of the new DOM element.</param>
+ /// <returns>New DOM element in the OData namespace.</returns>
+ /// <remarks>
+ /// If a value in the children collection is a string, then a new DOM text node is going to be created
+ /// for it and then appended as a child of the new DOM Element.
+ /// </remarks>
+
+ return xmlNewElement(dom, odataXmlNs, xmlQualifiedName(odataPrefix, name), children);
+};
+
+var xmlNewODataPrimitiveValue = function (value, typeName) {
+ /// <summary>Returns the string representation of primitive value for an OData XML document.</summary>
+ /// <param name="value">Primivite value to format.</param>
+ /// <param name="typeName" type="String" optional="true">Type name of the primitive value.</param>
+ /// <returns type="String">Formatted primitive value.</returns>
+
+ if (typeName === EDM_DATETIME || typeName === EDM_DATETIMEOFFSET || isDate(value)) {
+ return formatDateTimeOffset(value);
+ }
+ if (typeName === EDM_TIME) {
+ return formatDuration(value);
+ }
+ return value.toString();
+};
+
+var xmlNewODataElementInfo = function (domElement, dataServiceVersion) {
+ /// <summary>Creates an object that represents a new DOM element for an OData XML document and the data service version it requires.</summary>
+ /// <param name="domElement">New DOM element for an OData XML document.</param>
+ /// <param name="dataServiceVersion" type="String">Required data service version by the new DOM element.</param>
+ /// <returns type="Object">Object containing new DOM element and its required data service version.</returns>
+
+ return { element: domElement, dsv: dataServiceVersion };
+};
+
+var xmlNewODataProperty = function (dom, name, typeName, children) {
+ /// <summary>Creates a new DOM element for an entry property in an OData XML document.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="name" type="String">Property name.</param>
+ /// <param name="typeName" type="String" optional="true">Property type name.</param>
+ /// <param name="children" type="Array">Array containing DOM nodes or string values that will be added as children of the new DOM element.</param>
+ /// <remarks>
+ /// If a value in the children collection is a string, then a new DOM text node is going to be created
+ /// for it and then appended as a child of the new DOM Element.
+ /// </remarks>
+ /// <returns>New DOM element in the OData namespace for the entry property.</returns>
+
+ var typeAttribute = typeName ? xmlNewODataMetaAttribute(dom, "type", typeName) : null;
+ var property = xmlNewODataElement(dom, name, typeAttribute);
+ return xmlAppendChildren(property, children);
+};
+
+var xmlNewODataEdmProperty = function (dom, name, value, typeName) {
+ /// <summary>Creates a new DOM element for an EDM property in an OData XML document.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="name" type="String">Property name.</param>
+ /// <param name="value">Property value.</param>
+ /// <param name="typeName" type="String" optional="true">Property type name.</param>
+ /// <returns type="Object">
+ /// Object containing the new DOM element in the OData namespace for the EDM property and the
+ /// required data service version for this property.
+ /// </returns>
+
+ var propertyValue = xmlNewODataPrimitiveValue(value, typeName);
+ var property = xmlNewODataProperty(dom, name, typeName, propertyValue);
+ return xmlNewODataElementInfo(property, /*dataServiceVersion*/"1.0");
+};
+
+var xmlNewODataNullProperty = function (dom, name, typeName, model) {
+ /// <summary>Creates a new DOM element for a null property in an OData XML document.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="name" type="String">Property name.</param>
+ /// <param name="typeName" type="String" optional="true">Property type name.</param>
+ /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
+ /// <remarks>
+ /// If no typeName is specified, then it will be assumed that this is a primitive type property.
+ /// </remarks>
+ /// <returns type="Object">
+ /// Object containing the new DOM element in the OData namespace for the null property and the
+ /// required data service version for this property.
+ /// </returns>
+
+ var nullAttribute = xmlNewODataMetaAttribute(dom, "null", "true");
+ var property = xmlNewODataProperty(dom, name, typeName, nullAttribute);
+ var dataServiceVersion = lookupComplexType(typeName, model) ? "2.0" : "1.0";
+
+ return xmlNewODataElementInfo(property, dataServiceVersion);
+};
+
+var xmlNewODataCollectionProperty = function (dom, name, value, typeName, collectionMetadata, collectionModel, model) {
+ /// <summary>Creates a new DOM element for a collection property in an OData XML document.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="name" type="String">Property name.</param>
+ /// <param name="value">Property value either as an array or an object representing a collection in the library's internal representation.</param>
+ /// <param name="typeName" type="String" optional="true">Property type name.</param>
+ /// <param name="collectionMetadata" type="Object" optional="true">Object containing metadata about the collection property.</param>
+ /// <param name="collectionModel" type="Object" optional="true">Object describing the collection property in an OData conceptual schema.</param>
+ /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
+ /// <returns type="Object">
+ /// Object containing the new DOM element in the OData namespace for the collection property and the
+ /// required data service version for this property.
+ /// </returns>
+
+ var itemTypeName = getCollectionType(typeName);
+ var items = isArray(value) ? value : value.results;
+ var itemMetadata = typeName ? { type: itemTypeName} : {};
+ itemMetadata.properties = collectionMetadata.properties;
+
+ var xmlProperty = xmlNewODataProperty(dom, name, itemTypeName ? typeName : null);
+
+ var i, len;
+ for (i = 0, len = items.length; i < len; i++) {
+ var itemValue = items[i];
+ var item = xmlNewODataDataElement(dom, "element", itemValue, itemMetadata, collectionModel, model);
+
+ xmlAppendChild(xmlProperty, item.element);
+ }
+ return xmlNewODataElementInfo(xmlProperty, /*dataServiceVersion*/"3.0");
+};
+
+var xmlNewODataComplexProperty = function (dom, name, value, typeName, propertyMetadata, propertyModel, model) {
+ /// <summary>Creates a new DOM element for a complex type property in an OData XML document.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="name" type="String">Property name.</param>
+ /// <param name="value">Property value as an object in the library's internal representation.</param>
+ /// <param name="typeName" type="String" optional="true">Property type name.</param>
+ /// <param name="propertyMetadata" type="Object" optional="true">Object containing metadata about the complex type property.</param>
+ /// <param name="propertyModel" type="Object" optional="true">Object describing the complex type property in an OData conceptual schema.</param>
+ /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
+ /// <returns type="Object">
+ /// Object containing the new DOM element in the OData namespace for the complex type property and the
+ /// required data service version for this property.
+ /// </returns>
+
+ var xmlProperty = xmlNewODataProperty(dom, name, typeName);
+ var complexTypePropertiesMetadata = propertyMetadata.properties || {};
+ var complexTypeModel = lookupComplexType(typeName, model) || {};
+
+ var dataServiceVersion = "1.0";
+
+ for (var key in value) {
+ if (key !== "__metadata") {
+ var memberValue = value[key];
+ var memberModel = lookupProperty(complexTypeModel.property, key);
+ var memberMetadata = complexTypePropertiesMetadata[key] || {};
+ var member = xmlNewODataDataElement(dom, key, memberValue, memberMetadata, memberModel, model);
+
+ dataServiceVersion = maxVersion(dataServiceVersion, member.dsv);
+ xmlAppendChild(xmlProperty, member.element);
+ }
+ }
+ return xmlNewODataElementInfo(xmlProperty, dataServiceVersion);
+};
+
+var xmlNewODataSpatialProperty = function (dom, name, value, typeName, isGeography) {
+ /// <summary>Creates a new DOM element for an EDM spatial property in an OData XML document.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="name" type="String">Property name.</param>
+ /// <param name="value" type="Object">GeoJSON object containing the property value.</param>
+ /// <param name="typeName" type="String" optional="true">Property type name.</param>
+ /// <returns type="Object">
+ /// Object containing the new DOM element in the OData namespace for the EDM property and the
+ /// required data service version for this property.
+ /// </returns>
+
+ var geoJsonType = xmlODataInferSpatialValueGeoJsonType(value, typeName);
+
+ var gmlRoot = gmlNewODataSpatialValue(dom, value, geoJsonType, isGeography);
+ var xmlProperty = xmlNewODataProperty(dom, name, typeName, gmlRoot);
+
+ return xmlNewODataElementInfo(xmlProperty, "3.0");
+};
+
+var xmlNewODataDataElement = function (dom, name, value, dataItemMetadata, dataItemModel, model) {
+ /// <summary>Creates a new DOM element for a data item in an entry, complex property, or collection property.</summary>
+ /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+ /// <param name="name" type="String">Data item name.</param>
+ /// <param name="value" optional="true" mayBeNull="true">Value of the data item, if any.</param>
+ /// <param name="dataItemMetadata" type="Object" optional="true">Object containing metadata about the data item.</param>
+ /// <param name="dataItemModel" type="Object" optional="true">Object describing the data item in an OData conceptual schema.</param>
+ /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
+ /// <returns type="Object">
+ /// Object containing the new DOM element in the appropriate namespace for the data item and the
+ /// required data service version for it.
+ /// </returns>
+
+ var typeName = dataItemTypeName(value, dataItemMetadata, dataItemModel);
+ if (isPrimitive(value)) {
+ return xmlNewODataEdmProperty(dom, name, value, typeName || EDM_STRING);
+ }
+
+ var isGeography = isGeographyEdmType(typeName);
+ if (isGeography || isGeometryEdmType(typeName)) {
+ return xmlNewODataSpatialProperty(dom, name, value, typeName, isGeography);
+ }
+
+ if (isCollection(value, typeName)) {
+ return xmlNewODataCollectionProperty(dom, name, value, typeName, dataItemMetadata, dataItemModel, model);
+ }
+
+ if (isNamedStream(value)) {
+ return null;
+ }
+
+ // This may be a navigation property.
+ var navPropKind = navigationPropertyKind(value, dataItemModel);
+ if (navPropKind !== null) {
+ return null;
+ }
+
+ if (value === null) {
+ return xmlNewODataNullProperty(dom, name, typeName);
+ }
+
+ djsassert(isObject(value), "xmlNewODataEntryProperty - property '" + name + "' is not an object");
+ return xmlNewODataComplexProperty(dom, name, value, typeName, dataItemMetadata, dataItemModel, model);
+};
+
+var odataNewLinkDocument = function (data) {
+ /// <summary>Writes the specified data into an OData XML document.</summary>
+ /// <param name="data">Data to write.</param>
+ /// <returns>The root of the DOM tree built.</returns>
+
+ if (data && isObject(data)) {
+ var dom = xmlDom();
+ return xmlAppendChild(dom, xmlNewODataElement(dom, "uri", data.uri));
+ }
+ // Allow for undefined to be returned.
+};
+
+var xmlParser = function (handler, text) {
+ /// <summary>Parses an OData XML document.</summary>
+ /// <param name="handler">This handler.</param>
+ /// <param name="text" type="String">Document text.</param>
+ /// <returns>An object representation of the document; undefined if not applicable.</returns>
+
+ if (text) {
+ var doc = xmlParse(text);
+ var root = xmlFirstChildElement(doc);
+ if (root) {
+ return readODataXmlDocument(root);
+ }
+ }
+
+ // Allow for undefined to be returned.
+};
+
+var xmlSerializer = function (handler, data, context) {
+ /// <summary>Serializes an OData XML object into a document.</summary>
+ /// <param name="handler">This handler.</param>
+ /// <param name="data" type="Object">Representation of feed or entry.</param>
+ /// <param name="context" type="Object">Object with parsing context.</param>
+ /// <returns>A text representation of the data object; undefined if not applicable.</returns>
+
+ var cType = context.contentType = context.contentType || contentType(xmlMediaType);
+ if (cType && cType.mediaType === xmlMediaType) {
+ return xmlSerialize(odataNewLinkDocument(data));
+ }
+ return undefined;
+};
+
+exports.xmlHandler = odataHandler.handler(xmlParser, xmlSerializer, xmlMediaType, MAX_DATA_SERVICE_VERSION);
+
+// DATAJS INTERNAL START
+exports.adoDs = adoDs;
+exports.createAttributeExtension = createAttributeExtension;
+exports.createElementExtension = createElementExtension;
+exports.edmxNs = edmxNs;
+exports.edmNs1 = edmNs1;
+exports.edmNs1_1 = edmNs1_1;
+exports.edmNs1_2 = edmNs1_2
+exports.edmNs2a = edmNs2a;
+exports.edmNs2b = edmNs2b;
+exports.edmNs3 = edmNs3;
+exports.odataMetaXmlNs = odataMetaXmlNs;
+exports.odataMetaPrefix = odataMetaPrefix;
+exports.odataXmlNs = odataXmlNs;
+exports.odataPrefix = odataPrefix;
+exports.odataScheme = odataScheme;
+exports.odataRelatedPrefix = odataRelatedPrefix;
+exports.xmlNewODataElement = xmlNewODataElement;
+exports.xmlNewODataElementInfo = xmlNewODataElementInfo;
+exports.xmlNewODataMetaAttribute = xmlNewODataMetaAttribute;
+exports.xmlNewODataMetaElement = xmlNewODataMetaElement;
+exports.xmlNewODataDataElement = xmlNewODataDataElement;
+exports.xmlReadODataEdmPropertyValue = xmlReadODataEdmPropertyValue;
+exports.xmlReadODataProperty = xmlReadODataProperty;
+// DATAJS INTERNAL END
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/lib/store.js
----------------------------------------------------------------------
diff --git a/datajs/src/lib/store.js b/datajs/src/lib/store.js
new file mode 100644
index 0000000..1e291a0
--- /dev/null
+++ b/datajs/src/lib/store.js
@@ -0,0 +1,59 @@
+//SK name store.js
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// store.js
+
+
+
+
+exports.DomStore = DomStore = require('./store/dom.js');
+exports.IndexedDBStore = IndexedDBStore = require('./store/indexeddb.js');
+exports.MemoryStore = MemoryStore = require('./store/memory.js');
+
+// CONTENT START
+
+var mechanisms = {
+ indexeddb: IndexedDBStore,
+ dom: DomStore,
+ memory: MemoryStore
+};
+
+exports.defaultStoreMechanism = "best";
+
+exports.createStore = function (name, mechanism) {
+ /// <summary>Creates a new store object.</summary>
+ /// <param name="name" type="String">Store name.</param>
+ /// <param name="mechanism" type="String" optional="true">A specific mechanism to use (defaults to best, can be "best", "dom", "indexeddb", "webdb").</param>
+ /// <returns type="Object">Store object.</returns>
+
+ if (!mechanism) {
+ mechanism = exports.defaultStoreMechanism;
+ }
+
+ if (mechanism === "best") {
+ mechanism = (DomStore.isSupported()) ? "dom" : "memory";
+ }
+
+ var factory = mechanisms[mechanism];
+ if (factory) {
+ return factory.create(name);
+ }
+
+ throw { message: "Failed to create store", name: name, mechanism: mechanism };
+};
+
+// DATAJS INTERNAL START
+exports.mechanisms = mechanisms;
+// DATAJS INTERNAL END
+
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/lib/store/dom.js
----------------------------------------------------------------------
diff --git a/datajs/src/lib/store/dom.js b/datajs/src/lib/store/dom.js
new file mode 100644
index 0000000..f96b5ce
--- /dev/null
+++ b/datajs/src/lib/store/dom.js
@@ -0,0 +1,316 @@
+//SK name /store/store-dom.js
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// store-dom.js
+
+var utils = require('./../datajs.js').utils;
+
+// Imports.
+var throwErrorCallback = utils.throwErrorCallback;
+var delay = utils.delay;
+
+// CONTENT START
+
+var localStorage = null;
+
+var domStoreDateToJSON = function () {
+ /// <summary>Converts a Date object into an object representation friendly to JSON serialization.</summary>
+ /// <returns type="Object">Object that represents the Date.</returns>
+ /// <remarks>
+ /// This method is used to override the Date.toJSON method and is called only by
+ /// JSON.stringify. It should never be called directly.
+ /// </remarks>
+
+ var newValue = { v: this.valueOf(), t: "[object Date]" };
+ // Date objects might have extra properties on them so we save them.
+ for (var name in this) {
+ newValue[name] = this[name];
+ }
+ return newValue;
+};
+
+var domStoreJSONToDate = function (_, value) {
+ /// <summary>JSON reviver function for converting an object representing a Date in a JSON stream to a Date object</summary>
+ /// <param value="Object">Object to convert.</param>
+ /// <returns type="Date">Date object.</returns>
+ /// <remarks>
+ /// This method is used during JSON parsing and invoked only by the reviver function.
+ /// It should never be called directly.
+ /// </remarks>
+
+ if (value && value.t === "[object Date]") {
+ var newValue = new Date(value.v);
+ for (var name in value) {
+ if (name !== "t" && name !== "v") {
+ newValue[name] = value[name];
+ }
+ }
+ value = newValue;
+ }
+ return value;
+};
+
+var qualifyDomStoreKey = function (store, key) {
+ /// <summary>Qualifies the key with the name of the store.</summary>
+ /// <param name="store" type="Object">Store object whose name will be used for qualifying the key.</param>
+ /// <param name="key" type="String">Key string.</param>
+ /// <returns type="String">Fully qualified key string.</returns>
+
+ return store.name + "#!#" + key;
+};
+
+var unqualifyDomStoreKey = function (store, key) {
+ /// <summary>Gets the key part of a fully qualified key string.</summary>
+ /// <param name="store" type="Object">Store object whose name will be used for qualifying the key.</param>
+ /// <param name="key" type="String">Fully qualified key string.</param>
+ /// <returns type="String">Key part string</returns>
+
+ return key.replace(store.name + "#!#", "");
+};
+
+var DomStore = function (name) {
+ /// <summary>Constructor for store objects that use DOM storage as the underlying mechanism.</summary>
+ /// <param name="name" type="String">Store name.</param>
+ this.name = name;
+};
+
+DomStore.create = function (name) {
+ /// <summary>Creates a store object that uses DOM Storage as its underlying mechanism.</summary>
+ /// <param name="name" type="String">Store name.</param>
+ /// <returns type="Object">Store object.</returns>
+
+ if (DomStore.isSupported()) {
+ localStorage = localStorage || window.localStorage;
+ return new DomStore(name);
+ }
+
+ throw { message: "Web Storage not supported by the browser" };
+};
+
+DomStore.isSupported = function () {
+ /// <summary>Checks whether the underlying mechanism for this kind of store objects is supported by the browser.</summary>
+ /// <returns type="Boolean">True if the mechanism is supported by the browser; otherwise false.</summary>
+ return !!window.localStorage;
+};
+
+DomStore.prototype.add = function (key, value, success, error) {
+ /// <summary>Adds a new value identified by a key to the store.</summary>
+ /// <param name="key" type="String">Key string.</param>
+ /// <param name="value">Value that is going to be added to the store.</param>
+ /// <param name="success" type="Function" optional="no">Callback for a successful add operation.</param>
+ /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
+ /// <remarks>
+ /// This method errors out if the store already contains the specified key.
+ /// </remarks>
+
+ error = error || this.defaultError;
+ var store = this;
+ this.contains(key, function (contained) {
+ if (!contained) {
+ store.addOrUpdate(key, value, success, error);
+ } else {
+ delay(error, { message: "key already exists", key: key });
+ }
+ }, error);
+};
+
+DomStore.prototype.addOrUpdate = function (key, value, success, error) {
+ /// <summary>Adds or updates a value identified by a key to the store.</summary>
+ /// <param name="key" type="String">Key string.</param>
+ /// <param name="value">Value that is going to be added or updated to the store.</param>
+ /// <param name="success" type="Function" optional="no">Callback for a successful add or update operation.</param>
+ /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
+ /// <remarks>
+ /// This method will overwrite the key's current value if it already exists in the store; otherwise it simply adds the new key and value.
+ /// </remarks>
+
+ error = error || this.defaultError;
+
+ if (key instanceof Array) {
+ error({ message: "Array of keys not supported" });
+ } else {
+ var fullKey = qualifyDomStoreKey(this, key);
+ var oldDateToJSON = Date.prototype.toJSON;
+ try {
+ var storedValue = value;
+ if (storedValue !== undefined) {
+ // Dehydrate using json
+ Date.prototype.toJSON = domStoreDateToJSON;
+ storedValue = window.JSON.stringify(value);
+ }
+ // Save the json string.
+ localStorage.setItem(fullKey, storedValue);
+ delay(success, key, value);
+ }
+ catch (e) {
+ if (e.code === 22 || e.number === 0x8007000E) {
+ delay(error, { name: "QUOTA_EXCEEDED_ERR", error: e });
+ } else {
+ delay(error, e);
+ }
+ }
+ finally {
+ Date.prototype.toJSON = oldDateToJSON;
+ }
+ }
+};
+
+DomStore.prototype.clear = function (success, error) {
+ /// <summary>Removes all the data associated with this store object.</summary>
+ /// <param name="success" type="Function" optional="no">Callback for a successful clear operation.</param>
+ /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
+ /// <remarks>
+ /// In case of an error, this method will not restore any keys that might have been deleted at that point.
+ /// </remarks>
+
+ error = error || this.defaultError;
+ try {
+ var i = 0, len = localStorage.length;
+ while (len > 0 && i < len) {
+ var fullKey = localStorage.key(i);
+ var key = unqualifyDomStoreKey(this, fullKey);
+ if (fullKey !== key) {
+ localStorage.removeItem(fullKey);
+ len = localStorage.length;
+ } else {
+ i++;
+ }
+ }
+ delay(success);
+ }
+ catch (e) {
+ delay(error, e);
+ }
+};
+
+DomStore.prototype.close = function () {
+ /// <summary>This function does nothing in DomStore as it does not have a connection model</summary>
+};
+
+DomStore.prototype.contains = function (key, success, error) {
+ /// <summary>Checks whether a key exists in the store.</summary>
+ /// <param name="key" type="String">Key string.</param>
+ /// <param name="success" type="Function" optional="no">Callback indicating whether the store contains the key or not.</param>
+ /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
+ error = error || this.defaultError;
+ try {
+ var fullKey = qualifyDomStoreKey(this, key);
+ var value = localStorage.getItem(fullKey);
+ delay(success, value !== null);
+ } catch (e) {
+ delay(error, e);
+ }
+};
+
+DomStore.prototype.defaultError = throwErrorCallback;
+
+DomStore.prototype.getAllKeys = function (success, error) {
+ /// <summary>Gets all the keys that exist in the store.</summary>
+ /// <param name="success" type="Function" optional="no">Callback for a successful get operation.</param>
+ /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
+
+ error = error || this.defaultError;
+
+ var results = [];
+ var i, len;
+
+ try {
+ for (i = 0, len = localStorage.length; i < len; i++) {
+ var fullKey = localStorage.key(i);
+ var key = unqualifyDomStoreKey(this, fullKey);
+ if (fullKey !== key) {
+ results.push(key);
+ }
+ }
+ delay(success, results);
+ }
+ catch (e) {
+ delay(error, e);
+ }
+};
+
+/// <summary>Identifies the underlying mechanism used by the store.</summary>
+DomStore.prototype.mechanism = "dom";
+
+DomStore.prototype.read = function (key, success, error) {
+ /// <summary>Reads the value associated to a key in the store.</summary>
+ /// <param name="key" type="String">Key string.</param>
+ /// <param name="success" type="Function" optional="no">Callback for a successful reads operation.</param>
+ /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
+ error = error || this.defaultError;
+
+ if (key instanceof Array) {
+ error({ message: "Array of keys not supported" });
+ } else {
+ try {
+ var fullKey = qualifyDomStoreKey(this, key);
+ var value = localStorage.getItem(fullKey);
+ if (value !== null && value !== "undefined") {
+ // Hydrate using json
+ value = window.JSON.parse(value, domStoreJSONToDate);
+ }
+ else {
+ value = undefined;
+ }
+ delay(success, key, value);
+ } catch (e) {
+ delay(error, e);
+ }
+ }
+};
+
+DomStore.prototype.remove = function (key, success, error) {
+ /// <summary>Removes a key and its value from the store.</summary>
+ /// <param name="key" type="String">Key string.</param>
+ /// <param name="success" type="Function" optional="no">Callback for a successful remove operation.</param>
+ /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
+ error = error || this.defaultError;
+
+ if (key instanceof Array) {
+ error({ message: "Batches not supported" });
+ } else {
+ try {
+ var fullKey = qualifyDomStoreKey(this, key);
+ localStorage.removeItem(fullKey);
+ delay(success);
+ } catch (e) {
+ delay(error, e);
+ }
+ }
+};
+
+DomStore.prototype.update = function (key, value, success, error) {
+ /// <summary>Updates the value associated to a key in the store.</summary>
+ /// <param name="key" type="String">Key string.</param>
+ /// <param name="value">New value.</param>
+ /// <param name="success" type="Function" optional="no">Callback for a successful update operation.</param>
+ /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
+ /// <remarks>
+ /// This method errors out if the specified key is not found in the store.
+ /// </remarks>
+
+ error = error || this.defaultError;
+ var store = this;
+ this.contains(key, function (contained) {
+ if (contained) {
+ store.addOrUpdate(key, value, success, error);
+ } else {
+ delay(error, { message: "key not found", key: key });
+ }
+ }, error);
+};
+
+// DATAJS INTERNAL START
+exports.DomStore = DomStore;
+// DATAJS INTERNAL END
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/lib/store/indexeddb.js
----------------------------------------------------------------------
diff --git a/datajs/src/lib/store/indexeddb.js b/datajs/src/lib/store/indexeddb.js
new file mode 100644
index 0000000..5f6e097
--- /dev/null
+++ b/datajs/src/lib/store/indexeddb.js
@@ -0,0 +1,416 @@
+//SK name /store/store-indexeddb.js
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// store-indexeddb.js
+
+var utils = require('./../datajs.js').utils;
+
+
+// Imports.
+var throwErrorCallback = utils.throwErrorCallback;
+var delay = utils.delay;
+
+// CONTENT START
+
+var indexedDB = window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB || window.indexedDB;
+var IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange;
+var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || {};
+
+var IDBT_READ_ONLY = IDBTransaction.READ_ONLY || "readonly";
+var IDBT_READ_WRITE = IDBTransaction.READ_WRITE || "readwrite";
+
+var getError = function (error, defaultError) {
+ /// <summary>Returns either a specific error handler or the default error handler</summary>
+ /// <param name="error" type="Function">The specific error handler</param>
+ /// <param name="defaultError" type="Function">The default error handler</param>
+ /// <returns type="Function">The error callback</returns>
+
+ return function (e) {
+ var errorFunc = error || defaultError;
+ if (!errorFunc) {
+ return;
+ }
+
+ // Old api quota exceeded error support.
+ if (Object.prototype.toString.call(e) === "[object IDBDatabaseException]") {
+ if (e.code === 11 /* IndexedDb disk quota exceeded */) {
+ errorFunc({ name: "QuotaExceededError", error: e });
+ return;
+ }
+ errorFunc(e);
+ return;
+ }
+
+ var errName;
+ try {
+ var errObj = e.target.error || e;
+ errName = errObj.name;
+ } catch (ex) {
+ errName = (e.type === "blocked") ? "IndexedDBBlocked" : "UnknownError";
+ }
+ errorFunc({ name: errName, error: e });
+ };
+};
+
+var openStoreDb = function (store, success, error) {
+ /// <summary>Opens the store object's indexed db database.</summary>
+ /// <param name="store" type="IndexedDBStore">The store object</param>
+ /// <param name="success" type="Function">The success callback</param>
+ /// <param name="error" type="Function">The error callback</param>
+
+ var storeName = store.name;
+ var dbName = "_datajs_" + storeName;
+
+ var request = indexedDB.open(dbName);
+ request.onblocked = error;
+ request.onerror = error;
+
+ request.onupgradeneeded = function () {
+ var db = request.result;
+ if (!db.objectStoreNames.contains(storeName)) {
+ db.createObjectStore(storeName);
+ }
+ };
+
+ request.onsuccess = function (event) {
+ var db = request.result;
+ if (!db.objectStoreNames.contains(storeName)) {
+ // Should we use the old style api to define the database schema?
+ if ("setVersion" in db) {
+ var versionRequest = db.setVersion("1.0");
+ versionRequest.onsuccess = function () {
+ var transaction = versionRequest.transaction;
+ transaction.oncomplete = function () {
+ success(db);
+ };
+ db.createObjectStore(storeName, null, false);
+ };
+ versionRequest.onerror = error;
+ versionRequest.onblocked = error;
+ return;
+ }
+
+ // The database doesn't have the expected store.
+ // Fabricate an error object for the event for the schema mismatch
+ // and error out.
+ event.target.error = { name: "DBSchemaMismatch" };
+ error(event);
+ return;
+ }
+
+ db.onversionchange = function(event) {
+ event.target.close();
+ };
+ success(db);
+ };
+};
+
+var openTransaction = function (store, mode, success, error) {
+ /// <summary>Opens a new transaction to the store</summary>
+ /// <param name="store" type="IndexedDBStore">The store object</param>
+ /// <param name="mode" type="Short">The read/write mode of the transaction (constants from IDBTransaction)</param>
+ /// <param name="success" type="Function">The success callback</param>
+ /// <param name="error" type="Function">The error callback</param>
+
+ var storeName = store.name;
+ var storeDb = store.db;
+ var errorCallback = getError(error, store.defaultError);
+
+ if (storeDb) {
+ success(storeDb.transaction(storeName, mode));
+ return;
+ }
+
+ openStoreDb(store, function (db) {
+ store.db = db;
+ success(db.transaction(storeName, mode));
+ }, errorCallback);
+};
+
+var IndexedDBStore = function (name) {
+ /// <summary>Creates a new IndexedDBStore.</summary>
+ /// <param name="name" type="String">The name of the store.</param>
+ /// <returns type="Object">The new IndexedDBStore.</returns>
+ this.name = name;
+};
+
+IndexedDBStore.create = function (name) {
+ /// <summary>Creates a new IndexedDBStore.</summary>
+ /// <param name="name" type="String">The name of the store.</param>
+ /// <returns type="Object">The new IndexedDBStore.</returns>
+ if (IndexedDBStore.isSupported()) {
+ return new IndexedDBStore(name);
+ }
+
+ throw { message: "IndexedDB is not supported on this browser" };
+};
+
+IndexedDBStore.isSupported = function () {
+ /// <summary>Returns whether IndexedDB is supported.</summary>
+ /// <returns type="Boolean">True if IndexedDB is supported, false otherwise.</returns>
+ return !!indexedDB;
+};
+
+IndexedDBStore.prototype.add = function (key, value, success, error) {
+ /// <summary>Adds a key/value pair to the store</summary>
+ /// <param name="key" type="String">The key</param>
+ /// <param name="value" type="Object">The value</param>
+ /// <param name="success" type="Function">The success callback</param>
+ /// <param name="error" type="Function">The error callback</param>
+ var name = this.name;
+ var defaultError = this.defaultError;
+ var keys = [];
+ var values = [];
+
+ if (key instanceof Array) {
+ keys = key;
+ values = value;
+ } else {
+ keys = [key];
+ values = [value];
+ }
+
+ openTransaction(this, IDBT_READ_WRITE, function (transaction) {
+ transaction.onabort = getError(error, defaultError, key, "add");
+ transaction.oncomplete = function () {
+ if (key instanceof Array) {
+ success(keys, values);
+ } else {
+ success(key, value);
+ }
+ };
+
+ for (var i = 0; i < keys.length && i < values.length; i++) {
+ transaction.objectStore(name).add({ v: values[i] }, keys[i]);
+ }
+ }, error);
+};
+
+IndexedDBStore.prototype.addOrUpdate = function (key, value, success, error) {
+ /// <summary>Adds or updates a key/value pair in the store</summary>
+ /// <param name="key" type="String">The key</param>
+ /// <param name="value" type="Object">The value</param>
+ /// <param name="success" type="Function">The success callback</param>
+ /// <param name="error" type="Function">The error callback</param>
+ var name = this.name;
+ var defaultError = this.defaultError;
+ var keys = [];
+ var values = [];
+
+ if (key instanceof Array) {
+ keys = key;
+ values = value;
+ } else {
+ keys = [key];
+ values = [value];
+ }
+
+ openTransaction(this, IDBT_READ_WRITE, function (transaction) {
+ transaction.onabort = getError(error, defaultError);
+ transaction.oncomplete = function () {
+ if (key instanceof Array) {
+ success(keys, values);
+ } else {
+ success(key, value);
+ }
+ };
+
+ for (var i = 0; i < keys.length && i < values.length; i++) {
+ var record = { v: values[i] };
+ transaction.objectStore(name).put(record, keys[i]);
+ }
+ }, error);
+};
+
+IndexedDBStore.prototype.clear = function (success, error) {
+ /// <summary>Clears the store</summary>
+ /// <param name="success" type="Function">The success callback</param>
+ /// <param name="error" type="Function">The error callback</param>
+ var name = this.name;
+ var defaultError = this.defaultError;
+ openTransaction(this, IDBT_READ_WRITE, function (transaction) {
+ transaction.onerror = getError(error, defaultError);
+ transaction.oncomplete = function () {
+ success();
+ };
+
+ transaction.objectStore(name).clear();
+ }, error);
+};
+
+IndexedDBStore.prototype.close = function () {
+ /// <summary>Closes the connection to the database</summary>
+ if (this.db) {
+ this.db.close();
+ this.db = null;
+ }
+};
+
+IndexedDBStore.prototype.contains = function (key, success, error) {
+ /// <summary>Returns whether the store contains a key</summary>
+ /// <param name="key" type="String">The key</param>
+ /// <param name="success" type="Function">The success callback</param>
+ /// <param name="error" type="Function">The error callback</param>
+ var name = this.name;
+ var defaultError = this.defaultError;
+ openTransaction(this, IDBT_READ_ONLY, function (transaction) {
+ var objectStore = transaction.objectStore(name);
+ var request = objectStore["get"](key);
+
+ transaction.oncomplete = function () {
+ success(!!request.result);
+ };
+ transaction.onerror = getError(error, defaultError);
+ }, error);
+};
+
+IndexedDBStore.prototype.defaultError = throwErrorCallback;
+
+IndexedDBStore.prototype.getAllKeys = function (success, error) {
+ /// <summary>Gets all the keys from the store</summary>
+ /// <param name="success" type="Function">The success callback</param>
+ /// <param name="error" type="Function">The error callback</param>
+ var name = this.name;
+ var defaultError = this.defaultError;
+ openTransaction(this, IDBT_READ_WRITE, function (transaction) {
+ var results = [];
+
+ transaction.oncomplete = function () {
+ success(results);
+ };
+
+ var request = transaction.objectStore(name).openCursor();
+
+ request.onerror = getError(error, defaultError);
+ request.onsuccess = function (event) {
+ var cursor = event.target.result;
+ if (cursor) {
+ results.push(cursor.key);
+ // Some tools have issues because continue is a javascript reserved word.
+ cursor["continue"].call(cursor);
+ }
+ };
+ }, error);
+};
+
+/// <summary>Identifies the underlying mechanism used by the store.</summary>
+IndexedDBStore.prototype.mechanism = "indexeddb";
+
+IndexedDBStore.prototype.read = function (key, success, error) {
+ /// <summary>Reads the value for the specified key</summary>
+ /// <param name="key" type="String">The key</param>
+ /// <param name="success" type="Function">The success callback</param>
+ /// <param name="error" type="Function">The error callback</param>
+ /// <remarks>If the key does not exist, the success handler will be called with value = undefined</remarks>
+ var name = this.name;
+ var defaultError = this.defaultError;
+ var keys = (key instanceof Array) ? key : [key];
+
+ openTransaction(this, IDBT_READ_ONLY, function (transaction) {
+ var values = [];
+
+ transaction.onerror = getError(error, defaultError, key, "read");
+ transaction.oncomplete = function () {
+ if (key instanceof Array) {
+ success(keys, values);
+ } else {
+ success(keys[0], values[0]);
+ }
+ };
+
+ for (var i = 0; i < keys.length; i++) {
+ // Some tools have issues because get is a javascript reserved word.
+ var objectStore = transaction.objectStore(name);
+ var request = objectStore["get"].call(objectStore, keys[i]);
+ request.onsuccess = function (event) {
+ var record = event.target.result;
+ values.push(record ? record.v : undefined);
+ };
+ }
+ }, error);
+};
+
+IndexedDBStore.prototype.remove = function (key, success, error) {
+ /// <summary>Removes the specified key from the store</summary>
+ /// <param name="key" type="String">The key</param>
+ /// <param name="success" type="Function">The success callback</param>
+ /// <param name="error" type="Function">The error callback</param>
+ var name = this.name;
+ var defaultError = this.defaultError;
+ var keys = (key instanceof Array) ? key : [key];
+
+ openTransaction(this, IDBT_READ_WRITE, function (transaction) {
+ transaction.onerror = getError(error, defaultError);
+ transaction.oncomplete = function () {
+ success();
+ };
+
+ for (var i = 0; i < keys.length; i++) {
+ // Some tools have issues because continue is a javascript reserved word.
+ var objectStore = transaction.objectStore(name);
+ objectStore["delete"].call(objectStore, keys[i]);
+ }
+ }, error);
+};
+
+IndexedDBStore.prototype.update = function (key, value, success, error) {
+ /// <summary>Updates a key/value pair in the store</summary>
+ /// <param name="key" type="String">The key</param>
+ /// <param name="value" type="Object">The value</param>
+ /// <param name="success" type="Function">The success callback</param>
+ /// <param name="error" type="Function">The error callback</param>
+ var name = this.name;
+ var defaultError = this.defaultError;
+ var keys = [];
+ var values = [];
+
+ if (key instanceof Array) {
+ keys = key;
+ values = value;
+ } else {
+ keys = [key];
+ values = [value];
+ }
+
+ openTransaction(this, IDBT_READ_WRITE, function (transaction) {
+ transaction.onabort = getError(error, defaultError);
+ transaction.oncomplete = function () {
+ if (key instanceof Array) {
+ success(keys, values);
+ } else {
+ success(key, value);
+ }
+ };
+
+ for (var i = 0; i < keys.length && i < values.length; i++) {
+ var request = transaction.objectStore(name).openCursor(IDBKeyRange.only(keys[i]));
+ var record = { v: values[i] };
+ request.pair = { key: keys[i], value: record };
+ request.onsuccess = function (event) {
+ var cursor = event.target.result;
+ if (cursor) {
+ cursor.update(event.target.pair.value);
+ } else {
+ transaction.abort();
+ }
+ };
+ }
+ }, error);
+};
+
+// DATAJS INTERNAL START
+exports.IndexedDBStore = IndexedDBStore;
+// DATAJS INTERNAL END
+
+// CONTENT END
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/lib/store/memory.js
----------------------------------------------------------------------
diff --git a/datajs/src/lib/store/memory.js b/datajs/src/lib/store/memory.js
new file mode 100644
index 0000000..433f9d4
--- /dev/null
+++ b/datajs/src/lib/store/memory.js
@@ -0,0 +1,230 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// store-memory.js
+
+
+var utils = require('./../datajs.js').utils;
+
+
+// Imports.
+var throwErrorCallback = utils.throwErrorCallback;
+var delay = utils.delay;
+
+// CONTENT START
+
+var MemoryStore = function (name) {
+ /// <summary>Constructor for store objects that use a sorted array as the underlying mechanism.</summary>
+ /// <param name="name" type="String">Store name.</param>
+
+ var holes = [];
+ var items = [];
+ var keys = {};
+
+ this.name = name;
+
+ var getErrorCallback = function (error) {
+ return error || this.defaultError;
+ };
+
+ var validateKeyInput = function (key, error) {
+ /// <summary>Validates that the specified key is not undefined, not null, and not an array</summary>
+ /// <param name="key">Key value.</param>
+ /// <param name="error" type="Function">Error callback.</param>
+ /// <returns type="Boolean">True if the key is valid. False if the key is invalid and the error callback has been queued for execution.</returns>
+
+ var messageString;
+
+ if (key instanceof Array) {
+ messageString = "Array of keys not supported";
+ }
+
+ if (key === undefined || key === null) {
+ messageString = "Invalid key";
+ }
+
+ if (messageString) {
+ delay(error, { message: messageString });
+ return false;
+ }
+ return true;
+ };
+
+ this.add = function (key, value, success, error) {
+ /// <summary>Adds a new value identified by a key to the store.</summary>
+ /// <param name="key" type="String">Key string.</param>
+ /// <param name="value">Value that is going to be added to the store.</param>
+ /// <param name="success" type="Function" optional="no">Callback for a successful add operation.</param>
+ /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
+ /// <remarks>
+ /// This method errors out if the store already contains the specified key.
+ /// </remarks>
+
+ error = getErrorCallback(error);
+
+ if (validateKeyInput(key, error)) {
+ if (!keys.hasOwnProperty(key)) {
+ this.addOrUpdate(key, value, success, error);
+ } else {
+ error({ message: "key already exists", key: key });
+ }
+ }
+ };
+
+ this.addOrUpdate = function (key, value, success, error) {
+ /// <summary>Adds or updates a value identified by a key to the store.</summary>
+ /// <param name="key" type="String">Key string.</param>
+ /// <param name="value">Value that is going to be added or updated to the store.</param>
+ /// <param name="success" type="Function" optional="no">Callback for a successful add or update operation.</param>
+ /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
+ /// <remarks>
+ /// This method will overwrite the key's current value if it already exists in the store; otherwise it simply adds the new key and value.
+ /// </remarks>
+
+ error = getErrorCallback(error);
+
+ if (validateKeyInput(key, error)) {
+ var index = keys[key];
+ if (index === undefined) {
+ if (holes.length > 0) {
+ index = holes.splice(0, 1);
+ } else {
+ index = items.length;
+ }
+ }
+ items[index] = value;
+ keys[key] = index;
+ delay(success, key, value);
+ }
+ };
+
+ this.clear = function (success) {
+ /// <summary>Removes all the data associated with this store object.</summary>
+ /// <param name="success" type="Function" optional="no">Callback for a successful clear operation.</param>
+
+ items = [];
+ keys = {};
+ holes = [];
+
+ delay(success);
+ };
+
+ this.contains = function (key, success) {
+ /// <summary>Checks whether a key exists in the store.</summary>
+ /// <param name="key" type="String">Key string.</param>
+ /// <param name="success" type="Function" optional="no">Callback indicating whether the store contains the key or not.</param>
+
+ var contained = keys.hasOwnProperty(key);
+ delay(success, contained);
+ };
+
+ this.getAllKeys = function (success) {
+ /// <summary>Gets all the keys that exist in the store.</summary>
+ /// <param name="success" type="Function" optional="no">Callback for a successful get operation.</param>
+
+ var results = [];
+ for (var name in keys) {
+ results.push(name);
+ }
+ delay(success, results);
+ };
+
+ this.read = function (key, success, error) {
+ /// <summary>Reads the value associated to a key in the store.</summary>
+ /// <param name="key" type="String">Key string.</param>
+ /// <param name="success" type="Function" optional="no">Callback for a successful reads operation.</param>
+ /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
+ error = getErrorCallback(error);
+
+ if (validateKeyInput(key, error)) {
+ var index = keys[key];
+ delay(success, key, items[index]);
+ }
+ };
+
+ this.remove = function (key, success, error) {
+ /// <summary>Removes a key and its value from the store.</summary>
+ /// <param name="key" type="String">Key string.</param>
+ /// <param name="success" type="Function" optional="no">Callback for a successful remove operation.</param>
+ /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
+ error = getErrorCallback(error);
+
+ if (validateKeyInput(key, error)) {
+ var index = keys[key];
+ if (index !== undefined) {
+ if (index === items.length - 1) {
+ items.pop();
+ } else {
+ items[index] = undefined;
+ holes.push(index);
+ }
+ delete keys[key];
+
+ // The last item was removed, no need to keep track of any holes in the array.
+ if (items.length === 0) {
+ holes = [];
+ }
+ }
+
+ delay(success);
+ }
+ };
+
+ this.update = function (key, value, success, error) {
+ /// <summary>Updates the value associated to a key in the store.</summary>
+ /// <param name="key" type="String">Key string.</param>
+ /// <param name="value">New value.</param>
+ /// <param name="success" type="Function" optional="no">Callback for a successful update operation.</param>
+ /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
+ /// <remarks>
+ /// This method errors out if the specified key is not found in the store.
+ /// </remarks>
+
+ error = getErrorCallback(error);
+ if (validateKeyInput(key, error)) {
+ if (keys.hasOwnProperty(key)) {
+ this.addOrUpdate(key, value, success, error);
+ } else {
+ error({ message: "key not found", key: key });
+ }
+ }
+ };
+};
+
+MemoryStore.create = function (name) {
+ /// <summary>Creates a store object that uses memory storage as its underlying mechanism.</summary>
+ /// <param name="name" type="String">Store name.</param>
+ /// <returns type="Object">Store object.</returns>
+ return new MemoryStore(name);
+};
+
+MemoryStore.isSupported = function () {
+ /// <summary>Checks whether the underlying mechanism for this kind of store objects is supported by the browser.</summary>
+ /// <returns type="Boolean">True if the mechanism is supported by the browser; otherwise false.</returns>
+ return true;
+};
+
+MemoryStore.prototype.close = function () {
+ /// <summary>This function does nothing in MemoryStore as it does not have a connection model.</summary>
+};
+
+MemoryStore.prototype.defaultError = throwErrorCallback;
+
+/// <summary>Identifies the underlying mechanism used by the store.</summary>
+MemoryStore.prototype.mechanism = "memory";
+
+// DATAJS INTERNAL START
+exports.MemoryStore = MemoryStore;
+// DATAJS INTERNAL END
+
+ // CONTENT END
[14/15] [OLINGO-238] Build infrastructure for datajs I
Posted by ko...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/deferred.js
----------------------------------------------------------------------
diff --git a/datajs/src/deferred.js b/datajs/src/deferred.js
deleted file mode 100644
index 7f6f6a8..0000000
--- a/datajs/src/deferred.js
+++ /dev/null
@@ -1,179 +0,0 @@
-/// <reference path="odata-utils.js" />
-
-// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
-// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// deferred.js
-
-(function (window, undefined) {
-
- // CONTENT START
-
- var forwardCall = function (thisValue, name, returnValue) {
- /// <summary>Creates a new function to forward a call.</summary>
- /// <param name="thisValue" type="Object">Value to use as the 'this' object.</param>
- /// <param name="name" type="String">Name of function to forward to.</param>
- /// <param name="returnValue" type="Object">Return value for the forward call (helps keep identity when chaining calls).</param>
- /// <returns type="Function">A new function that will forward a call.</returns>
-
- return function () {
- thisValue[name].apply(thisValue, arguments);
- return returnValue;
- };
- };
-
- var DjsDeferred = function () {
- /// <summary>Initializes a new DjsDeferred object.</summary>
- /// <remarks>
- /// Compability Note A - Ordering of callbacks through chained 'then' invocations
- ///
- /// The Wiki entry at http://wiki.commonjs.org/wiki/Promises/A
- /// implies that .then() returns a distinct object.
- ////
- /// For compatibility with http://api.jquery.com/category/deferred-object/
- /// we return this same object. This affects ordering, as
- /// the jQuery version will fire callbacks in registration
- /// order regardless of whether they occur on the result
- /// or the original object.
- ///
- /// Compability Note B - Fulfillment value
- ///
- /// The Wiki entry at http://wiki.commonjs.org/wiki/Promises/A
- /// implies that the result of a success callback is the
- /// fulfillment value of the object and is received by
- /// other success callbacks that are chained.
- ///
- /// For compatibility with http://api.jquery.com/category/deferred-object/
- /// we disregard this value instead.
- /// </remarks>
-
- this._arguments = undefined;
- this._done = undefined;
- this._fail = undefined;
- this._resolved = false;
- this._rejected = false;
- };
-
- DjsDeferred.prototype = {
- then: function (fulfilledHandler, errorHandler /*, progressHandler */) {
- /// <summary>Adds success and error callbacks for this deferred object.</summary>
- /// <param name="fulfilledHandler" type="Function" mayBeNull="true" optional="true">Success callback.</param>
- /// <param name="errorHandler" type="Function" mayBeNull="true" optional="true">Error callback.</param>
- /// <remarks>See Compatibility Note A.</remarks>
-
- if (fulfilledHandler) {
- if (!this._done) {
- this._done = [fulfilledHandler];
- } else {
- this._done.push(fulfilledHandler);
- }
- }
-
- if (errorHandler) {
- if (!this._fail) {
- this._fail = [errorHandler];
- } else {
- this._fail.push(errorHandler);
- }
- }
-
- //// See Compatibility Note A in the DjsDeferred constructor.
- //// if (!this._next) {
- //// this._next = createDeferred();
- //// }
- //// return this._next.promise();
-
- if (this._resolved) {
- this.resolve.apply(this, this._arguments);
- } else if (this._rejected) {
- this.reject.apply(this, this._arguments);
- }
-
- return this;
- },
-
- resolve: function (/* args */) {
- /// <summary>Invokes success callbacks for this deferred object.</summary>
- /// <remarks>All arguments are forwarded to success callbacks.</remarks>
-
-
- if (this._done) {
- var i, len;
- for (i = 0, len = this._done.length; i < len; i++) {
- //// See Compability Note B - Fulfillment value.
- //// var nextValue =
- this._done[i].apply(null, arguments);
- }
-
- //// See Compatibility Note A in the DjsDeferred constructor.
- //// this._next.resolve(nextValue);
- //// delete this._next;
-
- this._done = undefined;
- this._resolved = false;
- this._arguments = undefined;
- } else {
- this._resolved = true;
- this._arguments = arguments;
- }
- },
-
- reject: function (/* args */) {
- /// <summary>Invokes error callbacks for this deferred object.</summary>
- /// <remarks>All arguments are forwarded to error callbacks.</remarks>
- if (this._fail) {
- var i, len;
- for (i = 0, len = this._fail.length; i < len; i++) {
- this._fail[i].apply(null, arguments);
- }
-
- this._fail = undefined;
- this._rejected = false;
- this._arguments = undefined;
- } else {
- this._rejected = true;
- this._arguments = arguments;
- }
- },
-
- promise: function () {
- /// <summary>Returns a version of this object that has only the read-only methods available.</summary>
- /// <returns>An object with only the promise object.</returns>
-
- var result = {};
- result.then = forwardCall(this, "then", result);
- return result;
- }
- };
-
- var createDeferred = function () {
- /// <summary>Creates a deferred object.</summary>
- /// <returns type="DjsDeferred">
- /// A new deferred object. If jQuery is installed, then a jQuery
- /// Deferred object is returned, which provides a superset of features.
- /// </returns>
-
- if (window.jQuery && window.jQuery.Deferred) {
- return new window.jQuery.Deferred();
- } else {
- return new DjsDeferred();
- }
- };
-
- // DATAJS INTERNAL START
- window.datajs.createDeferred = createDeferred;
- window.datajs.DjsDeferred = DjsDeferred;
- // DATAJS INTERNAL END
-
- // CONTENT END
-})(this);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/index.js
----------------------------------------------------------------------
diff --git a/datajs/src/index.js b/datajs/src/index.js
new file mode 100644
index 0000000..2079d66
--- /dev/null
+++ b/datajs/src/index.js
@@ -0,0 +1,22 @@
+
+
+window.dataJS = require('./lib/datajs.js');
+window.OData = require('./lib/odata.js');
+
+
+extend(window.OData, require('./lib/store.js'));
+extend(window.OData, require('./lib/cache.js'));
+
+
+
+function extend(target) {
+ var sources = [].slice.call(arguments, 1);
+ sources.forEach(function (source) {
+ for (var prop in source) {
+ target[prop] = source[prop];
+ }
+ });
+ return target;
+}
+
+
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/lib/cache.js
----------------------------------------------------------------------
diff --git a/datajs/src/lib/cache.js b/datajs/src/lib/cache.js
new file mode 100644
index 0000000..9f5d28f
--- /dev/null
+++ b/datajs/src/lib/cache.js
@@ -0,0 +1,1351 @@
+//SK name cache.js
+/// <reference path="odata-utils.js" />
+
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// cache.js
+
+
+exports.storeReq = require("./store.js");
+
+var utils = require('./datajs.js').utils;
+
+
+var assigned = utils.assigned;
+var delay = utils.delay;
+var extend = utils.extend;
+var djsassert = utils.djsassert;
+var isArray = utils.isArray;
+var normalizeURI = utils.normalizeURI;
+var parseInt10 = utils.parseInt10;
+var undefinedDefault = utils.undefinedDefault;
+
+var deferred = require('./datajs/deferred.js');
+var createDeferred = deferred.createDeferred;
+var DjsDeferred = deferred.DjsDeferred;
+var ODataCacheSource = require('./cache/source').ODataCacheSource;
+
+// CONTENT START
+
+var appendPage = function (operation, page) {
+ /// <summary>Appends a page's data to the operation data.</summary>
+ /// <param name="operation" type="Object">Operation with (i)ndex, (c)ount and (d)ata.</param>
+ /// <param name="page" type="Object">Page with (i)ndex, (c)ount and (d)ata.</param>
+
+ var intersection = intersectRanges(operation, page);
+ if (intersection) {
+ var start = intersection.i - page.i;
+ var end = start + (operation.c - operation.d.length);
+ operation.d = operation.d.concat(page.d.slice(start, end));
+ }
+};
+
+var intersectRanges = function (x, y) {
+ /// <summary>Returns the {(i)ndex, (c)ount} range for the intersection of x and y.</summary>
+ /// <param name="x" type="Object">Range with (i)ndex and (c)ount members.</param>
+ /// <param name="y" type="Object">Range with (i)ndex and (c)ount members.</param>
+ /// <returns type="Object">The intersection (i)ndex and (c)ount; undefined if there is no intersection.</returns>
+
+ var xLast = x.i + x.c;
+ var yLast = y.i + y.c;
+ var resultIndex = (x.i > y.i) ? x.i : y.i;
+ var resultLast = (xLast < yLast) ? xLast : yLast;
+ var result;
+ if (resultLast >= resultIndex) {
+ result = { i: resultIndex, c: resultLast - resultIndex };
+ }
+
+ return result;
+};
+
+var checkZeroGreater = function (val, name) {
+ /// <summary>Checks whether val is a defined number with value zero or greater.</summary>
+ /// <param name="val" type="Number">Value to check.</param>
+ /// <param name="name" type="String">Parameter name to use in exception.</param>
+
+ if (val === undefined || typeof val !== "number") {
+ throw { message: "'" + name + "' must be a number." };
+ }
+
+ if (isNaN(val) || val < 0 || !isFinite(val)) {
+ throw { message: "'" + name + "' must be greater than or equal to zero." };
+ }
+};
+
+var checkUndefinedGreaterThanZero = function (val, name) {
+ /// <summary>Checks whether val is undefined or a number with value greater than zero.</summary>
+ /// <param name="val" type="Number">Value to check.</param>
+ /// <param name="name" type="String">Parameter name to use in exception.</param>
+
+ if (val !== undefined) {
+ if (typeof val !== "number") {
+ throw { message: "'" + name + "' must be a number." };
+ }
+
+ if (isNaN(val) || val <= 0 || !isFinite(val)) {
+ throw { message: "'" + name + "' must be greater than zero." };
+ }
+ }
+};
+
+var checkUndefinedOrNumber = function (val, name) {
+ /// <summary>Checks whether val is undefined or a number</summary>
+ /// <param name="val" type="Number">Value to check.</param>
+ /// <param name="name" type="String">Parameter name to use in exception.</param>
+ if (val !== undefined && (typeof val !== "number" || isNaN(val) || !isFinite(val))) {
+ throw { message: "'" + name + "' must be a number." };
+ }
+};
+
+var removeFromArray = function (arr, item) {
+ /// <summary>Performs a linear search on the specified array and removes the first instance of 'item'.</summary>
+ /// <param name="arr" type="Array">Array to search.</param>
+ /// <param name="item">Item being sought.</param>
+ /// <returns type="Boolean">Whether the item was removed.</returns>
+
+ var i, len;
+ for (i = 0, len = arr.length; i < len; i++) {
+ if (arr[i] === item) {
+ arr.splice(i, 1);
+ return true;
+ }
+ }
+
+ return false;
+};
+
+var estimateSize = function (obj) {
+ /// <summary>Estimates the size of an object in bytes.</summary>
+ /// <param name="obj" type="Object">Object to determine the size of.</param>
+ /// <returns type="Integer">Estimated size of the object in bytes.</returns>
+ var size = 0;
+ var type = typeof obj;
+
+ if (type === "object" && obj) {
+ for (var name in obj) {
+ size += name.length * 2 + estimateSize(obj[name]);
+ }
+ } else if (type === "string") {
+ size = obj.length * 2;
+ } else {
+ size = 8;
+ }
+ return size;
+};
+
+var snapToPageBoundaries = function (lowIndex, highIndex, pageSize) {
+ /// <summary>Snaps low and high indices into page sizes and returns a range.</summary>
+ /// <param name="lowIndex" type="Number">Low index to snap to a lower value.</param>
+ /// <param name="highIndex" type="Number">High index to snap to a higher value.</param>
+ /// <param name="pageSize" type="Number">Page size to snap to.</param>
+ /// <returns type="Object">A range with (i)ndex and (c)ount of elements.</returns>
+
+ lowIndex = Math.floor(lowIndex / pageSize) * pageSize;
+ highIndex = Math.ceil((highIndex + 1) / pageSize) * pageSize;
+ return { i: lowIndex, c: highIndex - lowIndex };
+};
+
+// The DataCache is implemented using state machines. The following constants are used to properly
+// identify and label the states that these machines transition to.
+
+// DataCache state constants
+
+var CACHE_STATE_DESTROY = "destroy";
+var CACHE_STATE_IDLE = "idle";
+var CACHE_STATE_INIT = "init";
+var CACHE_STATE_READ = "read";
+var CACHE_STATE_PREFETCH = "prefetch";
+var CACHE_STATE_WRITE = "write";
+
+// DataCacheOperation state machine states.
+// Transitions on operations also depend on the cache current of the cache.
+
+var OPERATION_STATE_CANCEL = "cancel";
+var OPERATION_STATE_END = "end";
+var OPERATION_STATE_ERROR = "error";
+var OPERATION_STATE_START = "start";
+var OPERATION_STATE_WAIT = "wait";
+
+// Destroy state machine states
+
+var DESTROY_STATE_CLEAR = "clear";
+
+// Read / Prefetch state machine states
+
+var READ_STATE_DONE = "done";
+var READ_STATE_LOCAL = "local";
+var READ_STATE_SAVE = "save";
+var READ_STATE_SOURCE = "source";
+
+var DataCacheOperation = function (stateMachine, promise, isCancelable, index, count, data, pending) {
+ /// <summary>Creates a new operation object.</summary>
+ /// <param name="stateMachine" type="Function">State machine that describes the specific behavior of the operation.</param>
+ /// <param name="promise" type ="DjsDeferred">Promise for requested values.</param>
+ /// <param name="isCancelable" type ="Boolean">Whether this operation can be canceled or not.</param>
+ /// <param name="index" type="Number">Index of first item requested.</param>
+ /// <param name="count" type="Number">Count of items requested.</param>
+ /// <param name="data" type="Array">Array with the items requested by the operation.</param>
+ /// <param name="pending" type="Number">Total number of pending prefetch records.</param>
+ /// <returns type="DataCacheOperation">A new data cache operation instance.</returns>
+
+ /// <field name="p" type="DjsDeferred">Promise for requested values.</field>
+ /// <field name="i" type="Number">Index of first item requested.</field>
+ /// <field name="c" type="Number">Count of items requested.</field>
+ /// <field name="d" type="Array">Array with the items requested by the operation.</field>
+ /// <field name="s" type="Array">Current state of the operation.</field>
+ /// <field name="canceled" type="Boolean">Whether the operation has been canceled.</field>
+ /// <field name="pending" type="Number">Total number of pending prefetch records.</field>
+ /// <field name="oncomplete" type="Function">Callback executed when the operation reaches the end state.</field>
+
+ var stateData;
+ var cacheState;
+ var that = this;
+
+ that.p = promise;
+ that.i = index;
+ that.c = count;
+ that.d = data;
+ that.s = OPERATION_STATE_START;
+
+ that.canceled = false;
+ that.pending = pending;
+ that.oncomplete = null;
+
+ that.cancel = function () {
+ /// <summary>Transitions this operation to the cancel state and sets the canceled flag to true.</summary>
+ /// <remarks>The function is a no-op if the operation is non-cancelable.</summary>
+
+ if (!isCancelable) {
+ return;
+ }
+
+ var state = that.s;
+ if (state !== OPERATION_STATE_ERROR && state !== OPERATION_STATE_END && state !== OPERATION_STATE_CANCEL) {
+ that.canceled = true;
+ transition(OPERATION_STATE_CANCEL, stateData);
+ }
+ };
+
+ that.complete = function () {
+ /// <summary>Transitions this operation to the end state.</summary>
+
+ djsassert(that.s !== OPERATION_STATE_END, "DataCacheOperation.complete() - operation is in the end state", that);
+ transition(OPERATION_STATE_END, stateData);
+ };
+
+ that.error = function (err) {
+ /// <summary>Transitions this operation to the error state.</summary>
+ if (!that.canceled) {
+ djsassert(that.s !== OPERATION_STATE_END, "DataCacheOperation.error() - operation is in the end state", that);
+ djsassert(that.s !== OPERATION_STATE_ERROR, "DataCacheOperation.error() - operation is in the error state", that);
+ transition(OPERATION_STATE_ERROR, err);
+ }
+ };
+
+ that.run = function (state) {
+ /// <summary>Executes the operation's current state in the context of a new cache state.</summary>
+ /// <param name="state" type="Object">New cache state.</param>
+
+ cacheState = state;
+ that.transition(that.s, stateData);
+ };
+
+ that.wait = function (data) {
+ /// <summary>Transitions this operation to the wait state.</summary>
+
+ djsassert(that.s !== OPERATION_STATE_END, "DataCacheOperation.wait() - operation is in the end state", that);
+ transition(OPERATION_STATE_WAIT, data);
+ };
+
+ var operationStateMachine = function (opTargetState, cacheState, data) {
+ /// <summary>State machine that describes all operations common behavior.</summary>
+ /// <param name="opTargetState" type="Object">Operation state to transition to.</param>
+ /// <param name="cacheState" type="Object">Current cache state.</param>
+ /// <param name="data" type="Object" optional="true">Additional data passed to the state.</param>
+
+ switch (opTargetState) {
+ case OPERATION_STATE_START:
+ // Initial state of the operation. The operation will remain in this state until the cache has been fully initialized.
+ if (cacheState !== CACHE_STATE_INIT) {
+ stateMachine(that, opTargetState, cacheState, data);
+ }
+ break;
+
+ case OPERATION_STATE_WAIT:
+ // Wait state indicating that the operation is active but waiting for an asynchronous operation to complete.
+ stateMachine(that, opTargetState, cacheState, data);
+ break;
+
+ case OPERATION_STATE_CANCEL:
+ // Cancel state.
+ stateMachine(that, opTargetState, cacheState, data);
+ that.fireCanceled();
+ transition(OPERATION_STATE_END);
+ break;
+
+ case OPERATION_STATE_ERROR:
+ // Error state. Data is expected to be an object detailing the error condition.
+ stateMachine(that, opTargetState, cacheState, data);
+ that.canceled = true;
+ that.fireRejected(data);
+ transition(OPERATION_STATE_END);
+ break;
+
+ case OPERATION_STATE_END:
+ // Final state of the operation.
+ if (that.oncomplete) {
+ that.oncomplete(that);
+ }
+ if (!that.canceled) {
+ that.fireResolved();
+ }
+ stateMachine(that, opTargetState, cacheState, data);
+ break;
+
+ default:
+ // Any other state is passed down to the state machine describing the operation's specific behavior.
+ // DATAJS INTERNAL START
+ if (true) {
+ // Check that the state machine actually handled the sate.
+ var handled = stateMachine(that, opTargetState, cacheState, data);
+ djsassert(handled, "Bad operation state: " + opTargetState + " cacheState: " + cacheState, this);
+ } else {
+ // DATAJS INTERNAL END
+ stateMachine(that, opTargetState, cacheState, data);
+ // DATAJS INTERNAL START
+ }
+ // DATAJS INTERNAL END
+ break;
+ }
+ };
+
+ var transition = function (state, data) {
+ /// <summary>Transitions this operation to a new state.</summary>
+ /// <param name="state" type="Object">State to transition the operation to.</param>
+ /// <param name="data" type="Object" optional="true">Additional data passed to the state.</param>
+
+ that.s = state;
+ stateData = data;
+ operationStateMachine(state, cacheState, data);
+ };
+
+ that.transition = transition;
+
+ return that;
+};
+
+DataCacheOperation.prototype.fireResolved = function () {
+ /// <summary>Fires a resolved notification as necessary.</summary>
+
+ // Fire the resolve just once.
+ var p = this.p;
+ if (p) {
+ this.p = null;
+ p.resolve(this.d);
+ }
+};
+
+DataCacheOperation.prototype.fireRejected = function (reason) {
+ /// <summary>Fires a rejected notification as necessary.</summary>
+
+ // Fire the rejection just once.
+ var p = this.p;
+ if (p) {
+ this.p = null;
+ p.reject(reason);
+ }
+};
+
+DataCacheOperation.prototype.fireCanceled = function () {
+ /// <summary>Fires a canceled notification as necessary.</summary>
+
+ this.fireRejected({ canceled: true, message: "Operation canceled" });
+};
+
+
+var DataCache = function (options) {
+ /// <summary>Creates a data cache for a collection that is efficiently loaded on-demand.</summary>
+ /// <param name="options">
+ /// Options for the data cache, including name, source, pageSize,
+ /// prefetchSize, cacheSize, storage mechanism, and initial prefetch and local-data handler.
+ /// </param>
+ /// <returns type="DataCache">A new data cache instance.</returns>
+
+ var state = CACHE_STATE_INIT;
+ var stats = { counts: 0, netReads: 0, prefetches: 0, cacheReads: 0 };
+
+ var clearOperations = [];
+ var readOperations = [];
+ var prefetchOperations = [];
+
+ var actualCacheSize = 0; // Actual cache size in bytes.
+ var allDataLocal = false; // Whether all data is local.
+ var cacheSize = undefinedDefault(options.cacheSize, 1048576); // Requested cache size in bytes, default 1 MB.
+ var collectionCount = 0; // Number of elements in the server collection.
+ var highestSavedPage = 0; // Highest index of all the saved pages.
+ var highestSavedPageSize = 0; // Item count of the saved page with the highest index.
+ var overflowed = cacheSize === 0; // If the cache has overflowed (actualCacheSize > cacheSize or cacheSize == 0);
+ var pageSize = undefinedDefault(options.pageSize, 50); // Number of elements to store per page.
+ var prefetchSize = undefinedDefault(options.prefetchSize, pageSize); // Number of elements to prefetch from the source when the cache is idling.
+ var version = "1.0";
+ var cacheFailure;
+
+ var pendingOperations = 0;
+
+ var source = options.source;
+ if (typeof source === "string") {
+ // Create a new cache source.
+ source = new ODataCacheSource(options);
+ }
+ source.options = options;
+
+ // Create a cache local store.
+ var store = storeReq.createStore(options.name, options.mechanism);
+
+ var that = this;
+
+ that.onidle = options.idle;
+ that.stats = stats;
+
+ that.count = function () {
+ /// <summary>Counts the number of items in the collection.</summary>
+ /// <returns type="Object">A promise with the number of items.</returns>
+
+ if (cacheFailure) {
+ throw cacheFailure;
+ }
+
+ var deferred = createDeferred();
+ var canceled = false;
+
+ if (allDataLocal) {
+ delay(function () {
+ deferred.resolve(collectionCount);
+ });
+
+ return deferred.promise();
+ }
+
+ // TODO: Consider returning the local data count instead once allDataLocal flag is set to true.
+ var request = source.count(function (count) {
+ request = null;
+ stats.counts++;
+ deferred.resolve(count);
+ }, function (err) {
+ request = null;
+ deferred.reject(extend(err, { canceled: canceled }));
+ });
+
+ return extend(deferred.promise(), {
+ cancel: function () {
+ /// <summary>Aborts the count operation.</summary>
+ if (request) {
+ canceled = true;
+ request.abort();
+ request = null;
+ }
+ }
+ });
+ };
+
+ that.clear = function () {
+ /// <summary>Cancels all running operations and clears all local data associated with this cache.</summary>
+ /// <remarks>
+ /// New read requests made while a clear operation is in progress will not be canceled.
+ /// Instead they will be queued for execution once the operation is completed.
+ /// </remarks>
+ /// <returns type="Object">A promise that has no value and can't be canceled.</returns>
+
+ if (cacheFailure) {
+ throw cacheFailure;
+ }
+
+ if (clearOperations.length === 0) {
+ var deferred = createDeferred();
+ var op = new DataCacheOperation(destroyStateMachine, deferred, false);
+ queueAndStart(op, clearOperations);
+ return deferred.promise();
+ }
+ return clearOperations[0].p;
+ };
+
+ that.filterForward = function (index, count, predicate) {
+ /// <summary>Filters the cache data based a predicate.</summary>
+ /// <param name="index" type="Number">The index of the item to start filtering forward from.</param>
+ /// <param name="count" type="Number">Maximum number of items to include in the result.</param>
+ /// <param name="predicate" type="Function">Callback function returning a boolean that determines whether an item should be included in the result or not.</param>
+ /// <remarks>
+ /// Specifying a negative count value will yield all the items in the cache that satisfy the predicate.
+ /// </remarks>
+ /// <returns type="DjsDeferred">A promise for an array of results.</returns>
+ return filter(index, count, predicate, false);
+ };
+
+ that.filterBack = function (index, count, predicate) {
+ /// <summary>Filters the cache data based a predicate.</summary>
+ /// <param name="index" type="Number">The index of the item to start filtering backward from.</param>
+ /// <param name="count" type="Number">Maximum number of items to include in the result.</param>
+ /// <param name="predicate" type="Function">Callback function returning a boolean that determines whether an item should be included in the result or not.</param>
+ /// <remarks>
+ /// Specifying a negative count value will yield all the items in the cache that satisfy the predicate.
+ /// </remarks>
+ /// <returns type="DjsDeferred">A promise for an array of results.</returns>
+ return filter(index, count, predicate, true);
+ };
+
+ that.readRange = function (index, count) {
+ /// <summary>Reads a range of adjacent records.</summary>
+ /// <param name="index" type="Number">Zero-based index of record range to read.</param>
+ /// <param name="count" type="Number">Number of records in the range.</param>
+ /// <remarks>
+ /// New read requests made while a clear operation is in progress will not be canceled.
+ /// Instead they will be queued for execution once the operation is completed.
+ /// </remarks>
+ /// <returns type="DjsDeferred">
+ /// A promise for an array of records; less records may be returned if the
+ /// end of the collection is found.
+ /// </returns>
+
+ checkZeroGreater(index, "index");
+ checkZeroGreater(count, "count");
+
+ if (cacheFailure) {
+ throw cacheFailure;
+ }
+
+ var deferred = createDeferred();
+
+ // Merging read operations would be a nice optimization here.
+ var op = new DataCacheOperation(readStateMachine, deferred, true, index, count, [], 0);
+ queueAndStart(op, readOperations);
+
+ return extend(deferred.promise(), {
+ cancel: function () {
+ /// <summary>Aborts the readRange operation.</summary>
+ op.cancel();
+ }
+ });
+ };
+
+ that.ToObservable = that.toObservable = function () {
+ /// <summary>Creates an Observable object that enumerates all the cache contents.</summary>
+ /// <returns>A new Observable object that enumerates all the cache contents.</returns>
+ if (!window.Rx || !window.Rx.Observable) {
+ throw { message: "Rx library not available - include rx.js" };
+ }
+
+ if (cacheFailure) {
+ throw cacheFailure;
+ }
+
+ return window.Rx.Observable.CreateWithDisposable(function (obs) {
+ var disposed = false;
+ var index = 0;
+
+ var errorCallback = function (error) {
+ if (!disposed) {
+ obs.OnError(error);
+ }
+ };
+
+ var successCallback = function (data) {
+ if (!disposed) {
+ var i, len;
+ for (i = 0, len = data.length; i < len; i++) {
+ // The wrapper automatically checks for Dispose
+ // on the observer, so we don't need to check it here.
+ obs.OnNext(data[i]);
+ }
+
+ if (data.length < pageSize) {
+ obs.OnCompleted();
+ } else {
+ index += pageSize;
+ that.readRange(index, pageSize).then(successCallback, errorCallback);
+ }
+ }
+ };
+
+ that.readRange(index, pageSize).then(successCallback, errorCallback);
+
+ return { Dispose: function () { disposed = true; } };
+ });
+ };
+
+ var cacheFailureCallback = function (message) {
+ /// <summary>Creates a function that handles a callback by setting the cache into failure mode.</summary>
+ /// <param name="message" type="String">Message text.</param>
+ /// <returns type="Function">Function to use as error callback.</returns>
+ /// <remarks>
+ /// This function will specifically handle problems with critical store resources
+ /// during cache initialization.
+ /// </remarks>
+
+ return function (error) {
+ cacheFailure = { message: message, error: error };
+
+ // Destroy any pending clear or read operations.
+ // At this point there should be no prefetch operations.
+ // Count operations will go through but are benign because they
+ // won't interact with the store.
+ djsassert(prefetchOperations.length === 0, "prefetchOperations.length === 0");
+ var i, len;
+ for (i = 0, len = readOperations.length; i < len; i++) {
+ readOperations[i].fireRejected(cacheFailure);
+ }
+ for (i = 0, len = clearOperations.length; i < len; i++) {
+ clearOperations[i].fireRejected(cacheFailure);
+ }
+
+ // Null out the operation arrays.
+ readOperations = clearOperations = null;
+ };
+ };
+
+ var changeState = function (newState) {
+ /// <summary>Updates the cache's state and signals all pending operations of the change.</summary>
+ /// <param name="newState" type="Object">New cache state.</param>
+ /// <remarks>This method is a no-op if the cache's current state and the new state are the same.</remarks>
+
+ if (newState !== state) {
+ state = newState;
+ var operations = clearOperations.concat(readOperations, prefetchOperations);
+ var i, len;
+ for (i = 0, len = operations.length; i < len; i++) {
+ operations[i].run(state);
+ }
+ }
+ };
+
+ var clearStore = function () {
+ /// <summary>Removes all the data stored in the cache.</summary>
+ /// <returns type="DjsDeferred">A promise with no value.</returns>
+ djsassert(state === CACHE_STATE_DESTROY || state === CACHE_STATE_INIT, "DataCache.clearStore() - cache is not on the destroy or initialize state, current sate = " + state);
+
+ var deferred = new DjsDeferred();
+ store.clear(function () {
+
+ // Reset the cache settings.
+ actualCacheSize = 0;
+ allDataLocal = false;
+ collectionCount = 0;
+ highestSavedPage = 0;
+ highestSavedPageSize = 0;
+ overflowed = cacheSize === 0;
+
+ // version is not reset, in case there is other state in eg V1.1 that is still around.
+
+ // Reset the cache stats.
+ stats = { counts: 0, netReads: 0, prefetches: 0, cacheReads: 0 };
+ that.stats = stats;
+
+ store.close();
+ deferred.resolve();
+ }, function (err) {
+ deferred.reject(err);
+ });
+ return deferred;
+ };
+
+ var dequeueOperation = function (operation) {
+ /// <summary>Removes an operation from the caches queues and changes the cache state to idle.</summary>
+ /// <param name="operation" type="DataCacheOperation">Operation to dequeue.</param>
+ /// <remarks>This method is used as a handler for the operation's oncomplete event.</remarks>
+
+ var removed = removeFromArray(clearOperations, operation);
+ if (!removed) {
+ removed = removeFromArray(readOperations, operation);
+ if (!removed) {
+ removeFromArray(prefetchOperations, operation);
+ }
+ }
+
+ pendingOperations--;
+ changeState(CACHE_STATE_IDLE);
+ };
+
+ var fetchPage = function (start) {
+ /// <summary>Requests data from the cache source.</summary>
+ /// <param name="start" type="Number">Zero-based index of items to request.</param>
+ /// <returns type="DjsDeferred">A promise for a page object with (i)ndex, (c)ount, (d)ata.</returns>
+
+ djsassert(state !== CACHE_STATE_DESTROY, "DataCache.fetchPage() - cache is on the destroy state");
+ djsassert(state !== CACHE_STATE_IDLE, "DataCache.fetchPage() - cache is on the idle state");
+
+ var deferred = new DjsDeferred();
+ var canceled = false;
+
+ var request = source.read(start, pageSize, function (data) {
+ var page = { i: start, c: data.length, d: data };
+ deferred.resolve(page);
+ }, function (err) {
+ deferred.reject(err);
+ });
+
+ return extend(deferred, {
+ cancel: function () {
+ if (request) {
+ request.abort();
+ canceled = true;
+ request = null;
+ }
+ }
+ });
+ };
+
+ var filter = function (index, count, predicate, backwards) {
+ /// <summary>Filters the cache data based a predicate.</summary>
+ /// <param name="index" type="Number">The index of the item to start filtering from.</param>
+ /// <param name="count" type="Number">Maximum number of items to include in the result.</param>
+ /// <param name="predicate" type="Function">Callback function returning a boolean that determines whether an item should be included in the result or not.</param>
+ /// <param name="backwards" type="Boolean">True if the filtering should move backward from the specified index, falsey otherwise.</param>
+ /// <remarks>
+ /// Specifying a negative count value will yield all the items in the cache that satisfy the predicate.
+ /// </remarks>
+ /// <returns type="DjsDeferred">A promise for an array of results.</returns>
+ index = parseInt10(index);
+ count = parseInt10(count);
+
+ if (isNaN(index)) {
+ throw { message: "'index' must be a valid number.", index: index };
+ }
+ if (isNaN(count)) {
+ throw { message: "'count' must be a valid number.", count: count };
+ }
+
+ if (cacheFailure) {
+ throw cacheFailure;
+ }
+
+ index = Math.max(index, 0);
+
+ var deferred = createDeferred();
+ var arr = [];
+ var canceled = false;
+ var pendingReadRange = null;
+
+ var readMore = function (readIndex, readCount) {
+ if (!canceled) {
+ if (count >= 0 && arr.length >= count) {
+ deferred.resolve(arr);
+ } else {
+ pendingReadRange = that.readRange(readIndex, readCount).then(function (data) {
+ for (var i = 0, length = data.length; i < length && (count < 0 || arr.length < count); i++) {
+ var dataIndex = backwards ? length - i - 1 : i;
+ var item = data[dataIndex];
+ if (predicate(item)) {
+ var element = {
+ index: readIndex + dataIndex,
+ item: item
+ };
+
+ backwards ? arr.unshift(element) : arr.push(element);
+ }
+ }
+
+ // Have we reached the end of the collection?
+ if ((!backwards && data.length < readCount) || (backwards && readIndex <= 0)) {
+ deferred.resolve(arr);
+ } else {
+ var nextIndex = backwards ? Math.max(readIndex - pageSize, 0) : readIndex + readCount;
+ readMore(nextIndex, pageSize);
+ }
+ }, function (err) {
+ deferred.reject(err);
+ });
+ }
+ }
+ };
+
+ // Initially, we read from the given starting index to the next/previous page boundary
+ var initialPage = snapToPageBoundaries(index, index, pageSize);
+ var initialIndex = backwards ? initialPage.i : index;
+ var initialCount = backwards ? index - initialPage.i + 1 : initialPage.i + initialPage.c - index;
+ readMore(initialIndex, initialCount);
+
+ return extend(deferred.promise(), {
+ cancel: function () {
+ /// <summary>Aborts the filter operation</summary>
+ if (pendingReadRange) {
+ pendingReadRange.cancel();
+ }
+ canceled = true;
+ }
+ });
+ };
+
+ var fireOnIdle = function () {
+ /// <summary>Fires an onidle event if any functions are assigned.</summary>
+
+ if (that.onidle && pendingOperations === 0) {
+ that.onidle();
+ }
+ };
+
+ var prefetch = function (start) {
+ /// <summary>Creates and starts a new prefetch operation.</summary>
+ /// <param name="start" type="Number">Zero-based index of the items to prefetch.</param>
+ /// <remarks>
+ /// This method is a no-op if any of the following conditions is true:
+ /// 1.- prefetchSize is 0
+ /// 2.- All data has been read and stored locally in the cache.
+ /// 3.- There is already an all data prefetch operation queued.
+ /// 4.- The cache has run out of available space (overflowed).
+ /// <remarks>
+
+ if (allDataLocal || prefetchSize === 0 || overflowed) {
+ return;
+ }
+
+ djsassert(state === CACHE_STATE_READ, "DataCache.prefetch() - cache is not on the read state, current state: " + state);
+
+ if (prefetchOperations.length === 0 || (prefetchOperations[0] && prefetchOperations[0].c !== -1)) {
+ // Merging prefetch operations would be a nice optimization here.
+ var op = new DataCacheOperation(prefetchStateMachine, null, true, start, prefetchSize, null, prefetchSize);
+ queueAndStart(op, prefetchOperations);
+ }
+ };
+
+ var queueAndStart = function (op, queue) {
+ /// <summary>Queues an operation and runs it.</summary>
+ /// <param name="op" type="DataCacheOperation">Operation to queue.</param>
+ /// <param name="queue" type="Array">Array that will store the operation.</param>
+
+ op.oncomplete = dequeueOperation;
+ queue.push(op);
+ pendingOperations++;
+ op.run(state);
+ };
+
+ var readPage = function (key) {
+ /// <summary>Requests a page from the cache local store.</summary>
+ /// <param name="key" type="Number">Zero-based index of the reuqested page.</param>
+ /// <returns type="DjsDeferred">A promise for a found flag and page object with (i)ndex, (c)ount, (d)ata, and (t)icks.</returns>
+
+ djsassert(state !== CACHE_STATE_DESTROY, "DataCache.readPage() - cache is on the destroy state");
+
+ var canceled = false;
+ var deferred = extend(new DjsDeferred(), {
+ cancel: function () {
+ /// <summary>Aborts the readPage operation.</summary>
+ canceled = true;
+ }
+ });
+
+ var error = storeFailureCallback(deferred, "Read page from store failure");
+
+ store.contains(key, function (contained) {
+ if (canceled) {
+ return;
+ }
+ if (contained) {
+ store.read(key, function (_, data) {
+ if (!canceled) {
+ deferred.resolve(data !== undefined, data);
+ }
+ }, error);
+ return;
+ }
+ deferred.resolve(false);
+ }, error);
+ return deferred;
+ };
+
+ var savePage = function (key, page) {
+ /// <summary>Saves a page to the cache local store.</summary>
+ /// <param name="key" type="Number">Zero-based index of the requested page.</param>
+ /// <param name="page" type="Object">Object with (i)ndex, (c)ount, (d)ata, and (t)icks.</param>
+ /// <returns type="DjsDeferred">A promise with no value.</returns>
+
+ djsassert(state !== CACHE_STATE_DESTROY, "DataCache.savePage() - cache is on the destroy state");
+ djsassert(state !== CACHE_STATE_IDLE, "DataCache.savePage() - cache is on the idle state");
+
+ var canceled = false;
+
+ var deferred = extend(new DjsDeferred(), {
+ cancel: function () {
+ /// <summary>Aborts the readPage operation.</summary>
+ canceled = true;
+ }
+ });
+
+ var error = storeFailureCallback(deferred, "Save page to store failure");
+
+ var resolve = function () {
+ deferred.resolve(true);
+ };
+
+ if (page.c > 0) {
+ var pageBytes = estimateSize(page);
+ overflowed = cacheSize >= 0 && cacheSize < actualCacheSize + pageBytes;
+
+ if (!overflowed) {
+ store.addOrUpdate(key, page, function () {
+ updateSettings(page, pageBytes);
+ saveSettings(resolve, error);
+ }, error);
+ } else {
+ resolve();
+ }
+ } else {
+ updateSettings(page, 0);
+ saveSettings(resolve, error);
+ }
+ return deferred;
+ };
+
+ var saveSettings = function (success, error) {
+ /// <summary>Saves the cache's current settings to the local store.</summary>
+ /// <param name="success" type="Function">Success callback.</param>
+ /// <param name="error" type="Function">Errror callback.</param>
+
+ var settings = {
+ actualCacheSize: actualCacheSize,
+ allDataLocal: allDataLocal,
+ cacheSize: cacheSize,
+ collectionCount: collectionCount,
+ highestSavedPage: highestSavedPage,
+ highestSavedPageSize: highestSavedPageSize,
+ pageSize: pageSize,
+ sourceId: source.identifier,
+ version: version
+ };
+
+ store.addOrUpdate("__settings", settings, success, error);
+ };
+
+ var storeFailureCallback = function (deferred/*, message*/) {
+ /// <summary>Creates a function that handles a store error.</summary>
+ /// <param name="deferred" type="DjsDeferred">Deferred object to resolve.</param>
+ /// <param name="message" type="String">Message text.</param>
+ /// <returns type="Function">Function to use as error callback.</returns>
+ /// <remarks>
+ /// This function will specifically handle problems when interacting with the store.
+ /// </remarks>
+
+ return function (/*error*/) {
+ // var console = window.console;
+ // if (console && console.log) {
+ // console.log(message);
+ // console.dir(error);
+ // }
+ deferred.resolve(false);
+ };
+ };
+
+ var updateSettings = function (page, pageBytes) {
+ /// <summary>Updates the cache's settings based on a page object.</summary>
+ /// <param name="page" type="Object">Object with (i)ndex, (c)ount, (d)ata.</param>
+ /// <param name="pageBytes" type="Number">Size of the page in bytes.</param>
+
+ var pageCount = page.c;
+ var pageIndex = page.i;
+
+ // Detect the collection size.
+ if (pageCount === 0) {
+ if (highestSavedPage === pageIndex - pageSize) {
+ collectionCount = highestSavedPage + highestSavedPageSize;
+ }
+ } else {
+ highestSavedPage = Math.max(highestSavedPage, pageIndex);
+ if (highestSavedPage === pageIndex) {
+ highestSavedPageSize = pageCount;
+ }
+ actualCacheSize += pageBytes;
+ if (pageCount < pageSize && !collectionCount) {
+ collectionCount = pageIndex + pageCount;
+ }
+ }
+
+ // Detect the end of the collection.
+ if (!allDataLocal && collectionCount === highestSavedPage + highestSavedPageSize) {
+ allDataLocal = true;
+ }
+ };
+
+ var cancelStateMachine = function (operation, opTargetState, cacheState, data) {
+ /// <summary>State machine describing the behavior for cancelling a read or prefetch operation.</summary>
+ /// <param name="operation" type="DataCacheOperation">Operation being run.</param>
+ /// <param name="opTargetState" type="Object">Operation state to transition to.</param>
+ /// <param name="cacheState" type="Object">Current cache state.</param>
+ /// <param name="data" type="Object" optional="true">Additional data passed to the state.</param>
+ /// <remarks>
+ /// This state machine contains behavior common to read and prefetch operations.
+ /// </remarks>
+
+ var canceled = operation.canceled && opTargetState !== OPERATION_STATE_END;
+ if (canceled) {
+ if (opTargetState === OPERATION_STATE_CANCEL) {
+ // Cancel state.
+ // Data is expected to be any pending request made to the cache.
+ if (data && data.cancel) {
+ data.cancel();
+ }
+ }
+ }
+ return canceled;
+ };
+
+ var destroyStateMachine = function (operation, opTargetState, cacheState) {
+ /// <summary>State machine describing the behavior of a clear operation.</summary>
+ /// <param name="operation" type="DataCacheOperation">Operation being run.</param>
+ /// <param name="opTargetState" type="Object">Operation state to transition to.</param>
+ /// <param name="cacheState" type="Object">Current cache state.</param>
+ /// <remarks>
+ /// Clear operations have the highest priority and can't be interrupted by other operations; however,
+ /// they will preempt any other operation currently executing.
+ /// </remarks>
+
+ var transition = operation.transition;
+
+ // Signal the cache that a clear operation is running.
+ if (cacheState !== CACHE_STATE_DESTROY) {
+ changeState(CACHE_STATE_DESTROY);
+ return true;
+ }
+
+ switch (opTargetState) {
+ case OPERATION_STATE_START:
+ // Initial state of the operation.
+ transition(DESTROY_STATE_CLEAR);
+ break;
+
+ case OPERATION_STATE_END:
+ // State that signals the operation is done.
+ fireOnIdle();
+ break;
+
+ case DESTROY_STATE_CLEAR:
+ // State that clears all the local data of the cache.
+ clearStore().then(function () {
+ // Terminate the operation once the local store has been cleared.
+ operation.complete();
+ });
+ // Wait until the clear request completes.
+ operation.wait();
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+ };
+
+ var prefetchStateMachine = function (operation, opTargetState, cacheState, data) {
+ /// <summary>State machine describing the behavior of a prefetch operation.</summary>
+ /// <param name="operation" type="DataCacheOperation">Operation being run.</param>
+ /// <param name="opTargetState" type="Object">Operation state to transition to.</param>
+ /// <param name="cacheState" type="Object">Current cache state.</param>
+ /// <param name="data" type="Object" optional="true">Additional data passed to the state.</param>
+ /// <remarks>
+ /// Prefetch operations have the lowest priority and will be interrupted by operations of
+ /// other kinds. A preempted prefetch operation will resume its execution only when the state
+ /// of the cache returns to idle.
+ ///
+ /// If a clear operation starts executing then all the prefetch operations are canceled,
+ /// even if they haven't started executing yet.
+ /// </remarks>
+
+ // Handle cancelation
+ if (!cancelStateMachine(operation, opTargetState, cacheState, data)) {
+
+ var transition = operation.transition;
+
+ // Handle preemption
+ if (cacheState !== CACHE_STATE_PREFETCH) {
+ if (cacheState === CACHE_STATE_DESTROY) {
+ if (opTargetState !== OPERATION_STATE_CANCEL) {
+ operation.cancel();
+ }
+ } else if (cacheState === CACHE_STATE_IDLE) {
+ // Signal the cache that a prefetch operation is running.
+ changeState(CACHE_STATE_PREFETCH);
+ }
+ return true;
+ }
+
+ switch (opTargetState) {
+ case OPERATION_STATE_START:
+ // Initial state of the operation.
+ if (prefetchOperations[0] === operation) {
+ transition(READ_STATE_LOCAL, operation.i);
+ }
+ break;
+
+ case READ_STATE_DONE:
+ // State that determines if the operation can be resolved or has to
+ // continue processing.
+ // Data is expected to be the read page.
+ var pending = operation.pending;
+
+ if (pending > 0) {
+ pending -= Math.min(pending, data.c);
+ }
+
+ // Are we done, or has all the data been stored?
+ if (allDataLocal || pending === 0 || data.c < pageSize || overflowed) {
+ operation.complete();
+ } else {
+ // Continue processing the operation.
+ operation.pending = pending;
+ transition(READ_STATE_LOCAL, data.i + pageSize);
+ }
+ break;
+
+ default:
+ return readSaveStateMachine(operation, opTargetState, cacheState, data, true);
+ }
+ }
+ return true;
+ };
+
+ var readStateMachine = function (operation, opTargetState, cacheState, data) {
+ /// <summary>State machine describing the behavior of a read operation.</summary>
+ /// <param name="operation" type="DataCacheOperation">Operation being run.</param>
+ /// <param name="opTargetState" type="Object">Operation state to transition to.</param>
+ /// <param name="cacheState" type="Object">Current cache state.</param>
+ /// <param name="data" type="Object" optional="true">Additional data passed to the state.</param>
+ /// <remarks>
+ /// Read operations have a higher priority than prefetch operations, but lower than
+ /// clear operations. They will preempt any prefetch operation currently running
+ /// but will be interrupted by a clear operation.
+ ///
+ /// If a clear operation starts executing then all the currently running
+ /// read operations are canceled. Read operations that haven't started yet will
+ /// wait in the start state until the destory operation finishes.
+ /// </remarks>
+
+ // Handle cancelation
+ if (!cancelStateMachine(operation, opTargetState, cacheState, data)) {
+
+ var transition = operation.transition;
+
+ // Handle preemption
+ if (cacheState !== CACHE_STATE_READ && opTargetState !== OPERATION_STATE_START) {
+ if (cacheState === CACHE_STATE_DESTROY) {
+ if (opTargetState !== OPERATION_STATE_START) {
+ operation.cancel();
+ }
+ } else if (cacheState !== CACHE_STATE_WRITE) {
+ // Signal the cache that a read operation is running.
+ djsassert(state == CACHE_STATE_IDLE || state === CACHE_STATE_PREFETCH, "DataCache.readStateMachine() - cache is not on the read or idle state.");
+ changeState(CACHE_STATE_READ);
+ }
+
+ return true;
+ }
+
+ switch (opTargetState) {
+ case OPERATION_STATE_START:
+ // Initial state of the operation.
+ // Wait until the cache is idle or prefetching.
+ if (cacheState === CACHE_STATE_IDLE || cacheState === CACHE_STATE_PREFETCH) {
+ // Signal the cache that a read operation is running.
+ changeState(CACHE_STATE_READ);
+ if (operation.c > 0) {
+ // Snap the requested range to a page boundary.
+ var range = snapToPageBoundaries(operation.i, operation.c, pageSize);
+ transition(READ_STATE_LOCAL, range.i);
+ } else {
+ transition(READ_STATE_DONE, operation);
+ }
+ }
+ break;
+
+ case READ_STATE_DONE:
+ // State that determines if the operation can be resolved or has to
+ // continue processing.
+ // Data is expected to be the read page.
+ appendPage(operation, data);
+ var len = operation.d.length;
+ // Are we done?
+ if (operation.c === len || data.c < pageSize) {
+ // Update the stats, request for a prefetch operation.
+ stats.cacheReads++;
+ prefetch(data.i + data.c);
+ // Terminate the operation.
+ operation.complete();
+ } else {
+ // Continue processing the operation.
+ transition(READ_STATE_LOCAL, data.i + pageSize);
+ }
+ break;
+
+ default:
+ return readSaveStateMachine(operation, opTargetState, cacheState, data, false);
+ }
+ }
+
+ return true;
+ };
+
+ var readSaveStateMachine = function (operation, opTargetState, cacheState, data, isPrefetch) {
+ /// <summary>State machine describing the behavior for reading and saving data into the cache.</summary>
+ /// <param name="operation" type="DataCacheOperation">Operation being run.</param>
+ /// <param name="opTargetState" type="Object">Operation state to transition to.</param>
+ /// <param name="cacheState" type="Object">Current cache state.</param>
+ /// <param name="data" type="Object" optional="true">Additional data passed to the state.</param>
+ /// <param name="isPrefetch" type="Boolean">Flag indicating whether a read (false) or prefetch (true) operation is running.
+ /// <remarks>
+ /// This state machine contains behavior common to read and prefetch operations.
+ /// </remarks>
+
+ var error = operation.error;
+ var transition = operation.transition;
+ var wait = operation.wait;
+ var request;
+
+ switch (opTargetState) {
+ case OPERATION_STATE_END:
+ // State that signals the operation is done.
+ fireOnIdle();
+ break;
+
+ case READ_STATE_LOCAL:
+ // State that requests for a page from the local store.
+ // Data is expected to be the index of the page to request.
+ request = readPage(data).then(function (found, page) {
+ // Signal the cache that a read operation is running.
+ if (!operation.canceled) {
+ if (found) {
+ // The page is in the local store, check if the operation can be resolved.
+ transition(READ_STATE_DONE, page);
+ } else {
+ // The page is not in the local store, request it from the source.
+ transition(READ_STATE_SOURCE, data);
+ }
+ }
+ });
+ break;
+
+ case READ_STATE_SOURCE:
+ // State that requests for a page from the cache source.
+ // Data is expected to be the index of the page to request.
+ request = fetchPage(data).then(function (page) {
+ // Signal the cache that a read operation is running.
+ if (!operation.canceled) {
+ // Update the stats and save the page to the local store.
+ if (isPrefetch) {
+ stats.prefetches++;
+ } else {
+ stats.netReads++;
+ }
+ transition(READ_STATE_SAVE, page);
+ }
+ }, error);
+ break;
+
+ case READ_STATE_SAVE:
+ // State that saves a page to the local store.
+ // Data is expected to be the page to save.
+ // Write access to the store is exclusive.
+ if (cacheState !== CACHE_STATE_WRITE) {
+ changeState(CACHE_STATE_WRITE);
+ request = savePage(data.i, data).then(function (saved) {
+ if (!operation.canceled) {
+ if (!saved && isPrefetch) {
+ operation.pending = 0;
+ }
+ // Check if the operation can be resolved.
+ transition(READ_STATE_DONE, data);
+ }
+ changeState(CACHE_STATE_IDLE);
+ });
+ }
+ break;
+
+ default:
+ // Unknown state that can't be handled by this state machine.
+ return false;
+ }
+
+ if (request) {
+ // The operation might have been canceled between stack frames do to the async calls.
+ if (operation.canceled) {
+ request.cancel();
+ } else if (operation.s === opTargetState) {
+ // Wait for the request to complete.
+ wait(request);
+ }
+ }
+
+ return true;
+ };
+
+ // Initialize the cache.
+ store.read("__settings", function (_, settings) {
+ if (assigned(settings)) {
+ var settingsVersion = settings.version;
+ if (!settingsVersion || settingsVersion.indexOf("1.") !== 0) {
+ cacheFailureCallback("Unsupported cache store version " + settingsVersion)();
+ return;
+ }
+
+ if (pageSize !== settings.pageSize || source.identifier !== settings.sourceId) {
+ // The shape or the source of the data was changed so invalidate the store.
+ clearStore().then(function () {
+ // Signal the cache is fully initialized.
+ changeState(CACHE_STATE_IDLE);
+ }, cacheFailureCallback("Unable to clear store during initialization"));
+ } else {
+ // Restore the saved settings.
+ actualCacheSize = settings.actualCacheSize;
+ allDataLocal = settings.allDataLocal;
+ cacheSize = settings.cacheSize;
+ collectionCount = settings.collectionCount;
+ highestSavedPage = settings.highestSavedPage;
+ highestSavedPageSize = settings.highestSavedPageSize;
+ version = settingsVersion;
+
+ // Signal the cache is fully initialized.
+ changeState(CACHE_STATE_IDLE);
+ }
+ } else {
+ // This is a brand new cache.
+ saveSettings(function () {
+ // Signal the cache is fully initialized.
+ changeState(CACHE_STATE_IDLE);
+ }, cacheFailureCallback("Unable to write settings during initialization."));
+ }
+ }, cacheFailureCallback("Unable to read settings from store."));
+
+ return that;
+};
+
+exports.createDataCache = function (options) {
+ /// <summary>Creates a data cache for a collection that is efficiently loaded on-demand.</summary>
+ /// <param name="options">
+ /// Options for the data cache, including name, source, pageSize,
+ /// prefetchSize, cacheSize, storage mechanism, and initial prefetch and local-data handler.
+ /// </param>
+ /// <returns type="DataCache">A new data cache instance.</returns>
+ checkUndefinedGreaterThanZero(options.pageSize, "pageSize");
+ checkUndefinedOrNumber(options.cacheSize, "cacheSize");
+ checkUndefinedOrNumber(options.prefetchSize, "prefetchSize");
+
+ if (!assigned(options.name)) {
+ throw { message: "Undefined or null name", options: options };
+ }
+
+ if (!assigned(options.source)) {
+ throw { message: "Undefined source", options: options };
+ }
+
+ return new DataCache(options);
+};
+
+// DATAJS INTERNAL START
+//window.datajs.estimateSize = estimateSize;
+exports.estimateSize = estimateSize;
+// DATAJS INTERNAL END
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/lib/cache/source.js
----------------------------------------------------------------------
diff --git a/datajs/src/lib/cache/source.js b/datajs/src/lib/cache/source.js
new file mode 100644
index 0000000..bcb61de
--- /dev/null
+++ b/datajs/src/lib/cache/source.js
@@ -0,0 +1,182 @@
+//SK name /cache/cache-source.js
+/// <reference path="odata-utils.js" />
+
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// cache-source.js
+
+var utils = require("./../datajs.js").utils;
+var odataRequest = require("./../odata.js").request;
+
+var parseInt10 = utils.parseInt10;
+var normalizeURICase = utils.normalizeURICase;
+
+// CONTENT START
+
+var appendQueryOption = function (uri, queryOption) {
+ /// <summary>Appends the specified escaped query option to the specified URI.</summary>
+ /// <param name="uri" type="String">URI to append option to.</param>
+ /// <param name="queryOption" type="String">Escaped query option to append.</param>
+ var separator = (uri.indexOf("?") >= 0) ? "&" : "?";
+ return uri + separator + queryOption;
+};
+
+var appendSegment = function (uri, segment) {
+ /// <summary>Appends the specified segment to the given URI.</summary>
+ /// <param name="uri" type="String">URI to append a segment to.</param>
+ /// <param name="segment" type="String">Segment to append.</param>
+ /// <returns type="String">The original URI with a new segment appended.</returns>
+
+ var index = uri.indexOf("?");
+ var queryPortion = "";
+ if (index >= 0) {
+ queryPortion = uri.substr(index);
+ uri = uri.substr(0, index);
+ }
+
+ if (uri[uri.length - 1] !== "/") {
+ uri += "/";
+ }
+ return uri + segment + queryPortion;
+};
+
+var buildODataRequest = function (uri, options) {
+ /// <summary>Builds a request object to GET the specified URI.</summary>
+ /// <param name="uri" type="String">URI for request.</param>
+ /// <param name="options" type="Object">Additional options.</param>
+
+ return {
+ method: "GET",
+ requestUri: uri,
+ user: options.user,
+ password: options.password,
+ enableJsonpCallback: options.enableJsonpCallback,
+ callbackParameterName: options.callbackParameterName,
+ formatQueryString: options.formatQueryString
+ };
+};
+
+var findQueryOptionStart = function (uri, name) {
+ /// <summary>Finds the index where the value of a query option starts.</summary>
+ /// <param name="uri" type="String">URI to search in.</param>
+ /// <param name="name" type="String">Name to look for.</param>
+ /// <returns type="Number">The index where the query option starts.</returns>
+
+ var result = -1;
+ var queryIndex = uri.indexOf("?");
+ if (queryIndex !== -1) {
+ var start = uri.indexOf("?" + name + "=", queryIndex);
+ if (start === -1) {
+ start = uri.indexOf("&" + name + "=", queryIndex);
+ }
+ if (start !== -1) {
+ result = start + name.length + 2;
+ }
+ }
+ return result;
+};
+
+var queryForData = function (uri, options, success, error) {
+ /// <summary>Gets data from an OData service.</summary>
+ /// <param name="uri" type="String">URI to the OData service.</param>
+ /// <param name="options" type="Object">Object with additional well-known request options.</param>
+ /// <param name="success" type="Function">Success callback.</param>
+ /// <param name="error" type="Function">Error callback.</param>
+ /// <returns type="Object">Object with an abort method.</returns>
+
+ var request = queryForDataInternal(uri, options, [], success, error);
+ return request;
+};
+
+var queryForDataInternal = function (uri, options, data, success, error) {
+ /// <summary>Gets data from an OData service taking into consideration server side paging.</summary>
+ /// <param name="uri" type="String">URI to the OData service.</param>
+ /// <param name="options" type="Object">Object with additional well-known request options.</param>
+ /// <param name="data" type="Array">Array that stores the data provided by the OData service.</param>
+ /// <param name="success" type="Function">Success callback.</param>
+ /// <param name="error" type="Function">Error callback.</param>
+ /// <returns type="Object">Object with an abort method.</returns>
+
+ var request = buildODataRequest(uri, options);
+ var currentRequest = oRta_request.request(request, function (newData) {
+ var next = newData.__next;
+ var results = newData.results;
+
+ data = data.concat(results);
+
+ if (next) {
+ currentRequest = queryForDataInternal(next, options, data, success, error);
+ } else {
+ success(data);
+ }
+ }, error, undefined, options.httpClient, options.metadata);
+
+ return {
+ abort: function () {
+ currentRequest.abort();
+ }
+ };
+};
+
+var ODataCacheSource = function (options) {
+ /// <summary>Creates a data cache source object for requesting data from an OData service.</summary>
+ /// <param name="options">Options for the cache data source.</param>
+ /// <returns type="ODataCacheSource">A new data cache source instance.</returns>
+
+ var that = this;
+ var uri = options.source;
+
+ that.identifier = normalizeURICase(encodeURI(decodeURI(uri)));
+ that.options = options;
+
+ that.count = function (success, error) {
+ /// <summary>Gets the number of items in the collection.</summary>
+ /// <param name="success" type="Function">Success callback with the item count.</param>
+ /// <param name="error" type="Function">Error callback.</param>
+ /// <returns type="Object">Request object with an abort method./<param>
+
+ var options = that.options;
+ return odataRequest.request(
+ buildODataRequest(appendSegment(uri, "$count"), options),
+ function (data) {
+ var count = parseInt10(data.toString());
+ if (isNaN(count)) {
+ error({ message: "Count is NaN", count: count });
+ } else {
+ success(count);
+ }
+ }, error, undefined, options.httpClient, options.metadata);
+ };
+
+ that.read = function (index, count, success, error) {
+ /// <summary>Gets a number of consecutive items from the collection.</summary>
+ /// <param name="index" type="Number">Zero-based index of the items to retrieve.</param>
+ /// <param name="count" type="Number">Number of items to retrieve.</param>
+ /// <param name="success" type="Function">Success callback with the requested items.</param>
+ /// <param name="error" type="Function">Error callback.</param>
+ /// <returns type="Object">Request object with an abort method./<param>
+
+ var queryOptions = "$skip=" + index + "&$top=" + count;
+ return queryForData(appendQueryOption(uri, queryOptions), that.options, success, error);
+ };
+
+ return that;
+};
+
+// DATAJS INTERNAL START
+exports.ODataCacheSource = ODataCacheSource;
+//window.datajs.ODataCacheSource = ODataCacheSource;
+// DATAJS INTERNAL END
+
+// CONTENT END
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/lib/datajs.js
----------------------------------------------------------------------
diff --git a/datajs/src/lib/datajs.js b/datajs/src/lib/datajs.js
new file mode 100644
index 0000000..eef7a68
--- /dev/null
+++ b/datajs/src/lib/datajs.js
@@ -0,0 +1,95 @@
+//SK name datajs.js
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// datajs.js
+
+//var utils = require('./lib/utils.js');
+//var xml = require('./lib/xml.js');
+//var deferred = require('./lib/deferred.js');
+//var odata = require('./lib/odata.js');
+
+
+//expose all external usable functions via self.apiFunc = function
+exports.version = {
+ major: 0,
+ minor: 0,
+ build: 0
+};
+
+
+exports.deferred = require('./datajs/deferred.js');
+exports.utils = require('./datajs/utils.js');
+exports.xml = require('./datajs/xml.js');
+
+
+/*
+function extend(target) {
+ var sources = [].slice.call(arguments, 1);
+ sources.forEach(function (source) {
+ for (var prop in source) {
+ target[prop] = source[prop];
+ }
+ });
+ return target;
+}
+*/
+
+
+/*
+(function (window, undefined) {
+
+ var datajs = window.datajs || {};
+ var odata = window.OData || {};
+
+ // AMD support
+ if (typeof define === 'function' && define.amd) {
+ define('datajs', datajs);
+ define('OData', odata);
+ } else {
+ window.datajs = datajs;
+ window.OData = odata;
+ }
+
+ datajs.version = {
+ major: 1,
+ minor: 1,
+ build: 1
+ };
+
+ // INCLUDE: utils.js
+ // INCLUDE: xml.js
+
+ // INCLUDE: deferred.js
+
+ // INCLUDE: odata-utils.js
+ // INCLUDE: odata-net.js
+ // INCLUDE: odata-handler.js
+ // INCLUDE: odata-gml.js
+ // INCLUDE: odata-xml.js
+ // INCLUDE: odata-atom.js
+ // INCLUDE: odata-metadata.js
+ // INCLUDE: odata-json-light.js
+ // INCLUDE: odata-json.js
+ // INCLUDE: odata-batch.js
+ // INCLUDE: odata.js
+
+ // INCLUDE: store-dom.js
+ // INCLUDE: store-indexeddb.js
+ // INCLUDE: store-memory.js
+ // INCLUDE: store.js
+
+ // INCLUDE: cache-source.js
+ // INCLUDE: cache.js
+
+})(this);*/
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/lib/datajs/deferred.js
----------------------------------------------------------------------
diff --git a/datajs/src/lib/datajs/deferred.js b/datajs/src/lib/datajs/deferred.js
new file mode 100644
index 0000000..e73b2f9
--- /dev/null
+++ b/datajs/src/lib/datajs/deferred.js
@@ -0,0 +1,178 @@
+//SK name deferred.js
+/// <reference path="odata-utils.js" />
+
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// deferred.js
+
+
+// CONTENT START
+
+var forwardCall = function (thisValue, name, returnValue) {
+ /// <summary>Creates a new function to forward a call.</summary>
+ /// <param name="thisValue" type="Object">Value to use as the 'this' object.</param>
+ /// <param name="name" type="String">Name of function to forward to.</param>
+ /// <param name="returnValue" type="Object">Return value for the forward call (helps keep identity when chaining calls).</param>
+ /// <returns type="Function">A new function that will forward a call.</returns>
+
+ return function () {
+ thisValue[name].apply(thisValue, arguments);
+ return returnValue;
+ };
+};
+
+var DjsDeferred = function () {
+ /// <summary>Initializes a new DjsDeferred object.</summary>
+ /// <remarks>
+ /// Compability Note A - Ordering of callbacks through chained 'then' invocations
+ ///
+ /// The Wiki entry at http://wiki.commonjs.org/wiki/Promises/A
+ /// implies that .then() returns a distinct object.
+ ////
+ /// For compatibility with http://api.jquery.com/category/deferred-object/
+ /// we return this same object. This affects ordering, as
+ /// the jQuery version will fire callbacks in registration
+ /// order regardless of whether they occur on the result
+ /// or the original object.
+ ///
+ /// Compability Note B - Fulfillment value
+ ///
+ /// The Wiki entry at http://wiki.commonjs.org/wiki/Promises/A
+ /// implies that the result of a success callback is the
+ /// fulfillment value of the object and is received by
+ /// other success callbacks that are chained.
+ ///
+ /// For compatibility with http://api.jquery.com/category/deferred-object/
+ /// we disregard this value instead.
+ /// </remarks>
+
+ this._arguments = undefined;
+ this._done = undefined;
+ this._fail = undefined;
+ this._resolved = false;
+ this._rejected = false;
+};
+
+DjsDeferred.prototype = {
+ then: function (fulfilledHandler, errorHandler /*, progressHandler */) {
+ /// <summary>Adds success and error callbacks for this deferred object.</summary>
+ /// <param name="fulfilledHandler" type="Function" mayBeNull="true" optional="true">Success callback.</param>
+ /// <param name="errorHandler" type="Function" mayBeNull="true" optional="true">Error callback.</param>
+ /// <remarks>See Compatibility Note A.</remarks>
+
+ if (fulfilledHandler) {
+ if (!this._done) {
+ this._done = [fulfilledHandler];
+ } else {
+ this._done.push(fulfilledHandler);
+ }
+ }
+
+ if (errorHandler) {
+ if (!this._fail) {
+ this._fail = [errorHandler];
+ } else {
+ this._fail.push(errorHandler);
+ }
+ }
+
+ //// See Compatibility Note A in the DjsDeferred constructor.
+ //// if (!this._next) {
+ //// this._next = createDeferred();
+ //// }
+ //// return this._next.promise();
+
+ if (this._resolved) {
+ this.resolve.apply(this, this._arguments);
+ } else if (this._rejected) {
+ this.reject.apply(this, this._arguments);
+ }
+
+ return this;
+ },
+
+ resolve: function (/* args */) {
+ /// <summary>Invokes success callbacks for this deferred object.</summary>
+ /// <remarks>All arguments are forwarded to success callbacks.</remarks>
+
+
+ if (this._done) {
+ var i, len;
+ for (i = 0, len = this._done.length; i < len; i++) {
+ //// See Compability Note B - Fulfillment value.
+ //// var nextValue =
+ this._done[i].apply(null, arguments);
+ }
+
+ //// See Compatibility Note A in the DjsDeferred constructor.
+ //// this._next.resolve(nextValue);
+ //// delete this._next;
+
+ this._done = undefined;
+ this._resolved = false;
+ this._arguments = undefined;
+ } else {
+ this._resolved = true;
+ this._arguments = arguments;
+ }
+ },
+
+ reject: function (/* args */) {
+ /// <summary>Invokes error callbacks for this deferred object.</summary>
+ /// <remarks>All arguments are forwarded to error callbacks.</remarks>
+ if (this._fail) {
+ var i, len;
+ for (i = 0, len = this._fail.length; i < len; i++) {
+ this._fail[i].apply(null, arguments);
+ }
+
+ this._fail = undefined;
+ this._rejected = false;
+ this._arguments = undefined;
+ } else {
+ this._rejected = true;
+ this._arguments = arguments;
+ }
+ },
+
+ promise: function () {
+ /// <summary>Returns a version of this object that has only the read-only methods available.</summary>
+ /// <returns>An object with only the promise object.</returns>
+
+ var result = {};
+ result.then = forwardCall(this, "then", result);
+ return result;
+ }
+};
+
+var createDeferred = function () {
+ /// <summary>Creates a deferred object.</summary>
+ /// <returns type="DjsDeferred">
+ /// A new deferred object. If jQuery is installed, then a jQuery
+ /// Deferred object is returned, which provides a superset of features.
+ /// </returns>
+
+ if (window.jQuery && window.jQuery.Deferred) {
+ return new window.jQuery.Deferred();
+ } else {
+ return new DjsDeferred();
+ }
+};
+
+// DATAJS INTERNAL START
+//window.datajs.createDeferred = createDeferred;
+//window.datajs.DjsDeferred = DjsDeferred;
+exports.createDeferred = createDeferred;
+exports.DjsDeferred = DjsDeferred;
+// DATAJS INTERNAL END
[07/15] [OLINGO-238] Build infrastructure for datajs I
Posted by ko...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/odata-atom.js
----------------------------------------------------------------------
diff --git a/datajs/src/odata-atom.js b/datajs/src/odata-atom.js
deleted file mode 100644
index d92c2a6..0000000
--- a/datajs/src/odata-atom.js
+++ /dev/null
@@ -1,1411 +0,0 @@
-/// <reference path="odata-utils.js" />
-/// <reference path="odata-handler.js" />
-/// <reference path="odata-xml.js" />
-
-// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
-// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// odata-atom.js
-
-(function (window, undefined) {
-
- var datajs = window.datajs || {};
- var odata = window.OData || {};
-
- // imports
- var contains = datajs.contains;
- var djsassert = datajs.djsassert;
- var isArray = datajs.isArray;
- var isObject = datajs.isObject;
- var isXmlNSDeclaration = datajs.isXmlNSDeclaration;
- var normalizeURI = datajs.normalizeURI;
- var parseInt10 = datajs.parseInt10;
- var xmlAppendChild = datajs.xmlAppendChild;
- var xmlAppendChildren = datajs.xmlAppendChildren
- var xmlAttributes = datajs.xmlAttributes;
- var xmlAttributeNode = datajs.xmlAttributeNode;
- var xmlAttributeValue = datajs.xmlAttributeValue;
- var xmlBaseURI = datajs.xmlBaseURI;
- var xmlChildElements = datajs.xmlChildElements;
- var xmlDom = datajs.xmlDom;
- var xmlFirstChildElement = datajs.xmlFirstChildElement;
- var xmlFindElementByPath = datajs.xmlFindElementByPath;
- var xmlFindNodeByPath = datajs.xmlFindNodeByPath;
- var xmlInnerText = datajs.xmlInnerText;
- var xmlLocalName = datajs.xmlLocalName;
- var xmlNamespaceURI = datajs.xmlNamespaceURI;
- var xmlNewAttribute = datajs.xmlNewAttribute;
- var xmlNewElement = datajs.xmlNewElement;
- var xmlNewFragment = datajs.xmlNewFragment;
- var xmlNewNodeByPath = datajs.xmlNewNodeByPath;
- var xmlNewNSDeclaration = datajs.xmlNewNSDeclaration;
- var xmlNewText = datajs.xmlNewText;
- var xmlNodeValue = datajs.xmlNodeValue;
- var xmlNS = datajs.xmlNS;
- var xmlnsNS = datajs.xmlnsNS;
- var xmlQualifiedName = datajs.xmlQualifiedName;
- var xmlParse = datajs.xmlParse;
- var xmlSerialize = datajs.xmlSerialize;
- var xmlSerializeDescendants = datajs.xmlSerializeDescendants;
- var xmlSibling = datajs.xmlSibling;
- var w3org = datajs.w3org;
-
- var adoDs = odata.adoDs;
- var contentType = odata.contentType;
- var createAttributeExtension = odata.createAttributeExtension;
- var createElementExtension = odata.createElementExtension;
- var handler = odata.handler;
- var isPrimitiveEdmType = odata.isPrimitiveEdmType;
- var isFeed = odata.isFeed;
- var isNamedStream = odata.isNamedStream;
- var lookupEntityType = odata.lookupEntityType;
- var lookupComplexType = odata.lookupComplexType;
- var lookupProperty = odata.lookupProperty;
- var navigationPropertyKind = odata.navigationPropertyKind;
- var MAX_DATA_SERVICE_VERSION = odata.MAX_DATA_SERVICE_VERSION;
- var maxVersion = odata.maxVersion;
- var odataXmlNs = odata.odataXmlNs;
- var odataMetaXmlNs = odata.odataMetaXmlNs;
- var odataMetaPrefix = odata.odataMetaPrefix;
- var odataPrefix = odata.odataPrefix;
- var odataRelatedPrefix = odata.odataRelatedPrefix;
- var odataScheme = odata.odataScheme;
- var parseBool = odata.parseBool;
- var parseDateTime = odata.parseDateTime;
- var parseDateTimeOffset = odata.parseDateTimeOffset;
- var parseDuration = odata.parseDuration;
- var parseTimezone = odata.parseTimezone;
- var xmlNewODataElement = odata.xmlNewODataElement;
- var xmlNewODataElementInfo = odata.xmlNewODataElementInfo;
- var xmlNewODataMetaAttribute = odata.xmlNewODataMetaAttribute;
- var xmlNewODataMetaElement = odata.xmlNewODataMetaElement;
- var xmlNewODataDataElement = odata.xmlNewODataDataElement;
- var xmlReadODataEdmPropertyValue = odata.xmlReadODataEdmPropertyValue;
- var xmlReadODataProperty = odata.xmlReadODataProperty;
-
- // CONTENT START
-
- var atomPrefix = "a";
-
- var atomXmlNs = w3org + "2005/Atom"; // http://www.w3.org/2005/Atom
- var appXmlNs = w3org + "2007/app"; // http://www.w3.org/2007/app
-
- var odataEditMediaPrefix = adoDs + "/edit-media/"; // http://schemas.microsoft.com/ado/2007/08/dataservices/edit-media
- var odataMediaResourcePrefix = adoDs + "/mediaresource/"; // http://schemas.microsoft.com/ado/2007/08/dataservices/mediaresource
- var odataRelatedLinksPrefix = adoDs + "/relatedlinks/"; // http://schemas.microsoft.com/ado/2007/08/dataservices/relatedlinks
-
- var atomAcceptTypes = ["application/atom+xml", "application/atomsvc+xml", "application/xml"];
- var atomMediaType = atomAcceptTypes[0];
-
- // These are the namespaces that are not considered ATOM extension namespaces.
- var nonExtensionNamepaces = [atomXmlNs, appXmlNs, xmlNS, xmlnsNS];
-
- // These are entity property mapping paths that have well-known paths.
- var knownCustomizationPaths = {
- SyndicationAuthorEmail: "author/email",
- SyndicationAuthorName: "author/name",
- SyndicationAuthorUri: "author/uri",
- SyndicationContributorEmail: "contributor/email",
- SyndicationContributorName: "contributor/name",
- SyndicationContributorUri: "contributor/uri",
- SyndicationPublished: "published",
- SyndicationRights: "rights",
- SyndicationSummary: "summary",
- SyndicationTitle: "title",
- SyndicationUpdated: "updated"
- };
-
- var expandedFeedCustomizationPath = function (path) {
- /// <summary>Returns an expanded customization path if it's well-known.</summary>
- /// <param name="path" type="String">Path to expand.</param>
- /// <returns type="String">Expanded path or just 'path' otherwise.</returns>
-
- return knownCustomizationPaths[path] || path;
- };
-
- var isExtensionNs = function (nsURI) {
- /// <summary>Checks whether the specified namespace is an extension namespace to ATOM.</summary>
- /// <param type="String" name="nsURI">Namespace to check.</param>
- /// <returns type="Boolean">true if nsURI is an extension namespace to ATOM; false otherwise.</returns>
-
- return !(contains(nonExtensionNamepaces, nsURI));
- };
-
- var atomFeedCustomization = function (customizationModel, entityType, model, propertyName, suffix) {
- /// <summary>Creates an object describing a feed customization that was delcared in an OData conceptual schema.</summary>
- /// <param name="customizationModel" type="Object">Object describing the customization delcared in the conceptual schema.</param>
- /// <param name="entityType" type="Object">Object describing the entity type that owns the customization in an OData conceputal schema.</param>
- /// <param name="model" type="Object">Object describing an OData conceptual schema.</param>
- /// <param name="propertyName" type="String" optional="true">Name of the property to which this customization applies.</param>
- /// <param name="suffix" type="String" optional="true">Suffix to feed customization properties in the conceptual schema.</param>
- /// <returns type="Object">Object that describes an applicable feed customization.</returns>
-
- suffix = suffix || "";
- var targetPath = customizationModel["FC_TargetPath" + suffix];
- if (!targetPath) {
- return null;
- }
-
- var sourcePath = customizationModel["FC_SourcePath" + suffix];
- var targetXmlPath = expandedFeedCustomizationPath(targetPath);
-
- var propertyPath = propertyName ? propertyName + (sourcePath ? "/" + sourcePath : "") : sourcePath;
- var propertyType = propertyPath && lookupPropertyType(model, entityType, propertyPath);
- var nsURI = customizationModel["FC_NsUri" + suffix] || null;
- var nsPrefix = customizationModel["FC_NsPrefix" + suffix] || null;
- var keepinContent = customizationModel["FC_KeepInContent" + suffix] || "";
-
- if (targetPath !== targetXmlPath) {
- nsURI = atomXmlNs;
- nsPrefix = atomPrefix;
- }
-
- return {
- contentKind: customizationModel["FC_ContentKind" + suffix],
- keepInContent: keepinContent.toLowerCase() === "true",
- nsPrefix: nsPrefix,
- nsURI: nsURI,
- propertyPath: propertyPath,
- propertyType: propertyType,
- entryPath: targetXmlPath
- };
- };
-
- var atomApplyAllFeedCustomizations = function (entityType, model, callback) {
- /// <summary>Gets all the feed customizations that have to be applied to an entry as per the enity type declared in an OData conceptual schema.</summary>
- /// <param name="entityType" type="Object">Object describing an entity type in a conceptual schema.</param>
- /// <param name="model" type="Object">Object describing an OData conceptual schema.</param>
- /// <param name="callback" type="Function">Callback function to be invoked for each feed customization that needs to be applied.</param>
-
- var customizations = [];
- while (entityType) {
- var sourcePath = entityType.FC_SourcePath;
- var customization = atomFeedCustomization(entityType, entityType, model);
- if (customization) {
- callback(customization);
- }
-
- var properties = entityType.property || [];
- var i, len;
- for (i = 0, len = properties.length; i < len; i++) {
- var property = properties[i];
- var suffixCounter = 0;
- var suffix = "";
-
- while (customization = atomFeedCustomization(property, entityType, model, property.name, suffix)) {
- callback(customization);
- suffixCounter++;
- suffix = "_" + suffixCounter;
- }
- }
- entityType = lookupEntityType(entityType.baseType, model);
- }
- return customizations;
- };
-
- var atomReadExtensionAttributes = function (domElement) {
- /// <summary>Reads ATOM extension attributes (any attribute not in the Atom namespace) from a DOM element.</summary>
- /// <param name="domElement">DOM element with zero or more extension attributes.</param>
- /// <returns type="Array">An array of extension attribute representations.</returns>
-
- var extensions = [];
- xmlAttributes(domElement, function (attribute) {
- var nsURI = xmlNamespaceURI(attribute);
- if (isExtensionNs(nsURI)) {
- extensions.push(createAttributeExtension(attribute, true));
- }
- });
- return extensions;
- };
-
- var atomReadExtensionElement = function (domElement) {
- /// <summary>Reads an ATOM extension element (an element not in the ATOM namespaces).</summary>
- /// <param name="domElement">DOM element not part of the atom namespace.</param>
- /// <returns type="Object">Object representing the extension element.</returns>
-
- return createElementExtension(domElement, /*addNamespaceURI*/true);
- };
-
- var atomReadDocument = function (domElement, baseURI, model) {
- /// <summary>Reads an ATOM entry, feed or service document, producing an object model in return.</summary>
- /// <param name="domElement">Top-level ATOM DOM element to read.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the ATOM document.</param>
- /// <param name="model" type="Object">Object that describes the conceptual schema.</param>
- /// <returns type="Object">The object model representing the specified element, undefined if the top-level element is not part of the ATOM specification.</returns>
-
- var nsURI = xmlNamespaceURI(domElement);
- var localName = xmlLocalName(domElement);
-
- // Handle service documents.
- if (nsURI === appXmlNs && localName === "service") {
- return atomReadServiceDocument(domElement, baseURI);
- }
-
- // Handle feed and entry elements.
- if (nsURI === atomXmlNs) {
- if (localName === "feed") {
- return atomReadFeed(domElement, baseURI, model);
- }
- if (localName === "entry") {
- return atomReadEntry(domElement, baseURI, model);
- }
- }
-
- // Allow undefined to be returned.
- };
-
- var atomReadAdvertisedActionOrFunction = function (domElement, baseURI) {
- /// <summary>Reads the DOM element for an action or a function in an OData Atom document.</summary>
- /// <param name="domElement">DOM element to read.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing the action or function target url.</param>
- /// <returns type="Object">Object with title, target, and metadata fields.</returns>
-
- var extensions = [];
- var result = { extensions: extensions };
- xmlAttributes(domElement, function (attribute) {
- var localName = xmlLocalName(attribute);
- var nsURI = xmlNamespaceURI(attribute);
- var value = xmlNodeValue(attribute);
-
- if (nsURI === null) {
- if (localName === "title" || localName === "metadata") {
- result[localName] = value;
- return;
- }
- if (localName === "target") {
- result.target = normalizeURI(value, xmlBaseURI(domElement, baseURI));
- return;
- }
- }
-
- if (isExtensionNs(nsURI)) {
- extensions.push(createAttributeExtension(attribute, true));
- }
- });
- return result;
- };
-
- var atomReadAdvertisedAction = function (domElement, baseURI, parentMetadata) {
- /// <summary>Reads the DOM element for an action in an OData Atom document.</summary>
- /// <param name="domElement">DOM element to read.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing the action or target url.</param>
- /// <param name="parentMetadata" type="Object">Object to update with the action metadata.</param>
-
- var actions = parentMetadata.actions = parentMetadata.actions || [];
- actions.push(atomReadAdvertisedActionOrFunction(domElement, baseURI));
- };
-
- var atomReadAdvertisedFunction = function (domElement, baseURI, parentMetadata) {
- /// <summary>Reads the DOM element for an action in an OData Atom document.</summary>
- /// <param name="domElement">DOM element to read.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing the action or target url.</param>
- /// <param name="parentMetadata" type="Object">Object to update with the action metadata.</param>
-
- var functions = parentMetadata.functions = parentMetadata.functions || [];
- functions.push(atomReadAdvertisedActionOrFunction(domElement, baseURI));
- };
-
- var atomReadFeed = function (domElement, baseURI, model) {
- /// <summary>Reads a DOM element for an ATOM feed, producing an object model in return.</summary>
- /// <param name="domElement">ATOM feed DOM element.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the ATOM feed.</param>
- /// <param name="model">Metadata that describes the conceptual schema.</param>
- /// <returns type="Object">A new object representing the feed.</returns>
-
- var extensions = atomReadExtensionAttributes(domElement);
- var feedMetadata = { feed_extensions: extensions };
- var results = [];
-
- var feed = { __metadata: feedMetadata, results: results };
-
- baseURI = xmlBaseURI(domElement, baseURI);
-
- xmlChildElements(domElement, function (child) {
- var nsURI = xmlNamespaceURI(child);
- var localName = xmlLocalName(child);
-
- if (nsURI === odataMetaXmlNs) {
- if (localName === "count") {
- feed.__count = parseInt(xmlInnerText(child), 10);
- return;
- }
- if (localName === "action") {
- atomReadAdvertisedAction(child, baseURI, feedMetadata);
- return;
- }
- if (localName === "function") {
- atomReadAdvertisedFunction(child, baseURI, feedMetadata);
- return;
- }
- }
-
- if (isExtensionNs(nsURI)) {
- extensions.push(createElementExtension(child));
- return;
- }
-
- // The element should belong to the ATOM namespace.
- djsassert(nsURI === atomXmlNs, "atomReadFeed - child feed element is not in the atom namespace!!");
-
- if (localName === "entry") {
- results.push(atomReadEntry(child, baseURI, model));
- return;
- }
- if (localName === "link") {
- atomReadFeedLink(child, feed, baseURI);
- return;
- }
- if (localName === "id") {
- feedMetadata.uri = normalizeURI(xmlInnerText(child), baseURI);
- feedMetadata.uri_extensions = atomReadExtensionAttributes(child);
- return;
- }
- if (localName === "title") {
- feedMetadata.title = xmlInnerText(child) || "";
- feedMetadata.title_extensions = atomReadExtensionAttributes(child);
- return;
- }
- });
-
- return feed;
- };
-
- var atomReadFeedLink = function (domElement, feed, baseURI) {
- /// <summary>Reads an ATOM link DOM element for a feed.</summary>
- /// <param name="domElement">ATOM link DOM element.</param>
- /// <param name="feed">Feed object to be annotated with the link data.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
-
- var link = atomReadLink(domElement, baseURI);
- var href = link.href;
- var rel = link.rel;
- var extensions = link.extensions;
- var metadata = feed.__metadata;
-
- if (rel === "next") {
- feed.__next = href;
- metadata.next_extensions = extensions;
- return;
- }
- if (rel === "self") {
- metadata.self = href;
- metadata.self_extensions = extensions;
- return;
- }
- };
-
- var atomReadLink = function (domElement, baseURI) {
- /// <summary>Reads an ATOM link DOM element.</summary>
- /// <param name="linkElement">DOM element to read.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing the link href.</param>
- /// <returns type="Object">A link element representation.</returns>
-
- baseURI = xmlBaseURI(domElement, baseURI);
-
- var extensions = [];
- var link = { extensions: extensions, baseURI: baseURI };
-
- xmlAttributes(domElement, function (attribute) {
- var nsURI = xmlNamespaceURI(attribute);
- var localName = xmlLocalName(attribute);
- var value = attribute.value;
-
- if (localName === "href") {
- link.href = normalizeURI(value, baseURI);
- return;
- }
- if (localName === "type" || localName === "rel") {
- link[localName] = value;
- return;
- }
-
- if (isExtensionNs(nsURI)) {
- extensions.push(createAttributeExtension(attribute, true));
- }
- });
-
- if (!link.href) {
- throw { error: "href attribute missing on link element", element: domElement };
- }
-
- return link;
- };
-
- var atomGetObjectValueByPath = function (path, item) {
- /// <summary>Gets a slashed path value from the specified item.</summary>
- /// <param name="path" type="String">Property path to read ('/'-separated).</param>
- /// <param name="item" type="Object">Object to get value from.</param>
- /// <returns>The property value, possibly undefined if any path segment is missing.</returns>
-
- // Fast path.
- if (path.indexOf('/') === -1) {
- return item[path];
- } else {
- var parts = path.split('/');
- var i, len;
- for (i = 0, len = parts.length; i < len; i++) {
- // Avoid traversing a null object.
- if (item === null) {
- return undefined;
- }
-
- item = item[parts[i]];
- if (item === undefined) {
- return item;
- }
- }
-
- return item;
- }
- };
-
- var atomSetEntryValueByPath = function (path, target, value, propertyType) {
- /// <summary>Sets a slashed path value on the specified target.</summary>
- /// <param name="path" type="String">Property path to set ('/'-separated).</param>
- /// <param name="target" type="Object">Object to set value on.</param>
- /// <param name="value">Value to set.</param>
- /// <param name="propertyType" type="String" optional="true">Property type to set in metadata.</param>
-
- var propertyName;
- if (path.indexOf('/') === -1) {
- target[path] = value;
- propertyName = path;
- } else {
- var parts = path.split('/');
- var i, len;
- for (i = 0, len = (parts.length - 1); i < len; i++) {
- // We construct each step of the way if the property is missing;
- // if it's already initialized to null, we stop further processing.
- var next = target[parts[i]];
- if (next === undefined) {
- next = {};
- target[parts[i]] = next;
- } else if (next === null) {
- return;
- }
- target = next;
- }
- propertyName = parts[i];
- target[propertyName] = value;
- }
-
- if (propertyType) {
- var metadata = target.__metadata = target.__metadata || {};
- var properties = metadata.properties = metadata.properties || {};
- var property = properties[propertyName] = properties[propertyName] || {};
- property.type = propertyType;
- }
- };
-
- var atomApplyCustomizationToEntryObject = function (customization, domElement, entry) {
- /// <summary>Applies a specific feed customization item to an object.</summary>
- /// <param name="customization">Object with customization description.</param>
- /// <param name="sourcePath">Property path to set ('source' in the description).</param>
- /// <param name="entryElement">XML element for the entry that corresponds to the object being read.</param>
- /// <param name="entryObject">Object being read.</param>
- /// <param name="propertyType" type="String">Name of property type to set.</param>
- /// <param name="suffix" type="String">Suffix to feed customization properties.</param>
-
- var propertyPath = customization.propertyPath;
- // If keepInConent equals true or the property value is null we do nothing as this overrides any other customization.
- if (customization.keepInContent || atomGetObjectValueByPath(propertyPath, entry) === null) {
- return;
- }
-
- var xmlNode = xmlFindNodeByPath(domElement, customization.nsURI, customization.entryPath);
-
- // If the XML tree does not contain the necessary elements to read the value,
- // then it shouldn't be considered null, but rather ignored at all. This prevents
- // the customization from generating the object path down to the property.
- if (!xmlNode) {
- return;
- }
-
- var propertyType = customization.propertyType;
- var propertyValue;
-
- if (customization.contentKind === "xhtml") {
- // Treat per XHTML in http://tools.ietf.org/html/rfc4287#section-3.1.1, including the DIV
- // in the content.
- propertyValue = xmlSerializeDescendants(xmlNode);
- } else {
- propertyValue = xmlReadODataEdmPropertyValue(xmlNode, propertyType || "Edm.String");
- }
- // Set the value on the entry.
- atomSetEntryValueByPath(propertyPath, entry, propertyValue, propertyType);
- };
-
- var lookupPropertyType = function (metadata, owningType, path) {
- /// <summary>Looks up the type of a property given its path in an entity type.</summary>
- /// <param name="metadata">Metadata in which to search for base and complex types.</param>
- /// <param name="owningType">Type to which property belongs.</param>
- /// <param name="path" type="String" mayBeNull="false">Property path to look at.</param>
- /// <returns type="String">The name of the property type; possibly null.</returns>
-
- var parts = path.split("/");
- var i, len;
- while (owningType) {
- // Keep track of the type being traversed, necessary for complex types.
- var traversedType = owningType;
-
- for (i = 0, len = parts.length; i < len; i++) {
- // Traverse down the structure as necessary.
- var properties = traversedType.property;
- if (!properties) {
- break;
- }
-
- // Find the property by scanning the property list (might be worth pre-processing).
- var propertyFound = lookupProperty(properties, parts[i]);
- if (!propertyFound) {
- break;
- }
-
- var propertyType = propertyFound.type;
-
- // We could in theory still be missing types, but that would
- // be caused by a malformed path.
- if (!propertyType || isPrimitiveEdmType(propertyType)) {
- return propertyType || null;
- }
-
- traversedType = lookupComplexType(propertyType, metadata);
- if (!traversedType) {
- return null;
- }
- }
-
- // Traverse up the inheritance chain.
- owningType = lookupEntityType(owningType.baseType, metadata);
- }
-
- return null;
- };
-
- var atomReadEntry = function (domElement, baseURI, model) {
- /// <summary>Reads a DOM element for an ATOM entry, producing an object model in return.</summary>
- /// <param name="domElement">ATOM entry DOM element.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the ATOM entry.</param>
- /// <param name="model">Metadata that describes the conceptual schema.</param>
- /// <returns type="Object">A new object representing the entry.</returns>
-
- var entryMetadata = {};
- var entry = { __metadata: entryMetadata };
-
- var etag = xmlAttributeValue(domElement, "etag", odataMetaXmlNs);
- if (etag) {
- entryMetadata.etag = etag;
- }
-
- baseURI = xmlBaseURI(domElement, baseURI);
-
- xmlChildElements(domElement, function (child) {
- var nsURI = xmlNamespaceURI(child);
- var localName = xmlLocalName(child);
-
- if (nsURI === atomXmlNs) {
- if (localName === "id") {
- atomReadEntryId(child, entryMetadata, baseURI);
- return;
- }
- if (localName === "category") {
- atomReadEntryType(child, entryMetadata);
- return;
- }
- if (localName === "content") {
- atomReadEntryContent(child, entry, entryMetadata, baseURI);
- return;
- }
- if (localName === "link") {
- atomReadEntryLink(child, entry, entryMetadata, baseURI, model);
- return;
- }
- return;
- }
-
- if (nsURI === odataMetaXmlNs) {
- if (localName === "properties") {
- atomReadEntryStructuralObject(child, entry, entryMetadata);
- return;
- }
- if (localName === "action") {
- atomReadAdvertisedAction(child, baseURI, entryMetadata);
- return;
- }
- if (localName === "function") {
- atomReadAdvertisedFunction(child, baseURI, entryMetadata);
- return;
- }
- }
- });
-
- // Apply feed customizations if applicable
- var entityType = lookupEntityType(entryMetadata.type, model);
- atomApplyAllFeedCustomizations(entityType, model, function (customization) {
- atomApplyCustomizationToEntryObject(customization, domElement, entry);
- });
-
- return entry;
- };
-
- var atomReadEntryId = function (domElement, entryMetadata, baseURI) {
- /// <summary>Reads an ATOM entry id DOM element.</summary>
- /// <param name="domElement">ATOM id DOM element.</param>
- /// <param name="entryMetadata">Entry metadata object to update with the id information.</param>
-
- entryMetadata.uri = normalizeURI(xmlInnerText(domElement), xmlBaseURI(domElement, baseURI));
- entryMetadata.uri_extensions = atomReadExtensionAttributes(domElement);
- };
-
- var atomReadEntryType = function (domElement, entryMetadata) {
- /// <summary>Reads type information from an ATOM category DOM element.</summary>
- /// <param name="domElement">ATOM category DOM element.</param>
- /// <param name="entryMetadata">Entry metadata object to update with the type information.</param>
-
- if (xmlAttributeValue(domElement, "scheme") === odataScheme) {
- if (entryMetadata.type) {
- throw { message: "Invalid AtomPub document: multiple category elements defining the entry type were encounterd withing an entry", element: domElement };
- }
-
- var typeExtensions = [];
- xmlAttributes(domElement, function (attribute) {
- var nsURI = xmlNamespaceURI(attribute);
- var localName = xmlLocalName(attribute);
-
- if (!nsURI) {
- if (localName !== "scheme" && localName !== "term") {
- typeExtensions.push(createAttributeExtension(attribute, true));
- }
- return;
- }
-
- if (isExtensionNs(nsURI)) {
- typeExtensions.push(createAttributeExtension(attribute, true));
- }
- });
-
- entryMetadata.type = xmlAttributeValue(domElement, "term");
- entryMetadata.type_extensions = typeExtensions;
- }
- };
-
- var atomReadEntryContent = function (domElement, entry, entryMetadata, baseURI) {
- /// <summary>Reads an ATOM content DOM element.</summary>
- /// <param name="domElement">ATOM content DOM element.</param>
- /// <param name="entry">Entry object to update with information.</param>
- /// <param name="entryMetadata">Entry metadata object to update with the content information.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the Atom entry content.</param>
-
- var src = xmlAttributeValue(domElement, "src");
- var type = xmlAttributeValue(domElement, "type");
-
- if (src) {
- if (!type) {
- throw {
- message: "Invalid AtomPub document: content element must specify the type attribute if the src attribute is also specified",
- element: domElement
- };
- }
-
- entryMetadata.media_src = normalizeURI(src, xmlBaseURI(domElement, baseURI));
- entryMetadata.content_type = type;
- }
-
- xmlChildElements(domElement, function (child) {
- if (src) {
- throw { message: "Invalid AtomPub document: content element must not have child elements if the src attribute is specified", element: domElement };
- }
-
- if (xmlNamespaceURI(child) === odataMetaXmlNs && xmlLocalName(child) === "properties") {
- atomReadEntryStructuralObject(child, entry, entryMetadata);
- }
- });
- };
-
- var atomReadEntryLink = function (domElement, entry, entryMetadata, baseURI, model) {
- /// <summary>Reads a link element on an entry.</summary>
- /// <param name="atomEntryLink">'link' element on the entry.</param>
- /// <param name="entry" type="Object">Entry object to update with the link data.</param>
- /// <param name="entryMetadata">Entry metadata object to update with the link metadata.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing the link href.</param>
- /// <param name="model" type="Object">Metadata that describes the conceptual schema.</param>
-
- var link = atomReadLink(domElement, baseURI);
-
- var rel = link.rel;
- var href = link.href;
- var extensions = link.extensions;
-
- if (rel === "self") {
- entryMetadata.self = href;
- entryMetadata.self_link_extensions = extensions;
- return;
- }
-
- if (rel === "edit") {
- entryMetadata.edit = href;
- entryMetadata.edit_link_extensions = extensions;
- return;
- }
-
- if (rel === "edit-media") {
- entryMetadata.edit_media = link.href;
- entryMetadata.edit_media_extensions = extensions;
- atomReadLinkMediaEtag(link, entryMetadata);
- return;
- }
-
- // This might be a named stream edit link
- if (rel.indexOf(odataEditMediaPrefix) === 0) {
- atomReadNamedStreamEditLink(link, entry, entryMetadata);
- return;
- }
-
- // This might be a named stram media resource (read) link
- if (rel.indexOf(odataMediaResourcePrefix) === 0) {
- atomReadNamedStreamSelfLink(link, entry, entryMetadata);
- return;
- }
-
- // This might be a navigation property
- if (rel.indexOf(odataRelatedPrefix) === 0) {
- atomReadNavPropLink(domElement, link, entry, entryMetadata, model);
- return;
- }
-
- if (rel.indexOf(odataRelatedLinksPrefix) === 0) {
- atomReadNavPropRelatedLink(link, entryMetadata);
- return;
- }
- };
-
- var atomReadNavPropRelatedLink = function (link, entryMetadata) {
- /// <summary>Reads a link represnting the links related to a navigation property in an OData Atom document.</summary>
- /// <param name="link" type="Object">Object representing the parsed link DOM element.</param>
- /// <param name="entryMetadata" type="Object">Entry metadata object to update with the related links information.</param>
-
- var propertyName = link.rel.substring(odataRelatedLinksPrefix.length);
- djsassert(propertyName, "atomReadNavPropRelatedLink - property name is null, empty or undefined!");
-
- // Set the extra property information on the entry object metadata.
- entryMetadata.properties = entryMetadata.properties || {};
- var propertyMetadata = entryMetadata.properties[propertyName] = entryMetadata.properties[propertyName] || {};
-
- propertyMetadata.associationuri = link.href;
- propertyMetadata.associationuri_extensions = link.extensions;
- };
-
- var atomReadNavPropLink = function (domElement, link, entry, entryMetadata, model) {
- /// <summary>Reads a link representing a navigation property in an OData Atom document.</summary>
- /// <param name="domElement">DOM element for a navigation property in an OData Atom document.</summary>
- /// <param name="link" type="Object">Object representing the parsed link DOM element.</param>
- /// <param name="entry" type="Object">Entry object to update with the navigation property.</param>
- /// <param name="entryMetadata">Entry metadata object to update with the navigation property metadata.</param>
- /// <param name="model" type="Object">Metadata that describes the conceptual schema.</param>
-
- // Get any inline data.
- var inlineData;
- var inlineElement = xmlFirstChildElement(domElement, odataMetaXmlNs, "inline");
- if (inlineElement) {
- var inlineDocRoot = xmlFirstChildElement(inlineElement);
- var inlineBaseURI = xmlBaseURI(inlineElement, link.baseURI);
- inlineData = inlineDocRoot ? atomReadDocument(inlineDocRoot, inlineBaseURI, model) : null;
- } else {
- // If the link has no inline content, we consider it deferred.
- inlineData = { __deferred: { uri: link.href} };
- }
-
- var propertyName = link.rel.substring(odataRelatedPrefix.length);
-
- // Set the property value on the entry object.
- entry[propertyName] = inlineData;
-
- // Set the extra property information on the entry object metadata.
- entryMetadata.properties = entryMetadata.properties || {};
- var propertyMetadata = entryMetadata.properties[propertyName] = entryMetadata.properties[propertyName] || {};
-
- propertyMetadata.extensions = link.extensions;
- };
-
- var atomReadNamedStreamEditLink = function (link, entry, entryMetadata) {
- /// <summary>Reads a link representing the edit-media url of a named stream in an OData Atom document.</summary>
- /// <param name="link" type="Object">Object representing the parsed link DOM element.</param>
- /// <param name="entry" type="Object">Entry object to update with the named stream data.</param>
- /// <param name="entryMetadata">Entry metadata object to update with the named stream metadata.</param>
-
- var propertyName = link.rel.substring(odataEditMediaPrefix.length);
- djsassert(propertyName, "atomReadNamedStreamEditLink - property name is null, empty or undefined!");
-
- var namedStreamMediaResource = atomGetEntryNamedStreamMediaResource(propertyName, entry, entryMetadata);
- var mediaResource = namedStreamMediaResource.value;
- var mediaResourceMetadata = namedStreamMediaResource.metadata;
-
- var editMedia = link.href;
-
- mediaResource.edit_media = editMedia;
- mediaResource.content_type = link.type;
- mediaResourceMetadata.edit_media_extensions = link.extensions;
-
- // If there is only the edit link, make it the media self link as well.
- mediaResource.media_src = mediaResource.media_src || editMedia;
- mediaResourceMetadata.media_src_extensions = mediaResourceMetadata.media_src_extensions || [];
-
- atomReadLinkMediaEtag(link, mediaResource);
- };
-
- var atomReadNamedStreamSelfLink = function (link, entry, entryMetadata) {
- /// <summary>Reads a link representing the self url of a named stream in an OData Atom document.</summary>
- /// <param name="link" type="Object">Object representing the parsed link DOM element.</param>
- /// <param name="entry" type="Object">Entry object to update with the named stream data.</param>
- /// <param name="entryMetadata">Entry metadata object to update with the named stream metadata.</param>
-
- var propertyName = link.rel.substring(odataMediaResourcePrefix.length);
- djsassert(propertyName, "atomReadNamedStreamEditLink - property name is null, empty or undefined!");
-
- var namedStreamMediaResource = atomGetEntryNamedStreamMediaResource(propertyName, entry, entryMetadata);
- var mediaResource = namedStreamMediaResource.value;
- var mediaResourceMetadata = namedStreamMediaResource.metadata;
-
- mediaResource.media_src = link.href;
- mediaResourceMetadata.media_src_extensions = link.extensions;
- mediaResource.content_type = link.type;
- };
-
- var atomGetEntryNamedStreamMediaResource = function (name, entry, entryMetadata) {
- /// <summary>Gets the media resource object and metadata object for a named stream in an entry object.</summary>
- /// <param name="link" type="Object">Object representing the parsed link DOM element.</param>
- /// <param name="entry" type="Object">Entry object from which the media resource object will be obtained.</param>
- /// <param name="entryMetadata" type="Object">Entry metadata object from which the media resource metadata object will be obtained.</param>
- /// <remarks>
- /// If the entry doest' have a media resource for the named stream indicated by the name argument, then this function will create a new
- /// one along with its metadata object.
- /// <remarks>
- /// <returns type="Object"> Object containing the value and metadata of the named stream's media resource. <returns>
-
- entryMetadata.properties = entryMetadata.properties || {};
-
- var mediaResourceMetadata = entryMetadata.properties[name];
- var mediaResource = entry[name] && entry[name].__mediaresource;
-
- if (!mediaResource) {
- mediaResource = {};
- entry[name] = { __mediaresource: mediaResource };
- entryMetadata.properties[name] = mediaResourceMetadata = {};
- }
- return { value: mediaResource, metadata: mediaResourceMetadata };
- };
-
- var atomReadLinkMediaEtag = function (link, mediaResource) {
- /// <summary>Gets the media etag from the link extensions and updates the media resource object with it.</summary>
- /// <param name="link" type="Object">Object representing the parsed link DOM element.</param>
- /// <param name="mediaResource" type="Object">Object containing media information for an OData Atom entry.</param>
- /// <remarks>
- /// The function will remove the extension object for the etag if it finds it in the link extensions and will set
- /// its value under the media_etag property of the mediaResource object.
- /// <remarks>
- /// <returns type="Object"> Object containing the value and metadata of the named stream's media resource. <returns>
-
- var extensions = link.extensions;
- var i, len;
- for (i = 0, len = extensions.length; i < len; i++) {
- if (extensions[i].namespaceURI === odataMetaXmlNs && extensions[i].name === "etag") {
- mediaResource.media_etag = extensions[i].value;
- extensions.splice(i, 1);
- return;
- }
- }
- };
-
- var atomReadEntryStructuralObject = function (domElement, parent, parentMetadata) {
- /// <summary>Reads an atom entry's property as a structural object and sets its value in the parent and the metadata in the parentMetadata objects.</summary>
- /// <param name="propertiesElement">XML element for the 'properties' node.</param>
- /// <param name="parent">
- /// Object that will contain the property value. It can be either an antom entry or
- /// an atom complex property object.
- /// </param>
- /// <param name="parentMetadata">Object that will contain the property metadata. It can be either an atom entry metadata or a complex property metadata object</param>
-
- xmlChildElements(domElement, function (child) {
- var property = xmlReadODataProperty(child);
- if (property) {
- var propertyName = property.name;
- var propertiesMetadata = parentMetadata.properties = parentMetadata.properties || {};
- propertiesMetadata[propertyName] = property.metadata;
- parent[propertyName] = property.value;
- }
- });
- };
-
- var atomReadServiceDocument = function (domElement, baseURI) {
- /// <summary>Reads an AtomPub service document</summary>
- /// <param name="atomServiceDoc">DOM element for the root of an AtomPub service document</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the AtomPub service document.</param>
- /// <returns type="Object">An object that contains the properties of the service document</returns>
-
- var workspaces = [];
- var extensions = [];
-
- baseURI = xmlBaseURI(domElement, baseURI);
- // Find all the workspace elements.
- xmlChildElements(domElement, function (child) {
- if (xmlNamespaceURI(child) === appXmlNs && xmlLocalName(child) === "workspace") {
- workspaces.push(atomReadServiceDocumentWorkspace(child, baseURI));
- return;
- }
- extensions.push(createElementExtension(child));
- });
-
- // AtomPub (RFC 5023 Section 8.3.1) says a service document MUST contain one or
- // more workspaces. Throw if we don't find any.
- if (workspaces.length === 0) {
- throw { message: "Invalid AtomPub service document: No workspace element found.", element: domElement };
- }
-
- return { workspaces: workspaces, extensions: extensions };
- };
-
- var atomReadServiceDocumentWorkspace = function (domElement, baseURI) {
- /// <summary>Reads a single workspace element from an AtomPub service document</summary>
- /// <param name="domElement">DOM element that represents a workspace of an AtomPub service document</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the AtomPub service document workspace.</param>
- /// <returns type="Object">An object that contains the properties of the workspace</returns>
-
- var collections = [];
- var extensions = [];
- var title; // = undefined;
-
- baseURI = xmlBaseURI(domElement, baseURI);
-
- xmlChildElements(domElement, function (child) {
- var nsURI = xmlNamespaceURI(child);
- var localName = xmlLocalName(child);
-
- if (nsURI === atomXmlNs) {
- if (localName === "title") {
- if (title !== undefined) {
- throw { message: "Invalid AtomPub service document: workspace has more than one child title element", element: child };
- }
-
- title = xmlInnerText(child);
- return;
- }
- }
-
- if (nsURI === appXmlNs) {
- if (localName === "collection") {
- collections.push(atomReadServiceDocumentCollection(child, baseURI));
- }
- return;
- }
- extensions.push(atomReadExtensionElement(child));
- });
-
- return { title: title || "", collections: collections, extensions: extensions };
- };
-
- var atomReadServiceDocumentCollection = function (domElement, baseURI) {
- /// <summary>Reads a service document collection element into an object.</summary>
- /// <param name="domElement">DOM element that represents a collection of an AtomPub service document.</param>
- /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the AtomPub service document collection.</param>
- /// <returns type="Object">An object that contains the properties of the collection.</returns>
-
-
- var href = xmlAttributeValue(domElement, "href");
-
- if (!href) {
- throw { message: "Invalid AtomPub service document: collection has no href attribute", element: domElement };
- }
-
- baseURI = xmlBaseURI(domElement, baseURI);
- href = normalizeURI(href, xmlBaseURI(domElement, baseURI));
- var extensions = [];
- var title; // = undefined;
-
- xmlChildElements(domElement, function (child) {
- var nsURI = xmlNamespaceURI(child);
- var localName = xmlLocalName(child);
-
- if (nsURI === atomXmlNs) {
- if (localName === "title") {
- if (title !== undefined) {
- throw { message: "Invalid AtomPub service document: collection has more than one child title element", element: child };
- }
- title = xmlInnerText(child);
- }
- return;
- }
-
- if (nsURI !== appXmlNs) {
- extensions.push(atomReadExtensionElement(domElement));
- }
- });
-
- // AtomPub (RFC 5023 Section 8.3.3) says the collection element MUST contain
- // a title element. It's likely to be problematic if the service doc doesn't
- // have one so here we throw.
- if (!title) {
- throw { message: "Invalid AtomPub service document: collection has no title element", element: domElement };
- }
-
- return { title: title, href: href, extensions: extensions };
- };
-
- var atomNewElement = function (dom, name, children) {
- /// <summary>Creates a new DOM element in the Atom namespace.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="name" type="String">Local name of the Atom element to create.</param>
- /// <param name="children" type="Array">Array containing DOM nodes or string values that will be added as children of the new DOM element.</param>
- /// <returns>New DOM element in the Atom namespace.</returns>
- /// <remarks>
- /// If a value in the children collection is a string, then a new DOM text node is going to be created
- /// for it and then appended as a child of the new DOM Element.
- /// </remarks>
-
- return xmlNewElement(dom, atomXmlNs, xmlQualifiedName(atomPrefix, name), children);
- };
-
- var atomNewAttribute = function (dom, name, value) {
- /// <summary>Creates a new DOM attribute for an Atom element in the default namespace.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="name" type="String">Local name of the OData attribute to create.</param>
- /// <param name="value">Attribute value.</param>
- /// <returns>New DOM attribute in the default namespace.</returns>
-
- return xmlNewAttribute(dom, null, name, value);
- };
-
- var atomCanRemoveProperty = function (propertyElement) {
- /// <summary>Checks whether the property represented by domElement can be removed from the atom document DOM tree.</summary>
- /// <param name="propertyElement">DOM element for the property to test.</param>
- /// <remarks>
- /// The property can only be removed if it doens't have any children and only has namespace or type declaration attributes.
- /// </remarks>
- /// <returns type="Boolean">True is the property can be removed; false otherwise.</returns>
-
- if (propertyElement.childNodes.length > 0) {
- return false;
- }
-
- var isEmpty = true;
- var attributes = propertyElement.attributes;
- var i, len;
- for (i = 0, len = attributes.length; i < len && isEmpty; i++) {
- var attribute = attributes[i];
-
- isEmpty = isEmpty && isXmlNSDeclaration(attribute) ||
- (xmlNamespaceURI(attribute) == odataMetaXmlNs && xmlLocalName(attribute) === "type");
- }
- return isEmpty;
- };
-
- var atomNewODataNavigationProperty = function (dom, name, kind, value, model) {
- /// <summary>Creates a new Atom link DOM element for a navigation property in an OData Atom document.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="name" type="String">Property name.</param>
- /// <param name="kind" type="String">Navigation property kind. Expected values are "deferred", "entry", or "feed".</param>
- /// <param name="value" optional="true" mayBeNull="true">Value of the navigation property, if any.</param>
- /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
- /// <returns type="Object">
- /// Object containing the new Atom link DOM element for the navigation property and the
- /// required data service version for this property.
- /// </returns>
-
- var linkType = null;
- var linkContent = null;
- var linkContentBodyData = null;
- var href = "";
-
- if (kind !== "deferred") {
- linkType = atomNewAttribute(dom, "type", "application/atom+xml;type=" + kind);
- linkContent = xmlNewODataMetaElement(dom, "inline");
-
- if (value) {
- href = value.__metadata && value.__metadata.uri || "";
- linkContentBodyData =
- atomNewODataFeed(dom, value, model) ||
- atomNewODataEntry(dom, value, model);
- xmlAppendChild(linkContent, linkContentBodyData.element);
- }
- } else {
- href = value.__deferred.uri;
- }
-
- var navProp = atomNewElement(dom, "link", [
- atomNewAttribute(dom, "href", href),
- atomNewAttribute(dom, "rel", normalizeURI(name, odataRelatedPrefix)),
- linkType,
- linkContent
- ]);
-
- return xmlNewODataElementInfo(navProp, linkContentBodyData ? linkContentBodyData.dsv : "1.0");
- };
-
- var atomNewODataEntryDataItem = function (dom, name, value, dataItemMetadata, dataItemModel, model) {
- /// <summary>Creates a new DOM element for a data item in an entry, complex property, or collection property.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="name" type="String">Data item name.</param>
- /// <param name="value" optional="true" mayBeNull="true">Value of the data item, if any.</param>
- /// <param name="dataItemMetadata" type="Object" optional="true">Object containing metadata about the data item.</param>
- /// <param name="dataItemModel" type="Object" optional="true">Object describing the data item in an OData conceptual schema.</param>
- /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
- /// <returns type="Object">
- /// Object containing the new DOM element in the appropriate namespace for the data item and the
- /// required data service version for it.
- /// </returns>
-
- if (isNamedStream(value)) {
- return null;
- }
-
- var dataElement = xmlNewODataDataElement(dom, name, value, dataItemMetadata, dataItemModel, model);
- if (!dataElement) {
- // This may be a navigation property.
- var navPropKind = navigationPropertyKind(value, dataItemModel);
- djsassert(navPropKind !== null, "atomNewODataEntryDataItem - navigation property kind is null for property " + name);
-
- dataElement = atomNewODataNavigationProperty(dom, name, navPropKind, value, model);
- }
- return dataElement;
- };
-
- var atomEntryCustomization = function (dom, entry, entryProperties, customization) {
- /// <summary>Applies a feed customization by transforming an Atom entry DOM element as needed.</summary>
- /// <param name="dom">DOM document used for creating any new DOM nodes required by the customization.</param>
- /// <param name="entry">DOM element for the Atom entry to which the customization is going to be applied.</param>
- /// <param name="entryProperties">DOM element containing the properties of the Atom entry.</param>
- /// <param name="customization" type="Object">Object describing an applicable feed customization.</param>
- /// <remarks>
- /// Look into the atomfeedCustomization function for a description of the customization object.
- /// </remarks>
- /// <returns type="String">Data service version required by the applied customization</returns>
-
- var atomProperty = xmlFindElementByPath(entryProperties, odataXmlNs, customization.propertyPath);
- var atomPropertyNullAttribute = atomProperty && xmlAttributeNode(atomProperty, "null", odataMetaXmlNs);
- var atomPropertyValue;
- var dataServiceVersion = "1.0";
-
- if (atomPropertyNullAttribute && atomPropertyNullAttribute.value === "true") {
- return dataServiceVersion;
- }
-
- if (atomProperty) {
- atomPropertyValue = xmlInnerText(atomProperty) || "";
- if (!customization.keepInContent) {
- dataServiceVersion = "2.0";
- var parent = atomProperty.parentNode;
- var candidate = parent;
-
- parent.removeChild(atomProperty);
- while (candidate !== entryProperties && atomCanRemoveProperty(candidate)) {
- parent = candidate.parentNode;
- parent.removeChild(candidate);
- candidate = parent;
- }
- }
- }
-
- var targetNode = xmlNewNodeByPath(dom, entry,
- customization.nsURI, customization.nsPrefix, customization.entryPath);
-
- if (targetNode.nodeType === 2) {
- targetNode.value = atomPropertyValue;
- return dataServiceVersion;
- }
-
- var contentKind = customization.contentKind;
- xmlAppendChildren(targetNode, [
- contentKind && xmlNewAttribute(dom, null, "type", contentKind),
- contentKind === "xhtml" ? xmlNewFragment(dom, atomPropertyValue) : atomPropertyValue
- ]);
-
- return dataServiceVersion;
- };
-
- var atomNewODataEntry = function (dom, data, model) {
- /// <summary>Creates a new DOM element for an Atom entry.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="data" type="Object">Entry object in the library's internal representation.</param>
- /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
- /// <returns type="Object">
- /// Object containing the new DOM element for the Atom entry and the required data service version for it.
- /// </returns>
-
- var payloadMetadata = data.__metadata || {};
- var propertiesMetadata = payloadMetadata.properties || {};
-
- var etag = payloadMetadata.etag;
- var uri = payloadMetadata.uri;
- var typeName = payloadMetadata.type;
- var entityType = lookupEntityType(typeName, model);
-
- var properties = xmlNewODataMetaElement(dom, "properties");
- var entry = atomNewElement(dom, "entry", [
- atomNewElement(dom, "author",
- atomNewElement(dom, "name")
- ),
- etag && xmlNewODataMetaAttribute(dom, "etag", etag),
- uri && atomNewElement(dom, "id", uri),
- typeName && atomNewElement(dom, "category", [
- atomNewAttribute(dom, "term", typeName),
- atomNewAttribute(dom, "scheme", odataScheme)
- ]),
- // TODO: MLE support goes here.
- atomNewElement(dom, "content", [
- atomNewAttribute(dom, "type", "application/xml"),
- properties
- ])
- ]);
-
- var dataServiceVersion = "1.0";
- for (var name in data) {
- if (name !== "__metadata") {
- var entryDataItemMetadata = propertiesMetadata[name] || {};
- var entryDataItemModel = entityType && (
- lookupProperty(entityType.property, name) ||
- lookupProperty(entityType.navigationProperty, name));
-
- var entryDataItem = atomNewODataEntryDataItem(dom, name, data[name], entryDataItemMetadata, entryDataItemModel, model);
- if (entryDataItem) {
- var entryElement = entryDataItem.element;
- var entryElementParent = (xmlNamespaceURI(entryElement) === atomXmlNs) ? entry : properties;
-
- xmlAppendChild(entryElementParent, entryElement);
- dataServiceVersion = maxVersion(dataServiceVersion, entryDataItem.dsv);
- }
- }
- }
-
- atomApplyAllFeedCustomizations(entityType, model, function (customization) {
- var customizationDsv = atomEntryCustomization(dom, entry, properties, customization);
- dataServiceVersion = maxVersion(dataServiceVersion, customizationDsv);
- });
-
- return xmlNewODataElementInfo(entry, dataServiceVersion);
- };
-
- var atomNewODataFeed = function (dom, data, model) {
- /// <summary>Creates a new DOM element for an Atom feed.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="data" type="Object">Feed object in the library's internal representation.</param>
- /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
- /// <returns type="Object">
- /// Object containing the new DOM element for the Atom feed and the required data service version for it.
- /// </returns>
-
- var entries = isArray(data) ? data : data.results;
-
- if (!entries) {
- return null;
- }
-
- var dataServiceVersion = "1.0";
- var atomFeed = atomNewElement(dom, "feed");
-
- var i, len;
- for (i = 0, len = entries.length; i < len; i++) {
- var atomEntryData = atomNewODataEntry(dom, entries[i], model);
- xmlAppendChild(atomFeed, atomEntryData.element);
- dataServiceVersion = maxVersion(dataServiceVersion, atomEntryData.dsv);
- }
- return xmlNewODataElementInfo(atomFeed, dataServiceVersion);
- };
-
- var atomNewODataDocument = function (data, model) {
- /// <summary>Creates a new OData Atom document.</summary>
- /// <param name="data" type="Object">Feed or entry object in the libary's internal representaion.</param>
- /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
- /// <returns type="Object">
- /// Object containing the new DOM document for the Atom document and the required data service version for it.
- /// </returns>
-
- if (data) {
- var atomRootWriter = isFeed(data) && atomNewODataFeed ||
- isObject(data) && atomNewODataEntry;
-
- if (atomRootWriter) {
- var dom = xmlDom();
- var atomRootData = atomRootWriter(dom, data, model);
-
- if (atomRootData) {
- var atomRootElement = atomRootData.element;
- xmlAppendChildren(atomRootElement, [
- xmlNewNSDeclaration(dom, odataMetaXmlNs, odataMetaPrefix),
- xmlNewNSDeclaration(dom, odataXmlNs, odataPrefix)
- ]);
- return xmlNewODataElementInfo(xmlAppendChild(dom, atomRootElement), atomRootData.dsv);
- }
- }
- }
- return null;
- };
-
- var atomParser = function (handler, text, context) {
- /// <summary>Parses an ATOM document (feed, entry or service document).</summary>
- /// <param name="handler">This handler.</param>
- /// <param name="text" type="String">Document text.</param>
- /// <param name="context" type="Object">Object with parsing context.</param>
- /// <returns>An object representation of the document; undefined if not applicable.</returns>
-
- if (text) {
- var atomDoc = xmlParse(text);
- var atomRoot = xmlFirstChildElement(atomDoc);
- if (atomRoot) {
- return atomReadDocument(atomRoot, null, context.metadata);
- }
- }
- };
-
- var atomSerializer = function (handler, data, context) {
- /// <summary>Serializes an ATOM object into a document (feed or entry).</summary>
- /// <param name="handler">This handler.</param>
- /// <param name="data" type="Object">Representation of feed or entry.</param>
- /// <param name="context" type="Object">Object with parsing context.</param>
- /// <returns>An text representation of the data object; undefined if not applicable.</returns>
-
- var cType = context.contentType = context.contentType || contentType(atomMediaType);
- if (cType && cType.mediaType === atomMediaType) {
- var atomDoc = atomNewODataDocument(data, context.metadata);
- if (atomDoc) {
- context.dataServiceVersion = maxVersion(context.dataServiceVersion || "1.0", atomDoc.dsv);
- return xmlSerialize(atomDoc.element);
- }
- }
- // Allow undefined to be returned.
- };
-
- odata.atomHandler = handler(atomParser, atomSerializer, atomAcceptTypes.join(","), MAX_DATA_SERVICE_VERSION);
-
- // DATAJS INTERNAL START
- odata.atomParser = atomParser;
- odata.atomSerializer = atomSerializer;
- odata.atomReadDocument = atomReadDocument;
- odata.atomReadFeed = atomReadFeed;
- odata.atomReadFeedLink = atomReadFeedLink;
- odata.atomReadLink = atomReadLink;
- odata.atomReadExtensionElement = atomReadExtensionElement;
- odata.atomReadExtensionAttributes = atomReadExtensionAttributes;
- odata.atomReadEntry = atomReadEntry;
- odata.atomReadEntryType = atomReadEntryType;
- odata.atomReadEntryContent = atomReadEntryContent;
- odata.atomReadEntryLink = atomReadEntryLink;
- odata.atomReadEntryStructuralObject = atomReadEntryStructuralObject;
- odata.atomReadServiceDocument = atomReadServiceDocument;
- odata.atomReadServiceDocumentWorkspace = atomReadServiceDocumentWorkspace;
- odata.atomReadServiceDocumentCollection = atomReadServiceDocumentCollection;
- odata.expandedFeedCustomizationPath = expandedFeedCustomizationPath;
- odata.lookupPropertyType = lookupPropertyType;
- odata.atomSetEntryValueByPath = atomSetEntryValueByPath;
- // DATAJS INTERNAL END
-
- // CONTENT END
-})(this);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/odata-batch.js
----------------------------------------------------------------------
diff --git a/datajs/src/odata-batch.js b/datajs/src/odata-batch.js
deleted file mode 100644
index 770d875..0000000
--- a/datajs/src/odata-batch.js
+++ /dev/null
@@ -1,393 +0,0 @@
-/// <reference path="odata-utils.js" />
-
-// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
-// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// odata-batch.js
-
-(function (window, undefined) {
-
- var datajs = window.datajs || {};
- var odata = window.OData || {};
-
- // Imports
-
- var extend = datajs.extend;
- var isArray = datajs.isArray;
- var trimString = datajs.trimString;
-
- var contentType = odata.contentType;
- var handler = odata.handler;
- var isBatch = odata.isBatch;
- var MAX_DATA_SERVICE_VERSION = odata.MAX_DATA_SERVICE_VERSION;
- var normalizeHeaders = odata.normalizeHeaders;
- var payloadTypeOf = odata.payloadTypeOf;
- var prepareRequest = odata.prepareRequest;
-
- // CONTENT START
- var batchMediaType = "multipart/mixed";
- var responseStatusRegex = /^HTTP\/1\.\d (\d{3}) (.*)$/i;
- var responseHeaderRegex = /^([^()<>@,;:\\"\/[\]?={} \t]+)\s?:\s?(.*)/;
-
- var hex16 = function () {
- /// <summary>
- /// Calculates a random 16 bit number and returns it in hexadecimal format.
- /// </summary>
- /// <returns type="String">A 16-bit number in hex format.</returns>
-
- return Math.floor((1 + Math.random()) * 0x10000).toString(16).substr(1);
- };
-
- var createBoundary = function (prefix) {
- /// <summary>
- /// Creates a string that can be used as a multipart request boundary.
- /// </summary>
- /// <param name="prefix" type="String" optional="true">String to use as the start of the boundary string</param>
- /// <returns type="String">Boundary string of the format: <prefix><hex16>-<hex16>-<hex16></returns>
-
- return prefix + hex16() + "-" + hex16() + "-" + hex16();
- };
-
- var partHandler = function (context) {
- /// <summary>
- /// Gets the handler for data serialization of individual requests / responses in a batch.
- /// </summary>
- /// <param name="context">Context used for data serialization.</param>
- /// <returns>Handler object.</returns>
-
- return context.handler.partHandler;
- };
-
- var currentBoundary = function (context) {
- /// <summary>
- /// Gets the current boundary used for parsing the body of a multipart response.
- /// </summary>
- /// <param name="context">Context used for parsing a multipart response.</param>
- /// <returns type="String">Boundary string.</returns>
-
- var boundaries = context.boundaries;
- return boundaries[boundaries.length - 1];
- };
-
- var batchParser = function (handler, text, context) {
- /// <summary>Parses a batch response.</summary>
- /// <param name="handler">This handler.</param>
- /// <param name="text" type="String">Batch text.</param>
- /// <param name="context" type="Object">Object with parsing context.</param>
- /// <returns>An object representation of the batch.</returns>
-
- var boundary = context.contentType.properties["boundary"];
- return { __batchResponses: readBatch(text, { boundaries: [boundary], handlerContext: context }) };
- };
-
- var batchSerializer = function (handler, data, context) {
- /// <summary>Serializes a batch object representation into text.</summary>
- /// <param name="handler">This handler.</param>
- /// <param name="data" type="Object">Representation of a batch.</param>
- /// <param name="context" type="Object">Object with parsing context.</param>
- /// <returns>An text representation of the batch object; undefined if not applicable.</returns>
-
- var cType = context.contentType = context.contentType || contentType(batchMediaType);
- if (cType.mediaType === batchMediaType) {
- return writeBatch(data, context);
- }
- };
-
- var readBatch = function (text, context) {
- /// <summary>
- /// Parses a multipart/mixed response body from from the position defined by the context.
- /// </summary>
- /// <param name="text" type="String" optional="false">Body of the multipart/mixed response.</param>
- /// <param name="context">Context used for parsing.</param>
- /// <returns>Array of objects representing the individual responses.</returns>
-
- var delimiter = "--" + currentBoundary(context);
-
- // Move beyond the delimiter and read the complete batch
- readTo(text, context, delimiter);
-
- // Ignore the incoming line
- readLine(text, context);
-
- // Read the batch parts
- var responses = [];
- var partEnd;
-
- while (partEnd !== "--" && context.position < text.length) {
- var partHeaders = readHeaders(text, context);
- var partContentType = contentType(partHeaders["Content-Type"]);
-
- var changeResponses;
- if (partContentType && partContentType.mediaType === batchMediaType) {
- context.boundaries.push(partContentType.properties["boundary"]);
- try {
- changeResponses = readBatch(text, context);
- } catch (e) {
- e.response = readResponse(text, context, delimiter);
- changeResponses = [e];
- }
- responses.push({ __changeResponses: changeResponses });
- context.boundaries.pop();
- readTo(text, context, "--" + currentBoundary(context));
- } else {
- if (!partContentType || partContentType.mediaType !== "application/http") {
- throw { message: "invalid MIME part type " };
- }
- // Skip empty line
- readLine(text, context);
- // Read the response
- var response = readResponse(text, context, delimiter);
- try {
- if (response.statusCode >= 200 && response.statusCode <= 299) {
- partHandler(context.handlerContext).read(response, context.handlerContext);
- } else {
- // Keep track of failed responses and continue processing the batch.
- response = { message: "HTTP request failed", response: response };
- }
- } catch (e) {
- response = e;
- }
-
- responses.push(response);
- }
-
- partEnd = text.substr(context.position, 2);
-
- // Ignore the incoming line.
- readLine(text, context);
- }
- return responses;
- };
-
- var readHeaders = function (text, context) {
- /// <summary>
- /// Parses the http headers in the text from the position defined by the context.
- /// </summary>
- /// <param name="text" type="String" optional="false">Text containing an http response's headers</param>
- /// <param name="context">Context used for parsing.</param>
- /// <returns>Object containing the headers as key value pairs.</returns>
- /// <remarks>
- /// This function doesn't support split headers and it will stop reading when it hits two consecutive line breaks.
- /// </remarks>
-
- var headers = {};
- var parts;
- var line;
- var pos;
-
- do {
- pos = context.position;
- line = readLine(text, context);
- parts = responseHeaderRegex.exec(line);
- if (parts !== null) {
- headers[parts[1]] = parts[2];
- } else {
- // Whatever was found is not a header, so reset the context position.
- context.position = pos;
- }
- } while (line && parts);
-
- normalizeHeaders(headers);
-
- return headers;
- };
-
- var readResponse = function (text, context, delimiter) {
- /// <summary>
- /// Parses an HTTP response.
- /// </summary>
- /// <param name="text" type="String" optional="false">Text representing the http response.</param>
- /// <param name="context" optional="false">Context used for parsing.</param>
- /// <param name="delimiter" type="String" optional="false">String used as delimiter of the multipart response parts.</param>
- /// <returns>Object representing the http response.</returns>
-
- // Read the status line.
- var pos = context.position;
- var match = responseStatusRegex.exec(readLine(text, context));
-
- var statusCode;
- var statusText;
- var headers;
-
- if (match) {
- statusCode = match[1];
- statusText = match[2];
- headers = readHeaders(text, context);
- readLine(text, context);
- } else {
- context.position = pos;
- }
-
- return {
- statusCode: statusCode,
- statusText: statusText,
- headers: headers,
- body: readTo(text, context, "\r\n" + delimiter)
- };
- };
-
- var readLine = function (text, context) {
- /// <summary>
- /// Returns a substring from the position defined by the context up to the next line break (CRLF).
- /// </summary>
- /// <param name="text" type="String" optional="false">Input string.</param>
- /// <param name="context" optional="false">Context used for reading the input string.</param>
- /// <returns type="String">Substring to the first ocurrence of a line break or null if none can be found. </returns>
-
- return readTo(text, context, "\r\n");
- };
-
- var readTo = function (text, context, str) {
- /// <summary>
- /// Returns a substring from the position given by the context up to value defined by the str parameter and increments the position in the context.
- /// </summary>
- /// <param name="text" type="String" optional="false">Input string.</param>
- /// <param name="context" type="Object" optional="false">Context used for reading the input string.</param>
- /// <param name="str" type="String" optional="true">Substring to read up to.</param>
- /// <returns type="String">Substring to the first ocurrence of str or the end of the input string if str is not specified. Null if the marker is not found.</returns>
-
- var start = context.position || 0;
- var end = text.length;
- if (str) {
- end = text.indexOf(str, start);
- if (end === -1) {
- return null;
- }
- context.position = end + str.length;
- } else {
- context.position = end;
- }
-
- return text.substring(start, end);
- };
-
- var writeBatch = function (data, context) {
- /// <summary>
- /// Serializes a batch request object to a string.
- /// </summary>
- /// <param name="data" optional="false">Batch request object in payload representation format</param>
- /// <param name="context" optional="false">Context used for the serialization</param>
- /// <returns type="String">String representing the batch request</returns>
-
- if (!isBatch(data)) {
- throw { message: "Data is not a batch object." };
- }
-
- var batchBoundary = createBoundary("batch_");
- var batchParts = data.__batchRequests;
- var batch = "";
- var i, len;
- for (i = 0, len = batchParts.length; i < len; i++) {
- batch += writeBatchPartDelimiter(batchBoundary, false) +
- writeBatchPart(batchParts[i], context);
- }
- batch += writeBatchPartDelimiter(batchBoundary, true);
-
- // Register the boundary with the request content type.
- var contentTypeProperties = context.contentType.properties;
- contentTypeProperties.boundary = batchBoundary;
-
- return batch;
- };
-
- var writeBatchPartDelimiter = function (boundary, close) {
- /// <summary>
- /// Creates the delimiter that indicates that start or end of an individual request.
- /// </summary>
- /// <param name="boundary" type="String" optional="false">Boundary string used to indicate the start of the request</param>
- /// <param name="close" type="Boolean">Flag indicating that a close delimiter string should be generated</param>
- /// <returns type="String">Delimiter string</returns>
-
- var result = "\r\n--" + boundary;
- if (close) {
- result += "--";
- }
-
- return result + "\r\n";
- };
-
- var writeBatchPart = function (part, context, nested) {
- /// <summary>
- /// Serializes a part of a batch request to a string. A part can be either a GET request or
- /// a change set grouping several CUD (create, update, delete) requests.
- /// </summary>
- /// <param name="part" optional="false">Request or change set object in payload representation format</param>
- /// <param name="context" optional="false">Object containing context information used for the serialization</param>
- /// <param name="nested" type="boolean" optional="true">Flag indicating that the part is nested inside a change set</param>
- /// <returns type="String">String representing the serialized part</returns>
- /// <remarks>
- /// A change set is an array of request objects and they cannot be nested inside other change sets.
- /// </remarks>
-
- var changeSet = part.__changeRequests;
- var result;
- if (isArray(changeSet)) {
- if (nested) {
- throw { message: "Not Supported: change set nested in other change set" };
- }
-
- var changeSetBoundary = createBoundary("changeset_");
- result = "Content-Type: " + batchMediaType + "; boundary=" + changeSetBoundary + "\r\n";
- var i, len;
- for (i = 0, len = changeSet.length; i < len; i++) {
- result += writeBatchPartDelimiter(changeSetBoundary, false) +
- writeBatchPart(changeSet[i], context, true);
- }
-
- result += writeBatchPartDelimiter(changeSetBoundary, true);
- } else {
- result = "Content-Type: application/http\r\nContent-Transfer-Encoding: binary\r\n\r\n";
- var partContext = extend({}, context);
- partContext.handler = handler;
- partContext.request = part;
- partContext.contentType = null;
-
- prepareRequest(part, partHandler(context), partContext);
- result += writeRequest(part);
- }
-
- return result;
- };
-
- var writeRequest = function (request) {
- /// <summary>
- /// Serializes a request object to a string.
- /// </summary>
- /// <param name="request" optional="false">Request object to serialize</param>
- /// <returns type="String">String representing the serialized request</returns>
-
- var result = (request.method ? request.method : "GET") + " " + request.requestUri + " HTTP/1.1\r\n";
- for (var name in request.headers) {
- if (request.headers[name]) {
- result = result + name + ": " + request.headers[name] + "\r\n";
- }
- }
-
- result += "\r\n";
-
- if (request.body) {
- result += request.body;
- }
-
- return result;
- };
-
- odata.batchHandler = handler(batchParser, batchSerializer, batchMediaType, MAX_DATA_SERVICE_VERSION);
-
- // DATAJS INTERNAL START
- odata.batchSerializer = batchSerializer;
- odata.writeRequest = writeRequest;
- // DATAJS INTERNAL END
-
- // CONTENT END
-})(this);
\ No newline at end of file
[06/15] [OLINGO-238] Build infrastructure for datajs I
Posted by ko...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/odata-gml.js
----------------------------------------------------------------------
diff --git a/datajs/src/odata-gml.js b/datajs/src/odata-gml.js
deleted file mode 100644
index 2bcf5f5..0000000
--- a/datajs/src/odata-gml.js
+++ /dev/null
@@ -1,831 +0,0 @@
-// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
-// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// odata-gml.js
-
-(function (window, undefined) {
-
- var datajs = window.datajs || {};
- var odata = window.OData || {};
-
- // Imports.
-
- var contains = datajs.contains;
- var djsassert = datajs.djsassert;
- var http = datajs.http;
- var isArray = datajs.isArray;
- var xmlAppendChild = datajs.xmlAppendChild;
- var xmlAttributeValue = datajs.xmlAttributeValue;
- var xmlChildElements = datajs.xmlChildElements;
- var xmlFirstChildElement = datajs.xmlFirstChildElement;
- var xmlInnerText = datajs.xmlInnerText;
- var xmlLocalName = datajs.xmlLocalName;
- var xmlNamespaceURI = datajs.xmlNamespaceURI;
- var xmlNewElement = datajs.xmlNewElement;
- var xmlQualifiedName = datajs.xmlQualifiedName;
- var GEOJSON_POINT = odata.GEOJSON_POINT;
- var GEOJSON_LINESTRING = odata.GEOJSON_LINESTRING;
- var GEOJSON_POLYGON = odata.GEOJSON_POLYGON;
- var GEOJSON_MULTIPOINT = odata.GEOJSON_MULTIPOINT;
- var GEOJSON_MULTILINESTRING = odata.GEOJSON_MULTILINESTRING;
- var GEOJSON_MULTIPOLYGON = odata.GEOJSON_MULTIPOLYGON;
- var GEOJSON_GEOMETRYCOLLECTION = odata.GEOJSON_GEOMETRYCOLLECTION;
-
- // CONTENT START
- var gmlOpenGis = http + "www.opengis.net"; // http://www.opengis.net
- var gmlXmlNs = gmlOpenGis + "/gml"; // http://www.opengis.net/gml
- var gmlSrsPrefix = gmlOpenGis + "/def/crs/EPSG/0/"; // http://www.opengis.net/def/crs/EPSG/0/
-
- var gmlPrefix = "gml";
-
- var gmlCreateGeoJSONOBject = function (type, member, data) {
- /// <summary>Creates a GeoJSON object with the specified type, member and value.</summary>
- /// <param name="type" type="String">GeoJSON object type.</param>
- /// <param name="member" type="String">Name for the data member in the GeoJSON object.</param>
- /// <param name="data">Data to be contained by the GeoJSON object.</param>
- /// <returns type="Object">GeoJSON object.</returns>
-
- var result = { type: type };
- result[member] = data;
- return result;
- };
-
- var gmlSwapLatLong = function (coordinates) {
- /// <summary>Swaps the longitude and latitude in the coordinates array.</summary>
- /// <param name="coordinates" type="Array">Array of doubles descrbing a set of coordinates.</param>
- /// <returns type="Array">Array of doubles with the latitude and longitude components swapped.</returns>
-
- if (isArray(coordinates) && coordinates.length >= 2) {
- var tmp = coordinates[0];
- coordinates[0] = coordinates[1];
- coordinates[1] = tmp;
- }
- return coordinates;
- };
-
- var gmlReadODataMultiItem = function (domElement, type, member, members, valueReader, isGeography) {
- /// <summary>
- /// Reads a GML DOM element that represents a composite structure like a multi-point or a
- /// multi-geometry returnig its GeoJSON representation.
- /// </summary>
- /// <param name="domElement">GML DOM element.</param>
- /// <param name="type" type="String">GeoJSON object type.</param>
- /// <param name="member" type="String">Name for the child element representing a single item in the composite structure.</param>
- /// <param name="members" type="String">Name for the child element representing a collection of items in the composite structure.</param>
- /// <param name="valueReader" type="Function">Callback function invoked to get the coordinates of each item in the comoposite structure.</param>
- /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
- /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns type="Object">GeoJSON object.</returns>
-
- var coordinates = gmlReadODataMultiItemValue(domElement, member, members, valueReader, isGeography);
- return gmlCreateGeoJSONOBject(type, "coordinates", coordinates);
- };
-
- var gmlReadODataMultiItemValue = function (domElement, member, members, valueReader, isGeography) {
- /// <summary>
- /// Reads the value of a GML DOM element that represents a composite structure like a multi-point or a
- /// multi-geometry returnig its items.
- /// </summary>
- /// <param name="domElement">GML DOM element.</param>
- /// <param name="type" type="String">GeoJSON object type.</param>
- /// <param name="member" type="String">Name for the child element representing a single item in the composite structure.</param>
- /// <param name="members" type="String">Name for the child element representing a collection of items in the composite structure.</param>
- /// <param name="valueReader" type="Function">Callback function invoked to get the transformed value of each item in the comoposite structure.</param>
- /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
- /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns type="Array">Array containing the transformed value of each item in the multi-item.</returns>
-
- var items = [];
-
- xmlChildElements(domElement, function (child) {
- if (xmlNamespaceURI(child) !== gmlXmlNs) {
- return;
- }
-
- var localName = xmlLocalName(child);
-
- if (localName === member) {
- var valueElement = xmlFirstChildElement(child, gmlXmlNs);
- if (valueElement) {
- var value = valueReader(valueElement, isGeography);
- if (value) {
- items.push(value);
- }
- }
- return;
- }
-
- if (localName === members) {
- xmlChildElements(child, function (valueElement) {
- if (xmlNamespaceURI(valueElement) !== gmlXmlNs) {
- return;
- }
-
- var value = valueReader(valueElement, isGeography);
- if (value) {
- items.push(value);
- }
- });
- }
- });
- return items;
- };
-
- var gmlReadODataCollection = function (domElement, isGeography) {
- /// <summary>Reads a GML DOM element representing a multi-geometry returning its GeoJSON representation.</summary>
- /// <param name="domElement">DOM element.</param>
- /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
- /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns type="Object">MultiGeometry object in GeoJSON format.</returns>
-
- var geometries = gmlReadODataMultiItemValue(domElement, "geometryMember", "geometryMembers", gmlReadODataSpatialValue, isGeography);
- return gmlCreateGeoJSONOBject(GEOJSON_GEOMETRYCOLLECTION, "geometries", geometries);
- };
-
- var gmlReadODataLineString = function (domElement, isGeography) {
- /// <summary>Reads a GML DOM element representing a line string returning its GeoJSON representation.</summary>
- /// <param name="domElement">DOM element.</param>
- /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
- /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns type="Object">LineString object in GeoJSON format.</returns>
-
- return gmlCreateGeoJSONOBject(GEOJSON_LINESTRING, "coordinates", gmlReadODataLineValue(domElement, isGeography));
- };
-
- var gmlReadODataMultiLineString = function (domElement, isGeography) {
- /// <summary>Reads a GML DOM element representing a multi-line string returning its GeoJSON representation.</summary>
- /// <param name="domElement">DOM element.</param>
- /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
- /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns type="Object">MultiLineString object in GeoJSON format.</returns>
-
- return gmlReadODataMultiItem(domElement, GEOJSON_MULTILINESTRING, "curveMember", "curveMembers", gmlReadODataLineValue, isGeography);
- };
-
- var gmlReadODataMultiPoint = function (domElement, isGeography) {
- /// <summary>Reads a GML DOM element representing a multi-point returning its GeoJSON representation.</summary>
- /// <param name="domElement">DOM element.</param>
- /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
- /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns type="Object">MultiPoint object in GeoJSON format.</returns>
-
- return gmlReadODataMultiItem(domElement, GEOJSON_MULTIPOINT, "pointMember", "pointMembers", gmlReadODataPointValue, isGeography);
- };
-
- var gmlReadODataMultiPolygon = function (domElement, isGeography) {
- /// <summary>Reads a GML DOM element representing a multi-polygon returning its GeoJSON representation.</summary>
- /// <param name="domElement">DOM element.</param>
- /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
- /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns type="Object">MultiPolygon object in GeoJSON format.</returns>
-
- return gmlReadODataMultiItem(domElement, GEOJSON_MULTIPOLYGON, "surfaceMember", "surfaceMembers", gmlReadODataPolygonValue, isGeography);
- };
-
- var gmlReadODataPoint = function (domElement, isGeography) {
- /// <summary>Reads a GML DOM element representing a point returning its GeoJSON representation.</summary>
- /// <param name="domElement">DOM element.</param>
- /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
- /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns type="Object">Point object in GeoJSON format.</returns>
-
- return gmlCreateGeoJSONOBject(GEOJSON_POINT, "coordinates", gmlReadODataPointValue(domElement, isGeography));
- };
-
- var gmlReadODataPolygon = function (domElement, isGeography) {
- /// <summary>Reads a GML DOM element representing a polygon returning its GeoJSON representation.</summary>
- /// <param name="domElement">DOM element.</param>
- /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
- /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns type="Object">Polygon object in GeoJSON format.</returns>
-
- return gmlCreateGeoJSONOBject(GEOJSON_POLYGON, "coordinates", gmlReadODataPolygonValue(domElement, isGeography));
- };
-
- var gmlReadODataLineValue = function (domElement, isGeography) {
- /// <summary>Reads the value of a GML DOM element representing a line returning its set of coordinates.</summary>
- /// <param name="domElement">DOM element.</param>
- /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
- /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns type="Array">Array containing an array of doubles for each coordinate of the line.</returns>
-
- var coordinates = [];
-
- xmlChildElements(domElement, function (child) {
- var nsURI = xmlNamespaceURI(child);
-
- if (nsURI !== gmlXmlNs) {
- return;
- }
-
- var localName = xmlLocalName(child);
-
- if (localName === "posList") {
- coordinates = gmlReadODataPosListValue(child, isGeography);
- return;
- }
- if (localName === "pointProperty") {
- coordinates.push(gmlReadODataPointWrapperValue(child, isGeography));
- return;
- }
- if (localName === "pos") {
- coordinates.push(gmlReadODataPosValue(child, isGeography));
- return;
- }
- });
-
- return coordinates;
- };
-
- var gmlReadODataPointValue = function (domElement, isGeography) {
- /// <summary>Reads the value of a GML DOM element representing a point returning its coordinates.</summary>
- /// <param name="domElement">DOM element.</param>
- /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
- /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns type="Array">Array of doubles containing the point coordinates.</returns>
-
- var pos = xmlFirstChildElement(domElement, gmlXmlNs, "pos");
- return pos ? gmlReadODataPosValue(pos, isGeography) : [];
- };
-
- var gmlReadODataPointWrapperValue = function (domElement, isGeography) {
- /// <summary>Reads the value of a GML DOM element wrapping an element representing a point returning its coordinates.</summary>
- /// <param name="domElement">DOM element.</param>
- /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
- /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns type="Array">Array of doubles containing the point coordinates.</returns>
-
- var point = xmlFirstChildElement(domElement, gmlXmlNs, "Point");
- return point ? gmlReadODataPointValue(point, isGeography) : [];
- };
-
- var gmlReadODataPolygonValue = function (domElement, isGeography) {
- /// <summary>Reads the value of a GML DOM element representing a polygon returning its set of coordinates.</summary>
- /// <param name="domElement">DOM element.</param>
- /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
- /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns type="Array">Array containing an array of array of doubles for each ring of the polygon.</returns>
-
- var coordinates = [];
- var exteriorFound = false;
- xmlChildElements(domElement, function (child) {
- if (xmlNamespaceURI(child) !== gmlXmlNs) {
- return;
- }
-
- // Only the exterior and the interior rings are interesting
- var localName = xmlLocalName(child);
- if (localName === "exterior") {
- exteriorFound = true;
- coordinates.unshift(gmlReadODataPolygonRingValue(child, isGeography));
- return;
- }
- if (localName === "interior") {
- coordinates.push(gmlReadODataPolygonRingValue(child, isGeography));
- return;
- }
- });
-
- if (!exteriorFound && coordinates.length > 0) {
- // Push an empty exterior ring.
- coordinates.unshift([[]]);
- }
-
- return coordinates;
- };
-
- var gmlReadODataPolygonRingValue = function (domElement, isGeography) {
- /// <summary>Reads the value of a GML DOM element representing a linear ring in a GML Polygon element.</summary>
- /// <param name="domElement">DOM element.</param>
- /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
- /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns type="Array">Array containing an array of doubles for each coordinate of the linear ring.</returns>
-
- var value = [];
- xmlChildElements(domElement, function (child) {
- if (xmlNamespaceURI(child) !== gmlXmlNs || xmlLocalName(child) !== "LinearRing") {
- return;
- }
- value = gmlReadODataLineValue(child, isGeography);
- });
- return value;
- };
-
- var gmlReadODataPosListValue = function (domElement, isGeography) {
- /// <summary>Reads the value of a GML DOM element representing a list of positions retruning its set of coordinates.</summary>
- /// <param name="domElement">DOM element.</param>
- /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
- /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
- ///
- /// The positions described by the list are assumed to be 2D, so
- /// an exception will be thrown if the list has an odd number elements.
- /// </remarks>
- /// <returns type="Array">Array containing an array of doubles for each coordinate in the list.</returns>
-
- var coordinates = gmlReadODataPosValue(domElement, false);
- var len = coordinates.length;
-
- if (len % 2 !== 0) {
- throw { message: "GML posList element has an uneven number of numeric values" };
- }
-
- var value = [];
- for (var i = 0; i < len; i += 2) {
- var pos = coordinates.slice(i, i + 2);
- value.push(isGeography ? gmlSwapLatLong(pos) : pos);
- }
- return value;
- };
-
- var gmlReadODataPosValue = function (domElement, isGeography) {
- /// <summary>Reads the value of a GML element describing a position or a set of coordinates in an OData spatial property value.</summary>
- /// <param name="property">DOM element for the GML element.</param>
- /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
- /// will be deserialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns type="Array">Array of doubles containing the coordinates.</returns>
-
- var value = [];
- var delims = " \t\r\n";
- var text = xmlInnerText(domElement);
-
- if (text) {
- var len = text.length;
- var start = 0;
- var end = 0;
-
- while (end <= len) {
- if (delims.indexOf(text.charAt(end)) !== -1) {
- var coord = text.substring(start, end);
- if (coord) {
- value.push(parseFloat(coord));
- }
- start = end + 1;
- }
- end++;
- }
- }
-
- return isGeography ? gmlSwapLatLong(value) : value;
- };
-
- var gmlReadODataSpatialValue = function (domElement, isGeography) {
- /// <summary>Reads the value of a GML DOM element a spatial value in an OData XML document.</summary>
- /// <param name="domElement">DOM element.</param>
- /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
- /// will be deserialized as the second component of each position coordinates in the resulting GeoJSON object.
- /// </remarks>
- /// <returns type="Array">Array containing an array of doubles for each coordinate of the polygon.</returns>
-
- var localName = xmlLocalName(domElement);
- var reader;
-
- switch (localName) {
- case "Point":
- reader = gmlReadODataPoint;
- break;
- case "Polygon":
- reader = gmlReadODataPolygon;
- break;
- case "LineString":
- reader = gmlReadODataLineString;
- break;
- case "MultiPoint":
- reader = gmlReadODataMultiPoint;
- break;
- case "MultiCurve":
- reader = gmlReadODataMultiLineString;
- break;
- case "MultiSurface":
- reader = gmlReadODataMultiPolygon;
- break;
- case "MultiGeometry":
- reader = gmlReadODataCollection;
- break;
- default:
- throw { message: "Unsupported element: " + localName, element: domElement };
- }
-
- var value = reader(domElement, isGeography);
- // Read the CRS
- // WCF Data Services qualifies the srsName attribute withing the GML namespace; however
- // other end points might no do this as per the standard.
-
- var srsName = xmlAttributeValue(domElement, "srsName", gmlXmlNs) ||
- xmlAttributeValue(domElement, "srsName");
-
- if (srsName) {
- if (srsName.indexOf(gmlSrsPrefix) !== 0) {
- throw { message: "Unsupported srs name: " + srsName, element: domElement };
- }
-
- var crsId = srsName.substring(gmlSrsPrefix.length);
- if (crsId) {
- value.crs = {
- type: "name",
- properties: {
- name: "EPSG:" + crsId
- }
- };
- }
- }
- return value;
- };
-
- var gmlNewODataSpatialValue = function (dom, value, type, isGeography) {
- /// <summary>Creates a new GML DOM element for the value of an OData spatial property or GeoJSON object.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="value" type="Object">Spatial property value in GeoJSON format.</param>
- /// <param name="type" type="String">String indicating the GeoJSON type of the value to serialize.</param>
- /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
- /// will be serialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns>New DOM element in the GML namespace for the spatial value. </returns>
-
- var gmlWriter;
-
- switch (type) {
- case GEOJSON_POINT:
- gmlWriter = gmlNewODataPoint;
- break;
- case GEOJSON_LINESTRING:
- gmlWriter = gmlNewODataLineString;
- break;
- case GEOJSON_POLYGON:
- gmlWriter = gmlNewODataPolygon;
- break;
- case GEOJSON_MULTIPOINT:
- gmlWriter = gmlNewODataMultiPoint;
- break;
- case GEOJSON_MULTILINESTRING:
- gmlWriter = gmlNewODataMultiLineString;
- break;
- case GEOJSON_MULTIPOLYGON:
- gmlWriter = gmlNewODataMultiPolygon;
- break;
- case GEOJSON_GEOMETRYCOLLECTION:
- gmlWriter = gmlNewODataGeometryCollection;
- break;
- default:
- djsassert(false, "gmlNewODataSpatialValue - Unknown GeoJSON type <" + type + ">!!");
- return null;
- }
-
- var gml = gmlWriter(dom, value, isGeography);
-
- // Set the srsName attribute if applicable.
- var crs = value.crs;
- if (crs) {
- if (crs.type === "name") {
- var properties = crs.properties;
- var name = properties && properties.name;
- if (name && name.indexOf("ESPG:") === 0 && name.length > 5) {
- var crsId = name.substring(5);
- var srsName = xmlNewAttribute(dom, null, "srsName", gmlPrefix + crsId);
- xmlAppendChild(gml, srsName);
- }
- }
- }
-
- return gml;
- };
-
- var gmlNewODataElement = function (dom, name, children) {
- /// <summary>Creates a new DOM element in the GML namespace.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="name" type="String">Local name of the GML element to create.</param>
- /// <param name="children" type="Array">Array containing DOM nodes or string values that will be added as children of the new DOM element.</param>
- /// <returns>New DOM element in the GML namespace.</returns>
- /// <remarks>
- /// If a value in the children collection is a string, then a new DOM text node is going to be created
- /// for it and then appended as a child of the new DOM Element.
- /// </remarks>
-
- return xmlNewElement(dom, gmlXmlNs, xmlQualifiedName(gmlPrefix, name), children);
- };
-
- var gmlNewODataPosElement = function (dom, coordinates, isGeography) {
- /// <summary>Creates a new GML pos DOM element.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="coordinates" type="Array">Array of doubles describing the coordinates of the pos element.</param>
- /// <param name="isGeography" type="Boolean">Flag indicating if the coordinates use a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first coordinate is the Longitude and
- /// will be serialized as the second component of the <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns>New pos DOM element in the GML namespace.</returns>
-
- var posValue = isArray(coordinates) ? coordinates : [];
-
- // If using a geographic reference system, then the first coordinate is the longitude and it has to
- // swapped with the latitude.
- posValue = isGeography ? gmlSwapLatLong(posValue) : posValue;
-
- return gmlNewODataElement(dom, "pos", posValue.join(" "));
- };
-
- var gmlNewODataLineElement = function (dom, name, coordinates, isGeography) {
- /// <summary>Creates a new GML DOM element representing a line.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="name" type="String">Name of the element to create.</param>
- /// <param name="coordinates" type="Array">Array of array of doubles describing the coordinates of the line element.</param>
- /// <param name="isGeography" type="Boolean">Flag indicating if the coordinates use a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates is the Longitude and
- /// will be serialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns>New DOM element in the GML namespace.</returns>
-
- var element = gmlNewODataElement(dom, name);
- if (isArray(coordinates)) {
- var i, len;
- for (i = 0, len = coordinates.length; i < len; i++) {
- xmlAppendChild(element, gmlNewODataPosElement(dom, coordinates[i], isGeography));
- }
-
- if (len === 0) {
- xmlAppendChild(element, gmlNewODataElement(dom, "posList"));
- }
- }
- return element;
- };
-
- var gmlNewODataPointElement = function (dom, coordinates, isGeography) {
- /// <summary>Creates a new GML Point DOM element.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="value" type="Object">GeoJSON Point object.</param>
- /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
- /// will be serialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns>New DOM element in the GML namespace for the GeoJSON Point.</returns>
-
- return gmlNewODataElement(dom, "Point", gmlNewODataPosElement(dom, coordinates, isGeography));
- };
-
- var gmlNewODataLineStringElement = function (dom, coordinates, isGeography) {
- /// <summary>Creates a new GML LineString DOM element.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="coordinates" type="Array">Array of array of doubles describing the coordinates of the line element.</param>
- /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
- /// will be serialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns>New DOM element in the GML namespace for the GeoJSON LineString.</returns>
-
- return gmlNewODataLineElement(dom, "LineString", coordinates, isGeography);
- };
-
- var gmlNewODataPolygonRingElement = function (dom, name, coordinates, isGeography) {
- /// <summary>Creates a new GML DOM element representing a polygon ring.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="name" type="String">Name of the element to create.</param>
- /// <param name="coordinates" type="Array">Array of array of doubles describing the coordinates of the polygon ring.</param>
- /// <param name="isGeography" type="Boolean">Flag indicating if the coordinates use a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates is the Longitude and
- /// will be serialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns>New DOM element in the GML namespace.</returns>
-
- var ringElement = gmlNewODataElement(dom, name);
- if (isArray(coordinates) && coordinates.length > 0) {
- var linearRing = gmlNewODataLineElement(dom, "LinearRing", coordinates, isGeography);
- xmlAppendChild(ringElement, linearRing);
- }
- return ringElement;
- };
-
- var gmlNewODataPolygonElement = function (dom, coordinates, isGeography) {
- /// <summary>Creates a new GML Polygon DOM element for a GeoJSON Polygon object.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="coordinates" type="Array">Array of array of array of doubles describing the coordinates of the polygon.</param>
- /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
- /// will be serialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns>New DOM element in the GML namespace.</returns>
-
- var len = coordinates && coordinates.length;
- var element = gmlNewODataElement(dom, "Polygon");
-
- if (isArray(coordinates) && len > 0) {
- xmlAppendChild(element, gmlNewODataPolygonRingElement(dom, "exterior", coordinates[0], isGeography));
-
- var i;
- for (i = 1; i < len; i++) {
- xmlAppendChild(element, gmlNewODataPolygonRingElement(dom, "interior", coordinates[i], isGeography));
- }
- }
- return element;
- };
-
- var gmlNewODataPoint = function (dom, value, isGeography) {
- /// <summary>Creates a new GML Point DOM element for a GeoJSON Point object.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="value" type="Object">GeoJSON Point object.</param>
- /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
- /// will be serialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns>New DOM element in the GML namespace for the GeoJSON Point.</returns>
-
- return gmlNewODataPointElement(dom, value.coordinates, isGeography);
- };
-
- var gmlNewODataLineString = function (dom, value, isGeography) {
- /// <summary>Creates a new GML LineString DOM element for a GeoJSON LineString object.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="value" type="Object">GeoJSON LineString object.</param>
- /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
- /// will be serialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns>New DOM element in the GML namespace for the GeoJSON LineString.</returns>
-
- return gmlNewODataLineStringElement(dom, value.coordinates, isGeography);
- };
-
- var gmlNewODataPolygon = function (dom, value, isGeography) {
- /// <summary>Creates a new GML Polygon DOM element for a GeoJSON Polygon object.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="value" type="Object">GeoJSON Polygon object.</param>
- /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
- /// will be serialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns>New DOM element in the GML namespace for the GeoJSON Polygon.</returns>
-
- return gmlNewODataPolygonElement(dom, value.coordinates, isGeography);
- };
-
- var gmlNewODataMultiItem = function (dom, name, members, items, itemWriter, isGeography) {
- /// <summary>Creates a new GML DOM element for a composite structure like a multi-point or a multi-geometry.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="name" type="String">Name of the element to create.</param>
- /// <param name="items" type="Array">Array of items in the composite structure.</param>
- /// <param name="isGeography" type="Boolean">Flag indicating if the multi-item uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in each of the items is the Longitude and
- /// will be serialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns>New DOM element in the GML namespace.</returns>
-
- var len = items && items.length;
- var element = gmlNewODataElement(dom, name);
-
- if (isArray(items) && len > 0) {
- var membersElement = gmlNewODataElement(dom, members);
- var i;
- for (i = 0; i < len; i++) {
- xmlAppendChild(membersElement, itemWriter(dom, items[i], isGeography));
- }
- xmlAppendChild(element, membersElement);
- }
- return element;
- };
-
- var gmlNewODataMultiPoint = function (dom, value, isGeography) {
- /// <summary>Creates a new GML MultiPoint DOM element for a GeoJSON MultiPoint object.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="value" type="Object">GeoJSON MultiPoint object.</param>
- /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
- /// will be serialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns>New DOM element in the GML namespace for the GeoJSON MultiPoint.</returns>
-
- return gmlNewODataMultiItem(dom, "MultiPoint", "pointMembers", value.coordinates, gmlNewODataPointElement, isGeography);
- };
-
- var gmlNewODataMultiLineString = function (dom, value, isGeography) {
- /// <summary>Creates a new GML MultiCurve DOM element for a GeoJSON MultiLineString object.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="value" type="Object">GeoJSON MultiLineString object.</param>
- /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
- /// will be serialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns>New DOM element in the GML namespace for the GeoJSON MultiLineString.</returns>
-
- return gmlNewODataMultiItem(dom, "MultiCurve", "curveMembers", value.coordinates, gmlNewODataLineStringElement, isGeography);
- };
-
- var gmlNewODataMultiPolygon = function (dom, value, isGeography) {
- /// <summary>Creates a new GML MultiSurface DOM element for a GeoJSON MultiPolygon object.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="value" type="Object">GeoJSON MultiPolygon object.</param>
- /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
- /// will be serialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns>New DOM element in the GML namespace for the GeoJSON MultiPolygon.</returns>
-
- return gmlNewODataMultiItem(dom, "MultiSurface", "surfaceMembers", value.coordinates, gmlNewODataPolygonElement, isGeography);
- };
-
- var gmlNewODataGeometryCollectionItem = function (dom, value, isGeography) {
- /// <summary>Creates a new GML element for an item in a geometry collection object.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="item" type="Object">GeoJSON object in the geometry collection.</param>
- /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
- /// will be serialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns>New DOM element in the GML namespace.</returns>
-
- return gmlNewODataSpatialValue(dom, value, value.type, isGeography);
- };
-
- var gmlNewODataGeometryCollection = function (dom, value, isGeography) {
- /// <summary>Creates a new GML MultiGeometry DOM element for a GeoJSON GeometryCollection object.</summary>
- /// <param name="dom">DOM document used for creating the new DOM Element.</param>
- /// <param name="value" type="Object">GeoJSON GeometryCollection object.</param>
- /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
- /// <remarks>
- /// When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
- /// will be serialized as the second component of each <pos> element in the GML DOM tree.
- /// </remarks>
- /// <returns>New DOM element in the GML namespace for the GeoJSON GeometryCollection.</returns>
-
- return gmlNewODataMultiItem(dom, "MultiGeometry", "geometryMembers", value.geometries, gmlNewODataGeometryCollectionItem, isGeography);
- };
-
- // DATAJS INTERNAL START
- odata.gmlNewODataSpatialValue = gmlNewODataSpatialValue;
- odata.gmlReadODataSpatialValue = gmlReadODataSpatialValue;
- odata.gmlXmlNs = gmlXmlNs;
- // DATAJS INTERNAL END
-
- // CONTENT END
-})(this);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/f1cfcbc5/datajs/src/odata-handler.js
----------------------------------------------------------------------
diff --git a/datajs/src/odata-handler.js b/datajs/src/odata-handler.js
deleted file mode 100644
index 5f83429..0000000
--- a/datajs/src/odata-handler.js
+++ /dev/null
@@ -1,276 +0,0 @@
-// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
-// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// odata-handler.js
-
-(function (window, undefined) {
-
- var datajs = window.datajs || {};
- var odata = window.OData || {};
-
- // Imports.
- var assigned = datajs.assigned;
- var extend = datajs.extend;
- var trimString = datajs.trimString;
-
- var maxVersion = odata.maxVersion;
-
- // CONTENT START
-
- var MAX_DATA_SERVICE_VERSION = "3.0";
-
- var contentType = function (str) {
- /// <summary>Parses a string into an object with media type and properties.</summary>
- /// <param name="str" type="String">String with media type to parse.</param>
- /// <returns>null if the string is empty; an object with 'mediaType' and a 'properties' dictionary otherwise.</returns>
-
- if (!str) {
- return null;
- }
-
- var contentTypeParts = str.split(";");
- var properties = {};
-
- var i, len;
- for (i = 1, len = contentTypeParts.length; i < len; i++) {
- var contentTypeParams = contentTypeParts[i].split("=");
- properties[trimString(contentTypeParams[0])] = contentTypeParams[1];
- }
-
- return { mediaType: trimString(contentTypeParts[0]), properties: properties };
- };
-
- var contentTypeToString = function (contentType) {
- /// <summary>Serializes an object with media type and properties dictionary into a string.</summary>
- /// <param name="contentType">Object with media type and properties dictionary to serialize.</param>
- /// <returns>String representation of the media type object; undefined if contentType is null or undefined.</returns>
-
- if (!contentType) {
- return undefined;
- }
-
- var result = contentType.mediaType;
- var property;
- for (property in contentType.properties) {
- result += ";" + property + "=" + contentType.properties[property];
- }
- return result;
- };
-
- var createReadWriteContext = function (contentType, dataServiceVersion, context, handler) {
- /// <summary>Creates an object that is going to be used as the context for the handler's parser and serializer.</summary>
- /// <param name="contentType">Object with media type and properties dictionary.</param>
- /// <param name="dataServiceVersion" type="String">String indicating the version of the protocol to use.</param>
- /// <param name="context">Operation context.</param>
- /// <param name="handler">Handler object that is processing a resquest or response.</param>
- /// <returns>Context object.</returns>
-
- var rwContext = {};
- extend(rwContext, context);
- extend(rwContext, {
- contentType: contentType,
- dataServiceVersion: dataServiceVersion,
- handler: handler
- });
-
- return rwContext;
- };
-
- var fixRequestHeader = function (request, name, value) {
- /// <summary>Sets a request header's value. If the header has already a value other than undefined, null or empty string, then this method does nothing.</summary>
- /// <param name="request">Request object on which the header will be set.</param>
- /// <param name="name" type="String">Header name.</param>
- /// <param name="value" type="String">Header value.</param>
- if (!request) {
- return;
- }
-
- var headers = request.headers;
- if (!headers[name]) {
- headers[name] = value;
- }
- };
-
- var fixDataServiceVersionHeader = function (request, version) {
- /// <summary>Sets the DataServiceVersion header of the request if its value is not yet defined or of a lower version.</summary>
- /// <param name="request">Request object on which the header will be set.</param>
- /// <param name="version" type="String">Version value.</param>
- /// <remarks>
- /// If the request has already a version value higher than the one supplied the this function does nothing.
- /// </remarks>
-
- if (request) {
- var headers = request.headers;
- var dsv = headers["DataServiceVersion"];
- headers["DataServiceVersion"] = dsv ? maxVersion(dsv, version) : version;
- }
- };
-
- var getRequestOrResponseHeader = function (requestOrResponse, name) {
- /// <summary>Gets the value of a request or response header.</summary>
- /// <param name="requestOrResponse">Object representing a request or a response.</param>
- /// <param name="name" type="String">Name of the header to retrieve.</param>
- /// <returns type="String">String value of the header; undefined if the header cannot be found.</returns>
-
- var headers = requestOrResponse.headers;
- return (headers && headers[name]) || undefined;
- };
-
- var getContentType = function (requestOrResponse) {
- /// <summary>Gets the value of the Content-Type header from a request or response.</summary>
- /// <param name="requestOrResponse">Object representing a request or a response.</param>
- /// <returns type="Object">Object with 'mediaType' and a 'properties' dictionary; null in case that the header is not found or doesn't have a value.</returns>
-
- return contentType(getRequestOrResponseHeader(requestOrResponse, "Content-Type"));
- };
-
- var versionRE = /^\s?(\d+\.\d+);?.*$/;
- var getDataServiceVersion = function (requestOrResponse) {
- /// <summary>Gets the value of the DataServiceVersion header from a request or response.</summary>
- /// <param name="requestOrResponse">Object representing a request or a response.</param>
- /// <returns type="String">Data service version; undefined if the header cannot be found.</returns>
-
- var value = getRequestOrResponseHeader(requestOrResponse, "DataServiceVersion");
- if (value) {
- var matches = versionRE.exec(value);
- if (matches && matches.length) {
- return matches[1];
- }
- }
-
- // Fall through and return undefined.
- };
-
- var handlerAccepts = function (handler, cType) {
- /// <summary>Checks that a handler can process a particular mime type.</summary>
- /// <param name="handler">Handler object that is processing a resquest or response.</param>
- /// <param name="cType">Object with 'mediaType' and a 'properties' dictionary.</param>
- /// <returns type="Boolean">True if the handler can process the mime type; false otherwise.</returns>
-
- // The following check isn't as strict because if cType.mediaType = application/; it will match an accept value of "application/xml";
- // however in practice we don't not expect to see such "suffixed" mimeTypes for the handlers.
- return handler.accept.indexOf(cType.mediaType) >= 0;
- };
-
- var handlerRead = function (handler, parseCallback, response, context) {
- /// <summary>Invokes the parser associated with a handler for reading the payload of a HTTP response.</summary>
- /// <param name="handler">Handler object that is processing the response.</param>
- /// <param name="parseCallback" type="Function">Parser function that will process the response payload.</param>
- /// <param name="response">HTTP response whose payload is going to be processed.</param>
- /// <param name="context">Object used as the context for processing the response.</param>
- /// <returns type="Boolean">True if the handler processed the response payload and the response.data property was set; false otherwise.</returns>
-
- if (!response || !response.headers) {
- return false;
- }
-
- var cType = getContentType(response);
- var version = getDataServiceVersion(response) || "";
- var body = response.body;
-
- if (!assigned(body)) {
- return false;
- }
-
- if (handlerAccepts(handler, cType)) {
- var readContext = createReadWriteContext(cType, version, context, handler);
- readContext.response = response;
- response.data = parseCallback(handler, body, readContext);
- return response.data !== undefined;
- }
-
- return false;
- };
-
- var handlerWrite = function (handler, serializeCallback, request, context) {
- /// <summary>Invokes the serializer associated with a handler for generating the payload of a HTTP request.</summary>
- /// <param name="handler">Handler object that is processing the request.</param>
- /// <param name="serializeCallback" type="Function">Serializer function that will generate the request payload.</param>
- /// <param name="response">HTTP request whose payload is going to be generated.</param>
- /// <param name="context">Object used as the context for serializing the request.</param>
- /// <returns type="Boolean">True if the handler serialized the request payload and the request.body property was set; false otherwise.</returns>
- if (!request || !request.headers) {
- return false;
- }
-
- var cType = getContentType(request);
- var version = getDataServiceVersion(request);
-
- if (!cType || handlerAccepts(handler, cType)) {
- var writeContext = createReadWriteContext(cType, version, context, handler);
- writeContext.request = request;
-
- request.body = serializeCallback(handler, request.data, writeContext);
-
- if (request.body !== undefined) {
- fixDataServiceVersionHeader(request, writeContext.dataServiceVersion || "1.0");
-
- fixRequestHeader(request, "Content-Type", contentTypeToString(writeContext.contentType));
- fixRequestHeader(request, "MaxDataServiceVersion", handler.maxDataServiceVersion);
- return true;
- }
- }
-
- return false;
- };
-
- var handler = function (parseCallback, serializeCallback, accept, maxDataServiceVersion) {
- /// <summary>Creates a handler object for processing HTTP requests and responses.</summary>
- /// <param name="parseCallback" type="Function">Parser function that will process the response payload.</param>
- /// <param name="serializeCallback" type="Function">Serializer function that will generate the request payload.</param>
- /// <param name="accept" type="String">String containing a comma separated list of the mime types that this handler can work with.</param>
- /// <param name="maxDataServiceVersion" type="String">String indicating the highest version of the protocol that this handler can work with.</param>
- /// <returns type="Object">Handler object.</returns>
-
- return {
- accept: accept,
- maxDataServiceVersion: maxDataServiceVersion,
-
- read: function (response, context) {
- return handlerRead(this, parseCallback, response, context);
- },
-
- write: function (request, context) {
- return handlerWrite(this, serializeCallback, request, context);
- }
- };
- };
-
- var textParse = function (handler, body /*, context */) {
- return body;
- };
-
- var textSerialize = function (handler, data /*, context */) {
- if (assigned(data)) {
- return data.toString();
- } else {
- return undefined;
- }
- };
-
- odata.textHandler = handler(textParse, textSerialize, "text/plain", MAX_DATA_SERVICE_VERSION);
-
- // DATAJS INTERNAL START
- odata.contentType = contentType;
- odata.contentTypeToString = contentTypeToString;
- odata.handler = handler;
- odata.createReadWriteContext = createReadWriteContext;
- odata.fixRequestHeader = fixRequestHeader;
- odata.getRequestOrResponseHeader = getRequestOrResponseHeader;
- odata.getContentType = getContentType;
- odata.getDataServiceVersion = getDataServiceVersion;
- odata.MAX_DATA_SERVICE_VERSION = MAX_DATA_SERVICE_VERSION;
- // DATAJS INTERNAL END
-
- // CONTENT END
-})(this);
\ No newline at end of file