Author: lindner
Date: Mon Aug  9 10:51:15 2010
New Revision: 983578

URL: http://svn.apache.org/viewvc?rev=983578&view=rev
Log:
SHINDIG-1401 | Patch from Vadim Gerasimov | Adding Wave feature to support Wave 
Gadget API

Added:
    shindig/trunk/extras/src/main/javascript/features-extras/wave/
    shindig/trunk/extras/src/main/javascript/features-extras/wave/base.js
    
shindig/trunk/extras/src/main/javascript/features-extras/wave/dynamic-width.js
    shindig/trunk/extras/src/main/javascript/features-extras/wave/externs.js
    
shindig/trunk/extras/src/main/javascript/features-extras/wave/fake_gadgets.js
    shindig/trunk/extras/src/main/javascript/features-extras/wave/feature.xml
    shindig/trunk/extras/src/main/javascript/features-extras/wave/participant.js
    shindig/trunk/extras/src/main/javascript/features-extras/wave/state.js
    shindig/trunk/extras/src/main/javascript/features-extras/wave/taming.js
    shindig/trunk/extras/src/main/javascript/features-extras/wave/util.js
    shindig/trunk/extras/src/main/javascript/features-extras/wave/wave.js
    shindig/trunk/extras/src/main/javascript/features-extras/wave/wave.ui.js
Modified:
    shindig/trunk/extras/src/main/javascript/features-extras/features.txt

Modified: shindig/trunk/extras/src/main/javascript/features-extras/features.txt
URL: 
http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/features.txt?rev=983578&r1=983577&r2=983578&view=diff
==============================================================================
--- shindig/trunk/extras/src/main/javascript/features-extras/features.txt 
(original)
+++ shindig/trunk/extras/src/main/javascript/features-extras/features.txt Mon 
Aug  9 10:51:15 2010
@@ -17,3 +17,4 @@
 #  under the License.
 
 features-extras/org.jquery.core-1.4.2/feature.xml
+features-extras/wave/feature.xml

Added: shindig/trunk/extras/src/main/javascript/features-extras/wave/base.js
URL: 
http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/wave/base.js?rev=983578&view=auto
==============================================================================
--- shindig/trunk/extras/src/main/javascript/features-extras/wave/base.js 
(added)
+++ shindig/trunk/extras/src/main/javascript/features-extras/wave/base.js Mon 
Aug  9 10:51:15 2010
@@ -0,0 +1,136 @@
+/**
+ * Copyright 2010 Google Inc.
+ *
+ * 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.
+ *
+ */
+
+/**
+ * @fileoverview Provides the top level wave object.
+ */
+
+/**
+ * @namespace This namespace defines the top level wave object
+ * within the Wave Gadgets API.
+ */
+var wave = wave || {};
+
+/**
+ * Constructs a callback given the provided callback
+ * and an optional context.
+ *
+ * @constructor
+ * @this {wave.Callback}
+ * @class This class is an immutable utility class for handlings callbacks
+ *     with variable arguments and an optional context.
+ * @param {?(function(wave.State=, Object.<string, string>=)|
+ *           function(Array.<wave.Participant>=)|
+ *           function(wave.Mode.<number>=)
+ *          )} callback A callback function
+ *     or null.
+ * @param {Object=} opt_context If context is specified, the method will be
+ *     called back in the context of that object (optional).
+ */
+wave.Callback = function(callback, opt_context) {
+  this.callback_ = callback;
+  this.context_ = opt_context || null;
+};
+
+/**
+ * Invokes the callback method with any arguments passed.
+ *
+ * @param {...} var_args
+ * @export
+ */
+wave.Callback.prototype.invoke = function(var_args) {
+  if (this.callback_) {
+    this.callback_.apply(this.context_, arguments);
+  }
+};
+
+/**
+ * @name wave.Mode
+ * @class Identifiers for wave modes exhibited by the blip containing
+ *     the gadget.
+ * @enum {number}
+ * @export
+ */
+wave.Mode = {
+  /**
+   * @member wave.Mode
+   * @constant
+   * @name UNKNOWN
+   * @desc The blip containing the gadget is in an unknown mode.
+   * In this case, you should not attempt to edit the blip.
+   */
+  UNKNOWN: 0,
+  /**
+   * @member wave.Mode
+   * @constant
+   * @name VIEW
+   * @desc The blip containing the gadget is in view, but not edit mode.
+   */
+  VIEW: 1,
+  /**
+   * @member wave.Mode
+   * @constant
+   * @name EDIT
+   * @desc Editing the gadget blip
+   */
+  EDIT: 2,
+  /**
+   * @member wave.Mode
+   * @constant
+   * @name DIFF_ON_OPEN
+   * @desc The blip containing the gadget has changed since the last time
+   * it was opened and the gadget should notify this change to the user.
+   */
+  DIFF_ON_OPEN: 3,
+  /**
+   * @member wave.Mode
+   * @constant
+   * @name PLAYBACK
+   * @desc The blip containing the gadget is in playback mode.
+   */
+  PLAYBACK: 4
+}
+
+wave.API_PARAM_ = "wave";
+
+wave.ID_PARAM_ = "waveId";
+
+wave.id_ = null;
+
+wave.viewer_ = null;
+
+wave.host_ = null;
+
+wave.participants_ = [];
+
+wave.participantMap_ = {};
+
+wave.participantCallback_ = new wave.Callback(null);
+
+wave.state_ = null;
+
+wave.stateCallback_ = new wave.Callback(null);
+
+wave.privateState_ = null;
+
+wave.privateStateCallback_ = new wave.Callback(null);
+
+wave.mode_ = null;
+
+wave.modeCallback_ = new wave.Callback(null);
+
+wave.inWaveContainer_ = false;

