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

[1/2] git commit: Create core/builder module for dynamically constructing Elements Create core/exceptionframe for displaying the Ajax exception frame Rewire t5-ajax to use core/exceptionframe Rework other code to use core/spi:domReady()

Updated Branches:
  refs/heads/5.4-js-rewrite c562186a3 -> f9d53e733


Create core/builder module for dynamically constructing Elements
Create core/exceptionframe for displaying the Ajax exception frame
Rewire t5-ajax to use core/exceptionframe
Rework other code to use core/spi:domReady()


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

Branch: refs/heads/5.4-js-rewrite
Commit: f9d53e73340a37e297e5e6eeab870a37ad4581a6
Parents: 88045f0
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Wed Aug 8 15:04:35 2012 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Wed Aug 8 15:04:35 2012 -0700

----------------------------------------------------------------------
 .../META-INF/modules/core/builder.coffee           |  107 ++++++++++++
 .../META-INF/modules/core/exceptionframe.coffee    |   73 +++++++++
 .../coffeescript/META-INF/modules/core/spi.coffee  |  126 +++++++++++----
 .../coffeescript/META-INF/modules/core/zone.coffee |    5 +-
 .../main/resources/org/apache/tapestry5/t5-ajax.js |   80 +---------
 .../resources/org/apache/tapestry5/t5-prototype.js |   12 +-
 .../resources/org/apache/tapestry5/tapestry.js     |    2 +-
 7 files changed, 284 insertions(+), 121 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f9d53e73/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
