This implementation adds handlers to <a> elements that exist when the
config is inited, but it won't catch any anchor elements that are
dynamically created.  You could instead add a handler to the body and
use bubbling (supported by all major browsers for onclick).

On Tue, Feb 10, 2009 at 4:11 PM,  <[email protected]> wrote:
> Author: etnu
> Date: Wed Feb 11 00:11:51 2009
> New Revision: 743176
>
> URL: http://svn.apache.org/viewvc?rev=743176&view=rev
> Log:
> Patch for SHINDIG-750.
>
> This patch does a few things:
>
> - Adds several tests
> - Allows requestNavigateTo to take a string instead of a View (spec change)
> - Optionally adds event handlers to all anchors with hrefs that are not 
> missing, fragments, or absolute. The remaining URIs (relative uris) would not 
> work under existing gadgets anyway. To use this, you must add rewriteLinks : 
> true to your container config for the "views" feature.
>
> GadgetRenderingServlet still has to be modified to accept a parameter that 
> will specify the relative path for navigation as required by the spec. 
> Containers that are supporting the enhanced requestNavigateTo must ensure 
> that they are passing this parameter in order for it to work correctly.
>
>
> Added:
>    incubator/shindig/trunk/features/views/requestnavigateto-test.js
>    incubator/shindig/trunk/features/views/views-init-test.js
> Modified:
>    incubator/shindig/trunk/features/core.io/io.js
>    incubator/shindig/trunk/features/views/views.js
>
> Modified: incubator/shindig/trunk/features/core.io/io.js
> URL: 
> http://svn.apache.org/viewvc/incubator/shindig/trunk/features/core.io/io.js?rev=743176&r1=743175&r2=743176&view=diff
> ==============================================================================
> --- incubator/shindig/trunk/features/core.io/io.js (original)
> +++ incubator/shindig/trunk/features/core.io/io.js Wed Feb 11 00:11:51 2009
> @@ -255,7 +255,7 @@
>    * @private
>    */
>   function init (configuration) {
> -    config = configuration["core.io"];
> +    config = configuration["core.io"] || {};
>   }
>
>   var requiredConfig = {
>
> Added: incubator/shindig/trunk/features/views/requestnavigateto-test.js
> URL: 
> http://svn.apache.org/viewvc/incubator/shindig/trunk/features/views/requestnavigateto-test.js?rev=743176&view=auto
> ==============================================================================
> --- incubator/shindig/trunk/features/views/requestnavigateto-test.js (added)
> +++ incubator/shindig/trunk/features/views/requestnavigateto-test.js Wed Feb 
> 11 00:11:51 2009
> @@ -0,0 +1,76 @@
> +/*
> + * 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.
> + */
> +
> +
> +
> +function RequestNavigateToTest(name) {
> +  TestCase.call(this, name);
> +}
> +
> +RequestNavigateToTest.inherits(TestCase);
> +
> +(function() {
> +
> +var rpcs, oldRpc = gadgets.rpc;
> +
> +RequestNavigateToTest.prototype.setUp = function() {
> +  rpcs = [];
> +  gadgets.rpc = {
> +    call: function() {
> +      rpcs.push(arguments);
> +    }
> +  };
> +};
> +
> +RequestNavigateToTest.prototype.tearDown = function() {
> +  gadgets.rpc.call = oldRpc;
> +};
> +
> +RequestNavigateToTest.prototype.testBasic = function() {
> +  gadgets.views.requestNavigateTo("canvas");
> +
> +  this.assertEquals("requestNavigateTo", rpcs[0][1]);
> +  this.assertEquals("canvas", rpcs[0][3]);
> +};
> +
> +RequestNavigateToTest.prototype.testViewObject = function() {
> +  gadgets.views.requestNavigateTo(new gadgets.views.View("canvas"));
> +
> +  this.assertEquals("requestNavigateTo", rpcs[0][1]);
> +  this.assertEquals("canvas", rpcs[0][3]);
> +};
> +
> +RequestNavigateToTest.prototype.testKeyValueParams = function() {
> +  gadgets.views.requestNavigateTo("canvas", {foo:"bar"});
> +
> +  this.assertEquals("requestNavigateTo", rpcs[0][1]);
> +  this.assertEquals("canvas", rpcs[0][3]);
> +  this.assertEquals("bar", rpcs[0][4].foo);
> +};
> +
> +RequestNavigateToTest.prototype.testUriParams = function() {
> +  gadgets.views.requestNavigateTo("canvas", "/foo/bar?blah");
> +
> +  this.assertEquals("requestNavigateTo", rpcs[0][1]);
> +  this.assertEquals("canvas", rpcs[0][3]);
> +  this.assertEquals("/foo/bar?blah", rpcs[0][4]);
> +};
> +
> +})();
> +
>
> Added: incubator/shindig/trunk/features/views/views-init-test.js
> URL: 
> http://svn.apache.org/viewvc/incubator/shindig/trunk/features/views/views-init-test.js?rev=743176&view=auto
> ==============================================================================
> --- incubator/shindig/trunk/features/views/views-init-test.js (added)
> +++ incubator/shindig/trunk/features/views/views-init-test.js Wed Feb 11 
> 00:11:51 2009
> @@ -0,0 +1,113 @@
> +/*
> + * 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.
> + */
> +
> +function ViewsInitTest(name) {
> +  TestCase.call(this, name);
> +}
> +
> +ViewsInitTest.inherits(TestCase);
> +
> +(function() {
> +
> +var oldDocument = document;
> +var callback;
> +
> +ViewsInitTest.prototype.tearDown = function() {
> +  document = oldDocument;
> +};
> +
> +ViewsInitTest.prototype.testObjectParams = function() {
> +  gadgets.util.getUrlParameters = function() {
> +    return {"view-params": gadgets.json.stringify({foo: "bar"})};
> +  };
> +
> +  gadgets.config.init({views:{}});
> +
> +  this.assertEquals("bar", gadgets.views.getParams().foo);
> +};
> +
> +ViewsInitTest.prototype.testStringParams = function() {
> +  // In practice, containers should actually be passing this as the 'path' 
> query string param
> +  // to the gadget renderer, but we want to be sure that we can handle it 
> just in case.
> +  var path = "/foo/bar/baz.html?blah=blah&foo=bar";
> +  gadgets.util.getUrlParameters = function() {
> +    return {"view-params": gadgets.json.stringify(path)};
> +  };
> +
> +  gadgets.config.init({views:{}});
> +
> +  this.assertEquals(path, gadgets.views.getParams());
> +};
> +
> +function createAnchors(input) {
> +  var anchors = [];
> +  for (var i = 0, j = input.length; i < j; ++i) {
> +    anchors[i] = {
> +      href: input[i],
> +      eventName: null,
> +      addEventListener: function(name, func) {
> +        this.invokedAddEventListener = true;
> +        this.eventName = name;
> +      }
> +    };
> +  }
> +  return anchors;
> +}
> +
> +ViewsInitTest.prototype.testRewriteLinks = function() {
> +  var input = [
> +    "http://example.org/absolute";,
> +    "/relative/path?arg=foo",
> +    "#fragment",
> +    "/relative/path?arg=foo",
> +    null
> +  ];
> +
> +  var anchors = createAnchors(input);
> +
> +  // Make the last one pretend to be IE.
> +  anchors[3].attachEvent = function(name, func) {
> +    this.invokedAttachEvent = true;
> +    this.eventName = name;
> +  };
> +
> +  document = {
> +    getElementsByTagName: function(tag) {
> +      if (tag === "a") {
> +        return anchors;
> +      }
> +      return [];
> +    }
> +  };
> +
> +  gadgets.config.init({views:{rewriteLinks: true}});
> +
> +  this.assertEquals(null, anchors[0].eventName);
> +  this.assertEquals("click", anchors[1].eventName);
> +  this.assertEquals(null, anchors[2].eventName);
> +  this.assertEquals("onclick", anchors[3].eventName);
> +  this.assertEquals(null, anchors[4].eventName);
> +
> +  this.assertTrue(anchors[1].invokedAddEventListener);
> +  this.assertTrue(anchors[3].invokedAttachEvent);
> +
> +  this.assertTrue(typeof gadgets.views.getSupportedViews().rewriteLinks === 
> "undefined");
> +};
> +
> +})();
>
> Modified: incubator/shindig/trunk/features/views/views.js
> URL: 
> http://svn.apache.org/viewvc/incubator/shindig/trunk/features/views/views.js?rev=743176&r1=743175&r2=743176&view=diff
> ==============================================================================
> --- incubator/shindig/trunk/features/views/views.js (original)
> +++ incubator/shindig/trunk/features/views/views.js Wed Feb 11 00:11:51 2009
> @@ -45,6 +45,43 @@
>   var params = {};
>
>   /**
> +   * Forces navigation via requestNavigateTo.
> +   */
> +  function forceNavigate(href) {
> +    return function(e) {
> +      if (!e) {
> +        e = window.event;
> +      }
> +
> +      gadgets.views.requestNavigateTo(currentView, href);
> +
> +      e.cancelBubble = true;
> +      if (e.stopPropagation) {
> +        e.stopPropagation();
> +      }
> +      if (e.preventDefault) {
> +        e.preventDefault();
> +      }
> +      return false;
> +    };
> +  }
> +
> +  function attachLinkHandlers() {
> +    var anchors = document.getElementsByTagName("a");
> +    for (var i = 0, j = anchors.length; i < j; ++i) {
> +      var anchor = anchors[i];
> +      var href = anchor.href;
> +      if (href && !(href[0] === "#" || href.indexOf("://") !== -1)) {
> +        if (anchor.attachEvent) {
> +          anchor.attachEvent("onclick", forceNavigate(href));
> +        } else {
> +          anchor.addEventListener("click", forceNavigate(href), false);
> +        }
> +      }
> +    }
> +  }
> +
> +  /**
>    * Initializes views. Assumes that the current view is the "view"
>    * url parameter (or default if "view" isn't supported), and that
>    * all view parameters are in the form view-<name>
> @@ -52,17 +89,19 @@
>    *
>    */
>   function init(config) {
> -    var supported = config["views"];
> -
> -    for (var s in supported) if (supported.hasOwnProperty(s)) {
> -      var obj = supported[s];
> -      if (!obj) {
> -        continue;
> -      }
> -      supportedViews[s] = new gadgets.views.View(s, obj.isOnlyVisible);
> -      var aliases = obj.aliases || [];
> -      for (var i = 0, alias; alias = aliases[i]; ++i) {
> -        supportedViews[alias] = new gadgets.views.View(s, obj.isOnlyVisible);
> +    var conf = config.views || {};
> +    for (var s in conf) if (conf.hasOwnProperty(s)) {
> +      // TODO: Fix this by moving view names / config into a sub property.
> +      if (s != "rewriteLinks") {
> +        var obj = conf[s];
> +        if (!obj) {
> +          continue;
> +        }
> +        supportedViews[s] = new gadgets.views.View(s, obj.isOnlyVisible);
> +        var aliases = obj.aliases || [];
> +        for (var i = 0, alias; alias = aliases[i]; ++i) {
> +          supportedViews[alias] = new gadgets.views.View(s, 
> obj.isOnlyVisible);
> +        }
>       }
>     }
>
> @@ -72,6 +111,10 @@
>       params = gadgets.json.parse(urlParams["view-params"]) || params;
>     }
>     currentView = supportedViews[urlParams.view] || supportedViews["default"];
> +
> +    if (conf.rewriteLinks) {
> +      attachLinkHandlers();
> +    }
>   }
>
>   gadgets.config.register("views", null, init);
> @@ -204,15 +247,17 @@
>      * supports parameters will pass the optional parameters along to the 
> gadget
>      * in the new view.
>      *
> -     * @param {gadgets.views.View} view The view to navigate to
> +     * @param {string | gadgets.views.View} view The view to navigate to
>      * @param {Map.&lt;String, String&gt;} opt_params Parameters to pass to 
> the
>      *     gadget after it has been navigated to on the surface
>      * @param {string} opt_ownerId The ID of the owner of the page to 
> navigate to;
>      *                 defaults to the current owner.
>      */
>     requestNavigateTo : function(view, opt_params, opt_ownerId) {
> -      gadgets.rpc.call(
> -          null, "requestNavigateTo", null, view.getName(), opt_params, 
> opt_ownerId);
> +      if (typeof view !== "string") {
> +        view = view.getName();
> +      }
> +      gadgets.rpc.call(null, "requestNavigateTo", null, view, opt_params, 
> opt_ownerId);
>     },
>
>     /**
>
>
>

Reply via email to