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).

Component Model Use Cases: Difference between revisions

From WHATWG Wiki
Jump to navigation Jump to search
Line 13: Line 13:


Needs:
Needs:
* UA-level attachment
* ability to designate and use DOM SPIs only within the shadow scope
* ability to completely hide implementation details from author and user
* restricted post-UA-level styling using pseudoclasses
* restricted post-UA-level styling using pseudoclasses
* style/event propagation control at the borders of the shadow DOM
* style/event propagation control at the borders of the shadow DOM

Revision as of 21:57, 6 January 2011

A canonical set of uses cases that represents the set of problems we are trying to solve by implementing a component model. For implementation details, see XBL2 Spec.

This document is broken out into two sections: general use cases provide insight into how the component model could be used; specific use cases are interesting scenarios within the general use cases that should be treated as constraints/requirements, imposed on the specification/implementation of the component model.

General Use Cases

Built-in HTML Elements

Many non-trivial (i.e. with additional behavior and styling beyond the standard box model) elements that exist in HTML today could be implemented using HTML/CSS/JS. Gecko already takes this approach pretty far. It makes sense to provide a standardized way to accomplish this, with the short-term goals of reducing the size of browsers C++ code and making new element implementation easier, and the long-term goal of converging built-in HTML element implementations across browsers.

Requirements:

  • provide a uniform way to browsers to implement complex HTML elements, such as video/audio, sliders, progress elements, etc. possibly using scripting.

Needs:

  • restricted post-UA-level styling using pseudoclasses
  • style/event propagation control at the borders of the shadow DOM
  • high performance, especially compared to native implementation

Could use:

  • declarative templating/binding

Doesn't care:

  • mutable templates
  • dynamic attachment/detachment
  • template inheritance
  • attachment using CSS or DOM
  • content element (output ports), since they can't have children (this may change)
  • attribute/pseudo forwarding
  • xml:base handling

Interesting scenarios:

  • Implement a video/audio element. How can the binding reach into a private supporting API that is not available to the author?

Custom Widget System