new file mode 100644
index 0000000..0bf76d8
--- /dev/null
+++ b/tapestry-core/src/main/coffeescript/META-INF/modules/core/builder.coffee
@@ -0,0 +1,107 @@
+# 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/builder
+#
+# A system for constructing DOM element nodes for a particular structure in minimal code.  The basic syntax is:
+# builder(elementDescription, body...) and the result is a DOM element.  The element description is
+# primarily the name of the element.
+#
+# It may contain sequences of ".name"; these appropriate CSS syntax to describe a CSS class name for the element.  The
+# element name may be omitted when CSS class names are specified, in which case "div" is the default. Multiple CSS class
+# names are allowed.
+#
+# The description may also include a '>' character; this represents the start of a nested element; in this way
+# a structure can quickly be specified.
+#
+# The body may consist of:
+# Objects: used to specify attributes and event handles of the element
+# Strings: literal text
+# Array: a nested element definition
+# For an Object, each key and value is simply added as an attribute. However, keys that start with "on" are assumed to
+# be event handler functions. The special key "on" consists of nested event handlers for the keys. The following are
+# equivlent:
+# { onclick: -> ... } and
+# { on: { click: -> ... }}
+define ["_", "core/spi"], (_, spi) ->
+  createElement = (elementDescription) ->
+    # TODO: Support #id for setting the id of an element, maybe others, such as ?name for the name of an input element.
+    # That will require a regex or more sophisticated parsing.
+    terms = elementDescription.trim().split(".")
+
+    elementName = terms.shift() or "div"
+
+    element = document.createElement elementName
+
+    element.className = terms.join " "
+
+    return element
+
+  addAttributes = (element, attributes) ->
+    return unless attributes
+
+    wrapper = spi.wrap element
+
+    for name, value of attributes
+      if name is "on"
+        for eventName, handler of value
+          wrapper.on eventName, handler
+      else if name.startsWith "on"
+        wrapper.on (name.substring 2), value
+      else
+        wrapper.setAttribute name, value
+
+    return null
+
+  addAttributesAndBody = (element, body) ->
+    for nested in body
+      unless nested?
+        # Ignore null nodes
+      else if _.isString nested
+        element.appendChild document.createTextNode nested
+      else if _.isArray nested
+        [elementDescription, nestedBody...] = nested
+        nestedElement = buildTree elementDescription, nestedBody
+        element.appendChild nestedElement
+      else if _.isObject nested
+        addAttributes element, nested
+      else throw new Error "Unexpected body value <#{nested}> while building DOM elements."
+
+    return null
+
+  buildTree = (elementDescription, body) ->
+    splitx = elementDescription.indexOf ">"
+    currentDescription =
+      if splitx is -1
+        elementDescription
+      else
+        elementDescription.substring 0, splitx
+
+    element = createElement currentDescription
+
+    if splitx is -1
+      addAttributesAndBody element, body
+    else
+      nestedDescription = elementDescription.substring splitx + 1
+      nestedElement = buildTree nestedDescription, body
+      element.appendChild nestedElement
+
+    return element
+
+  # The module exports a single function that builds the tree of elements and returns the top element, wrapped as an
+  # spi.ElementWrapper.
+  (elementDescription, body...) ->
+    element = buildTree elementDescription, body
+
+    spi.wrap element
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f9d53e73/tapestry-core/src/main/coffeescript/META-INF/modules/core/exceptionframe.coffee
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/coffeescript/META-INF/modules/core/exceptionframe.coffee b/tapestry-core/src/main/coffeescript/META-INF/modules/core/exceptionframe.coffee
new file mode 100644
index 0000000..0293f2b
--- /dev/null
+++ b/tapestry-core/src/main/coffeescript/META-INF/modules/core/exceptionframe.coffee
@@ -0,0 +1,73 @@
+# 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/exceptionframe
+#
+# Manages a special element used to present a HTML exception report from an Ajax request (where a non-markup response
+# was expected, including a partial page render response).
+
+define ["core/spi", "core/builder", "_"],
+  (spi, builder, _) ->
+    container = null
+    iframe = null
+    iframeDocument = null
+
+    write = (content) ->
+      # Clear current content:
+      iframeDocument.open()
+      # Write new content:
+      iframeDocument.write content
+      iframeDocument.close()
+
+    clear = (event) ->
+      event.stop()
+      write ""
+      container.hide()
+
+    # Called after the window has resized to adjust the size of the iframe.
+    resize = ->
+      dims = spi.viewportDimensions()
+      ;
+
+      iframe.width = dims.width - 100
+      iframe.height = dims.height - 120
+
+    create = ->
+      return if container
+
+      container = builder ".t-exception-container",
+        ["iframe.t-exception-frame", width: "100%"],
+        [".t-exception-controls > span.t-exception-close", "Close"]
+
+      spi.body().append container.hide()
+
+      iframe = (container.find "iframe").element
+
+      # See http://xkr.us/articles/dom/iframe-document/
+
+      iframeDocument = iframe.contentWindow or iframe.contentDocument
+      if iframeDocument.document
+        iframeDocument = iframeDocument.document
+
+      container.on "click", ".t-exception-close", clear
+
+      spi.on window, "resize", (_.debounce resize, 20)
+
+    # Export single function:
+
+    (exceptionContent) ->
+      create()
+      write exceptionContent
+      resize()
+      container.show()
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f9d53e73/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 ff40b3e..e9aacce 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
@@ -13,35 +13,63 @@
 # limitations under the License.
 
 # Service Provider Interface
-# This is the core of the abstraction layer that allows the majority of components to operate
-# without caring whether the underlying infrastructure framework is Prototype, jQuery, or something else.
-# This is the standard SPI, which wraps Prototype ... but does it in a way that makes it relatively
-# easy to swap in jQuery instead.
+#
+# This is the core of the abstraction layer that allows the majority of components to operate without caring whether the
+# underlying infrastructure framework is Prototype, jQuery, or something else.  This is the standard SPI, which wraps
+# Prototype ... but does it in a way that makes it relatively easy to swap in jQuery instead.
 
 # TODO: Define a dependency on "prototype" when that's exposed as a stub module.
 define ["_"], (_) ->
   split = (str) ->
     _(str.split " ").reject (s) -> s is ""
 
+  # Converts content (provided to ElementWrapper.update() or .append()) into an appropriate type. This primarily exists
+  # to validate the value, and to "unpack" an ElementWrapper into a DOM element.
+  convertContent = (content) ->
+    if _.isString content
+      return content
+
+    if _.isElement content
+      return content
+
+    if content.constructor?.name is "ElementWrapper"
+      return content.element
+
+    throw new Error "Provided value <#{content}> is not valid as DOM element content."
+
   # Generic view of an Event that is passed to a handler function.
+  #
   # Properties:
+  # nativeEvent - the native Event object, which may provide additional information
   # memo - the object passed to ElementWrapper.trigger()
