You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2012/09/11 23:18:04 UTC

[1/3] git commit: Add spi/core:ElementWrapper.deepVisible() Rename a few methods of ElementWrapper Rebuild the FormFragment support using the module system Fix an incorrect attribute name in Form that disable client-side input validation

Updated Branches:
  refs/heads/5.4-js-rewrite 65aa66e34 -> 48bec3a6d


Add spi/core:ElementWrapper.deepVisible()
Rename a few methods of ElementWrapper
Rebuild the FormFragment support using the module system
Fix an incorrect attribute name in Form that disable client-side input validation


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/48bec3a6
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/48bec3a6
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/48bec3a6

Branch: refs/heads/5.4-js-rewrite
Commit: 48bec3a6dd11d2c2a0074b2f52de5db57f440819
Parents: 558ef40
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Tue Sep 11 14:17:31 2012 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Tue Sep 11 14:17:31 2012 -0700

----------------------------------------------------------------------
 .../META-INF/modules/core/builder.coffee           |    4 +-
 .../META-INF/modules/core/events.coffee            |   10 ++-
 .../META-INF/modules/core/form-fragment.coffee     |   78 +++++++++++
 .../META-INF/modules/core/forms.coffee             |    2 +-
 .../coffeescript/META-INF/modules/core/spi.coffee  |  103 +++++++++------
 .../apache/tapestry5/corelib/components/Form.java  |    2 +-
 .../tapestry5/corelib/components/FormFragment.java |   60 +++++----
 .../tapestry5/corelib/mixins/TriggerFragment.java  |   13 ++-
 .../services/ClientBehaviorSupportImpl.java        |   18 +--
 .../services/javascript/CoreJavaScriptStack.java   |    2 -
 .../tapestry5/services/ClientBehaviorSupport.java  |    5 +
 .../resources/org/apache/tapestry5/t5-forceload.js |    1 -
 .../org/apache/tapestry5/t5-formfragment.js        |  101 --------------
 .../resources/org/apache/tapestry5/t5-prototype.js |    4 +-
 .../resources/org/apache/tapestry5/tapestry.js     |   12 +-
 .../integration/app1/pages/test-spi.coffee         |   14 +-
 16 files changed, 226 insertions(+), 203 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/48bec3a6/tapestry-core/src/main/coffeescript/META-INF/modules/core/builder.coffee
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/coffeescript/META-INF/modules/core/builder.coffee b/tapestry-core/src/main/coffeescript/META-INF/modules/core/builder.coffee
index eb73e03..adf23ab 100644
--- a/tapestry-core/src/main/coffeescript/META-INF/modules/core/builder.coffee
+++ b/tapestry-core/src/main/coffeescript/META-INF/modules/core/builder.coffee
@@ -64,7 +64,7 @@ define ["_", "core/spi"], (_, spi) ->
   addAttributes = (element, attributes) ->
     return unless attributes
 
-    wrapper = spi.wrap element
+    wrapper = spi element
 
     for name, value of attributes
       if name is "on"
@@ -120,4 +120,4 @@ define ["_", "core/spi"], (_, spi) ->
   (elementDescription, body...) ->
     element = buildTree elementDescription, body
 
-    spi.wrap element
\ No newline at end of file
+    spi element
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/48bec3a6/tapestry-core/src/main/coffeescript/META-INF/modules/core/events.coffee
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/coffeescript/META-INF/modules/core/events.coffee b/tapestry-core/src/main/coffeescript/META-INF/modules/core/events.coffee
index d773f39..0131c15 100644
--- a/tapestry-core/src/main/coffeescript/META-INF/modules/core/events.coffee
+++ b/tapestry-core/src/main/coffeescript/META-INF/modules/core/events.coffee
@@ -62,4 +62,12 @@ define
 
     # Triggered (by the standard hanndler) just after the content in a Zone has updated. If the zone was not visible, it
     # is made visible after its content is changed, and before this event is triggered.
