Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

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

953 views
Skip to first unread message

David Mark

unread,
Jul 15, 2010, 11:38:13 PM7/15/10
to
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.
lice...@sencha.com
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[i];
};
}

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[i], array[i], i, array) ===
false) {

Why would they set - this - to array[i]? 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[i];
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[i];
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? :)

Garrett Smith

unread,
Jul 16, 2010, 1:28:00 AM7/16/10
to
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

RobG

unread,
Jul 16, 2010, 2:16:19 AM7/16/10
to
On Jul 16, 1:38 pm, David Mark <dmark.cins...@gmail.com> 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

David Mark

unread,
Jul 16, 2010, 2:31:09 AM7/16/10
to
On Jul 16, 1:28 am, Garrett Smith <dhtmlkitc...@gmail.com> 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

unread,
Jul 16, 2010, 2:50:51 AM7/16/10
to
On Jul 16, 2:16 am, RobG <rg...@iinet.net.au> wrote:
> On Jul 16, 1:38 pm, David Mark <dmark.cins...@gmail.com> 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? :)

RobG

unread,
Jul 16, 2010, 8:34:10 AM7/16/10
to
On Jul 16, 4:50 pm, David Mark <dmark.cins...@gmail.com> wrote:
> On Jul 16, 2:16 am, RobG <rg...@iinet.net.au> wrote:
>
> > On Jul 16, 1:38 pm, David Mark <dmark.cins...@gmail.com> 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/development-frameworks/possible-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

KCL

unread,
Jul 16, 2010, 10:10:34 AM7/16/10
to


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.

john

unread,
Jul 16, 2010, 12:05:30 PM7/16/10
to
On 16 Jul 9:10 AM, KCL wrote:
> On Jul 15, 10:38 pm, David Mark<dmark.cins...@gmail.com> 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".

Richard Cornford

unread,
Jul 16, 2010, 1:16:20 PM7/16/10
to
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.
<snip>

>> 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"?

Unlikely, in browser scripting the concept is far too vague (and the
term applied too loosely) for the set of things included not to cover at
least something that is acceptable to anyone in some way.

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

Yes, but that is not going to do you much good as it is a framework for
a particular type of web application (so will not suite other types) and
it is not available for outside use (and would only be commercially
available if it were).

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

David Mark is probably the wrong person to ask that question.

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

It didn't look like it need much time, or to achieve any depth. Just
copy the source text and work down it inserting comments on the things
that stand out. When the first line of code is a 'fix' for pre-ECMA 262
3rd edition browsers (a standard that came out in 1999 and where the
most recent browser that needed the 'fix' is IE 4, in a system that does
not support IE in any version) then you don't need depth to see fault.

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

The notion of the individual who hand codes every line from scratch is
an illusion. He is held up to suggest a polarized landscape where one
extreme is populated by self flagellating zealots, who are so clearly
insane that no credence can be given to anything they say. In reality,
even if an individual has no CS/programming training/experience and
starts out completely on their own wringing scripts into HTML documents
and seeing what they do in various browsers, they are going to find
themselves copying blocks of code from one place, or one document, and
pasting them into another. And if they are going to achieve anything
useful in the long run they are going to quickly learn to appreciate
code re-use, and soon design with the anticipation of code re-use. And
any previous experience with programming, or formal training, and they
will likely be designing for easy re-use from the outset.

Personally, I have been writing about and discussing strategies to
maximise the efficiency of code re-use in browser scripting, publishing
examples and testing my ideas in my work for more than half a decade. My
ideas in this regard do not lead to the large scale interdependent
general purpose browser scripting libraries (that is where my thinking
started nearly a decade ago, and is the thing I have been moving away
from ever since). Instead they were directed toward the creation of
browser scripts as a hierarchical structure of loosely coupled modules
specified as interfaces, where particular interfaces may have numerous
implementations, none of which attempt to be more general than a
particular context calls for, but each suited to a different context.
Thus I avoid the bloat and performance hit associated with attempts to
be truly general; implementations of interfaces do not even need to
consider issues that are not part of the context in which they are used,
and if the issue is in the context a different implementation of the
interface is used instead. Given this approach it is not too surprising
that I would be the person to introduce the "module pattern" back in
2003, as it is the ideal packaging unit for many of those interface
implementations.

This design strategy results in what is in effect a 'library' of
(easily, as in real life common contexts reoccur frequently) re-useable
code modules, but its concepts and architecture are quite difficult for
some to recognise as a 'library', it could not easily be packaged and
distributed, and indeed it is the intention of the design that the whole
never needs to be finished (in terms of creating an implementation of
every interface for every possible context, as some contexts are so
unlikely that I am unlikely to ever encounter them). The collected code
'library' is also not a framework, but it can be used to build
frameworks where they are needed, and those frameworks gain the
robustness of being made from well tried modules plus the possibility of
being well suited to their specific tasks/context.

Despite all that, and apparently because I occasionally make technical
comments about 'popular' general purpose libraries, there are plenty of
people who would like to characterise me as someone who 'writes
everything from scratch'.

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

It appears that while the "where is your ... general purpose browser
scripting library" is the response made by library authors to criticism
of their code up until the point where you publish such a library, from
that point onward the response switches to "its all just jealousy of our
popularity" and "your are only attacking us to promote your own
library". So its "damned if you do and damned if you don't", all the
time forgetting that a technical criticism stands or falls on its own
merits, (mostly[1]) independent of personal opinions.

As for "examples of alternatives"; one criticism relates to - isArray -,
but the group is littered with threads, long and short, devoted to
discriminating arrays from other things, proposals for array decimation
methods, criticisms of those proposals, counter proposals, other
object/primitive discrimination tasks, the handling of discrimination
tasks in general, and the avoidance of the need to handle discrimination
tasks. And given the breadth of those discussions would the example that
you would want to see accompanying the criticism be an example of an
alternative (and supposedly 'superior') - isArray - function or an
explanation of how to re-design the whole system in order to avoid the
need to make the discrimination, or something in between? In the event
that the originator of the criticism prefers an approach where you don't
design problems into a system unless you have a good way of solving
them, asking for the specifics of an alternative to accompany the
criticism might be asking quite a lot.

[1] Some criticisms made are actually opinion (even if widely/strongly
held). For example, a criticism of using - setTimeout( ... ); -,
commenting on the resolution of the identifier 'setTimeout', and
suggests using - window.setTimeout( ... ); - instead, does no more than
shift the identifier resolution issue to 'window'.

Richard.

David Mark

unread,
Jul 16, 2010, 1:37:01 PM7/16/10
to

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

Garrett Smith

unread,
Jul 16, 2010, 2:28:45 PM7/16/10
to
On 2010-07-15 11:31 PM, David Mark wrote:
> On Jul 16, 1:28 am, Garrett Smith<dhtmlkitc...@gmail.com> 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

David Mark

unread,
Jul 16, 2010, 2:40:20 PM7/16/10
to
On Jul 16, 2:28 pm, Garrett Smith <dhtmlkitc...@gmail.com> wrote:
> On 2010-07-15 11:31 PM, David Mark wrote:
>
> > On Jul 16, 1:28 am, Garrett Smith<dhtmlkitc...@gmail.com>  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

unread,
Jul 16, 2010, 3:14:34 PM7/16/10
to
On Jul 16, 12:05 pm, john <john.loves.spam...@gmail.com> wrote:
> On 16 Jul 9:10 AM, KCL wrote:
>
> > On Jul 15, 10:38 pm, David Mark<dmark.cins...@gmail.com>  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

unread,
Jul 16, 2010, 10:01:49 PM7/16/10
to
On Jul 15, 11:38 pm, David Mark <dmark.cins...@gmail.com> 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[i];
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.

Andrew Poulos

unread,
Jul 17, 2010, 6:28:37 AM7/17/10
to
On 17/07/2010 12:01 PM, David Mark wrote:
> On Jul 15, 11:38 pm, David Mark<dmark.cins...@gmail.com> 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.

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

Andrew Poulos

RobG

unread,
Jul 17, 2010, 9:55:01 AM7/17/10
to
On Jul 17, 12:01 pm, David Mark <dmark.cins...@gmail.com> 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

David Mark

unread,
Jul 17, 2010, 2:18:07 PM7/17/10
to

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

unread,
Jul 17, 2010, 2:59:15 PM7/17/10
to
On Jul 17, 6:28 am, Andrew Poulos <ap_p...@hotmail.com> wrote:
> On 17/07/2010 12:01 PM, David Mark wrote:
>
> > On Jul 15, 11:38 pm, David Mark<dmark.cins...@gmail.com>  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

unread,
Jul 17, 2010, 9:25:37 PM7/17/10
to
On Jul 17, 6:28 am, Andrew Poulos <ap_p...@hotmail.com> 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[i] && parseInt(this.getStyle(styles[m[i]]), 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. :)

Garrett Smith

unread,
Jul 18, 2010, 2:18:54 AM7/18/10
to
On 2010-07-17 06:25 PM, David Mark wrote:
> On Jul 17, 6:28 am, Andrew Poulos<ap_p...@hotmail.com> 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[i] == 'string') {
// (GS) If root is null, an error will result.
nodes = root.querySelectorAll(q[i]);

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

David Mark

unread,
Jul 18, 2010, 5:06:36 AM7/18/10
to
On Jul 18, 2:18 am, Garrett Smith <dhtmlkitc...@gmail.com> 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).

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

kangax

unread,
Jul 18, 2010, 9:10:26 AM7/18/10
to
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).

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.

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

<!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?

--
kangax

David Mark

unread,
Jul 18, 2010, 1:32:40 PM7/18/10
to
On Jul 18, 9:10 am, kangax <kan...@gmail.com> 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.

Garrett Smith

unread,
Jul 18, 2010, 4:22:58 PM7/18/10
to
On 2010-07-18 06: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.
>

Was there anything not right about that?

> There certainly are observable ways to trigger both — reflow and
> repaint; at least in WebKit (as that's the layout engine being discussed
> here).
>
> 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.
>

So there are things that have been associated with reflow an repaint.

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

[...]

A repaint occurring there wouldn't be surprising at all. The browser is
in a place where it it has new layout information and will need to queue
up a repaint. After the stack of execution contexts has completed would
be a good opportunity to do that recalc.

The recalc is not guaranteed there. What the code does to trigger a
recalc is probably pretty far from whatever it was that they perceived
as a need for a recalc.

>
> Or am I missing something?
>

I don't know. What's wrong with the criticism I provided?

Garrett

Garrett Smith

unread,
Jul 18, 2010, 5:18:55 PM7/18/10
to
On 2010-07-18 02:06 AM, David Mark wrote:
> On Jul 18, 2:18 am, Garrett Smith<dhtmlkitc...@gmail.com> 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

Improving quality reduces costs in the long run.

Testing more browsers improves quality. Given an an unknown browser X
the likelihood of the application failing in browser X inversely
correlated to the number of browsers that it the app is tested working in.

Testing in older shows how the app degrades or fails (degrading is
preferred, failure and errors should be avoided).

The marginal cost of testing in a desktop browser is low.

The cost of fixing the bugs can be high initially, and for the
inexperienced, this can seem not worth it, but as this is repeated, it
becomes easier because the type of constructs that are known to trigger
problems can be avoided.

Limiting the set of tested browsers may initially reduce costs (because
there is less work done), but at the cost of quality, which leads to
increases in costs.

[...]

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

ext-touch-debug.js..............458k
ext-touch-debug-w-comments.js...928k

[...]

[...]

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

Throwing an error for invalid syntax is fine. Throwing an error for
'[title="Hey, Joe"]' is introducing an error that is not present in the
browsers.

[...]

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

I can assume that the intention of the program was not realized in the
code. The documentation does not match the code and the code does not do
anything sensible. It is hard to make assertions of what the author was
thinking when the code looks mostly unintentional.

The code explains what it does well enough. Extra effort was required to
split on "," and create a loop and for what possible benefit? I really
can't say.

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

The function could have instead called `root.querySelectorAll`
unfettered by the splitting and looping, and would have avoided all of
those problems.

Of course, it should be first checked that `root` is not null, as calls
to `document.getElementById` can return null.

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

I suspect it may be a holdover from previous jQuery-inspired efforts.
Remember that older versions of jQuery supported XPath.

[...]
--
Garrett

David Mark

unread,
Jul 18, 2010, 5:27:21 PM7/18/10
to

They typically address this on exiting execution contexts, not at the
end of the stack.

David Mark

unread,
Jul 18, 2010, 5:42:42 PM7/18/10
to
On Jul 18, 5:18 pm, Garrett Smith <dhtmlkitc...@gmail.com> wrote:

[...]

>
> ext-touch-debug.js..............458k

Not sure what sort of "debugging" they had in mind. All it does is
hide mistakes, rather than throwing exceptions for unexpected usage
patterns.

But that measurement includes white space and penalizes long variable
names. That's why I prefer the equalizer of a minification when
making comparisons. jQuery (which does virtually nothing but queries)
is 70K+; Sencha (which supports only two WebKit variations) is 225K+
and the full build of My Library (which does more than the two
*combined* and works in virtually every browser known to man) is 140K
+. And unlike the other two, mine is not hopelessly tangled up in
interdependencies, which makes it easy to create much smaller custom
builds.

The marketers take the opposite tack of touting the sizes after
compression, which just confuses the uninitiated. For example, the
iPhone's cache limit is not based on the compressed size. For
another, if your HTML is 50K and CSS 30K, will the addition of the
"80K" Sencha Touch increase the payload by a factor of two or four?
Of course, the answer is four; but if you are going by the advertised
size, you would have to manually GZIP the HTML and CSS to find this
out. The marketers know that many developers will simply assume that
80K of HTML/CSS is equivalent to "80K" of Sencha.

[...]

>
> I suspect it may be a holdover from previous jQuery-inspired efforts.
> Remember that older versions of jQuery supported XPath.
>

How old? I only remember seeing XPath in Prototype. And AFAIK, they
are still trying to "support" it (despite the fact that it varies
wildly from their other forks).

kangax

unread,
Jul 18, 2010, 7:07:16 PM7/18/10
to
On 7/18/10 4:22 PM, Garrett Smith wrote:
> On 2010-07-18 06: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.
>>
>
> Was there anything not right about that?

Well, you said that "repaint" is an indication of a mystical
incantation. But browsers do repaint and do reflow; and there are
well-known things that trigger these actions. I just don't see what's
mystical or magical about that comment.

[...]

>>
>> Or am I missing something?
>>
> I don't know. What's wrong with the criticism I provided?

Oh, nothing is wrong with the rest of the message :) I was only curious
about the "repaint" part.

--
kangax

kangax

unread,
Jul 18, 2010, 7:18:12 PM7/18/10
to
On 7/18/10 1:32 PM, David Mark wrote:
> On Jul 18, 9:10 am, kangax<kan...@gmail.com> 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).
[...]
>> 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.

I see what you mean. And yes, I see they're adding a class, then
removing it in about 1 ms. I wonder what's the point of setting _both_
class and background; wouldn't class (with proper declarations) suffice?

I also wonder about the need for a function like this in the first
place. Reflows/repaints are usually being avoided as much as possible;
What could be the use for such function? Perhaps some layout/positioning
bug on mobile WebKit?

--
kangax

David Mark

unread,
Jul 18, 2010, 8:18:06 PM7/18/10
to

There's an easy explanation. They added code until it seemed to
"work". It's a classic mystical incantation.

>
> I also wonder about the need for a function like this in the first
> place.

There's good reason to wonder. Clearly they were having some sort of
problem and rather than trying to determine the root of it, resorted
to a magic spell (which may or may not hold up in future WebKit
versions).

> Reflows/repaints are usually being avoided as much as possible;

Absolutely. It's critical for performance in many areas (e.g.
animations, widgets). And if you don't understand how/when they
happen, you will end up with twitches (i.e. early flashes of content).

> What could be the use for such function? Perhaps some layout/positioning
> bug on mobile WebKit?
>

Something they ran into in their zeal to make a monolithic do-
everything library. Clearly they couldn't design around it as they
needed to solve every problem for every context. Some things never
change.

Garrett Smith

unread,
Jul 18, 2010, 10:15:13 PM7/18/10
to

jQuery 1.1.4 had XPath support. Other libraries seem to have been
inspired by that and the detritus from those libraries seems to remain
in Ext even in Sencha.

