/******************************************************************************* * OpenAjax-mashup.js * * Reference implementation of the OpenAjax Hub, as specified by OpenAjax Alliance. * Specification is under development at: * * http://www.openajax.org/member/wiki/OpenAjax_Hub_Specification * * Copyright 2006-2009 OpenAjax Alliance * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 . Unless * required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. * ******************************************************************************/ var OpenAjax = OpenAjax || {}; if ( !OpenAjax.hub ) { // prevent re-definition of the OpenAjax.hub object OpenAjax.hub = function() { var libs = {}; var ooh = "org.openajax.hub."; return /** @scope OpenAjax.hub */ { implementer: "http://openajax.org", implVersion: "2.0.4", specVersion: "2.0", implExtraData: {}, libraries: libs, registerLibrary: function(prefix, nsURL, version, extra) { libs[prefix] = { prefix: prefix, namespaceURI: nsURL, version: version, extraData: extra }; this.publish(ooh+"registerLibrary", libs[prefix]); }, unregisterLibrary: function(prefix) { this.publish(ooh+"unregisterLibrary", libs[prefix]); delete libs[prefix]; } }; }(); /** * Error * * Standard Error names used when the standard functions need to throw Errors. */ OpenAjax.hub.Error = { // Either a required argument is missing or an invalid argument was provided BadParameters: "OpenAjax.hub.Error.BadParameters", // The specified hub has been disconnected and cannot perform the requested // operation: Disconnected: "OpenAjax.hub.Error.Disconnected", // Container with specified ID already exists: Duplicate: "OpenAjax.hub.Error.Duplicate", // The specified ManagedHub has no such Container (or it has been removed) NoContainer: "OpenAjax.hub.Error.NoContainer", // The specified ManagedHub or Container has no such subscription NoSubscription: "OpenAjax.hub.Error.NoSubscription", // Permission denied by manager's security policy NotAllowed: "OpenAjax.hub.Error.NotAllowed", // Wrong communications protocol identifier provided by Container or HubClient WrongProtocol: "OpenAjax.hub.Error.WrongProtocol", // A 'tunnelURI' param was specified, but current browser does not support security features IncompatBrowser: "OpenAjax.hub.Error.IncompatBrowser" }; /** * SecurityAlert * * Standard codes used when attempted security violations are detected. Unlike * Errors, these codes are not thrown as exceptions but rather passed into the * SecurityAlertHandler function registered with the Hub instance. */ OpenAjax.hub.SecurityAlert = { // Container did not load (possible frame phishing attack) LoadTimeout: "OpenAjax.hub.SecurityAlert.LoadTimeout", // Hub suspects a frame phishing attack against the specified container FramePhish: "OpenAjax.hub.SecurityAlert.FramePhish", // Hub detected a message forgery that purports to come to a specified // container ForgedMsg: "OpenAjax.hub.SecurityAlert.ForgedMsg" }; /** * Debugging Help * * OpenAjax.hub.enableDebug * * If OpenAjax.hub.enableDebug is set to true, then the "debugger" keyword * will get hit whenever a user callback throws an exception, thereby * bringing up the JavaScript debugger. */ OpenAjax.hub._debugger = function() { }; //////////////////////////////////////////////////////////////////////////////// /** * OpenAjax.hub.ManagedHub * * Managed hub API for the manager application and for Containers. * * Implements OpenAjax.hub.Hub. */ /** * Create a new ManagedHub instance * @constructor * * This constructor automatically sets the ManagedHub's state to * CONNECTED. * * @param {Object} params * Parameters used to instantiate the ManagedHub. * Once the constructor is called, the params object belongs exclusively to * the ManagedHub. The caller MUST not modify it. * * The params object may contain the following properties: * * @param {Function} params.onPublish * Callback function that is invoked whenever a * data value published by a Container is about * to be delivered to some (possibly the same) Container. * This callback function implements a security policy; * it returns true if the delivery of the data is * permitted and false if permission is denied. * @param {Function} params.onSubscribe * Called whenever a Container tries to subscribe * on behalf of its client. * This callback function implements a security policy; * it returns true if the subscription is permitted * and false if permission is denied. * @param {Function} [params.onUnsubscribe] * Called whenever a Container unsubscribes on behalf of its client. * Unlike the other callbacks, onUnsubscribe is intended only for * informative purposes, and is not used to implement a security * policy. * @param {Object} [params.scope] * Whenever one of the ManagedHub's callback functions is called, * references to the JavaScript "this" keyword in the callback * function refer to this scope object * If no scope is provided, default is window. * @param {Function} [params.log] Optional logger function. Would * be used to log to console.log or equivalent. * * @throws {OpenAjax.hub.Error.BadParameters} if any of the required * parameters are missing */ OpenAjax.hub.ManagedHub = function( params ) { if ( ! params || ! params.onPublish || ! params.onSubscribe ) throw new Error( OpenAjax.hub.Error.BadParameters ); this._p = params; this._onUnsubscribe = params.onUnsubscribe ? params.onUnsubscribe : null; this._scope = params.scope || window; if ( params.log ) { var that = this; this._log = function( msg ) { try { params.log.call( that._scope, "ManagedHub: " + msg ); } catch( e ) { OpenAjax.hub._debugger(); } }; } else { this._log = function() {}; } this._subscriptions = { c:{}, s:null }; this._containers = {}; // Sequence # used to create IDs that are unique within this hub this._seq = 0; this._active = true; this._isPublishing = false; this._pubQ = []; }; /** * Subscribe to a topic on behalf of a Container. Called only by * Container implementations, NOT by manager applications. * * This function: * 1. Checks with the ManagedHub's onSubscribe security policy * to determine whether this Container is allowed to subscribe * to this topic. * 2. If the subscribe operation is permitted, subscribes to the * topic and returns the ManagedHub's subscription ID for this * subscription. * 3. If the subscribe operation is not permitted, throws * OpenAjax.hub.Error.NotAllowed. * * When data is published on the topic, the ManagedHub's * onPublish security policy will be invoked to ensure that * this Container is permitted to receive the published data. * If the Container is allowed to receive the data, then the * Container's sendToClient function will be invoked. * * When a Container needs to create a subscription on behalf of * its client, the Container MUST use this function to create * the subscription. * * @param {OpenAjax.hub.Container} container * A Container * @param {String} topic * A valid topic * @param {String} containerSubID * Arbitrary string ID that the Container uses to * represent the subscription. Must be unique within the * context of the Container * * @returns managerSubID * Arbitrary string ID that this ManagedHub uses to * represent the subscription. Will be unique within the * context of this ManagedHub * @type {String} * * @throws {OpenAjax.hub.Error.Disconnected} if this.isConnected() returns false * @throws {OpenAjax.hub.Error.NotAllowed} if subscription request is denied by the onSubscribe security policy * @throws {OpenAjax.hub.Error.BadParameters} if one of the parameters, e.g. the topic, is invalid */ OpenAjax.hub.ManagedHub.prototype.subscribeForClient = function( container, topic, containerSubID ) { this._assertConn(); // check subscribe permission if ( this._invokeOnSubscribe( topic, container ) ) { // return ManagedHub's subscriptionID for this subscription return this._subscribe( topic, this._sendToClient, this, { c: container, sid: containerSubID } ); } throw new Error(OpenAjax.hub.Error.NotAllowed); }; /** * Unsubscribe from a subscription on behalf of a Container. Called only by * Container implementations, NOT by manager application code. * * This function: * 1. Destroys the specified subscription * 2. Calls the ManagedHub's onUnsubscribe callback function * * This function can be called even if the ManagedHub is not in a CONNECTED state. * * @param {OpenAjax.hub.Container} container * container instance that is unsubscribing * @param {String} managerSubID * opaque ID of a subscription, returned by previous call to subscribeForClient() * * @throws {OpenAjax.hub.Error.NoSubscription} if subscriptionID does not refer to a valid subscription */ OpenAjax.hub.ManagedHub.prototype.unsubscribeForClient = function( container, managerSubID ) { this._unsubscribe( managerSubID ); this._invokeOnUnsubscribe( container, managerSubID ); }; /** * Publish data on a topic on behalf of a Container. Called only by * Container implementations, NOT by manager application code. * * @param {OpenAjax.hub.Container} container * Container on whose behalf data should be published * @param {String} topic * Valid topic string. Must NOT contain wildcards. * @param {*} data * Valid publishable data. To be portable across different * Container implementations, this value SHOULD be serializable * as JSON. * * @throws {OpenAjax.hub.Error.Disconnected} if this.isConnected() returns false * @throws {OpenAjax.hub.Error.BadParameters} if one of the parameters, e.g. the topic, is invalid */ OpenAjax.hub.ManagedHub.prototype.publishForClient = function( container, topic, data ) { this._assertConn(); this._publish( topic, data, container ); }; /** * Destroy this ManagedHub * * 1. Sets state to DISCONNECTED. All subsequent attempts to add containers, * publish or subscribe will throw the Disconnected error. We will * continue to allow "cleanup" operations such as removeContainer * and unsubscribe, as well as read-only operations such as * isConnected * 2. Remove all Containers associated with this ManagedHub */ OpenAjax.hub.ManagedHub.prototype.disconnect = function() { this._active = false; for (var c in this._containers) { this.removeContainer( this._containers[c] ); } }; /** * Get a container belonging to this ManagedHub by its clientID, or null * if this ManagedHub has no such container * * This function can be called even if the ManagedHub is not in a CONNECTED state. * * @param {String} containerId * Arbitrary string ID associated with the container * * @returns container associated with given ID * @type {OpenAjax.hub.Container} */ OpenAjax.hub.ManagedHub.prototype.getContainer = function( containerId ) { var container = this._containers[containerId]; return container ? container : null; }; /** * Returns an array listing all containers belonging to this ManagedHub. * The order of the Containers in this array is arbitrary. * * This function can be called even if the ManagedHub is not in a CONNECTED state. * * @returns container array * @type {OpenAjax.hub.Container[]} */ OpenAjax.hub.ManagedHub.prototype.listContainers = function() { var res = []; for (var c in this._containers) { res.push(this._containers[c]); } return res; }; /** * Add a container to this ManagedHub. * * This function should only be called by a Container constructor. * * @param {OpenAjax.hub.Container} container * A Container to be added to this ManagedHub * * @throws {OpenAjax.hub.Error.Duplicate} if there is already a Container * in this ManagedHub whose clientId is the same as that of container * @throws {OpenAjax.hub.Error.Disconnected} if this.isConnected() returns false */ OpenAjax.hub.ManagedHub.prototype.addContainer = function( container ) { this._assertConn(); var containerId = container.getClientID(); if ( this._containers[containerId] ) { throw new Error(OpenAjax.hub.Error.Duplicate); } this._containers[containerId] = container; }; /** * Remove a container from this ManagedHub immediately * * This function can be called even if the ManagedHub is not in a CONNECTED state. * * @param {OpenAjax.hub.Container} container * A Container to be removed from this ManagedHub * * @throws {OpenAjax.hub.Error.NoContainer} if no such container is found */ OpenAjax.hub.ManagedHub.prototype.removeContainer = function( container ) { var containerId = container.getClientID(); if ( ! this._containers[ containerId ] ) { throw new Error(OpenAjax.hub.Error.NoContainer); } container.remove(); delete this._containers[ containerId ]; }; /*** OpenAjax.hub.Hub interface implementation ***/ /** * Subscribe to a topic. * * This implementation of Hub.subscribe is synchronous. When subscribe * is called: * * 1. The ManagedHub's onSubscribe callback is invoked. The * container parameter is null, because the manager application, * rather than a container, is subscribing. * 2. If onSubscribe returns true, then the subscription is created. * 3. The onComplete callback is invoked. * 4. Then this function returns. * * @param {String} topic * A valid topic string. MAY include wildcards. * @param {Function} onData * Callback function that is invoked whenever an event is * published on the topic * @param {Object} [scope] * When onData callback or onComplete callback is invoked, * the JavaScript "this" keyword refers to this scope object. * If no scope is provided, default is window. * @param {Function} [onComplete] * Invoked to tell the client application whether the * subscribe operation succeeded or failed. * @param {*} [subscriberData] * Client application provides this data, which is handed * back to the client application in the subscriberData * parameter of the onData and onComplete callback functions. * * @returns subscriptionID * Identifier representing the subscription. This identifier is an * arbitrary ID string that is unique within this Hub instance * @type {String} * * @throws {OpenAjax.hub.Error.Disconnected} if this Hub instance is not in CONNECTED state * @throws {OpenAjax.hub.Error.BadParameters} if the topic is invalid (e.g. contains an empty token) */ OpenAjax.hub.ManagedHub.prototype.subscribe = function( topic, onData, scope, onComplete, subscriberData ) { this._assertConn(); this._assertSubTopic(topic); if ( ! onData ) { throw new Error( OpenAjax.hub.Error.BadParameters ); } scope = scope || window; // check subscribe permission if ( ! this._invokeOnSubscribe( topic, null ) ) { this._invokeOnComplete( onComplete, scope, null, false, OpenAjax.hub.Error.NotAllowed ); return; } // on publish event, check publish permissions var that = this; function publishCB( topic, data, sd, pcont ) { if ( that._invokeOnPublish( topic, data, pcont, null ) ) { try { onData.call( scope, topic, data, subscriberData ); } catch( e ) { OpenAjax.hub._debugger(); that._log( "caught error from onData callback to Hub.subscribe(): " + e.message ); } } } var subID = this._subscribe( topic, publishCB, scope, subscriberData ); this._invokeOnComplete( onComplete, scope, subID, true ); return subID; }; /** * Publish an event on a topic * * This implementation of Hub.publish is synchronous. When publish * is called: * * 1. The target subscriptions are identified. * 2. For each target subscription, the ManagedHub's onPublish * callback is invoked. Data is only delivered to a target * subscription if the onPublish callback returns true. * The pcont parameter of the onPublish callback is null. * This is because the ManagedHub, rather than a container, * is publishing the data. * * @param {String} topic * A valid topic string. MUST NOT include wildcards. * @param {*} data * Valid publishable data. To be portable across different * Container implementations, this value SHOULD be serializable * as JSON. * * @throws {OpenAjax.hub.Error.Disconnected} if this Hub instance is not in CONNECTED state * @throws {OpenAjax.hub.Error.BadParameters} if the topic cannot be published (e.g. contains * wildcards or empty tokens) or if the data cannot be published (e.g. cannot be serialized as JSON) */ OpenAjax.hub.ManagedHub.prototype.publish = function( topic, data ) { this._assertConn(); this._assertPubTopic(topic); this._publish( topic, data, null ); }; /** * Unsubscribe from a subscription * * This implementation of Hub.unsubscribe is synchronous. When unsubscribe * is called: * * 1. The subscription is destroyed. * 2. The ManagedHub's onUnsubscribe callback is invoked, if there is one. * 3. The onComplete callback is invoked. * 4. Then this function returns. * * @param {String} subscriptionID * A subscriptionID returned by Hub.subscribe() * @param {Function} [onComplete] * Callback function invoked when unsubscribe completes * @param {Object} [scope] * When onComplete callback function is invoked, the JavaScript "this" * keyword refers to this scope object. * If no scope is provided, default is window. * * @throws {OpenAjax.hub.Error.Disconnected} if this Hub instance is not in CONNECTED state * @throws {OpenAjax.hub.Error.NoSubscription} if no such subscription is found */ OpenAjax.hub.ManagedHub.prototype.unsubscribe = function( subscriptionID, onComplete, scope ) { this._assertConn(); if ( ! subscriptionID ) { throw new Error( OpenAjax.hub.Error.BadParameters ); } this._unsubscribe( subscriptionID ); this._invokeOnUnsubscribe( null, subscriptionID ); this._invokeOnComplete( onComplete, scope, subscriptionID, true ); }; /** * Returns true if disconnect() has NOT been called on this ManagedHub, * else returns false * * @returns Boolean * @type {Boolean} */ OpenAjax.hub.ManagedHub.prototype.isConnected = function() { return this._active; }; /** * Returns the scope associated with this Hub instance and which will be used * with callback functions. * * This function can be called even if the Hub is not in a CONNECTED state. * * @returns scope object * @type {Object} */ OpenAjax.hub.ManagedHub.prototype.getScope = function() { return this._scope; }; /** * Returns the subscriberData parameter that was provided when * Hub.subscribe was called. * * @param subscriberID * The subscriberID of a subscription * * @returns subscriberData * @type {*} * * @throws {OpenAjax.hub.Error.Disconnected} if this Hub instance is not in CONNECTED state * @throws {OpenAjax.hub.Error.NoSubscription} if there is no such subscription */ OpenAjax.hub.ManagedHub.prototype.getSubscriberData = function( subscriberID ) { this._assertConn(); var path = subscriberID.split("."); var sid = path.pop(); var sub = this._getSubscriptionObject( this._subscriptions, path, 0, sid ); if ( sub ) return sub.data; throw new Error( OpenAjax.hub.Error.NoSubscription ); }; /** * Returns the scope associated with a specified subscription. This scope will * be used when invoking the 'onData' callback supplied to Hub.subscribe(). * * @param subscriberID * The subscriberID of a subscription * * @returns scope * @type {*} * * @throws {OpenAjax.hub.Error.Disconnected} if this Hub instance is not in CONNECTED state * @throws {OpenAjax.hub.Error.NoSubscription} if there is no such subscription */ OpenAjax.hub.ManagedHub.prototype.getSubscriberScope = function( subscriberID ) { this._assertConn(); var path = subscriberID.split("."); var sid = path.pop(); var sub = this._getSubscriptionObject( this._subscriptions, path, 0, sid ); if ( sub ) { return sub.scope; } throw new Error( OpenAjax.hub.Error.NoSubscription ); }; /** * Returns the params object associated with this Hub instance. * Allows mix-in code to access parameters passed into constructor that created * this Hub instance. * * @returns params the params object associated with this Hub instance * @type {Object} */ OpenAjax.hub.ManagedHub.prototype.getParameters = function() { return this._p; }; /* PRIVATE FUNCTIONS */ /** * Send a message to a container's client. * This is an OAH subscriber's data callback. It is private to ManagedHub * and serves as an adapter between the OAH 1.0 API and Container.sendToClient. * * @param {String} topic Topic on which data was published * @param {Object} data Data to be delivered to the client * @param {Object} sd Object containing properties * c: container to which data must be sent * sid: subscription ID within that container * @param {Object} pcont Publishing container, or null if this data was * published by the manager */ OpenAjax.hub.ManagedHub.prototype._sendToClient = function(topic, data, sd, pcont) { if (!this.isConnected()) { return; } if ( this._invokeOnPublish( topic, data, pcont, sd.c ) ) { sd.c.sendToClient( topic, data, sd.sid ); } }; OpenAjax.hub.ManagedHub.prototype._assertConn = function() { if (!this.isConnected()) { throw new Error(OpenAjax.hub.Error.Disconnected); } }; OpenAjax.hub.ManagedHub.prototype._assertPubTopic = function(topic) { if ( !topic || topic === "" || (topic.indexOf("*") != -1) || (topic.indexOf("..") != -1) || (topic.charAt(0) == ".") || (topic.charAt(topic.length-1) == ".")) { throw new Error(OpenAjax.hub.Error.BadParameters); } }; OpenAjax.hub.ManagedHub.prototype._assertSubTopic = function(topic) { if ( ! topic ) { throw new Error(OpenAjax.hub.Error.BadParameters); } var path = topic.split("."); var len = path.length; for (var i = 0; i < len; i++) { var p = path[i]; if ((p === "") || ((p.indexOf("*") != -1) && (p != "*") && (p != "**"))) { throw new Error(OpenAjax.hub.Error.BadParameters); } if ((p == "**") && (i < len - 1)) { throw new Error(OpenAjax.hub.Error.BadParameters); } } }; OpenAjax.hub.ManagedHub.prototype._invokeOnComplete = function( func, scope, item, success, errorCode ) { if ( func ) { // onComplete is optional try { scope = scope || window; func.call( scope, item, success, errorCode ); } catch( e ) { OpenAjax.hub._debugger(); this._log( "caught error from onComplete callback: " + e.message ); } } }; OpenAjax.hub.ManagedHub.prototype._invokeOnPublish = function( topic, data, pcont, scont ) { try { return this._p.onPublish.call( this._scope, topic, data, pcont, scont ); } catch( e ) { OpenAjax.hub._debugger(); this._log( "caught error from onPublish callback to constructor: " + e.message ); } return false; }; OpenAjax.hub.ManagedHub.prototype._invokeOnSubscribe = function( topic, container ) { try { return this._p.onSubscribe.call( this._scope, topic, container ); } catch( e ) { OpenAjax.hub._debugger(); this._log( "caught error from onSubscribe callback to constructor: " + e.message ); } return false; }; OpenAjax.hub.ManagedHub.prototype._invokeOnUnsubscribe = function( container, managerSubID ) { if ( this._onUnsubscribe ) { var topic = managerSubID.slice( 0, managerSubID.lastIndexOf(".") ); try { this._onUnsubscribe.call( this._scope, topic, container ); } catch( e ) { OpenAjax.hub._debugger(); this._log( "caught error from onUnsubscribe callback to constructor: " + e.message ); } } }; OpenAjax.hub.ManagedHub.prototype._subscribe = function( topic, onData, scope, subscriberData ) { var handle = topic + "." + this._seq; var sub = { scope: scope, cb: onData, data: subscriberData, sid: this._seq++ }; var path = topic.split("."); this._recursiveSubscribe( this._subscriptions, path, 0, sub ); return handle; }; OpenAjax.hub.ManagedHub.prototype._recursiveSubscribe = function(tree, path, index, sub) { var token = path[index]; if (index == path.length) { sub.next = tree.s; tree.s = sub; } else { if (typeof tree.c == "undefined") { tree.c = {}; } if (typeof tree.c[token] == "undefined") { tree.c[token] = { c: {}, s: null }; this._recursiveSubscribe(tree.c[token], path, index + 1, sub); } else { this._recursiveSubscribe( tree.c[token], path, index + 1, sub); } } }; OpenAjax.hub.ManagedHub.prototype._publish = function( topic, data, pcont ) { // if we are currently handling a publish event, then queue this request // and handle later, one by one if ( this._isPublishing ) { this._pubQ.push( { t: topic, d: data, p: pcont } ); return; } this._safePublish( topic, data, pcont ); while ( this._pubQ.length > 0 ) { var pub = this._pubQ.shift(); this._safePublish( pub.t, pub.d, pub.p ); } }; OpenAjax.hub.ManagedHub.prototype._safePublish = function( topic, data, pcont ) { this._isPublishing = true; var path = topic.split("."); this._recursivePublish( this._subscriptions, path, 0, topic, data, pcont ); this._isPublishing = false; }; OpenAjax.hub.ManagedHub.prototype._recursivePublish = function(tree, path, index, name, msg, pcont) { if (typeof tree != "undefined") { var node; if (index == path.length) { node = tree; } else { this._recursivePublish(tree.c[path[index]], path, index + 1, name, msg, pcont); this._recursivePublish(tree.c["*"], path, index + 1, name, msg, pcont); node = tree.c["**"]; } if (typeof node != "undefined") { var sub = node.s; while ( sub ) { var sc = sub.scope; var cb = sub.cb; var d = sub.data; if (typeof cb == "string") { // get a function object cb = sc[cb]; } cb.call(sc, name, msg, d, pcont); sub = sub.next; } } } }; OpenAjax.hub.ManagedHub.prototype._unsubscribe = function( subscriptionID ) { var path = subscriptionID.split("."); var sid = path.pop(); if ( ! this._recursiveUnsubscribe( this._subscriptions, path, 0, sid ) ) { throw new Error( OpenAjax.hub.Error.NoSubscription ); } }; /** * @returns 'true' if properly unsubscribed; 'false' otherwise */ OpenAjax.hub.ManagedHub.prototype._recursiveUnsubscribe = function(tree, path, index, sid) { if ( typeof tree == "undefined" ) { return false; } if (index < path.length) { var childNode = tree.c[path[index]]; if ( ! childNode ) { return false; } this._recursiveUnsubscribe(childNode, path, index + 1, sid); if ( ! childNode.s ) { for (var x in childNode.c) { return true; } delete tree.c[path[index]]; } } else { var sub = tree.s; var sub_prev = null; var found = false; while ( sub ) { if ( sid == sub.sid ) { found = true; if ( sub == tree.s ) { tree.s = sub.next; } else { sub_prev.next = sub.next; } break; } sub_prev = sub; sub = sub.next; } if ( ! found ) { return false; } } return true; }; OpenAjax.hub.ManagedHub.prototype._getSubscriptionObject = function( tree, path, index, sid ) { if (typeof tree != "undefined") { if (index < path.length) { var childNode = tree.c[path[index]]; return this._getSubscriptionObject(childNode, path, index + 1, sid); } var sub = tree.s; while ( sub ) { if ( sid == sub.sid ) { return sub; } sub = sub.next; } } return null; }; /** * OpenAjax.hub._hub is the default ManagedHub instance that we use to * provide OAH 1.0 behavior. */ OpenAjax.hub._hub = new OpenAjax.hub.ManagedHub({ onSubscribe: function(topic, ctnr) { return true; }, onPublish: function(topic, data, pcont, scont) { return true; } }); /** * Subscribe to a topic. * * @param {String} topic * A valid topic string. MAY include wildcards. * @param {Function|String} onData * Callback function that is invoked whenever an event is published on the * topic. If 'onData' is a string, then it represents the name of a * function on the 'scope' object. * @param {Object} [scope] * When onData callback is invoked, * the JavaScript "this" keyword refers to this scope object. * If no scope is provided, default is window. * @param {*} [subscriberData] * Client application provides this data, which is handed * back to the client application in the subscriberData * parameter of the onData callback function. * * @returns {String} Identifier representing the subscription. * * @throws {OpenAjax.hub.Error.BadParameters} if the topic is invalid * (e.g.contains an empty token) */ OpenAjax.hub.subscribe = function(topic, onData, scope, subscriberData) { // resolve the 'onData' function if it is a string if ( typeof onData === "string" ) { scope = scope || window; onData = scope[ onData ] || null; } return OpenAjax.hub._hub.subscribe( topic, onData, scope, null, subscriberData ); }; /** * Unsubscribe from a subscription. * * @param {String} subscriptionID * Subscription identifier returned by subscribe() * * @throws {OpenAjax.hub.Error.NoSubscription} if no such subscription is found */ OpenAjax.hub.unsubscribe = function(subscriptionID) { return OpenAjax.hub._hub.unsubscribe( subscriptionID ); }; /** * Publish an event on a topic. * * @param {String} topic * A valid topic string. MUST NOT include wildcards. * @param {*} data * Valid publishable data. * * @throws {OpenAjax.hub.Error.BadParameters} if the topic cannot be published * (e.g. contains wildcards or empty tokens) */ OpenAjax.hub.publish = function(topic, data) { OpenAjax.hub._hub.publish(topic, data); }; //////////////////////////////////////////////////////////////////////////////// // Register the OpenAjax Hub itself as a library. OpenAjax.hub.registerLibrary("OpenAjax", "http://openajax.org/hub", "2.0", {}); } // !OpenAjax.hub /* Copyright 2006-2009 OpenAjax Alliance Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /** * Create a new Inline Container. * @constructor * @extends OpenAjax.hub.Container * * InlineContainer implements the Container interface to provide a container * that places components within the same browser frame as the main mashup * application. As such, this container does not isolate client components into * secure sandboxes. * * @param {OpenAjax.hub.ManagedHub} hub * Managed Hub instance to which this Container belongs * @param {String} clientID * A string ID that identifies a particular client of a Managed Hub. Unique * within the context of the ManagedHub. * @param {Object} params * Parameters used to instantiate the InlineContainer. * Once the constructor is called, the params object belongs exclusively to * the InlineContainer. The caller MUST not modify it. * The following are the pre-defined properties on params: * @param {Function} params.Container.onSecurityAlert * Called when an attempted security breach is thwarted. Function is defined * as follows: function(container, securityAlert) * @param {Function} [params.Container.onConnect] * Called when the client connects to the Managed Hub. Function is defined * as follows: function(container) * @param {Function} [params.Container.onDisconnect] * Called when the client disconnects from the Managed Hub. Function is * defined as follows: function(container) * @param {Object} [params.Container.scope] * Whenever one of the Container's callback functions is called, references * to "this" in the callback will refer to the scope object. If no scope is * provided, default is window. * @param {Function} [params.Container.log] * Optional logger function. Would be used to log to console.log or * equivalent. * * @throws {OpenAjax.hub.Error.BadParameters} if required params are not * present or null * @throws {OpenAjax.hub.Error.Duplicate} if a Container with this clientID * already exists in the given Managed Hub * @throws {OpenAjax.hub.Error.Disconnected} if ManagedHub is not connected */ OpenAjax.hub.InlineContainer = function( hub, clientID, params ) { if ( ! hub || ! clientID || ! params || ! params.Container || ! params.Container.onSecurityAlert ) { throw new Error(OpenAjax.hub.Error.BadParameters); } var cbScope = params.Container.scope || window; var connected = false; var subs = []; var subIndex = 0; var client = null; if ( params.Container.log ) { var log = function( msg ) { try { params.Container.log.call( cbScope, "InlineContainer::" + clientID + ": " + msg ); } catch( e ) { OpenAjax.hub._debugger(); } }; } else { log = function() {}; } this._init = function() { hub.addContainer( this ); }; /*** OpenAjax.hub.Container interface implementation ***/ this.getHub = function() { return hub; }; this.sendToClient = function( topic, data, subscriptionID ) { if ( connected ) { var sub = subs[ subscriptionID ]; try { sub.cb.call( sub.sc, topic, data, sub.d ); } catch( e ) { OpenAjax.hub._debugger(); client._log( "caught error from onData callback to HubClient.subscribe(): " + e.message ); } } }; this.remove = function() { if ( connected ) { finishDisconnect(); } }; this.isConnected = function() { return connected; }; this.getClientID = function() { return clientID; }; this.getPartnerOrigin = function() { if ( connected ) { return window.location.protocol + "//" + window.location.hostname; } return null; }; this.getParameters = function() { return params; }; /*** OpenAjax.hub.HubClient interface implementation ***/ this.connect = function( hubClient, onComplete, scope ) { if ( connected ) { throw new Error( OpenAjax.hub.Error.Duplicate ); } connected = true; client = hubClient; if ( params.Container.onConnect ) { try { params.Container.onConnect.call( cbScope, this ); } catch( e ) { OpenAjax.hub._debugger(); log( "caught error from onConnect callback to constructor: " + e.message ); } } invokeOnComplete( onComplete, scope, hubClient, true ); }; this.disconnect = function( hubClient, onComplete, scope ) { if ( ! connected ) { throw new Error( OpenAjax.hub.Error.Disconnected ); } finishDisconnect(); if ( params.Container.onDisconnect ) { try { params.Container.onDisconnect.call( cbScope, this ); } catch( e ) { OpenAjax.hub._debugger(); log( "caught error from onDisconnect callback to constructor: " + e.message ); } } invokeOnComplete( onComplete, scope, hubClient, true ); }; /*** OpenAjax.hub.Hub interface implementation ***/ this.subscribe = function( topic, onData, scope, onComplete, subscriberData ) { assertConn(); assertSubTopic( topic ); if ( ! onData ) { throw new Error( OpenAjax.hub.Error.BadParameters ); } var subID = "" + subIndex++; var success = false; var msg = null; try { var handle = hub.subscribeForClient( this, topic, subID ); success = true; } catch( e ) { // failure subID = null; msg = e.message; } scope = scope || window; if ( success ) { subs[ subID ] = { h: handle, cb: onData, sc: scope, d: subscriberData }; } invokeOnComplete( onComplete, scope, subID, success, msg ); return subID; }; this.publish = function( topic, data ) { assertConn(); assertPubTopic( topic ); hub.publishForClient( this, topic, data ); }; this.unsubscribe = function( subscriptionID, onComplete, scope ) { assertConn(); if ( typeof subscriptionID === "undefined" || subscriptionID === null ) { throw new Error( OpenAjax.hub.Error.BadParameters ); } var sub = subs[ subscriptionID ]; if ( ! sub ) { throw new Error( OpenAjax.hub.Error.NoSubscription ); } hub.unsubscribeForClient( this, sub.h ); delete subs[ subscriptionID ]; invokeOnComplete( onComplete, scope, subscriptionID, true ); }; this.getSubscriberData = function( subID ) { assertConn(); return getSubscription( subID ).d; }; this.getSubscriberScope = function( subID ) { assertConn(); return getSubscription( subID ).sc; }; /*** PRIVATE FUNCTIONS ***/ function invokeOnComplete( func, scope, item, success, errorCode ) { if ( func ) { // onComplete is optional try { scope = scope || window; func.call( scope, item, success, errorCode ); } catch( e ) { OpenAjax.hub._debugger(); // invokeOnComplete is only called for client interfaces (Hub and HubClient) client._log( "caught error from onComplete callback: " + e.message ); } } } function finishDisconnect() { for ( var subID in subs ) { hub.unsubscribeForClient( this, subs[subID].h ); } subs = []; subIndex = 0; connected = false; } function assertConn() { if ( ! connected ) { throw new Error( OpenAjax.hub.Error.Disconnected ); } } function assertPubTopic( topic ) { if ((topic == null) || (topic === "") || (topic.indexOf("*") != -1) || (topic.indexOf("..") != -1) || (topic.charAt(0) == ".") || (topic.charAt(topic.length-1) == ".")) { throw new Error(OpenAjax.hub.Error.BadParameters); } } function assertSubTopic( topic ) { if ( ! topic ) { throw new Error(OpenAjax.hub.Error.BadParameters); } var path = topic.split("."); var len = path.length; for (var i = 0; i < len; i++) { var p = path[i]; if ((p === "") || ((p.indexOf("*") != -1) && (p != "*") && (p != "**"))) { throw new Error(OpenAjax.hub.Error.BadParameters); } if ((p == "**") && (i < len - 1)) { throw new Error(OpenAjax.hub.Error.BadParameters); } } } function getSubscription( subID ) { var sub = subs[ subID ]; if ( sub ) { return sub; } throw new Error( OpenAjax.hub.Error.NoSubscription ); } this._init(); }; //////////////////////////////////////////////////////////////////////////////// /** * Create a new InlineHubClient. * @constructor * @extends OpenAjax.hub.HubClient * * @param {Object} params * Parameters used to instantiate the HubClient. * Once the constructor is called, the params object belongs to the * HubClient. The caller MUST not modify it. * The following are the pre-defined properties on params: * @param {Function} params.HubClient.onSecurityAlert * Called when an attempted security breach is thwarted * @param {Object} [params.HubClient.scope] * Whenever one of the HubClient's callback functions is called, * references to "this" in the callback will refer to the scope object. * If not provided, the default is window. * @param {Function} [params.HubClient.log] * Optional logger function. Would be used to log to console.log or * equivalent. * @param {OpenAjax.hub.InlineContainer} params.InlineHubClient.container * Specifies the InlineContainer to which this HubClient will connect * * @throws {OpenAjax.hub.Error.BadParameters} if any of the required * parameters are missing */ OpenAjax.hub.InlineHubClient = function( params ) { if ( ! params || ! params.HubClient || ! params.HubClient.onSecurityAlert || ! params.InlineHubClient || ! params.InlineHubClient.container ) { throw new Error(OpenAjax.hub.Error.BadParameters); } var container = params.InlineHubClient.container; var scope = params.HubClient.scope || window; if ( params.HubClient.log ) { var log = function( msg ) { try { params.HubClient.log.call( scope, "InlineHubClient::" + container.getClientID() + ": " + msg ); } catch( e ) { OpenAjax.hub._debugger(); } }; } else { log = function() {}; } this._log = log; /*** OpenAjax.hub.HubClient interface implementation ***/ /** * Requests a connection to the ManagedHub, via the InlineContainer * associated with this InlineHubClient. * * If the Container accepts the connection request, this HubClient's * state is set to CONNECTED and the HubClient invokes the * onComplete callback function. * * If the Container refuses the connection request, the HubClient * invokes the onComplete callback function with an error code. * The error code might, for example, indicate that the Container * is being destroyed. * * If the HubClient is already connected, calling connect will cause * the HubClient to immediately invoke the onComplete callback with * the error code OpenAjax.hub.Error.Duplicate. * * @param {Function} [onComplete] * Callback function to call when this operation completes. * @param {Object} [scope] * When the onComplete function is invoked, the JavaScript "this" * keyword refers to this scope object. * If no scope is provided, default is window. * * In this implementation of InlineHubClient, this function operates * SYNCHRONOUSLY, so the onComplete callback function is invoked before * this connect function returns. Developers are cautioned that in * IframeHubClient implementations, this is not the case. * * A client application may call InlineHubClient.disconnect and then call * InlineHubClient.connect to reconnect to the Managed Hub. */ this.connect = function( onComplete, scope ) { container.connect( this, onComplete, scope ); }; /** * Disconnect from the ManagedHub * * Disconnect immediately: * * 1. Sets the HubClient's state to DISCONNECTED. * 2. Causes the HubClient to send a Disconnect request to the * associated Container. * 3. Ensures that the client application will receive no more * onData or onComplete callbacks associated with this * connection, except for the disconnect function's own * onComplete callback. * 4. Automatically destroys all of the HubClient's subscriptions. * * @param {Function} [onComplete] * Callback function to call when this operation completes. * @param {Object} [scope] * When the onComplete function is invoked, the JavaScript "this" * keyword refers to the scope object. * If no scope is provided, default is window. * * In this implementation of InlineHubClient, the disconnect function operates * SYNCHRONOUSLY, so the onComplete callback function is invoked before * this function returns. Developers are cautioned that in IframeHubClient * implementations, this is not the case. * * A client application is allowed to call HubClient.disconnect and * then call HubClient.connect in order to reconnect. */ this.disconnect = function( onComplete, scope ) { container.disconnect( this, onComplete, scope ); }; this.getPartnerOrigin = function() { return container.getPartnerOrigin(); }; this.getClientID = function() { return container.getClientID(); }; /*** OpenAjax.hub.Hub interface implementation ***/ /** * Subscribe to a topic. * * @param {String} topic * A valid topic string. MAY include wildcards. * @param {Function} onData * Callback function that is invoked whenever an event is * published on the topic * @param {Object} [scope] * When onData callback or onComplete callback is invoked, * the JavaScript "this" keyword refers to this scope object. * If no scope is provided, default is window. * @param {Function} [onComplete] * Invoked to tell the client application whether the * subscribe operation succeeded or failed. * @param {*} [subscriberData] * Client application provides this data, which is handed * back to the client application in the subscriberData * parameter of the onData and onComplete callback functions. * * @returns subscriptionID * Identifier representing the subscription. This identifier is an * arbitrary ID string that is unique within this Hub instance * @type {String} * * @throws {OpenAjax.hub.Error.Disconnected} if this Hub instance is not in CONNECTED state * @throws {OpenAjax.hub.Error.BadParameters} if the topic is invalid (e.g. contains an empty token) * * In this implementation of InlineHubClient, the subscribe function operates * Thus, onComplete is invoked before this function returns. Developers are * cautioned that in most implementations of HubClient, onComplete is invoked * after this function returns. * * If unsubscribe is called before subscribe completes, the subscription is * immediately terminated, and onComplete is never invoked. */ this.subscribe = function( topic, onData, scope, onComplete, subscriberData ) { return container.subscribe( topic, onData, scope, onComplete, subscriberData ); }; /** * Publish an event on 'topic' with the given data. * * @param {String} topic * A valid topic string. MUST NOT include wildcards. * @param {*} data * Valid publishable data. To be portable across different * Container implementations, this value SHOULD be serializable * as JSON. * * @throws {OpenAjax.hub.Error.Disconnected} if this Hub instance * is not in CONNECTED state * * In this implementation, publish operates SYNCHRONOUSLY. * Data will be delivered to subscribers after this function returns. * In most implementations, publish operates synchronously, * delivering its data to the clients before this function returns. */ this.publish = function( topic, data ) { container.publish( topic, data ); }; /** * Unsubscribe from a subscription * * @param {String} subscriptionID * A subscriptionID returned by InlineHubClient.prototype.subscribe() * @param {Function} [onComplete] * Callback function invoked when unsubscribe completes * @param {Object} [scope] * When onComplete callback function is invoked, the JavaScript "this" * keyword refers to this scope object. * * @throws {OpenAjax.hub.Error.NoSubscription} if no such subscription is found * * To facilitate cleanup, it is possible to call unsubscribe even * when the HubClient is in a DISCONNECTED state. * * In this implementation of HubClient, this function operates SYNCHRONOUSLY. * Thus, onComplete is invoked before this function returns. Developers are * cautioned that in most implementations of HubClient, onComplete is invoked * after this function returns. */ this.unsubscribe = function( subscriptionID, onComplete, scope ) { container.unsubscribe( subscriptionID, onComplete, scope ); }; this.isConnected = function() { return container.isConnected(); }; this.getScope = function() { return scope; }; this.getSubscriberData = function( subID ) { return container.getSubscriberData( subID ); }; this.getSubscriberScope = function( subID ) { return container.getSubscriberScope( subID ); }; /** * Returns the params object associated with this Hub instance. * Allows mix-in code to access parameters passed into constructor that created * this Hub instance. * * @returns params the params object associated with this Hub instance * @type {Object} */ this.getParameters = function() { return params; }; };/* Copyright 2006-2009 OpenAjax Alliance Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ var OpenAjax = OpenAjax || {}; OpenAjax.hub = OpenAjax.hub || {}; OpenAjax.gadgets = typeof OpenAjax.gadgets === 'object' ? OpenAjax.gadgets : typeof gadgets === 'object' ? gadgets : {}; OpenAjax.gadgets.rpctx = OpenAjax.gadgets.rpctx || {}; (function() { // For now, we only use "oaaConfig" for the global "gadgets" object. If the "gadgets" global // already exists, then there is no reason to check for "oaaConfig". In the future, if we use // "oaaConfig" for other purposes, we'll need to remove the check for "!window.gadgets". if (typeof gadgets === 'undefined') { // "oaaConfig" can be specified as a global object. If not found, then look for it as an // attribute on the script line for the OpenAjax Hub JS file. if (typeof oaaConfig === 'undefined') { var scripts = document.getElementsByTagName("script"); // match "OpenAjax-mashup.js", "OpenAjaxManagedHub-all*.js", "OpenAjaxManagedHub-core*.js" var reHub = /openajax(?:managedhub-(?:all|core).*|-mashup)\.js$/i; for ( var i = scripts.length - 1; i >= 0; i-- ) { var src = scripts[i].getAttribute( "src" ); if ( !src ) { continue; } var m = src.match( reHub ); if ( m ) { var config = scripts[i].getAttribute( "oaaConfig" ); if ( config ) { try { oaaConfig = eval( "({ " + config + " })" ); } catch (e) {} } break; } } } if (typeof oaaConfig !== 'undefined' && oaaConfig.gadgetsGlobal) { gadgets = OpenAjax.gadgets; } } })(); if (!OpenAjax.hub.IframeContainer) { (function(){ /** * Create a new Iframe Container. * @constructor * @extends OpenAjax.hub.Container * * IframeContainer implements the Container interface to provide a container * that isolates client components into secure sandboxes by leveraging the * isolation features provided by browser iframes. * * SECURITY * * In order for the connection between the IframeContainer and IframeHubClient * to be fully secure, you must specify a valid 'tunnelURI'. Note that if you * do specify a 'tunnelURI', then only the WPM and NIX transports are used, * covering the following browsers: * IE 6+, Firefox 3+, Safari 4+, Chrome 2+, Opera 9+. * * If no 'tunnelURI' is specified, then some security features are disabled: * the IframeContainer will not report FramePhish errors, and on some browsers * IframeContainer and IframeHubClient will not be able to validate the * identity of their partner (i.e. getPartnerOrigin() will return 'null'). * However, not providing 'tunnelURI' allows the additional use of the RMR * and FE transports -- in addition to the above browsers, the Hub code will * also work on: * Firefox 1 & 2, Safari 2 & 3, Chrome 1. * * @param {OpenAjax.hub.ManagedHub} hub * Managed Hub instance to which this Container belongs * @param {String} clientID * A string ID that identifies a particular client of a Managed Hub. Unique * within the context of the ManagedHub. * @param {Object} params * Parameters used to instantiate the IframeContainer. * Once the constructor is called, the params object belongs exclusively to * the IframeContainer. The caller MUST not modify it. * The following are the pre-defined properties on params: * @param {Function} params.Container.onSecurityAlert * Called when an attempted security breach is thwarted. Function is defined * as follows: function(container, securityAlert) * @param {Function} [params.Container.onConnect] * Called when the client connects to the Managed Hub. Function is defined * as follows: function(container) * @param {Function} [params.Container.onDisconnect] * Called when the client disconnects from the Managed Hub. Function is * defined as follows: function(container) * @param {Object} [params.Container.scope] * Whenever one of the Container's callback functions is called, references * to "this" in the callback will refer to the scope object. If no scope is * provided, default is window. * @param {Function} [params.Container.log] * Optional logger function. Would be used to log to console.log or * equivalent. * @param {Object} params.IframeContainer.parent * DOM element that is to be parent of iframe * @param {String} params.IframeContainer.uri * Initial Iframe URI (Container will add parameters to this URI) * @param {String} [params.IframeContainer.tunnelURI] * URI of the tunnel iframe. Must be from the same origin as the page which * instantiates the IframeContainer. If not specified, connection will not * be fully secure (see SECURITY section). * @param {Object} [params.IframeContainer.iframeAttrs] * Attributes to add to IFRAME DOM entity. For example: * { style: { width: "100%", * height: "100%" }, * className: "some_class" } * @param {Number} [params.IframeContainer.timeout] * Load timeout in milliseconds. If not specified, defaults to 15000. If * the client at params.IframeContainer.uri does not establish a connection * with this container in the given time, the onSecurityAlert callback is * called with a LoadTimeout error code. * @param {Function} [params.IframeContainer.seed] * A function that returns a string that will be used to seed the * pseudo-random number generator, which is used to create the security * tokens. An implementation of IframeContainer may choose to ignore this * value. * @param {Number} [params.IframeContainer.tokenLength] * Length of the security tokens used when transmitting messages. If not * specified, defaults to 6. An implementation of IframeContainer may choose * to ignore this value. * * @throws {OpenAjax.hub.Error.BadParameters} if required params are not * present or null * @throws {OpenAjax.hub.Error.Duplicate} if a Container with this clientID * already exists in the given Managed Hub * @throws {OpenAjax.hub.Error.Disconnected} if hub is not connected */ OpenAjax.hub.IframeContainer = function( hub, clientID, params ) { assertValidParams( arguments ); var container = this; var scope = params.Container.scope || window; var connected = false; var subs = {}; var securityToken; var internalID; var timeout = params.IframeContainer.timeout || 15000; var loadTimer; if ( params.Container.log ) { var log = function( msg ) { try { params.Container.log.call( scope, "IframeContainer::" + clientID + ": " + msg ); } catch( e ) { OpenAjax.hub._debugger(); } }; } else { log = function() {}; } this._init = function() { // add to ManagedHub first, to see if clientID is a duplicate hub.addContainer( this ); // Create an "internal" ID, which is guaranteed to be unique within the // window, not just within the hub. internalID = OpenAjax.hub.IframeContainer._rpcRouter.add( clientID, this ); securityToken = generateSecurityToken( params, scope, log ); var relay = null; var transportName = OpenAjax.gadgets.rpc.getRelayChannel(); if ( params.IframeContainer.tunnelURI ) { if ( transportName !== "wpm" && transportName !== "nix" ) { throw new Error( OpenAjax.hub.Error.IncompatBrowser ); } } else { log( "WARNING: Parameter 'IframeContaienr.tunnelURI' not specified. Connection will not be fully secure." ); if ( transportName === "rmr" ) { relay = OpenAjax.gadgets.rpc.getOrigin( params.IframeContainer.uri ) + "/robots.txt"; } } // Create IFRAME to hold the client createIframe(); OpenAjax.gadgets.rpc.setupReceiver( internalID, relay ); startLoadTimer(); }; /*** OpenAjax.hub.Container interface ***/ this.sendToClient = function( topic, data, subscriptionID ) { OpenAjax.gadgets.rpc.call( internalID, "openajax.pubsub", null, "pub", topic, data, subscriptionID ); }; this.remove = function() { finishDisconnect(); clearTimeout( loadTimer ); OpenAjax.gadgets.rpc.removeReceiver( internalID ); var iframe = document.getElementById( internalID ); iframe.parentNode.removeChild( iframe ); OpenAjax.hub.IframeContainer._rpcRouter.remove( internalID ); }; this.isConnected = function() { return connected; }; this.getClientID = function() { return clientID; }; this.getPartnerOrigin = function() { if ( connected ) { var origin = OpenAjax.gadgets.rpc.getReceiverOrigin( internalID ); if ( origin ) { // remove port if present return ( /^([a-zA-Z]+:\/\/[^:]+).*/.exec( origin )[1] ); } } return null; }; this.getParameters = function() { return params; }; this.getHub = function() { return hub; }; /*** OpenAjax.hub.IframeContainer interface ***/ /** * Get the iframe associated with this iframe container * * This function returns the iframe associated with an IframeContainer, * allowing the Manager Application to change its size, styles, scrollbars, etc. * * CAUTION: The iframe is owned exclusively by the IframeContainer. The Manager * Application MUST NOT destroy the iframe directly. Also, if the iframe is * hidden and disconnected, the Manager Application SHOULD NOT attempt to make * it visible. The Container SHOULD automatically hide the iframe when it is * disconnected; to make it visible would introduce security risks. * * @returns iframeElement * @type {Object} */ this.getIframe = function() { return document.getElementById( internalID ); }; /*** private functions ***/ function assertValidParams( args ) { var hub = args[0], clientID = args[1], params = args[2]; if ( ! hub || ! clientID || ! params || ! params.Container || ! params.Container.onSecurityAlert || ! params.IframeContainer || ! params.IframeContainer.parent || ! params.IframeContainer.uri ) { throw new Error( OpenAjax.hub.Error.BadParameters ); } } this._handleIncomingRPC = function( command, topic, data ) { switch ( command ) { // publish // 'data' is topic message case "pub": hub.publishForClient( container, topic, data ); break; // subscribe // 'data' is subscription ID case "sub": var errCode = ""; // empty string is success try { subs[ data ] = hub.subscribeForClient( container, topic, data ); } catch( e ) { errCode = e.message; } return errCode; // unsubscribe // 'data' is subscription ID case "uns": var handle = subs[ data ]; hub.unsubscribeForClient( container, handle ); delete subs[ data ]; return data; // connect case "con": finishConnect(); return true; // disconnect case "dis": startLoadTimer(); finishDisconnect(); if ( params.Container.onDisconnect ) { try { params.Container.onDisconnect.call( scope, container ); } catch( e ) { OpenAjax.hub._debugger(); log( "caught error from onDisconnect callback to constructor: " + e.message ); } } return true; } }; this._onSecurityAlert = function( error ) { invokeSecurityAlert( rpcErrorsToOAA[ error ] ); }; // The RPC code requires that the 'name' attribute be properly set on the // iframe. However, setting the 'name' property on the iframe object // returned from 'createElement("iframe")' doesn't work on IE -- // 'window.name' returns null for the code within the iframe. The // workaround is to set the 'innerHTML' of a span to the iframe's HTML code, // with 'name' and other attributes properly set. function createIframe() { var span = document.createElement( "span" ); params.IframeContainer.parent.appendChild( span ); var iframeText = ''; span.innerHTML = iframeText; var tunnel = params.IframeContainer.tunnelURI; document.getElementById( internalID ).src = params.IframeContainer.uri + "#rpctoken=" + securityToken + (tunnel ? "&parent=" + encodeURIComponent( tunnel ) + "&forcesecure=true" : "&oaaParent=" + encodeURIComponent( OpenAjax.gadgets.rpc.getOrigin( window.location.href ))); } // If the relay iframe used by RPC has not been loaded yet, then we won't have unload protection // at this point. Since we can't detect when the relay iframe has loaded, we use a two stage // connection process. First, the child sends a connection msg and the container sends an ack. // Then the container sends a connection msg and the child replies with an ack. Since the // container can only send a message if the relay iframe has loaded, then we know if we get an // ack here that the relay iframe is ready. And we are fully connected. function finishConnect() { // connect acknowledgement function callback( result ) { if ( result ) { connected = true; clearTimeout( loadTimer ); document.getElementById( internalID ).style.visibility = "visible"; if ( params.Container.onConnect ) { try { params.Container.onConnect.call( scope, container ); } catch( e ) { OpenAjax.hub._debugger(); log( "caught error from onConnect callback to constructor: " + e.message ); } } } } OpenAjax.gadgets.rpc.call( internalID, "openajax.pubsub", callback, "cmd", "con" ); } function finishDisconnect() { if ( connected ) { connected = false; document.getElementById( internalID ).style.visibility = "hidden"; // unsubscribe from all subs for ( var s in subs ) { hub.unsubscribeForClient( container, subs[s] ); } subs = {}; } } function invokeSecurityAlert( errorMsg ) { try { params.Container.onSecurityAlert.call( scope, container, errorMsg ); } catch( e ) { OpenAjax.hub._debugger(); log( "caught error from onSecurityAlert callback to constructor: " + e.message ); } } function startLoadTimer() { loadTimer = setTimeout( function() { // alert the security alert callback invokeSecurityAlert( OpenAjax.hub.SecurityAlert.LoadTimeout ); // don't receive any more messages from HubClient container._handleIncomingRPC = function() {}; }, timeout ); } this._init(); }; //////////////////////////////////////////////////////////////////////////////// /** * Create a new IframeHubClient. * @constructor * @extends OpenAjax.hub.HubClient * * @param {Object} params * Once the constructor is called, the params object belongs to the * HubClient. The caller MUST not modify it. * The following are the pre-defined properties on params: * @param {Function} params.HubClient.onSecurityAlert * Called when an attempted security breach is thwarted * @param {Object} [params.HubClient.scope] * Whenever one of the HubClient's callback functions is called, * references to "this" in the callback will refer to the scope object. * If not provided, the default is window. * @param {Function} [params.HubClient.log] * Optional logger function. Would be used to log to console.log or * equivalent. * @param {Boolean} [params.IframeHubClient.requireParentVerifiable] * Set to true in order to require that this IframeHubClient use a * transport that can verify the parent Container's identity. * @param {Function} [params.IframeHubClient.seed] * A function that returns a string that will be used to seed the * pseudo-random number generator, which is used to create the security * tokens. An implementation of IframeHubClient may choose to ignore * this value. * @param {Number} [params.IframeHubClient.tokenLength] * Length of the security tokens used when transmitting messages. If * not specified, defaults to 6. An implementation of IframeHubClient * may choose to ignore this value. * * @throws {OpenAjax.hub.Error.BadParameters} if any of the required * parameters is missing, or if a parameter value is invalid in * some way. */ OpenAjax.hub.IframeHubClient = function( params ) { if ( ! params || ! params.HubClient || ! params.HubClient.onSecurityAlert ) { throw new Error( OpenAjax.hub.Error.BadParameters ); } var client = this; var scope = params.HubClient.scope || window; var connected = false; var subs = {}; var subIndex = 0; var clientID; // var securityToken; // XXX still need "securityToken"? if ( params.HubClient.log ) { var log = function( msg ) { try { params.HubClient.log.call( scope, "IframeHubClient::" + clientID + ": " + msg ); } catch( e ) { OpenAjax.hub._debugger(); } }; } else { log = function() {}; } this._init = function() { var urlParams = OpenAjax.gadgets.util.getUrlParameters(); if ( ! urlParams.parent ) { // The RMR transport does not require a valid relay file, but does need a URL // in the parent's domain. The URL does not need to point to valid file, so just // point to 'robots.txt' file. See RMR transport code for more info. var parent = urlParams.oaaParent + "/robots.txt"; OpenAjax.gadgets.rpc.setupReceiver( "..", parent ); } if ( params.IframeHubClient && params.IframeHubClient.requireParentVerifiable && OpenAjax.gadgets.rpc.getReceiverOrigin( ".." ) === null ) { // If user set 'requireParentVerifiable' to true but RPC transport does not // support this, throw error. OpenAjax.gadgets.rpc.removeReceiver( ".." ); throw new Error( OpenAjax.hub.Error.IncompatBrowser ); } OpenAjax.hub.IframeContainer._rpcRouter.add( "..", this ); // XXX The RPC layer initializes immediately on load, in the child (IframeHubClient). So it is too // late here to specify a security token for the RPC layer. At the moment, only the NIX // transport requires a child token (IFPC [aka FIM] is not supported). // securityToken = generateSecurityToken( params, scope, log ); var internalID = OpenAjax.gadgets.rpc.RPC_ID; if ( ! internalID ) { throw new Error( OpenAjax.hub.Error.WrongProtocol ); } clientID = internalID.substr( internalID.indexOf("_") + 1 ); }; /*** HubClient interface ***/ this.connect = function( onComplete, scope ) { if ( connected ) { throw new Error( OpenAjax.hub.Error.Duplicate ); } // connect acknowledgement function callback( result ) { if ( result ) { connected = true; if ( onComplete ) { try { onComplete.call( scope || window, client, true ); } catch( e ) { OpenAjax.hub._debugger(); log( "caught error from onComplete callback to connect(): " + e.message ); } } } } OpenAjax.gadgets.rpc.call( "..", "openajax.pubsub", callback, "con" ); }; this.disconnect = function( onComplete, scope ) { if ( !connected ) { throw new Error( OpenAjax.hub.Error.Disconnected ); } connected = false; // disconnect acknowledgement var callback = null; if ( onComplete ) { callback = function( result ) { try { onComplete.call( scope || window, client, true ); } catch( e ) { OpenAjax.hub._debugger(); log( "caught error from onComplete callback to disconnect(): " + e.message ); } }; } OpenAjax.gadgets.rpc.call( "..", "openajax.pubsub", callback, "dis" ); }; this.getPartnerOrigin = function() { if ( connected ) { var origin = OpenAjax.gadgets.rpc.getReceiverOrigin( ".." ); if ( origin ) { // remove port if present return ( /^([a-zA-Z]+:\/\/[^:]+).*/.exec( origin )[1] ); } } return null; }; this.getClientID = function() { return clientID; }; /*** Hub interface ***/ this.subscribe = function( topic, onData, scope, onComplete, subscriberData ) { assertConn(); assertSubTopic( topic ); if ( ! onData ) { throw new Error( OpenAjax.hub.Error.BadParameters ); } scope = scope || window; var subID = "" + subIndex++; subs[ subID ] = { cb: onData, sc: scope, d: subscriberData }; // subscribe acknowledgement function callback( result ) { if ( result !== '' ) { // error delete subs[ subID ]; } if ( onComplete ) { try { onComplete.call( scope, subID, result === "", result ); } catch( e ) { OpenAjax.hub._debugger(); log( "caught error from onComplete callback to subscribe(): " + e.message ); } } } OpenAjax.gadgets.rpc.call( "..", "openajax.pubsub", callback, "sub", topic, subID ); return subID; }; this.publish = function( topic, data ) { assertConn(); assertPubTopic( topic ); OpenAjax.gadgets.rpc.call( "..", "openajax.pubsub", null, "pub", topic, data ); }; this.unsubscribe = function( subscriptionID, onComplete, scope ) { assertConn(); if ( ! subscriptionID ) { throw new Error( OpenAjax.hub.Error.BadParameters ); } // if no such subscriptionID, or in process of unsubscribing given ID, throw error if ( ! subs[ subscriptionID ] || subs[ subscriptionID ].uns ) { throw new Error( OpenAjax.hub.Error.NoSubscription ); } // unsubscribe in progress subs[ subscriptionID ].uns = true; // unsubscribe acknowledgement function callback( result ) { delete subs[ subscriptionID ]; if ( onComplete ) { try { onComplete.call( scope || window, subscriptionID, true ); } catch( e ) { OpenAjax.hub._debugger(); log( "caught error from onComplete callback to unsubscribe(): " + e.message ); } } } OpenAjax.gadgets.rpc.call( "..", "openajax.pubsub", callback, "uns", null, subscriptionID ); }; this.isConnected = function() { return connected; }; this.getScope = function() { return scope; }; this.getSubscriberData = function( subscriptionID ) { assertConn(); if ( subs[ subscriptionID ] ) { return subs[ subscriptionID ].d; } throw new Error( OpenAjax.hub.Error.NoSubscription ); }; this.getSubscriberScope = function( subscriptionID ) { assertConn(); if ( subs[ subscriptionID ] ) { return subs[ subscriptionID ].sc; } throw new Error( OpenAjax.hub.Error.NoSubscription ); }; this.getParameters = function() { return params; }; /*** private functions ***/ this._handleIncomingRPC = function( command, topic, data, subscriptionID ) { if ( command === "pub" ) { // if subscription exists and we are not in process of unsubscribing... if ( subs[ subscriptionID ] && ! subs[ subscriptionID ].uns ) { try { subs[ subscriptionID ].cb.call( subs[ subscriptionID ].sc, topic, data, subs[ subscriptionID ].d ); } catch( e ) { OpenAjax.hub._debugger(); log( "caught error from onData callback to subscribe(): " + e.message ); } } } // else if command === "cmd"... // First time this function is called, topic should be "con". This is the 2nd stage of the // connection process. Simply need to return "true" in order to send an acknowledgement // back to container. See finishConnect() in the container object. if ( topic === "con" ) { return true; } return false; }; function assertConn() { if ( ! connected ) { throw new Error( OpenAjax.hub.Error.Disconnected ); } } function assertSubTopic( topic ) { if ( ! topic ) { throw new Error( OpenAjax.hub.Error.BadParameters ); } var path = topic.split("."); var len = path.length; for (var i = 0; i < len; i++) { var p = path[i]; if ((p === "") || ((p.indexOf("*") != -1) && (p != "*") && (p != "**"))) { throw new Error( OpenAjax.hub.Error.BadParameters ); } if ((p == "**") && (i < len - 1)) { throw new Error( OpenAjax.hub.Error.BadParameters ); } } } function assertPubTopic( topic ) { if ( !topic || topic === "" || (topic.indexOf("*") != -1) || (topic.indexOf("..") != -1) || (topic.charAt(0) == ".") || (topic.charAt(topic.length-1) == ".")) { throw new Error( OpenAjax.hub.Error.BadParameters ); } } this._init(); }; //////////////////////////////////////////////////////////////////////////////// // RPC object contents: // s: Service Name // f: From // c: The callback ID or 0 if none. // a: The arguments for this RPC call. // t: The authentication token. OpenAjax.hub.IframeContainer._rpcRouter = function() { var receivers = {}; function router() { var r = receivers[ this.f ]; if ( r ) { return r._handleIncomingRPC.apply( r, arguments ); } } function onSecurityAlert( receiverId, error ) { var r = receivers[ receiverId ]; if ( r ) { r._onSecurityAlert.call( r, error ); } } return { add: function( id, receiver ) { function _add( id, receiver ) { if ( id === ".." ) { if ( ! receivers[ ".." ] ) { receivers[ ".." ] = receiver; } return; } do { // a client with the specified ID already exists on this page; // create a unique ID newID = ((0x7fff * Math.random()) | 0).toString(16) + "_" + id; } while ( receivers[ newID ] ); receivers[ newID ] = receiver; return newID; } // when this function is first called, register the RPC service OpenAjax.gadgets.rpc.register( "openajax.pubsub", router ); OpenAjax.gadgets.rpc.config({ securityCallback: onSecurityAlert }); rpcErrorsToOAA[ OpenAjax.gadgets.rpc.SEC_ERROR_LOAD_TIMEOUT ] = OpenAjax.hub.SecurityAlert.LoadTimeout; rpcErrorsToOAA[ OpenAjax.gadgets.rpc.SEC_ERROR_FRAME_PHISH ] = OpenAjax.hub.SecurityAlert.FramePhish; rpcErrorsToOAA[ OpenAjax.gadgets.rpc.SEC_ERROR_FORGED_MSG ] = OpenAjax.hub.SecurityAlert.ForgedMsg; this.add = _add; return _add( id, receiver ); }, remove: function( id ) { delete receivers[ id ]; } }; }(); var rpcErrorsToOAA = {}; //////////////////////////////////////////////////////////////////////////////// function generateSecurityToken( params, scope, log ) { if ( ! OpenAjax.hub.IframeContainer._prng ) { // create pseudo-random number generator with a default seed var seed = new Date().getTime() + Math.random() + document.cookie; OpenAjax.hub.IframeContainer._prng = OpenAjax._smash.crypto.newPRNG( seed ); } var p = params.IframeContainer || params.IframeHubClient; if ( p && p.seed ) { try { var extraSeed = p.seed.call( scope ); OpenAjax.hub.IframeContainer._prng.addSeed( extraSeed ); } catch( e ) { OpenAjax.hub._debugger(); log( "caught error from 'seed' callback: " + e.message ); } } var tokenLength = (p && p.tokenLength) || 6; return OpenAjax.hub.IframeContainer._prng.nextRandomB64Str( tokenLength ); } })(); }/* Copyright 2006-2009 OpenAjax Alliance Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ // SMASH.CRYPTO // // Small library containing some minimal crypto functionality for a // - a hash-function: SHA-1 (see FIPS PUB 180-2 for definition) // BigEndianWord[5] <- smash.crypto.sha1( BigEndianWord[*] dataWA, int lenInBits) // // - a message authentication code (MAC): HMAC-SHA-1 (RFC2104/2202) // BigEndianWord[5] <- smash.crypto.hmac_sha1( // BigEndianWord[3-16] keyWA, // Ascii or Unicode string dataS, // int chrsz (8 for Asci/16 for Unicode) // // - pseudo-random number generator (PRNG): HMAC-SHA-1 in counter mode, following // Barak & Halevi, An architecture for robust pseudo-random generation and applications to /dev/random, CCS 2005 // rngObj <- smash.crypto.newPRNG( String[>=12] seedS) // where rngObj has methods // addSeed(String seed) // BigEndianWord[len] <- nextRandomOctets(int len) // Base64-String[len] <- nextRandomB64Str(int len) // Note: HMAC-SHA1 in counter-mode does not provide forward-security on corruption. // However, the PRNG state is kept inside a closure. So if somebody can break the closure, he probably could // break a whole lot more and forward-security of the prng is not the highest of concerns anymore :-) if ( typeof OpenAjax._smash == 'undefined' ) { OpenAjax._smash = {}; } OpenAjax._smash.crypto = { // Some utilities // convert a string to an array of big-endian words 'strToWA': function (/* Ascii or Unicode string */ str, /* int 8 for Asci/16 for Unicode */ chrsz){ var bin = Array(); var mask = (1 << chrsz) - 1; for(var i = 0; i < str.length * chrsz; i += chrsz) bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32); return bin; }, // MAC 'hmac_sha1' : function( /* BigEndianWord[3-16]*/ keyWA, /* Ascii or Unicode string */ dataS, /* int 8 for Asci/16 for Unicode */ chrsz) { // write our own hmac derived from paj's so we do not have to do constant key conversions and length checking ... var ipad = Array(16), opad = Array(16); for(var i = 0; i < 16; i++) { ipad[i] = keyWA[i] ^ 0x36363636; opad[i] = keyWA[i] ^ 0x5C5C5C5C; } var hash = this.sha1( ipad.concat(this.strToWA(dataS, chrsz)), 512 + dataS.length * chrsz); return this.sha1( opad.concat(hash), 512 + 160); }, // PRNG factory method // see below 'addSeed', 'nextRandomOctets' & 'nextRandomB64Octets' for public methods of returnd prng object 'newPRNG' : function (/* String[>=12] */ seedS) { var that = this; // parameter checking // We cannot really verify entropy but obviously the string must have at least a minimal length to have enough entropy // However, a 2^80 security seems ok, so we check only that at least 12 chars assuming somewhat random ASCII if ( (typeof seedS != 'string') || (seedS.length < 12) ) { alert("WARNING: Seed length too short ..."); } // constants var __refresh_keyWA = [ 0xA999, 0x3E36, 0x4706, 0x816A, 0x2571, 0x7850, 0xC26C, 0x9CD0, 0xBA3E, 0xD89D, 0x1233, 0x9525, 0xff3C, 0x1A83, 0xD491, 0xFF15 ]; // some random key for refresh ... // internal state var _keyWA = []; // BigEndianWord[5] var _cnt = 0; // int function extract(seedS) { return that.hmac_sha1(__refresh_keyWA, seedS, 8); } function refresh(seedS) { // HMAC-SHA1 is not ideal, Rijndal 256bit block/key in CBC mode with fixed key might be better // but to limit the primitives and given that we anyway have only limited entropy in practise // this seems good enough var uniformSeedWA = extract(seedS); for(var i = 0; i < 5; i++) { _keyWA[i] ^= uniformSeedWA[i]; } } // inital state seeding refresh(seedS); // public methods return { // Mix some additional seed into the PRNG state 'addSeed' : function (/* String */ seed) { // no parameter checking. Any added entropy should be fine ... refresh(seed); }, // Get an array of len random octets 'nextRandomOctets' : /* BigEndianWord[len] <- */ function (/* int */ len) { var randOctets = []; while (len > 0) { _cnt+=1; var nextBlock = that.hmac_sha1(_keyWA, (_cnt).toString(16), 8); for (var i=0; (i < 20) & (len > 0); i++, len--) { randOctets.push( (nextBlock[i>>2] >> (i % 4) ) % 256); } // Note: if len was not a multiple 20, some random octets are ignored here but who cares .. } return randOctets; }, // Get a random string of Base64-like (see below) chars of length len // Note: there is a slightly non-standard Base64 with no padding and '-' and '_' for '+' and '/', respectively 'nextRandomB64Str' : /* Base64-String <- */ function (/* int */ len) { var b64StrMap = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; var randOctets = this.nextRandomOctets(len); var randB64Str = ''; for (var i=0; i < len; i++) { randB64Str += b64StrMap.charAt(randOctets[i] & 0x3F); } return randB64Str; } }; }, // Digest function: // BigEndianWord[5] <- sha1( BigEndianWord[*] dataWA, int lenInBits) 'sha1' : function(){ // Note: all Section references below refer to FIPS 180-2. // private utility functions // - 32bit addition with wrap-around var add_wa = function (x, y){ var lsw = (x & 0xFFFF) + (y & 0xFFFF); var msw = (x >> 16) + (y >> 16) + (lsw >> 16); return (msw << 16) | (lsw & 0xFFFF); }; // - 32bit rotatate left var rol = function(num, cnt) { return (num << cnt) | (num >>> (32 - cnt)); }; // - round-dependent function f_t from Section 4.1.1 function sha1_ft(t, b, c, d) { if(t < 20) return (b & c) | ((~b) & d); if(t < 40) return b ^ c ^ d; if(t < 60) return (b & c) | (b & d) | (c & d); return b ^ c ^ d; } // - round-dependent SHA-1 constants from Section 4.2.1 function sha1_kt(t) { return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : (t < 60) ? -1894007588 : /* (t < 80) */ -899497514 ; } // main algorithm. return function( /* BigEndianWord[*] */ dataWA, /* int */ lenInBits) { // Section 6.1.1: Preprocessing //----------------------------- // 1. padding: (see also Section 5.1.1) // - append one 1 followed by 0 bits filling up 448 bits of last (512bit) block dataWA[lenInBits >> 5] |= 0x80 << (24 - lenInBits % 32); // - encode length in bits in last 64 bits // Note: we rely on javascript to zero file elements which are beyond last (partial) data-block // but before this length encoding! dataWA[((lenInBits + 64 >> 9) << 4) + 15] = lenInBits; // 2. 512bit blocks (actual split done ondemand later) var W = Array(80); // 3. initial hash using SHA-1 constants on page 13 var H0 = 1732584193; var H1 = -271733879; var H2 = -1732584194; var H3 = 271733878; var H4 = -1009589776; // 6.1.2 SHA-1 Hash Computation for(var i = 0; i < dataWA.length; i += 16) { // 1. Message schedule, done below // 2. init working variables var a = H0; var b = H1; var c = H2; var d = H3; var e = H4; // 3. round-functions for(var j = 0; j < 80; j++) { // postponed step 2 W[j] = ( (j < 16) ? dataWA[i+j] : rol(W[j-3] ^ W[j-8] ^ W[j-14] ^ W[j-16], 1)); var T = add_wa( add_wa( rol(a, 5), sha1_ft(j, b, c, d)), add_wa( add_wa(e, W[j]), sha1_kt(j)) ); e = d; d = c; c = rol(b, 30); b = a; a = T; } // 4. intermediate hash H0 = add_wa(a, H0); H1 = add_wa(b, H1); H2 = add_wa(c, H2); H3 = add_wa(d, H3); H4 = add_wa(e, H4); } return Array(H0, H1, H2, H3, H4); }; }() }; /* http://www.JSON.org/json2.js 2008-11-19 Public Domain. NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. See http://www.JSON.org/js.html This file creates a global JSON object containing two methods: stringify and parse. JSON.stringify(value, replacer, space) value any JavaScript value, usually an object or array. replacer an optional parameter that determines how object values are stringified for objects. It can be a function or an array of strings. space an optional parameter that specifies the indentation of nested structures. If it is omitted, the text will be packed without extra whitespace. If it is a number, it will specify the number of spaces to indent at each level. If it is a string (such as '\t' or ' '), it contains the characters used to indent at each level. This method produces a JSON text from a JavaScript value. When an object value is found, if the object contains a toJSON method, its toJSON method will be called and the result will be stringified. A toJSON method does not serialize: it returns the value represented by the name/value pair that should be serialized, or undefined if nothing should be serialized. The toJSON method will be passed the key associated with the value, and this will be bound to the object holding the key. For example, this would serialize Dates as ISO strings. Date.prototype.toJSON = function (key) { function f(n) { // Format integers to have at least two digits. return n < 10 ? '0' + n : n; } return this.getUTCFullYear() + '-' + f(this.getUTCMonth() + 1) + '-' + f(this.getUTCDate()) + 'T' + f(this.getUTCHours()) + ':' + f(this.getUTCMinutes()) + ':' + f(this.getUTCSeconds()) + 'Z'; }; You can provide an optional replacer method. It will be passed the key and value of each member, with this bound to the containing object. The value that is returned from your method will be serialized. If your method returns undefined, then the member will be excluded from the serialization. If the replacer parameter is an array of strings, then it will be used to select the members to be serialized. It filters the results such that only members with keys listed in the replacer array are stringified. Values that do not have JSON representations, such as undefined or functions, will not be serialized. Such values in objects will be dropped; in arrays they will be replaced with null. You can use a replacer function to replace those with JSON values. JSON.stringify(undefined) returns undefined. The optional space parameter produces a stringification of the value that is filled with line breaks and indentation to make it easier to read. If the space parameter is a non-empty string, then that string will be used for indentation. If the space parameter is a number, then the indentation will be that many spaces. Example: text = JSON.stringify(['e', {pluribus: 'unum'}]); // text is '["e",{"pluribus":"unum"}]' text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' text = JSON.stringify([new Date()], function (key, value) { return this[key] instanceof Date ? 'Date(' + this[key] + ')' : value; }); // text is '["Date(---current time---)"]' JSON.parse(text, reviver) This method parses a JSON text to produce an object or array. It can throw a SyntaxError exception. The optional reviver parameter is a function that can filter and transform the results. It receives each of the keys and values, and its return value is used instead of the original value. If it returns what it received, then the structure is not modified. If it returns undefined then the member is deleted. Example: // Parse the text. Values that look like ISO date strings will // be converted to Date objects. myData = JSON.parse(text, function (key, value) { var a; if (typeof value === 'string') { a = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); if (a) { return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6])); } } return value; }); myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { var d; if (typeof value === 'string' && value.slice(0, 5) === 'Date(' && value.slice(-1) === ')') { d = new Date(value.slice(5, -1)); if (d) { return d; } } return value; }); This is a reference implementation. You are free to copy, modify, or redistribute. This code should be minified before deployment. See http://javascript.crockford.com/jsmin.html USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO NOT CONTROL. */ /*jslint evil: true */ /*global JSON */ /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, lastIndex, length, parse, prototype, push, replace, slice, stringify, test, toJSON, toString, valueOf */ // Create a JSON object only if one does not already exist. We create the // methods in a closure to avoid creating global variables. if (!this.JSON) { JSON = {}; } (function () { function f(n) { // Format integers to have at least two digits. return n < 10 ? '0' + n : n; } if (typeof Date.prototype.toJSON !== 'function') { Date.prototype.toJSON = function (key) { return this.getUTCFullYear() + '-' + f(this.getUTCMonth() + 1) + '-' + f(this.getUTCDate()) + 'T' + f(this.getUTCHours()) + ':' + f(this.getUTCMinutes()) + ':' + f(this.getUTCSeconds()) + 'Z'; }; String.prototype.toJSON = Number.prototype.toJSON = Boolean.prototype.toJSON = function (key) { return this.valueOf(); }; } var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, gap, indent, meta = { // table of character substitutions '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\' }, rep; function quote(string) { // If the string contains no control characters, no quote characters, and no // backslash characters, then we can safely slap some quotes around it. // Otherwise we must also replace the offending characters with safe escape // sequences. escapable.lastIndex = 0; return escapable.test(string) ? '"' + string.replace(escapable, function (a) { var c = meta[a]; return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); }) + '"' : '"' + string + '"'; } function str(key, holder) { // Produce a string from holder[key]. var i, // The loop counter. k, // The member key. v, // The member value. length, mind = gap, partial, value = holder[key]; // If the value has a toJSON method, call it to obtain a replacement value. if (value && typeof value === 'object' && typeof value.toJSON === 'function') { value = value.toJSON(key); } // If we were called with a replacer function, then call the replacer to // obtain a replacement value. if (typeof rep === 'function') { value = rep.call(holder, key, value); } // What happens next depends on the value's type. switch (typeof value) { case 'string': return quote(value); case 'number': // JSON numbers must be finite. Encode non-finite numbers as null. return isFinite(value) ? String(value) : 'null'; case 'boolean': case 'null': // If the value is a boolean or null, convert it to a string. Note: // typeof null does not produce 'null'. The case is included here in // the remote chance that this gets fixed someday. return String(value); // If the type is 'object', we might be dealing with an object or an array or // null. case 'object': // Due to a specification blunder in ECMAScript, typeof null is 'object', // so watch out for that case. if (!value) { return 'null'; } // Make an array to hold the partial results of stringifying this object value. gap += indent; partial = []; // Is the value an array? if (Object.prototype.toString.apply(value) === '[object Array]') { // The value is an array. Stringify every element. Use null as a placeholder // for non-JSON values. length = value.length; for (i = 0; i < length; i += 1) { partial[i] = str(i, value) || 'null'; } // Join all of the elements together, separated with commas, and wrap them in // brackets. v = partial.length === 0 ? '[]' : gap ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : '[' + partial.join(',') + ']'; gap = mind; return v; } // If the replacer is an array, use it to select the members to be stringified. if (rep && typeof rep === 'object') { length = rep.length; for (i = 0; i < length; i += 1) { k = rep[i]; if (typeof k === 'string') { v = str(k, value); if (v) { partial.push(quote(k) + (gap ? ': ' : ':') + v); } } } } else { // Otherwise, iterate through all of the keys in the object. for (k in value) { if (Object.hasOwnProperty.call(value, k)) { v = str(k, value); if (v) { partial.push(quote(k) + (gap ? ': ' : ':') + v); } } } } // Join all of the member texts together, separated with commas, // and wrap them in braces. v = partial.length === 0 ? '{}' : gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : '{' + partial.join(',') + '}'; gap = mind; return v; } } // If the JSON object does not yet have a stringify method, give it one. if (typeof JSON.stringify !== 'function') { JSON.stringify = function (value, replacer, space) { // The stringify method takes a value and an optional replacer, and an optional // space parameter, and returns a JSON text. The replacer can be a function // that can replace values, or an array of strings that will select the keys. // A default replacer method can be provided. Use of the space parameter can // produce text that is more easily readable. var i; gap = ''; indent = ''; // If the space parameter is a number, make an indent string containing that // many spaces. if (typeof space === 'number') { for (i = 0; i < space; i += 1) { indent += ' '; } // If the space parameter is a string, it will be used as the indent string. } else if (typeof space === 'string') { indent = space; } // If there is a replacer, it must be a function or an array. // Otherwise, throw an error. rep = replacer; if (replacer && typeof replacer !== 'function' && (typeof replacer !== 'object' || typeof replacer.length !== 'number')) { throw new Error('JSON.stringify'); } // Make a fake root object containing our value under the key of ''. // Return the result of stringifying the value. return str('', {'': value}); }; } // If the JSON object does not yet have a parse method, give it one. if (typeof JSON.parse !== 'function') { JSON.parse = function (text, reviver) { // The parse method takes a text and an optional reviver function, and returns // a JavaScript value if the text is a valid JSON text. var j; function walk(holder, key) { // The walk method is used to recursively walk the resulting structure so // that modifications can be made. var k, v, value = holder[key]; if (value && typeof value === 'object') { for (k in value) { if (Object.hasOwnProperty.call(value, k)) { v = walk(value, k); if (v !== undefined) { value[k] = v; } else { delete value[k]; } } } } return reviver.call(holder, key, value); } // Parsing happens in four stages. In the first stage, we replace certain // Unicode characters with escape sequences. JavaScript handles many characters // incorrectly, either silently deleting them, or treating them as line endings. cx.lastIndex = 0; if (cx.test(text)) { text = text.replace(cx, function (a) { return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); }); } // In the second stage, we run the text against regular expressions that look // for non-JSON patterns. We are especially concerned with '()' and 'new' // because they can cause invocation, and '=' because it can cause mutation. // But just to be safe, we want to reject all unexpected forms. // We split the second stage into 4 regexp operations in order to work around // crippling inefficiencies in IE's and Safari's regexp engines. First we // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we // replace all simple value tokens with ']' characters. Third, we delete all // open brackets that follow a colon or comma or that begin the text. Finally, // we look to see that the remaining characters are only whitespace or ']' or // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. if (/^[\],:{}\s]*$/. test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'). replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { // In the third stage we use the eval function to compile the text into a // JavaScript structure. The '{' operator is subject to a syntactic ambiguity // in JavaScript: it can begin a block or an object literal. We wrap the text // in parens to eliminate the ambiguity. j = eval('(' + text + ')'); // In the optional fourth stage, we recursively walk the new structure, passing // each name/value pair to a reviver function for possible transformation. return typeof reviver === 'function' ? walk({'': j}, '') : j; } // If the text is not JSON parseable, then a SyntaxError is thrown. throw new SyntaxError('JSON.parse'); }; } })(); /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /** * @fileoverview External functions used by the OpenSocial RPC code. This file * is for use by OpenAjax only. */ //--- from core.util/util.js ---// /** * @static * @class Provides general-purpose utility functions. * @name gadgets.util */ OpenAjax.gadgets.util = function() { /** * Parses URL parameters into an object. * @param {string} url - the url parameters to parse * @return {Array.} The parameters as an array */ function parseUrlParams(url) { // Get settings from url, 'hash' takes precedence over 'search' component // don't use document.location.hash due to browser differences. var query; var queryIdx = url.indexOf("?"); var hashIdx = url.indexOf("#"); if (hashIdx === -1) { query = url.substr(queryIdx + 1); } else { // essentially replaces "#" with "&" query = [url.substr(queryIdx + 1, hashIdx - queryIdx - 1), "&", url.substr(hashIdx + 1)].join(""); } return query.split("&"); } var parameters = null; var onLoadHandlers = []; return /** @scope gadgets.util */ { /** * Gets the URL parameters. * * @param {string=} opt_url Optional URL whose parameters to parse. * Defaults to window's current URL. * @return {Object} Parameters passed into the query string * @member gadgets.util * @private Implementation detail. */ getUrlParameters : function (opt_url) { if (parameters !== null && typeof opt_url === "undefined") { // "parameters" is a cache of current window params only. return parameters; } var parsed = {}; var pairs = parseUrlParams(opt_url || document.location.href); var unesc = window.decodeURIComponent ? decodeURIComponent : unescape; for (var i = 0, j = pairs.length; i < j; ++i) { var pos = pairs[i].indexOf('='); if (pos === -1) { continue; } var argName = pairs[i].substring(0, pos); var value = pairs[i].substring(pos + 1); // difference to IG_Prefs, is that args doesn't replace spaces in // argname. Unclear on if it should do: // argname = argname.replace(/\+/g, " "); value = value.replace(/\+/g, " "); parsed[argName] = unesc(value); } if (typeof opt_url === "undefined") { // Cache current-window params in parameters var. parameters = parsed; } return parsed; }, /** * Registers an onload handler. * @param {function()} callback The handler to run * * @member gadgets.util */ registerOnLoadHandler : function (callback) { onLoadHandlers.push(callback); }, /** * Runs all functions registered via registerOnLoadHandler. * @private Only to be used by the container, not gadgets. */ runOnLoadHandlers : function () { for (var i = 0, j = onLoadHandlers.length; i < j; ++i) { onLoadHandlers[i](); } }, /** * Attach an event listener to given DOM element * * @param {object} elem DOM element on which to attach event. * @param {string} eventName Event type to listen for. * @param {function} callback Invoked when specified event occurs. * @param {boolean} useCapture If true, initiates capture. */ 'attachBrowserEvent': function(elem, eventName, callback, useCapture) { if (elem.addEventListener) { elem.addEventListener(eventName, callback, useCapture); } else if (elem.attachEvent) { elem.attachEvent('on' + eventName, callback); } }, /** * Remove event listener * * @param {object} elem DOM element from which to remove event. * @param {string} eventName Event type to remove. * @param {function} callback Listener to remove. * @param {boolean} useCapture Specifies whether listener being removed was added with * capture enabled. */ 'removeBrowserEvent': function(elem, eventName, callback, useCapture) { if (elem.removeEventListener) { elem.removeEventListener(eventName, callback, useCapture); } else if (elem.detachEvent){ elem.detachEvent('on' + eventName, callback); } } }; }(); // Initialize url parameters so that hash data is pulled in before it can be // altered by a click. OpenAjax.gadgets.util.getUrlParameters(); //--- from core.json/json.js ---// OpenAjax.gadgets.json = OpenAjax.gadgets.json || {}; if ( ! OpenAjax.gadgets.json.stringify ) { OpenAjax.gadgets.json = { parse: function(str) { try { if (str==="postmessage.test"){return false;} return window.JSON.parse(str); } catch (e) { return false; } }, stringify: function(obj) { try { return window.JSON.stringify(obj); } catch (e) { return null; } } }; } //--- from core.log/log.js ---// /** * Log an informational message */ OpenAjax.gadgets.log = function(message) { OpenAjax.gadgets.log.logAtLevel(OpenAjax.gadgets.log.INFO, message); }; /** * Log a warning */ OpenAjax.gadgets.warn = function(message) { OpenAjax.gadgets.log.logAtLevel(OpenAjax.gadgets.log.WARNING, message); }; /** * Log an error */ OpenAjax.gadgets.error = function(message) { OpenAjax.gadgets.log.logAtLevel(OpenAjax.gadgets.log.ERROR, message); }; /** * Sets the log level threshold. * @param {Number} logLevel - New log level threshold. * @static */ OpenAjax.gadgets.setLogLevel = function(logLevel) { OpenAjax.gadgets.log.logLevelThreshold_ = logLevel; }; /** * Logs a log message if output console is available, and log threshold is met. * @param {Number} level - the level to log with. Optional, defaults to * @param {Object} message - The message to log * gadgets.log.INFO. * @static */ OpenAjax.gadgets.log.logAtLevel = function(level, message) { if (level < OpenAjax.gadgets.log.logLevelThreshold_ || !OpenAjax.gadgets.log._console) { return; } var gadgetconsole = OpenAjax.gadgets.log._console; if (level == OpenAjax.gadgets.log.WARNING && gadgetconsole.warn) { gadgetconsole.warn(message); } else if (level == OpenAjax.gadgets.log.ERROR && gadgetconsole.error) { gadgetconsole.error(message); } else if (gadgetconsole.log) { gadgetconsole.log(message); } }; /** * Log level for informational logging. * @static */ OpenAjax.gadgets.log.INFO = 1; /** * Log level for warning logging. * @static */ OpenAjax.gadgets.log.WARNING = 2; /** * Log level for error logging. * @static */ OpenAjax.gadgets.log.ERROR = 3; /** * Log level for no logging * @static */ OpenAjax.gadgets.log.NONE = 4; /** * Current log level threshold. * @type Number * @private * @static */ OpenAjax.gadgets.log.logLevelThreshold_ = OpenAjax.gadgets.log.INFO; /** * Console to log to * @private * @static */ OpenAjax.gadgets.log._console = window.console ? window.console : window.opera ? window.opera.postError : undefined; //////////////////////////////////////////////////////////////////////////////////////////////////// // onload handler compatibility code //////////////////////////////////////////////////////////////////////////////////////////////////// (function() { // XXX What if this script file (iframe.js) is dynamically loaded after the page has loaded. if ( ! window.__isgadget ) { var loaded = false; function onload() { if ( ! loaded ) { loaded = true; // This is necessary for the RMR and FE transports. OpenAjax.gadgets.util.runOnLoadHandlers(); // Since the page has now loaded, change registerOnLoadHandler() to immediately fire // callback. OpenAjax.gadgets.util.registerOnLoadHandler = function( callback ) { setTimeout( callback, 0 ); }; // prevent IE memory leak if ( window.detachEvent ) { window.detachEvent( "onload", onload ); } } } if ( window.addEventListener ) { document.addEventListener( "DOMContentLoaded", onload, false ); window.addEventListener( "load", onload, false ); } else if ( window.attachEvent ) { // XXX use doScroll trick? window.attachEvent( "onload", onload ); } } })(); /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ OpenAjax.gadgets.rpctx = OpenAjax.gadgets.rpctx || {}; /* * For Gecko-based browsers, the security model allows a child to call a * function on the frameElement of the iframe, even if the child is in * a different domain. This method is dubbed "frameElement" (fe). * * The ability to add and call such functions on the frameElement allows * a bidirectional channel to be setup via the adding of simple function * references on the frameElement object itself. In this implementation, * when the container sets up the authentication information for that gadget * (by calling setAuth(...)) it as well adds a special function on the * gadget's iframe. This function can then be used by the gadget to send * messages to the container. In turn, when the gadget tries to send a * message, it checks to see if this function has its own function stored * that can be used by the container to call the gadget. If not, the * function is created and subsequently used by the container. * Note that as a result, FE can only be used by a container to call a * particular gadget *after* that gadget has called the container at * least once via FE. * * fe: Gecko-specific frameElement trick. * - Firefox 1+ */ if (!OpenAjax.gadgets.rpctx.frameElement) { // make lib resilient to double-inclusion OpenAjax.gadgets.rpctx.frameElement = function() { // Consts for FrameElement. var FE_G2C_CHANNEL = '__g2c_rpc'; var FE_C2G_CHANNEL = '__c2g_rpc'; var process; var ready; function callFrameElement(targetId, from, rpc) { try { if (from !== '..') { // Call from gadget to the container. var fe = window.frameElement; if (typeof fe[FE_G2C_CHANNEL] === 'function') { // Complete the setup of the FE channel if need be. if (typeof fe[FE_G2C_CHANNEL][FE_C2G_CHANNEL] !== 'function') { fe[FE_G2C_CHANNEL][FE_C2G_CHANNEL] = function(args) { process(OpenAjax.gadgets.json.parse(args)); }; } // Conduct the RPC call. fe[FE_G2C_CHANNEL](OpenAjax.gadgets.json.stringify(rpc)); return; } } else { // Call from container to gadget[targetId]. var frame = document.getElementById(targetId); if (typeof frame[FE_G2C_CHANNEL] === 'function' && typeof frame[FE_G2C_CHANNEL][FE_C2G_CHANNEL] === 'function') { // Conduct the RPC call. frame[FE_G2C_CHANNEL][FE_C2G_CHANNEL](OpenAjax.gadgets.json.stringify(rpc)); return; } } } catch (e) { } return true; } return { getCode: function() { return 'fe'; }, isParentVerifiable: function() { return false; }, init: function(processFn, readyFn) { // No global setup. process = processFn; ready = readyFn; return true; }, setup: function(receiverId, token) { // Indicate OK to call to container. This will be true // by the end of this method. if (receiverId !== '..') { try { var frame = document.getElementById(receiverId); frame[FE_G2C_CHANNEL] = function(args) { process(OpenAjax.gadgets.json.parse(args)); }; } catch (e) { return false; } } if (receiverId === '..') { ready('..', true); var ackFn = function() { window.setTimeout(function() { OpenAjax.gadgets.rpc.call(receiverId, OpenAjax.gadgets.rpc.ACK); }, 500); }; // Setup to container always happens before onload. // If it didn't, the correct fix would be in gadgets.util. OpenAjax.gadgets.util.registerOnLoadHandler(ackFn); } return true; }, call: function(targetId, from, rpc) { callFrameElement(targetId, from, rpc); } }; }(); } // !end of double-inclusion guard /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ OpenAjax.gadgets.rpctx = OpenAjax.gadgets.rpctx || {}; /* * For all others, we have a fallback mechanism known as "ifpc". IFPC * exploits the fact that while same-origin policy prohibits a frame from * accessing members on a window not in the same domain, that frame can, * however, navigate the window heirarchy (via parent). This is exploited by * having a page on domain A that wants to talk to domain B create an iframe * on domain B pointing to a special relay file and with a message encoded * after the hash (#). This relay, in turn, finds the page on domain B, and * can call a receipt function with the message given to it. The relay URL * used by each caller is set via the gadgets.rpc.setRelayUrl(..) and * *must* be called before the call method is used. * * ifpc: Iframe-based method, utilizing a relay page, to send a message. * - No known major browsers still use this method, but it remains * useful as a catch-all fallback for the time being. */ if (!OpenAjax.gadgets.rpctx.ifpc) { // make lib resilient to double-inclusion OpenAjax.gadgets.rpctx.ifpc = function() { var iframePool = []; var callId = 0; var ready; /** * Encodes arguments for the legacy IFPC wire format. * * @param {Object} args * @return {string} the encoded args */ function encodeLegacyData(args) { var argsEscaped = []; for(var i = 0, j = args.length; i < j; ++i) { argsEscaped.push(encodeURIComponent(OpenAjax.gadgets.json.stringify(args[i]))); } return argsEscaped.join('&'); } /** * Helper function to emit an invisible IFrame. * @param {string} src SRC attribute of the IFrame to emit. * @private */ function emitInvisibleIframe(src) { var iframe; // Recycle IFrames for (var i = iframePool.length - 1; i >=0; --i) { var ifr = iframePool[i]; try { if (ifr && (ifr.recyclable || ifr.readyState === 'complete')) { ifr.parentNode.removeChild(ifr); if (window.ActiveXObject) { // For MSIE, delete any iframes that are no longer being used. MSIE // cannot reuse the IFRAME because a navigational click sound will // be triggered when we set the SRC attribute. // Other browsers scan the pool for a free iframe to reuse. iframePool[i] = ifr = null; iframePool.splice(i, 1); } else { ifr.recyclable = false; iframe = ifr; break; } } } catch (e) { // Ignore; IE7 throws an exception when trying to read readyState and // readyState isn't set. } } // Create IFrame if necessary if (!iframe) { iframe = document.createElement('iframe'); iframe.style.border = iframe.style.width = iframe.style.height = '0px'; iframe.style.visibility = 'hidden'; iframe.style.position = 'absolute'; iframe.onload = function() { this.recyclable = true; }; iframePool.push(iframe); } iframe.src = src; window.setTimeout(function() { document.body.appendChild(iframe); }, 0); } return { getCode: function() { return 'ifpc'; }, isParentVerifiable: function() { return true; }, init: function(processFn, readyFn) { // No global setup. ready = readyFn; ready('..', true); // Ready immediately. return true; }, setup: function(receiverId, token) { // Indicate readiness to send to receiver. ready(receiverId, true); return true; }, call: function(targetId, from, rpc) { // Retrieve the relay file used by IFPC. Note that // this must be set before the call, and so we conduct // an extra check to ensure it is not blank. var relay = OpenAjax.gadgets.rpc.getRelayUrl(targetId); ++callId; if (!relay) { OpenAjax.gadgets.warn('No relay file assigned for IFPC'); return; } // The RPC mechanism supports two formats for IFPC (legacy and current). var src = null; if (rpc.l) { // Use legacy protocol. // Format: #iframe_id&callId&num_packets&packet_num&block_of_data var callArgs = rpc.a; src = [relay, '#', encodeLegacyData([from, callId, 1, 0, encodeLegacyData([from, rpc.s, '', '', from].concat( callArgs))])].join(''); } else { // Format: #targetId & sourceId@callId & packetNum & packetId & packetData src = [relay, '#', targetId, '&', from, '@', callId, '&1&0&', encodeURIComponent(OpenAjax.gadgets.json.stringify(rpc))].join(''); } // Conduct the IFPC call by creating the Iframe with // the relay URL and appended message. emitInvisibleIframe(src); return true; } }; }(); } // !end of double inclusion guard /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ OpenAjax.gadgets.rpctx = OpenAjax.gadgets.rpctx || {}; /** * For Internet Explorer before version 8, the security model allows anyone * parent to set the value of the "opener" property on another window, * with only the receiving window able to read it. * This method is dubbed "Native IE XDC" (NIX). * * This method works by placing a handler object in the "opener" property * of a gadget when the container sets up the authentication information * for that gadget (by calling setAuthToken(...)). At that point, a NIX * wrapper is created and placed into the gadget by calling * theframe.contentWindow.opener = wrapper. Note that as a result, NIX can * only be used by a container to call a particular gadget *after* that * gadget has called the container at least once via NIX. * * The NIX wrappers in this RPC implementation are instances of a VBScript * class that is created when this implementation loads. The reason for * using a VBScript class stems from the fact that any object can be passed * into the opener property. * While this is a good thing, as it lets us pass functions and setup a true * bidirectional channel via callbacks, it opens a potential security hole * by which the other page can get ahold of the "window" or "document" * objects in the parent page and in turn wreak havok. This is due to the * fact that any JS object useful for establishing such a bidirectional * channel (such as a function) can be used to access a function * (eg. obj.toString, or a function itself) created in a specific context, * in particular the global context of the sender. Suppose container * domain C passes object obj to gadget on domain G. Then the gadget can * access C's global context using: * var parentWindow = (new obj.toString.constructor("return window;"))(); * Nulling out all of obj's properties doesn't fix this, since IE helpfully * restores them to their original values if you do something like: * delete obj.toString; delete obj.toString; * Thus, we wrap the necessary functions and information inside a VBScript * object. VBScript objects in IE, like DOM objects, are in fact COM * wrappers when used in JavaScript, so we can safely pass them around * without worrying about a breach of context while at the same time * allowing them to act as a pass-through mechanism for information * and function calls. The implementation details of this VBScript wrapper * can be found in the setupChannel() method below. * * nix: Internet Explorer-specific window.opener trick. * - Internet Explorer 6 * - Internet Explorer 7 */ if (!OpenAjax.gadgets.rpctx.nix) { // make lib resilient to double-inclusion OpenAjax.gadgets.rpctx.nix = function() { // Consts for NIX. VBScript doesn't // allow items to start with _ for some reason, // so we need to make these names quite unique, as // they will go into the global namespace. var NIX_WRAPPER = 'GRPC____NIXVBS_wrapper'; var NIX_GET_WRAPPER = 'GRPC____NIXVBS_get_wrapper'; var NIX_HANDLE_MESSAGE = 'GRPC____NIXVBS_handle_message'; var NIX_CREATE_CHANNEL = 'GRPC____NIXVBS_create_channel'; var MAX_NIX_SEARCHES = 10; var NIX_SEARCH_PERIOD = 500; // JavaScript reference to the NIX VBScript wrappers. // Gadgets will have but a single channel under // nix_channels['..'] while containers will have a channel // per gadget stored under the gadget's ID. var nix_channels = {}; var isForceSecure = {}; // Store the ready signal method for use on handshake complete. var ready; var numHandlerSearches = 0; // Search for NIX handler to parent. Tries MAX_NIX_SEARCHES times every // NIX_SEARCH_PERIOD milliseconds. function conductHandlerSearch() { // Call from gadget to the container. var handler = nix_channels['..']; if (handler) { return; } if (++numHandlerSearches > MAX_NIX_SEARCHES) { // Handshake failed. Will fall back. OpenAjax.gadgets.warn('Nix transport setup failed, falling back...'); ready('..', false); return; } // If the gadget has yet to retrieve a reference to // the NIX handler, try to do so now. We don't do a // typeof(window.opener.GetAuthToken) check here // because it means accessing that field on the COM object, which, // being an internal function reference, is not allowed. // "in" works because it merely checks for the prescence of // the key, rather than actually accessing the object's property. // This is just a sanity check, not a validity check. if (!handler && window.opener && "GetAuthToken" in window.opener) { handler = window.opener; // Create the channel to the parent/container. // First verify that it knows our auth token to ensure it's not // an impostor. if (handler.GetAuthToken() == OpenAjax.gadgets.rpc.getAuthToken('..')) { // Auth match - pass it back along with our wrapper to finish. // own wrapper and our authentication token for co-verification. var token = OpenAjax.gadgets.rpc.getAuthToken('..'); handler.CreateChannel(window[NIX_GET_WRAPPER]('..', token), token); // Set channel handler nix_channels['..'] = handler; window.opener = null; // Signal success and readiness to send to parent. // Container-to-gadget bit flipped in CreateChannel. ready('..', true); return; } } // Try again. window.setTimeout(function() { conductHandlerSearch(); }, NIX_SEARCH_PERIOD); } // Returns current window location, without hash values function getLocationNoHash() { var loc = window.location.href; var idx = loc.indexOf('#'); if (idx == -1) { return loc; } return loc.substring(0, idx); } // When "forcesecure" is set to true, use the relay file and a simple variant of IFPC to first // authenticate the container and gadget with each other. Once that is done, then initialize // the NIX protocol. function setupSecureRelayToParent(rpctoken) { // To the parent, transmit the child's URL, the passed in auth // token, and another token generated by the child. var childToken = (0x7FFFFFFF * Math.random()) | 0; // TODO expose way to have child set this value var data = [ getLocationNoHash(), childToken ]; OpenAjax.gadgets.rpc._createRelayIframe(rpctoken, data); // listen for response from parent var hash = window.location.href.split('#')[1] || ''; function relayTimer() { var newHash = window.location.href.split('#')[1] || ''; if (newHash !== hash) { clearInterval(relayTimerId); var params = OpenAjax.gadgets.util.getUrlParameters(window.location.href); if (params.childtoken == childToken) { // parent has been authenticated; now init NIX conductHandlerSearch(); return; } // security error -- token didn't match ready('..', false); } } var relayTimerId = setInterval( relayTimer, 100 ); } return { getCode: function() { return 'nix'; }, isParentVerifiable: function(opt_receiverId) { // NIX is only parent verifiable if a receiver was setup with "forcesecure" set to TRUE. if (opt_receiverId) { return isForceSecure[opt_receiverId]; } return false; }, init: function(processFn, readyFn) { ready = readyFn; // Ensure VBScript wrapper code is in the page and that the // global Javascript handlers have been set. // VBScript methods return a type of 'unknown' when // checked via the typeof operator in IE. Fortunately // for us, this only applies to COM objects, so we // won't see this for a real Javascript object. if (typeof window[NIX_GET_WRAPPER] !== 'unknown') { window[NIX_HANDLE_MESSAGE] = function(data) { window.setTimeout( function() { processFn(OpenAjax.gadgets.json.parse(data)); }, 0); }; window[NIX_CREATE_CHANNEL] = function(name, channel, token) { // Verify the authentication token of the gadget trying // to create a channel for us. if (OpenAjax.gadgets.rpc.getAuthToken(name) === token) { nix_channels[name] = channel; ready(name, true); } }; // Inject the VBScript code needed. var vbscript = // We create a class to act as a wrapper for // a Javascript call, to prevent a break in of // the context. 'Class ' + NIX_WRAPPER + '\n ' // An internal member for keeping track of the // name of the document (container or gadget) // for which this wrapper is intended. For // those wrappers created by gadgets, this is not // used (although it is set to "..") + 'Private m_Intended\n' // Stores the auth token used to communicate with // the gadget. The GetChannelCreator method returns // an object that returns this auth token. Upon matching // that with its own, the gadget uses the object // to actually establish the communication channel. + 'Private m_Auth\n' // Method for internally setting the value // of the m_Intended property. + 'Public Sub SetIntendedName(name)\n ' + 'If isEmpty(m_Intended) Then\n' + 'm_Intended = name\n' + 'End If\n' + 'End Sub\n' // Method for internally setting the value of the m_Auth property. + 'Public Sub SetAuth(auth)\n ' + 'If isEmpty(m_Auth) Then\n' + 'm_Auth = auth\n' + 'End If\n' + 'End Sub\n' // A wrapper method which actually causes a // message to be sent to the other context. + 'Public Sub SendMessage(data)\n ' + NIX_HANDLE_MESSAGE + '(data)\n' + 'End Sub\n' // Returns the auth token to the gadget, so it can // confirm a match before initiating the connection + 'Public Function GetAuthToken()\n ' + 'GetAuthToken = m_Auth\n' + 'End Function\n' // Method for setting up the container->gadget // channel. Not strictly needed in the gadget's // wrapper, but no reason to get rid of it. Note here // that we pass the intended name to the NIX_CREATE_CHANNEL // method so that it can save the channel in the proper place // *and* verify the channel via the authentication token passed // here. + 'Public Sub CreateChannel(channel, auth)\n ' + 'Call ' + NIX_CREATE_CHANNEL + '(m_Intended, channel, auth)\n' + 'End Sub\n' + 'End Class\n' // Function to get a reference to the wrapper. + 'Function ' + NIX_GET_WRAPPER + '(name, auth)\n' + 'Dim wrap\n' + 'Set wrap = New ' + NIX_WRAPPER + '\n' + 'wrap.SetIntendedName name\n' + 'wrap.SetAuth auth\n' + 'Set ' + NIX_GET_WRAPPER + ' = wrap\n' + 'End Function'; try { window.execScript(vbscript, 'vbscript'); } catch (e) { return false; } } return true; }, setup: function(receiverId, token, forcesecure) { isForceSecure[receiverId] = !!forcesecure; if (receiverId === '..') { if (forcesecure) { setupSecureRelayToParent(token); } else { conductHandlerSearch(); } return true; } try { var frame = document.getElementById(receiverId); var wrapper = window[NIX_GET_WRAPPER](receiverId, token); frame.contentWindow.opener = wrapper; } catch (e) { return false; } return true; }, call: function(targetId, from, rpc) { try { // If we have a handler, call it. if (nix_channels[targetId]) { nix_channels[targetId].SendMessage(OpenAjax.gadgets.json.stringify(rpc)); } } catch (e) { return false; } return true; }, // data = [child URL, child auth token] relayOnload: function(receiverId, data) { // transmit childtoken back to child to complete authentication var src = data[0] + '#childtoken=' + data[1]; var childIframe = document.getElementById(receiverId); childIframe.src = src; } }; }(); } // !end of double-inclusion guard /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ OpenAjax.gadgets.rpctx = OpenAjax.gadgets.rpctx || {}; /* * For older WebKit-based browsers, the security model does not allow for any * known "native" hacks for conducting cross browser communication. However, * a variation of the IFPC (see below) can be used, entitled "RMR". RMR is * a technique that uses the resize event of the iframe to indicate that a * message was sent (instead of the much slower/performance heavy polling * technique used when a defined relay page is not avaliable). Simply put, * RMR uses the same "pass the message by the URL hash" trick that IFPC * uses to send a message, but instead of having an active relay page that * runs a piece of code when it is loaded, RMR merely changes the URL * of the relay page (which does not even have to exist on the domain) * and then notifies the other party by resizing the relay iframe. RMR * exploits the fact that iframes in the dom of page A can be resized * by page A while the onresize event will be fired in the DOM of page B, * thus providing a single bit channel indicating "message sent to you". * This method has the added benefit that the relay need not be active, * nor even exist: a 404 suffices just as well. * * rmr: WebKit-specific resizing trick. * - Safari 2+ * - Chrome 1 */ if (!OpenAjax.gadgets.rpctx.rmr) { // make lib resilient to double-inclusion OpenAjax.gadgets.rpctx.rmr = function() { // Consts for RMR, including time in ms RMR uses to poll for // its relay frame to be created, and the max # of polls it does. var RMR_SEARCH_TIMEOUT = 500; var RMR_MAX_POLLS = 10; // JavaScript references to the channel objects used by RMR. // Gadgets will have but a single channel under // rmr_channels['..'] while containers will have a channel // per gadget stored under the gadget's ID. var rmr_channels = {}; var process; var ready; /** * Append an RMR relay frame to the document. This allows the receiver * to start receiving messages. * * @param {Node} channelFrame Relay frame to add to the DOM body. * @param {string} relayUri Base URI for the frame. * @param {string} data to pass along to the frame. * @param {string=} opt_frameId ID of frame for which relay is being appended (optional). */ function appendRmrFrame(channelFrame, relayUri, data, opt_frameId) { var appendFn = function() { // Append the iframe. document.body.appendChild(channelFrame); // Set the src of the iframe to 'about:blank' first and then set it // to the relay URI. This prevents the iframe from maintaining a src // to the 'old' relay URI if the page is returned to from another. // In other words, this fixes the bfcache issue that causes the iframe's // src property to not be updated despite us assigning it a new value here. channelFrame.src = 'about:blank'; if (opt_frameId) { // Process the initial sent payload (typically sent by container to // child/gadget) only when the relay frame has finished loading. We // do this to ensure that, in processRmrData(...), the ACK sent due // to processing can actually be sent. Before this time, the frame's // contentWindow is null, making it impossible to do so. channelFrame.onload = function() { processRmrData(opt_frameId); }; } channelFrame.src = relayUri + '#' + data; }; if (document.body) { appendFn(); } else { // Common gadget case: attaching header during in-gadget handshake, // when we may still be in script in head. Attach onload. OpenAjax.gadgets.util.registerOnLoadHandler(function() { appendFn(); }); } } /** * Sets up the RMR transport frame for the given frameId. For gadgets * calling containers, the frameId should be '..'. * * @param {string} frameId The ID of the frame. */ function setupRmr(frameId) { if (typeof rmr_channels[frameId] === "object") { // Sanity check. Already done. return; } var channelFrame = document.createElement('iframe'); var frameStyle = channelFrame.style; frameStyle.position = 'absolute'; frameStyle.top = '0px'; frameStyle.border = '0'; frameStyle.opacity = '0'; // The width here is important as RMR // makes use of the resize handler for the frame. // Do not modify unless you test thoroughly! frameStyle.width = '10px'; frameStyle.height = '1px'; channelFrame.id = 'rmrtransport-' + frameId; channelFrame.name = channelFrame.id; // Use the explicitly set relay, if one exists. Otherwise, // Construct one using the parent parameter plus robots.txt // as a synthetic relay. This works since browsers using RMR // treat 404s as legitimate for the purposes of cross domain // communication. var relayUri = OpenAjax.gadgets.rpc.getRelayUrl(frameId); if (!relayUri) { relayUri = OpenAjax.gadgets.rpc.getOrigin(OpenAjax.gadgets.util.getUrlParameters()["parent"]) + '/robots.txt'; } rmr_channels[frameId] = { frame: channelFrame, receiveWindow: null, relayUri: relayUri, searchCounter : 0, width: 10, // Waiting means "waiting for acknowledgement to be received." // Acknowledgement always comes as a special ACK // message having been received. This message is received // during handshake in different ways by the container and // gadget, and by normal RMR message passing once the handshake // is complete. waiting: true, queue: [], // Number of non-ACK messages that have been sent to the recipient // and have been acknowledged. sendId: 0, // Number of messages received and processed from the sender. // This is the number that accompanies every ACK to tell the // sender to clear its queue. recvId: 0 }; if (frameId !== '..') { // Container always appends a relay to the gadget, before // the gadget appends its own relay back to container. The // gadget, in the meantime, refuses to attach the container // relay until it finds this one. Thus, the container knows // for certain that gadget to container communication is set // up by the time it finds its own relay. In addition to // establishing a reliable handshake protocol, this also // makes it possible for the gadget to send an initial batch // of messages to the container ASAP. appendRmrFrame(channelFrame, relayUri, getRmrData(frameId)); } // Start searching for our own frame on the other page. conductRmrSearch(frameId); } /** * Searches for a relay frame, created by the sender referenced by * frameId, with which this context receives messages. Once * found with proper permissions, attaches a resize handler which * signals messages to be sent. * * @param {string} frameId Frame ID of the prospective sender. */ function conductRmrSearch(frameId) { var channelWindow = null; // Increment the search counter. rmr_channels[frameId].searchCounter++; try { var targetWin = OpenAjax.gadgets.rpc._getTargetWin(frameId); if (frameId === '..') { // We are a gadget. channelWindow = targetWin.frames['rmrtransport-' + OpenAjax.gadgets.rpc.RPC_ID]; } else { // We are a container. channelWindow = targetWin.frames['rmrtransport-..']; } } catch (e) { // Just in case; may happen when relay is set to about:blank or unset. // Catching exceptions here ensures that the timeout to continue the // search below continues to work. } var status = false; if (channelWindow) { // We have a valid reference to "our" RMR transport frame. // Register the proper event handlers. status = registerRmrChannel(frameId, channelWindow); } if (!status) { // Not found yet. Continue searching, but only if the counter // has not reached the threshold. if (rmr_channels[frameId].searchCounter > RMR_MAX_POLLS) { // If we reach this point, then RMR has failed and we // fall back to IFPC. return; } window.setTimeout(function() { conductRmrSearch(frameId); }, RMR_SEARCH_TIMEOUT); } } /** * Attempts to conduct an RPC call to the specified * target with the specified data via the RMR * method. If this method fails, the system attempts again * using the known default of IFPC. * * @param {string} targetId Module Id of the RPC service provider. * @param {string} serviceName Name of the service to call. * @param {string} from Module Id of the calling provider. * @param {Object} rpc The RPC data for this call. */ function callRmr(targetId, serviceName, from, rpc) { var handler = null; if (from !== '..') { // Call from gadget to the container. handler = rmr_channels['..']; } else { // Call from container to the gadget. handler = rmr_channels[targetId]; } if (handler) { // Queue the current message if not ACK. // ACK is always sent through getRmrData(...). if (serviceName !== OpenAjax.gadgets.rpc.ACK) { handler.queue.push(rpc); } if (handler.waiting || (handler.queue.length === 0 && !(serviceName === OpenAjax.gadgets.rpc.ACK && rpc && rpc.ackAlone === true))) { // If we are awaiting a response from any previously-sent messages, // or if we don't have anything new to send, just return. // Note that we don't short-return if we're ACKing just-received // messages. return true; } if (handler.queue.length > 0) { handler.waiting = true; } var url = handler.relayUri + "#" + getRmrData(targetId); try { // Update the URL with the message. handler.frame.contentWindow.location = url; // Resize the frame. var newWidth = handler.width == 10 ? 20 : 10; handler.frame.style.width = newWidth + 'px'; handler.width = newWidth; // Done! } catch (e) { // Something about location-setting or resizing failed. // This should never happen, but if it does, fall back to // the default transport. return false; } } return true; } /** * Returns as a string the data to be appended to an RMR relay frame, * constructed from the current request queue plus an ACK message indicating * the currently latest-processed message ID. * * @param {string} toFrameId Frame whose sendable queued data to retrieve. */ function getRmrData(toFrameId) { var channel = rmr_channels[toFrameId]; var rmrData = {id: channel.sendId}; if (channel) { rmrData.d = Array.prototype.slice.call(channel.queue, 0); rmrData.d.push({s:OpenAjax.gadgets.rpc.ACK, id:channel.recvId}); } return OpenAjax.gadgets.json.stringify(rmrData); } /** * Retrieve data from the channel keyed by the given frameId, * processing it as a batch. All processed data is assumed to have been * generated by getRmrData(...), pairing that method with this. * * @param {string} fromFrameId Frame from which data is being retrieved. */ function processRmrData(fromFrameId) { var channel = rmr_channels[fromFrameId]; var data = channel.receiveWindow.location.hash.substring(1); // Decode the RPC object array. var rpcObj = OpenAjax.gadgets.json.parse(decodeURIComponent(data)) || {}; var rpcArray = rpcObj.d || []; var nonAckReceived = false; var noLongerWaiting = false; var numBypassed = 0; var numToBypass = (channel.recvId - rpcObj.id); for (var i = 0; i < rpcArray.length; ++i) { var rpc = rpcArray[i]; // If we receive an ACK message, then mark the current // handler as no longer waiting and send out the next // queued message. if (rpc.s === OpenAjax.gadgets.rpc.ACK) { // ACK received - whether this came from a handshake or // an active call, in either case it indicates readiness to // send messages to the from frame. ready(fromFrameId, true); if (channel.waiting) { noLongerWaiting = true; } channel.waiting = false; var newlyAcked = Math.max(0, rpc.id - channel.sendId); channel.queue.splice(0, newlyAcked); channel.sendId = Math.max(channel.sendId, rpc.id || 0); continue; } // If we get here, we've received > 0 non-ACK messages to // process. Indicate this bit for later. nonAckReceived = true; // Bypass any messages already received. if (++numBypassed <= numToBypass) { continue; } ++channel.recvId; process(rpc); // actually dispatch the message } // Send an ACK indicating that we got/processed the message(s). // Do so if we've received a message to process or if we were waiting // before but a received ACK has cleared our waiting bit, and we have // more messages to send. Performing this operation causes additional // messages to be sent. if (nonAckReceived || (noLongerWaiting && channel.queue.length > 0)) { var from = (fromFrameId === '..') ? OpenAjax.gadgets.rpc.RPC_ID : '..'; callRmr(fromFrameId, OpenAjax.gadgets.rpc.ACK, from, {ackAlone: nonAckReceived}); } } /** * Registers the RMR channel handler for the given frameId and associated * channel window. * * @param {string} frameId The ID of the frame for which this channel is being * registered. * @param {Object} channelWindow The window of the receive frame for this * channel, if any. * * @return {boolean} True if the frame was setup successfully, false * otherwise. */ function registerRmrChannel(frameId, channelWindow) { var channel = rmr_channels[frameId]; // Verify that the channel is ready for receiving. try { var canAccess = false; // Check to see if the document is in the window. For Chrome, this // will return 'false' if the channelWindow is inaccessible by this // piece of JavaScript code, meaning that the URL of the channelWindow's // parent iframe has not yet changed from 'about:blank'. We do this // check this way because any true *access* on the channelWindow object // will raise a security exception, which, despite the try-catch, still // gets reported to the debugger (it does not break execution, the try // handles that problem, but it is still reported, which is bad form). // This check always succeeds in Safari 3.1 regardless of the state of // the window. canAccess = 'document' in channelWindow; if (!canAccess) { return false; } // Check to see if the document is an object. For Safari 3.1, this will // return undefined if the page is still inaccessible. Unfortunately, this // *will* raise a security issue in the debugger. // TODO Find a way around this problem. canAccess = typeof channelWindow['document'] == 'object'; if (!canAccess) { return false; } // Once we get here, we know we can access the document (and anything else) // on the window object. Therefore, we check to see if the location is // still about:blank (this takes care of the Safari 3.2 case). var loc = channelWindow.location.href; // Check if this is about:blank for Safari. if (loc === 'about:blank') { return false; } } catch (ex) { // For some reason, the iframe still points to about:blank. We try // again in a bit. return false; } // Save a reference to the receive window. channel.receiveWindow = channelWindow; // Register the onresize handler. function onresize() { processRmrData(frameId); } if (typeof channelWindow.attachEvent === "undefined") { channelWindow.onresize = onresize; } else { channelWindow.attachEvent("onresize", onresize); } if (frameId === '..') { // Gadget to container. Signal to the container that the gadget // is ready to receive messages by attaching the g -> c relay. // As a nice optimization, pass along any gadget to container // queued messages that have backed up since then. ACK is enqueued in // getRmrData to ensure that the container's waiting flag is set to false // (this happens in the below code run on the container side). appendRmrFrame(channel.frame, channel.relayUri, getRmrData(frameId), frameId); } else { // Process messages that the gadget sent in its initial relay payload. // We can do this immediately because the container has already appended // and loaded a relay frame that can be used to ACK the messages the gadget // sent. In the preceding if-block, however, the processRmrData(...) call // must wait. That's because appendRmrFrame may not actually append the // frame - in the context of a gadget, this code may be running in the // head element, so it cannot be appended to body. As a result, the // gadget cannot ACK the container for messages it received. processRmrData(frameId); } return true; } return { getCode: function() { return 'rmr'; }, isParentVerifiable: function() { return true; }, init: function(processFn, readyFn) { // No global setup. process = processFn; ready = readyFn; return true; }, setup: function(receiverId, token) { try { setupRmr(receiverId); } catch (e) { OpenAjax.gadgets.warn('Caught exception setting up RMR: ' + e); return false; } return true; }, call: function(targetId, from, rpc) { return callRmr(targetId, rpc.s, from, rpc); } }; }(); } // !end of double-inclusion guard /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ OpenAjax.gadgets.rpctx = OpenAjax.gadgets.rpctx || {}; /** * Transport for browsers that support native messaging (various implementations * of the HTML5 postMessage method). Officially defined at * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html. * * postMessage is a native implementation of XDC. A page registers that * it would like to receive messages by listening the the "message" event * on the window (document in DPM) object. In turn, another page can * raise that event by calling window.postMessage (document.postMessage * in DPM) with a string representing the message and a string * indicating on which domain the receiving page must be to receive * the message. The target page will then have its "message" event raised * if the domain matches and can, in turn, check the origin of the message * and process the data contained within. * * wpm: postMessage on the window object. * - Internet Explorer 8+ * - Safari 4+ * - Chrome 2+ * - Webkit nightlies * - Firefox 3+ * - Opera 9+ */ if (!OpenAjax.gadgets.rpctx.wpm) { // make lib resilient to double-inclusion OpenAjax.gadgets.rpctx.wpm = function() { var process, ready; var postMessage; var pmSync = false; var pmEventDomain = false; // Some browsers (IE, Opera) have an implementation of postMessage that is // synchronous, although HTML5 specifies that it should be asynchronous. In // order to make all browsers behave consistently, we run a small test to detect // if postMessage is asynchronous or not. If not, we wrap calls to postMessage // in a setTimeout with a timeout of 0. // Also, Opera's "message" event does not have an "origin" property (at least, // it doesn't in version 9.64; presumably, it will in version 10). If // event.origin does not exist, use event.domain. The other difference is that // while event.origin looks like ://:, event.domain // consists only of . // function testPostMessage() { var hit = false; function receiveMsg(event) { if (event.data == "postmessage.test") { hit = true; if (typeof event.origin === "undefined") { pmEventDomain = true; } } } OpenAjax.gadgets.util.attachBrowserEvent(window, "message", receiveMsg, false); window.postMessage("postmessage.test", "*"); // if 'hit' is true here, then postMessage is synchronous if (hit) { pmSync = true; } OpenAjax.gadgets.util.removeBrowserEvent(window, "message", receiveMsg, false); } function onmessage(packet) { var rpc = OpenAjax.gadgets.json.parse(packet.data); if (!rpc || !rpc.f) { return; } // for security, check origin against expected value var origRelay = OpenAjax.gadgets.rpc.getRelayUrl(rpc.f) || OpenAjax.gadgets.util.getUrlParameters()["parent"]; var origin = OpenAjax.gadgets.rpc.getOrigin(origRelay); if (!pmEventDomain ? packet.origin !== origin : packet.domain !== /^.+:\/\/([^:]+).*/.exec( origin )[1]) { return; } process(rpc); } return { getCode: function() { return 'wpm'; }, isParentVerifiable: function() { return true; }, init: function(processFn, readyFn) { process = processFn; ready = readyFn; testPostMessage(); if (!pmSync) { postMessage = function(win, msg, origin) { win.postMessage(msg, origin); }; } else { postMessage = function(win, msg, origin) { window.setTimeout( function() { win.postMessage(msg, origin); }, 0); }; } // Set up native postMessage handler. OpenAjax.gadgets.util.attachBrowserEvent(window, 'message', onmessage, false); ready('..', true); // Immediately ready to send to parent. return true; }, setup: function(receiverId, token, forcesecure) { // If we're a gadget, send an ACK message to indicate to container // that we're ready to receive messages. if (receiverId === '..') { if (forcesecure) { OpenAjax.gadgets.rpc._createRelayIframe(token); } else { OpenAjax.gadgets.rpc.call(receiverId, OpenAjax.gadgets.rpc.ACK); } } return true; }, call: function(targetId, from, rpc) { var targetWin = OpenAjax.gadgets.rpc._getTargetWin(targetId); // targetOrigin = canonicalized relay URL var origRelay = OpenAjax.gadgets.rpc.getRelayUrl(targetId) || OpenAjax.gadgets.util.getUrlParameters()["parent"]; var origin = OpenAjax.gadgets.rpc.getOrigin(origRelay); if (origin) { postMessage(targetWin, OpenAjax.gadgets.json.stringify(rpc), origin); } else { OpenAjax.gadgets.error("No relay set (used as window.postMessage targetOrigin)" + ", cannot send cross-domain message"); } return true; }, relayOnload: function(receiverId, data) { ready(receiverId, true); } }; }(); } // !end of double-inclusion guard /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ /** * @fileoverview Remote procedure call library for gadget-to-container, * container-to-gadget, and gadget-to-gadget (thru container) communication. */ /** * gadgets.rpc Transports * * All transports are stored in object gadgets.rpctx, and are provided * to the core gadgets.rpc library by various build rules. * * Transports used by core gadgets.rpc code to actually pass messages. * each transport implements the same interface exposing hooks that * the core library calls at strategic points to set up and use * the transport. * * The methods each transport must implement are: * + getCode(): returns a string identifying the transport. For debugging. * + isParentVerifiable(): indicates (via boolean) whether the method * has the property that its relay URL verifies for certain the * receiver's protocol://host:port. * + init(processFn, readyFn): Performs any global initialization needed. Called * before any other gadgets.rpc methods are invoked. processFn is * the function in gadgets.rpc used to process an rpc packet. readyFn is * a function that must be called when the transport is ready to send * and receive messages bidirectionally. Returns * true if successful, false otherwise. * + setup(receiverId, token): Performs per-receiver initialization, if any. * receiverId will be '..' for gadget-to-container. Returns true if * successful, false otherwise. * + call(targetId, from, rpc): Invoked to send an actual * message to the given targetId, with the given serviceName, from * the sender identified by 'from'. Payload is an rpc packet. Returns * true if successful, false otherwise. */ if (!OpenAjax.gadgets.rpc) { // make lib resilient to double-inclusion /** * @static * @namespace Provides operations for making rpc calls. * @name gadgets.rpc */ OpenAjax.gadgets.rpc = function() { /** * @const * @private */ var CALLBACK_NAME = '__cb'; /** * @const * @private */ var DEFAULT_NAME = ''; /** Exported constant, for use by transports only. * @const * @type {string} * @member gadgets.rpc */ var ACK = '__ack'; /** * Timeout and number of attempts made to setup a transport receiver. * @const * @private */ var SETUP_FRAME_TIMEOUT = 500; /** * @const * @private */ var SETUP_FRAME_MAX_TRIES = 10; var services = {}; var relayUrl = {}; var useLegacyProtocol = {}; var authToken = {}; var callId = 0; var callbacks = {}; var setup = {}; var sameDomain = {}; var params = {}; var receiverTx = {}; var earlyRpcQueue = {}; // isGadget =~ isChild for the purposes of rpc (used only in setup). var isChild = (window.top !== window.self); // Set the current rpc ID from window.name immediately, to prevent // shadowing of window.name by a "var name" declaration, or similar. var rpcId = window.name; var securityCallback = function() {}; var LOAD_TIMEOUT = 0; var FRAME_PHISH = 1; var FORGED_MSG = 2; // Fallback transport is simply a dummy impl that emits no errors // and logs info on calls it receives, to avoid undesired side-effects // from falling back to IFPC or some other transport. var fallbackTransport = (function() { function logFn(name) { return function() { OpenAjax.gadgets.log("gadgets.rpc." + name + "(" + OpenAjax.gadgets.json.stringify(Array.prototype.slice.call(arguments)) + "): call ignored. [caller: " + document.location + ", isChild: " + isChild + "]"); }; } return { getCode: function() { return "noop"; }, isParentVerifiable: function() { return true; // Not really, but prevents transport assignment to IFPC. }, init: logFn("init"), setup: logFn("setup"), call: logFn("call") }; })(); // Load the authentication token for speaking to the container // from the gadget's parameters, or default to '0' if not found. if (OpenAjax.gadgets.util) { params = OpenAjax.gadgets.util.getUrlParameters(); } /** * Return a transport representing the best available cross-domain * message-passing mechanism available to the browser. * *

Transports are selected on a cascading basis determined by browser * capability and other checks. The order of preference is: *

    *
  1. wpm: Uses window.postMessage standard. *
  2. dpm: Uses document.postMessage, similar to wpm but pre-standard. *
  3. nix: Uses IE-specific browser hacks. *
  4. rmr: Signals message passing using relay file's onresize handler. *
  5. fe: Uses FF2-specific window.frameElement hack. *
  6. ifpc: Sends messages via active load of a relay file. *
*

See each transport's commentary/documentation for details. * @return {Object} * @member gadgets.rpc */ function getTransport() { return typeof window.postMessage === 'function' ? OpenAjax.gadgets.rpctx.wpm : typeof window.postMessage === 'object' ? OpenAjax.gadgets.rpctx.wpm : window.ActiveXObject ? OpenAjax.gadgets.rpctx.nix : navigator.userAgent.indexOf('WebKit') > 0 ? OpenAjax.gadgets.rpctx.rmr : navigator.product === 'Gecko' ? OpenAjax.gadgets.rpctx.frameElement : OpenAjax.gadgets.rpctx.ifpc; } /** * Function passed to, and called by, a transport indicating it's ready to * send and receive messages. */ function transportReady(receiverId, readySuccess) { var tx = transport; if (!readySuccess) { tx = fallbackTransport; } receiverTx[receiverId] = tx; // If there are any early-queued messages, send them now directly through // the needed transport. var earlyQueue = earlyRpcQueue[receiverId] || []; for (var i = 0; i < earlyQueue.length; ++i) { var rpc = earlyQueue[i]; // There was no auth/rpc token set before, so set it now. rpc.t = getAuthToken(receiverId); tx.call(receiverId, rpc.f, rpc); } // Clear the queue so it won't be sent again. earlyRpcQueue[receiverId] = []; } // Track when this main page is closed or navigated to a different location // ("unload" event). // NOTE: The use of the "unload" handler here and for the relay iframe // prevents the use of the in-memory page cache in modern browsers. // See: https://developer.mozilla.org/en/using_firefox_1.5_caching // See: http://webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/ var mainPageUnloading = false, hookedUnload = false; function hookMainPageUnload() { if ( hookedUnload ) { return; } function onunload() { mainPageUnloading = true; } OpenAjax.gadgets.util.attachBrowserEvent(window, 'unload', onunload, false); hookedUnload = true; } function relayOnload(targetId, sourceId, token, data, relayWindow) { // Validate auth token. if (!authToken[sourceId] || authToken[sourceId] !== token) { OpenAjax.gadgets.error("Invalid auth token. " + authToken[sourceId] + " vs " + token); securityCallback(sourceId, FORGED_MSG); } relayWindow.onunload = function() { if (setup[sourceId] && !mainPageUnloading) { securityCallback(sourceId, FRAME_PHISH); OpenAjax.gadgets.rpc.removeReceiver(sourceId); } }; hookMainPageUnload(); data = OpenAjax.gadgets.json.parse(decodeURIComponent(data)); transport.relayOnload(sourceId, data); } /** * Helper function to process an RPC request * @param {Object} rpc RPC request object * @private */ function process(rpc) { // // RPC object contents: // s: Service Name // f: From // c: The callback ID or 0 if none. // a: The arguments for this RPC call. // t: The authentication token. // if (rpc && typeof rpc.s === 'string' && typeof rpc.f === 'string' && rpc.a instanceof Array) { // Validate auth token. if (authToken[rpc.f]) { // We don't do type coercion here because all entries in the authToken // object are strings, as are all url params. See setupReceiver(...). if (authToken[rpc.f] !== rpc.t) { OpenAjax.gadgets.error("Invalid auth token. " + authToken[rpc.f] + " vs " + rpc.t); securityCallback(rpc.f, FORGED_MSG); } } if (rpc.s === ACK) { // Acknowledgement API, used to indicate a receiver is ready. window.setTimeout(function() { transportReady(rpc.f, true); }, 0); return; } // If there is a callback for this service, attach a callback function // to the rpc context object for asynchronous rpc services. // // Synchronous rpc request handlers should simply ignore it and return a // value as usual. // Asynchronous rpc request handlers, on the other hand, should pass its // result to this callback function and not return a value on exit. // // For example, the following rpc handler passes the first parameter back // to its rpc client with a one-second delay. // // function asyncRpcHandler(param) { // var me = this; // setTimeout(function() { // me.callback(param); // }, 1000); // } if (rpc.c) { rpc.callback = function(result) { OpenAjax.gadgets.rpc.call(rpc.f, CALLBACK_NAME, null, rpc.c, result); }; } // Call the requested RPC service. var result = (services[rpc.s] || services[DEFAULT_NAME]).apply(rpc, rpc.a); // If the rpc request handler returns a value, immediately pass it back // to the callback. Otherwise, do nothing, assuming that the rpc handler // will make an asynchronous call later. if (rpc.c && typeof result !== 'undefined') { OpenAjax.gadgets.rpc.call(rpc.f, CALLBACK_NAME, null, rpc.c, result); } } } /** * Helper method returning a canonicalized protocol://host[:port] for * a given input URL, provided as a string. Used to compute convenient * relay URLs and to determine whether a call is coming from the same * domain as its receiver (bypassing the try/catch capability detection * flow, thereby obviating Firebug and other tools reporting an exception). * * @param {string} url Base URL to canonicalize. * @memberOf gadgets.rpc */ function getOrigin(url) { if (!url) { return ""; } url = url.toLowerCase(); if (url.indexOf("//") == 0) { url = window.location.protocol + url; } if (url.indexOf("://") == -1) { // Assumed to be schemaless. Default to current protocol. url = window.location.protocol + "//" + url; } // At this point we guarantee that "://" is in the URL and defines // current protocol. Skip past this to search for host:port. var host = url.substring(url.indexOf("://") + 3); // Find the first slash char, delimiting the host:port. var slashPos = host.indexOf("/"); if (slashPos != -1) { host = host.substring(0, slashPos); } var protocol = url.substring(0, url.indexOf("://")); // Use port only if it's not default for the protocol. var portStr = ""; var portPos = host.indexOf(":"); if (portPos != -1) { var port = host.substring(portPos + 1); host = host.substring(0, portPos); if ((protocol === "http" && port !== "80") || (protocol === "https" && port !== "443")) { portStr = ":" + port; } } // Return ://[] return protocol + "://" + host + portStr; } function getTargetWin(id) { if (typeof id === "undefined" || id === "..") { return window.parent; } // Cast to a String to avoid an index lookup. id = String(id); // Try window.frames first var target = window.frames[id]; if (target) { return target; } // Fall back to getElementById() target = document.getElementById(id); if (target && target.contentWindow) { return target.contentWindow; } return null; } // Pick the most efficient RPC relay mechanism. var transport = getTransport(); // Create the Default RPC handler. services[DEFAULT_NAME] = function() { OpenAjax.gadgets.warn('Unknown RPC service: ' + this.s); }; // Create a Special RPC handler for callbacks. services[CALLBACK_NAME] = function(callbackId, result) { var callback = callbacks[callbackId]; if (callback) { delete callbacks[callbackId]; callback(result); } }; /** * Conducts any frame-specific work necessary to setup * the channel type chosen. This method is called when * the container page first registers the gadget in the * RPC mechanism. Gadgets, in turn, will complete the setup * of the channel once they send their first messages. */ function setupFrame(frameId, token, forcesecure) { if (setup[frameId] === true) { return; } if (typeof setup[frameId] === 'undefined') { setup[frameId] = 0; } var tgtFrame = document.getElementById(frameId); if (frameId === '..' || tgtFrame != null) { if (transport.setup(frameId, token, forcesecure) === true) { setup[frameId] = true; return; } } if (setup[frameId] !== true && setup[frameId]++ < SETUP_FRAME_MAX_TRIES) { // Try again in a bit, assuming that frame will soon exist. window.setTimeout(function() { setupFrame(frameId, token, forcesecure); }, SETUP_FRAME_TIMEOUT); } else { // Fail: fall back for this gadget. receiverTx[frameId] = fallbackTransport; setup[frameId] = true; } } /** * Attempts to make an rpc by calling the target's receive method directly. * This works when gadgets are rendered on the same domain as their container, * a potentially useful optimization for trusted content which keeps * RPC behind a consistent interface. * * @param {string} target Module id of the rpc service provider * @param {Object} rpc RPC data * @return {boolean} */ function callSameDomain(target, rpc) { if (typeof sameDomain[target] === 'undefined') { // Seed with a negative, typed value to avoid // hitting this code path repeatedly. sameDomain[target] = false; var targetRelay = OpenAjax.gadgets.rpc.getRelayUrl(target); if (getOrigin(targetRelay) !== getOrigin(window.location.href)) { // Not worth trying -- avoid the error and just return. return false; } var targetEl = getTargetWin(target); try { // If this succeeds, then same-domain policy applied sameDomain[target] = targetEl.OpenAjax.gadgets.rpc.receiveSameDomain; } catch (e) { // Shouldn't happen due to origin check. Caught to emit // more meaningful error to the caller. OpenAjax.gadgets.error("Same domain call failed: parent= incorrectly set."); } } if (typeof sameDomain[target] === 'function') { // Call target's receive method sameDomain[target](rpc); return true; } return false; } /** * Sets the relay URL of a target frame. * @param {string} targetId Name of the target frame. * @param {string} url Full relay URL of the target frame. * @param {boolean=} opt_useLegacy True if this relay needs the legacy IFPC * wire format. * * @member gadgets.rpc * @deprecated */ function setRelayUrl(targetId, url, opt_useLegacy) { // make URL absolute if necessary if (!/http(s)?:\/\/.+/.test(url)) { if (url.indexOf("//") == 0) { url = window.location.protocol + url; } else if (url.charAt(0) == '/') { url = window.location.protocol + "//" + window.location.host + url; } else if (url.indexOf("://") == -1) { // Assumed to be schemaless. Default to current protocol. url = window.location.protocol + "//" + url; } } relayUrl[targetId] = url; useLegacyProtocol[targetId] = !!opt_useLegacy; } /** * Helper method to retrieve the authToken for a given gadget. * Not to be used directly. * @member gadgets.rpc * @return {string} */ function getAuthToken(targetId) { return authToken[targetId]; } /** * Sets the auth token of a target frame. * @param {string} targetId Name of the target frame. * @param {string} token The authentication token to use for all * calls to or from this target id. * * @member gadgets.rpc * @deprecated */ function setAuthToken(targetId, token, forcesecure) { token = token || ""; // Coerce token to a String, ensuring that all authToken values // are strings. This ensures correct comparison with URL params // in the process(rpc) method. authToken[targetId] = String(token); setupFrame(targetId, token, forcesecure); } function setupContainerGadgetContext(rpctoken, opt_forcesecure) { /** * Initializes gadget to container RPC params from the provided configuration. */ function init(config) { var configRpc = config ? config.rpc : {}; var parentRelayUrl = configRpc.parentRelayUrl; // Allow for wild card parent relay files as long as it's from a // white listed domain. This is enforced by the rendering servlet. if (parentRelayUrl.substring(0, 7) !== 'http://' && parentRelayUrl.substring(0, 8) !== 'https://' && parentRelayUrl.substring(0, 2) !== '//') { // Relative path: we append to the parent. // We're relying on the server validating the parent parameter in this // case. Because of this, parent may only be passed in the query, not fragment. if (typeof params.parent === "string" && params.parent !== "") { // Otherwise, relayUrl['..'] will be null, signaling transport // code to ignore rpc calls since they cannot work without a // relay URL with host qualification. if (parentRelayUrl.substring(0, 1) !== '/') { // Path-relative. Trust that parent is passed in appropriately. var lastSlash = params.parent.lastIndexOf('/'); parentRelayUrl = params.parent.substring(0, lastSlash + 1) + parentRelayUrl; } else { // Host-relative. parentRelayUrl = getOrigin(params.parent) + parentRelayUrl; } } } var useLegacy = !!configRpc.useLegacyProtocol; setRelayUrl('..', parentRelayUrl, useLegacy); if (useLegacy) { transport = OpenAjax.gadgets.rpctx.ifpc; transport.init(process, transportReady); } // Sets the auth token and signals transport to setup connection to container. var forceSecure = opt_forcesecure || params.forcesecure || false; setAuthToken('..', rpctoken, forceSecure); } var requiredConfig = { parentRelayUrl : OpenAjax.gadgets.config.NonEmptyStringValidator }; OpenAjax.gadgets.config.register("rpc", requiredConfig, init); } function setupContainerGenericIframe(rpctoken, opt_parent, opt_forcesecure) { // Generic child IFRAME setting up connection w/ its container. // Use the opt_parent param if provided, or the "parent" query param // if found -- otherwise, do nothing since this call might be initiated // automatically at first, then actively later in IFRAME code. var forcesecure = opt_forcesecure || params.forcesecure || false; var parent = opt_parent || params.parent; if (parent) { setRelayUrl('..', parent); setAuthToken('..', rpctoken, forcesecure); } } function setupChildIframe(gadgetId, opt_frameurl, opt_authtoken, opt_forcesecure) { if (!OpenAjax.gadgets.util) { return; } var childIframe = document.getElementById(gadgetId); if (!childIframe) { throw new Error("Cannot set up gadgets.rpc receiver with ID: " + gadgetId + ", element not found."); } // The "relay URL" can either be explicitly specified or is set as // the child IFRAME URL verbatim. var relayUrl = opt_frameurl || childIframe.src; setRelayUrl(gadgetId, relayUrl); // The auth token is parsed from child params (rpctoken) or overridden. var childParams = OpenAjax.gadgets.util.getUrlParameters(childIframe.src); var rpctoken = opt_authtoken || childParams.rpctoken; var forcesecure = opt_forcesecure || childParams.forcesecure; setAuthToken(gadgetId, rpctoken, forcesecure); } /** * Sets up the gadgets.rpc library to communicate with the receiver. *

This method replaces setRelayUrl(...) and setAuthToken(...) * *

Simplified instructions - highly recommended: *

    *
  1. Generate <iframe id="<ID>" src="...#parent=<PARENTURL>&rpctoken=<RANDOM>"/> * and add to DOM. *
  2. Call gadgets.rpc.setupReceiver("<ID>"); *

    All parent/child communication initializes automatically from here. * Naturally, both sides need to include the library. *

* *

Detailed container/parent instructions: *

    *
  1. Create the target IFRAME (eg. gadget) with a given <ID> and params * rpctoken= (eg. #rpctoken=1234), which is a random/unguessbable * string, and parent=<url>, where <url> is the URL of the container. *
  2. Append IFRAME to the document. *
  3. Call gadgets.rpc.setupReceiver(<ID>) *

    [Optional]. Strictly speaking, you may omit rpctoken and parent. This * practice earns little but is occasionally useful for testing. * If you omit parent, you MUST pass your container URL as the 2nd * parameter to this method. *

* *

Detailed gadget/child IFRAME instructions: *

    *
  1. If your container/parent passed parent and rpctoken params (query string * or fragment are both OK), you needn't do anything. The library will self- * initialize. *
  2. If "parent" is omitted, you MUST call this method with targetId '..' * and the second param set to the parent URL. *
  3. If "rpctoken" is omitted, but the container set an authToken manually * for this frame, you MUST pass that ID (however acquired) as the 2nd param * to this method. *
* * @member gadgets.rpc * @param {string} targetId * @param {string=} opt_receiverurl * @param {string=} opt_authtoken * @param {boolean=} opt_forcesecure */ function setupReceiver(targetId, opt_receiverurl, opt_authtoken, opt_forcesecure) { if (targetId === '..') { // Gadget/IFRAME to container. var rpctoken = opt_authtoken || params.rpctoken || params.ifpctok || ""; if (window['__isgadget'] === true) { setupContainerGadgetContext(rpctoken, opt_forcesecure); } else { setupContainerGenericIframe(rpctoken, opt_receiverurl, opt_forcesecure); } } else { // Container to child. setupChildIframe(targetId, opt_receiverurl, opt_authtoken, opt_forcesecure); } } return /** @scope gadgets.rpc */ { config: function(config) { if (typeof config.securityCallback === 'function') { securityCallback = config.securityCallback; } }, /** * Registers an RPC service. * @param {string} serviceName Service name to register. * @param {function(Object,Object)} handler Service handler. * * @member gadgets.rpc */ register: function(serviceName, handler) { if (serviceName === CALLBACK_NAME || serviceName === ACK) { throw new Error("Cannot overwrite callback/ack service"); } if (serviceName === DEFAULT_NAME) { throw new Error("Cannot overwrite default service:" + " use registerDefault"); } services[serviceName] = handler; }, /** * Unregisters an RPC service. * @param {string} serviceName Service name to unregister. * * @member gadgets.rpc */ unregister: function(serviceName) { if (serviceName === CALLBACK_NAME || serviceName === ACK) { throw new Error("Cannot delete callback/ack service"); } if (serviceName === DEFAULT_NAME) { throw new Error("Cannot delete default service:" + " use unregisterDefault"); } delete services[serviceName]; }, /** * Registers a default service handler to processes all unknown * RPC calls which raise an exception by default. * @param {function(Object,Object)} handler Service handler. * * @member gadgets.rpc */ registerDefault: function(handler) { services[DEFAULT_NAME] = handler; }, /** * Unregisters the default service handler. Future unknown RPC * calls will fail silently. * * @member gadgets.rpc */ unregisterDefault: function() { delete services[DEFAULT_NAME]; }, /** * Forces all subsequent calls to be made by a transport * method that allows the caller to verify the message receiver * (by way of the parent parameter, through getRelayUrl(...)). * At present this means IFPC or WPM. * @member gadgets.rpc */ forceParentVerifiable: function() { if (!transport.isParentVerifiable()) { transport = OpenAjax.gadgets.rpctx.ifpc; } }, /** * Calls an RPC service. * @param {string} targetId Module Id of the RPC service provider. * Empty if calling the parent container. * @param {string} serviceName Service name to call. * @param {function()|null} callback Callback function (if any) to process * the return value of the RPC request. * @param {*} var_args Parameters for the RPC request. * * @member gadgets.rpc */ call: function(targetId, serviceName, callback, var_args) { targetId = targetId || '..'; // Default to the container calling. var from = '..'; if (targetId === '..') { from = rpcId; } ++callId; if (callback) { callbacks[callId] = callback; } var rpc = { s: serviceName, f: from, c: callback ? callId : 0, a: Array.prototype.slice.call(arguments, 3), t: authToken[targetId], l: useLegacyProtocol[targetId] }; if (targetId !== '..' && !document.getElementById(targetId)) { // The target has been removed from the DOM. Don't even try. OpenAjax.gadgets.log("WARNING: attempted send to nonexistent frame: " + targetId); return; } // If target is on the same domain, call method directly if (callSameDomain(targetId, rpc)) { return; } // Attempt to make call via a cross-domain transport. // Retrieve the transport for the given target - if one // target is misconfigured, it won't affect the others. var channel = receiverTx[targetId]; if (!channel) { // Not set up yet. Enqueue the rpc for such time as it is. if (!earlyRpcQueue[targetId]) { earlyRpcQueue[targetId] = [ rpc ]; } else { earlyRpcQueue[targetId].push(rpc); } return; } // If we are told to use the legacy format, then we must // default to IFPC. if (useLegacyProtocol[targetId]) { channel = OpenAjax.gadgets.rpctx.ifpc; } if (channel.call(targetId, from, rpc) === false) { // Fall back to IFPC. This behavior may be removed as IFPC is as well. receiverTx[targetId] = fallbackTransport; transport.call(targetId, from, rpc); } }, /** * Gets the relay URL of a target frame. * @param {string} targetId Name of the target frame. * @return {string|undefined} Relay URL of the target frame. * * @member gadgets.rpc */ getRelayUrl: function(targetId) { var url = relayUrl[targetId]; // Some RPC methods (wpm, for one) are unhappy with schemeless URLs. if (url && url.substring(0,1) === '/') { if (url.substring(1,2) === '/') { // starts with '//' url = document.location.protocol + url; } else { // relative URL, starts with '/' url = document.location.protocol + '//' + document.location.host + url; } } return url; }, setRelayUrl: setRelayUrl, setAuthToken: setAuthToken, setupReceiver: setupReceiver, getAuthToken: getAuthToken, // Note: Does not delete iframe removeReceiver: function(receiverId) { delete relayUrl[receiverId]; delete useLegacyProtocol[receiverId]; delete authToken[receiverId]; delete setup[receiverId]; delete sameDomain[receiverId]; delete receiverTx[receiverId]; }, /** * Gets the RPC relay mechanism. * @return {string} RPC relay mechanism. See above for * a list of supported types. * * @member gadgets.rpc */ getRelayChannel: function() { return transport.getCode(); }, /** * Receives and processes an RPC request. (Not to be used directly.) * Only used by IFPC. * @param {Array.} fragment An RPC request fragment encoded as * an array. The first 4 elements are target id, source id & call id, * total packet number, packet id. The last element stores the actual * JSON-encoded and URI escaped packet data. * * @member gadgets.rpc * @deprecated */ receive: function(fragment, otherWindow) { if (fragment.length > 4) { process(OpenAjax.gadgets.json.parse( decodeURIComponent(fragment[fragment.length - 1]))); } else { relayOnload.apply(null, fragment.concat(otherWindow)); } }, /** * Receives and processes an RPC request sent via the same domain. * (Not to be used directly). Converts the inbound rpc object's * Array into a local Array to pass the process() Array test. * @param {Object} rpc RPC object containing all request params * @member gadgets.rpc */ receiveSameDomain: function(rpc) { // Pass through to local process method but converting to a local Array rpc.a = Array.prototype.slice.call(rpc.a); window.setTimeout(function() { process(rpc); }, 0); }, // Helper method to get the protocol://host:port of an input URL. // see docs above getOrigin: getOrigin, getReceiverOrigin: function(receiverId) { var channel = receiverTx[receiverId]; if (!channel) { // not set up yet return null; } if (!channel.isParentVerifiable(receiverId)) { // given transport cannot verify receiver origin return null; } var origRelay = OpenAjax.gadgets.rpc.getRelayUrl(receiverId) || OpenAjax.gadgets.util.getUrlParameters().parent; return OpenAjax.gadgets.rpc.getOrigin(origRelay); }, /** * Internal-only method used to initialize gadgets.rpc. * @member gadgets.rpc */ init: function() { // Conduct any global setup necessary for the chosen transport. // Do so after gadgets.rpc definition to allow transport to access // gadgets.rpc methods. if (transport.init(process, transportReady) === false) { transport = fallbackTransport; } if (isChild) { setupReceiver('..'); } }, /** Returns the window keyed by the ID. null/".." for parent, else child */ _getTargetWin: getTargetWin, /** Create an iframe for loading the relay URL. Used by child only. */ _createRelayIframe: function(token, data) { var relay = OpenAjax.gadgets.rpc.getRelayUrl('..'); if (!relay) { return; } // Format: #targetId & sourceId & authToken & data var src = relay + '#..&' + rpcId + '&' + token + '&' + encodeURIComponent(OpenAjax.gadgets.json.stringify(data)); var iframe = document.createElement('iframe'); iframe.style.border = iframe.style.width = iframe.style.height = '0px'; iframe.style.visibility = 'hidden'; iframe.style.position = 'absolute'; function appendFn() { // Append the iframe. document.body.appendChild(iframe); // Set the src of the iframe to 'about:blank' first and then set it // to the relay URI. This prevents the iframe from maintaining a src // to the 'old' relay URI if the page is returned to from another. // In other words, this fixes the bfcache issue that causes the iframe's // src property to not be updated despite us assigning it a new value here. iframe.src = 'javascript:""'; iframe.src = src; } if (document.body) { appendFn(); } else { OpenAjax.gadgets.util.registerOnLoadHandler(function() { appendFn(); }); } return iframe; }, ACK: ACK, RPC_ID: rpcId, SEC_ERROR_LOAD_TIMEOUT: LOAD_TIMEOUT, SEC_ERROR_FRAME_PHISH: FRAME_PHISH, SEC_ERROR_FORGED_MSG : FORGED_MSG }; }(); // Initialize library/transport. OpenAjax.gadgets.rpc.init(); } // !end of double-inclusion guard /** Licensed Materials - Property of IBM, 5724-U69, (C) Copyright IBM Corp. 2008, 2012 - All Rights reserved. **/ require(["dojo/_base/connect", "dojo/string", "dojo/back", "dojox/xml/parser", "dojox/uuid/generateRandomUuid"], function(dConnect, dString, dBack){ dojo.provide("com.ibm.mm.enabler.core"); dojo.i18n._preloadLocalizations("com.ibm.mm.enabler.nls.enabler", ["ROOT","ar","ca","cs","da","de","el","en","es","fi","fr","he","hr","hu","it","ja","ko","nb","nl","no","pl","pt","pt-br","ro","ru","sk","sl","sv","th","tr","uk","zh","zh-tw"]); (function() { var ver = "3.0.0.20110927-1750".split("."); var flag = "enabler.core"; if (flag) { flag = "_" + flag; } if (ver.length == 4) { dojo.setObject("com.ibm.mashups.enabler.version",{ major: ver[0], minor: ver[1], patch: ver[2], "flag": flag, revision: ver[3], toString: function() { return this.major + "." + this.minor + "." + this.patch + (this.flag || "") + " (" + this.revision + ")"; // String } }); } })(); if(!dojo._hasResource["com.ibm.mashups.enabler.Deferred_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.Deferred_API"] = true; dojo.provide("com.ibm.mashups.enabler.Deferred_API"); dojo.provide("com.ibm.mashups.enabler.Deferred"); /** * Base interface for all classes which handle actions asynchronously. * An action may involve one or more operations, for example creating or * updating a model resource, which in turn may involve one or more HTTP * requests. The Deferred interface allows to trigger a callback after * the entire action, i.e. all involved HTTP requests, is finished. Thus, * the Deferred interface may be used to get the overall result of an action. * @ibm-api * @ibm-module Base2 */ dojo.declare( "com.ibm.mashups.enabler.Deferred", null, { /** * Sets the handler of the deferred action. It is called when the entire * action has finished.
* Please note that the status of the action is transported only with * callbacks, even if you use synchronous mode. If you need to check the status, * you must use callback functions. * @param {Object} callback the callback funtion in the format of Function(Object resource, int statusCode, Object[] params). * Must not be null
*     Callbackparameters
*     resource - resource object or id string * of the related resource. * May be null in case the action does not relate * to a particular resource. In case multiple resources are involved in the * action, the DeferredOperation interface may be used to obtain the resource * objects or string ids of those resources.
*     statusCode - the overall HTTP status * code of the action (the highest status code of the involved operations).
*     params - the parameters * passed into the callback * @param {Object[]} parameters optional array of parameters to be * passed on to the callback function. May be null * @return {com.ibm.mashups.enabler.Deferred} the deferred object */ setFinishedCallback: function(callback, parameters) { }, /** * Executes the deferred action and invokes the callback functions set * with the deferred object. * @param {Boolean} sync indicates if the deferred action is executed * synchronously or asynchronously. Optional, defaults to true. * @return {Object} resource if called asynchronously, the return value is * undefined, otherwise a resource object or id string of the * related resource is returned.
In order to obtain information on * the resource as well as on the status code of the operation, you * must use the callback functions of the deferred object. */ start: function(sync) { return {}; } }); } if(!dojo._hasResource["com.ibm.mm.enabler.DeferredImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.DeferredImpl"] = true; dojo.provide("com.ibm.mm.enabler.DeferredImpl"); // base dojo.declare("com.ibm.mm.enabler.DeferredImpl", [com.ibm.mashups.enabler.Deferred], { _chainedDeferred: null, _sync: false, _previous: null, // If you mixin the DeferredImpl into your class, you may use a different // set of parameters for the constructor, but then you do not have access // to the parameters 'context', 'startfn', as well as 'params' and thus, // you need to overwrite the start function, which accesses those parameters. // If you want to use the start function defined in DeferredImpl, you need // to make sure, the parameters 'context', 'startfn', as well as 'params' // are set in the constructor of DeferredImpl. constructor: function(context, startfn, params){ // context for start function this.context = context; // start function this.startfn = startfn; // parameters to pass to start function this.params = params; }, // deprecated addErrorCallback: function(callback, parameters){ dojo.deprecated("com.ibm.mashups.enabler.Deferred.addErrorCallback()", "use com.ibm.mashups.enabler.Deferred.setFinishedCallback() instead"); this.errorCallback = callback; this.errorCallbackParameters = parameters; }, // deprecated addFinishedCallback: function(callback, parameters){ dojo.deprecated("com.ibm.mashups.enabler.Deferred.addFinishedCallback()", "use com.ibm.mashups.enabler.Deferred.setFinishedCallback() instead"); this.finishedCallback = callback; this.finishedCallbackParameters = parameters; // forward compatibility //this.setFinishedCallback(callback, parameters); }, setFinishedCallback: function(callback, parameters){ this.finishedCallback2 = callback; this.finishedCallbackParameters2 = parameters; return this; }, start: function(sync, previous){ this._sync = (sync || typeof(sync) == 'undefined'); var ret = null; if (dojo.isFunction(this.startfn)) { ret = dojo.hitch(this.context || null, this.startfn)(this, this._sync, this.params, previous || null); } return ret; }, getFinishedCallback: function(){ return this.finishedCallback2; }, getFinishedCallbackParameters: function(){ return this.finishedCallbackParameters2; }, setChainedDeferred: function(deferred){ this._chainedDeferred = deferred; }, getChainedDeferred: function(){ return this._chainedDeferred; }, getPrevious: function(){ return this._previous; }, _setPreviousDeferred: function(deferred, result, status){ this._previous = { deferred: deferred, result: result, status: status }; }, removeChainedDeferred: function(){ this._chainedDeferred = null; }, /** * call this at the end of whatever you are doing * * @param {Object} result * @param {Object} status */ finish: function(result, status){ try { if (dojo.isFunction(this.getFinishedCallback())) { // call callback dojo.partial(this.getFinishedCallback())(result, status, this.getFinishedCallbackParameters()); } else { if (dojo.isFunction(this.finishedCallback) && ("" + status).indexOf('2') === 0) { // backwards compatibility dojo.partial(this.finishedCallback)(result, this.finishedCallbackParameters); } else { if (dojo.isFunction(this.errorCallback) && status >= 400) { dojo.partial(this.errorCallback)(result, this.errorCallbackParameters); } } } } catch (e) { } if (this._chainedDeferred) { this._chainedDeferred._setPreviousDeferred(this, result, status); this._chainedDeferred.start(this._sync); } } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.Deferred"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.Deferred"] = true; dojo.provide( "com.ibm.mashups.enabler.Deferred"); dojo.require( "com.ibm.mm.enabler.DeferredImpl" ); } if(!dojo._hasResource["com.ibm.mashups.enabler.context.LocalizedContext_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.context.LocalizedContext_API"] = true; dojo.provide("com.ibm.mashups.enabler.context.LocalizedContext_API"); dojo.provide("com.ibm.mashups.enabler.context.LocalizedContext"); /** * LocalizedContext to get the preferred locale, the default locale, as well as * titles and descriptions of localized resources within this localized context. * * @ibm-api * @ibm-module Base2 */ dojo.declare("com.ibm.mashups.enabler.context.LocalizedContext", null, { /** * Returns the preferred locale of this LocalizedContext. * @ibm-api * @type {String} * @return the preferred locale */ getPreferredLocale : function() { }, /** * Returns the default locale of this LocalizedContext. * @ibm-api * @type {String} * @return the default locale */ getDefaultLocale : function() { }, /** * Returns the locale of the localized resource, which matches best the locale set with * the browser. * @ibm-api * @param {com.ibm.mashups.enabler.Localized} localized resource implementing the Localized interface; must not be null * @type {String} * @return the preferred locale. Returns null if no locale is available. */ getLocale : function(localized) { }, /** * Returns the display locale set with the browser matching the specified locale. * @ibm-api * @param {String} locale; mandatory, must not be null * @type {String} * @return the display locale. Returns null if no display locale is available. */ getDisplayLocale : function(locale) { }, /** * Returns the title of the localized resource in the locale, which matches best the locale * set with the browser. * @ibm-api * @param {com.ibm.mashups.enabler.Localized} localized resource implementing the Localized interface; must not be null * @type {String} * @return the title string in the preferred locale. Returns null if no locale is available. */ getTitle : function(localized) { }, /** * Returns the description of the localized resource in the locale, which matches best the * locale set with the browser. * @ibm-api * @param {com.ibm.mashups.enabler.Localized} localized resource implementing the Localized interface; must not be null * @type {String} * @return the description string in the preferred locale. Returns null if no locale is available. */ getDescription : function(localized) { } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.xml.XPath_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.xml.XPath_API"] = true; dojo.provide("com.ibm.mashups.enabler.xml.XPath_API"); dojo.provide("com.ibm.mashups.enabler.xml.XPath"); /** * Interface provides functions to select nodes by evaluating XPATH expression * * @ibm-api * @ibm-module Base2 */ dojo.declare("com.ibm.mashups.enabler.xml.XPath", null, { /** * This interface returns a list of XMLNodes upon XPATH evaluation. * @param {String} xpathExpr the xpath expression (i.e. /atom:content). Must not be NULL. * @param {XMLDocument} doc the XML document. Must not be NULL. * @param {JSON} namespaces the namespaces used as part of the xpath expression. The json must be of the format {"prefix": "URL", ... }; must not be NULL.
* Example: { "atom" : "http://www.w3.org/2005/Atom", "app" : "http://www.w3.org/2007/app" }; * * @return {XMLNodeList} select nodes from XML document with xpath; may be null. */ evaluateXPath : function(xpathExpr, doc, namespaces) { }, /** * This interface returns a single Entry upon XPATH evaluation or null if the entry is not present. * * @param {String} xpathExpr the xpath expression (i.e. /atom:content). Must not be NULL. * @param {XMLDocument} doc the XML document. Must not be NULL. * @param {JSON} namespaces the namespaces used as part of the xpath expression. The json must be of the format {"prefix": "URL", ... }; must not be NULL.
* Example: { "atom" : "http://www.w3.org/2005/Atom", "app" : "http://www.w3.org/2007/app" }; * * @return {Object} */ evaluateEntry: function(xpathExpr, doc, namespaces) { }, /** * This interface returns a boolean upon XPATH evaluation. Returns false if the result is not valid (e.g. node does not exist, etc.). * * @param {String} xpathExpr the xpath expression (i.e. /atom:content). Must not be NULL. * @param {XMLDocument} doc the XML document. Must not be NULL. * @param {JSON} namespaces the namespaces used as part of the xpath expression. The json must be of the format {"prefix": "URL", ... }; must not be NULL.
* Example: { "atom" : "http://www.w3.org/2005/Atom", "app" : "http://www.w3.org/2007/app" }; * * @return {Boolean} */ evaluateBoolean: function(xpathExpr, doc, namespaces) { }, /** * This interface returns a String upon XPATH evaluation. Returns an empty String if the result is not valid (e.g. node does not exist, etc.). * If you want to check for existence of an attribute/element use either evaluateBoolean (which returns false if the element is not present) or evaluateEntry (which returns null if the element is not present). * * @param {String} xpathExpr the xpath expression (i.e. /atom:content). Must not be NULL. * @param {XMLDocument} doc the XML document. Must not be NULL. * @param {JSON} namespaces the namespaces used as part of the xpath expression. The json must be of the format {"prefix": "URL", ... }; must not be NULL.
* Example: { "atom" : "http://www.w3.org/2005/Atom", "app" : "http://www.w3.org/2007/app" }; * * @return {String} */ evaluateString: function(xpathExpr, doc, namespaces) { }, /** * This interface returns a Number upon XPATH evaluation. Returns zero (0) if the result is not valid (e.g. node does not exist, etc.). * If you want to check for existence of an attribute/element use either evaluateBoolean (which returns false if the element is not present) or evaluateEntry (which returns null if the element is not present). * * @param {String} xpathExpr the xpath expression (i.e. /atom:content). Must not be NULL. * @param {XMLDocument} doc the XML document. Must not be NULL. * @param {JSON} namespaces the namespaces used as part of the xpath expression. The json must be of the format {"prefix": "URL", ... }; must not be NULL.
* Example: { "atom" : "http://www.w3.org/2005/Atom", "app" : "http://www.w3.org/2007/app" }; * * @return {Number} */ evaluateNumber: function(xpathExpr, doc, namespaces) { } }); } if(!dojo._hasResource["com.ibm.mm.enabler.utils.Dom"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.utils.Dom"] = true; dojo.provide("com.ibm.mm.enabler.utils.Dom"); com.ibm.mm.enabler.utils.Dom = { getAttributeWithNS: function(element, attName, localAttName, nsUri) { if (!element) { return null; } if (!attName) { return null; } if (!localAttName) { return null; } if (!nsUri) { return null; } var value = null; if (dojo.isIE) { // IE with no namepsace value = element.getAttribute(attName); if (value === null || value == "") { // IE with namepsace var attributes = element.attributes; for (var i = attributes.length; i > 0; i--) { if (attributes[i - 1].baseName == localAttName && attributes[i - 1].namespaceURI == nsUri) { value = attributes[i - 1].value; break; } } } } else { // Safari & Firefox value = element.getAttributeNS(nsUri, localAttName); } return value; }, setAttributeWithNS: function(dom, element, attName, localAttName, nsUri, value) { if (!dojo.isObject(element)) { throw new Error("element must be a DOMNode"); } if (dojo.isIE) { var attr = dom.createNode(2, attName, nsUri); // set value if (value === null || value === undefined) { value = ""; } attr.nodeValue = value; // attach to element element.setAttributeNode(attr); } else { element.setAttributeNS(nsUri, attName, value); } }, textContent: function(node, text) { if (!node) { return ""; } if (arguments.length > 1) { var doc = node.ownerDocument; var aNode = doc.createTextNode(text || ""); // IE8 createTextNode fails when text == null com.ibm.mm.enabler.utils.Dom.replaceChildren(node, aNode); return; } else { var tc = dojox.xml.parser.textContent(node); if (tc) { return tc; } return dojo.map(node.childNodes || [], function(node) { return (node.nodeType > 0 && node.nodeType < 4) ? node.nodeValue : ""; }).join(""); } }, createElement: function(dom, name, ns) { var newElem; if (dojo.isIE) { if (ns) { newElem = dom.createNode(1, name, ns); } else { newElem = dom.createElement(name); } } else { newElem = dom.createElementNS(ns, name); } return newElem; }, destroyNode: function(node) { //avoid pseudo leaks since our webpage are open for long long time! var garbageBin = dojo.byId('IELeakGarbageBin'); if (!garbageBin) { garbageBin = dojo.create("div",{ id: "IELeakGarbageBin", style: {display: "none"} }, dojo.body()); } // move the element to the garbage bin dojo.place(node,garbageBin); dojo.attr(garbageBin,'innerHTML',''); if (node.nodeType != 3) { // ingore TEXT_NODE if (dojo.isIE) { dojo.attr(node,'outerHTML',''); //prevent ugly IE mem leak } } }, createDocument: function(/*string?*/str, /*string?*/ mimetype) { return dojox.xml.parser.parse(str, mimetype); }, replaceChildren: function(/*Element*/node, /*Node || array*/ newChildren) { return dojox.xml.parser.replaceChildren(node, newChildren); }, innerXML: function(node) { return node ? dojox.xml.parser.innerXML(node) : null; }, removeChildren: function(node) { return dojox.xml.parser.removeChildren(node); }, copyChildren: function(/*Element*/srcNode, /*Element*/ destNode, /*boolean?*/ trim) { var clonedNode = srcNode.cloneNode(true); return this.moveChildren(clonedNode, destNode, trim); // number }, moveChildren: function(srcNode, destNode, trim) { var count = 0; if (trim) { while (srcNode.hasChildNodes() && srcNode.firstChild.nodeType == 3) { srcNode.removeChild(srcNode.firstChild); } while (srcNode.hasChildNodes() && srcNode.lastChild.nodeType == 3) { srcNode.removeChild(srcNode.lastChild); } } while (srcNode.hasChildNodes()) { destNode.appendChild(srcNode.firstChild); count++; } return count; // number }, /** * Get's the local name of the node passed in as parameter * * @param {Node} node the node of which to get the local name * @return {String} the local name of the node or null if the node doesn't have a local name */ getLocalName: function(node) { if (!node) { return null; } switch (node.nodeType) { case 3: return "#text"; case 1: return node.localName || com.ibm.mm.enabler.utils.Dom.removeNodeNS(node.nodeName); } return null; }, /** * Get's the namespace prefix from the given nodename or null if there is no NS Prefix. * * @param {String} nodeName The name of the node * @return {String} the namespace prefix of the node name or null if there is none. */ getNodeNSPrefix: function(nodeName) { var tN = '' + nodeName; var hasColon = tN.indexOf(':'); return (hasColon != -1) ? tN.substring(0, hasColon) : null; }, /** * Removes the namespace from a node name. * This is a copy of com.ibm.mashups.widget.dijit.url.util.Dom.removeNodeNs and should * replace this method in case, this one here becomes public. * * @private * @param {String} nodeName the node name with or without namespace * @return {String} the node name without namespace * @see com.ibm.mashups.widget.dijit.url.util.Dom#removeNodeNs(String) */ removeNodeNS: function(nodeName) { var tN = '' + nodeName; var hasColon = tN.indexOf(':'); return (hasColon != -1) ? tN.substring(1 + hasColon) : nodeName; }, /** * Looks up the namespace for the specified prefix * @param {Node} node the node for which to lookup the namespace * @param {String} prefix the prefix to lookup the namespace for. * @return {String} the namespace for the specified prefix or null if the namespace for the prefix wasn't found. */ lookupNamespaceURI: function(node, prefix) { // If we are not on IE, we have native support for this if (!dojo.isIE) { return node.lookupNamespaceURI(prefix); } // seems we are on IE, so let's do some magic here var lastNode = node; // while node != null and node isn't a document while (lastNode && lastNode.nodeType != 9) { var attrValue = lastNode.getAttribute("xmlns:" + prefix); if (attrValue) { return attrValue; } lastNode = lastNode.parentNode; } return null; } }; } if(!dojo._hasResource["com.ibm.mm.enabler.xml.xpath._Generic"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.xml.xpath._Generic"] = true; dojo.provide("com.ibm.mm.enabler.xml.xpath._Generic"); // generic impl dojo.declare("com.ibm.mm.enabler.xml.xpath._Generic", null, { constructor: function(){ }, _evaluateXPath: function(/*String*/xpathExpr, /*DOMDocument*/ doc, /*Object{prefix:ns,prefix2:ns2,...}*/ namespaces){ if (dojo.isSafari) { return this._safariEvaluateXPath(xpathExpr, doc, namespaces); } else if (dojo.isIE) { return this._ieEvaluateXPath(xpathExpr, doc, namespaces); } else { return this._geckoEvaluateXPath(xpathExpr, doc, namespaces); } }, _transformNode: function(result, resType){ if (typeof XPathResult != "undefined" && result instanceof XPathResult) { return this._xpathResultValue(result, resType); } else { if (resType == com.ibm.mm.enabler.xml.xpath._Generic.ANY_TYPE) { return result; } else if (resType == com.ibm.mm.enabler.xml.xpath._Generic.NUMBER_TYPE) { return parseFloat(com.ibm.mm.enabler.utils.Dom.textContent(result)); } else if (resType == com.ibm.mm.enabler.xml.xpath._Generic.STRING_TYPE) { return com.ibm.mm.enabler.utils.Dom.textContent(result); } else if (resType == com.ibm.mm.enabler.xml.xpath._Generic.BOOLEAN_TYPE) { return !!result; } } return null; }, _xpathResultValue: function(node, resType){ if (resType == com.ibm.mm.enabler.xml.xpath._Generic.ANY_TYPE) { return node; } else if (resType == com.ibm.mm.enabler.xml.xpath._Generic.NUMBER_TYPE) { return node.numberValue; } else if (resType == com.ibm.mm.enabler.xml.xpath._Generic.STRING_TYPE) { return node.stringValue; } else if (resType == com.ibm.mm.enabler.xml.xpath._Generic.BOOLEAN_TYPE) { return node.booleanValue; } return null; }, _evaluateXPathSingle: function(xpathExpr, doc, namespaces, resType){ resType = resType || com.ibm.mm.enabler.xml.xpath._Generic.ANY_TYPE; var result; if (dojo.isSafari) { result = this._safariEvaluateXPathRaw(xpathExpr, doc, namespaces, resType); if (XPathResult && result instanceof XPathResult) { if (resType == com.ibm.mm.enabler.xml.xpath._Generic.ANY_TYPE) { return result.iterateNext(); } return this._transformNode(result, resType); } else if (result) { return this._transformNode(result[0], resType); } } else if (dojo.isIE) { result = this._ieEvaluateXPathRawSingle(xpathExpr, doc, namespaces); if (result || result === null) { return this._transformNode(result, resType); } } else { result = this._geckoEvaluateXPathRaw(xpathExpr, doc, namespaces, resType); if (result && resType == com.ibm.mm.enabler.xml.xpath._Generic.ANY_TYPE) { return result.iterateNext(); } else { return this._transformNode(result, resType); } } return result || null; }, _geckoEvaluateXPath: function(/*String*/xpathExpr, /*DOMDocument*/ doc, /*Object{prefix:ns,prefix2:ns2,...}*/ namespaces){ var result = this._geckoEvaluateXPathRaw(xpathExpr, doc, namespaces, com.ibm.mm.enabler.xml.xpath._Generic.ANY_TYPE); var resultSet = []; if (result) { var thisResult; while ((thisResult = result.iterateNext())) { resultSet.push(thisResult); } } return resultSet; }, _geckoEvaluateXPathRaw: function(xpathExpr, doc, namespaces, type){ var xmlDocument = doc; if (doc.nodeType != 9) { xmlDocument = doc.ownerDocument; } return xmlDocument.evaluate(xpathExpr, doc, function(prefix){ return namespaces[prefix] ? namespaces[prefix].toString() : null; }, type, null); }, _ieEvaluateXPath: function(/*String*/xpathExpr, /*DOMDocument*/ doc, /*Object{prefix:ns,prefix2:ns2,...}*/ namespaces){ var result = this._ieEvaluateXPathRaw(xpathExpr, doc, namespaces); return result || []; }, _setIeNamespaces: function(doc, namespaces) { if (namespaces) { var ns = []; var item; for (var prop in namespaces) { // JSLINT-IGNORE: Filtering for prototype properties must not be done here, as namespaces often use dojo.delegate to save memory - dojo.delegate uses the prototype functionality for doing so - we use dojo.isFunction() which should suffice. // ATTENTION: DON'T ADD .hasOwnProperty() CHECK HERE! item = namespaces[prop]; if (prop != "xml") { // we cannot use !dojo.isFunction(item) as it costs too much performance // There is no automatic namespace recognition, this is a workaround ns.push("xmlns:", prop, "='", item, "' "); } } if(dojo.isIE !=11){ var sDoc = doc.ownerDocument || doc; sDoc.setProperty("SelectionNamespaces", ns.join("")); sDoc.setProperty("SelectionLanguage", "XPath"); } } }, _ieEvaluateXPathRaw: function(xpathExpr, doc, namespaces){ this._setIeNamespaces(doc, namespaces); return doc.selectNodes(xpathExpr); }, _ieEvaluateXPathRawSingle: function(xpathExpr, doc, namespaces){ this._setIeNamespaces(doc, namespaces); return doc.selectSingleNode(xpathExpr); }, _safariEvaluateXPath: function(/*String*/xpathExpr, /*DOMDocument*/ doc, /*Object{prefix:ns,prefix2:ns2,...}*/ namespaces){ var result = this._safariEvaluateXPathRaw(xpathExpr, doc, namespaces, com.ibm.mm.enabler.xml.xpath._Generic.ANY_TYPE); if (XPathResult && result instanceof XPathResult) { var resultSet = []; var thisResult; while ((thisResult = result.iterateNext())) { resultSet.push(thisResult); } return resultSet; } return result || []; }, _safariEvaluateXPathRaw: function(xpathExpr, doc, namespaces, type){ if (typeof XPathResult != "undefined") { //use build in xpath support for Safari 3.0 return document.evaluate(xpathExpr, doc, function(prefix){ return namespaces[prefix] ? namespaces[prefix].toString() : null; }, type, null); } else if (doc.selectNodes) { //use javeline Safari2 xpath support return doc.selectNodes(xpathExpr); } } }); com.ibm.mm.enabler.xml.xpath._Generic.ANY_TYPE = 0; com.ibm.mm.enabler.xml.xpath._Generic.NUMBER_TYPE = 1; com.ibm.mm.enabler.xml.xpath._Generic.STRING_TYPE = 2; com.ibm.mm.enabler.xml.xpath._Generic.BOOLEAN_TYPE = 3; } if(!dojo._hasResource["com.ibm.mm.enabler.xml.XPathImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.xml.XPathImpl"] = true; dojo.provide("com.ibm.mm.enabler.xml.XPathImpl"); dojo.declare("com.ibm.mm.enabler.xml.XPathImpl", [com.ibm.mashups.enabler.xml.XPath, com.ibm.mm.enabler.xml.xpath._Generic], { modelMessages: null, constructor: function() { this.modelMessages = dojo.i18n.getLocalization("com.ibm.mm.enabler", "modelMessages"); }, ANY_TYPE: com.ibm.mm.enabler.xml.xpath._Generic.ANY_TYPE, NUMBER_TYPE: com.ibm.mm.enabler.xml.xpath._Generic.NUMBER_TYPE, STRING_TYPE: com.ibm.mm.enabler.xml.xpath._Generic.STRING_TYPE, BOOLEAN_TYPE: com.ibm.mm.enabler.xml.xpath._Generic.BOOLEAN_TYPE, evaluateXPath: function(xpathExpr, doc, namespaces) { if(!dojo.isString(xpathExpr) || xpathExpr.length === 0) { throw new Error(this.modelMessages.E_INVALID_XPATH_EXPR_0); } if(!doc) { throw new Error(this.modelMessages.E_INVALID_DOCUMENT_0); } var ret = this._evaluateXPath(xpathExpr, doc, namespaces); return ret; }, evaluateSingle: function(xpathExpr, doc, namespaces, type) { if(!dojo.isString(xpathExpr) || xpathExpr.length === 0) { throw new Error(this.modelMessages.E_INVALID_XPATH_EXPR_0); } if(!doc) { throw new Error(this.modelMessages.E_INVALID_DOCUMENT_0); } return this._evaluateXPathSingle(xpathExpr, doc, namespaces, type); }, evaluateEntry: function(xpathExpr, doc, namespaces) { return this.evaluateSingle(xpathExpr, doc, namespaces, com.ibm.mashups.enabler.xml.XPath.ANY_TYPE); }, evaluateBoolean: function(xpathExpr, doc, namespaces) { return this.evaluateSingle(xpathExpr, doc, namespaces, com.ibm.mashups.enabler.xml.XPath.BOOLEAN_TYPE); }, evaluateString: function(xpathExpr, doc, namespaces) { return this.evaluateSingle(xpathExpr, doc, namespaces, com.ibm.mashups.enabler.xml.XPath.STRING_TYPE); }, evaluateNumber: function(xpathExpr, doc, namespaces) { return this.evaluateSingle(xpathExpr, doc, namespaces, com.ibm.mashups.enabler.xml.XPath.NUMBER_TYPE); }, /** * evaluates the specified xpath, but creates xml elements, which are not part * of the document; please note that attributes are not supported * * @param {Object} xPath * @param {Object} node * @param {Object} namespaces */ createXPath: function(xPath, node, namespaces) { // split off first part of xpath var xPathParts = xPath.split("/"); // handle head var qName = xPathParts[0]; // extract name and name space var qNameParts = qName.split(":"); var name, namespace; if (qNameParts.length > 1) { namespace = qNameParts[0]; name = qNameParts[1]; } else { name = qNameParts[0]; } // search for first part of xpath (what about case insensitive search for attributes, especially "_" vs "-" in locales?) var names = com.ibm.mashups.enabler.xml.XPath.evaluateXPath((namespace ? namespace + ":" : "") + name, node, namespaces); var result; if (names && names.length > 0) { // use existing xml element result = names[0]; } else { // what about attributes? // create xml element result = com.ibm.mm.enabler.utils.Dom.createElement(node.ownerDocument, (namespace ? namespace + ":" : "") + name, namespace ? namespaces[namespace] : null); node.appendChild(result); } // handle remaining parts of xpath if (xPathParts.length > 1) { // recursive call with remaining xpath part result = com.ibm.mashups.enabler.xml.XPath.createXPath(xPath.substr(xPath.indexOf("/") + 1), result, namespaces); } return result; } }); // create the singleton com.ibm.mashups.enabler.xml.XPath = new com.ibm.mm.enabler.xml.XPathImpl(); // backwards compatibility - still needed? // TODO remove this in next enabler version com.ibm.mm.enabler.xml.xpath.evaluateXPath = function(xpathExpr, doc, namespaces) { dojo.deprecated("com.ibm.mm.enabler.xml.xpath.evaluateXPath", "The method com.ibm.mm.enabler.xml.xpath.evaluateXPath is deprecated, please use com.ibm.mashups.enabler.xml.XPath.evaluateXPath instead"); return com.ibm.mm.enabler.xml.xpath._Generic.evaluateXPath.apply(null, arguments); }; } if(!dojo._hasResource["com.ibm.mashups.enabler.xml.XPath"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.xml.XPath"] = true; dojo.provide("com.ibm.mashups.enabler.xml.XPath"); } if(!dojo._hasResource["com.ibm.mm.enabler.utils.LocaleHelper"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.utils.LocaleHelper"] = true; dojo.provide("com.ibm.mm.enabler.utils.LocaleHelper"); com.ibm.mm.enabler.utils.LocaleHelper = { getLocale:function(/*com.ibm.mashups.enabler.Localized*/localized,aLocale,defaultLocale){ if (typeof localized == "undefined" || localized === null) { return null; } var localeArr = localized.getLocales(); if (typeof localeArr == "undefined" || localeArr === null || !dojo.isArray(localeArr)) { return null; } if (localeArr.length === 0) { return null; } var returnLocale = null; if (localeArr.length === 1) { returnLocale = localeArr[0]; } var arr = {}; for (var i in localeArr) { if (Object.prototype.hasOwnProperty.call(localeArr,i)) { var temp = localeArr[i]; arr[temp] = temp; } } var tempArr; if (returnLocale === null) { if (typeof aLocale != "undefined" && aLocale !== null) { returnLocale = this.findMatchLocale(arr, aLocale); if (returnLocale === null) { tempArr = aLocale.split(/-|_/); if (tempArr.length == 2) { var iLocale = tempArr[0]; if (typeof arr[iLocale] != "undefined" && arr[iLocale] !== null) { returnLocale = iLocale; } } } } } if (returnLocale === null) { //get browser locale var browserLocale = (dojo.isIE ? navigator.userLanguage : navigator.language).toLowerCase(); if (typeof ibmConfig != "undefined" && ibmConfig && typeof(ibmConfig.locale) != "undefined" && ibmConfig.locale) { browserLocale = ibmConfig.locale; } if (browserLocale !== null) { //browserLocale = browserLocale.replace(/-/,"_"); returnLocale = this.findMatchLocale(arr, browserLocale); if (returnLocale === null) { tempArr = browserLocale.split(/-|_/); if (tempArr.length == 2) { var tempLocale = tempArr[0]; if (typeof arr[tempLocale] != "undefined" && arr[tempLocale] !== null) { returnLocale = tempLocale; } } } } } if (returnLocale === null) { if (defaultLocale) { returnLocale = defaultLocale; } } if (returnLocale === null) { if (arr.en) { returnLocale = "en"; } } if (returnLocale === null) { returnLocale = localeArr[0]; } return returnLocale; }, findMatchLocale:function(arr,locale){ var returnLocale = null; if (arr[locale]) { returnLocale = locale; } var serverLocale = this.toServerLocale(locale); if (returnLocale === null && arr[serverLocale]) { returnLocale = serverLocale; } var serverLocaleLowercase = serverLocale.toLowerCase(); if (returnLocale === null && arr[serverLocaleLowercase]) { returnLocale = serverLocaleLowercase; } return returnLocale; }, /** * match a locale against an array of locales * * TODO: also allow preferred to be an array * * @param {String} preferred * @param {Array} available */ matchLocale: function(preferred, available) { return com.ibm.mm.enabler.utils.LocaleHelper._matchLocale( com.ibm.mm.enabler.utils.LocaleHelper._getLocaleObj(preferred), com.ibm.mm.enabler.utils.LocaleHelper.normalizeLocale(available)); }, /** * match a normalized locale against an array of normalized locales * * FIXME: we need to add handling of multiple possible locales matching against multiple available ones, * keeping in mind the order the user defined and also handling for exceptions * (e.g. pt-br must not fall back to pt, sh traditional must fall back to simplified, etc.) * * @param {Object} locale an locale object * @param {Array} locales an Array of normalized locale strings */ _matchLocale: function(locale, locales, stop) { // console.debug("match locale:",locale,"against",locales); var _origLocale = locale; var match = null; var found = dojo.some(locales, function(item) { if (item == com.ibm.mm.enabler.utils.LocaleHelper.normalizeLocale(locale.toString())) { match = item; return true; } }); if (found && match) { return match; } if (locale.variant) { // try without variant locale.variant = null; return com.ibm.mm.enabler.utils.LocaleHelper._matchLocale(locale, locales); } if (locale.country) { // try without country locale.country = null; return com.ibm.mm.enabler.utils.LocaleHelper._matchLocale(locale, locales); } if (!stop) { // TODO: make list of aliases [he,iw], to automate this for other fallbacks. locale = _origLocale; switch (locale.language) { case 'he': // special handling for hebrew (he and iw (old) are equal) locale.language = "iw"; break; case 'iw': // special handling for hebrew (he and iw (old) are equal) locale.language = "he"; break; } return com.ibm.mm.enabler.utils.LocaleHelper._matchLocale(locale, locales, true); } return null; }, /** * (DE_dE_VariAnt -> de_DE) * removes the variant part to sustain backwards compatibility - please use com.ibm.mm.enabler.utils.LocaleHelper.normalizeLocale * whitespaces are trimmed at the beginning and end * * @deprecated * * @param {Object} locale */ toServerLocale:function(locale) { if (!locale) { return null; } if (locale.indexOf("-") < 0) { return locale; } locale = locale.replace(/-/, "_"); var tempArr = locale.split('_'); var lang = tempArr[0]; var country = tempArr[1].toUpperCase(); var returnLocale = lang + "_" + country; return returnLocale; }, /** * returns a locale object with normalized parts * * (DE_dE_VariAnt -> {language: 'de', country: 'DE', variant: 'VariAnt'}) * whitespaces are trimmed at the beginning and end * * @param {String|Array} locale * */ _getLocaleObj: function(locale) { if (dojo.isArray(locale)) { return dojo.map(locale, function(item) { return com.ibm.mm.enabler.utils.LocaleHelper._getLocaleObj(item); }); } else if (dojo.isString(locale) && dojo.string.trim(locale).length > 0) { var localeObj = { language: null, country: null, variant: null, toString: function() { return (this.language ? this.language + (this.country ? "_" + this.country + (this.variant ? "_" + this.variant : "") : "") : ""); }, isValid: function() { return !!this.language; } }; var parts = dojo.string.trim(locale).replace(/-/g, "_").split('_'); switch (parts.length) { case 3: // we have got a variant localeObj.variant = parts[2]; // JSLINT-IGNORE: NO BREAK HERE // ATTN: no break here case 2: // we have got a country localeObj.country = parts[1].toUpperCase(); // JSLINT-IGNORE: NO BREAK HERE // ATTN: no break here case 1: // and we have got a language localeObj.language = parts[0].toLowerCase(); break; } return localeObj; } else { return null; } }, /** * normalizes a locale or an array of locales * * (DE_dE_VariAnt -> de-DE_VariAnt) * whitespaces are trimmed at the beginning and end * @param {String|Array} locale */ normalizeLocale: function(locale) { if (dojo.isArray(locale)) { return dojo.map(locale, function(item) { return com.ibm.mm.enabler.utils.LocaleHelper.normalizeLocale(item); }); } else if (locale && dojo.isString(locale)) { return locale.replace(/_/g, "-").toLowerCase(); } else { return null; } } }; } if(!dojo._hasResource["com.ibm.mm.enabler.model.NameSpaceFactory"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.model.NameSpaceFactory"] = true; dojo.provide("com.ibm.mm.enabler.model.NameSpaceFactory"); dojo.declare( "com.ibm.mm.enabler.model.NameSpaceFactoryImpl", null, { constructor:function () { // name space prefixes this.NS_APP = "app"; this.NS_ATOM = "atom"; this.NS_THR = "thr"; this.NS_UM = "um"; this.NS_XHTML = "xhtml"; this.NS_XML = "xml"; this.NS_XSI = "xsi"; this.NS_OPENSEARCH = "opensearch"; this.NS_CM = "cm"; this.NS_CA = "ca"; this.NS_AC = "ac"; this.NS_EVENT_DATATYPES = "event-datatypes"; this.NS_XMLNS = "xmlns"; this.NS_XSD = "xsd"; this.NS_JS = "js"; // name space URIs this.namespaces = {}; this.namespaces[this.NS_APP] = "http://www.w3.org/2007/app"; this.namespaces[this.NS_ATOM] = "http://www.w3.org/2005/Atom"; this.namespaces[this.NS_THR] = "http://purl.org/syndication/thread/1.0"; this.namespaces[this.NS_UM] = "http://www.ibm.com/xmlns/prod/websphere/um.xsd"; this.namespaces[this.NS_XHTML] = "http://www.w3.org/1999/xhtml"; this.namespaces[this.NS_XML] = "http://www.w3.org/XML/1998/namespace"; this.namespaces[this.NS_XSI] = "http://www.w3.org/2001/XMLSchema-instance"; this.namespaces[this.NS_XMLNS] = "http://www.w3.org/2000/xmlns/"; this.namespaces[this.NS_OPENSEARCH] = "http://a9.com/-/spec/opensearch/1.1/"; this.namespaces[this.NS_CM] = "http://www.ibm.com/xmlns/prod/composite-applications/v1.0"; this.namespaces[this.NS_CA] = "http://www.ibm.com/xmlns/prod/composite-applications/v1.0"; this.namespaces[this.NS_AC] = "http://www.ibm.com/xmlns/prod/lotus/access-control/v1.0"; this.namespaces[this.NS_EVENT_DATATYPES] = "http://www.ibm.com/xmlns/prod/lotus/mashups/event-datatypes"; this.namespaces[this.NS_XSD] = "http://www.w3.org/2001/XMLSchema"; this.namespaces[this.NS_JS] = "text/javascript"; }, /** * Returns an object with a property for each element in the * passed in array and the corresponding name space uri as value * @param {Array} prefixes */ getNameSpaces: function(prefixes) { var result = {}; var len = prefixes.length; for (var i=0; i dojo.doc.title = title.replace(/&/g,"&").replace(/"/g,"\"").replace(/>/g,">").replace(/</g,"<"); } }); com.ibm.mm.enabler.context.PageContext = new com.ibm.mm.enabler.context.PageContextImpl(); } if(!dojo._hasResource["com.ibm.mashups.enabler.context.PageContext"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.context.PageContext"] = true; dojo.provide("com.ibm.mashups.enabler.context.PageContext"); } if(!dojo._hasResource["com.ibm.mashups.enabler.context.Factory_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.context.Factory_API"] = true; dojo.provide("com.ibm.mashups.enabler.context.Factory_API"); dojo.provide("com.ibm.mashups.enabler.context.Factory"); /** * Factory to get context objects. * * @ibm-module Base2 */ dojo.declare("com.ibm.mashups.enabler.context.Factory", null, { /** * Returns a LocalizedContext. * * @ibm-api * * @return {com.ibm.mashups.enabler.context.LocalizedContext} localized context. */ getLocalizedContext: function(){ }, /** * Returns a LocalizedContext for the specified locales. * * @ibm-spi * * @param {String} preferredLocale preferred locale to use; optional, defaults to the preferred * locale set with the browser. * @param {String} defaultLocale default locale to use; optional, defaults to the locale "en" * @return {com.ibm.mashups.enabler.context.LocalizedContext} localized context for the specified locales. */ getLocalizedContext: function(preferredLocale, defaultLocale){ // JSLINT-IGNORE: separation between public API and SPI }, /** * Returns a PageContext. * * @ibm-spi * @since 2.4 * * @return {com.ibm.mashups.enabler.context.PageContext} the page context */ getPageContext: function(){ } }); } if(!dojo._hasResource["com.ibm.mm.enabler.context.FactoryImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.context.FactoryImpl"] = true; dojo.provide("com.ibm.mm.enabler.context.FactoryImpl"); // factory implementation dojo.declare( "com.ibm.mm.enabler.context.FactoryImpl", [com.ibm.mashups.enabler.context.Factory], { constructor:function () { }, getLocalizedContext: function(preferredLocale, defaultLocale) { return new com.ibm.mm.enabler.context.LocalizedContextImpl(preferredLocale, defaultLocale); }, getPageContext: function() { return new com.ibm.mm.enabler.context.PageContextImpl(); } } ); // factory singleton com.ibm.mashups.enabler.context.Factory = new com.ibm.mm.enabler.context.FactoryImpl(); } if(!dojo._hasResource["com.ibm.mashups.enabler.context.Factory"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.context.Factory"] = true; dojo.provide("com.ibm.mashups.enabler.context.Factory"); } if(!dojo._hasResource["com.ibm.mashups.enabler.services.ConfigConstants"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.services.ConfigConstants"] = true; dojo.provide("com.ibm.mashups.enabler.services.ConfigConstants"); /** * This constants class contains well defined constants available to the config service. * They are defined in the ConfigService.properties * @ibm-spi * @ibm-module Base2 */ dojo.declare("com.ibm.mashups.enabler.services.ConfigConstants", null, { /** * URL pointing to the proxy * @type String */ PROXY_URL: "com.ibm.mashups.proxy.url", /** * URL pointing to the hub * @type String */ HUB_URL: "com.ibm.mashups.hub.url", /** * URL pointing to login * @type String */ LOGIN_URL: "com.ibm.mashups.url.login", /** * URL pointing to logout * @type String */ LOGOUT_URL: "com.ibm.mashups.url.logout", /** * context root of the server * @type String */ CONTEXT_ROOT: "com.ibm.mashups.contextroot", /** * context root of the enabler component * @type String */ CONTEXT_ROOT_ENABLER: "com.ibm.mashups.contextroot.enabler", /** * context root of the builder component * @type String */ CONTEXT_ROOT_BUILDER: "com.ibm.mashups.contextroot.builder", /** * public name of the content handler servlet * @type String */ CONTENTHANDLER_PUBLIC: "com.ibm.mashups.contenthandler.public", /** * private name of the content handler servlet * @type String */ CONTENTHANDLER_PRIVATE: "com.ibm.mashups.contenthandler.private", /** * public name of the embedding handler servlet * @type String */ EMBEDDING_PUBLIC: "com.ibm.mashups.embedding.public", /** * private name of the content handler servlet * @type String */ EMBEDDING_PRIVATE: "com.ibm.mashups.embedding.private", /** * TBD * @type String */ THEMES_FEEDS_EXPIRATION: "themes.feed.expiration", /** * comma separated list of all available locales in the system * @type String */ AVAILABLE_LOCALES: "availableLocales", /** * the default locale of the mashups system * @type String */ DEFAULT_LOCALE: "default.locale", /** * the default locale that's based on user preference for UI components to display date,currency etc. * @type String */ DISPLAY_LOCALE: "displayLocale", /** * defines whether PUT/DELETE tunneling over POST should be used * @type String */ TUNNEL_MODE: "tunnel.mode", /** * turns on debugging * @type String */ CLIENT_IS_DEBUG: "isDebug", /** * BiDi setting * @type String */ CLIENT_IS_BIDI: "isBidi", /** * Definition Url list of the widgets which is sandbox disabled: /dataEditor/dataEditor.xml,id1,id2 * @type String */ WIDGETDEFID_SANDBOX_DISABLED: "com.ibm.mashups.sandbox.force.disable", /** * Trace configuration for the client runtime * @type String */ TRACE_CONFIG: "traceConfig", /** * tbd * @type String */ CLIENT_POPUP_CONSOLE: "popupConsole", /** * tbd * @type String */ CLIENT_ALLOW_PUBLISH_LOGGING: "allowPublishLogging", /** * tbd * @type String */ CLIENT_ALLOW_PUBLISH_TRACING: "allowPublishTracing", /** * tbd * @type String */ CLIENT_ADDITIONAL_SERVICES: "additionalServices", /** * Theme id used in case no theme is set. * @type String */ CLIENT_DEFAULT_THEME_ID: "com.ibm.mashups.theme.defaultThemeId", /** * tbd * @type String */ CLIENT_PAGE_SOURCE_READ_ONLY: "pageSourceReadOnly", /** * Group name used for auto accepting pages * @type String */ CLIENT_AUTO_ACCEPT_SHARED_GROUPNAME: "autoAcceptSharedGroupName", /** * Default value for page level auto wiring enablement * @type String */ AUTO_WIRING_DEFAULT_ENABLED: "autoWiringDefaultEnabled", /** * tbd * @type String */ CLIENT_USER_ID_KEY: "userIdKey", /** * tbd * @type String */ CLIENT_GROUP_CN_KEY: "groupCNKey", /** * Url used to fetch the service document * @type String */ SERVICE_DOCUMENT_URL: "serviceDocumentUrl", /** * turns on multipart support * @type String */ MULTIPART_ENABLED: "com.ibm.mashups.multipart.enabled", /** * if multipart support is enabled, determines if requests are correlated * by hostname * @type String */ MULTIPART_CORRELATE_HOSTS: "com.ibm.mashups.multipart.correlatehosts", /** * if multipart support is enabled, should URLs with query strings be * considered cacheable * @type String */ MULTIPART_CACHE_QUERIES: "com.ibm.mashups.multipart.cachequeries", /** * Returns the semicolon separated list of Endpoint IDs * @type String */ ENDPOINTS: "endpointIDs", /** * Returns the name of the Endpoints Config Provider * @type String */ ENDPOINT_CONFIG_PROVIDER: "Endpoints", /** * Returns the name of the Anonymous User Config setting * @type {String} */ ANONYMOUS_USER: "anonymousUser", /** * MetaData name used to recognize whether a page is hidden or not * @type String */ NAVIGATION_HIDDEN: "com.ibm.mashups.navigation.hidden", /** * MetaData name used to recognize whether a space is hidden or not * @type String */ SPACE_HIDDEN: "com.ibm.mashups.space.hidden", /** * Returns the name of the current User Config setting * @type String */ USER: "user", /** * Returns the name of subdomains Config setting, subdomains are used to create sandboxed iwidgets * @type String */ SUBDOMAINS: "subdomains", /** * Returns the name of server domain Config setting * @type String */ SERVERDOMAIN: "serverdomain", /** * Returns the name of sandboxenabled Config setting, sandboxed feature is disabled if this configuration is set to false * @type String */ SANDBOXENABLED: "sandboxenabled", /** * Returns the name of config setting that decides if subdomain should be reused when an existing sandboxed iwidget is removed from the page. * @type String */ SUBDOMAINREUSE: "subdomainreuse", /** * MetaData name used to indicate attributes that need to added to url * @type String */ NAVSTATE_PERSISTENCE_URL: "navstate.persistence.url", /** * MetaData name used to indicate attributes that need to added to persistence store * @type String */ NAVSTATE_PERSISTENCE_PSTORE: "navstate.persistence.pstore", /** * MetaData name used to indicate number of widgets whose navigation state will be added to url * @type String */ NAVSTATE_PERSISTENCE_URL_LIMIT: "navstate.persistence.url.limit", /** * MetaData name used to indicate number of sharedparametersets whose navigation state will be added to url * @type String */ NAVSTATE_PERSISTENCE_URL_SPLIMIT: "navstate.persistence.url.splimit", /** * MetaData name used to indicate if navigation state is huffmann encoded or not * @type String */ NAVSTATE_HUFFMANNENCODE_ENABLED: "navstate.huffmannencode.enabled", /** * MetaData name used to indicate the html fragment that's displayed when a widget is under loading * @type String */ LOADING_HTML: "loadingHTML", /** * Specified whether pageloading should be optimized (Multipart) * @type String */ PAGE_LOAD_OPTIMIZATION: "pageLoadOptimization", /** * Specified whether pageloading should be optimized for themes (Multipart) * @type String */ PAGE_LOAD_OPTIMIZATION_THEME: "pageLoadOptimizationTheme", /** * Specifies whether application widgets should be optimized (Multipart) * @type String */ PAGE_LOAD_OPTIMIZATION_APP_WIDGETS: "pageLoadOptimizationAppWidgets", /** * Allows to create New Spaces and Pages for anonymous users * @type String */ ANONYMOUS_ALLOW_CREATE: "com.ibm.mashups.anonymous.allow.create", /** * If displayName is not sent from server use this property for User Display Name * @type String */ DEFAULT_USER_DISPLAY_PROP: "com.ibm.mashups.default.user.display.prop", /** * The product name which will show up in the browser title, other product can replace it. * @type String */ PRODUCT_NAME: "com.ibm.mashups.productname", /** * If displayName is not sent from server use this property for Group Display Name * @type String */ DEFAULT_GROUP_DISPLAY_PROP: "com.ibm.mashups.default.group.display.prop", /** * The unique name of the welcome space * @type String */ WELCOME_SPACE_ID: "com.ibm.mashups.welcome.space.name", /** * The filter as regexp for characters used on page and space title. * @type String */ BUILDER_TITLE_FILTER_REGEXP : "com.ibm.mashups.builder.filter.title.regexp", /** * ID of the Anonymous Virtual User * @type String */ ANON_VIRTUAL_USER_ID : "com.ibm.mashups.anonUserId", /** * ID of the All Authenticated Users Virtual Group * @type String */ ALL_AUTH_VIRTUAL_GROUP_ID : "com.ibm.mashups.allAuthGroupId", /** * The server type this enabler is connected to. It can be either SERVER_TYPE_MASHUPS or SERVER_TYPE_PORTAL * @type String */ SERVER_TYPE : "com.ibm.mashups.server", /** * The server type value for Lotus Mashups * @type String */ SERVER_TYPE_MASHUPS : "Lotus_Mashups", /** * The server type value for WebSphere Portal * @type String */ SERVER_TYPE_PORTAL : "WebSphere_Portal", /** * The server type value for Business Space */ SERVER_TYPE_BSPACE : "Business_Space", /** * Anonymous mode enabled default is false * @type String */ ANON_MODE_ENABLED : "com.ibm.mashups.anonymous.mode", /** * Setting to true will prevent search clients for automatically adding wildcards * to user and group searches. Default is false. * @type String */ AUTO_WILDCARD_DISABLED : "com.ibm.mashups.autoWildcardSearchDisabled", /** * Sets the name of the property in the ContextMenu_Provider to use for the * context menu * @type String */ CONTEXT_MENU_NAME : "com.ibm.mashups.contextmenu.name", WIDGET_BUILDER_ENABLED : "com.ibm.mashups.widgetBuilder.enabled", CREATE_SPACE_TEMPLATE_MODE: "createSpaceOnTemplateMode", FAVORITE_SPACES_MAXIMUM_NUMBER: "favorite.spaces.maximum.number", RECENT_SPACES_MAXIMUM_NUMBER: "recent.spaces.maximum.number", /** * Register resources that's preloaded with enabler so enabler won't load it anymore * For example: * [{globalid: "lconn.coreUtilities", version: "2.5"}, {globalid: "lconn.coreCSS", version: "2.5"}] * @type String */ REGISTER_LOADEDRESOURCES:"register.loadedresources", /** * Defines the persistence mode that should be used by the iContext. Default is DOM. */ PERSISTENCE_MODE: "com.ibm.mashups.enabler.icontext.persistence.mode", /** * Defines the read-only persistence mode for the event provider that is used by the iContext. It overwrites any mode defined as part of PERSISTENCE_MODE.Default is DOM. */ PERSISTENCE_MODE_EVENTS: "com.ibm.mashups.enabler.icontext.persistence.mode.events", /** * Defines the modifiable persistence mode for the event provider that is used by the iContext. It overwrites any mode defined as part of PERSISTENCE_MODE.Default is DOM. */ PERSISTENCE_MODE_EVENTS_MODIFIABLE: "com.ibm.mashups.enabler.icontext.persistence.mode.events.modifiable", /** * Defines the read-only persistence mode for the wire provider that is used by the iContext. It overwrites any mode defined as part of PERSISTENCE_MODE.Default is DOM. */ PERSISTENCE_MODE_WIRES: "com.ibm.mashups.enabler.icontext.persistence.mode.wires", /** * Defines the modifiable persistence mode for the wire provider that is used by the iContext. It overwrites any mode defined as part of PERSISTENCE_MODE.Default is DOM. */ PERSISTENCE_MODE_WIRES_MODIFIABLE: "com.ibm.mashups.enabler.icontext.persistence.mode.wires.modifiable", /** * Defines the read-only persistence mode for the attributes provider that is used by the iContext. It overwrites any mode defined as part of PERSISTENCE_MODE.Default is DOM. */ PERSISTENCE_MODE_ATTRIBUTES: "com.ibm.mashups.enabler.icontext.persistence.mode.attributes", /** * Defines the modifiable persistence mode for the attributes provider that is used by the iContext. It overwrites any mode defined as part of PERSISTENCE_MODE.Default is DOM. */ PERSISTENCE_MODE_ATTRIBUTES_MODIFIABLE: "com.ibm.mashups.enabler.icontext.persistence.mode.attributes.modifiable", /** * Defines whether the json attributes implementation will be injecting the attributes defined in the widget xml * as well into the attributes map. This will only apply if the json attributes have been enabled through the PERSISTENCE_MODE_ATTRIBUTES setting. */ PERSISTENCE_MODE_ATTRIBUTES_JSON_INJECTXML: "com.ibm.mashups.enabler.icontext.attributes.json.injectxml", /** * Defines whether autocommit is enabled on the iContext. If set to true the iContext will automatically commit data to the * backend if commit is called on e.g. the iWidgetAttributes. */ ICONTEXT_AUTO_COMMIT: "com.ibm.mashups.enabler.icontext.autocommit", ID_PREFIX: "com.ibm.mashups.iWidget.idPrefix", /** * Defines how violations of enabler usage is prompted to the user; see *
    *
  • API_ENFORCEMENT_MODE_WARN
  • *
  • API_ENFORCEMENT_MODE_ERROR
  • *
* Defaults to API_ENFORCEMENT_MODE_WARN. * @type String * @private */ API_ENFORCEMENT_MODE: "com.ibm.mashups.enabler.enforcement", /** * Warnings will be prompted in the console denoting usage errors of the enabler api. * @type String * @private */ API_ENFORCEMENT_MODE_WARN: "warning", /** * Errors will be thrown denoting usage errors of the enabler api, note that * this potentially breaks the driver if the api is used incorrectly. * @type String * @private */ API_ENFORCEMENT_MODE_ERROR: "error", /** * With this option the location (a URL) of the widget which will be displayed for non previewable content can be defined. * If empty (thats the default) the widget delivered with the enabler will be used. * * @since 3.0 * @type String */ NON_PREVIEWABLE_WIDGET_LOCATION: "com.ibm.mashups.enabler.layout.widget.NonPreviewableContentWidget.location", /** * Size limit of page descriptions, implied from persistence * @since 3.0 * @type String */ LIMIT_PAGE_DESCRIPTION: "com.ibm.mashups.persistence.page.description.limit", /** * Defines whether personalize is allowed or not for users. Defaults to true. * @since 3.0 * @type Boolean */ WIDGET_PERSONALIZE_ENABLED: "com.ibm.mashups.widget.attributes.personalize.enabled", /** * Defines maximum page number when creating page base on page from hub. Defaults to 50. * @since 3.0 * @type String */ SPACEMANAGER_PAGE_QUERYCOUNT : "com.ibm.mashups.spacemanager.page.queryCount", /** * Defines the search keyword when pages in hub are queried. Keep it empty will return all pages. * @since 3.0 * @type String */ SPACEMANAGER_PAGE_QUERYKEYWORD : "com.ibm.mashups.spacemanager.page.queryKeyword", /** * Defines maximum space number when creating space base on space from hub. Defaults to 50. * @since 3.0 * @type String */ SPACEMANAGER_SPACE_QUERYCOUNT : "com.ibm.mashups.spacemanager.spacetemplate.queryCount", /** * Defines the search keyword when spaces in hub are queried. Keep it empty will return all spaces. * @since 3.0 * @type String */ SPACEMANAGER_SPACE_QUERYKEYWORD : "com.ibm.mashups.spacemanager.spacetemplate.queryKeyword", /** * Defines the search keyword when spaces in hub are queried. Keep it empty will return all spaces. * @since 3.0 * @type String */ LOCALAPPS_REGEX : "com.ibm.mashups.multipart.localapps.regex", /** * Defines the format (as a regular expression) of the server side object IDs. * @since 3.0 * @type String */ SERVER_OBJECT_ID_FORMAT: "com.ibm.mashups.server.oid.format", /** * Defines whether to use queued widget rendering. Default to true. * @since 3.0.0.1 * @type Boolean */ QUEUE_RENDERING: "com.ibm.mashups.queueRendering" }); com.ibm.mashups.enabler.services.ConfigConstants = new com.ibm.mashups.enabler.services.ConfigConstants(); } if(!dojo._hasResource["com.ibm.mashups.enabler.services.ConfigObject_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.services.ConfigObject_API"] = true; dojo.provide("com.ibm.mashups.enabler.services.ConfigObject_API"); dojo.provide("com.ibm.mashups.enabler.services.ConfigObject"); /** * The Config Object allows to access config variables as defined by the system. * for a specific config provider. * @ibm-spi * @ibm-module Base2 */ dojo.declare("com.ibm.mashups.enabler.services.ConfigObject", null, { /** * This method returns the value of the config variable as defined by the system * @param {String} name the name of the config variable * @return {String} the value of the config variable. Maybe be NULL. */ getValue: function(name) { return null; }, /** * This method returns the value of the config variable as defined by the system in a async way * @param {String} name the name of the config variable * @return {com.ibm.mashups.enabler.Deferred} a deferred object used to start this operation. The return value * when executed through the deferred object is the value of the config variable. Maybe be NULL */ getValueDeferred: function(name) { return null; } }); } if(!dojo._hasResource["com.ibm.mm.enabler.services.ConfigObjectDefaultImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.services.ConfigObjectDefaultImpl"] = true; dojo.provide("com.ibm.mm.enabler.services.ConfigObjectDefaultImpl"); dojo.declare("com.ibm.mm.enabler.services.ConfigObjectDefaultImpl", [com.ibm.mashups.enabler.services.ConfigObject], { constructor: function(provider, configService) { this.provider = provider; this.configService = configService; this.ns = {}; this.ns.app = "http://www.w3.org/2007/app"; this.ns.atom = "http://www.w3.org/2005/Atom"; }, /** * @deprecated */ getPreferenceValue: function( /*string*/name) { if (this.provider == "all") { return this.configService.getValue(name); } else { return this._getValue(this.provider, name); } return null; }, getValue: function( /*string*/name) { if (this.provider == "all") { return this.configService.getValue(name, internal); } else { return this._getValue(this.provider, name); } return null; }, _getValue: function(/*string*/provider, /*string*/ name) { return null; }, getValueDeferred: function(/*string*/name){ if (this.provider == "all") { return new com.ibm.mm.enabler.DeferredImpl(this, function(deferred, sync, name) { var callBack = deferred.getFinishedCallback(); var retValue = this.configService.getValue(name, internal); if (retValue && callBack ) { callBack(retValue, com.ibm.mm.enabler.model.HttpStatusCodes.HTTP_OK, deferred.getFinishedCallbackParameters()); } return retValue; }); } else { return this._getValueDeferred(this.provider, name); } }, _getValueDeferred: function(/*string*/provider, /*string*/ name) { return null; } }); // IMPORTANT // ibmConfig.enablerLayerModules is a comma separated string of all supported modules at runtime // This section dynamically loads the Extended representation when the variable enablerLayerModules contains the given module if ((ibmConfig.enablerLayerModules) && (dojo.indexOf(ibmConfig.enablerLayerModules, "Base")>=0)) { dojo["require"]("com.ibm.mm.enabler.services.ConfigObjectExtendedImpl"); // JSLINT-IGNORE: This needs to be done to allow modularization and to support the minimal layer } } if(!dojo._hasResource["com.ibm.mashups.enabler.services.ConfigObject"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.services.ConfigObject"] = true; dojo.provide("com.ibm.mashups.enabler.services.ConfigObject"); } if(!dojo._hasResource["com.ibm.mashups.enabler.services.ConfigService_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.services.ConfigService_API"] = true; dojo.provide("com.ibm.mashups.enabler.services.ConfigService_API"); dojo.provide("com.ibm.mashups.enabler.services.ConfigService"); /** * The Config Service allows to access config variables as defined by the system. * The service can be retrieved using the following code:
* var configService = com.ibm.mashups.services.ServiceManager.getService(
*     com.ibm.mashups.enabler.services.ConfigService.SERVICE_NAME);

* @ibm-spi * @ibm-module Base2 */ dojo.declare("com.ibm.mashups.enabler.services.ConfigService", null, { /** * The service name to be used to fetch the service from the ServiceManager * @type String */ SERVICE_NAME: "configService", /** * This method returns the value of the config variable as defined by the system * @param {String} name the name of the config variable * @return {String} the value of the config variable. Maybe be NULL. */ getValue: function(name) { return null; }, /** * This method returns the value of the config object for a config provider * @param {String} name the name of the config provider * @return {com.ibm.mashups.enabler.services.ConfigObject} the config provider. Maybe be NULL. */ getConfigObject: function(name) { return null; }, /** * This method returns the Config Provider names. Each Config Provider will * have a corresponding ConfigObject. * @return {String[]} the config provider names. Never NULL. */ getConfigProviderNames: function() { return null; } }); // make sure we can reference this globally com.ibm.mashups.enabler.services.ConfigService.SERVICE_NAME = "configService"; } if(!dojo._hasResource["com.ibm.mashups.services.ServiceManager_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.services.ServiceManager_API"] = true; dojo.provide("com.ibm.mashups.services.ServiceManager_API"); dojo.provide("com.ibm.mashups.services.ServiceManager"); /** * This interface manages services that are provided to the system, i.e. to iWidgets and other components.
* It provides capability to access Services in Lotus Mashups.
* By default EventService and ConfigService are provided.
* Page components are able to use event services by using following api:

* var eventService = com.ibm.mashups.services.ServiceManager.getService(
*     com.ibm.mashups.iwidget.services.EventService.SERVICE_NAME);

*

* Configuration of services:
* This section describes how each service is configured and how additional services can be added.

* * Through the ConfigService.properties one can define an additional property named "additionalServices" * defining additional services besides EventService and ConfigService.

* Each entry should have the following format.

* "name": service name.
* "path": url that point to the service js file.
* "baseClass": the class that implements the service. one instance of this class will be generated.
*

* Example:
*    additionalServices = [
*    { "name":"SecurityService",
*      "path":"/mum/js/com/ibm/enabler/iw/securityservices.js",
*      "baseClass":"com.ibm.mm.iwidget.services.SecurityService"}
*    ]

* * @ibm-spi * @ibm-module Base2 */ dojo.declare("com.ibm.mashups.services.ServiceManager",null, { /** * @private */ constructor:function(){ }, /** This interface allow page components to get the required service. @param{String} serviceName required service name that's used to uniquely identify a service . @type Object @returns{Object} an instance of required service. NULL if configured incorrectly. */ getService:function(serviceName) { } } ); } if(!dojo._hasResource["com.ibm.mashups.services.ServiceManager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.services.ServiceManager"] = true; dojo.provide("com.ibm.mashups.services.ServiceManager"); } if(!dojo._hasResource["com.ibm.mm.services.ServiceManagerImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.services.ServiceManagerImpl"] = true; dojo.provide("com.ibm.mm.services.ServiceManagerImpl"); dojo.declare("com.ibm.mm.services.ServiceManagerImpl", com.ibm.mashups.services.ServiceManager, { constructor: function() { this._serviceEntries = {}; //allow overwritten if ibmConfig.loadServices is set ibmConfig = ibmConfig || {}; ibmConfig.additionalServices = ibmConfig.additionalServices || null; if (ibmConfig.additionalServices) { var entries = dojo.fromJson(ibmConfig.additionalServices); for (var i in entries) { if (Object.prototype.hasOwnProperty.call(entries,i)) { var anEntry = entries[i]; this._serviceEntries[anEntry.name] = anEntry; } } } }, getService: function(serviceName) { var serviceEntry = this._serviceEntries[serviceName]; serviceEntry = serviceEntry || null; if (serviceEntry !== null) { var serviceHandler = serviceEntry.serviceHandler; serviceHandler = serviceHandler || null; if (serviceHandler === null) { // assume js is already loaded, create service object serviceHandler = this._createService(serviceEntry); serviceHandler = serviceHandler || null; if (serviceHandler === null) { this._loadScript(serviceEntry); // serviceHandler = this._createService(serviceEntry); } else { this._serviceEntries[serviceName].serviceHandler = serviceHandler; } } } return this._serviceEntries[serviceName].serviceHandler; }, //if serviceHandler is String, then it's baseClass //if it's object, then it's the service handler instance setService: function(serviceName, serviceHandler) { serviceHandler = serviceHandler || null; if (serviceHandler === null) { return null; } //create new service or overwrite an existing service var serviceEntry = this._serviceEntries[serviceName]; serviceEntry = serviceEntry || null; if (serviceEntry !== null) { delete this._serviceEntries[serviceName]; } if (!this._serviceEntries[serviceName]) { this._serviceEntries[serviceName] = {}; } if (dojo.isString(serviceHandler)) { this._serviceEntries[serviceName].baseClass = serviceHandler; } else { this._serviceEntries[serviceName].serviceHandler = serviceHandler; } }, _loadScript: function(serviceEntry) { var me = this; dojo.xhrGet({ url: serviceEntry.path, handleAs: "text", sync: true, load: function(result) { dojo.eval(result); // JSLINT-IGNORE: We have to evaluate the services JavaScript in this case var serviceHandler = me._createService(serviceEntry); if (typeof serviceHandler != "undefined" && serviceHandler !== null) { var serviceName = serviceEntry.name; serviceEntry.serviceHandler = serviceHandler; } }, error: function(data, ioArgs) { } }); }, _createService: function(serviceEntry) { var service = null; try { service = new (dojo.getObject(serviceEntry.baseClass))(); } catch (err) { } return service; } }); com.ibm.mashups.services.ServiceManager = new com.ibm.mm.services.ServiceManagerImpl(); } if(!dojo._hasResource["com.ibm.mm.enabler.services.AbstractConfigServiceImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.services.AbstractConfigServiceImpl"] = true; dojo.provide("com.ibm.mm.enabler.services.AbstractConfigServiceImpl"); dojo.declare("com.ibm.mm.enabler.services.AbstractConfigServiceImpl", com.ibm.mashups.enabler.services.ConfigService, { constructor: function(){ }, /** * @deprecated */ getPreferenceValue: function( /*string*/name){ return this.getValue(name); }, getValue: function( /*string*/name, internal){ var value = ibmConfig[name]; return value; }, getConfigObject: function(/*string*/configProvider){ return null; }, getConfigProviderNames: function(){ return null; } }); } if(!dojo._hasResource["com.ibm.mm.enabler.services.ConfigServiceDefaultImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.services.ConfigServiceDefaultImpl"] = true; dojo.provide("com.ibm.mm.enabler.services.ConfigServiceDefaultImpl"); // inject this service into the ServiceManager at the end. Therefore we have to require the implementation // // // dojo.declare("com.ibm.mm.enabler.services.ConfigServiceDefaultImpl", [com.ibm.mm.enabler.services.AbstractConfigServiceImpl], { constructor: function() { }, _getConfigObject: function(/*string*/configProvider) { if (!ibmConfig["CO_" + configProvider]) { var co = new com.ibm.mm.enabler.services.ConfigObjectDefaultImpl(configProvider, this); ibmConfig["CO_" + configProvider] = co; } return ibmConfig["CO_" + configProvider]; }, _getConfigProviderNames: function() { var ret = []; ret.push("all"); return ret; }, getValue: function(name) { var ret = this.inherited(arguments, [name, true]); return ret; }, getConfigObject: function(name) { var ret = this._getConfigObject(name); return ret; }, getConfigProviderNames: function() { var ret = this._getConfigProviderNames(); return ret; } }); com.ibm.mashups.services.ServiceManager.setService("configService", "com.ibm.mm.enabler.services.ConfigServiceDefaultImpl"); // IMPORTANT // ibmConfig.enablerLayerModules is a comma separated string of all supported modules at runtime // This section dynamically loads the Extended representation when the variable enablerLayerModules contains the given module if ((ibmConfig.enablerLayerModules) && (dojo.indexOf(ibmConfig.enablerLayerModules, "Base")>=0)) { dojo["require"]("com.ibm.mm.enabler.services.ConfigServiceExtendedImpl"); // JSLINT-IGNORE: This needs to be done to allow modularization and to support the minimal layer } } if(!dojo._hasResource["com.ibm.mashups.enabler.services.ConfigService"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.services.ConfigService"] = true; dojo.provide("com.ibm.mashups.enabler.services.ConfigService"); } if(!dojo._hasResource["com.ibm.mashups.enabler.utils.EndpointHelper_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.utils.EndpointHelper_API"] = true; dojo.provide("com.ibm.mashups.enabler.utils.EndpointHelper_API"); dojo.provide("com.ibm.mashups.enabler.utils.EndpointHelper"); /** * Helper utility for endpoint encoded urls. * * @ibm-module Base2 * TODO: Change/Remove */ dojo.declare("com.ibm.mashups.enabler.utils.EndpointHelper", null, { /** * This method resolves endpoint://{endpointid}/relativeurl * * @param {String} url the url to resolve for endpoints * @return {String} the url with endpoints resolved */ resolve: function(url) { return null; } }); } if(!dojo._hasResource["com.ibm.mm.enabler.EndpointUtils"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.EndpointUtils"] = true; dojo.provide("com.ibm.mm.enabler.EndpointUtils"); dojo.declare("com.ibm.mm.enabler.EndpointUtilsDefaultImpl", null, { constructor: function(){ }, checkForEndpoints: function(/*String*/url){ return null; } }); com.ibm.mm.enabler.EndpointUtils = new com.ibm.mm.enabler.EndpointUtilsDefaultImpl(); // IMPORTANT // ibmConfig.enablerLayerModules is a comma separated string of all supported modules at runtime // This section dynamically loads the Extended representation when the variable enablerLayerModules contains the given module if ((ibmConfig.enablerLayerModules) && (dojo.indexOf(ibmConfig.enablerLayerModules, "iWidget")>=0)) { dojo["require"]("com.ibm.mm.enabler.EndpointUtilsExtendedImpl"); // JSLINT-IGNORE: This needs to be done to allow modularization and to support the minimal layer } } if(!dojo._hasResource["com.ibm.mm.enabler.utils.EndpointHelperImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.utils.EndpointHelperImpl"] = true; dojo.provide("com.ibm.mm.enabler.utils.EndpointHelperImpl"); dojo.declare("com.ibm.mm.enabler.utils.EndpointHelperImpl", null, { resolve: function(url) { if (!url) { return url; } var url2 = com.ibm.mm.enabler.EndpointUtils.checkForEndpoints(url); if (url2) { return url2; } return url; } } ); com.ibm.mashups.enabler.utils.EndpointHelper = new com.ibm.mm.enabler.utils.EndpointHelperImpl(); } if(!dojo._hasResource["com.ibm.mashups.enabler.utils.EndpointHelper"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.utils.EndpointHelper"] = true; dojo.provide("com.ibm.mashups.enabler.utils.EndpointHelper"); } if(!dojo._hasResource["com.ibm.mashups.enabler.utils.URLHelper_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.utils.URLHelper_API"] = true; dojo.provide("com.ibm.mashups.enabler.utils.URLHelper_API"); dojo.provide("com.ibm.mashups.enabler.utils.URLHelper"); /** * Helper utility for encoding urls. * * @ibm-module Base2 */ dojo.declare("com.ibm.mashups.enabler.utils.URLHelper", null, { /** * This method rewrites a url and takes care for instance to proxify the given url * * @ibm-api * * @param {String} url the url to rewrite * @return {String} the encoded url */ rewriteURL: function(targetUrl){ return null; } }); } if(!dojo._hasResource["com.ibm.mm.enabler.utils.Misc"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.utils.Misc"] = true; dojo.provide("com.ibm.mm.enabler.utils.Misc"); com.ibm.mm.enabler.utils.Misc = { /** * Example usage: * * * * var myObj = {a: 1, b: "bla", c: function(){}}; * * com.ibm.mm.enabler.utils.Misc.forIn(myObj,function(item,idx,arr) { * console.debug(arguments); * }); * // prints: * // [1, "a", Object { a=1, more...}] * // ["bla", "b", Object { a=1, more...}] * // [function(), "c", Object { a=1, more...}] * * * var myScope = { * count: 0, * f: function(item,idx,arr) { * this.count++; * } * } * com.ibm.mm.enabler.utils.Misc.forIn(myObj,'f',myScope); * * console.debug(myScope.count); // prints: 3 * @param {Object} obj The object to iterate over * @param {Function|String} func The function to call on each object with three parameters: value, key, object * @param {Object} scope Optional, the scope to call the function on. */ forIn: function(obj, func, scope) { if(!obj || typeof obj != "object") { return; } scope = scope || null; var item; for(var idx in obj) { if(Object.prototype.hasOwnProperty.call(obj,idx)) { item = obj[idx]; dojo.hitch(scope,func)(item,idx,obj); } } }, encodePath: function(path, decoded) { if (path.length === 0) { return path; } var parts = path.split("/"); for (var i=0; i 0) { if (urlString.indexOf("/") === 0) { return false; } if (urlString.indexOf("?") === 0) { return false; } var schema = urlString.substring(0, urlString.indexOf(":")); if (!supportedSchema[schema]) { rc = true; } } return rc; } }; } if(!dojo._hasResource["com.ibm.mm.enabler.utils.HttpUrl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.utils.HttpUrl"] = true; dojo.provide("com.ibm.mm.enabler.utils.HttpUrl"); dojo.declare("com.ibm.mm.enabler.utils.HttpUrl", null, { constructor: function( /*String*/urlString, /*boolean*/ resolveEndpoints){ if (resolveEndpoints !== false) { var resolved = com.ibm.mm.enabler.EndpointUtils.checkForEndpoints(urlString); if (resolved) { urlString = resolved; } } this.pocurl = this._resolvePocUrl(urlString); if (!this.pocurl) { this.scheme = this._extractScheme(urlString); this.server = this._extractServer(urlString); this.port = this._extractPort(urlString); this.path = this._extractPath(urlString); this.parameters = this._extractQuery(urlString); this.anchor = this._extractAnchor(urlString); } }, _resolvePocUrl: function(urlString){ var rv = null; if (com.ibm.mm.enabler.utils.Misc.isPocUrl(urlString)) { var prefix = this._getPrefix(); urlString = escape(unescape(urlString)); // encode before adding as parameter rv = prefix.concat(urlString); } return rv; }, _getPrefix: function(){ var cs = com.ibm.mashups.services.ServiceManager.getService(com.ibm.mashups.enabler.services.ConfigService.SERVICE_NAME); var serverRoot = cs.getValue(com.ibm.mashups.enabler.services.ConfigConstants.CONTEXT_ROOT); var anonymousUser = cs.getValue(com.ibm.mashups.enabler.services.ConfigConstants.ANONYMOUS_USER); var contenthandlerPath; if (anonymousUser) { contenthandlerPath = cs.getValue(com.ibm.mashups.enabler.services.ConfigConstants.CONTENTHANDLER_PUBLIC); } else { contenthandlerPath = cs.getValue(com.ibm.mashups.enabler.services.ConfigConstants.CONTENTHANDLER_PRIVATE); } var rv = serverRoot.concat(contenthandlerPath).concat("?uri="); return rv; }, addParameter: function( /*String*/name, /*String*/ value){ if (dojo.isString(this.parameters[name])) { this.parameters[name] = [this.parameters[name], value]; } else if (dojo.isArray(this.parameters[name])) { this.parameters[name].push(value); } else { this.parameters[name] = value; } }, setParameter: function(/*String*/name, /*Object*/ value){ if (!this.parameters) { this.parameters = {}; } this.parameters[name] = value; }, getParameter: function(/*String*/name){ if (!this.parameters) { return false; } return this.parameters[name]; }, getParameters: function(){ return this.parameters; }, isProxyNeeded: function(){ var loc = document.location; // first test the scheme: if (loc.protocol != this.scheme) { return true; } // test the host if (!this._equalsServer(loc.hostname)) { return true; } // simplest case, ports are the same, return false if (loc.port == this.port) { return false; } var defaultPort; // tests for http with default port if (this.scheme == "http:") { defaultPort = "80"; if ((loc.port == "" && this.port == defaultPort) || (loc.port == defaultPort && this.port == "")) { return false; } } // tests for https with default port if (this.scheme == "https:") { defaultPort = "443"; if ((loc.port == "" && this.port == defaultPort) || (loc.port == defaultPort && this.port == "")) { return false; } } return true; }, toServerRelativeString: function(decoded){ if (this.pocurl) { return this.pocurl; } var str = ""; if (this.path != "") { str += "/" + com.ibm.mm.enabler.utils.Misc.encodePath(this.path, decoded); } if (!com.ibm.mm.enabler.utils.Misc.isEmpty(this.parameters)) { str += "?" + (decoded ? this._parametersToQuery(this.parameters) : dojo.objectToQuery(this.parameters)); } if (this.anchor != "") { str += "#" + this.anchor; } return str; }, toProxifiedString: function(){ //check if we need the proxy if (this.pocurl) { return this.pocurl; } if (typeof ibmConfig == 'undefined') { return this.toString(); } var newURL = com.ibm.mashups.services.ServiceManager.getService(com.ibm.mashups.enabler.services.ConfigService.SERVICE_NAME).getValue(com.ibm.mashups.enabler.services.ConfigConstants.PROXY_URL); if (!newURL) { return this.toString(); } newURL += "/"; if (window.location.protocol == this.scheme && this._equalsServer(window.location.hostname)) { if (window.location.port == this.port) { return this.toString(); } else if (this.scheme == "http:" && window.location.port == "" && this.port == "80") { return this.toString(); } else if (this.scheme == "https:" && window.location.port == "" && this.port == "443") { return this.toString(); } else if (this.scheme == "http:" && window.location.port == "80" && this.port == "") { return this.toString(); } else if (this.scheme == "https:" && window.location.port == "443" && this.port == "") { return this.toString(); } } // rewrite if (this.scheme == "https:") { newURL += "https/" + this.server + ((this.port != "443" && this.port != "") ? ":" + this.port : ""); } else { newURL += "http/" + this.server + ((this.port != "80" && this.port != "") ? ":" + this.port : ""); } // add the slash portion in ANY case newURL += "/"; if (this.path != "") { newURL += com.ibm.mm.enabler.utils.Misc.encodePath(this.path); } if (!com.ibm.mm.enabler.utils.Misc.isEmpty(this.parameters)) { newURL += "?" + dojo.objectToQuery(this.parameters); } if (this.anchor != "") { newURL += "#" + this.anchor; } return newURL; }, toString: function(decoded){ if (this.pocurl) { return this.pocurl; } var str = ""; //safari doesn't support url normalization on xhr request if (this.server != "") { str += this.scheme + "//" + this.server; if (this.port != "") { if (this.scheme == "http:" && this.port == "80") { str += ""; } else if (this.scheme == "https:" && this.port == "443") { str += ""; } else { str += ":" + this.port; } } } // add the slash portion in ANY case str += "/"; if (this.path != "") { str += com.ibm.mm.enabler.utils.Misc.encodePath(this.path, decoded); } if (!com.ibm.mm.enabler.utils.Misc.isEmpty(this.parameters)) { str += "?" + (decoded ? this._parametersToQuery(this.parameters) : dojo.objectToQuery(this.parameters)); } if (this.anchor != "") { str += "#" + this.anchor; } return str; }, _parametersToQuery: function(params){ var str = ""; // concatenation function (defined outside of the for-loop) var fn = function(value){ str += k + "=" + value + "&"; }; for (var k in params) { // concatenate parameters if (dojo.isArray(params[k])) { dojo.forEach(params[k], fn); } else { fn(params[k]); } } // remove trailing ampersand if (str.lastIndexOf('&') === str.length - 1) { str = str.substr(0, str.length - 1); } return str; }, _isAbsolute: function(){ return this._absoluteURL; }, _extractScheme: function(/*String*/urlString){ // important check as :// may appear as query parameter and then below logic doesn't work in case it is a relative URL var isRelative = urlString.indexOf("/") === 0; if (isRelative) { return window.location.protocol; // location.protocol returns the protocol like http: or https: } var indexOfScheme = urlString.indexOf("://"); if (indexOfScheme == -1) { this._absoluteURL = false; return window.location.protocol; // location.protocol returns the protocol like http: or https: } this._absoluteURL = true; return urlString.substring(0, indexOfScheme + 1); }, _extractServer: function(/*String*/urlString){ var indexOfScheme = urlString.indexOf(this.scheme); var retVal = ""; if (indexOfScheme === 0) { var serverAndPort; var indexOfSlash = urlString.indexOf("/", indexOfScheme + this.scheme.length + 2); if (indexOfSlash != -1) { serverAndPort = urlString.substring(indexOfScheme + this.scheme.length + 2, indexOfSlash); } else { serverAndPort = urlString.substring(indexOfScheme + this.scheme.length + 2); } retVal = serverAndPort.split(":")[0]; } else { var hostname = window.location.hostname; retVal = this._isIPv6(hostname) ? "[" + hostname + "]" : hostname; } return retVal; }, _extractPort: function(/*String*/urlString){ var indexOfServer = urlString.indexOf(this.server); var retVal = ""; if (indexOfServer >= 0) { var serverAndPort; var indexOfSlash = urlString.indexOf("/", indexOfServer); if (indexOfSlash != -1) { serverAndPort = urlString.substring(indexOfServer, indexOfSlash); } else { serverAndPort = urlString.substring(indexOfServer); } var serverAndPortParts = serverAndPort.split(":"); if (serverAndPortParts.length > 1) { retVal = serverAndPortParts[1]; } } if (retVal == "") { if (urlString.indexOf("/") === 0) { retVal = window.location.port; } else { retVal = ""; } } return retVal; }, _extractPath: function( /*String*/urlString){ var indexOfScheme = urlString.indexOf(this.scheme); var startIndex = 0; if (indexOfScheme === 0) { startIndex = this.scheme.length + 2; } var retVal = ""; var indexOfSlash = urlString.indexOf("/", startIndex); var indexOfQuery = urlString.indexOf("?"); var indexOfHash = urlString.lastIndexOf("#"); if (indexOfQuery >= 0) { retVal = urlString.substring(indexOfSlash + 1, indexOfQuery); } else { if (indexOfHash >= 0 && indexOfSlash != -1) { retVal = urlString.substring(indexOfSlash + 1, indexOfHash); } else if (indexOfSlash != -1) { retVal = urlString.substring(indexOfSlash + 1); } } return retVal; }, _extractQuery: function( /*String*/urlString){ var retVal = {}; var urlParts = urlString.split("?"); if (urlParts.length > 1) { retVal = dojo.queryToObject(urlParts[1].split("#")[0]); } return retVal; }, _extractAnchor: function( /*String*/urlString){ var retVal = ""; var urlParts = urlString.split("#"); if (urlParts.length > 1) { retVal = urlParts[urlParts.length - 1]; } return retVal; }, _isIPv6: function(hostname){ // only IPv6 addresses contain colons // note: the input hostname MUST NOT contain a port return hostname.indexOf(":") != -1; }, _equalsServer: function(hostname){ // consider square brackets in IPv6 case return this.server == (this._isIPv6(hostname) ? "[" + hostname + "]" : hostname); } }); } if(!dojo._hasResource["com.ibm.mm.enabler.utils.URLHelper"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.utils.URLHelper"] = true; dojo.provide("com.ibm.mm.enabler.utils.URLHelper"); dojo.declare("com.ibm.mm.enabler.utils.URLHelperImpl", com.ibm.mashups.enabler.utils.URLHelper, { rewriteURL: function(targetUrl){ var _targetURL = new com.ibm.mm.enabler.utils.HttpUrl(targetUrl); return _targetURL.toProxifiedString(); } }); com.ibm.mashups.enabler.utils.URLHelper = new com.ibm.mm.enabler.utils.URLHelperImpl(); com.ibm.mm.enabler.utils.URLHelper = com.ibm.mashups.enabler.utils.URLHelper; } if(!dojo._hasResource["com.ibm.mashups.enabler.utils.URLHelper"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.utils.URLHelper"] = true; dojo.provide("com.ibm.mashups.enabler.utils.URLHelper"); } if(!dojo._hasResource["com.ibm.mm.enabler.services.ConfigObjectExtendedImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.services.ConfigObjectExtendedImpl"] = true; dojo.provide("com.ibm.mm.enabler.services.ConfigObjectExtendedImpl"); /* * This is injected on the fly and not fetched through an API. Therefore we need to define the @ibm-module so that the build process is picking it up * @ibm-module Base * * This value defines the order in which the packages should be printed out into the dojo profile. Default is 100. * Any number that is smaller causes this class to be written out before any other with a higher number * @ibm-dojo-profile-level 40 */ dojo.declare("com.ibm.mm.enabler.services.ConfigObjectExtendedImpl", [com.ibm.mm.enabler.services.ConfigObjectDefaultImpl], { constructor: function(provider, configService) { this.valuesArray = null; this.provider = provider; this.configService = configService; }, _getValue: function(/*string*/provider, /*string*/ name) { if (!this.valuesArray) { this._loadConfigData(provider); } return this.valuesArray[name]; }, _getValueDeferred: function(/*string*/provider, /*string*/ name) { return new com.ibm.mm.enabler.DeferredImpl(this, function(deferred, sync, name) { var callBack = deferred.getFinishedCallback(); if (!this.valuesArray) { // lazy load, to support dojo layer build dojo["require"]("com.ibm.mashups.enabler.xml.XPath"); // JSLINT-IGNORE: This needs to be done to allow modularization and not break the layer build dojo["require"]("com.ibm.mashups.enabler.model.url.ModelUrlFactory"); // JSLINT-IGNORE: This needs to be done to allow modularization and not break the layer build dojo["require"]("com.ibm.mm.enabler.services.ModelRestServiceRequest"); // JSLINT-IGNORE: This needs to be done to allow modularization and not break the layer build var providerCheck = "ConfigProvider." + provider; var provider2 = ibmConfig[providerCheck]; if ((typeof provider2 != "undefined") || (provider2 !== null)) { provider = provider2; } var myUrl = com.ibm.mashups.enabler.model.url.ModelUrlFactory.createModelURL(com.ibm.mashups.enabler.model.url.ModelUrlFactory.CONFIG_URL, this); myUrl.setSchemeSpecificPart("/" + provider + "/*"); var serviceReq = new com.ibm.mm.enabler.services.ModelRestServiceRequest(myUrl, null, null, false, sync); var me = this; serviceReq.read(function(type, data, xhr, args) { if(!me.valuesArray) { me.valuesArray = {}; } var configXmls = com.ibm.mashups.enabler.xml.XPath.evaluateXPath("//atom:entry/atom:content/preferences/root/node/map/*", data, me.ns); if (configXmls && configXmls.length > 0) { for (var i = 0, l = configXmls.length; i < l; i++) { var key = configXmls[i].getAttribute("key"); var value = configXmls[i].getAttribute("value"); me.valuesArray[key] = value; } } if (me.valuesArray[name] && callBack) { callBack(me.valuesArray[name], com.ibm.mm.enabler.model.HttpStatusCodes.HTTP_OK, deferred.getFinishedCallbackParameters()); } }); } else if (this.valuesArray[name] && callBack) { callBack(this.valuesArray[name], com.ibm.mm.enabler.model.HttpStatusCodes.HTTP_OK, deferred.getFinishedCallbackParameters()); } return this.valuesArray && this.valuesArray[name]; }, name); }, _loadConfigData: function(/*string*/provider) { // lazy load, to support dojo layer build dojo["require"]("com.ibm.mashups.enabler.xml.XPath"); // JSLINT-IGNORE: This needs to be done to allow modularization and not break the layer build dojo["require"]("com.ibm.mashups.enabler.model.url.ModelUrlFactory"); // JSLINT-IGNORE: This needs to be done to allow modularization and not break the layer build dojo["require"]("com.ibm.mm.enabler.services.ModelRestServiceRequest"); // JSLINT-IGNORE: This needs to be done to allow modularization and not break the layer build var providerCheck = "ConfigProvider." + provider; var provider2 = ibmConfig[providerCheck]; if ((typeof provider2 != "undefined") || (provider2 !== null)) { provider = provider2; } var ret = {}; var myUrl = com.ibm.mashups.enabler.model.url.ModelUrlFactory.createModelURL(com.ibm.mashups.enabler.model.url.ModelUrlFactory.CONFIG_URL, this); myUrl.setSchemeSpecificPart("/" + provider + "/*"); var serviceReq = new com.ibm.mm.enabler.services.ModelRestServiceRequest(myUrl, null, null, false, true); var me = this; serviceReq.read(function(type, data, xhr, args) { var configXmls = com.ibm.mashups.enabler.xml.XPath.evaluateXPath("//atom:entry/atom:content/preferences/root/node/map/*", data, me.ns); if (configXmls && configXmls.length > 0) { for (var i = 0; i < configXmls.length; i++) { var name = configXmls[i].getAttribute("key"); var value = configXmls[i].getAttribute("value"); ret[name] = value; } } }); this.valuesArray = ret; } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.strategy.Strategy"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.strategy.Strategy"] = true; dojo.provide("com.ibm.mashups.enabler.strategy.Strategy"); /** * Interface that acts as base interface for all strategies. It can be set on * models to define the behavior of the model, i.e. how resources are loaded * from the server. * @ibm-api * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.strategy.Strategy", null, {}); } if(!dojo._hasResource["com.ibm.mashups.enabler.model.Model_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.Model_API"] = true; dojo.provide("com.ibm.mashups.enabler.model.Model_API"); dojo.provide("com.ibm.mashups.enabler.model.Model"); /** * Base class for all models * * @ibm-api * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.model.Model", null, { /** * Sets the specified array of strategies or in case none has been * defined falls back to the default strategy * @param {com.ibm.mashups.enabler.strategy.Strategy[]} strategy array of strategies to set; * may be null * @type void */ setStrategy : function(strategy) { }, /** * Returns the array of strategies which are in use * @return {com.ibm.mashups.enabler.strategy.Strategy[]} array of strategies in use, null if no * strategies are in use */ getStrategies : function() { }, /** * Returns the specified strategy * @param {strategy} strategy class name or array index of strategy * @return {com.ibm.mashups.enabler.strategy.Strategy} strategy in use, null if no * strategy with the specified type is in use * @ibm-spi */ getStrategy : function(strategy) { }, /** * Adds a strategy to the strategies array * @param {com.ibm.mashups.enabler.strategy.Strategy} strategy strategy to add; must not be null * @return {int} index where the strategy was added in the strategies array */ addStrategy : function(strategy) { }, /** * Removes the specified strategy * @param {strategy} strategy class name or array index of the strategy; must not be * null * @type void */ removeStrategy : function(strategy) { } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.model.Model"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.Model"] = true; dojo.provide("com.ibm.mashups.enabler.model.Model"); } if(!dojo._hasResource["com.ibm.mashups.enabler.strategy.NoCacheStrategy"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.strategy.NoCacheStrategy"] = true; dojo.provide("com.ibm.mashups.enabler.strategy.NoCacheStrategy"); /** * Interface to control, if caching is used for obtaining model artifacts * * @since 3.0 * * @ibm-spi * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.strategy.NoCacheStrategy", com.ibm.mashups.enabler.strategy.Strategy, { /** * @private */ _apply: function(restRequest) { // this is the spec way, but nobody cares. Try it yourself: http://www.mnot.net/javascript/xmlhttprequest/cache.html restRequest.setHeader("Pragma", "no-cache"); restRequest.setHeader("Cache-Control", "no-cache"); // This works on all major browsers even though it is not the spec way restRequest.setHeader("If-Modified-Since", "Thu, 1 Jan 1970 00:00:00 GMT"); // the only other solution is to use the existing parameter solution (pragma=no-cache) or something like dojo with a random parameter } }); } if(!dojo._hasResource["com.ibm.mm.enabler.model.ModelImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.model.ModelImpl"] = true; dojo.provide("com.ibm.mm.enabler.model.ModelImpl"); dojo.declare("com.ibm.mm.enabler.model.ModelImpl", com.ibm.mashups.enabler.model.Model, { /** * @private */ // FIXME: use _strategies strategy: null, constructor: function() { // messages this.modelMessages = dojo.i18n.getLocalization("com.ibm.mm.enabler", "modelMessages"); }, setStrategy: function(strategy) { if (strategy === null || typeof strategy == 'undefined') { this.strategy = null; } else if (com.ibm.mm.enabler.utils.Misc.isInstanceOf(strategy, Array)) { if (strategy.length > 0) { this.strategy = []; dojo.forEach(strategy, function(item, idx, arr) { this.strategy.push(item); this._preprocessStrategy(item); }, this); } } else { this.strategy = [strategy]; this._preprocessStrategy(strategy); } }, getStrategies: function() { // FIXME: expose copy of array return this.strategy || []; }, addStrategy: function(strategy) { if (strategy === null || typeof strategy == 'undefined') { throw new Error(this.modelMessages.E_PARAM_ISNULL_0); } if (null === this.strategy) { // null strategy array this.strategy = []; } // do preprocessing of strategies this._preprocessStrategy(strategy); // potentially replace existing strategy of same type for (var i = 0, l = this.strategy.length; i < l; i++) { // only dojo objects have declaredClass if (this.strategy[i].declaredClass) { if (strategy instanceof (dojo.getObject(this.strategy[i].declaredClass))) { this.strategy[i] = strategy; return i; } } } return (this.strategy.push(strategy) - 1); }, removeStrategy: function(s) { if (s === null || typeof s == 'undefined') { throw new Error(this.modelMessages.E_PARAM_ISNULL_0); } if (!this.strategy) { return; } else if (dojo.isString(s)) { s = this._getIndexOfStrategyByType(s); } if (!isNaN(s) && (s < this.strategy.length) && (s >= 0)) { this.strategy.splice(s, 1 + s); } }, getStrategy: function(s) { if (!this.strategy) { return null; } else if (dojo.isString(s)) { return this._findStrategyByType(s); } else { if (!isNaN(s) && (s < this.strategy.length) && (s >= 0)) { return this.strategy[s]; } else { return null; } } }, _findStrategyByType: function(type) { var i = this._getIndexOfStrategyByType(type); return i >= 0 ? this.strategy[i] : null; }, _getIndexOfStrategyByType: function(type) { if (this.strategy) { for (var i = 0, l = this.strategy.length; i < l; i++) { // only dojo objects have declaredClass if (this.strategy[i].declaredClass) { if (type == this.strategy[i].declaredClass) { return i; } } } } return -1; }, _preprocessStrategy: function(s) { if (com.ibm.mm.enabler.utils.Misc.isInstanceOf(s, com.ibm.mashups.enabler.strategy.NoCacheStrategy)) { if (dojo.isFunction(this.invalidate)) { this.invalidate(); } } } }); } if(!dojo._hasResource["com.ibm.mm.enabler.services.ModelRestServiceRequest"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.services.ModelRestServiceRequest"] = true; dojo.provide("com.ibm.mm.enabler.services.ModelRestServiceRequest"); /* * This is injected on the fly and not fetched through an API. Therefore we need * to define the @ibm-module so that the build process is picking it up * @ibm-module Base * * This value defines the order in which the packages should be printed out into * the dojo profile. Default is 100. Any number that is smaller causes this * class to be written out before any other with a higher number * @ibm-dojo-profile-level 50 */ dojo.declare("com.ibm.mm.enabler.services.ModelRestServiceRequest", null, { REQUEST_METHOD_POST: "POST", REQUEST_METHOD_PUT: "PUT", REQUEST_METHOD_DELETE: "DELETE", POST_ACTION_HEADER: "X-Method-Override", MODIFICATION_COOKIE: "modified.id", constructor: function( /* HttpUrl */feedlocation, /* HTMLFormElement? */ formNode, /* Function? */ formFilter, /* boolean? */ textOnly, /* boolean? */ sync) { if (com.ibm.mm.enabler.services.ModelRestServiceRequestStatic.getXRequestDigest()) { feedlocation.setParameter("digest", com.ibm.mm.enabler.services.ModelRestServiceRequestStatic.getXRequestDigest()); } this._feedURI = feedlocation.toProxifiedString(); this._textOnly = textOnly; if (textOnly) { this._handleAs = "text"; } else { this._handleAs = "xml"; } this._sync = sync; this._formNode = formNode; this._formFilter = formFilter; this._config = com.ibm.mashups.services.ServiceManager.getService(com.ibm.mashups.enabler.services.ConfigService.SERVICE_NAME); this._headers = {}; this.logoutVerificationForRaw = false; // Make sure this isn't undefined. if (!this._sync) { this._sync = false; } }, setHandleAs: function(handleAs) { if (handleAs == "atom") { this._handleAs = "xml"; } else { this._handleAs = handleAs; } }, setHeader: function(name, value) { this._headers[name] = value; }, enableLogoutVerificationForRawRetrieval: function() { this.logoutVerificationForRaw = true; }, // summary: Sends a request to one of the Portal REST Services and handles // the response. // description: Create a new instance of this object for every REST service // request that is // sent. The URL is passed in to the constructor. If a form node and form // filter is // passed into the constructor, the REST service request is handled as a // form submit. // The request can also be executed synchronously if TRUE is passed into the // constructor. // In general, only the model implementations should send these requests. create: function( /* ibm.atom.Feed */feed, /* Function */ callbackfn, /* Object? */ addtlCallbackFnArguments) { // summary: Creates an entry in a feed. // description: Creates an entry in a feed. This operation is not // implemented in this // class. It should be overridden by subclasses and properly implemented // if // the REST service supports the create operation. // feed: the ATOM feed object // entry: the ATOM entry to create // callbackfn: the function to call when the operation is complete this._updateCookie(); var me = this; var args = { url: this._feedURI, headers: { // "If-Modified-Since": "Thu, 1 Jan 1970 00:00:00 GMT", "Content-Type": "application/atom+xml; charset=utf-8" }, // temporary to force the browser to ignore cached requests load: function(response, ioArgs) { var xhr = ioArgs.xhr; var data = response; var xrd = xhr.getResponseHeader("X-Request-Digest"); if (xrd !== null) { com.ibm.mm.enabler.services.ModelRestServiceRequestStatic.setXRequestDigest(xrd); } var contentType = xhr.getResponseHeader("Content-Type"); if (typeof contentType != "undefined" && contentType !== null && contentType.indexOf("text/html") >= 0) { me._doLogin(); return; } if (dojo.isIE) { data = dojox.xml.parser.parse(xhr.responseText); } callbackfn(com.ibm.mm.enabler.services.ModelRestServiceRequest.XHR_STATUS_LOAD, data, xhr, addtlCallbackFnArguments); }, error: function(response, ioArgs) { var xhr = ioArgs.xhr; var status = xhr.status; // Check whether we are having an authorization problem if (status == 401) { me._doLogin(); return; } callbackfn(com.ibm.mm.enabler.services.ModelRestServiceRequest.XHR_STATUS_ERROR, null, xhr, addtlCallbackFnArguments); }, sync: this._sync, postData: feed.toString(), handleAs: this._handleAs }; dojo.rawXhrPost(args); }, read: function( /* Function? */callbackfn, /* Object? */ addtlCallbackFnArguments) { // summary: Read the ATOM feed provided by the REST service. // description: If textOnly is set to true, the ATOM feed is returned as // text and // passed in as a single argument to the specified callback function. // Otherwise, the ATOM feed is parsed into an {@link ibm.atom.Feed} // object // and passed into the callback function along with the original XML // Document // Object Model object. // callbackfn: the function to call when the operation is complete (only // valid if // sync is false) // addtlCallbackFnArguments: any arguments to pass through to the // callback function if (this._textOnly) { this._retrieveRawFeed(callbackfn, addtlCallbackFnArguments); } else { this._retrieve(callbackfn, addtlCallbackFnArguments); } }, update: function( /* ibm.atom.Feed */feed, /* Function */ callbackfn, /* Object? */ addtlCallbackFnArguments) { // summary: Updates an entry in a feed. // description: Updates an entry in a feed. This operation is not // implemented in this // class. It should be overridden by subclasses and properly implemented // if the // REST service supports the update operation. // feed: the ATOM feed object // entry: the ATOM entry to create // callbackfn: the function to call when the operation is complete this._updateCookie(); var me = this; var args = { url: this._feedURI, load: function(response, ioArgs) { var xhr = ioArgs.xhr; var xrd = xhr.getResponseHeader("X-Request-Digest"); if (xrd !== null) { com.ibm.mm.enabler.services.ModelRestServiceRequestStatic.setXRequestDigest(xrd); } var contentType = xhr.getResponseHeader("Content-Type"); if (typeof contentType != "undefined" && contentType !== null && contentType.indexOf("text/html") >= 0) { me._doLogin(); return; } // this seems to be fixed with dojo 1.4.1 ... WTF ? Seems or IS ??? // if (dojo.isIE < 7) { // data = dojox.xml.parser.parse(xhr.responseText,"application/xml"); // } dojo.partial(callbackfn)(com.ibm.mm.enabler.services.ModelRestServiceRequest.XHR_STATUS_LOAD, response, xhr, addtlCallbackFnArguments); }, error: function(response, ioArgs) { var xhr = ioArgs.xhr; var status = xhr.status; // Check whether we are having an authorization problem if (status == 401) { me._doLogin(); return; } dojo.partial(callbackfn)(com.ibm.mm.enabler.services.ModelRestServiceRequest.XHR_STATUS_ERROR, null, xhr, addtlCallbackFnArguments); }, sync: this._sync, handleAs: this._handleAs }; var requestHeaders = { // "If-Modified-Since": "Thu, 1 Jan 1970 00:00:00 GMT", "Content-Type": "application/atom+xml; charset=utf-8" }; var mpHandler = com.ibm.mashups.enabler.io.XHRMultipartFactory.create(); var inTrans = mpHandler.isTransaction(); // we verify for sync here as well because we know that the transactions // gets aborted by the multipart processing and hence we can do the PUT // right away if (com.ibm.mashups.services.ServiceManager.getService(com.ibm.mashups.enabler.services.ConfigService.SERVICE_NAME).getValue(com.ibm.mashups.enabler.services.ConfigConstants.TUNNEL_MODE) === true && (!inTrans || this._sync)) { requestHeaders[this.POST_ACTION_HEADER] = this.REQUEST_METHOD_PUT; args.headers = requestHeaders; args.postData = feed; dojo.rawXhrPost(args); } else { args.putData = feed; args.headers = requestHeaders; dojo.rawXhrPut(args); } }, remove: function(/* Function */callbackfn, /* Object? */ addtlCallbackFnArguments) { // summary: Removes an entry from a feed. // description: Removes an entry from a feed. This operation is not // implemented in this // class. It should be overridden by subclasses and properly implemented // if the // REST service supports the remove operation. // feed: the ATOM feed object // entry: the ATOM entry to create // callbackfn: the function to call when the operation is complete this._updateCookie(); var me = this; var args = { url: this._feedURI, load: function(response, ioArgs) { var type = com.ibm.mm.enabler.services.ModelRestServiceRequest.XHR_STATUS_LOAD; var data = response; var xhr = ioArgs.xhr; var xrd = xhr.getResponseHeader("X-Request-Digest"); if (xrd !== null) { com.ibm.mm.enabler.services.ModelRestServiceRequestStatic.setXRequestDigest(xrd); } var contentType = xhr.getResponseHeader("Content-Type"); if (typeof contentType != "undefined" && contentType !== null && contentType.indexOf("text/html") >= 0) { me._doLogin(); return; } if (dojo.isIE) { data = dojox.xml.parser.parse(xhr.responseText); } callbackfn(type, data, xhr, addtlCallbackFnArguments); }, error: function(response, ioArgs) { var xhr = ioArgs.xhr; var status = xhr.status; // Check whether we are having an authorization problem if (status == 401) { me._doLogin(); return; } callbackfn(com.ibm.mm.enabler.services.ModelRestServiceRequest.XHR_STATUS_ERROR, null, xhr, addtlCallbackFnArguments); }, sync: this._sync, handleAs: this._handleAs }; var requestHeaders = { // "If-Modified-Since": "Thu, 1 Jan 1970 00:00:00 GMT", "Content-Type": "application/atom+xml" }; if (com.ibm.mashups.services.ServiceManager.getService(com.ibm.mashups.enabler.services.ConfigService.SERVICE_NAME).getValue(com.ibm.mashups.enabler.services.ConfigConstants.TUNNEL_MODE) === true) { requestHeaders[this.POST_ACTION_HEADER] = this.REQUEST_METHOD_DELETE; args.headers = requestHeaders; dojo.rawXhrPost(args); } else { args.headers = requestHeaders; dojo.xhrDelete(args); } }, _retrieveRawFeed: function(callbackfn, callbackargs) { var me = this; dojo.xhrGet({ url: this._feedURI, headers: this._headers, load: function(data, ioArgs) { var xhr = ioArgs.xhr; var xrd = xhr.getResponseHeader("X-Request-Digest"); if (xrd !== null) { com.ibm.mm.enabler.services.ModelRestServiceRequestStatic.setXRequestDigest(xrd); } if (me.logoutVerificationForRaw) { // in this case we assume that a X-Request-Digest is always returned from the resolver // if it is not coming back it had to be due to a login challange if (!xrd) { me._doLogin(); return; } } callbackfn(com.ibm.mm.enabler.services.ModelRestServiceRequest.XHR_STATUS_LOAD, data, ioArgs.xhr, callbackargs); }, error: function(data, ioArgs) { var xhr = ioArgs.xhr; var status = xhr.status; // Check whether we are having an authorization problem if (status == 401) { me._doLogin(); return; } callbackfn(com.ibm.mm.enabler.services.ModelRestServiceRequest.XHR_STATUS_ERROR, data, ioArgs.xhr, callbackargs); }, sync: this._sync, handleAs: this._handleAs }); }, _retrieve: function(callbackfn, callbackargs, formNode, formFilter) { var content = {}; // temp my ass var mt = "xml"; // temp if (dojo.isIE) { // content = { "com.ibm.wps.web2.contenttype": "text/xml" }; mt = "text"; // temp } var me = this; var args = { url: this._feedURI, content: content, headers: this._headers, load: function(response, ioArgs) { var data = response; var xhr = ioArgs.xhr; var xrd = xhr.getResponseHeader("X-Request-Digest"); if (xrd !== null) { com.ibm.mm.enabler.services.ModelRestServiceRequestStatic.setXRequestDigest(xrd); } var contentType = xhr.getResponseHeader("Content-Type"); // If the HTML content is returned, this is probably another // re-direction so we need to // force a full-page refresh. if (typeof contentType != "undefined" && contentType !== null && contentType.indexOf("text/html") >= 0) { me._doLogin(); return; } if (dojo.isIE) { var doc = com.ibm.mm.enabler.utils.Dom.createDocument(data); callbackfn(com.ibm.mm.enabler.services.ModelRestServiceRequest.XHR_STATUS_LOAD, doc, xhr, callbackargs); } else { callbackfn(com.ibm.mm.enabler.services.ModelRestServiceRequest.XHR_STATUS_LOAD, data, xhr, callbackargs); } }, error: function(response, ioArgs) { var data = response; var xhr = ioArgs.xhr; var status = xhr.status; // Check whether we are having an authorization problem if (status == 401) { me._doLogin(); return; } if (dojo.isIE) { var doc = null; try { if (data) { doc = com.ibm.mm.enabler.utils.Dom.createDocument(data); } } catch (e) { } callbackfn(com.ibm.mm.enabler.services.ModelRestServiceRequest.XHR_STATUS_ERROR, doc, xhr, callbackargs); } else { callbackfn(com.ibm.mm.enabler.services.ModelRestServiceRequest.XHR_STATUS_ERROR, data, xhr, callbackargs); } }, sync: this._sync, handleAs: mt }; var method = "Get"; if (this._formNode) { args.form = this._formNode; method = "Post"; } if (this._formFilter) { args.formFilter = this._formFilter; } dojo["xhr" + method](args); }, _updateCookie: function() { var dt = new Date(); var properties = {}; properties.path = this._config.getValue(com.ibm.mashups.enabler.services.ConfigConstants.CONTEXT_ROOT); dojo.cookie(this.MODIFICATION_COOKIE, dt.getTime(), properties); }, _doLogin: function() { // lazy load, to support dojo layer build dojo["require"]("com.ibm.mashups.enabler.model.state.NavigationStateModelFactory"); // JSLINT-IGNORE: // This // needs // to // be // done // to // allow // modularization // and // not // break // the // layer // build dojo["require"]("com.ibm.mashups.enabler.model.state.UrlGeneratorFactory"); // JSLINT-IGNORE: // This // needs // to // be // done // to // allow // modularization // and // not // break // the // layer // build var pid = null; var url = document.location.href; // get full page refresh redirect url var cb = function(url) { if (url) { top.location.href = url; } }; var navStateModel = com.ibm.mashups.enabler.model.state.NavigationStateModelFactory.getNavigationStateModel(); com.ibm.mashups.enabler.model.state.UrlGeneratorFactory.getURLGenerator().getUrl(navStateModel, cb, { nohash: "true" }); }, toString: function() { return this._feedURI; } }); com.ibm.mm.enabler.services.ModelRestServiceRequestStatic = { xRequestDigest : null, getXRequestDigest: function() { if ((null === this.xRequestDigest) && (ibmConfig["com.ibm.resolver.digest"])) { this.xRequestDigest = ibmConfig["com.ibm.resolver.digest"]; } return this.xRequestDigest; }, setXRequestDigest: function(digest) { this.xRequestDigest = digest; }, invalidateXRequestDigest: function() { // update digest var dt = new Date(); var digest = dt.getTime(); this.setXRequestDigest(digest); // update cookie var properties = {}; var cs = com.ibm.mashups.services.ServiceManager.getService(com.ibm.mashups.enabler.services.ConfigService.SERVICE_NAME); properties.path = cs.getValue(com.ibm.mashups.enabler.services.ConfigConstants.CONTEXT_ROOT); dojo.cookie("modified.id", digest, properties); } }; // constants com.ibm.mm.enabler.services.ModelRestServiceRequest.XHR_STATUS_LOAD = "load"; com.ibm.mm.enabler.services.ModelRestServiceRequest.XHR_STATUS_ERROR = "error"; dojo.declare("com.ibm.mm.enabler.services.XHRModelHeaderExtensionImpl", null, { constructor: function() { this.originalDojoXHR = dojo.xhr; dojo.xhr = dojo.hitch(this, function(/* String */method, /* dojo.__XhrArgs */ args, /* Boolean */ hasBody) { if (!args.headers) { args.headers = {}; } args.headers["X-IBM-XHR"] = "true"; var ret = this.originalDojoXHR(method, args, hasBody); return ret; }); } }); com.ibm.mm.enabler.services.XHRModelHeaderExtension = new com.ibm.mm.enabler.services.XHRModelHeaderExtensionImpl(); } if(!dojo._hasResource["com.ibm.mm.enabler.endpoints.XHREndpointExtensionImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.endpoints.XHREndpointExtensionImpl"] = true; dojo.provide("com.ibm.mm.enabler.endpoints.XHREndpointExtensionImpl"); dojo.declare("com.ibm.mm.enabler.endpoints.XHREndpointExtensionImpl", null, { constructor: function(){ this.originalDojoXHR = dojo.xhr; dojo.xhr = dojo.hitch(this, function(/* String */ method, /* dojo.__XhrArgs */ args, /* Boolean */ hasBody) { var url = args.url; var url2 = com.ibm.mm.enabler.EndpointUtils.checkForEndpoints(url); url2 = url2 || null; if (url2 !== null) { args.url = url2; } var ret = this.originalDojoXHR(method, args, hasBody); return ret; }); } }); com.ibm.mm.enabler.endpoints.XHREndpointExtension = new com.ibm.mm.enabler.endpoints.XHREndpointExtensionImpl(); } if(!dojo._hasResource["com.ibm.mm.enabler.services.ConfigServiceExtendedImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.services.ConfigServiceExtendedImpl"] = true; dojo.provide("com.ibm.mm.enabler.services.ConfigServiceExtendedImpl"); /* * This is injected on the fly and not fetched through an API. Therefore we need to define the @ibm-module so that the build process is picking it up * @ibm-module Base * * This value defines the order in which the packages should be printed out into the dojo profile. Default is 100. * Any number that is smaller causes this class to be written out before any other with a higher number * @ibm-dojo-profile-level 40 */ // inject this service into the ServiceManager at the end. Therefore we have to require the implementation dojo.declare("com.ibm.mm.enabler.services.ConfigServiceExtendedImpl", [com.ibm.mm.enabler.services.ConfigServiceDefaultImpl], { constructor: function() { }, _getConfigObject: function(/*string*/configProvider) { if (!ibmConfig["CO_" + configProvider]) { var co = new com.ibm.mm.enabler.services.ConfigObjectExtendedImpl(configProvider, this); ibmConfig["CO_" + configProvider] = co; } return ibmConfig["CO_" + configProvider]; }, _getConfigProviderNames: function() { // lazy load, to support dojo layer build dojo["require"]("com.ibm.mashups.enabler.model.url.ModelUrlFactory"); // JSLINT-IGNORE: This needs to be done to allow modularization and not break the layer build var ret = []; ret.push("all"); var myUrl = com.ibm.mashups.enabler.model.url.ModelUrlFactory.createModelURL(com.ibm.mashups.enabler.model.url.ModelUrlFactory.CONFIG_URL, this); myUrl.setSchemeSpecificPart("/*"); myUrl.setParameter("rep", "compact"); var serviceReq = new com.ibm.mm.enabler.services.ModelRestServiceRequest(myUrl, null, null, false, true); var me = this; serviceReq.read(function(type, data, xhr, args) { var configXmls = com.ibm.mashups.enabler.xml.XPath.evaluateXPath("//atom:entry/atom:id", data, me.ns); if (configXmls && configXmls.length > 0) { for (var i = 0, l = configXmls.length; i < l; i++) { var configXml = com.ibm.mm.enabler.utils.Dom.textContent(configXmls[i]); var lastSlash = configXml.indexOf("/", 9); configXml = configXml.substring(8, lastSlash).trim(); for (var config in ibmConfig) { if (ibmConfig[config] === configXml) { configXml = config.substring(15); } } ret.push(configXml); } } }); return ret; } }); com.ibm.mashups.services.ServiceManager.setService("configService", "com.ibm.mm.enabler.services.ConfigServiceExtendedImpl"); } if(!dojo._hasResource["com.ibm.mashups.enabler.model.ServiceDocumentModel_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.ServiceDocumentModel_API"] = true; dojo.provide("com.ibm.mashups.enabler.model.ServiceDocumentModel_API"); dojo.provide("com.ibm.mashups.enabler.model.ServiceDocumentModel"); /** * An singleton that represents the Service Document * * @ibm-spi * @ibm-module Base * * This value defines the order in which the packages should be printed out into the dojo profile. Default is 100. * Any number that is smaller causes this class to be written out before any other with a higher number * @ibm-dojo-profile-level 50 */ dojo.declare("com.ibm.mashups.enabler.model.ServiceDocumentModel", null, { /** * Constant representing the navigation service * @type {String} */ SERVICE_NAVIGATION: "navigation", /** * Constant representing the space navigation service * @type {String} */ SERVICE_SPACE_NAVIGATION: "space-navigation", /** * Constant representing the shared navigation service * @type {String} */ SERVICE_SHARED_NAVIGATION: "shared-navigation", /** * Constant representing the content service * @type {String} */ SERVICE_CONTENT: "content", /** * Constant representing the catalog service * @type {String} */ SERVICE_CATALOG: "catalog", /** * Constant representing the resource service * @type {String} */ SERVICE_RESOURCE: "resource", /** * Constant representing the widget service * @type {String} */ SERVICE_WIDGET: "widget", /** * Constant representing the theme service * @type {String} */ SERVICE_THEME: "theme", /** * Constant representing the user service * @type {String} */ SERVICE_USER: "user", /** * Constant representing generic model services * @type {String} */ SERVICE_MODEL: "model", /** * Constant representing multipart services * @type {String} */ SERVICE_MULTIPART: "multipart", /** * Constant representing the huffman encoding of multipart services * @type {String} */ SERVICE_HUFFMAN: "huffman", /** * Constant representing the sitemap encoding of multipart services * @type {String} */ SERVICE_SITEMAP: "sitemap", /** * Constant representing the commit handler sitemap encoding of multipart services * @type {String} */ SERVICE_SITEMAP_COMMITHANDLER: "commit-handler", /** * Constant representing the composite application service * @type {String} */ SERVICE_COMPOSITE: "composite-applications", /** * Constant representing the space service * @type {String} */ SERVICE_SPACE: "application", /** * Constant representing the space favorites service * @type {String} */ SERVICE_SPACE_FAVORITE: "application-favorite", /** * Constant representing the template service * @type {String} */ SERVICE_TEMPLATE: "template", /** * Constant representing the config service * @type {String} */ SERVICE_CONFIG: "config", /** * Constant representing the webdav filestore * @type {String} */ SERVICE_FILESTORE: "filestore", /** * Constant representing generic webdav services * @type {String} */ SERVICE_WEBDAV: "webdav", /** * Invalidates the Service Document Model in order for it to be re-initialized again. * * @type void */ invalidate: function() { }, /** * Returns a two-dimensional array of IDs representing services which are attached to a specific endpoint namespace. * The IDs in the second dimension are required to lookup the service data.
* Example: [["webdav"],["filestore"]]
* Only the combination of both IDs make the service unique and must be used to lookup the service data * * @Returns {String[][]} A two-dimensional array with the second dimension being a list of IDs which represent the service. */ getModelCollections: function() { }, /** * Returns a two-dimensional array of IDs representing services which are attached to mashups specifically. * The IDs in the second dimension are required to lookup the service data.
* Example: [["webdav"],["filestore"]]
* Only the combination of both IDs make the service unique and must be used to lookup the service data * * @return {String[][]} A two-dimensional array with the second dimension being a list of IDs which represent the service. */ getMashupsCollections: function() { }, /** * Returns a JSON object for a given collection link in the service document. Not all elements are mandatory.
* JSON format
* { id: "the id array",
* url :"the url",
* template :"the template",
* idprefix: "id|oid",
* namespaces : { "base" : "base-url", "model" : "model-url", "ext" : "ext-url", "creation-context" : "creation-context-url" },
* accept: "accept MIME type",
* version: "major.minor"
* }
* @param {String[]} idArray The ID Array to lookup the service for. * @type Object * @return {Object} Returns a JSON object for a given collection link in the service document */ getCollectionData: function(idArray) { } } ); } if(!dojo._hasResource["com.ibm.mm.enabler.model.ServiceDocumentModel"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.model.ServiceDocumentModel"] = true; dojo.provide("com.ibm.mm.enabler.model.ServiceDocumentModel"); dojo.declare("com.ibm.mm.enabler.model.ServiceDocumentModelImpl", com.ibm.mashups.enabler.model.ServiceDocumentModel, { SERVICE_NAVIGATION: "navigation", SERVICE_SPACE_NAVIGATION: "space-navigation", SERVICE_SHARED_NAVIGATION: "shared-navigation", SERVICE_CONTENT: "content", SERVICE_CATALOG: "catalog", SERVICE_RESOURCE: "resource", SERVICE_WIDGET: "widget", SERVICE_THEME: "theme", SERVICE_USER: "user", SERVICE_MODEL: "model", SERVICE_MULTIPART: "multipart", SERVICE_HUFFMAN: "huffman", SERVICE_SITEMAP: "sitemap", SERVICE_SITEMAP_COMMITHANDLER: "commit-handler", SERVICE_COMPOSITE: "composite-applications", SERVICE_SPACE: "application", SERVICE_SPACE_FAVORITE: "application-favorite", SERVICE_TEMPLATE: "template", SERVICE_CONFIG: "config", SERVICE_FILESTORE: "filestore", SERVICE_WEBDAV: "webdav", constructor: function () { this.prefix = "service"; this.ns = { "atom" : "http://www.w3.org/2005/Atom", "app" : "http://www.w3.org/2007/app", "service" : "http://www.ibm.com/xmlns/prod/sw/model/service/1.0"}; this.xmlData = null; this.xmlDataAsString = null; this.max_version = null; this.cache = []; }, getInstance: function() { var instance = com.ibm.mm.enabler.model.ServiceDocumentModelImpl._instance; return instance ? instance : (com.ibm.mm.enabler.model.ServiceDocumentModelImpl._instance = new com.ibm.mm.enabler.model.ServiceDocumentModelImpl()); }, invalidate: function() { this.xmlData = null; this.max_version = null; }, _loadAhead: function() { // lazy load, to support dojo layer build dojo["require"]("com.ibm.mashups.enabler.model.url.ModelUrlFactory"); // JSLINT-IGNORE: This needs to be done to allow modularization and not break the layer build if (ibmConfig.servicedocument) { if (this.xmlDataAsString != ibmConfig.servicedocument) { this.xmlData = null; } } if (this.xmlData) { return; } if (ibmConfig.servicedocument) { this.xmlData = dojox.xml.parser.parse( ibmConfig.servicedocument ); this.xmlDataAsString = ibmConfig.servicedocument; } else { var myUrl; if (ibmConfig.serviceDocumentUrl) { myUrl = new com.ibm.mm.enabler.utils.HttpUrl(ibmConfig.serviceDocumentUrl); } else { myUrl = com.ibm.mashups.enabler.model.url.ModelUrlFactory.createModelURL("service", null); myUrl.setNodes([{ value: "collection", isID: false }]); } var serviceReq = new com.ibm.mm.enabler.services.ModelRestServiceRequest(myUrl, null, null, false, true); serviceReq.read( dojo.hitch(this, function (type, data, xhr, args) { if (type == com.ibm.mm.enabler.services.ModelRestServiceRequest.XHR_STATUS_LOAD) { this.xmlData = data; } else if (type == com.ibm.mm.enabler.services.ModelRestServiceRequest.XHR_STATUS_ERROR) { // TODO } } ) ); } this._fillCache(); }, _fillCache: function() { this.max_version = null; if (ibmConfig.servicedocument_version_max) { this.max_version = parseInt(ibmConfig.servicedocument_version_max.replace(/\./g, ""),10); } var matches = []; var i, l, found; var expr = "//app:collection"; var nodes = com.ibm.mashups.enabler.xml.XPath.evaluateXPath(expr, this.xmlData, this.ns); for (i=0, l = nodes.length; i0) { var terms = []; for (var ii=0, ll = nodes2.length; ii0) { var terms = []; for (var ii=0,ll=nodes2.length; iithis.max_version)) { score = -1000; // disregard; } scoreCard[i] = score; } // see who won var winner = -1; var winningScore = 1000; // we need at least one matched item, therefore the minimum is 1000 points for (i = 0, scl = scoreCard.length; i < scl; i++) { if (scoreCard[i] > winningScore) { winner = i; winningScore = scoreCard[i]; } } if (winner == -1) { return null; } return this.cache[winner]; }, _processCollection: function(i, node) { var ret = {}; // we found a match var expr3 = "app:categories//atom:category[@term]"; var nodes3 = com.ibm.mashups.enabler.xml.XPath.evaluateXPath(expr3, node, this.ns); var nodeIDs = []; if (nodes3) { for (var jj = 0, ll = nodes3.length; jj < ll; jj++) { var term = nodes3[jj].getAttribute('term'); if (term.indexOf("enabler-ns-")===0) { continue; } nodeIDs.push(term); } } ret.id = nodeIDs; ret.url = node.getAttribute("href"); ret.version = com.ibm.mm.enabler.utils.Dom.getAttributeWithNS( node,"service:version","version",this.ns.service); if (!ret.version) { ret.version = "1.0"; } ret.template = com.ibm.mm.enabler.utils.Dom.getAttributeWithNS( node,"service:template","template",this.ns.service); ret.idprefix = "id"; var ns = {}; expr3 = "app:categories/atom:category[@term='enabler-ns-base']"; nodes3 = com.ibm.mashups.enabler.xml.XPath.evaluateEntry(expr3, node, this.ns); if (nodes3) { ns.base = nodes3.getAttribute("scheme"); if (ns.base.indexOf("/mashups/")==-1) { ret.idprefix = "oid"; } } expr3 = "app:categories/atom:category[@term='enabler-ns-model']"; nodes3 = com.ibm.mashups.enabler.xml.XPath.evaluateEntry(expr3, node, this.ns); if (nodes3) { ns.model = nodes3.getAttribute("scheme"); } expr3 = "app:categories/atom:category[@term='enabler-ns-ext']"; nodes3 = com.ibm.mashups.enabler.xml.XPath.evaluateEntry(expr3, node, this.ns); if (nodes3) { ns.ext = nodes3.getAttribute("scheme"); } expr3 = "app:categories/atom:category[@term='enabler-ns-creationcontext']"; nodes3 = com.ibm.mashups.enabler.xml.XPath.evaluateEntry(expr3, node, this.ns); if (nodes3) { ns["creation-context"] = nodes3.getAttribute("scheme"); } ret.namespaces = ns; expr3 = "app:accept"; nodes3 = com.ibm.mashups.enabler.xml.XPath.evaluateEntry(expr3, node, this.ns); if (nodes3) { ret.accept = nodes3.firstChild.nodeValue; } return ret; } } ); com.ibm.mm.enabler.model.ServiceDocumentModel = com.ibm.mm.enabler.model.ServiceDocumentModelImpl.prototype.getInstance(); com.ibm.mashups.enabler.model.ServiceDocumentModel = com.ibm.mm.enabler.model.ServiceDocumentModel; } if(!dojo._hasResource["com.ibm.mashups.enabler.model.ServiceDocumentModel"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.ServiceDocumentModel"] = true; dojo.provide("com.ibm.mashups.enabler.model.ServiceDocumentModel"); } if(!dojo._hasResource["com.ibm.mashups.enabler.Commitable"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.Commitable"] = true; dojo.provide("com.ibm.mashups.enabler.Commitable"); /** * An interface that adds methods for checking for changes and appyling them. * @since 2.4 * @ibm-api * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.Commitable", null, { /** * States whether this object is "dirty", meaning changes where done on this object. * @return {boolean} true if changes where made to the object, false otherwise. */ isDirty: function(){ return false; }, /** * Commits the modifications applied to this object.
* @return {DeferredOperation} a deferred object used to start this operation. * The return value when executed through the deferred object is null */ commit: function(){ } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.DefaultLocalized"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.DefaultLocalized"] = true; dojo.provide("com.ibm.mashups.enabler.DefaultLocalized"); /** * Read-Only interface providing methods to obtain default title, description, * and locale * @ibm-spi * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.DefaultLocalized", null, { /** * Returns the default locale.
*
* @return {String} the default locale; may be null. */ getDefaultLocale: function(){ }, /** * Returns the default title. * @return {String} the default title of this node; may be null. */ getDefaultTitle: function(){ }, /** * Returns the default description of this object. * @return {String} the default description; may be null. */ getDefaultDescription: function(){ } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.Iterator"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.Iterator"] = true; dojo.provide("com.ibm.mashups.enabler.Iterator"); /** * Extended iterator interface, which allows iterating over elements * in a sequentiell order. It allows to set the starting point of the * iteration and exposes the number of elements in the iteration. * * @ibm-api * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.Iterator", null, { /** * Returns true if the iteration has more elements. * @return {Boolean} true if the iterator has more elements, * otherwise false. */ hasNext: function(){ }, /** * Returns the next element in the iteration. Calling this method * repeatedly until the hasNext() method returns false will return * each element in the underlying collection exactly once. * The cursor position is increased by one. if no element is available * at the specified position, null is returned and the * position is not changed * * @returns {Object} the next element in the iteration */ next: function(){ }, /** * Returns the number of elements in this iterator. * * @return {com.ibm.mashups.enabler.Deferred} a deferred object used to start this operation. The * return value when executed through the deferred object * is the number of elements in this iterator */ size: function(){ }, /** * Sets the zero-based position of the cursor, i.e the last * element is addressed through size()-1. * A position which is out of the bounds of the current iteration * is ignored and in this case the position is set to the nearest * possible value within valid bounds. * * @param {int} position position of the cursor. Defaults to zero * @type void */ setCursorPosition: function(position){ }, /** * Returns the zero-based position of the cursor, i.e. zero for the first element * * @return {int} the position of the cursor */ getCursorPosition: function(){ } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.DeferredIterator_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.DeferredIterator_API"] = true; dojo.provide("com.ibm.mashups.enabler.DeferredIterator_API"); dojo.provide("com.ibm.mashups.enabler.DeferredIterator"); /** * The DeferredIterator can be used to iterate over a list of objects * in an asynchronous fashion. The callback handler is called as * soon as the next object has been loaded. * The start method is only used for the asynchronous aspect of * the deferred iterator. For the synchronous aspect the methods * such as hasNext() can be called directly. * @ibm-api * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.DeferredIterator", [com.ibm.mashups.enabler.Deferred, com.ibm.mashups.enabler.Iterator], { /** * Sets the handler of the deferred action. It is called when the * next object in the list has been loaded and is ready to be processed. * @param {Object} callback the callback funtion in the format of Function(object nextElement, Object[] params). Must not be null
*     Callbackparameters
*     nextElement - the next * object in the list
*     params - the parameters * passed into the addForEachCallback * @param {Object[]} parameters optional array of parameters to be * passed on to the callback function * @return {com.ibm.mashups.enabler.DeferredIterator} the deferred object */ setForEachCallback: function(callback, parameters){ } }); } if(!dojo._hasResource["com.ibm.mm.enabler.DeferredIteratorImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.DeferredIteratorImpl"] = true; dojo.provide("com.ibm.mm.enabler.DeferredIteratorImpl"); // iterator dojo.declare("com.ibm.mm.enabler.DeferredIteratorImpl", [com.ibm.mashups.enabler.DeferredIterator, com.ibm.mm.enabler.DeferredImpl], { setForEachCallback: function(callback, parameters){ this.foreachCallback = callback; this.foreachCallbackParameters = parameters; return this; }, /** * there's a typo in this one, keeping it around for backwards compat * * @param {Object} callback * @param {Object} parameters */ setForeachCallback: function(callback, parameters){ return this.setForEachCallback(callback, parameters); }, getForeachCallback: function(){ return this.foreachCallback; }, getForeachCallbackParameters: function(){ return this.foreachCallbackParameters; }, nextFinish: function(entry) { if(dojo.isFunction(this.getForeachCallback())) { // call callback dojo.partial(this.getForeachCallback())(entry, this.getForeachCallbackParameters()); } }, start: function(sync){ while (this.hasNext(this, sync)) { this.next(this, sync); } } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.DeferredIterator"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.DeferredIterator"] = true; dojo.provide("com.ibm.mashups.enabler.DeferredIterator"); } if(!dojo._hasResource["com.ibm.mashups.enabler.DeferredOperation_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.DeferredOperation_API"] = true; dojo.provide("com.ibm.mashups.enabler.DeferredOperation_API"); dojo.provide("com.ibm.mashups.enabler.DeferredOperation"); /** * In addition to the Deferred interface, which allows to trigger callbacks after the * entire action has finished, the DeferredOperation interface allows to trigger a * callback for each involved operation. * @ibm-api * @ibm-module Base */ dojo.declare( "com.ibm.mashups.enabler.DeferredOperation", [com.ibm.mashups.enabler.Deferred], { /** * Mode of operation: retrieving a resource * @type String */ OPERATION_GET: "GET", /** * Mode of operation: creating a resource * @type String */ OPERATION_CREATE: "CREATE", /** * Mode of operation: modifying a resource * @type String */ OPERATION_MODIFY: "MODIFY", /** * Mode of operation: deleting a resource * @type String */ OPERATION_DELETE: "DELETE", /** * Sets the handler of the deferred action. The handler is called for each * operation the action involves. * @param {Object} callback the callback funtion in the format of Function(Object node, string mode, int statusCode, Object[] params). Must not be null
*     Callbackparameters
*     node - resource object or string id of the * related resource, depending on the operation. For example, when a resource is created, the * resource itself is returned. In case of a delete operation, the id is returned * instead.
*     mode - the mode of the operation. * May be one of OPERATION_GET, OPERATION_CREATE, * OPERATION_MODIFY, or OPERATION_DELETE.
*     statusCode - the overall HTTP status code * of the operation.
*     params - the parameters * passed into the callback * @param {Object[]} parameters optional array of parameters to be * passed on to the callback function. May be null * @return {com.ibm.mashups.enabler.DeferredOperation} the deferred object */ setOperationCallback: function(callback, parameters) { } }); com.ibm.mashups.enabler.DeferredOperation.OPERATION_GET = "GET"; com.ibm.mashups.enabler.DeferredOperation.OPERATION_CREATE = "CREATE"; com.ibm.mashups.enabler.DeferredOperation.OPERATION_MODIFY = "MODIFY"; com.ibm.mashups.enabler.DeferredOperation.OPERATION_DELETE = "DELETE"; } if(!dojo._hasResource["com.ibm.mm.enabler.model.HttpStatusCodes"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.model.HttpStatusCodes"] = true; dojo.provide("com.ibm.mm.enabler.model.HttpStatusCodes"); dojo.provide("com.ibm.mm.enabler.model.HttpStatusCodesImpl"); dojo.declare("com.ibm.mm.enabler.model.HttpStatusCodesImpl", null, { HTTP_CONTINUE: "100", HTTP_SWITCHING_PROTOCOLS: "101", HTTP_OK: "200", HTTP_CREATED: "201", HTTP_BAD_REQUEST: "400", HTTP_NOT_FOUND: "404", HTTP_REQUEST_TIMEOUT: "408", HTTP_INTERNAL_SERVER_ERROR: "500", HTTP_SERVICE_UNAVAILABLE: "503" }); com.ibm.mm.enabler.model.HttpStatusCodes = new com.ibm.mm.enabler.model.HttpStatusCodesImpl(); } if(!dojo._hasResource["com.ibm.mm.enabler.DeferredOperationImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.DeferredOperationImpl"] = true; dojo.provide("com.ibm.mm.enabler.DeferredOperationImpl"); // operation dojo.declare("com.ibm.mm.enabler.DeferredOperationImpl", [com.ibm.mashups.enabler.DeferredOperation, com.ibm.mm.enabler.DeferredImpl], { operationCallback: null, operationCallbackParameters: null, setOperationCallback: function(callback, parameters){ this.operationCallback = callback; this.operationCallbackParameters = parameters; return this; }, getOperationCallback: function(){ return this.operationCallback; }, getOperationCallbackParameters: function(){ return this.operationCallbackParameters; }, finishOperation: function(result, operation, status) { if(dojo.isFunction(this.getOperationCallback())) { // call callback if(dojo.isOpera && status === 0) { status = com.ibm.mm.enabler.model.HttpStatusCodes.HTTP_NOT_FOUND; } dojo.partial(this.getOperationCallback())(result, operation, status, this.getOperationCallbackParameters()); } } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.DeferredOperation"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.DeferredOperation"] = true; dojo.provide("com.ibm.mashups.enabler.DeferredOperation"); } if(!dojo._hasResource["com.ibm.mashups.enabler.DirtyFlagProvider_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.DirtyFlagProvider_API"] = true; dojo.provide("com.ibm.mashups.enabler.DirtyFlagProvider_API"); dojo.provide("com.ibm.mashups.enabler.DirtyFlagProvider"); /** * Base interface that allows to track whether a node or model has been modified (i.e. became dirty). * * @since 3.0.0.1 * @ibm-spi * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.DirtyFlagProvider", null, { /** * Tests whether the instance is dirty. Instances that have been modified, or newly created return true. * * @return {Boolean} true if the instance is dirty, otherwise false. */ isDirty: function() {}, /** * Marks this instance as dirty. */ setDirty: function() {}, /** * Marks this instance as not dirty, i.e. clean. */ setClean: function() {}, /** * Adds a callback handler to be called when the instance changes its state. * * @param {Object} ctx The context in which to run the callback handler * Must not be null * @param {Object} callback the callback funtion in the format of Function(Object[] passed in with addDirtyCallback). * Must not be null * @param {Object[]} parameters optional array of parameters to be * passed on to the callback function. May be null * @param {Boolean} alwaysFire Specifies whether to only fire when clean->dirty (set flag to false) or also fire when dirty->dirty (set flag to true) */ addDirtyCallback: function(ctx, callback, parameters, alwaysFire) { }, /** * Removes a callback handler previously added * * @param {Object} callback the callback funtion to be removed. * Must not be null */ removeDirtyCallback: function(fn){ } }); } if(!dojo._hasResource["com.ibm.mm.enabler.DirtyFlagProviderImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.DirtyFlagProviderImpl"] = true; dojo.provide("com.ibm.mm.enabler.DirtyFlagProviderImpl"); dojo.declare("com.ibm.mm.enabler.DirtyFlagProviderImpl", com.ibm.mashups.enabler.DirtyFlagProvider, { _dirty: false, setDirty: function() { this._setDirty(); }, _setDirty: function() { var wasFalse = this._dirty === false; this._dirty = true; if (this._dirtyCallbacks) { dojo.forEach(this._dirtyCallbacks, function(cb) { if ((wasFalse || cb.alwaysFire) && dojo.isFunction(cb.fn)) { dojo.hitch(cb.ctx || null, cb.fn)(cb.args); } }, this); } }, setClean: function() { this._setClean(); }, _setClean: function() { this._dirty = false; }, isDirty: function() { return this._dirty; }, _isDirty: function() { return this._dirty; }, addDirtyCallback: function(ctx, fn, args, alwaysFire) { this._addDirtyCallback(ctx, fn, args, alwaysFire); }, /** * ctx = context * fn = function to call * args = arguments to that function * alwaysFire (boolean) = whether to only fire when clean->dirty (set flag to false) or also fire when dirty->dirty (set flag to true) */ _addDirtyCallback: function(ctx, fn, args, alwaysFire) { if (!this._dirtyCallbacks) { this._dirtyCallbacks = []; } this._dirtyCallbacks.push({ ctx: ctx, fn: fn, args: args, alwaysFire: !!alwaysFire }); }, removeDirtyCallback: function(fn) { this._removeDirtyCallback(fn); }, _removeDirtyCallback: function(fn) { if (this._dirtyCallbacks) { for (var i = this._dirtyCallbacks.length; i > 0; i--) { if (fn === this._dirtyCallbacks[i - 1].fn) { this._dirtyCallbacks.splice(i - 1, 1); break; } } } } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.DirtyFlagProvider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.DirtyFlagProvider"] = true; dojo.provide("com.ibm.mashups.enabler.DirtyFlagProvider"); } if(!dojo._hasResource["com.ibm.mashups.enabler.Discardable_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.Discardable_API"] = true; dojo.provide("com.ibm.mashups.enabler.Discardable_API"); dojo.provide("com.ibm.mashups.enabler.Discardable"); /** * Discardable interface, which allows to discard artifacts or the whole * model. * * @since 2.4 * * @ibm-api * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.Discardable", null, { /** * Discards the specified node, or the whole model if no node is specified. * @parameter {Object} node node to discard, must not be null; optional * @type void */ discard : function(node) { } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.Discardable"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.Discardable"] = true; dojo.provide("com.ibm.mashups.enabler.Discardable"); } if(!dojo._hasResource["com.ibm.mashups.enabler.Identifiable"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.Identifiable"] = true; dojo.provide("com.ibm.mashups.enabler.Identifiable"); /** * Interface for any resource in the system that can be identified * @ibm-api * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.Identifiable", null, { /** * Returns the ID of the resource that implements the Identifiable interface. * @return {String} the identifier; never null */ getID: function(){ }, /** * Returns the unique name of the resource that implements the Identifiable interface. * @return {String} the unique name; never null * @private */ getUniqueName: function(){ } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.Invalidatable_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.Invalidatable_API"] = true; dojo.provide("com.ibm.mashups.enabler.Invalidatable_API"); dojo.provide("com.ibm.mashups.enabler.Invalidatable"); /** * Invalidatable interface, which allows to invalidate artifacts or the whole * model. * * @since 2.4 * * @ibm-api * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.Invalidatable", null, { /** * Invalidates the specified node, or the whole model if no node is specified. * * @param {Object} node node to invalidate, must not be null; optional * @type void */ invalidate : function(node) { } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.Invalidatable"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.Invalidatable"] = true; dojo.provide("com.ibm.mashups.enabler.Invalidatable"); } if(!dojo._hasResource["com.ibm.mashups.enabler.Locator"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.Locator"] = true; dojo.provide( "com.ibm.mashups.enabler.Locator"); /** * This interface defines search methods that allow locating resources in a model. * A resource is identified by its ID (mandatory). This interface is the base for all locators; * other locators allow a more specific search in the context they are offered in, * e.g. a search for a node with certain properties in a model.
* A Locator is usually obtained using the getLocator() method . *

 * var treeModel model = ...;
 * var locator = model.getLocator();
 * var node = locator.find(...);
 * 
* This locator returns an {@code Object} which is part of some model. * What exact kind of object is returned depends on the locator. * Please refer to individual JavaScriptDoc for the locator used. * The result object can be expected to be an element of the model * the locator is used on unless specified otherwise. * @ibm-api * @ibm-module Base */ dojo.declare( "com.ibm.mashups.enabler.Locator", null, { /** * Returns an element of a model with the given ID. * @param {com.ibm.mashups.enabler.Identifiable} id identifiable or string id of the object to find; * must not be null. * @return {com.ibm.mashups.enabler.Deferred} a deferred object used to start this operation. * The return value when executed through the deferred object is * the element with the given ID or null if the element cannot be found. */ find: function (id) { } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.ListModel"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.ListModel"] = true; dojo.provide("com.ibm.mashups.enabler.ListModel"); /** * A read-only model representing a list. Acting as a base class for all concrete list models. * @ibm-api * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.ListModel", [com.ibm.mashups.enabler.model.Model, com.ibm.mashups.enabler.Locator], { /** * Returns an iterator over elements of the list. * * @return {com.ibm.mashups.enabler.DeferredIterator} a deferred iterator */ iterator: function(){ } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.ListModelController"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.ListModelController"] = true; dojo.provide("com.ibm.mashups.enabler.ListModelController"); /** * A modifiable model representing a list. Acting as a base class for all concrete list models. * @ibm-api * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.ListModelController", com.ibm.mashups.enabler.ListModel, { /** * Creates a new model object. The created node can be inserted * into the model using an appropriate insert method defined * on a subinterface of this interface. The node will not appear in the model * unless it is inserted. * @param {JSON} context array of predefined information * used for the creation of the node. May be null. Accepted * names are defined in the appropriate subinterfaces * @type Object * @return the created node */ create: function(context){ }, /** * Confirms whether creating the node is possible. * @param {JSON} context array of predefined information * used for the creation of the node. May be null. Accepted * names are defined in the appropriate subinterfaces * @return {Boolean} true if the node can be created, otherwise false. */ confirmCreate: function(context){ }, /** * Inserts the specified node into the list model at the specified * position; the node must be created with the create method of the * concrete ListModel * * @param {Object} node node or node uri (without any scope) to * insert into the list model. Must not be * null * @param {Object} nextNode node object or node uri (without any scope) of * the successor node before which the node * is to be inserted; * if null is specified, the * node is appended at the end of the existing nodes * @type void */ insert: function(node, nextNode){ }, /** * Confirms whether inserting the node is possible. * @param {Object} node node or node uri (without any scope) to * insert into the list model. Must not be * null * @param {Object} nextNode node object or node uri (without any scope) of * the successor node before which the node * is to be inserted; * if null is specified, the * node is appended at the end of the existing nodes * @return {Boolean} true if the node can be inserted, otherwise false. */ confirmInsert: function(node, nextNode){ }, /** * Removes the specified node from the list model * * @param{Object} node node object or node uri (without any scope). * Must not be null * @type void */ remove: function(node){ }, /** * Confirms whether removing the node is possible. * @param{Object} node node object or node uri (without any scope). * Must not be null * @return {Boolean} true if the node can be removed, otherwise false. */ confirmRemove: function(node){ } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.Localized_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.Localized_API"] = true; dojo.provide("com.ibm.mashups.enabler.Localized_API"); dojo.provide("com.ibm.mashups.enabler.Localized"); /** * Read-Only interface providing methods to obtain title and description of a * resource. Please note that title or description are only returned if they * are available in the requested locale. No fallback for locales is performed. * @ibm-api * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.Localized", null, { /** * Returns an array containing the locales that are supported by this * object. The presence of a locale in this list does not mean that a title * and description is available, but rather that either one or both * are available in that locale.
*
* Note: Modifying the array does not change the supported locales. * @return {String[]} a list of locales defined for this object, returns an * empty array if no locales are supported. Can never be null. */ getLocales: function(){ }, /** * Returns the title of this object in the given locale. * @param {String} locale the locale for which to retrieve the title, * must not be null. * @return {String} the title of this node in the given locale. If a title is not * available in the given locale, this method will return null. * It is up to the invoker of the method to implement an appropriate fallback mechanism. */ getTitle: function(locale){ }, /** * Returns the titles of this object in a map (key: locale, value: title). * * @param {String} locale (optional) the locale for which to retrieve the titles, can be null. If locale is null/omitted, all are returned. * @return {Object} the titles of this node in a locale<->title map. If a locale was given, the result will be a map containing only those locales with country specific matches (e.g. if you give a locale "pt", you might also get brazilian portugese ("pt-BR") - if you give a locale "zh-TW", you won't get "zh"). If there are no titles (matching the given locale), an empty object will be returned. * * @since 3.0 */ getTitles: function(){ }, /** * Returns the description of this object in the given locale. * @param {String} locale the locale for which to retrieve the * description, must not be null. * @return {String} the description of this node in the given locale. If a * description is not available in the given locale, this method * will return null. It is up to the invoker of the * method to implement an appropriate fallback mechanism. */ getDescription: function(locale){ }, /** * Returns the descriptions of this object in a map (key: locale, value: description). * * @param {String} locale (optional) the locale for which to retrieve the descriptions, can be null. If locale is null/omitted, all are returned. * @return {Object} the descriptions of this node in a locale<->description map. If a locale was given, the result will be a map containing only those locales with country specific matches (e.g. if you give a locale "pt", you might also get brazilian portugese ("pt-BR") - if you give a locale "zh-TW", you won't get "zh"). If there are no descriptions (matching the given locale), an empty object will be returned. * * @since 3.0 */ getDescriptions: function(locale){ } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.ModifiableLocalized"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.ModifiableLocalized"] = true; dojo.provide("com.ibm.mashups.enabler.ModifiableLocalized"); /** * Modifiable interface providing methods to set title and description of a * resource. * @ibm-api * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.ModifiableLocalized", com.ibm.mashups.enabler.Localized, { /** * Sets the title for the given locale. * @param {String} title title to set; must not be null * @param {String} locale locale to set the title for; must not be null * @return {String} the former title; if none existed, null is returned */ setTitle: function(title, locale){ }, /** * Confirms whether setting the title for the given locale is possible. * @param {String} title title to set; must not be null * @param {String} locale locale to set the title for; must not be null * @return {Boolean} true if the value can be set, otherwise false. */ confirmSetTitle: function(title, locale){ }, /** * Removes the title for the given locale. * @param {String} locale locale of the title to remove; must not be null * @type void */ removeTitle: function(locale){ }, /** * Indicates if the title for the specified locale may be removed. * @param {String} locale locale for which to indicate if the title may be removed; must not be null * @return {Boolean} true if the title can be removed, otherwise false. */ confirmRemoveTitle: function(locale){ }, /** * Removes all titles. * @type void */ removeTitles: function(){ }, /** * Indicates if the titles for all locales may be removed. * @return {Boolean} true if all titles can be removed, otherwise * false. */ confirmRemoveTitles: function(){ }, /** * Sets the description for the given locale. * @param {String} desc description to set; must not be null * @param {String} locale locale to set the description for; must not be null * @return {String} the former description; if none existed, null is returned */ setDescription: function(desc, locale){ }, /** * Confirms whether setting the description for the given locale is possible. * @param {String} desc description to set; must not be null * @param {String} locale locale to set the description for; must not be null * @return {Boolean} true if the value can be set, otherwise false. */ confirmSetDescription: function(desc, locale){ }, /** * Removes the description for the given locale. * @param {String} locale locale of the description to remove; must not be null * @type void */ removeDescription: function(locale){ }, /** * Indicates if the description for the specified locale may be removed. * @param {String} locale locale for which to indicate if the description may be removed; must not be null * @return {Boolean} true if the description can be removed, otherwise false. */ confirmRemoveDescription: function(locale){ }, /** * Removes all description. * @type void */ removeDescriptions: function(){ }, /** * Indicates if the description for all locales may be removed. * @return {Boolean} true if all descriptions can be removed, otherwise * false. */ confirmRemoveDescriptions: function(){ } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.Localized"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.Localized"] = true; dojo.provide("com.ibm.mashups.enabler.Localized"); } if(!dojo._hasResource["com.ibm.mashups.enabler.Representation_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.Representation_API"] = true; dojo.provide("com.ibm.mashups.enabler.Representation_API"); dojo.provide("com.ibm.mashups.enabler.Representation"); /** * An interface that allows retrieving a URL and mime type representing the resource. * @ibm-api * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.Representation", com.ibm.mashups.enabler.Identifiable, { /** * Returns the mimetype of the representation. * @return {String} the identifier; never null */ getID: function(){ }, /** * Returns a full or absolute URL pointing to the resource in another representation. * @return {String} the URL pointing to the other representation; never null */ getURL: function(){ }, /** * Returns the mimetype of the content to which the URL is pointing to. * @return {String} the mimetype; never null */ getMimeType: function(){ } }); } if(!dojo._hasResource["com.ibm.mm.enabler.RepresentationImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.RepresentationImpl"] = true; dojo.provide( "com.ibm.mm.enabler.RepresentationImpl"); // representation dojo.declare( "com.ibm.mm.enabler.RepresentationImpl", com.ibm.mashups.enabler.Representation, { constructor:function (url, type) { this.url = url; this.type = type; }, getID: function() { return this.type; }, getURL: function() { return this.url; }, getMimeType: function() { return this.type; } } ); } if(!dojo._hasResource["com.ibm.mashups.enabler.Representation"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.Representation"] = true; dojo.provide("com.ibm.mashups.enabler.Representation"); } if(!dojo._hasResource["com.ibm.mashups.enabler.RepresentationProvider_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.RepresentationProvider_API"] = true; dojo.provide("com.ibm.mashups.enabler.RepresentationProvider_API"); dojo.provide("com.ibm.mashups.enabler.RepresentationProvider"); /** * An interface that allows to retrieve information about different representations of the resource. * @ibm-api * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.RepresentationProvider", null, { /** * Returns a ListModel containing information about the alternate representations available. The model contains Representation objects . * @see com.ibm.mashups.enabler.Representation * @return {com.ibm.mashups.enabler.ListModel} ListModel containing alternate representations of the resource; never null */ getAlternateModel: function(){ } }); } if(!dojo._hasResource["com.ibm.mm.enabler.RepresentationModelImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.RepresentationModelImpl"] = true; dojo.provide("com.ibm.mm.enabler.RepresentationModelImpl"); // alternate representation list model dojo.declare("com.ibm.mm.enabler.RepresentationModelImpl", [com.ibm.mashups.enabler.ListModel, com.ibm.mm.enabler.DeferredIteratorImpl], { constructor: function(nodes) { this.loadedNodes = {}; this.entries = []; this.cursor = 0; this.size = null; this.start = null; this.num = null; this.strategy = null; // now fill in loadedNodes and entries if (nodes && nodes.length > 0) { this.size = nodes.length; for (var i = 0; i < nodes.length; i++) { var link = nodes[i]; var url = link.getAttribute("href"); var mimetype = link.getAttribute("type"); // create a new representation node var uri = mimetype; var node = new com.ibm.mm.enabler.RepresentationImpl(url, mimetype); // setup the internal objects this.entries[i] = uri; this.loadedNodes[uri] = node; } } }, find: function(uri) { return new com.ibm.mm.enabler.DeferredImpl(this, this._find, uri); }, _find: function(deferred, sync, uri) { return this._load(uri, deferred, sync); }, start: function(sync) { while (this._hasNext(this, sync)) { if (this._next(this, sync)) { continue; } else { break; } } }, hasNext: function() { return this._hasNext(null, true); }, _hasNext: function(deferred, sync) { if (this.start === null || this.cursor < this.start || (this.cursor >= (this.start + this.num) && (this.size > this.cursor))) { this._loadAhead(deferred, sync); } return (this.size > this.cursor); }, next: function() { return this._next(null, true); }, _next: function(deferred, sync) { return this._hasNext(deferred, sync) ? this.loadedNodes[this.entries[this.cursor++]] : null; }, size: function() { return this.size; }, setCursorPosition: function(position) { this.cursor = position; }, getCursorPosition: function() { return this.cursor; }, setStrategy: function(strategy) { if (com.ibm.mm.enabler.utils.Misc.isInstanceOf(strategy, Array)) { // evaluate the first strategy only this.strategy = strategy[0]; } else { // backwards compatibility this.strategy = strategy; } }, _load: function(uri, deferred, sync) { if (uri in this.loadedNodes) { // fetch node from cache if(deferred) { deferred.finish(this.loadedNodes[uri], com.ibm.mm.enabler.model.HttpStatusCodes.HTTP_OK); } } return this.loadedNodes[uri]; }, _loadAhead: function(deferred, sync) { // noop } }); } if(!dojo._hasResource["com.ibm.mm.enabler.RepresentationProviderImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.RepresentationProviderImpl"] = true; dojo.provide("com.ibm.mm.enabler.RepresentationProviderImpl"); // representation provider dojo.declare("com.ibm.mm.enabler.RepresentationProviderImpl", com.ibm.mashups.enabler.RepresentationProvider, { constructor: function() { // service document and initialization this.serviceJson = com.ibm.mm.enabler.model.ServiceDocumentModel.getCollectionData(com.ibm.mm.enabler.model.ServiceDocumentModel.SERVICE_NAVIGATION); var nsf = com.ibm.mm.enabler.model.NameSpaceFactory; this.r_ns = dojo.delegate(this.serviceJson.namespaces, nsf.getNameSpaces([nsf.NS_ATOM, nsf.NS_XML])); this.XPATH = "atom:link"; }, getAlternateModel: function() { var validLinks = []; var md = com.ibm.mashups.enabler.xml.XPath.evaluateXPath(this.XPATH, this.xmlData, this.r_ns); if (md && md.length > 0) { for (var i = 0, l = md.length; i < l; i++) { var link = md[i]; var rel = link.getAttribute("rel"); var extrel = com.ibm.mm.enabler.utils.Dom.getAttributeWithNS(link, "ext:rel", "rel", this.r_ns.ext); if (extrel == "") { extrel = null; } if (((!rel) || (rel == 'alternate')) && (!extrel)) { validLinks[validLinks.length] = link; } } } var model = new com.ibm.mm.enabler.RepresentationModelImpl(validLinks); return model; } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.RepresentationProvider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.RepresentationProvider"] = true; dojo.provide("com.ibm.mashups.enabler.RepresentationProvider"); } if(!dojo._hasResource["com.ibm.mashups.enabler.ResourceLocator"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.ResourceLocator"] = true; dojo.provide("com.ibm.mashups.enabler.ResourceLocator"); /** * Interface for finding resources within a model. * @ibm-api * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.ResourceLocator", com.ibm.mashups.enabler.Locator, { /** * Returns the URL of the resource to be located, or null if the resource cannot be found. * @param {Object} node A node of the model this locator is implemented on. Must not be null. * @param {String} name The name of the resource to be located within the given model. The name can also contain a directory path relative to the model. Must not be null. * @return {String} The URL that can be used to fetch the resource, or null if the resource cannot be found. * @deprecated Use findResourceURL instead. */ findResourceUrl: function(node, name){ }, /** * Returns the URL of the resource to be located, or null if the resource cannot be found. * @param {Object} node A node of the model this locator is implemented on. Must not be null. * @param {String} name The name of the resource to be located within the given model. The name can also contain a directory path relative to the model. Must not be null. * @return {String} The URL that can be used to fetch the resource, or null if the resource cannot be found. */ findResourceURL: function(node, name){ } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.SubmittableForm_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.SubmittableForm_API"] = true; dojo.provide("com.ibm.mashups.enabler.SubmittableForm_API"); dojo.provide("com.ibm.mashups.enabler.SubmittableForm"); /** * An interface representing a submittable form. Submittable forms can be used * to import resources of models, which implement the SubmittableFormProvider * interface, for example spaces or templates. The provider of submittable forms * automatically set the necessary URL parameters, such as enctype, action and method. * To submit a submittable form, you invoke the submit()-method, which in turn * imports the resource using an appropriate xhr request.

* Example:
* * var form = spaceModel.getSubmittableImportForm(spaceId);
* form.submit().start();
*
* @ibm-api * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.SubmittableForm", com.ibm.mashups.enabler.Identifiable, { /** * Returns the URL this form is submitted to. Used to fill in the action attribute in the form. * @return {String} the URL this form is submitted to; never null */ getURL: function(){ }, /** * Returns the HTTP method used to submit this form. Used to fill in the method attribute in the form. * @return {String} the method; never null */ getMethod: function(){ }, /** * Submits the form * @return {com.ibm.mashups.enabler.Deferred} a deferred object used to start this operation. */ submit: function(){ } }); } if(!dojo._hasResource["com.ibm.mm.enabler.SubmittableFormImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.SubmittableFormImpl"] = true; dojo.provide("com.ibm.mm.enabler.SubmittableFormImpl"); dojo.declare("com.ibm.mm.enabler.SubmittableFormImpl", com.ibm.mashups.enabler.SubmittableForm, { constructor: function(url, method, formId){ this.url = url; this.method = method; this.formId = formId; }, /** * Returns the URL this form is submitted to. Used to fill in the action attribute in the form. * @return {String} the URL this form is submitted to; never null */ getURL: function(){ return this.url; }, /** * Returns the HTTP method used to submit this form. Used to fill in the method attribute in the form. * @return {String} the method; never null */ getMethod: function(){ return this.method; }, /** * Submits the form * @return {com.ibm.mashups.enabler.Deferred} a deferred object used to start this operation. */ submit: function(){ return new com.ibm.mm.enabler.DeferredImpl(this, this._submit); }, /** * Submits the form * @return {com.ibm.mashups.enabler.Deferred} a deferred object used to start this operation. */ _submit: function(deferred){ dojo.io.iframe.send({ url: this.url, method: this.method, handleAs: "text", // For IE issue form: document.getElementsByName(this.formId)[0], load: function(data, ioArgs){ if(deferred) { deferred.finish(data, com.ibm.mm.enabler.model.HttpStatusCodes.HTTP_CREATED); } }, error: function(data, ioArgs){ if(deferred) { deferred.finish(data, com.ibm.mm.enabler.model.HttpStatusCodes.HTTP_NOT_FOUND); } } }); } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.SubmittableForm"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.SubmittableForm"] = true; dojo.provide("com.ibm.mashups.enabler.SubmittableForm"); } if(!dojo._hasResource["com.ibm.mashups.enabler.SubmittableFormProvider_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.SubmittableFormProvider_API"] = true; dojo.provide("com.ibm.mashups.enabler.SubmittableFormProvider_API"); dojo.provide("com.ibm.mashups.enabler.SubmittableFormProvider"); /** * An interface that allows to retieve submittable form * @ibm-api * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.SubmittableFormProvider", null, { /** * Returns a SubmittableForm object associated with the given id. * @param {String} id the id of the html form this object is associated with * @return {com.ibm.mashups.enabler.SubmittableForm} SubmittableForm object, maybe null */ getSubmittableForm: function(id){ } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.model.url.ModelUrl_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.url.ModelUrl_API"] = true; dojo.provide("com.ibm.mashups.enabler.model.url.ModelUrl_API"); dojo.provide("com.ibm.mashups.enabler.model.url.ModelUrl"); /** * Interface representing a model URL. This class should be used by the specific model * API's in order to generate a valid model URL. The low level classes like ModelRestServiceRequest * expect a request to be made with an implementation of the interface. It also allows an easy way * to handle URIs. e.g.
* <scheme>:<primaryNode>@<secondaryNode> * scheme-specific part = <primaryNode>@<secondaryNode> * * @ibm-spi * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.model.url.ModelUrl", null, { /** * @private */ constructor: function () { }, /** * Sets the nodes of the scheme-specific part. * @param {JSONArray} nodes an array containing the nodes of the scheme-specific part in a JSON notation way.
* The ordering of the array elements specifies the position of the node, meaning * the array element 0 will become node 1 and so on and so forth.

* valid JSON attributes are:
*
    *
  • value {String} [mandatory]
  • *
  • isID {boolean} [optional, default: true]
  • *
  • subModel {String} [optional]
  • *

* example for "nodes":
* * [ {
* value: "100",
* isID: false,
* subModel: "member"
* } ] *
* @type {void} */ setNodes: function(nodes) { }, /** * Sets the scheme-specific part of the unerlying URI. * @param {String} value the value for the scheme-specifc part. (Must not be null) * @type {void} */ setSchemeSpecificPart: function (value) { }, /** * Returns the scheme-specific part of the underlying URI. * @type {String} * @return the scheme-specific part. If a scheme-specific part was set through setSchemeSpecificPart * the raw value will be returned. If the SSP was set by using setNodes, * the converted part will be returned. If neither a node nor the raw SSP was set, * this method returns null. */ getSchemeSpecificPart: function() { return null; }, /** * Adds the value of the specified parameter. * @param {String} name the name of the parameter; must not be null. * @param {String} value the value of the parameter. Valid is only a single String. (Must not be null) * @type {void} */ addParameter: function (name, value) { }, /** * Sets the value(s) of the specified parameter. * @param {String} name the name of the parameter; must not be null. * @param {String} value the value of the parameter. Valid are either a single String or a String array. (Must not be null) * @type {void} */ setParameter: function (name, value) { }, /** * Returns the value(s) of the specified parameter. * @param {String} name the name of the parameter; must not be null. * @type {String} * @return the value(s) of the specified parameter or null if the specified parameter wasn't found. In case the parameter has one value * the return type is String. For multiple values a String array is returned. */ getParameter: function (name) { return null; }, /** * Returns the parameters as an object. Note: this must be used read-only * @type {JSON} * @return an object containing all parameters in the format { <name>: [<value>, <value>, ... ], ... } */ getParameters: function() { return null; }, /** * Returns the absolute URL of this object. * @type {String} * @return the absolute URL of this object. e.g. http://myhost/contenthandler?uri=acme:id:myid * or /contenthandler?uri=acme:id:myid */ getAbsoluteURL: function () { return null; }, /** * The same as getAbsoluteURL with the difference that this URL is (if needed) converted to a proxified URL * @type {String} * @return the proxified absolute URL. e.g. http://acme.com/proxy/http/myhost/contenthandler?uri=acme:id:myid */ getProxifiedAbsoluteURL: function () { return null; }, /** * Returns the model URI of this object. If the complete link is e.g. /mum/contenthandler?uri=acme:id:myid, * this method will return acme:id:myid. * @type {String} * @return the URI portion of this Model URL. */ getModelURI: function () { return null; } } ); } if(!dojo._hasResource["com.ibm.mashups.enabler.model.url.ModelUrl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.url.ModelUrl"] = true; dojo.provide("com.ibm.mashups.enabler.model.url.ModelUrl"); } if(!dojo._hasResource["com.ibm.mashups.enabler.model.url.ModelUrlFactory_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.url.ModelUrlFactory_API"] = true; dojo.provide("com.ibm.mashups.enabler.model.url.ModelUrlFactory_API"); dojo.provide("com.ibm.mashups.enabler.model.url.ModelUrlFactory"); /** * Interface for a ModelUrl Factory that allows to generate ModelUrl's a comfortable way. * This class should not be instantiated directly, but should be used through it's defined singleton * (com.ibm.mashups.enabler.model.url.ModelUrlFactory). * @ibm-spi * @ibm-module Base */ dojo.declare( "com.ibm.mashups.enabler.model.url.ModelUrlFactory", null, { /** * Constant for creation of a navigation URL * @type {String} */ NAVIGATION_URL: "nav", /** * Constant for creation of a layout URL * @type {String} */ LAYOUT_URL: "layout", /** * Constant for creation of a shared navigation URL * @type {String} */ SHARED_NAVIGATION_URL: "sharednav", /** * Constant for creation of a fragment URL * @type {String} */ FRAGMENT_URL: "fragment", /** * Constant for creation of a fragment-media URL * @type {String} */ FRAGMENT_MEDIA_URL: "fragment-media", /** * Constant for creation of a user URL * @type {String} */ USER_URL: "user", /** * Constant for creation of a theme URL * @type {String} */ THEME_URL: "theme", /** * Constant for creation of a theme-media URL * @type {String} */ THEME_MEDIA_URL: "theme-media", /** * Constant for creation of a catalog URL * @type {String} */ CATALOG_URL: "cat", /** * Constant for creation of a config URL * @type {String} */ CONFIG_URL: "config", /** * Constant for creation of a space URL * @type {String} */ SPACE_URL: "space", /** * Constant for creation of a space-favorite URL * @type {String} */ SPACE_FAVORITE_URL: "space-favorite", /** * Constant for creation of a ac URL * @type {String} */ AC_URL: "ac", /** * Constant for creation of a ac URL * @type {String} */ AI_URL: "ai", /** * Constant for creation of a template URL * @type {String} */ TEMPLATE_URL: "template", /** * Constant for widget model * @type {String} */ WIDGET_URL: "widget", /** * Constant for event model * @type {String} */ EVENT_URL: "event", /** * Constant for member sub model * @type {String} */ SUBMODEL_MEMBER: "member", /** * Constant for role sub model * @type {String} */ SUBMODEL_ROLE: "role", /** * Constant for allowed-access sub model * @type {String} */ SUBMODEL_ACCESS: "access", /** * Constant for resource sub model * @type {String} */ SUBMODEL_RESOURCE: "resource", RESOURCE_URL: "resource-service", /** * @private **/ constructor:function () { }, /** * Create a ModelUrl based on the specified urlType. Afterwards parameters and scheme * specific parts can be changed.
* Sample: *
var myURL = com.ibm.mashups.enabler.model.url.ModelUrlFactory.createModelURL(com.ibm.mashups.enabler.model.url.ModelUrlFactory.NAVIGATION_URL, this);
* @param {String} urlType the type of ModelUrl that should be created. You should use the URL constants that are defined in this interface. (Must not be null) * @param {com.ibm.mashups.enabler.model.Model} model the model used to create this ModelUrl object for. (Might be null) * @type {com.ibm.mashups.enabler.model.url.ModelUrl} * @return the created ModelUrl. Returns null if the specified urlType is not known. * @deprecated Use createModelURL instead. */ createModelUrl: function (urlType, model) { return new com.ibm.mashups.enabler.model.url.ModelUrl(urlType, model); }, /** * Create a ModelUrl based on the specified urlType. Afterwards parameters and scheme * specific parts can be changed.
* Sample: *
var myURL = com.ibm.mashups.enabler.model.url.ModelUrlFactory.createModelURL(com.ibm.mashups.enabler.model.url.ModelUrlFactory.NAVIGATION_URL, this);
* @param {String} urlType the type of ModelUrl that should be created. You should use the URL constants that are defined in this interface. (Must not be null) * @param {com.ibm.mashups.enabler.model.Model} model the model used to create this ModelUrl object for. (Might be null) * @type {com.ibm.mashups.enabler.model.url.ModelUrl} * @return the created ModelUrl. Returns null if the specified urlType is not known. */ createModelURL: function (urlType, model) { return new com.ibm.mashups.enabler.model.url.ModelUrl(urlType, model); }, /** * Create a ModelUrl based on the specified URL. Afterwards parameters and scheme specific parts can be changed. * @param {String} url the URL that should be used to create a ModelUrl. (Must not be null) * @param {com.ibm.mashups.enabler.model.Model} model the model used to create this ModelUrl object for. (Might be null) * @type {com.ibm.mashups.enabler.model.url.ModelUrl} * @return the created ModelUrl (Must not be null). * @deprecated Use getModelURL instead. */ getModelUrl: function (url, model) { return new com.ibm.mashups.enabler.model.url.ModelUrl(url, model); }, /** * Create a ModelUrl based on the specified URL. Afterwards parameters and scheme specific parts can be changed. * @param {String} url the URL that should be used to create a ModelUrl. (Must not be null) * @param {com.ibm.mashups.enabler.model.Model} model the model used to create this ModelUrl object for. (Might be null) * @type {com.ibm.mashups.enabler.model.url.ModelUrl} * @return the created ModelUrl (Must not be null). */ getModelURL: function (url, model) { return new com.ibm.mashups.enabler.model.url.ModelUrl(url, model); } } ); } if(!dojo._hasResource["com.ibm.mm.enabler.model.url.BaseModelUrl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.model.url.BaseModelUrl"] = true; dojo.provide("com.ibm.mm.enabler.model.url.BaseModelUrl"); dojo.declare("com.ibm.mm.enabler.model.url.BaseModelUrl", [com.ibm.mashups.enabler.model.url.ModelUrl], { modelSchema: null, schemeSpecific: null, isMediaUrl: false, httpUrl: null, VALUE: "value", IS_ID: "isID", SUBMODEL: "submodel", constructor: function() { this.nodes = []; this.prefix = null; this.subModelSchemeMap = {}; this.subModelSchemeMap[com.ibm.mashups.enabler.model.url.ModelUrlFactory.SUBMODEL_RESOURCE] = "resource"; this.subModelSchemeMap[com.ibm.mashups.enabler.model.url.ModelUrlFactory.SUBMODEL_ROLE] = "role"; this.subModelSchemeMap[com.ibm.mashups.enabler.model.url.ModelUrlFactory.SUBMODEL_MEMBER] = "member"; this.subModelSchemeMap[com.ibm.mashups.enabler.model.url.ModelUrlFactory.SUBMODEL_ACCESS] = "access"; }, _loadPrefix: function() { if (!this.prefix) { // service document and initialization this.serviceJson = com.ibm.mm.enabler.model.ServiceDocumentModel.getCollectionData(com.ibm.mm.enabler.model.ServiceDocumentModel.SERVICE_NAVIGATION); this.prefix = this.serviceJson.idprefix; } }, setPrimaryNode: function(value, isID, subModel) { var primary = {}; primary.value = value; primary.isID = (isID === false) ? isID : true; primary.subModel = subModel; this.nodes[0] = primary; this._updateURI(); }, setSecondaryNode: function(value, isID, subModel) { var secondary = {}; secondary.value = value; secondary.isID = (isID === false) ? isID : true; secondary.subModel = subModel; this.nodes[1] = secondary; this._updateURI(); }, setNodes: function(nodes) { this.nodes = nodes; for (var i = 0; i < nodes.length; i++) { nodes[i].isID = (nodes[i].isID === false) ? nodes[i].isID : true; } this._updateURI(); }, setSchemeSpecificPart: function(value) { this.nodes = []; this.schemeSpecific = value; this._updateURI(); }, getSchemeSpecificPart: function() { if (this.schemeSpecific) { return this.schemeSpecific; } var tempSSP = ""; if (this.isMediaUrl) { tempSSP = "/"; } if (!this.nodes) { return tempSSP; } var i, node; if (this.isMediaUrl) { for (i = 0; i < this.nodes.length; i++) { node = this.nodes[i]; // the prefix MUST only be loaded if the prefix is needed, since the // loading method uses this function as well which would causea infinite loop if (node.isID && !this.prefix) { this._loadPrefix(); } if (i > 0) { if (i < this.nodes.length - 1) { tempSSP += "@"; } else { tempSSP += "/"; } } tempSSP += node.value; } } else { for (i = 0; i < this.nodes.length; i++) { node = this.nodes[i]; // the prefix MUST only be loaded if the prefix is needed, since the // loading method uses this function as well which would causea infinite loop if (node.isID && !this.prefix) { this._loadPrefix(); } if (tempSSP != "") { tempSSP += "@"; } if (node.subModel) { tempSSP += this.subModelSchemeMap[node.subModel] + ":"; } if (node.isID) { tempSSP += this.prefix + ":"; } tempSSP += node.value; } } return tempSSP; }, _updateURI: function() { var uri = this.modelSchema + ":" + this.getSchemeSpecificPart(); this.httpUrl.setParameter("uri", uri); }, addParameter: function(name, value) { this.httpUrl.addParameter(name, value); }, setParameter: function(name, value) { this.httpUrl.setParameter(name, value); }, getParameter: function(name) { return this.httpUrl.getParameter(name); }, getParameters: function() { return this.httpUrl.getParameters(); }, getAbsoluteURL: function() { return this.httpUrl.toString(); }, getProxifiedAbsoluteURL: function() { return this.httpUrl.toProxifiedString(); }, getModelURI: function() { return this.httpUrl.getParameter("uri"); }, toProxifiedString: function() { // TBD: REMOVE AFTER FULL SWITCH return this.httpUrl.toProxifiedString(); } }); } if(!dojo._hasResource["com.ibm.mm.enabler.model.url.SchemeBasedModelUrlImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.model.url.SchemeBasedModelUrlImpl"] = true; dojo.provide("com.ibm.mm.enabler.model.url.SchemeBasedModelUrlImpl"); dojo.declare("com.ibm.mm.enabler.model.url.SchemeBasedModelUrlImpl", [com.ibm.mm.enabler.model.url.BaseModelUrl], { constructor: function(modelSchema, model) { this.modelSchema = modelSchema; this.model = model; var configService = com.ibm.mashups.services.ServiceManager.getService(com.ibm.mashups.enabler.services.ConfigService.SERVICE_NAME); var url = ""; // add the contextroot url += configService.getValue(com.ibm.mashups.enabler.services.ConfigConstants.CONTEXT_ROOT); // add the public contenthandler url var anonymousUser = configService.getValue(com.ibm.mashups.enabler.services.ConfigConstants.ANONYMOUS_USER); var contenthandlerPath; if (anonymousUser) { contenthandlerPath = configService.getValue(com.ibm.mashups.enabler.services.ConfigConstants.CONTENTHANDLER_PUBLIC); } else { contenthandlerPath = configService.getValue(com.ibm.mashups.enabler.services.ConfigConstants.CONTENTHANDLER_PRIVATE); } url += contenthandlerPath; this.httpUrl = new com.ibm.mm.enabler.utils.HttpUrl(url); this.httpUrl.setParameter("uri", this.modelSchema); // first initialization } }); } if(!dojo._hasResource["com.ibm.mm.enabler.model.url.SchemeBasedModelMediaUrlImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.model.url.SchemeBasedModelMediaUrlImpl"] = true; dojo.provide("com.ibm.mm.enabler.model.url.SchemeBasedModelMediaUrlImpl"); dojo.declare("com.ibm.mm.enabler.model.url.SchemeBasedModelMediaUrlImpl", [com.ibm.mm.enabler.model.url.SchemeBasedModelUrlImpl], { constructor: function(modelSchema, model) { this.isMediaUrl = true; } }); } if(!dojo._hasResource["com.ibm.mm.enabler.model.url.ThemeResourceUrlImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.model.url.ThemeResourceUrlImpl"] = true; dojo.provide("com.ibm.mm.enabler.model.url.ThemeResourceUrlImpl"); dojo.declare("com.ibm.mm.enabler.model.url.ThemeResourceUrlImpl", [com.ibm.mm.enabler.model.url.BaseModelUrl], { constructor: function (modelSchema, model) { this.modelSchema = modelSchema; this.model = model; this.httpUrl = new com.ibm.mm.enabler.utils.HttpUrl("/"); this.httpUrl.setParameter("uri", this.modelSchema); // first initialization }, _updateURI: function() { // at this point we know it must be a theme or skin resource we try to fetch var resource, url; if (this.nodes.length==2) { // theme var themeId = this.nodes[0].value; resource = this.nodes[1].value; var themeNode = this.model.find(themeId).start(); url = themeNode._getBaseUrl(); this.httpUrl = new com.ibm.mm.enabler.utils.HttpUrl(url+resource); } else if (this.nodes.length==3) { // skin var skinId = this.nodes[0].value; //var themeId = this.nodes[1].value; resource = this.nodes[2].value; var skinNode = this.model.find(skinId).start(); url = skinNode._getBaseUrl(); this.httpUrl = new com.ibm.mm.enabler.utils.HttpUrl(url+resource); } else { this.httpUrl = new com.ibm.mm.enabler.utils.HttpUrl("/"); } } } ); } if(!dojo._hasResource["com.ibm.mm.enabler.model.url.StringBasedModelUrlImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.model.url.StringBasedModelUrlImpl"] = true; dojo.provide("com.ibm.mm.enabler.model.url.StringBasedModelUrlImpl"); dojo.declare("com.ibm.mm.enabler.model.url.StringBasedModelUrlImpl", [com.ibm.mm.enabler.model.url.BaseModelUrl], { constructor: function(url, model) { if (!com.ibm.mm.enabler.model.url.StringBasedModelUrlImpl.CONTEXT_ROOT) { com.ibm.mm.enabler.model.url.StringBasedModelUrlImpl.CONTEXT_ROOT = com.ibm.mashups.services.ServiceManager.getService(com.ibm.mashups.enabler.services.ConfigService.SERVICE_NAME).getValue(com.ibm.mashups.enabler.services.ConfigConstants.CONTEXT_ROOT); com.ibm.mm.enabler.model.url.StringBasedModelUrlImpl.PRIVATE_HANDLER = com.ibm.mm.enabler.model.url.StringBasedModelUrlImpl.CONTEXT_ROOT + com.ibm.mashups.services.ServiceManager.getService(com.ibm.mashups.enabler.services.ConfigService.SERVICE_NAME).getValue(com.ibm.mashups.enabler.services.ConfigConstants.CONTENTHANDLER_PRIVATE); com.ibm.mm.enabler.model.url.StringBasedModelUrlImpl.PUBLIC_HANDLER = com.ibm.mm.enabler.model.url.StringBasedModelUrlImpl.CONTEXT_ROOT + com.ibm.mashups.services.ServiceManager.getService(com.ibm.mashups.enabler.services.ConfigService.SERVICE_NAME).getValue(com.ibm.mashups.enabler.services.ConfigConstants.CONTENTHANDLER_PUBLIC); } if (url.indexOf("?") === 0) { // add the public contenthandler url var anonymousUser = com.ibm.mashups.services.ServiceManager.getService(com.ibm.mashups.enabler.services.ConfigService.SERVICE_NAME).getValue(com.ibm.mashups.enabler.services.ConfigConstants.ANONYMOUS_USER); var contenthandlerPath; if (anonymousUser) { contenthandlerPath = com.ibm.mm.enabler.model.url.StringBasedModelUrlImpl.PUBLIC_HANDLER; } else { contenthandlerPath = com.ibm.mm.enabler.model.url.StringBasedModelUrlImpl.PRIVATE_HANDLER; } var newURL = ""; // add contenthandlerPath newURL += contenthandlerPath; url = newURL + url; } this.httpUrl = new com.ibm.mm.enabler.utils.HttpUrl(url); } }); } if(!dojo._hasResource["com.ibm.mm.enabler.model.url.ModelUrlFactoryImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.model.url.ModelUrlFactoryImpl"] = true; dojo.provide("com.ibm.mm.enabler.model.url.ModelUrlFactoryImpl"); dojo.declare("com.ibm.mm.enabler.model.url.ModelUrlFactoryImpl", [com.ibm.mashups.enabler.model.url.ModelUrlFactory], { WEBDAV_URL: "webdav", /** * @private **/ constructor: function() { this.schemeMap = {}; this.schemeMap[this.NAVIGATION_URL] = "nm"; this.schemeMap[this.SHARED_NAVIGATION_URL] = "snm"; this.schemeMap[this.FRAGMENT_URL] = "fragment"; this.schemeMap[this.FRAGMENT_MEDIA_URL] = "fragment-media"; this.schemeMap[this.USER_URL] = "um"; this.schemeMap[this.THEME_URL] = "theme"; this.schemeMap[this.THEME_MEDIA_URL] = "theme-media"; this.schemeMap[this.CATALOG_URL] = "catalog"; this.schemeMap[this.CONFIG_URL] = "config"; this.schemeMap[this.SPACE_URL] = "space"; this.schemeMap[this.SPACE_FAVORITE_URL] = "space-favorite"; this.schemeMap[this.AC_URL] = "ac"; this.schemeMap[this.AI_URL] = "ai"; this.schemeMap[this.TEMPLATE_URL] = "template"; this.schemeMap[this.LAYOUT_URL] = "lm"; // internal, not exposed this.schemeMap.service = "service"; this.schemeMap[this.WEBDAV_URL] = "dav:mmdav"; this.schemeMap[this.WIDGET_URL] = "wm"; this.schemeMap[this.EVENT_URL] = "ce"; this.schemeMap[this.RESOURCE_URL] = "resource-service"; }, // @deprecated createModelUrl: function(urlType, model) { return this.createModelURL(urlType, model); }, createModelURL: function(urlType, model) { var modelSchema = com.ibm.mashups.enabler.model.url.ModelUrlFactory.schemeMap[urlType]; if (!modelSchema) { return null; } var urlImpl; if (urlType == this.THEME_MEDIA_URL) { urlImpl = new com.ibm.mm.enabler.model.url.ThemeResourceUrlImpl(modelSchema, model); } else if (urlType == this.FRAGMENT_MEDIA_URL) { urlImpl = new com.ibm.mm.enabler.model.url.SchemeBasedModelMediaUrlImpl(modelSchema, model); } else { urlImpl = new com.ibm.mm.enabler.model.url.SchemeBasedModelUrlImpl(modelSchema, model); } return urlImpl; }, // @deprecated getModelUrl: function(url, model) { return this.getModelURL(url, model); }, getModelURL: function(url, model) { return new com.ibm.mm.enabler.model.url.StringBasedModelUrlImpl(url, model); } }); // legacy com.ibm.mm.enabler.model.UrlFactory = new com.ibm.mm.enabler.model.url.ModelUrlFactoryImpl(); // define public factory com.ibm.mashups.enabler.model.url.ModelUrlFactory = com.ibm.mm.enabler.model.UrlFactory; } if(!dojo._hasResource["com.ibm.mashups.enabler.model.url.ModelUrlFactory"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.url.ModelUrlFactory"] = true; dojo.provide("com.ibm.mashups.enabler.model.url.ModelUrlFactory"); } if(!dojo._hasResource["com.ibm.mm.enabler.SubmittableFormProviderImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.SubmittableFormProviderImpl"] = true; dojo.provide("com.ibm.mm.enabler.SubmittableFormProviderImpl"); // submittable form provider dojo.declare("com.ibm.mm.enabler.SubmittableFormProviderImpl", com.ibm.mashups.enabler.SubmittableFormProvider, { constructor: function(){ }, /** * Returns a SubmittableForm object associated with the given id. * @param {String} id the id of the html form this object is associated with * @return {SubmittableForm} SubmittableForm object, maybe null */ getSubmittableForm: function(id){ var model = null; var url; if (id == "spaceForm") { url = new com.ibm.mashups.enabler.model.url.ModelUrlFactory.createModelURL(com.ibm.mashups.enabler.model.url.ModelUrlFactory.SPACE_URL, null); url.setNodes([{ value: "collection", isID: false }]); url.setParameter("mode", "import"); url.setParameter("mime-type", "text/html"); url = url.toProxifiedString(); /*"/mum/mycontenthandler?uri=space:collection&mode=import"*/ model = new com.ibm.mm.enabler.SubmittableFormImpl(url, "post", id); } else if (id == "pageForm") { var serviceJson = com.ibm.mm.enabler.model.ServiceDocumentModel.getCollectionData(com.ibm.mm.enabler.model.ServiceDocumentModel.SERVICE_RESOURCE); url = new com.ibm.mashups.enabler.model.url.ModelUrlFactory.getModelURL(serviceJson.url, this); url.setParameter("mode", "import"); url.setParameter("mime-type", "text/html"); // post the spaceId to server. if (arguments[1]) { url.setParameter("spaceId", arguments[1]); } url = url.toProxifiedString(); /*"/mum/mycontenthandler?uri=resource:collection&mode=import"*/ model = new com.ibm.mm.enabler.SubmittableFormImpl(url, "post", id); } else if (id == "spacePageForm") { url = new com.ibm.mashups.enabler.model.url.ModelUrlFactory.createModelURL(com.ibm.mashups.enabler.model.url.ModelUrlFactory.SPACE_URL, null); url.setNodes([{ value: "collection", isID: false }]); url.setParameter("mode", "import"); url.setParameter("mime-type", "text/html"); // When we import page .data file came from old BSpace data, we should use the import space rest api, and post spaceId to server. if (arguments[1]) { url.setParameter("spaceId", arguments[1]); } // The form id is come from the arguments[2] var postForm = null; if (arguments[2]) { postForm = arguments[2]; } url = url.toProxifiedString(); /*"/mum/mycontenthandler?uri=space:collection&mode=import"*/ model = new com.ibm.mm.enabler.SubmittableFormImpl(url, "post", postForm); } return model; } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.SubmittableFormProvider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.SubmittableFormProvider"] = true; dojo.provide("com.ibm.mashups.enabler.SubmittableFormProvider"); } if(!dojo._hasResource["com.ibm.mashups.enabler.TimeStamped_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.TimeStamped_API"] = true; dojo.provide("com.ibm.mashups.enabler.TimeStamped_API"); dojo.provide("com.ibm.mashups.enabler.TimeStamped"); /** * Model interface for specific date access properties: This is information such as the * creation date or the last modification date of a resource. * @ibm-api * @ibm-module Base */ dojo.declare( "com.ibm.mashups.enabler.TimeStamped", null, { /** * Returns the creation date of the resource. * @return {Date} the creation date, never null. */ getCreated: function () { }, /** * Returns the modification date of the resource. * @return {Date} the modification date, never null. */ getLastModified: function () { } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.TimeStamped"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.TimeStamped"] = true; dojo.provide( "com.ibm.mashups.enabler.TimeStamped" ); } if(!dojo._hasResource["com.ibm.mashups.enabler.Transformable_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.Transformable_API"] = true; dojo.provide("com.ibm.mashups.enabler.Transformable_API"); dojo.provide("com.ibm.mashups.enabler.Transformable"); /** * Interface for resources in the system that can be transformed * @ibm-spi * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.Transformable", null, { /** * Returns the xml representation of the resource. It may be modified, * e.g. with an xsl transformation. * WARNING: Please note that you must change the xml representation * of the resource in a compatible way only, since the Enabler API * operates on this representation. Otherwise the Enabler API may * function incorrectly or break. * @return {Object} the xml representation; never null */ getXml: function() { }, /** * Sets the specified xml of the resource. * WARNING: Please note that you must set a valid xml representation * of the resource, since the Enabler API operates on this representation. * Otherwise the Enabler API may function incorrectly or break. * @param {Object} xml the xml representation to set for the resource */ setXml: function(xml) { } }); } if(!dojo._hasResource["com.ibm.mm.enabler.TransformableImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.TransformableImpl"] = true; dojo.provide("com.ibm.mm.enabler.TransformableImpl"); // transformable dojo.declare("com.ibm.mm.enabler.TransformableImpl", [com.ibm.mashups.enabler.Transformable, com.ibm.mm.enabler.DirtyFlagProviderImpl], { constructor: function() { }, getXml: function() { return this.xmlData; }, setXml: function(xml, keepClean) { this.xmlData = xml; if (this._resetCachedRawID) { // if this also implements the IdentifiableXml aspect we need to clean out any cached raw id at this point this._resetCachedRawID(); } if (!keepClean) { this._setDirty(); } } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.Transformable"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.Transformable"] = true; dojo.provide("com.ibm.mashups.enabler.Transformable"); } if(!dojo._hasResource["com.ibm.mashups.enabler.TreeModel"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.TreeModel"] = true; dojo.provide("com.ibm.mashups.enabler.TreeModel"); /** * This interface provides a generic tree model acting as a base class * for all concrete tree models * @ibm-api * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.TreeModel", [com.ibm.mashups.enabler.model.Model, com.ibm.mashups.enabler.Locator], { /** * Returns the root node of the model; may return null * if the concrete tree model supports for empty models * * @type Deferred * @return a deferred object used to start this operation. The * return value when executed through the deferred object * is the root object of the tree model */ getRoot: function(){ }, /** * Returns whether or not the given node has children. Please pay * attention to the documentation of the return value; it is not * guaranteed that children are present if the method returns * true - the iterator might be empty. * * @param {Object} node node object or node uri (without any scope) * for which to check if it has children. Must * not be null. * @return {Boolean} true if the specified node has children, false otherwise */ hasChildren: function(node){ }, /** * Returns an iterator over the child elements for the given node. * * @param {Object} node node object or node uri (without any scope) * for which to return its children. Must not * be null. * @return {com.ibm.mashups.enabler.DeferredIterator} deferred iterator for the children of the given node. * Never null */ getChildren: function(node){ }, /** * Returns the parent of a given node. * @param {Object} node node object or node uri (without any scope) * for which to return its parent. Must not * be null. * @return {com.ibm.mashups.enabler.Deferred} a deferred object used to start this operation. The * return value when executed through the deferred object * is the parent of the given node, or null * if the node has no parent */ getParent: function(node){ } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.TreeModelController"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.TreeModelController"] = true; dojo.provide("com.ibm.mashups.enabler.TreeModelController"); /** * This modifiable interface provides a generic tree model acting as a base class * for all concrete tree models * @ibm-api * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.TreeModelController", com.ibm.mashups.enabler.TreeModel, { /** * creates a new model object. The created node can be inserted * into the model using an appropriate insert method defined * on a subinterface of this interface. The node will not appear in the model * unless it is inserted. * @param {JSON} context array of predefined information * used for the creation of the node. May be null. Accepted * names are defined in the appropriate subinterfaces * @type Object * @return the created node */ create: function(context){ }, /** * Confirms whether creating the node is possible. * @param {JSON} context array of predefined information * used for the creation of the node. May be null. Accepted * names are defined in the appropriate subinterfaces * @return {Boolean} true if the node can be created, otherwise false. */ confirmCreate: function(context){ }, /** * Inserts a node into the tree model at the specified location; * the node must either be created with the create method of the * concrete tree model before, or must exist in the tree model; * in this case the existing node is moved to the specified location * * @param {Object} node node to insert or move. Must not be * null. * @param {Object} parentNode node object or node uri (without any * scope) of the parent node. The given * node is inserted/moved underneath the * parent node; must not be null. * @param {Object} nextNode node object or node uri (without any * scope) of the successor node before * which the node is to be inserted; * if null is specified, * the node is appended at the end of * the existing nodes * @type void */ insert: function(node, parentNode, nextNode){ }, /** * Confirms whether inserting the node is possible. * @param {Object} node node to insert or move. Must not be * null. * @param {Object} parentNode node object or node uri (without any * scope) of the parent node. The given * node is inserted/moved underneath the * parent node; must not be null. * @param {Object} nextNode node object or node uri (without any * scope) of the successor node before * which the node is to be inserted; * if null is specified, * the node is appended at the end of * the existing nodes * @return {Boolean} true if the node can be inserted, otherwise false. */ confirmInsert: function(node, parentNode, nextNode){ }, /** * Deletes a node from the model. All its children are deleted as well. * * @param {Object} node node object or node uri (without any scope) * to delete from the model. Must not be null. * @type void */ remove: function(node){ }, /** * Confirms whether removing the node is possible. * @param{Object} node node object or node uri (without any scope). * Must not be null * @return {Boolean} true if the node can be removed, otherwise false. */ confirmRemove: function(node){ } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.io.DynamicResolver_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.io.DynamicResolver_API"] = true; dojo.provide("com.ibm.mashups.enabler.io.DynamicResolver_API"); dojo.provide("com.ibm.mashups.enabler.io.DynamicResolver"); /** * This provides a system plugin point where extensions can be registered * to provide immediate resolution of IO requests for data that can be * retrieved from the client. It allows circumvention of remote requests * to serve data that is already available in the system. It also allows * an completely extensible URL naming system such that URLs passed to * IO requests can take on formats besides typical ones such as http or https. * Extension formats and schemes can be handled by custom plugins to allow * an arbitrary mapping of resources on the client to URLs that can be serviced * through normal IO requests. * The service can be retrieved using the following code:
* var dynamicResolver = com.ibm.mashups.services.ServiceManager.getService(
*     com.ibm.mashups.enabler.io.DynamicResolver.SERVICE_NAME);

* @ibm-spi * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.io.DynamicResolver", null, { /** * The service name to be used to fetch the service from the ServiceManager * @type String */ SERVICE_NAME: "dynamicResolver", /** * Registers a plugin for immediate request resolution. * @param {String} id the id of the plugin * @param {Function} matcher the function that returns a validation result * to verify if the plugin can resolve the current request. Function format: * Function(String url).
* This function must return a "truthy" value to indicate that it can resolve * this request, or a "falsy" value if it cannot. Whatever this function returns * will be passed into the plugin's resolver function as the second argument. * @param {Function} resolver the function that resolves the current request * and passes the response data back to the caller. Function format: * Function(String url, Anything validationResult).
* This function must return the data for the response. * @param {Boolean} first optional argument to specify if this plugin should * take precedence over all existing plugins if set to true. If it is false * the plugin will take lowest precedence of existing plugins. Default is false. * @type void */ register: function(/*String*/ id, /*Function*/matcher, /*Function*/resolver, /*Boolean?*/first) { }, /** * Unregisters a plugin by its registered id. * @param {String} id the id of the plugin to unregister * @type void */ unregister: function(/*String*/id) { } }); com.ibm.mashups.enabler.io.DynamicResolver.SERVICE_NAME = "dynamicResolver"; } if(!dojo._hasResource["com.ibm.mm.enabler.io.XHRWrapper"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.io.XHRWrapper"] = true; dojo.provide("com.ibm.mm.enabler.io.XHRWrapper"); dojo.declare("com.ibm.mm.enabler.io.XHRWrapper", null, { constructor: function(ioArgs, partString, statusCode, contentType, partHeaders) { this.ioArgs = ioArgs; this.xhr = ioArgs.xhr; this.readyState = ioArgs.xhr.readyState; this.responseText = partString; this.responseXML = ioArgs.xhr.responseXML; this.status = statusCode; this.statusText = ioArgs.xhr.statusText; this.contentType = contentType; this.partHeaders = partHeaders; }, getAllResponseHeaders: function() { return this.xhr.getAllResponseHeaders(); }, getInterface: function() { return this.xhr.getInterface(); }, getResponseHeader: function(header) { var headerString = header + ''; if (this.partHeaders[headerString]) { return this.partHeaders[headerString]; } else if (headerString.toLowerCase() == "content-type") { return (this.contentType); } return this.xhr.getResponseHeader(header); } }); } if(!dojo._hasResource["com.ibm.mm.enabler.io.DynamicResolver"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.io.DynamicResolver"] = true; dojo.provide("com.ibm.mm.enabler.io.DynamicResolver"); dojo.declare("com.ibm.mm.enabler.io.DynamicResolver", com.ibm.mashups.enabler.io.DynamicResolver, { constructor: function(){ this._plugins = []; // each plugin has format -> [id,matchFn,resolveFn] // Wrap dojo.xhr; if a resolver is found, use it, otherwise delegate to unwrapped dojo.xhr var me = this, origXhr = dojo.xhr; dojo.xhr = function(){ var fn = me.getResolver.apply(me, arguments) || origXhr; return fn.apply(this, arguments); }; }, _buildDfdFn: function(fname, obj, ioArgs){ var func = obj[fname]; return func ? function(val){ return func.call(obj, val, ioArgs); } : null; }, resolve: function(/*Function*/resolver, /*Object*/ validationResult, /* String */ method, /* dojo.__XhrArgs */ args, /* Boolean */ hasBody){ // called in scope of original xhr call, not in DynamicResolver instance scope var data = null, isErr = false, dfd = new dojo.Deferred(), ioArgs = { // dojo.__IoCallbackArgs args: args, url: com.ibm.mm.enabler.EndpointUtils.checkForEndpoints(args.url) || args.url, // check for endpoint URLs handleAs: args.handleAs || "text", xhr: { // need this stubbed out for XHRWrapper readyState: 4, responseXML: null, statusText: "" } }; dfd.addCallback(this._buildDfdFn("load", args, ioArgs)).addErrback(this._buildDfdFn("error", args, ioArgs)).addBoth(this._buildDfdFn("handle", args, ioArgs)); ioArgs.xhr = new com.ibm.mm.enabler.io.XHRWrapper(ioArgs, "", 200, "text", {}); try { data = resolver(ioArgs.url, validationResult); // use potentially endpoint-resolved URL ioArgs.xhr.status = 200; if (data) { ioArgs.xhr.responseText = data; if (args.handleAs === "xml" && typeof data === "string") { // create document object from text string ioArgs.xhr.responseXML = com.ibm.mm.enabler.utils.Dom.createDocument(data); } } } catch (err) { ioArgs.xhr.status = 500; data = err; ioArgs.xhr.responseText = err.toString(); isErr = true; } dfd[isErr ? "errback" : "callback"](data); return dfd; // dojo.Deferred }, _embedValidation: function(fn, vResult){ var me = this; return function(method, args, hasBody){ return me.resolve(fn, vResult, method, args, hasBody); }; }, getResolver: function(/* String */method, /* dojo.__XhrArgs */ args, /* Boolean */ hasBody){ if (method && method.toLowerCase() == "get") { for (var i = 0; i < this._plugins.length; i++) { var plg = this._plugins[i]; var ret = plg[1](args.url); if (ret) { // escape closure around the unnecessaries return this._embedValidation(plg[2], ret); } } } return null; }, register: function(/*String*/id, /*Function*/ plgMatcher, /*Function*/ plgResolver, /*Boolean?*/ first){ this._plugins[first ? "unshift" : "push"]([id, plgMatcher, plgResolver]); }, unregister: function(/*String*/id){ for (var i = 0; i < this._plugins.length; i++) { if (id === this._plugins[i][0]) { this._plugins.splice(i, 1); return; } } } }); com.ibm.mashups.services.ServiceManager.setService(com.ibm.mashups.enabler.io.DynamicResolver.SERVICE_NAME, "com.ibm.mm.enabler.io.DynamicResolver"); } if(!dojo._hasResource["com.ibm.mashups.enabler.io.DynamicResolver"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.io.DynamicResolver"] = true; dojo.provide("com.ibm.mashups.enabler.io.DynamicResolver"); } if(!dojo._hasResource["com.ibm.mashups.enabler.io.XHRMultipart_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.io.XHRMultipart_API"] = true; dojo.provide("com.ibm.mashups.enabler.io.XHRMultipart_API"); dojo.provide("com.ibm.mashups.enabler.io.XHRMultipart"); /** * Provides Dojo XHR support. Requests are batched together via a transaction * concept - Dojo XHR requests which are made between the start and end * transaction calls will be batched. This would include any Dojo API's which would * use Dojo XHR. If the com.ibm.mashups.multipart.correlatehosts * Configuration Service property is set to true, multipart requests will be * split by hostname. * @ibm-api * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.io.XHRMultipart", null, { /** * @private */ constructor: function() { }, /** * Begins a multipart transaction. If the com.ibm.mashups.multipart.enabled * property is set to false, this method simply returns. * @type void */ startTransaction: function() { }, /** * Ends a multipart transaction and submits the multipart request to * the server. If the com.ibm.mashups.multipart.enabled * property is set to false, this method simply returns. * @return {DeferredOperation} a deferred object used to start this operation. * The return value when executed through the deferred object is null */ endTransactionDeferred: function() { }, /** * Ends a multipart transaction and submits the multipart request to * the server. If the com.ibm.mashups.multipart.enabled * property is set to false, this method simply returns. * @param {Object} callback the callback funtion in the format of Function(Object[] params). May be null
*     Callbackparameters
*     params - the parameters * passed into the callback * @param {Object[]} parameters optional array of parameters to be * passed on to the callback function. May be null * @type void * @deprecated Use endTransactionDeferred instead. */ endTransaction: function(callback, parameters) { }, /** * Suspends a mulitpart transaction, allowing normal XHR requests * to be made. If the com.ibm.mashups.multipart.enabled * property is set to false, this method simply returns. * @type void */ suspendTransaction: function() { }, /** * Resumes a mulitpart transaction. If the com.ibm.mashups.multipart.enabled * property is set to false, this method simply returns. * @type void */ resumeTransaction: function() { }, /** * Returns if there is an active multipart transaction * @return {Boolean} true if there is an active multipart * transaction, false otherwise */ isTransaction: function() { return false; } }); } if(!dojo._hasResource["com.ibm.mm.enabler.ServiceDocConsumer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.ServiceDocConsumer"] = true; dojo.provide("com.ibm.mm.enabler.ServiceDocConsumer"); dojo.declare("com.ibm.mm.enabler.ServiceDocConsumer",null,{ _noop: function(){}, _initServiceDoc: function() { this._initServiceDoc = this._noop; // turns this init into a noop for this object } }); } if(!dojo._hasResource["com.ibm.mm.enabler.encode.huffman.ZEncoder"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.encode.huffman.ZEncoder"] = true; dojo.provide("com.ibm.mm.enabler.encode.huffman.ZEncoder"); dojo.declare("com.ibm.mm.enabler.encode.huffman.ZEncoder", null, { HEX_CHARS: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"], UNSAFE_CHARS: "$&+,/:;=?@ <>#%{}|\\^~[]`\"Z", constructor: function() { }, isUnsafeChar: function(testChar) { if (this.UNSAFE_CHARS.indexOf(testChar) > -1 || testChar.charCodeAt(0) <= 32 || testChar.charCodeAt(0) >= 123) { return true; } return false; }, zEncode: function(value) { var retVal = ""; for (var i = 0; i < value.length; ++i) { var currentChar = value.charAt(i); if (!this.isUnsafeChar(currentChar)) { retVal += currentChar; continue; } retVal += this.zEncodeChar(currentChar); } return retVal; }, zEncodeChar: function(plainChar) { var magicChar = "Z"; return magicChar + this.byteToHex(plainChar.charCodeAt(0)); }, byteToHex: function(byteValue) { var upper = Math.floor(byteValue / 16); var lower = byteValue % 16; return this.HEX_CHARS[upper] + this.HEX_CHARS[lower]; }, zDecode: function(value) { var retVal = ""; var magicChar = "Z"; if (value.indexOf(magicChar) != -1) { for (var i = 0, l = value.length; i < l; i++) { var charX = value.charAt(i); if (charX == magicChar) { var hex = "0x" + value.substr(i + 1, 2); i = i + 2; try { var charCode = parseInt(hex,16); retVal = retVal.concat(String.fromCharCode(charCode)); } catch (e) { continue; } } else { retVal = retVal.concat(value.substr(i, 1)); //concat character } } } else { retVal = value; } return retVal; } }); com.ibm.mm.enabler.encode.huffman.ZEncoder = new com.ibm.mm.enabler.encode.huffman.ZEncoder(); } if(!dojo._hasResource["com.ibm.mm.enabler.encode.huffman.HuffmanURL"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.encode.huffman.HuffmanURL"] = true; dojo.provide("com.ibm.mm.enabler.encode.huffman.HuffmanURL"); dojo.declare("com.ibm.mm.enabler.encode.huffman.HuffmanURL", null, { // alphabet used for base64 encoding, this is NOT the default base64 alphabet but an alphabet that only contains URL safe characters URL_ALPHABET: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_!", constructor: function() { }, /** Encodes the huffman codes of the tokens in the alphabet into a stream * @param the target stream * @param the map between token and prefix * @param the array of tokens to encode */ _encodeTokens: function(stream, nodes, tokens) { // iterate over all tokens var len = tokens.length; for (var i = 0; i < len; ++i) { // add the code for the token this._addBits(stream, nodes[tokens[i]].prefix); } // return the stream return this._encodeStream(stream); }, /** Encodes the dwords in the stream into a base64 encoded string * * @param stream stream to encode * @return a string of the base64 encoded dwords */ _encodeStream: function(stream) { // number of bytes to encode var len = stream.dwords.length * 4; // push the last dword if (stream.bits > 0) { // add the last dword stream.dwords.push(stream.dword); // update the length len += ((stream.bits + 0x07) >> 0x03); stream.bits = 0; } // compute the number of bytes and encode return this._encodeBase64(stream.dwords, 0, len); }, /* Initializes the stream object * @param stream the stream to be initialized * @return the actual stream */ _initStream: function(stream) { // reset the masks and the current dword stream.dword = 0; stream.mask = 1; stream.bits = 0; // start with an empty array of encoded dwords stream.dwords = []; // the stream return stream; }, /* Encode an array of 0/1 values that are stored in the data array into a sequence of 32 bit values stored * in the stream. * * @param stream target stream that contains a dword array * @param data the data array of 0/1 values to be encoded */ _addBits: function(stream, data) { // cache the data in local variables and save it back to the stream object at the end var mask = stream.mask, dword = stream.dword, bits = stream.bits; // add all bits sequentially var len = data.length, off = 0; while (len > 0) { // check how many bits we can add in a batch var copy = Math.min(len, 0x20 - bits); for (var i = 0; i < copy; ++i) { // add the bit if (data[off + i] == 1) { dword |= mask; } mask <<= 1; } // update bits += copy; len -= copy; off += copy; // check for an overflow if (bits == 0x20) { // add the new word stream.dwords.push(dword); bits = 0; mask = 1; dword = 0; } } // update the object stream.mask = mask; stream.bits = bits; stream.dword = dword; }, /* Adds a single bit (0/1) to the the stream * @param stream target stream that contains a dword array * @param bit to be encoded, must be 1 or 0 */ _addBit: function(stream, bit) { // add to the dword if (bit == 1) { stream.dword |= stream.mask; } stream.mask <<= 1; stream.bits++; // check for the max mask if (stream.bits == 0x20) { // add the dword to the list stream.dwords.push(stream.dword); stream.dword = 0; stream.mask = 1; stream.bits = 0; } }, /** encodes the data into base64 format, the data is packed in 32bit integer values in little endian notation. * Offset and length refer to the actual bytes, not the dwords. */ _encodeBase64: function(data, off, len) { // cache the alphabet var ab = this.URL_ALPHABET; // starting dword and offset of the byte inside the dword var srcIdx = off >> 0x02; var shift = off & 0x03; // the current dword and a place holder for the next (wrapping) dword var value = data[srcIdx++], newValue; // the four 6-bit numbers that we decode from three consequtive bytes var c1, c2, c3, c4; // the resulting base64 encoding var result = ""; // iterate over the range of bytes in three-byte tuples for (var i = len; i > 0; i -= 3) { /** get the next three bytes. We use direct bit operations based on the packing. */ switch (shift) { case 0: // all bytes are available inside the dword c1 = ((value >> 0x02) & 0x3f); c2 = ((value << 0x04) & 0x30) | ((value >> 0x0c) & 0x0f); c3 = ((value >> 0x06) & 0x3c) | ((value >> 0x16) & 0x03); c4 = ((value >> 0x10) & 0x3f); // next shift shift = 3; break; case 1: // all bytes are available inside the dword c1 = ((value >> 0x0a) & 0x3f); c2 = ((value >> 0x04) & 0x30) | ((value >> 0x14) & 0x0f); c3 = ((value >> 0x0e) & 0x3c) | ((value >> 0x1e) & 0x03); c4 = ((value >> 0x18) & 0x3f); // next shift shift = 0; value = data[srcIdx++]; break; case 2: // wrap around to the next dword newValue = data[srcIdx++]; c1 = ((value >> 0x12) & 0x3f); c2 = ((value >> 0x0c) & 0x30) | ((value >> 0x1c) & 0x0f); c3 = ((value >> 0x16) & 0x3c) | ((newValue >> 0x06) & 0x03); c4 = (newValue & 0x3f); // next shift value = newValue; shift = 1; break; case 3: // wrap around to the next dword newValue = data[srcIdx++]; c1 = ((value >> 0x1A) & 0x3f); c2 = ((value >> 0x14) & 0x30) | ((newValue >> 0x04) & 0x0f); c3 = ((newValue << 0x02) & 0x3c) | ((newValue >> 0x0e) & 0x03); c4 = ((newValue >> 0x08) & 0x3f); // next shift value = newValue; shift = 2; break; } // padding switch (i) { case 1: c3 = 0x40; c4 = 0x40; break; case 2: c4 = 0x40; break; } // construct the 4-character tuple result += ab.charAt(c1); result += ab.charAt(c2); result += ab.charAt(c3); result += ab.charAt(c4); } // return the result of the encoding process return result; }, //decode encoded string //conver 4 byte into 3 //return an array of charcode //first item in the array should be the right most in bit stream... _decodeBase64: function(encodedStr) { var ab = this.URL_ALPHABET; var len = encodedStr.length / 4; var i = 0; var array = []; //each array item contains 3 char for (var j = 0; j < len; j++) { var padding = 0; indexC1 = ab.indexOf(encodedStr.charAt(i++)); indexC2 = ab.indexOf(encodedStr.charAt(i++)); indexC3 = ab.indexOf(encodedStr.charAt(i++)); if (indexC3 == 64) { padding++; } indexC4 = ab.indexOf(encodedStr.charAt(i++)); if (indexC4 == 64) { padding++; } c1 = (indexC1 << 2) | (indexC2 >> 4); //this is the last byte (from right) c2 = ((indexC2 & 15) << 4) | (indexC3 >> 2); //this is the middle byte c3 = ((indexC3 & 3) << 6) | indexC4; //this is the byte on the left array.push(c1); switch (padding) { case 0: array.push(c2); array.push(c3); break; case 1: array.push(c2); break; case 2: break; } } return array; }, /** Callback used by the sort method to compare nodes by frequency */ _frequencyCompare: function(n1, n2) { return n1.frequency - n2.frequency; }, /** Initializes the encoding and the prefixes of the huffman tree. The * method writes the tree structure as a bit sequence into the stream and * initializes the node prefixes with the huffman code. * * @param stream the stream that contains the tree structure and the sequence of the node names * @param node the current node in the tree to encode * @param prefix the huffman prefix of the parent node, an array that contains 0/1 bits */ _initTree: function(stream, node, prefix) { // iterate into the children if (node.left && node.right) { // add to the stream this._addBit(stream, 1); // recurse the left and right branch this._initTree(stream, node.left, prefix.concat(0)); this._initTree(stream, node.right, prefix.concat(1)); } else { // add to the stream this._addBit(stream, 0); // this is our huffman code! node.prefix = prefix; // add this node stream.tokens.push(node.name); } // ok return stream; }, _dumpTokens: function(tree, nodes) { }, /** Constructs the huffman tree from the token sequence * * @param array of tokens * @return the URL that encodes the tokens */ _buildTree: function(tokens) { // build a list of token frequencies var nodes = {}; // iterate and fill the node map var len = tokens.length; var node, i; for (i = len - 1; i >= 0; --i) { // do we know the node? var token = tokens[i]; node = nodes[token]; if (node) { // increment the frequency of the node node.frequency++; } else { // construct the new token node = { frequency: 1, name: token }; // add the node nodes[token] = node; } } // produce a sorted list based on the frequencies var queue = []; for (node in nodes) { if (Object.prototype.hasOwnProperty.call(nodes,node)) { queue.push(nodes[node]); } } queue.sort(this._frequencyCompare); // build the huffman tree while (queue.length > 1) { // remove the smallest items var left = queue.shift(), right = queue.shift(); // construct the new, combined node queue.push({ frequency: left.frequency + right.frequency, left: left, right: right }); queue.sort(this._frequencyCompare); } // now, we have the tree, initialize its huffman codes var root = queue[0]; var tree = this._initTree(this._initStream({ tokens: [] }), queue.shift(), []); this._dumpTokens(tree, nodes); // serialize the tree into a prefix var url = this._encodeStream(tree); // append the tokens len = tree.tokens.length; for (i = 0; i < len; ++i) { url += "/" + com.ibm.mm.enabler.encode.huffman.ZEncoder.zEncode(tree.tokens[i]); } // serialize the huffman codes url += "/" + this._encodeTokens(this._initStream({}), nodes, tokens); // return the url return url; }, /** Constructs the huffman tree from a data string an a regular expression that splits * the string into tokens. The delimiters are considered part of the tokens. * @param data the data string to split * @param regexStrg the regular expression string, e.g. "[\/\.<>]" * * @return the encoded URL */ _buildTreeFromRegex: function(data, regexStrg) { // compile the regex var regex = new RegExp(regexStrg, "g"); // record the split positions var pos = []; var result; while ((result = regex.exec(data))) { pos.push(result.index); } // padding if (pos[0]) { pos.unshift(0); } if (pos[pos.length - 1] != data.length) { pos.push(data.length); } // split var tokens = []; for (result = 1; result < pos.length; ++result) { tokens.push(data.substring(pos[result - 1], pos[result])); } // construct the URL return this._buildTree(tokens); }, /** Constructs the huffman tree from the token sequence * * @param array of tokens * @return the URL that encodes the tokens */ createRawSchemeSpecificPartFromTokens: function(tokens) { return this._buildTree(tokens); }, /** Constructs the huffman tree from a data string an a regular expression that splits * the string into tokens. The delimiters are considered part of the tokens. * @param data the data string to split * @param regexStrg the regular expression string, e.g. "[\/\.<>]" * * @return the encoded URL */ createRawSchemeSpecificPartFromRegex: function(data, regexStrg) { return this._buildTreeFromRegex(data, regexStrg); }, /** Restores data from the encoded huffman tree based on the token sequence * @param url encoded data * @return the data string that's decoded from huffman tree */ getDataFromHuffmanTree: function(tree) { return this._restoreData(tree); }, _restoreData: function(tree) { if (!tree) { return null; } var i0 = tree.indexOf("/"); var i1 = tree.lastIndexOf("/"); if ((i0 >= 0) && (i1 >= 0)) { var treeStream = this._decodeBase64(tree.substring(0, i0)); var encodedToken = tree.substring(i0 + 1, i1).split("/"); var codeStream = this._decodeBase64(tree.substring(i1 + 1)); //array of decoded tokens encodedTokens = this._decodeTokens(encodedToken); //build tree with token var root = this._readStructure(this._convertBitToChar(treeStream), encodedTokens); var bitArr = this._convertBitToChar(codeStream); var retVal = ""; while (bitArr.length > 0) { retVal = this._buildData(retVal, bitArr, root); } return retVal; } return null; }, _buildData: function(retVal, bitArr, root) { var found = false; var node = null; while (!found) { var bit = bitArr.shift(); if (typeof bit == "undefined") { node = null; break; } node = this._getNode(bit, root); if (node && node.token && node.token) { found = true; } else if (!node) { found = true; } root = node; } if (found && node) { retVal = retVal.concat(node.token); } return retVal; }, _getNode: function(bit, parent) { //0 --left, 1--right var node = null; node = (bit == 1) ? parent.right : parent.left; if (!node) { return null; } return node; }, _convertBitToChar: function(charCodeArr) { var arr = []; var mask = 0x01; var bit = 0; for (var i = 0; i < charCodeArr.length; i++) { var charCode = charCodeArr[i]; for (var j = 0; j < 8; j++) { bit = charCode & mask; arr.push(bit); charCode = (charCode >> 1); //remove 1 bit } } return arr; }, _readStructure: function(charArr, encodedTokens) { var bit = charArr.shift(); var node = {}; if (bit == 1) { // internal node node.left = this._readStructure(charArr, encodedTokens); node.right = this._readStructure(charArr, encodedTokens); } else { //leaf node var token = encodedTokens.shift(); node.token = token; } return node; }, // an array of tokens try to zDecode it _decodeTokens: function(encodedToken) { var arr = []; for (var i in encodedToken) { if (Object.prototype.hasOwnProperty.call(encodedToken,i)) { arr.push(com.ibm.mm.enabler.encode.huffman.ZEncoder.zDecode(encodedToken[i])); } } return arr; } }); com.ibm.mm.enabler.encode.huffman.HuffmanURL = new com.ibm.mm.enabler.encode.huffman.HuffmanURL(); } if(!dojo._hasResource["com.ibm.mm.enabler.ArrayMap"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.ArrayMap"] = true; dojo.provide("com.ibm.mm.enabler.ArrayMap"); dojo.declare("com.ibm.mm.enabler.ArrayMap", null, { constructor: function(){ this.entries = []; this.keys = {}; }, values: function(){ return this.entries; }, put: function(/*String*/key,/*object*/ value){ var index = this.keys[key]; if (typeof index != 'undefined' && index !== null) { this.entries[index] = value; } else { index = this.entries.length; this.entries.push(value); this.keys[key] = index; } }, getKey: function(index){ if (index < this.entries.length) { for (var key in this.keys) { if(Object.prototype.hasOwnProperty.call(this.keys,key)) { var temp = this.keys[key]; if (temp !== null && temp == index) { return temp; } } } } else { return null; } }, getValue: function(index){ return (index < this.entries.length) ? this.entries[index] : null; }, get: function(key){ var index = this.keys[key]; if (typeof index != 'undefined' && index !== null) { var value = this.entries[index]; return value; } return null; }, remove: function(key){ var index = this.keys[key]; if (typeof index != 'undefined' && index !== null) { this.entries.splice(index, 1); this.keys[key] = null; } return index; }, size: function(){ return this.entries.length; }, keySet: function(){ var arr = []; com.ibm.mm.enabler.utils.Misc.forIn(this.keys,function(value,key) { arr.push(key); }); return arr; } }); } if(!dojo._hasResource["com.ibm.mm.enabler.io.XHRMultipartImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.io.XHRMultipartImpl"] = true; dojo.provide("com.ibm.mm.enabler.io.XHRMultipartImpl"); dojo.declare("com.ibm.mm.enabler.io.XHRMultipartImpl", [com.ibm.mashups.enabler.io.XHRMultipart, com.ibm.mm.enabler.ServiceDocConsumer], { DYN_RES: com.ibm.mashups.services.ServiceManager.getService(com.ibm.mashups.enabler.io.DynamicResolver.SERVICE_NAME), statics: { semaphore: 0, digest: null, suspendedXhr: null }, constructor: function() { this.method = "POST"; this.partsArray = null; var configService = com.ibm.mashups.services.ServiceManager.getService(com.ibm.mashups.enabler.services.ConfigService.SERVICE_NAME); this.correlateHosts = configService.getValue(com.ibm.mashups.enabler.services.ConfigConstants.MULTIPART_CORRELATE_HOSTS); this.correlatedHosts = null; this.cacheQueries = false; var cacheQueriesConfig = configService.getValue(com.ibm.mashups.enabler.services.ConfigConstants.MULTIPART_CACHE_QUERIES); if (typeof(cacheQueriesConfig) !== "undefined" && cacheQueriesConfig !== null && cacheQueriesConfig === true) { this.cacheQueries = true; } this.privateUrl = configService.getValue(com.ibm.mashups.enabler.services.ConfigConstants.CONTEXT_ROOT) + configService.getValue(com.ibm.mashups.enabler.services.ConfigConstants.CONTENTHANDLER_PRIVATE); this.publicUrl = configService.getValue(com.ibm.mashups.enabler.services.ConfigConstants.CONTEXT_ROOT) + configService.getValue(com.ibm.mashups.enabler.services.ConfigConstants.CONTENTHANDLER_PUBLIC); this.doSiteMap = true; this.urlMaxLength = 2000; // unique (arbitrary) boundary this.boundary = "{EB2F8DA2-5B2C-F66A-CDD0-A2D42143F5AC}"; this.newL = "\r\n"; this.sep = "--"; this.startB = this.newL + this.sep + this.boundary + this.newL; this.endB = this.sep + this.boundary + this.sep + this.newL; // used to capture the header //this.headerRegx = /\r\n\s*([^\r]*)\s*/mg; this.headerRegx = new RegExp(this.newL + "\s*([^\r]*)\s*", "mg");// JSLINT-IGNORE: Enabler Team decided to keep this paradigma from dojo in tact this.headerPartsRegx = /\s*([^:]*):\s*(.+)/; // used to find the boundary this.boundaryRegx = /boundary\s*=\s*\"?([^\"]*)\"?/; this.multipartParts = false; this.replaceDigest = false; this.digest = null; }, _initServiceDoc: function() { this.inherited("_initServiceDoc", arguments); this.doMultipart = com.ibm.mashups.enabler.io.XHRMultipartFactory.isMultipartEnabled(); if(this.doMultipart) { this.serviceMPJson = com.ibm.mm.enabler.model.ServiceDocumentModel.getCollectionData([com.ibm.mm.enabler.model.ServiceDocumentModel.SERVICE_MODEL, com.ibm.mm.enabler.model.ServiceDocumentModel.SERVICE_MULTIPART]); this.serviceSMJson = com.ibm.mm.enabler.model.ServiceDocumentModel.getCollectionData([com.ibm.mm.enabler.model.ServiceDocumentModel.SERVICE_MODEL, com.ibm.mm.enabler.model.ServiceDocumentModel.SERVICE_HUFFMAN]); this.serviceCHJson = com.ibm.mm.enabler.model.ServiceDocumentModel.getCollectionData([com.ibm.mm.enabler.model.ServiceDocumentModel.SERVICE_MODEL, com.ibm.mm.enabler.model.ServiceDocumentModel.SERVICE_SITEMAP_COMMITHANDLER]); } }, _partHandler: function(partArgs, responsePart, ioArgs, partHeaders) { var work = dojo.hitch(partArgs, function() { try { if (com.ibm.mm.enabler.utils.Misc.isInstanceOf(responsePart, Error)) { if (this.error) { this.error(responsePart, ioArgs, partHeaders); } } else if (ioArgs.xhr.status >= 400) { if (this.error) { this.error(new Error(ioArgs.xhr.status + ": " + partHeaders.URI), ioArgs, partHeaders); } } else { if (this.load) { this.load(responsePart, ioArgs, partHeaders); } } // always call the handle function if it exists if (this.handle) { this.handle(responsePart, ioArgs, partHeaders); } } catch (err) { // make one attempt to call the error handler try { if (this.error) { this.error(responsePart, ioArgs, partHeaders); } } catch (err2) { //noop } } }); // JSLINT-IGNORE: Enabler Team decided to keep this paradigma from dojo in tact work(); }, _handleMultiPartResponse: function(parts, multipartParts, scope, response, ioArgs) { // Getting the Content-Type header from the response, and extract // the boundary string var contentType = ioArgs.xhr.getResponseHeader("Content-Type"); var boundMatch = contentType.match(scope.boundaryRegx); if (!boundMatch) { throw new Error("No boundary specified in Content-Type response header"); } var bound = boundMatch[1]; var stripPossibleCharSetIndex = bound.indexOf(";"); if (stripPossibleCharSetIndex!=-1) { bound = bound.substring(0,stripPossibleCharSetIndex); } // build a regx from the response boundary string used to split the parts var splitterRegx = new RegExp(scope.newL + scope.sep + bound, "mg"); var respParts = response.split(splitterRegx); // if handleAs is xml, it comes as text so build it using the domUtilities // iterate through the response parts, handling the callbacks for each var mpHandler = null; if (multipartParts) { mpHandler = new com.ibm.mm.enabler.io.XHRMultipartImpl(); mpHandler.startTransaction(); } var i = 1; for (var current in parts) { if (Object.prototype.hasOwnProperty.call(parts, current)) { var partArgs = parts[current]; for (var x = 0, l = partArgs.length; x 0)) { // ensure bad headers are not allowed through if (-1 == header[1].indexOf(":")) { continue; } if (-1 == header[1].indexOf("digest=")) { var headerParts = header[1].match(scope.headerPartsRegx); partHeaders[headerParts[1]] = headerParts[2]; if (headerParts[1] == "X-Status-Code") { statusCodeText = headerParts[2]; } else if (headerParts[1] == "Content-Type") { contentType = headerParts[2]; } } } part = dojo.string.trim(part.substr(scope.headerRegx.lastIndex + scope.newL.length)); var partString = part; if (requestArgs.handleAs == "xml") { // create document object from text string part = com.ibm.mm.enabler.utils.Dom.createDocument(part); } else { // call the appropriate content handler for this part // dojo.contentHandlers is public since Dojo 1.4 part = dojo.contentHandlers[requestArgs.handleAs]({ responseText: part }); } // Set the appropriate status code var statusCode = parseInt(statusCodeText, 10); var xhrWrapper = new com.ibm.mm.enabler.io.XHRWrapper(ioArgs, partString, statusCode, contentType, partHeaders); var xhr = ioArgs.xhr; ioArgs.xhr = xhrWrapper; scope._partHandler(requestArgs, part, ioArgs, partHeaders); ioArgs.xhr = xhr; } } } if (multipartParts) { mpHandler.endTransactionDeferred().start(); } }, _multiPartXhr: function( /*String*/method, /*dojo.__XhrArgs*/ args, /*Array*/ parts, /*boolean*/ multipartParts) { // summary: Sends a request with a multi-part body (and content type) to // the server. Uses dojo.xhr functions under the covers, so the args // object has the same structure as what those functions expect. // The main difference is that this function builds the raw post or put // data automatically from the parts array. Each item in the parts array // is an object which is a subset of the dojo.__XhrArgs type. The callbacks // should be specified per part as this function will provide a general // callback that parses the multi-part response and calls the callback // associated with that response part provided in the parts array. // method: String specifying the HTTP method used. Must be either POST or PUT. // Default is POST. // args: dojo.__XhrArgs specifying how this XHR should be handled. The following // properties are not used since they do not make sense in this context - // [form, handle, load, content, handleAs] // parts: Array the multiple parts to use to build the multi-part request body. // Each item in the array should be an object with these properties - // { // headers: Object key-value map which is used to write out a // section at the top of this part in the form key: value. // Example could be Content-Type of this part of the multi-part // request. // data: String text to write out the body of this part // load: function(response, ioArgs){} callback called where // the response body is the body of the part associated this // request part // error: function(response, ioArgs){} callback called when // a failure occurs either in the transmission or from the // server // handle: function(response, ioArgs){} callback called at the // end of this request with either the response or an error // if one occured // handleAs: String value indicating how the response body of this // part should be handled // } // returns: Deferred object which can be used to attach additional callbacks to var body = ""; var headersStr = null; for (var current in parts) { if (Object.prototype.hasOwnProperty.call(parts, current)) { for (var entry in parts[current]) { if (Object.prototype.hasOwnProperty.call(parts[current], entry)) { var part = parts[current][entry]; part.handleAs = part.handleAs ? part.handleAs.toLowerCase() : "text"; headersStr = ""; for (var x in part.headers) { if (Object.prototype.hasOwnProperty.call(part.headers, x)) { headersStr += x + ": " + part.headers[x] + this.newL; } } body += this.startB + headersStr + this.newL; if (part.data && part.data.length > 1) { body += part.data + this.newL; } else if (part.postData && part.postData.length > 1) { body += part.postData + this.newL; } else if (part.putData && part.putData.length > 1) { body += part.putData + this.newL; } } } } } body += this.endB; // if method is PUT, leave it be; otherwise set it to POST if (method.toUpperCase() != "PUT") { method = "POST"; } var me = this; var status; var xhrArgs = dojo.mixin({}, args, { load: function(response, ioArgs) { me._handleMultiPartResponse(parts, multipartParts, me, response, ioArgs); status = ioArgs.xhr.status; }, error: function(response, ioArgs) { dojo.forEach(parts, function(part) { for (var x = 0, l = part.length; x this.urlMaxLength) { // fall back status = this._doMultipartPOSTRequest(this.method, parts, this.multipartParts); } else { var me = this; xhrArgs = { url: url, load: function(response, ioArgs) { me._handleMultiPartResponse(parts, me.multipartParts, me, response, ioArgs); status = ioArgs.xhr.status; }, // JSLINT-IGNORE: Enabler Team decided to keep this paradigma from dojo in tact error: function(response, ioArgs) { dojo.forEach(parts, function(part) { for (var x = 0, l = part.length; x -1) { newUrl += unescape(url.substring(proxyPrefix.length, slashPos)); newUrl += url.substring(slashPos); } else { newUrl = "http://" + url.substring(proxyPrefix.length); } url = newUrl; } // OR changed url to be HttpURL and get files by res:/ var httpUrl = new com.ibm.mm.enabler.utils.HttpUrl(url); // extract the digest var digest = this._extractDigest(httpUrl, url); if (digest) { if (null === this.digest && false === this.replaceDigest) { this.replaceDigest = true; } else if (digest !== this.digest) { this.replaceDigest = false; } this.digest = digest; } else { this.digest = ""; this.replaceDigest = false; } // add any dojo.xhr content parameters if (args.content) { for (var name in args.content) { if (Object.prototype.hasOwnProperty.call(args.content, name)) { var value = args.content[name]; httpUrl.addParameter(name, value); } } } var uri = ""; var isProxyNeeded = httpUrl.isProxyNeeded(); if (isProxyNeeded) { uri = httpUrl.toString(); // the URI is the true url } else { // FIXME: currently the server/resolver can't handle res URIs for a data sink var method = (args.method) ? args.method.toLowerCase() : null; if (method && (method == "post" || method == "put" || method == "delete")) { uri = httpUrl.getParameter("uri"); } else { uri = "res:" + httpUrl.toServerRelativeString(); // need to prefix res: before the server relative url } } return uri; }, _processMultipartBody: function(parts) { var useCommitHandler = false; for (var w in parts) { if (Object.prototype.hasOwnProperty.call(parts, w)) { for (var x in parts[w]) { if (Object.prototype.hasOwnProperty.call(parts[w], x)) { // Create a header for our method var args = parts[w][x]; var uri = this._createPocURI(args); var contentIdHeader = uri; args.headers = dojo.mixin({}, args.headers, { "X-Method-Override": args.method, "Content-ID": contentIdHeader }); if ("GET" !== args.method) { useCommitHandler = true; } } } } } return useCommitHandler; }, _createSiteMap: function(parts) { var cxml = ''; for (var w in parts) { if (Object.prototype.hasOwnProperty.call(parts, w)) { // Create a header for our method var args = parts[w][0]; args.handleAs = args.handleAs ? args.handleAs.toLowerCase() : "text"; var uri = this._createPocURI(args).replace(//g, ">").replace(/&/g, "&"); cxml += ''; } } cxml += ''; return cxml; }, _extractDigest: function(httpUrl, url) { // check for a normal parameter var digest; var tempDigest = httpUrl.getParameter("digest"); if (!tempDigest) { // potentially portal style: // /wps/mycontenthandler/!ut/p/digest!YYKwv4D5SWBlr5MXQwCujg/res//mccbuilder/widget-catalog/breadcrumbWidget.xml?pragma=cache&max-age=1209600&cache-scope=public&vary=none&user-context=false?cache-scope=public&vary=none&user-context=false&max-age=1209600 var start = url.indexOf("digest!"); if (0 < start) { start += 7; var end = url.indexOf("/", start); digest = url.substring(start, end); } } else { digest = tempDigest; } return digest; }, _updateDigest: function(url) { if (!this.replaceDigest) { return url; } // potentially portal style: // /wps/mycontenthandler/!ut/p/digest!YYKwv4D5SWBlr5MXQwCujg/res//mccbuilder/widget-catalog/breadcrumbWidget.xml?pragma=cache&max-age=1209600&cache-scope=public&vary=none&user-context=false?cache-scope=public&vary=none&user-context=false&max-age=1209600 var digest; var end; var start = url.indexOf("digest!"); if (0 < start) { start += 7; end = url.indexOf("/", start); digest = url.substring(start, end); } else if (!digest) { // url parameter start = url.indexOf("digest="); if (0 < start) { start += 7; end = url.indexOf("&", start); if (-1 === end) { digest = url.substring(start); } else { digest = url.substring (start, end); } } } var retval = url; if (digest) { retval = url.replace(digest, this.digest); } return retval; } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.io.XHRMultipart"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.io.XHRMultipart"] = true; dojo.provide("com.ibm.mashups.enabler.io.XHRMultipart"); } if(!dojo._hasResource["com.ibm.mashups.enabler.io.XHRMultipartFactory_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.io.XHRMultipartFactory_API"] = true; dojo.provide("com.ibm.mashups.enabler.io.XHRMultipartFactory_API"); dojo.provide("com.ibm.mashups.enabler.io.XHRMultipartFactory"); /** * Interface representing the XHR multipart handler factory * @ibm-api * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.io.XHRMultipartFactory", null, { /** * Returns a new XHR multipart handler * * @return {com.ibm.mashups.enabler.io.XHRMultipart} a new multipart * handler, never null */ create: function(){ }, /** * Returns if multipart is enabled on the server * @return {Boolean} true if multipart is * enabled, false otherwise */ isMultipartEnabled: function(){ }, /** * Returns if application widgets should be fetched in multipart requests * @return {Boolean} true if application widgets should be * fetched in multipart requests, false otherwise */ isMultipartApplicationWidgets: function(){ } }); } if(!dojo._hasResource["com.ibm.mm.enabler.io.XHRMultipartFactoryImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.io.XHRMultipartFactoryImpl"] = true; dojo.provide("com.ibm.mm.enabler.io.XHRMultipartFactoryImpl"); // public factory dojo.declare("com.ibm.mm.enabler.io.XHRMultipartFactoryImpl", [com.ibm.mashups.enabler.io.XHRMultipartFactory, com.ibm.mm.enabler.ServiceDocConsumer], { constructor: function() { this._init = false; this.serviceMPJson = null; this.doMultipart = false; var configService = com.ibm.mashups.services.ServiceManager.getService(com.ibm.mashups.enabler.services.ConfigService.SERVICE_NAME); var pageLoadOptAppWidgets = configService.getValue(com.ibm.mashups.enabler.services.ConfigConstants.PAGE_LOAD_OPTIMIZATION_APP_WIDGETS); this.multipartAppWidgets = false; if (typeof(pageLoadOptAppWidgets) == "undefined" || pageLoadOptAppWidgets === null || pageLoadOptAppWidgets === true) { this.multipartAppWidgets = true; } }, _initServiceDoc: function() { this.inherited("_initServiceDoc", arguments); // service document and initialization if (dojo.exists("com.ibm.mm.enabler.model.ServiceDocumentModel")) { this.serviceMPJson = com.ibm.mm.enabler.model.ServiceDocumentModel.getCollectionData([com.ibm.mm.enabler.model.ServiceDocumentModel.SERVICE_MODEL, com.ibm.mm.enabler.model.ServiceDocumentModel.SERVICE_MULTIPART]); } if(this.serviceMPJson && this.serviceMPJson.url) { this.doMultipart = true; } }, create: function() { return new com.ibm.mm.enabler.io.XHRMultipartImpl(); }, isMultipartEnabled: function() { if(!this._init) { this._init = true; var configService = com.ibm.mashups.services.ServiceManager.getService(com.ibm.mashups.enabler.services.ConfigService.SERVICE_NAME); var multipartConfig = configService.getValue(com.ibm.mashups.enabler.services.ConfigConstants.MULTIPART_ENABLED); // disable on IE6 if (dojo.isIE != 6 && multipartConfig) { this._initServiceDoc(); } } return this.doMultipart; }, isMultipartApplicationWidgets: function() { return this.multipartAppWidgets; } }); // public factory com.ibm.mashups.enabler.io.XHRMultipartFactory = new com.ibm.mm.enabler.io.XHRMultipartFactoryImpl(); } if(!dojo._hasResource["com.ibm.mashups.enabler.io.XHRMultipartFactory"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.io.XHRMultipartFactory"] = true; dojo.provide("com.ibm.mashups.enabler.io.XHRMultipartFactory"); dojo.require( "com.ibm.mm.enabler.io.XHRMultipartFactoryImpl" ); } if(!dojo._hasResource["com.ibm.mashups.enabler.model.state.Accessor"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.state.Accessor"] = true; dojo.provide("com.ibm.mashups.enabler.model.state.Accessor"); /** * Interface representing an Accessor. * * @ibm-spi * @ibm-module Base */ dojo.declare("com.ibm.mashups.enabler.model.state.Accessor", null, {}); } if(!dojo._hasResource["com.ibm.mashups.enabler.model.state.PageAccessor_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.state.PageAccessor_API"] = true; dojo.provide("com.ibm.mashups.enabler.model.state.PageAccessor_API"); dojo.provide("com.ibm.mashups.enabler.model.state.PageAccessor"); /** * Interface representing an PageAccessor. * @ibm-spi * @ibm-module Base */ dojo.declare( "com.ibm.mashups.enabler.model.state.PageAccessor", [com.ibm.mashups.enabler.model.state.Accessor] , { /** * Returns the of the page within a space. * @type String * @return {String} The page id of provided space */ getPageID:function() { }, /** * Sets the page of the space * @param {String} pageId id of page * @type void */ setPageID:function(pageId) { }, /** * Confirms if it's possible to set a new page id * @param {String} pageId id of page * @type Boolean * @return{Boolean} return true if it's possible to set a new page id */ confirmSetPageID:function(pageId) { return true; } }); } if(!dojo._hasResource["com.ibm.mm.enabler.model.state.PageAccessorImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.model.state.PageAccessorImpl"] = true; dojo.provide("com.ibm.mm.enabler.model.state.PageAccessorImpl"); dojo.declare("com.ibm.mm.enabler.model.state.PageAccessorImpl", [com.ibm.mashups.enabler.model.state.PageAccessor], { constructor: function(navStateModel, spaceid) { this.navStateModel = navStateModel; if (spaceid) { this.spaceid = spaceid; } }, getPageID: function() { var state = this.navStateModel._state; var rc = null; if (!state) { return null; } if (!this.spaceid) { if (state.pid) { return state.pid.value; } return null; } else { if (state.pageselection && state.pageselection[this.spaceid]) { return state.pageselection[this.spaceid].value; } return null; } return null; }, setPageID: function(pageId) { var state = this.navStateModel._state; if (!state) { this.navStateModel._state = {}; state = this.navStateModel._state; } if (!pageId) { state.pid = null; if (this.spaceid) { if (state.pageselection && state.pageselection[this.spaceid]) { state.pageselection[this.spaceid] = null; } } this.navStateModel.setDirty(true, "pid"); return; } var lm = new Date().getTime(); state.pid = state.pid ? state.pid : {}; state.pid.value = pageId; state.pid.params = state.pid.params ? state.pid.params : {}; state.pid.params.lm = lm; if (this.spaceid) { if (!state.pageselection) { state.pageselection = {}; } if (!state.pageselection[this.spaceid]) { state.pageselection[this.spaceid] = {}; } state.pageselection[this.spaceid].value = pageId; state.pageselection[this.spaceid].params = state.pageselection[this.spaceid].params ? state.pageselection[this.spaceid].params : {}; state.pageselection[this.spaceid].params.lm = lm; } this.navStateModel.setDirty(true, "pid"); } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.model.state.PageAccessor"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.state.PageAccessor"] = true; dojo.provide("com.ibm.mashups.enabler.model.state.PageAccessor"); } if(!dojo._hasResource["com.ibm.mashups.enabler.model.state.SpaceAccessor_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.state.SpaceAccessor_API"] = true; dojo.provide("com.ibm.mashups.enabler.model.state.SpaceAccessor_API"); dojo.provide("com.ibm.mashups.enabler.model.state.SpaceAccessor"); /** * Interface representing a SpaceAccessor. * @ibm-spi * @ibm-module Base */ dojo.declare( "com.ibm.mashups.enabler.model.state.SpaceAccessor", [com.ibm.mashups.enabler.model.state.Accessor], { /** * Returns the of the currently selected space. * @type String * @return {String} The spaceid */ getSpaceID:function() { }, /** * Sets the space * @param {String} spaceId id of space * @type void */ setSpaceID:function(spaceId) { }, /** * Confirms if it's possible ot set the space id * @param {String} spaceId id of space * @type Boolean * @return{Boolean} return true if it's possible to set the new space id */ confirmSetSpaceID:function(spaceId) { return true; } }); } if(!dojo._hasResource["com.ibm.mm.enabler.model.state.SpaceAccessorImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.model.state.SpaceAccessorImpl"] = true; dojo.provide("com.ibm.mm.enabler.model.state.SpaceAccessorImpl"); dojo.declare("com.ibm.mm.enabler.model.state.SpaceAccessorImpl", [com.ibm.mashups.enabler.model.state.SpaceAccessor], { constructor: function(navStateModel) { this.navStateModel = navStateModel; }, getSpaceID: function() { var state = this.navStateModel._state; if (!state) { return null; } if (state.sid && state.sid.value) { return state.sid.value; } return null; }, _setSpaceIDInternal: function(spaceId) { var state = this.navStateModel._state; if (!state) { this.navStateModel._state = {}; state = this.navStateModel._state; } var lm = new Date().getTime(); //todo if (typeof spaceId == "undefined") { state.sid = {}; } else { state.sid = state.sid ? state.sid : {}; state.sid.value = spaceId; state.sid.params = state.sid.params ? state.sid.params : {}; state.sid.params.lm = lm; } if (state.pid) { state.pid = null; } }, setSpaceID: function(spaceId) { this._setSpaceIDInternal(spaceId); this.navStateModel.setDirty(true, "sid"); } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.model.state.SpaceAccessor"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.state.SpaceAccessor"] = true; dojo.provide("com.ibm.mashups.enabler.model.state.SpaceAccessor"); } if(!dojo._hasResource["com.ibm.mashups.enabler.model.state.WidgetAccessor_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.state.WidgetAccessor_API"] = true; dojo.provide("com.ibm.mashups.enabler.model.state.WidgetAccessor_API"); dojo.provide("com.ibm.mashups.enabler.model.state.WidgetAccessor"); /** * Interface representing a WidgetAccessor. Reserved Widget Paramers: * "cp" : the reserved paremeter for widget customized state. * "h" : the reserved paremeter for widget height. * "w" : the reserved paremeter for widget width. * "st" : the reserved paremeter for widget window state. * "md" : the reserved paremeter for widget mode. * @ibm-spi * @ibm-module Base */ dojo.declare( "com.ibm.mashups.enabler.model.state.WidgetAccessor", [com.ibm.mashups.enabler.model.state.Accessor], { /** * @private */ constructor:function (navStateModel, id) { }, /** * Returns the widget id of the Widget * @type String * @return {String} ID of required Widget */ getWidgetID:function() { }, /** * Returns the values of the required widget state parameter. If state has only one value, this method returns a single array with a length of 1. * * @since 2.4 * @param {String} key The name of the required parameter of Widget Navigation State * "cp" is the reserved parameter for widget customized state. * @type String * @return {String[]} Values of required parameter */ getWidgetStateValues:function(key) { }, /** * Returns the state of the required widget state parameter * @param {String} key The name of the required parameter of Widget Navigation State * "cp" is the reserved parameter for widget customized state. * @type String * @return {String} Value of required parameter */ getWidgetState:function(key) { }, /** * Set the value of a widget state parameter * * @since 2.4 * @param {String} key The name of the required parameter * @param {String[]} values The values of the required parameter * @type WidgetAccessor * @return{WidgetAccessor} return an handle of WidgetAccessor upon successful, null upon failure. */ setWidgetState:function(key,values){ }, /** * Confirms whether setting the values for the given widget state parameter is possible. * * @since 2.4 * @param {String} key The name of the required parameter * @param {String[]} values The values of the required parameter * @type Boolean * @return {Boolean} true if the values can be set, otherwise false. */ confirmSetWidgetState:function(key,values){ return true; }, /** * Set the value of a widget state parameter * * @since 2.4 * @param {String} key The name of the required parameter * @param {String} value The value of the required parameter * @type WidgetAccessor * @return{WidgetAccessor} return an handle of WidgetAccessor upon successful, null upon failure. */ setWidgetState:function(key,value){ // JSLINT-IGNORE: in Java functions with the same name but different signatures are allowed - this is only used for generating JavaDoc }, /** * Confirms whether setting the value for the given widget state parameter is possible. * * @since 2.4 * @param {String} key The name of the required parameter * @param {String} value The value of the required parameter * @type Boolean * @return {Boolean} true if the value can be set, otherwise false. */ confirmSetWidgetState:function(key,value){// JSLINT-IGNORE: in Java functions with the same name but different signatures are allowed - this is only used for generating JavaDoc return true; }, /** * Remove a widget state parameter * @param {String} key The name of the required parameter * @type WidgetAccessor * @return{WidgetAccessor} return an handle of WidgetAccessor upon successful, null upon failure. */ removeWidgetState:function(key){ }, /** * Confirms whether removing a widget state parameter is possible * * @since 2.4 * @param {String} key The name of the required parameter * @type Boolean * @return{Boolean} return true if the required parameter can be removed */ confirmRemoveWidgetState:function(key){ return true; }, /** * Returns the names of custimized widget state * @type String[] * @return {String[]} an array of customized widget state names */ getWidgetStateNames:function(){ }, /** * Returns the mode of the required widget * @type String * @return {String} The mode of the required widget and null if no mode is set yet. */ getWidgetMode:function() { }, /** * Set the mode of a widget * @param {String} mode of the required widget * @type WidgetAccessor * @return{WidgetAccessor} return an handle of WidgetAccessor upon successful, null upon failure. */ setWidgetMode:function(mode) { }, /** * Confirms whether it's possible or not to set the widget to a new mode * @param {String} mode of the required widget * @type Boolean * @return{Boolean} return true if it's possible to set widget to the new model */ confirmSetWidgetMode:function(mode) { return true; }, /** * Returns the window state of the required widget * @type String * @return {String} The window state of the required widget following states are allowed: "normal","minimize","maximize". It returns null if no windowstate is set yet. */ getWindowState:function() { }, /** * Set the window state of a widget * @param {String} windowState The window state of the required widget * @type WidgetAccessor * @return{WidgetAccessor} return an handle of WidgetAccessor upon successful, null upon failure. */ setWindowState:function(windowState) { }, /** * Confirms whether it's possible or not to set the widget to a new window state * @param {String} windowState The window state of the required widget * @type Boolean * @return{Boolean} return true if it's possible to set widget to the new window state */ confirmSetWindowState:function(windowState) { return true; }, /** * Returns the size of the required widget * @type Object * @return {Object} A JSON object representing the widget width/height, for example: {w:"200",h:"400"} */ getSize:function() { }, /** * Set the size of a widget * @param {String} width The width of the widget * @param {String} height The height of the widget * @type WidgetAccessor * @return{WidgetAccessor} return an handle of WidgetAccessor upon successful, null upon failure. */ setSize:function(width, height) { }, /** * Confirms whether it's possible or not to set the widget to the new width and height * @param {String} width The width of the widget * @param {String} height The height of the widget * @type Boolean * @return{Boolean} return true if it's possible to set widget to the new width and height */ confirmSetSize:function(width,height) { return true; }, /** * "minimize" window state supported by enabler * @type String */ MIN: "minimize", /** * "maximize" window state supported by enabler * @type String */ MAX: "maximize", /** * "normal" window state supported by enabler * @type String */ NORMAL: "normal" }); } if(!dojo._hasResource["com.ibm.mm.enabler.model.state.WidgetAccessorImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.model.state.WidgetAccessorImpl"] = true; dojo.provide("com.ibm.mm.enabler.model.state.WidgetAccessorImpl"); dojo.declare("com.ibm.mm.enabler.model.state.WidgetAccessorImpl", [com.ibm.mashups.enabler.model.state.WidgetAccessor], { constructor: function(navStateModel, id){ this.navStateModel = navStateModel; this.wid = id; this.uniqueWid = this._getUniqueWid(); this.widgetNavStateNode = navStateModel._find(this.WIDGET_PREFIX + this.navStateModel.DELIMITER + this.uniqueWid); if (this.wid != this.uniqueWid && !this.widgetNavStateNode) { this.widgetNavStateNodeFallback = navStateModel._find(this.WIDGET_PREFIX + this.navStateModel.DELIMITER + this.wid); } }, WIDGET_PREFIX: "wparams", WIDTH: "w", HEIGHT: "h", WINDOWSTATE: "st", SYSTEMSTATE: "rp", CUSTOMSTATE: "cp", VALUE: "value", PARAMS: "params", MODE: "md", RP: { w: "w", h: "h", st: "st", md: "md" }, VIEW: "view", getWidgetID: function(){ return this.wid; }, _getUniqueWid: function(){ return this.navStateModel._getUniqueWid(this.wid); }, getWidgetStateSet: function(){ var value = null; if (!this.widgetNavStateNode && !this.widgetNavStateNodeFallback) { return null; } var widgetNavStateNode = this.widgetNavStateNode; if (!widgetNavStateNode) { widgetNavStateNode = this.widgetNavStateNodeFallback; } var data = widgetNavStateNode.getRef(); if (data && data[this.VALUE]) { if (data[this.VALUE][this.CUSTOMSTATE]) { value = data[this.VALUE][this.CUSTOMSTATE]; } } if (value && !dojo.isString(value)) { value = dojo.toJson(value); } return value; //always return string as defined by the spec }, _createWidgetNavStateNode: function(){ var aNode = this.navStateModel.create({ key: this.uniqueWid }); var parentNode = this.navStateModel._find(this.WIDGET_PREFIX); if (!parentNode) { var temp = this.navStateModel.create({ key: this.WIDGET_PREFIX }); this.navStateModel.insert(temp, this.navStateModel._getRoot()); parentNode = this.navStateModel._find(this.WIDGET_PREFIX); } this.navStateModel.insert(aNode, parentNode); aNode = this.navStateModel._find(this.WIDGET_PREFIX + this.navStateModel.DELIMITER + this.uniqueWid); return aNode; }, setWidgetStateSet: function(object){ //it should be a simple String,save as an object internally var value = null; //need to support both string or object //save as object for portal CSA2 support if (dojo.isString(object)) { try { object = dojo.fromJson(object); } catch (e) { // just use the string } } if (!this.widgetNavStateNode) { //create this.widgetNavStateNode this.widgetNavStateNode = this._createWidgetNavStateNode(); } var data = this.widgetNavStateNode.getRef(); data.params = data.params ? data.params : {}; data.params.lm = new Date().getTime(); //todo if (data && data[this.VALUE]) { if (data[this.VALUE][this.CUSTOMSTATE]) { value = dojo.clone(data[this.VALUE][this.CUSTOMSTATE]); } } data[this.VALUE] = data[this.VALUE] ? data[this.VALUE] : {}; var obj = object; if (value && !dojo.isString(value) && !dojo.isString(object)) { obj = dojo.mixin(value, object); //mixin behaviour } data[this.VALUE][this.CUSTOMSTATE] = obj; this.navStateModel.setDirty(true); return this; }, _getWidgetSystemState: function(key){ var value = null; if (!this.widgetNavStateNode && !this.widgetNavStateNodeFallback) { return null; } var widgetNavStateNode = this.widgetNavStateNode; if (!widgetNavStateNode) { widgetNavStateNode = this.widgetNavStateNodeFallback; } var data = widgetNavStateNode.getRef(); if (data && data[this.VALUE]) { if (data[this.VALUE][this.SYSTEMSTATE]) { data = data[this.VALUE][this.SYSTEMSTATE]; if (data && data[key]) { value = data[key]; } } } return value; }, _setWidgetSystemState: function(key, value){ //overwrite behaviour if (!this.widgetNavStateNode) { this.widgetNavStateNode = this._createWidgetNavStateNode(); } var data = this.widgetNavStateNode.getRef(); data.params = data.params ? data.params : {}; data.params.lm = new Date().getTime(); //todo var keyRef = null; data[this.VALUE] = data[this.VALUE] ? data[this.VALUE] : {}; data[this.VALUE][this.SYSTEMSTATE] = data[this.VALUE][this.SYSTEMSTATE] ? data[this.VALUE][this.SYSTEMSTATE] : {}; keyRef = data[this.VALUE][this.SYSTEMSTATE]; keyRef[key] = value; this.navStateModel.setDirty(true); return this; }, getWidgetState: function(key){ var rc = this._getWidgetStateValue(key) || null; if (!rc) { return null; } if (!dojo.isString(rc)) { rc = dojo.toJson(rc); } return rc; }, _getWidgetStateValue: function(key){ if (!key) { return null; } if (key && key == "cp") { return this.getWidgetStateSet(); } if (this.RP[key]) { return this._getWidgetSystemState(key); } var value = null; if (!this.widgetNavStateNode && !this.widgetNavStateNodeFallback) { return null; } var widgetNavStateNode = this.widgetNavStateNode; if (!widgetNavStateNode) { widgetNavStateNode = this.widgetNavStateNodeFallback; } var data = widgetNavStateNode.getRef(); if (data && data[this.VALUE]) { if (data[this.VALUE][this.CUSTOMSTATE]) { data = data[this.VALUE][this.CUSTOMSTATE]; if (dojo.isString(data)) { return null; } if (data && data[key]) { value = data[key]; } } } return value; }, getWidgetStateValues: function(key){ // TODO implement var rc = this._getWidgetStateValue(key) || null; if (!rc) { return null; } if (dojo.isString(rc)) { var arr = []; arr.push(rc); return arr; } return rc; }, getWidgetStateNames: function(){ var names = []; if (!this.widgetNavStateNode && !this.widgetNavStateNodeFallback) { return null; } var widgetNavStateNode = this.widgetNavStateNode; if (!widgetNavStateNode) { widgetNavStateNode = this.widgetNavStateNodeFallback; } var data = widgetNavStateNode.getRef(); if (data && data[this.VALUE]) { if (data[this.VALUE][this.CUSTOMSTATE]) { data = data[this.VALUE][this.CUSTOMSTATE]; if (dojo.isString(data)) { return null; } if (data) { for (var i in data) { if (Object.prototype.hasOwnProperty.call(data, i)) { if (data[i]) { //if it's not deleted names.push(i); } } } } } } if (names.length === 0) { return null; } return names; }, setWidgetState: function(key, value){ if (!key || !value) { return null; } if (key && key == "cp") { return this.setWidgetStateSet(value); } var isValidValue = false; if (dojo.isArray(value) && value.length >= 1) { if (dojo.isString(value[0])) { isValidValue = true; } } if (!isValidValue) { if (dojo.isString(value)) { isValidValue = true; } } if (!isValidValue) { return null; } if (this.RP[key]) { return this._setWidgetSystemState(key, value); } //overwrite behaviour if (key && key == "cp") { return this.setWidgetStateSet(value); } if (!this.widgetNavStateNode) { this.widgetNavStateNode = this._createWidgetNavStateNode(); } var data = this.widgetNavStateNode.getRef(); data.params = data.params ? data.params : {}; data.params.lm = new Date().getTime(); //todo var keyRef = null; data[this.VALUE] = data[this.VALUE] ? data[this.VALUE] : {}; data[this.VALUE][this.CUSTOMSTATE] = data[this.VALUE][this.CUSTOMSTATE] ? data[this.VALUE][this.CUSTOMSTATE] : {}; keyRef = data[this.VALUE][this.CUSTOMSTATE]; keyRef[key] = value; this.navStateModel.setDirty(true); return this; }, removeWidgetState: function(key){ if (!key) { return false; } if (this.RP[key]) { return this._removeWidgetSystemState(key); } if (!this.widgetNavStateNode) { return false; } var data = this.widgetNavStateNode.getRef(); data.params = data.params ? data.params : {}; data.params.lm = new Date().getTime(); //todo if (key && key == "cp") { if (data && data[this.VALUE] && data[this.VALUE][this.CUSTOMSTATE]) { data[this.VALUE][this.CUSTOMSTATE] = null; this.navStateModel.setDirty(true); return true; } return false; } if (data && data[this.VALUE] && data[this.VALUE][this.CUSTOMSTATE]) { var keyRef = data[this.VALUE][this.CUSTOMSTATE]; if (keyRef && keyRef[key]) { keyRef[key] = null; this.navStateModel.setDirty(true); return true; } } return false; }, _removeWidgetSystemState: function(key){ if (!key) { return false; } if (!this.widgetNavStateNode) { return false; } var data = this.widgetNavStateNode.getRef(); data.params = data.params ? data.params : {}; data.params.lm = new Date().getTime(); //todo if (data && data[this.VALUE] && data[this.VALUE][this.SYSTEMSTATE]) { var keyRef = data[this.VALUE][this.SYSTEMSTATE]; if (keyRef && keyRef[key]) { keyRef[key] = null; this.navStateModel.setDirty(true); return true; } } return false; }, getWindowState: function(){ rc = this._getWidgetSystemState(this.WINDOWSTATE); //rc = rc ? rc : this.NORMAL; return rc; }, setWindowState: function(windowState){ if (windowState && (windowState == this.MIN || windowState == this.MAX || windowState == this.NORMAL)) { this._setWidgetSystemState(this.WINDOWSTATE, windowState); } }, getWidgetMode: function(){ var rc = this._getWidgetSystemState(this.MODE); //rc = rc ? rc : this.VIEW; return rc; }, setWidgetMode: function(aMode){ if (aMode) { this._setWidgetSystemState(this.MODE, aMode); return this; } return null; }, getSize: function(){ var size = {}; var height = this._getWidgetSystemState(this.HEIGHT); var width = this._getWidgetSystemState(this.WIDTH); if (height) { size[this.HEIGHT] = height; } if (width) { size[this.WIDTH] = width; } if (!size[this.HEIGHT] && !size[this.WIDTH]) { return null; } return size; }, setSize: function(width, height){ if (width) { this._setWidgetSystemState(this.WIDTH, width); } if (height) { this._setWidgetSystemState(this.HEIGHT, height); } return this; } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.model.state.WidgetAccessor"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.state.WidgetAccessor"] = true; dojo.provide("com.ibm.mashups.enabler.model.state.WidgetAccessor"); } if(!dojo._hasResource["com.ibm.mashups.enabler.model.state.PageModeAccessor_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.state.PageModeAccessor_API"] = true; dojo.provide("com.ibm.mashups.enabler.model.state.PageModeAccessor_API"); dojo.provide("com.ibm.mashups.enabler.model.state.PageModeAccessor"); /** * Interface representing an PageModeAccessor. * @ibm-spi * @ibm-module Base */ dojo.declare( "com.ibm.mashups.enabler.model.state.PageModeAccessor", [com.ibm.mashups.enabler.model.state.Accessor] , { /** * VIEW mode of page, can be used as com.ibm.mashups.enabler.model.state.PageModeAccessor.VIEW with "view" as the actual value
* @type String */ VIEW:"view", /** * EDIT mode of page, can be used as com.ibm.mashups.enabler.model.state.PageModeAccessor.EDIT with "edit" as the actual value
* @type String */ EDIT:"edit", /** * Returns the of the page mode of current page. * @type String * @return {String} The page mode of current page */ getPageMode:function() { }, /** * Sets the page mode of the page * @param {String} pageMode The mode of the page * @type void */ setPageMode:function(pageMode) { }, /** * Confirms if it's possible to set a new page mode * @param {String} pageMode The mode of the page * @type Boolean * @return{Boolean} return true if it's possible to set a new page mode */ confirmSetPageMode:function(pageMode) { return true; } }); com.ibm.mashups.enabler.model.state.PageModeAccessor.VIEW = "view"; com.ibm.mashups.enabler.model.state.PageModeAccessor.EDIT = "edit"; } if(!dojo._hasResource["com.ibm.mm.enabler.model.state.PageModeAccessorImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.model.state.PageModeAccessorImpl"] = true; dojo.provide("com.ibm.mm.enabler.model.state.PageModeAccessorImpl"); dojo.declare("com.ibm.mm.enabler.model.state.PageModeAccessorImpl", [com.ibm.mashups.enabler.model.state.PageModeAccessor], { constructor: function(navStateModel) { // it supports 3 modes: "view","edit","unload" -- unload is internal at this moment and used to indicate a page is being unloaded this.navStateModel = navStateModel; }, getPageMode: function() { var pageMode = this.navStateModel._getPageMode(); if (!pageMode) { return null; } return pageMode; }, setPageMode: function(mode) { if (mode) { this.navStateModel._setPageMode(mode); } return; } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.model.state.PageModeAccessor"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.state.PageModeAccessor"] = true; dojo.provide("com.ibm.mashups.enabler.model.state.PageModeAccessor"); } if(!dojo._hasResource["com.ibm.mashups.enabler.model.state.ShareableParameterSetAccessor_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.state.ShareableParameterSetAccessor_API"] = true; dojo.provide("com.ibm.mashups.enabler.model.state.ShareableParameterSetAccessor_API"); dojo.provide("com.ibm.mashups.enabler.model.state.ShareableParameterSetAccessor"); /** * Interface representing a ShareableParameterSetAccessor. * @ibm-spi * @ibm-module Base */ dojo.declare( "com.ibm.mashups.enabler.model.state.ShareableParameterSetAccessor", [com.ibm.mashups.enabler.model.state.Accessor], { /** * Returns the id of ShareableParamterSet * @type String * @return {String} name of ShareableParameterSet */ getId:function() { }, /** * Returns the scope of ShareableParamterSet or null, if this accessor represents the global scope. * @type String * @return {String} name of the scope */ getScope:function() { }, /** * Returns an array of all Shareable Parameter names within this Shareable Parameter Set * @type String[] * @return {String[]} array of all the ShareableParameterSet */ getAllNames:function() { }, /** * Set the value of a required item. It will replace the old value. If the value is a serialized version of complex data type, it's recommended for the widget to get the original * value, update the complex object and serialize again before calling this api. * @param {String} itemName The name of the required parameter * @param {String} value The value of the required parameter * @type Boolean * @return {Boolean} return true if item is updated or created successfully. */ setItemValue:function(itemName,value){ }, /** * Confirm if it's possible to set the value of a required item. It will replace the old value. If the value is a serialized version of complex data type, it's recommended for the widget to get the original * value, update the complex object and serialize again before calling this api. * @param {String} itemName The name of the required parameter * @param {String} value The value of the required parameter * @type Boolean * @return {Boolean} return true if it's possible to set the value */ confirmSetItemValue:function(itemName,value){ return true; }, /** * Remove the required item * @param {String} itemName The name of the required parameter that needs to be removed * @type Boolean * @return {Boolean} return true if item is removed successfully. */ removeItem:function(itemName){ }, /** * confirm if it's possible to remove the required item * @param {String} itemName The name of the required parameter that needs to be removed * @type Boolean * @return {Boolean} return true if it's possible to remove item */ confirmRemoveItem:function(itemName){ return true; }, /** * Returns the value of required item name * @param {String} itemName the name of the required parameter * @type String * @return {String} value of the required item */ getItemValue:function(itemName) { }, /** * Register listener so listener will be notified when an item set is updated * @param {Function} listener which is a js function that's already scoped properly. * @return{String} listener id */ registerListener:function(listener) { }, /** * Remove the listener given a listener id * @param {String} listenerId id of the listener that will be removed. * @type Boolean * @return {Boolean} return true if listener is removed successfully */ removeListener:function(listenerId) { }, /** * Confirm if it's possible to remove the listener given a listener id * @param {String} listenerId id of the listener that will be removed. * @type Boolean * @return {Boolean} return true if it's possible to remove Listener */ confirmRemoveListener:function(listenerId) { return true; } }); } if(!dojo._hasResource["com.ibm.mm.enabler.model.state.ShareableParameterSetAccessorImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.model.state.ShareableParameterSetAccessorImpl"] = true; dojo.provide("com.ibm.mm.enabler.model.state.ShareableParameterSetAccessorImpl"); dojo.declare("com.ibm.mm.enabler.model.state.ShareableParameterSetAccessorImpl", [com.ibm.mashups.enabler.model.state.ShareableParameterSetAccessor], { /** * @private */ DELETE_TOKEN: "DELETE_TOKEN", TYPE_NEW: "newItem", TYPE_UPDATE: "changedValue", TYPE_REMOVE: "removedItem", constructor: function(navStateModel, name, scope) { /*{ value:{//type: newItem/changedValue/removedItem page:{value:"3",params:{_isDirty:true,_type:"changedValue",_oldVal:"4"}}, tablesize:{value:"10"} } params:{lm:{},_listener:{}} } */ if (!scope) { this.scope = com.ibm.mm.enabler.model.state.ShareableParameterSetAccessorImpl.GLOBAL_SCOPE; } else { this.scope = scope; } this.name = name; this.navStateModel = navStateModel; this.navStateNode = navStateModel._find("sparams" + this.navStateModel.DELIMITER + name + this.navStateModel.DELIMITER + this.scope); }, _createNavStateNode: function() { var temp; var parentNode = this.navStateModel._find("sparams"); if (!parentNode) { temp = this.navStateModel.create({ key: "sparams" }); this.navStateModel.insert(temp, this.navStateModel._getRoot()); parentNode = this.navStateModel._find("sparams"); } var nameNode = this.navStateModel._find(this.name); if (!nameNode) { temp = this.navStateModel.create({ key: this.name }); this.navStateModel.insert(temp, parentNode); nameNode = this.navStateModel._find("sparams" + this.navStateModel.DELIMITER + this.name); } var scopeNode = this.navStateModel.create({ key: this.scope }); this.navStateModel.insert(scopeNode, nameNode); scopeNode = this.navStateModel._find("sparams" + this.navStateModel.DELIMITER + this.name + this.navStateModel.DELIMITER + this.scope); return scopeNode; }, getId: function() { return this.name; }, getScope: function() { return this.scope; }, getAllNames: function() { if (!this.navStateNode) { return null; } var arr = []; var data = this.navStateNode.getRef(); if (data && data[this.navStateModel.VALUE]) { for (var i in data[this.navStateModel.VALUE]) { if (data[this.navStateModel.VALUE].hasOwnProperty(i)) { var value = data[this.navStateModel.VALUE][i][this.navStateModel.VALUE]; if (value && value != this.DELETE_TOKEN) { arr.push(i); } } } } return arr; }, setItemValue: function(itemName, value) { if (!this.navStateNode) { //create this.widgetNavStateNode this.navStateNode = this._createNavStateNode(); } var data = this.navStateNode.getRef(); data.params = data.params ? data.params : {}; data.params.lm = new Date().getTime(); //mark lm of itemset data.value = data.value ? data.value : {}; var change = {}; if (!data.value[itemName]) { //new item data.value[itemName] = {}; data.value[itemName].value = value; data.value[itemName].params = data.value[itemName].params ? data.value[itemName].params : {}; data.value[itemName].params._isDirty = true; change.alias = itemName; change.type = this.TYPE_NEW; change.newVal = value; data.value[itemName].params._change = change; } else if (data.value[itemName]) { var oldValue = dojo.clone(data.value[itemName].value); data.value[itemName].value = value; data.value[itemName].params = data.value[itemName].params ? data.value[itemName].params : {}; var isDirty = data.value[itemName].params._isDirty; if (isDirty) { //check various condition change = data.value[itemName].params._change; if (change.type == this.TYPE_NEW) { change.newVal = value; } else if (change.type == this.TYPE_UPDATE) { change.newVal = value; } else if (change.type == this.TYPE_REMOVE) { if (change.oldVal) { change.type = this.TYPE_UPDATE; } else { change.type = this.TYPE_NEW; } change.newVal = value; } } else { change.type = this.TYPE_UPDATE; change.oldVal = oldValue; change.newVal = value; change.alias = itemName; data.value[itemName].params._change = change; } data.value[itemName].params._isDirty = true; } this.navStateModel.setDirty(true); return true; }, removeItem: function(itemName) { if (!this.navStateNode) { return false; } var data = this.navStateNode.getRef(); data.params = data.params ? data.params : {}; data.params.lm = new Date().getTime(); //mark lm of itemset if (data && data[this.navStateModel.VALUE]) { if (data[this.navStateModel.VALUE][itemName]) { var anItem = data[this.navStateModel.VALUE][itemName]; var oldValue = dojo.clone(anItem.value); anItem.value = this.DELETE_TOKEN; anItem.params = anItem.params ? anItem.params : {}; var isDirty = anItem.params._isDirty; var change = {}; if (isDirty) { change = anItem.params._change; if (change.type == this.TYPE_NEW) { //completely remove this item //data[this.navStateModel.VALUE][itemName]; delete data[this.navStateModel.VALUE][itemName]; } else if (change.type == this.TYPE_UPDATE) { change.type = this.TYPE_REMOVE; change.newVal = null; delete change.oldVal; } //don't do anything if it's remove } else { change.type = this.TYPE_REMOVE; change.alias = itemName; change.oldVal = oldValue; anItem.params._change = change; anItem.params._isDirty = true; } this.navStateModel.setDirty(true); } else { return false; //if item not found } } return true; }, getItemValue: function(itemName) { if (!this.navStateNode) { return null; } var data = this.navStateNode.getRef(); if (data && data[this.navStateModel.VALUE]) { if (data[this.navStateModel.VALUE][itemName]) { var anItemNode = data[this.navStateModel.VALUE][itemName]; var value = anItemNode[this.navStateModel.VALUE]; if (value && value != this.DELETE_TOKEN) { return value; } } } return null; }, registerListener: function(listener) { if (!this.navStateNode) { //create this.widgetNavStateNode this.navStateNode = this._createNavStateNode(); } var data = this.navStateNode.getRef(); var params = data[this.navStateModel.PARAMS]; if (!params) { data[this.navStateModel.PARAMS] = {}; params = data[this.navStateModel.PARAMS]; } if (!params._listeners) { params._listeners = {}; } var listenerId = this.navStateModel._generateListenerId(); params._listeners[listenerId] = listener; //save the function pointer here return listenerId; }, removeListener: function(listenerId) { if (!this.navStateNode) { return null; } var data = this.navStateNode.getRef(); var params = data[this.navStateModel.PARAMS]; if (params && params._listeners) { var listeners = params._listeners; if (listeners[listenerId]) { listeners[listenerId] = null; delete listeners[listenerId]; return true; } } return false; //listener not found }, _setItems: function(changedItems) { // add data to navigationstate for (var i in changedItems) { if (changedItems[i] && changedItems[i] == this.DELETE_TOKEN) { this.removeItem(i); } else if (changedItems[i]) { this.setItemValue(i, changedItems[i]); } } } }); com.ibm.mm.enabler.model.state.ShareableParameterSetAccessorImpl.GLOBAL_SCOPE = "global"; } if(!dojo._hasResource["com.ibm.mashups.enabler.model.state.ShareableParameterSetAccessor"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.state.ShareableParameterSetAccessor"] = true; dojo.provide("com.ibm.mashups.enabler.model.state.ShareableParameterSetAccessor"); } if(!dojo._hasResource["com.ibm.mashups.enabler.model.state.LayoutContainerAccessor_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.state.LayoutContainerAccessor_API"] = true; dojo.provide("com.ibm.mashups.enabler.model.state.LayoutContainerAccessor_API"); dojo.provide("com.ibm.mashups.enabler.model.state.LayoutContainerAccessor"); /** * Interface representing a LayoutContainerAccessor. Reserved layout container paramers: * "w" : the reserved parameter for layout container width. * @ibm-spi * @ibm-module Base */ dojo.declare( "com.ibm.mashups.enabler.model.state.LayoutContainerAccessor", [com.ibm.mashups.enabler.model.state.Accessor], { /** * @private */ constructor:function (navStateModel, componentId, pageId) { }, /** * Returns the id of the layout container * @type String * @return {String} ID of required layout container */ getID:function() { }, /** * Returns the size of the required layout container * @type Object * @return {Object} A JSON object representing the layout container width, for example: {w:"70%"} */ getSize:function() { }, /** * Set the size of a layout container * @param {String} width The width of the layout container * @type LayoutContainerAccessor * @return{LayoutContainerAccessor} return an handle of LayoutContainerAccessor upon successful, null upon failure. */ setSize:function(width) { }, /** * Confirms whether it's possible or not to set the layout container to the new width and height * @param {String} width The width of the layout container * @type Boolean * @return{Boolean} return true if it's possible to set layout container to the new width and height */ confirmSetSize:function(width) { return true; } }); } if(!dojo._hasResource["com.ibm.mm.enabler.model.state.LayoutContainerAccessorImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.model.state.LayoutContainerAccessorImpl"] = true; dojo.provide("com.ibm.mm.enabler.model.state.LayoutContainerAccessorImpl"); dojo.declare("com.ibm.mm.enabler.model.state.LayoutContainerAccessorImpl", [com.ibm.mashups.enabler.model.state.LayoutContainerAccessor], { constructor: function(navStateModel, containerId, pageId){ this.navStateModel = navStateModel; this.cid = containerId; this.pid = pageId; var delim = this.navStateModel.DELIMITER; var path = this.LAYOUT_PREFIX; path += delim + this.pid; this.layoutNavStateNode = navStateModel._find(path); if (this.layoutNavStateNode) { path += delim + this.VALUE + delim + this.cid; this.layoutContainerNavStateNode = navStateModel._find(path); } else { this.layoutContainerNavStateNode = null; } }, LAYOUT_PREFIX: "lcparams", WIDTH: "w", SYSTEMSTATE: "rp", VALUE: "value", PARAMS: "params", MODE: "md", RP: { w: "w" }, getID: function(){ return this.cid; }, _getLayoutContainerSystemState: function(key){ var value = null; if (!this.layoutContainerNavStateNode) { return null; } var data = this.layoutContainerNavStateNode.getRef(); if (data && data[this.VALUE]) { if (data[this.VALUE][this.SYSTEMSTATE]) { data = data[this.VALUE][this.SYSTEMSTATE]; if (data && data[key]) { value = data[key]; } } } return value; }, _setLayoutContainerSystemState: function(key, value){ var data; //overwrite behavior if (!this.layoutContainerNavStateNode) { this.layoutContainerNavStateNode = this._createLayoutContainerNavStateNode(); } data = this.layoutNavStateNode.getRef(); data.params = data.params ? data.params : {}; data.params.lm = new Date().getTime(); data = this.layoutContainerNavStateNode.getRef(); var keyRef = null; data[this.VALUE] = data[this.VALUE] ? data[this.VALUE] : {}; data[this.VALUE][this.SYSTEMSTATE] = data[this.VALUE][this.SYSTEMSTATE] ? data[this.VALUE][this.SYSTEMSTATE] : {}; keyRef = data[this.VALUE][this.SYSTEMSTATE]; keyRef[key] = value; this.navStateModel.setDirty(true); return this; }, _createLayoutNavStateNode: function(){ var aNode = this.navStateModel.create({ key: this.pid }); var parentNode = this.navStateModel._find(this.LAYOUT_PREFIX); if (!parentNode) { var temp = this.navStateModel.create({ key: this.LAYOUT_PREFIX }); this.navStateModel.insert(temp, this.navStateModel._getRoot()); parentNode = this.navStateModel._find(this.LAYOUT_PREFIX); } this.navStateModel.insert(aNode, parentNode); aNode = this.navStateModel._find(this.LAYOUT_PREFIX + this.navStateModel.DELIMITER + this.pid); return aNode; }, _createLayoutContainerNavStateNode: function(){ //overwrite behaviour if (!this.layoutNavStateNode) { this.layoutNavStateNode = this._createLayoutNavStateNode(); } var data = this.layoutNavStateNode.getRef(); data[this.VALUE] = data[this.VALUE] ? data[this.VALUE] : {}; var delim = this.navStateModel.DELIMITER; var path = this.LAYOUT_PREFIX + delim + this.pid + delim + this.VALUE; var aNode = this.navStateModel.create({ key: this.cid }); var parentNode = this.navStateModel._find(path); this.navStateModel.insert(aNode, parentNode); aNode = this.navStateModel._find(path + delim + this.cid); return aNode; }, getSize: function(){ var size = {}; var width = this._getLayoutContainerSystemState(this.WIDTH); if (width) { size[this.WIDTH] = width; return size; } else { return null; } return size; }, setSize: function(width){ if (width) { this._setLayoutContainerSystemState(this.WIDTH, width); } return this; } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.model.state.LayoutContainerAccessor"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.state.LayoutContainerAccessor"] = true; dojo.provide("com.ibm.mashups.enabler.model.state.LayoutContainerAccessor"); } if(!dojo._hasResource["com.ibm.mashups.enabler.model.state.LayoutAccessor_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.state.LayoutAccessor_API"] = true; dojo.provide("com.ibm.mashups.enabler.model.state.LayoutAccessor_API"); dojo.provide("com.ibm.mashups.enabler.model.state.LayoutAccessor"); /** * Interface representing a LayoutAccessor. Reserved layout container parameters: * "templateURL" : the reserved parameter for layout template URL. * @ibm-spi * @ibm-module Base */ dojo.declare( "com.ibm.mashups.enabler.model.state.LayoutAccessor", [com.ibm.mashups.enabler.model.state.Accessor], { /** * @private */ constructor:function (navStateModel, pageId) { }, /** * Returns the layout template URL (can be used to determine if the state layout is inconsistent with the page instance layout) * @type String * @return {String} A url to the layout's template. Uses dav: endpoint notation, e.g. "dav:filestore/layout-tempates/2ColumnEqual" */ getTemplateURL:function() { }, /** * Sets the layout template URL * @param {String} url The layout templateURL. Uses dav: endpoint notation, e.g. "dav:filestore/layout-tempates/2ColumnEqual" * @type LayoutAccessor * @return{com.ibm.mashups.enabler.model.state.LayoutAccessor} returns a LayoutAccessor upon success, null upon failure. */ setTemplateURL:function(url) { }, /** * Returns the layout container accessor for the specified layout container id in this layout. (Note: Possibly non-intinutively Layout contains LayoutContainers.) * @param {String} containerId The layout container id for the desired layout container. * @type LayoutContainerAccessor * @return {com.ibm.mashups.enabler.model.state.LayoutContainerAccessor} Returns the specified LayoutContainerAccessor upon success, null upon failure. */ getContainerAccessor:function(containerId) { }, /** * Removes all layout containers and the template URL (can be used to remove obsolete layout's i.e. when the state layout is not the same as the page instance layout) * @param {Array} pageWidgets Set of widgets on page that if in model should have their size removed. Optional parameter. * @type LayoutContainerAccessor * @return{com.ibm.mashups.enabler.model.state.LayoutAccessor} Returns a LayoutAccessor upon success, null upon failure. */ removeAll:function(pageWidgets) { } }); } if(!dojo._hasResource["com.ibm.mm.enabler.model.state.LayoutAccessorImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.model.state.LayoutAccessorImpl"] = true; dojo.provide("com.ibm.mm.enabler.model.state.LayoutAccessorImpl"); dojo.declare("com.ibm.mm.enabler.model.state.LayoutAccessorImpl", [com.ibm.mashups.enabler.model.state.LayoutAccessor], { constructor: function(navStateModel, pageId){ this.navStateModel = navStateModel; this.pid = pageId; this.path = this.LAYOUT_PREFIX + this.navStateModel.DELIMITER + this.pid; this.layoutNavStateNode = null; }, LAYOUT_PREFIX: "lcparams", WIDGET_PREFIX: "wparams", VALUE: "value", TEMPLATE_URL: "templateURL", SYSTEMSTATE: "rp", WIDTH: "w", HEIGHT: "h", _getLayoutState: function(key){ var value = null; // we need to check if the layoutNavsState node exists for each call because // layout containers can create this node too. if (!this.layoutNavStateNode) { this.layoutNavStateNode = this.navStateModel._find(this.path); if (!this.layoutNavStateNode) return null; } var data = this.layoutNavStateNode.getRef(); if (data && data[key]) value = data[key]; return value; }, _setLayoutState: function(key, value){ var data; //overwrite behavior if (!this.layoutNavStateNode) { this.layoutNavStateNode = this.navStateModel._find(this.path); if (!this.layoutNavStateNode) this.layoutNavStateNode = this._createLayoutNavStateNode(); } data = this.layoutNavStateNode.getRef(); data.params = data.params ? data.params : {}; data.params.lm = new Date().getTime(); data[key] = value; this.navStateModel.setDirty(true); return this; }, _createLayoutNavStateNode: function(){ var aNode = this.navStateModel.create({ key: this.pid }); var parentNode = this.navStateModel._find(this.LAYOUT_PREFIX); if (!parentNode) { var temp = this.navStateModel.create({ key: this.LAYOUT_PREFIX }); this.navStateModel.insert(temp, this.navStateModel._getRoot()); parentNode = this.navStateModel._find(this.LAYOUT_PREFIX); } this.navStateModel.insert(aNode, parentNode); aNode = this.navStateModel._find(this.path); return aNode; }, getTemplateURL: function(){ return this._getLayoutState(this.TEMPLATE_URL); }, setTemplateURL: function(url){ return this._setLayoutState(this.TEMPLATE_URL, url); }, removeAll: function(pageWidgets) { var delim = this.navStateModel.DELIMITER; if (pageWidgets && this.navStateModel._find(this.WIDGET_PREFIX)) { var i; var systemState; for (i = 0; i < pageWidgets.length; i++) { systemState = this.navStateModel._find(this.WIDGET_PREFIX + delim + pageWidgets[i] + delim + this.VALUE + delim + this.SYSTEMSTATE); if (systemState) { systemState = systemState.getRef(); delete systemState[this.WIDTH]; delete systemState[this.HEIGHT]; this.navStateModel.setDirty(true); } } } if (this.layoutNavStateNode) { this.navStateModel.remove(this.layoutNavStateNode); this.navStateModel.setDirty(true); delete this.layoutNavStateNode; } return this; }, getContainerAccessor: function(containerId) { return new com.ibm.mm.enabler.model.state.LayoutContainerAccessorImpl(this.navStateModel, containerId, this.pid); } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.model.state.LayoutAccessor"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.state.LayoutAccessor"] = true; dojo.provide("com.ibm.mashups.enabler.model.state.LayoutAccessor"); } if(!dojo._hasResource["com.ibm.mashups.enabler.model.state.AccessorFactory_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.state.AccessorFactory_API"] = true; dojo.provide("com.ibm.mashups.enabler.model.state.AccessorFactory_API"); dojo.provide("com.ibm.mashups.enabler.model.state.AccessorFactory"); /** * Interface representing an AccessorFactory. Accessor API should be used to read/write information from NavigationStateModel. * @ibm-spi * @ibm-module Base */ dojo.declare( "com.ibm.mashups.enabler.model.state.AccessorFactory", null, { /** * Returns the Accessor to access Page selection in each Space * @param {com.ibm.mashups.enabler.model.state.NavigationStateModel} navStateModel NavigationStateModel to get Space/Page Selection * @param {String} spaceId spaceId to getPage Selection * @type com.ibm.mashups.enabler.model.state.PageAccessor * @return {com.ibm.mashups.enabler.model.state.PageAccessor} The PageAccessor of NavigationStateModel */ getPageAccessor:function(navStateModel,spaceId) { // look for node in model and instatiate the Page Accessor with Node }, /** * Returns the Accessor to access Space selection * @param {com.ibm.mashups.enabler.model.state.NavigationStateModel} navStateModel NavigationStateModel to get Space Selection * @type com.ibm.mashups.enabler.model.state.SpaceAccessor * @return {com.ibm.mashups.enabler.model.state.SpaceAccessor} The SpaceAccessor of NavigationStateModel */ getSpaceAccessor:function(navStateModel) { }, /** * Returns the Widget Accessor to access Widget state information * @param {com.ibm.mashups.enabler.model.state.NavigationStateModel} navStateModel to Widget Navigation State * @param {String} widgetId to Widget Navigation State * @type com.ibm.mashups.enabler.model.state.WidgetAccessor * @return {com.ibm.mashups.enabler.model.state.WidgetAccessor} The WidgetAccessor of NavigationStateModel */ getWidgetAccessor:function(navStateModel, widgetId) { }, /** * Returns the Accessor to access Page mode of current page * @param {com.ibm.mashups.enabler.model.state.NavigationStateModel} navStateModel NavigationStateModel to get Space/Page Selection * @type com.ibm.mashups.enabler.model.state.PageModeAccessor * @return {com.ibm.mashups.enabler.model.state.PageModeAccessor} The PageModeAccessor of NavigationStateModel */ getPageModeAccessor:function(navStateModel) { // look for node in model and instatiate the Page Accessor with Node }, /** * Returns the Accessor to access the sharable parameters * @param {com.ibm.mashups.enabler.model.state.NavigationStateModel} navStateModel NavigationStateModel to get ShareableParameterSet * @param {String} id id of ShareableParameterSet * @param {String} scope optional scope for the sharable item set. If not provided or null, the global scope is returned. * @type com.ibm.mashups.enabler.model.state.ShareableParameterSetAccessor * @return {com.ibm.mashups.enabler.model.state.ShareableParameterSetAccessor} The ShareableParameterSetAccessor of NavigationStateModel */ getShareableParameterSetAccessor:function(navStateModel,id,scope) { // look for node in model and instatiate the Page Accessor with Node }, /** * Returns the Layout Accessor to access page layout state information * @param {com.ibm.mashups.enabler.model.state.NavigationStateModel} navStateModel to Layout Navigation State * @param {String} pageId of the page containing the Layout Container * @type com.ibm.mashups.enabler.model.state.LayoutAccessor * @return {com.ibm.mashups.enabler.model.state.LayoutAccessor} The LayoutAccessor of NavigationStateModel for the specified page */ getLayoutAccessor:function(navStateModel, pageId){ } }); } if(!dojo._hasResource["com.ibm.mm.enabler.model.state.AccessorFactoryImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.model.state.AccessorFactoryImpl"] = true; dojo.provide("com.ibm.mm.enabler.model.state.AccessorFactoryImpl"); dojo.declare("com.ibm.mm.enabler.model.state.AccessorFactoryImpl", [com.ibm.mashups.enabler.model.state.AccessorFactory], { constructor: function() { }, getPageAccessor: function(navStateModel, spaceId) { return new com.ibm.mm.enabler.model.state.PageAccessorImpl(navStateModel, spaceId); }, getPageModeAccessor: function(navStateModel) { return new com.ibm.mm.enabler.model.state.PageModeAccessorImpl(navStateModel); }, getSpaceAccessor: function(navStateModel) { return new com.ibm.mm.enabler.model.state.SpaceAccessorImpl(navStateModel); }, getWidgetAccessor: function(navStateModel, widgetId) { return new com.ibm.mm.enabler.model.state.WidgetAccessorImpl(navStateModel, widgetId); }, getShareableParameterSetAccessor: function(navStateModel, name, scope) { return new com.ibm.mm.enabler.model.state.ShareableParameterSetAccessorImpl(navStateModel, name, scope); }, getLayoutAccessor:function(navStateModel, pageId){ return new com.ibm.mm.enabler.model.state.LayoutAccessorImpl(navStateModel, pageId); } }); com.ibm.mashups.enabler.model.state.AccessorFactory = new com.ibm.mm.enabler.model.state.AccessorFactoryImpl(); } if(!dojo._hasResource["com.ibm.mashups.enabler.model.state.AccessorFactory"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.state.AccessorFactory"] = true; dojo.provide("com.ibm.mashups.enabler.model.state.AccessorFactory"); } if(!dojo._hasResource["com.ibm.mashups.enabler.model.state.NavigationStateModel_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.state.NavigationStateModel_API"] = true; dojo.provide("com.ibm.mashups.enabler.model.state.NavigationStateModel_API"); dojo.provide("com.ibm.mashups.enabler.model.state.NavigationStateModel"); /** * Interface for a Navigation state model.
* Navigation State API does not garantee that any modifications issued on the API have any further impact on the
* user experience of any widgets or components on the page. Widgets or components may choose to listen to changes on the Navigation
* State Model and react properly upon those changes. However any user experience change cuased by those components are not part of
* the contract of this API and therefore these UI behaviour may change going forward
* * AccessorFactory API should be used to read/write navigation state within NavigationStateModel.

* var navStateModel=com.ibm.mashups.enabler.model.state.NavigationStateModelFactory.getNavigationStateModel();
* var widgetAccessor = com.ibm.mashups.enabler.model.state.AccessorFactory.getWidgetAccessor(navStateModel);
* widgetAccessor.setSize("200","300");
* var deferred = navStateModel.commit();
* deferred.setFinishedCallback(cb);
* deferred.start();
* * @ibm-spi * @ibm-module Base */ dojo.declare( "com.ibm.mashups.enabler.model.state.NavigationStateModel", null, { /** * The name of the event to handle to get NavState update notifications. * @type String */ ONNAVSTATEUPDATED:"com.ibm.mashups.enabler.model.state.onNavStateUpdated", /** * This method starts a global transaction for a NavigationStateModel object
* @type void */ startTransaction: function () { return; }, /** * This method commits all changes done withing a global transaction for a NavigationStateModel object
* @type void */ commitTransaction: function () { return; }, /** * This method discards all changes done within a transaction for a NavigationStateModel object and restores the original NavigationStateModel object.
* @type void */ discardTransaction: function () { return; }, /** * This method starts a global transaction for a NavigationStateModel object
* @return {boolean} Returns true if a transaction has been started, false otherwise. */ isTransaction: function () { return false; }, /** * Commits the modifications applied to this model and all dependent models.
* @param {Object} additionalParams Optional JSON object to control various aspects while commiting
*   addToHistory (Boolean) - true if the state should be added to the browser history, false otherwise
*   allowRedirect (Boolean) - true if the page should be refreshed after the commit, false otherwise. Note, this parameter is ignored if the commit is synchronous
* @return {DeferredOperation} a deferred object used to start this operation. * The return value when executed through the deferred object is null */ commit: function (additionalParams) { return new com.ibm.mashups.enabler.Deferred(); }, /** * Discards the modifications applied to this model.
* @type void */ discard: function () { return; }, /** * Dispose this model completely all the navigation state will be destroyed.
* @type void */ dispose: function () { return; } }); } if(!dojo._hasResource["com.ibm.mashups.enabler.services.IdentificationService_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.services.IdentificationService_API"] = true; dojo.provide("com.ibm.mashups.enabler.services.IdentificationService_API"); dojo.provide("com.ibm.mashups.enabler.services.IdentificationService"); /** * Interface to work with client side ids. * @ibm-spi * @ibm-module Base * @since 3.0 */ dojo.declare("com.ibm.mashups.enabler.services.IdentificationService", null, { /** * Returns a new client side ID. * @return {String} client side id; never null. */ createClientID: function() { }, /** * This method attaches a client side id to make it know to the service * @param {Object} clientID client side id as string or Identifiable object * @return {void} * @since 3.0.0.1 */ attachClientID: function(clientID) { }, /** * Releases an earlier through getClientID loaded client id. * @param {String} id the id to release * @return {void} */ releaseClientID: function(id) { }, /** * Checks whether the specified id is a client id of this IdentificationService * @param {String} id the id to check for client id * @return {boolean} true if the specified id is a client id false otherwise. */ isClientID: function(id) { }, /** * Checks whether the specified id is a server id generated by the underling server implementation * @param {String} id the id to check for server id * @return {boolean} true if the specified id is a server id false otherwise. */ isServerID: function(id) { }, /** * Checks whether the specified id is neither an client id nor an server id but is specified outside the mashup framework. * * @param {String} id the id to check for alien id * @return {boolean} true if the specified id is a alien id false otherwise. */ isAlienID: function(id) { }, /** * This method attaches a server side id to an existing client side id. * @param {Object} clientID client side id as string or Identifiable object * @param {Object} serverID server side id as string or Identifiable object * @return {void} */ attachServerID: function(clientID, serverID) { }, /** * Returns the attached server side id for any given client side id. Returns the * specified id, if it cannot be resolved. * @param {String} id the id to resolve * @return {String} id the resolved id */ resolveID: function(id) { }, /** * Returns the attached server side id for any given client side id. Returns the * specified id, if it cannot be resolved. * @param {String} id the id to resolve * @return {com.ibm.mashups.enabler.Identifiable} id the resolved id */ resolveIdentifiable: function(id) { } }); } if(!dojo._hasResource["com.ibm.mm.enabler.utils.Utils"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.utils.Utils"] = true; /*WARNING: don't include this class in any iWidget2 modules,it should be exclusively used by Model related api*/ dojo.provide("com.ibm.mm.enabler.utils.Utils"); dojo.declare("com.ibm.mm.enabler.utils.UtilsImpl", null, { constructor: function() { // we do a lazy init this.serviceJson = null; }, _lazyInit: function() { if (this.serviceJson) { return; } this.xmlDom = com.ibm.mm.enabler.utils.Dom.createDocument(); // service document and initialization this.serviceJson = com.ibm.mm.enabler.model.ServiceDocumentModel.getCollectionData(com.ibm.mm.enabler.model.ServiceDocumentModel.SERVICE_NAVIGATION); this.prefix = this.serviceJson.idprefix; var nsf = com.ibm.mm.enabler.model.NameSpaceFactory; this.ns = dojo.delegate(this.serviceJson.namespaces, nsf.getNameSpaces([nsf.NS_ATOM])); }, createNode: function(name, ns) { this._lazyInit(); return com.ibm.mm.enabler.utils.Dom.createElement(this.xmlDom, name, ns); }, createLinkNode: function(href, rel, ns) { var linkNode = this.createNode("atom:link", ns); linkNode.setAttribute("href", href); linkNode.setAttribute("rel", rel); return linkNode; }, createExtLinkNode: function(href, rel, extrel) { this._lazyInit(); var nsf = com.ibm.mm.enabler.model.NameSpaceFactory; var linkNode = this.createNode("atom:link", this.ns[nsf.NS_ATOM]); linkNode.setAttribute("href", href); if (rel) { linkNode.setAttribute("rel", rel); } com.ibm.mm.enabler.utils.Dom.setAttributeWithNS(this.xmlDom, linkNode, "ext:rel", "rel", this.ns.ext, extrel); return linkNode; }, getIdFromExtUri: function(prefix, node) { this._lazyInit(); var id = null; var uri = com.ibm.mm.enabler.utils.Dom.getAttributeWithNS(node, "ext:uri", "uri", this.ns.ext); // remove model scope from id if (uri) { // check for associative id var aPos = uri.indexOf("@"); if (aPos != -1) { uri = uri.slice(0, aPos); } id = uri; // remove model scope from id var idPos = id.lastIndexOf(":"); if (idPos != -1) { id = id.slice(idPos + 1); } idPos = id.toUpperCase().lastIndexOf("%3A"); if (idPos != -1) { id = id.slice(idPos + 3); } idPos = id.lastIndexOf("/"); if (idPos != -1) { id = id.slice(idPos + 1); } } return id; }, getHrefFromIdentifiable: function(identifiable) { return (identifiable && (typeof identifiable._getParameters == "function")) ? identifiable._getParameters().href : null; }, getIdFromIdentifiable: function(identifiable) { if(com.ibm.mm.enabler.utils.Misc.isInstanceOf(identifiable, com.ibm.mashups.enabler.Identifiable)) { return identifiable.getID(); } else if(dojo.isString(identifiable)) { return dojo.string.trim(identifiable); } else { return identifiable; } }, setAttributeWithNS: function(element, attName, nsUri, value) { this._lazyInit(); com.ibm.mm.enabler.utils.Dom.setAttributeWithNS(this.xmlDom, element, attName, null, nsUri, value); }, createFeed: function(id, title, entry, namespaces) { var ns = ""; for (var prefix in namespaces) { if (Object.prototype.hasOwnProperty.call(namespaces,prefix)) { ns += "xmlns:" + prefix + "=\"" + namespaces[prefix] + "\" "; } } var time = new Date(); var feed = '\n' + '\n' + '' + title + '\n' + '' + id + '\n' + '' + time.toGMTString() + '\n' + entry + ''; return feed; } }); com.ibm.mm.enabler.utils.Utils = new com.ibm.mm.enabler.utils.UtilsImpl(); } if(!dojo._hasResource["com.ibm.mm.enabler.IdentifiableHelper"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.IdentifiableHelper"] = true; dojo.provide("com.ibm.mm.enabler.IdentifiableHelper"); //com.ibm.mm.enabler.IdentifiableHelper.getID = function(id){ // // check for associative id // var aPos = id.indexOf("@"); // if (aPos != -1) { // id = id.slice(0, aPos); // } // // // remove model scope from id // var idPos = id.lastIndexOf(":"); // if (idPos != -1) { // id = id.slice(idPos + 1); // } // idPos = id.toUpperCase().lastIndexOf("%3A"); // if (idPos != -1) { // id = id.slice(idPos + 3); // } // idPos = id.lastIndexOf("/"); // if (idPos != -1) { // id = id.slice(idPos + 1); // } // // return id; //}; com.ibm.mm.enabler.IdentifiableHelper.ID_MATCHER = /^(.*?)(%3a)?([ \.\w_\-]*)(@.*?)?$/i; com.ibm.mm.enabler.IdentifiableHelper.getID = function(id) { var matches = id.match(com.ibm.mm.enabler.IdentifiableHelper.ID_MATCHER); return matches ? matches[3] : ""; }; //com.ibm.mm.enabler.IdentifiableHelper.replaceID = function(currentId, prefix, newId){ // // // associative id (including '@') // var aPos = currentId.indexOf("@"); // var association = (aPos != -1) ? currentId.slice(aPos) : ""; // // // model schema // var mPos = currentId.indexOf(prefix + ":"); // var model = (mPos > 0) ? currentId.slice(0, mPos) : ""; // // // remove model scope and add 'newId:' from input newId if necessary // var idPos = newId.indexOf(prefix + ":"); // var value = (idPos >= 0) ? newId.slice(idPos) : prefix + ":" + newId; // // return model + value + association; //}; com.ibm.mm.enabler.IdentifiableHelper.replaceID = function(currentId, prefix, newId) { var id = com.ibm.mm.enabler.IdentifiableHelper.getID(newId); var matches = currentId.match(com.ibm.mm.enabler.IdentifiableHelper.ID_MATCHER); return prefix + ":" + id + (matches ? (matches[4] || "") : ""); }; } if(!dojo._hasResource["com.ibm.mm.enabler.utils.Atom"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.utils.Atom"] = true; dojo.provide("com.ibm.mm.enabler.utils.Atom"); com.ibm.mm.enabler.utils.Atom = { // atom feed _FEED: "atom:feed", // atom entry _ENTRY: "atom:entry", // atom link _LINK: "atom:link", // atom id _ID: "atom:id", // next link _NEXT_LINK: "atom:link[@rel='next']", // edit link _EDIT_LINK: "atom:link[@rel='edit']", // replies link _REPLIES_LINK: "atom:link[@rel='replies']", // replies link href _REPLIES_LINK_HREF: "atom:link[@rel='replies']/@href", // in-reply-to link _IN_REPLY_TO_LINK: "thr:in-reply-to", // in-reply-to link href _IN_REPLY_TO_LINK_HREF: "thr:in-reply-to/@href", /** * Creates an atom:entry with a title and an optional element for a specific model artifact. * * Example usage: * * * * var res = com.ibm.mm.enabler.utils.Misc._createAtomEntry("new navigation node", "model:navigation-node", namespace); * var entry = res.entryElement; // reference to * var id = res.idElement; // reference to * var model = res.modelElement; // reference to * * @param {String} title title of the atom:entry * @param {String} qname the qname of the model artifact to be created in the atom:content element * @param {String} namespace corresponding name space * @return {Object} object with properties "entryElement", "modelElement" (optional), and "idElement" */ createEntry: function(title, qname, namespace){ var result = {}; // name spaces var nsf = com.ibm.mm.enabler.model.NameSpaceFactory; var ns = nsf.getNameSpaces([nsf.NS_ATOM]); // atom:entry var entry = com.ibm.mm.enabler.utils.Utils.createNode("atom:entry", ns.atom); // atom:id var idElem = com.ibm.mm.enabler.utils.Utils.createNode("atom:id", ns.atom); entry.appendChild(idElem); // atom:title var titleElem = com.ibm.mm.enabler.utils.Utils.createNode("atom:title", ns.atom); if (title) { com.ibm.mm.enabler.utils.Dom.textContent(titleElem, title); } entry.appendChild(titleElem); // atom:updated var updated = com.ibm.mm.enabler.utils.Utils.createNode("atom:updated", ns.atom); var time = new Date(); com.ibm.mm.enabler.utils.Dom.textContent(updated, time.toGMTString()); entry.appendChild(updated); // atom:content var content = com.ibm.mm.enabler.utils.Utils.createNode("atom:content", ns.atom); content.setAttribute("type", "application/xml"); entry.appendChild(content); if (qname && namespace) { // add specified element var elem = com.ibm.mm.enabler.utils.Utils.createNode(qname, namespace); content.appendChild(elem); result.modelElement = elem; } result.entryElement = entry; result.idElement = idElem; return result; } }; } if(!dojo._hasResource["com.ibm.mm.enabler.persistence.xml.IdentifiableXmlImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.persistence.xml.IdentifiableXmlImpl"] = true; dojo.provide("com.ibm.mm.enabler.persistence.xml.IdentifiableXmlImpl"); // i18n dojo.declare("com.ibm.mm.enabler.persistence.xml.IdentifiableXmlImpl", [com.ibm.mashups.enabler.Identifiable, com.ibm.mm.enabler.DirtyFlagProviderImpl, com.ibm.mm.enabler.ServiceDocConsumer], { constructor: function(){ // messages this.modelMessages = dojo.i18n.getLocalization("com.ibm.mm.enabler", "modelMessages"); this._resetCachedRawID(); this._addDirtyCallback(this, this._resetCachedRawID, null, true); }, // class member - must NOT be an instance member _cachedRawIdToken: {}, _resetCachedRawID: function(){ this._cachedRawID = this._cachedRawIdToken; }, _cachedRawID: null, _initServiceDoc: function(){ this.inherited("_initServiceDoc", arguments); // service document and initialization var serviceJson = com.ibm.mm.enabler.model.ServiceDocumentModel.getCollectionData(com.ibm.mm.enabler.model.ServiceDocumentModel.SERVICE_NAVIGATION); var nsf = com.ibm.mm.enabler.model.NameSpaceFactory; this.id_ns = dojo.delegate(serviceJson.namespaces, nsf.getNameSpaces([nsf.NS_ATOM, nsf.NS_THR, nsf.NS_XML, nsf.NS_OPENSEARCH, nsf.NS_XHTML, nsf.NS_APP])); this.id_prefix = serviceJson.idprefix; }, getID: function(){ var id = this._getRawID(); return id ? com.ibm.mm.enabler.IdentifiableHelper.getID(id) : id; }, _getRawID: function(){ this._initServiceDoc(); if (this._cachedRawID === this._cachedRawIdToken) { var result = null; var node = com.ibm.mashups.enabler.xml.XPath.evaluateString(com.ibm.mm.enabler.utils.Atom._ID, this.xmlData, this.id_ns); if (node) { result = dojo.string.trim(node); } this._cachedRawID = result; } return this._cachedRawID; }, equals: function(identifiable){ return com.ibm.mm.enabler.utils.Utils.getIdFromIdentifiable(this) == com.ibm.mm.enabler.utils.Utils.getIdFromIdentifiable(identifiable); }, setID: function(id){ this._initServiceDoc(); var rawID = this._getRawID(); var newId = com.ibm.mm.enabler.IdentifiableHelper.replaceID(rawID || "", this.id_prefix, id); if (newId != rawID) { this._setRawID(newId); } }, _setRawID: function(id){ this._initServiceDoc(); id = id || ""; var node = com.ibm.mashups.enabler.xml.XPath.evaluateEntry(com.ibm.mm.enabler.utils.Atom._ID, this.xmlData, this.id_ns); if (node) { var currentId = this._getRawID(); if (id != currentId) { com.ibm.mm.enabler.utils.Dom.textContent(node, id); this._setDirty(); // populate cache this._cachedRawID = dojo.string.trim(id); } } else { throw new Error(dojo.string.substitute(this.modelMessages.E_ELEMENT_NOT_FOUND_2, [com.ibm.mm.enabler.utils.Atom._ID, this.toString()])); } }, getUniqueName: function(){ this._initServiceDoc(); var name = null; var res = com.ibm.mashups.enabler.xml.XPath.evaluateEntry(com.ibm.mm.enabler.utils.Atom._ID, this.xmlData, this.id_ns); if (res) { name = com.ibm.mm.enabler.utils.Dom.getAttributeWithNS(res, "ext:uniquename", "uniquename", this.id_ns.ext); } return name || ""; } }); } if(!dojo._hasResource["com.ibm.mm.enabler.IdentifierImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.IdentifierImpl"] = true; dojo.provide("com.ibm.mm.enabler.IdentifierImpl"); // identifier dojo.declare("com.ibm.mm.enabler.IdentifierImpl", com.ibm.mm.enabler.persistence.xml.IdentifiableXmlImpl, { _id: null, _params: null, constructor: function(id, params) { if (dojo.isString(id)) { this._id = id; } else { this.xmlData = id; } this._params = params; }, setID: function(id) { if (this._id) { this._id = id; } else { this.inherited(arguments); } }, getID: function() { return this._id ? com.ibm.mm.enabler.IdentifiableHelper.getID(this._id) : this.inherited(arguments); }, _getParameters: function() { return this._params; }, /** * This method returns the raw id like it is stored in the atom entry */ _getRawID: function() { return this._id ? this._id : this.inherited(arguments); }, _setRawID: function(id) { if (!this._id) { var nodes = com.ibm.mashups.enabler.xml.XPath.evaluateEntry(com.ibm.mm.enabler.utils.Atom._ID, this.xmlData, this.id_ns); if (nodes) { com.ibm.mm.enabler.utils.Dom.textContent(nodes, id); } } } }); } if(!dojo._hasResource["com.ibm.mm.enabler.services.IdentificationServiceImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.services.IdentificationServiceImpl"] = true; dojo.provide("com.ibm.mm.enabler.services.IdentificationServiceImpl"); dojo.declare("com.ibm.mm.enabler.services.IdentificationServiceImpl", [com.ibm.mashups.enabler.services.IdentificationService], { constructor: function() { // client ids this.clientIds = {}; // client id map this.clientServerMap = {}; var regexString = com.ibm.mashups.services.ServiceManager.getService(com.ibm.mashups.enabler.services.ConfigService.SERVICE_NAME).getValue(com.ibm.mashups.enabler.services.ConfigConstants.SERVER_OBJECT_ID_FORMAT); if (!regexString) { regexString = "M[A-F0-9]+$"; } // the regexp for the Server ID this.serverOidRegExp = new RegExp(regexString); }, createClientID: function() { while (true) { var id = dojox.uuid.generateRandomUuid().replace(/-/g, "_"); if (!(id in this.clientIds)) { this.clientIds[id] = null; return id; } } // unreachable code return null; }, attachClientID: function(clientID) { this.clientIds[clientID] = null; }, releaseClientID: function(id) { var cidString = com.ibm.mm.enabler.utils.Utils.getIdFromIdentifiable(id); if (this.isClientID(cidString)) { delete this.clientIds[cidString]; delete this.clientServerMap[cidString]; } }, isClientID: function(id) { return (id in this.clientIds); }, isServerID: function(id) { return this.serverOidRegExp.test(id); }, isAlienID: function(id) { return !this.isServerID(id) && !this.isClientID(id); }, attachServerID: function(cid, sid) { var cidString = com.ibm.mm.enabler.utils.Utils.getIdFromIdentifiable(cid); var sidString = com.ibm.mm.enabler.utils.Utils.getIdFromIdentifiable(sid); // create mapping this.clientServerMap[cidString] = sidString; }, resolveID: function(id) { var cidString = com.ibm.mm.enabler.utils.Utils.getIdFromIdentifiable(id); return (cidString in this.clientServerMap) ? this.clientServerMap[cidString] : cidString; }, resolveIdentifiable: function(id) { return new com.ibm.mm.enabler.IdentifierImpl(this.resolveID(id)); } }); com.ibm.mashups.enabler.services.IdentificationService = new com.ibm.mm.enabler.services.IdentificationServiceImpl(); } if(!dojo._hasResource["com.ibm.mashups.enabler.services.IdentificationService"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.services.IdentificationService"] = true; dojo.provide("com.ibm.mashups.enabler.services.IdentificationService"); } if(!dojo._hasResource["com.ibm.mashups.enabler.model.state.NavigationStateProcessor_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.enabler.model.state.NavigationStateProcessor_API"] = true; dojo.provide("com.ibm.mashups.enabler.model.state.NavigationStateProcessor_API"); dojo.provide("com.ibm.mashups.enabler.model.state.NavigationStateProcessor"); /** * Interface representing NavigationStateProcessor.NavigationState is internally Represented as an JSON object.
* Paramters are predefined.
* * {
* sid:{
*   value: <sid>,
*   params:{}
* },
* pid:{
*   value: <pid>,
*   params:{}
* },
* pageselection:{
*   <spaceid>:{
*     value: <pageid>,
*     params:{lm:<timestamp>}
*   },
*   <spaceid>:{
*     value: <pageid>,
*     params:{lm:<timestamp>}
*   }
* },
* wparams:{
*   <wid>:{
*     value: {
*       rp:{w:<"200">,h:<"300">,st:<"NORMAL">},
*       cp:{<page:"3">}
*     },
*     params:{lm:<timestamp>}
*   },
*   <wid>:{
*     value: {
*       rp:{w:<"300">,h:<"400">,st:<"MAX">},
*       cp:{<page:"4">}
*     },
*     params:{lm:<timestamp>}
*   }
* },
* lcparams:{
*   <pid>:{
*   templateURL: "<dav:filestore/layout-templates/2ColumnEqual>",{
*     value: {
*       <lcid>:{
*         value: {
*           rp:{w:<"70%">}
*         }
*       },
*       <lcid>:{
*         value: {
*           rp:{w:<"30%">}
*         }
*       }
*     },
*     params:{lm:<timestamp>}
*   },
*   <pid>:{
*   templateURL: "<dav:filestore/layout-templates/3ColumnEqual>",{
*     value: {
*       <lcid>:{
*         value: {
*           rp:{w:<"30%">}
*         }
*       },
*       <lcid>:{
*         value: {
*           rp:{w:<"30%">}
*         }
*       },
*       <lcid>:{
*         value: {
*           rp:{w:<"40%">}
*         }
*       }
*     },
*     params:{lm:<timestamp>}
*   }
* },
* sparams:{
*   <id>:{
*     global: {
*       params:{lm:<timestamp>},
*       value: {
*         <name>:{
*           value: <value>,
*           params:{lm:<timestamp>}
*         },
*         <name>:{
*           value: <value>,
*           params:{lm:<timestamp>}
*       }
*     },
*     <scope-id>: {
*       params:{lm:<timestamp>},
*       value: {
*         <name>:{
*           value: <value>,
*           params:{lm:<timestamp>}
*         },
*         <name>:{
*           value: <value>,
*           params:{lm:<timestamp>}
*       }
*   }
* }
* }
*
*
* Navigation State parameters will be written to url or persistence store upon configuration.
* Here's the default configuration:
*
    *
  • navstate.persistence.url = pid,cp,sparams
  • *
  • persistence.pstore = w,h,st,pid,sid,pageselection
  • *
*
* Following is the list of parameters that are configurable:
*
    *
  • pid: page id
  • *
  • sid: space id
  • *
  • pageselection: page selections
  • *
  • sparams: shareable parameter sets
  • *
  • h: widget height
  • *
  • w: widget width
  • *
  • st: widget window state
  • *
  • md: widget mode
  • *
  • cp: widget customized state
  • *
* * Upon page loading or page refresh, navigationstatemodel is initialized with navigation state data from url or
* persistence. "decode" will be used to load data from url and "preprocess" will be used to load data from persistence.
* Upon commit on NavigationStateModel updates, navigation state data will be sent to url or sent to persistence.
* "postprocess" will send the updates to persistence and "encode" will generate the new url fragment based on latest navigation state.
* * * @ibm-spi * @ibm-module Base */ dojo.declare( "com.ibm.mashups.enabler.model.state.NavigationStateProcessor", null, { /** * Encodes the specified widget instance id. * @param {String} wid widget instance id; different page may have same widget instance id. * @param {com.ibm.mashups.enabler.model.state.NavigationStateModel} navigationStateModel * @type String * @return {String} unique id, representing a widget instance on a page */ encodeWidgetIdentifier: function(wid, navigationStateModel){ }, /** * Decodes a unique widget instance id. * @param {String} wid unique widget instance id. * @param {com.ibm.mashups.enabler.model.state.NavigationStateModel} navigationStateModel * @type String * @return {String} widget instance id */ decodeWidgetIdentifier: function(wid, navigationStateModel){ }, /** * Decode the url and store the state into a JSON Object. JSON object should be * pass into Callback. If no callback is defined, navigation state is returned.
* callback:function(state){};
* @param {String} url url string * @param {Function} callback callback function * @type Object * @return {Object} navigation state object */ decode:function(url,callback){ }, /** * Encode state object and generate fragment. Fragment should be passed into callback function.
* callback(fragment); * If no callback is defined, url fragment is returned.
* @param {Object} state JSON object representing Mashup state * @param {Function} callback callback function which takes the following parameters: *   additionalParams (JSON) - if the additionalParams was passed in to the encode * function, then it must be passed back into the callback function
*   responseParams (JSON) - Optional If additionalParams.allowRedirect is true and this is an asynchronous commit, * then the implementation of this function may pass responseParams.doRedirect set to true to refresh the page after the commit is completed
* @param {Object} oldState JSON object representing Mashup state before it gets updated * @param {Object} additionalParams Optional JSON object to control various aspects of encoding or the registered callback * @param {com.ibm.mashups.enabler.model.state.NavigationStateModel} navigationStateModel * @type String * @return {String} the url fragment that contains navigation state */ encode:function(state,callback,oldState, additionalParams, navigationStateModel){ }, /** * @deprecated Use generateURL instead. * * @param {Object} state * @param {Function} callback * @param {JSON} params * @type String */ generateUrl:function(state,callback,params){ }, /** * Encode state object and generate full url. URL should be absolute URL. URL should be passed into callback function. * If no callback, full url is returned.
* callback:function(url){};
* Sample parameter: {nohash:"true"}
* if "nohash" is set to true,the returned url will not contain state in hash.
* By default Lotus Mashups only supports url that contains navigation state in hash.
* Extensions can be added to support additional parameter by using extension registry.
* * @param {Object} state JSON object representing Mashup state * @param {Function} callback callback function * @param {JSON} params additional parameter in json format * @type String * @return {String} full url that contains navigation state */ generateURL:function(state,callback,params){ }, /** * Preprocess could be used to filter the original state. For example, * pulling more state information that's cached in cookie.
* The final state should be passed into callback.
* callback:function(state){};
* If no callback, state object will be returned.
* @param {Object} state JSON object representing Mashup state * @param {Function} callback callback function * @type Object * @return {Object} object contains navigation state */ preprocess:function(state,callback){ }, /** * Dispose the any navigation state that's persisted. Callback is executed when dispose action is done.
* callback:function(){}; * @param {Function} callback callback function * @type void */ dispose:function(callback){ }, /** * Postprocess could be used to filter the original state before url is generated. * For example,some state information should be persisted into cookie.
* The final state should be passed into callback.
* callback:function(state){};
* If no callback, state object will be returned.
* @param {Object} state JSON object representing Mashup state * @param {Function} callback callback function * @param {Object} oldState JSON object representing Mashup state before it gets updated * @param {Object} additionalParams Optional JSON object to control various aspects of encoding or the registered callback. * @type Object * @return {Object} object contains navigation state */ postprocess:function(state,callback,oldState, additionalParams){ } }); } if(!dojo._hasResource["com.ibm.mm.enabler.model.state.CookieManager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.model.state.CookieManager"] = true; dojo.provide("com.ibm.mm.enabler.model.state.CookieManager"); dojo.declare("com.ibm.mm.enabler.model.state.CookieManager", null, { //cookie limit is 4096byte(at least for IE) //cookie is persisted per user, cookiename uid+"_state" //need to split if we run into problems /* {sid:{value:,params:{}}, * pid:{value:,params:{}}, * pageselection:{ * :{value:,params:{lm:}}, * :{value:,params:{lm:}} * }, * wparams:{ * :{value:{rp:{w:<"200">,h:<"300">,st:<"NORMAL">}},params:{lm:}}, * :{value:{rp:{w:<"300">,h:<"400">,st:<"MAX">}},params:{lm:}} * } * } */ constructor: function() { this._dirty = false; this.cookiePath = window.location.pathname; }, COOKIE_PREFIX: "digest.ignore.state.", disposeState: function() { if (ibmConfig["com.ibm.mashups.embedding.isActive"]===true) { // in case of embedding we are not allowed to write out a cookie return; } var id = this._getCookieID(); if (id && dojo.cookie(id)) { if (dojo.isIE) { dojo.cookie(id, null, { expires: -1 }); } else { dojo.cookie(id, null, { expires: -1, path: this.cookiePath }); } } if (this._state) { delete this._state; } this._dirty = false; }, _getCookieID: function() { //get user id if (!this._cookieID) { var configSvr = com.ibm.mashups.services.ServiceManager.getService(com.ibm.mashups.enabler.services.ConfigService.SERVICE_NAME); var uid = configSvr.getValue(com.ibm.mashups.enabler.services.ConfigConstants.USER); if (!uid || (uid && uid == "null")) { return null; } //this._cookieID = uid+"_state"; this._cookieID = this.COOKIE_PREFIX + uid; } return this._cookieID; }, _init: function() { if (!this._getCookieID()) { this._state = {}; return; } if (dojo.cookie.isSupported()) { if (dojo.cookie(this._getCookieID()) && dojo.fromJson(dojo.cookie(this._getCookieID()))) { this._state = dojo.fromJson(dojo.cookie(this._getCookieID())); } } if (!this._state) { this._state = {}; } }, getState: function(id) { //if id is not defined, return the whole state object if (!this._state) { this._init(); } if (!id) { return this._state; } if (this._state[id]) { return this._state[id]; } return null; }, setState: function(id,/*object*/ value) { //pid,sid,pageselection,wparams if (!this._state) { this._state = {}; } this._state[id] = value; //create/overwrite this._dirty = true; }, removeState: function(id) { if (this._state[id]) { delete this._state[id]; this._dirty = true; } }, commit: function() { if (ibmConfig["com.ibm.mashups.embedding.isActive"]===true) { // in case of embedding we are not allowed to write out a cookie return; } //cookie expiration? if (this._dirty) { if (!this._getCookieID()) { this._dirty = false; return; } if (dojo.cookie.isSupported()) { if (dojo.isIE) { dojo.cookie(this._getCookieID(), dojo.toJson(this._state), { expires: 3652 }); } else { dojo.cookie(this._getCookieID(), dojo.toJson(this._state), { expires: 3652, path: this.cookiePath }); } } this._dirty = false; } } }); com.ibm.mashups.enabler.model.state.CookieManager = new com.ibm.mm.enabler.model.state.CookieManager(); } if(!dojo._hasResource["com.ibm.mashups.iwidget.model.Factory_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.iwidget.model.Factory_API"] = true; dojo.provide("com.ibm.mashups.iwidget.model.Factory_API"); dojo.provide("com.ibm.mashups.iwidget.model.Factory"); /** * Interface represents iWidgetModelFactory * @ibm-spi * @ibm-module iWidget2 */ dojo.declare("com.ibm.mashups.iwidget.model.Factory", null, { /** * @private */ constructor: function() { }, /** Returns global widget model. @type com.ibm.mashups.iwidget.model.WidgetModel @returns{com.ibm.mashups.iwidget.model.WidgetModel } Interface for WidgetModel. */ getGlobalWidgetModel: function() { } }); } if(!dojo._hasResource["com.ibm.mm.iwidget.Constants"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.iwidget.Constants"] = true; dojo.provide("com.ibm.mm.iwidget.Constants"); dojo.declare("com.ibm.mm.iwidget.Constants", null, { constructor: function() { }, WIDGETEVENT_PREFIX: "widgetevents.", WILDCARD_PREFIX: "*.", mode: { VIEW:/*String*/ "view",//The generated markup fragment(s) should reflect normal interaction with the iWidget EDIT:/*String*/ "edit",//The generated markup fragment(s) should reflect iWidget interactions for editing iWidget attributes scoped to this instance of iwidget, but applicable to all users PERSONALIZE:/*String*/ "personalize",//The generated markup fragment(s) should reflect iWidget interactions for personalizing iwidget attributes scoped to this instance on the iWidget for this user CONFIG:/*String*/ "config",//The generated markup fragment(s) should reflect iWidget interactions for editing iwidget attributes scoped to all instances of the iWidget for all users HELP:/*String*/ "help"//The iWidget should generate markup fragment(s) to assist the user with interacting with the iWidget }, mode_view: "view", mode_edit: "edit", mode_help: "help", event: { TITLE:/*String*/ "title",//Name for the Attribute holding event title DESCRIPTION:/*String*/ "description"//Name for the Attribute holding event description }, ATTRIBUTES:/*String*/ "attributes", //Name for the ManagedItemSet holding the customization attributes. IDESCRIPTOR:/*String*/ "idescriptor", //Name for the ManagedItemSet holding the items describing the iWidget USERPROFILE:/*String*/ "userprofile", //Name for the ManagedItemSet holding data about the user windowstate: { NORMAL:/*String*/ "normal", MINIMIZE:/*String*/ "minimize", MAXIMIZE:/*String*/ "maximize" }, status: { SUCCESS:/*int*/ 200, TIMEOUT:/*int*/ 408, NOTFOUND:/*int*/ 404, INTERROR:/*int*/ 500, OTHER:/*int*/ 303 }, changeType: { CHANGEDVALUE:/*String*/ "changedValue", NEWITEM:/*String*/ "newItem", REMOVEDITEM:/*String*/ "removedItem" }, iDescriptorItems: { title: "title", name: "name", description: "description", defaultHeight: "defaultHeight", defaultWidth: "defaultWidth", displayLocale: "displayLocale", mode: "mode", author: "author", email: "email", website: "website", version: "version", icon: "icon", windowState: "windowState", messageLocale:"messageLocale", availableMessageLocales:"availableMessageLocales", thumbnail:"thumbnail" }, IW_PREFIX: "iw-", IW_DEFINITION_TYPE: "iwidget", OSGADGET_DEFINITION_TYPE: "os-gadget", CSSCLASS_INSTANCE: { iwWidget: "iWidget", iwOSGadget: "OSGadget", iwSandbox:"Sandbox", iwDefinition: "Definition", iwEventDescription:"EventDescription", iwPayloadType:"PayloadType", iwHandled: "Handled", iwPublished: "Published", iwDescription: "Description", iwTitle:"Title", iwEvent:"Event", iwDescRef:"DescRef", iwGlobalid:"Globalid", iwHandler: "Handler", iwNewWire: "NewWire", iwRemoveWire: "RemoveWire", iwReadOnly: "ReadOnly", iwItemSet: "ItemSet", iwItem: "Item", iwValue: "Value", iwContent: "Content", iwReceivedEvent: "ReceivedEvent", iwSourceEvent: "SourceEvent", iwTargetEvent: "TargetEvent", iwMappedName: "MappedName", iwStandalone: "Standalone" }, CSSCLASS_PREFIXED_INSTANCE: { /* filled at runtime */}, CSSCLASS_PERSONALIZED: "mm-Personalized", RESOURCE: { src: "src", id: "id", globalid: "globalid", mimeType: "mimeType", callback: "callback", version: "version", blockInit:"blockInit", skipLoad:"skipLoad" }, EVENTS: { onLoad:/*String*/ "onLoad", onUnLoad:/*String*/ "onUnload", onModeChanged:/*String*/ "onModeChanged", onItemSetChanged:/*String*/ "onItemSetChanged", unloadWidget:/*String*/ "/enabler/unloadWidget", unSubscribeWire:/*String*/ "/enabler/unSubscribeWire", modeChanged:/*String*/ "modeChanged", onSizeChanged:/*String*/ "onSizeChanged", onNavStateChanged:/*String*/ "onNavStateChanged", onAttributeSaved:/*String*/ "com.ibm.mashups.iwidget.onAttributeSaved", onWindowStateChanged:/*String*/ "onWindowStateChanged", onIncompleteEventDescription:/*String*/"onIncompleteEventDescription" }, eventservice:{ type:{ MAIN:"MAIN", IFRAME:"IFRAME" } } }); com.ibm.mm.iwidget.Constants = new com.ibm.mm.iwidget.Constants(); (function() { for(var key in com.ibm.mm.iwidget.Constants.CSSCLASS_INSTANCE) { if(Object.prototype.hasOwnProperty.call(com.ibm.mm.iwidget.Constants.CSSCLASS_INSTANCE,key)) { com.ibm.mm.iwidget.Constants.CSSCLASS_PREFIXED_INSTANCE[key] = com.ibm.mm.iwidget.Constants.IW_PREFIX + com.ibm.mm.iwidget.Constants.CSSCLASS_INSTANCE[key]; } } })(); // TODO: move to legacy layer iwConstants = com.ibm.mm.iwidget.Constants; } if(!dojo._hasResource["com.ibm.mashups.iwidget.widget.WireProvider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.iwidget.widget.WireProvider"] = true; dojo.provide("com.ibm.mashups.iwidget.widget.WireProvider"); /** * Interface defines functions to access handled or published event descriptions. * @ibm-spi * @ibm-module iWidget2 */ dojo.declare("com.ibm.mashups.iwidget.widget.WireProvider", null, { /** * @private */ constructor: function(id) { }, /** This method returns an array of supported wires. @type com.ibm.mashups.iwidget.widget.Wire[] @returns{com.ibm.mashups.iwidget.widget.Wire[] } array of Wire this iWidget is wired as target . */ getWires: function() { } }); } if(!dojo._hasResource["com.ibm.mashups.iwidget.IEventDescription_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.iwidget.IEventDescription_API"] = true; dojo.provide("com.ibm.mashups.iwidget.IEventDescription_API"); dojo.provide("com.ibm.mashups.iwidget.IEventDescription"); /** * It contains various pieces of information describing an event. * * @ibm-api * @ibm-module iWidget2 */ dojo.declare("com.ibm.mashups.iwidget.IEventDescription", null, { constructor: function() { /** * @private */ }, /** The alias of the event. @type String */ alias:/*String*/ "", /** The name of the event. @type String */ name:/*String*/ "", /** The type of any payload. If this is set to null, no information is being provided. @type String */ type:/*String*/ "", /** This provides the name of a callback function with the following signature and no return value.       function(ievent) @type String */ handlingFn:/*String*/ "", /** it returns a user-oriented description (markup allowed) of the event in the requested locale. If no locale is supplied, the default locale of the iWidget is used (with "en" being the default iWidget locale). The description is likely to be displayed when a user is wiring event flow between iWidgets. @param{String} locale required locale. Can be NULL. If no locale is supplied, the default locale of the iWidget is used (with "en" being the default iWidget locale). @type String @returns{String} Return the description of a given locale,if no locale is provided, then the default locale of the iWidget is used. @deprecated please use getAttribute("description",locale) instead @since Deprecated since Version 2.0 */ getDescription: function(/*String*/locale) { return null; }, /** This provides the default language of all the localized attributes within this event description. @type String */ lang:/*String*/ "", /** This indicates if an event is a handled event or not. Default value is false. @type Boolean */ isHandled: false, /** This indicates if an event is a published event or not. Default value is false. @type Boolean */ isPublished: false, /** This method returns the asking value of an attribute of the event description. Each event description should have title and description . Normally title and description should be globalized, default locale should be specified by using the iso language code, if missing, the value for the default locale will be en.
@param{String} attributeName name of attribute. Can Not be NULL. @param{String} locale required locale. Can be NULL. If no locale is supplied, the default locale of the iWidget is used (with "en" being the default iWidget locale). @type String @returns{String} Return the value of the required attribute,if locale is provided, it returns locale specific value. */ getAttribute: function(/*String*/attributeName,/*String*/ locale) { return null; }, /** The method set the value for a given event description attribute.It returns a handle of this eventdescription, return null upon failure. If the locale parameter is absent, then the given attribute won't be locale specific. @param{String} attributeName name of attribute. Can Not be NULL. @param{String} attributeValue value of attribute. Can Not be NULL. @param{String} locale optional, locale. Can be NULL. @type com.ibm.mashups.iwidget.IEventDescription @returns{com.ibm.mashups.iwidget.IEventDescription} return a handle of this eventdescription, return null upon failure.. */ setAttribute: function(/*String*/attributeName, /* String*/ attributeValue, /*String*/ locale) { } }); } if(!dojo._hasResource["com.ibm.mm.iwidget.IEventDescriptionImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.iwidget.IEventDescriptionImpl"] = true; dojo.provide("com.ibm.mm.iwidget.IEventDescriptionImpl"); dojo.declare("com.ibm.mm.iwidget.IEventDescriptionImpl", com.ibm.mashups.iwidget.IEventDescription, { constructor: function(/*String*/name,/*function*/ handlingFn,/*String*/ type,/*String*/ description,/*String[]*/ aliases, defaultLang,/*[]*/ descriptions) { if (dojo.isString(name)) { /*backward compatibility, some widget are still trying to create iEventDescription by using this constuctor as is!*/ var obj = {}; obj.name = name; handlingFn = handlingFn || null; if (handlingFn) { obj.handlingFn = handlingFn; obj.isHandled = true; obj.isPublished = false; //backward compatibility either isPublished or isHandled } else { obj.isPublished = true; } type = type || null; if (type) { obj.type = type; } defaultLang = defaultLang || null; if (defaultLang) { obj.lang = defaultLang; } else { obj.lang = "en"; } //how to set isPublished? or set it later obj.attributes = {}; obj.localizedAttributes = {}; aliases = aliases || null; if (aliases) { obj.attributes.aliases = aliases; } descriptions = descriptions || null; if (descriptions) { obj.localizedAttributes = descriptions; } //backward compatibility if (description) { if (!obj.localizedAttributes[obj.lang]) { obj.localizedAttributes[obj.lang] = {}; } obj.localizedAttributes[obj.lang].description = description; } this._internalJsonObj = obj; } else { this._internalJsonObj = name; } this.initPredefinedFields(this._internalJsonObj); }, initPredefinedFields: function(obj) { //initialize fields this.name = obj.name; this.type = obj.type; this.lang = obj.lang; this.handlingFn = obj.handlingFn; this.isHandled = obj.isHandled; this.isPublished = obj.isPublished; // if (this.handlingFn) { // this.isHandled = true; // } // else { // this.isHandled = false; // } // // set isPublished to true only when both isHandled and isPublished is not defined // // this is required for backward compatiblity reason // if ((obj.isPublished && obj.isPublished == "true") || obj.isPublished) { // this.isPublished = true; // } }, getDescription: function(locale) { return this._getLocalizedAttribute("description", locale); }, getTitle: function(locale) { return this._getLocalizedAttribute("title", locale); }, _getLocalizedAttribute: function(attributeName, locale) { var attValue = null, altAttValue = null; var lc = com.ibm.mashups.enabler.context.Factory.getLocalizedContext(locale, this.lang); var finalLocale = lc.getLocale(this); if (this.localemapping && this.localemapping[finalLocale]) { finalLocale = this.localemapping[finalLocale]; } if (this._internalJsonObj.localizedAttributes) { altAttValue = this._internalJsonObj.localizedAttributes[finalLocale]; if (altAttValue) { attValue = altAttValue[attributeName]; } } if (!attValue) { attValue = this[attributeName]; } if (typeof attValue == "undefined") { attValue = null; } return attValue; }, setOnRemoveWire: function(/*String*/handler) { if (typeof handler == "undefined" || handler === null) { handler = "onRemoveWire"; } //this.onRemoveWire = handler; if (typeof this._internalJsonObj.attributes == "undefined") { this._internalJsonObj.attributes = {}; } this._internalJsonObj.attributes.onRemoveWire = handler; return this; }, getOnRemoveWire: function() { //can remove? if (typeof this._internalJsonObj.attributes != "undefined" && this._internalJsonObj.attributes.onRemoveWire) { return this._internalJsonObj.attributes.onRemoveWire; } return null; }, setOnNewWire: function(/*String*/handler) { if (typeof handler == "undefined" || handler === null) { handler = "onNewWire"; } //this.onNewWire = handler; if (typeof this._internalJsonObj.attributes == "undefined") { this._internalJsonObj.attributes = {}; } this._internalJsonObj.attributes.onNewWire = handler; return this; }, getOnNewWire: function() { if (typeof this._internalJsonObj.attributes != "undefined" && this._internalJsonObj.attributes.onNewWire) { return this._internalJsonObj.attributes.onNewWire; } return null; }, getLocales: function() { var locales = []; var mapping = {}; if (this._internalJsonObj.localizedAttributes) { for (var i in this._internalJsonObj.localizedAttributes) { if (Object.prototype.hasOwnProperty.call(this._internalJsonObj.localizedAttributes,i)) { locales.push(i); var normalizedLocale = com.ibm.mm.enabler.utils.LocaleHelper.normalizeLocale(i); if (normalizedLocale != i) { mapping[normalizedLocale] = i; } } } } this.localemapping = mapping; return locales; }, toString: function() { //return null or unserialized string, dojo will throw exception if it's not a valid Json obj var temp = this.toJson(); return dojo.toJson(temp); }, _getInternalJsonObj: function() { return this._internalJsonObj; }, toJson: function() { var internalJson = {}; for (var i in this._internalJsonObj) { if (Object.prototype.hasOwnProperty.call(this._internalJsonObj,i)) { if (i == "handlingFn") { //it could be functionpointer if (dojo.isFunction(this._internalJsonObj[i])) { internalJson[i] = "HANDLEFN"; continue; } } internalJson[i] = dojo.clone(this._internalJsonObj[i]); } } return internalJson; }, clone: function() { var temp = dojo.toJson(this._internalJsonObj); if (temp) { return new com.ibm.mm.iwidget.IEventDescriptionImpl(dojo.fromJson(temp)); } else { return null; } }, getAttribute: function(attName, locale) { if (!attName) { return null; } if (!locale) { if (this._internalJsonObj.attributes && typeof this._internalJsonObj.attributes[attName] != "undefined") { return this._internalJsonObj.attributes[attName]; } //get value for default locale if (this._internalJsonObj.localizedAttributes && this._internalJsonObj.localizedAttributes[this.lang]) { var attValue = this._internalJsonObj.localizedAttributes[this.lang][attName]; if (attValue) { return attValue; } } return null; //if no such attributes or localized attributes } else { return this._getLocalizedAttribute(attName, locale); } }, setAttribute: function(attName, attValue, locale) { //todo; if no locale defined and attributes is predefined such as "title","description", set the value on default locale //return a handle of this eventdescription, return null upon failure. if (!attName) { return null; } if (typeof attValue == "undefined") { return null; // allow value to be null } if (!locale) { if (typeof this._internalJsonObj.attributes == "undefined") { this._internalJsonObj.attributes = {}; } this._internalJsonObj.attributes[attName] = attValue; if (attValue === null) { delete this._internalJsonObj.attributes[attName]; } return this; } if (!this._internalJsonObj.localizedAttributes[locale]) { this._internalJsonObj.localizedAttributes[locale] = {}; } this._internalJsonObj.localizedAttributes[locale][attName] = attValue; if (attValue === null) { delete this._internalJsonObj.localizedAttributes[locale][attName]; } return this; }, copyRuntimeProperties: function(eventDesc2Copy) { if ((!this.handlingFn) && (eventDesc2Copy.handlingFn)) { this.handlingFn = eventDesc2Copy.handlingFn; } if ((!this._internalJsonObj.handlingFn) && (eventDesc2Copy._internalJsonObj.handlingFn)) { this._internalJsonObj.handlingFn = eventDesc2Copy._internalJsonObj.handlingFn; } if (typeof this._internalJsonObj.attributes == "undefined") { this._internalJsonObj.attributes = {}; } for (name in eventDesc2Copy._internalJsonObj.attributes) { if (!this._internalJsonObj.attributes[name]) { this._internalJsonObj.attributes[name] = eventDesc2Copy._internalJsonObj.attributes[name]; } } } }); } if(!dojo._hasResource["com.ibm.mashups.iwidget.IEventDescription"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.iwidget.IEventDescription"] = true; dojo.provide("com.ibm.mashups.iwidget.IEventDescription"); } if(!dojo._hasResource["com.ibm.mashups.iwidget.widget.EventProvider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.iwidget.widget.EventProvider"] = true; dojo.provide("com.ibm.mashups.iwidget.widget.EventProvider"); /** * Interface defines functions to access handled or published event descriptions. * @ibm-spi * @ibm-module iWidget2 */ dojo.declare("com.ibm.mashups.iwidget.widget.EventProvider", null, { /** * @private */ constructor: function() { }, /** This method returns an array of event description. Only published event of this widget will be returned. @type {com.ibm.mashups.iwidget.IEventDescription} @returns{com.ibm.mashups.iwidget.IEventDescription[] } array of event description */ getWidgetPublishedEvents: function() { }, /** This method returns an array of event description. Only handled event of this widget will be returned. @type {com.ibm.mashups.iwidget.IEventDescription[]} @returns{com.ibm.mashups.iwidget.IEventDescription[] } array of event description */ getWidgetHandledEvents: function() { }, /** This method returns the required event. @param {String}name name of required public event @type {com.ibm.mashups.iwidget.IEventDescription} @returns{com.ibm.mashups.iwidget.IEventDescription } an event description it returns NULL if event can't be found. */ getPublicEvent: function(name) { } }); } if(!dojo._hasResource["com.ibm.mashups.iwidget.widget.Properties_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.iwidget.widget.Properties_API"] = true; dojo.provide("com.ibm.mashups.iwidget.widget.Properties_API"); dojo.provide("com.ibm.mashups.iwidget.widget.Properties"); /** * Interface defines functions to iterates , updates and persist Properties. * @ibm-spi * @ibm-module iWidget2 */ dojo.declare("com.ibm.mashups.iwidget.widget.Properties", null, { /** * @private */ constructor: function() { }, /** * This method returns the value of the required item * @param{String} itemName name of the item.Must never be NULL. * @param{String} locale the locale of the value to fetch. if locale isn't defined, the * DEFAULT_LOCALE will be used * @return{String} return the value of required item */ getItemValue: function(/*String*/itemName, locale) { }, /** * This method returns an array of Strings,providing the name of each item. * @return{String[]} return an array of items names and return NULL if the set contains no item */ getAllNames: function() { return null; }, /** * This methods returns the locales for the item specified by itemName * @param{String} itemName the name of the item for which do get the locales. * @return{String[]} return an array of locales valid for the specified itemName, returns an empty array if no localized item values are available. */ getItemLocales: function(itemName) { }, /** * This method allows the caller to check whether a specific item is readOnly or not. * @param{String} itemName the item name of the item to check readOnly * @return{Boolean} true if the item exists and is read only, false otherwise. */ isReadOnly: function(itemName) { } }); } if(!dojo._hasResource["com.ibm.mm.iwidget.widget.PropertiesImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.iwidget.widget.PropertiesImpl"] = true; dojo.provide("com.ibm.mm.iwidget.widget.PropertiesImpl"); dojo.declare("com.ibm.mm.iwidget.widget.PropertiesImpl", com.ibm.mashups.iwidget.widget.Properties, { DELETE_TOKEN: "com.ibm.mm.iwidget.widget.DELETE_TOKEN", TYPE_NEW: "newItem", TYPE_UPDATE: "updatedValue", TYPE_REMOVE: "removedItem", /** * @param items {ItemSet JSON} the items this Properties class is based on * @param defaultProps {Properties} The default properties object **/ constructor: function(items, defaultProps) { this._defaultProperties = defaultProps; // create the new object this._items = {}; if (items) { this._items = items; } this._localizedItems = {}; // define the default locale of this properties set this.DEFAULT_LOCALE = ibmConfig[com.ibm.mashups.enabler.services.ConfigConstants.DEFAULT_LOCALE]; if (!this.DEFAULT_LOCALE) { this.DEFAULT_LOCALE = "en"; } }, /** * Internal method which can be used by ENABLER components for determining the default locale of an Properties Element */ _getItemDefaultLocale: function(itemName) { var defLocale = null; if (this._items[itemName]) { if (this._items[itemName].defaultLocale) { defLocale = this._items[itemName].defaultLocale; } } if (!defLocale) { defLocale = null; } return defLocale; }, getLocalizedItemValue:function(itemName,locale){ //internal function, used by private ItemSet //no fallback to default locale if (!itemName || !locale) { return; } if (!(itemName in this._items) && !this._defaultProperties) { return null; } var item = this._items[itemName]; var value = null; if (!item.values) { return null; } var matchLocales = []; for (var i in item.values) { if (Object.prototype.hasOwnProperty.call(item.values,i)) { matchLocales.push(i); } } var normalizedLocale; // check if we have a value for the specified locale normalizedLocale = com.ibm.mm.enabler.utils.LocaleHelper.matchLocale(locale, matchLocales); for (var i in item.values) { if (normalizedLocale == com.ibm.mm.enabler.utils.LocaleHelper.normalizeLocale(i)) { value = item.values[i]; break; } } if (value == this.DELETE_TOKEN) { return null; } return value; }, getItemValue: function(itemName, locale) { // if we don't have an item and don't have default properties, we can exit right away if (!(itemName in this._items) && !this._defaultProperties) { return null; } // if we don't have the item we can delegate to default props (which we checked earlier) if (!(itemName in this._items)) { return this._defaultProperties.getItemValue(itemName, locale); } // seems we have an item, so let's do the magic var item = this._items[itemName]; var value = null; if ((typeof locale == "undefined" || locale === null) && typeof item.value != "undefined" && item.value !== null) { if (item.value == this.DELETE_TOKEN) { return null; } return item.value; } if (!item.values) { return null; } var matchLocales = []; for (var i in item.values) { if (Object.prototype.hasOwnProperty.call(item.values,i)) { matchLocales.push(i); } } var normalizedLocale; // check if we have a value for the specified locale if (locale) { normalizedLocale = com.ibm.mm.enabler.utils.LocaleHelper.matchLocale(locale, matchLocales); for (var i in item.values) { if (normalizedLocale == com.ibm.mm.enabler.utils.LocaleHelper.normalizeLocale(i)) { value = item.values[i]; break; } } } // test the default locale of the item if (item.defaultLocale && value === null) { normalizedLocale = com.ibm.mm.enabler.utils.LocaleHelper.matchLocale(item.defaultLocale, matchLocales); for (var i in item.values) { if (normalizedLocale == com.ibm.mm.enabler.utils.LocaleHelper.normalizeLocale(i)) { value = item.values[i]; break; } } } // test the default of the sytem if (this.DEFAULT_LOCALE && value === null) { normalizedLocale = com.ibm.mm.enabler.utils.LocaleHelper.matchLocale(this.DEFAULT_LOCALE, matchLocales); for (var i in item.values) { if (normalizedLocale == com.ibm.mm.enabler.utils.LocaleHelper.normalizeLocale(i)) { value = item.values[i]; break; } } } // otherwise the first locale wins if (value === null) { for (var lang in item.values) { if (Object.prototype.hasOwnProperty.call(item.values,lang)) { value = item.values[lang]; break; } } } if (value == this.DELETE_TOKEN) { return null; } return value; }, getItemLocales: function(itemName) { var locales = []; if (itemName in this._items && this._items[itemName].values) { for (var locale in this._items[itemName].values) { if (Object.prototype.hasOwnProperty.call(this._items[itemName].values,locale)) { locales.push(locale); } } } /*if (itemName in this._items && this._items[itemName].value) { locales.push(""); }*/ if (locales.length === 0) { return null; } return locales; }, getAllNames: function() { //return empty array if there's no item var defaultNames = []; if (this._defaultProperties) { defaultNames = this._defaultProperties.getAllNames(); } var mergedItems = {}; for (var i = 0; i < defaultNames.length; i++) { mergedItems[defaultNames[i]] = null; } for (var itemName in this._items) { if (this._items[itemName] && this._items[itemName]._change && this._items[itemName]._change.changeType == this.TYPE_REMOVE) { if (itemName in mergedItems) { delete mergedItems[itemName]; } } else { mergedItems[itemName] = null; } } var names = []; for (var itemName2 in mergedItems) { if (Object.prototype.hasOwnProperty.call(mergedItems,itemName2)) { names.push(itemName2); } } return names; }, isReadOnly: function(itemName) { var item = this._items[itemName]; return (this._defaultProperties && this_defaultProperties.isReadOnly(itemName)) || (item && item.readOnly); } }); } if(!dojo._hasResource["com.ibm.mashups.iwidget.widget.Properties"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.iwidget.widget.Properties"] = true; dojo.provide("com.ibm.mashups.iwidget.widget.Properties"); } if(!dojo._hasResource["com.ibm.mashups.iwidget.widget.PropertiesProvider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.iwidget.widget.PropertiesProvider"] = true; dojo.provide("com.ibm.mashups.iwidget.widget.PropertiesProvider"); /** * Read-Only interface defines functions to access properties that's defined with iWidget. * @ibm-spi * @ibm-module iWidget2 */ dojo.declare("com.ibm.mashups.iwidget.widget.PropertiesProvider", null, { /** * @private */ constructor: function() { }, /** This method returns an object that contains iDescriptor items as defined by iWidget spec. It contains default title and icon @type com.ibm.mashups.iwidget.widget.Properties @returns{com.ibm.mashups.iwidget.widget.Properties } object that contains iWidget iDescriptor items information */ getIDescriptorItems: function() { }, /** This method returns an object that contains attributes as defined by iWidget spec. @type com.ibm.mashups.iwidget.widget.Properties @returns{com.ibm.mashups.iwidget.widget.Properties } object that contains iWidget iDescriptor items information */ getAttributes: function() { } }); } if(!dojo._hasResource["com.ibm.mashups.iwidget.widget.IWidgetDefinition_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.iwidget.widget.IWidgetDefinition_API"] = true; dojo.provide("com.ibm.mashups.iwidget.widget.IWidgetDefinition_API"); dojo.provide("com.ibm.mashups.iwidget.widget.IWidgetDefinition"); /** * Interface defines functions to access all the data object in widget definition. PropertiesProvider is not implemented. * @ibm-spi * @ibm-module iWidget2 */ dojo.declare("com.ibm.mashups.iwidget.widget.IWidgetDefinition",[com.ibm.mashups.iwidget.widget.EventProvider,com.ibm.mashups.iwidget.widget.PropertiesProvider],{ /** * @private */ constructor:function(){ }, /** This method returns an array of supported modes such as "view" and "edit". @returns{String[] } array of supported modes this iWidget supports. */ getSupportedModes:function(){ }, /** This method returns a JSON based spec compliant object that represents all the data that's defined in widget xml.

Rule to follow:
1. Element -- "iw:iwidget" is considered to be root Element and a root object is created from here.

2. Any attribute of this element will be a field in the root object. '_' will be added as prefix to field names.
":" within any namespaced attribute will be replaced with "_". <iw:iwidget id="map" xml:base="/root/test/" allowInstanceContent="false"......>
{ _id:"map",_xml_base:"/root/test/",_allowInstanceContent:"false"......}

3. All repreatable elements, element name (append with "s") is used as a field name and an object is created to contain all the repeatable elements. Within that object, value of "id" attribute is used as field name for an individual element if id attribute is available.
{
     resources:{
          "myId":{_id:"myId",_src:"my.js"},
           "myOtherId":{_id:"myOtherId",_src:"my2.js"}
      }
}

4. For "iw:content" elements, "contents" is used as the key in the parent object and an object is created to contain all the content elements.
For each "content" element, "mode" attribute is used as the key and CDATA section is saved as the value.
{
   contents:{
       "view": {
         "_mode": "view",
         "value": "mycontent"
       }
    }
}

5. For "iw:alt" elements,"alts" is used as the key in parent object and an object is created to contain all the alt elements.
For each "alt" element, "lang" attribute is used as the key and all the attributes are saved per attributes convention.
eventDescname:{
     _id:"eventDescnname",
     _payloadType:"payloadType",
     alts:{
          "en":{_lang:'en',_description:"description",_descriptionURI:"descriptionURI"},
          "zh":{_lang:'zh',_description:"description",_descriptionURI:"descriptionURI"}
     }
}

An example of simple iWidget and the return result.
<iw:iwidget id="stock" xmlns:iw="http://www.ibm.com/xmlns/prod/iWidget" iScope="stock" allowInstanceContent="true" supportedModes="view edit " mode="view" lang="en">
    <iw:itemSet id="attributes" private="true" onItemSetChanged="changeItemSet">
      <iw:item id="broker" readOnly="false" value="Etrade" />
      <iw:item id="company" value="IBM" />
   </iw:itemSet>
    <iw:event id="sendStockData" eventDescName="sendStockDataDesc" published="true" onNewWire="sendData" />
    <iw:eventDescription id="sendStockDataDesc" payloadType="stockData" title="Send stock data" lang="en" >
     <iw:alt title="Send stock data" lang="en" />
   </iw:eventDescription>
   <iw:resource src="stock.js" id="stock" />
   <iw:content mode="view"> <![CDATA[ mycontent ]]> </iw:content>
   </iw:iwidget>

Example of returnin json object.
{ _id:"map",_allowInstanceContent:"true",_iScope:"stock",_supportedModes:"view edit",_mode:"view",_lang:"en",
    itemSets:{
      "attributes":{ _id:"attributes", _private:"true",_onItemSetChanged:"changedItemSet",
       items:{
          "broker":{ _id:"broker",_readOnly:"false", _value:"Etrade"},
          "company":{ _id:"company",_value;"IBM"}
       }
       }
   },
   events:{
      "sendStockData":{ _id:"sendStockData", _eventDescName:"sendStockDataDesc", _published:"true",_onNewWire:"sendData"}
   },
   eventDescriptions:{
      "sendStockDataDesc":{ _id:"sendStockDataDesc", _payloadType:"stockData",_title:"Send stock data",_lang:"en",
          alts:{
              "en":{ _lang:"en",_title:"Send stock data"}
          }
       }
    },
    resources:{
      "stock":{ _id:"stock", _src:"stock.js"}
   },
   contents:{
       "view": {
         "_mode": "view",
         "value": "mycontent"
       }
    }
}
@returns{object} a JSON based, spec compliant object that represents all the data that's defined in widget.xml */ toSpecObject:function(){ } }); } if(!dojo._hasResource["com.ibm.mm.iwidget.widget.IWidgetDefinitionDefaultImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.iwidget.widget.IWidgetDefinitionDefaultImpl"] = true; dojo.provide("com.ibm.mm.iwidget.widget.IWidgetDefinitionDefaultImpl"); //no support on EventProvider, //todo toSpecObject should just return the json object dojo.declare("com.ibm.mm.iwidget.widget.IWidgetDefinitionDefaultImpl", com.ibm.mashups.iwidget.widget.IWidgetDefinition, { namespaces: { "iw": "http://www.ibm.com/xmlns/prod/iWidget" }, reservedAttributes: { iScope: "iScope", supportedModes: "supportedModes", id: "id", allowInstanceContent: "allowInstanceContent", lang: "language", "xml_lang":"_xml_lang", "xmlns_iw": "_xmlns_iw", supportedWindowStates: "supportedWindowStates", "xml_base": "_xml_base", sandbox:"sandbox" }, constructor: function(/*/object*/widgetDef, xmlStr, specObject) { this.widgetDef = widgetDef; //xmlStr is now widgetDef.xmlStr, xmlData is rarely used so only load when it's called in toSpec function. if (xmlStr) { this.xmlStr = xmlStr; } if (specObject) { this.specObject = specObject; this._specObjectToWidgetDef(); } }, getXmlBase: function() { if (this.widgetDef.xmlBase) { return this.widgetDef.xmlBase; } return null; }, getAllowInstanceContent: function() { return this.widgetDef.allowInstanceContent; }, getResources: function() { if (!this.resources) { this.resources = []; } return this.resources; }, getIScope: function() { return this.widgetDef.iScope; }, getWidgetEvents: function() { return this.widgetDef.widgetEvents; }, getMarkupByMode: function(mode) { if (this.widgetDef.markup) { if (!mode) { mode = "view"; } var temp = this.widgetDef.markup[mode]; return temp; } else { return null; } }, setMarkupByMode: function(mode, elem) { if (this.widgetDef.markup) { if (!mode) { mode = "view"; } this.widgetDef.markup[mode] = elem; //simple replacement return this; } return null; }, _getManagedItemSetListener: function(itemsetname) { if (!itemsetname) { return null; } if (itemsetname != iwConstants.ATTRIBUTES && itemsetname != iwConstants.IDESCRIPTOR) { return null; } if (this.widgetDef.itemSetsArr) { var defAttrItemSet = this.widgetDef.itemSetsArr[itemsetname]; if (defAttrItemSet && defAttrItemSet.onItemSetChanged) { return defAttrItemSet.onItemSetChanged; } } return null; }, _getManagedItemSetItems: function(itemsetname, simpleAttributes) { var properties = {}; if (this.widgetDef.itemSetsArr) { var defAttrItemSet = this.widgetDef.itemSetsArr[itemsetname]; if (defAttrItemSet) { for (var itemName in defAttrItemSet.items) { if (Object.prototype.hasOwnProperty.call(defAttrItemSet.items, itemName)) { properties[itemName] = defAttrItemSet.items[itemName]; // the new internal json itemset notation is compatible with the SPI } } } } // determine the default locale for fallback /*var lang = ibmConfig[com.ibm.mashups.enabler.services.ConfigConstants.DEFAULT_LOCALE]; if (!lang) lang = "en";*/ simpleAttributes = simpleAttributes || null; if (simpleAttributes) { for (var attName in simpleAttributes) { if (Object.prototype.hasOwnProperty.call(simpleAttributes,attName)) { var value = simpleAttributes[attName]; if (typeof value != "undefined" && value !== null) { var property = {}; //property.defaultLocale = lang; property.readOnly = false; //property.values = {}; //property.values[lang] = value; property.value = value; property.id = attName; properties[attName] = property; } } } } return new com.ibm.mm.iwidget.widget.PropertiesImpl(properties); }, /** * PropertiesProvider Impl */ getAttributes: function() { if (!this.attributeProperties) { this.attributeProperties = this._getManagedItemSetItems(iwConstants.ATTRIBUTES, this.widgetDef.simpleAttributes); } return this.attributeProperties; }, /** * PropertiesProvider Impl */ getIDescriptorItems: function() { if (!this.idescriptorProperties) { this.idescriptorProperties = this._getManagedItemSetItems(iwConstants.IDESCRIPTOR, this.widgetDef.iDescriptor); } return this.idescriptorProperties; }, getAllItemSetNames: function() { var names = []; if (!this.widgetDef.itemSetsArr) { return names; } for (var itemName in this.widgetDef.itemSetsArr) { if (Object.prototype.hasOwnProperty.call(this.widgetDef.itemSetsArr,itemName)) { var itemSetWrapper = this.widgetDef.itemSetsArr[itemName]; if (typeof(itemSetWrapper) != "undefined" && itemName != iwConstants.ATTRIBUTES && itemName != iwConstants.IDESCRIPTOR) { names.push(itemSetWrapper.id); } } } return names; }, getItemSet: function(/*String*/name) { if (name == "attributes") { return this.getAttributes(); } var itemSetWrapper = this.widgetDef.itemSetsArr[name] || null; if (!itemSetWrapper) { return null; } return itemSetWrapper; }, getWidgetId: function() { return this.widgetDef.id; }, getWidgetName: function() { return this.widgetDef.id; }, getPayloadDefs: function() { return null; }, getPayloadDef: function(name) { return null; }, getPayloadDefNames: function() { var arr = []; return arr; }, getSupportedModes: function() { var temp = this.widgetDef.supportedModes; if (!temp) { return null; } var arr = temp.split(" "); return arr; }, getSupportedWindowStates: function() { var temp = this.widgetDef.supportedWindowStates; if (!temp) { return null; } var arr = temp.split(" "); return arr; }, getDefaultLanguage: function() { return this.widgetDef.lang; }, getMarkup: function() { return this.widgetDef.markup; }, _specObjectToWidgetDef: function() { this.widgetDef = {}; if (null === this.specObject) { return; } // id var temp = this.specObject._id; if (!temp) { temp = this.specObject._name; } this.widgetDef.id = null; this.widgetDef.name = null; if (temp){ this.widgetDef.id = temp; this.widgetDef.name = temp; } // allowInstanceContent this.widgetDef.allowInstanceContent = false; temp = this.specObject._allowInstanceContent; if (temp && temp == "true") { this.widgetDef.allowInstanceContent = true; } // iScope temp = this.specObject._iScope; this.widgetDef.iScope = null; if (temp) { this.widgetDef.iScope = temp; } // supportedModes temp = this.specObject._supportedModes; if (!temp) { temp = "view"; } this.widgetDef.supportedModes = temp; // supportedWindowStates temp = this.specObject._supportedWindowStates; if (!temp) { temp = "normal"; } this.widgetDef.supportedWindowStates = temp; // lang temp = this.specObject._lang; if (!temp) { temp = this.specObject._xml_lang; } if (!temp){ temp = "en"; } this.widgetDef.lang = temp; // xml:base temp = this.specObject._xml_base; if (temp){ this.widgetDef.xmlBase = temp; } // iDescriptor var iDescriptorItems = iwConstants.iDescriptorItems; var iDescriptor = {}; for (var i in iDescriptorItems) { if (Object.prototype.hasOwnProperty.call(iDescriptorItems,i)) { var name = iDescriptorItems[i]; var value = this.specObject['_' + name]; if (typeof value == "undefined") { value = null; } iDescriptor[name] = value; } } this.widgetDef.iDescriptor = iDescriptor; // simple attributes and widget events var simpleAttributes = {}; var widgetEvents = {}; for (var j in this.specObject) { if (Object.prototype.hasOwnProperty.call(this.specObject,j)) { // only root level attributes if (0 !== j.indexOf('_')) { continue; } var attr = j; attr = attr.substr(1); if (attr.indexOf("on") !== 0 && !iwConstants.iDescriptorItems[attr] && !this.reservedAttributes[attr]) { simpleAttributes[attr] = this.specObject[j]; } else if (attr.indexOf("on") === 0) { widgetEvents[attr] = this.specObject[j]; } } } this.widgetDef.simpleAttributes = simpleAttributes; this.widgetDef.widgetEvents = widgetEvents; // markup this.widgetDef.markup = this._extractMarkupFromSpecObject(); // itemSets var itemSets = this._extractItemSetsFromSpecObject(this.widgetDef); if (null !== itemSets) { this.widgetDef.itemSetsArr = itemSets; } // public events this.widgetDef.publicEvents = this._extractEventsFromSpecObject(); // resources this.widgetDef.resources = this._extractResourcesFromSpecObject(); // payload defs // this.widgetDef.payloadDefs = this._extractPayloadDefsFromSpecObject(); // event descriptions this.widgetDef.eventDescriptions = this._extractEventDescFromSpecObject(); }, // never used // _extractEventsFromSpecObject: function() { // // widget events // var widgetEvents = {}; // for (var i in this.specObject) { // var handler = this.specObject[i]; // if (typeof handler != "undefined" && handler != null) { // widgetEvents[event.name] = handler; // } // } // return widgetEvents; // }, _extractMarkupFromSpecObject: function() { var contents = this.specObject.contents; var widgetDefContents = {}; for (var mode in contents) { if (Object.prototype.hasOwnProperty.call(contents,mode)) { if (contents[mode]) { widgetDefContents[mode] = {}; if (contents[mode]._uri) { widgetDefContents[mode].uri = contents[mode]._uri; } if (contents[mode].value) { widgetDefContents[mode].content = contents[mode].value; } } } } return widgetDefContents; }, _extractItemSetsFromSpecObject: function(widgetDef) { var itemSets = this.specObject.itemSets; if (itemSets) { var itemSetsArr = {}; var shareableItemSetsArr = {}; for (var i in itemSets) { if (Object.prototype.hasOwnProperty.call(itemSets,i)) { var itemSet = itemSets[i]; var id = i; var onItemSetChanged = itemSet._onItemSetChanged; var temp = itemSet._private; var isPrivate = true; if (temp && temp == "false") { isPrivate = false; } var alias = itemSet._alias?itemSet._alias:null; var descriptionRef = itemSet._description; var itemSetWrapper = { id: id, onItemSetChanged: onItemSetChanged, isPrivate: isPrivate }; if (alias){ itemSetWrapper.alias = alias; } itemSetWrapper.items = {}; var items = itemSet.items; // WARNING: this assumes that an itemset only contains items ! for (var j in items) { if (Object.prototype.hasOwnProperty.call(items,j)) { var item = items[j]; var readOnly = false; var readOnlyAtt = item._readOnly; if (readOnlyAtt && readOnlyAtt == "true") { readOnly = true; } var id2 = item._id; var alias2 = item._alias?item._alias:null; var value = item._value; var lang = item._lang; if (!lang){ lang = item._xml_lang; } var anItem = {}; anItem.id = id2; if (alias2){ anItem.alias = alias2; } anItem.readOnly = readOnly; if (lang) { anItem.defaultLocale = lang; } //value could be "" if (typeof value != "undefined" && value !== null && !lang) { anItem.value = value; } if (typeof value != "undefined" && value !== null && lang){ anItem.values = {}; anItem.values[lang]=value; } var values = item.alts; for (var v in values) { if (Object.prototype.hasOwnProperty.call(values,v)) { var valueNode = values[v]; var locale = v; var localeValue = valueNode._value; if (!anItem.values) { anItem.values = {}; } anItem.values[locale] = localeValue; // if default value for default locale is defined in alts, remove default value here so no duplicates if (lang && locale == lang && anItem.value){ delete anItem.value; } } } itemSetWrapper.items[id2] = anItem; } } if (isPrivate === true) { itemSetsArr[id] = itemSetWrapper; } else { shareableItemSetsArr[id] = itemSetWrapper; } } } widgetDef.shareableItemSetsArr = shareableItemSetsArr; return itemSetsArr; } return null; }, _extractEventsFromSpecObject: function() { var events = this.specObject.events; var eventsArray = {}; if (events && events.length !== 0) { for (var j in events) { if (Object.prototype.hasOwnProperty.call(events,j)) { var event = events[j]; //todo. handler attributes var iEvent = {}; for (var i in event) { if (Object.prototype.hasOwnProperty.call(event,i)) { var name = i; if (0 === i.indexOf('_')) { name = name.substr(1); } var value = event[i]; if (name == "eventDescName") { name = "description"; //backward compatibility } if (name == "handled") { name = "isHandled"; //align with js representation } if (name == "published") { name = "isPublished"; //align with js representation } if (value) { iEvent[name] = value; } } } eventsArray[iEvent.id] = iEvent; } } } return eventsArray; }, _extractResourcesFromSpecObject: function() { var resources = []; var nodes = this.specObject.resources; var j = 0; if (nodes && nodes.length !== 0) { for (var i in nodes) { if (Object.prototype.hasOwnProperty.call(nodes,i)) { var node = nodes[i]; var resource = {}; var id = node._id; if (!id) { id = node._globalid; } resource[iwConstants.RESOURCE.id] = id?id:null; var src = node._src; if (!src) { src = node._uri; } resource[iwConstants.RESOURCE.src] = src; resource[iwConstants.RESOURCE.version] = node._version?node._version:null; resource[iwConstants.RESOURCE.callback] = node._callback?node._callback:null; resource[iwConstants.RESOURCE.mimeType] = node._mimeType?node._mimeType:null; resource[iwConstants.RESOURCE.blockInit] = node._blockInit?node._blockInit:null; resource[iwConstants.RESOURCE.globalid] = node._globalid?node._globalid:null; resource[iwConstants.RESOURCE.skipLoad] = node._skipLoad?node._skipLoad:null; resources[j] = resource; j++; } } } return resources; }, _extractPayloadDefsFromSpecObject: function() { var payloadDefsArr = {}; var payloadDefs = this.specObject.payloadDefs; for (var i in payloadDefs) { if (Object.prototype.hasOwnProperty.call(payloadDefs,i)) { var aNode = payloadDef[i]; // MDG to do fix! // var payloadDef = com.ibm.mm.iwidget.Utils.getPayloadDef(aNode); //payloadDefsArr[i]=payloadDef; } } }, //todo! _extractEventDescFromSpecObject: function() { var eventDescriptions = {}; var eventDescs = this.specObject.eventDescriptions; if (eventDescs && eventDescs.length !== 0) { for (var i in eventDescs) { if (Object.prototype.hasOwnProperty.call(eventDescs,i)) { var node = eventDescs[i]; var eventDescription = {}; var id = i; eventDescription.id = id; eventDescription.payloadType = node._payloadType; eventDescription.description = node._description; eventDescription.title = node._title; eventDescription.descriptionURI = node._descriptionURI?node._descriptionURI:null; //eventDescription.aliases = node._aliases?node._aliases:null; var lang = node._lang; if (!lang ){ lang = node._xml_lang; } if (lang) { eventDescription.lang = lang; } var children = node.alts; for (var j in children) { if (Object.prototype.hasOwnProperty.call(children,j)) { var aNode = children[j]; var temp = {}; temp.description = aNode._description; temp.title = aNode._title; temp.descriptionURI = aNode._descriptionURI?aNode_descriptionURI:null; if (!eventDescription.descriptions){ eventDescription.descriptions = {}; } eventDescription.descriptions[j] = temp; } } eventDescriptions[id] = eventDescription; } } } return eventDescriptions; }, toSpecObject: function() { if (this.specObject) { return this.specObject; } var outputJSON = {}; return outputJSON; } }); com.ibm.mm.iwidget.widget.IWidgetDefinitionImpl = com.ibm.mm.iwidget.widget.IWidgetDefinitionDefaultImpl; // IMPORTANT // ibmConfig.enablerLayerModules is a comma separated string of all supported modules at runtime // This section dynamically loads the Extended representation when the variable enablerLayerModules contains the given module if ((ibmConfig.enablerLayerModules) && (dojo.indexOf(ibmConfig.enablerLayerModules, "iWidget") >= 0)) { dojo["require"]("com.ibm.mm.iwidget.widget.IWidgetDefinitionExtendedImpl"); // JSLINT-IGNORE: This needs to be done to allow modularization and to support the minimal layer } } if(!dojo._hasResource["com.ibm.mashups.iwidget.widget.IWidgetDefinition"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.iwidget.widget.IWidgetDefinition"] = true; dojo.provide("com.ibm.mashups.iwidget.widget.IWidgetDefinition"); } if(!dojo._hasResource["com.ibm.mashups.iwidget.widget.ModifiableProperties_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.iwidget.widget.ModifiableProperties_API"] = true; dojo.provide("com.ibm.mashups.iwidget.widget.ModifiableProperties_API"); dojo.provide("com.ibm.mashups.iwidget.widget.ModifiableProperties"); /** * Modifiable interface defines functions to iterates , updates and persist Properties. * @ibm-spi * @ibm-module iWidget2 */ dojo.declare("com.ibm.mashups.iwidget.widget.ModifiableProperties", [com.ibm.mashups.iwidget.widget.Properties], { /** * @private */ constructor: function() { }, /** * This method creates or overwrites the value of the required item * @param{String}itemName name of the item. Must never be NULL. * @param{String} itemValue value of the item. Must never be NULL. * @param{Boolean} readOnly whether the item value is read only (on this level). * @param{String} locale the locale in which the item value is * @return{com.ibm.mashups.iwidget.widget.Properties} return an handle of InstanceProperties upon successful, NULL upon failure. */ setItemValue: function(itemName, itemValue, readOnly, locale) { }, /** * Removes the named item from the set. * @param{String} itemName name of the item that should be removed.Must never be NULL. * @return{com.ibm.mashups.iwidget.widget.Properties} return an handle of InstanceProperties upon successful, NULL upon failure.. */ removeItem: function(itemName) { //summary:This method sets an value of an iDescriptor item }, /** * Removes the specified item value with the given locale. * @param{String} itemName the name of the item for which to remove the value. * @param{String} locale the locale of the value to remove. Must never be NULL * @return{void} */ removeItemValue: function(itemName, locale) { } }); } if(!dojo._hasResource["com.ibm.mm.iwidget.widget.ModifiablePropertiesImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.iwidget.widget.ModifiablePropertiesImpl"] = true; dojo.provide("com.ibm.mm.iwidget.widget.ModifiablePropertiesImpl"); dojo.declare("com.ibm.mm.iwidget.widget.ModifiablePropertiesImpl", [com.ibm.mashups.iwidget.widget.ModifiableProperties, com.ibm.mm.iwidget.widget.PropertiesImpl], { constructor: function(items, defaultProps) { this._dirty = false; }, _buildChange: function(item, itemName, oldVal, newVal, isRemove) { var isDirty = item._dirty; if (!isDirty) { item._dirty = true; } var change = item._change ? item._change : {}; change.id = itemName; if (isRemove) { //if it's remove action if (isDirty && change.changeType && change.changeType == this.TYPE_NEW) { item._dirty = false; delete item._change; return; } else if (isDirty) { change.changeType = this.TYPE_REMOVE; return; } item._change.changeType = this.TYPE_REMOVE; item._change.oldVal = oldVal; return; } if (isDirty && change.changeType) { if (change.changeType == this.TYPE_NEW) { change.newVal = newVal; } else { change.changeType = this.TYPE_UPDATE; change.newVal = newVal; } } else { if (oldVal) { change.oldVal = oldVal; } if (newVal) { change.newVal = newVal; } if (oldVal) { change.changeType = this.TYPE_UPDATE; } else { change.changeType = this.TYPE_NEW; } } item._change = change; return; }, setItemValue: function(itemName, itemValue, readOnly, locale) { if (!itemName || !itemValue) { return null; } if (itemName in this._items) { if (this._defaultProperties && this._defaultProperties.isReadOnly(itemName)) { return null; } } var oldValue = {}; var newValue = {}; var isReadOnly; if (!locale || (locale && locale == "")) { //that means this is a nonlocalized item if (itemName in this._items) { oldValue = {}; newValue = {}; if (this._items[itemName].values) { oldValue = dojo.clone(this._items[itemName].values); if (this._items[itemName].value) { oldValue[""] = this._items[itemName].value; } newValue = dojo.clone(this._items[itemName].values); newValue[""] = itemValue; } else { if (this._items[itemName].value) { oldValue[""] = this._items[itemName].value; } newValue[""] = itemValue; } this._items[itemName].value = itemValue; this._buildChange(this._items[itemName], itemName, oldValue, newValue); } else { var anItem = {}; anItem.id = itemName; //anItem.name = itemName; anItem.value = itemValue; isReadOnly = !!readOnly; anItem.readOnly = isReadOnly; this._items[itemName] = anItem; newValue = {}; newValue[""] = itemValue; this._items[itemName] = this._items[itemName] ? this._items[itemName] : {}; this._buildChange(this._items[itemName], itemName, null, newValue); } if (this._items[itemName]._dirty) { this._dirty = true; } return this; } var normalizedLocale = locale.replace(/-/g, "_"); // normalize the locale if (itemName in this._items) { oldValue = {}; newValue = {}; //this is update if (this._items[itemName].values) { oldValue = dojo.clone(this._items[itemName].values); } this._items[itemName].values[normalizedLocale] = itemValue; newValue = dojo.clone(this._items[itemName].values); if (this._items[itemName].value) { oldValue[""] = this._items[itemName].value; newValue[""] = this._items[itemName].value; } this._items[itemName].readOnly = readOnly; this._buildChange(this._items[itemName], itemName, oldValue, itemValue); if (this._items[itemName]._dirty) { this._dirty = true; } return this; } //if it's a new item var item = {}; item.values = {}; item.values[normalizedLocale] = itemValue; item.id = itemName; isReadOnly = !!readOnly; item.readOnly = isReadOnly; this._items[itemName] = item; newValue = dojo.clone(item.values); this._buildChange(this._items[itemName], itemName, null, newValue); if (this._items[itemName]._dirty) { this._dirty = true; } return this; }, removeItem: function(itemName) { //remove all the values of the Item // check if this item is read-only on the parent level if (this._defaultProperties && this._defaultProperties.isReadOnly(itemName)) { throw "The specified item [" + itemName + "] is readOnly!"; } var change = {}; var deleted = false; if (itemName in this._items) { //delete this._items[itemName]; //this._items only keeps track of any change if (this._items[itemName]._dirty) { this._items[itemName].value = this.DELETE_TOKEN; this._items[itemName].values = this.DELETE_TOKEN; change = this._items[itemName]._change ? this._items[itemName]._change : {}; if (change.changeType == this.TYPE_NEW) { delete this._items[itemName]; return this; } else { change.changeType = this.TYPE_REMOVE; //keep old value } } else { var oldValue = {}; if (this._items[itemName].values) { oldValue = dojo.clone(this._items[itemName].values); } if (this._items[itemName].value) { oldValue[""] = this._items[itemName].value; } this._items[itemName].value = this.DELETE_TOKEN; this._items[itemName].values = this.DELETE_TOKEN; change = {}; change.changeType = this.TYPE_REMOVE; change.itemName = itemName; change.oldVal = oldValue; this._items[itemName]._change = change; this._items[itemName]._dirty = true; } deleted = true; } if (deleted) { this._dirty = true; return this; } else { return null; } }, removeItemValue: function(itemName, locale) { if (!locale) { //remove nonlocalized value locale = ""; } // check if this item is read-only on the parent level if (this._defaultProperties && this._defaultProperties.isReadOnly(itemName)) { throw "The specified item [" + itemName + "] is readOnly!"; } var normalizedLocale = locale.replace(/-/g, "_"); // normalize the locale var deleted = false; var change = {}; if (itemName in this._items) { if (this._items[itemName]._dirty) { change = this._items[itemName]._change ? this._items[itemName]._change : {}; if (change.changeType == this.TYPE_REMOVE) { return null; //item is already removed } else if (change.changeType == this.TYPE_NEW) { //don't change type if (normalizedLocale == "" && this._items[itemName].value && this._items[itemName].value != this.DELETE_TOKEN) { delete this._items[itemName].value; if (this._items[itemName]._change.newVal[""]) { delete this._items[itemName]._change.newVal[""]; } deleted = true; } if (normalizedLocale != "") { if (this._items[itemName].values[normalizedLocale]) { delete this._items[itemName].values[normalizedLocale]; if (this._items[itemName]._change.newVal[normalizedLocale]) { delete this._items[itemName]._change.newVal[normalizedLocale]; } deleted = true; } } if (this._isEmpty(this._items[itemName]._change.newVal)) { delete this._items[itemName]._dirty; delete this._items[itemName]._change; } } else { //update if (normalizedLocale == "" && this._items[itemName].value && this._items[itemName].value != this.DELETE_TOKEN) { delete this._items[itemName].value; if (this._items[itemName]._change.newVal[""]) { delete this._items[itemName]._change.newVal[""]; } deleted = true; } if (this._items[itemName].values[normalizedLocale]) { delete this._items[itemName].values[normalizedLocale]; if (this._items[itemName]._change.newVal[normalizedLocale]) { delete this._items[itemName]._change.newVal[normalizedLocale]; } deleted = true; } } } else { var oldValue = {}; var newValue = {}; if (normalizedLocale == "" && this._items[itemName].value) { change = {}; change.id = itemName; oldValue = {}; newValue = {}; if (this._items[itemName].values) { change.changeType = this.TYPE_UPDATE; oldValue = dojo.clone(this._items[itemName].values); oldValue[""] = this._items[itemName][""]; change.oldVal = oldValue; change.newVal = dojo.clone(this._items[itemName].values); delete this._items[itemName].value; } else { change.changeType = this.TYPE_REMOVE; oldValue[""] = this._items[itemName][""]; change.oldVal = oldValue; delete this._items[itemName].value; } this._items[itemName]._change = change; this._items[itemName]._dirty = true; deleted = true; } if (normalizedLocale in this._items[itemName].values) { change = {}; change.id = itemName; oldValue = {}; newValue = {}; if (this._items[itemName].value) { change.changeType = this.TYPE_UPDATE; oldValue = dojo.clone(this._items[itemName].values); oldValue[""] = this._items[itemName][""]; change.oldVal = oldValue; change.newVal = dojo.clone(this._items[itemName].values); change.newVal[""] = this._items[itemName].value; delete change.newVal[normalizedLocale]; delete this._items[itemName].value; } else { oldValue = dojo.clone(this._items[itemName].values); delete this._items[itemName].values[normalizedLocale]; if (this._isEmpty(this._items[itemName].values)) { change.changeType = this.TYPE_REMOVE; } else { change.changeType = this.TYPE_UPDATE; change.newVal = dojo.clone(this._items[itemName].values); } change.oldVal = oldValue; } this._items[itemName]._change = change; this._items[itemName]._dirty = true; deleted = true; } } } if (deleted) { this._dirty = true; return this; } else { return null; } }, _isDirty: function() { return this._dirty; }, _setDirty: function(value) { this._dirty = value; }, _isItemDirty: function(itemName) { if (!itemName) { return false; } var isDirty = false; if (this._items[itemName]) { isDirty = this._items[itemName]._dirty; } return isDirty; }, _setItemDirty: function(itemName, value) { if (!itemName) { return; } if (this._items[itemName]) { this._items[itemName]._dirty = value; if (typeof value != "undefined" && !value) { delete this._items[itemName]._dirty; delete this._items[itemName]._change; } if (this._items[itemName].values && this._items[itemName].values == this.DELETE_TOKEN) { delete this._items[itemName].values; } if (this._items[itemName].value && this._items[itemName].value == this.DELETE_TOKEN) { delete this._items[itemName].value; } if (!this._items[itemName].value && !this._items[itemName].values) { delete this._items[itemName]; } } }, _getInternalItemValue: function(itemName) { if (this._items[itemName]) { return this._items[itemName]; } return null; }, _isEmpty: function(obj) { return com.ibm.mm.enabler.utils.Misc.isEmpty(obj); }, _getRequiredValue: function(obj, locale) { if (!obj) { return null; } if (dojo.isString(obj)) { return obj; } if (locale) { if (obj[locale]) { return obj[locale]; } else { return null; } } var singleValue = null; var j = 0; for (var i in obj) { if (Object.prototype.hasOwnProperty.call(obj,i)) { if (i == "") { singleValue = obj[i]; } j++; } } if (singleValue && j == 1) { return singleValue; } return obj; }, _updateProperties:function(updatedProperties){ //used by sandboxed mode... updates is sent from wrapper to stub //merge the updates, latest one overwrites the old one var updatedItems = dojo.mixin(this._items,updatedProperties); this._items = updatedItems; this._dirty = true; }, toJson:function(){ return this._items; } }); } if(!dojo._hasResource["com.ibm.mashups.iwidget.widget.ModifiableProperties"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.iwidget.widget.ModifiableProperties"] = true; dojo.provide("com.ibm.mashups.iwidget.widget.ModifiableProperties"); } if(!dojo._hasResource["com.ibm.mashups.iwidget.widget.ModifiablePropertiesProvider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.iwidget.widget.ModifiablePropertiesProvider"] = true; dojo.provide("com.ibm.mashups.iwidget.widget.ModifiablePropertiesProvider"); /** * Modifiable interface defines functions to access properties that's defined with iWidget. * @ibm-spi * @ibm-module iWidget2 */ dojo.declare("com.ibm.mashups.iwidget.widget.ModifiablePropertiesProvider", null, { /** * @private */ constructor: function() { }, /** This method returns an object that contains iDescriptor items as defined by iWidget spec. It contains default title and icon @type com.ibm.mashups.iwidget.widget.ModifiableProperties @returns{com.ibm.mashups.iwidget.widget.ModifiableProperties } object that contains iWidget iDescriptor items information */ getIDescriptorItems: function() { }, /** This method returns an object that contains attributes as defined by iWidget spec. @type com.ibm.mashups.iwidget.widget.ModifiableProperties @returns{com.ibm.mashups.iwidget.widget.ModifiableProperties } object that contains iWidget iDescriptor items information */ getAttributes: function() { } }); } if(!dojo._hasResource["com.ibm.mashups.iwidget.widget.ModifiableWireProvider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.iwidget.widget.ModifiableWireProvider"] = true; dojo.provide("com.ibm.mashups.iwidget.widget.ModifiableWireProvider"); /** * Interface defines functions to access handled or published event descriptions. * @ibm-spi * @ibm-module iWidget2 */ dojo.declare("com.ibm.mashups.iwidget.widget.ModifiableWireProvider", com.ibm.mashups.iwidget.widget.WireProvider, { /** * @private */ constructor: function(id) { }, /** * @param {String}sourceWidgetId id of the widget that will publish the event * @param {String}sourceEventName name of the event source widget will publish * @param {String}targetEventName name of the event the receiving widget and this event will handle the event published by source widget * @type void */ addWire: function(sourceWidgetId, sourceEventName, targetEventName) { }, /** * @param {String}sourceWidgetId id of the widget that will publish the event * @param {String}sourceEventName name of the event source widget will publish * @param {String}targetEventName name of the event the receiving widget and this event will handle the event published by source widget * @type void */ removeWire: function(sourceWidgetId, sourceEventName, targetEventName) { } }); } if(!dojo._hasResource["com.ibm.mashups.iwidget.widget.IWidgetInstance_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.iwidget.widget.IWidgetInstance_API"] = true; dojo.provide("com.ibm.mashups.iwidget.widget.IWidgetInstance_API"); dojo.provide("com.ibm.mashups.iwidget.widget.IWidgetInstance"); /** * Interface defines functions to access all the instance level descriptive data. * @ibm-spi * @ibm-module iWidget2 */ dojo.declare("com.ibm.mashups.iwidget.widget.IWidgetInstance", [com.ibm.mashups.iwidget.widget.ModifiablePropertiesProvider, com.ibm.mashups.iwidget.widget.ModifiableWireProvider], { /** * @private */ constructor: function() { } }); } if(!dojo._hasResource["com.ibm.mm.iwidget.Utils"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.iwidget.Utils"] = true; dojo.provide("com.ibm.mm.iwidget.Utils"); dojo.declare("com.ibm.mm.iwidget.UtilsDefaultImpl", null, { constructor: function() { }, widgetClassRE: new RegExp("(mm:|mm_|iw-)iWidget"), findElementByAttribute: function(/*String*/att,/*String*/ value,/*DOMElement*/ root,/*[]*/ element, hasMultiple){ var aRoot = root; if (!root.childNodes) { return false; } if (att == "class") { dojo.query("." + value, root).forEach(function(ele){ element.push(ele); }); return element.length !== 0; } else if (att == "query") { dojo.query(value, root).forEach(function(ele){ element.push(ele); }); return element.length !== 0; } //other attributes if (root.getElementsByTagName) { var nodes = root.getElementsByTagName("*"); for (var i = 0, l = nodes.length; i < l; i++) { var aNode = nodes[i]; if (aNode && aNode.getAttribute) { var childValue = aNode.getAttribute(att); if (childValue == value) { element.push(aNode); if (!hasMultiple) { return true; } } } } } // made this order change for 20459. The above code should fix 20459 for dojo test. If it fails 20403 and 20330, the following code will catch it // This is to avoid using the hacking code // made the change for 20403 and 20330 since IE7 returns wrong value with code in the other attributes section above if (att == "id") { dojo.query("#" + value, root).forEach(function(ele){ element.push(ele); }); return element.length !== 0; } return false; }, getClass: function(/*object*/node){ var childValue = node.getAttribute("class"); childValue = childValue ? childValue : node.getAttribute("className"); return childValue; }, checkParentElement: function(/*Node*/selfNode, /*RegExp*/ classToFind){ if (selfNode) { var dadNode = selfNode.parentNode; if (dadNode) { if (dadNode.className) { if (dadNode.className.match(classToFind)) { return dadNode.id; } } return this.checkParentElement(dadNode, classToFind); } } return null; }, getWidgetParent: function(/*Domnode*/node, /*RegExp*/ classToFind){ if (dojo.isString(node)) { node = dojo.byId(node); } if (!classToFind) { classToFind = this.widgetClassRE; } return this.checkParentElement(node, classToFind); }, getParents: function(/*widget*/widget,/*array*/ arr){ var parent = widget.getParent(); if (parent) { arr.push(parent); this.getParents(parent, arr); } return; }, /** * This utility method takes an id from the markup and returns * an unprefixed id to pass into an enabler model (like Widget, * Wire or Event.) IE7 doesn't support ids that start with a * number so the server may encode the ids with a prefix, * like 'id_' to make an id valid. * * If the markup id starts with the prefix from * ibmConfig["com.ibm.mashups.iWidget.idPrefix"] this method * will remove the prefix. * * If the id does not start with the prefix no action will be * taken. * * @param {String} id from the markup * @return {String} the unprefixed id to pass to the enabler * models */ getModelID: function(/*string*/id){ var ret = id; var prefix = ibmConfig[com.ibm.mashups.enabler.services.ConfigConstants.ID_PREFIX]; if (prefix && dojo.isString(ret)) { var indx = ret.indexOf(prefix); if (indx === 0) { ret = ret.substring(prefix.length); } } return ret; }, /** * This utility method takes an id from an enabler (like Widget, * Wire or Event) and returns a prefixed markup id. IE7 doesn't * support ids that start with a number so the server may encode * the ids with a prefix, like 'id_' to make an id valid. * * If the model id starts with a number this method will take * prefix from ibmConfig["com.ibm.mashups.iWidget.idPrefix"] * and prepend it to the id passed in. * * * @param {String} id retrieved from an enabler model * @return {String} the prefixed id to match the markup returned * from the server */ getMarkupID: function(/*string*/id) { var ret = id; var prefix = ibmConfig[com.ibm.mashups.enabler.services.ConfigConstants.ID_PREFIX]; if (prefix && dojo.isString(ret)) { ret = prefix + ret; } return ret; }, stripHashPrefix: function(str) { if (dojo.isString(str)) { var pos = str.indexOf('#'); if (pos !== -1) { // not enough to just strip first character, because IE prepends the URL. return str.substr(1 + pos); } } return str; }, /** * This method is internal only, it is mainly used for classes that use the "Model" type of instances */ _getWidgetTitle: function(widgetId) { return null; } }); // IMPORTANT // ibmConfig.enablerLayerModules is a comma separated string of all supported modules at runtime // This section dynamically loads the Extended representation when the variable enablerLayerModules contains the given module if ((ibmConfig.enablerLayerModules) && (dojo.indexOf(ibmConfig.enablerLayerModules, "iWidget") >= 0)) { dojo["require"]("com.ibm.mm.iwidget.UtilsExtended"); // JSLINT-IGNORE: This needs to be done to allow modularization and to support the minimal layer } else { com.ibm.mm.iwidget.Utils = new com.ibm.mm.iwidget.UtilsDefaultImpl(); } } if(!dojo._hasResource["com.ibm.mm.iwidget.widget.IWidgetInstanceDefaultImpl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.iwidget.widget.IWidgetInstanceDefaultImpl"] = true; dojo.provide("com.ibm.mm.iwidget.widget.IWidgetInstanceDefaultImpl"); dojo.declare("com.ibm.mm.iwidget.widget.IWidgetInstanceDefaultImpl", com.ibm.mashups.iwidget.widget.IWidgetInstance, { constructor: function(wrapper, /*RootElement*/widgetSpan,/*String*/ id){ this.wrapper = wrapper; this.rootElement = widgetSpan; this.id = id; this.ns = widgetSpan.className.substr(0, 3); var nodes = []; var className = this.ns + "Definition"; com.ibm.mm.iwidget.Utils.findElementByAttribute("query", "> ."+className, this.rootElement, nodes, false); if (nodes && nodes.length > 0) { var node = nodes[0]; var url = node.getAttribute("href"); if (typeof(url) != "undefined" && url !== null) { this.widgetXMLUrl = url; } } }, _destroy: function(){ // #17713 one leak for widgetWrapper.rootElement (iw-iWidget DIV) if (this.rootElement) { this.rootElement = null; } }, getDefaultViewContent: function(){ if (this.defaultViewContent) { return this.defaultViewContent; } var className = this.ns + "Content"; var node = null; var nodeList = dojo.query("> ." + className+"."+iwConstants.mode_view, this.rootElement); if (nodeList) { node = nodeList[0]; } if (!node) { nodeList = dojo.query("> ." + className, this.rootElement); if (nodeList) { node = nodeList[0]; } } if (node) { this.defaultViewContent = node.innerHTML; return this.defaultViewContent; } else { return null; } }, getWidgetEvents: function(){ //simple events including all the predefined events and onSth. event if (this.widgetEvents) { return this.widgetEvents; } var widgetEvents = {}; var attributes = this.rootElement.attributes; for (var i = 0; i < attributes.length; i++) { var attribute = attributes[i]; if (attribute.name !== null && attribute.name.indexOf("on") === 0) { var handler = this.rootElement.getAttribute(attribute.name); if (typeof handler != "undefined" && handler !== null) { widgetEvents[attribute.name] = handler; } } } this.widgetEvents = widgetEvents; return this.widgetEvents; }, _addWire: function(wire){ }, _removeWire: function(id){ }, addWire: function(sourceWidget, sourceEvent, targetEvent){ }, removeWire: function(sourceWidget, sourceEvent, targetEvent){ }, _getPublicEvents: function(){ return null; }, getWires: function(){ return []; }, getWireModel: function(){ return null; }, /** * ModifiablePropertiesProvider Impl */ getAttributes: function(){ if (!this.attributeProperties) { //return all the attributes as JSON data var attributes = this.getItemSets()[iwConstants.ATTRIBUTES]; var properties = {}; if (attributes) { for (var itemName in attributes) { if (Object.prototype.hasOwnProperty.call(attributes, itemName)) { properties[itemName] = attributes[itemName]; // we are compatible with the new internal itemset format } } } this.attributeProperties = new com.ibm.mm.iwidget.widget.ModifiablePropertiesImpl(properties); } return this.attributeProperties; }, /** * ModifiablePropertiesProvider Impl */ getIDescriptorItems: function(){ if (!this.idescriptorProperties) { //return all the attributes as JSON data var iDescriptor = this.getItemSets()[iwConstants.IDESCRIPTOR]; var properties = {}; if (iDescriptor) { for (var itemName in iDescriptor) { if (Object.prototype.hasOwnProperty.call(iDescriptor, itemName)) { properties[itemName] = iDescriptor[itemName]; // we are compatible with the new internal itemset format // (this is working here, because on instance level we got the idescriptor from markup, not def) } } } this.idescriptorProperties = new com.ibm.mm.iwidget.widget.ModifiablePropertiesImpl(properties); } return this.idescriptorProperties; }, _getItemSets: function(){ if (this.itemSets) { return this.itemSets; } this.loadItemSets(); return this.itemSets; }, getItemSets: function(){ //returns a list of itemsets: each itemset is like following // { itemname1:object,itemname2;object} // return this._getItemSets(); }, getItemSet: function(itemSetName){ //returns json object as indicated in _loadItem //{ itemName1:{},itemName2:{}} if (!itemSetName) { return null; } var itemSets = this._getItemSets(); if (itemSets && itemSets[itemSetName]) { return itemSets[itemSetName]; } }, loadItemSets: function(){ //this.itemSets = this._loadItemSets(this.rootElement, this.ns); this.itemSets = this._loadItemSetsOptimized(this.rootElement, this.ns); }, _loadItemSetsOptimized: function(rootElement, ns){ var itemSets = {}; if (rootElement.childNodes.length) { dojo.query('> .'+ns+com.ibm.mm.iwidget.Constants.CSSCLASS_INSTANCE.iwItemSet+' > .'+ns+com.ibm.mm.iwidget.Constants.CSSCLASS_INSTANCE.iwItem, rootElement).forEach(function(item){ var setName = dojo.attr(item.parentNode, 'title'); if (setName) { if (!itemSets[setName]) { itemSets[setName] = {}; } var anItem = this._loadItemOptimized(item, ns); itemSets[setName][anItem.id] = anItem; } }, this); } return itemSets; }, _loadItemOptimized: function(elem, ns){ var css = com.ibm.mm.iwidget.Constants.CSSCLASS_INSTANCE; var item = { id: com.ibm.mm.iwidget.Utils.stripHashPrefix(dojo.attr(elem, 'href')), readOnly: dojo.hasClass(elem, ns + css.iwReadOnly) }; var lang = dojo.attr(elem, 'lang'); if (lang) { item.defaultLocale = lang; } var value; var children = dojo.query('> .' + ns + css.iwValue, elem); if (children.length) { item.values = {}; children.forEach(function(valElem){ var locale = dojo.attr(valElem, 'lang') || lang; item.values[locale] = com.ibm.mm.enabler.utils.Dom.textContent(valElem); }); } else { value = com.ibm.mm.enabler.utils.Dom.textContent(elem); if (dojo.isString(value)) { item.value = dojo.string.trim(value); } } return item; }, // invalidate itemsets _invalidateItemSets: function(name){ if (!name) { // invalidate all itemset this.itemSets = {}; } else { // invalidate a single itemsets this.itemSets[name] = {}; } }, _getInstanceMarkup: function(){ var node = dojo.clone(this.rootElement); //remove content div if it's available dojo.query("> ." + this.ns + "Content", node).forEach(function(contentNode){ com.ibm.mm.enabler.utils.Dom.destroyNode(contentNode); }); dojo.query("> ." + this.ns + "loading", node).forEach(function(contentNode){ com.ibm.mm.enabler.utils.Dom.destroyNode(contentNode); }); var tempEl = document.createElement("div"); tempEl.appendChild(node); var html = tempEl.innerHTML; return html; } }); com.ibm.mm.iwidget.widget.IWidgetInstanceImpl = com.ibm.mm.iwidget.widget.IWidgetInstanceDefaultImpl; // IMPORTANT // ibmConfig.enablerLayerModules is a comma separated string of all supported modules at runtime // This section dynamically loads the Extended representation when the variable enablerLayerModules contains the given module if ((ibmConfig.enablerLayerModules) && (dojo.indexOf(ibmConfig.enablerLayerModules, "iWidget") >= 0)) { dojo["require"]("com.ibm.mm.iwidget.widget.IWidgetInstanceExtendedImpl"); // JSLINT-IGNORE: This needs to be done to allow modularization and to support the minimal layer } } if(!dojo._hasResource["com.ibm.mashups.iwidget.widget.IWidgetInstance"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.iwidget.widget.IWidgetInstance"] = true; dojo.provide("com.ibm.mashups.iwidget.widget.IWidgetInstance"); } if(!dojo._hasResource["com.ibm.mashups.iwidget.widget.IWidgetWrapper_API"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mashups.iwidget.widget.IWidgetWrapper_API"] = true; dojo.provide("com.ibm.mashups.iwidget.widget.IWidgetWrapper_API"); dojo.provide("com.ibm.mashups.iwidget.widget.IWidgetWrapper"); /** * IWidgetWrapper interface represents a runtime instance of an iWidget on the page. Information provided by the IWidgetWrapper is an aggregation of definition level data and instance level data. * To get desriptive data that's specific to instance level and definition level. It should use Provider api that's implemented by IWidgetDefinition or IWidgetIstance. * @ibm-spi * @ibm-module iWidget2 */ dojo.declare("com.ibm.mashups.iwidget.widget.IWidgetWrapper", [com.ibm.mashups.iwidget.widget.WireProvider, com.ibm.mashups.iwidget.widget.EventProvider], { /** * @private */ constructor: function() { }, /** This method returns iWidgetDefinition of this runtime instance.
var deferred = widgetWrapper.getIWidgetDefinition();
deferred.setFinishedCallback(callback,parameters);
deferred.start(true);
here are the callback parameters that will be passed into callback function:
    resource - IWidgetDefinition object
    statusCode - the overall HTTP status,code of the action (the highest status code of the involved operations).
    params - the parameters passed into the callback
@type com.ibm.mashups.enabler.Deferred @returns{com.ibm.mashups.enabler.Deferred} a deferred object used to start this operation. @see com.ibm.mashups.iwidget.widget.IWidgetDefinition */ getIWidgetDefinition: function() { }, /** Sets the iWidgetDefinition for this runtime instance @param{com.ibm.mashups.iwidget.widget.IWidgetDefinition} widgetDefinition IWidgetDefinition to use for this runtime instance. Must not be null. @type{void} @return{void} */ setIWidgetDefinition: function(widgetDefinition) { }, /** This method returns iWidgetInstance which contains all the descriptive data for this iWidget instance @type com.ibm.mashups.iwidget.widget.IWidgetInstance @returns{com.ibm.mashups.iwidget.widget.IWidgetInstance } iWidgetInstance object */ getIWidgetInstance: function() { }, /** * This method returns the a clone of the content of the widget as it is inside of the DOM.
It removes automatically * any markup that was added to the DOM using microformats (given that the microformat implements the unProcess handler).
* This method does not remove any additional DOM changes that where done by the widget itself and applies the unProcess only
* to the subnodes of the actual widget node.

* If your widget needs to take special action to it's DOM nodes before the getMarkup is processing it, you can define the method
* _onGetMarkup in your widgets JavaScript file. This method, as part of the iScope, will always be called before the actual
* markup is processed.

* The synchrounus mode of returned Deferred is not supported. * @type com.ibm.mashups.enabler.Deferred * @returns {com.ibm.mashups.enabler.Deferred} a deferred object used to fetch the actual markup. */ getMarkup: function() { }, /** This method returns true if an iwidget instance is already loaded on the page dom. @type Boolean @returns{Boolean } true if widget is already completely rendered on the page. */ isLoaded: function() { }, /** * This method returns true if an iwidget instance is standalone on the page. * @type Boolean * @returns{Boolean} true if widget is standalone on the page. */ isStandalone: function() { }, /** This method displays the widgets on the page if widget has not been displayed yet. @type void */ doRender: function() { } }); } if(!dojo._hasResource["com.ibm.mm.enabler.aggregation.javascript.Filter"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["com.ibm.mm.enabler.aggregation.javascript.Filter"] = true; dojo.provide("com.ibm.mm.enabler.aggregation.javascript.Filter"); function com_ibm_enabler_aggregation_javascript_globalEvalNonIE( /*String*/javascript) { // summary: Evaluates a string of javascript in the global scope. // description: Calling eval.call( self, ... ); from within a JS object apparently makes "this" point to the object from which the // eval call was made even though the scope is set using the "call" function. Therefore we need to have this function // available in the global scope and not as a member variable on a JS object. eval.call(self, javascript); } dojo.declare("com.ibm.mm.enabler.aggregation.javascript.Filter", null, { // summary: Base interface for a filter. Each implementation must implement // the doFilter function. // description: Passes the given event through to give the implementation of // this filter a chance to alter or handle the event in some way. constructor: function() { }, doFilter: function( script) { // summary: Filter the given event. // description: Allows this filter to handle or alter the event. If this function // returns true, processing is stopped and the event is considered "handled". // script: the script block (string or HTMLElement) //dojo.unimplemented( "com.ibm.mm.enabler.aggregation.JavascriptFilter.doFilter" ); }, evalGlobal: function( javascript) { // summary: Evaluates the given javascript in the global context. // javascript: a string of javascript to evaluate. if (window.execScript) { // JSLINT-IGNORE: We have to use eval here window.execScript(this._stripHTMLComments(javascript), "JavaScript"); // JSLINT-IGNORE: We have to use eval here } else { //Using eval.call( window, javascript ) was apparently not really eval'ing //in the global scope since 'this' was still referring to the Filter object //and not the window object as it should have (or I think it should have)... com_ibm_enabler_aggregation_javascript_globalEvalNonIE(javascript); } }, _stripHTMLComments: function(str) { // summary: Strip all HTML comments from a script block. // description: Although HTML comments are allowed in a script block by the browser // IE throws up whenever you try and eval a javascript string in the global context // that has HTML comments in the string. var resultStr = str; resultStr = resultStr.replace(/)]+-->/g, ''); return resultStr; }, prepareDocumentWrite: function(buffer) { // summary: Prepares support for document.write() and document.writeln // description: Overrides the original document.write() and document.writeln() // functions with functions writing to the buffer var me = this; document.write = function() { // JSLINT-IGNORE: We have to use eval here me._documentWrite(buffer, document.write.arguments); // JSLINT-IGNORE: We have to use eval here }; document.writeln = function(str) { // JSLINT-IGNORE: We have to use eval here me._documentWrite(buffer, document.writeln.arguments); // JSLINT-IGNORE: We have to use eval here }; }, _documentWrite: function(buffer, args) { // summary: Internal document.write() function writing to the given buffer // description: Just appends the given String arguments to our buffer for (var i = 0, l = args.length; i < l; i++) { buffer.content += args[i]; } }, applyDocumentWrite: function( script, buffer) { // summary: Injects the markup in the given buffer into the DOM // description: Looks up the script element in the original DOM // and injects the markup before that element var cont = buffer.content || null; if (cont !== null && cont.length > 0) { var i = 0; if (dojo.isIE) { // Attention: IE needs the
tag available, otherwise