-    didUpdate: "t5:zone:did-update"
\ No newline at end of file
+    didUpdate: "t5:zone:did-update"
+
+  # Event names for arbitrary elements. These notifications exist primarily to allow for customizations in how
+  # certain behaviors are presented, for example, to add animation when certain elements are hidden or revealed.
+  element:
+    # Triggered when a hidden element has just been displayed.
+    didShow: "t5:element:did-show"
+    # Trigered when a visible element has just been hidden.
+    didHide: "t5:element:did-hide"

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/48bec3a6/tapestry-core/src/main/coffeescript/META-INF/modules/core/form-fragment.coffee
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/coffeescript/META-INF/modules/core/form-fragment.coffee b/tapestry-core/src/main/coffeescript/META-INF/modules/core/form-fragment.coffee
new file mode 100644
index 0000000..601f0ac
--- /dev/null
+++ b/tapestry-core/src/main/coffeescript/META-INF/modules/core/form-fragment.coffee
@@ -0,0 +1,78 @@
+# Copyright 2012 The Apache Software Foundation
+#
+# 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.
+
+
+# ##core/form-fragment
+#
+define ["core/spi", "core/events", "core/compat/tapestry"],
+  (spi, events) ->
+
+    # Initializes a FormFragment element
+    #
+    # * spec.element - id of fragment's element
+    # * spec.bound - (optional) reference to function that determines bound
+    #   (used with `core/spi:EventWrapper.deepVisible()`)
+    # * spec.alwaysSubmit - (optional) if true, then fields inside the fragment submit their values
+    #   even when the fragment is not visible. If false (default), then field data is not submitted.
+    initFragment = (spec) ->
+      element = spi spec.element
+      hidden = spi "#{spec.element}-hidden"
+      form = spi hidden.element.form
+
+      opts = spec.bound and { bound: spec.bound} or null
+
+      unless spec.alwaysSubmit
+        hidden.element.disabled = ! element.deepVisible opts
+
+      updateUI = (makeVisible) ->
+        unless spec.alwaysSubmit
+          hidden.element.disabled = ! (makeVisible and element.container().deepVisible opts)
+
+        element[if makeVisible then "show" else "hide"]()
+
+        element.trigger events.element[if makeVisible then "didShow" else "didHide"]
+
+      element.on Tapestry.CHANGE_VISIBILITY_EVENT, (event) ->
+        event.stop()
+
+        makeVisible = event.memo.visible
+
+        unless makeVisible is element.visible()
+          updateUI makeVisible
+
+      element.on Tapestry.HIDE_AND_REMOVE_EVENT, (event) ->
+        event.stop()
+        element.remove()
+
+    # Initializes a trigger for a FormFragment
+    #
+    # * spec.triggerId - id of checkbox or radio button
+    # * spec.fragmentId - id of FormFragment element
+    # * spec.invert - (optional) if true, then checked trigger hides (not shows) the fragment
+    linkTrigger = (spec) ->
+      trigger = spi spec.triggerId
+      invert = spec.invert or false
+
+      update = ->
+        checked = trigger.element.checked
+        makeVisible = checked isnt invert
+
+        (spi spec.fragmentId).trigger Tapestry.CHANGE_VISIBILITY_EVENT,  visible: makeVisible
+
+      if trigger.element.type is "radio"
+        spi.on trigger.element.form, "click", update
+      else
+        trigger.on "click", update
+
+    { initFragment, linkTrigger }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/48bec3a6/tapestry-core/src/main/coffeescript/META-INF/modules/core/forms.coffee
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/coffeescript/META-INF/modules/core/forms.coffee b/tapestry-core/src/main/coffeescript/META-INF/modules/core/forms.coffee
index d4ea5ae..12d830f 100644
--- a/tapestry-core/src/main/coffeescript/META-INF/modules/core/forms.coffee
+++ b/tapestry-core/src/main/coffeescript/META-INF/modules/core/forms.coffee
@@ -90,7 +90,7 @@ define ["core/events", "core/spi", "core/builder", "core/compat/tapestry"],
       # was responsible for the eventual submit; this is very important to Ajax updates, otherwise the
       # information about which control triggered the submit gets lost.
       spi.body().on "click", "input[type=submit], input[type=image]", (event) ->
-        setSubmittingHidden (spi.wrap this.element.form), this
+        setSubmittingHidden (spi this.element.form), this
 
     exports =
       setSubmittingElement: (form, element) ->

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/48bec3a6/tapestry-core/src/main/coffeescript/META-INF/modules/core/spi.coffee
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/coffeescript/META-INF/modules/core/spi.coffee b/tapestry-core/src/main/coffeescript/META-INF/modules/core/spi.coffee
index c0aaaab..c8aa667 100644
--- a/tapestry-core/src/main/coffeescript/META-INF/modules/core/spi.coffee
+++ b/tapestry-core/src/main/coffeescript/META-INF/modules/core/spi.coffee
@@ -21,9 +21,7 @@
 define ["_", "prototype"], (_) ->
 
   domLoaded = false
-  # When the document has loaded, convert `domReady` to just execute the callback immediately.
-  $(document).observe "dom:loaded", ->
-    domLoaded = true
+  $(document).observe "dom:loaded", -> domLoaded = true
 
   # _internal_: splits the string into words separated by whitespace
   split = (str) ->
@@ -120,7 +118,7 @@ define ["_", "prototype"], (_) ->
   #   and the memo as the second parameter. `this` will be the ElementWrapper for the matched element.
   class EventHandler
     constructor: (elements, eventNames, match, handler) ->