Ext provides additional syntax extensions to match style values (CSS
Value Selectors. The documentation for Sencha states that those are
supported, but they're not.

Ext-JS's (full/big version) more recent design borrows from the jQuery
NFD approach. The timeline is clear that jQuery did that first and the
Ext copied it. Regardless, NFD is a design mistake, no matter how
popular it becomes and no matter many libraries copy it. The reason I
mention this is it seems that Ext-JS has been following what jQuery
does, copying the mistakes and adding its own mistakes to that.

Ext-JS actually makes jQUery look good.

The Sencha documentation I mentioned earlier:
<http://www.sencha.com/deploy/dev/docs/?class=Ext.DomQuery>

The documnetation is quoted in full below. The reason I have done this
is that the documentation may change and when it does, the comments I've
made about it will not apply. By posting that inline, the comments will
be relevant to what is posted here, even if the document at that URI
changes.

The documentation does not reflect what the code does.

| Provides high performance selector/xpath processing by compiling
| queries into reusable functions. New pseudo classes and matchers can
| be plugged. It works on HTML and XML documents (if a content node is
| passed in).
|
| DomQuery supports most of the CSS3 selectors spec, along with some
| custom selectors and basic XPath.
|
| All selectors, attribute filters and pseudos below can be combined
| infinitely in any order. For example "div.foo:nth-child(odd)
| [@foo=bar].bar:first" would be a perfectly valid selector. Node
| filters are processed in the order in which they appear,
| which allows you to optimize your queries for your document structure.
| Element Selectors:
|

That is an example claimed of XPath support. An error will be thrown if
this is followed.

Sencha does not support XPath selectors, except those that also match
exactly the production for CSS Selectors, as [foo=bar], which is valid
XPath and also a valid CSS Selector.

| * * any element

That operator is supported in Sencha, though not properly supported in
Ext-JS, depending on the browser, its version, document mode, etc. The
fundamental problem with the NFD approach that they borrowed from jQuery.

| * E an element with the tag E
| * E F All descendent elements of E that have the tag F
| * E > F or E/F all direct children elements of E that have the tag F
| * E + F all elements with the tag F that are immediately preceded by
| an element with the tag E
| * E ~ F all elements with the tag F that are preceded by a sibling
| element with the tag E
|
| Attribute Selectors:
|
| The use of @ and quotes are optional. For example, div[@foo='bar'] is
| also a valid attribute selector.
|

No, that's not how CSS Selectors work and an error will be thrown if
this is followed.

| * E[foo] has an attribute "foo"
| * E[foo=bar] has an attribute "foo" that equals "bar"
| * E[foo^=bar] has an attribute "foo" that starts with "bar"
| * E[foo$=bar] has an attribute "foo" that ends with "bar"
| * E[foo*=bar] has an attribute "foo" that contains the substring "bar"
| * E[foo%=2] has an attribute "foo" that is evenly divisible by 2
| * E[foo!=bar] has an attribute "foo" that does not equal "bar"
|
| Pseudo Classes:
|
| * E:first-child E is the first child of its parent
| * E:last-child E is the last child of its parent
| * E:nth-child(n) E is the nth child of its parent (1 based as per the
| spec)
| * E:nth-child(odd) E is an odd child of its parent
| * E:nth-child(even) E is an even child of its parent
| * E:only-child E is the only child of its parent
| * E:checked E is an element that is has a checked attribute that is
| true
| (e.g. a radio or checkbox)
| * E:first the first E in the resultset
| * E:last the last E in the resultset
| * E:nth(n) the nth E in the resultset (1 based)
| * E:odd shortcut for :nth-child(odd)
| * E:even shortcut for :nth-child(even)
| * E:contains(foo) E's innerHTML contains the substring "foo"
| * E:nodeValue(foo) E contains a textNode with a nodeValue that equals
| "foo"

The syntax extensions there, including :nodeValue, will throw an error.

| * E:not(S) an E element that does not match simple selector S
| * E:has(S) an E element that has a descendent that matches simple
| selector S
| * E:next(S) an E element whose next sibling matches simple selector S
| * E:prev(S) an E element whose previous sibling matches simple
| selector S
| * E:any(S1|S2|S2) an E element which matches any of the simple
| selectors
| S1, S2 or S3//\\
|
| CSS Value Selectors:
|

These will all throw errors in Sencha and they do not work in Ext,
either, as you've reviewed the section of code the reads styles, and
that returns different results, when trying to read:

{visibility=visible}

- the result returned depends on the browser and how styles are calculated.

For example, if the default value for visibility is used, the element's
visibility is calcualted as "inherit" (which is correct) and in that
case, the result won't include that element. Except where it does, and
that depends on the browser.

But that is about Ext-JS (big version), not Sencha. In Sencha, all of
this stuff throws errors.

(I've got a some errands to do, so I'm going to post the rest of this
here wihout editing)

| * E{display=none} css value "display" that equals "none"
| * E{display^=none} css value "display" that starts with "none"
| * E{display$=none} css value "display" that ends with "none"
| * E{display*=none} css value "display" that contains the substring
| "none"
| * E{display%=2} css value "display" that is evenly divisible by 2
| * E{display!=none} css value "display" that does not equal "none"
|
|
|
| This class is a singleton and cannot be created directly.
| Public Properties
| Property Defined By
| matchers : Object
| Collection of matching regular expressions and code snippets. Each
| capture group within () will be replace the {} in ...
| Collection of matching regular expressions and code snippets. Each
| capture group within () will be replace the {} in the select statement
| as specified by their index.
| DomQuery
| pseudos : Object
| Object hash of "pseudo class" filter functions which are used when
| filtering selections. Each function is passed two ...
|
| Object hash of "pseudo class" filter functions which are used when
| filtering selections. Each function is passed two parameters:
|
| * c : Array
| An Array of DOM elements to filter.
| * v : String
| The argument (if any) supplied in the selector.
|
| A filter function returns an Array of DOM elements which conform to
| the pseudo class.
|
| In addition to the provided pseudo classes listed above such as
| first-child and nth-child, developers may add additional, custom psuedo
| class filters to select elements according to application-specific
| requirements.
|
| For example, to filter <a> elements to only return links to external
| resources:
|
| Ext.DomQuery.pseudos.external = function(c, v){
| var r = [], ri = -1;
| for(var i = 0, ci; ci = c[i]; i++){
| // Include in result set only if it's a link to an external resource
| if(ci.hostname != location.hostname){
| r[++ri] = ci;
| }
| }
| return r;
| };
|
| Then external links could be gathered with the following statement:
|
| var externalLinks = Ext.select("a:external");
|
| DomQuery
| Public Methods
| Method Defined By
| compile( String selector, [String type] ) : Function
| Compiles a selector/xpath query into a reusable function. The returned
| function takes one parameter "root" (optional)...
| Compiles a selector/xpath query into a reusable function. The returned
| function takes one parameter "root" (optional), which is the context
| node from where the query should start.
| Parameters:
|
| * selector : String
| The selector/xpath query
| * type : String
| (optional) Either "select" (the default) or "simple" for a simple
| selector match
|
| Returns:
|
| * Function
|
| DomQuery
| filter( Array el, String selector, Boolean nonMatches ) : Array
| Filters an array of elements to only include matches of a simple


| selector (e.g. div.some-class or span:first-child)

| Filters an array of elements to only include matches of a simple


| selector (e.g. div.some-class or span:first-child)

| Parameters:
|
| * el : Array
| An array of elements to filter
| * selector : String


| The simple selector to test

| * nonMatches : Boolean
| If true, it returns the elements that DON'T match the selector instead
| of the ones that match
|
| Returns:
|
| * Array
| An Array of DOM elements which match the selector. If there are no


| matches, and empty Array is returned.
|

| DomQuery
| is( String/HTMLElement/Array el, String selector ) : Boolean
| Returns true if the passed element(s) match the passed simple selector


| (e.g. div.some-class or span:first-child)

| Returns true if the passed element(s) match the passed simple selector


| (e.g. div.some-class or span:first-child)

| Parameters:
|
| * el : String/HTMLElement/Array
| An element id, element or array of elements
| * selector : String


| The simple selector to test
|

| Returns:
|
| * Boolean
|
| DomQuery
| jsSelect( String selector, [Node/String root] ) : Array


| Selects a group of elements.
| Selects a group of elements.

| Parameters:
|
| * selector : String
| The selector/xpath query (can be a comma separated list of selectors)
| * root : Node/String
| (optional) The start of the query (defaults to document).
|
| Returns:
|
| * Array
| An Array of DOM elements which match the selector. If there are no


| matches, and empty Array is returned.
|

| DomQuery
| operators() : void
| Collection of operator comparison functions. The default operators are
| =, !=, ^=, $=, *=, %=, |= and ~=. New operator...
| Collection of operator comparison functions. The default operators are
| =, !=, ^=, $=, *=, %=, |= and ~=. New operators can be added as long
| as the match the format c= where c is any character other than space,
| > <.
| Parameters:
|
| * None.
|
| Returns:
|
| * void
|

At least half of these operators are syntax extensions.

| DomQuery
| selectNode( String selector, [Node root] ) : Element
| Selects a single element.
| Selects a single element.
| Parameters:
|
| * selector : String
| The selector/xpath query
| * root : Node
| (optional) The start of the query (defaults to document).
|
| Returns:
|
| * Element
| The DOM element which matched the selector.
|
| DomQuery
| selectNumber( String selector, [Node root], Number defaultValue ) :
| Number
| Selects the value of a node, parsing integers and floats. Returns the
| defaultValue, or 0 if none is specified.
| Selects the value of a node, parsing integers and floats. Returns the
| defaultValue, or 0 if none is specified.
| Parameters:
|
| * selector : String
| The selector/xpath query
| * root : Node
| (optional) The start of the query (defaults to document).
| * defaultValue : Number
|
| Returns:
|
| * Number
|
| DomQuery
| selectValue( String selector, [Node root], String defaultValue ) :
| String
| Selects the value of a node, optionally replacing null with the
| defaultValue.
| Selects the value of a node, optionally replacing null with the
| defaultValue.
| Parameters:
|
| * selector : String
| The selector/xpath query
| * root : Node
| (optional) The start of the query (defaults to document).
| * defaultValue : String
|
| Returns: String
|
| DomQuery

The `selectValue` and `selectNumber` methods are missing altogether from
Sencha.

typeof Ext.DomQuery.selectValue

"undefined"
--
Garrett

David Mark

unread,
Jul 18, 2010, 11:26:28 PM7/18/10
to

Yes, Ext has it. And, like Prototype, there's not a chance in hell it
matches their other forks. For example, they are all afflicted by the
same misconceptions about attributes. It you look at documents as
database tables, elements as rows and attributes as fields, the
monumental futility of CSS selector query engines (as implemented in
all of the "major" libraries) is clear. Who would use such a
database? The only defense I've heard from those who lean on these
things is that they don't care because they somehow manage to avoid
the problems (which vary wildly from one browser to the next) at least
in the browsers they "care" about. Of course that would require an
inhuman amount of memorization to make work and there would always be
the chance that the ever-shifting libraries could invalidate their map
at any time. And then there are the browsers they've never heard of
(most notably the ones that have yet to be published).

>
> Ext provides additional syntax extensions to match style values (CSS
> Value Selectors. The documentation for Sencha states that those are
> supported, but they're not.

Of course not. We've seen how Ext/Sencha deal with styles. They are
just as clumsy with those as they are with attributes. Thus large
portions of their documentation are pure fantasy.

>
> Ext-JS's (full/big version) more recent design borrows from the jQuery
> NFD approach. The timeline is clear that jQuery did that first and the
> Ext copied it.

Yes, Sizzle was a fraud perpetrated on jQuery users, dressed up as a
performance increase. Here's John Resig lamenting what should have
been the end of his old query code:-

http://ejohn.org/blog/thoughts-on-queryselectorall/#postcomment

...then he went ahead and piled QSA on top of it. His fellow
"luminaries" predictably followed suit.

And speaking of the other efforts; you mentioned that ExtJS was the
worst of the worst with respect to queries. But I don't know how you
could get much more inept than Dojo's, which relies on their "attr"
function, which has always been complete gibberish. It's only a
couple of dozen lines of code and I once tried to explain its illogic
to them, but they just kept chirping: "show me where it fails". I was
reluctant to do that as it would predictably lead to patches without
understanding (or fixing) the general problem. But even after
producing a couple of failure cases, they were still hesitant to
change anything, lest they break compatibility. Of course,
"compatibility" that produces one result in IE8 standards mode and
another in its compatibility view is not something to preserve.
Furthermore, their "vaunted" widgets and parser rely heavily on this
function, so the mistakes manifest themselves in virtually everything
they do. Their forums, mailing lists, etc. are full of confused
questions (and even more confused answers) related to these issues.

> Regardless, NFD is a design mistake, no matter how
> popular it becomes and no matter many libraries copy it.

Of course it is. A child could see that.

> The reason I
> mention this is it seems that Ext-JS has been following what jQuery
> does, copying the mistakes and adding its own mistakes to that.

It appears that way. And they have the gall to charge people to use
recycled garbage.

>
> Ext-JS actually makes jQUery look good.

It's apples and oranges, but if you just compare the Ext core to
jQuery, then I'd have to agree. Pity. And people wonder why I don't
like *any* of these things.

>
> The Sencha documentation I mentioned earlier:
> <http://www.sencha.com/deploy/dev/docs/?class=Ext.DomQuery>
>
> The documnetation is quoted in full below. The reason I have done this
> is that the documentation may change and when it does, the comments I've
> made about it will not apply. By posting that inline, the comments will
> be relevant to what is posted here, even if the document at that URI
> changes.
>
> The documentation does not reflect what the code does.
>
> | Provides high performance selector/xpath processing by compiling
> | queries into reusable functions. New pseudo classes and matchers can
> | be plugged. It works on HTML and XML documents (if a content node is
> | passed in).

That sounds like an optimistic appraisal of ExtJS, but Sencha Touch
does nothing of the sort. It "compiles" nothing and certainly won't
work with XML documents.

> |
> | DomQuery supports most of the CSS3 selectors spec, along with some
> | custom selectors and basic XPath.
> |
> | All selectors, attribute filters and pseudos below can be combined
> | infinitely in any order.

Infinitely. :) Of course, even one selector may get the wrong
result, depending on browser, rendering mode, phase of the moon, etc.
Why do developers insist on buying in to this stuff? The whole idea
was doomed from the start, has failed miserably and yet is more
popular than ever. The popularity is often used as an excuse to use
queries, while the myriad technical issues are brushed off as
irrelevant. Go figure.

> For example "div.foo:nth-child(odd)
> | [@foo=bar].bar:first" would be a perfectly valid selector. Node
> | filters are processed in the order in which they appear,
> | which allows you to optimize your queries for your document structure.
> | Element Selectors:
> |
>
> That is an example claimed of XPath support. An error will be thrown if
> this is followed.
>
> Sencha does not support XPath selectors, except those that also match
> exactly the production for CSS Selectors, as [foo=bar], which is valid
> XPath and also a valid CSS Selector.

Yes, occasionally works by coincidence.

>
> | * * any element
>
> That operator is supported in Sencha, though not properly supported in
> Ext-JS, depending on the browser, its version, document mode, etc. The
> fundamental problem with the NFD approach that they borrowed from jQuery.

Yes, the native implementations are incompatible with the scripted
query engines, which are often incompatible with themselves (e.g.
changing from one version of jQuery to the next).

>
> | * E an element with the tag E
> | * E F All descendent elements of E that have the tag F
> | * E > F or E/F all direct children elements of E that have the tag F
> | * E + F all elements with the tag F that are immediately preceded by
> | an element with the tag E
> | * E ~ F all elements with the tag F that are preceded by a sibling
> | element with the tag E
> |
> | Attribute Selectors:
> |
> | The use of @ and quotes are optional. For example, div[@foo='bar'] is
> | also a valid attribute selector.
> |
>
> No, that's not how CSS Selectors work and an error will be thrown if
> this is followed.

When it comes to attributes, they've got so many problems that
developers should just forget about using such queries. Of course,
many jQuery tutorials demonstrate querying by attribute values.

>
> | * E[foo] has an attribute "foo"
> | * E[foo=bar] has an attribute "foo" that equals "bar"
> | * E[foo^=bar] has an attribute "foo" that starts with "bar"
> | * E[foo$=bar] has an attribute "foo" that ends with "bar"
> | * E[foo*=bar] has an attribute "foo" that contains the substring "bar"
> | * E[foo%=2] has an attribute "foo" that is evenly divisible by 2
> | * E[foo!=bar] has an attribute "foo" that does not equal "bar"
> |
> | Pseudo Classes:
> |
> | * E:first-child E is the first child of its parent
> | * E:last-child E is the last child of its parent
> | * E:nth-child(n) E is the nth child of its parent (1 based as per the
> | spec)
> | * E:nth-child(odd) E is an odd child of its parent
> | * E:nth-child(even) E is an even child of its parent
> | * E:only-child E is the only child of its parent
> | * E:checked E is an element that is has a checked attribute that is
> | true
> | (e.g. a radio or checkbox)

That's not right. For one, a checked attribute cannot be
"true" (except in an invalid document) and the :checked pseudo queries
the *property* so as to take user input into account. Fortunately, I
think that's what they all do anyway; but unfortunately, they do the
same thing when querying the CHECKED attribute. In my experience,
most of the participants in these projects don't know the difference.

> | * E:first the first E in the resultset
> | * E:last the last E in the resultset
> | * E:nth(n) the nth E in the resultset (1 based)
> | * E:odd shortcut for :nth-child(odd)
> | * E:even shortcut for :nth-child(even)
> | * E:contains(foo) E's innerHTML contains the substring "foo"
> | * E:nodeValue(foo) E contains a textNode with a nodeValue that equals
> | "foo"
>
> The syntax extensions there, including :nodeValue, will throw an error.

Yes. The :contains pseudo was in at least one of the Selectors drafts,
but was eventually dropped, so QSA implementations can't parse it.

>
> | * E:not(S) an E element that does not match simple selector S
> | * E:has(S) an E element that has a descendent that matches simple
> | selector S
> | * E:next(S) an E element whose next sibling matches simple selector S
> | * E:prev(S) an E element whose previous sibling matches simple
> | selector S
> | * E:any(S1|S2|S2) an E element which matches any of the simple
> | selectors
> | S1, S2 or S3//\\
> |
> | CSS Value Selectors:
> |
>
> These will all throw errors in Sencha and they do not work in Ext,
> either, as you've reviewed the section of code the reads styles, and
> that returns different results, when trying to read:
>
> {visibility=visible}
>
> - the result returned depends on the browser and how styles are calculated.

Yes, using these things to query by style values is even less
predictable than querying by attribute values.

>
> For example, if the default value for visibility is used, the element's
> visibility is calcualted as "inherit" (which is correct) and in that
> case, the result won't include that element. Except where it does, and
> that depends on the browser.

No, "inherit" would be incorrect for getComputedStyle. For elements
without a visibility rule, "visible" is the expected result. Now,
IE's "cascaded styles" will indeed return "inherit" as IE doesn't
compute styles at all, simply returning whatever is specified in
applicable rules (or the default value, which is "inherit" in this
case).

Regardless, I'm sure that ExtJS fails to account for this (among many
other things). Just like jQuery! :)

>
> But that is about Ext-JS (big version), not Sencha. In Sencha, all of
> this stuff throws errors.

Of course as it has no query engine; it simply hands off all queries
to QSA.

>
> (I've got a some errands to do, so I'm going to post the rest of this
> here wihout editing)
>
> | * E{display=none} css value "display" that equals "none"
> | * E{display^=none} css value "display" that starts with "none"
> | * E{display$=none} css value "display" that ends with "none"
> | * E{display*=none} css value "display" that contains the substring
> | "none"

There's not a chance in hell they got any of those right cross-
browser.

> | * E{display%=2} css value "display" that is evenly divisible by 2

LOL. What on earth would that mean?

> | * E{display!=none} css value "display" that does not equal "none"
> |
> |
> |
> | This class is a singleton and cannot be created directly.

It's neither a class nor a singleton.

> | Public Properties

All JS properties are public.

> | Property Defined By
> | matchers : Object
> | Collection of matching regular expressions and code snippets. Each
> | capture group within () will be replace the {} in ...
> | Collection of matching regular expressions and code snippets. Each
> | capture group within () will be replace the {} in the select statement
> | as specified by their index.
> | DomQuery
> | pseudos : Object
> | Object hash of "pseudo class" filter functions which are used when
> | filtering selections. Each function is passed two ...

Oh God. As usual, these types of projects get ten steps ahead of
themselves. I mean, it's 2010 and their basic queries are still
broken. What's the point of piling all of this other nonsense on top?

[snip more delusions]

There's a lot of that going on. They were clearly pressed for time.

>
> typeof Ext.DomQuery.selectValue
>
> "undefined"

Here's a good acid test for a Web application:-

typeof Ext == 'undefined'

,,,with true being the desired result. ;)

Ry Nohryb

unread,
Jul 19, 2010, 1:51:48 AM7/19/10
to
On Jul 18, 8:18 am, Garrett Smith <dhtmlkitc...@gmail.com> wrote:
>
> 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.
>

You're mistaken, again, Garrett.
Yes, there are ways to force both reflows and repaints.
For example, this (google groups) page can be forced to repaint with:

document.body.style.opacity= 0;
setTimeout(function(){document.body.style.opacity= 1},0);

Or with:
document.body.style.visibility= "hidden";
setTimeout(function(){document.body.style.visibility= ""},0);

And to reflow (+ repaint):
document.body.style.maxWidth= "50px";
setTimeout(function(){document.body.style.maxWidth= ""},0);

HTH,
--
Jorge.

David Mark

unread,
Jul 19, 2010, 2:25:34 AM7/19/10
to