Added: 
shindig/trunk/extras/src/main/javascript/features-extras/wave/dynamic-width.js
URL: 
http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/wave/dynamic-width.js?rev=983578&view=auto
==============================================================================
--- 
shindig/trunk/extras/src/main/javascript/features-extras/wave/dynamic-width.js 
(added)
+++ 
shindig/trunk/extras/src/main/javascript/features-extras/wave/dynamic-width.js 
Mon Aug  9 10:51:15 2010
@@ -0,0 +1,176 @@
+/**
+ * Copyright 2010 Google Inc.
+ *
+ * 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.
+ *
+ */
+
+// TODO: Define a more convenient set of methods for iframe resizing in wave.
+
+/**
+ * @fileoverview This library augments gadgets.window with functionality
+ * to change the width of a gadget dynamically. Derived from the
+ * dynamic-height feature source code.
+ * See:
+ * 
http://svn.apache.org/repos/asf/shindig/trunk/features/src/main/javascript/features/dynamic-height/dynamic-height.js
+ */
+
+/**
+ * @static
+ * @class This namespace is used by the Gadgets API for the features it offers
+ * in all containers, including Wave. Those are documented here:
+ * http://code.google.com/apis/gadgets/docs/reference/
+ * @name gadgets
+ */
+
+/**
+ * @static
+ * @class This namespace is defined by the Gadgets API, and documented here:
+ * http://code.google.com/apis/gadgets/docs/reference/#gadgets.window <br>
+ * The Wave Gadgets API adds an additional method on top of the set documented
+ * there.
+ * @name gadgets.window
+ */
+gadgets.window = gadgets.window || {};
+
+// we wrap these in an anonymous function to avoid storing private data
+// as members of gadgets.window.
+(function() {
+
+  var oldWidth;
+
+  /**
+   * Parse out the value (specified in px) for a CSS attribute of an element.
+   *
+   * @param {Element} elem the element with the attribute to look for.
+   * @param {string} attr the CSS attribute name of interest.
+   * @returns {number} the value of the px attr of the elem.
+   * @private
+   */
+  function parseIntFromElemPxAttribute(elem, attr) {
+    var style = window.getComputedStyle(elem, "");
+    var value = style.getPropertyValue(attr);
+    value.match(/^([0-9]+)/);
+    return parseInt(RegExp.$1, 10);
+  }
+
+  /**
+   * For Webkit-based browsers, calculate the width of the gadget iframe by
+   * iterating through all elements in the gadget, starting with the body tag.
+   * It is not sufficient to only account body children elements, because
+   * CSS style position "float" may place a child element outside of the
+   * containing parent element. Not counting "float" elements may lead to
+   * undercounting.
+   *
+   * @returns {number} the width of the gadget.
+   * @private
+   */
+  function getWidthForWebkit() {
+    var result = 0;
+    var queue = [ document.body ];
+
+    while (queue.length > 0) {
+      var elem = queue.shift();
+      var children = elem.childNodes;
+
+      for (var i = 0; i < children.length; i++) {
+        var child = children[i];
+        if (typeof child.offsetLeft !== 'undefined' &&
+            typeof child.scrollWidth !== 'undefined') {
+          // scrollHeight already accounts for border-bottom, padding-bottom.
+          var right = child.offsetLeft + child.scrollWidth +
+              parseIntFromElemPxAttribute(child, "margin-right");
+          result = Math.max(result, right);
+        }
+        queue.push(child);
+      }
+    }
+
+    // Add border, padding and margin of the containing body.
+    return result
+        + parseIntFromElemPxAttribute(document.body, "border-right")
+        + parseIntFromElemPxAttribute(document.body, "margin-right")
+        + parseIntFromElemPxAttribute(document.body, "padding-right");
+  }
+
+  /**
+   * Adjusts the gadget width
+   * @param {number=} opt_width An optional preferred width in pixels. If not
+   *     specified, will attempt to fit the gadget to its content.
+   * @member gadgets.window
+   */
+  gadgets.window.adjustWidth = function(opt_width) {
+    var newWidth = parseInt(opt_width, 10);
+    var widthAutoCalculated = false;
+    if (isNaN(newWidth)) {
+      widthAutoCalculated = true;
+
+      // Resize the gadget to fit its content.
+
+      // Get the width of the viewport
+      var vw = gadgets.window.getViewportDimensions().width;
+      var body = document.body;
+      var docEl = document.documentElement;
+      if (document.compatMode === 'CSS1Compat' && docEl.scrollWidth) {
+        // In Strict mode:
+        // The inner content height is contained in either:
+        //    document.documentElement.scrollWidth
+        //    document.documentElement.offsetWidth
+        // Based on studying the values output by different browsers,
+        // use the value that's NOT equal to the viewport width found above.
+        newWidth = docEl.scrollWidth !== vw ?
+                     docEl.scrollWidth : docEl.offsetWidth;
+      } else if (navigator.userAgent.indexOf('AppleWebKit') >= 0) {
+        // In Webkit:
+        // Property scrollWidth and offsetWidth will only increase in value.
+        // This will incorrectly calculate reduced width of a gadget
+        // (ie: made smaller).
+        newWidth = getWidthForWebkit();
+      } else if (body && docEl) {
+        // In Quirks mode:
+        // documentElement.clientWidth is equal to documentElement.offsetWidth
+        // except in IE.  In most browsers, document.documentElement can be 
used
+        // to calculate the inner content width.
+        // However, in other browsers (e.g. IE), document.body must be used
+        // instead.  How do we know which one to use?
+        // If document.documentElement.clientWidth does NOT equal
+        // document.documentElement.offsetWidth, then use document.body.
+        var sw = docEl.scrollWidth;
+        var ow = docEl.offsetWidth;
+        if (docEl.clientWidth !== ow) {
+          sw = body.scrollWidth;
+          ow = body.offsetWidth;
+        }
+
+        // Detect whether the inner content width is bigger or smaller
+        // than the bounding box (viewport).  If bigger, take the larger
+        // value.  If smaller, take the smaller value.
+        if (sw > vw) {
+          // Content is larger
+          newWidth = sw > ow ? sw : ow;
+        } else {
+          // Content is smaller
+          newWidth = sw < ow ? sw : ow;
+        }
+      }
+    }
+
+    // Only make the RPC call if width has changed
+    if (newWidth !== oldWidth &&
+        !isNaN(newWidth) &&
+        !(widthAutoCalculated && newWidth === 0)) {
+      oldWidth = newWidth;
+      gadgets.rpc.call(null, "setIframeWidth", null, newWidth);
+    }
+  };
+}());