+  # type - the name of the event that was triggered
+  # char - the character value of the pressed key, if a printable character (string)
+  # key -The key value of the pressed key. This is the same as the char property for printable keys,
+  # or a key name for others.
   # stop() - function to prevent propogation of the event (both bubbling and the default action).
-  class Event
+  class EventWrapper
 
-    constructor: (@prototypeEvent) ->
-      @memo = @prototypeEvent.memo
+    constructor: (event) ->
+      @nativeEvent = event
+      @memo = event.memo
+      @type = event.type
+
+      @char = event.char
+      @key = event.key
 
     # Stops the event which prevents further propagation of the event,
     # as well as event bubbling.
     stop: ->
-      @prototypeEvent.stop()
+      @nativeEvent.stop()
 
   # Value returned from on(); an EventHandler is used to stop listening to
-  # events, or even pause listening.
+  # events, or even temporarily pause listening.
   class EventHandler
 
   # Registers the handler as an event listener for matching elements and event names.
+  # Note: it is possible to add handlers for events on the window object, but
+  # start() and stop() do not do anything for such events.
+  #
   # elements - array of DOM elements
   # eventNames - array of event names
   # match - selector to match bubbled elements, or null
@@ -52,14 +80,19 @@ define ["_"], (_) ->
       wrapped = (prototypeEvent, matchedElement) ->
         # Set "this" to be the matched element (jQuery style), rather than
         # the element on which the event is observed.
-        handler.call(matchedElement, new Event prototypeEvent)
+        handler.call(matchedElement, new EventWrapper prototypeEvent)
 
       # Prototype Event.Handler instances
       @protoHandlers = []
 
       _.each elements, (element) =>
         _.each eventNames, (eventName) =>
-          @protoHandlers.push element.on eventName, match, wrapped
+          if element is window
+            unless _.isEmpty match
+              throw Error("Matching of elements by selector is not supported for window events.")
+            Event.observe element, eventName, wrapped
+          else
+            @protoHandlers.push element.on eventName, match, wrapped
 
     # Invoked after stop() to restart event listening. Returns this EventHandler instance.
     start: ->
@@ -100,10 +133,10 @@ define ["_"], (_) ->
     getAttribute: (name) ->
       @element.readAttribute name
 
-    # Set the value of the attribute to the given value, then returns this
-    # ElementWrapper.
-    # Note: Prototype has special support for values null, true, and false
-    # that may not be duplicated by other implementations of the SPI.
+    # Set the value of the attribute to the given value, then returns this ElementWrapper.
+    #
+    # Note: Prototype has special support for values null, true, and false that may not be duplicated by other
+    # implementations of the SPI.
     setAttribute: (name, value) ->
       # TODO: case where name is an object, i.e., multiple attributes in a single call.
       # Well, you can just do it, but its not guaranteed to work the same across
@@ -125,16 +158,36 @@ define ["_"], (_) ->
       @element.addClassName name
       this
 
-    # Updates this element with new content, replacing any old content. The new content
-    # may be HTML text, or a DOM element, or null (to remove the body of the element).
+    # Updates this element with new content, replacing any old content. The new content may be HTML text, or a DOM
+    # element, or null (to remove the body of the element).
+    #
     # Returns this ElementWrapper.
     update: (content) ->
-      @element.update content
+      @element.update (convertContent content)
+      this
+
+    # Appends new content (Element or HTML markup string) to the element.
+    #
+    # Returns this ElementWrapper.
+    append: (content) ->
+      @element.insert bottom: (convertContent content)
       this
 
-    # 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).
+    # Finds the first child element that matches the CSS selector.
+    #
+    # Returns the ElementWrapper for the child element, or null if not found.
+    find: (selector) ->
+      match = @element.down selector
+
+      # Prototype returns undefined if not found, we want to return null.
+      if match
+        new ElementWrapper match
+      else
+        return null
+
+    # 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
@@ -142,14 +195,15 @@ define ["_"], (_) ->
 
       @container
 
-    # Returns true if this element is visible, false otherwise. This does not check
-    # to see if all containers of the element are visible.
+    # 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()
 
     # Fires a named event. Returns this ElementWrapper.