It doesn't. This oversimplification of the issue was covered earlier
in the thread (just a few hours ago). Of course you can cause the
document to reflow/repaint if you change its style and exit an
execution context (though it may not happen immediately). The
question is why you would need to do that with the styling equivalent
of a no-op. The answer is that you wouldn't unless you were stuck and
resorting to programming by mystical incantation.

Please read before posting next time. Thanks!

Garrett Smith

unread,
Jul 19, 2010, 3:04:27 AM7/19/10
to
On 2010-07-18 10:51 PM, Ry Nohryb wrote:
> On Jul 18, 8:18 am, Garrett Smith<dhtmlkitc...@gmail.com> wrote:
>>
>> 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.
>>
>
> You're mistaken, again, Garrett.

Did you need more explanation, after all that I have explained to you
already?

> Yes, there are ways to force both reflows and repaints.

If that is true, you have not proven it.

> For example, this (google groups) page can be forced to repaint with:
>

No, it cannot. About the best you can do is hope that the browser will
repaint.

So you've made observations of what happened in the browser and
concluded that those observations are premises for causality, huh?

That is a classic Post hoc ergo propter hoc fallacy. I saw B after A.
Therefore, A causes B. (fallacious).

[snip]

That code proves nothing at all. Where is the specification (or even
browser documentation) for "how to repaint"? There is none, is there?

>
> HTH,

It does not. The browser will repaint when it needs to.

Repaint issues are not new to me. I have dealt with them many years ago
when the then popular hacks included such things as modifying the status
bar and even resizing the window.

resizeBy(0, 1);
resizeBy(0, -1);

(!)
Voodoo.
--
Garrett

Ry Nohryb

unread,
Jul 19, 2010, 3:12:14 AM7/19/10
to
On Jul 19, 8:25 am, David Mark <dmark.cins...@gmail.com> wrote:
> (...) The

> question is why you would need to do that with the styling equivalent
> of a no-op.  The answer is that you wouldn't unless you were stuck and
> resorting to programming by mystical incantation.

I always read before posting: it was a reply to Garrett's assertion
"We know that there is no way to force a repaint", which is -plainly-
false. See:

"Faster HTML and CSS: Layout Engine Internals for Web Developers",
David Baron.
http://www.youtube.com/v/a2_6bGNZ7bA

>
> Please read before posting next time.  Thanks!

You're welcome.
--
Jorge.

David Mark

unread,
Jul 19, 2010, 3:14:21 AM7/19/10
to
On Jul 19, 3:12 am, Ry Nohryb <jo...@jorgechamorro.com> wrote:
> On Jul 19, 8:25 am, David Mark <dmark.cins...@gmail.com> wrote:
>
> > (...) The
> > question is why you would need to do that with the styling equivalent
> > of a no-op.  The answer is that you wouldn't unless you were stuck and
> > resorting to programming by mystical incantation.
>
> I always read before posting: it was a reply to Garrett's assertion
> "We know that there is no way to force a repaint", which is -plainly-
> false.

Which was pointless.

> See:
>
> "Faster HTML and CSS: Layout Engine Internals for Web Developers",
> David Baron.http://www.youtube.com/v/a2_6bGNZ7bA
>

As is that. You are your videos. :(

Ry Nohryb

unread,
Jul 19, 2010, 3:29:51 AM7/19/10
to
On Jul 19, 9:04 am, Garrett Smith <dhtmlkitc...@gmail.com> wrote:
> On 2010-07-18 10:51 PM, Ry Nohryb wrote:
> (...)

>
> > For example, this (google groups) page can be forced to repaint with:
>
> No, it cannot. About the best you can do is hope that the browser will
> repaint.
>
> So you've made observations of what happened in the browser and
> concluded that those observations are premises for causality, huh?
> (...)

What I said is not based on any "mystical incantation" but on what the
author of Mozilla's rendering engine explains in this video:

"Faster HTML and CSS: Layout Engine Internals for Web Developers",
David Baron.
http://www.youtube.com/v/a2_6bGNZ7bA

Obviously you too (I told Mark already) ought to see it in order to
learn the fundamentals of the inner workings of rendering engines, and
once you begin to see through the black box, you (and Mark) will be
able to stop thinking about it any more in terms of mystical
incantations.

HTH,
--
Jorge.

Garrett Smith

unread,
Jul 19, 2010, 3:37:32 AM7/19/10
to
On 2010-07-18 08:26 PM, David Mark wrote:
> On Jul 18, 10:15 pm, Garrett Smith<dhtmlkitc...@gmail.com> wrote:
>> On 2010-07-18 02:42 PM, David Mark wrote:
>>
>>> On Jul 18, 5:18 pm, Garrett Smith<dhtmlkitc...@gmail.com> wrote:
>>
>>> [...]
>>
>>>> ext-touch-debug.js..............458k
>>
[...]

>
> And speaking of the other efforts; you mentioned that ExtJS was the
> worst of the worst with respect to queries. But I don't know how you
> could get much more inept than Dojo's, which relies on their "attr"

I did not review Dojo's in depth, but the overall design approach makes
more sense. From memory, dojo uses its own engine first, and if that
works, then it tries to use NodeSelector the next time.

> function, which has always been complete gibberish. It's only a
> couple of dozen lines of code and I once tried to explain its illogic
> to them, but they just kept chirping: "show me where it fails". I was
> reluctant to do that as it would predictably lead to patches without
> understanding (or fixing) the general problem. But even after
> producing a couple of failure cases, they were still hesitant to
> change anything, lest they break compatibility. Of course,
> "compatibility" that produces one result in IE8 standards mode and
> another in its compatibility view is not something to preserve.
> Furthermore, their "vaunted" widgets and parser rely heavily on this
> function, so the mistakes manifest themselves in virtually everything
> they do. Their forums, mailing lists, etc. are full of confused
> questions (and even more confused answers) related to these issues.
>

The predicament is that fixing the broken abstraction affects the
dependencies.

Changes to low-level abstractions propagate to higher level abstractions
and the result is instability.

The alternative to causing such instability -- and which Dojo has seemed
to favor here -- is to not fix the bugs.

Of course the problem with that is that everything is broken and as you
pointed out, broken differently across different browsers, rendering
mode, etc.

An low level abstraction that is fundamentally broken is a serious problem.

>> Regardless, NFD is a design mistake, no matter how
>> popular it becomes and no matter many libraries copy it.
>
> Of course it is. A child could see that.
>
>> The reason I
>> mention this is it seems that Ext-JS has been following what jQuery
>> does, copying the mistakes and adding its own mistakes to that.
>
> It appears that way. And they have the gall to charge people to use
> recycled garbage.
>

Well, if it is coming at premium cost, there will be those who think
that it must be better.
[...]

>>
>> | Provides high performance selector/xpath processing by compiling
>> | queries into reusable functions. New pseudo classes and matchers can
>> | be plugged. It works on HTML and XML documents (if a content node is
>> | passed in).
>
> That sounds like an optimistic appraisal of ExtJS, but Sencha Touch
> does nothing of the sort. It "compiles" nothing and certainly won't
> work with XML documents.
>

Ext-JS -- not Sencha -- dynamically create functions that they reuse.
This is what they mean by "compiled". that doesn't apply to Sencha, but
just an FYI about what they mean by "compile".

[...]

>
> That's not right. For one, a checked attribute cannot be
> "true" (except in an invalid document) and the :checked pseudo queries
> the *property* so as to take user input into account. Fortunately, I
> think that's what they all do anyway; but unfortunately, they do the
> same thing when querying the CHECKED attribute. In my experience,
> most of the participants in these projects don't know the difference.
>

Not all, and there are some that check attributes. NWMatcher is
cognizant of that, at least.

[...]

>
>>
>> | * E:not(S) an E element that does not match simple selector S
>> | * E:has(S) an E element that has a descendent that matches simple
>> | selector S
>> | * E:next(S) an E element whose next sibling matches simple selector S
>> | * E:prev(S) an E element whose previous sibling matches simple
>> | selector S
>> | * E:any(S1|S2|S2) an E element which matches any of the simple
>> | selectors
>> | S1, S2 or S3//\\
>> |
>> | CSS Value Selectors:
>> |
>>
>> These will all throw errors in Sencha and they do not work in Ext,
>> either, as you've reviewed the section of code the reads styles, and
>> that returns different results, when trying to read:
>>
>> {visibility=visible}
>>
>> - the result returned depends on the browser and how styles are calculated.
>
> Yes, using these things to query by style values is even less
> predictable than querying by attribute values.
>

It is.

The selector engine can be accessed from both
Ext.Element.selectorFunction and Ext.query. These are core abstractions
in the library and are accessed from two core parts of the library, both
of which express a package interdependency.

A selector engine that offers no deliberate syntax extensions is safer,
because it does not have as much deviation from the spec.

Any library that uses custom selectors, selectors that match attributes,
and anything that uses native-first dual approach cannot be easily
fixed. Continuing to use such library either changed or unchanged would
be unsafe.

Any library that uses a broken query selector at the core is just as
broken as its query engine. Fixing the bugs causes instability. Problems
are not limited to queries, however.

When changes to low-level abstractions propagate to higher level
abstractions the result is instability.

Each bug in Ext-JS's selector engine necessarily propagates to a higher
level. When the selector engine's behavior is changed, that change is
propagated to all of the higher level dependencies. Such behavioral
changes cause instability. The alternative to causing such changes is to
not fix the bugs.

Buyer Beware.
The alternative for the end user is to not use include such things on
the page. As I have always advised for the developer who is considering
using a js library: Carefully review the source code of any js library
before using it.

<https://groups.google.com/group/comp.lang.javascript/msg/c23d62071aad2626>

>>
>> For example, if the default value for visibility is used, the element's
>> visibility is calcualted as "inherit" (which is correct) and in that
>> case, the result won't include that element. Except where it does, and
>> that depends on the browser.
>
> No, "inherit" would be incorrect for getComputedStyle. For elements
> without a visibility rule, "visible" is the expected result. Now,
> IE's "cascaded styles" will indeed return "inherit" as IE doesn't
> compute styles at all, simply returning whatever is specified in
> applicable rules (or the default value, which is "inherit" in this
> case).
>

That's correct.

var a = Ext.query("{visibility=inherit}");

The result of that in Ext shows that it does not work consistently
either, and a.length will be 0, depending on the browser. This is due to
the fact that it relies on Ext.Dom.getStyle, which, like most everything
in Ext-JS, is very broken.

> Regardless, I'm sure that ExtJS fails to account for this (among many
> other things). Just like jQuery! :)
>
>>
>> But that is about Ext-JS (big version), not Sencha. In Sencha, all of
>> this stuff throws errors.
>
> Of course as it has no query engine; it simply hands off all queries
> to QSA.
>

If it had simply handed queries off to `querySelectorAll`, it would not
have created as many problems.

Extra effort was required to split on "," and create a loop, adding
duplicates to the returned result.

So while they do use querySelectorAll, they go to a lot of extra effort
to complicate it and create problems. Why they expended this extra
effort, I cannot say.

The code with comments being blatantly false could be attributed to haste.

>>
>> (I've got a some errands to do, so I'm going to post the rest of this
>> here wihout editing)
>>
>> | * E{display=none} css value "display" that equals "none"
>> | * E{display^=none} css value "display" that starts with "none"
>> | * E{display$=none} css value "display" that ends with "none"
>> | * E{display*=none} css value "display" that contains the substring
>> | "none"
>
> There's not a chance in hell they got any of those right cross-
> browser.
>

You reviewed Ext.Dom.getStyle and, as you pointed out,
`hasRightMarginBug` is completely missing for the script.

"hasRightMarginBug" in Ext.platform

false

It seems they forgot to include that property, though continue to
reference it. Since the resolution results in undefined and since
undefined evaluates to false, any code that uses that identifier in a
boolean context is completely useless and dead code.

And so all of the:

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

| display = this.getStyle('display');

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

is dead code and will never be evaluated.

>> | * E{display!=none} css value "display" that does not equal "none"
>> |
>> |
>> |
>> | This class is a singleton and cannot be created directly.
>
> It's neither a class nor a singleton.
>
>> | Public Properties
>
> All JS properties are public.
>
>> | Property Defined By
>> | matchers : Object
>> | Collection of matching regular expressions and code snippets. Each
>> | capture group within () will be replace the {} in ...
>> | Collection of matching regular expressions and code snippets. Each
>> | capture group within () will be replace the {} in the select statement
>> | as specified by their index.
>> | DomQuery
>> | pseudos : Object
>> | Object hash of "pseudo class" filter functions which are used when
>> | filtering selections. Each function is passed two ...
>
> Oh God. As usual, these types of projects get ten steps ahead of
> themselves. I mean, it's 2010 and their basic queries are still
> broken. What's the point of piling all of this other nonsense on top?
>
> [snip more delusions]
>

Although library author is free to make any design decision he chooses,
if the design decisions violate the CSS specifications and drafts (and
these do), then the code cannot honestly be said to be CSS3 compliant.

Ext-JS claims "DomQuery supports most of the CSS3 selectors spec, along
with some custom selectors and basic XPath". Whether Ext supports more
than half of CSS3 selectors depends on the browser and the claim of
"basic XPath" support is false (possibly outdated documentation from
previous jQuery copying).

Seems so. Yet another framework rushed to market, marketed heavily,
using fancy demos with nice images.

The difference between marketing and engineering seems to not very well
perceived.

Looking at demos is much more accessible than being able to make
assessments of front end code quality.

The number of individuals who look at the demos is going to be larger
than the number of individuals who review the code. This is not surprising.

What is surprising is that prior to the recent angel investment into
Sencha, they did not a few qualified individuals to do code review on
it. This would not have been much investment and could have helped avoid
such an amazing waste of money[1].

From the perspective of the investor who does not have any idea of the
code quality, he could employ two highly qualified individuals for a
maximum of one week each to review and assess the code at a cost under
10,000 USD. In reality, it is not hard to look at the code and find a
mistake at line 1:

window.undefined = window.undefined;

- and continue to find a very high defect rate and significantly bad
defects that we have covered and other glaring errors and design
mistakes that were covered by RobG[2].

Having volunteered so much free time over the years to spread knowledge
of web development, it seems that too few care about the code.

The financial losses from projects debilitated by bad code is real.

Bad code costs money.

Bad code hides bugs that might not surface immediately.

Tangled messy code can't be changed easily. The time involved to add a
new feature can be double, and then coming back to regression testing,
bugfixes for all of the change propagation.

This can lead to losing customers from bugs and even project failure
(and I have swam from such sunken ships, having failed to inspire the
captain into smart choices). It is not easy to measure how much money
was wasted by bad code. There is never a "good code" control group and
problems and debt compound.

Ext-JS is very buggy. It is awful code.

Any javascript developer who Ext-JS either has not read the source code
enough, is not capable of understanding the problems, or has read and
understood the problems but has not appreciated the consequences deeply.
The choice to use Ext-JS is a substantially irresponsible and uninformed
decision that puts quality and long-term success of his project at risk.

[1] <http://techcrunch.com/2010/06/23/sencha-html5-funding-sequoia/>
[2] "jquery vs dojo vs yui etc"
<http://groups.google.com/group/comp.lang.javascript/msg/d49c2a6b9a01c55c>
--
Garret

Ry Nohryb

unread,
Jul 19, 2010, 3:41:14 AM7/19/10
to
On Jul 19, 9:04 am, Garrett Smith <dhtmlkitc...@gmail.com> wrote:
>
> Did you need more explanation, after all that I have explained to you
> already?

The answer, my friend, is blowin' in the wind.
--
Jorge.

David Mark

unread,
Jul 19, 2010, 3:42:43 AM7/19/10
to

Sorry for the confusion, you *and* your videos.

David Mark

unread,
Jul 19, 2010, 3:43:39 AM7/19/10
to
On Jul 19, 3:29 am, Ry Nohryb <jo...@jorgechamorro.com> wrote:
> On Jul 19, 9:04 am, Garrett Smith <dhtmlkitc...@gmail.com> wrote:
>
> > On 2010-07-18 10:51 PM, Ry Nohryb wrote:
> > (...)
>
> > > For example, this (google groups) page can be forced to repaint with:
>
> > No, it cannot. About the best you can do is hope that the browser will
> > repaint.
>
> > So you've made observations of what happened in the browser and
> > concluded that those observations are premises for causality, huh?
> > (...)
>
> What I said is not based on any "mystical incantation" but on what the
> author of Mozilla's rendering engine explains in this video:
>
> "Faster HTML and CSS: Layout Engine Internals for Web Developers",
> David Baron.http://www.youtube.com/v/a2_6bGNZ7bA

>
> Obviously you too (I told Mark already) ought to see it in order to
> learn the fundamentals of the inner workings of rendering engines, and
> once you begin to see through the black box, you (and Mark) will be
> able to stop thinking about it any more in terms of mystical
> incantations.
>
> HTH,

Nope. I don't need to watch the video. You need to learn to read.
Thanks!

David Mark

unread,
Jul 19, 2010, 4:28:56 AM7/19/10
to
On Jul 19, 3:37 am, Garrett Smith <dhtmlkitc...@gmail.com> wrote:
> On 2010-07-18 08:26 PM, David Mark wrote:> On Jul 18, 10:15 pm, Garrett Smith<dhtmlkitc...@gmail.com>  wrote:
> >> On 2010-07-18 02:42 PM, David Mark wrote:
>
> >>> On Jul 18, 5:18 pm, Garrett Smith<dhtmlkitc...@gmail.com>    wrote:
>
> >>> [...]
>
> >>>> ext-touch-debug.js..............458k
>
> [...]
>
>
>
> > And speaking of the other efforts; you mentioned that ExtJS was the
> > worst of the worst with respect to queries.  But I don't know how you
> > could get much more inept than Dojo's, which relies on their "attr"
>
> I did not review Dojo's in depth, but the overall design approach makes
> more sense. From memory, dojo uses its own engine first, and if that
> works, then it tries to use NodeSelector the next time.

Its own engine is the problem. Certainly it isn't aware of whether it
works or not (unless "works" means avoiding exceptions).

>
> > function, which has always been complete gibberish.  It's only a
> > couple of dozen lines of code and I once tried to explain its illogic
> > to them, but they just kept chirping: "show me where it fails".  I was
> > reluctant to do that as it would predictably lead to patches without
> > understanding (or fixing) the general problem.  But even after
> > producing a couple of failure cases, they were still hesitant to
> > change anything, lest they break compatibility.  Of course,
> > "compatibility" that produces one result in IE8 standards mode and
> > another in its compatibility view is not something to preserve.
> > Furthermore, their "vaunted" widgets and parser rely heavily on this
> > function, so the mistakes manifest themselves in virtually everything
> > they do.  Their forums, mailing lists, etc. are full of confused
> > questions (and even more confused answers) related to these issues.
>
> The predicament is that fixing the broken abstraction affects the
> dependencies.

The problem is that their abstraction is inconsistent cross-browser,
so is nothing to cling to. The other problem is that none of them can
define what it is supposed to be doing.

>
> Changes to low-level abstractions propagate to higher level abstractions
> and the result is instability.

But when you are already getting two different results for the same
browser (e.g. IE8 depending on rendering mode), it indicates you
better change something. I went through all of the dependencies and
certainly none are written to expect two different results in IE8.