Added: shindig/trunk/extras/src/main/javascript/features-extras/wave/externs.js
URL: 
http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/wave/externs.js?rev=983578&view=auto
==============================================================================
--- shindig/trunk/extras/src/main/javascript/features-extras/wave/externs.js 
(added)
+++ shindig/trunk/extras/src/main/javascript/features-extras/wave/externs.js 
Mon Aug  9 10:51:15 2010
@@ -0,0 +1,25 @@
+/**
+ * Copyright 2010 Google Inc.
+ *
+ * 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.
+ *
+ */
+
+/**
+ * @fileoverview Contains variable declarations so that the jscompiler
+ * will not report errors on these objects.
+ */
+
+var gadgets;
+gadgets.rpc;
+gadgets.rpc.call = function(parent, serviceName, opt_callback, opt_params) {};

Added: 
shindig/trunk/extras/src/main/javascript/features-extras/wave/fake_gadgets.js
URL: 
http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/wave/fake_gadgets.js?rev=983578&view=auto
==============================================================================
--- 
shindig/trunk/extras/src/main/javascript/features-extras/wave/fake_gadgets.js 
(added)
+++ 
shindig/trunk/extras/src/main/javascript/features-extras/wave/fake_gadgets.js 
Mon Aug  9 10:51:15 2010
@@ -0,0 +1,50 @@
+/**
+ * Copyright 2010 Google Inc.
+ *
+ * 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.
+ *
+ */
+
+/**
+ * @fileoverview Provides stubs and fakes for the gadgets namespace
+ * that is used in the API. This is used by jsunit tests.
+ */
+var gadgets = gadgets || {};
+
+gadgets.util = {};
+
+gadgets.util.registerOnLoadHandler = function(callback) {
+  callback.call();
+};
+
+gadgets.util.getUrlParameters = function() {
+  var params = {};
+  var waveParamName = 'wave';
+  params[waveParamName] = true;
+  params.hasOwnProperty = function(key) {
+    return !!this[key];
+  }
+  return params;
+};
+
+gadgets.json = {};
+
+gadgets.json.parse = function(data) {
+  return data;
+};
+
+gadgets.rpc = {};
+
+gadgets.rpc.register = function() {};
+
+gadgets.rpc.call = function() {};

Added: shindig/trunk/extras/src/main/javascript/features-extras/wave/feature.xml
URL: 
http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/wave/feature.xml?rev=983578&view=auto
==============================================================================
--- shindig/trunk/extras/src/main/javascript/features-extras/wave/feature.xml 
(added)
+++ shindig/trunk/extras/src/main/javascript/features-extras/wave/feature.xml 
Mon Aug  9 10:51:15 2010
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<!--
+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.
+-->
+<feature>
+  <name>wave</name>
+  <dependency>dynamic-height</dependency>
+  <dependency>locked-domain</dependency>
+  <dependency>rpc</dependency>
+  <gadget>
+    <script src="base.js"/>
+    <script src="dynamic-width.js"/>
+    <script src="participant.js"/>
+    <script src="state.js"/>
+    <script src="taming.js"/>
+    <script src="util.js"/>
+    <script src="wave.js"/>
+    <script src="wave.ui.js"/>
+  </gadget>
+</feature>

Added: 
shindig/trunk/extras/src/main/javascript/features-extras/wave/participant.js
URL: 
http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/wave/participant.js?rev=983578&view=auto
==============================================================================
--- 
shindig/trunk/extras/src/main/javascript/features-extras/wave/participant.js 
(added)
+++ 
shindig/trunk/extras/src/main/javascript/features-extras/wave/participant.js 
Mon Aug  9 10:51:15 2010
@@ -0,0 +1,85 @@
+/**
+ * Copyright 2010 Google Inc.
+ *
+ * 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.
+ *
+ */
+
+/**
+ * @fileoverview Provides classes for defining and managing participants
+ * on a wave.
+ */
+
+/**
+ * Creates a new participant.
+ *
+ * @class This class specifies participants on a wave.
+ * @constructor
+ * Participant information can be dynamically updated (except for  IDs).
+ * This includes the thumbnail URL, display name, and  any future extensions to
+ * the participant. Instead of storing this information, gadgets should update
+ * displayed participant data each time they receive a participant callback.
+ * @this {wave.Participant}
+ * @param {string=} id Participant id.
+ * @param {string=} displayName Participant display name.
+ * @param {string=} thumbnailUrl Profile thumbnail URL.
+ */
+wave.Participant = function(id, displayName, thumbnailUrl) {
+  this.id_ = id || '';
+  this.displayName_ = displayName || '';
+  this.thumbnailUrl_ = thumbnailUrl || '';
+};
+
+/**
+ * Gets the unique identifier of this participant.
+ *
+ * @return {string} The participant's id.
+ * @export
+ */
+wave.Participant.prototype.getId = function() {
+  return this.id_;
+};
+
+/**
+ * Gets the human-readable display name of this participant.
+ *
+ * @return {string} The participant's human-readable display name.
+ * @export
+ */
+wave.Participant.prototype.getDisplayName = function() {
+  return this.displayName_;
+};
+
+/**
+ * Gets the url of the thumbnail image for this participant.
+ *
+ * @return {string} The participant's thumbnail image url.
+ * @export
+ */
+wave.Participant.prototype.getThumbnailUrl = function() {
+  return this.thumbnailUrl_;
+};
+
+/**
+ * Constructs a Participant object from JSON data.
+ *
+ * @param {!Object.<string, string>} json JSON object.
+ * @return {wave.Participant}
+ */
+wave.Participant.fromJson_ = function(json) {
+  var p = new wave.Participant();
+  p.id_ = json['id'];
+  p.displayName_ = json['displayName'];
+  p.thumbnailUrl_ = json['thumbnailUrl'];
+  return p;
+};

