FAQ

[dojo-contributors] Has, builds, and UA-based feature determination

Kris Zyp
Jan 31, 2011 at 1:35 pm
Partly sparked by Alex's last blog post [1] (I've been thinking about
this subject anyway though), I wanted to go little further in looking
ahead at how I believe we can develop Dojo, RequireJS, and has.js to
create truly optimal applications across different browsers/devices.
First, a few foundational principles. The last decade of JavaScript
development has clearly taught the reliability of using feature
detection. To be clear, UA-sniffing does belong in our source code. This
is clearly the right way to create future-proof source code and to avoid
this in our source code for the sake of performance would be premature
optimization. However, Alex has also clearly pointed out that feature
detection must be optimized out eventually. While our source code may
use feature detection, it is unacceptable for all the feature tests to
be downloaded to every browser and executed when UA-sniffing based
optimizations are available. This is where the build comes in. For the
most part, a built application should be based on UA, and use feature
detection as little as possible. Arguing about whether feature detection
or UA-sniffing naive. Briefly, the right time for feature detection and
UA-sniffing is:
* Feature detection at source code level
* UA based determination of features at the build level to eliminate
run-time feature tests

With this approach our source code is future-proof and we can readily
create builds based on the latest UA feature sets without source code
modifications.

Fortunately our move to the standardized convention of has() makes this
type of optimization well within reach. RequireJS has already proven the
ease at which has() branches can eliminate unused feature branches/code.
However, currently we are not offering any help with the actual creation
of UA-specific build layers and the branching to those layers. RequireJS
simply delegates this to the developer to deal with. This is a
non-trivial problem though, and I think significant benefit can be
gained by providing tooling/help in this area.

I threw together a little package to demonstrate a solution we could
provide for UA-sniffing based optimization for feature detection (this
is not functional code right now, just demonstrates the idea):
https://github.com/kriszyp/ua-optimized
The basic premise here is that we have a AMD plugin "ua-optimized" that
can do UA-sniffing to branch to different build layers that were
generated with known feature sets. You would load your app like:

require(["ua-optimized!my-app"]);

At dev time ua-optimized! would basically be a no-op and would just load
the "my-app" module. During the build, ua-optimized would generate
various (perhaps a dozen or even dozens) build/layers of my-app based
optimized for different UA's and their known feature sets and then most
or all of feature tests and used branches would eliminated. It would
also generate a "default" layer that would corresponded to unknown UAs
and would include all the features and branches. When ua-optimized is
run on built modules, it would then use the UA string to load the
correct UA-specific version of my-app (or the default if the UA is not
known).

Again, the advantage here is that one could build applications and
properly make use of feature detection for safe, reliable code. The
built applications can leverage known UAs to short-cut out of
unnecessary feature tests, while still falling back to feature tests for
unknown user agents. UA-feature set information can be updated in the
future to improve builds without any modification to source code.

There are a couple minor pieces needed to put this puzzle together:

* We need an API for AMD plugins to trigger recursive builds. I assume
this is a pretty simple addition to the build systems.
* We need a database of UAs and their feature sets (based on has.js
tests). Is Pete or any has.js folks already collecting this information?

From bogus@does.not.exist.com Tue Jan 18 18:42:17 2011
From: bogus@does.not.exist.com ()
Date: Tue, 18 Jan 2011 23:42:17 -0000
Subject: No subject
Message-ID: <mailman.1.1296498952.13280.dojo-contributors@mail.dojotoolkit.org>

is getting stored somewhere.

[1] http://infrequently.org/2011/01/cutting-the-interrogation-short/

Thanks,
Kris
<https://github.com/kriszyp/ua-optimized>

--------------040204080907020508010208
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

<html>
<head>

<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
</head>
<body bgcolor="#FFFFFF" text="#000000">
Partly sparked by Alex's last blog post [1] (I've been thinking
about this subject anyway though), I wanted to go little further in
looking ahead at how I believe we can develop Dojo, RequireJS, and
has.js to create truly optimal applications across different
browsers/devices. First, a few foundational principles. The last
decade of JavaScript development has clearly taught the reliability
of using feature detection. To be clear, UA-sniffing does belong in
our source code. This is clearly the right way to create
future-proof source code and to avoid this in our source code for
the sake of performance would be premature optimization. However,
Alex has also clearly pointed out that feature detection must be
optimized out eventually. While our source code may use feature
detection, it is unacceptable for all the feature tests to be
downloaded to every browser and executed when UA-sniffing based
optimizations are available. This is where the build comes in. For
the most part, a built application should be based on UA, and use
feature detection as little as possible. Arguing about whether
feature detection or UA-sniffing naive. Briefly, the right time for
feature detection and UA-sniffing is:<br>
* Feature detection at source code level<br>
* UA based determination of features at the build level to eliminate
run-time feature tests<br>
<br>
With this approach our source code is future-proof and we can
readily create builds based on the latest UA feature sets without
source code modifications.<br>
<br>
Fortunately our move to the standardized convention of has() makes
this type of optimization well within reach. RequireJS has already
proven the ease at which has() branches can eliminate unused feature
branches/code. However, currently we are not offering any help with
the actual creation of UA-specific build layers and the branching to
those layers. RequireJS simply delegates this to the developer to
deal with. This is a non-trivial problem though, and I think
significant benefit can be gained by providing tooling/help in this
area.<br>
<br>
I threw together a little package to demonstrate a solution we could
provide for UA-sniffing based optimization for feature detection
(this is not functional code right now, just demonstrates the idea):<br>
<a href="https://github.com/kriszyp/ua-optimized">https://github.com/kriszyp/ua-optimized</a><br>
The basic premise here is that we have a AMD plugin "ua-optimized"
that can do UA-sniffing to branch to different build layers that
were generated with known feature sets. You would load your app
like:<br>
<br>
require(["ua-optimized!my-app"]);<br>
<br>
At dev time ua-optimized! would basically be a no-op and would just
load the "my-app" module. During the build, ua-optimized would
generate various (perhaps a dozen or even dozens) build/layers of
my-app based optimized for different UA's and their known feature
sets and then most or all of feature tests and used branches would
eliminated. It would also generate a "default" layer that would
corresponded to unknown UAs and would include all the features and
branches. When ua-optimized is run on built modules, it would then
use the UA string to load the correct UA-specific version of my-app
(or the default if the UA is not known). <br>
<br>
Again, the advantage here is that one could build applications and
properly make use of feature detection for safe, reliable code. The
built applications can leverage known UAs to short-cut out of
unnecessary feature tests, while still falling back to feature tests
for unknown user agents. UA-feature set information can be updated
in the future to improve builds without any modification to source
code.<br>
<br>
There are a couple minor pieces needed to put this puzzle together:<br>
<br>
* We need an API for AMD plugins to trigger recursive builds. I
assume this is a pretty simple addition to the build systems.<br>
* We need a database of UAs and their feature sets (based on has.js
tests). Is Pete or any has.js folks already collecting this
information? From
<a class="moz-txt-link-freetext" href="http://dante.dojotoolkit.org/hasjs/tests/runTests.html">http://dante.dojotoolkit.org/hasjs/tests/runTests.html</a>, it looks it
is getting stored somewhere.<br>
<br>
[1] <a
href="http://infrequently.org/2011/01/cutting-the-interrogation-short/">http://infrequently.org/2011/01/cutting-the-interrogation-short/</a><br>
<br>
Thanks,<br>
Kris<br>
<a href="https://github.com/kriszyp/ua-optimized"></a>
</body>
</html>

--------------040204080907020508010208--
reply

Search Discussions