>
> The alternative to causing such instability -- and which Dojo has seemed
> to favor here -- is to not fix the bugs.

There's not a chance in hell that fixing the bugs I am referring to
would cause instability. In fact, I rewrote virtually every module
and add-on and demonstrated that all of the unit tests still passed.
Hard to argue with that. Yet somehow they managed.

>
> Of course the problem with that is that everything is broken and as you
> pointed out, broken differently across different browsers, rendering
> mode, etc.

Right.

>
> An low level abstraction that is fundamentally broken is a serious problem.

Yes, and for them it remains a problem to this day. That indicates
that nobody on that project has a clue what they are doing. They
can't even fix simple problems when handed the solutions on a silver
platter (see also jQuery).

>
> >> Regardless, NFD is a design mistake, no matter how
> >> popular it becomes and no matter many libraries copy it.
>
> > Of course it is.  A child could see that.
>
> >> The reason I
> >> mention this is it seems that Ext-JS has been following what jQuery
> >> does, copying the mistakes and adding its own mistakes to that.
>
> > It appears that way.  And they have the gall to charge people to use
> > recycled garbage.
>
> Well, if it is coming at premium cost, there will be those who think
> that it must be better.

Yes, snob appeal. But I think it is the graphics that are the biggest
draw. Of course, choosing a framework based on pretty widgets is like
choosing a car based on its radio.

> [...]
>
>
>
> >> | Provides high performance selector/xpath processing by compiling
> >> | queries into reusable functions. New pseudo classes and matchers can
> >> | be plugged. It works on HTML and XML documents (if a content node is
> >> | passed in).
>
> > That sounds like an optimistic appraisal of ExtJS, but Sencha Touch
> > does nothing of the sort.  It "compiles" nothing and certainly won't
> > work with XML documents.
>
> Ext-JS -- not Sencha -- dynamically create functions that they reuse.

I know.

> This is what they mean by "compiled". that doesn't apply to Sencha, but
> just an FYI about what they mean by "compile".

I've seen it elsewhere as well.

>
> [...]
>
>
>
> > That's not right.  For one, a checked attribute cannot be
> > "true" (except in an invalid document) and the :checked pseudo queries
> > the *property* so as to take user input into account.  Fortunately, I
> > think that's what they all do anyway; but unfortunately, they do the
> > same thing when querying the CHECKED attribute.  In my experience,
> > most of the participants in these projects don't know the difference.
>
> Not all, and there are some that check attributes. NWMatcher is
> cognizant of that, at least.

Yes, that thing works better than most of the "majors". Certainly
mine does too. Perhaps Dojo's will some day too as one of their
owners informed me long after his contributors had refused to
implement my recommendations that they were sniffing around my
attributes primer (a la John Resig). I had to remind him that it was
copyrighted. I'll be keeping my eye on them too. ;)

Where does this "native-first dual approach" term come from? I know
what you mean, but I've never heard it called that.

>
> Any library that uses a broken query selector at the core is just as
> broken as its query engine.

Of course. And Dojo uses theirs incessantly. That's why virtually
every "module" in their core requires dojo.query. How ominous is
that?

> Fixing the bugs causes instability. Problems
> are not limited to queries, however.

The fixes I recommended would not have destabilized anything. They
would have simply fixed the inconsistencies, which were not results
that were expected by the rest of the "modules".

>
> When changes to low-level abstractions propagate to higher level
> abstractions the result is instability.

Not in the case I'm speaking of. The result would have been exactly
the opposite (as was demonstrated in my branch of the code).

>
> Each bug in Ext-JS's selector engine necessarily propagates to a higher
> level. When the selector engine's behavior is changed, that change is
> propagated to all of the higher level dependencies. Such behavioral
> changes cause instability. The alternative to causing such changes is to
> not fix the bugs.

I haven't bothered tracking down all of their problems as nobody has
offered me any money to do so. :)

>
> Buyer Beware.
> The alternative for the end user is to not use include such things on
> the page. As I have always advised for the developer who is considering
> using a js library: Carefully review the source code of any js library
> before using it.

And in the case of a GP library, consider why in the hell you would
want such a thing in the first place.

>
> <https://groups.google.com/group/comp.lang.javascript/msg/c23d62071aad...>


>
>
>
> >> For example, if the default value for visibility is used, the element's
> >> visibility is calcualted as "inherit" (which is correct) and in that
> >> case, the result won't include that element. Except where it does, and
> >> that depends on the browser.
>
> > No, "inherit" would be incorrect for getComputedStyle.  For elements
> > without a visibility rule, "visible" is the expected result.  Now,
> > IE's "cascaded styles" will indeed return "inherit" as IE doesn't
> > compute styles at all, simply returning whatever is specified in
> > applicable rules (or the default value, which is "inherit" in this
> > case).
>
> That's correct.
>
> var a = Ext.query("{visibility=inherit}");
>
> The result of that in Ext shows that it does not work consistently
> either, and a.length will be 0, depending on the browser. This is due to
> the fact that it relies on Ext.Dom.getStyle, which, like most everything
> in Ext-JS, is very broken.

But they do have some nice graphics. :)

>
> > Regardless, I'm sure that ExtJS fails to account for this (among many
> > other things).  Just like jQuery!  :)
>
> >> But that is about Ext-JS (big version), not Sencha. In Sencha, all of
> >> this stuff throws errors.
>
> > Of course as it has no query engine; it simply hands off all queries
> > to QSA.
>
> If it had simply handed queries off to `querySelectorAll`, it would not
> have created as many problems.

Yes, I forgot about their inexplicable preprocessing.

>
> Extra effort was required to split on "," and create a loop, adding
> duplicates to the returned result.

Clearly tacked on my author(s) who had no idea what they were doing (a
common theme with these things). Who knows what they were thinking as
there are no explanatory comments.

>
> So while they do use querySelectorAll, they go to a lot of extra effort
> to complicate it and create problems. Why they expended this extra
> effort, I cannot say.

Only they can and they haven't. I suspect they will quietly remove
that code some time in the near future.

>
> The code with comments being blatantly false could be attributed to haste.

For such a Frankenstein-like effort it probably is. Much of it sounds
like it is describing ExtJS.

>
>
>
> >> (I've got a some errands to do, so I'm going to post the rest of this
> >> here wihout editing)
>
> >> | * E{display=none} css value "display" that equals "none"
> >> | * E{display^=none} css value "display" that starts with "none"
> >> | * E{display$=none} css value "display" that ends with "none"
> >> | * E{display*=none} css value "display" that contains the substring
> >> | "none"
>
> > There's not a chance in hell they got any of those right cross-
> > browser.
>
> You reviewed Ext.Dom.getStyle and, as you pointed out,
> `hasRightMarginBug` is completely missing for the script.

Haste makes waste. :)

>
> "hasRightMarginBug" in Ext.platform
>
> false
>
> It seems they forgot to include that property, though continue to
> reference it. Since the resolution results in undefined and since
> undefined evaluates to false, any code that uses that identifier in a
> boolean context is completely useless and dead code.

In a way, that describes the entire script. I can't think of one
thing they did right. And there's so much blatantly wrong that it
might as well be rewritten from scratch.

>
> And so all of the:
>
> | if (Ext.platform.hasRightMarginBug && marginRightRe.test(prop) && out
> | != '0px') {
> |     display = this.getStyle('display');
> |     el.style.display = 'inline-block';
> |     result = view.getComputedStyle(el, '');
> |     el.style.display = display;
> | }
>
> is dead code and will never be evaluated.

Yes, dead weight.

>
> >> | * E{display!=none} css value "display" that does not equal "none"
> >> |
> >> |
> >> |
> >> | This class is a singleton and cannot be created directly.
>
> > It's neither a class nor a singleton.
>
> >> | Public Properties
>
> > All JS properties are public.
>
> >> | Property Defined By
> >> | matchers : Object
> >> | Collection of matching regular expressions and code snippets. Each
> >> | capture group within () will be replace the {} in ...
> >> | Collection of matching regular expressions and code snippets. Each
> >> | capture group within () will be replace the {} in the select statement
> >> | as specified by their index.
> >> | DomQuery
> >> | pseudos : Object
> >> | Object hash of "pseudo class" filter functions which are used when
> >> | filtering selections. Each function is passed two ...
>
> > Oh God.  As usual, these types of projects get ten steps ahead of
> > themselves.  I mean, it's 2010 and their basic queries are still
> > broken.  What's the point of piling all of this other nonsense on top?
>
> > [snip more delusions]
>
> Although library author is free to make any design decision he chooses,
> if the design decisions violate the CSS specifications and drafts (and
> these do), then the code cannot honestly be said to be CSS3 compliant.

There's very little CSS3 in Sencha, despite the disingenuous ad
campaign. Not much HTML5 either. Who knew marketers lied? :)

>
> Ext-JS claims "DomQuery supports most of the CSS3 selectors spec, along
> with some custom selectors and basic XPath". Whether Ext supports more
> than half of CSS3 selectors depends on the browser and the claim of
> "basic XPath" support is false (possibly outdated documentation from
> previous jQuery copying).

Probably.

I can't think of one of those that has really made an impact on the
Web though. Hopefully this will be just one more whale on the beach.

>
> The difference between marketing and engineering seems to not very well
> perceived.

If at all. The first question on the mind of Web developers seems to
be about popularity. They seem to think that popularity implies
continuous improvement and easy support, despite overwhelming evidence
to the contrary (see jQuery).

>
> Looking at demos is much more accessible than being able to make
> assessments of front end code quality.

Yes, by a long shot. And once they fall in love with the demos, most
developers don't want to hear about the bad code, compatibility
issues, lack of competent support, etc. They want something they can
copy and paste and ship today (and never mind the ramifications for
their clients).

>
> The number of individuals who look at the demos is going to be larger
> than the number of individuals who review the code. This is not surprising.

Yes. What is surprising is that anyone would listen to "experts" who
advocate scripts based on pretty graphics and snazzy demos.

>
> What is surprising is that prior to the recent angel investment into
> Sencha, they did not a few qualified individuals to do code review on
> it.

The Ext people think they are qualified, though that misconception has
likely been shaken at this point (unless they are locked up in sound-
proof booths with blinders on).

> This would not have been much investment and could have helped avoid
> such an amazing waste of money[1].

Yes. It's a shame to see people throwing good money after bad.

>
>  From the perspective of the investor who does not have any idea of the
> code quality, he could employ two highly qualified individuals for a
> maximum of one week each to review and assess the code at a cost under
> 10,000 USD.

Hell, I did it for free. Well, not really. I just touched on the
highlights here. I charged for the full analysis. Some people
realize that spending a little money to avoid wasting a lot makes good
business sense. It didn't take me a week and I didn't charge anywhere
near $5,000. But I could definitely write a similar (and much better)
framework in that neighborhood (and did so for one client about a year
back).

> In reality, it is not hard to look at the code and find a
> mistake at line 1:
>
>    window.undefined = window.undefined;

Yeah, that was a bad omen.

>
> - and continue to find a very high defect rate and significantly bad
> defects that we have covered and other glaring errors and design
> mistakes that were covered by RobG[2].

No, not hard at all. So you have to wonder about the *best*
developers they have on the project and what the hell they are doing
all day.

>
> Having volunteered so much free time over the years to spread knowledge
> of web development, it seems that too few care about the code.

Oh, I bet somebody from Sencha is taking notes. The question is
whether they have anyone on the payroll who can interpret them in a
timely fashion.

>
> The financial losses from projects debilitated by bad code is real.
>
> Bad code costs money.
>
> Bad code hides bugs that might not surface immediately.
>
> Tangled messy code can't be changed easily. The time involved to add a
> new feature can be double, and then coming back to regression testing,
> bugfixes for all of the change propagation.

Sure. Ask anyone unfortunate enough to be saddled with Dojo.

>
> This can lead to losing customers from bugs and even project failure
> (and I have swam from such sunken ships, having failed to inspire the
> captain into smart choices).
> It is not easy to measure how much money
> was wasted by bad code. There is never a "good code" control group and
> problems and debt compound.
>
> Ext-JS is very buggy. It is awful code.

As improbably as it may seem. that's an understatement.

>
> Any javascript developer who Ext-JS either has not read the source code
> enough, is not capable of understanding the problems, or has read and
> understood the problems but has not appreciated the consequences deeply.

Happens all the time.

> The choice to use Ext-JS is a substantially irresponsible and uninformed
> decision that puts quality and long-term success of his project at risk.

And the choice to use Sencha Touch is exponentially worse, which could
only be described as insane.

Garrett Smith

unread,
Jul 19, 2010, 3:32:25 PM7/19/10
to
That's not a standard and not any browser documentation. It does not
explain how to force a repaint. I find it painful to watch that man
speak. Is there particular citation that you would like to reference?
You can enter the text.
--
Garrett

kangax

unread,
Jul 19, 2010, 9:52:27 PM7/19/10
to

What he talks about is also partially present in these documents (by
same author):

<https://developer.mozilla.org/en/Notes_on_HTML_Reflow>
<https://developer.mozilla.org/en/Introduction_to_Layout_in_Mozilla>

I would also like to (once again) quote Dave Hyat of WebKit fame
(<www.stubbornella.org/content/2009/03/27/reflows-repaints-css-performance-making-your-javascript-slow/#comment-13157>):


<quote>

[...]

element.style.width = ‘50px’;
var v = element.offsetWidth;
element.style.width = ‘55px’;
v = element.offsetWidth;

You just caused two reflows to happen, since asking for offsetWidth
forced the element to reflow in order to answer you question (because it
had a pending change to style).

This is the real performance bottleneck to be wary of. Browsers are
smart about avoiding reflows when they can, but if you create code that
forces a reflow in order to answer a question, then you can create
severe performance bottlenecks.

[...]

</quote>

--
kangax

David Mark

unread,
Jul 19, 2010, 10:33:20 PM7/19/10
to
> (<www.stubbornella.org/content/2009/03/27/reflows-repaints-css-performa...>):

>
> <quote>
>
> [...]
>
> element.style.width = ‘50px’;
> var v = element.offsetWidth;
> element.style.width = ‘55px’;
> v = element.offsetWidth;
>
> You just caused two reflows to happen, since asking for offsetWidth
> forced the element to reflow in order to answer you question (because it
> had a pending change to style).

Of course, if the element is absolutely positioned, the browser won't
have to re-flow the entire document. That's something else to keep in
mind.

>
> This is the real performance bottleneck to be wary of. Browsers are
> smart about avoiding reflows when they can, but if you create code that
> forces a reflow in order to answer a question, then you can create
> severe performance bottlenecks.
>

Yes and unnecessary repaints are even worse. Not just for
performance, but they can wreak havoc on aesthetics as well.

Garrett Smith

unread,
Jul 20, 2010, 1:04:41 AM7/20/10
to

That document discusses reflow (in Gecko).

> <https://developer.mozilla.org/en/Introduction_to_Layout_in_Mozilla>
>

That document discusses painting (in Gecko) and states the event that
triggers it as being content received. It does not state which mechanism
is responsible for triggering repainting.

Nicole Sullivan's blog? I'll normall pass on that one. It seems you've
got a disagreement with the fact that there's no way to force the
browser to repaint, but you won't actually say that and just post up links.

So lets see what the OO-CSS expert has to say.

| A repaint occurs when changes are made to an elements skin that
} changes visibility, but do not affect its layout

The repaint may occur after a request for a style change has been made,
but that won't happen every time.

Try writing a loop-based animation and if you can get it to update, then
you've gotten a repaint to occur.

var i;
for(i = 0; i < 1000; i++) {
moveDiv();
}

function moveDiv(){
document.getElementById("a").style.left = i + "px";
repaint();
}

function repaint() {
// your code here.
}