As it is today (Jan 1, 2011), pretty much every Javascript framework has a widget system (see http://jqueryui.com/, http://sproutcore.com/, http://o.dojotoolkit.org/projects/dijit, http://cappuccino.org/, http://code.google.com/webtoolkit/, http://code.google.com/closure/library/, http://www.sencha.com/ as just a few examples). All of these these widget systems are framework-specific and mostly incompatible with each other. Because the Web platform doesn't provide a well-functioning way to extend HTML elements, all of these tend to build a parallel widget space, where widget objects act as proxies to DOM objects, and the extensibility exists only within that parallel widget space. A DOM-based component model should aim to eliminate the need for this parallel space and allow widget systems to just use DOM with the goals of:

  • reducing the amount of widget-space-related code written in each framework
  • providing better, leak-free abstraction for widgets
  • providing interoperable API to allow widgets from different frameworks to coexist and integrate.

Requirements:

  • provide a uniform way (i.e. DOM) to declare widget APIs
  • encapsulate widget implementation details
  • enable control over how styles and events outside of a widget affect it
  • enable widget styling primitives
  • asynchronously instantiate and initialize widgets (for instance, display a widget without starting up a script context, then progressively enhance with script).
  • allow seamless reuse a widget written using various libraries or frameworks
  • allow using widgets declaratively, with minimal knowledge of the underlying implementation
  • provide a way to create new widgets by extending existing widgets

Needs:

  • shadow DOM
  • content element (output ports)
  • style/event propagation control at the borders of the shadow DOM
  • attachment using CSS and DOM
  • separate instantiation and binding phases (or another way to allow asynchronous binding)
  • attribute/pseudo forwarding
  • declarative templating/binding

Could use:

  • dynamic attachment/detachment
  • template inheritance

Doesn't care:

  • mutable templates
  • xml:base handling

Interesting scenarios:

  • Implement a "polaroid frame" widget? This widget, when bound to any element would display its contents in a Polaroid(tm)-like frame.
  • Suppose the widget system has a centralized "settings" widget, with which all other widgets should communicate to add their settings. Implement this communication, provided that all widgets are opaque elements.
  • Implement a "tab set" widget. As you add "tabs" to it, tab titles appear in a row at the top, and tab contents appear in the main area, only visible when the corresponding tab title is selected.

Layout Manager

Does:

  • provide a framework for client-side restructuring of content to accommodate layout
  • support both imperative a declarative layout models
  • provide templating/theming capabilities

Needs:

  • shadow DOM
  • content element (output ports)
  • attachment using CSS and DOM
  • separate instantiation and binding phases (or another way to allow asynchronous binding)

Could use:

Doesn't care:

  • mutable templates
  • xml:base handling

Specialized Markup Languages

It's possible to imagine the component model to be used for lightweight implementations of specialized markup languages, such as MathML. This section needs work.

Specific Use Cases

Shadow DOM

A component model should allow a component to hide its implementation details from the consumer. For instance, consider this bit of code:

<input type="range">

The least thing the user of this element would expect is being able to walk down the DOM subtree of the input element and find the thumb element inside:

<input type="range">
    <div></div>
</input>

Similarly, that's not what the code managing the range slider would want to happen. Thus, the shadow DOM is a way to implement a DOM subtree that is rendered as part of the document, but is not accessible by traversing the document tree. Shadow DOM provides the necessary level of isolation between component and non-component parts of the DOM tree and is the fundamental part of the component model.

Dynamic Binding Mechanism

Being able to apply and unapply a shadow DOM tree, its style information and the code that manages them as one atomic action seems important. For instance, changing the type attribute of the input element immediately triggers the change of how the element looks and behaves. One can view this described in CSS as:

input[type='text'] {
    binding: url(http://example.com/input/text/);
}

input[type='range'] {
    binding: url(http://example.com/input/range/);
}

In the code snippet above, it is implied that the shadow subtree, styles, and code are applied/unapplied atomically and dynamically as the type attribute value changes.

Multiple Shadow DOM Subtrees On Element

A new component might want to build upon an existing component to provide new functionality. For example, I might want to turn the input type="range" into a dial, rather than a slider. The dial code is implemented as a shadow DOM subtree and is bound to the element like so:

/* CSS */
input[type='range'].dial {
    binding: url(http://example.com/dial/);
}

To use my dial, I have this bit of code:

function setDialMode(id, dial)
{
    var input = document.getElementById(id);
    if (dial)
      input.classList.add('dial');
    else
      input.classList.remove('dial');
}

The user's expectations is that the input element turns into a dial once the dial class is set and reverts back to the slider once it's removed. Given that slider itself is implemented as a shadow DOM subtree, this indicates that either:

  1. multiple shadow subtrees could exist on an element at the same time with only one subtree rendered. This implies some sort of "selector memory" ability, which is completely foreign to how things work in the browser today.
  2. a shadow subtree is destroyed and rebuilt every time selector applies/unapplies. This is also bad, because destroying discards any modifications to the subtree that may have occurred during its lifetime.

User Agent-Level Attachment

Since the component model is used to implement built-in HTML elements, there has to be a way apply subtree/style/code at the UA level. The attachment at this level has to satisfy these criteria:

  1. It should happen before any other component attachment (like UA-level stylesheets).
  2. It should allow the component code to access API methods that are accessible only to the UA-level attachment. For instance, a video element implementation may need to operate on the native video frame. Direct access to the video frame should not be allowed outside of the UA-level components.
  3. It should allow the component implementation details to be completely hidden. There should be no way to detect whether an HTML element is built using the component model.

Tens of Thousands of Widgets

The implementation should be able to efficiently handle a very large number of instances from the same template (see discussion).

<html>
<head>
    <binding element="div">
        <style scoped>
            div.pretty {
                background-color: Pretty;
            }
        </style>
        <template>
            <div class="pretty">Pretty is, pretty does.</div>
        </template>
    </binding>
</head>
<body>
    <script>
        for(var i = 0; i < 20 * 1000; ++i)
            document.body.appendChild(document.createElement('div'));
    </script>
</body>
</html>

Insertion Points, Not Containers

Output ports need to be insertion points, not cointainers. If the output port is a container (that is, an existing element in the shadow subtree is designated as a place to add the "light" nodes), some layout scenarios aren't possible. In this example, you can not use flexbox to layout all of the paragraphs in the story:

<template>
    <p>Once upon a time,
    <content includes="p">
    <p>And they lived happily ever after
</template>

It is useful to think of the output port as a collapsed range.

Shadow Subtree Mutation

Because content element is an insertion point, what happens when the elements around it change? What happens when the insertion point moves?

  • Modifying includes attribute. What happens when you modify the includes element on the output port?
  • Nested shadow subtrees. Suppose you have two bindings, one applied inside another:
<html>
<head>
    <binding element="div#foo">
        <template>
            <span>
                <content></content>
            </span>
        </template>
    </binding>
    <binding element="div#bar">
        <template>
            <div>
                <div id="foo">
                    <span>Blah</span>
                    <content></content>
                </div>
        </template>
    </binding>
</head>
<body>
    <div id="foo">
        <p>Monkeys
    </div>
</body>
</html>

Sequence of actions:

  1. Add a div element to div#bar.
  2. Move content element in div#bar template as the first child of div

What happens?

Dynamicity of Rules

As XBL2 spec'd today, the includes attribute is fully dynamic. That is, changing this attribute results in node redistribution. Being able to control node distribution from outside of the shadow subtree seems like a useful feature. Consider this example:

<html>
<head>
    <binding element="ul.news">
        <template>
            <h2>Breaking News</h2>
            <ul id="breaking">
                <content includes="li.breaking"></content>
            </ul>
            <h2>Other News</h2>
            <ul id="other">
                <content></content>
            </ul>
        </template>
    </binding>
</head>
<body>
    <ul class="news">
        <li class="breaking">Santa seen crossing Atlantic</li>
        <li>Pies pose serious health risk, scientists say</li>
    </ul>
</body>
</html>

Here, the importance of the news item is controlled outside of the shadow subtree. By setting/removing class breaking on a news item, the consumer of the binding can move it in and out of the breaking news section. Implementing this without dynamic rules seems cumbersome and non-trivial.