Added: shindig/trunk/extras/src/main/javascript/features-extras/wave/state.js
URL: 
http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/wave/state.js?rev=983578&view=auto
==============================================================================
--- shindig/trunk/extras/src/main/javascript/features-extras/wave/state.js 
(added)
+++ shindig/trunk/extras/src/main/javascript/features-extras/wave/state.js Mon 
Aug  9 10:51:15 2010
@@ -0,0 +1,167 @@
+/**
+ * Copyright 2010 Google Inc.
+ *
+ * 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.
+ *
+ */
+
+/**
+ * @fileoverview Provides classes for defining and managing the
+ * synchronized gadget state.
+ */
+
+/**
+ * Creates a new state object to hold properties of the gadget.
+ *
+ * @constructor
+ * @class This class contains state properties of the Gadget.
+ * @this {wave.State}
+ * @param {string=} opt_rpc rpc name
+ * @export
+ */
+wave.State = function(opt_rpc) {
+  this.setState_(null);
+  this.rpc_ = opt_rpc === undefined ? 'wave_gadget_state' : opt_rpc;
+};
+
+/**
+ * Retrieve a value from the synchronized state.
+ * As of now, get always returns a string. This will change at some point
+ * to return whatever was set.
+ *
+ * @param {string} key Value for the specified key to retrieve.
+ * @param {?string=} opt_default Optional default value if non-existant
+ *     (optional).
+ * @return {?string} Object for the specified key or null if not found.
+ * @export
+ */
+wave.State.prototype.get = function(key, opt_default) {
+  if (key in this.state_) {
+    return this.state_[key];
+  }
+  return opt_default === undefined ? null: opt_default;
+};
+
+/**
+ * Retrieve the valid keys for the synchronized state.
+ *
+ * @return {Array.<string>} set of keys
+ * @export
+ */
+wave.State.prototype.getKeys = function() {
+  var keys = [];
+  for (var key in this.state_) {
+    keys.push(key);
+  }
+  return keys;
+};
+
+/**
+ * Updates the state delta. This is an asynchronous call that
+ * will update the state and not take effect immediately. Creating
+ * any key with a null value will attempt to delete the key.
+ *
+ * @param {!Object.<string, ?string>} delta Map of key-value pairs representing
+ * a delta of keys to update.
+ * @export
+ */
+wave.State.prototype.submitDelta = function(delta) {
+  gadgets.rpc.call(null, this.rpc_, null, delta);
+};
+
+/**
+ * Submits delta that contains only one key-value pair. Note that if value is
+ * null the key will be removed from the state.
+ * See submitDelta(delta) for semantic details.
+ *
+ * @param {string} key
+ * @param {?string} value
+ * @export
+ */
+wave.State.prototype.submitValue = function(key, value) {
+  var delta = {};
+  delta[key] = value;
+  this.submitDelta(delta);
+};
+
+/**
+ * Submits a delta to remove all key-values in the state.
+ *
+ * @export
+ */
+wave.State.prototype.reset = function() {
+  var delta = {};
+  for (var key in this.state_) {
+    delta[key] = null;
+  }
+  this.submitDelta(delta);
+};
+
+/**
+ * Pretty prints the current state object. Note this is a debug method
+ * only.
+ *
+ * @return {string} The stringified state.
+ * @export
+ */
+wave.State.prototype.toString = function() {
+  return wave.util.printJson(this.state_, true);
+};
+
+/**
+ * Set the state object to the given value.
+ *
+ * @param {Object.<string, string>} state
+ */
+wave.State.prototype.setState_ = function(state) {
+  this.state_ = state || {};
+};
+
+/**
+ * Calculate a delta object that would turn this state into the state given
+ * in the parameter when applied to this state.
+ *
+ * @param {!Object.<string, string>} state
+ * @return {!Object.<string, string>} delta
+ */
+wave.State.prototype.calculateDelta_ = function(state) {
+  var delta = {};
+  for (var key in state) {
+    var hasKey = this.state_.hasOwnProperty(key);
+    if (!hasKey || (this.state_[key] != state[key])) {
+      delta[key] = state[key];
+    }
+  }
+  for (var key in this.state_) {
+    if (!state.hasOwnProperty(key)) {
+      delta[key] = null;
+    }
+  }
+  return delta;
+};
+
+/**
+ * Apply the given delta object to this state.
+ *
+ * @param {!Object.<string, string>} delta
+ */
+wave.State.prototype.applyDelta_ = function(delta) {
+  this.state_ = this.state_ || {};
+  for (var key in delta) {
+    if (delta[key] != null) {
+      this.state_[key] = delta[key];
+    } else {
+      delete this.state_[key];
+    }
+  }
+};