Also do realize that when you flesh out the repaint, even if you can get
it to work (it won't happen, but try if you like), then the fact that it
works could not be used as argument that a repaint can be forced; it
would only show that you did something and then a repaint occurred.

>
>
> <quote>
>
> [...]
>
> element.style.width = ‘50px’;
> var v = element.offsetWidth;
> element.style.width = ‘55px’;
> v = element.offsetWidth;
>
> You just caused two reflows to happen, since asking for offsetWidth
> forced the element to reflow in order to answer you question (because it
> had a pending change to style).
>

Does not state that reading `offsetWidth` will trigger a repaint?

No, it doesn't. That's a good thing for Mr Hyatt because that would be a
false statement.

What it says is -- well it says exactly what it says, which is short and
simple, so I won't try and paraphrase.

And so reading offsetWidth to trigger a repaint would be a demonstration
of a misconception that the consequences of doing that would cause a
repaint (it won't).

> This is the real performance bottleneck to be wary of. Browsers are
> smart about avoiding reflows when they can, but if you create code that
> forces a reflow in order to answer a question, then you can create
> severe performance bottlenecks.
>

Informative, but not any evidence that a repaint can be triggered.
--
Garrett

kangax

unread,
Jul 20, 2010, 2:57:18 AM7/20/10
to

Yes. You mentioned browser documentation. That's the one I'm aware of,
and it's related to the topic discussed here.

>
>> <https://developer.mozilla.org/en/Introduction_to_Layout_in_Mozilla>
>>
>
> That document discusses painting (in Gecko) and states the event that
> triggers it as being content received. It does not state which mechanism
> is responsible for triggering repainting.

But the previous one does, afaict (although vaguely).

"A style change reflow is performed when the presentation shell's global
stylistic information is changed; e.g., addition or removal of a style
sheet, a change to the shell's default font."

>
>> I would also like to (once again) quote Dave Hyat of WebKit fame
>> (<www.stubbornella.org/content/2009/03/27/reflows-repaints-css-performance-making-your-javascript-slow/#comment-13157>):
>>
>>
>
> Nicole Sullivan's blog? I'll normall pass on that one.

What's with ad hominem? :) I'm failing to see how it matters on which
blog WebKit developer explains when/how reflow occurs in WebKit?

> It seems you've
> got a disagreement with the fact that there's no way to force the
> browser to repaint, but you won't actually say that and just post up links.

Wait, didn't I start original reply with "There certainly are observable
ways to trigger ..."? Is that "not actually saying it"?

>
> So lets see what the OO-CSS expert has to say.

I linked to Hyat's comment though, not post itself. He even says that
most of what she says doesn't apply to WebKit in an earlier comment:

<quote>
Just FYI, very little of what you’ve written here applies to WebKit.
There’s nothing overly scary about either a typical reflow or repaint in
WebKit as long as what you do doesn’t affect the geometry of the entire
page.
</quote>

>
> | A repaint occurs when changes are made to an elements skin that
> } changes visibility, but do not affect its layout
>
> The repaint may occur after a request for a style change has been made,
> but that won't happen every time.
>
> Try writing a loop-based animation and if you can get it to update, then
> you've gotten a repaint to occur.
>
> var i;
> for(i = 0; i < 1000; i++) {
> moveDiv();
> }
>
> function moveDiv(){
> document.getElementById("a").style.left = i + "px";
> repaint();
> }
>
> function repaint() {
> // your code here.
> }
>
> Also do realize that when you flesh out the repaint, even if you can get
> it to work (it won't happen, but try if you like), then the fact that it
> works could not be used as argument that a repaint can be forced; it
> would only show that you did something and then a repaint occurred.

Given lack of standard or definitive documentation, observations is the
only thing we can work with. In Chrome your code does in fact trigger
repaints every time style is queried (screenshot —
<http://twitpic.com/26xr2n/full>).

Look at multiple "layout" events, followed by "Style recalculation".

That's what I meant by "observable ways to trigger reflow/repaint".

>
>>
>>
>> <quote>
>>
>> [...]
>>
>> element.style.width = ‘50px’;
>> var v = element.offsetWidth;
>> element.style.width = ‘55px’;
>> v = element.offsetWidth;
>>
>> You just caused two reflows to happen, since asking for offsetWidth
>> forced the element to reflow in order to answer you question (because it
>> had a pending change to style).
>>
>
> Does not state that reading `offsetWidth` will trigger a repaint?
>
> No, it doesn't. That's a good thing for Mr Hyatt because that would be a
> false statement.
>
> What it says is -- well it says exactly what it says, which is short and
> simple, so I won't try and paraphrase.
>
> And so reading offsetWidth to trigger a repaint would be a demonstration
> of a misconception that the consequences of doing that would cause a
> repaint (it won't).
>
>> This is the real performance bottleneck to be wary of. Browsers are
>> smart about avoiding reflows when they can, but if you create code that
>> forces a reflow in order to answer a question, then you can create
>> severe performance bottlenecks.
>>
> Informative, but not any evidence that a repaint can be triggered.

He said "...but if you create code that forces a reflow". As I read it,
that means you _can_ create code that forces reflow. Why would he talk
about something nonexistent?

What exactly triggers reflow/repaint is a different story and probably
varies among browsers.

--
kangax

Garrett Smith

unread,
Jul 20, 2010, 3:02:55 AM7/20/10
to
On 2010-07-19 01:28 AM, David Mark wrote:
> On Jul 19, 3:37 am, Garrett Smith<dhtmlkitc...@gmail.com> wrote:
>> On 2010-07-18 08:26 PM, David Mark wrote:> On Jul 18, 10:15 pm, Garrett Smith<dhtmlkitc...@gmail.com> wrote:
>>>> On 2010-07-18 02:42 PM, David Mark wrote:
>>
>>>>> On Jul 18, 5:18 pm, Garrett Smith<dhtmlkitc...@gmail.com> wrote:
>>
>>>>> [...]
>>
>>>>>> ext-touch-debug.js..............458k

[...]

> Where does this "native-first dual approach" term come from? I know


> what you mean, but I've never heard it called that.

I have named the query antipattern Native First Dual Approach, or "NFD
approach".

The NFD approach is to try to use `document.querySelectorAll`, where
supported and where it is either unsupported or where it throws an
error, a fallback selector matching engine is used.

Libraries that use NFD include jQuery, YUI, and Ext-js, among others.

Native-first Dual Approach Diagram

(query input)
|
<Native QSA Support?>
Y N
| |
| |
[Try Use QSA] +-- [Use Fallback]
| / |
<error thrown?> / <Fallback Supports Input?>
Y N-+ Y N
| /| | [Throw error]
| / | | |
[Use Fallback*] | [perform match |
| and return result] |
| | |
[return result] | |
| | |
END END END

Diagram of native-first dual approach. Notice the three different
possible endings.

Most queries with attribute or pseudoclass selectors will have a
different path depending on the browser, version, and rendering mode.

Libraries that use NFD include jQuery, YUI, and Ext-js, among others.
Dojo does the opposite. Dojo uses the fallback first and then, if that
works, tries to use querySelectorAll. This might seem odd, but when the
problems with NFD query engine is understood, it is much safer. Another
approach is to filter all input by defining an `isValidQuery` type of
function to make sure that it is valid.


CSS Selectors are recursively defined:

| selector
| : simple_selector [ combinator selector | S+ [ combinator? selector
| ]? ]?

As such, it is not possible to parse one with a javascript RegExp
because javascript RegExps are not recursive. The input must be parsed.

Normative Reference:
CSS2.1 <http://www.w3.org/TR/CSS2/grammar.html#grammar>

>>
>> Each bug in Ext-JS's selector engine necessarily propagates to a higher
>> level. When the selector engine's behavior is changed, that change is
>> propagated to all of the higher level dependencies. Such behavioral
>> changes cause instability. The alternative to causing such changes is to
>> not fix the bugs.
>
> I haven't bothered tracking down all of their problems as nobody has
> offered me any money to do so. :)
>

[...]

>>
>>> Regardless, I'm sure that ExtJS fails to account for this (among many
>>> other things). Just like jQuery! :)
>>
>>>> But that is about Ext-JS (big version), not Sencha. In Sencha, all of
>>>> this stuff throws errors.
>>
>>> Of course as it has no query engine; it simply hands off all queries
>>> to QSA.
>>
>> If it had simply handed queries off to `querySelectorAll`, it would not
>> have created as many problems.
>
> Yes, I forgot about their inexplicable preprocessing.
>

It's like car with shoes for wheels. I could never forget that.

>>
>> Extra effort was required to split on "," and create a loop, adding
>> duplicates to the returned result.
>
> Clearly tacked on my author(s) who had no idea what they were doing (a
> common theme with these things). Who knows what they were thinking as
> there are no explanatory comments.
>

There are from me. I explain exactly what the code does. I did not have
to test it before making the analysis to know exactly how the code would
perform and where it would fail.

I was able to find the defects very quickly.

>>
>> The code with comments being blatantly false could be attributed to haste.
>
> For such a Frankenstein-like effort it probably is. Much of it sounds
> like it is describing ExtJS.
>

Actually the current Ext-JS version does not support XPath. The code
comment appears to be a hold-over from past jQuery copying efforts which
had, in older versions of Ext, supported XPath.

Regardless, to code comment is wrong. The code does not do what it says
it does.

>>
>>>> | * E{display!=none} css value "display" that does not equal "none"
>>>> |
>>>> |
>>>> |
>>>> | This class is a singleton and cannot be created directly.
>>
>>> It's neither a class nor a singleton.
>>

It is a singleton in the sense that there is only one of them.

>>>> | Public Properties
>>
>>> All JS properties are public.
>>

The various "privete" code comments are false claims.

[...]

>>
>> Although library author is free to make any design decision he chooses,
>> if the design decisions violate the CSS specifications and drafts (and
>> these do), then the code cannot honestly be said to be CSS3 compliant.
>
> There's very little CSS3 in Sencha, despite the disingenuous ad
> campaign. Not much HTML5 either. Who knew marketers lied? :)
>

The source code explains what it does. Those who are unable or unwilling
to analyze the source code won't know. Fortunately that does not include
me.

The thread isn't as negative as some might see it. I showed that I can
provide good code reviews that anyone at any level of experience -- the
authors included -- should be able to appreciate. The review on the
query engine provided a good model for making code review. I would like
to encourage such reviews more.

In addition to writing code, I provide assessments of code (in-house
reviews) and mentor other developers. If the code is not awful -- and
unfortunately most front end code is -- I can show how the code can be
made to run twice as fast, on more devices, at less than half the size.

>>
>> Ext-JS claims "DomQuery supports most of the CSS3 selectors spec, along
>> with some custom selectors and basic XPath". Whether Ext supports more
>> than half of CSS3 selectors depends on the browser and the claim of
>> "basic XPath" support is false (possibly outdated documentation from
>> previous jQuery copying).
>
> Probably.
>


>>


>>>> The `selectValue` and `selectNumber` methods are missing altogether from
>>>> Sencha.
>>
>>> There's a lot of that going on. They were clearly pressed for time.
>>

The documentation does not reflect reality.

>>
>> The difference between marketing and engineering seems to not very well
>> perceived.
>
> If at all. The first question on the mind of Web developers seems to
> be about popularity. They seem to think that popularity implies
> continuous improvement and easy support, despite overwhelming evidence
> to the contrary (see jQuery).
>

Appeal to popularity.

>>
>> The number of individuals who look at the demos is going to be larger
>> than the number of individuals who review the code. This is not surprising.
>
> Yes. What is surprising is that anyone would listen to "experts" who
> advocate scripts based on pretty graphics and snazzy demos.
>

What else can they listen to? You think they want to come on usenet and
read code reviews? And if they do, do you think they can understand your
code reviews? Try and read the code review you wrote from the point of
view of someone who is ignorant.

My code review outline:
<http://groups.google.com/group/comp.lang.javascript/msg/316e025b15e466a3?dmode=source>

and follow-up:
<http://groups.google.com/group/comp.lang.javascript/msg/c8f81b8b3486e3e8?dmode=source>

Should those be linked from the the Code Guidelines doc and Code Review
Guidelines docs?

>>
>> What is surprising is that prior to the recent angel investment into
>> Sencha, they did not a few qualified individuals to do code review on
>> it.
>
> The Ext people think they are qualified, though that misconception has
> likely been shaken at this point (unless they are locked up in sound-
> proof booths with blinders on).
>

What the Ext people think of themselves does not matter.

"Is the salesman trying to make the product look good? Is there anything
that he might not have told me, out of ignorance or otherwise?"

>> This would not have been much investment and could have helped avoid
>> such an amazing waste of money[1].
>
> Yes. It's a shame to see people throwing good money after bad.
>

They seem misguided.

>>
>> From the perspective of the investor who does not have any idea of the
>> code quality, he could employ two highly qualified individuals for a
>> maximum of one week each to review and assess the code at a cost under
>> 10,000 USD.
>
> Hell, I did it for free. Well, not really. I just touched on the
> highlights here. I charged for the full analysis. Some people

So they paid you? You wrote above that nobody offered you any money to
do so.

> realize that spending a little money to avoid wasting a lot makes good


> business sense. It didn't take me a week and I didn't charge anywhere
> near $5,000. But I could definitely write a similar (and much better)
> framework in that neighborhood (and did so for one client about a year
> back).
>

The investors may not have known that such an analysis was even
possible. Can the source code be analyzed by an independent third party?
Who knows?

Returning to the car-purchasing example, a buyer might want to take the
car he so likes (nice radio, comfy seats, looks cool, etc), down to his
own mechanic for an analysis.

Someone in the predicament of making assessments of the framework, but
not having the skill to do so does not need a "mobile applications
development framework shop"! What he needs is one or a few individuals
who are qualified of making an assessment.

Basically, what the investors needed was an expert analysis prior.

The uninformed cannot know the least amount of time it will take to make
such assessment. A very complicated framework that had good code and a
sophisticated build process might take considerable time to and effort
investigate and drawing metrics for it is going to be very involved and
complicated.

It turned out that such rigorous investigations would not have been
necessary in this case because the code is so bad that it can be
dismissed. Continued analysis beyond that point is pointless.

What is the point in finding out how they've packaged and organized
they're bugs? By accident, the `hasRightMarginBug` identifier was found
to be absent and with the many false comments about properties being
"private" (they aren't).

>>
>> Having volunteered so much free time over the years to spread knowledge
>> of web development, it seems that too few care about the code.
>
> Oh, I bet somebody from Sencha is taking notes. The question is
> whether they have anyone on the payroll who can interpret them in a
> timely fashion.
>

I don't much care for giving free help to the Ext-JS guys. About 8
months ago, a colleage of mine informed me that they were in need of a
JS developer. I re-familiarized myself with their code and found room
for major improvement.

And so I gave my colleage the "OK" to pass on my contact info. So,
rather helping them, I get to do remote project postmortem, pro bono.

[...]

>>
>> Any javascript developer who Ext-JS either has not read the source code
>> enough, is not capable of understanding the problems, or has read and
>> understood the problems but has not appreciated the consequences deeply.
>
> Happens all the time.
>
>> The choice to use Ext-JS is a substantially irresponsible and uninformed
>> decision that puts quality and long-term success of his project at risk.
>
> And the choice to use Sencha Touch is exponentially worse, which could
> only be described as insane.

No, it could be described as misguided or not fully informed, or
informed, but not understanding the ramifications.

Do not consider "misguided" to be an insult; it is a position that most
of us are in, in more ways than we realize.
--
Garrett

David Mark

unread,
Jul 20, 2010, 4:10:18 AM7/20/10
to
On Jul 20, 3:02 am, Garrett Smith <dhtmlkitc...@gmail.com> wrote:
> On 2010-07-19 01:28 AM, David Mark wrote:
>
> > On Jul 19, 3:37 am, Garrett Smith<dhtmlkitc...@gmail.com>  wrote:
> >> On 2010-07-18 08:26 PM, David Mark wrote:>  On Jul 18, 10:15 pm, Garrett Smith<dhtmlkitc...@gmail.com>    wrote:
> >>>> On 2010-07-18 02:42 PM, David Mark wrote:
>
> >>>>> On Jul 18, 5:18 pm, Garrett Smith<dhtmlkitc...@gmail.com>      wrote:
>
> >>>>> [...]
>
> >>>>>> ext-touch-debug.js..............458k
>
> [...]
>
> > Where does this "native-first dual approach" term come from?  I know
> > what you mean, but I've never heard it called that.
>
> I have named the query antipattern Native First Dual Approach, or "NFD
> approach".

But who knows that? Using this abbreviation without explaining
exactly what it means will likely lead to confusion.

>
> The NFD approach is to try to use `document.querySelectorAll`, where
> supported and where it is either unsupported or where it throws an
> error, a fallback selector matching engine is used.

Yes.

>
> Libraries that use NFD include jQuery, YUI, and Ext-js, among others.
>
> Native-first Dual Approach Diagram
>
>     (query input)
>          |
> <Native QSA Support?>
>   Y              N
>   |              |
>   |              |
> [Try Use QSA]   +-- [Use Fallback]
>    |                /     |
>   <error thrown?>  / <Fallback Supports Input?>
>    Y           N-+        Y          N
>    |            /|        |     [Throw error]
>    |           / |        |              |
> [Use Fallback*] |   [perform match      |
>                  |    and return result] |
>                  |          |            |
>             [return result] |            |
>                    |        |            |
>                   END       END         END
>
> Diagram of native-first dual approach. Notice the three different
> possible endings.
>
> Most queries with attribute or pseudoclass selectors will have a
> different path depending on the browser, version, and rendering mode.

Yes. It's a completely insane design for a browser script. And the
sad thing is that most jQuery scripts (including jQuery itself) rely
on queries for everything.

>
> Libraries that use NFD include jQuery, YUI, and Ext-js, among others.

Yes.

> Dojo does the opposite. Dojo uses the fallback first and then, if that
> works, tries to use querySelectorAll.

Whatever.

> This might seem odd, but when the
> problems with NFD query engine is understood, it is much safer.

I don't see how. Their fallback is complete BS. So what will it do
when QSA contradicts it?

> Another
> approach is to filter all input by defining an `isValidQuery` type of
> function to make sure that it is valid.

Yes, that is the only 100% solution. Of course, most of the offending
libraries needn't bother as they support very few browsers that lack
QSA and will likely stop "supporting" the ones that don't (e.g. IE <
8) very soon. In the query department, they'll be reduced to wrappers
for QSA and will then have more time to find other things to screw up.

>
> CSS Selectors are recursively defined:
>
> | selector
> |  : simple_selector [ combinator selector | S+ [ combinator? selector
> | ]? ]?
>
> As such, it is not possible to parse one with a javascript RegExp
> because javascript RegExps are not recursive. The input must be parsed.

No question. That's what I did.

>
> Normative Reference:
> CSS2.1 <http://www.w3.org/TR/CSS2/grammar.html#grammar>
>
>
>
> >> Each bug in Ext-JS's selector engine necessarily propagates to a higher
> >> level. When the selector engine's behavior is changed, that change is
> >> propagated to all of the higher level dependencies. Such behavioral
> >> changes cause instability. The alternative to causing such changes is to
> >> not fix the bugs.
>
> > I haven't bothered tracking down all of their problems as nobody has
> > offered me any money to do so.  :)
>
> [...]
>
>
>
> >>> Regardless, I'm sure that ExtJS fails to account for this (among many
> >>> other things).  Just like jQuery!  :)
>
> >>>> But that is about Ext-JS (big version), not Sencha. In Sencha, all of
> >>>> this stuff throws errors.
>
> >>> Of course as it has no query engine; it simply hands off all queries
> >>> to QSA.
>
> >> If it had simply handed queries off to `querySelectorAll`, it would not
> >> have created as many problems.
>
> > Yes, I forgot about their inexplicable preprocessing.
>
> It's like car with shoes for wheels. I could never forget that.

I try not to retain every little screw-up I see in JS libraries.
Thankfully I don't need to (unlike those who insist on relying on such
things).

>
>
>
> >> Extra effort was required to split on "," and create a loop, adding
> >> duplicates to the returned result.
>
> > Clearly tacked on my author(s) who had no idea what they were doing (a
> > common theme with these things).  Who knows what they were thinking as
> > there are no explanatory comments.
>
> There are from me. I explain exactly what the code does.

I know what the code does. I don't know what sort of thinking went
into the authors' decision-making. There's no convenient explanation
for such lunacy.

> I did not have
> to test it before making the analysis to know exactly how the code would
> perform and where it would fail.

Yes, seeing that code the first time was a spit-take moment for me as
well.

>
> I was able to find the defects very quickly.

Yes. It's amazing that virtually every line of code in the thing is
defective. Like shooting fish in a barrel. Of course, the
uninitiated can't fathom this, so I often hear the knee-jerk "wow you
must have spent a lot of time on that" reaction. The reality is the
authors' didn't spend near enough time. The fact that all of the
"majors" are similarly defective leads to "aw, you just don't like
frameworks" retorts. If you don't know any better, reviews are easy
to misinterpret.

>
>
>
> >> The code with comments being blatantly false could be attributed to haste.
>
> > For such a Frankenstein-like effort it probably is.  Much of it sounds
> > like it is describing ExtJS.
>
> Actually the current Ext-JS version does not support XPath.

I thought I saw it in there. Whatever.

> The code
> comment appears to be a hold-over from past jQuery copying efforts which
> had, in older versions of Ext, supported XPath.
>
> Regardless, to code comment is wrong. The code does not do what it says
> it does.

Clearly.

>
>
>
> >>>> | * E{display!=none} css value "display" that does not equal "none"
> >>>> |
> >>>> |
> >>>> |
> >>>> | This class is a singleton and cannot be created directly.
>
> >>> It's neither a class nor a singleton.
>
> It is a singleton in the sense that there is only one of them.

But that carries no weight in JS as there are only one of any object.
There are no classes of objects, so there is no such differentiation
to be made.

>
> >>>> | Public Properties
>
> >>> All JS properties are public.
>
> The various "privete" code comments are false claims.

Yes. And they confuse the hell out of people.

>
> [...]
>
>
>
> >> Although library author is free to make any design decision he chooses,
> >> if the design decisions violate the CSS specifications and drafts (and
> >> these do), then the code cannot honestly be said to be CSS3 compliant.
>
> > There's very little CSS3 in Sencha, despite the disingenuous ad
> > campaign.  Not much HTML5 either.  Who knew marketers lied?  :)
>
> The source code explains what it does. Those who are unable or unwilling
> to analyze the source code won't know. Fortunately that does not include
> me.