-      throw new Error("No event handler was provided.") unless handler?
+      throw new Error "No event handler was provided." unless handler?
 
       wrapped = (prototypeEvent) ->
         # Set `this` to be the matched ElementWrapper, rather than the element on which the event is observed.
@@ -298,23 +296,43 @@ define ["_", "prototype"], (_) ->
 
       _.map matches, (e) -> new ElementWrapper e
 
-    # Returns an ElementWrapper for this element's containing element. The ElementWrapper is created lazily, and
+    # Returns an ElementWrapper for this element's containing element.  The ElementWrapper is created lazily, and
     # cached. Returns null if this element has no parentNode (either because this element is the document object, or
     # because this element is not yet attached to the DOM).
-    getContainer: ->
-      unless @container
-        return null unless element.parentNode
-        @container = new ElementWrapper(element.parentNode)
+    container: ->
+      parentNode = @element.parentNode
+      return null unless parentNode
 
-      @container
+      new ElementWrapper(parentNode)
 
     # Returns true if this element is visible, false otherwise. This does not check to see if all containers of the
     # element are visible.
     visible: ->
       @element.visible()
 
+    # Returns true if this element is visible, and all parent elements are also visible.
+    # * options - optional object used to customize the search:
+    # ** bound - function passed the DOM element, returns true if the element represents the upper bound that terminates
+    #   the search (at which point, true is returned).
+    #
+    # The default bound is the document body (this is a change from 5.3, where the default bound was the nearest
+    # form element).
+    deepVisible: (options) ->
+
+      boundf = options?.bound or (element) -> element is document.body
+
+      cursor = this
+      while cursor
+        return false unless cursor.visible()
+        cursor = cursor.container()
+
+        return true if cursor and boundf cursor.element
+
+      # Bound not reached, meaning that the Element is not currently attached to the DOM.
+      false
+
     # Fires a named event, passing an optional _memo_ object to event handler functions. This must support
-    # common native events (exact list TBD), as well as native events (in Prototype, native events must have
+    # common native events (exact list TBD), as well as custom events (in Prototype, custom events must have
     # a prefix that ends with a colon).
     #
     # * eventName - name of event to trigger on the wrapped Element
@@ -323,14 +341,14 @@ define ["_", "prototype"], (_) ->
     #
     # Returns this ElementWrapper.
     trigger: (eventName, memo) ->
-      throw new Error("Attempt to trigger event with null event name") unless eventName?
+      throw new Error "Attempt to trigger event with null event name" unless eventName?
 
       if (eventName.indexOf ':') > 0
         # Custom event is supported directly by Prototype:
         @element.fire eventName, memo
       else
         # Native events take some extra work:
-        throw new Error("Memo must be null when triggering a native event") if memo
+        throw new Error "Memo must be null when triggering a native event" if memo
 
         fireNativeEvent @element, eventName
 
@@ -353,16 +371,17 @@ define ["_", "prototype"], (_) ->
 
     # Adds an event handler for one or more events.
     #
-    # events - one or more event names, separated by spaces
-    # match - optional: CSS expression used as a filter; only events that bubble
-    # up to the wrapped element from an originating element that matches the CSS expression
-    # will invoke the handler.
-    # handler - function invoked; the function is passed an EventWrapper object.
+    # * events - one or more event names, separated by spaces
+    # * match - optional: CSS expression used as a filter; only events that bubble
+    #   up to the wrapped element from an originating element that matches the CSS expression
+    #   will invoke the handler.
+    # * handler - function invoked; the function is passed an EventWrapper object.
     #
     # Returns an EventHandler object, making it possible to turn event observation on or off.
     on: (events, match, handler) ->
       exports.on @element, events, match, handler
 
+  # _internal_: converts a selector to an array of DOM elements
   parseSelectorToElements = (selector) ->
     if _.isString selector
       return $$ selector
@@ -380,7 +399,8 @@ define ["_", "prototype"], (_) ->
   # Performs an asynchronous Ajax request, invoking callbacks when it completes.
   #
   # This is very low level; most code will want to go through the `core/ajax` module instead,
-  # which adds better handling of exceptions and failures, and handles Tapestry's
+  # which adds better handling of exceptions and failures, and handles Tapestry's partial page
+  # render reponse keys.
   #
   # * options.method - "post", "get", etc., default: "post".
   #   Adds a "_method" parameter and uses "post" to handle "delete", etc.
@@ -419,7 +439,7 @@ define ["_", "prototype"], (_) ->
           if options.onfailure
             options.onfailure response, message
           else
-            throw new Error(message)
+            throw new Error message
 
       onSuccess: (response) ->
 
@@ -437,12 +457,30 @@ define ["_", "prototype"], (_) ->
 
     new Ajax.Request(url, finalOptions)
 
