You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by mh...@apache.org on 2011/05/10 04:58:06 UTC

svn commit: r1101292 - in /shindig/trunk/features/src: main/javascript/features/ main/javascript/features/core.util.dom/ main/javascript/features/core.util.urlparams/ main/javascript/features/core.util/ test/javascript/features/

Author: mhermanto
Date: Tue May 10 02:58:05 2011
New Revision: 1101292

URL: http://svn.apache.org/viewvc?rev=1101292&view=rev
Log:
(Start of) breaking up core.util into core.util.dom and core.util.string.
http://codereview.appspot.com/4538045/

Added:
    shindig/trunk/features/src/main/javascript/features/core.util.dom/
    shindig/trunk/features/src/main/javascript/features/core.util.dom/dom.js
    shindig/trunk/features/src/main/javascript/features/core.util.dom/feature.xml
Modified:
    shindig/trunk/features/src/main/javascript/features/core.util.urlparams/urlparams.js
    shindig/trunk/features/src/main/javascript/features/core.util/feature.xml
    shindig/trunk/features/src/main/javascript/features/core.util/util.js
    shindig/trunk/features/src/main/javascript/features/features.txt
    shindig/trunk/features/src/test/javascript/features/alltests.js

Added: shindig/trunk/features/src/main/javascript/features/core.util.dom/dom.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/core.util.dom/dom.js?rev=1101292&view=auto
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/core.util.dom/dom.js (added)
+++ shindig/trunk/features/src/main/javascript/features/core.util.dom/dom.js Tue May 10 02:58:05 2011
@@ -0,0 +1,70 @@
+/*
+ * 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 General purpose utilities that gadgets can use.
+ */
+
+/**
+ * @static
+ * @class Provides general-purpose utility functions.
+ * @name gadgets.util
+ */
+gadgets.util = gadgets.util || {};
+
+(function() {  
+  
+  var XHTML_SPEC = 'http://www.w3.org/1999/xhtml';
+
+  /**
+   * Creates an HTML or XHTML element.
+   * @param {string} tagName The type of element to construct.
+   * @return {Element} The newly constructed element.
+   */
+  gadgets.util.createElement = function(tagName) {
+    var element;
+    if ((!document.body) || document.body.namespaceURI) {
+      try {
+        element = document.createElementNS(XHTML_SPEC, tagName);
+      } catch (nonXmlDomException) {
+      }
+    }
+    return element || document.createElement(tagName);
+  };
+  
+  
+  /**
+   * Gets the HTML or XHTML body element.
+   * @return {Element} The DOM node representing body.
+   */
+  gadgets.util.getBodyElement = function() {
+    if (document.body) {
+      return document.body;
+    }
+    try {
+      var xbodies = document.getElementsByTagNameNS(XHTML_SPEC, 'body');
+      if (xbodies && (xbodies.length == 1)) {
+        return xbodies[0];
+      }
+    } catch (nonXmlDomException) {
+    }
+    return document.documentElement || document;
+  };
+
+})();
\ No newline at end of file

Added: shindig/trunk/features/src/main/javascript/features/core.util.dom/feature.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/core.util.dom/feature.xml?rev=1101292&view=auto
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/core.util.dom/feature.xml (added)
+++ shindig/trunk/features/src/main/javascript/features/core.util.dom/feature.xml Tue May 10 02:58:05 2011
@@ -0,0 +1,29 @@
+<?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>core.util.dom</name>
+  <dependency>globals</dependency>
+  <all>
+    <script src="dom.js"/>
+    <api>
+      <exports type="js">gadgets.util.createElement</exports>
+      <exports type="js">gadgets.util.getBodyElement</exports>
+    </api>
+  </all>
+</feature>

Modified: shindig/trunk/features/src/main/javascript/features/core.util.urlparams/urlparams.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/core.util.urlparams/urlparams.js?rev=1101292&r1=1101291&r2=1101292&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/core.util.urlparams/urlparams.js (original)
+++ shindig/trunk/features/src/main/javascript/features/core.util.urlparams/urlparams.js Tue May 10 02:58:05 2011
@@ -26,8 +26,9 @@
  * @class Provides a thin method for parsing url parameters.
  * @name gadgets.util
  */
+gadgets.util = gadgets.util || {};
 