Unfortunately, those who would use something like this are unlikely to
bother. Anyone who knows anything about this stuff would throw it
away after reading the first line.

>
> The thread isn't as negative as some might see it.

It's really hard to be positive about something so negative. That's
another thing that the masses seem to misunderstand. These things
really are incompetently done. There's no dancing around that fact.
It's like they'd prefer to be lied to than to hear that truth.

> I showed that I can
> provide good code reviews that anyone at any level of experience -- the
> authors included -- should be able to appreciate.

I thought this was my review. Granted you chipped in a few bits. If
they have any sense at all, the authors are taking notes. Of course,
you can't really learn browser scripting from reading a review. There
wasn't time to turn every point into a tutorial.

> The review on the
> query engine provided a good model for making code review. I would like
> to encourage such reviews more.

Then encourage them more. :)

>
> In addition to writing code, I provide assessments of code (in-house
> reviews) and mentor other developers.

Yes, I do as well. For those who want to learn (and actually save
time rather than perpetually flushing it down the toilet). Most
don't, apparently seeing Web development as some sort of puzzle that
they need to solve on their own.

> If the code is not awful -- and
> unfortunately most front end code is -- I can show how the code can be
> made to run twice as fast, on more devices, at less than half the size.

I often find there's room for more dramatic improvement than that. I
can remember a Dojo grid that took *minutes* to sort and I got that
down to less than ten seconds. How? By eliminating unnecessary
reflows/repaints. How did I do that? By eliminating function calls
in between updating the cells. Of course, there was no guarantee that
those reflows/repaints would occur on each call, but they clearly did
often enough to decrease performance by roughly a factor of 10. I've
made similar improvements in similar fashion to hundreds of
functions. The rules don't seem to change, nor do the percentage of
people who understand them (which is very small).

>
>
>
> >> Ext-JS claims "DomQuery supports most of the CSS3 selectors spec, along
> >> with some custom selectors and basic XPath". Whether Ext supports more
> >> than half of CSS3 selectors depends on the browser and the claim of
> >> "basic XPath" support is false (possibly outdated documentation from
> >> previous jQuery copying).
>
> > Probably.
>
> >>>> The `selectValue` and `selectNumber` methods are missing altogether from
> >>>> Sencha.
>
> >>> There's a lot of that going on.  They were clearly pressed for time.
>
> The documentation does not reflect reality.

Neither does the code. If only they did not reflect reality in the
same way. :)

>
>
>
> >> The difference between marketing and engineering seems to not very well
> >> perceived.
>
> > If at all.  The first question on the mind of Web developers seems to
> > be about popularity.  They seem to think that popularity implies
> > continuous improvement and easy support, despite overwhelming evidence
> > to the contrary (see jQuery).
>
> Appeal to popularity.

Yes. I find such appeals revolting. Programming is a science after
all. And these scripts are 100% transparent. It's not like being
stuck with a buggy OS (as some pseudo-intellectual observers like to
compare them to).

>
>
>
> >> The number of individuals who look at the demos is going to be larger
> >> than the number of individuals who review the code. This is not surprising.
>
> > Yes.  What is surprising is that anyone would listen to "experts" who
> > advocate scripts based on pretty graphics and snazzy demos.
>
> What else can they listen to? You think they want to come on usenet and
> read code reviews?

Some do, if only for the entertainment value. A few may actually
learn something. The rest don't understand the words, so focus on the
pervasive negativity, which makes them feel compassion for the bums
that are trying to fleece them into using bogus scripts, buying
worthless books, etc.

> And if they do, do you think they can understand your
> code reviews?

There's nothing particularly subterranean about my reviews
(particularly not this one).


> Try and read the code review you wrote from the point of
> view of someone who is ignorant.

Well, if they don't know JS at all (which is a good bet as the authors
of these scripts sure don't).

>
> My code review outline:
> <http://groups.google.com/group/comp.lang.javascript/msg/316e025b15e46...>
>
> and follow-up:
> <http://groups.google.com/group/comp.lang.javascript/msg/c8f81b8b3486e...>


>
> Should those be linked from the the Code Guidelines doc and Code Review
> Guidelines docs?

I don't understand the question.

>
>
>
> >> What is surprising is that prior to the recent angel investment into
> >> Sencha, they did not a few qualified individuals to do code review on
> >> it.
>
> > The Ext people think they are qualified, though that misconception has
> > likely been shaken at this point (unless they are locked up in sound-
> > proof booths with blinders on).
>
> What the Ext people think of themselves does not matter.

The point is that they don't seek out qualified opinions as they think
their own qualify as such (see Google, Yahoo, etc.)

>
> "Is the salesman trying to make the product look good? Is there anything
> that he might not have told me, out of ignorance or otherwise?"

Who are you quoting?

>
> >> This would not have been much investment and could have helped avoid
> >> such an amazing waste of money[1].
>
> > Yes.  It's a shame to see people throwing good money after bad.
>
> They seem misguided.

And lighter in the wallet. :)

>
>
>
> >>   From the perspective of the investor who does not have any idea of the
> >> code quality, he could employ two highly qualified individuals for a
> >> maximum of one week each to review and assess the code at a cost under
> >> 10,000 USD.
>
> > Hell, I did it for free.  Well, not really.  I just touched on the
> > highlights here.  I charged for the full analysis.  Some people
>
> So they paid you? You wrote above that nobody offered you any money to
> do so.

Not Ext. I reviewed the whole thing from stem to stern for a client.
And certainly Ext (er Sencha) has never been a client of mine.

>
> > realize that spending a little money to avoid wasting a lot makes good
> > business sense.  It didn't take me a week and I didn't charge anywhere
> > near $5,000.  But I could definitely write a similar (and much better)
> > framework in that neighborhood (and did so for one client about a year
> > back).
>
> The investors may not have known that such an analysis was even
> possible. Can the source code be analyzed by an independent third party?
> Who knows?

I'm sure the investors didn't know anything about the source code.
They were likely dazzled by the pretty graphics (which make up the
bulk of the archive).

>
> Returning to the car-purchasing example, a buyer might want to take the
> car he so likes (nice radio, comfy seats, looks cool, etc), down to his
> own mechanic for an analysis.
>
> Someone in the predicament of making assessments of the framework, but
> not having the skill to do so does not need a "mobile applications
> development framework shop"! What he needs is one or a few individuals
> who are qualified of making an assessment.
>
> Basically, what the investors needed was an expert analysis prior.

Of course. And they clearly didn't get one.

>
> The uninformed cannot know the least amount of time it will take to make
> such assessment. A very complicated framework that had good code and a
> sophisticated build process might take considerable time to and effort
> investigate and drawing metrics for it is going to be very involved and
> complicated.
>
> It turned out that such rigorous investigations would not have been
> necessary in this case because the code is so bad that it can be
> dismissed. Continued analysis beyond that point is pointless.

Like I said, I was pretty sure it was DOA on line 1. At least, that
was a pretty strong indicator. By the time I got three or four dozen
lines in, I was definitely sure. But I went ahead and read the rest.
It was good for a laugh anyway.

>
> What is the point in finding out how they've packaged and organized
> they're bugs? By accident, the `hasRightMarginBug` identifier was found
> to be absent and with the many false comments about properties being
> "private" (they aren't).

You should read Dojo some day. Now there's a comedy classic. :)

>
>
>
> >> Having volunteered so much free time over the years to spread knowledge
> >> of web development, it seems that too few care about the code.
>
> > Oh, I bet somebody from Sencha is taking notes.  The question is
> > whether they have anyone on the payroll who can interpret them in a
> > timely fashion.
>
> I don't much care for giving free help to the Ext-JS guys.

I don't either. That's why I don't solve *every* problem for them in
the reviews (much to the chagrin of some anonymous posters).

> About 8
> months ago, a colleage of mine informed me that they were in need of a
> JS developer.

They need more than one.

> I re-familiarized myself with their code and found room
> for major improvement.

Yes, they've got plenty of vacancies. :)

>
> And so I gave my colleage the "OK" to pass on my contact info. So,
> rather helping them, I get to do remote project postmortem, pro bono.

There seems to be a scene missing. (?)

>
> [...]
>
>
>
> >> Any javascript developer who Ext-JS either has not read the source code
> >> enough, is not capable of understanding the problems, or has read and
> >> understood the problems but has not appreciated the consequences deeply.
>
> > Happens all the time.
>
> >> The choice to use Ext-JS is a substantially irresponsible and uninformed
> >> decision that puts quality and long-term success of his project at risk.
>
> > And the choice to use Sencha Touch is exponentially worse, which could
> > only be described as insane.
>
> No, it could be described as misguided or not fully informed, or
> informed, but not understanding the ramifications.

I meant in light of this thread. Obviously, if they haven't read it
then they don't know.

>
> Do not consider "misguided" to be an insult

I don't consider it an insult any more than misinformed or even
ignorant. Of course some people are ignorant of the fact that
ignorance is not the same as stupidity.

> it is a position that most
> of us are in, in more ways than we realize.

Not me. I know exactly where I'm going. :)

Garrett Smith

unread,
Jul 20, 2010, 4:24:58 AM7/20/10
to

What ad hominem? Are you reading more into what I wrote?

What you seem to fail to grasp is that recalc != repaint. That is,
recalc is not causing pixels to be visully updated to the user.

A repaint is when the browser paints the pixels so they are visually
rendered.

>> It seems you've
>> got a disagreement with the fact that there's no way to force the
>> browser to repaint, but you won't actually say that and just post up
>> links.
>
> Wait, didn't I start original reply with "There certainly are observable
> ways to trigger ..."? Is that "not actually saying it"?
>

So you think you can force a repaint, huh?

It didn't actually happen in the loop test, though, did it?

>>
>> So lets see what the OO-CSS expert has to say.
>
> I linked to Hyat's comment though, not post itself. He even says that
> most of what she says doesn't apply to WebKit in an earlier comment:
>
> <quote>
> Just FYI, very little of what you’ve written here applies to WebKit.
> There’s nothing overly scary about either a typical reflow or repaint in
> WebKit as long as what you do doesn’t affect the geometry of the entire
> page.
> </quote>
>
>>
>> | A repaint occurs when changes are made to an elements skin that
>> } changes visibility, but do not affect its layout
>>
>> The repaint may occur after a request for a style change has been made,
>> but that won't happen every time.
>>
>> Try writing a loop-based animation and if you can get it to update, then
>> you've gotten a repaint to occur.
>>

HEre is a complete example.

Notice that when the div gets to "500" that the title will update in
chrome. You may want to bump the j loop up to 50000 iterations -- 10x
what it is now (5000) to notice that.

The div starts at the left and ends 1000px left from that. It is not
ever visibile at 500. Setting innerHTML didn't change that; nothing
will. You can't make the browser repaint.

The best you can do is give it a condition under which it thinks a
repaint should occur and then wait for it to do that. It won't do it on
exiting each function but it should probably want to do that after
completing the stack of execution contexts.

<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>How do I make the browser repaint?</title>
</head>
<body>
<div id="a" style="position: absolute; background: red; width: 20px;
height: 20px; top: 4em; left: 0;">a</div>
<script>

function start(){


var i;
for(i = 0; i < 1000; i++) {
moveDiv();
}

function moveDiv(){
document.getElementById("a").style.left = i + "px";
repaint();
}


function repaint() {
if(i === 500) {
for(var j = 0; j < 5000; j++) {
document.getElementById("a").innerHTML = "b";
document.title = new Date(j).toString();
}
}
// your code here.
}
}
</script>
<button onclick="start()">start()</button>
</body>
</html>


>
> Given lack of standard or definitive documentation, observations is the
> only thing we can work with. In Chrome your code does in fact trigger
> repaints every time style is queried (screenshot —
> <http://twitpic.com/26xr2n/full>).
>

No, it does not.

> Look at multiple "layout" events, followed by "Style recalculation".
>

That is style recalc. Remember recalc != repaint.

> That's what I meant by "observable ways to trigger reflow/repaint".
>

You're conflating repaint and reflow now with punctuation.

Once again, does the quote from Hyatt state that reading `offsetWidth`
will trigger a repaint?
--
Garrett

kangax

unread,
Jul 20, 2010, 9:24:50 AM7/20/10
to
On 7/20/10 4:24 AM, Garrett Smith wrote:
> On 2010-07-19 11:57 PM, kangax wrote:
>> On 7/20/10 1:04 AM, Garrett Smith wrote:
>>> On 2010-07-19 06:52 PM, kangax wrote:
>>>> On 7/19/10 3:32 PM, Garrett Smith wrote:
[...]

>>> Nicole Sullivan's blog? I'll normall pass on that one.
>>
>> What's with ad hominem? :) I'm failing to see how it matters on which
>> blog WebKit developer explains when/how reflow occurs in WebKit?
>>
>
> What ad hominem? Are you reading more into what I wrote?
>
> What you seem to fail to grasp is that recalc != repaint. That is,
> recalc is not causing pixels to be visully updated to the user.

That much is clear.

>
> A repaint is when the browser paints the pixels so they are visually
> rendered.

Yep.

[...]

>>> | A repaint occurs when changes are made to an elements skin that
>>> } changes visibility, but do not affect its layout
>>>
>>> The repaint may occur after a request for a style change has been made,
>>> but that won't happen every time.
>>>
>>> Try writing a loop-based animation and if you can get it to update, then
>>> you've gotten a repaint to occur.
>>>
> HEre is a complete example.
>
> Notice that when the div gets to "500" that the title will update in
> chrome. You may want to bump the j loop up to 50000 iterations -- 10x
> what it is now (5000) to notice that.
>
> The div starts at the left and ends 1000px left from that. It is not
> ever visibile at 500. Setting innerHTML didn't change that; nothing
> will. You can't make the browser repaint.

Ok.

>
> The best you can do is give it a condition under which it thinks a
> repaint should occur and then wait for it to do that. It won't do it on
> exiting each function but it should probably want to do that after
> completing the stack of execution contexts.

Right.

[snip example]