-  exports =
+
+  # The main export is a function that wraps a DOM element as an ElementWrapper; additional functions are attached as
+  # properties.
+  #
+  # * element - a DOM element, or a string id of a DOM element
+  #
+  # Returns the ElementWrapper, or null if no element with the id exists
+  exports = wrapElement = (element) ->
+    if _.isString element
+      element = $ element
+      return null unless element
+    else
+      throw new Error "Attempt to wrap a null DOM element" unless element
+
+    new ElementWrapper element
+
+  _.extend exports,
+    wrap: wrapElement
+
     ajaxRequest: ajaxRequest
 
     # Invokes the callback only once the DOM has finished loading all elements (other resources, such as images, may
     # still be in-transit). This is a safe time to search the DOM, modify attributes, and attach event handlers.
-    # Returns this modules exports, for chained calls. If the DOM has already loaded, the callback is invoked
+    # Returns this module's exports, for chained calls. If the DOM has already loaded, the callback is invoked
     # immediately.
     domReady: (callback) ->
       if domLoaded
@@ -470,25 +508,14 @@ define ["_", "prototype"], (_) ->
 
       elements = parseSelectorToElements selector
 
-      return new EventHandler(elements, (split events), match, handler)
-
-    # Returns an ElementWrapper for the provided DOM element that includes key behaviors:
-    #
-    # * element - a DOM element, or the window, or the unique id of a DOM element
-    #
-    # Returns the ElementWrapper, or null if no DOM element with the given id exists.
-    wrap: (element) ->
-      if _.isString element
-        element = $ element
-        return null unless element
-      else
-        throw new Error("Attempt to wrap a null DOM element") unless element
-
-      new ElementWrapper element
+      new EventHandler(elements, (split events), match, handler)
 
     # Returns a wrapped version of the document.body element. Care must be take to not invoke this function before the
     # body element exists; typically only after the DOM has loaded, such as a `domReady()` callback.
-    body: -> bodyWrapper ?= (exports.wrap document.body)
+    body: ->
+      throw new Error "May not access body until after DOM has loaded." unless domLoaded
+
+      bodyWrapper ?= (wrapElement document.body)
 
     # Returns the current dimensions of the viewport. An object with keys `width` and `height` (in pixels) is returned.
     viewportDimensions: -> document.viewport.getDimensions()
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/48bec3a6/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java
index 9ea3b63..b74ea0d 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java
@@ -357,7 +357,7 @@ public class Form implements ClientElement, FormValidationControl
 
         if (clientValidation != ClientValidation.NONE)
         {
-            writer.attributes("data-t5-validate", "submit");
+            writer.attributes("data-validate", "submit");
         }
 
         resources.renderInformalParameters(writer);

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/48bec3a6/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormFragment.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormFragment.java b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormFragment.java
index f49e1a1..0e08011 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormFragment.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormFragment.java
@@ -1,4 +1,4 @@
-// Copyright 2008, 2009, 2010, 2011 The Apache Software Foundation
+// Copyright 2008-2012 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -14,12 +14,7 @@
 
 package org.apache.tapestry5.corelib.components;
 
-import org.apache.tapestry5.BindingConstants;
-import org.apache.tapestry5.CSSClassConstants;
-import org.apache.tapestry5.ClientElement;
-import org.apache.tapestry5.ComponentAction;
-import org.apache.tapestry5.ComponentResources;
-import org.apache.tapestry5.MarkupWriter;
+import org.apache.tapestry5.*;
 import org.apache.tapestry5.annotations.Environmental;
 import org.apache.tapestry5.annotations.Parameter;
 import org.apache.tapestry5.annotations.SupportsInformalParameters;
@@ -29,7 +24,8 @@ import org.apache.tapestry5.corelib.internal.HiddenFieldPositioner;
 import org.apache.tapestry5.corelib.mixins.TriggerFragment;
 import org.apache.tapestry5.dom.Element;
 import org.apache.tapestry5.ioc.annotations.Inject;
-import org.apache.tapestry5.services.ClientBehaviorSupport;
+import org.apache.tapestry5.json.JSONLiteral;
+import org.apache.tapestry5.json.JSONObject;
 import org.apache.tapestry5.services.ClientDataEncoder;
 import org.apache.tapestry5.services.Environment;
 import org.apache.tapestry5.services.FormSupport;
@@ -49,15 +45,15 @@ import org.slf4j.Logger;
  * The client-side element will now listen to two new event defined by client-side constants:
  * <dl>
  * <dt>Tapestry.CHANGE_VISIBILITY_EVENT</dt>
- * <dd>Change the visiblity as per the event memo's visibility property. When the visiblity changes, the correct
+ * <dd>Change the visibility as per the event memo's visibility property. When the visibility changes, the correct
  * animation is executed.</dd>
  * <dt>Tapestry.HIDE_AND_REMOVE_EVENT</dt>
  * <dd>Hides the element, then removes it from the DOM entirely.
  * </dl>