Added: shindig/trunk/extras/src/main/javascript/features-extras/wave/taming.js
URL: 
http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/wave/taming.js?rev=983578&view=auto
==============================================================================
--- shindig/trunk/extras/src/main/javascript/features-extras/wave/taming.js 
(added)
+++ shindig/trunk/extras/src/main/javascript/features-extras/wave/taming.js Mon 
Aug  9 10:51:15 2010
@@ -0,0 +1,92 @@
+/**
+ * Copyright 2010 Google Inc.
+ *
+ * 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.
+ *
+ */
+
+/**
+ * @fileoverview  Tame and expose wave.* API to cajoled gadgets.
+ */
+
+var tamings___ = tamings___ || [];
+var caja___;
+var ___;
+tamings___.push(function(imports) {
+  // wave.Mode is an object literal that holds only constants
+  ___.grantRead(wave, 'Mode');
+
+  /**
+   * The following taming of wave.Callback and wave.Callback.invoke
+   * is needed because:
+   *   - wave.Callback is exposed to cajoled code
+   *   - wave.Callback.invoke is exposed to cajoled code
+   *   - the wave api invokes some callbacks constructed by itself
+   *     and others constructed by cajoled code
+   */
+  function SafeCallback(tameCallback, opt_tameContext) {
+   var okCallback = {apply: ___.markFuncFreeze(function(ignored, args) {
+     return ___.callPub(tameCallback, 'apply', [opt_tameContext, args]);
+   })};
+   return new wave.Callback(okCallback, ___.USELESS);
+  }
+
+  SafeCallback.prototype = wave.Callback.prototype;
+  wave.Callback.prototype.constructor = SafeCallback;
+  ___.markCtor(SafeCallback, Object, 'Callback');
+  ___.primFreeze(SafeCallback);
+  ___.tamesTo(wave.Callback, SafeCallback);
+
+  ___.handleGenericMethod(SafeCallback.prototype, 'invoke', function(var_args) 
{
+   return ___.callPub(this.callback_, 'apply', [___.tame(this.context_),
+                                                Array.slice(arguments, 0)]);
+  });
+
+  caja___.whitelistCtors([
+    [wave, 'Participant', Object],
+    [wave, 'State', Object]
+  ]);
+
+  caja___.whitelistMeths([
+    [wave.Participant, 'getDisplayName'],
+    [wave.Participant, 'getId'],
+    [wave.Participant, 'getThumbnailUrl'],
+
+    [wave.State, 'get'],
+    [wave.State, 'getKeys'],
+    [wave.State, 'reset'],
+    [wave.State, 'submitDelta'],
+    [wave.State, 'submitValue'],
+    [wave.State, 'toString']
+  ]);
+
+  caja___.whitelistFuncs([
+    [wave, 'getHost'],
+    [wave, 'getMode'],
+    [wave, 'getParticipantById'],
+    [wave, 'getParticipants'],
+    [wave, 'getState'],
+    [wave, 'getTime'],
+    [wave, 'getViewer'],
+    [wave, 'isInWaveContainer'],
+    [wave, 'log'],
+    [wave, 'setModeCallback'],
+    [wave, 'setParticipantCallback'],
+    [wave, 'setStateCallback'],
+
+    [wave.util, 'printJson']
+  ]);
+
+  imports.outers.wave = ___.tame(wave);
+  ___.grantRead(imports.outers, 'wave');
+});

Added: shindig/trunk/extras/src/main/javascript/features-extras/wave/util.js
URL: 
http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/wave/util.js?rev=983578&view=auto
==============================================================================
--- shindig/trunk/extras/src/main/javascript/features-extras/wave/util.js 
(added)
+++ shindig/trunk/extras/src/main/javascript/features-extras/wave/util.js Mon 
Aug  9 10:51:15 2010
@@ -0,0 +1,92 @@
+/**
+ * Copyright 2010 Google Inc.
+ *
+ * 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.
+ *
+ */
+
+/**
+ * @fileoverview Provides utility methods.
+ */
+
+/**
+ * @namespace This namespace defines utility methods for use within
+ * the Wave Gadgets API.
+ */
+wave.util = wave.util || {};
+
+wave.util.SPACES_ = '                                                 ';
+
+wave.util.toSpaces_ = function(tabs) {
+  return wave.util.SPACES_.substring(0, tabs * 2);
+}
+
+wave.util.isArray_ = function(obj) {
+  try {
+    return obj && typeof(obj.length) == 'number';
+  } catch (e) {
+    return false;
+  }
+};
+
+/**
+ * Outputs JSON objects in text format. Optionally pretty print.
+ *
+ * @param {Object} obj The object to print.
+ * @param {boolean=} opt_pretty If true, pretty print (optional).
+ * @param {number=} opt_tabs Number of tabs to start indent.
+ * @return {string} The formatted object in text.
+ */
+wave.util.printJson = function(obj, opt_pretty, opt_tabs) {
+  if (!obj || typeof(obj.valueOf()) != 'object') {
+    if (typeof(obj) == 'string') {
+      return '\'' + obj + '\'';
+    }
+    else if (obj instanceof Function) {
+      return '[function]';
+    }
+    return '' + obj;
+  }
+  var text = [];
+  var isArray = wave.util.isArray_(obj);
+  var brace = isArray ? '[]' : '{}';
+  var newline = opt_pretty ? '\n' : '';
+  var spacer = opt_pretty ? ' ' : '';
+  var i = 0;
+  var tabs = opt_tabs || 1;
+  if (!opt_pretty) {
+    tabs = 0;
+  }
+  text.push(brace.charAt(0));
+  for (var key in obj) {
+    var value = obj[key];
+    if (i++ > 0) {
+      text.push(', ');
+    }
+    if (isArray) {
+      text.push(wave.util.printJson(value, opt_pretty, tabs + 1));
+    } else {
+      text.push(newline);
+      text.push(wave.util.toSpaces_(tabs));
+      text.push(key + ': ');
+      text.push(spacer);
+      text.push(wave.util.printJson(value, opt_pretty, tabs + 1));
+    }
+  }
+  if (!isArray) {
+    text.push(newline);
+    text.push(wave.util.toSpaces_(tabs - 1));
+  }
+  text.push(brace.charAt(1));
+  return text.join('');
+};