+    #
     # eventName - name of event to trigger on the wrapped Element
-    # memo - optional value assocated with the event; available as Event.memo in event handler functions
+    # memo - optional value assocated with the event; available as WrappedeEvent.memo in event handler functions
     trigger: (eventName, memo) ->
       throw new Error("Attempt to trigger event with null event name") unless eventName?
 
@@ -157,20 +211,17 @@ define ["_"], (_) ->
       this
 
     # 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 Event object.
+    # 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
 
-    # Searches for elements contained within this element, matching the CSS selector.
-    # Returns an array of matching elements.
-    find: (selector) ->
-      @element.select selector
-
   parseSelectorToElements = (selector) ->
     if _.isString selector
       return $$ selector
@@ -183,10 +234,12 @@ define ["_"], (_) ->
 
     [selector]
 
+  bodyWrapper = null
+
   exports =
 
-  # 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.
+  # 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.
     domReady: (callback) ->
       document.observe "dom:loaded", callback
@@ -213,8 +266,15 @@ define ["_"], (_) ->
 
     # Returns a wrapper for the provided DOM element that includes key behaviors:
     # hide(), show(), remove(), etc.
-    # element - a DOM element, or the unique id of a DOM element
+    # element - a DOM element, or the window, or the unique id of a DOM element
     # Returns the ElementWrapper.
     wrap: (element) ->
       throw new Error("Attempt to wrap a null DOM element") unless element
       new ElementWrapper element
+
+    # 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)
+
+    # Returns the current dimensions of the viewport. An object with keys width and height is returned.
+    viewportDimensions: -> document.viewport.getDimensions()
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f9d53e73/tapestry-core/src/main/coffeescript/META-INF/modules/core/zone.coffee
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/coffeescript/META-INF/modules/core/zone.coffee b/tapestry-core/src/main/coffeescript/META-INF/modules/core/zone.coffee
index 8986cef..afbb04c 100644
--- a/tapestry-core/src/main/coffeescript/META-INF/modules/core/zone.coffee
+++ b/tapestry-core/src/main/coffeescript/META-INF/modules/core/zone.coffee
@@ -15,9 +15,7 @@
 define ["core/spi", "core/events"],
   (spi, events) ->
     spi.domReady ->
-      body = spi.wrap document.body
-
-      body.on events.zone.update, (event) ->
+      spi.body().on events.zone.update, (event) ->
         zone = spi.wrap this
 
         zone.trigger events.zone.willUpdate
@@ -30,6 +28,5 @@ define ["core/spi", "core/events"],
 
         zone.trigger events.zone.didUpdate
 
-
     # No meaningful value is returned.
     true
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f9d53e73/tapestry-core/src/main/resources/org/apache/tapestry5/t5-ajax.js
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/resources/org/apache/tapestry5/t5-ajax.js b/tapestry-core/src/main/resources/org/apache/tapestry5/t5-ajax.js
index 32f024c..ff2a4eb 100644
--- a/tapestry-core/src/main/resources/org/apache/tapestry5/t5-ajax.js
+++ b/tapestry-core/src/main/resources/org/apache/tapestry5/t5-ajax.js
@@ -17,89 +17,15 @@
  * Defines Tapestry Ajax support, which includes sending requests and receiving
  * replies, but also includes default handlers for errors and failures, and
  * processing of Tapestry's partial page render response (a common response for