>>
>> Given lack of standard or definitive documentation, observations is the
>> only thing we can work with. In Chrome your code does in fact trigger
>> repaints every time style is queried (screenshot —
>> <http://twitpic.com/26xr2n/full>).
>>
>
> No, it does not.

Sorry, it triggers reflow, not repaint (as you can see from the
screeenshot). By reflow I mean what they call "layout" event (with
description of "The browser's rendering engine performed layout
calculations."). That's the only layout event displayed by SpeedTracer;
there's no differentiation between reflow and "recalc" (as you call it).

Repaint happens later, whenever browser finds time for it (as your
example demonstrates).

[...]

>> He said "...but if you create code that forces a reflow". As I read it,
>> that means you _can_ create code that forces reflow. Why would he talk
>> about something nonexistent?
>>
>
> Once again, does the quote from Hyatt state that reading `offsetWidth`
> will trigger a repaint?

The quote implies that reading `offsetWidth` will trigger _reflow_ under
certain conditions.

I now see that there are 2 reasons for my misunderstanding of your
argument.

First of all, I didn't clearly differentiate reflow and repaint when you
said "you can't force repaint".

Second — and more important — I have a different understanding of
"force/trigger"; I know that browsers don't _repaint_ on every change of
style (and/or querying of computed style after such change) but making
browser perform repaint in the near future falls under the definition of
"trigger repaint" for me. Browser doesn't repaint _immediately_ but it
still does eventually, which means that repaint was forced/triggered.

--
kangax

David Mark

unread,
Jul 20, 2010, 2:24:15 PM7/20/10
to
> > (<www.stubbornella.org/content/2009/03/27/reflows-repaints-css-performa...>):

>
> Nicole Sullivan's blog? I'll normall pass on that one. It seems you've
> got a disagreement with the fact that there's no way to force the
> browser to repaint, but you won't actually say that and just post up links.
>
> So lets see what the OO-CSS expert has to say.
>
> | A repaint occurs when changes are made to an elements skin that
>
> } changes visibility, but do not affect its layout
>
> The repaint may occur after a request for a style change has been made,
> but that won't happen every time.
>
> Try writing a loop-based animation and if you can get it to update, then
> you've gotten a repaint to occur.
>
> var i;
> for(i = 0; i < 1000; i++) {
>    moveDiv();
>
> }
>
> function moveDiv(){
>    document.getElementById("a").style.left = i + "px";
>    repaint();
>
> }
>
> function repaint() {
>    // your code here.
>
> }
>
> Also do realize that when you flesh out the repaint, even if you can get
> it to work (it won't happen, but try if you like), then the fact that it
> works could not be used as argument that a repaint can be forced; it
> would only show that you did something and then a repaint occurred.
>

Browsers don't *always* reflow/repaint on exiting execution contexts.
But the fact is that they do sometimes (I know this from experience).
Nobody but the browser developers know exactly what factors determine
whether they do it or not. The above example likely illustrates that
they abstain while in the middle of a loop.

The important thing to know is that they do *not* repaint until they
exit the context that queued the style changes. You can't force
repaints on demand, but can certainly avoid them when needed.

David Mark

unread,
Jul 20, 2010, 2:33:11 PM7/20/10
to
> >>> (<www.stubbornella.org/content/2009/03/27/reflows-repaints-css-performa...>):

>
> >> Nicole Sullivan's blog? I'll normall pass on that one.
>
> > What's with ad hominem? :) I'm failing to see how it matters on which
> > blog WebKit developer explains when/how reflow occurs in WebKit?
>
> What ad hominem? Are you reading more into what I wrote?
>
> What you seem to fail to grasp is that recalc != repaint.  That is,
> recalc is not causing pixels to be visully updated to the user.
>
> A repaint is when the browser paints the pixels so they are visually
> rendered.
>
> >> It seems you've
> >> got a disagreement with the fact that there's no way to force the
> >> browser to repaint, but you won't actually say that and just post up
> >> links.
>
> > Wait, didn't I start original reply with "There certainly are observable
> > ways to trigger ..."? Is that "not actually saying it"?
>
> So you think you can force a repaint, huh?
>
> It didn't actually happen in the loop test, though, did it?

That doesn't mean that it won't do it in all cases. The browser knows
it is in a loop after all.

>
>
>
>
>
> >> So lets see what the OO-CSS expert has to say.
>
> > I linked to Hyat's comment though, not post itself. He even says that
> > most of what she says doesn't apply to WebKit in an earlier comment:
>
> > <quote>
> > Just FYI, very little of what you’ve written here applies to WebKit.
> > There’s nothing overly scary about either a typical reflow or repaint in
> > WebKit as long as what you do doesn’t affect the geometry of the entire
> > page.
> > </quote>
>
> >> | A repaint occurs when changes are made to an elements skin that
> >> } changes visibility, but do not affect its layout
>
> >> The repaint may occur after a request for a style change has been made,
> >> but that won't happen every time.
>
> >> Try writing a loop-based animation and if you can get it to update, then
> >> you've gotten a repaint to occur.
>
> HEre is a complete example.

Another loop. You can can't force a repaint, but you can't predict
when they will happen either (your theory about waiting until the
execution stack is exhausted is definitely wrong).

>
> Notice that when the div gets to "500" that the title will update in
> chrome. You may want to bump the j loop up to 50000 iterations -- 10x
> what it is now (5000) to notice that.
>
> The div starts at the left and ends 1000px left from that. It is not
> ever visibile at 500. Setting innerHTML didn't change that; nothing
> will. You can't make the browser repaint.
>
> The best you can do is give it a condition under which it thinks a
> repaint should occur and then wait for it to do that. It won't do it on
> exiting each function but it should probably want to do that after
> completing the stack of execution contexts.

Your general "it won't do it on exiting each function" statement is
just as false as saying it will do it on demand. The fact is that
browsers do sometimes reflow/repaint on exiting execution contexts
(and before the stack is exhausted). It would certainly be nice if
they didn't, but I know from experience that is not the case. For
one, I can't count how many times I've improved the performance of
widgets by avoiding function calls in the middle of updating styles.
And I mean exponentially, so it wasn't just the overhead of calling
the functions. For two, I've dealt with flickers and twitches due to
"unexpected" repaints. They happen in some contexts and the solution
is always the same.

Garrett Smith

unread,
Jul 20, 2010, 3:15:04 PM7/20/10
to
On 2010-07-20 11:33 AM, David Mark wrote:
> On Jul 20, 4:24 am, Garrett Smith<dhtmlkitc...@gmail.com> wrote:
>> On 2010-07-19 11:57 PM, kangax wrote:
>>
>>
>>
>>
>>
>>> On 7/20/10 1:04 AM, Garrett Smith wrote:
>>>> On 2010-07-19 06:52 PM, kangax wrote:
>>>>> On 7/19/10 3:32 PM, Garrett Smith wrote:
>>>>>> On 2010-07-19 12:29 AM, Ry Nohryb wrote:
>>>>>>> On Jul 19, 9:04 am, Garrett Smith<dhtmlkitc...@gmail.com> wrote:
>>>>>>>> On 2010-07-18 10:51 PM, Ry Nohryb wrote:
>>>>>>>> (...)
>>

[snip massive overquote]

>> HEre is a complete example.
>
> Another loop. You can can't force a repaint, but you can't predict
> when they will happen either (your theory about waiting until the
> execution stack is exhausted is definitely wrong)
>

What's wrong and why?

Exhausting execution contexts -- sounds like they need to get some sleep.

>>
>> Notice that when the div gets to "500" that the title will update in
>> chrome. You may want to bump the j loop up to 50000 iterations -- 10x
>> what it is now (5000) to notice that.
>>
>> The div starts at the left and ends 1000px left from that. It is not
>> ever visibile at 500. Setting innerHTML didn't change that; nothing
>> will. You can't make the browser repaint.
>>
>> The best you can do is give it a condition under which it thinks a
>> repaint should occur and then wait for it to do that. It won't do it on
>> exiting each function but it should probably want to do that after
>> completing the stack of execution contexts.
>
> Your general "it won't do it on exiting each function" statement is
> just as false as saying it will do it on demand. The fact is that

No, that statement is correct and the xample shows that to be true.
tt render the div -- no repainting. Function `moveDiv` calls
`document.getElementById` and `repaint` each 1000x. Function repaint
calls the `Date` constructor and `Date.prototype.toString` 5000x each.
That makes 11000 function calls, if I counted right.

All that is needed to determine that the browser will not repaint on
exiting each function call is to find one case where exiting a function
call does not cause a repaint.

The example fulfills that requirement. No repainting took place after
any of some 11000 function calls.
--
Garrett

David Mark

unread,
Jul 20, 2010, 3:24:58 PM7/20/10
to
On Jul 20, 3:15 pm, Garrett Smith <dhtmlkitc...@gmail.com> wrote:
> On 2010-07-20 11:33 AM, David Mark wrote:
>
> > On Jul 20, 4:24 am, Garrett Smith<dhtmlkitc...@gmail.com>  wrote:
> >> On 2010-07-19 11:57 PM, kangax wrote:
>
> >>> On 7/20/10 1:04 AM, Garrett Smith wrote:
> >>>> On 2010-07-19 06:52 PM, kangax wrote:
> >>>>> On 7/19/10 3:32 PM, Garrett Smith wrote:
> >>>>>> On 2010-07-19 12:29 AM, Ry Nohryb wrote:
> >>>>>>> On Jul 19, 9:04 am, Garrett Smith<dhtmlkitc...@gmail.com>  wrote:
> >>>>>>>> On 2010-07-18 10:51 PM, Ry Nohryb wrote:
> >>>>>>>> (...)
>
> [snip massive overquote]
>
> >> HEre is a complete example.
>
> > Another loop.  You can can't force a repaint, but you can't predict
> > when they will happen either (your theory about waiting until the
> > execution stack is exhausted is definitely wrong)
>
> What's wrong and why?

I explained that. In short, it's false.

>
> Exhausting execution contexts -- sounds like they need to get some sleep.

That word has other meanings.

>
>
>
>
>
>
>
> >> Notice that when the div gets to "500" that the title will update in
> >> chrome. You may want to bump the j loop up to 50000 iterations -- 10x
> >> what it is now (5000) to notice that.
>
> >> The div starts at the left and ends 1000px left from that. It is not
> >> ever visibile at 500. Setting innerHTML didn't change that; nothing
> >> will. You can't make the browser repaint.
>
> >> The best you can do is give it a condition under which it thinks a
> >> repaint should occur and then wait for it to do that. It won't do it on
> >> exiting each function but it should probably want to do that after
> >> completing the stack of execution contexts.
>
> > Your general "it won't do it on exiting each function" statement is
> > just as false as saying it will do it on demand.  The fact is that
>
> No, that statement is correct and the xample shows that to be true.

No it doesn't. Your sample demonstrates that at least one browser on
one PC failed to do it in a loop. I find it quite reasonable that
browsers would abstain from repaints in such a loop. Don't you?

> tt render the div -- no repainting. Function `moveDiv` calls
> `document.getElementById` and `repaint` each 1000x. Function repaint
> calls the `Date` constructor and `Date.prototype.toString` 5000x each.
> That makes 11000 function calls, if I counted right.
>
> All that is needed to determine that the browser will not repaint on
> exiting each function call is to find one case where exiting a function
> call does not cause a repaint.

As I've said (about 1000 times now, dating back for years). They
don't *always* do it. The key word is *always*. So your loop does
not disprove my position.

>
> The example fulfills that requirement. No repainting took place after
> any of some 11000 function calls.

And likely won't after 11 million function calls. All you have
demonstrated is one case where a browser does not repaint.

Garrett Smith

unread,
Jul 20, 2010, 6:06:51 PM7/20/10
to
On 2010-07-20 12:24 PM, David Mark wrote:
> On Jul 20, 3:15 pm, Garrett Smith<dhtmlkitc...@gmail.com> wrote:
>> On 2010-07-20 11:33 AM, David Mark wrote:
>>
>>> On Jul 20, 4:24 am, Garrett Smith<dhtmlkitc...@gmail.com> wrote:
>>>> On 2010-07-19 11:57 PM, kangax wrote:
>>
>>>>> On 7/20/10 1:04 AM, Garrett Smith wrote:
>>>>>> On 2010-07-19 06:52 PM, kangax wrote:
>>>>>>> On 7/19/10 3:32 PM, Garrett Smith wrote:
>>>>>>>> On 2010-07-19 12:29 AM, Ry Nohryb wrote:
>>>>>>>>> On Jul 19, 9:04 am, Garrett Smith<dhtmlkitc...@gmail.com> wrote:
>>>>>>>>>> On 2010-07-18 10:51 PM, Ry Nohryb wrote:
>>>>>>>>>> (...)
>>
>> [snip massive overquote]
>>
>>>> HEre is a complete example.
>>
>>> Another loop. You can can't force a repaint, but you can't predict
>>> when they will happen either (your theory about waiting until the
>>> execution stack is exhausted is definitely wrong)
>>
>> What's wrong and why?
>
> I explained that. In short, it's false.
>

Here you go again with "I've already explained" stories, claiming to
have done things that never took place. My my what an imagination.

>>
>> Exhausting execution contexts -- sounds like they need to get some sleep.
>
> That word has other meanings.
>

Get some rest.

>>>> Notice that when the div gets to "500" that the title will update in
>>>> chrome. You may want to bump the j loop up to 50000 iterations -- 10x
>>>> what it is now (5000) to notice that.
>>
>>>> The div starts at the left and ends 1000px left from that. It is not
>>>> ever visibile at 500. Setting innerHTML didn't change that; nothing
>>>> will. You can't make the browser repaint.
>>
>>>> The best you can do is give it a condition under which it thinks a
>>>> repaint should occur and then wait for it to do that. It won't do it on
>>>> exiting each function but it should probably want to do that after
>>>> completing the stack of execution contexts.
>>
>>> Your general "it won't do it on exiting each function" statement is
>>> just as false as saying it will do it on demand. The fact is that
>>
>> No, that statement is correct and the xample shows that to be true.
>
> No it doesn't.

The example shows a function call completing and a repaint no occurring
and so "it won't do it on exiting each function" is a true statement.

Your sample demonstrates that at least one browser on


Just one? Or most? Or was it every browser you tested in?

Which browser updated the position of the div at 500 and what else did
you do to get it to do that?

> one PC failed to do it in a loop. I find it quite reasonable that
> browsers would abstain from repaints in such a loop. Don't you?
>

What "reasonable browser behavior"?

>> tt render the div -- no repainting. Function `moveDiv` calls
>> `document.getElementById` and `repaint` each 1000x. Function repaint
>> calls the `Date` constructor and `Date.prototype.toString` 5000x each.
>> That makes 11000 function calls, if I counted right.
>>
>> All that is needed to determine that the browser will not repaint on
>> exiting each function call is to find one case where exiting a function
>> call does not cause a repaint.
>
> As I've said (about 1000 times now, dating back for years). They
> don't *always* do it. The key word is *always*. So your loop does
> not disprove my position.
>

The example proves "it won't do it on exiting each function", which you
claimed to be false and *that* claim was a false claim.

Have you been sleeping?

>>
>> The example fulfills that requirement. No repainting took place after
>> any of some 11000 function calls.
>
> And likely won't after 11 million function calls. All you have
> demonstrated is one case where a browser does not repaint.

That was all that was needed to suppor the claim "it won't do it on
exiting each function".
--
Garrett

Ry Nohryb

unread,
Jul 20, 2010, 6:10:07 PM7/20/10
to
On Jul 20, 8:24 pm, David Mark <dmark.cins...@gmail.com> wrote:
> (...) The above example likely illustrates that

> they abstain while in the middle of a loop.
>
> The important thing to know is that they do *not* repaint until they
> exit the context that queued the style changes.  You can't force
> repaints on demand, but can certainly avoid them when needed.
> (...)

Except Opera. Oper repaints in a separate thread, in parallel with the
JS thread:

http://jorgechamorro.com/cljs/101/

Only in Opera: you'll see a growing green dot dropping.

Tested in : navigator.userAgent: Opera/9.80 (Macintosh; Intel Mac OS
X; U; en) Presto/2.6.30 Version/10.60.
--
Jorge.

Ry Nohryb

unread,
Jul 20, 2010, 6:22:11 PM7/20/10
to

Oops, forgot to paste in the code:

window.onload= function (here, stop, s) {
here= document.getElementById('here');
s= 9;
while (s < 4e2) {
here.style.fontSize= ++s+ "px";
stop= +new Date()+ 50;
while (+new Date() < stop) { ; }
}
here.style.fontSize= "";
setTimeout(onload, 1e3);
};
--
Jorge.

David Mark

unread,
Jul 20, 2010, 6:35:03 PM7/20/10
to
On Jul 20, 6:10 pm, Ry Nohryb <jo...@jorgechamorro.com> wrote:
> On Jul 20, 8:24 pm, David Mark <dmark.cins...@gmail.com> wrote:
>
> > (...) The above example likely illustrates that
> > they abstain while in the middle of a loop.
>
> > The important thing to know is that they do *not* repaint until they
> > exit the context that queued the style changes.  You can't force
> > repaints on demand, but can certainly avoid them when needed.
> > (...)
>
> Except Opera. Oper repaints in a separate thread, in parallel with the
> JS thread:
>
> http://jorgechamorro.com/cljs/101/
>
> Only in Opera:

No not only in Opera.

David Mark

unread,
Jul 20, 2010, 6:44:17 PM7/20/10
to
On Jul 20, 6:06 pm, Garrett Smith <dhtmlkitc...@gmail.com> wrote:
> On 2010-07-20 12:24 PM, David Mark wrote:
>
>
>
>
>
> > On Jul 20, 3:15 pm, Garrett Smith<dhtmlkitc...@gmail.com>  wrote:
> >> On 2010-07-20 11:33 AM, David Mark wrote:
>
> >>> On Jul 20, 4:24 am, Garrett Smith<dhtmlkitc...@gmail.com>    wrote:
> >>>> On 2010-07-19 11:57 PM, kangax wrote:
>
> >>>>> On 7/20/10 1:04 AM, Garrett Smith wrote:
> >>>>>> On 2010-07-19 06:52 PM, kangax wrote:
> >>>>>>> On 7/19/10 3:32 PM, Garrett Smith wrote:
> >>>>>>>> On 2010-07-19 12:29 AM, Ry Nohryb wrote:
> >>>>>>>>> On Jul 19, 9:04 am, Garrett Smith<dhtmlkitc...@gmail.com>    wrote:
> >>>>>>>>>> On 2010-07-18 10:51 PM, Ry Nohryb wrote:
> >>>>>>>>>> (...)
>
> >> [snip massive overquote]
>
> >>>> HEre is a complete example.
>
> >>> Another loop.  You can can't force a repaint, but you can't predict
> >>> when they will happen either (your theory about waiting until the
> >>> execution stack is exhausted is definitely wrong)
>
> >> What's wrong and why?
>
> > I explained that.  In short, it's false.
>
> Here you go again with "I've already explained" stories, claiming to
> have done things that never took place. My my what an imagination.

My, my what a jackass.

Not only have I provided anecdotal evidence, which most assuredly
happened (do you really think I would make up stories for you?), but
I've provided at least one example that remains on the Web to this
day. That was months ago, which is indicative of how ridiculous this
"debate" has become. I was right. You were/are wrong. No amount of
semantics will change that.

>
>
>
> >> Exhausting execution contexts -- sounds like they need to get some sleep.
>
> > That word has other meanings.
>
> Get some rest.

Get some sense.

>
>
>
> >>>> Notice that when the div gets to "500" that the title will update in
> >>>> chrome. You may want to bump the j loop up to 50000 iterations -- 10x
> >>>> what it is now (5000) to notice that.
>
> >>>> The div starts at the left and ends 1000px left from that. It is not
> >>>> ever visibile at 500. Setting innerHTML didn't change that; nothing
> >>>> will. You can't make the browser repaint.
>
> >>>> The best you can do is give it a condition under which it thinks a
> >>>> repaint should occur and then wait for it to do that. It won't do it on
> >>>> exiting each function but it should probably want to do that after
> >>>> completing the stack of execution contexts.
>
> >>> Your general "it won't do it on exiting each function" statement is
> >>> just as false as saying it will do it on demand.  The fact is that
>
> >> No, that statement is correct and the xample shows that to be true.
>
> > No it doesn't.
>
> The example shows a function call completing and a repaint no occurring
> and so "it won't do it on exiting each function" is a true statement.

Your statement is (intentionally) vague. If you are saying that it
won't do it on *every* function exit, then you have been agreeing with
me all along. (?)

>
> Your sample demonstrates that at least one browser on
>
> Just one? Or most? Or was it every browser you tested in?

I didn't test your code at all. But from experience I know that it
likely won't repaint during the loop (which proves absolutely
nothing).

>
> Which browser updated the position of the div at 500 and what else did
> you do to get it to do that?

You really think I bothered with your code?

>
> > one PC failed to do it in a loop.  I find it quite reasonable that
> > browsers would abstain from repaints in such a loop.  Don't you?
>
> What "reasonable browser behavior"?

Who are you quoting?

>
> >> tt render the div -- no repainting. Function `moveDiv` calls
> >> `document.getElementById` and `repaint` each 1000x. Function repaint
> >> calls the `Date` constructor and `Date.prototype.toString` 5000x each.
> >> That makes 11000 function calls, if I counted right.
>
> >> All that is needed to determine that the browser will not repaint on
> >> exiting each function call is to find one case where exiting a function
> >> call does not cause a repaint.
>
> > As I've said (about 1000 times now, dating back for years).  They
> > don't *always* do it.  The key word is *always*.  So your loop does
> > not disprove my position.
>
> The example proves "it won't do it on exiting each function", which you
> claimed to be false and *that* claim was a false claim.
>
> Have you been sleeping?

Again, your position has been that it *never* does it except when the
execution stack is finished. That's false. The statement "it won't
do it on exiting each function" can be interpreted two ways (that it
will never do it on such exits and that it may well do it some of the
time). Recall that the latter has been my assertion all along (and
the former yours).

>
>
>
> >> The example fulfills that requirement. No repainting took place after
> >> any of some 11000 function calls.
>
> > And likely won't after 11 million function calls.  All you have
> > demonstrated is one case where a browser does not repaint.
>
> That was all that was needed to suppor the claim "it won't do it on
> exiting each function".

See above.

Garrett Smith

unread,
Jul 20, 2010, 6:51:45 PM7/20/10
to
On 2010-07-20 06:24 AM, kangax wrote:
> On 7/20/10 4:24 AM, Garrett Smith wrote:
>> On 2010-07-19 11:57 PM, kangax wrote:
>>> On 7/20/10 1:04 AM, Garrett Smith wrote:
>>>> On 2010-07-19 06:52 PM, kangax wrote:
>>>>> On 7/19/10 3:32 PM, Garrett Smith wrote:
> [...]
>>>> Nicole Sullivan's blog? I'll normall pass on that one.
>>>
>>> What's with ad hominem? :) I'm failing to see how it matters on which
>>> blog WebKit developer explains when/how reflow occurs in WebKit?
>>>
>>
>> What ad hominem? Are you reading more into what I wrote?
>>

I still don't see that be taken as a personal attack on Nicole Sullivan.

You quoted Dave Hyatt, the context in which the comment was made matters
and so although normally I'd pass on reading that blog, it seemed only
proper that the blog entry should be read so as to understand the
context of Hyatt's context.

So I'm not sure where I went wrong. Or if.

[...]

>
>>
>> The best you can do is give it a condition under which it thinks a
>> repaint should occur and then wait for it to do that. It won't do it on
>> exiting each function but it should probably want to do that after
>> completing the stack of execution contexts.
>
> Right.
>

[...]

>
> Second — and more important — I have a different understanding of
> "force/trigger"; I know that browsers don't _repaint_ on every change of
> style (and/or querying of computed style after such change) but making
> browser perform repaint in the near future falls under the definition of
> "trigger repaint" for me. Browser doesn't repaint _immediately_ but it
> still does eventually, which means that repaint was forced/triggered.
>

If there is new layout information that needs painting, the browser will
hopefully paint it.

The code in question may address an issue in webkit with repainting. Or
it may address a problem that the authors have created.