Added: shindig/trunk/extras/src/main/javascript/features-extras/wave/wave.js
URL: 
http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/wave/wave.js?rev=983578&view=auto
==============================================================================
--- shindig/trunk/extras/src/main/javascript/features-extras/wave/wave.js 
(added)
+++ shindig/trunk/extras/src/main/javascript/features-extras/wave/wave.js Mon 
Aug  9 10:51:15 2010
@@ -0,0 +1,388 @@
+/**
+ * Copyright 2010 Google Inc.
+ *
+ * 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.
+ *
+ */
+
+/**
+ * @fileoverview Provides access to the wave API in gadgets.
+ *
+ * Clients can access the wave API by the wave object.
+ *
+ * Example:
+ * <pre>
+ *   var state;
+ *   var privateState;
+ *   var viewer;
+ *   var participants;
+ *   if (wave && wave.isInWaveContainer()) {
+ *     state = wave.getState();
+ *     privateState = wave.getPrivateState();
+ *     viewer = wave.getViewer();
+ *     participants = wave.getParticipants();
+ *   }
+ * </pre>
+ */
+
+/**
+ * Checks the wave parameter to determine whether the gadget container claims
+ * to be wave-aware.
+ */
+wave.checkWaveContainer_ = function() {
+  var params = gadgets.util.getUrlParameters();
+  wave.inWaveContainer_ =
+      (params.hasOwnProperty(wave.API_PARAM_) && params[wave.API_PARAM_]);
+  wave.id_ = (params.hasOwnProperty(wave.ID_PARAM_) && params[wave.ID_PARAM_]);
+};
+
+/**
+ * Indicates whether the gadget runs inside a wave container.
+ *
+ * @return {boolean} whether the gadget runs inside a wave container
+ * @export
+ */
+wave.isInWaveContainer = function() {
+  return wave.inWaveContainer_;
+};
+
+/**
+ * Participant callback relay.
+ *
+ * @param {{myId: string, authorId: string,
+ *          participants: Object.<string, string>}} data participants object.
+ */
+wave.receiveWaveParticipants_ = function(data) {
+  wave.viewer_ = null;
+  wave.host_ = null;
+  wave.participants_ = [];
+  wave.participantMap_ = {};
+  var myId = data['myId'];
+  var hostId = data['authorId'];
+  var participants = data['participants'];
+  for (var id in participants) {
+    var p = wave.Participant.fromJson_(participants[id]);
+    if (id == myId) {
+      wave.viewer_ = p;
+    }
+    if (id == hostId) {
+      wave.host_ = p;
+    }
+    wave.participants_.push(p);
+    wave.participantMap_[id] = p;
+  }
+  if (!wave.viewer_ && myId) {
+    // In this case, the viewer has not yet been added to the participant
+    // list, and so did not have a complete Participant object created.
+    // Let's create it here.
+    var p = new wave.Participant(myId, myId);
+    wave.viewer_ = p;
+    wave.participants_.push(p);
+    wave.participantMap_[myId] = p;
+  }
+  wave.participantCallback_.invoke(wave.participants_);
+};
+
+/**
+ * State callback relay.
+ *
+ * @param {!Object.<string, string>} data raw state data object.
+ */
+wave.receiveState_ = function(data) {
+  wave.state_ = wave.state_ || new wave.State('wave_gadget_state');
+  var delta = wave.state_.calculateDelta_(data);
+  wave.state_.setState_(data);
+  wave.stateCallback_.invoke(wave.state_, delta);
+};
+
+/**
+ * Private state callback relay.
+ *
+ * @param {!Object.<string, string>} data raw state data object.
+ */
+wave.receivePrivateState_ = function(data) {
+  wave.privateState_ =
+      wave.privateState_ || new wave.State('wave_private_gadget_state');
+  var delta = wave.privateState_.calculateDelta_(data);
+  wave.privateState_.setState_(data);
+  wave.privateStateCallback_.invoke(wave.privateState_, delta);
+};
+
+/**
+ * State delta callback relay.
+ *
+ * @param {!Object.<string, string>} delta the delta object.
+ */
+wave.receiveStateDelta_ = function(delta) {
+  wave.state_ = wave.state_ || new wave.State('wave_gadget_state');
+  wave.state_.applyDelta_(delta);
+  wave.stateCallback_.invoke(wave.state_, delta);
+};
+
+/**
+ * Private state delta callback relay.
+ *
+ * @param {!Object.<string, string>} delta the delta object.
+ */
+wave.receivePrivateStateDelta_ = function(delta) {
+  wave.privateState_ =
+      wave.privateState_ || new wave.State('wave_private_gadget_state');
+  wave.privateState_.applyDelta_(delta);
+  wave.privateStateCallback_.invoke(wave.privateState_, delta);
+};
+
+/**
+ * Mode callback relay.
+ *
+ * @param {!Object.<string, string>} data raw mode object.
+ */
+wave.receiveMode_ = function(data) {
+  wave.mode_ = data || {};
+  wave.modeCallback_.invoke(wave.getMode());
+};
+
+/**
+ * Get the <code>Participant</code> whose client renders this gadget.
+ *
+ * @return {wave.Participant} the viewer (null if not known)
+ * @export
+ */
+wave.getViewer = function() {
+  return wave.viewer_;
+};
+
+/**
+ * Returns the <code>Participant</code> who added this gadget
+ * to the blip.
+ * Note that the host may no longer be in the participant list.
+ *
+ * @return {wave.Participant} host (null if not known)
+ * @export
+ */
+wave.getHost = function() {
+  return wave.host_;
+};
+
+/**
+ * Returns a list of <code>Participant</code>s on the Wave.
+ *
+ * @return {Array.<wave.Participant>} Participant list.
+ * @export
+ */
+wave.getParticipants = function() {
+  return wave.participants_;
+};
+
+/**
+ * Returns a <code>Participant</code> with the given id.
+ *
+ * @param {string} id The id of the participant to retrieve.
+ * @return {wave.Participant} The participant with the given id.
+ * @export
+ */
+wave.getParticipantById = function(id) {
+  return wave.participantMap_[id];
+};
+
+/**
+ * Returns the gadget state as a <code>wave.State</code> object.
+ *
+ * @return {wave.State} gadget state (null if not known)
+ * @export
+ */
+wave.getState = function() {
+  return wave.state_;
+};
+
+/**
+ * Returns the private gadget state as a <code>wave.State</code> object.
+ *
+ * @return {wave.State} private gadget state (null if not known)
+ * @export
+ */
+wave.getPrivateState = function() {
+  return wave.privateState_;
+};
+
+/**
+ * Returns the gadget <code>wave.Mode</code>.
+ *
+ * @return {wave.Mode} gadget mode.
+ * @export
+ */
+wave.getMode = function() {
+  if (wave.mode_) {
+    var playback = wave.mode_['${playback}'];
+    var edit = wave.mode_['${edit}'];
+    if ((playback != null) && (edit != null)) {
+      if (playback == '1') {
+        return wave.Mode.PLAYBACK;
+      } else if (edit == '1') {
+        return wave.Mode.EDIT;
+      } else {
+        return wave.Mode.VIEW;
+      }
+    }
+  }
+  return wave.Mode.UNKNOWN;
+};
+
+/**
+ * Returns the playback state of the wave/wavelet/gadget.
+ * Note: For compatibility UNKNOWN mode identified as PLAYBACK.
+ *
+ * @return {boolean} whether the gadget is in the playback state
+ * @deprecated Use wave.getMode().
+ * @export
+ */
+wave.isPlayback = function() {
+  var mode = wave.getMode();
+  return (mode == wave.Mode.PLAYBACK) || (mode == wave.Mode.UNKNOWN);
+};
+
+/**
+ * Sets the gadget state update callback. If the state is already received
+ * from the container, the callback is invoked immediately to report the
+ * current gadget state. Only invoke callback can be defined. Consecutive calls
+ * would remove the old callback and set the new one.
+ *
+ * @param {function(wave.State=, Object.<string, string>=)} callback function
+ * @param {Object=} opt_context the object that receives the callback
+ * @export
+ */
+wave.setStateCallback = function(callback, opt_context) {
+  wave.stateCallback_ = new wave.Callback(callback, opt_context);
+  if (wave.state_) {
+    wave.stateCallback_.invoke(wave.state_, wave.state_.state_);
+  }
+};
+
+/**
+ * Sets the private gadget state update callback. Works similarly to
+ * setStateCallback but handles the private state events.
+ *
+ * @param {function(wave.State=, Object.<string, string>=)} callback function
+ * @param {Object=} opt_context the object that receives the callback
+ * @export
+ */
+wave.setPrivateStateCallback = function(callback, opt_context) {
+  wave.privateStateCallback_ = new wave.Callback(callback, opt_context);
+  if (wave.privateState_) {
+    wave.privateStateCallback_.invoke(
+        wave.privateState_, wave.privateState_.state_);
+  }
+};
+
+/**
+ * Sets the participant update callback. If the participant information is
+ * already received, the callback is invoked immediately to report the
+ * current participant information. Only one callback can be defined.
+ * Consecutive calls would remove old callback and set the new one.
+ *
+ * @param {function(Array.<wave.Participant>)} callback function
+ * @param {Object=} [opt_context] the object that receives the callback
+ * @export
+ */
+wave.setParticipantCallback = function(callback, opt_context) {
+  wave.participantCallback_ = new wave.Callback(callback, opt_context);
+  if (wave.participants_) {
+    wave.participantCallback_.invoke(wave.participants_);
+  }
+};
+
+/**
+ * Sets the mode change callback.
+ *
+ * @param {function(wave.Mode)} callback function
+ * @param {Object=} [opt_context] the object that receives the callback
+ * @export
+ */
+wave.setModeCallback = function(callback, opt_context) {
+  wave.modeCallback_ = new wave.Callback(callback, opt_context);
+  if (wave.mode_) {
+    wave.modeCallback_.invoke(wave.getMode());
+  }
+};
+
+/**
+ * Retrieves the current time of the viewer.
+ *
+ * TODO: Define the necessary gadget <-> container communication and
+ * implement playback time.
+ *
+ * @return {number} The gadget time.
+ * @export
+ */
+wave.getTime = function() {
+  // For now just return the current time.
+  return new Date().getTime();
+};
+
+/**
+ * Requests the container to output a log message.
+ *
+ * @param {string} message The message to output to the log.
+ * @export
+ */
+wave.log = function(message) {
+  gadgets.rpc.call(null, 'wave_log', null, message || '');
+};
+
+/**
+ * Requests the container to update the snippet visible in wave digest.
+ *
+ * @param {string} snippet Snippet to associate with the gadget.
+ * @export
+ */
+wave.setSnippet = function(snippet) {
+  gadgets.rpc.call(null, 'set_snippet', null, snippet || '');
+};
+
+/**
+ * Returns serialized wave ID or null if not known.
+ *
+ * @return {?string} Serialized wave ID.
+ * @export
+ */
+wave.getWaveId = function() {
+  return wave.id_;
+};
+
+/**
+ * Internal initialization.
+ */
+wave.internalInit_ = function() {
+  wave.checkWaveContainer_();
+  if (wave.isInWaveContainer()) {
+    gadgets.rpc.register('wave_participants', wave.receiveWaveParticipants_);
+    gadgets.rpc.register('wave_gadget_state', wave.receiveState_);
+    gadgets.rpc.register('wave_state_delta', wave.receiveStateDelta_);
+    gadgets.rpc.register(
+        'wave_private_gadget_state', wave.receivePrivateState_);
+    gadgets.rpc.register(
+        'wave_private_state_delta', wave.receivePrivateStateDelta_);
+    gadgets.rpc.register('wave_gadget_mode', wave.receiveMode_);
+    gadgets.rpc.call(null, 'wave_enable', null, '1.0');
+  }
+};
+
+/**
+ * Sets up the wave gadget variables and callbacks.
+ */
+(wave.init_ = function() {
+  if (window['gadgets']) {
+    gadgets.util.registerOnLoadHandler(function() {
+      wave.internalInit_();
+    });
+  }
+})();