5 responses

  • Kris Zyp at Jan 31, 2011 at 5:25 pm

    On 1/31/2011 11:35 AM, Kris Zyp wrote:
    Partly sparked by Alex's last blog post [1] (I've been thinking about
    this subject anyway though), I wanted to go little further in looking
    ahead at how I believe we can develop Dojo, RequireJS, and has.js to
    create truly optimal applications across different browsers/devices.
    First, a few foundational principles. The last decade of JavaScript
    development has clearly taught the reliability of using feature
    detection. To be clear, UA-sniffing does belong in our source code.
    Correction: UA-sniffing does *not* belong in our source code.

    Sorry for the typo.
    Kris
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://mail.dojotoolkit.org/pipermail/dojo-contributors/attachments/20110131/0599ac2c/attachment.htm
  • James Burke at Jan 31, 2011 at 6:20 pm

    2011/1/31 Kris Zyp <kzyp at dojotoolkit.org>:
    * We need an API for AMD plugins to trigger recursive builds. I assume this
    is a pretty simple addition to the build systems.
    This is just my first thoughts, so subject to change/good arguments:

    The multi-build work should be done outside of the loader plugin, and
    even outside the main builder used for JS modules. This is a job for a
    more generic build tool like make or ant.

    I believe the build tool for a JavaScript dependency system should
    focus more strictly on combining sets of modules together, since that
    is the hard part that cannot be replicated in other build systems
    (particularly loading of plugins to figure out if they should include
    optimized resources).

    Furthermore, I would expect Dojo to never ship with all of those
    builds done as part of a Dojo distribution -- that is an optimization
    step reserved for the optimization of an app, not of a library that
    may be used as an app. Or if it is distributed, it is not the main
    distribution -- something that has 5-10 builds of the toolkit inside
    it for each type of UA profile would freak people out just on the
    download size alone, never mind the set of server rules they need to
    put in place to serve them correctly.

    While it is worthwhile to work out a system for UA+version specific
    builds, not everyone will want them. The file size management
    complexity cost and serverside URL routing setup to get it to work
    will be seen as too much complication for many sites, and I expect
    that once a display ad service is put on the site, any gain by this
    sort of optimization will likely go unnoticed, particularly if only
    the has tests used by the code are included vs. the full set.

    To be clear: I am not arguing it is not worthwhile, but that it is
    just one piece of an optimization story, and there is a complexity
    cost to implementing it, and not everyone should be forced to take the
    hit of that complexity cost. It needs to be taken when the site is
    ready to take it on.

    So I see the work as identifying how more generic build tools could
    use a database of the has profiles in a build step. I could see this
    as generally useful knowledge that is tracked as part of the has.js
    project, since it is likely useful even outside any JS module-specific
    build tool.

    James

    From bogus@does.not.exist.com Tue Jan 18 18:42:17 2011
    From: bogus@does.not.exist.com ()
    Date: Tue, 18 Jan 2011 23:42:17 -0000
    Subject: No subject
    Message-ID: <mailman.5.1297912278.13280.dojo-contributors@mail.dojotoolkit.org>

    - 2/21 - 1.6 RC
    - 2/28 - 1.6 release
    - IE9 will be supported in a point release, presumably 1.6.1

    --002354435d081a7887049c71bee5
    Content-Type: text/html; charset=ISO-8859-1


    From bogus@does.not.exist.com Tue Jan 18 18:42:17 2011
    From: bogus@does.not.exist.com ()
    Date: Tue, 18 Jan 2011 23:42:17 -0000
    Subject: No subject
    Message-ID: <mailman.6.1297912279.13280.dojo-contributors@mail.dojotoolkit.org>

    --002354435d081a7887049c71bee5--

    From bogus@does.not.exist.com Tue Jan 18 18:42:17 2011
    From: bogus@does.not.exist.com ()
    Date: Tue, 18 Jan 2011 23:42:17 -0000
    Subject: No subject
    Message-ID: <mailman.8.1299377370.13280.dojo-contributors@mail.dojotoolkit.org>

    worst case, every node with a "ref" setting will trace up to <body> looking
    for a parent ref. That still sounds CPU intensive but maybe not the end of
    the world.

    Note: you probably should be calling dojo.getObject() rather than
    dojo.eval(), will you ever pass eval() more than a dot separated identifier?

    --------
    I'm still confused by ref vs. binding. In one of your test files you
    have:

    dijit.byId("view").set("binding", binding);


    Yet, there's no "binding" attribute declared in _DataBindingMixin.js.


    In one of your test files you have:


    <input id="taxes" dojoType="dijit.form.NumberTextBox" ref="
    loanModel.Taxes"/>


    In that example ref is both the StatefulModel object and the attribute
    inside of it. (loanModel.Taxes is a number, right?)


    ------
    Have you thought that users might try to specify ref (or is it binding?) as
    an object rather than as a string? Something like:

    new dijit.form.TextBox({ref: myStatefulModel.employeeName})

    That's not quite right because it will end up as though I had done this:

    new dijit.form.TextBox({ref: "John Smith"})

    but anyway it seems like the app should be able to specify the Stateful
    object being bound as an object rather than as a string name of a global
    variable.


    Note that we have this pattern in other widget parameters, for example
    DateTextBox.value is a Date object, but when you construct a DateTextBox or
    call set("value", ...) you can pass in a string for the value and it gets
    converted. In your case it seems like ref (or is it binding?) should be an
    Object, but you allow a string as a parameter to the constructor or argument
    to set("ref", ...) .

    ----------

    Here's a test case for you to add, it seems like this should work, but it
    won't work w/your current code:

    myWidget = new myWidget({ref: "foo.bar"}) <--- can't eval ref yet
    since no parent
    myWidget.placeAt(dojo.body());
    myWidget.startup() <--- should set widget's value according to model
    myWiget.set("ref", "baz.bam") <-- should reset widget's value according
    to new model


    On Sun, Mar 6, 2011 at 5:17 AM, Rahul Akolkar wrote:

    Hi Bill,

    Inline.
    On Fri, Mar 4, 2011 at 10:33 PM, Bill Keese wrote:
    Glad you are getting good feedback from Ben.
    <snip/>

    Yup, good to have more pairs of eagle eyes on this. I am in the middle
    of some minor refactorings based on all the comments so far. I expect
    to have a refreshed patch by the end of the weekend.

    Here's a reply to some of the stuff from my original note.
    <snap/>

    Thanks, I was hoping it'd come in before my refreshed patch became ready
    :-)

    2. DataBindingMixin

    a) file structure
    The root of the patch is _DataBindingMixin.js, which gets mixed into
    _WidgetBase. Current code for that is split across two files as:

    dojo.declare("dijit._DataBindingMixin", null, { ... });

    dojo.extend(dijit._WidgetBase, new dijit._DataBindingMixin());

    It would be simpler like this:

    dojo.extend(dijit._WidgetBase, {...});

    You can still pull _DataBindingMixin.js into StatefulModel.js if you
    don't
    want apps to need to explicitly dojo.require(DataBindingMixin).
    <snap/>

    Correct, thats indeed the objective. The data binding mixin is not
    something we'd want apps to explicitly dojo.require(). By "pull into",
    I'm thinking you mean inline the source into the other file? Thats an
    option.

    Sorry, I meant that you could list _DataBindingMixin in the list of requires
    for StatefulModel, in the first line define() call.
    <snip/>

    Oh, got it.

    But I agree with Ben's comment, it seems wrong to make a dijit dependency on
    StatefulModel just so apps can avoid an extra dojo.require() call
    Would StatefulModel ever be useful outside of widgets? A recursive
    dojo.Stateful sounds useful in general, not sure about the other stuff in
    there.
    <snap/>

    Right, the dijit.StatefulModel class is already geared to deal with
    specifics of a view layer (all the valid, readOnly, relevant etc.
    meta-data lends well to view layer bindings). In theory, one could
    capture the essence of the recursive model for reuse elsewhere. But
    while it may be possible to craft a base class that is purely a
    recursive dojo.Stateful model and then subclass it to provide what is
    effectively dijit.StatefulModel functionality now, I can't say I have
    many usecases at hand. Ofcourse, such refactoring can also happen down
    the road if deemed essential.

    e) _initControl()

    This is run from postCreate(), yet it assumes that the widget is
    anchored to
    the document. You shouldn't assume that until startup() is called;
    in
    particular it's not true for programatically created widgets ex: new
    dijit.form.TextBox().placeAt(...)
    <snip/>

    OK, I'll look into (d) and (e) above.
    About having every widget trace up the tree to find a parent with a binding
    specified, or if there's no such parent then tracing all the way to
    <body>... we faced that same problem with the bidi group and their
    lobbying for every widget to support a dir parameter (possibly) being
    inherited from an ancestor . We didn't want to have every single widget
    calling getParent() repeatedly to inspect it's ancestors as that seemed like
    it would degrade performance on page load. So we ended up adding code to
    the parser to pass down the dir inherited from the ancestor. I wonder if
    that makes sense here.
    <snip/>

    It may make sense, but let me step back a bit. Some thoughts, in no
    particular order:

    I assume by getParent() you mean dijit.getEnclosingWidget() which is
    what is used here. The number of these calls is a function of: (a)
    Number of data-bound widgets, (b) Topology of binds i.e. amount of
    relative refs implied by nesting and (c) Average DOM separation (along
    parent axis) between nested data-bound dijits.

    The observed rule of thumb is that at page load you'd expect roughly
    2x the number of dijit.getEnclosingWidget() calls as the number of
    data-bound widgets. This is somewhat less pervasive than bidi as it
    only applies to data-bound dijits (clearly, a view may have data-bound
    dijits and others that aren't data-bound).

    There are two scenarios where bindings are calculated (or recalculated):
    * Initial page load
    * Programmatic binding update (example: when user chooses to list
    details for a particular search result in the master-detail demos in
    the patch, causing the bindings in the detail portion of the view to
    be updated)

    Ben had a suggestion about an optional parent binding param to
    _setupBinding(), which effectively removes the need for any DOM
    operations or parent widget lookups in the second case.

    For the initial page load, the roughly 2x dijit.getEnclosingWidget()
    calls may be avoided if we can get the parent binding to be
    "inherited" through the parser. OTOH, these calls aren't terribly
    expensive either (operations therein include .parentNode references,
    getting the widgetId attribute values and a lookups into the widget
    registry), so some of this could be done as incremental improvements.

    In your response to Ben you gave this example:
    model:
    { foo : { bar : { baz : { freddy : { frog : "prince" } } } } }


    markup:
    <div dojoType="dijit.mvc.Group" ref="model.foo">
    <div dojoType="dijit.mvc.Group" ref="bar">
    <div dojoType="dijit.mvc.Group" ref="baz">
    <div dojoType="dijit.mvc.Group" ref="freddy">
    <div dojoType="dijit.form.TextBox" ref="frog">


    Hopefully that doesn't execute in O(n^2), where every widget needs to trace
    to the top of the tree, does it?
    <snap/>

    In the above example:
    * There are exactly 5 getEnclosingWidget() calls
    * The total number of node.parentNode references looked up (including
    those within these 5 calls) is exactly equal to the DOM depth of the
    textbox on the page

    Let me try to understand why you say O(n^2), since every widget isn't
    trying to reach every other widget on the page. Worst case performance
    is linear to the total number of data-bound widgets (n) where the
    constant in the linear equation is the average DOM separation across
    all data-bound widgets (k). I guess you are assuming n tends to k on a
    given page? (not usually the case). Also, if total number of dijits on
    page is N, n < N is common, if not outrightly n << N.

    I don't really understand the code that
    executes for the TextBox figures out that it's connected to
    model.foo.bar.baz.freddy.frog. (What info is cached inside of the
    innermost Group?)
    <snip/>

    There is no caching per se, direct references to nodes within the
    StatefulModel are stored as "binding" property on appropriate dijits.
    Here is how things work in above scenario:
    1. Outermost group finds no data-bound parent, evals "model.foo" to
    obtain its ref StatefulModel node
    2. The next three groups locate their data-bound parent immediately
    i.e. on first parent lookup (as its also the DOM parent), and each
    resolves their ref expression as relative to parent. So, in the
    absolute sense, 2nd group refs model.foo.bar, 3rd refs
    model.foo.bar.baz and so on.
    3. The textbox similarly (relatively) obtains its "binding" as a ref
    to the model.foo.bar.baz.freddy.frog node (parent:
    model.foo.bar.baz.freddy, relative ref: frog). At which point, the
    data (i.e. "value") and meta-data associations are set up between that
    model node and the textbox, thereby the textbox displays the value
    from the model i.e. "prince".

    Anyway, the parser has an "inherited" parameter that could be used to pass
    down the ref from the parent. I'm not sure if using it makes sense or not.
    <snap/>

    See above.

    4. NumberTextBox, ValidationTextBox

    These methods are now assuming a super-class isValid() method, but
    that
    method only exists when _DataBindingMixin is included. I guess we
    need
    to
    define an empty isValid() method in _WidgetBase? I don't know what
    happens
    when you call this.inherited(arguments) and there's no such
    super-class
    function, but even if it works, it seems fragile.
    <snap/>

    Nothing happens, see line 190 (linking to a few lines before that for
    context):
    http://bugs.dojotoolkit.org/browser/dojo/trunk/_base/declare.js?rev#778#L186
    That aside, yes, this was slightly tricky because there was no
    corresponding isValid() in _WidgetBase whereas I think there should
    be. Also, not all dijits check base class validity (where applicable)
    before deciding their isValid() status and once its added to
    _WidgetBase, they should (and thereby, the model validity will be
    accounted for in cases where the data binding mixin is applied).
    OK, adding it to _WidgetBase is something to consider. But again, there
    would be the "problem" where your mixin is simply overwriting the
    isValid()method in _WidgetBase.js, like it's overwriting postCreate() now.
    The isValid() problem is harder to solve since dojo.connect() doesn't work
    since you need to return a value, I guess you should be doing something
    like:
    var oldIsValid = dijit._WidgetBase.isValid;
    dijit._WidgetBase.isValid = function(){ return this.oldIsValid() &&
    your-code-here; }
    <snip/>

    OK, that would cover all bases. OTOH, isValid() would simply return
    true in _WidgetBase, can't imagine much else going on there.

    5. dijit.mvc._Container

    This has >100 lines of cut-pasted code from _Templated and doesn't
    support
    the new data-dojo-attach-point etc. syntax. Can you do better? See
    dijit.Declaration, maybe you can have similar code.
    <snip/>

    Yes, its listed as a TODO in code -- it'd be good to remove that
    duplication. The issue as I remember was that I wasn't able to reuse
    _Templated directly as the way it deals with templates and template
    caches is different from, say repeat, where the template is inline
    (body). I'll take another look at dijit.Declaration, but ISTR some
    other differences there.

    This inheritance from _Container to both Group and Repeater confuses me.
    While Group is just a plain wrapper widget, similar to dijit.form.Form or
    dijit.layout.ContentPane, Repeater is a different beast that generates from
    a template.
    <snap/>

    It sure would be confusing if that were the case :-) Group does not
    inherit from _Container, it inherits from _WidgetBase. Its the
    simplest data-bound widget that is very useful in setting up
    hierarchical data bindings (ref'ing to intermediate model nodes).

    I guess my question is, why does mvc._Container have any code
    about templates?
    <snip/>

    In hindsight, somewhat unnecessary. I've refactored that out of
    _Container (please see next patch in a day or two).

    b) the declaredClass references here and in other parts of the code
    aren't
    future-proof. declaredClass will likely go away in 2.0.
    <snap/>

    OK, any future-proof equivalent? I'll investigate or use a bit more of
    the duck typing sauce if needed.
    Yes, if there isn't an obvious way to ducktype (ex: testing if a certain
    method like then() is available), then in dijit for example we have
    isContainer and isLayoutContainer flags on widgets that indicate they have a
    certain functionality.
    <snap/>

    Thanks, there is, toPlainObject() is used as the duck typing signature.

    -Rahul
    --000e0cd5c8720ff651049dc6defa
    Content-Type: text/html; charset=ISO-8859-1
    Content-Transfer-Encoding: quoted-printable

    <font size="2">OK, so part of what I was asking was whether parent.get(&quot;ref&quot;) just returned parent.ref, or if it computed the return value by tracing up the tree.   From your response it&#39;s clear that it just returns parent.ref.  So</font> in the worst case, every node with a &quot;ref&quot; setting will trace up to &lt;body&gt; looking for a parent ref.   That still sounds CPU intensive but maybe not the end of the world.
    <div><font size="2"><br></font></div><div><font size="2">Note: you probably should be calling dojo.getObject() rather than dojo.eval(), will you ever pass eval() more than a dot separated identifier?</font></div><div><font size="2"><br>

    </font></div><div><font size="2">--------</font></div><div><font size="2"><div>I&#39;m still confused by ref vs. binding.    In one of your test files you have:</div><div><br></div><div><p style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0px">

    dijit.byId(&quot;view&quot;).set(&quot;binding&quot;, binding);</p><p style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0px"><br></p><p style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0px">

    Yet, there&#39;s no &quot;binding&quot; attribute declared in _DataBindingMixin.js.</p><p style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0px"><br></p><p style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0px">
    In one of your test files you have:</p><p style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0px"><br></p><p style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0px"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta http-equiv="Content-Style-Type" content="text/css">
    <title></title>
    <meta name="Generator" content="Cocoa HTML Writer">
    <meta name="CocoaVersion" content="1038.35">
    <style type="text/css">
    p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #1738f5}
    span.s1 {color: #b52422}
    span.s2 {color: #000000}
    span.s3 {color: #ff201a}
    </style>


    </p><p class="p1">&lt;<span class="s1">input</span><span class="s2"> </span><span class="s3">id</span><span class="s2">=&quot;</span>taxes<span class="s2">&quot; </span><span class="s3">dojoType</span><span class="s2">=&quot;</span>dijit.form.NumberTextBox<span class="s2">&quot; </span><span class="s3">ref</span><span class="s2">=&quot;</span>loanModel.Taxes<span class="s2">&quot;</span>/&gt;</p>
    <p class="p1"><br></p><p class="p1"><font class="Apple-style-span" color="#000000" face="arial, helvetica, sans-serif" size="2">In that example ref is both the StatefulModel object and the attribute inside of it.   (loanModel.Taxes is a number, right?)</font></p>
    <p></p><p style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0px">
    <br></p><p style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0px">------</p></div></font></div><div><font size="2">Have you thought that users might try to specify ref (or is it binding?) as an object rather than as a string?   Something like:</font></div>
    <div><font size="2"><br></font></div><div><font size="2">      new dijit.form.TextBox({ref: myStatefulModel.employeeName})</font></div>
    <div><font size="2"><br></font></div><div><meta charset="utf-8"><div><font size="2">That&#39;s not quite right because it will end up as though I had done this:</font></div><div><font size="2"><br></font></div><div><font size="2"><div>
    <font size="2">      new dijit.form.TextBox({ref: &quot;John Smith&quot;})</font></div><div><font size="2"><br></font></div></font></div><div>but anyway it seems like the app should be able to specify the Stateful object being bound as an object rather than as a string name of a global variable.</div>
    </div><div><br></div><div><br></div><div><font size="2">Note that we have this pattern in other widget parameters, for example DateTextBox.value is a Date object, but when you construct a DateTextBox or call set(&quot;value&quot;, ...) you can pass in a string for the value and it gets converted.   In your case it seems like ref (or is it binding?) should be an Object, but you allow a string as a parameter to the constructor or argument to set(&quot;ref&quot;, ...) .</font></div>

    <div><br></div><div>----------</div><div><br></div><div><font size="2">Here&#39;s a test case for you to add, it seems like this should work, but it won&#39;t work w/your current code:</font></div><div><font size="2"><br>
    </font></div><div><font size="2">    myWidget = new myWidget({ref: &quot;foo.bar&quot;})    &lt;--- can&#39;t eval ref yet since no parent</font></div>
    <div><font size="2">    myWidget.placeAt(dojo.body());</font></div><div><font size="2">    myWidget.startup()  &lt;--- should set widget&#39;s value according to model</font></div><div><font size="2">    myWiget.set(&quot;ref&quot;, &quot;baz.bam&quot;) &lt;-- should reset widget&#39;s value according to new model</font></div>

    <div><font size="2"><br></font><br></div><div><br></div><div><div class="gmail_quote">On Sun, Mar 6, 2011 at 5:17 AM, Rahul Akolkar <span dir="ltr">&lt;<a href="mailto:rahul.akolkar at gmail.com" target="_blank">rahul.akolkar at gmail.com</a>&gt;</span> wrote:<br>

    <blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi Bill,<br>
    <br>
    Inline.<br>
    <div><br>
    On Fri, Mar 4, 2011 at 10:33 PM, Bill Keese &lt;<a href="mailto:bill at dojotoolkit.org" target="_blank">bill at dojotoolkit.org</a>&gt; wrote:<br>
    &gt; Glad you are getting good feedback from Ben.<br>
    </div>&lt;snip/&gt;<br>
    <br>
    Yup, good to have more pairs of eagle eyes on this. I am in the middle<br>
    of some minor refactorings based on all the comments so far. I expect<br>
    to have a refreshed patch by the end of the weekend.<br>
    <div><br>
    <br>
    &gt; Here&#39;s a reply to some of the stuff from my original note.<br>
    &gt;<br>
    </div>&lt;snap/&gt;<br>
    <br>
    Thanks, I was hoping it&#39;d come in before my refreshed patch became ready :-)<br>
    <div><br>
    <br>
    &gt;&gt;<br>
    &gt;&gt; &gt; 2. DataBindingMixin<br>
    &gt;&gt; &gt;<br>
    &gt;&gt; &gt; a) file structure<br>
    &gt;&gt; &gt; The root of the patch is _DataBindingMixin.js, which gets mixed into<br>
    &gt;&gt; &gt; _WidgetBase.   Current code for that is split across two files as:<br>
    &gt;&gt; &gt;<br>
    &gt;&gt; &gt; dojo.declare(&quot;dijit._DataBindingMixin&quot;, null, { ... });<br>
    &gt;&gt; &gt;<br>
    &gt;&gt; &gt; dojo.extend(dijit._WidgetBase, new dijit._DataBindingMixin());<br>
    &gt;&gt; &gt;<br>
    &gt;&gt; &gt; It would be simpler like this:<br>
    &gt;&gt; &gt;<br>
    &gt;&gt; &gt; dojo.extend(dijit._WidgetBase, {...});<br>
    &gt;&gt; &gt;<br>
    &gt;&gt; &gt; You can still pull _DataBindingMixin.js into StatefulModel.js if you<br>
    &gt;&gt; &gt; don&#39;t<br>
    &gt;&gt; &gt; want apps to need to explicitly dojo.require(DataBindingMixin).<br>
    &gt;&gt; &gt;<br>
    &gt;&gt; &lt;snap/&gt;<br>
    &gt;&gt;<br>
    &gt;&gt; Correct, thats indeed the objective. The data binding mixin is not<br>
    &gt;&gt; something we&#39;d want apps to explicitly dojo.require(). By &quot;pull into&quot;,<br>
    &gt;&gt; I&#39;m thinking you mean inline the source into the other file? Thats an<br>
    &gt;&gt; option.<br>
    &gt;<br>
    &gt;<br>
    &gt; Sorry, I meant that you could list _DataBindingMixin in the list of requires<br>
    &gt; for StatefulModel, in the first line define() call.<br>
    </div>&lt;snip/&gt;<br>
    <br>
    Oh, got it.<br>
    <div><br>
    <br>
    &gt; But I agree with Ben&#39;s comment, it seems wrong to make a dijit dependency on<br>
    &gt; StatefulModel just so apps can avoid an extra dojo.require() call<br>
    &gt; Would StatefulModel ever be useful outside of widgets?    A recursive<br>
    &gt; dojo.Stateful sounds useful in general, not sure about the other stuff in<br>
    &gt; there.<br>
    &gt;<br>
    </div>&lt;snap/&gt;<br>
    <br>
    Right, the dijit.StatefulModel class is already geared to deal with<br>
    specifics of a view layer (all the valid, readOnly, relevant etc.<br>
    meta-data lends well to view layer bindings). In theory, one could<br>
    capture the essence of the recursive model for reuse elsewhere. But<br>
    while it may be possible to craft a base class that is purely a<br>
    recursive dojo.Stateful model and then subclass it to provide what is<br>
    effectively dijit.StatefulModel functionality now, I can&#39;t say I have<br>
    many usecases at hand. Ofcourse, such refactoring can also happen down<br>
    the road if deemed essential.<br>
    <div><br>
    <br>
    &gt;&gt; &gt; e) _initControl()<br>
    &gt;&gt; &gt;<br>
    &gt;&gt; &gt; This is run from postCreate(), yet it assumes that the widget is<br>
    &gt;&gt; &gt; anchored to<br>
    &gt;&gt; &gt; the document.   You shouldn&#39;t assume that until startup() is called; in<br>
    &gt;&gt; &gt; particular it&#39;s not true for programatically created widgets ex:  new<br>
    &gt;&gt; &gt; dijit.form.TextBox().placeAt(...)<br>
    &gt;&gt; &gt;<br>
    &gt;&gt; &lt;snip/&gt;<br>
    &gt;&gt;<br>
    &gt;&gt; OK, I&#39;ll look into (d) and (e) above.<br>
    &gt;&gt;<br>
    &gt;<br>
    &gt; About having every widget trace up the tree to find a parent with a binding<br>
    &gt; specified, or if there&#39;s no such parent then tracing all the way to<br>
    &gt; &lt;body&gt;...    we faced that same problem with the bidi group and their<br>
    &gt; lobbying for every widget to support a dir parameter (possibly) being<br>
    &gt; inherited from an ancestor .  We didn&#39;t want to have every single widget<br>
    &gt; calling getParent() repeatedly to inspect it&#39;s ancestors as that seemed like<br>
    &gt; it would degrade performance on page load.   So we ended up adding code to<br>
    &gt; the parser to pass down the dir inherited from the ancestor.   I wonder if<br>
    &gt; that makes sense here.<br>
    </div>&lt;snip/&gt;<br>
    <br>
    It may make sense, but let me step back a bit. Some thoughts, in no<br>
    particular order:<br>
    <br>
    I assume by getParent() you mean dijit.getEnclosingWidget() which is<br>
    what is used here. The number of these calls is a function of: (a)<br>
    Number of data-bound widgets, (b) Topology of binds i.e. amount of<br>
    relative refs implied by nesting and (c) Average DOM separation (along<br>
    parent axis) between nested data-bound dijits.<br>
    <br>
    The observed rule of thumb is that at page load you&#39;d expect roughly<br>
    2x the number of dijit.getEnclosingWidget() calls as the number of<br>
    data-bound widgets. This is somewhat less pervasive than bidi as it<br>
    only applies to data-bound dijits (clearly, a view may have data-bound<br>
    dijits and others that aren&#39;t data-bound).<br>
    <br>
    There are two scenarios where bindings are calculated (or recalculated):<br>
    * Initial page load<br>
    * Programmatic binding update (example: when user chooses to list<br>
    details for a particular search result in the master-detail demos in<br>
    the patch, causing the bindings in the detail portion of the view to<br>
    be updated)<br>
    <br>
    Ben had a suggestion about an optional parent binding param to<br>
    _setupBinding(), which effectively removes the need for any DOM<br>
    operations or parent widget lookups in the second case.<br>
    <br>
    For the initial page load, the roughly 2x dijit.getEnclosingWidget()<br>
    calls may be avoided if we can get the parent binding to be<br>
    &quot;inherited&quot; through the parser. OTOH, these calls aren&#39;t terribly<br>
    expensive either (operations therein include .parentNode references,<br>
    getting the widgetId attribute values and a lookups into the widget<br>
    registry), so some of this could be done as incremental improvements.<br>
    <div><br>
    <br>
    &gt; In your response to Ben you gave this example:<br>
    &gt; model:<br>
    &gt;  { foo : { bar : { baz : { freddy : { frog : &quot;prince&quot; } } } } }<br>
    &gt;<br>
    &gt;<br>
    &gt; markup:<br>
    &gt;  &lt;div dojoType=&quot;dijit.mvc.Group&quot; ref=&quot;model.foo&quot;&gt;<br>
    &gt;  &lt;div dojoType=&quot;dijit.mvc.Group&quot; ref=&quot;bar&quot;&gt;<br>
    &gt;   &lt;div dojoType=&quot;dijit.mvc.Group&quot; ref=&quot;baz&quot;&gt;<br>
    &gt;    &lt;div dojoType=&quot;dijit.mvc.Group&quot; ref=&quot;freddy&quot;&gt;<br>
    &gt;     &lt;div dojoType=&quot;dijit.form.TextBox&quot; ref=&quot;frog&quot;&gt;<br>
    &gt;<br>
    &gt;<br>
    &gt; Hopefully that doesn&#39;t execute in O(n^2), where every widget needs to trace<br>
    &gt; to the top of the tree, does it?<br>
    </div>&lt;snap/&gt;<br>
    <br>
    In the above example:<br>
    * There are exactly 5 getEnclosingWidget() calls<br>
    * The total number of node.parentNode references looked up (including<br>
    those within these 5 calls) is exactly equal to the DOM depth of the<br>
    textbox on the page<br>
    <br>
    Let me try to understand why you say O(n^2), since every widget isn&#39;t<br>
    trying to reach every other widget on the page. Worst case performance<br>
    is linear to the total number of data-bound widgets (n) where the<br>
    constant in the linear equation is the average DOM separation across<br>
    all data-bound widgets (k). I guess you are assuming n tends to k on a<br>
    given page? (not usually the case). Also, if total number of dijits on<br>
    page is N, n &lt; N is common, if not outrightly n &lt;&lt; N.<br>
    <div><br>
    <br>
    &gt; I don&#39;t really understand the code that<br>
    &gt; executes for the TextBox figures out that it&#39;s connected to<br>
    &gt; model.foo.bar.baz.freddy.frog.   (What info is cached inside of the<br>
    &gt; innermost Group?)<br>
    </div>&lt;snip/&gt;<br>
    <br>
    There is no caching per se, direct references to nodes within the<br>
    StatefulModel are stored as &quot;binding&quot; property on appropriate dijits.<br>
    Here is how things work in above scenario:<br>
    1. Outermost group finds no data-bound parent, evals &quot;model.foo&quot; to<br>
    obtain its ref StatefulModel node<br>
    2. The next three groups locate their data-bound parent immediately<br>
    i.e. on first parent lookup (as its also the DOM parent), and each<br>
    resolves their ref expression as relative to parent. So, in the<br>
    absolute sense, 2nd group refs model.foo.bar, 3rd refs<br>
    model.foo.bar.baz and so on.<br>
    3. The textbox similarly (relatively) obtains its &quot;binding&quot; as a ref<br>
    to the model.foo.bar.baz.freddy.frog node (parent:<br>
    model.foo.bar.baz.freddy, relative ref: frog). At which point, the<br>
    data (i.e. &quot;value&quot;) and meta-data associations are set up between that<br>
    model node and the textbox, thereby the textbox displays the value<br>
    from the model i.e. &quot;prince&quot;.<br>
    <div><br>
    <br>
    &gt; Anyway, the parser has an &quot;inherited&quot; parameter that could be used to pass<br>
    &gt; down the ref from the parent.  I&#39;m not sure if using it makes sense or not.<br>
    &gt;<br>
    </div>&lt;snap/&gt;<br>
    <br>
    See above.<br>
    <div><div></div><div><br>
    <br>
    &gt;&gt;<br>
    &gt;&gt; &gt; 4. NumberTextBox, ValidationTextBox<br>
    &gt;&gt; &gt;<br>
    &gt;&gt; &gt; These methods are now assuming a super-class isValid() method, but that<br>
    &gt;&gt; &gt; method only exists when _DataBindingMixin is included.   I guess we need<br>
    &gt;&gt; &gt; to<br>
    &gt;&gt; &gt; define an empty isValid() method in _WidgetBase?   I don&#39;t know what<br>
    &gt;&gt; &gt; happens<br>
    &gt;&gt; &gt; when you call this.inherited(arguments) and there&#39;s no such super-class<br>
    &gt;&gt; &gt; function, but even if it works, it seems fragile.<br>
    &gt;&gt; &lt;snap/&gt;<br>
    &gt;&gt;<br>
    &gt;&gt; Nothing happens, see line 190 (linking to a few lines before that for<br>
    &gt;&gt; context):<br>
    &gt;&gt; <a href="http://bugs.dojotoolkit.org/browser/dojo/trunk/_base/declare.js?rev=23778#L186" target="_blank">http://bugs.dojotoolkit.org/browser/dojo/trunk/_base/declare.js?rev=23778#L186</a><br>
    &gt;&gt;<br>
    &gt;&gt; That aside, yes, this was slightly tricky because there was no<br>
    &gt;&gt; corresponding isValid() in _WidgetBase whereas I think there should<br>
    &gt;&gt; be. Also, not all dijits check base class validity (where applicable)<br>
    &gt;&gt; before deciding their isValid() status and once its added to<br>
    &gt;&gt; _WidgetBase, they should (and thereby, the model validity will be<br>
    &gt;&gt; accounted for in cases where the data binding mixin is applied).<br>
    &gt;&gt;<br>
    &gt;<br>
    &gt; OK, adding it to _WidgetBase is something to consider.    But again, there<br>
    &gt; would be the &quot;problem&quot; where your mixin is simply overwriting the<br>
    &gt; isValid()method in _WidgetBase.js, like it&#39;s overwriting postCreate() now.<br>
    &gt;  The isValid() problem is harder to solve since dojo.connect() doesn&#39;t work<br>
    &gt; since you need to return a value, I guess you should be doing something<br>
    &gt; like:<br>
    &gt; var oldIsValid = dijit._WidgetBase.isValid;<br>
    &gt; dijit._WidgetBase.isValid = function(){ return this.oldIsValid() &amp;&amp;<br>
    &gt; your-code-here; }<br>
    &gt;<br>
    </div></div>&lt;snip/&gt;<br>
    <br>
    OK, that would cover all bases. OTOH, isValid() would simply return<br>
    true in _WidgetBase, can&#39;t imagine much else going on there.<br>
    <div><br>
    <br>
    &gt;&gt;<br>
    &gt;&gt; &gt; 5. dijit.mvc._Container<br>
    &gt;&gt; &gt;<br>
    &gt;&gt; &gt; This has &gt;100 lines of cut-pasted code from _Templated and doesn&#39;t<br>
    &gt;&gt; &gt; support<br>
    &gt;&gt; &gt; the new data-dojo-attach-point etc. syntax.   Can you do better?   See<br>
    &gt;&gt; &gt; dijit.Declaration, maybe you can have similar code.<br>
    &gt;&gt; &lt;snip/&gt;<br>
    &gt;&gt;<br>
    &gt;&gt; Yes, its listed as a TODO in code -- it&#39;d be good to remove that<br>
    &gt;&gt; duplication. The issue as I remember was that I wasn&#39;t able to reuse<br>
    &gt;&gt; _Templated directly as the way it deals with templates and template<br>
    &gt;&gt; caches is different from, say repeat, where the template is inline<br>
    &gt;&gt; (body). I&#39;ll take another look at dijit.Declaration, but ISTR some<br>
    &gt;&gt; other differences there.<br>
    &gt;<br>
    &gt;<br>
    &gt; This inheritance from _Container to both Group and Repeater confuses me.<br>
    &gt;  While Group is just a plain wrapper widget, similar to dijit.form.Form or<br>
    &gt; dijit.layout.ContentPane, Repeater is a different beast that generates from<br>
    &gt; a template.<br>
    </div>&lt;snap/&gt;<br>
    <br>
    It sure would be confusing if that were the case :-) Group does not<br>
    inherit from _Container, it inherits from _WidgetBase. Its the<br>
    simplest data-bound widget that is very useful in setting up<br>
    hierarchical data bindings (ref&#39;ing to intermediate model nodes).<br>
    <div><br>
    <br>
    &gt;   I guess my question is, why does mvc._Container have any code<br>
    &gt; about templates?<br>
    &gt;<br>
    </div>&lt;snip/&gt;<br>
    <br>
    In hindsight, somewhat unnecessary. I&#39;ve refactored that out of<br>
    _Container (please see next patch in a day or two).<br>
    <div><br>
    <br>
    &gt;&gt;<br>
    &gt;&gt; &gt; b) the declaredClass references here and in other parts of the code<br>
    &gt;&gt; &gt; aren&#39;t<br>
    &gt;&gt; &gt; future-proof.   declaredClass will likely go away in 2.0.<br>
    &gt;&gt; &lt;snap/&gt;<br>
    &gt;&gt;<br>
    &gt;&gt; OK, any future-proof equivalent? I&#39;ll investigate or use a bit more of<br>
    &gt;&gt; the duck typing sauce if needed.<br>
    &gt;<br>
    &gt; Yes, if there isn&#39;t an obvious way to ducktype (ex: testing if a certain<br>
    &gt; method like then() is available), then in dijit for example we have<br>
    &gt; isContainer and isLayoutContainer flags on widgets that indicate they have a<br>
    &gt; certain functionality.<br>
    &gt;<br>
    </div>&lt;snap/&gt;<br>
    <br>
    Thanks, there is, toPlainObject() is used as the duck typing signature.<br>
    <font color="#888888"><br>
    -Rahul<br>
    </font></blockquote></div><br></div>

    --000e0cd5c8720ff651049dc6defa--

    From bogus@does.not.exist.com Tue Jan 18 18:42:17 2011
    From: bogus@does.not.exist.com ()
    Date: Tue, 18 Jan 2011 23:42:17 -0000
    Subject: No subject
    Message-ID: <mailman.10.1299861896.13280.dojo-contributors@mail.dojotoolkit.org>

    say an IBM product includes some sort of distribution, it is a lot
    easier to prove IP et al if the actual source of something is clear.
    In other words, if the main distribution was assembled from a repo
    owned and maintained by the Dojo Foundation, it is a lot easier for
    IBM's lawyers to approve the distribution--as opposed to having to
    trace the code history through a bunch of individual GitHub accounts.
    It also ensures that things like CLAs and such have actually been
    checked against *before* getting a distribution.

    Does that make sense? It's kind of wordy and the coffee hasn't
    entirely kicked in yet =)

    -- Tom

    From bogus@does.not.exist.com Tue Jan 18 18:42:17 2011
    From: bogus@does.not.exist.com ()
    Date: Tue, 18 Jan 2011 23:42:17 -0000
    Subject: No subject
    Message-ID: <mailman.17.1301565859.13280.dojo-contributors@mail.dojotoolkit.org>

    one of these). Ideally we could have also tablets vs phones detection for
    each of these platforms. Even if that is not much leveraged now compare to
    the other flags I suspect more and more people might need to adapt to mobile
    vs tablets.

    What other thinks? Should we all continue to have our own detection or
    should we put that in a central place and where?

    Thanks,
    --
    Christophe

    --002354471ad45428f4049fc46a51
    Content-Type: text/html; charset=ISO-8859-1
    Content-Transfer-Encoding: quoted-printable

    Hi everyone,<br><br>Sorry if that has already been raised but I&#39;m starting to see more and more code that is detecting mobile devices vs desktop devices.<br><br>There is some in touch event patch:<br><br><span style="white-space: pre-wrap;"><a href="http://bugs.dojotoolkit.org/attachment/ticket/12176/touch0.2.patch" target="_blank">http://bugs.dojotoolkit.org/attachment/ticket/12176/touch0.2.patch</a><br>
    <br>That is detecting iOS/Android/Mobile<br><br>There is some in dojox.mobile:<br><br><a href="http://svn.dojotoolkit.org/src/dojox/trunk/mobile/app/_event.js">http://svn.dojotoolkit.org/src/dojox/trunk/mobile/app/_event.js</a><br>
    <br>That is detecting iPhone/Android/WebOS<br><br>And finally there is some in demos (and probably users code) that is doing something similar.<br><br>Shouldn&#39;t we consolidate that so that not everyone has to write his own detection and also that everyone get consistent results (for example dojox.mobile isIPhone does not take iPad into account while touch events patch is)?<br>
    <br clear="all"></span>From what I see we need at least iOS/Android &amp; WebOS detection (mobile being one of these). Ideally we could have also tablets vs phones detection for each of these platforms. Even if that is not much leveraged now compare to the other flags I suspect more and more people might need to adapt to mobile vs tablets.<br>
    <br>What other thinks? Should we all continue to have our own detection or should we put that in a central place and where?<br><br>Thanks,<br>-- <br>Christophe<br>

    --002354471ad45428f4049fc46a51--

    From bogus@does.not.exist.com Tue Jan 18 18:42:17 2011
    From: bogus@does.not.exist.com ()
    Date: Tue, 18 Jan 2011 23:42:17 -0000
    Subject: No subject
    Message-ID: <mailman.18.1301586576.13280.dojo-contributors@mail.dojotoolkit.org>

    Dojo codebase could be handled by this simple query engine. The more
    exotic queries are rarely if ever used internally, and most apps could
    probably be built with the simple engine.

    * dojo/query is a new module, and effectively using this instead of base
    (and thus dojo/_base/query) is the opt-in to simpler, more native-based
    querying.

    * Backwards compatible, base will load "dojo/query!slick" or
    "dojo/query!dojo/acme" or something. We can also allow for configuration
    to opt-in to conditionally load the full selector engine (use native
    codepath if possible) rather than always loading it.

    * dojo/query provides the NodeList wrapping of the arrays returned from
    the selector engine. This makes it easier to plug in selector engines
    without the selector engine actually having to do the NodeList wrapping.
    A selector engine only needs to return arrays. Therefore we can use
    Sizzle or Slick with little or no modification (rather than having to
    keep a fork in the dojo codebase).

    * First class support for CSS matching testing. The default
    implementation uses the vendorMatchesSelector() if available, otherwise
    the internal matching code, which means we can do efficient event
    delegation (from what I can tell, the current implementation in dojox is
    painfully inefficient since it relies on full queries to check for CSS
    matching).

    * Uses has() branching. The full module is about 3.3 KB (compressed, not
    gzipped). With a modern browser build (with qSA) it is less than 2KB
    (just the plugin code, NodeList wrapping and root correction with fast
    paths when qSA is not the fastest approach).

    * At the intersection of the new event handling and this proposed query
    selection mechanism, I added event delegation support to
    NodeList.prototype.on in my branch to consider, so you can do:
    query("#list").on("li:click") to listen for clicks on <li> children of
    the #list.
    This leverages the efficient match method provided by the selector
    engine (which by default comes from native impl if available).

    * The default implementation should be very fast for simple common
    queries since it fast-paths to native specific methods when possible.

    Let me know if you think this is worth pursuing.
    Thanks,
    Kris
    On 3/25/2011 7:56 PM, Stephen Chung wrote:
    My suggestions in order to help out programmers out here:

    Option #1: Split dojo.query into two parts, say dojo.query and
    dojo.simpleQuery. dojo.simpleQuery to handle only subset of selectors
    that all popular QSA implementations can handle (i.e. the LCD set).
    dojo.query continue to handle all, including advanced, queries.
    dojo.simpleQuery delegates to QSA where possible. dojo.query is
    always JS implementation.

    Option #2: Always delegate dojo.query to QSA where available, which
    means that the same dojo.query call may fail in some browsers ??? the
    programmer just has to test. Make dojo.queryAdvanced ==> always JS ???
    anybody who wants it ???just to work??? everywhere without extensive
    testing can use this instead.

    You can see that the goal of my suggestion is to make sure that the
    dev and built versions behave the same in all browsers. That???s
    because if builds work differently from dev version, it is usually a
    royal pain to debug...

    - Stephen


    *From:* Kris Zyp <mailto:kzyp at dojotoolkit.org>
    *Sent:* Saturday, 26 March, 2011 12:36 AM
    *To:* dojo dev. <mailto:dojo-contributors at mail.dojotoolkit.org>
    *Cc:* Stephen Chung <mailto:Stephen.Chung at intexact.com>
    *Subject:* Re: [dojo-contributors] Query Selector Engines
    On 3/25/2011 10:18 AM, Stephen Chung wrote:
    My $0.02's worth of experience:

    Originally wrote dojo.query("> input, > select, > textarea", node) to
    iterate through all the input elements under a frame node. No prob here.

    Then build with webkitMobile set. Suddenly didn't work on the iPad
    (non-built version worked ok). Strangely, the same code continued to work
    in desktop WebKit browser.
    This illustrates a fundamental problem with build-pragmas and why we
    are switching to has(). Dev runtime and build-time should behave the
    same. When you have different branches for builds then dev runtime you
    inevitably run into problems. We shouldn't need warning messages, we
    need consistent execution paths. The webkitMobile branch in dojo.query
    is buggy because it doesn't get exercised.
    Took most of one day with "console.log" statements (seems to only way to
    debug strange errors on the iPad) to figure out why: with
    webkitMobile set,
    dojo.query redirects to QSA. However, when the second argument is set, it
    tagged "#"+node in front of the query text, making it "#frame > input, >
    select, > textarea" which skipped all the select/textarea tags.

    I eventually had to remove the call to dojo.query and manually looped
    through the children.

    So, currently dojo.query and QSA are not 100% compatible anyway
    (considering
    the flaky interpretation of the ">" children queries and the "," group
    queries in QSA), so I am pretty sure many people out there are going through
    the same thing, finding out the first time they tested their new build to
    know that it failed to work on some browsers with QSA.
    Just FYI, if you run our unit tests on the native QSA there are number
    of other tests that fail. I believe there are some complicated :not
    tests that no browsers handle like we do at the moment, and then IE8
    fails on a lot of the pseudo selectors (assuming some of that is fixed
    in IE9). Not that these queries are really used that much. Looking at
    the Dojo code base, almost all dojo.query() calls are easily handled
    by any native QSA (at least if we fixed the > and , combination bug,
    which I noticed when I looked at that code as well). I saw one test
    that used a :nth-child that IE wouldn't have been able to handle, and
    dojox.mobile uses similar pseudos (but obviously it isn't targeted at IE).

    I think Dojo base clearly needs to default to our full CSS
    capabilities. Having an opt-in for less guarantees (FF and WebKit's
    QSA at least still reliably provide more selectors than any mere
    mortal should ever need) so native QSA can be used more frequently
    would be beneficial.
    Thanks,
    Kris

    ------------------------------------------------------------------------

    No virus found in this incoming message.
    Checked by AVG - www.avg.com
    Version: 9.0.894 / Virus Database: 271.1.1/3529 - Release Date:
    03/26/11 00:54:00

    --------------080800090002030206030804
    Content-Type: text/html; charset=UTF-8
    Content-Transfer-Encoding: 8bit

    <html>
    <head>
    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
    </head>
    <body bgcolor="#FFFFFF" text="#000000">
    Based on these suggestions (for different levels of querying), and
    the move to better modularization and feature detect branching, I
    put together an attempt at a new query entry module:<br>
    <a
    href="https://github.com/kriszyp/dojo/blob/has-modularize/query.js">https://github.com/kriszyp/dojo/blob/has-modularize/query.js</a><br>
    Key parts of this approach:<br>
    * This module provides a default very simple lightweight selector
    implementation and leans heavily on native querySelectorAll when
    available. You can then choose to load a full selector engine if you
    want with injection via AMD plugin syntax or the setEngine method:<br>
    For example, to use the Sizzle engine, we could do:<br>
    define("dojo/query!sizzle", function(query){<br>
    ...<br>
    or to only use Sizzle if a good native qSA is not available:<br>
    define("dojo/query!sizzle?", function(query){<br>
    or to use jQuery:<br>
    query.setEngine($)<br>
    When you only need basic queries, you can do:<br>
    define("dojo/query", function(query){<br>
    query("#id div");<br>
    When you require something like "dojo/query!slick?" it allows you to
    only load a full engine if there isn't a native qSA, so mobile
    builds can still be very light.<br>
    define("dojo/query!slick?", function(query){<br>
    query("#id div:nth-child(odd)");<br>
    From my survey of Dojo, it looks like virtually every query used in
    the Dojo codebase could be handled by this simple query engine. The
    more exotic queries are rarely if ever used internally, and most
    apps could probably be built with the simple engine.<br>
    <br>
    * dojo/query is a new module, and effectively using this instead of
    base (and thus dojo/_base/query) is the opt-in to simpler, more
    native-based querying.<br>
    <br>
    * Backwards compatible, base will load "dojo/query!slick" or
    "dojo/query!dojo/acme" or something. We can also allow for
    configuration to opt-in to conditionally load the full selector
    engine (use native codepath if possible) rather than always loading
    it.<br>
    <br>
    * dojo/query provides the NodeList wrapping of the arrays returned
    from the selector engine. This makes it easier to plug in selector
    engines without the selector engine actually having to do the
    NodeList wrapping. A selector engine only needs to return arrays.
    Therefore we can use Sizzle or Slick with little or no modification
    (rather than having to keep a fork in the dojo codebase).<br>
    <br>
    * First class support for CSS matching testing. The default
    implementation uses the vendorMatchesSelector() if available,
    otherwise the internal matching code, which means we can do
    efficient event delegation (from what I can tell, the current
    implementation in dojox is painfully inefficient since it relies on
    full queries to check for CSS matching).<br>
    <br>
    * Uses has() branching. The full module is about 3.3 KB (compressed,
    not gzipped). With a modern browser build (with qSA) it is less than
    2KB (just the plugin code, NodeList wrapping and root correction
    with fast paths when qSA is not the fastest approach).<br>
    <br>
    * At the intersection of the new event handling and this proposed
    query selection mechanism, I added event delegation support to
    NodeList.prototype.on in my branch to consider, so you can do:<br>
    query("#list").on("li:click") to listen for clicks on &lt;li&gt;
    children of the #list.<br>
    This leverages the efficient match method provided by the selector
    engine (which by default comes from native impl if available).<br>
    <br>
    * The default implementation should be very fast for simple common
    queries since it fast-paths to native specific methods when
    possible.<br>
    <br>
    Let me know if you think this is worth pursuing.<br>
    Thanks,<br>
    Kris<br>
    <br>
    On 3/25/2011 7:56 PM, Stephen Chung wrote:
    <blockquote cite="mid:74D363A654CE41B8815C0338D2F91BE5 at StephenChung"
    type="cite">
    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
    <div dir="ltr">
    <div style="FONT-FAMILY: 'Droid Sans'; COLOR: #080000;
    FONT-SIZE: 14pt">
    <div><font size="4">My suggestions in order to help out
    programmers out here:</font></div>
    <div>??</div>
    <div><font size="4">Option #1: Split dojo.query into two
    parts, say dojo.query and dojo.simpleQuery.??
    dojo.simpleQuery to handle only subset of selectors that
    all popular QSA implementations can handle (i.e. the LCD
    set).?? dojo.query continue to handle all, including
    advanced, queries.?? dojo.simpleQuery delegates to QSA
    where possible.?? dojo.query is always JS implementation.</font></div>
    <div>??</div>
    <div><font size="4">Option #2: Always delegate dojo.query to
    QSA where available, which means that the same dojo.query
    call may fail in some browsers ??? the programmer just has
    to test.?? Make dojo.queryAdvanced ==&gt; always JS ???
    anybody who wants it ???just to work??? everywhere without
    extensive testing can use this instead.</font></div>
    <div>??</div>
    <div><font size="4">You can see that the goal of my suggestion
    is to make sure that the dev and built versions behave the
    same in all browsers.?? That???s because if builds work
    differently from dev version, it is usually a royal pain
    to debug...</font></div>
    <div>??</div>
    <div><font size="4">- Stephen</font></div>
    <div>??</div>
    <div style="FONT-STYLE: normal; DISPLAY: inline; FONT-FAMILY:
    'Calibri'; COLOR: #000000; FONT-SIZE: small; FONT-WEIGHT:
    normal; TEXT-DECORATION: none">
    <div style="FONT: 10pt tahoma">
    <div>??</div>
    <div style="BACKGROUND: #f5f5f5">
    <div style="font-color: black"><b>From:</b> <a
    moz-do-not-send="true" title="kzyp at dojotoolkit.org"
    href="mailto:kzyp at dojotoolkit.org">Kris Zyp</a> </div>
    <div><b>Sent:</b> Saturday, 26 March, 2011 12:36 AM</div>
    <div><b>To:</b> <a moz-do-not-send="true"
    title="dojo-contributors at mail.dojotoolkit.org"
    href="mailto:dojo-contributors at mail.dojotoolkit.org">dojo
    dev.</a> </div>
    <div><b>Cc:</b> <a moz-do-not-send="true"
    title="Stephen.Chung at intexact.com"
    href="mailto:Stephen.Chung at intexact.com">Stephen
    Chung</a> </div>
    <div><b>Subject:</b> Re: [dojo-contributors] Query
    Selector Engines</div>
    </div>
    </div>
    <div>??</div>
    </div>
    <div style="FONT-STYLE: normal; DISPLAY: inline; FONT-FAMILY:
    'Calibri'; COLOR: #000000; FONT-SIZE: small; FONT-WEIGHT:
    normal; TEXT-DECORATION: none">On 3/25/2011 10:18 AM,
    Stephen Chung wrote: <br>
    <span style="WHITE-SPACE: pre">&gt; My $0.02's worth of
    experience: <br>
    &gt; <br>
    &gt; Originally wrote dojo.query("&gt; input, &gt; select,
    &gt; textarea", node) to <br>
    &gt; iterate through all the input elements under a frame
    node. No prob here. <br>
    &gt; <br>
    &gt; Then build with webkitMobile set. Suddenly didn't
    work on the iPad <br>
    &gt; (non-built version worked ok). Strangely, the same
    code continued to work <br>
    &gt; in desktop WebKit browser. <br>
    </span><br>
    This illustrates a fundamental problem with build-pragmas
    and why we are switching to has(). Dev runtime and
    build-time should behave the same. When you have different
    branches for builds then dev runtime you inevitably run into
    problems. We shouldn't need warning messages, we need
    consistent execution paths. The webkitMobile branch in
    dojo.query is buggy because it doesn't get exercised.<br>
    <span style="WHITE-SPACE: pre"><br>
    &gt; Took most of one day with "console.log" statements
    (seems to only way to <br>
    &gt; debug strange errors on the iPad) to figure out why:
    with webkitMobile set, <br>
    &gt; dojo.query redirects to QSA. However, when the second
    argument is set, it <br>
    &gt; tagged "#"+node in front of the query text, making it
    "#frame &gt; input, &gt; <br>
    &gt; select, &gt; textarea" which skipped all the
    select/textarea tags. <br>
    &gt; <br>
    &gt; I eventually had to remove the call to dojo.query and
    manually looped <br>
    &gt; through the children. <br>
    &gt; <br>
    &gt; So, currently dojo.query and QSA are not 100%
    compatible anyway (considering <br>
    &gt; the flaky interpretation of the "&gt;" children
    queries and the "," group <br>
    &gt; queries in QSA), so I am pretty sure many people out
    there are going through <br>
    &gt; the same thing, finding out the first time they
    tested their new build to <br>
    &gt; know that it failed to work on some browsers with
    QSA. <br>
    </span><br>
    Just FYI, if you run our unit tests on the native QSA there
    are number of other tests that fail. I believe there are
    some complicated :not tests that no browsers handle like we
    do at the moment, and then IE8 fails on a lot of the pseudo
    selectors (assuming some of that is fixed in IE9). Not that
    these queries are really used that much. Looking at the Dojo
    code base, almost all dojo.query() calls are easily handled
    by any native QSA (at least if we fixed the &gt; and ,
    combination bug, which I noticed when I looked at that code
    as well). I saw one test that used a :nth-child that IE
    wouldn't have been able to handle, and dojox.mobile uses
    similar pseudos (but obviously it isn't targeted at IE).<br>
    <br>
    I think Dojo base clearly needs to default to our full CSS
    capabilities. Having an opt-in for less guarantees (FF and
    WebKit's QSA at least still reliably provide more selectors
    than any mere mortal should ever need) so native QSA can be
    used more frequently would be beneficial.<br>
    Thanks,<br>
    Kris<br>
    <p>
    </p>
    <hr>
    <br>
    No virus found in this incoming message.<br>
    Checked by AVG - <a class="moz-txt-link-abbreviated" href="http://www.avg.com">www.avg.com</a> <br>
    Version: 9.0.894 / Virus Database: 271.1.1/3529 - Release
    Date: 03/26/11 00:54:00<br>
    </div>
    </div>
    </div>
    </blockquote>
    <br>
    </body>
    </html>

    --------------080800090002030206030804--

    From bogus@does.not.exist.com Tue Jan 18 18:42:17 2011
    From: bogus@does.not.exist.com ()
    Date: Tue, 18 Jan 2011 23:42:17 -0000
    Subject: No subject
    Message-ID: <mailman.19.1301744374.13280.dojo-contributors@mail.dojotoolkit.org>

    * Two-way / bi-directional binds between application data models and
    widgets (supported via ref)
    * One-way binds between model items for client-side "calculates"
    (supported via bindProperties)

    Here as well, I am not against adding more "modes" to a generic
    substrate (the stateless bits I mention above) if others think its
    worthwhile.

    - Bindings -- should be able to markup multiple bindings to multiple
    properties of the widget, hopefully in both directions! That way, for
    example, you can bind the value of a ValidationTextBox to one property on
    the model, then bind the validation function to another property, and bind
    the display formatting mask to yet another property etc.
    <snip/>

    Sure, this can be done programmatically. Some of the things you
    mention above don't usually change on the widget side so binds in both
    directions may not be necessary, though there isn't any reason why
    they can't be set up in both directions if needed.

    Or by markup, did you mean doing this declaratively? That may require
    some changes -- see recent thread about model-bound menus for some
    illustrations in this space.

    - I suggest that, instead of creating a dijit.mvc.Group container class,
    just put the hierarchical binding context mechanism into WidgetBase. Then
    any widget can act as a holder of a binding context for all its children.
    In other words, binding to data context should be completely orthogonal to
    the widgets system. You may still eventually still need a dijit.Group just
    for grouping things though (it is generic enough to not need the MVC
    annotation).
    <snap/>

    Agreed, particularly since this is how things work :-) If there is a
    data-bound parent already, it sets up the hierarchical data binding
    context. If there is no "natural" parent, and grouping some subset of
    the view makes sense given application view semantics, a group
    container may be used which is a simple shell whose primarily purpose
    is to provide common data binding context to its descendents. The
    machinery to do all this is provided in the DataBindingMixin.

    - Not sure whether this is in dijit.StatefulModel (have to scan through the
    patch), but it should also abstract out an array of items, automatically
    keeping track of the "current" one. Programs can next/back/jump through the
    array, changing the current item, which automatically updates bound widgets
    to display new data. Currently, the programmer has to set the "ref"
    property in order to change binding to the new array index property -- we
    should be able to save this little program step as well, since this occurs
    in almost every master-detail type form.
    <snip/>

    Right, there is value to adding current index tracking for arrays.
    Ofcourse, till its available, this can be tracked easily by the
    application model.

    All-in-all, a summary of my suggestions (so far):

    1. Abstract binding mechanism into requiring at least one dojo.Stateful and
    one object; ability to bind to any property, with type/format converters
    support
    2. dojo.StatefulModel and dijit.StatefulModel on top of raw-metal binding,
    with added features (e.g. dojo.StatefulModel can connect to dojo.store's,
    and dijit.StatefulModel handles widgets)
    3. Different binding modes -- one-way in both directions, two-way, once
    only, and perhaps others as well
    4. Declaratively specify multiple bindings on one widget to different
    properties
    5. Extend binding contexts with the ability to keep track of the "current
    object" if the object acting as binding context is an array, with
    programmatic control -- which means that, if specified, this context will
    pass the current object to its children as binding context instead of the
    array (which requires its children to manually bind to an index)
    <snap/>

    Good feedback, I've responded to these items above. I see now that you
    mean declaratively for item 4 -- this is something on the incremental
    roadmap.

    Best,
    -Rahul

    Will give more comments after looking through patch code. Thanks!

    - Stephen
    From bogus@does.not.exist.com Tue Jan 18 18:42:17 2011
    From: bogus@does.not.exist.com ()
    Date: Tue, 18 Jan 2011 23:42:17 -0000
    Subject: No subject
    Message-ID: <mailman.20.1302129533.13280.dojo-contributors@mail.dojotoolkit.org>

    the 1.6.1 fixes (particularly IE9 and FF4 support) in by next week's
    meeting, so we can release 1.6.1. Thanks!

    --20cf3054a4b50b926504a047a88c
    Content-Type: text/html; charset=ISO-8859-1
    Content-Transfer-Encoding: quoted-printable

    <font size="2">From the meeting today (in case you weren&#39;t there), the plan is to get all the 1.6.1 fixes (particularly IE9 and FF4 support) in by next week&#39;s meeting, so we can release 1.6.1.    Thanks!</font>

    --20cf3054a4b50b926504a047a88c--

    From bogus@does.not.exist.com Tue Jan 18 18:42:17 2011
    From: bogus@does.not.exist.com ()
    Date: Tue, 18 Jan 2011 23:42:17 -0000
    Subject: No subject
    Message-ID: <mailman.25.1303996751.13280.dojo-contributors@mail.dojotoolkit.org>

    that has been connected to used to have a _listeners property. The chart
    event handling is checking for this property to avoid superfluous work.
    Since this commit the property is not here anymore and no work is done
    anymore ;)

    Is there something similar with the new event handling that charting code
    can use instead to check for listeners presence on a method?

    Thanks,
    --
    Christophe
    On Tue, Apr 26, 2011 at 5:34 AM, Kris Zyp wrote:

    I just made a substantial checkin (r24471) of the new event handling
    system and query delegation modules. By checking this in, I don't mean
    to indicate that this is an unreversable change to Dojo, but it seems
    clear that we need to get these proposed changes easily available to
    test and keeping a branch is difficult to maintain. Bill has provided me
    a ton of assistance in testing this out on Dijit (Thank you Bill!), so
    hopefully it is in relatively good shape as far as stability (I guess we
    will see though). Changes include:

    * Addition of dojo/listen, a lighter weight event handling module that
    loses some of the cruft that dojo.connect has built up, and provides
    some cool new features including event delegation, extension events,
    touch event normalization, method/event separation, and event dispatching.
    * Addition of dojo/aspect, a very small module to add aspects to
    methods. This is included since dojo/listen relies on this module for
    listening to non-DOM objects. This suppors before, after, and around
    advice based largely on Eugene's suggestions/specifications.
    * dojo/_base/connect.js and .../event.js built on dojo/listen now, with
    some back-compat shims to keep it's behavior the same.
    * dojo.NodeList includes an on() method that delegates to dojo/listen
    for nodes in the NodeList (with full event delegation support of course).
    * Addition of dojo/mouse.js to provide the mouse.enter and mouse.leave
    extension events that correspond to dojo.connect's "mouseenter" and
    "mouseleave" emulated events.
    * Added some feature detect tests to dojo/has.js for tests that are used
    by multiple modules.
    * Added JSON validation dojo/json.js for secure/strict validation of
    JSON in browsers without native support.
    * Addition of dojo/query.js as entry module to performing DOM/selector
    queries. This delegates to Acme by default, but can be configured for
    alternate engines (tested with Slick, Sizzle, and the new lite engine).
    * Cleaner separation of selector engine so we can use Slick and Sizzle
    without (or with minimal module wrapping) modification.
    * Move Acme (dojo/_base/query.js) to dojo/selector/acme.js for better
    clarity
    * Addition of dojo/selector/lite.js as a very simple lightweight engine
    that can be used as alternative to Acme for applications that don't need
    everything Acme has.
    * New unit tests to test this new stuff
    * Some other minor updates to modules to better leverage improved AMD
    support in Dojo.
    * loader-catchApi config setting to false by default. It is terribly
    difficult to debug without this.

    I recognize there are still some wrinkles to be ironed out. I have some
    experiments with managing memory for IE leakage. The class DOM-JS object
    cycle problem is well understood and solvable, however the way we are
    currently solving the problem actually causes memory leaks in IE8 and
    newer, and I really would like to avoid causing additional leakage. I
    have tried some alternative approaches, but IE8 also some weird iframe
    related memory leakage that are very difficult to pin down (it is not
    the same as the normal DOM cycle leakage), so I still hope to make some
    improvements in this area.

    Let me know what issues you find.
    Thanks,
    Kris
    _______________________________________________
    dojo-contributors mailing list
    dojo-contributors at mail.dojotoolkit.org
    http://mail.dojotoolkit.org/mailman/listinfo/dojo-contributors
    --0016e6509fb2d9378b04a1fa66af
    Content-Type: text/html; charset=ISO-8859-1
    Content-Transfer-Encoding: quoted-printable

    Hi Krys,<br><br>Following your commit, if you play with the charting test case below and try to get tooltips on chart markers you&#39;ll see that charting event handling is broken because no tooltip appear:<br><br><a href="http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/charting/tests/test_event2d.html">http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/charting/tests/test_event2d.html</a><br>
    <br>From what I can see charting event handling relies on the fact that a method that has been connected to used to have a _listeners property. The chart event handling is checking for this property to avoid superfluous work. Since this commit the property is not here anymore and no work is done anymore ;)<br>
    <br>Is there something similar with the new event handling that charting code can use instead to check for listeners presence on a method? <br><br>Thanks,<br>--<br>Christophe<br><br><div class="gmail_quote">On Tue, Apr 26, 2011 at 5:34 AM, Kris Zyp <span dir="ltr">&lt;<a href="mailto:kzyp at dojotoolkit.org">kzyp at dojotoolkit.org</a>&gt;</span> wrote:<br>
    <blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">I just made a substantial checkin (r24471) of the new event handling<br>
    system and query delegation modules. By checking this in, I don&#39;t mean<br>
    to indicate that this is an unreversable change to Dojo, but it seems<br>
    clear that we need to get these proposed changes easily available to<br>
    test and keeping a branch is difficult to maintain. Bill has provided me<br>
    a ton of assistance in testing this out on Dijit (Thank you Bill!), so<br>
    hopefully it is in relatively good shape as far as stability (I guess we<br>
    will see though). Changes include:<br>
    <br>
    * Addition of dojo/listen, a lighter weight event handling module that<br>
    loses some of the cruft that dojo.connect has built up, and provides<br>
    some cool new features including event delegation, extension events,<br>
    touch event normalization, method/event separation, and event dispatching.<br>
    * Addition of dojo/aspect, a very small module to add aspects to<br>
    methods. This is included since dojo/listen relies on this module for<br>
    listening to non-DOM objects. This suppors before, after, and around<br>
    advice based largely on Eugene&#39;s suggestions/specifications.<br>
    * dojo/_base/connect.js and .../event.js built on dojo/listen now, with<br>
    some back-compat shims to keep it&#39;s behavior the same.<br>
    * dojo.NodeList includes an on() method that delegates to dojo/listen<br>
    for nodes in the NodeList (with full event delegation support of course).<br>
    * Addition of dojo/mouse.js to provide the mouse.enter and mouse.leave<br>
    extension events that correspond to dojo.connect&#39;s &quot;mouseenter&quot; and<br>
    &quot;mouseleave&quot; emulated events.<br>
    * Added some feature detect tests to dojo/has.js for tests that are used<br>
    by multiple modules.<br>
    * Added JSON validation dojo/json.js for secure/strict validation of<br>
    JSON in browsers without native support.<br>
    * Addition of dojo/query.js as entry module to performing DOM/selector<br>
    queries. This delegates to Acme by default, but can be configured for<br>
    alternate engines (tested with Slick, Sizzle, and the new lite engine).<br>
    * Cleaner separation of selector engine so we can use Slick and Sizzle<br>
    without (or with minimal module wrapping) modification.<br>
    * Move Acme (dojo/_base/query.js) to dojo/selector/acme.js for better<br>
    clarity<br>
    * Addition of dojo/selector/lite.js as a very simple lightweight engine<br>
    that can be used as alternative to Acme for applications that don&#39;t need<br>
    everything Acme has.<br>
    * New unit tests to test this new stuff<br>
    * Some other minor updates to modules to better leverage improved AMD<br>
    support in Dojo.<br>
    * loader-catchApi config setting to false by default. It is terribly<br>
    difficult to debug without this.<br>
    <br>
    I recognize there are still some wrinkles to be ironed out. I have some<br>
    experiments with managing memory for IE leakage. The class DOM-JS object<br>
    cycle problem is well understood and solvable, however the way we are<br>
    currently solving the problem actually causes memory leaks in IE8 and<br>
    newer, and I really would like to avoid causing additional leakage. I<br>
    have tried some alternative approaches, but IE8 also some weird iframe<br>
    related memory leakage that are very difficult to pin down (it is not<br>
    the same as the normal DOM cycle leakage), so I still hope to make some<br>
    improvements in this area.<br>
    <br>
    Let me know what issues you find.<br>
    Thanks,<br>
    Kris<br>
    _______________________________________________<br>
    dojo-contributors mailing list<br>
    <a href="mailto:dojo-contributors at mail.dojotoolkit.org">dojo-contributors@mail.dojotoolkit.org</a><br>
    <a href="http://mail.dojotoolkit.org/mailman/listinfo/dojo-contributors" target="_blank">http://mail.dojotoolkit.org/mailman/listinfo/dojo-contributors</a><br>
    </blockquote></div><br><br>

    --0016e6509fb2d9378b04a1fa66af--

    From bogus@does.not.exist.com Tue Jan 18 18:42:17 2011
    From: bogus@does.not.exist.com ()
    Date: Tue, 18 Jan 2011 23:42:17 -0000
    Subject: No subject
    Message-ID: <mailman.29.1306254018.13280.dojo-contributors@mail.dojotoolkit.org>

    If it can help reduce memory usage and uses less cpu for mobile dijit, big
    +1

    Some ideas for improving the dojo.connect() / not sure if there's a need for
    a whole new api:
    Instead of passing around 'event objects', the default behavior could be to
    generate "event identifiers' / integer

    eventId = dojo.connect(...);

    All events would be registered somewhere (no more 'magic cookies'?)

    // then you can consistently get an 'event object' through some other api
    dojo.event(eventId).cancel();

    Maybe dojo.on() could be a wrapper for:

    dojo.on = {
    var eventId = dojo.connect(...);
    return dojo.event(eventId);
    }


    From bogus@does.not.exist.com Tue Jan 18 18:42:17 2011
    From: bogus@does.not.exist.com ()
    Date: Tue, 18 Jan 2011 23:42:17 -0000
    Subject: No subject
    Message-ID: <mailman.30.1306323288.13280.dojo-contributors@mail.dojotoolkit.org>

    variable initialization to null. (was there previously in 1.6).

    thx
    --
    Patrick

    From bogus@does.not.exist.com Tue Jan 18 18:42:17 2011
    From: bogus@does.not.exist.com ()
    Date: Tue, 18 Jan 2011 23:42:17 -0000
    Subject: No subject
    Message-ID: <mailman.31.1306765932.13280.dojo-contributors@mail.dojotoolkit.org>

    truly private I would probably suggest that they simply copy the
    original code, make their alterations, and use the altered code in
    place of the original. Sometimes this can be very difficult
    (especially in the case where the alteration needs to be made in the
    middle of a largish inheritance chain), at which point the
    _byConvention works out ok.

    I will reiterate what Kris said though; I think many people who come
    to rely on using _functions directly are either shooting themselves in
    the foot eventually, or it is a good indicator that the original
    _function should have probably been part of the public contract in the
    first place--so it might not be a bad idea to try to get a sense of
    which _methods are being used by consumers of the library on a regular
    basis, and perhaps move some of those towards being public (i.e.
    without the "_") as we shift towards 2.0.

    Cheers--
    Tom
    On Sun, May 29, 2011 at 4:02 PM, Kris Zyp wrote:
    To voice the other side, I believe that true private functions are
    indeed very valuable. The reason we have private functions is to because
    the function forms part of the inner workings of an implementation. We
    need to be free to change and improve upon our implementations of APIs
    in order to continue to evolve and improve Dojo. Private functions also
    can have performance advantages in many situations and better
    compressibility characteristics. Our _private-by-convention indeed has a
    place (there are other situations where these methods perform better),
    but frequently has led to a blurry, shoddy state of extensibility. Users
    end up using (or extending) _private functions and then either we are
    stuck supporting it or their code breaks in a future upgrade. With true
    public and private functions the lines are clearly drawn: Use/extend the
    public methods if you want a hassle free upgrade, these are the only
    ones you can use without changing the source code. If you really need to
    deal with implementations internals, than you must modify Dojo source
    code. The upgrade process then clearly and explicitly involves merging,
    rather than lurking hidden potholes of possible internal-yet-exposed API
    changes. If you want a highly extensible class, provide a lot public
    methods. If you want internals that you are still working out and
    optimizing, private them. IMHO, _private-by-convention is often
    indicative of trying to import class-centic model from other languages
    rather than groking the scope-centric JS model... But still, there is
    still certainly a time and place for each of the techniques. Good
    programmers know when to use each. Anyway, just my 2c on this.
    Thanks,
    Kris
    On 5/29/2011 2:07 PM, Mike Wilcox wrote:
    On May 29, 2011, at 2:50 PM, Eugene Lazutkin wrote:

    Are we okay to use techniques that prevent users from monkey-patching
    our code dynamically?
    I've voiced this opinion a few times before. Not allowing monkey patching may hamper advanced users of the library for no good reason.

    I have monkey patches in DojoX FX - Timeline, Complex and Reverse all monkey patch dojo.animation - and this was enormously difficult due to the large amount of private methods and variables. So this kind of protection would prohibit library extensions as well.

    Mike

    _______________________________________________
    dojo-contributors mailing list
    dojo-contributors at mail.dojotoolkit.org
    http://mail.dojotoolkit.org/mailman/listinfo/dojo-contributors
    _______________________________________________
    dojo-contributors mailing list
    dojo-contributors at mail.dojotoolkit.org
    http://mail.dojotoolkit.org/mailman/listinfo/dojo-contributors
    From bogus@does.not.exist.com Tue Jan 18 18:42:17 2011
    From: bogus@does.not.exist.com ()
    Date: Tue, 18 Jan 2011 23:42:17 -0000
    Subject: No subject
    Message-ID: <mailman.32.1307142520.13280.dojo-contributors@mail.dojotoolkit.org>

    pull in the top level js to get started as in the following (or the
    dojo.require equivalent thereof):

    require(['dojox/mvc', ...], ...)

    This would effectively load things like the bind substrate, the model
    and its factory function, the data binding mixin and related
    _WidgetBase monkey patches to give us ref semantics on dijits etc.
    Many of the mvc tests and examples then depend on the dojox global.
    This is quite a simple for users, they don't worry about most bits
    mentioned in this paragraph.

    If we removed the top level js file, did the _base -> main renaming
    (AMD question - would that change the require to dojox/mvc/main? got a
    pointer to related docs?), removed dojox global references etc., it
    might be better given thats where we're heading. I don't know if we
    have the time before tag and whether all supporting bits (doc parser
    etc.) are firmly in place.

    -Rahul

    -Adam
    On Thu, Jun 2, 2011 at 4:44 PM, Rahul Akolkar wrote:

    Lets use dojox.mvc as the exemplar, I suggest this because of my
    interest it in, but also because the following make it a good
    candidate:

    * This will be the first dojox.mvc release, there are no
    compatibility constraints
    * Its a small codebase (relative to some others in dojox)
    * It has the right representative code patterns (global dojox
    assumption, top level js file, monkey patches into dijit)

    The way some of the dojox.mvc structure was added (such as top level
    js) was by looking at other dojox siblings. If exemplary is desired in
    AMD or any other perspective, then exemplars are needed :-)

    I encourage anyone interested to just dig in and improve dojox.mvc.
    After all, its now in SVN [1].

    -Rahul

    [1] http://svn.dojotoolkit.org/src/dojox/trunk/mvc/
    (and: http://svn.dojotoolkit.org/src/dojox/trunk/mvc.js)
  • Kris Zyp at Feb 1, 2011 at 12:22 am

    On 1/31/2011 4:20 PM, James Burke wrote:
    2011/1/31 Kris Zyp <kzyp at dojotoolkit.org>:
    * We need an API for AMD plugins to trigger recursive builds. I assume this
    is a pretty simple addition to the build systems.
    This is just my first thoughts, so subject to change/good arguments:

    The multi-build work should be done outside of the loader plugin, and
    even outside the main builder used for JS modules. This is a job for a
    more generic build tool like make or ant.
    That is a reasonable way to approach the problem as well, and could
    possibly be better. However, there is a necessary coupling and
    interaction between the runtime UA-sniffing/branching module that loads
    the UA-specific layer and the build scripting process that creates those
    layers. The intent with using a plugin is to encapsulate and automate
    this synchronization all in a compact package that can be installed like
    any other JS package. It would be nice to save developers from hassles
    of installation and integration of build scripts, incorporate the UA
    branching module into built code, and ensuring that layers are
    synchronized with that branching. Maybe that can be done with higher
    level build tool...

    Even if my suggested solution isn't for everyone, hopefully the
    underlying principle is solid: we can and should be using feature
    detection in our source modules, and we can and should encourage the
    removal of feature detection as build-time optimization through UA
    branching tools.
    I believe the build tool for a JavaScript dependency system should
    focus more strictly on combining sets of modules together, since that
    is the hard part that cannot be replicated in other build systems
    (particularly loading of plugins to figure out if they should include
    optimized resources).

    Furthermore, I would expect Dojo to never ship with all of those
    builds done as part of a Dojo distribution -- that is an optimization
    step reserved for the optimization of an app, not of a library that
    may be used as an app. Or if it is distributed, it is not the main
    distribution -- something that has 5-10 builds of the toolkit inside
    it for each type of UA profile would freak people out just on the
    download size alone, never mind the set of server rules they need to
    put in place to serve them correctly.
    Definitely agree, this is only for apps.
    While it is worthwhile to work out a system for UA+version specific
    builds, not everyone will want them. The file size management
    complexity cost and serverside URL routing setup to get it to work
    will be seen as too much complication for many sites, and I expect
    that once a display ad service is put on the site, any gain by this
    sort of optimization will likely go unnoticed, particularly if only
    the has tests used by the code are included vs. the full set.
    It is indeed less compelling if only tests get excluded. If major blocks
    of code are removed (because it is not needed for a particular feature
    set), it becomes much more compelling. If you are developing an
    application with a focus on using HTML5 features like new form elements,
    CSS3 animations, and standard DOM interaction, and omitting larger
    components for mobile targets, I think it could be very reasonable to
    have applications that are many times bigger in an IE build than latest
    the mobile webkit builds. These types of applications is where this type
    of system becomes tremendously beneficial. And this type of web
    application development is becoming increasingly prevalent now and in
    the future.
    To be clear: I am not arguing it is not worthwhile, but that it is
    just one piece of an optimization story, and there is a complexity
    cost to implementing it, and not everyone should be forced to take the
    hit of that complexity cost. It needs to be taken when the site is
    ready to take it on.
    There isn't anything about such a plugin that would introduce a
    (complexity) cost to those that aren't using it is there?
    So I see the work as identifying how more generic build tools could
    use a database of the has profiles in a build step. I could see this
    as generally useful knowledge that is tracked as part of the has.js
    project, since it is likely useful even outside any JS module-specific
    build tool.
    Yes, regardless of the solution, a database of has profiles is important
    (and the corresponding UA-driven branching code). Pete, do you have
    that? Where is our has() test results going when we do the online test?
    Thanks,
    Kris
  • Eugene Lazutkin at Feb 1, 2011 at 12:35 am
    Both Alex and Kris are right --- the whole optimization story should be
    thought out properly, and while doing it, we have to tame complexity as
    well.

    I am a supporter of feature testing, yet we should be reasonable,
    without fanaticism. How many tests are enough? Dozens? Hundreds?
    Thousands? What should we test for? Existing bugs only? Present bugs only?

    Remember our problems with DOM geometry --- how almost impossible to get
    it right? Recently I've been working with MathJax (www.mathjax.org),
    which lays out math formulas using absolutely crazy combinations of CSS
    and DOM structures. It is open source. So I looked inside at some point
    - --- its code based on flags: "if this bug", "if that bug", "if quirks",
    and so on --- more than a dozen of such flags corresponding to different
    bugs. My understanding is that majority of them are not feature-tested
    directly in the code, but calculated using other means, including
    UA-sniffing.

    Q: how to test layout bugs? The are limits to feature testing.

    Still with all complex machinery they have in place --- e.g., it is far
    more complex than what we have in our DOM geometry --- I was still
    getting visual glitches. It turned out that they never expected (and
    never tested) layout inside <div contentEditable=true>. And I don't
    blame them. If they start to test all possible yet exotic
    configurations, number of feature tests will grow in geometric progression.

    Q: where to stop?

    Some time ago I was working on a project, and found a bug/feature, which
    was common for 2-3 browsers. Immediately I devised a test for it, and
    fluffy kittens and unicorns rejoiced. Now, going over my old code, I am
    deleting branches marked "Safari 3", "Firefox 2", "Opera 9.5", "IE6",
    and so on --- I don't support those browsers anymore. But for the love
    of multiple rainbows I cannot remember how relevant my old feature tests
    were. Did they become irrelevant with "Firefox 2", or are they still
    present? To answer this question I have to go over supported browsers
    (two dozens?) and see if they are there or not.

    Even if it is not present at the moment, should I keep them in the
    off-chance that they will surface again?

    Q: how to maintain, and retire tests?

    Why don't I keep old tests? I like beautiful well-readable code. All
    those pesky tests obscure the real intent. In short I want to remove as
    much branches/tests as possible to streamline logic, and maybe gain some
    performance. But in reality it was far from trivial, unlike UA-sniffing.

    Q: how to evolve/upgrade applications with feature-tests over time?

    I guess my point is that feature tests are not a cure-all, it is not
    something programmers should take on faith without usual due diligence.
    While they can be a right tool for certain things, they are not the only
    proper tool in town. And the whole arsenal should be thought out carefully.

    Cheers,

    Eugene
    On 1/31/11 1:35 PM, Kris Zyp wrote:
    Partly sparked by Alex's last blog post [1] (I've been thinking about
    this subject anyway though), I wanted to go little further in looking
    ahead at how I believe we can develop Dojo, RequireJS, and has.js to
    create truly optimal applications across different browsers/devices.
    First, a few foundational principles. The last decade of JavaScript
    development has clearly taught the reliability of using feature
    detection. To be clear, UA-sniffing does belong in our source code. This
    is clearly the right way to create future-proof source code and to avoid
    this in our source code for the sake of performance would be premature
    optimization. However, Alex has also clearly pointed out that feature
    detection must be optimized out eventually. While our source code may
    use feature detection, it is unacceptable for all the feature tests to
    be downloaded to every browser and executed when UA-sniffing based
    optimizations are available. This is where the build comes in. For the
    most part, a built application should be based on UA, and use feature
    detection as little as possible. Arguing about whether feature detection
    or UA-sniffing naive. Briefly, the right time for feature detection and
    UA-sniffing is:
    * Feature detection at source code level
    * UA based determination of features at the build level to eliminate
    run-time feature tests

    With this approach our source code is future-proof and we can readily
    create builds based on the latest UA feature sets without source code
    modifications.

    Fortunately our move to the standardized convention of has() makes this
    type of optimization well within reach. RequireJS has already proven the
    ease at which has() branches can eliminate unused feature branches/code.
    However, currently we are not offering any help with the actual creation
    of UA-specific build layers and the branching to those layers. RequireJS
    simply delegates this to the developer to deal with. This is a
    non-trivial problem though, and I think significant benefit can be
    gained by providing tooling/help in this area.

    I threw together a little package to demonstrate a solution we could
    provide for UA-sniffing based optimization for feature detection (this
    is not functional code right now, just demonstrates the idea):
    https://github.com/kriszyp/ua-optimized
    The basic premise here is that we have a AMD plugin "ua-optimized" that
    can do UA-sniffing to branch to different build layers that were
    generated with known feature sets. You would load your app like:

    require(["ua-optimized!my-app"]);

    At dev time ua-optimized! would basically be a no-op and would just load
    the "my-app" module. During the build, ua-optimized would generate
    various (perhaps a dozen or even dozens) build/layers of my-app based
    optimized for different UA's and their known feature sets and then most
    or all of feature tests and used branches would eliminated. It would
    also generate a "default" layer that would corresponded to unknown UAs
    and would include all the features and branches. When ua-optimized is
    run on built modules, it would then use the UA string to load the
    correct UA-specific version of my-app (or the default if the UA is not
    known).

    Again, the advantage here is that one could build applications and
    properly make use of feature detection for safe, reliable code. The
    built applications can leverage known UAs to short-cut out of
    unnecessary feature tests, while still falling back to feature tests for
    unknown user agents. UA-feature set information can be updated in the
    future to improve builds without any modification to source code.

    There are a couple minor pieces needed to put this puzzle together:

    * We need an API for AMD plugins to trigger recursive builds. I assume
    this is a pretty simple addition to the build systems.
    * We need a database of UAs and their feature sets (based on has.js
    tests). Is Pete or any has.js folks already collecting this information?
    From http://dante.dojotoolkit.org/hasjs/tests/runTests.html, it looks it
    is getting stored somewhere.

    [1] http://infrequently.org/2011/01/cutting-the-interrogation-short/

    Thanks,
    Kris
    <https://github.com/kriszyp/ua-optimized>



    _______________________________________________
    dojo-contributors mailing list
    dojo-contributors at mail.dojotoolkit.org
    http://mail.dojotoolkit.org/mailman/listinfo/dojo-contributors
  • Bill Keese at Feb 1, 2011 at 3:30 am
    Eugene, well said.

    My instinct is that we should "feature test" for bugs still present in the
    latest version of each browser (IE8, FF4, latest Chrome/Safari, etc.), but
    short-circuit the tests for bugs that have already been fixed. For
    example, this would save 25 lines of code:


    addtest("dom-dynamic-base", function (g, d, el){ return !(dojo.isFF <
    4 || dojo.isIE < 8); });

    The upside is size and performance for non-platform-specific builds. The
    downside is problems with browser spoofing and possibility that this bug
    will resurface some time in the future, or that the bug currently exists on
    some browser we don't know about.

    Also, before deciding anything, we should wait to see how many
    tests/branches we actually need, and how many are just relevant for IE6-8,
    etc. etc. has.js is currently 7K compressed and minified, and runs at
    about 150ms on iPhone. We won't need all the tests in there, but OTOH we
    will need lots of tests that aren't there yet. (For example, if we
    actually converted dijit.Editor to feature testing, if that's even possible,
    the size/performance would become a bigger issue.)

    On Tue, Feb 1, 2011 at 2:35 PM, Eugene Lazutkin wrote:

    -----BEGIN PGP SIGNED MESSAGE-----
    Hash: SHA1

    Both Alex and Kris are right --- the whole optimization story should be
    thought out properly, and while doing it, we have to tame complexity as
    well.

    I am a supporter of feature testing, yet we should be reasonable,
    without fanaticism. How many tests are enough? Dozens? Hundreds?
    Thousands? What should we test for? Existing bugs only? Present bugs only?

    Remember our problems with DOM geometry --- how almost impossible to get
    it right? Recently I've been working with MathJax (www.mathjax.org),
    which lays out math formulas using absolutely crazy combinations of CSS
    and DOM structures. It is open source. So I looked inside at some point
    - --- its code based on flags: "if this bug", "if that bug", "if quirks",
    and so on --- more than a dozen of such flags corresponding to different
    bugs. My understanding is that majority of them are not feature-tested
    directly in the code, but calculated using other means, including
    UA-sniffing.

    Q: how to test layout bugs? The are limits to feature testing.

    Still with all complex machinery they have in place --- e.g., it is far
    more complex than what we have in our DOM geometry --- I was still
    getting visual glitches. It turned out that they never expected (and
    never tested) layout inside <div contentEditable=true>. And I don't
    blame them. If they start to test all possible yet exotic
    configurations, number of feature tests will grow in geometric progression.

    Q: where to stop?

    Some time ago I was working on a project, and found a bug/feature, which
    was common for 2-3 browsers. Immediately I devised a test for it, and
    fluffy kittens and unicorns rejoiced. Now, going over my old code, I am
    deleting branches marked "Safari 3", "Firefox 2", "Opera 9.5", "IE6",
    and so on --- I don't support those browsers anymore. But for the love
    of multiple rainbows I cannot remember how relevant my old feature tests
    were. Did they become irrelevant with "Firefox 2", or are they still
    present? To answer this question I have to go over supported browsers
    (two dozens?) and see if they are there or not.

    Even if it is not present at the moment, should I keep them in the
    off-chance that they will surface again?

    Q: how to maintain, and retire tests?

    Why don't I keep old tests? I like beautiful well-readable code. All
    those pesky tests obscure the real intent. In short I want to remove as
    much branches/tests as possible to streamline logic, and maybe gain some
    performance. But in reality it was far from trivial, unlike UA-sniffing.

    Q: how to evolve/upgrade applications with feature-tests over time?

    I guess my point is that feature tests are not a cure-all, it is not
    something programmers should take on faith without usual due diligence.
    While they can be a right tool for certain things, they are not the only
    proper tool in town. And the whole arsenal should be thought out carefully.

    Cheers,

    Eugene
    On 1/31/11 1:35 PM, Kris Zyp wrote:
    Partly sparked by Alex's last blog post [1] (I've been thinking about
    this subject anyway though), I wanted to go little further in looking
    ahead at how I believe we can develop Dojo, RequireJS, and has.js to
    create truly optimal applications across different browsers/devices.
    First, a few foundational principles. The last decade of JavaScript
    development has clearly taught the reliability of using feature
    detection. To be clear, UA-sniffing does belong in our source code. This
    is clearly the right way to create future-proof source code and to avoid
    this in our source code for the sake of performance would be premature
    optimization. However, Alex has also clearly pointed out that feature
    detection must be optimized out eventually. While our source code may
    use feature detection, it is unacceptable for all the feature tests to
    be downloaded to every browser and executed when UA-sniffing based
    optimizations are available. This is where the build comes in. For the
    most part, a built application should be based on UA, and use feature
    detection as little as possible. Arguing about whether feature detection
    or UA-sniffing naive. Briefly, the right time for feature detection and
    UA-sniffing is:
    * Feature detection at source code level
    * UA based determination of features at the build level to eliminate
    run-time feature tests

    With this approach our source code is future-proof and we can readily
    create builds based on the latest UA feature sets without source code
    modifications.

    Fortunately our move to the standardized convention of has() makes this
    type of optimization well within reach. RequireJS has already proven the
    ease at which has() branches can eliminate unused feature branches/code.
    However, currently we are not offering any help with the actual creation
    of UA-specific build layers and the branching to those layers. RequireJS
    simply delegates this to the developer to deal with. This is a
    non-trivial problem though, and I think significant benefit can be
    gained by providing tooling/help in this area.

    I threw together a little package to demonstrate a solution we could
    provide for UA-sniffing based optimization for feature detection (this
    is not functional code right now, just demonstrates the idea):
    https://github.com/kriszyp/ua-optimized
    The basic premise here is that we have a AMD plugin "ua-optimized" that
    can do UA-sniffing to branch to different build layers that were
    generated with known feature sets. You would load your app like:

    require(["ua-optimized!my-app"]);

    At dev time ua-optimized! would basically be a no-op and would just load
    the "my-app" module. During the build, ua-optimized would generate
    various (perhaps a dozen or even dozens) build/layers of my-app based
    optimized for different UA's and their known feature sets and then most
    or all of feature tests and used branches would eliminated. It would
    also generate a "default" layer that would corresponded to unknown UAs
    and would include all the features and branches. When ua-optimized is
    run on built modules, it would then use the UA string to load the
    correct UA-specific version of my-app (or the default if the UA is not
    known).

    Again, the advantage here is that one could build applications and
    properly make use of feature detection for safe, reliable code. The
    built applications can leverage known UAs to short-cut out of
    unnecessary feature tests, while still falling back to feature tests for
    unknown user agents. UA-feature set information can be updated in the
    future to improve builds without any modification to source code.

    There are a couple minor pieces needed to put this puzzle together:

    * We need an API for AMD plugins to trigger recursive builds. I assume
    this is a pretty simple addition to the build systems.
    * We need a database of UAs and their feature sets (based on has.js
    tests). Is Pete or any has.js folks already collecting this information?
    From http://dante.dojotoolkit.org/hasjs/tests/runTests.html, it looks it
    is getting stored somewhere.

    [1] http://infrequently.org/2011/01/cutting-the-interrogation-short/

    Thanks,
    Kris
    <https://github.com/kriszyp/ua-optimized>



    _______________________________________________
    dojo-contributors mailing list
    dojo-contributors at mail.dojotoolkit.org
    http://mail.dojotoolkit.org/mailman/listinfo/dojo-contributors
    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.4.11 (Darwin)
    Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

    iEYEARECAAYFAk1Hm4sACgkQY214tZwSfCukMQCeLqLuRKpcPA3cCmcgRRVahvbn
    7rsAnit0v7acy2e2Olt13dB/cvryoDNe
    =Huv+
    -----END PGP SIGNATURE-----
    _______________________________________________
    dojo-contributors mailing list
    dojo-contributors at mail.dojotoolkit.org
    http://mail.dojotoolkit.org/mailman/listinfo/dojo-contributors
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://mail.dojotoolkit.org/pipermail/dojo-contributors/attachments/20110201/92505bd5/attachment-0001.htm

Related Discussions

Discussion Navigation
viewthread | post