Method `Ext.Element.prototype.repaint` triggers an error condition by
setting `dom.style.background = null`.

That mistake is one of many mistakes.

Think about reviewing some of this code. For example, you could look at
`El.get` from ext-touch-debug-w-comments.js.

I suggest (to anyone) to read it carefully, see what it does, what it
gets wrong, and then test that. Then post up the findings. Just a
reminder: Quick quips about the code are not helpful to anyone.

I picked this function because there are things in it that I suspect you
won't like.

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

if(!el){
return null;
}

if (typeof el == "string") {
if (!(dom = document.getElementById(el))) {
return null;
}
if (Ext.cache[el] && Ext.cache[el].el) {
extEl = Ext.cache[el].el;
extEl.dom = dom;
} else {
extEl = El.addToCache(new El(dom));
}
return extEl;
} else if (el.tagName) {
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));
}
return extEl;
} else if (el instanceof El) {
if(el != El.docEl){


el.dom = document.getElementById(el.id) || el.dom;
}
return el;
} else if(el.isComposite) {
return el;
} else if(Ext.isArray(el)) {
return El.select(el);
} else if(el == document) {

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

Garrett Smith

unread,
Jul 20, 2010, 7:15:46 PM7/20/10
to
On 2010-07-20 03:44 PM, David Mark wrote:
> On Jul 20, 6:06 pm, Garrett Smith<dhtmlkitc...@gmail.com> wrote:
>> On 2010-07-20 12:24 PM, David Mark wrote:
>>
>>
>>
>>
>>
>>> On Jul 20, 3:15 pm, Garrett Smith<dhtmlkitc...@gmail.com> wrote:
>>>> On 2010-07-20 11:33 AM, David Mark wrote:
>>
>>>>> On Jul 20, 4:24 am, Garrett Smith<dhtmlkitc...@gmail.com> wrote:
>>>>>> On 2010-07-19 11:57 PM, kangax wrote:
>>
>>>>>>> On 7/20/10 1:04 AM, Garrett Smith wrote:
>>>>>>>> On 2010-07-19 06:52 PM, kangax wrote:
>>>>>>>>> On 7/19/10 3:32 PM, Garrett Smith wrote:
>>>>>>>>>> On 2010-07-19 12:29 AM, Ry Nohryb wrote:
>>>>>>>>>>> On Jul 19, 9:04 am, Garrett Smith<dhtmlkitc...@gmail.com> wrote:
>>>>>>>>>>>> On 2010-07-18 10:51 PM, Ry Nohryb wrote:
>>>>>>>>>>>> (...)
>>
>>>> [snip massive overquote]
>>
>>>>>> HEre is a complete example.
>>
>>>>> Another loop. You can can't force a repaint, but you can't predict
>>>>> when they will happen either (your theory about waiting until the
>>>>> execution stack is exhausted is definitely wrong)
>>
>>>> What's wrong and why?
>>
>>> I explained that. In short, it's false.
>>
>> Here you go again with "I've already explained" stories, claiming to
>> have done things that never took place. My my what an imagination.
>
> My, my what a jackass.
>

That's David Mark I know. And *that* is a example of ad hominem.

More graceful ways to recognize a mistake than that exist.

> Not only have I provided anecdotal evidence, which most assuredly
> happened (do you really think I would make up stories for you?), but
> I've provided at least one example that remains on the Web to this
> day. That was months ago, which is indicative of how ridiculous this
> "debate" has become. I was right. You were/are wrong. No amount of
> semantics will change that.
>

I've stated nothing wrong. I've stated now four or five times that the
browser won't repaint on exiting each function. You chose to argue about
that. Why you would choose to argue about that can only be explained by
you and so far you've not explained anything that supports why you
believe the statement I made was incorrect.

And while I cannot say your absense of an explanation is wrong, your
claim that I was wrong is false and your claim that you have made an
explanation was also not true. It's not the first time you've made such
claims. Recall when I was copying everything you did, how I copied all
of your best jQuery code reviews? How I was "aping" your code?

The claim that my statement was false was incorrect. I can't see why
you're having such trouble realizing it. Anyone who read it carefully
and tested the example I posted should see that the statement I made is,
in fact, correct and proven by my example.

Is your ego getting in the way of recognizing the mistake? Pretty much
anyone can recognize that what was posted was correct and continuing to
say that it wasn't is unlikely to change that.

Pity. Given what you've posted, I am afraid that the reader's judgment
call may be to dismiss your review as that of a man who is not reasonable.

>>
>>
>>
>>>> Exhausting execution contexts -- sounds like they need to get some sleep.
>>
>>> That word has other meanings.
>>
>> Get some rest.
>
> Get some sense.
>

[...]

>>
>> Which browser updated the position of the div at 500 and what else did
>> you do to get it to do that?
>
> You really think I bothered with your code?
>

I know that you tend to not read specs and don't test things very well.
You tend to post carelessly and the formatting of the code reviews marks
an example of that.

>>
>>> one PC failed to do it in a loop. I find it quite reasonable that
>>> browsers would abstain from repaints in such a loop. Don't you?
>>
>> What "reasonable browser behavior"?
>
> Who are you quoting?
>

You brought up the subject of reasonable browser behavior but didn't say
what that was.

>> The example proves "it won't do it on exiting each function", which you
>> claimed to be false and *that* claim was a false claim.
>>
>> Have you been sleeping?
>
> Again, your position has been that it *never* does it except when the
> execution stack is finished.

OK. That's where you went wrong. I did not make that claim.
--
Garrett

David Mark

unread,
Jul 20, 2010, 7:24:38 PM7/20/10
to

You don't know me and you always pull this sort of stupid shit where
you bait relentlessly and then cry when scolded. What the hell is
wrong with you? Next time, refrain from calling me a liar.

>
> More graceful ways to recognize a mistake than that exist.

I've made no mistake.

[...]

>
> > Again, your position has been that it *never* does it except when the
> > execution stack is finished.
>
> OK. That's where you went wrong. I did not make that claim.

You stuck to that claim for months. Pardon me if I missed your
recent, vaguely worded flip-flop. So you finally get it that browsers
don't wait until the end of the execution stack to reflow/repaint?
That should help you learn how to optimize browser scripts,
particularly widgets. Glad I could help. :)

Garrett Smith

unread,
Jul 20, 2010, 10:44:01 PM7/20/10
to

What I wrote wasn't vague at all!

You surrounded what I wrote in quotes, then said it was false and stuck
with it for three or four posts.

> don't wait until the end of the execution stack to reflow/repaint?
> That should help you learn how to optimize browser scripts,
> particularly widgets. Glad I could help. :)

Your design advice is reflected in the style of code seen in "my library".

The claim that the browser uses completing a function call with in a
call stack as a trigger to repaint is a different matter.

I can't recall ever seeing a test case as evidence to that. I don't
anticipate seeing one either.
--
Garrett

RobG

unread,
Jul 20, 2010, 11:02:12 PM7/20/10
to
On Jul 21, 4:33 am, David Mark <dmark.cins...@gmail.com> wrote:
[...]

> Another loop.  You can can't force a repaint, but you can't predict
> when they will happen either (your theory about waiting until the
> execution stack is exhausted is definitely wrong).

It may be a trivial example, but a repaint will generally occur when
an alert dialog is presented:

<script type="text/javascript">

window.onload = function(){
window.setTimeout(foo, 1000);
};

function foo() {
var i,
el = document.getElementById('d0'),
n = 10000,
s = 6;

while (s < 1000) {

// Show alert dialog at half way
if (s == 500) {
alert('redraw...');
}

el.style.fontSize = ++s + "pt";
i = n;

// Simulate doing stuff
while (i--) ;
}
};

</script>

<div id="d0"
style="color: green; vertical-align:top;">&#176;</div>


--
Rob

Andrew Poulos

unread,
Jul 20, 2010, 11:26:43 PM7/20/10
to
On 21/07/2010 12:44 PM, Garrett Smith wrote:
> On 2010-07-20 04:24 PM, David Mark wrote:
>> On Jul 20, 7:15 pm, Garrett Smith<dhtmlkitc...@gmail.com> wrote:
>>> On 2010-07-20 03:44 PM, David Mark wrote:
>>>> On Jul 20, 6:06 pm, Garrett Smith<dhtmlkitc...@gmail.com> wrote:
>>>>> On 2010-07-20 12:24 PM, David Mark wrote:
>>>
>>>>>> On Jul 20, 3:15 pm, Garrett Smith<dhtmlkitc...@gmail.com> wrote:
>>>>>>> On 2010-07-20 11:33 AM, David Mark wrote:
>>>
>>>>>>>> On Jul 20, 4:24 am, Garrett Smith<dhtmlkitc...@gmail.com> wrote:
>>>>>>>>> On 2010-07-19 11:57 PM, kangax wrote:
>>>
>>>>>>>>>> On 7/20/10 1:04 AM, Garrett Smith wrote:
>>>>>>>>>>> On 2010-07-19 06:52 PM, kangax wrote:
>>>>>>>>>>>> On 7/19/10 3:32 PM, Garrett Smith wrote:
>>>>>>>>>>>>> On 2010-07-19 12:29 AM, Ry Nohryb wrote:
>>>>>>>>>>>>>> On Jul 19, 9:04 am, Garrett Smith<dhtmlkitc...@gmail.com>
>>>>>>>>>>>>>> wrote:
>>>>>>>>>>>>>>> On 2010-07-18 10:51 PM, Ry Nohryb wrote:
>>>>>>>>>>>>>>> (...)
>>>
>>>>>>> [snip massive over quote]

Do you guys know how it reads when a js library that is being marketed
as something its not is rightly exposed as such and to then have a bunch
of js "experts" playing with and/or insulting each other? I'd say that
for the Sencha people it gives them sufficient grounds to not even
bother to refute any of the claims.

Andrew Poulos

David Mark

unread,
Jul 20, 2010, 11:32:44 PM7/20/10
to

Of course it was. Read it aloud until you comprehend the dual
meaning. Or don't. I'm tired of this discussion (and the dozens that
lead up to it).

The fact is that you have recently changed your position to match
mine. Previously you argued vehemently that browsers *never* did
reflows or repaints until the end of the execution stack. You didn't
say that sometimes they did and sometimes they didn't as that was what
I was saying. It's not like those months worth of arguments were some
sort of misunderstanding. Your point was clear, as was mine.

>
> You surrounded what I wrote in quotes, then said it was false and stuck
> with it for three or four posts.

Whatever.

>
> > don't wait until the end of the execution stack to reflow/repaint?
> > That should help you learn how to optimize browser scripts,
> > particularly widgets.  Glad I could help.  :)
>
> Your design advice is reflected in the style of code seen in "my library".

Indeed there are parts of My Library that avoid unwanted reflows/
repaints to avoid unwanted flashes of content, performance loss, etc.
Does that surprise you?

>
> The claim that the browser uses completing a function call with in a
> call stack as a trigger to repaint is a different matter.

I never claimed anything of the sort. You always leave out the
"sometimes" part.

>
> I can't recall ever seeing a test case as evidence to that.

Your amnesia is a well-known problem and I imagine the style of code
in "your library" reflects that.

> I don't
> anticipate seeing one either.

I suggest you try very hard to retrieve that part of your memory.

And how the hell do you not know this stuff anyway? It's really
basic. Dojo's stupid grid was setting innerHTML on hundreds of cells,
calling functions to do each one. Took minutes. I eliminated the
function calls and reduced it to seconds. If you don't have lots of
similar anecdotes, then you either have no experience with such things
or you don't know what the hell you are doing. Clear?


David Mark

unread,
Jul 20, 2010, 11:34:32 PM7/20/10
to

Yes. Calling a host methods (as opposed to native functions) doesn't
usually allow for that, but it makes sense that those that display
modal dialogs are an exception.

Garrett Smith

unread,
Jul 21, 2010, 4:46:11 PM7/21/10
to

No doubt.

Name-calling and downtalking others hurts technical discussion and hurts
the person doing those things probably much more than the intended
recipient of such insults.

Technical criticism littered with such mudslinging reduce the s/n ratio.
What's worse is that a non-technical observer might dismiss the
discussion as crazed zealotry.

I will publish an article on some of this stuff soon. It is the same
article I was going to publish three weeks ago. The article will contain
some of the things that I have posted here. Give me one more week.
--
Garret

David Mark

unread,
Jul 21, 2010, 4:58:45 PM7/21/10
to

I doubt whether that follow. But you do have a habit of burying
useful threads in confused nonsense, which then has to be sorted out,
else newcomers won't understand the original points.

>
> Name-calling and downtalking others hurts technical discussion and hurts
> the person doing those things probably much more than the intended
> recipient of such insults.

Yeah, so stop doing it. And don't bother posting back with one of
your innocent routines. Your modus operandi is well-known at this
point. You post thinly disguised attempts at insults, get called on
them and then whine and point fingers like a child.

>
> Technical criticism littered with such mudslinging reduce the s/n ratio.
> What's worse is that a non-technical observer might dismiss the
> discussion as crazed zealotry.

Good thing the lion's share of the useful information is in the first
message in the thread.

>
> I will publish an article on some of this stuff soon. It is the same
> article I was going to publish three weeks ago.

Yes, yes.

> The article will contain
> some of the things that I have posted here. Give me one more week.

Whatever.

Garrett Smith

unread,
Jul 21, 2010, 6:27:35 PM7/21/10
to
I'll agree to disagree on that.
--
Garrett

David Mark

unread,
Jul 21, 2010, 11:50:07 PM7/21/10
to

Yes, but luckily the important parts were posted before the thread
degenerated into another reflow/repaint "argument". :)

> I'd say that
> for the Sencha people it gives them sufficient grounds to not even
> bother to refute any of the claims.

Fine by me. Ext must D-I-E. :)

To that end, I've recently added (very basic) touch and geolocation
add-ons to My Library. Wrapping up a storage bit as well (supporting
Web and cookie transports and open to add more). I'll be adding
progressive enhancement for HTML5 soon and have already leveraged CSS3
considerably (widget skins, transform add-on, etc.) What I haven't
done (and won't do) is publish dubious hyperbole and graphics-laden
demos to create a Wizard of Oz effect. I want prospective users to
think for themselves and realize that graphics have nothing to do with
JS/CSS (except as an optional embellishment).

And having just finished a standards-based iPhone/iPad Web app (to be
wrapped for the app store) that uses HTML/CSS with only a tiny bit of
JS, I am again reminded of the futility of using something like Sencha
Touch (or JQTouch, IUI, etc.) My app works in every browser I tried
(all of the majors going back two or three versions), used no
sniffing, no XHR, allowed the content to reside in the HTML (where it
belongs) and looks just as dazzling as any native app.

ISTM that with CSS media queries, I could make any Web app or site
animate and contort itself to fit the smaller screens and iPhone look/
feel (in the same way that I use handheld style sheets to suit
"normal" phones). Well, that's assuming they are lightweight enough
and don't use table (or JS) based layouts. And now that I think about
it, as far as bloat (e.g. tons of Flash, heavy images, etc.), I wonder
if display:none prevents downloads in these devices. Probably not.

Garrett Smith

unread,
Jul 22, 2010, 2:33:28 AM7/22/10
to
On 2010-07-16 10:16 AM, Richard Cornford wrote:
> 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.
> <snip>
[...]

>> Given the depth of your review, it would seem you have
>> some time on your hands.
>
> It didn't look like it need much time, or to achieve any depth. Just

The initial could have benefited from a little more effort and care to
avoid wrapping.

> copy the source text and work down it inserting comments on the things
> that stand out. When the first line of code is a 'fix' for pre-ECMA 262
> 3rd edition browsers (a standard that came out in 1999 and where the
> most recent browser that needed the 'fix' is IE 4, in a system that does
> not support IE in any version) then you don't need depth to see fault.
>

Including Sencha on any page results in errors in IE due to
addEventListener. So it is not like a graceful degradation strategy
could even be employed.

[...]

>
> Personally, I have been writing about and discussing strategies to
> maximise the efficiency of code re-use in browser scripting, publishing
> examples and testing my ideas in my work for more than half a decade. My
> ideas in this regard do not lead to the large scale interdependent
> general purpose browser scripting libraries (that is where my thinking
> started nearly a decade ago, and is the thing I have been moving away
> from ever since). Instead they were directed toward the creation of
> browser scripts as a hierarchical structure of loosely coupled modules
> specified as interfaces, where particular interfaces may have numerous
> implementations, none of which attempt to be more general than a
> particular context calls for, but each suited to a different context.
> Thus I avoid the bloat and performance hit associated with attempts to
> be truly general; implementations of interfaces do not even need to
> consider issues that are not part of the context in which they are used,
> and if the issue is in the context a different implementation of the
> interface is used instead. Given this approach it is not too surprising
> that I would be the person to introduce the "module pattern" back in
> 2003, as it is the ideal packaging unit for many of those interface
> implementations.
>

The performance hit is not just in download, but in keeping the
functions in memory, and then the chance that it may not be cached, and
on a mobile device, a possible extra cost of data plan, depending if the
user's plan or connection (roaming).

Performance is an issue, but I think it's not the only reason.

An interface that has a lot of behavior, if something changes, then
anything that depends on that must be retested.

But what about cross-browser DOM abstraction code -- for things such as
reading styles, traversal, events?

What sort of advice you could offer for for organizing DOM abstraction
code? Can you provide any advice for how I've organized APE JS Library?

> This design strategy results in what is in effect a 'library' of
> (easily, as in real life common contexts reoccur frequently) re-useable
> code modules, but its concepts and architecture are quite difficult for
> some to recognise as a 'library', it could not easily be packaged and
> distributed, and indeed it is the intention of the design that the whole
> never needs to be finished (in terms of creating an implementation of
> every interface for every possible context, as some contexts are so
> unlikely that I am unlikely to ever encounter them). The collected code
> 'library' is also not a framework, but it can be used to build
> frameworks where they are needed, and those frameworks gain the
> robustness of being made from well tried modules plus the possibility of
> being well suited to their specific tasks/context.
>

While I am aware of the benefits from interface-based design and of
using the SOLID principles, I feel like I struggle with applying them.

How do you define "framework" from a mechanical standpoint?

I think of a framework as being some sort of container that holds the
system together.

[...]
--
Garrett

meph...@gmail.com

unread,
Dec 23, 2015, 5:24:47 PM12/23/15
to
On Thursday, July 15, 2010 at 11:38:13 PM UTC-4, 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.
>
> /*
> Copyright(c) 2010 Sencha Inc.
> lice...@sencha.com
> 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[i];
> };
> }
>
> 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[i], array[i], i, array) ===
> false) {
>
> Why would they set - this - to array[i]? 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[i];
> 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[i];
> 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,

I know that this is a really old post...I was unsure of another way to start a conversation but I am a J2EE/Web developer and think you did a really good analysis of this code. I had used dojo for a while, switched to jquery, and learned to love XHR/JSON in a client/server style of app design. Im wondering if your thoughts on jquery/dojo/any libraries have changed over the years..meaning things got better...or if the same problems are just as bad. I was still new to js in 2010 but it seemed awful then overall...things seem to be predictible if not reliable now...

Many thanks for any time give to the question!
0 new messages