Added: shindig/trunk/extras/src/main/javascript/features-extras/wave/wave.ui.js
URL: 
http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/wave/wave.ui.js?rev=983578&view=auto
==============================================================================
--- shindig/trunk/extras/src/main/javascript/features-extras/wave/wave.ui.js 
(added)
+++ shindig/trunk/extras/src/main/javascript/features-extras/wave/wave.ui.js 
Mon Aug  9 10:51:15 2010
@@ -0,0 +1,136 @@
+/**
+ * Copyright 2010 Google Inc.
+ *
+ * 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.
+ *
+ */
+
+/**
+ * @fileoverview UI extension to the basic wave gadget API.
+ *
+ * wave.ui allows gadgets to get the look and feel of other
+ * wave elements.
+ *
+ * Example: turn a link into a wave button
+ * <pre>
+ *   <a id="butTest" href="#" onclick="alert('hi!')">Text</a>
+ *
+ *   <script>
+ *     wave.ui.makeButton(document.getElementById('butTest'));
+ *   </script>
+ * </pre>
+ */
+
+if (typeof wave == "undefined") {
+  wave = {};
+};
+
+if (typeof wave.ui == "undefined") {
+/**
+ * @namespace This namespace defines methods for creating a wave
+ * look & feel inside a gadget.
+ */
+  wave.ui = {};
+};
+
+wave.ui.BASE = 'http://wave-api.appspot.com/public/';
+
+wave.ui.cssLoaded = false;
+
+/**
+ * Loads a CSS with Wave-like styles into the gadget, including font
+ * properties, link properties, and the properties for the wave-styled
+ * button, dialog, and frame.
+ *
+ * @export
+ */
+wave.ui.loadCss = function() {
+  if (wave.ui.cssLoaded) {
+    return;
+  }
+  wave.ui.cssLoaded = true;
+  var fileref = document.createElement("link")
+  fileref.setAttribute("rel", "stylesheet")
+  fileref.setAttribute("type", "text/css")
+  fileref.setAttribute("href", wave.ui.BASE + "wave.ui.css")
+  document.getElementsByTagName("head")[0].appendChild(fileref)
+}
+
+/**
+ * Converts the passed in target into a wave-styled button.
+ *
+ * @param {Element} target element to turn into a button. The target should be
+ * an anchor element.
+ * @export
+ */
+wave.ui.makeButton = function(target) {
+  wave.ui.loadCss();
+  target.innerHTML = '<span>' + target.innerHTML + '</span>';
+  target.className += ' wavebutton';
+};
+
+/**
+ * Converts the passed in target into a wave-styled dialog.
+ *
+ * For now it only creates a centered box. The close button in the upper right
+ * corner will be default do nothing.
+ *
+ * @param {Element} target element to turn into a dialog. The target should be
+ * a div.
+ * @param {string} title
+ * @export
+ */
+wave.ui.makeDialog = function(target, title, onclick) {
+  wave.ui.loadCss();
+
+  var body = target.innerHTML;
+  target.innerHTML = '';
+
+  var headDiv = document.createElement('div');
+  headDiv.className = 'wavedialoghead';
+
+  var span = document.createElement('span');
+
+  var closeDiv = document.createElement('div');
+  closeDiv.className = 'wavedialogclose';
+  function closeFunction() {
+    target.style.display = 'none';
+  }
+  closeDiv.onclick = onclick || closeFunction;
+
+  span.appendChild(closeDiv);
+  span.appendChild(document.createTextNode(title));
+
+  headDiv.appendChild(span);
+  target.appendChild(headDiv);
+
+  var bodyDiv = document.createElement('div');
+  bodyDiv.className = 'wavedialogbody';
+  bodyDiv.innerHTML = body;
+  target.appendChild(bodyDiv);
+  target.className += ' wavedialog';
+};
+
+/**
+ * Converts the passed in target into a wave-styled frame.
+ *
+ * @param {Element} target element to turn into a frame. The target should be
+ * a div.
+ * @export
+ */
+wave.ui.makeFrame = function(target) {
+  wave.ui.loadCss();
+  target.innerHTML = '<div class="waveboxhead"><span>&nbsp;</span></div>' +
+      '<div class="waveboxbody">' + target.innerHTML + '</div>';
+  target.className += ' wavebox';
+};


Reply via email to