- * 
+ *
+ * @tapestrydoc
  * @see TriggerFragment
  * @see Form
- * @tapestrydoc
  */
 @SupportsInformalParameters
 public class FormFragment implements ClientElement
@@ -74,7 +70,7 @@ public class FormFragment implements ClientElement
      * If true, then the fragment submits the values from fields it contains <em>even if</em> the fragment is not
      * visible.
      * The default is to omit values from fields when the enclosing fragment is non visible.
-     * 
+     *
      * @since 5.2.0
      */
     @Parameter
@@ -82,14 +78,18 @@ public class FormFragment implements ClientElement
 
     /**
      * Name of a function on the client-side Tapestry.ElementEffect object that is invoked to make the fragment visible.
-     * If not specified, then the default "slidedown" function is used.
+     * This is no longer used.
+     *
+     * @deprecated Deprecated in 5.4; clients that wish to animate should handle the <code>events.element.didShow</code> client-side event.
      */
     @Parameter(defaultPrefix = BindingConstants.LITERAL)
     private String show;
 
     /**
      * Name of a function on the client-side Tapestry.ElementEffect object that is invoked when the fragment is to be
-     * hidden. If not specified, the default "slideup" function is used.
+     * hidden.  This is no longer used.
+     *
+     * @deprecated Deprecated in 5.4; clients that wish to animate should handle the <code>events.element.didHide</code> client-side event.
      */
     @Parameter(defaultPrefix = BindingConstants.LITERAL)
     private String hide;
@@ -110,10 +110,11 @@ public class FormFragment implements ClientElement
 
     /**
      * A javascript function that overrides the default visibility search bound.
-     * Tapestry normally ensures that not only the form fragment but all parent elements up to the containing form
+     * Tapestry normally ensures that not only the form fragment but all parent elements up to the containing body
      * are visible when determining whether to submit the contents of a form fragment.  This behavior can be modified by
      * supplying a javascript function that receives the "current" element in the chain.  Returning true will stop the
-     * search (and report "isDeepVisible" as true).  Returning false will continue the search up the chain.
+     * search (and report ElementWrapper.deepVisible() as true).  Returning false will continue the search up the chain.
+     *
      * @since 5.3
      */
     @Parameter(defaultPrefix = BindingConstants.LITERAL, allowNull = false)
@@ -128,9 +129,6 @@ public class FormFragment implements ClientElement
     @Inject
     private ComponentResources resources;
 
-    @Environmental
-    private ClientBehaviorSupport clientBehaviorSupport;
-
     private String clientId;
 
     private ComponentActionSink componentActions;
@@ -168,9 +166,23 @@ public class FormFragment implements ClientElement
         resources.renderInformalParameters(writer);
 
         if (!visible)
+        {
             element.addClassName(CSSClassConstants.INVISIBLE);
+        }
+
+        JSONObject spec = new JSONObject("element", clientId);
+
+        if (visibleBound != null)
+        {
+            spec.put("bound", new JSONLiteral(visibleBound));
+        }
+
+        if (alwaysSubmit)
+        {
+            spec.put("alwaysSubmit", true);
+        }
 
-        clientBehaviorSupport.addFormFragment(clientId, alwaysSubmit, show, hide, visibleBound);
+        javascriptSupport.require("core/form-fragment").invoke("initFragment").with(spec);
 
         componentActions = new ComponentActionSink(logger, clientDataEncoder);
 
@@ -206,18 +218,18 @@ public class FormFragment implements ClientElement
     /**
      * Closes the &lt;div&gt; tag and pops off the {@link org.apache.tapestry5.services.FormSupport} environmental
      * override.
-     * 
+     *
      * @param writer
      */
     void afterRender(MarkupWriter writer)
     {
         hiddenFieldPositioner.getElement().attributes("type", "hidden",
 
-        "name", Form.FORM_DATA,
+                "name", Form.FORM_DATA,
 
-        "id", clientId + "-hidden",
+                "id", clientId + "-hidden",
 
-        "value", componentActions.getClientData());
+                "value", componentActions.getClientData());
 
         writer.end(); // div
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/48bec3a6/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/TriggerFragment.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/TriggerFragment.java b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/TriggerFragment.java
index 1a1b93e..3be32bf 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/TriggerFragment.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/TriggerFragment.java
@@ -1,4 +1,4 @@
-// Copyright 2008, 2010, 2011 The Apache Software Foundation
+// Copyright 2008, 2010, 2011, 2012 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -59,8 +59,15 @@ public class TriggerFragment
     @HeartbeatDeferred
     void beginRender()
     {
-        JSONObject spec = new JSONObject("triggerId", container.getClientId(), "fragmentId", fragment.getClientId()).put("invert", invert);
+        JSONObject spec = new JSONObject(
+                "triggerId", container.getClientId(),
+                "fragmentId", fragment.getClientId());
 
-        javascriptSupport.addInitializerCall("linkTriggerToFormFragment", spec);
+        if (invert)
+        {
+            spec.put("invert", true);
+        }
+
+        javascriptSupport.require("core/form-fragment").invoke("linkTrigger").with(spec);
     }
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/48bec3a6/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientBehaviorSupportImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientBehaviorSupportImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientBehaviorSupportImpl.java
index 3a018b3..7f0cd8e 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientBehaviorSupportImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientBehaviorSupportImpl.java
@@ -18,7 +18,6 @@ import org.apache.tapestry5.Field;
 import org.apache.tapestry5.Link;
 import org.apache.tapestry5.corelib.data.InsertPosition;
 import org.apache.tapestry5.json.JSONArray;