- * many types of Ajax requests).             `
+ * many types of Ajax requests).
  */
-define("core/compat/t5-ajax", ["core/compat/t5-spi"], function () {
+define("core/compat/t5-ajax", ["core/exceptionframe"], function (exceptionframe) {
     T5.define("ajax", function () {
 
-        var _ = T5._;
-        var $ = T5.$;
-        var spi = T5.spi;
-
-        var exceptionContainer, iframe, iframeDocument;
 
         function noop() {
         }
 
-        function writeToErrorIFrame(content) {
-            // Clear current content.
-            iframeDocument.open();
-            // Write in the new content.
-            iframeDocument.write(content);
-            iframeDocument.close();
-
-        }
-
-        function resizeExceptionDialog() {
-            // Very Prototype specific!
-            var dims = document.viewport.getDimensions();
-
-            iframe.width = dims.width - 100;
-            iframe.height = dims.height - (100 + 20);
-        }
-
-        /**
-         * When there's a server-side failure, Tapestry sends back the exception report page as HTML.
-         * This function creates and displays a dialog that presents that content to the user using
-         * a created iframe element.
-         * @param exceptionContext HTML markup for the exception report
-         */
-        function showExceptionDialog(exceptionContent) {
-
-            if (!exceptionContainer) {
-                var markup = [ "<div class='t-exception-container'>",
-                    "<iframe class='t-exception-frame' width='100%'></iframe>",
-                    "<div class='t-exception-controls'>",
-                    "<span class='t-exception-close'>Close</span>",
-                    "</div>",
-                    "</div>"].join("");
-
-                exceptionContainer = T5.dom.find(T5.dom.appendMarkup(document.body, markup), 'div.t-exception-container');
-
-                iframe = T5.dom.find(exceptionContainer, "iframe");
-
-                // See http://xkr.us/articles/dom/iframe-document/
-
-                iframeDocument = (iframe.contentWindow || iframe.contentDocument);
-                if (iframeDocument.document) {
-                    iframeDocument = iframeDocument.document;
-                }
-
-                var closeButton = T5.dom.find(exceptionContainer, ".t-exception-close");
-
-                T5.dom.observe(closeButton, "click", function (event) {
-                    event.stop();
-                    writeToErrorIFrame("");
-                    T5.dom.hide(exceptionContainer);
-                });
-
-                // Call it now to set initial width/height.
-
-                resizeExceptionDialog();
-
-                // Very Prototype specific:
-
-                // See http://groups.google.com/group/prototype-scriptaculous/browse_thread/thread/1b0ce3e94020121f/cdbab773fd8e7a4b
-                // debounced to handle the rate at which IE sends the resizes (every pixel!)
-
-                Event.observe(window, "resize", _.debounce(resizeExceptionDialog, 20));
-            }
-
-
-            writeToErrorIFrame(exceptionContent);
-
-            exceptionContainer.show();
-        }
 
         function defaultFailure(transport) {
         }
@@ -146,7 +72,7 @@ define("core/compat/t5-ajax", ["core/compat/t5-spi"], function () {
             defaultFailure: defaultFailure,
             defaultException: defaultException,
             defaultSuccess: noop,
-            showExceptionDialog: showExceptionDialog,
+            showExceptionDialog: exceptionframe,
             request: request
         };
     });

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f9d53e73/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 183b2ea..e12500c 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
@@ -18,12 +18,12 @@
  * Prototype JavaScript library. May also make modifications to Prototype to
  * work with Tapestry.
  */
-define("core/compat/t5-spi", ["core/compat/t5", "core/compat/t5-events", "core/compat/t5-pubsub"], function () {
+define("core/compat/t5-spi", ["core/spi", "core/compat/t5", "core/compat/t5-events", "core/compat/t5-pubsub"], function (spi) {
     T5.define("spi", function () {
 
         function observe(element, eventName, listener) {
 
-            var handler = $(element).on(eventName, listener);
+            var handler = spi.on(element, eventName, listener);
 
             element = null;
             eventName = null;
@@ -34,17 +34,17 @@ define("core/compat/t5-spi", ["core/compat/t5", "core/compat/t5-events", "core/c
             };
         }
 
-        document.observe("dom:loaded", function () {
+        /** This will likely go soon. */
+        spi.domReady(function () {
             T5.sub(T5.events.REMOVE_EVENT_HANDLERS, null, function (element) {
+                        // TODO: Remaining Prototype dependency here:
                         Event.stopObserving(element);
                     }
             );
         });
 
         function appendMarkup(element, markup) {
-            var element = $(element);
-
-            element.insert({ bottom: markup });
+            spi.wrap(element).append(markup);
 
             return element;
         }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f9d53e73/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 c9cc2cd..570ffe5 100644
--- a/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
+++ b/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
@@ -180,7 +180,7 @@ define("core/compat/tapestry", [
          * document object (support for which is provided by Prototype).
          */
         onDOMLoaded: function (callback) {
-            document.observe("dom:loaded", callback);
+            spi.domReady(callback);
         },
 
         /**