A user account is required in order to edit this wiki, but we've had to disable public user registrations due to spam.
To request an account, ask an autoconfirmed user on Chat (such as one of these permanent autoconfirmed members).
Behavior Attachment: Difference between revisions
No edit summary |
mNo edit summary |
||
(33 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
The purpose of this document is provide a general overview of the behavior attachment problem in the Web. | |||
==Overview== | |||
'''Behavior''' can be viewed as a modular unit of Javascript, DOM elements, and CSS styles, designed to be [http://en.wikipedia.org/wiki/Loose_coupling loosely coupled] with its consumer, which could be either a document or another behavior. '''Behavior attachment''' is a mechanism for composing behaviors. | |||
HTML, as exists today, does not provide an organized way of attaching behavior to a DOM element. While you can add individual scripting methods, properties and event handlers to it, there is no way to do this atomically and with proper encapsulation. | |||
In order to effectively provide encapsulation, a behavior attachment method should provide the following properties: | |||
* '''DOM encapsulation''', typically using [http://glazkov.com/2011/01/14/what-the-heck-is-shadow-dom/ shadow DOM]. '''Shadow DOM''' refers to the ability of the browser to include a subtree of DOM elements into the rendering of a document, but not into the main document DOM tree. | |||
* '''Style encapsulation''', or a way to manage expectations of styles outside of the behavior affecting it, and conversely, styles of the behavior affecting the outside. | |||
* '''Event encapsulation''', which is a way to ensure that events, firing inside of the behavior’s DOM elements do not accidentally expose behavior’s implementation details. | |||
==Examples in the Wild== | |||
===Javascript Frameworks=== | |||
In Web applications, the lack of proper behavior attachment method is addressed at a library level, with every Javascript framework attempting to solve this problem. Here is a quick overview of approaches: | |||
{| cellpadding="10" cellspacing="0" style="border-collapse: collapse;" | {| cellpadding="10" cellspacing="0" style="border-collapse: collapse;" | ||
Line 18: | Line 26: | ||
| Creates a parallel object hierarchy to create illusion of homogenous object space, with full wrappers around DOM objects. Relies on [http://dojotoolkit.org/reference-guide/dijit/layout/AccordionContainer.html#id3 inheritance-style] approach by assigning each DOM element a '''dojoType''' attribute in markup, then traversing DOM and attaching corresponding behavior. | | Creates a parallel object hierarchy to create illusion of homogenous object space, with full wrappers around DOM objects. Relies on [http://dojotoolkit.org/reference-guide/dijit/layout/AccordionContainer.html#id3 inheritance-style] approach by assigning each DOM element a '''dojoType''' attribute in markup, then traversing DOM and attaching corresponding behavior. | ||
|- valign="top" style="border-bottom: 1px solid LightGray;" | |- valign="top" style="border-bottom: 1px solid LightGray;" | ||
| align="right" | [http://code.google.com/webtoolkit/ | | align="right" | [http://code.google.com/webtoolkit/ Google Web Toolkit] | ||
| Also uses parallel object hierarchy to shield the user from behavior attachment deficiency, relying on inheritance | | Also uses parallel object hierarchy to shield the user from behavior attachment deficiency, relying on [http://google-web-toolkit.googlecode.com/svn/javadoc/latest/com/google/gwt/user/client/ui/Button.html inheritance] for compartmentalization and reuse. | ||
|- valign="top" style="border-bottom: 1px solid LightGray;" | |- valign="top" style="border-bottom: 1px solid LightGray;" | ||
| align="right" | [http://jqueryui.com/ JQuery UI] | | align="right" | [http://jqueryui.com/ JQuery UI] | ||
| | | A good balance of insulation from DOM objects with just-in-time wrapping. [http://en.wikipedia.org/wiki/Progressive_enhancement Progressive enhancement] is the adopted technique of [http://jqueryui.com/demos/accordion/ applying behavior]. The behavior is transient and often an API is provide to [http://jqueryui.com/demos/accordion/#method-destroy detach] it. It's interesting that the API is very late-bound and based on passing strings as method names. | ||
|- valign="top" style="border-bottom: 1px solid LightGray;" | |- valign="top" style="border-bottom: 1px solid LightGray;" | ||
| align="right" | [http://www.prototypejs.org/ Prototype] | | align="right" | [http://www.prototypejs.org/ Prototype] | ||
Line 28: | Line 36: | ||
|- valign="top" style="border-bottom: 1px solid LightGray;" | |- valign="top" style="border-bottom: 1px solid LightGray;" | ||
| align="right" | [http://www.sencha.com/ Sencha] | | align="right" | [http://www.sencha.com/ Sencha] | ||
| | | Aggressive insulation from DOM with a Javascript objects as proxies, simple [http://dev.sencha.com/deploy/ext-4.0.2a/examples/form/combos.js inheritance model] (even maps ids of the underlying DOM elements to the variable names). | ||
|- valign="top" style="border-bottom: 1px solid LightGray;" | |- valign="top" style="border-bottom: 1px solid LightGray;" | ||
| align="right" | [http://www.sproutcore.com/ SproutCore] | | align="right" | [http://www.sproutcore.com/ SproutCore] | ||
| | | Again, Javascript objects as proxies, extensive inheritance-based hierarchy of [http://docs.sproutcore.com/#doc=frameworks_core_foundation_mixins_template_helpers_text_field_support.js&src=true UI objects]. | ||
|} | |||
Two interesting symptoms emerge after analysis of the approaches: | |||
* '''Parallel object hierarchies'''. Since there is no way to incorporate a DOM element into object hierarchy, Javascript objects typically expose behavior-specific APIs, while using DOM objects as building blocks underneath. This extra layer of indirection has a negative impact on framework interoperability and is generally a [http://en.wikipedia.org/wiki/Leaky_abstraction leaky abstraction]. | |||
* '''Dynamic-sounding techniques for permanently attaching behavior'''. In the absence of a way to instantiate a DOM element with a new behavior attached, many frameworks use decoration/mixin-like patterns in its place. However the semantics and effect of application is one-way in most cases, indicating that the actual intent is to attach behavior as close to element instantiation as possible. | |||
===Extensions=== | |||
Behavior attachment is also used by browser extensions, where an extension script, running in the context of the document, may attach extra behavior (including UI), to give the user more functionality within a document. Typical examples of such extensions are: | |||
* [https://chrome.google.com/webstore/detail/kanbnempkjnhadplbfgdaagijdbdbjeb Auto Replay for YouTube] | |||
* [https://chrome.google.com/webstore/detail/chiikmhgllekggjhdfjhajkfdkcngplp Scroll To Top Button] | |||
* [https://chrome.google.com/webstore/detail/nonjdcjchghhkdoolnlbekcfllmednbl Hover Zoom] | |||
* [https://chrome.google.com/webstore/detail/naddbmiihfcdfaeencbcmbpioghcjlje Craigslist Helper] | |||
The main challenge for these extensions is to add and remove behavior to DOM elements (including extra DOM elements) to an existing document with least disruption, preferably in a way where the scripts of the document aren’t ever aware of these behavior attachments. | |||
===Built-in HTML Elements=== | |||
Another example of behavior attachment can sometimes be found in the browser itself, where complex built-in controls are created using shadow DOM. Here are a few examples in [http://webkit.org WebKit]: | |||
* <code>input</code> [http://codesearch.google.com/codesearch#OAMlx_jo-ck/src/third_party/WebKit/Source/WebCore/html/HTMLInputElement.cpp&l=106 element] | |||
* <code>audio</code> and <code>video</code> [http://codesearch.google.com/codesearch#OAMlx_jo-ck/src/third_party/WebKit/Source/WebCore/html/shadow/MediaControlRootElement.cpp element]. This one is interesting, because it's composed out of other HTML elements with attached behavior (like <code>input[type=range]</code>). | |||
* <code>details</code> [http://codesearch.google.com/codesearch#OAMlx_jo-ck/src/third_party/WebKit/Source/WebCore/html/HTMLDetailsElement.cpp&l=155 element] | |||
This behavior attachment is singular and permanent, surviving throughout the lifetime of the element. '''Encapsulation''' is an important property for this behavior attachment, since the browser should never leak the implementation details of the HTML elements to the document. | |||
==Behavior Attachment Methods== | |||
To better understand the intent of behavior attachment, we can split these examples in the wild into two general groups: | |||
* An '''element behavior attachment''', where the behavior is permanently associated with the element and creates a new type of element; and | |||
* A '''decorator behavior attachment''', where transient behaviors are given to or taken away from an element, modifying aspects of its properties, but leave the identity of an element intact. | |||
The table below provides a comprehensive comparison between the two methods: | |||
{| cellpadding="10" cellspacing="0" style="border-collapse: collapse;" | {| cellpadding="10" cellspacing="0" style="border-collapse: collapse;" | ||
|- valign="top" style="border-bottom: 1px solid LightGray;" | |- valign="top" style="border-bottom: 1px solid LightGray;" | ||
! width="10%" | | ! width="10%" | | ||
! width="40%" align="left" | Element | |||
! width="40%" align="left" | Decorator | ! width="40%" align="left" | Decorator | ||
|- valign="top" style="border-bottom: 1px solid LightGray;" | |- valign="top" style="border-bottom: 1px solid LightGray;" | ||
! align="right" | Purpose | ! align="right" | Purpose | ||
| Create new content building blocks. | |||
| Give existing content new behavior and/or appearance. | | Give existing content new behavior and/or appearance. | ||
|- valign="top" style="border-bottom: 1px solid LightGray;" | |- valign="top" style="border-bottom: 1px solid LightGray;" | ||
! align="right" | Paradigm | ! align="right" | Paradigm | ||
| [http://en.wikipedia.org/wiki/Object-oriented_programming Object-Oriented Programming] | |||
| [http://en.wikipedia.org/wiki/Aspect-oriented_programming Aspect-Oriented Programming] | | [http://en.wikipedia.org/wiki/Aspect-oriented_programming Aspect-Oriented Programming] | ||
|- valign="top" style="border-bottom: 1px solid LightGray;" | |- valign="top" style="border-bottom: 1px solid LightGray;" | ||
! align="right" | Compartmentalization and Reuse Vehicle | ! align="right" | Compartmentalization and Reuse Vehicle | ||
| Inheritance | |||
| Aspect | | Aspect | ||
|- valign="top" style="border-bottom: 1px solid LightGray;" | |- valign="top" style="border-bottom: 1px solid LightGray;" | ||
! align="right" | Symptoms | ! align="right" | Symptoms | ||
| | |||
* There is only one behavior that is typically associated with an element. | |||
* There is a desire to minimize the time when an element has no associated behavior. | |||
| | | | ||
* It is expected that an element may abruptly enter or exit association with the behavior. | * It is expected that an element may abruptly enter or exit association with the behavior. | ||
* There is a desire to not intrude on the original properties of an element. | * There is a desire to not intrude on the original properties of an element. | ||
|- valign="top" style="border-bottom: 1px solid LightGray;" | |- valign="top" style="border-bottom: 1px solid LightGray;" | ||
! align="right" | Examples of Use | ! align="right" | Examples of Use | ||
| | | | ||
* Implement built-in HTML controls: input/textarea, media, etc. | * Implement built-in HTML controls: input/textarea, media, etc. | ||
* Define an element to represent a customizable calendar view. | * Define an element to represent a customizable calendar view. | ||
* Define a button row control with application-specific grouping logic (see GMail button bars). | * Define a button row control with application-specific grouping logic (see GMail button bars). | ||
| | |||
* Add special UI treatment to all vcards in a document. | |||
* Create an extension to provide extra download options for certain types of links. | |||
|- valign="top" style="border-bottom: 1px solid LightGray;" | |- valign="top" style="border-bottom: 1px solid LightGray;" | ||
! align="right" | Identity | ! align="right" | Identity | ||
| Creates a new type of element. | |||
| Does not change the identity of the element. | | Does not change the identity of the element. | ||
|- valign="top" style="border-bottom: 1px solid LightGray;" | |- valign="top" style="border-bottom: 1px solid LightGray;" | ||
! align="right" | Lifetime | ! align="right" | Lifetime | ||
| Permanent, originates with the element’s creation and exists through the lifetime. | |||
| Transient, added and removed dynamically. | | Transient, added and removed dynamically. | ||
|- valign="top" style="border-bottom: 1px solid LightGray;" | |- valign="top" style="border-bottom: 1px solid LightGray;" | ||
! align="right" | Environment | ! align="right" | Environment | ||
| Full control of content. | |||
| Foreign document or limited control of content. | | Foreign document or limited control of content. | ||
|- valign="top" style="border-bottom: 1px solid LightGray;" | |- valign="top" style="border-bottom: 1px solid LightGray;" | ||
! align="right" | Defining Traits | ! align="right" | Defining Traits | ||
| | |||
* Composable | |||
* Interoperable | |||
| | | | ||
* Unobtrusive | * Unobtrusive | ||
* Dynamic | * Dynamic | ||
|- valign="top" style="border-bottom: 1px solid LightGray;" | |- valign="top" style="border-bottom: 1px solid LightGray;" | ||
! align="right" | Shadow Tree | ! align="right" | Shadow Tree | ||
| Only one tree, initialized as the element is created. Inherited shadow trees can be reused, nested in the element's tree. | |||
| Each decorator must have its own shadow subtree, and the aggregate shadow tree of an element is composed out of these subtrees. | | Each decorator must have its own shadow subtree, and the aggregate shadow tree of an element is composed out of these subtrees. | ||
|- valign="top" | |- valign="top" | ||
! align="right" | DOM API | ! align="right" | DOM API | ||
| Explicitly interested in exposing methods or properties on the DOM element as its API. | |||
| Should avoid adding any extra methods or properties to the DOM element that’s being decorated. | | Should avoid adding any extra methods or properties to the DOM element that’s being decorated. | ||
|} | |} | ||
== | ==Existing Specifications and Implementations== | ||
===What does XBL2 do?=== | ===What does XBL2 do?=== | ||
* There are two ways to bind: using [http://dev.w3.org/2006/xbl2/#attachment-using-ltbinding-elementgt binding element] (inline or via external document) and [http://dev.w3.org/2006/xbl2/#attachment-using-css using CSS]. The former somewhat matches the notion to be element behavior, and the latter is the decorator behavior. However, there is no distinct difference in the attachment mechanism. | * There are two ways to bind: using [http://dev.w3.org/2006/xbl2/#attachment-using-ltbinding-elementgt binding element] (inline or via external document) and [http://dev.w3.org/2006/xbl2/#attachment-using-css using CSS]. The former somewhat matches the notion to be element behavior, and the latter is the decorator behavior. However, there is no distinct difference in the attachment mechanism. | ||
* Inheritance is entirely self-contained, using “extends” attribute. However, the prototype chain of the implementation object is fixed up to follow inherited bindings. | * Inheritance is entirely self-contained, using “extends” attribute. However, the prototype chain of the implementation object is fixed up to follow inherited bindings. | ||
* There is a fair bit of machinery specified to marry the aspect and inheritance concepts seamlessly. | * There is a [http://dev.w3.org/2006/xbl2/#binding-inheritance fair bit] of machinery specified to marry the aspect and inheritance concepts seamlessly. | ||
* There is no notion of extending DOM elements. | * There is no notion of extending DOM elements. | ||
Latest revision as of 17:09, 11 July 2011
The purpose of this document is provide a general overview of the behavior attachment problem in the Web.
Overview
Behavior can be viewed as a modular unit of Javascript, DOM elements, and CSS styles, designed to be loosely coupled with its consumer, which could be either a document or another behavior. Behavior attachment is a mechanism for composing behaviors.
HTML, as exists today, does not provide an organized way of attaching behavior to a DOM element. While you can add individual scripting methods, properties and event handlers to it, there is no way to do this atomically and with proper encapsulation.
In order to effectively provide encapsulation, a behavior attachment method should provide the following properties:
- DOM encapsulation, typically using shadow DOM. Shadow DOM refers to the ability of the browser to include a subtree of DOM elements into the rendering of a document, but not into the main document DOM tree.
- Style encapsulation, or a way to manage expectations of styles outside of the behavior affecting it, and conversely, styles of the behavior affecting the outside.
- Event encapsulation, which is a way to ensure that events, firing inside of the behavior’s DOM elements do not accidentally expose behavior’s implementation details.
Examples in the Wild
Javascript Frameworks
In Web applications, the lack of proper behavior attachment method is addressed at a library level, with every Javascript framework attempting to solve this problem. Here is a quick overview of approaches:
Library | Behavior Attachment Implementation |
---|---|
Dijit (Dojo's UI Library) | Creates a parallel object hierarchy to create illusion of homogenous object space, with full wrappers around DOM objects. Relies on inheritance-style approach by assigning each DOM element a dojoType attribute in markup, then traversing DOM and attaching corresponding behavior. |
Google Web Toolkit | Also uses parallel object hierarchy to shield the user from behavior attachment deficiency, relying on inheritance for compartmentalization and reuse. |
JQuery UI | A good balance of insulation from DOM objects with just-in-time wrapping. Progressive enhancement is the adopted technique of applying behavior. The behavior is transient and often an API is provide to detach it. It's interesting that the API is very late-bound and based on passing strings as method names. |
Prototype | Uses prototype inheritance chain to bestow new properties/methods on a DOM element. The changes are purely additive and imply permanent change in context of document’s lifetime. |
Sencha | Aggressive insulation from DOM with a Javascript objects as proxies, simple inheritance model (even maps ids of the underlying DOM elements to the variable names). |
SproutCore | Again, Javascript objects as proxies, extensive inheritance-based hierarchy of UI objects. |
Two interesting symptoms emerge after analysis of the approaches:
- Parallel object hierarchies. Since there is no way to incorporate a DOM element into object hierarchy, Javascript objects typically expose behavior-specific APIs, while using DOM objects as building blocks underneath. This extra layer of indirection has a negative impact on framework interoperability and is generally a leaky abstraction.
- Dynamic-sounding techniques for permanently attaching behavior. In the absence of a way to instantiate a DOM element with a new behavior attached, many frameworks use decoration/mixin-like patterns in its place. However the semantics and effect of application is one-way in most cases, indicating that the actual intent is to attach behavior as close to element instantiation as possible.
Extensions
Behavior attachment is also used by browser extensions, where an extension script, running in the context of the document, may attach extra behavior (including UI), to give the user more functionality within a document. Typical examples of such extensions are:
The main challenge for these extensions is to add and remove behavior to DOM elements (including extra DOM elements) to an existing document with least disruption, preferably in a way where the scripts of the document aren’t ever aware of these behavior attachments.
Built-in HTML Elements
Another example of behavior attachment can sometimes be found in the browser itself, where complex built-in controls are created using shadow DOM. Here are a few examples in WebKit:
input
elementaudio
andvideo
element. This one is interesting, because it's composed out of other HTML elements with attached behavior (likeinput[type=range]
).details
element
This behavior attachment is singular and permanent, surviving throughout the lifetime of the element. Encapsulation is an important property for this behavior attachment, since the browser should never leak the implementation details of the HTML elements to the document.
Behavior Attachment Methods
To better understand the intent of behavior attachment, we can split these examples in the wild into two general groups:
- An element behavior attachment, where the behavior is permanently associated with the element and creates a new type of element; and
- A decorator behavior attachment, where transient behaviors are given to or taken away from an element, modifying aspects of its properties, but leave the identity of an element intact.
The table below provides a comprehensive comparison between the two methods:
Element | Decorator | |
---|---|---|
Purpose | Create new content building blocks. | Give existing content new behavior and/or appearance. |
Paradigm | Object-Oriented Programming | Aspect-Oriented Programming |
Compartmentalization and Reuse Vehicle | Inheritance | Aspect |
Symptoms |
|
|
Examples of Use |
|
|
Identity | Creates a new type of element. | Does not change the identity of the element. |
Lifetime | Permanent, originates with the element’s creation and exists through the lifetime. | Transient, added and removed dynamically. |
Environment | Full control of content. | Foreign document or limited control of content. |
Defining Traits |
|
|
Shadow Tree | Only one tree, initialized as the element is created. Inherited shadow trees can be reused, nested in the element's tree. | Each decorator must have its own shadow subtree, and the aggregate shadow tree of an element is composed out of these subtrees. |
DOM API | Explicitly interested in exposing methods or properties on the DOM element as its API. | Should avoid adding any extra methods or properties to the DOM element that’s being decorated. |
Existing Specifications and Implementations
What does XBL2 do?
- There are two ways to bind: using binding element (inline or via external document) and using CSS. The former somewhat matches the notion to be element behavior, and the latter is the decorator behavior. However, there is no distinct difference in the attachment mechanism.
- Inheritance is entirely self-contained, using “extends” attribute. However, the prototype chain of the implementation object is fixed up to follow inherited bindings.
- There is a fair bit of machinery specified to marry the aspect and inheritance concepts seamlessly.
- There is no notion of extending DOM elements.
What does XBL1 do?
- There does not seem to be a separation between these two decorator and element behavior attachment. The http://mxr.mozilla.org/mozilla2.0/source/toolkit/content/xul.css seems to indicate the need for element attachment.
What does HTC do?
- HTC does not have the concept of shadow DOM, but the specified behavior is firmly an element behavior attachment.
What does sXBL do?
- It appears that the spec is abandoned, but the gist is similar to XBL2, except there is only one shadow tree, direct access to shadow subtree, and a binding model that seems to indicate element behavior attachment, but using decorator API.