-gadgets.util = function() {
+(function() {  
   var parameters = null;
 
   /**
@@ -51,50 +52,49 @@ gadgets.util = function() {
     return query.split('&');
   }
 
-  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) {
-      var no_opt_url = typeof opt_url === 'undefined';
-      if (parameters !== null && no_opt_url) {
-        // "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, ' ');
-        try {
-          parsed[argName] = unesc(value);
-        } catch (e) {
-          // Undecodable/invalid value; ignore.
-        }
+  /**
+   * 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.
+   */
+  gadgets.util.getUrlParameters = function(opt_url) {
+    var no_opt_url = typeof opt_url === 'undefined';
+    if (parameters !== null && no_opt_url) {
+      // "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;
       }
-      if (no_opt_url) {
-        // Cache current-window params in parameters var.
-        parameters = parsed;
+      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, ' ');
+      try {
+        parsed[argName] = unesc(value);
+      } catch (e) {
+        // Undecodable/invalid value; ignore.
       }
-      return parsed;
     }
+    if (no_opt_url) {
+      // Cache current-window params in parameters var.
+      parameters = parsed;
+    }
+    return parsed;
   };
-}();
+})();
+
 // Initialize url parameters so that hash data is pulled in before it can be
 // altered by a click.
 gadgets.util.getUrlParameters();

Modified: shindig/trunk/features/src/main/javascript/features/core.util/feature.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/core.util/feature.xml?rev=1101292&r1=1101291&r2=1101292&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/core.util/feature.xml (original)
+++ shindig/trunk/features/src/main/javascript/features/core.util/feature.xml Tue May 10 02:58:05 2011
@@ -21,12 +21,12 @@
   <dependency>globals</dependency>
   <dependency>taming</dependency>
   <dependency>core.config</dependency>
+  <dependency>core.util.dom</dependency>
   <dependency>core.util.urlparams</dependency>
   <all>
     <script src="util.js"/>
     <script src="taming.js" caja="1"/>
     <api>
-      <exports type="js">gadgets.util.getUrlParameters</exports>
       <exports type="js">gadgets.util.makeClosure</exports>
       <exports type="js">gadgets.util.makeEnum</exports>
       <exports type="js">gadgets.util.getFeatureParameters</exports>
@@ -39,9 +39,7 @@
       <exports type="js">gadgets.util.unescapeString</exports>
       <exports type="js">gadgets.util.attachBrowserEvent</exports>
       <exports type="js">gadgets.util.removeBrowserEvent</exports>
-      <exports type="js">gadgets.util.createElement</exports>
       <exports type="js">gadgets.util.createIframeElement</exports>
-      <exports type="js">gadgets.util.getBodyElement</exports>
     </api>
   </all>
 </feature>

Modified: shindig/trunk/features/src/main/javascript/features/core.util/util.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/core.util/util.js?rev=1101292&r1=1101291&r2=1101292&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/core.util/util.js (original)
+++ shindig/trunk/features/src/main/javascript/features/core.util/util.js Tue May 10 02:58:05 2011
@@ -21,21 +21,19 @@
  * @fileoverview General purpose utilities that gadgets can use.
  */
 
-// Short-term incremental library-building mechanism.
-var __getUrlParameters = gadgets.util.getUrlParameters;
-
 /**
  * @static
  * @class Provides general-purpose utility functions.
  * @name gadgets.util
  */