-import org.apache.tapestry5.json.JSONLiteral;
 import org.apache.tapestry5.json.JSONObject;
 import org.apache.tapestry5.services.ClientBehaviorSupport;
 import org.apache.tapestry5.services.Environment;
@@ -72,7 +71,7 @@ public class ClientBehaviorSupportImpl implements ClientBehaviorSupport
     }
 
     /**
-     * @deprecated Use {@link #addFormFragment(String,boolean,String,String)} instead
+     * @deprecated Use {@link #addFormFragment(String, boolean, String, String)} instead
      */
     public void addFormFragment(String clientId, String showFunctionName, String hideFunctionName)
     {
@@ -89,18 +88,7 @@ public class ClientBehaviorSupportImpl implements ClientBehaviorSupport
 
     public void addFormFragment(String clientId, boolean alwaysSubmit, String showFunctionName, String hideFunctionName, String visibilityBoundFunctionName)
     {
-        JSONObject spec = new JSONObject("element", clientId);
-
-        addFunction(spec, "show", showFunctionName);
-        addFunction(spec, "hide", hideFunctionName);
-
-        if (visibilityBoundFunctionName != null)
-            spec.put("bound", new JSONLiteral(visibilityBoundFunctionName));
-
-        if (alwaysSubmit)
-            spec.put("alwaysSubmit", true);
-
-        javascriptSupport.addInitializerCall("formFragment", spec);
+        throw new UnsupportedOperationException("ClientBehaviorSupport.addFormFragment is no longer supported. Use the core/form-fragment module instead.");
     }
 
     public void addFormInjector(String clientId, Link link, InsertPosition insertPosition, String showFunctionName)
@@ -149,6 +137,8 @@ public class ClientBehaviorSupportImpl implements ClientBehaviorSupport
     public void commit()
     {
         if (validations.length() != 0)
+        {
             javascriptSupport.addInitializerCall("validate", validations);
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/48bec3a6/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/CoreJavaScriptStack.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/CoreJavaScriptStack.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/CoreJavaScriptStack.java
index 0e85a2a..1e0e491 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/CoreJavaScriptStack.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/CoreJavaScriptStack.java
@@ -90,8 +90,6 @@ public class CoreJavaScriptStack implements JavaScriptStack
 
                     ROOT + "/t5-console.js",
 
-                    ROOT + "/t5-formfragment.js",
-
                     ROOT + "/t5-alerts.js",
 
                     ROOT + "/tapestry.js",

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/48bec3a6/tapestry-core/src/main/java/org/apache/tapestry5/services/ClientBehaviorSupport.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/ClientBehaviorSupport.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/ClientBehaviorSupport.java
index 1cd8d47..2ca64ab 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/ClientBehaviorSupport.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/ClientBehaviorSupport.java
@@ -23,6 +23,8 @@ import org.apache.tapestry5.corelib.data.InsertPosition;
  * the client-side behavior associated with {@link org.apache.tapestry5.corelib.components.FormFragment}s.
  *
  * @see org.apache.tapestry5.corelib.components.Zone
+ * @deprecated Deprecated in 5.4 with no replacement. Use {@link org.apache.tapestry5.services.javascript.JavaScriptSupport} directly,
+ *             instead.
  */
 public interface ClientBehaviorSupport
 {
@@ -88,6 +90,8 @@ public interface ClientBehaviorSupport
     /**
      * Adds a new client-side Tapestry.FormFragment object. FormFragment's are used to make parts of a client-side form
      * visible or invisible, which involves interactions with both the server-side and client-side validation.
+     * <p/>
+     * <strong>This implementation has been removed in 5.4; it throws an {@link UnsupportedOperationException}.</strong>
      *
      * @param clientId
      *         client-side id of the element that will be made visible or invisible
@@ -101,6 +105,7 @@ public interface ClientBehaviorSupport
      * @param visibilityBoundFunctionName
      *         name of the function used to bound the isDeepVisible search, or null for the default
      * @since 5.3
+     * @deprecated In 5.4; use the <code>core/form-fragment</code> module instead.
      */
     void addFormFragment(String clientId, boolean alwaysSubmit, String showFunctionName, String hideFunctionName, String visibilityBoundFunctionName);
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/48bec3a6/tapestry-core/src/main/resources/org/apache/tapestry5/t5-forceload.js
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/resources/org/apache/tapestry5/t5-forceload.js b/tapestry-core/src/main/resources/org/apache/tapestry5/t5-forceload.js
index 9bec9ee..dcb810b 100644
--- a/tapestry-core/src/main/resources/org/apache/tapestry5/t5-forceload.js
+++ b/tapestry-core/src/main/resources/org/apache/tapestry5/t5-forceload.js
@@ -21,7 +21,6 @@
  */
 define("core/compat/t5-forceload", [
     "core/compat/t5-alerts",
-    "core/compat/t5-formfragment",
     "core/compat/tree",
     "core/compat/tapestry-messages"],
         // Does nothing, but forces the other define()-ed "modules" to have their dependencies

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/48bec3a6/tapestry-core/src/main/resources/org/apache/tapestry5/t5-formfragment.js
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/resources/org/apache/tapestry5/t5-formfragment.js b/tapestry-core/src/main/resources/org/apache/tapestry5/t5-formfragment.js
deleted file mode 100644
index 84ff768..0000000
--- a/tapestry-core/src/main/resources/org/apache/tapestry5/t5-formfragment.js
+++ /dev/null
@@ -1,101 +0,0 @@
-/* Copyright 2011, 2012 The Apache Software Foundation
- *
- * 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.
- */
-
-define("core/compat/t5-formfragment", ["core/compat/t5-init"], function () {
-    T5.extendInitializers(function () {
-
-        function init(spec) {
-
-            var element = $(spec.element);
-
-            var hidden = $(spec.element + "-hidden");
-            var form = $(hidden.form);
-
-            var opts = (spec.bound && { bound: spec.bound }) || {};
-            if (!spec.alwaysSubmit) {
-                hidden.disabled = !element.isDeepVisible(opts);
-            }
-
-            function updateUI(makeVisible) {
-
-                if (!spec.alwaysSubmit) {
-                    hidden.disabled = !(makeVisible && element.parentNode.isDeepVisible(opts));
-                }
-
-                var effect = makeVisible ? Tapestry.ElementEffect[spec.show]
-                        || Tapestry.ElementEffect.slidedown
-                        : Tapestry.ElementEffect[spec.hide]
-                        || Tapestry.ElementEffect.slideup;
-                return effect(element);
-            }
-
-            element.observe(Tapestry.CHANGE_VISIBILITY_EVENT, function (event) {
-                // Since events propagate up, you have to call event.stop()
-                // here to prevent hiding/revealing any container FormFragment elements.
-                event.stop();
-
-                var makeVisible = event.memo.visible;
-
-                if (makeVisible == element.visible())
-                    return;
-
-                updateUI(makeVisible);
-            });
-
-            element.observe(Tapestry.HIDE_AND_REMOVE_EVENT,
-                    function (event) {
-                        event.stop();
-                        var effect = updateUI(false);
-
-                        effect.options.afterFinish = function () {
-                            Tapestry.remove(element);
-                        };
-                    });
-        }
-
-        /**
-         * Links a FormFragment to a trigger (a radio or a checkbox), such
-         * that changing the trigger will hide or show the FormFragment.
-         * Care should be taken to render the page with the checkbox and the
-         * FormFragment's visibility in agreement.
-         */
-        function linker(spec) {
-            var trigger = $(spec.triggerId);
-
-            function update() {
-                var checked = trigger.checked;
-                var makeVisible = checked == !spec.invert;
-
-                $(spec.fragmentId).fire(Tapestry.CHANGE_VISIBILITY_EVENT, {
-                    visible: makeVisible
-                }, true);
-            }
-
-            // Let the event bubble up to the form level.
-            if (trigger.type == "radio") {
-                $(trigger.form).observe("click", update);
-                return;
-            }
-
-            // Normal trigger is a checkbox; listen just to it.
-            trigger.observe("click", update);
-        }
-
-        return {
-            formFragment: init,
-            linkTriggerToFormFragment: linker
-        };
-    });
-});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/48bec3a6/tapestry-core/src/main/resources/org/apache/tapestry5/t5-prototype.js
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/resources/org/apache/tapestry5/t5-prototype.js b/tapestry-core/src/main/resources/org/apache/tapestry5/t5-prototype.js
index e12500c..4be58b4 100644
--- a/tapestry-core/src/main/resources/org/apache/tapestry5/t5-prototype.js
+++ b/tapestry-core/src/main/resources/org/apache/tapestry5/t5-prototype.js
@@ -44,7 +44,7 @@ define("core/compat/t5-spi", ["core/spi", "core/compat/t5", "core/compat/t5-even
         });
 
         function appendMarkup(element, markup) {
-            spi.wrap(element).append(markup);
+            spi(element).append(markup);
 
             return element;
         }
@@ -58,4 +58,4 @@ define("core/compat/t5-spi", ["core/spi", "core/compat/t5", "core/compat/t5-even
         };
     });
 
-});
\ No newline at end of file
+});

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/48bec3a6/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js b/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
index 8cdcde8..44263f5 100644
--- a/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
+++ b/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
@@ -504,7 +504,7 @@ define("core/compat/tapestry", [
                  *            (a Submit or LinkSubmit)
                  */
                 setSubmittingElement: function (form, element) {
-                    forms.setSubmittingElement(spi.wrap(form), spi.wrap(element));
+                    forms.setSubmittingElement(spi(form), spi(element));
                 },
 
                 /**
@@ -512,7 +512,7 @@ define("core/compat/tapestry", [
                  * the form.
                  */
                 skipValidation: function (form) {
-                    forms.skipValidation(spi.wrap(form));
+                    forms.skipValidation(spi(form));
                 },
 
                 /**
@@ -1314,15 +1314,15 @@ define("core/compat/tapestry", [
     });
 
     function _show(element) {
-        return new spi.wrap(element).show();
+        return new spi(element).show();
     }
 
     function _hide(element) {
-        return new spi.wrap(element).hide();
+        return new spi(element).hide();
     }
 
     function _none(element) {
-        return new spi.wrap(element);
+        return new spi(element);
     }
 
     /*
@@ -1387,7 +1387,7 @@ define("core/compat/tapestry", [
             this.elementId = spec.element;
 
             // When updates arrive, the outer element is always made visible.
-            this.element = spi.wrap(spec.element);
+            this.element = spi(spec.element);
             this.specParameters = spec.parameters;
 
             /* Link the div back to this zone. */

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/48bec3a6/tapestry-core/src/test/coffeescript/org/apache/tapestry5/integration/app1/pages/test-spi.coffee
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/coffeescript/org/apache/tapestry5/integration/app1/pages/test-spi.coffee b/tapestry-core/src/test/coffeescript/org/apache/tapestry5/integration/app1/pages/test-spi.coffee
index c38dfe1..234ed3f 100644
--- a/tapestry-core/src/test/coffeescript/org/apache/tapestry5/integration/app1/pages/test-spi.coffee
+++ b/tapestry-core/src/test/coffeescript/org/apache/tapestry5/integration/app1/pages/test-spi.coffee
@@ -2,19 +2,19 @@ require ["core/spi"], (spi) ->
   module "core/spi"
 
   test "get wrapped element by id", ->
-    e = spi.wrap "spi-eventelement"
+    e = spi "spi-eventelement"
 
     ok e isnt null, "element found and wrapped"
 
   test "get wrapped element by unknown id is null", ->
-    e = spi.wrap "spi-does-not-exist-element"
+    e = spi "spi-does-not-exist-element"
 
     ok e is null, "element not found and null"
 
   test "pause and resume events", ->
 
     clicks = 0
-    container = spi.wrap "spi-eventelement"
+    container = spi "spi-eventelement"
     button = container.find "a"
 
     # Remember that Prototype will never trigger a native event, just a
@@ -45,7 +45,7 @@ require ["core/spi"], (spi) ->
   test "trigger native events", ->
 
     clicks = 0
-    container = spi.wrap "spi-eventelement"
+    container = spi "spi-eventelement"
     button = container.find "a"
 
     eh = container.on "click", "a", (event) ->
@@ -61,7 +61,7 @@ require ["core/spi"], (spi) ->
   test "selector used with events filters", ->
 
     clicks = 0
-    container = spi.wrap "spi-eventelement"
+    container = spi "spi-eventelement"
     primary = container.find "a.btn-primary"
     secondary = container.find "a[data-use=secondary]"
 
@@ -81,7 +81,7 @@ require ["core/spi"], (spi) ->
 
   test "this is matched element in handler", ->
 
-    container = spi.wrap "spi-eventelement"
+    container = spi "spi-eventelement"
     primary = container.find "a.btn-primary"
 
     eh = container.on "x:click", "a.btn-primary", (event) ->
@@ -95,7 +95,7 @@ require ["core/spi"], (spi) ->
 
   test "visibility, hide(), and show()", ->
 
-    e = (spi.wrap "spi-visibility").find "span"
+    e = (spi "spi-visibility").find "span"
 
     equal e.visible(), true, "element is initially visible"