### Eclipse Workspace Patch 1.0
#P xwiki-platform-web
Index: standard/pom.xml
===================================================================
--- standard/pom.xml (revision 22346)
+++ standard/pom.xml (working copy)
@@ -62,6 +62,12 @@
xwiki-rest${platform.core.version}
+
+
+ org.xwiki.platform
+ xwiki-social-opensocial
+ 1.0-SNAPSHOT
+
@@ -253,6 +259,9 @@
+ **/containers/default/*.js
+ **/shindig.properties
+ **/opensocial/*.js**/*-min.js**/*-debug.js**/langs/*.js
Index: standard/src/main/webapp/templates/addfriend.vm
===================================================================
--- standard/src/main/webapp/templates/addfriend.vm (revision 0)
+++ standard/src/main/webapp/templates/addfriend.vm (revision 0)
@@ -0,0 +1,28 @@
+$response.setContentType("application/x-json")
+## verify if the current user has the necessary rights to add a friend
+## if no necessary rights, return 5 as error code
+#if(!$hasAdmin && !$xwiki.hasAccessLevel("edit", $context.user, $doc.fullName))
+ 5
+#else
+#set($fullname = $request.get("name"))
+## verify is the user is self
+## is so, return 1 as error code
+#if($fullname == $doc.fullName)
+ 1
+#else
+ ## verify if the user is already a friend
+ #set($exists = "$!doc.getObject('XWiki.FriendClass', 'friendName', $fullname)")
+ #if($exists != "")
+ ## verify if the user is already a friend
+ ## if so, return 2 as error code
+ 2
+ #else
+ ## return 0, as success code
+ 0
+ #set($obj = $doc.newObject("XWiki.FriendClass"))
+ $obj.set("friendName", $fullname)
+ #set($discard = $doc.save())
+ #end
+#end
+#end
+
Index: standard/src/main/webapp/resources/js/xwiki/opensocial/util.js
===================================================================
--- standard/src/main/webapp/resources/js/xwiki/opensocial/util.js (revision 0)
+++ standard/src/main/webapp/resources/js/xwiki/opensocial/util.js (revision 0)
@@ -0,0 +1,29 @@
+/**
+ * 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 Utility functions for the Open Gadget Container
+ */
+
+Function.prototype.inherits = function(parentCtor) {
+ function tempCtor() {};
+ tempCtor.prototype = parentCtor.prototype;
+ this.superClass_ = parentCtor.prototype;
+ this.prototype = new tempCtor();
+ this.prototype.constructor = this;
+};
\ No newline at end of file
Index: standard/src/main/webapp/templates/deletefriend.vm
===================================================================
--- standard/src/main/webapp/templates/deletefriend.vm (revision 0)
+++ standard/src/main/webapp/templates/deletefriend.vm (revision 0)
@@ -0,0 +1,30 @@
+## verify if the current user has the necessary rights to add a friend
+## if no necessary rights, return error
+#set($hasRights = !$hasAdmin && !$xwiki.hasAccessLevel("edit", $context.user, $doc.fullName))
+#if($hasRights)
+ #set($rspMsg = "not enough rights")
+ #set($redirectUrl = "?xpart=error")
+#else
+ #set($fullname = $request.get("name"))
+ #set($obj = $doc.getObject("XWiki.FriendClass", "friendName", $fullname))
+ ## verify if document really has such an object
+ ## if not, return error
+ #if(!$obj)
+ #set($rspMsg = "no such object")
+ #set($redirectUrl = "?xpart=error")
+ #else
+ ## finally remove the object
+ ## return ok, as success code or redirect
+ #set($discard = $doc.removeObject($obj))
+ #set($discard = $doc.save())
+ #set($rspMsg = "ok")
+ #set($redirectUrl = "")
+ #end
+#end
+#if($request.ajax)
+ $rspMsg
+#elseif($request.xredirect)
+ $response.sendRedirect("$request.xredirect$redirectUrl")
+#else
+ $response.sendRedirect("$doc.getURL('view')$redirectUrl")
+#end
Index: standard/src/main/webapp/resources/js/xwiki/opensocial/cookies.js
===================================================================
--- standard/src/main/webapp/resources/js/xwiki/opensocial/cookies.js (revision 0)
+++ standard/src/main/webapp/resources/js/xwiki/opensocial/cookies.js (revision 0)
@@ -0,0 +1,272 @@
+/**
+ * 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 Functions for setting, getting and deleting cookies
+ */
+
+/**
+ * Namespace for cookie functions
+ */
+
+// TODO: find the official solution for a cookies library
+var shindig = shindig || {};
+shindig.cookies = shindig.cookies || {};
+
+
+shindig.cookies.JsType_ = {
+ UNDEFINED: 'undefined'
+};
+
+shindig.cookies.isDef = function(val) {
+ return typeof val != shindig.cookies.JsType_.UNDEFINED;
+};
+
+
+/**
+ * Sets a cookie.
+ * The max_age can be -1 to set a session cookie. To remove and expire cookies,
+ * use remove() instead.
+ *
+ * @param {string} name The cookie name.
+ * @param {string} value The cookie value.
+ * @param {number} opt_maxAge The max age in seconds (from now). Use -1 to set
+ * a session cookie. If not provided, the default is
+ * -1 (i.e. set a session cookie).
+ * @param {string} opt_path The path of the cookie, or null to not specify a
+ * path attribute (browser will use the full request
+ * path). If not provided, the default is '/' (i.e.
+ * path=/).
+ * @param {string} opt_domain The domain of the cookie, or null to not specify
+ * a domain attribute (browser will use the full
+ * request host name). If not provided, the default
+ * is null (i.e. let browser use full request host
+ * name).
+ */
+shindig.cookies.set = function(name, value, opt_maxAge, opt_path, opt_domain) {
+ // we do not allow '=' or ';' in the name
+ if (/;=/g.test(name)) {
+ throw new Error('Invalid cookie name "' + name + '"');
+ }
+ // we do not allow ';' in value
+ if (/;/g.test(value)) {
+ throw new Error('Invalid cookie value "' + value + '"');
+ }
+
+ if (!shindig.cookies.isDef(opt_maxAge)) {
+ opt_maxAge = -1;
+ }
+
+ var domainStr = opt_domain ? ';domain=' + opt_domain : '';
+ var pathStr = opt_path ? ';path=' + opt_path : '';
+
+ var expiresStr;
+
+ // Case 1: Set a session cookie.
+ if (opt_maxAge < 0) {
+ expiresStr = '';
+
+ // Case 2: Expire the cookie.
+ // Note: We don't tell people about this option in the function doc because
+ // we prefer people to use ExpireCookie() to expire cookies.
+ } else if (opt_maxAge === 0) {
+ // Note: Don't use Jan 1, 1970 for date because NS 4.76 will try to convert
+ // it to local time, and if the local time is before Jan 1, 1970, then the
+ // browser will ignore the Expires attribute altogether.
+ var pastDate = new Date(1970, 1 /*Feb*/, 1); // Feb 1, 1970
+ expiresStr = ';expires=' + pastDate.toUTCString();
+
+ // Case 3: Set a persistent cookie.
+ } else {
+ var futureDate = new Date((new Date).getTime() + opt_maxAge * 1000);
+ expiresStr = ';expires=' + futureDate.toUTCString();
+ }
+
+ document.cookie = name + '=' + value + domainStr + pathStr + expiresStr;
+};
+
+
+/**
+ * Returns the value for the first cookie with the given name
+ * @param {string} name The name of the cookie to get
+ * @param {string} opt_default If not found this is returned instead.
+ * @return {string|undefined} The value of the cookie. If no cookie is set this
+ * returns opt_default or undefined if opt_default is
+ * not provided.
+ */
+shindig.cookies.get = function(name, opt_default) {
+ var nameEq = name + "=";
+ var cookie = String(document.cookie);
+ for (var pos = -1; (pos = cookie.indexOf(nameEq, pos + 1)) >= 0;) {
+ var i = pos;
+ // walk back along string skipping whitespace and looking for a ; before
+ // the name to make sure that we don't match cookies whose name contains
+ // the given name as a suffix.
+ while (--i >= 0) {
+ var ch = cookie.charAt(i);
+ if (ch == ';') {
+ i = -1; // indicate success
+ break;
+ }
+ }
+ if (i == -1) { // first cookie in the string or we found a ;
+ var end = cookie.indexOf(';', pos);
+ if (end < 0) {
+ end = cookie.length;
+ }
+ return cookie.substring(pos + nameEq.length, end);
+ }
+ }
+ return opt_default;
+};
+
+
+/**
+ * Removes and expires a cookie.
+ *
+ * @param {string} name The cookie name.
+ * @param {string} opt_path The path of the cookie, or null to expire a cookie
+ * set at the full request path. If not provided, the
+ * default is '/' (i.e. path=/).
+ * @param {string} opt_domain The domain of the cookie, or null to expire a
+ * cookie set at the full request host name. If not
+ * provided, the default is null (i.e. cookie at
+ * full request host name).
+ */
+shindig.cookies.remove = function(name, opt_path, opt_domain) {
+ var rv = shindig.cookies.containsKey(name);
+ shindig.cookies.set(name, '', 0, opt_path, opt_domain);
+ return rv;
+};
+
+
+/**
+ * Gets the names and values for all the cookies
+ * @private
+ * @return {Object} An object with keys and values
+ */
+shindig.cookies.getKeyValues_ = function() {
+ var cookie = String(document.cookie);
+ var parts = cookie.split(/\s*;\s*/);
+ var keys = [], values = [], index, part;
+ for (var i = 0; part = parts[i]; i++) {
+ index = part.indexOf('=');
+
+ if (index == -1) { // empty name
+ keys.push('');
+ values.push(part);
+ } else {
+ keys.push(part.substring(0, index));
+ values.push(part.substring(index + 1));
+ }
+ }
+ return {keys: keys, values: values};
+};
+
+
+/**
+ * Gets the names for all the cookies
+ * @return {Array} An array with the names of the cookies
+ */
+shindig.cookies.getKeys = function() {
+ return shindig.cookies.getKeyValues_().keys;
+};
+
+
+/**
+ * Gets the values for all the cookies
+ * @return {Array} An array with the values of the cookies
+ */
+shindig.cookies.getValues = function() {
+ return shindig.cookies.getKeyValues_().values;
+};
+
+
+/**
+ * Whether there are any cookies for this document
+ * @return {boolean}
+ */
+shindig.cookies.isEmpty = function() {
+ return document.cookie === '';
+};
+
+
+/**
+ * Returns the number of cookies for this document
+ * @return {number}
+ */
+shindig.cookies.getCount = function() {
+ var cookie = String(document.cookie);
+ if (cookie === '') {
+ return 0;
+ }
+ var parts = cookie.split(/\s*;\s*/);
+ return parts.length;
+};
+
+
+/**
+ * Returns whether there is a cookie with the given name
+ * @param {string} key The name of the cookie to test for
+ * @return {boolean}
+ */
+shindig.cookies.containsKey = function(key) {
+ var sentinel = {};
+ // if get does not find the key it returns the default value. We therefore
+ // compare the result with an object to ensure we do not get any false
+ // positives.
+ return shindig.cookies.get(key, sentinel) !== sentinel;
+};
+
+
+/**
+ * Returns whether there is a cookie with the given value. (This is an O(n)
+ * operation.)
+ * @param {string} value The value to check for
+ * @return {boolean}
+ */
+shindig.cookies.containsValue = function(value) {
+ // this O(n) in any case so lets do the trivial thing.
+ var values = shindig.cookies.getKeyValues_().values;
+ for (var i = 0; i < values.length; i++) {
+ if (values[i] == value) {
+ return true;
+ }
+ }
+ return false;
+};
+
+
+/**
+ * Removes all cookies for this document
+ */
+shindig.cookies.clear = function() {
+ var keys = shindig.cookies.getKeyValues_().keys;
+ for (var i = keys.length - 1; i >= 0; i--) {
+ shindig.cookies.remove(keys[i]);
+ }
+};
+
+/**
+ * Static constant for the size of cookies. Per the spec, there's a 4K limit
+ * to the size of a cookie. To make sure users can't break this limit, we
+ * should truncate long cookies at 3950 bytes, to be extra careful with dumb
+ * browsers/proxies that interpret 4K as 4000 rather than 4096
+ * @type number
+ */
+shindig.cookies.MAX_COOKIE_LENGTH = 3950;
Index: standard/src/main/webapp/WEB-INF/classes/shindig.properties
===================================================================
--- standard/src/main/webapp/WEB-INF/classes/shindig.properties (revision 0)
+++ standard/src/main/webapp/WEB-INF/classes/shindig.properties (revision 0)
@@ -0,0 +1,102 @@
+# 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.
+
+# Location of feature manifests (comma separated)
+shindig.features.default=res://features/features.txt
+
+# Location of container configurations (comma separated)
+shindig.containers.default=res://containers/default/container.js
+
+# A file containing blacklisted gadgets.
+shindig.blacklist.file=
+
+### Inbound OAuth support
+# The URL base to use for full OAuth support (three-legged)
+shindig.oauth.base-url=/xwiki/oauth/
+shindig.oauth.authorize-action=/xwiki/WEB-INF/authorize.jsp
+shindig.oauth.legacy-body-signing=true
+shindig.oauth.enable-oauth-1.0=true
+shindig.oauth.enable-signed-callbacks=true
+
+### Outbound OAuth support
+shindig.signing.state-key=
+shindig.signing.key-name=
+shindig.signing.key-file=
+shindig.signing.global-callback-url=http://localhost:8080/xwiki/gadgets/oauthcallback
+shindig.signing.enable-signed-callbacks=true
+
+# If enabled here, configuration values can be found in container configuration files.
+shindig.locked-domain.enabled=false
+
+# TODO: This needs to be moved to container configuration.
+shindig.content-rewrite.include-urls=.*
+shindig.content-rewrite.exclude-urls=
+shindig.content-rewrite.include-tags=link,script,embed,img,style
+shindig.content-rewrite.expires=86400
+shindig.content-rewrite.proxy-url=/xwiki/gadgets/proxy?url=
+shindig.content-rewrite.concat-url=/xwiki/gadgets/concat?
+
+#
+# Default set of forced libs to allow for better caching
+#
+# NOTE: setting this causes the EndToEnd test to fail the opensocial-templates test
+#shindig.gadget-rewrite.default-forced-libs=core:core.io
+shindig.gadget-rewrite.default-forced-libs=
+
+# Configuration for image rewriter
+shindig.image-rewrite.max-inmem-bytes = 1048576
+shindig.image-rewrite.max-palette-size = 256
+shindig.image-rewrite.allow-jpeg-conversion = true
+shindig.image-rewrite.jpeg-compression = 0.75
+shindig.image-rewrite.min-threshold-bytes = 200
+
+# Configuration for template rewriter
+shindig.template-rewrite.extension-tag-namespace=http://ns.opensocial.org/2009/extensions
+
+# These values provide default TTLs for HTTP responses that don't use caching headers.
+shindig.cache.http.defaultTtl=3600000
+shindig.cache.http.negativeCacheTtl=60000
+
+# A default refresh interval for XML files, since there is no natural way for developers to
+# specify this value, and most HTTP responses don't include good cache control headers.
+shindig.cache.xml.refreshInterval=300000
+
+# Add entries in the form shindig.cache.lru..capacity to specify capacities for different
+# caches when using the LruCacheProvider.
+# It is highly recommended that the EhCache implementation be used instead of the LRU cache.
+shindig.cache.lru.default.capacity=1000
+shindig.cache.lru.expressions.capacity=1000
+shindig.cache.lru.gadgetSpecs.capacity=1000
+shindig.cache.lru.messageBundles.capacity=1000
+shindig.cache.lru.httpResponses.capacity=10000
+
+# The location of the EhCache configuration file.
+shindig.cache.ehcache.config=res://org/apache/shindig/common/cache/ehcache/ehcacheConfig.xml
+
+# True to enable JMX integration with cache stats
+shindig.cache.ehcache.jmx.enabled=true
+
+# true to enable JMX stats.
+shindig.cache.ehcache.jmx.stats=true
+
+# true to skip expensive encoding detection.
+# if true, will only attempt to validate utf-8. Assumes all other encodings are ISO-8859-1.
+shindig.http.fast-encoding-detection=true
+
+# true to force strict content type checking for requests made to API endpoints.
+# E.g. require application/json for JSON-RPC
+shindig.api.disallow-unknown-content-types=true
Index: standard/src/main/webapp/resources/js/xwiki/opensocial/gadgets.js
===================================================================
--- standard/src/main/webapp/resources/js/xwiki/opensocial/gadgets.js (revision 0)
+++ standard/src/main/webapp/resources/js/xwiki/opensocial/gadgets.js (revision 0)
@@ -0,0 +1,804 @@
+/**
+ * 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 Open Gadget Container
+ */
+
+var gadgets = gadgets || {};
+
+gadgets.error = {};
+gadgets.error.SUBCLASS_RESPONSIBILITY = 'subclass responsibility';
+gadgets.error.TO_BE_DONE = 'to be done';
+
+gadgets.log = function(message) {
+ if (window.console && console.log) {
+ console.log(message);
+ } else {
+ var logEntry = document.createElement('div');
+ logEntry.className = 'gadgets-log-entry';
+ logEntry.innerHTML = message;
+ document.body.appendChild(logEntry);
+ }
+};
+
+/**
+ * Calls an array of asynchronous functions and calls the continuation
+ * function when all are done.
+ * @param {Array} functions Array of asynchronous functions, each taking
+ * one argument that is the continuation function that handles the result
+ * That is, each function is something like the following:
+ * function(continuation) {
+ * // compute result asynchronously
+ * continuation(result);
+ * }
+ * @param {Function} continuation Function to call when all results are in. It
+ * is pass an array of all results of all functions
+ * @param {Object} opt_this Optional object used as "this" when calling each
+ * function
+ */
+gadgets.callAsyncAndJoin = function(functions, continuation, opt_this) {
+ var pending = functions.length;
+ var results = [];
+ for (var i = 0; i < functions.length; i++) {
+ // we need a wrapper here because i changes and we need one index
+ // variable per closure
+ var wrapper = function(index) {
+ functions[index].call(opt_this, function(result) {
+ results[index] = result;
+ if (--pending === 0) {
+ continuation(results);
+ }
+ });
+ };
+ wrapper(i);
+ }
+};
+
+
+// ----------
+// Extensible
+
+gadgets.Extensible = function() {
+};
+
+/**
+ * Sets the dependencies.
+ * @param {Object} dependencies Object whose properties are set on this
+ * container as dependencies
+ */
+gadgets.Extensible.prototype.setDependencies = function(dependencies) {
+ for (var p in dependencies) {
+ this[p] = dependencies[p];
+ }
+};
+
+/**
+ * Returns a dependency given its name.
+ * @param {String} name Name of dependency
+ * @return {Object} Dependency with that name or undefined if not found
+ */
+gadgets.Extensible.prototype.getDependencies = function(name) {
+ return this[name];
+};
+
+
+
+// -------------
+// UserPrefStore
+
+/**
+ * User preference store interface.
+ * @constructor
+ */
+gadgets.UserPrefStore = function() {
+};
+
+/**
+ * Gets all user preferences of a gadget.
+ * @param {Object} gadget Gadget object
+ * @return {Object} All user preference of given gadget
+ */
+gadgets.UserPrefStore.prototype.getPrefs = function(gadget) {
+ throw Error(gadgets.error.SUBCLASS_RESPONSIBILITY);
+};
+
+/**
+ * Saves user preferences of a gadget in the store.
+ * @param {Object} gadget Gadget object
+ * @param {Object} prefs User preferences
+ */
+gadgets.UserPrefStore.prototype.savePrefs = function(gadget) {
+ throw Error(gadgets.error.SUBCLASS_RESPONSIBILITY);
+};
+
+
+// -------------
+// DefaultUserPrefStore
+
+/**
+ * User preference store implementation.
+ * TODO: Turn this into a real implementation that is production safe
+ * @constructor
+ */
+gadgets.DefaultUserPrefStore = function() {
+ gadgets.UserPrefStore.call(this);
+};
+gadgets.DefaultUserPrefStore.inherits(gadgets.UserPrefStore);
+
+gadgets.DefaultUserPrefStore.prototype.getPrefs = function(gadget) { };
+
+gadgets.DefaultUserPrefStore.prototype.savePrefs = function(gadget) { };
+
+
+// -------------
+// GadgetService
+
+/**
+ * Interface of service provided to gadgets for resizing gadgets,
+ * setting title, etc.
+ * @constructor
+ */
+gadgets.GadgetService = function() {
+};
+
+gadgets.GadgetService.prototype.setHeight = function(elementId, height) {
+ throw Error(gadgets.error.SUBCLASS_RESPONSIBILITY);
+};
+
+gadgets.GadgetService.prototype.setTitle = function(gadget, title) {
+ throw Error(gadgets.error.SUBCLASS_RESPONSIBILITY);
+};
+
+gadgets.GadgetService.prototype.setUserPref = function(id) {
+ throw Error(gadgets.error.SUBCLASS_RESPONSIBILITY);
+};
+
+
+// ----------------
+// IfrGadgetService
+
+/**
+ * Base implementation of GadgetService.
+ * @constructor
+ */
+gadgets.IfrGadgetService = function() {
+ gadgets.GadgetService.call(this);
+ gadgets.rpc.register('resize_iframe', this.setHeight);
+ gadgets.rpc.register('set_pref', this.setUserPref);
+ gadgets.rpc.register('set_title', this.setTitle);
+ gadgets.rpc.register('requestNavigateTo', this.requestNavigateTo);
+};
+
+gadgets.IfrGadgetService.inherits(gadgets.GadgetService);
+
+gadgets.IfrGadgetService.prototype.setHeight = function(height) {
+ if (height > gadgets.container.maxheight_) {
+ height = gadgets.container.maxheight_;
+ }
+
+ var element = document.getElementById(this.f);
+ if (element) {
+ element.style.height = height + 'px';
+ }
+};
+
+gadgets.IfrGadgetService.prototype.setTitle = function(title) {
+ var element = document.getElementById(this.f + '_title');
+ if (element) {
+ element.innerHTML = title.replace(/&/g, '&').replace(/ 0) {
+ url += '&appParams=' + encodeURIComponent(paramStr);
+ }
+ }
+
+ if (url && document.location.href.indexOf(url) == -1) {
+ document.location.href = url;
+ }
+};
+
+/**
+ * This is a silly implementation that will need to be overriden by almost all
+ * real containers.
+ * TODO: Find a better default for this function
+ *
+ * @param view The view name to get the url for
+ */
+gadgets.IfrGadgetService.prototype.getUrlForView = function(
+ view) {
+ if (view === 'canvas') {
+ return '/canvas';
+ } else if (view === 'profile') {
+ return '/profile';
+ } else {
+ return null;
+ }
+};
+
+gadgets.IfrGadgetService.prototype.getGadgetIdFromModuleId = function(
+ moduleId) {
+ // Quick hack to extract the gadget id from module id
+ return parseInt(moduleId.match(/_([0-9]+)$/)[1], 10);
+};
+
+
+// -------------
+// LayoutManager
+
+/**
+ * Layout manager interface.
+ * @constructor
+ */
+gadgets.LayoutManager = function() {
+};
+
+/**
+ * Gets the HTML element that is the chrome of a gadget into which the content
+ * of the gadget can be rendered.
+ * @param {Object} gadget Gadget instance
+ * @return {Object} HTML element that is the chrome for the given gadget
+ */
+gadgets.LayoutManager.prototype.getGadgetChrome = function(gadget) {
+ throw Error(gadgets.error.SUBCLASS_RESPONSIBILITY);
+};
+
+// -------------------
+// StaticLayoutManager
+
+/**
+ * Static layout manager where gadget ids have a 1:1 mapping to chrome ids.
+ * @constructor
+ */
+gadgets.StaticLayoutManager = function() {
+ gadgets.LayoutManager.call(this);
+};
+
+gadgets.StaticLayoutManager.inherits(gadgets.LayoutManager);
+
+/**
+ * Sets chrome ids, whose indexes are gadget instance ids (starting from 0).
+ * @param {Array} gadgetChromeIds Gadget id to chrome id map
+ */
+gadgets.StaticLayoutManager.prototype.setGadgetChromeIds =
+ function(gadgetChromeIds) {
+ this.gadgetChromeIds_ = gadgetChromeIds;
+};
+
+gadgets.StaticLayoutManager.prototype.getGadgetChrome = function(gadget) {
+ var chromeId = this.gadgetChromeIds_[gadget.id];
+ return chromeId ? document.getElementById(chromeId) : null;
+};
+
+
+// ----------------------
+// FloatLeftLayoutManager
+
+/**
+ * FloatLeft layout manager where gadget ids have a 1:1 mapping to chrome ids.
+ * @constructor
+ * @param {String} layoutRootId Id of the element that is the parent of all
+ * gadgets.
+ */
+gadgets.FloatLeftLayoutManager = function(layoutRootId) {
+ gadgets.LayoutManager.call(this);
+ this.layoutRootId_ = layoutRootId;
+};
+
+gadgets.FloatLeftLayoutManager.inherits(gadgets.LayoutManager);
+
+gadgets.FloatLeftLayoutManager.prototype.getGadgetChrome =
+ function(gadget) {
+ var layoutRoot = document.getElementById(this.layoutRootId_);
+ if (layoutRoot) {
+ var chrome = document.createElement('div');
+ chrome.className = 'gadgets-gadget-chrome';
+ chrome.style.cssFloat = 'left';
+ layoutRoot.appendChild(chrome);
+ return chrome;
+ } else {
+ return null;
+ }
+};
+
+
+// ------
+// Gadget
+
+/**
+ * Creates a new instance of gadget. Optional parameters are set as instance
+ * variables.
+ * @constructor
+ * @param {Object} params Parameters to set on gadget. Common parameters:
+ * "specUrl": URL to gadget specification
+ * "private": Whether gadget spec is accessible only privately, which means
+ * browser can load it but not gadget server
+ * "spec": Gadget Specification in XML
+ * "viewParams": a javascript object containing attribute value pairs
+ * for this gadgets
+ * "secureToken": an encoded token that is passed on the URL hash
+ * "hashData": Query-string like data that will be added to the
+ * hash portion of the URL.
+ * "specVersion": a hash value used to add a v= param to allow for better caching
+ * "title": the default title to use for the title bar.
+ * "height": height of the gadget
+ * "width": width of the gadget
+ * "debug": send debug=1 to the gadget server, gets us uncompressed
+ * javascript
+ */
+gadgets.Gadget = function(params) {
+ this.userPrefs_ = {};
+
+ if (params) {
+ for (var name in params) if (params.hasOwnProperty(name)) {
+ this[name] = params[name];
+ }
+ }
+ if (!this.secureToken) {
+ // Assume that the default security token implementation is
+ // in use on the server.
+ this.secureToken = 'XWiki.Alice:XWiki.Alice:appid:cont:url:0:default';
+ }
+};
+
+gadgets.Gadget.prototype.getUserPrefs = function() {
+ return this.userPrefs_;
+};
+
+gadgets.Gadget.prototype.setUserPrefs = function(userPrefs) {
+ this.userPrefs_ = userPrefs;
+ gadgets.container.userPrefStore.savePrefs(this);
+};
+
+gadgets.Gadget.prototype.getUserPref = function(name) {
+ return this.userPrefs_[name];
+};
+
+gadgets.Gadget.prototype.setUserPref = function(name, value) {
+ this.userPrefs_[name] = value;
+ gadgets.container.userPrefStore.savePrefs(this);
+};
+
+gadgets.Gadget.prototype.render = function(chrome) {
+ if (chrome) {
+ var gadget = this;
+ this.getContent(function(content) {
+ chrome.innerHTML = content;
+ window.frames[gadget.getIframeId()].location = gadget.getIframeUrl();
+ });
+ }
+};
+
+gadgets.Gadget.prototype.getContent = function(continuation) {
+ gadgets.callAsyncAndJoin([
+ this.getTitleBarContent, this.getUserPrefsDialogContent,
+ this.getMainContent], function(results) {
+ continuation(results.join(''));
+ }, this);
+};
+
+/**
+ * Gets title bar content asynchronously or synchronously.
+ * @param {Function} continuation Function that handles title bar content as
+ * the one and only argument
+ */
+gadgets.Gadget.prototype.getTitleBarContent = function(continuation) {
+ throw Error(gadgets.error.SUBCLASS_RESPONSIBILITY);
+};
+
+/**
+ * Gets user preferences dialog content asynchronously or synchronously.
+ * @param {Function} continuation Function that handles user preferences
+ * content as the one and only argument
+ */
+gadgets.Gadget.prototype.getUserPrefsDialogContent = function(continuation) {
+ throw Error(gadgets.error.SUBCLASS_RESPONSIBILITY);
+};
+
+/**
+ * Gets gadget content asynchronously or synchronously.
+ * @param {Function} continuation Function that handles gadget content as
+ * the one and only argument
+ */
+gadgets.Gadget.prototype.getMainContent = function(continuation) {
+ throw Error(gadgets.error.SUBCLASS_RESPONSIBILITY);
+};
+
+/*
+ * Gets additional parameters to append to the iframe url
+ * Override this method if you need any custom params.
+ */
+gadgets.Gadget.prototype.getAdditionalParams = function() {
+ return '';
+};
+
+
+// ---------
+// IfrGadget
+
+gadgets.IfrGadget = function(opt_params) {
+ gadgets.Gadget.call(this, opt_params);
+ this.serverBase_ = '../../../'; // default gadget server
+};
+
+gadgets.IfrGadget.inherits(gadgets.Gadget);
+
+gadgets.IfrGadget.prototype.GADGET_IFRAME_PREFIX_ = 'remote_iframe_';
+
+gadgets.IfrGadget.prototype.CONTAINER = 'default';
+
+gadgets.IfrGadget.prototype.cssClassGadget = 'gadgets-gadget';
+gadgets.IfrGadget.prototype.cssClassTitleBar = 'gadgets-gadget-title-bar';
+gadgets.IfrGadget.prototype.cssClassTitle = 'gadgets-gadget-title';
+gadgets.IfrGadget.prototype.cssClassTitleButtonBar =
+ 'gadgets-gadget-title-button-bar';
+gadgets.IfrGadget.prototype.cssClassGadgetUserPrefsDialog =
+ 'gadgets-gadget-user-prefs-dialog';
+gadgets.IfrGadget.prototype.cssClassGadgetUserPrefsDialogActionBar =
+ 'gadgets-gadget-user-prefs-dialog-action-bar';
+gadgets.IfrGadget.prototype.cssClassTitleButton = 'gadgets-gadget-title-button';
+gadgets.IfrGadget.prototype.cssClassGadgetContent = 'gadgets-gadget-content';
+gadgets.IfrGadget.prototype.rpcToken = (0x7FFFFFFF * Math.random()) | 0;
+gadgets.IfrGadget.prototype.rpcRelay = 'files/container/rpc_relay.html';
+
+gadgets.IfrGadget.prototype.getTitleBarContent = function(continuation) {
+ continuation('