Sencha Touch--Support 2 browsers in just 228K!

Discussion in 'Javascript' started by David Mark, Jul 16, 2010.

  1. David Mark

    David Mark Guest

    Sencha Touch is a bizarre mish-mash of ExtJS and a jQuery plug-in
    called JQTouch. It is advertised as the first "HTML5 framework" based
    on "standards" like HTML5 and CSS3. Of course, HTML5 is neither a
    standard nor widely implemented and the script eschews CSS3 for
    proprietary WebKit extensions. And the most bizarre thing is that
    very little of the script relates to HTML5.

    The script is touted as "cross-browser", despite the fact that it is
    admittedly dual-browser at best. It weighs 228K (minified) and
    several of its key features rely on UA-based browser sniffing.

    The rationalization for these unfortunate facts is that Android and
    iPhone/iPod/iPad devices account for 90% of the mobile market. It is
    unclear who conducted that study; but regardless, unlike in school,
    90% is not an A-, particularly when the remaining 10% are left with
    non-functioning applications. The weight problem is dismissed with
    the usual marketing tactic of quoting sizes after GZIP compression
    (only 80K!) And feature detection is deemed "impossible" due to the
    fact that common features implemented in the two "supported" browsers
    vary in their behavior (apparently feature testing is outside of the
    authors' realm of understanding).

    Not much new here. It's the same "tired old arguments" that readers
    of this group have heard over and over. This shouldn't be surprising
    as library developers keep making the same tired old mistakes. And,
    of course, most newcomers to this group have failed to read each and
    every previous related post, so repetition is required.

    /*
    Copyright(c) 2010 Sencha Inc.

    http://www.sencha.com/touchlicense
    */

    Yes, they plan to charge money for this thing.

    // for old browsers
    window.undefined = window.undefined;

    First line and it is the usual rookie mistake. Note that this line
    runs in the global execution context, so - this - points to the global
    object. Why not use that instead of attempting to augment a host
    object? Likely because this line has been copied and pasted from a
    similarly ludicrous script that preceded it. There is no standard for
    the window object and, as a host object, it is explicitly allowed to
    throw an exception (or fail silently) in this case.

    This is not a minor quibble. IE can be configured to disallow host
    object expandos and nobody knows how many other browsers behave in
    similar fashion (perhaps even by default).

    The sum effect of this first line of code is to indicate that the
    authors don't really know what they are doing. Not only is "this"
    shorter than "window" (neither of which will be shortened on
    minification), but you have to wonder what "old browsers" this dual-
    browser framework is attempting to placate. As will become evident,
    no such browser stands a chance in hell of running this script, so the
    only explanation is cargo cult programming (i.e. they saw this line in
    another script and copied it without understanding the ramifications).

    /**
    * @class Ext

    There are no classes in ECMAScript implementations.

    * Ext core utilities and functions.

    Everything old is new again. :)

    * @singleton

    It goes without saying that there are no singletons either.

    */

    Ext.setup = function(config) {
    if (Ext.isObject(config)) {

    Oh dear. We'll get to that one shortly. Suffice to say that there is
    no call for this (no pun intended).

    if (config.addMetaTags !== false) {
    var viewport = Ext.get(document.createElement('meta')),
    app = Ext.get(document.createElement('meta')),
    statusBar = Ext.get(document.createElement('meta')),
    startupScreen =
    Ext.get(document.createElement('link')),
    appIcon = Ext.get(document.createElement('link'));


    Okay. Five elements created.

    viewport.set({
    name: 'viewport',
    content: 'width=device-width, user-scalable=no,
    initial-scale=1.0, maximum-scale=1.0;'
    });

    No call for this either. As we'll see, the "set" function is another
    botched attempt at setting attributes and/or properties.

    if (config.fullscreen !== false) {
    app.set({
    name: 'apple-mobile-web-app-capable',
    content: 'yes'
    });

    Ditto.

    if (Ext.isString(config.statusBarStyle)) {

    The isString function is also dubious.

    statusBar.set({
    name: 'apple-mobile-web-app-status-bar-style',
    content: config.statusBarStyle
    });
    }
    }

    if (Ext.isString(config.tabletStartupScreen) &&
    Ext.platform.isTablet) {

    Ext.platform is populated largely by UA-based browser sniffing.

    startupScreen.set({
    rel: 'apple-touch-startup-image',
    href: config.tabletStartupScreen
    });
    } else if (Ext.isString(config.phoneStartupScreen) &&
    Ext.platform.isPhone) {
    startupScreen.set({
    rel: 'apple-touch-startup-image',
    href: config.phoneStartupScreen
    });
    }

    if (config.icon) {
    config.phoneIcon = config.tabletIcon = config.icon;
    }

    This is a very odd design. Why have three properties? If they were
    going to allow specifying separate icons for what they "detect" as
    phones and tablets, then surely they shouldn't step on them without
    looking.

    var precomposed = (config.glossOnIcon == false) ? '-
    precomposed' : '';
    if (Ext.isString(config.tabletIcon) &&
    Ext.platform.isTablet) {

    Why didn't they just check config.icon?

    appIcon.set({
    rel: 'apple-touch-icon' + precomposed,
    href: config.tabletIcon
    });
    } else if (Ext.isString(config.phoneIcon) &&
    Ext.platform.isPhone) {
    appIcon.set({
    el: 'apple-touch-icon' + precomposed,
    href: config.phoneIcon
    });
    }

    var head = Ext.get(document.getElementsByTagName('head')
    [0]);

    Why pass the result to Ext.get? Is there some ill-advised host object
    augmentation going on here?

    head.appendChild(viewport);
    if (app.getAttribute('name')) head.appendChild(app);
    if (statusBar.getAttribute('name'))
    head.appendChild(statusBar);

    if (appIcon.getAttribute('href'))
    head.appendChild(appIcon);
    if (startupScreen.getAttribute('href'))
    head.appendChild(startupScreen);
    }

    Nope. They used only standard DOM methods. Of course, there was no
    need to call getAttribute at all. They could have just checked the
    corresponding DOM properties; but more importantly, as seen above,
    they are the ones who set (or didn't set) these attributes in the
    first place. In other words, the logic takes the long way around,
    unnecessarily involving one of the least trustworthy methods in the
    history of browser scripting (getAttribute).

    And why did they create all of those elements in advance when some or
    all of them may not be appended at all? In short, the whole preceding
    mess could be re-factored in five minutes to save several function and
    host method calls, not to mention the creation of up to five elements.

    When choosing a browser script, one of the first questions should be
    who: wrote it and what is their relative level of proficiency? It's
    not a "personal smear" to make a judgment call at this point. The
    authors are obviously yet another batch of clueless neophytes (see
    also jQuery, Prototype, Dojo, YUI, ExtJS, MooTools, etc.) Suffice to
    say that leaning on a script written by such authors is going to lead
    to problems. Readers with even the slightest experience in cross-
    browser scripting can stamp this one "Avoid at all Costs" and move on
    at this point (if they haven't already).

    if (Ext.isArray(config.preloadImages)) {

    Oops. There is no way to write a reliable "isArray" function in JS.
    And as above, there is no reason to do anything more than a boolean
    type conversion here (as long as the documentation indicates that this
    property must be an array). Anything "truthy" that is not an array
    will result in a silent failure as written, which is the least helpful
    result (often described as "robustness" by library authors).

    for (var i = config.preloadImages.length - 1; i >= 0; i--)
    {

    How about:-

    for (var i = config.preloadImages.length; i--;) {

    Sure that's a minor quibble, but it is yet another glimpse into the
    authors' proficiency (or lack thereof). We are only a few dozen lines
    in and virtually every line needs to be rewritten (which should take
    *one* proficient JS developer about ten minutes).

    (new Image()).src = config.preloadImages;
    };
    }

    if (Ext.isFunction(config.onReady)) {
    Ext.onReady(config.onReady, config.scope || window);
    }

    As we'll see, the isFunction function is yet another dubious entry.
    And scope has *nothing* to do with the - this - despite the insistence
    of seemingly every "major" library author. In this case, it's not
    just a naming snafu as the ExtJS developers constantly refer to - this
    - as "scope" in their documentation and support forums. And if they
    don't understand why that is wrong, they haven't gotten past the first
    page of the manual. I wonder what they call scope. Bananas?
    Seriously, you have to wonder if these developers understand the
    language they are using at all.

    Ext.apply = function(object, config, defaults) {
    // no "this" reference for friendly out of scope calls

    There they go again.

    if (defaults) {

    What? No isObject call? :)

    Ext.apply(object, defaults);
    }
    if (object && config && typeof config == 'object') {
    for (var key in config) {

    Oops. Unfiltered for-in loops are a very bad idea (at least for
    scripts deployed on the Web). If this script is mashed up with
    something that augments Object.prototype (e.g. older versions of the
    unfortunately named Prototype library), all hell will break loose here
    (in the deepest part of their core).

    object[key] = config[key];
    }
    }
    return object;
    };

    Calling this function "apply" was a pretty silly idea as well (because
    of Function.prototype.apply). You've got to wonder if the authors are
    that out of touch (no pun intended) or simply trying to confuse
    beginners to keep them dependent on their dubious offerings. Both are
    unsavory prospects.

    Ext.apply(Ext, {
    userAgent: navigator.userAgent.toLowerCase(),

    Nellie bar the door. As has been known for a decade, referencing this
    deception device cannot lead to anything good.

    applyIf : function(object, config) {
    var property, undefined;

    There's no need to declare a local "undefined" identifier.

    if (object) {
    for (property in config) {

    Another unfiltered for-in.

    if (object[property] === undefined) {

    Just use the typeof operator.

    object[property] = config[property];
    }
    }
    }
    return object;
    },

    /**
    * Repaints the whole page. This fixes frequently encountered
    painting issues in mobile Safari.
    */

    Their "fix" is nothing but a mystical incantation. Clearly their
    script has had problems with the one platform they seek to support,
    but rather than attempting to understand the cause of these problems,
    they've resorted to nonsense code that appears to "fix" the problem in
    whatever mobile devices they had handy to test with at the time of
    writing.

    repaint : function() {
    var mask = Ext.getBody().createChild({
    cls: 'x-mask x-mask-transparent'
    });

    Here they create and immediately discard a wrapper object for
    document.body.

    setTimeout(function() {
    mask.remove();
    }, 0);

    ISTM that using 0 for the second argument to setTimeout is ill-advised
    (as is the implied global).

    },

    /**
    * Generates unique ids. If the element already has an id, it is
    unchanged
    * @param {Mixed} el (optional) The element to generate an id for
    * @param {String} prefix (optional) Id prefix (defaults "ext-
    gen")
    * @return {String} The generated Id.
    */
    id : function(el, prefix) {
    return (el = Ext.getDom(el) || {}).id = el.id || (prefix ||
    "ext-gen") + (++Ext.idSeed);
    },

    That's just plain ridiculous and falls under the category of "concise"
    code that is all the rage these days. How about something like this:-

    var id;

    if (typeof el == 'string') { // ID passed, find it
    el = document.getElementById(el);
    }

    if (el) { // Element exists
    if (el.id) { // Has an ID
    id = el.id;
    } else { // Does not have an ID, assign
    id = el.id = (prefix || "ext-gen") + (++Ext.idSeed);
    }
    }

    return id; // undefined if element not found

    It's not as if that will be any longer once white space and comments
    are removed. Will be a hell of a lot easier to maintain and debug as
    well (no phantom ID's generated).

    [skipped tired old Ext "class" related functions]

    urlEncode : function(o, pre){
    var empty,
    buf = [],
    e = encodeURIComponent;

    Ext.iterate(o, function(key, item){

    Why not just use a for-in loop? If the (omitted) comments are to be
    believed, then o is only allowed to be an Object object. The iterate
    function makes calls to isObject, isEmpty and isIterable in a futile
    attempt to support Object, Array and host objects with one function.

    empty = Ext.isEmpty(item);

    As we shall see, isEmpty is another unnecessary function and itself
    calls isArray (of all things).

    Ext.each(empty ? key : item, function(val){
    buf.push('&', e(key), '=', (!Ext.isEmpty(val) && (val !
    = key || !empty)) ? (Ext.isDate(val) ? Ext.encode(val).replace(/"/g,
    '') : e(val)) : '');
    });
    });

    Hmmm. Skipping ahead, the Ext.encode function is defined as:-

    /**
    * Shorthand for {@link Ext.util.JSON#encode}
    * @param {Mixed} o The variable to encode
    * @return {String} The JSON string
    * @member Ext
    * @method encode
    */
    Ext.encode = Ext.util.JSON.encode;

    And the "longhand" version is defined as:-

    /**
    * @class Ext.util.JSON

    How is an object literal a class?

    * Modified version of Douglas Crockford"s json.js that doesn"t
    * mess with the Object prototype
    * http://www.json.org/js.html
    * @singleton

    :)

    */
    Ext.util.JSON = {
    encode : function(o) {
    return JSON.stringify(o);
    },

    Now what does JSON have to do with urlencoding dates?

    So far none of this is anything close to professional code and much of
    it is positively senseless. Still no sign of HTML5 either. :)

    On to decoding:-

    /**
    * Takes an encoded URL and and converts it to an object. Example:
    * <pre><code>
    Ext.urlDecode("foo=1&bar=2"); // returns {foo: "1", bar: "2"}
    Ext.urlDecode("foo=1&bar=2&bar=3&bar=4", false); // returns {foo: "1",
    bar: ["2", "3", "4"]}
    </code></pre>

    Of course, none of those are URL's.

    * @param {String} string
    * @param {Boolean} overwrite (optional) Items of the same name
    will overwrite previous values instead of creating an an array
    (Defaults to false).
    * @return {Object} A literal with members

    A what?!

    */
    urlDecode : function(string, overwrite){
    if(Ext.isEmpty(string)){
    return {};
    }
    var obj = {},
    pairs = string.split('&'),
    d = decodeURIComponent,
    name,
    value;
    Ext.each(pairs, function(pair) {
    pair = pair.split('=');
    name = d(pair[0]);
    value = d(pair[1]);
    obj[name] = overwrite || !obj[name] ? value :
    [].concat(obj[name]).concat(value);
    });
    return obj;
    },

    Interesting. No call to Ext.decode. I guess JSON is only related to
    encoding URL's. :)

    /**
    * Convert certain characters (&, <, >, and ') to their HTML
    character equivalents for literal display in web pages.
    * @param {String} value The string to encode
    * @return {String} The encoded text
    */
    htmlEncode : function(value){
    return Ext.util.Format.htmlEncode(value);
    },

    Unnecessary bloat and another unneeded function call. Odd choices for
    a mobile framework.

    /**
    * Appends content to the query string of a URL, handling logic
    for whether to place
    * a question mark or ampersand.
    * @param {String} url The URL to append to.
    * @param {String} s The content to append to the URL.
    * @return (String) The resulting URL
    */
    urlAppend : function(url, s){
    if(!Ext.isEmpty(s)){

    Another half-dozen unneeded function calls. This would be bad enough
    in and of itself, but the functions in question are highly dubious as
    well. Try this:-

    if (s) {

    return url + (url.indexOf('?') === -1 ? '?' : '&') + s;

    No need for a strict comparison there. It's ham-fisted and makes
    future maintainers (and reviewers) have to pause and wonder why they
    did it.

    }
    return url;
    },

    /**
    * Converts any iterable (numeric indices and a length property)
    into a true array

    There's no such thing as an "iterable" or a "true array".

    * Don't use this on strings. IE doesn't support "abc"[0] which
    this implementation depends on.

    Oh, I they needn't worry about IE. ;)

    * For strings, use this instead: "abc".match(/./g) => [a,b,c];

    That's a syntax error (so don't use it).

    * @param {Iterable} the iterable object to be turned into a true
    Array.
    * @return (Array) array
    */
    toArray : function(array, start, end){
    return Array.prototype.slice.call(array, start || 0, end ||
    array.length);

    That will blow up in IE < 9.

    },

    /**
    * Iterates an array calling the supplied function.

    Not according to the next line.

    * @param {Array/NodeList/Mixed} array The array to be iterated.
    If this

    There is no way to reliably differentiate between Array and host
    objects (so don't design systems that hinge on making that work). And
    I don't know what a "Mixed" is supposed to be.

    each : function(array, fn, scope) {

    That's not scope! :)

    if (Ext.isEmpty(array, true)) {
    return 0;
    }

    Whatever. They'd have been much better off copying
    Array.prototype.forEach (then they could use that when available).

    if (!Ext.isIterable(array) || Ext.isPrimitive(array)) {
    array = [array];
    }

    Now there's a bizarre disjunction. If it is not "iterable" or it is a
    primitive? You have to wonder what sort of "iterable" their code
    would identify as a primitive. It's positively Dojo-esque (meaning
    full of incomprehensible intertwined type-checking calls where none
    are needed).

    for (var i = 0, len = array.length; i < len; i++) {
    if (fn.call(scope || array, array, i, array) ===
    false) {

    Why would they set - this - to array? That's going to lead to some
    odd results.

    return i;
    };
    }
    return true;
    },

    iterate : function(obj, fn, scope){
    if(Ext.isEmpty(obj)){
    return;
    }
    if (Ext.isIterable(obj)) {
    Ext.each(obj, fn, scope);
    return;
    }
    else if(Ext.isObject(obj)) {
    for (var prop in obj) {
    if (obj.hasOwnProperty(prop)) {

    Finally, a filter! :) Inconsistent with the rest though. You've got
    to wonder if they simply forgot to filter the others. More likely
    this is simply a slap-dash patchwork of previous scripts (e.g. ExtJS,
    JQTouch).

    if (fn.call(scope || obj, prop, obj[prop], obj)
    === false) {
    return;
    };
    }
    }
    }
    },

    The indisputedly unreliable (and wholly unneeded) type-checking
    permeates everything. All hopes of cross-browser compatibility are
    lost (for no other reason than the authors were/are too green to
    design a system this complicated).

    * <b>Note</b>: the dom node to be found actually needs to exist
    (be rendered, etc)
    * when this method is called to be successful.
    * @param {Mixed} el

    Apparently "Mixed" means "botched". In this case, the function is
    expected to discriminate between native and host objects. Such
    "overloading" strategies are highly ill-advised in JS, yet seemingly
    everything in this script relies on them.

    * @return HTMLElement
    */
    getDom : function(el) {
    if (!el || !document) {
    return null;
    }

    Now when is document going to type-convert to false?

    return el.dom ? el.dom : (typeof el == 'string' ?
    document.getElementById(el) : el);
    },

    /**
    * Returns the current document body as an {@link Ext.Element}.
    * @return Ext.Element The document body
    */
    getBody : function(){
    return Ext.get(document.body || false);
    },

    More gobbledygook. It's as if every line is designed with madness in
    mind. The first line of Ext.get is:-

    if(!el){
    return null;
    }

    ....and it's not as if document.body will be missing in either of the
    two browsers they aspire to support. Regardless, why not something
    like this:-

    var body = document.body;
    return body ? Ext.get(body) : null;

    Function calls are not free and a "mobile framework" needs to be as
    efficient as possible due to the limited resources available to mobile
    browsers. By the same token, property access costs and this thing
    uses them constantly when they could easily be avoided.

    /**
    * Returns the current HTML document object as an {@link
    Ext.Element}.
    * @return Ext.Element The document
    */
    getDoc : function(){
    return Ext.get(document);
    },

    This is jQuery-itis. In other words, an API abstraction that makes no
    sense. Why would they wrap a document object in an Ext.Element
    object. After all, elements and documents are very different types of
    DOM nodes. What do the element-specific methods do for documents?
    And assuming there are any document-specific methods, what do they do
    for elements? It's mind-boggling. The only rationalization I've
    heard for such a bizarre design is that Web developers could be
    confused by more than one wrapper type. :)

    /**
    * This is shorthand reference to {@link Ext.ComponentMgr#get}.
    * Looks up an existing {@link Ext.Component Component} by {@link
    Ext.Component#id id}
    * @param {String} id The component {@link Ext.Component#id id}
    * @return Ext.Component The Component, <tt>undefined</tt> if not
    found, or <tt>null</tt> if a
    * Class was found.
    */
    getCmp : function(id){
    return Ext.ComponentMgr.get(id);
    },

    Another ridiculous waste of time and space.

    So far, everything that can go wrong has gone wrong. Literally. No
    doubt, this is somehow my fault. In other words, if I hadn't pointed
    out all of these problems then they wouldn't exist. :)

    /**
    * Returns the current orientation of the mobile device
    * @return {String} Either 'portrait' or 'landscape'
    */
    getOrientation: function() {
    return window.innerHeight > window.innerWidth ? 'portrait' :
    'landscape';
    },

    Highly dubious and virtually never needed. In the same way that older
    libraries attempt to replace rock-solid mechanisms like IE's
    conditional comments with browser sniffing, this attempts to can CSS3
    media queries.

    http://www.w3.org/TR/css3-mediaqueries/#orientation

    Of course, you can't sell what you can't can. :)

    /**
    * <p>Removes this element from the document, removes all DOM
    event listeners, and deletes the cache reference.
    * All DOM event listeners are removed from this element. If
    {@link Ext#enableNestedListenerRemoval} is
    * <code>true</code>, then DOM event listeners are also removed
    from all child nodes. The body node
    * will be ignored if passed in.</p>
    * @param {HTMLElement} node The node to remove
    */
    removeNode : function(n){
    if (n && n.parentNode && n.tagName != 'BODY') {

    Checking for the body is ludicrous. If the calling application fouls
    up and passes the body, a silent failure will only obscure the
    mistake, making it harder for the developers to track it down. Same
    for checking the parentNode property.

    Ext.EventManager.removeAll(n);

    Almost certainly unneeded. If their EventManager thing actually
    creates circular references then they should fix that, not dance
    around the problem with this outdated Crockfordian strategy. And
    regardless, this script won't work with IE (the browser with the
    circular reference problem) anyway.

    n.parentNode.removeChild(n);
    delete Ext.cache[n.id];
    }
    },

    /**
    * Attempts to destroy any objects passed to it by removing all
    event listeners, removing them from the
    * DOM (if applicable) and calling their destroy functions (if
    available). This method is primarily
    * intended for arguments of type {@link Ext.Element} and {@link
    Ext.Component}, but any subclass of

    There are no classes in JS, so there can be no subclasses.

    * {@link Ext.util.Observable} can be passed in. Any number of
    elements and/or components can be
    * passed into this function in a single call as separate
    arguments.
    * @param {Mixed} arg1 An {@link Ext.Element}, {@link
    Ext.Component}, or an Array of either of these to destroy

    Again, you cannot reliably tell an Object from an Array object.
    Designing such systems in JS is like deliberately walking into a wall
    (over and over in the case of this script).

    * @param {Mixed} arg2 (optional)
    * @param {Mixed} etc... (optional)
    */
    destroy : function() {
    var ln = arguments.length,
    i, arg;
    for (i = 0; i < ln; i++) {
    arg = arguments;
    if (arg) {
    if (Ext.isArray(arg)) {
    this.destroy.apply(this, arg);
    }
    else if (Ext.isFunction(arg.destroy)) {
    arg.destroy();
    }
    else if (arg.dom) {
    arg.remove();
    }
    }
    }
    },

    isIterable : function(v){
    //check for array or arguments
    if(Ext.isArray(v) || v.callee){
    return true;
    }

    The isArray function is unreliable and the presence of a "callee"
    property does not indicate anything close to what they are trying to
    determine (see their previous definition of an "iterable"). And
    you've got to wonder what sort of strange design would require passing
    the arguments object to a function like this. I mean, the only way a
    variable could reference an arguments objects is by explicitly setting
    it to reference an arguments object.

    //check for node list type
    if(/NodeList|
    HTMLCollection/.test(Object.prototype.toString.call(v))){
    return true;
    }

    Not only is the RegExp botched, but host objects are allowed to return
    *anything* in response to a toString call. For example, this will
    fail in many versions of IE (and presumably at least some of its
    mobile derivations). Of course, this script will fall flat on its
    face in IE anyway, for no reason other than dubious design decisions.

    //NodeList has an item and length property
    //IXMLDOMNodeList has nextNode method, needs to be checked
    first.

    Suffice to say that an application that needs to pass an XML nodelist
    to this function is doomed from the start. Likely that includes the
    framework itself.

    return ((typeof v.nextNode != 'undefined' || v.item) &&
    Ext.isNumber(v.length));
    },

    Ext.isNumber is another one of the botched (and unneeded) type-
    checking functions.

    So obviously, the "isIterable" function is an untenable (and unneeded)
    design. And each time the authors hit upon a host object that
    returned the "wrong" result they added another set of checks to make
    it "right", instead of realizing they were pissing in the wind from
    the start. Again, very Dojo-esque.

    /**
    * Utility method for validating that a value is numeric,
    returning the specified default value if it is not.
    * @param {Mixed} value Should be a number, but any type will be
    handled appropriately
    * @param {Number} defaultValue The value to return if the
    original value is non-numeric
    * @return {Number} Value, if numeric, else defaultValue
    */
    num : function(v, defaultValue){
    v = Number(Ext.isEmpty(v) || Ext.isArray(v) || typeof v ==
    'boolean' || (typeof v == 'string' && v.trim().length == 0) ? NaN :
    v);
    return isNaN(v) ? defaultValue : v;
    },

    Another faulty design, rendered in typically bizarre and unreliable
    fashion (nothing that calls isArray can be considered reliable). And
    you really must wonder what sort of application would need such a
    function.

    /**
    * <p>Returns true if the passed value is empty.</p>
    * <p>The value is deemed to be empty if it is<div class="mdetail-
    params"><ul>
    * <li>null</li>
    * <li>undefined</li>
    * <li>an empty array</li>
    * <li>a zero length string (Unless the <tt>allowBlank</tt>
    parameter is <tt>true</tt>)</li>
    * </ul></div>
    * @param {Mixed} value The value to test
    * @param {Boolean} allowBlank (optional) true to allow empty
    strings (defaults to false)
    * @return {Boolean}
    */
    isEmpty : function(v, allowBlank) {
    return v == null || ((Ext.isArray(v) && !v.length)) || (!
    allowBlank ? v === '' : false);
    },

    Another call to isArray, which means the previous functions results in
    two calls to that unreliable function. There appears to be no real
    design work here, just a bunch of ill-advised functions tangled up in
    haphazard fashion. I can hear the chorus of "show me where it fails"
    now. :)

    And again, read the description and wonder what sort of strange
    application would need such a function.

    /**
    * Returns true if the passed value is a JavaScript array,
    otherwise false.
    * @param {Mixed} value The value to test
    * @return {Boolean}
    */
    isArray : function(v) {
    return Object.prototype.toString.apply(v) === '[object
    Array]';
    },

    There it is. The "Miller Device" has been proven unreliable.

    /**
    * Returns true if the passed object is a JavaScript date object,
    otherwise false.
    * @param {Object} object The object to test
    * @return {Boolean}
    */
    isDate : function(v) {
    return Object.prototype.toString.apply(v) === '[object Date]';
    },

    Same.

    /**
    * Returns true if the passed value is a JavaScript Object,
    otherwise false.
    * @param {Mixed} value The value to test
    * @return {Boolean}
    */
    isObject : function(v) {
    return !!v && Object.prototype.toString.call(v) === '[object
    Object]';
    },

    The left part of the conjunction is clearly unneeded. And if they
    would just stop to think about their design, they'd realize that a
    typeof test would do just as well if they disallowed host objects as
    arguments to this function (which they should do anyway).

    /**
    * Returns true if the passed value is a JavaScript 'primitive', a
    string, number or boolean.
    * @param {Mixed} value The value to test
    * @return {Boolean}
    */
    isPrimitive : function(v) {
    return Ext.isString(v) || Ext.isNumber(v) || Ext.isBoolean(v);
    },

    This review could really be compressed to a string of "unneeded and
    botched" comments (a good ways through the core of this thing nothing
    is close to competently designed or implemented). Trying to learn
    anything about browser scripting from the code and/or documentation of
    scripts like this is hopeless as the authors mangle virtually every
    aspect of the language (e.g. scope, primitives, literals, etc.) Yet
    somehow many developers have come to the conclusion that they *must*
    abdicate all responsibility for browser scripting to "expert" efforts
    like this one.

    /**
    * Returns true if the passed value is a JavaScript Function,
    otherwise false.
    * @param {Mixed} value The value to test
    * @return {Boolean}
    */
    isFunction : function(v) {
    return Object.prototype.toString.apply(v) === '[object
    Function]';
    },

    Unneeded and botched. The ambiguities that led to the advent of the
    (unreliable) "Miller Device" do not apply to Function objects (i.e.
    just use typeof). But I suppose the "designers" wanted to allow for
    discrimination between RegExp, Function and host objects, despite the
    fact that there is no practical application for such testing.
    Ironically, defenders of such scripts often pepper their retorts with
    references to the "real world". :)

    /**
    * Returns true if the passed value is a number. Returns false for
    non-finite numbers.
    * @param {Mixed} value The value to test
    * @return {Boolean}
    */
    isNumber : function(v) {
    return Object.prototype.toString.apply(v) === '[object
    Number]' && isFinite(v);
    },

    Unneeded and botched. Recall that isPrimitive calls this, yet it is
    clearly "designed" to allow Number objects to slip through.

    /**
    * Returns true if the passed value is a string.
    * @param {Mixed} value The value to test
    * @return {Boolean}
    */
    isString : function(v) {
    return Object.prototype.toString.apply(v) === '[object
    String]';
    },

    Unneeded and botched (see previous).

    /**util
    * Returns true if the passed value is a boolean.
    * @param {Mixed} value The value to test
    * @return {Boolean}
    */
    isBoolean : function(v) {
    return Object.prototype.toString.apply(v) === '[object
    Boolean]';
    },

    Clearly we are dealing with a cargo cult here, copying and pasting
    patterns of code without the slightest understanding of what it does.
    This one reduces to:-

    isBoolean : function(v) {
    return typeof v == 'boolean';
    },

    ....which is clearly a waste of a function call (why wouldn't you just
    use the typeof operator in the first place?)

    /**
    * Returns true if the passed value is an HTMLElement
    * @param {Mixed} value The value to test
    * @return {Boolean}
    */
    isElement : function(v) {
    return !!v && v.tagName;
    },

    Unneeded and botched.

    /**
    * Returns true if the passed value is not undefined.
    * @param {Mixed} value The value to test
    * @return {Boolean}
    */
    isDefined : function(v){
    return typeof v !== 'undefined';
    },

    Unneeded function with an unneeded strict comparison.

    /**
    * URL to a blank file used by Ext when in secure mode for iframe src
    and onReady src to prevent
    * the IE insecure content warning (<tt>'about:blank'</tt>, except for
    IE in secure mode, which is <tt>'javascript:""'</tt>).
    * @type String
    */
    Ext.SSL_SECURE_URL = Ext.isSecure && 'about:blank';

    Huh? This is isSecure:-

    isSecure : /^https/i.test(window.location.protocol),

    ....so if the document is not served with the https protocol, the above
    will be false (which is obviously not a string).

    Ext.ns = Ext.namespace;

    Why? To save themselves keystrokes? Or perhaps this is a misguided
    attempt to shorten the download. Either way it makes no sense.

    I'm still looking for the first bit that indicates some semblance of
    sense. Though I know there are those who will dismiss this review in
    light of the really "cool" Solitaire demo. In other words, regardless
    of how bad the code is, if any sort of application can be demonstrated
    to "work" in at least two browsers, then arguments about the quality
    of the code can be dismissed out of hand (commonly phrased as "we
    write code for users!").

    Ext.ns(
    'Ext.util',
    'Ext.data',
    'Ext.list',
    'Ext.form',
    'Ext.menu',
    'Ext.state',
    'Ext.layout',
    'Ext.app',
    'Ext.ux',
    'Ext.plugins',
    'Ext.direct'
    );

    Another waste of time and space, though I am sure some misguided
    programmers would consider this more "advanced" than simple assigning
    properties to the Ext object.

    I skipped the "namespace" function; here it is:-

    /**
    * Creates namespaces to be used for scoping variables and classes
    so that they are not global.

    Scoping?! This (repeated) criticism is not being petty. I run into
    programmers all the time who use the term "scope" to refer to all
    sorts of things that have nothing to do with scope. I have to wonder
    what word they would use if they actually wanted to discuss scope
    (it's not as if scope is an arcane subject in the context of JS).
    Scripts and comments like this are to blame.

    * Specifying the last node of a namespace implicitly creates all
    other nodes. Usage:
    * <pre><code>
    Ext.namespace('Company', 'Company.data');
    Ext.namespace('Company.data'); // equivalent and preferable to above
    syntax
    Company.Widget = function() { ... }
    Company.data.CustomStore = function(config) { ... }
    </code></pre>
    * @param {String} namespace1
    * @param {String} namespace2
    * @param {String} etc
    * @return {Object} The namespace object. (If multiple arguments
    are passed, this will be the last namespace created)
    * @method namespace
    */
    namespace : function() {
    var ln = arguments.length,
    i, value, split, x, xln;

    for (i = 0; i < ln; i++) {
    value = arguments;
    parts = value.split(".");
    object = window[parts[0]] = Object(window[parts[0]]);

    As mentioned, using the window object in lieu of a reference to the
    global object is a common rookie mistake.

    And why are they calling Object? I suppose it is in the name of
    "robustness" again, obscuring rather than exposing problems and making
    the debugging of applications more difficult.

    For example, assume that the global "Ext" variable unexpectedly has
    been set to the primitive value of 5. Passing that to Object will
    result in a Number object, not an Object object (clearly not what was
    desired). The application developer should be aware that something
    had gone horribly wrong prior to the conversion, so forcing the issue
    is counter-productive.

    for (x = 1, xln = parts.length; x < xln; x++) {
    object = object[parts[x]] = Object(object[parts[x]]);

    More of the same.

    }
    }
    return object;
    },

    [Skip the usual ExtJS function wrapper suspects]

    /**
    * @class String
    * These functions are available on every String object.
    */
    Ext.applyIf(String.prototype, {

    Good night.

    Never did get to the HTML5 bits. Having reviewed the script in its
    entirety for a client, I know they are few and far between. There's a
    dozen line function to create AUDIO elements (complete with browser
    sniffing and lacking any sort of feature detection), and another that
    does the same for VIDEO elements. I don't know if localStorage is
    part of the "official" HTML5 effort, but they've got a wrapper for
    that. Oh and another dozen lines dealing with geolocation (also fuzzy
    on whether that is part of HTML5). IIRC, that's about it.

    As for the "touch" part. They've attempted to smooth out the
    differences in the ontouch* event handling (between the two browsers
    they aspire to support) using more browser sniffing. Also IIRC, they
    attempt to synthesize the ongesture* events based on touches. Like
    the rest of it, it's a tangled up house of cards.

    Pretty lousy name too. Sencha doesn't exactly roll off the tongue,
    does it? :)
     
    David Mark, Jul 16, 2010
    #1
    1. Advertising

  2. On 2010-07-15 08:38 PM, David Mark wrote:
    > Sencha Touch is a bizarre mish-mash of ExtJS and a jQuery plug-in


    The code Sencha, or "Ext Touch" is of such poor quality that it does not
    seem worth reviewing and the flaws start from line 1.

    [...]

    > Yes, they plan to charge money for this thing.
    >
    > // for old browsers
    > window.undefined = window.undefined;
    >


    Which of the two browsers is that for?

    > First line and it is the usual rookie mistake. Note that this line
    > runs in the global execution context, so - this - points to the global
    > object. Why not use that instead of attempting to augment a host
    > object? Likely because this line has been copied and pasted from a
    > similarly ludicrous script that preceded it. There is no standard for
    > the window object and, as a host object, it is explicitly allowed to
    > throw an exception (or fail silently) in this case.
    >
    > This is not a minor quibble. IE can be configured to disallow host
    > object expandos


    Can it? How so?

    Sencha is apparently not intended to be used on any version of Internet
    Explorer. By including sencha js on a page, errors are thrown in
    Internet Explorer due to calling document.addEventListener.

    // for browsers that support DOMContentLoaded
    document.addEventListener('DOMContentLoaded', fireReady, false);

    The comment is very misleading. The addEventListener method is not
    feature tested and despite what the comment says, it is not known if the
    browser supports DOMContentLoaded or not. Other parts of Sencha have
    code for Internet Explorer, so why did they design it to fail in IE on
    this line? It would be trivial to provide a fallback for IE on that.

    [...]

    You're pulling weeds out of a patch of poison ivy. The design is the
    problem and fixing those issues isn't gonna make much difference.

    > Pretty lousy name too. Sencha doesn't exactly roll off the tongue,
    > does it? :)


    No, if they want to sell, then they got the name right, and they sure
    did get investment money from it, so it is working.

    Trends say that a name should be Japanese or have an "x" or an "i" in
    it. The web page should use buzzwords. If intended for sale, then it can
    make outlandish claims (because the fools with money will not know or
    care), just so long as it has good-looking demos and graphics.

    The website of sencha.com, I read:

    | Web Standards
    | Sencha Touch is built with web standard HTML5, CSS3, and Javascript,
    | making it a very flexible mobile app framework

    HTML5 and CSS3 are not standards, they are what is known as W3C Working
    Drafts <URL: http://www.w3.org/2005/10/Process-20051014/tr#first-wd>.
    "Javascript" is not a web standard either. By using "built with," they
    further avoid making claims of adherence to either of those drafts
    allowing the reader to make a "very flexible" interpretation.

    I'll cover some of the more significant flaws in Sencha later.
    --
    Garrett
     
    Garrett Smith, Jul 16, 2010
    #2
    1. Advertising

  3. David Mark

    RobG Guest

    On Jul 16, 1:38 pm, David Mark <> wrote:
    > Sencha Touch is a bizarre mish-mash of ExtJS and a jQuery plug-in
    > called JQTouch.  It is advertised as the first "HTML5 framework" based
    > on "standards" like HTML5 and CSS3.  Of course, HTML5 is neither a
    > standard nor widely implemented


    Ah, but it's the next best buzz-word after "Web 2-point-oh" and
    "AJAX".

    > and the script eschews CSS3 for
    > proprietary WebKit extensions.  And the most bizarre thing is that
    > very little of the script relates to HTML5.
    >
    > The script is touted as "cross-browser", despite the fact that it is
    > admittedly dual-browser at best.  It weighs 228K (minified)


    The other excuse is that it can be stored on the client using the
    HTML5 cache. I think that cache will be abused by every library author
    or web developer who finds it easier to dump a huge resource on the
    client than write efficient code. Usually that means users of
    inefficient frameworks.

    > and
    > several of its key features rely on UA-based browser sniffing.


    There was a post in the iPhone GG recently from someone selling
    platform statistics lamenting that you can't tell which model of
    iPhone the browser is running in from the UA string.


    [...]

    > As for the "touch" part.  They've attempted to smooth out the
    > differences in the ontouch* event handling (between the two browsers
    > they aspire to support) using more browser sniffing.  Also IIRC, they
    > attempt to synthesize the ongesture* events based on touches.  Like
    > the rest of it, it's a tangled up house of cards.


    I visited their site with an iPhone. Of the 3 demos listed, two didn't
    work at all. The one that did was designed for iPad and was almost
    useless on an iPhone.


    --
    Rob
     
    RobG, Jul 16, 2010
    #3
  4. David Mark

    David Mark Guest

    On Jul 16, 1:28 am, Garrett Smith <> wrote:
    > On 2010-07-15 08:38 PM, David Mark wrote:
    >
    > > Sencha Touch is a bizarre mish-mash of ExtJS and a jQuery plug-in

    >
    > The code Sencha, or "Ext Touch" is of such poor quality that it does not
    > seem worth reviewing and the flaws start from line 1.


    No question there, yet I predict that hordes of prospective mobile Web
    developers will flock to it based on outrageous lies (also known as
    marketing) and pretty graphics.

    >
    > [...]
    >
    > > Yes, they plan to charge money for this thing.

    >
    > > // for old browsers
    > > window.undefined = window.undefined;

    >
    > Which of the two browsers is that for?


    Well, neither of course. :)

    I already reported this (and several other issues) to the author (or
    the main author) of Sencha Touch. Predictably, just like the Dojo
    hacks, he referred to my suggestions as "optimizations" (rather than
    wholesale replacements of code so dubious it never should have been
    written in the first place).

    >
    > > First line and it is the usual rookie mistake.  Note that this line
    > > runs in the global execution context, so - this - points to the global
    > > object.  Why not use that instead of attempting to augment a host
    > > object?  Likely because this line has been copied and pasted from a
    > > similarly ludicrous script that preceded it.  There is no standard for
    > > the window object and, as a host object, it is explicitly allowed to
    > > throw an exception (or fail silently) in this case.

    >
    > > This is not a minor quibble.  IE can be configured to disallow host
    > > object expandos

    >
    > Can it? How so?


    I think you know full well how so.

    document.expando = false;

    Perhaps you are quibbling with the use of the term "configure"?

    >
    > Sencha is apparently not intended to be used on any version of Internet
    > Explorer.


    Yes, apparently they don't "care" about IE, yet they mention IE in
    their comments. And if not for highly dubious design decisions, the
    script could easily run in any version of IE. Their justification is
    likely that they didn't want to bloat their "svelte" 80K of
    (compressed) code. Of course, My Library which runs in IE5-9 (and
    virtually everything else) and features fifty times the functionality
    is a little more than half that size (when compressed in the same
    way).

    > By including sencha js on a page, errors are thrown in
    > Internet Explorer due to calling document.addEventListener.


    Which makes it fairly useless for the Web (if you only consider mobile
    devices).

    >
    > // for browsers that support DOMContentLoaded
    > document.addEventListener('DOMContentLoaded', fireReady, false);
    >
    > The comment is very misleading. The addEventListener method is not
    > feature tested and despite what the comment says, it is not known if the
    > browser supports DOMContentLoaded or not.


    No question there.

    > Other parts of Sencha have
    > code for Internet Explorer, so why did they design it to fail in IE on
    > this line? It would be trivial to provide a fallback for IE on that.


    Because it is a hastily thrown together mish-mash dressed up as a
    breakthrough.

    >
    > [...]
    >
    > You're pulling weeds out of a patch of poison ivy. The design is the
    > problem and fixing those issues isn't gonna make much difference.


    I agree that the entire thing should be scrapped and the authors are
    clearly nowhere near proficient enough to write cross-browser
    scripts. They've got little more than some pretty graphics and
    bluster. But that never stopped jQuery (and many similar efforts) and
    it didn't seem to register on the Ajaxian editors (of course, nothing
    ever does).

    >
    > > Pretty lousy name too.  Sencha doesn't exactly roll off the tongue,
    > > does it?  :)

    >
    > No, if they want to sell, then they got the name right,


    How do you consider Sencha to be "right"?

    > and they sure
    > did get investment money from it, so it is working.


    I know all about the millions they got recently, but that's not
    exclusively because of this product. They have a whole host of bad
    scripts and a history of selling them. It will be interesting to see
    if they use any of that money to hire competent programmers.

    >
    > Trends say that a name should be Japanese or have an "x" or an "i" in
    > it.


    Who conducted that study? And I don't see an "x" or an "i" in Sencha.

    > The web page should use buzzwords. If intended for sale, then it can
    > make outlandish claims (because the fools with money will not know or
    > care), just so long as it has good-looking demos and graphics.


    Exactly.

    >
    > The website of sencha.com, I read:
    >
    > | Web Standards
    > | Sencha Touch is built with web standard HTML5, CSS3, and Javascript,
    > | making it a very flexible mobile app framework


    Lies, lies, lies.

    >
    > HTML5 and CSS3 are not standards, they are what is known as W3C Working
    > Drafts <URL:http://www.w3.org/2005/10/Process-20051014/tr#first-wd>.


    That's why I referred to them as "standards".

    > "Javascript" is not a web standard either.


    Sure as hell not the way they write it. :)

    > By using "built with," they
    > further avoid making claims of adherence to either of those drafts
    > allowing the reader to make a "very flexible" interpretation.


    If their brains are malleable enough.

    >
    > I'll cover some of the more significant flaws in Sencha later.


    It certainly doesn't get any better from where I left off. If
    anything, it gets much worse. I didn't even get to the most egregious
    browser sniffs.

    IIRC, there was a comment that indicated they would remove a sniff as
    soon as Android supported something or other. And where will that
    leave users of the older devices? We've gone from "aw, just get a new
    browser" to "aw, just get a new phone". I suppose if you are "lucky"
    you can just upgrade the device's OS and download another 228K of
    Sencha (for each site that "upgrades" the script of course).

    And at least for now, users of IE mobile, Blackberry and Opera Mini
    browsers are left with a pile of error messages. But the marketers
    spin that as covering a full 90% of the mobile Web (A-!).
     
    David Mark, Jul 16, 2010
    #4
  5. David Mark

    David Mark Guest

    On Jul 16, 2:16 am, RobG <> wrote:
    > On Jul 16, 1:38 pm, David Mark <> wrote:
    >
    > > Sencha Touch is a bizarre mish-mash of ExtJS and a jQuery plug-in
    > > called JQTouch.  It is advertised as the first "HTML5 framework" based
    > > on "standards" like HTML5 and CSS3.  Of course, HTML5 is neither a
    > > standard nor widely implemented

    >
    > Ah, but it's the next best buzz-word after "Web 2-point-oh" and
    > "AJAX".


    When did investment bankers turn into easily misdirected morons?
    That's what I want to know.

    >
    > > and the script eschews CSS3 for
    > > proprietary WebKit extensions.  And the most bizarre thing is that
    > > very little of the script relates to HTML5.

    >
    > > The script is touted as "cross-browser", despite the fact that it is
    > > admittedly dual-browser at best.  It weighs 228K (minified)

    >
    > The other excuse is that it can be stored on the client using the
    > HTML5 cache.


    I'm sure they will try, even though HTML5 is still a pipe dream. From
    what I've heard the manifest stuff is a nightmare, particularly if
    your scripts are ever-changing (as this one certainly will be). It's
    another layer of complexity aimed at people who are overwhelmed to
    begin with.

    > I think that cache will be abused by every library author
    > or web developer who finds it easier to dump a huge resource on the
    > client than write efficient code. Usually that means users of
    > inefficient frameworks.


    Of course. They'll pass the "savings" on to the end-user.

    >
    > > and
    > > several of its key features rely on UA-based browser sniffing.

    >
    > There was a post in the iPhone GG recently from someone selling
    > platform statistics lamenting that you can't tell which model of
    > iPhone the browser is running in from the UA string.


    Right. The ExtJS (er Sencha) developers are already getting irritable
    about people reporting that their stuff doesn't work. Lots of replies
    in their support forums start along the lines of "We told you we only
    care about version XYZ!". Like many JS library developers before
    them, they create problems (usually through monumental incompetence)
    and then get pissed off when people report them. If only people would
    stop messing with their fantasies. :)

    >
    > [...]
    >
    > > As for the "touch" part.  They've attempted to smooth out the
    > > differences in the ontouch* event handling (between the two browsers
    > > they aspire to support) using more browser sniffing.  Also IIRC, they
    > > attempt to synthesize the ongesture* events based on touches.  Like
    > > the rest of it, it's a tangled up house of cards.

    >
    > I visited their site with an iPhone. Of the 3 demos listed, two didn't
    > work at all.


    Well, as the song goes, one out of three ain't bad. Oh wait... :)

    > The one that did was designed for iPad and was almost
    > useless on an iPhone.
    >


    Yes, their "Universal UI" turned out to be nonsense. They've since
    changed their tune on it, describing it as an "experiment". I wonder
    what would their bankers would think about investing millions in such
    experiments?

    At this point, they've tried to support two (nearly identical)
    browsers and failed miserably, even with the crutch of browser
    sniffing. But if history (e.g. jQuery) is any indicator, their starry-
    eyed fans will dismiss any attempts to disrupt their delusions by
    rationalizing "aw, they'll get it right eventually" or "nobody's
    perfect". Save time, save money, write less, do more, etc. Sound
    familiar? :)
     
    David Mark, Jul 16, 2010
    #5
  6. David Mark

    RobG Guest

    On Jul 16, 4:50 pm, David Mark <> wrote:
    > On Jul 16, 2:16 am, RobG <> wrote:
    >
    > > On Jul 16, 1:38 pm, David Mark <> wrote:

    >
    > > > Sencha Touch is a bizarre mish-mash of ExtJS and a jQuery plug-in
    > > > called JQTouch.  It is advertised as the first "HTML5 framework" based
    > > > on "standards" like HTML5 and CSS3.  Of course, HTML5 is neither a
    > > > standard nor widely implemented

    >
    > > Ah, but it's the next best buzz-word after "Web 2-point-oh" and
    > > "AJAX".

    >
    > When did investment bankers turn into easily misdirected morons?
    > That's what I want to know.


    I'll accept that as sarcasm, it's not *their* money that they are
    risking. They tend to be good survivors, as Thucydides said:

    "... most people are more prepared to call villainy cleverness than
    simple mindedness honesty."

    Try this article from InfoWorld about Sencha and jQTouch:

    "Possible escapes from the mobile SDKs' clutches"
    "Writing a new mobile application from scratch for each customer on
    each platform? There are alternatives that don't engender huge costs"

    <URL: http://www.infoworld.com/t/developm...escapes-the-mobile-sdks-clutches-763?page=0,1
    >


    Yeah, right. Provided all mobile devices start running browsers based
    on the latest WebKit nightly. It wasn't that long ago some were saying
    the browser war is over, why doesn't everyone just use IE? Apparently
    all mobile devices should just adopt WebKit and mimic iPhone/iPad/iPod
    Touch.

    [...]
    > At this point, they've tried to support two (nearly identical)
    > browsers and failed miserably, even with the crutch of browser
    > sniffing.


    Not really surprising though is it.


    --
    Rob
     
    RobG, Jul 16, 2010
    #6
  7. David Mark

    KCL Guest

    On Jul 15, 10:38 pm, David Mark <> wrote:
    > Sencha Touch is a bizarre mish-mash of ExtJS and a jQuery plug-in
    > called JQTouch.  It is advertised as the first "HTML5 framework" based
    > on "standards" like HTML5 and CSS3.  Of course, HTML5 is neither a
    > standard nor widely implemented and the script eschews CSS3 for
    > proprietary WebKit extensions.  And the most bizarre thing is that
    > very little of the script relates to HTML5.
    >
    > The script is touted as "cross-browser", despite the fact that it is
    > admittedly dual-browser at best.  It weighs 228K (minified) and
    > several of its key features rely on UA-based browser sniffing.
    >
    > The rationalization for these unfortunate facts is that Android and
    > iPhone/iPod/iPad devices account for 90% of the mobile market.  It is
    > unclear who conducted that study; but regardless, unlike in school,
    > 90% is not an A-, particularly when the remaining 10% are left with
    > non-functioning applications.  The weight problem is dismissed with
    > the usual marketing tactic of quoting sizes after GZIP compression
    > (only 80K!)  And feature detection is deemed "impossible" due to the
    > fact that common features implemented in the two "supported" browsers
    > vary in their behavior (apparently feature testing is outside of the
    > authors' realm of understanding).
    >
    > Not much new here.  It's the same "tired old arguments" that readers
    > of this group have heard over and over.  This shouldn't be surprising
    > as library developers keep making the same tired old mistakes.  And,
    > of course, most newcomers to this group have failed to read each and
    > every previous related post, so repetition is required.



    The first things that come to mind after reading all the criticism is
    this: Are all of you who are tearing these guys a new one against the
    concept of a "framework"? Is there some framework you DON'T think is
    a piece of crap? I see a lot of tearing down--have you built an
    alternative? Given the depth of your review, it would seem you have
    some time on your hands.

    Honestly, I agree with just about every comment you made but without
    offering a legitimate alternative or two, your post comes off as a
    bitter, elitist attack by someone who looks down at anyone who doesn't
    hand-code every line from scratch.

    Give some balance, eh? Either give examples of alternatives you think
    "measure up" or write your own.
     
    KCL, Jul 16, 2010
    #7
  8. David Mark

    john Guest

    On 16 Jul 9:10 AM, KCL wrote:
    > On Jul 15, 10:38 pm, David Mark<> wrote:
    > The first things that come to mind after reading all the criticism is
    > this: Are all of you who are tearing these guys a new one against the
    > concept of a "framework"? Is there some framework you DON'T think is
    > a piece of crap?


    No one bats an eye when a movie critic rips into the latest release
    despite most critics never having written, directed or produced a film
    of their own. Why is it a problem here? Why are you worried about
    negative criticism of a lifeless mass of characters? Don't worry their
    feeling won't be hurt.

    > Give some balance, eh? Either give examples of alternatives you think
    > "measure up" or write your own.


    You could have taken the few seconds required to navigate to google.com
    and type in "David Mark javascript library".
     
    john, Jul 16, 2010
    #8
  9. David Mark

    David Mark Guest

    On Jul 16, 10:10 am, KCL <> wrote:
    > On Jul 15, 10:38 pm, David Mark <> wrote:
    >
    >
    >
    >
    >
    > > Sencha Touch is a bizarre mish-mash of ExtJS and a jQuery plug-in
    > > called JQTouch.  It is advertised as the first "HTML5 framework" based
    > > on "standards" like HTML5 and CSS3.  Of course, HTML5 is neither a
    > > standard nor widely implemented and the script eschews CSS3 for
    > > proprietary WebKit extensions.  And the most bizarre thing is that
    > > very little of the script relates to HTML5.

    >
    > > The script is touted as "cross-browser", despite the fact that it is
    > > admittedly dual-browser at best.  It weighs 228K (minified) and
    > > several of its key features rely on UA-based browser sniffing.

    >
    > > The rationalization for these unfortunate facts is that Android and
    > > iPhone/iPod/iPad devices account for 90% of the mobile market.  It is
    > > unclear who conducted that study; but regardless, unlike in school,
    > > 90% is not an A-, particularly when the remaining 10% are left with
    > > non-functioning applications.  The weight problem is dismissed with
    > > the usual marketing tactic of quoting sizes after GZIP compression
    > > (only 80K!)  And feature detection is deemed "impossible" due to the
    > > fact that common features implemented in the two "supported" browsers
    > > vary in their behavior (apparently feature testing is outside of the
    > > authors' realm of understanding).

    >
    > > Not much new here.  It's the same "tired old arguments" that readers
    > > of this group have heard over and over.  This shouldn't be surprising
    > > as library developers keep making the same tired old mistakes.  And,
    > > of course, most newcomers to this group have failed to read each and
    > > every previous related post, so repetition is required.

    >
    > The first things that come to mind after reading all the criticism is
    > this:  Are all of you who are tearing these guys a new one against the
    > concept of a "framework"?


    Well, you didn't read very carefully, did you? Not once in the entire
    review did I tear into the concept of a framework. The review was
    largely a line-by-line dismantling of the code in "Sencha Touch".

    > Is there some framework you DON'T think is
    > a piece of crap?


    A framework for *what*?

    > I see a lot of tearing down--have you built an
    > alternative?


    Yes. Several. Google.

    > Given the depth of your review, it would seem you have
    > some time on your hands.


    Your attempt at being a smart-ass fails because, in reality, I tore
    through that mess in under an hour. Any experienced developer could
    rewrite every line I cited in two. That's what is appalling about it.

    >
    > Honestly, I agree with just about every comment you made but without
    > offering a legitimate alternative or two, your post comes off as a
    > bitter, elitist attack by someone who looks down at anyone who doesn't
    > hand-code every line from scratch.


    I don't believe you understand (or even read) every comment I made.
    And you clearly missed the "legitimate alternative" (or two) that were
    included.

    And disillusioned neophytes always dismiss code criticism as "elitist"
    and "bitter". This would seem to be due to paranoia (i.e. if the
    authors of the framework I lean on are clueless, then where does that
    leave me?)

    >
    > Give some balance, eh?  Either give examples of alternatives you think
    > "measure up" or write your own.


    Could you be any more lost? Read the post again and do some research;
    then you can talk (and hopefully your message will have changed to
    reflect reality by then).
     
    David Mark, Jul 16, 2010
    #9
  10. On 2010-07-15 11:31 PM, David Mark wrote:
    > On Jul 16, 1:28 am, Garrett Smith<> wrote:
    >> On 2010-07-15 08:38 PM, David Mark wrote:
    >>
    >>> Sencha Touch is a bizarre mish-mash of ExtJS and a jQuery plug-in

    >>


    [...]

    >>> This is not a minor quibble. IE can be configured to disallow host
    >>> object expandos

    >>
    >> Can it? How so?

    >
    > I think you know full well how so.
    >
    > document.expando = false;
    >


    That is a document setting. There's no good reason for doing that.

    > Perhaps you are quibbling with the use of the term "configure"?
    >

    I suspected you didn't actually mean what you wrote. A setting that is
    performed by the user is not controllable by the page author.

    Contrast to that, document.expando, a document setting is set
    exclusively by the page is not entirely out of the authors' hands. There
    may be cases such as an advert which affects the document, but those can
    often be mitigated. In the case of the advert, keeping the advert in an
    iframe would avoid that.

    Any third party library that sets document.expando = false is probably
    going to cause a lot of problems.

    Among reasons for not using expandos, the fact that document.expando may
    be set to false seems not a good one.

    When it is known that IE will throw errors on simple things like:
    alert.a = 12; and that alert is a host method, or that adding
    document.rootElement might result in an error where the implementation
    comes along and defines that. Those possibilities can easily be factored
    out by not adding expandos.

    [...]

    >
    >> Other parts of Sencha have
    >> code for Internet Explorer, so why did they design it to fail in IE on
    >> this line? It would be trivial to provide a fallback for IE on that.

    >
    > Because it is a hastily thrown together mish-mash dressed up as a
    > breakthrough.
    >


    IT is because they've copy'n'pasted from the existing Ext-js code and
    that code, despite all the OO plumbing, has interdependencies and code
    duplication. Many things from Ext.util.Element

    >>
    >> [...]
    >>
    >> You're pulling weeds out of a patch of poison ivy. The design is the
    >> problem and fixing those issues isn't gonna make much difference.

    >
    > I agree that the entire thing should be scrapped and the authors are
    > clearly nowhere near proficient enough to write cross-browser
    > scripts. They've got little more than some pretty graphics and
    > bluster. But that never stopped jQuery (and many similar efforts) and
    > it didn't seem to register on the Ajaxian editors (of course, nothing
    > ever does).
    >
    >>
    >>> Pretty lousy name too. Sencha doesn't exactly roll off the tongue,
    >>> does it? :)

    >>
    >> No, if they want to sell, then they got the name right,

    >
    > How do you consider Sencha to be "right"?
    >


    Because it works for them.

    >> and they sure
    >> did get investment money from it, so it is working.

    >
    > I know all about the millions they got recently, but that's not
    > exclusively because of this product. They have a whole host of bad
    > scripts and a history of selling them. It will be interesting to see
    > if they use any of that money to hire competent programmers.
    >
    >>
    >> Trends say that a name should be Japanese or have an "x" or an "i" in
    >> it.

    >
    > Who conducted that study? And I don't see an "x" or an "i" in Sencha.
    >


    Sencha is Japamese.
    --
    Garrett
     
    Garrett Smith, Jul 16, 2010
    #10
  11. David Mark

    David Mark Guest

    On Jul 16, 2:28 pm, Garrett Smith <> wrote:
    > On 2010-07-15 11:31 PM, David Mark wrote:
    >
    > > On Jul 16, 1:28 am, Garrett Smith<>  wrote:
    > >> On 2010-07-15 08:38 PM, David Mark wrote:

    >
    > >>> Sencha Touch is a bizarre mish-mash of ExtJS and a jQuery plug-in

    >
    > [...]
    >
    > >>> This is not a minor quibble.  IE can be configured to disallow host
    > >>> object expandos

    >
    > >> Can it? How so?

    >
    > > I think you know full well how so.

    >
    > > document.expando = false;

    >
    > That is a document setting. There's no good reason for doing that.
    >
    > > Perhaps you are quibbling with the use of the term "configure"?

    >
    > I suspected you didn't actually mean what you wrote. A setting that is
    > performed by the user is not controllable by the page author.
    >
    > Contrast to that, document.expando, a document setting is set
    > exclusively by the page is not entirely out of the authors' hands. There
    > may be cases such as an advert which affects the document, but those can
    > often be mitigated. In the case of the advert, keeping the advert in an
    > iframe would avoid that.
    >
    > Any third party library that sets document.expando = false is probably
    > going to cause a lot of problems.
    >
    > Among reasons for not using expandos, the fact that document.expando may
    > be set to false seems not a good one.


    It's just one. Certainly not the most important.

    >
    > When it is known that IE will throw errors on simple things like:
    > alert.a = 12; and that alert is a host method, or that adding
    > document.rootElement might result in an error where the implementation
    > comes along and defines that. Those possibilities can easily be factored
    > out by not adding expandos.


    Yes, that's my point; particularly when they are completely unneeded
    (as with that window.undefined nonsense).

    >
    > [...]
    >
    >
    >
    > >> Other parts of Sencha have
    > >> code for Internet Explorer, so why did they design it to fail in IE on
    > >> this line? It would be trivial to provide a fallback for IE on that.

    >
    > > Because it is a hastily thrown together mish-mash dressed up as a
    > > breakthrough.

    >
    > IT is because they've copy'n'pasted from the existing Ext-js code and
    > that code, despite all the OO plumbing, has interdependencies and code
    > duplication. Many things from Ext.util.Element
    >


    You seem to have trailed off.

    >
    >
    >
    >
    >
    >
    > >> [...]

    >
    > >> You're pulling weeds out of a patch of poison ivy. The design is the
    > >> problem and fixing those issues isn't gonna make much difference.

    >
    > > I agree that the entire thing should be scrapped and the authors are
    > > clearly nowhere near proficient enough to write cross-browser
    > > scripts.  They've got little more than some pretty graphics and
    > > bluster.  But that never stopped jQuery (and many similar efforts) and
    > > it didn't seem to register on the Ajaxian editors (of course, nothing
    > > ever does).

    >
    > >>> Pretty lousy name too.  Sencha doesn't exactly roll off the tongue,
    > >>> does it?  :)

    >
    > >> No, if they want to sell, then they got the name right,

    >
    > > How do you consider Sencha to be "right"?

    >
    > Because it works for them.


    Works in what way? And who is to say that another name would have
    worked better or worse?

    >
    > >> and they sure
    > >> did get investment money from it, so it is working.

    >
    > > I know all about the millions they got recently, but that's not
    > > exclusively because of this product.  They have a whole host of bad
    > > scripts and a history of selling them.  It will be interesting to see
    > > if they use any of that money to hire competent programmers.

    >
    > >> Trends say that a name should be Japanese or have an "x" or an "i" in
    > >> it.

    >
    > > Who conducted that study?  And I don't see an "x" or an "i" in Sencha..

    >
    > Sencha is Japamese.


    One out of three ain't bad?
     
    David Mark, Jul 16, 2010
    #11
  12. David Mark

    David Mark Guest

    On Jul 16, 12:05 pm, john <> wrote:
    > On 16 Jul 9:10 AM, KCL wrote:
    >
    > > On Jul 15, 10:38 pm, David Mark<>  wrote:
    > > The first things that come to mind after reading all the criticism is
    > > this:  Are all of you who are tearing these guys a new one against the
    > > concept of a "framework"?  Is there some framework you DON'T think is
    > > a piece of crap?

    >
    > No one bats an eye when a movie critic rips into the latest release
    > despite most critics never having written, directed or produced a film
    > of their own.


    Yes. In fact the typical "fanboy" loves to rag on movies, but that
    mindset rarely carries over to JS libraries. Instead it is "I'm okay,
    you're okay" and anyone who dares to say different is labeled as
    "elitist" and/or "bitter". It is amusing that every "retort" from
    such people (and perhaps they all come from the same anonymous clod?)
    is a carbon copy of all that came before it.

    * Why do you want to write everything from scratch?

    * Wow, that must have taken a lot of time to sort out!

    * Let's see you write something better.

    * Okay, you wrote something better; now UR just jealous coz nobody
    uses it. :)

    The first one indicates a fundamental misunderstanding of the debate
    about GP frameworks. The second is a lame attempt at humor. The
    third is child-like baiting and reflects the same misunderstanding as
    the first. The last is a predictable Hail Mary from people who have
    found themselves boxed into a logical corner.

    It really makes you wonder about the reasoning ability (or lack
    thereof) of the average Web developer. After half a decade of
    listening to the same old oversimplifications and bleating about Ajax
    and JS libraries, I've come to wonder if their median age is twelve.
    Of course, that's an insult to at least some twelve-year-olds. :)

    > Why is it a problem here? Why are you worried about
    > negative criticism of a lifeless mass of characters? Don't worry their
    > feeling won't be hurt.


    The issue is that the typical Web developer is incapable of writing
    cross-browser scripts. They really, really want to do it, but reality
    is so unfair. :)

    So they are constantly searching for that magic framework that will
    allow them to fake it. As such, they get very irritable when told
    that no such framework exists. They are much more open to listen to
    those who nurse their fantasies than those who burst their balloons.
    Again, it's a very child-like mentality. Don't tell them Santa Claus
    is not real. :)

    >
    > > Give some balance, eh?  Either give examples of alternatives you think
    > > "measure up" or write your own.

    >
    > You could have taken the few seconds required to navigate to google.com
    > and type in "David Mark javascript library".


    They never do until they are told. Then they change their tune to
    suit their delusions (the jealousy angle). Anything to avoid the
    unpleasant reality of their own shortcomings. Of course, if they
    spent more time learning and less bleating, perhaps they might someday
    be capable of doing what they so desperately want to do.
     
    David Mark, Jul 16, 2010
    #12
  13. David Mark

    David Mark Guest

    On Jul 15, 11:38 pm, David Mark <> wrote:
    > Sencha Touch is a bizarre mish-mash of ExtJS and a jQuery plug-in
    > called JQTouch.


    And I am so jealous (and have so much time on my hands) that I will
    pick up where I left off. The public outcry was just not loud enough
    to suit my taste. :)

    And yes, that's sarcasm. My primary motivation for posting code
    reviews is to prevent people from wasting their own time (and money)
    on garbage. Then there's always the possibility that people might
    learn something from them.

    Of course, this particular script is so awful that anyone who could
    learn from its dissection probably won't, instead choosing to focus on
    my motivations, time management, etc.

    Now where was I? Ah yes, the conditional augmentation of native
    prototypes.

    /**
    * @class String
    * These functions are available on every String object.
    */
    Ext.applyIf(String.prototype, {
    /**
    * Escapes the passed string for ' and \
    * @param {String} string The string to escape
    * @return {String} The escaped string
    * @static
    */
    escape : function(string) {
    return string.replace(/('|\\)/g, "\\$1");
    },

    What's wrong with that picture? For one, extending native prototypes
    is a bad idea for a Web framework, which will likely have to coexist
    (i.e. play nice) with other scripts. Of course, extending them if and
    only if they haven't been previously extended with *something* is
    madness. I mean, there's no way for the script to know if that
    something is compatible with its own prospective augmentations.

    [skip lots more of those]

    (function() {
    Ext.Element = Ext.extend(Object, {
    /**
    * The default unit to append to CSS values where a unit isn't
    provided (defaults to px).
    * @type String
    */
    defaultUnit : "px",

    constructor : function(element, forceNew) {

    This is a very awkward way to write a constructor.


    var dom = typeof element == 'string'
    ? document.getElementById(element)
    : element,
    id;

    if (!dom) {
    return null;
    }

    And that's a very odd thing to do in a constructor.


    id = dom.id;
    if (!forceNew && id && Ext.cache[id]) {
    return Ext.cache[id].el;

    As is that.

    }

    /**
    * The DOM element
    * @type HTMLElement
    */
    this.dom = dom;

    Ill-advised to hitch a host object to an Object object. This sets the
    stage for unintended circular references, but it's a moot point as
    this script will never run in IE anyway. ISTM that this code was
    copied and pasted from ExtJS though, which is troubling.

    /**
    * The DOM element ID
    * @type String
    */
    this.id = id || Ext.id(dom);

    This is ridiculously invasive. Every "wrapped" DOM element must have
    an ID? And didn't I see this being used to wrap document nodes as
    well?

    return this;

    That line clearly does nothing as this is a constructor.

    },

    /**
    * Sets the passed attributes as attributes of this element (a
    style attribute can be a string, object or function)

    Oh here we go. Why is it that library authors refuse to understand
    attributes/properties? How do you simplify DOM manipulation for the
    masses when you don't understand the first thing about DOM
    manipulation?

    * @param {Object} o The object with the attributes
    * @param {Boolean} useSet (optional) false to override the
    default setAttribute to use expandos.

    Make it stop. :(

    * @return {Ext.Element} this
    */
    set : function(o, useSet) {
    var el = this.dom,
    attr,
    value;

    for (attr in o) {
    if (o.hasOwnProperty(attr)) {
    value = o[attr];
    if (attr == 'style') {
    this.applyStyles(value);
    }
    else if (attr == 'cls') {
    el.className = value;
    }

    Why? Is "cls" easier to recognize than "class"?

    else if (useSet !== false) {
    el.setAttribute(attr, value);
    }
    else {
    el[attr] = value;
    }

    Zero value-add there; it's left solely to the application developer to
    deal with the attributes vs. properties issues. I suppose that's
    better than trying to add value and hopelessly fouling everything up
    (see jQuery, Dojo, YUI, etc.)

    }
    }
    return this;
    },

    /**
    * Returns true if this element matches the passed simple selector
    (e.g. div.some-class or span:first-child)
    * @param {String} selector The simple selector to test
    * @return {Boolean} True if this element matches the selector,
    else false
    */
    is : function(simpleSelector) {
    return Ext.DomQuery.is(this.dom, simpleSelector);
    },

    In this case, Ext.DomQuery is simply a wafer-thin wrapper for QSA,
    which is nowhere near consistent cross-browser and will not match the
    expectations of developers raised on jQuery (and the like).

    /**
    * Returns the value of the "value" attribute
    * @param {Boolean} asNumber true to parse the value as a number
    * @return {String/Number}

    Or undefined or NaN. That's the trouble with trying to abstract a
    diverse set of DOM node types with a single wrapper (see jQuery).

    */
    getValue : function(asNumber){
    var val = this.dom.value;
    return asNumber ? parseInt(val, 10) : val;
    },

    addListener : function(eventName, fn, scope, options){
    Ext.EventManager.on(this.dom, eventName, fn, scope || this,
    options);
    return this;
    },

    It should be pointed out that all of these unnecessary dot operations
    slow the code down and impede the efforts of minifiers as well.
    Again, odd choices for a mobile framework.

    /**
    * <p>Removes this element's dom reference. Note that event and
    cache removal is handled at {@link Ext#removeNode}</p>
    */
    remove : function() {
    var me = this,
    dom = me.dom;

    if (dom) {

    Just let it crash if they try to remove it twice. The developers will
    thank you as it will make tracking down bugs in their applications
    that much easier.

    delete me.dom;
    Ext.removeNode(dom);
    }
    },


    isAncestor : function(c) {
    var p = this.dom;
    c = Ext.getDom(c);
    if (p && c) {

    Same problem as above. Trying to hard to be "robust" without
    considering the ramifications for the application developers.

    return p.contains(c);
    }
    return false;
    },

    Missing documentation for that one.

    /**
    * Determines if this element is a descendent of the passed in
    Element.
    * @param {Mixed} element An Ext.Element, HTMLElement or string
    linking to an id of an Element.

    Mixed === Botched. Never design systems that must discriminate
    between host and native objects.

    * @returns {Boolean}
    */
    isDescendent : function(p) {
    return Ext.fly(p).isAncestorOf(this);
    },

    /**
    * Returns true if this element is an ancestor of the passed
    element
    * @param {HTMLElement/String} el The element to check
    * @return {Boolean} True if this element is an ancestor of el,
    else false
    */
    contains : function(el) {
    return !el ? false : this.isAncestor(el);
    },

    If an application passes this method an argument that type-converts to
    false then something is very wrong with the application (and a
    "robust" silent failure is not going to help matters). Get the
    feeling that if they removed all of this "robustness", the framework
    itself would fall apart? It's been noted several times that many of
    these functions pose the question of what sort of odd application
    would require them. The obvious answer is that the framework itself
    requires them (which indicates that its overall "design" is faulty).

    /**
    * Returns the value of an attribute from the element's underlying
    DOM node.
    * @param {String} name The attribute name
    * @param {String} namespace (optional) The namespace in which to
    look for the attribute
    * @return {String} The attribute value
    */
    getAttribute : function(name, ns) {
    var d = this.dom;
    return d.getAttributeNS(ns, name) || d.getAttribute(ns + ":" +
    name) || d.getAttribute(name) || d[name];
    },

    For starters, this script has no chance of working in XML parse mode.
    Perhaps they were thinking of SVG, but the only place they call this
    is in that muddled META injection code at the very start. Second,
    attribute values are allowed to be empty strings. And last but not
    least, attribute names do not always match their associated property
    names.

    Again, you've got to wonder if the ostensible experts behind this
    "ground-breaking" framework are really this ignorant of basic DOM
    operations (a la jQuery) or are simply trying to make this stuff as
    confusing as possible to keep curious Web developers in the dark (and
    therefore perpetually dependent on scripts like this).

    Either way, it's poison, creating problems while solving nothing at
    all. This is what the typical wheels look like. So why shouldn't
    they be re-invented? They are square after all. In this particular
    case there is no need for such a wheel in 99.9% of Web applications
    (and sure as hell not in that form).

    /**
    * Set the innerHTML of this element
    * @param {String} html The new HTML
    * @return {Ext.Element} this
    */
    setHTML : function(html) {
    if(this.dom) {

    If an applications attempts to set the inner HTML after it has
    destroyed the reference to the element, the developers need to know so
    they can track down the problem in their code. Sorry for the
    repetition, but it is caused by the code which makes the same mistakes
    over and over.

    this.dom.innerHTML = html;
    }
    return this;

    And thanks to the ill-advised "chaining" design, there's no way to
    return an indication of failure, so the only practical thing to do in
    case of failures is to let it blow up.

    },

    /**
    * Returns the innerHTML of an Element or an empty string if the
    element's
    * dom no longer exists.
    */
    getHTML : function() {
    return this.dom ? this.dom.innerHTML : '';
    },

    Again.

    setVisible : function(visible, animate) {
    var me = this,

    Why?

    dom = me.dom,
    mode = this.getVisibilityMode();

    switch (mode) {
    case Ext.Element.VISIBILITY:
    this.removeClass(['x-hidden-display', 'x-hidden-
    offsets']);
    this[visible ? 'removeClass' : 'addClass']('x-hidden-
    visibility');
    break;

    It is absurd to couple this basic (and critical) functionality with
    CSS classes. Inefficient too.

    case Ext.Element.DISPLAY:
    this.removeClass(['x-hidden-visibility', 'x-hidden-
    offsets']);
    this[visible ? 'removeClass' : 'addClass']('x-hidden-
    display');
    break;

    case Ext.Element.OFFSETS:
    this.removeClass(['x-hidden-visibility', 'x-hidden-
    display']);
    this[visible ? 'removeClass' : 'addClass']('x-hidden-
    offsets');
    break;

    Delete that line.

    }

    return me;

    Did they think that - this - (scope in Ext-speak) would change in the
    course of adding and removing classes?

    },

    getVisibilityMode: function() {
    var dom = this.dom,
    mode = Ext.Element.data(dom, 'visibilityMode');

    if (mode === undefined) {
    Ext.Element.data(dom, 'visibilityMode', mode =
    Ext.Element.DISPLAY);
    }

    Don't do sets in gets!

    return mode;
    },

    setDisplayMode : function(mode) {
    Ext.Element.data(this.dom, 'visibilityMode', mode);
    return this;
    }

    Bit of an incongruity there. You get "visibility mode" but set
    "display mode". And they call my API subterranean. :)

    El.prototype.on = El.prototype.addListener;
    El.prototype.un = El.prototype.removeListener;

    More "shorthand" waste.

    // Alias for people used to Ext JS and Ext Core
    El.prototype.update = El.prototype.setHTML;

    Same.

    El.get = function(el){
    var extEl,
    dom,
    id;

    if(!el){
    return null;
    }

    Delete that (I'm done repeating myself about the "robustness" issue).


    if (typeof el == "string") { // element id
    if (!(dom = document.getElementById(el))) {
    return null;
    }
    if (Ext.cache[el] && Ext.cache[el].el) {

    They seem to look at property access as a freebie.

    extEl = Ext.cache[el].el;
    extEl.dom = dom;
    } else {
    extEl = El.addToCache(new El(dom));

    There's that oddball constructor, which jumps through the same hoops
    as this function.

    }
    return extEl;
    } else if (el.tagName) { // dom element
    if(!(id = el.id)){
    id = Ext.id(el);
    }
    if (Ext.cache[id] && Ext.cache[id].el) {
    extEl = Ext.cache[id].el;
    extEl.dom = el;
    } else {
    extEl = El.addToCache(new El(el));
    }

    Deja vu all over again. :)

    return extEl;
    } else if (el instanceof El) {
    if(el != El.docEl){
    // refresh dom element in case no longer valid,
    // catch case where it hasn't been appended
    el.dom = document.getElementById(el.id) || el.dom;
    }
    return el;
    } else if(el.isComposite) {
    return el;

    The isComposite property might indicate that this is one of their
    jQuery-like wrappers (multiple elements). Well, at least they
    recognized that using one abstraction for single and multiple nodes is
    silly. But why would one pass such an object to this method?

    } else if(Ext.isArray(el)) {

    D'oh!

    return El.select(el);
    } else if(el == document) {
    // create a bogus element object representing the document
    object

    Yes, the word "bogus" seems appropriate. This has got to be one of
    the strangest API's I've ever seen (and that's saying something).

    if(!El.docEl){
    var F = function(){};
    F.prototype = El.prototype;
    El.docEl = new F();
    El.docEl.dom = document;

    It should be noted that this script will never work for multi-frame
    applications.

    }
    return El.docEl;
    }
    return null;
    };

    // private

    Like hell it is. :)

    El.addToCache = function(el, id){
    id = id || el.id;

    Why would they want to override the ID?

    Ext.cache[id] = {
    el: el,
    data: {},
    events: {}
    };
    return el;
    };

    // private method for getting and setting element data

    Nope. It's just as public as every other JS property. They really do
    seem to go out of their way to confuse the hell out of beginners.

    El.data = function(el, key, value) {
    el = El.get(el);
    if (!el) {
    return null;
    }
    var c = Ext.cache[el.id].data;
    if(arguments.length == 2) {

    How about:-

    if (typeof value == 'undefined') {

    return c[key];
    }
    else {
    return (c[key] = value);
    }
    };

    jQuery-ish getter/setter, which is about the least intuitive interface
    imaginable.

    // private

    No.

    // Garbage collection - uncache elements/purge listeners on orphaned
    elements

    ISTM that if you really feel the need to "purge listeners" (rather
    than leaving that to the built-in GC) then you need to do it before
    the elements are orphaned. Of course, this is all stems from an IE
    issue and this script will never run in IE.

    // so we don't hold a reference and cause the browser to retain them
    El.garbageCollect = function(){
    if(!Ext.enableGarbageCollector){
    clearInterval(El.collectorThreadId);

    Thread ID?

    } else {
    var id,
    el,
    dom,
    o;

    for(id in Ext.cache){

    They waffle back and forth between filtered and unfiltered for-in
    loops.

    o = Ext.cache[id];
    if(o.skipGarbageCollection){
    continue;
    }

    Don't use - continue - as it just makes the code harder to follow.

    el = o.el;
    dom = el.dom;
    if(!dom || !dom.parentNode || (!dom.offsetParent && !
    document.getElementById(id))){

    If dom does not hold a reference to an element then there's nothing to
    do here. And if the element does not have an offsetParent (a test
    that will blow up for orphans in IE), it sure as hell won't be found
    by getEBI.

    if(Ext.enableListenerCollection){
    Ext.EventManager.removeAll(dom);

    There's one instance where they are "saving" themselves with ill-
    advised type-checking. In other words, they are hiding mistakes from
    themselves, just as they do for application developers.

    }
    delete Ext.cache[eid];
    }
    }
    }
    };
    //El.collectorThreadId = setInterval(El.garbageCollect, 20000);

    Interesting.

    /*Ext.EventManager.on(window, 'unload', function(){
    delete Ext.cache;
    delete El._flyweights;
    });*/

    As is that. For the record, this can be deleted for good.

    Ext.applyIf(Ext.Element, {

    Why conditional? Ext.Element is created by this script.

    unitRe: /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i,
    camelRe: /(-[a-z])/gi,
    opacityRe: /alpha\(opacity=(.*)\)/i,

    No. And this is an IE-ism (so what is it doing in here?)

    propertyCache: {},
    borders: {l: 'border-left-width', r: 'border-right-width', t:
    'border-top-width', b: 'border-bottom-width'},
    paddings: {l: 'padding-left', r: 'padding-right', t: 'padding-
    top', b: 'padding-bottom'},
    margins: {l: 'margin-left', r: 'margin-right', t: 'margin-top', b:
    'margin-bottom'},

    Wastes of space.

    addUnits : function(size) {
    if (size === "" || size == "auto" || size === undefined) {
    size = size || '';
    }

    So if size is an empty string or undefined, awkardly assign it an
    empty string (which it was to begin with for the former case). If
    size is "auto" this is also a no-op.

    I see why they did this; it's the *how* that bothers me. Good code is
    easy to follow and therefore easy to maintain. The jQuery-ish logic
    above is obviously not good code.

    else if (!isNaN(size) || !this.unitRe.test(size)) {

    It's interesting that they left out null from the above check,
    particularly as they will almost certainly be passing the results of
    getComputedStyle to this function.

    size = size + (this.defaultUnit || 'px');

    One expected outcome is "nullpx".

    }
    return size;
    },

    parseBox : function(box) {
    if (typeof box != 'string') {
    box = box.toString();
    }
    var parts = box.split(' '),
    ln = parts.length;

    if (ln == 1) {
    parts[1] = parts[2] = parts[3] = parts[0];
    }
    else if (ln == 2) {
    parts[2] = parts[0];
    parts[3] = parts[1];
    }
    else if (ln == 3) {
    parts[3] = parts[1];
    }


    Should have used a switch statement.


    return {
    top :parseInt(parts[0], 10) || 0,
    right :parseInt(parts[1], 10) || 0,
    bottom:parseInt(parts[2], 10) || 0,
    left :parseInt(parts[3], 10) || 0
    };
    },


    /**
    * Retrieves the document height
    * @returns {Number} documentHeight
    */
    getDocumentHeight: function() {
    return Math.max(!Ext.isStrict ? document.body.scrollHeight :
    document.documentElement.scrollHeight, this.getViewportHeight());
    },

    Wishful thinking that much of this script will function as expected in
    quirks mode. And clearly the call to getViewportHeight is a mystical
    incantation (the only way it could "work" is by coincidence). The
    logic makes zero sense and without comments it's hard to know what
    they were thinking.

    /**
    * Retrieves the viewport height of the window.
    * @returns {Number} viewportHeight
    */
    getViewportHeight: function(){
    return window.innerHeight;
    },

    That (sort of) explains their confusion. The innerHeight is the
    height of the viewport in Android (which is not resizable by the user,
    except by rotating the device). But why wasn't document.scrollHeight
    good enough for them?

    In any event, window.innerHeight returns the height of the user-
    controlled "viewfinder" in iPhone, which is a whole different story.
    So in most cases the results will vary wildly between the two
    browsers. To answer a reader question from earlier in the thread: can
    I do better? You better fucking believe it. I do it for my clients
    every day. Just wrapped up a function to retrieve the viewport or
    "viewfinder" dimensions (and position) and it works in hell of lot
    more than two browsers. ;)

    /**
    * Retrieves the viewport size of the window.

    What's a window? :)

    * @returns {Object} object containing width and height properties
    */
    getViewSize : function() {
    return {
    width: window.innerWidth,
    height: window.innerHeight
    };
    },

    As mentioned, this is botched, even in the two devices this script
    aspires to support.

    /**
    * Gets the current position of the element based on page
    coordinates. Element must be part of the DOM tree to have page
    coordinates (display:none or elements not appended return false).


    The most overused, overrated and thoroughly unneeded function in the
    history of browser scripting. Designing systems that rely on this
    working is madness.


    * @return {Array} The XY position of the element
    */
    getXY : (function() {
    // if(Ext.platform.hasGetBoundingClientRect) {
    // return function() {
    // var dom = this.dom,
    // box, scroll;
    //
    // if (!dom || !dom.ownerDocument ||
    dom.ownerDocument.body === dom) {
    // return [0, 0];
    // }
    //
    // box = dom.getBoundingClientRect();
    // scroll = Ext.fly(document).getScroll();
    // return [Math.round(box.left + scroll.left),
    Math.round(box.top + scroll.top)];
    // };
    // }
    // else {

    I see why they commented out that fork. Like the YUI developers, they
    haven't quite come to grips with gBCR.

    return function() {
    var body = document.body || document.documentElement,

    Dear God. All the earmarks of a script being cobbled together without
    any inkling of what it is actually doing. I guess this is where that
    "show me where it fails" attitude comes from. Deep down, the authors
    of the "major" GP libraries know they are clueless, so all they have
    to cling to are unit test results in the handful of browsers they
    observe. As soon as things appear to work, they declare a job well
    done (and scream bloody murder when told they need to change
    something).

    dom = parent = this.dom,
    x = y = 0;

    if (!dom || dom === body) {
    return [0, 0];
    }

    That makes no sense. I guess they only tested with the Ext CSS
    "reset" in place. IIRC, it wipes out margins on the body (among many
    other things). Sets EM and STRONG to use default font-weight and font-
    style as well. :)

    while (parent) {
    x += parent.offsetLeft;
    y += parent.offsetTop;

    if(parent != dom) {
    // For webkit, we need to add parent's
    clientLeft/Top as well.

    As is the case with most modern browsers.

    x += parent.clientLeft || 0;
    y += parent.clientTop || 0;
    }

    parent = parent.offsetParent;
    }

    // Safari absolute incorrectly account for body
    offsetTop.
    if (Ext.platform.isWebkit && this.isStyle('position',
    'absolute')) {
    y -= body.offsetTop;
    }

    Unneeded (as always) UA sniff. Easy enough to feature test, but given
    that they don't "support" anything but two WebKit variants...

    parent = dom.parentNode;
    while (parent && parent != body) {
    x -= parent.scrollLeft;
    y -= parent.scrollTop;
    parent = parent.parentNode;
    }

    That's an extremely expensive (and error-prone) operation that is only
    needed in special cases. Doing it every time through is a terrible
    waste.

    return [x, y];
    };
    // }
    })(),

    /**
    * Sets the position of the element in page coordinates,
    regardless of how the element is positioned.

    I sincerely doubt that. Though the task is not particularly
    difficult. Take a guess (perhaps using the offsetLeft/Top property
    values) and set the left/top styles, get the resulting absolute
    position (as best you can) and adjust by the difference between what
    it is and what you want it to be. Suffice to say, that's not what
    they did.

    * The element must be part of the DOM tree to have page
    coordinates (display:none or elements not appended return false).
    * @param {Array} pos Contains X & Y [x, y] values for new
    position (coordinates are page-based)
    * @return {Ext.Element} this
    */
    setXY : function(pos) {
    var me = this;

    Again with the "me". (!)

    if(arguments.length > 1) {
    pos = [pos, arguments[1]];
    }

    // me.position();
    var pts = me.translatePoints(pos),
    style = me.dom.style;

    for (pos in pts) {
    if(!isNaN(pts[pos])) style[pos] = pts[pos] + "px";
    }
    return me;
    },

    /**
    * Gets the left X coordinate
    * @param {Boolean} local True to get the local css position
    instead of page coordinate
    * @return {Number}
    */
    getLeft : function(local) {
    return parseInt(this.getStyle('left'), 10) || 0;
    },

    Use parseFloat.


    getBox : function(contentBox, local) {
    var me = this,
    dom = me.dom,
    width = dom.offsetWidth,
    height = dom.offsetHeight,
    xy, box, l, r, t, b;

    if (!local) {
    xy = me.getXY();
    }
    else if (contentBox) {
    xy = [0,0];
    }
    else {
    xy = [parseInt(me.getStyle("left"), 10) || 0,
    parseInt(me.getStyle("top"), 10) || 0];

    Again, use parseFloat. I know it is counter-intuitive that fractions
    of pixels could matter, but they do. The loss of precision will bite
    you when doing subsequent arithmetic on the coordinates or dimensions.

    }

    if (!contentBox) {
    box = {
    x: xy[0],
    y: xy[1],
    0: xy[0],
    1: xy[1],
    width: width,
    height: height
    };

    The CSS left/top combined with the offsetWidth/Height. Seems like an
    odd (and impractical) combination.

    }
    else {
    l = me.getBorderWidth.call(me, "l") +
    me.getPadding.call(me, "l");
    r = me.getBorderWidth.call(me, "r") +
    me.getPadding.call(me, "r");
    t = me.getBorderWidth.call(me, "t") +
    me.getPadding.call(me, "t");
    b = me.getBorderWidth.call(me, "b") +
    me.getPadding.call(me, "b");

    What's wrong with that picture? :)

    box = {
    x: xy[0] + l,
    y: xy[1] + t,
    0: xy[0] + l,
    1: xy[1] + t,
    width: width - (l + r),
    height: height - (t + b)

    And why didn't they just start with the clientLeft/Top/Height/Width
    and add/subtract the padding?

    };
    }

    box.left = box.x;
    box.top = box.y;
    box.right = box.x + box.width;
    box.bottom = box.y + box.height;

    return box;
    },

    /**
    * Return an object defining the area of this Element which can be
    passed to {@link #setBox} to
    * set another Element's size/location to match this element.
    * @param {Boolean} asRegion(optional) If true an Ext.util.Region
    will be returned

    Everything is so tangled up. And they assert that this thing is
    modular.

    * @return {Object} box An object in the format<pre><code>
    {
    x: &lt;Element's X position>,
    y: &lt;Element's Y position>,
    width: &lt;Element's width>,
    height: &lt;Element's height>,
    bottom: &lt;Element's lower bound>,
    right: &lt;Element's rightmost bound>
    }

    getPageBox : function(getRegion) {
    var me = this,

    Why do they keep doing this (no pun intended)? If it is to save a few
    bytes, they are wasting time they could spend effecting reductions
    that would actually be significant (e.g. setting local references to
    repeatedly called Ext methods, which would also increase performance).

    el = me.dom,
    w = el.offsetWidth,
    h = el.offsetHeight,
    xy = me.getXY(),
    t = xy[1],
    r = xy[0] + w,
    b = xy[1] + h,
    l = xy[0];

    if (getRegion) {
    return new Ext.util.Region(t, r, b, l);
    }

    So if you want to use this method, you are stuck with Ext.util.Region
    (and all of its dependencies).

    else {
    return {
    left: l,
    top: t,
    width: w,
    height: h,
    right: r,
    bottom: b
    };
    }
    },

    /**
    * Translates the passed page coordinates into left/top css values
    for this element

    As mentioned, I severely doubt it.

    * @param {Number/Array} x The page x or an array containing [x,
    y]
    * @param {Number} y (optional) The page y, required if x is not
    an array
    * @return {Object} An object with left and top properties. e.g.
    {left: (value), top: (value)}
    */
    translatePoints : function(x, y) {
    y = isNaN(x[1]) ? y : x[1];
    x = isNaN(x[0]) ? x : x[0];

    I find the constant use of isNaN disturbing. Certainly more readable
    options are available.

    var me = this,
    relative = me.isStyle('position', 'relative'),
    o = me.getXY(),
    l = parseInt(me.getStyle('left'), 10),
    t = parseInt(me.getStyle('top'), 10);

    l = !isNaN(l) ? l : (relative ? 0 : me.dom.offsetLeft);
    t = !isNaN(t) ? t : (relative ? 0 : me.dom.offsetTop);

    return {left: (x - o[0] + l), top: (y - o[1] + t)};
    }

    Not a chance. And I'm really bitter that they fouled it up. :)

    addClass: function(className) {
    var me = this,
    i,
    len,
    v,
    cls = [];

    if (!Ext.isArray(className)) {

    D'oh! The near-constant use of isArray is also a giant red flag, due
    to the fact that it is impossible to write a reliable cross-browser
    isArray function. Of course, it's not as big a concern for a script
    that only aspires to support two browsers.

    if (className && !this.hasClass(className)) {
    me.dom.className += " " + className;
    }

    This has got to be straight out of ExtJS. They always end up with
    leading spaces in their class names.

    }
    else {
    for (i = 0, len = className.length; i < len; i++) {
    v = className;
    if (v && !me.hasClass(v)) {
    cls.push(v);
    }
    }
    if (cls.length) {
    me.dom.className += " " + cls.join(" ");
    }
    }
    return me;
    },

    /**
    * Removes one or more CSS classes from the element.
    * @param {String/Array} className The CSS class to remove, or an
    array of classes
    * @return {Ext.Element} this
    */
    removeClass: function(className) {
    var me = this,
    i,
    idx,
    len,
    cls,
    elClasses;
    if (!Ext.isArray(className)) {
    className = [className];
    }

    Backwards. How about:-

    if (typeof className == 'string') {

    No function call, no iffy isArray determination (and therefore no
    cross-browser worries) and no need for the awkard negative test (which
    seem to be everywhere in this script).

    /**
    * Checks if the specified CSS class exists on this element's DOM
    node.
    * @param {String} className The CSS class to check for
    * @return {Boolean} True if the class exists, else false
    */
    hasClass: function(className) {
    return className && (' ' + this.dom.className + ' ').indexOf('
    ' + className + ' ') != -1;
    },

    Unnecessary type conversion test, (lots of) unnecessary concatenation
    and only allows for spaces as delimiters.

    Suffice to say, it doesn't get any better from here. If this thing
    isn't completely rewritten in competent fashion, it's going to drop
    dead.
     
    David Mark, Jul 17, 2010
    #13
  14. David Mark

    RobG Guest

    On Jul 17, 12:01 pm, David Mark <> wrote:
    [...]
    > Now where was I?  Ah yes, the conditional augmentation of native
    > prototypes.


    I think you meant built-in prototypes (those of Object, String, etc.).
    Native prototypes (i.e. those of constructors created using
    javascript) are the only ones that should be augmented.


    --
    Rob
     
    RobG, Jul 17, 2010
    #14
  15. David Mark

    David Mark Guest

    On Jul 17, 9:55 am, RobG <> wrote:
    > On Jul 17, 12:01 pm, David Mark <> wrote:
    > [...]
    >
    > > Now where was I?  Ah yes, the conditional augmentation of native
    > > prototypes.

    >
    > I think you meant built-in prototypes (those of Object, String, etc.).
    > Native prototypes (i.e. those of constructors created using
    > javascript) are the only ones that should be augmented.
    >


    Yes. I meant the prototypes of built-ins like Number, String, etc.
    They didn't go so far as to augment Object.prototype, which would have
    played havoc with their unfiltered for-in loops.
     
    David Mark, Jul 17, 2010
    #15
  16. David Mark

    David Mark Guest

    On Jul 17, 6:28 am, Andrew Poulos <> wrote:
    > On 17/07/2010 12:01 PM, David Mark wrote:
    >
    > > On Jul 15, 11:38 pm, David Mark<>  wrote:
    > >> Sencha Touch is a bizarre mish-mash of ExtJS and a jQuery plug-in
    > >> called JQTouch.

    >
    > > Now where was I?  Ah yes, the conditional augmentation of native
    > > prototypes.

    >
    > What gets me is that even though it must be quite emotionally hurtful to
    > have something (that they are probably quite proud of) criticised in
    > such a strident manner they never appear to even acknowledge the
    > validity or otherwise of the comments nor to take any steps towards
    > addressing them.


    The authors of such efforts appear to work in a parallel universe
    where their ignorance is seen as "pragmatism" (see Dojo). They
    dismiss any and all technical criticism as the bitter ravings of those
    who "write everything from scratch".

    >
    > It would be heartening to read something like "yes, you're right but
    > we're working to improve".
    >


    When I posted a few of these comments below their Ajaxian commercial,
    a couple of them showed up. But I don't think it was in an effort to
    learn as much as it was to try to save face. After all, they know
    their target market reads Ajaxian religiously.

    IIRC, the first guy to show up insinuated that I must not have much
    experience with mobile devices (LOL) and that sniffing the UA string
    was necessary for such agents (even to support two WebKit variations).

    Then the main author chimed in with some of the usual generalized non-
    arguments. "We're not perfect" comes to mind. Of course, there is a
    wide gap between perfection and failure. He also credited me for
    turning them on to some "optimizations". That's what the Dojo-ers
    said when I rewrote most of their crap. It's an attempt to
    marginalize the input and allow them to use the suggestions without
    giving away any significant credit. And then there is the time-worn
    "gee, that must have taken a lot of time", which tries to paint their
    simple efforts as impossibly intricate and excuse their shortcomings
    as the result of very busy schedules. I take that last one as an
    attempt at a sly insult.

    So the "major" GP library developers don't show up here to defend
    their decisions because they know they have no answers. They
    generally don't ask questions because that would cause debate about
    their own credentials (after all, aren't they supposed to have all of
    the answers?) What they do is damage control, insulting critics,
    questioning their motivations and eventually copying whatever bits
    they can grasp (see jQuery).

    And their fans, who worship these people like almighty saviors, are
    typically happy to go along with such charades (as opposed to actually
    trying to learn something). After all, if their "gods" turn out to be
    false idols, where does that leave them? Basically looking foolish
    and with a ton of catch-up work ahead of them. It's easier to accept
    thin rationalizations that preserve their collective fantasies.
     
    David Mark, Jul 17, 2010
    #16
  17. David Mark

    David Mark Guest

    On Jul 17, 6:28 am, Andrew Poulos <> wrote:

    [...]

    >
    > It would be heartening to read something like "yes, you're right but
    > we're working to improve".
    >


    Revisiting the rest of this thing, ISTM that they would have to first
    learn a lot more about browser scripting and then rewrite the whole
    thing from scratch. I mean, if there are glaring errors,
    misconceptions and design missteps in virtually every function, it
    indicates that most proficient of those involved is in over their
    head.

    /**
    * Normalizes currentStyle and computedStyle.

    No it doesn't, The currentStyle bit was cropped out as it is only
    needed for IE.

    * @param {String} property The style property whose value is
    returned.
    * @return {String} The current value of the style property for
    this element.
    */
    getStyle: function(prop) {
    var dom = this.dom,
    value,
    computedStyle,
    result,
    display;

    if (dom == document) {
    return null;
    }

    That's ridiculous. If the application passes a reference to a
    document node to this function, the application has a problem (which
    needs to be tracked down). The null return value is needed to
    represent other (more expected) calamities (like elements with a
    display style of "none" or any number of possibilities in IE).

    prop = Ext.Element.normalize(prop);

    result = (value = dom.style[prop]) ? value : (computedStyle =
    window.getComputedStyle(dom, null)) ? computedStyle[prop] : null;

    First off, you don't use the inline style, except as a last resort.
    It may well be something like "30%" or "3em" (according to the above
    comments this function seeks to "normalize" computed/current styles).

    Second, using window.getComputedStyle is simply wrong. The method is
    to be found on the document.defaultView object, which by coincidence
    often references the window object.

    Third the "concise" nested ternary operations with assignments is a
    pattern only a "Jorge" could love.

    Instead:-

    computedStyle = document.defaultView.getComputedStyle(dom, null));

    if (computedStyle) {
    computedStyle = computedStyle[prop];
    }

    if (!computedStyle) {
    computedStyle = dom.style[prop] || null;
    }

    Of course, the last bit isn't really needed as it won't come into play
    unless the element has a display style of "none" (in which case the
    application developer has made a mistake).

    // Fix bug caused by this: https://bugs.webkit.org/show_bug.cgi?id=13343

    Yes, WebKit has at least a couple of problems with right margins.

    if (Ext.platform.hasRightMarginBug && marginRightRe.test(prop)
    && out != '0px') {

    That flag (hasRightMarginBug) is clearly from ExtJS (and almost
    certainly set by a UA sniff). It is not set anywhere in this script.

    This is the sort of issue that is to be designed around. Cross-
    browser designs based on retrieving accurate computed style values are
    flawed from the start. This is especially true for margins, which may
    be collapsed (though not the case for horizontal margins). To
    determine a horizontal (left/right) margin in pixels, I imagine I
    would set the appropriate style to "0" and check if the offsetLeft
    changed. Personally, I've never had a cause to do this in any
    context.

    Of course for an ostensibly cross-browser, GP framework, you can't
    design around anything. You've got to try to cram in every solution
    to every problem to suit every context (which is inherently
    inappropriate for software that must be downloaded).

    These are the hardest scripts to write and virtually impossible to get
    100% correct. This is why only newcomers attempt them, making the
    resulting failures easily predictable. What's troubling is that the
    starry-eyed neophytes typically refuse to admit defeat, instead opting
    to hide their unrealized designs behind browser sniffing (and
    asserting not to care about browsers, old, unknown or yet to be
    created that break such ill-advised inferences). That's why the
    notion of users changing their UA strings makes them so
    uncomfortable. If only they realized that it is the browser sniffing
    scripts that force users to do so (i.e. they are the problem, not the
    savvy users).

    http://www.jibbering.com/faq/notes/detect-browser/

    display = this.getStyle('display');

    No good. The correct line for this occasion is:-

    display = el.style.display;

    el.style.display = 'inline-block';
    result = view.getComputedStyle(el, '');
    el.style.display = display;

    See what I mean? Imagine if the inline display style is not specified
    (fairly typical). And consider that this script uses classes to hide
    elements. If this code were ever executed, there's a good possibility
    that an inline style will be set (where none existed before) and the
    element will rebuff all future attempts by the framework to hide it.
    Alternatively, that last line may end up trying to set an inline style
    of "null" (good for a warning or exception, depending on the browser).

    }

    // Webkit returns rgb values for transparent.

    So what? The script only endeavors to support WebKit. As for
    normalization, the rgb format is far more useful for a script as it
    matches the other umpteen billion color/opacity combinations.

    if (result == 'rgba(0, 0, 0, 0)') {
    result = 'transparent';
    }

    return result;
    },

    /**
    * Wrapper for setting style properties, also takes single object
    parameter of multiple styles.
    * @param {String/Object} property The style property to be set,
    or an object of multiple styles.
    * @param {String} value (optional) The value to apply to the
    given property, or null if an object was passed.
    * @return {Ext.Element} this
    */
    setStyle: function(prop, value) {
    var tmp,
    style;

    if (!Ext.isObject(prop)) {

    Again, try this:-

    if (typeof prop == 'string') {

    No function call, no property lookup and no negative assertion. Use a
    "constant" and it will minify to something like:-

    if(typeof a==b){

    ....which is shorter than:-

    if(!Ext.isObject(a)){

    tmp = {};
    tmp[prop] = value;
    prop = tmp;
    }

    for (style in prop) {

    Forgot the filter again.

    value = prop[style];
    style = Ext.Element.normalize(style);
    this.dom.style[style] = value;

    That's a lot of extra work each time through (glohal identifier
    resolution and property lookups). Each function call opens the door
    for a reflow/repaint as well.

    }

    return this;
    },

    /**
    * <p>Returns the dimensions of the element available to lay
    content out in.<p>

    Available to lay content out in?

    * <p>If the element (or any ancestor element) has CSS style
    <code>display : none</code>, the dimensions will be zero.</p>
    */
    getViewSize: function() {
    var doc = document,
    dom = this.dom;

    if (dom == doc || dom == doc.body) {
    return {
    width: Ext.Element.getViewportWidth(),
    height: Ext.Element.getViewportHeight()
    };
    }

    Ridiculous. The client dimensions of the body have nothing to do with
    the viewport dimensions (except in IE5 and IE quirks mode). Some
    browsers in quirks mode (stupidly) store the clientHeight/Width of the
    HTML element in those properties on the BODY in a botched attempt to
    copy IE's quirks mode implementation. Yes, really. :)

    http://www.cinsoft.net/viewport.asp

    So here we have library authors misinterpreting a misinterpretation of
    a ten-year-old MS standard.

    Given how screwed up the non-IE browsers are in this respect, if you
    really had a need to find the client dimensions of the BODY (hard to
    imagine), you would need to subtract the border dimensions from its
    offsetHeight/Width.

    else {
    return {
    width: dom.clientWidth,
    height: dom.clientHeight
    };
    }
    },

    So this method retrieves the clientHeight/Width of an element, except
    for the BODY which returns window.innerHeight/Width. I suppose with
    the Ext CSS reset in place, that might just pass superficial testing,
    despite being completely wrong. This is why I dismiss the "show me
    where it fails" mentality. If you don't understand what you are
    doing, there is always the possibility of guessing and stumbling on to
    an "answer" that appears to work in *some* cases (see also "we don't
    care about other cases").

    /**
    * Forces the browser to repaint this element

    Browsers repaint elements when they are damned good and ready. The
    presence of a function like this indicates an attempt to solve a
    problem created elsewhere in the script (and likely due to a
    misunderstanding of how/when browsers reflow/repaint content). And
    this is the second such function encountered in this script.

    * @return {Ext.Element} this
    */
    repaint: function() {
    var dom = this.dom;
    this.addClass("x-repaint");
    dom.style.background = 'transparent none';
    setTimeout(function() {
    dom.style.background = null;

    Dear Christ. They actually set a style to null *on purpose* (earlier
    it was pointed out that they left the door open for this to happen by
    accident).

    Am I being to hard on them? Remember, they intend to charge money for
    this tripe (and have already used it to induce investors to fork over
    millions). It's well-known that jQuery (and especially its plug-ins)
    are awful, but I'd sooner use those. At least they are free.

    Ext.get(dom).removeClass("x-repaint");
    },
    1);
    return this;
    },

    /**
    * Retrieves the width of the element accounting for the left and
    right
    * margins.
    */
    getOuterWidth: function() {
    return this.getWidth() + this.getMargin('lr');
    },

    How about:-

    return this.dom.offsetWidth + ...

    Function calls are *expensive* and mobile devices don't have resources
    to burn.

    // private

    Nope. :)

    sumStyles: function(sides, styles) {
    var val = 0,
    m = sides.match(/\w/g),

    Why not just split on spaces?

    len = m.length,
    s,
    i;

    for (i = 0; i < len; i++) {
    s = m && parseInt(this.getStyle(styles[m]), 10);

    As mentioned previously, this can result in a round-off error. Use
    parseFloat.

    if (s) {
    val += Math.abs(s);
    }

    I guess they don't like negative margins. :)

    }
    return val;
    }

    And so on and so on (and scooby dooby dooby).

    Skipping past more everyday code to try to find something close to
    resembling HTML5...

    if (Ext.platform.isPhone) {
    cfg = {
    tag: 'embed',
    type: 'audio/mpeg',
    target: 'myself',
    src: this.src || this.url,
    controls: 'true'
    };
    } else {
    cfg = {
    tag: 'audio',
    src: this.src || this.url
    };
    }

    That represents virtually the entire "HTML5" audio bit. This is
    Ext.platform.isPhone:-

    isPhone: /android|iphone/i.test(Ext.userAgent) && !(/ipad/
    i.test(Ext.userAgent)),

    As mentioned, this thing only *attempts* to work in two types of
    phones (90% of the market according to some unidentified study) plus
    one tablet. Still, the above code assumes that all iPhones/Androids
    (past, present and future) are better off with a non-standard EMBED
    element. My guess is they didn't like the way AUDIO elements take up
    the entire screen when played on these devices (but that's what users
    expect them to do).

    This unfortunate "isPhone" heuristic is also used to style the body.

    if (Ext.platform.isPhone) {
    cls.push('x-phone');
    }

    Who needs media queries?

    I don't see any reason to mince words. This thing stinks. You'd have
    to be insane to use it on a mobile Website. Using it to create a faux
    native app is ill-advised as well. The "Sencha" name got the green
    part right, but this is almost (but not entirely) unlike tea. :)
     
    David Mark, Jul 18, 2010
    #17
  18. On 2010-07-17 06:25 PM, David Mark wrote:
    > On Jul 17, 6:28 am, Andrew Poulos<> wrote:
    >
    > [...]
    >
    >>
    >> It would be heartening to read something like "yes, you're right but
    >> we're working to improve".
    >>

    >
    > Revisiting the rest of this thing, ISTM that they would have to first
    > learn a lot more about browser scripting and then rewrite the whole
    > thing from scratch. I mean, if there are glaring errors,
    > misconceptions and design missteps in virtually every function, it
    > indicates that most proficient of those involved is in over their
    > head.
    >


    [...]

    >
    > /**
    > * Forces the browser to repaint this element
    >


    The name "repaint" has the outward indication of a mystical incantation.
    We know that there is no way to force a repaint, and so when I see a
    name like that, I know that the method won't directly cause the browser
    to repaint and that it will, at best, perform an unrelated action that
    was associated with addressing a perceived problem.

    > Browsers repaint elements when they are damned good and ready. The
    > presence of a function like this indicates an attempt to solve a
    > problem created elsewhere in the script (and likely due to a
    > misunderstanding of how/when browsers reflow/repaint content). And
    > this is the second such function encountered in this script.
    >



    > * @return {Ext.Element} this
    > */
    > repaint: function() {
    > var dom = this.dom;
    > this.addClass("x-repaint");
    > dom.style.background = 'transparent none';
    > setTimeout(function() {
    > dom.style.background = null;
    >


    Neither null nor "null" are a valid value for background.

    DOM 2 Style defines what must happen when the display property is set:
    <http://www.w3.org/TR/1998/REC-CSS2-19980512/visuren.html#propdef-display>

    | display of type DOMString
    | See the /_background property definition_/ in CSS2.
    | Exceptions on setting
    | DOMException
    |
    |
    | SYNTAX_ERR: Raised if the new value has a syntax error and is
    | unparsable.

    That says that a SYNTAX_ERR is if the new value is unparseable, and to
    determine if the value `null` is parseable (it isn't, but just in case
    that was not blatantly obvious), the reader is directed to the
    definition in CSS 2 which is linked from the text "/_background property
    definition_/" links to DOM 2 Style:
    <http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSS2Properties-background>

    Looking at CSS2:
    | 'background'
    | Value: [<'background-color'> || <'background-image'> ||
    | <'background-repeat'> || <'background-attachment'> || <'background-
    | position'>] | inherit

    And so it is clear that neither null nor "null" are valid property
    values. Setting `element.style.display = null`, if the value `null` is
    interpreted as the string value "null", then it should raise a SYNTAX_ERR.

    That error will happen in IE but since IE is not supported they don't
    care. That exception won't happen in webkit so they get away with it there.

    [...]

    > native app is ill-advised as well. The "Sencha" name got the green
    > part right,


    That's actually funny.

    Sencha, or Ext for TouchScreen devices, supports only a couple devices,
    and at a nearly 500k, what does it do?

    One might look to the documentation but the documentation is for Ext-JS
    and the code for Sencha is largely different.

    As various parts of Sencha have been discussed, the query engine has not
    yet been mentioned. Of all of the javascript query engines I have
    reviewed, Ext-JS is hands down, the worst (and by a very large margin).
    The problems with the query engine depend on the version of Ext-JS go
    back and forth depending on the version of Ext. The latest version uses
    NFD (native first, dual) approach. I'll detail more on these, as well as
    the NFD query antipattern, in a future post. For now, lets have a look
    at the query engine for Sencha.

    The current release of Sencha's query selector uses only
    document.querySelectorAll, and supports none of the extensions that are
    supported by other version of Ext-JS. Since Sencha splits input on ","
    first, it breaks on any selector that contains a comma, such as
    [title="Hey, Joe"].

    These problems in the source code should be easy for anyone to see.

    Splitting input on "," creates two significant problems, actually.

    The first problem is that it creates invalid selectors out of any
    perfectly valid selector that contains a comma. For example, Sencha will
    convert the selector '[title="Hey, Joe"]' to '[title="Hey,' and ' Joe"],
    both of which are invalid. Sencha then passes each item to
    document.querySelectorAll which throws an uncaught error on the invalid
    '[title="Hey,' selector.

    The second problem is that when it "works", the result can contain
    duplicates.

    For example, for a document that contains three divs:

    <body>
    <div></div> <div></div> <div></div>
    </body>

    The following code:
    [Ext.query("div").length , Ext.query("div, div").length]

    - results [3, 6]

    My code comments below are annotated with (GS), as in
    // (GS) A review comment left by Garrett Smith.

    Code review begins:

    /**
    * Selects a group of elements.
    * @param {String} selector The selector/xpath query (can be a comma
    * separated list of selectors)
    * @param {Node/String} root (optional) The start of the query
    * (defaults to document).
    * @return {Array} An Array of DOM elements which match the selector.
    * If there are no matches, and empty Array is returned.
    */
    select : function(q, root) {
    var results = [],
    nodes,
    i,
    j,
    qlen,
    nlen;

    root = root || document;
    if (typeof root == 'string') {
    // (GS) This call may return null.
    root = document.getElementById(root);
    }

    // (GS) splitting the input on "," will break lexical rules and
    // (GS) will match any simple selector that has a comma in it.
    q = q.split(",");
    for (i = 0, qlen = q.length; i < qlen; i++) {
    if (typeof q == 'string') {
    // (GS) If root is null, an error will result.
    nodes = root.querySelectorAll(q);

    for (j = 0, nlen = nodes.length; j < nlen; j++) {
    results.push(nodes[j]);
    }
    }
    }
    return results;
    },

    As seen in the results, selectors that are separated by a comma are
    added to the results. After reading the code, it is clear that the code
    does exactly what should be expected of it.

    There is no apparent reason for such design decision; the results are
    surprising and probably undesirable for most. This appears to be a yet
    another careless mistake and one that adds the overhead of creating an
    array and looping through the result.

    Misleading Comment
    The code comment documents the selector param as a selector/xpath query.
    That is misleading because the code is not designed to handle XPath
    expressions. Method document.querySelectorAll uses CSS Selectors. It
    will throw errors on any invalid syntax. There are a couple syntax
    similiarties between XPath and CSS Selectors, however the differences
    between the two are much greater. XPath expressions and CSS Selectors
    are represented by different standards.

    Since Sencha uses document.querySelectorAll, it can be assured that an
    error will occur when using XPath. Ext.query("//foo"); will result in an
    error being thrown.

    Bigger is Better?
    At nearly 500k, with comments stripped, the core of Sencha is larger
    than jQuery and YUI combined. The drawbacks to such a large codebase on
    mobile device that has a web browser include: slow download times, extra
    cost to end user (depends on plan, connection and roaming charges),
    memory and processing overhead of interpreting the javascript and
    keeping it in memory, and filling or exceed a browser's cache-limit.

    Despite the size, Sencha is only supported on a few browsers and only on
    those browsers that have native NodeSelector support. Despite those
    limitations, it still manages to introduce more bugs than the browsers
    provide.

    Other Browsers
    Sencha is apparently not intended to be used on any version of Internet
    Explorer. By including sencha js on a page, errors are thrown in
    Internet Explorer due to calling document.addEventListener.
    --
    Garrett
     
    Garrett Smith, Jul 18, 2010
    #18
  19. David Mark

    David Mark Guest

    On Jul 18, 2:18 am, Garrett Smith <> wrote:

    [...]

    >
    > That error will happen in IE but since IE is not supported they don't
    > care. That exception won't happen in webkit so they get away with it there.


    Yes, this is yet another case of script developers hiding (current or
    potential) problems from *themselves*. I cringe every time I hear "I
    don't care about browser XYZ" or "Nobody uses browser XYZ" as an
    excuse for limited testing or slovenly feature detection. The former
    of which is like testing a new car design exclusively on freshly paved
    highways. You have to go off-road to conduct a proper stress-test.
    And why is it always the most inexperienced developers (i.e. the ones
    who would most benefit) who spout such drivel? For example, about a
    year back I had some snot-nose nastily asking me why I was "wasting
    time" loading a test page in IE7. (!) How much fucking time does it
    take to load a page and note whether or not it throws an exception?
    Predictably their subsequent "effort" threw exceptions in IE7 (and IE6
    and IE5 and IE8 compatibility mode and God knows what else), wasting
    the time of countless end-users. And the punchline is that the
    project was a credit card form, so the oversight certainly cost them
    some sales (not to mention embarrassment).

    >
    > [...]
    >
    > > native app is ill-advised as well.  The "Sencha" name got the green
    > > part right,

    >
    > That's actually funny.


    I'm a funny guy.

    >
    > Sencha, or Ext for TouchScreen devices, supports only a couple devices,
    > and at a nearly 500k, what does it do?


    So as not to cause confusion, I prefer to compare minified sizes (and
    I can't see penalizing scripts for using long variable names). It's
    bad enough that marketers report sizes after compression. I assume
    you are referring to the size with white space and without comments.
    Of course, it is 228K minified, but the CSS and graphics easily push
    the payload over 500K. Add the application script, markup and assets
    and the total will approach 1MB. The ExtJS camp say to just use a
    manifest (as if phones have unlimited room to store such
    monstrosities). And due to the browser sniffing in the script and the
    ever-changing mobile environments, "upgrades" are likely to be
    frequent, requiring end-users to re-download this crap endlessly.

    JFTR, I know from experience that you can do much of the flashy "CSS3"
    stuff seen in the Sencha demos with 0K of script (and without the
    ridiculous CSS "resets" and monolithic "themes" that they are
    pushing).

    >
    > One might look to the documentation but the documentation is for Ext-JS
    > and the code for Sencha is largely different.


    Yes, it is an unlikely (and unwieldy) marriage of ExtJS and JQTouch.
    There's a match made in hell.

    >
    > As various parts of Sencha have been discussed, the query engine has not
    > yet been mentioned.


    I think I mentioned at some point that it was simply a QSA wrapper
    (and not a very good one).

    > Of all of the javascript query engines I have
    > reviewed, Ext-JS is hands down, the worst (and by a very large margin).


    I recently went through the (much) bigger version and it is the usual
    crap. Do all of these developers work in sound-proof booths with
    blinders on? That can't be as most of the same mistakes show up in
    all of them (indicating they copy one another). But none of them read
    (or search) this newsgroup; that's for sure.

    > The problems with the query engine depend on the version of Ext-JS go
    > back and forth depending on the version of Ext.


    Sounds like jQuery. It's because they are using guesswork rather than
    understanding and then patching problems as they are reported. If
    their patches break last year's browser they just cross that browser
    off the "supported" list rather than trying to see where they went
    wrong. It's laughable as these query engines boil down to basic
    string parsing and DOM traversal, so should work in virtually any
    browser released in the last five years (and many older ones). You
    sure can't offer a clean degradation path for "ancient" or unforeseen
    agents if your core logic (on which everything hinges) throws
    exceptions and/or returns incorrect results in Opera 9. But then, the
    developers stopped "caring" about Opera 9 as soon as their patchworks
    stopped working in it (see also Dojo).

    > The latest version uses
    > NFD (native first, dual) approach.


    The big one? The "Touch" version uses QSA only. The "dual" approach
    is obviously flawed (as recounted numerous times) as the old
    patchworks vary wildly from QSA. In other words, "Sizzle" was/is a
    complete fraud. It's like using an MS SQL Server database, except
    when it is down, then routing queries to some buggy, incompatible open-
    source piece of shit maintained by "DB Ninjas".

    > I'll detail more on these, as well as
    > the NFD query antipattern, in a future post.


    It may not have had a name, but the pattern has long since been outed
    as bunk. Trouble is that library devotees don't listen. Try to
    explain any of this stuff to them and they start bleating about
    reinventing wheels and assembly language (see Kenny).

    > For now, lets have a look
    > at the query engine for Sencha.
    >
    > The current release of Sencha's query selector uses only
    > document.querySelectorAll, and supports none of the extensions that are
    > supported by other version of Ext-JS. Since Sencha splits input on ","
    > first, it breaks on any selector that contains a comma, such as
    > [title="Hey, Joe"].


    It makes me wonder why they are splitting in the first place. Likely
    a holdover from the bigger version. That's the sort of thing that
    happens when "programmers" rearrange patterns of code without
    understanding them.

    >
    > These problems in the source code should be easy for anyone to see.
    >
    > Splitting input on "," creates two significant problems, actually.
    >
    > The first problem is that it creates invalid selectors out of any
    > perfectly valid selector that contains a comma. For example, Sencha will
    > convert the selector '[title="Hey, Joe"]' to '[title="Hey,' and ' Joe"],
    > both of which are invalid. Sencha then passes each item to
    > document.querySelectorAll which throws an uncaught error on the invalid
    > '[title="Hey,' selector.


    Oh for Christ's sake; that's right. They didn't even bother to wrap
    the QSA call in a try-catch. Probably too elitist for them. Such
    incompetence makes me bitter (and jealous). :)

    >
    > The second problem is that when it "works", the result can contain
    > duplicates.


    Of course.

    >
    > For example, for a document that contains three divs:
    >
    > <body>
    >    <div></div>  <div></div>  <div></div>
    > </body>
    >
    > The following code:
    > [Ext.query("div").length , Ext.query("div, div").length]
    >
    > - results [3, 6]


    Doesn't get much worse than that. :(

    >
    > My code comments below are annotated with (GS), as in
    > // (GS) A review comment left by Garrett Smith.
    >
    > Code review begins:
    >
    > /**
    >   * Selects a group of elements.
    >   * @param {String} selector The selector/xpath query (can be a comma
    >   * separated list of selectors)


    As noted, that's pure fantasy (or complete ignorance).

    >   * @param {Node/String} root (optional) The start of the query
    >   * (defaults to document).
    >   * @return {Array} An Array of DOM elements which match the selector.
    >   * If there are no matches, and empty Array is returned.
    >   */
    > select : function(q, root) {
    >      var results = [],
    >          nodes,
    >          i,
    >          j,
    >          qlen,
    >          nlen;
    >
    >      root = root || document;
    >      if (typeof root == 'string') {
    >          // (GS) This call may return null.
    >          root = document.getElementById(root);
    >      }
    >
    >      // (GS) splitting the input on "," will break lexical rules and
    >      // (GS) will match any simple selector that has a comma in it.
    >      q = q.split(",");
    >      for (i = 0, qlen = q.length; i < qlen; i++) {
    >          if (typeof q == 'string') {
    >              // (GS) If root is null, an error will result.
    >              nodes = root.querySelectorAll(q);
    >
    >              for (j = 0, nlen = nodes.length; j < nlen;j++) {
    >                  results.push(nodes[j]);
    >              }
    >          }
    >      }
    >      return results;
    >
    > },
    >
    > As seen in the results, selectors that are separated by a comma are
    > added to the results. After reading the code, it is clear that the code
    > does exactly what should be expected of it.


    Yes. It shouldn't take an "elitist" in an "ivory tower" to spot
    that. If writing a QSA wrapper was a homework assignment for a first-
    year CS student, this code would certainly result in a 0.

    >
    > There is no apparent reason for such design decision; the results are
    > surprising and probably undesirable for most.


    Probably?!

    > This appears to be a yet
    > another careless mistake and one that adds the overhead of creating an
    > array and looping through the result.


    All for no reason, unless they were literally *trying* to fall flat on
    their face.

    >
    > Misleading Comment
    > The code comment documents the selector param as a selector/xpath query.


    Hard to tell whether that is a misconception or a copy/paste mistake.
    That's the problem with "technical" writers who don't speak the
    language (see scope, thread, literal, private, class, singleton, etc.)

    > That is misleading because the code is not designed to handle XPath
    > expressions. Method document.querySelectorAll uses CSS Selectors. It
    > will throw errors on any invalid syntax. There are a couple syntax
    > similiarties between XPath and CSS Selectors, however the differences
    > between the two are much greater. XPath expressions and CSS Selectors
    > are represented by different standards.
    >
    > Since Sencha uses document.querySelectorAll, it can be assured that an
    > error will occur when using XPath.


    An uncaught error no less. Odd considering their neurotic type-
    checking tendencies. This is one case where they definitely needed to
    handle exceptions due to variations in QSA implementations.

    > Ext.query("//foo"); will result in an
    > error being thrown.
    >
    > Bigger is Better?
    > At nearly 500k, with comments stripped, the core of Sencha is larger
    > than jQuery and YUI combined.


    But it's much smaller if you GZIP the files! I've seen it described
    as a "svelte" 80K which the clueless blogger found "amazing" given its
    "unparalleled" feature set. And last I checked, the full build of My
    Library was a little over half that.

    > The drawbacks to such a large codebase on
    > mobile device that has a web browser include: slow download times, extra
    > cost to end user (depends on plan, connection and roaming charges),
    > memory and processing overhead of interpreting the javascript and
    > keeping it in memory, and filling or exceed a browser's cache-limit.


    Yes, even with a magic manifest.

    >
    > Despite the size, Sencha is only supported on a few browsers and only on
    > those browsers that have native NodeSelector support. Despite those
    > limitations, it still manages to introduce more bugs than the browsers
    > provide.


    Yes, it clearly creates more problems than it solves. But just look
    at those cool graphics! And (from the Ajaxian infomercial) two guys
    dressed like Obi-wan Kenobi can't be wrong. :)

    >
    > Other Browsers
    > Sencha is apparently not intended to be used on any version of Internet
    > Explorer.


    Or anything besides WebKit. Inexplicably, they equate proprietary
    WebKit extensions with CSS3. Odd choice considering the fact that the
    latest Opera and Firefox support most of the same stuff (including
    transitions).

    > By including sencha js on a page, errors are thrown in
    > Internet Explorer due to calling document.addEventListener.


    Yes, that's one of many reasons it won't run in any MSHTML-based user
    agents. I guess they wasted so much space that they didn't have room
    to fit in a call to attachEvent.

    I've got an HTML5 audio add-on and video would require very similar
    code (perhaps I'll combine them). Things like localStorage and
    geolocation are trivial. And they left out a host of (real) HTML5
    features too. I will have to make some time to "catch up" on these
    fronts. Certainly I have plenty of room for such add-ons.
    Prospective testers should contact me...
     
    David Mark, Jul 18, 2010
    #19
  20. David Mark

    David Mark Guest

    On Jul 18, 9:10 am, kangax <> wrote:
    > On 7/18/10 2:18 AM, Garrett Smith wrote:
    >
    > > On 2010-07-17 06:25 PM, David Mark wrote:

    > [...]
    >
    > >> /**
    > >> * Forces the browser to repaint this element

    >
    > > The name "repaint" has the outward indication of a mystical incantation..
    > > We know that there is no way to force a repaint, and so when I see a
    > > name like that, I know that the method won't directly cause the browser
    > > to repaint and that it will, at best, perform an unrelated action that
    > > was associated with addressing a perceived problem.

    >
    > I'm not sure where you coming from with this.
    >
    > There certainly are observable ways to trigger both — reflow and
    > repaint; at least in WebKit (as that's the layout engine being discussed
    > here).


    It's certainly fairly predictable.

    >
    > In Chrome you can use Speed Tracer
    > (<http://code.google.com/webtoolkit/speedtracer/>, developed by Google
    > themselves, IIRC) to take a peek into when browser reflows the document
    > and when it repaints the screen.


    It should be noted that is but one flavor of WebKit. It's a desktop
    version as well, so may behave in a slightly different manner than
    mobile variations.

    >
    > Try something like this, to see both — reflow and repaing hapenning at
    > ~3085ms:


    Well sure changing the style rules at 3000ms will cause the browser to
    reflow/repaint at some time shortly after 3000ms from current. At
    least under normal circumstances.

    >
    > <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
    >    "http://www.w3.org/TR/html4/strict.dtd">
    > <html>
    >    <head>
    >      <title></title>
    >      <style type="text/css">
    >        #test { width: 100px; background: red; }
    >      </style>
    >    </head>
    >    <body>
    >      <div id="test">test</div>
    >      <script type="text/javascript">
    >        setTimeout(function() {
    >          document.styleSheets[0].addRule('#test', 'width: 200px');
    >        }, 3000);
    >      </script>
    >    </body>
    > </html>
    >
    > [...]
    >
    > Or am I missing something?
    >


    Yes; the code in question seems to assert that it can make the browser
    reflow/repaint at a specific point in the execution. And it doesn't
    change the style rules, but does the styling equivalent of a no-op.
     
    David Mark, Jul 18, 2010
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Rob R. Ainscough
    Replies:
    1
    Views:
    513
    intrader
    Jun 25, 2005
  2. =?Utf-8?B?TWFuc28=?=

    Multiple browsers support and themes

    =?Utf-8?B?TWFuc28=?=, Mar 22, 2006, in forum: ASP .Net
    Replies:
    0
    Views:
    388
    =?Utf-8?B?TWFuc28=?=
    Mar 22, 2006
  3. El Kabong

    Browsers, browsers! Quo vadis?

    El Kabong, May 11, 2007, in forum: HTML
    Replies:
    23
    Views:
    945
    dorayme
    May 13, 2007
  4. Han Holl
    Replies:
    4
    Views:
    367
    Nobuyoshi Nakada
    Oct 12, 2006
  5. Tim W
    Replies:
    11
    Views:
    848
    Hot-Text
    Aug 8, 2012
Loading...

Share This Page