-gadgets.util = function() {
+gadgets.util = gadgets.util || {};
+
+(function() {  
+  
   var features = {};
   var services = {};
   var onLoadHandlers = [];
 
-  var XHTML_SPEC = 'http://www.w3.org/1999/xhtml';
-
   function attachAttributes(elem, opt_attribs) {
     var attribs = opt_attribs || {};
     for (var attrib in attribs) {
@@ -156,285 +154,236 @@ gadgets.util = function() {
     gadgets.config.register('core.util', null, init);
   }
 
-  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 : __getUrlParameters,
-
-    /**
-     * Creates a closure that is suitable for passing as a callback.
-     * Any number of arguments
-     * may be passed to the callback;
-     * they will be received in the order they are passed in.
-     *
-     * @param {Object} scope The execution scope; may be null if there is no
-     *     need to associate a specific instance of an object with this
-     *     callback.
-     * @param {function(Object,Object)} callback The callback to invoke when this is run;
-     *     any arguments passed in will be passed after your initial arguments.
-     * @param {Object} var_args Initial arguments to be passed to the callback.
-     *
-     * @member gadgets.util
-     * @private Implementation detail.
-     */
-    makeClosure : function(scope, callback, var_args) {
-      // arguments isn't a real array, so we copy it into one.
-      var baseArgs = [];
-      for (var i = 2, j = arguments.length; i < j; ++i) {
-        baseArgs.push(arguments[i]);
-      }
-      return function() {
-        // append new arguments.
-        var tmpArgs = baseArgs.slice();
-        for (var i = 0, j = arguments.length; i < j; ++i) {
-          tmpArgs.push(arguments[i]);
-        }
-        return callback.apply(scope, tmpArgs);
-      };
-    },
-
-    /**
-     * Utility function for generating an "enum" from an array.
-     *
-     * @param {Array.<string>} values The values to generate.
-     * @return {Object.<string,string>} An object with member fields to handle
-     *   the enum.
-     *
-     * @private Implementation detail.
-     */
-    makeEnum : function(values) {
-      var i, v, obj = {};
-      for (i = 0; (v = values[i]); ++i) {
-        obj[v] = v;
+  /**
+   * Creates a closure that is suitable for passing as a callback.
+   * Any number of arguments
+   * may be passed to the callback;
+   * they will be received in the order they are passed in.
+   *
+   * @param {Object} scope The execution scope; may be null if there is no
+   *     need to associate a specific instance of an object with this
+   *     callback.
+   * @param {function(Object,Object)} callback The callback to invoke when this is run;
+   *     any arguments passed in will be passed after your initial arguments.
+   * @param {Object} var_args Initial arguments to be passed to the callback.
+   *
+   * @member gadgets.util
+   * @private Implementation detail.
+   */
+  gadgets.util.makeClosure = function(scope, callback, var_args) {
+    // arguments isn't a real array, so we copy it into one.
+    var baseArgs = [];
+    for (var i = 2, j = arguments.length; i < j; ++i) {
+      baseArgs.push(arguments[i]);
+    }
+    return function() {
+      // append new arguments.
+      var tmpArgs = baseArgs.slice();
+      for (var i = 0, j = arguments.length; i < j; ++i) {
+        tmpArgs.push(arguments[i]);
       }
-      return obj;
-    },
+      return callback.apply(scope, tmpArgs);
+    };
+  };
 
-    /**
-     * Gets the feature parameters.
-     *
-     * @param {string} feature The feature to get parameters for.
-     * @return {Object} The parameters for the given feature, or null.
-     *
-     * @member gadgets.util
-     */
-    getFeatureParameters : function(feature) {
-      return typeof features[feature] === 'undefined' ? null : features[feature];
-    },
-
-    /**
-     * Returns whether the current feature is supported.
-     *
-     * @param {string} feature The feature to test for.
-     * @return {boolean} True if the feature is supported.
-     *
-     * @member gadgets.util
-     */
-    hasFeature : function(feature) {
-      return typeof features[feature] !== 'undefined';
-    },
-
-    /**
-     * Returns the list of services supported by the server
-     * serving this gadget.
-     *
-     * @return {Object} List of Services that enumerate their methods.
-     *
-     * @member gadgets.util
-     */
-    getServices : function() {
-      return services;
-    },
-
-    /**
-     * 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]();
-      }
-    },
+  /**
+   * Utility function for generating an "enum" from an array.
+   *
+   * @param {Array.<string>} values The values to generate.
+   * @return {Object.<string,string>} An object with member fields to handle
+   *   the enum.
+   *
+   * @private Implementation detail.
+   */
+  gadgets.util.makeEnum = function(values) {
+    var i, v, obj = {};
+    for (i = 0; (v = values[i]); ++i) {
+      obj[v] = v;
+    }
+    return obj;
+  };
 
-    /**
-     * Escapes the input using html entities to make it safer.
-     *
-     * If the input is a string, uses gadgets.util.escapeString.
-     * If it is an array, calls escape on each of the array elements
-     * if it is an object, will only escape all the mapped keys and values if
-     * the opt_escapeObjects flag is set. This operation involves creating an
-     * entirely new object so only set the flag when the input is a simple
-     * string to string map.
-     * Otherwise, does not attempt to modify the input.
-     *
-     * @param {Object} input The object to escape.
-     * @param {boolean=} opt_escapeObjects Whether to escape objects.
-     * @return {Object} The escaped object.
-     * @private Only to be used by the container, not gadgets.
-     */
-    escape : function(input, opt_escapeObjects) {
-      if (!input) {
-        return input;
-      } else if (typeof input === 'string') {
-        return gadgets.util.escapeString(input);
-      } else if (typeof input === 'array') {
-        for (var i = 0, j = input.length; i < j; ++i) {
-          input[i] = gadgets.util.escape(input[i]);
-        }
-      } else if (typeof input === 'object' && opt_escapeObjects) {
-        var newObject = {};
-        for (var field in input) {
-          if (input.hasOwnProperty(field)) {
-            newObject[gadgets.util.escapeString(field)] = gadgets.util.escape(input[field], true);
-          }
-        }
-        return newObject;
-      }
-      return input;
-    },
+  /**
+   * Gets the feature parameters.
+   *
+   * @param {string} feature The feature to get parameters for.
+   * @return {Object} The parameters for the given feature, or null.
+   *
+   * @member gadgets.util
+   */
+  gadgets.util.getFeatureParameters = function(feature) {
+    return typeof features[feature] === 'undefined' ? null : features[feature];
+  };
 
-    /**
-     * Escapes the input using html entities to make it safer.
-     *
-     * Currently not in the spec -- future proposals may change
-     * how this is handled.
-     *
-     * @param {string} str The string to escape.
-     * @return {string} The escaped string.
-     */
-    escapeString : escapeString,
-
-    /**
-     * Reverses escapeString
-     *
-     * @param {string} str The string to unescape.
-     * @return {string}
-     */
-    unescapeString : function(str) {
-      if (!str) return str;
-      return str.replace(/&#([0-9]+);/g, unescapeEntity);
-    },
-
-    /**
-     * Attach an event listener to given DOM element (Not a gadget standard)
-     *
-     * @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 (typeof elem.addEventListener != 'undefined') {
-        elem.addEventListener(eventName, callback, useCapture);
-      } else if (typeof elem.attachEvent != 'undefined') {
-        elem.attachEvent('on' + eventName, callback);
-      } else {
-        gadgets.warn('cannot attachBrowserEvent: ' + eventName);
-      }
-    },
+  /**
+   * Returns whether the current feature is supported.
+   *
+   * @param {string} feature The feature to test for.
+   * @return {boolean} True if the feature is supported.
+   *
+   * @member gadgets.util
+   */
+  gadgets.util.hasFeature = function(feature) {
+    return typeof features[feature] !== 'undefined';
+  };
 
-    /**
-     * Remove event listener. (Shindig internal implementation only)
-     *
-     * @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);
-      } else {
-        gadgets.warn('cannot removeBrowserEvent: ' + eventName);
-      }
-    },
+  /**
+   * Returns the list of services supported by the server
+   * serving this gadget.
+   *
+   * @return {Object} List of Services that enumerate their methods.
+   *
+   * @member gadgets.util
+   */
+  gadgets.util.getServices = function() {
+    return services;
+  };
 
-    /**
-     * Creates an HTML or XHTML element.
-     * @param {string} tagName The type of element to construct.
-     * @return {Element} The newly constructed element.
-     */
-    createElement : function(tagName) {
-      // TODO: factor this out to core.util.dom.
-      var element;
-      if ((!document.body) || document.body.namespaceURI) {
-        try {
-          element = document.createElementNS(XHTML_SPEC, tagName);
-        } catch (nonXmlDomException) {
-        }
-      }
-      return element || document.createElement(tagName);
-    },
+  /**
+   * Registers an onload handler.
+   * @param {function()} callback The handler to run.
+   *
+   * @member gadgets.util
+   */
+  gadgets.util.registerOnLoadHandler = function(callback) {
+    onLoadHandlers.push(callback);
+  };
 
-    /**
-     * Creates an HTML or XHTML iframe element with attributes.
-     * @param {Object=} opt_attribs Optional set of attributes to attach. The
-     * only working attributes are spelled the same way in XHTML attribute
-     * naming (most strict, all-lower-case), HTML attribute naming (less strict,
-     * case-insensitive), and JavaScript property naming (some properties named
-     * incompatibly with XHTML/HTML).
-     * @return {Element} The DOM node representing body.
-     */
-    createIframeElement : function(opt_attribs) {
-      // TODO: factor this out to core.util.dom.
-      var frame = gadgets.util.createElement('iframe');
-      try {
-        // TODO: provide automatic mapping to only set the needed
-        // and JS-HTML-XHTML compatible subset through stringifyElement (just
-        // 'name' and 'id', AFAIK). The values of the attributes will be
-        // stringified should the stringifyElement code path be taken (IE)
-        var tagString = stringifyElement('iframe', opt_attribs);
-        var ieFrame = gadgets.util.createElement(tagString);
-        if (ieFrame &&
-            ((!frame) ||
-             ((ieFrame.tagName == frame.tagName) &&
-              (ieFrame.namespaceURI == frame.namespaceURI)))) {
-          frame = ieFrame;
+  /**
+   * Runs all functions registered via registerOnLoadHandler.
+   * @private Only to be used by the container, not gadgets.
+   */
+  gadgets.util.runOnLoadHandlers = function() {
+    for (var i = 0, j = onLoadHandlers.length; i < j; ++i) {
+      onLoadHandlers[i]();
+    }
+  };
+
+  /**
+   * Escapes the input using html entities to make it safer.
+   *
+   * If the input is a string, uses gadgets.util.escapeString.
+   * If it is an array, calls escape on each of the array elements
+   * if it is an object, will only escape all the mapped keys and values if
+   * the opt_escapeObjects flag is set. This operation involves creating an
+   * entirely new object so only set the flag when the input is a simple
+   * string to string map.
+   * Otherwise, does not attempt to modify the input.
+   *
+   * @param {Object} input The object to escape.
+   * @param {boolean=} opt_escapeObjects Whether to escape objects.
+   * @return {Object} The escaped object.
+   * @private Only to be used by the container, not gadgets.
+   */
+  gadgets.util.escape = function(input, opt_escapeObjects) {
+    if (!input) {
+      return input;
+    } else if (typeof input === 'string') {
+      return gadgets.util.escapeString(input);
+    } else if (typeof input === 'array') {
+      for (var i = 0, j = input.length; i < j; ++i) {
+        input[i] = gadgets.util.escape(input[i]);
+      }
+    } else if (typeof input === 'object' && opt_escapeObjects) {
+      var newObject = {};
+      for (var field in input) {
+        if (input.hasOwnProperty(field)) {
+          newObject[gadgets.util.escapeString(field)] = gadgets.util.escape(input[field], true);
         }
-      } catch (nonStandardCallFailed) {
-      }
-      attachAttributes(frame, opt_attribs);
-      return frame;
-    },
-
-    /**
-     * Gets the HTML or XHTML body element.
-     * @return {Element} The DOM node representing body.
-     */
-    getBodyElement : function() {
-      // TODO: factor this out to core.util.dom.
-      if (document.body) {
-        return document.body;
       }
-      try {
-        var xbodies = document.getElementsByTagNameNS(XHTML_SPEC, 'body');
-        if (xbodies && (xbodies.length == 1)) {
-          return xbodies[0];
-        }
-      } catch (nonXmlDomException) {
+      return newObject;
+    }
+    return input;
+  };
+
+  /**
+   * Escapes the input using html entities to make it safer.
+   *
+   * Currently not in the spec -- future proposals may change
+   * how this is handled.
+   *
+   * @param {string} str The string to escape.
+   * @return {string} The escaped string.
+   */
+  gadgets.util.escapeString = escapeString;
+
+  /**
+   * Reverses escapeString
+   *
+   * @param {string} str The string to unescape.
+   * @return {string}
+   */
+  gadgets.util.unescapeString = function(str) {
+    if (!str) return str;
+    return str.replace(/&#([0-9]+);/g, unescapeEntity);
+  };
+
+  /**
+   * Attach an event listener to given DOM element (Not a gadget standard)
+   *
+   * @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.
+   */
+  gadgets.util.attachBrowserEvent = function(elem, eventName, callback, useCapture) {
+    if (typeof elem.addEventListener != 'undefined') {
+      elem.addEventListener(eventName, callback, useCapture);
+    } else if (typeof elem.attachEvent != 'undefined') {
+      elem.attachEvent('on' + eventName, callback);
+    } else {
+      gadgets.warn('cannot attachBrowserEvent: ' + eventName);
+    }
+  };
+
+  /**
+   * Remove event listener. (Shindig internal implementation only)
+   *
+   * @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.
+   */
+  gadgets.util.removeBrowserEvent = function(elem, eventName, callback, useCapture) {
+    if (elem.removeEventListener) {
+      elem.removeEventListener(eventName, callback, useCapture);
+    } else if (elem.detachEvent) {
+      elem.detachEvent('on' + eventName, callback);
+    } else {
+      gadgets.warn('cannot removeBrowserEvent: ' + eventName);
+    }
+  };
+
+  /**
+   * Creates an HTML or XHTML iframe element with attributes.
+   * @param {Object=} opt_attribs Optional set of attributes to attach. The
+   * only working attributes are spelled the same way in XHTML attribute
+   * naming (most strict, all-lower-case), HTML attribute naming (less strict,
+   * case-insensitive), and JavaScript property naming (some properties named
+   * incompatibly with XHTML/HTML).
+   * @return {Element} The DOM node representing body.
+   */
+  gadgets.util.createIframeElement = function(opt_attribs) {
+    // TODO: factor this out to core.util.dom.
+    var frame = gadgets.util.createElement('iframe');
+    try {
+      // TODO: provide automatic mapping to only set the needed
+      // and JS-HTML-XHTML compatible subset through stringifyElement (just
+      // 'name' and 'id', AFAIK). The values of the attributes will be
+      // stringified should the stringifyElement code path be taken (IE)
+      var tagString = stringifyElement('iframe', opt_attribs);
+      var ieFrame = gadgets.util.createElement(tagString);
+      if (ieFrame &&
+          ((!frame) ||
+           ((ieFrame.tagName == frame.tagName) &&
+            (ieFrame.namespaceURI == frame.namespaceURI)))) {
+        frame = ieFrame;
       }
-      return document.documentElement || document;
+    } catch (nonStandardCallFailed) {
     }
+    attachAttributes(frame, opt_attribs);
+    return frame;
   };
-}();
+
+})();

Modified: shindig/trunk/features/src/main/javascript/features/features.txt
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/features.txt?rev=1101292&r1=1101291&r2=1101292&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/features.txt (original)
+++ shindig/trunk/features/src/main/javascript/features/features.txt Tue May 10 02:58:05 2011
@@ -36,6 +36,7 @@ features/core.log/feature.xml
 features/core.none/feature.xml
 features/core.prefs/feature.xml
 features/core.util/feature.xml
+features/core.util.dom/feature.xml
 features/core.util.urlparams/feature.xml
 features/core/feature.xml
 features/dynamic-height.height/feature.xml

Modified: shindig/trunk/features/src/test/javascript/features/alltests.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/test/javascript/features/alltests.js?rev=1101292&r1=1101291&r2=1101292&view=diff
==============================================================================
--- shindig/trunk/features/src/test/javascript/features/alltests.js (original)
+++ shindig/trunk/features/src/test/javascript/features/alltests.js Tue May 10 02:58:05 2011
@@ -40,7 +40,8 @@ if (!this.JsUtil) {
   eval(JsUtil.prototype.include(srcDir + '/core/json-jsimpl.js'));
   eval(JsUtil.prototype.include(srcDir + '/core/json-flatten.js'));
   eval(JsUtil.prototype.include(srcDir + '/core/auth.js'));
-  eval(JsUtil.prototype.include(srcDir + '/core/util.js'));
+  eval(JsUtil.prototype.include(srcDir + '/core.util.dom/dom.js'));
+  eval(JsUtil.prototype.include(srcDir + '/core.util/util.js'));
   eval(JsUtil.prototype.include(srcDir + '/core/prefs.js'));
   eval(JsUtil.prototype.include(srcDir + '/core/log.js'));
   eval(JsUtil.prototype.include(srcDir + '/core.io/io.js'));