Is it?
First suspicious file is browser.js (wonder what that could be?)
//
==========================================================================
// Project: SproutCore - JavaScript Application Framework
// Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
// Portions ©2008-2009 Apple Inc. All rights reserved.
// License: Licened under MIT license (see license.js)
//
==========================================================================
Hmm. Portions copyright Apple, Inc. Big company == Great JS.
/** Detects the current browser type. Borrowed from jQuery + prototype
*/
Oh no.
SC.browser = (function() {
var userAgent = navigator.userAgent.toLowerCase();
var version = (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ )
|| [])[1] ;
var browser = /** @scope SC.browser */ {
Please, make it stop. :) Scope?
/** The current browser version */
version: version,
/** non-zero if webkit-based browser */
safari: (/webkit/).test( userAgent ) ? version : 0,
Non-zero? This must be their own unique interpretation of jQuery's
sniffing. I wonder if they realize that jQuery moved forward one step
to object inferences.
/** non-zero if this is an opera-based browser */
opera: (/opera/).test( userAgent ) ? version : 0,
The one browser in the world that is easy to detect and they blew it.
Of course, there should be no reason to detect Opera in 2010 (or 2009
or 2008...) Can only go downhill from here.
/** non-zero if this is IE */
msie: (/msie/).test( userAgent ) && !(/opera/).test( userAgent ) ?
version : 0,
Sad, especially considering IE has conditional comments. Oh, but that
won't fit into their plans of creating a way-cool browser scripting
framework. :)
/** non-zero if this is a miozilla based browser */
Miozilla? Not very polished is it?
mozilla: (/mozilla/).test( userAgent ) && !(/(compatible|
webkit)/).test( userAgent ) ? version : 0,
/** non-zero if this is mobile safari */
mobileSafari: (/apple.*mobile.*safari/).test(userAgent) ?
version : 0,
/** non-zero if we are on windows */
windows: !!(/(windows)/).test(userAgent),
/** non-zero if we are on a mac */
mac: !!((/(macintosh)/).test(userAgent) || (/(mac os x)/).test
(userAgent)),
language: (navigator.language || navigator.browserLanguage).split
('-', 1)[0]
};
// Add more SC-like descriptions...
Huh? Comments that don't make sense are worse than no comments at
all.
SC.extend(browser, /** @scope SC.browser */ {
isOpera: !!browser.opera,
isIe: !!browser.msie,
isIE: !!browser.msie,
isSafari: !!browser.safari,
isMobileSafari: !!browser.mobileSafari,
isMozilla: !!browser.mozilla,
isWindows: !!browser.windows,
isMac: !!browser.mac,
/**
The current browser name. This is useful for switch statements.
*/
How so?
current: browser.msie ? 'msie' : browser.mozilla ? 'mozilla' :
browser.safari ? 'safari' : browser.opera ? 'opera' : 'unknown'
}) ;
return browser ;
})();
I don't even want to look in the next file. How about...
core_query.js. Sounds promising. :)
//
==========================================================================
// Project: SproutCore - JavaScript Application Framework
// Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
// Portions ©2008-2009 Apple Inc. All rights reserved.
// License: Licened under MIT license (see license.js)
//
==========================================================================
/*globals CQ add*/
require('system/builder') ;
/**
CoreQuery is a simplified DOM manipulation library used internally
by SproutCore to find and edit DOM elements. Outside of SproutCore,
you should generally use a more full-featured DOM library such as
Prototype or jQuery.
In other words, abandon all hope... How is it that all of these
various JS projects turn out with the same sort nonsense inside them.
The logic (and lack thereof), the comments, the documentation, the
forum posts, etc. are always so far distanced from reality; and yet,
the justifications for them always reference some Real World where it
makes sense to be ignorant, incompetent, apathetic and lazy. Oh, and
grandiose. :)
Why can't these people find another language to screw up?
"CoreQuery itself is a subset of jQuery with some additional plugins.
If you have jQuery already loaded when SproutCore loads, in fact, it
will replace CoreQuery with the full jQuery library and install any
CoreQuery plugins, including support for the SC.Enumerable mixin."
Well, this is going to be a very short review...
"Much of this code is adapted from jQuery 1.2.6, which is available
under an MIT license just like SproutCore."
...and history lesson. ::)
var styleFloat = SC.browser.msie ? "styleFloat" : "cssFloat";
I remember that one. It's pretty much Game Over as everything else in
the ZIP sits atop this.
// A helper method for determining if an element's values are broken
Again, worthless comments are worse than worthless.
var styleIsBorked = function styleIsBorked( elem ) {
Oh, a named function expression. Somebody let the developers out of
the sound-proof booth. They need to make contact with the rest of the
world.
if ( !SC.browser.safari ) return false;
So, only "values" in Safari (or whatever this thing thinks is Safari)
can be "borked". I really dislike cutesy geek-speak like that. It's
another layer of cheese (on top of a moldy jQuery circa 2007).
// defaultView is cached
Again with the silly comments.
var ret = defaultView.getComputedStyle( elem, null );
return !ret || ret.getPropertyValue("color") === "";
} ;
// implement core methods here from jQuery that we want available all
the
// time. Use this area to implement jQuery-compatible methods ONLY.
// New methods should be added at the bottom of the file, where they
will
// be installed as plugins on CoreQuery or jQuery.
CQ = CoreQuery = SC.Builder.create( /** @scope SC.CoreQuery.fn */ {
Whatever. Skipping to bottom...
// Add some global helper methods.
SC.mixin(SC.$, {
/** @private helper method to determine if an element is visible.
Exposed
for use in testing. */
isVisible: function(elem) {
var CQ = SC.$;
return ("hidden"!=elem.type) && (CQ.css(elem,"display")!="none")
&& (CQ.css(elem,"visibility")!="hidden");
}
}) ;
I've seen that pattern before (and it never fails to make me cringe).
What on earth do hidden inputs have to do with elements that have been
styled hidden (or removed from the layout?) The developers can't see
them? Thanks for bottling that guys. :)
for(var key in enumerable) {
if (!enumerable.hasOwnProperty(key)) continue ;
Oops, just lost Safari 2. It's not that it's necessary to support all
older browsers, but you can't just cut them off in the middle of a
script with an exception. I assume the developers didn't realize what
they were doing (usually a fair assumption).
for ( name in options ) {
CQ.attr(
(type)?this.style:this,
name, CQ.prop( this, options[ name ], type, i, name ));
}
No filter on that one? The attr method is the usual suspect from
jQuery. Hard to believe anyone would copy it at this point. Of
course, it's hard to believe anyone would still be using it at this
late date. Whatever.
// Check to see if the W3C box model is being used
boxModel: !SC.browser.msie || document.compatMode ===
"CSS1Compat",
That was in jQuery until they "punted" box models (along with quirks
mode in general).
isCoreQuery: YES, // walk like a duck
That's about enough I think. Over 30 people wasted a lot of time
building widgets on top of this rubbish heap. The 5000 unit tests are
obviously worthless. I could have told them all they needed to know
without writing a single one. Executive summary: forget it.
Obviously nobody is ever going to go back in here and rewrite this
jQuery regurgitation (and they sure as hell can't "upgrade" it
either). So they might as well turn out the lights and padlock the
place. The world didn't need a parallel jQuery universe (and sure as
hell not another jQuery UI). ;)
And how do I know the author(s) will find this review "superficial".
In reality, I gave it far more time than it deserved. Guys, find
another hobby. I mean that in the kindest possible sense. :)
Also I think nitpicking little bits of code like this is really pointless. Anyone who has written a big project knows that some parts receive more attention then others based on their actual real world needs. Picking one remote part like this and disecting it misses all to useful stuff you might have found if you has just looked.
For example spend some time looking at the datastore or observer layers
---
frmsrcurl: http://compgroups.net/comp.lang.javascript/SproutCore-over-20000-lines-of-new-code
Very often? Why is an old version of jQuery (!) in there at all? And
the comments indicate it will use an extant jQuery if found. That's
suicide as newer versions are incompatible. So good luck with that!
>
> Also I think nitpicking little bits of code like this is really pointless. Anyone who has written a big project knows that some parts receive more attention then others based on their actual real world needs.
Oh, the "real world" argument? Here's a thought: the lowest level DOM
code is everything for a project like this. Don't build castles in a
swamp. ;)
> Picking one remote part like this and disecting it misses all to useful stuff you might have found if you has just looked.
Remote part? It's deep in the core.
>
> For example spend some time looking at the datastore or observer layers
Is it worth it? What do those layers sit upon?
And Happy New Year! :)
//
==========================================================================
// Project: SproutCore - JavaScript Application Framework
// Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
// Portions ©2008-2009 Apple Inc. All rights reserved.
// License: Licened under MIT license (see license.js)
//
==========================================================================
sc_require('system/builder');
/** set update mode on context to replace content (preferred) */
SC.MODE_REPLACE = 'replace';
/** set update mode on context to append content */
SC.MODE_APPEND = 'append';
/** set update mode on context to prepend content */
SC.MODE_PREPEND = 'prepend';
/**
@namespace
A RenderContext is a builder that can be used to generate HTML for
views or
to update an existing element. Rather than making changes to an
element
directly, you use a RenderContext to queue up changes to the
element,
finally applying those changes or rendering the new element when you
are
finished.
You will not usually create a render context yourself but you will
be passed
a render context as the first parameter of your render() method on
custom
views.
Render contexts are essentially arrays of strings. You can add a
string to
the context by calling push(). You can retrieve the entire array as
a
single string using join(). This is basically the way the context
is used
for views. You are passed a render context and expected to add
strings of
HTML to the context like a normal array. Later, the context will be
joined
into a single string and converted into real HTML for display on
screen.
In addition to the core push and join methods, the render context
also
supports some extra methods that make it easy to build tags.
context.begin() <-- begins a new tag context
context.end() <-- ends the tag context...
*/
SC.RenderContext = SC.Builder.create(/** SC.RenderContext.fn */ {
SELF_CLOSING: SC.CoreSet.create().addEach('area base basefront br hr
input img link meta'.w()),
basefont (and it is long deprecated)
/**
When you create a context you should pass either a tag name or an
element
that should be used as the basis for building the context. If you
pass
an element, then the element will be inspected for class names,
styles
and other attributes. You can also call update() or replace() to
modify the element with you context contents.
If you do not pass any parameters, then we assume the tag name is
'div'.
A second parameter, parentContext, is used internally for
chaining. You
should never pass a second argument.
@param {String|DOMElement} tagNameOrElement
@returns {SC.RenderContext} receiver
*/
init: function(tagNameOrElement, prevContext) {
if (tagNameOrElement === undefined) tagNameOrElement = 'div';
// if a prevContext was passed, setup with that first...
if (prevContext) {
this.prevObject = prevContext ;
this.strings = prevContext.strings ;
this.offset = prevContext.length + prevContext.offset ;
}
if (!this.strings) this.strings = [] ;
// if tagName is string, just setup for rendering new tagName
this.needsContent = YES ;
if (SC.typeOf(tagNameOrElement) === SC.T_STRING) {
this._tagName = tagNameOrElement.toLowerCase();
this._needsTag = YES ; // used to determine if end() needs to
wrap tag
// increase length of all contexts to leave space for opening
tag
var c = this;
while(c) { c.length++; c = c.prevObject; }
this.strings.push(null);
this._selfClosing = this.SELF_CLOSING.contains(this._tagName);
} else {
this._elem = tagNameOrElement ;
this._needsTag = NO ;
this.length = 0 ;
this.needsContent = NO ;
}
return this ;
},
// ..........................................................
// PROPERTIES
//
// NOTE: We store this as an actual array of strings so that
browsers that
// support dense arrays will use them.
/**
The current working array of strings.
@property {Array}
*/
strings: null,
/**
this initial offset into the strings array where this context
instance
has its opening tag.
@property {Number}
*/
offset: 0,
/**
the current number of strings owned by the context, including the
opening
tag.
@property {Number}
*/
length: 0,
/**
Specify the method that should be used to update content on the
element.
In almost all cases you want to replace the content. Very
carefully
managed code (such as in CollectionView) can append or prepend
content
instead.
You probably do not want to change this propery unless you know
what you
are doing.
@property {String}
*/
updateMode: SC.MODE_REPLACE,
/**
YES if the context needs its content filled in, not just its
outer
attributes edited. This will be set to YES anytime you push
strings into
the context or if you don't create it with an element to start
with.
*/
needsContent: NO,
// ..........................................................
// CORE STRING API
//
/**
Returns the string at the designated index. If you do not pass
anything
returns the string array. This index is an offset from the start
of the
strings owned by this context.
@param {Number} idx the index
@returns {String|Array}
*/
get: function(idx) {
var strings = this.strings || [];
return (idx === undefined) ? strings.slice(this.offset,
this.length) : strings[idx+this.offset];
},
/**
Adds a string to the render context for later joining. Note that
you can
pass multiple arguments to this method and each item will be
pushed.
@param {String} line the liene to add to the string.
Liene?
@returns {SC.RenderContext} receiver
*/
push: function(line) {
var strings = this.strings, len = arguments.length;
if (!strings) this.strings = strings = []; // create array lazily
if (len > 1) {
strings.push.apply(strings, arguments) ;
} else strings.push(line);
// adjust string length for context and all parents...
var c = this;
while(c) { c.length += len; c = c.prevObject; }
this.needsContent = YES;
return this;
},
/**
Pushes the passed string onto the array, but first escapes the
string
to ensure that no user-entered HTML is processed as HTML.
@param {String} line one or mroe lines of text to add
@returns {SC.RenderContext} receiver
*/
text: function(line) {
var len = arguments.length, idx=0;
for(idx=0;idx<len;idx++) {
this.push(SC.RenderContext.escapeHTML(arguments[idx]));
}
return this ;
},
/**
Joins the strings together, returning the result. But first, this
will
end any open tags.
@param {String} joinChar optional string to use in joins. def
empty string
@returns {String} joined string
*/
join: function(joinChar) {
// generate tag if needed...
if (this._needsTag) this.end();
var strings = this.strings;
return strings ? strings.join(joinChar || '') : '' ;
},
// ..........................................................
// GENERATING
//
/**
Begins a new render context based on the passed tagName or
element.
Generate said context using end().
@returns {SC.RenderContext} new context
*/
begin: function(tagNameOrElement) {
// console.log('%@.begin(%@) called'.fmt(this, tagNameOrElement));
Delete debugging code.
return SC.RenderContext(tagNameOrElement, this);
},
/**
If the current context targets an element, this method returns
the
element. If the context does not target an element, this method
will
render the context into an offscreen element and return it.
@returns {DOMElement} the element
*/
element: function() {
if (this._elem) return this._elem;
// create factory div if needed
var ret, child;
if (!SC.RenderContext.factory) {
SC.RenderContext.factory = document.createElement('div');
}
SC.RenderContext.factory.innerHTML = this.join();
// In IE something weird happens when reusing the same element.
That doesn't inspire confidence. ;)
// After setting innerHTML, the innerHTML of the element in the
previous view
// turns blank. Seems that there is something weird with their
garbage
// collection algorithm.
No. There is something weird going on with your script(s).
// I tried just removing the nodes after keeping a
// reference to the first child, but it didnt work.
// Ended up cloning the first child.
http://www.jibbering.com/faq/faq_notes/clj_posts.html#ps1DontWork
if(SC.RenderContext.factory.innerHTML.length>0){
child = SC.RenderContext.factory.firstChild.cloneNode(true);
SC.RenderContext.factory.innerHTML = '';
} else {
child = null;
}
return child ;
},
/**
Removes an element with the passed id in the currently managed
element.
*/
remove: function(elementId) {
// console.log('remove('+elementId+')');
if (!elementId) return ;
Delete the above two lines. If the calling code is broken, let it
break so you can see the problem(s). ;)
var el, elem = this._elem ;
if (!elem || !elem.removeChild) return ;
Huh? No removeChild method featured, so fail silently?
el = document.getElementById(elementId) ;
if (el) {
el = elem.removeChild(el) ;
el = null;
}
},
/**
If an element was set on this context when it was created, this
method
will actually apply any changes to the element itself. If you
have not
written any inner html into the context, then the innerHTML of
the
element will not be changed, otherwise it will be replaced with
the new
innerHTML.
Also, any attributes, id, classNames or styles you've set will be
updated as well. This also ends the editing context session and
cleans
up.
@returns {SC.RenderContext} previous context or null if top
*/
update: function() {
var elem = this._elem,
mode = this.updateMode,
key, value, styles, factory, cur, next, before;
this._innerHTMLReplaced = NO;
if (!elem) {
// throw "Cannot update context because there is no source
element";
return ;
*Sigh* See above.
}
// console.log('%@#update() called'.fmt(this));
// if (this.length>0) console.log(this.join());
// else console.log('<no length>');
// replace innerHTML
if (this.length>0) {
this._innerHTMLReplaced = YES;
if (mode === SC.MODE_REPLACE) {
elem.innerHTML = this.join();
} else {
factory = elem.cloneNode(false);
factory.innerHTML = this.join() ;
before = (mode === SC.MODE_APPEND) ? null : elem.firstChild;
cur = factory.firstChild ;
while(cur) {
next = cur.nextSibling ;
elem.insertBefore(cur, next);
cur = next ;
}
cur = next = factory = before = null ; // cleanup
}
}
// note: each of the items below only apply if the private
variable has
// been set to something other than null (indicating they were
used at
// some point during the build)
// if we have attrs, apply them
if (this._attrsDidChange && (value = this._attrs)) {
for(key in value) {
if (!value.hasOwnProperty(key)) continue;
You just sank Safari 2. See previous post.
if (value[key] === null) { // remove empty attrs
elem.removeAttribute(key);
LOL. You are making the same mistakes as jQuery, Prototype, YUI, etc.
http://www.cinsoft.net/attributes.html
} else {
SC.$(elem).attr(key, value[key]);
You can't be a little pregnant. Thank you very much for wasting my
time. :)
Th idea of parsing navigator.userAgent is faulty inference.
>
> Oh no.
>
>
> SC.browser = (function() {
>
> var userAgent = navigator.userAgent.toLowerCase();
> var version = (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ )
> || [])[1] ;
>
> var browser = /** @scope SC.browser */ {
>
>
> Please, make it stop. :) Scope?
>
@Scope is a JS-doc comment. I did argue with Michael Matthews about that.
JS-Doc toolkit comments are a pain in hte neck to keep up to date and
just add clutter to the actual code. But anyway, that is why that
comment xists.
> /** The current browser version */
> version: version,
>
> /** non-zero if webkit-based browser */
> safari: (/webkit/).test( userAgent ) ? version : 0,
>
That is a wrongly named identifier. "webkit" is not safari. Webkit is on
Palm pre, in Chrome, in iris.
>
> Non-zero? This must be their own unique interpretation of jQuery's
> sniffing. I wonder if they realize that jQuery moved forward one step
> to object inferences.
>
>
> /** non-zero if this is an opera-based browser */
> opera: (/opera/).test( userAgent ) ? version : 0,
>
>
> The one browser in the world that is easy to detect and they blew it.
> Of course, there should be no reason to detect Opera in 2010 (or 2009
> or 2008...) Can only go downhill from here.
>
>
> /** non-zero if this is IE */
> msie: (/msie/).test( userAgent ) && !(/opera/).test( userAgent ) ?
> version : 0,
>
MSIE is a very commonly faked user-agent. Recognizing that Opera masks
as "msie" should have been a hint that this might not be a good idea.
>
> Sad, especially considering IE has conditional comments. Oh, but that
> won't fit into their plans of creating a way-cool browser scripting
> framework. :)
>
Conditional comments would be much more accurate here. ScriptEngine
would, too, though cc would be best.
> mozilla: (/mozilla/).test( userAgent ) && !(/(compatible|
> webkit)/).test( userAgent ) ? version : 0,
>
It is less error-prone to use 'Gecko'. Applications that embed Mozilla
should not be using 'mozilla' in the userAgent, but would be likely to
have 'Gecko' in the user-agent. Regardless, this whole browser detection
inference is faulty.
> /** non-zero if this is mobile safari */
> mobileSafari: (/apple.*mobile.*safari/).test(userAgent) ?
> version : 0,
>
> /** non-zero if we are on windows */
> windows: !!(/(windows)/).test(userAgent),
>
> /** non-zero if we are on a mac */
> mac: !!((/(macintosh)/).test(userAgent) || (/(mac os x)/).test
> (userAgent)),
>
That should not be something the program would care about. A user
platform is not something that HTTP includes and might very well be
excluded from an embedded system.
> language: (navigator.language || navigator.browserLanguage).split
> ('-', 1)[0]
> };
>
> // Add more SC-like descriptions...
>
>
> Huh? Comments that don't make sense are worse than no comments at
> all.
>
That is a senseless comment.
[...]
>
>
> current: browser.msie ? 'msie' : browser.mozilla ? 'mozilla' :
> browser.safari ? 'safari' : browser.opera ? 'opera' : 'unknown'
>
It looks like four browsers. There are more than four browsers available
on the market and many of these are going to sadly fall into the
category of "unknown".
> }) ;
>
> return browser ;
>
> })();
>
>
> I don't even want to look in the next file. How about...
> core_query.js. Sounds promising. :)
>
>
> //
> ==========================================================================
> // Project: SproutCore - JavaScript Application Framework
> // Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
> // Portions ©2008-2009 Apple Inc. All rights reserved.
> // License: Licened under MIT license (see license.js)
> //
> ==========================================================================
> /*globals CQ add*/
>
> require('system/builder') ;
>
> /**
> CoreQuery is a simplified DOM manipulation library used internally
> by SproutCore to find and edit DOM elements. Outside of SproutCore,
> you should generally use a more full-featured DOM library such as
> Prototype or jQuery.
>
That is a useless comment. Useless because it does not state what
features are lacking and what these libraries should be used for.
>
> "CoreQuery itself is a subset of jQuery with some additional plugins.
> If you have jQuery already loaded when SproutCore loads, in fact, it
> will replace CoreQuery with the full jQuery library and install any
> CoreQuery plugins, including support for the SC.Enumerable mixin."
>
>
> Well, this is going to be a very short review...
>
>
> "Much of this code is adapted from jQuery 1.2.6, which is available
> under an MIT license just like SproutCore."
>
jQuery 1.2 has a lot of obvious bugs that were fixed. It should not be
used at this time.
>
> ...and history lesson. ::)
>
>
> var styleFloat = SC.browser.msie ? "styleFloat" : "cssFloat";
>
> I remember that one. It's pretty much Game Over as everything else in
> the ZIP sits atop this.
>
The problem with this inference is that it ties browser that has 'msie'
in userAgent to using 'styleFloat' and browsers that do not use 'cssFloat'.
Where available, the standard cssFloat property should be used. It is
very easy to detect:-
var FLOAT_PROP = "cssFloat";
if(document.documentElement.style[FLOAT_PROP] === "undefined") {
FLOAT_PROP = "styleFloat";
}
This assumes that cssFloat is supported, and if it isn't, then it uses
styleFloat.
> // A helper method for determining if an element's values are broken
>
>
> Again, worthless comments are worse than worthless.
>
>
> var styleIsBorked = function styleIsBorked( elem ) {
>
Best to not repeat feature tests; perform the feature test only once.
>
> Oh, a named function expression. Somebody let the developers out of
> the sound-proof booth. They need to make contact with the rest of the
> world.
>
There is no good reason to not use a FunctionDeclaration there.
>
> if ( !SC.browser.safari ) return false;
>
>
> So, only "values" in Safari (or whatever this thing thinks is Safari)
> can be "borked". I really dislike cutesy geek-speak like that. It's
> another layer of cheese (on top of a moldy jQuery circa 2007).
>
It isn't just Safari, remember, but *any* webkit here. Only a browser
that identifies as webkit may be borked.
>
> // defaultView is cached
>
>
> Again with the silly comments.
>
>
> var ret = defaultView.getComputedStyle( elem, null );
> return !ret || ret.getPropertyValue("color") === "";
> } ;
>
The method call to `getPropertyValue("color") can be replaced with
ret.color.
>
> // implement core methods here from jQuery that we want available all
> the
> // time. Use this area to implement jQuery-compatible methods ONLY.
> // New methods should be added at the bottom of the file, where they
> will
> // be installed as plugins on CoreQuery or jQuery.
> CQ = CoreQuery = SC.Builder.create( /** @scope SC.CoreQuery.fn */ {
>
That looks like an assignment to an undeclared identifier.
The identifiers should have been declared using `var`.
>
> // Add some global helper methods.
> SC.mixin(SC.$, {
>
The identifier `$` is not descriptive. It should be renamed to describe
what it means.
> /** @private helper method to determine if an element is visible.
> Exposed
yes, the method is exposed.
> for use in testing. */
> isVisible: function(elem) {
> var CQ = SC.$;
> return ("hidden"!=elem.type) && (CQ.css(elem,"display")!="none")
> && (CQ.css(elem,"visibility")!="hidden");
> }
>
> }) ;
It might be worth considering the case for visibility: collapse.
>
>
> I've seen that pattern before (and it never fails to make me cringe).
> What on earth do hidden inputs have to do with elements that have been
> styled hidden (or removed from the layout?) The developers can't see
> them? Thanks for bottling that guys. :)
>
>
> for(var key in enumerable) {
>
> if (!enumerable.hasOwnProperty(key)) continue ;
>
>
> Oops, just lost Safari 2. It's not that it's necessary to support all
> older browsers, but you can't just cut them off in the middle of a
> script with an exception. I assume the developers didn't realize what
> they were doing (usually a fair assumption).
>
>
> for ( name in options ) {
> CQ.attr(
> (type)?this.style:this,
> name, CQ.prop( this, options[ name ], type, i, name ));
> }
>
>
> No filter on that one? The attr method is the usual suspect from
> jQuery. Hard to believe anyone would copy it at this point. Of
> course, it's hard to believe anyone would still be using it at this
> late date. Whatever.
>
I have no idea what that method is intended to perform, but if it is
using jQuery.attr, it is obviously in very poor judgement, as is
everything else here.
>
> // Check to see if the W3C box model is being used
> boxModel: !SC.browser.msie || document.compatMode ===
> "CSS1Compat",
>
>
> That was in jQuery until they "punted" box models (along with quirks
> mode in general).
>
> isCoreQuery: YES, // walk like a duck
>
>
> That's about enough I think. Over 30 people wasted a lot of time
> building widgets on top of this rubbish heap.
Sounds like Dojo. This library is not going to die.
--
Garrett
comp.lang.javascript FAQ: http://jibbering.com/faq/
[...]
>
> Sounds like Dojo. This library is not going to die.
Is or isn't? It is a shame that so many people have worked for so
long to produce something like this. I don't wish failure on anybody,
but some people refuse to be helped (see the predicted Real World
comment from the "creator" of this thing).
This message is not wrapping so well. What newsreader are you using?
> Also I think nitpicking little bits of code like this is really pointless. Anyone who has written a big project knows that some parts receive more attention then others based on their actual real world needs. Picking one remote part like this and disecting it misses all to useful stuff you might have found if you has just looked.
>
That would seem like nitpicking if the point was not quality code.
The code in Sproutcore that was just displayed has problems. Browser
detection is known to be the source of forwards compibility issues.
Basing a library on faulty inferences at the base level in the
dependency chain is a disastrous decision. Such inferences and thinking
for detecting styleFloat show another poor inference.
None of that would pass code review. You probably don't want to hear
that and have probably spent a good amount of time on it, but it is the
truth.
> For example spend some time looking at the datastore or observer layers
If you would like to prepare for a code review, then this is a fine place.
I recommend formatting the code to 72 chars. you should prepare to
explain briefly the intent of the code (use diagrams if you like).
Posters of this newsgroup will find the errors and mistakes in it for you.
I can also meet you in person, as you're local.
>
> ---
> frmsrcurl: http://compgroups.net/comp.lang.javascript/SproutCore-over-20000-lines-of-new-code
Ah, using a web forum. Try downloading Thunderbird an getting an account
with a newsgroup provider. I use eternal-september.org. THe newsgroup is
comp.lang.javascript.
Isn't the adage "Look after the pennies and the pounds look after
themselves". Or, if you prefer, "God is in the detail".
Andrew Poulos
"Ready" for some unspecified purpose.
Unfortunately this crap is at the heart of Apple's MobileMe site.
Despite the "mobile" claim, it doesn't work on iPhone. They sniff for
mobile safari, block entry and tell you to use iPhone apps instead. It
also sniffs for, and refuses entry to, IE 6.
It is slow and fat - even simple pages are 1.5mb. If this is the
future of web applications, count me out.
--
Rob
> Charles Jolley wrote:
>> Hi I am the creator of sproutcore. If you had taken the time to look at
>> the rest of sproutcore you might have noticed that corequery is not used
>> very often because our view layer has a more powerful system called the
>> rendercontext.
>
> [snipped 400+ lines of garbage]
You have been told before that your code reviews are next to unreadable,
thus next to useless. You have also been asked before to take more care
when posting them. Suggestions have been made how this could be
accomplished. Please do everyone a favor and, as your New Year's
resolution, do not waste more bandwidth like this again. Thanks in advance.
PointedEars
--
realism: HTML 4.01 Strict
evangelism: XHTML 1.0 Strict
madness: XHTML 1.1 as application/xhtml+xml
-- Bjoern Hoehrmann
Wonder why they get so much attention then. :) And this addendum was
not so much a review as a demonstration of some very bad code (which
had been described as "more powerful" by the creator). It really
needed no introduction.
> You have also been asked before to take more care
> when posting them.
Yes.
> Suggestions have been made how this could be
> accomplished.
Yes.
> Please do everyone a favor and, as your New Year's
> resolution, do not waste more bandwidth like this again.
No, I'm sorry, To hell with the bandwidth.
> Thomas 'PointedEars' Lahn wrote:
>> David Mark wrote:
>> > Charles Jolley wrote:
>> >> Hi I am the creator of sproutcore. If you had taken the time to look
>> >> at the rest of sproutcore you might have noticed that corequery is
>> >> not used very often because our view layer has a more powerful system
>> >> called the rendercontext.
>> >
>> > [snipped 400+ lines of garbage]
>>
>> You have been told before that your code reviews are next to unreadable,
>> thus next to useless.
>
> Wonder why they get so much attention then. :)
Interest in a thing does not imply acceptance of that thing. Besides, I
would not call four followups, out of a group of regulars of at least 10
people, out of a newsgroup used by at least 2313 people, out of a medium
used by millions, "much attention".
> And this addendum was not so much a review as a demonstration of some
> very bad code (which had been described as "more powerful" by the
> creator). It really needed no introduction.
I am sure nobody expected an introduction. This is about the difficulty a
reader must be having when trying to determine which part of your posting
belongs to the code and which part to your comments about it. Such
postings are _not_ useful, and they certainly do not help anyone (to see
your point).
>> You have also been asked before to take more care
>> when posting them.
>
> Yes.
>
>> Suggestions have been made how this could be
>> accomplished.
>
> Yes.
>
>> Please do everyone a favor and, as your New Year's
>> resolution, do not waste more bandwidth like this again.
>
> No, I'm sorry, To hell with the bandwidth.
And to hell with your readers? So you are just a poser after all?
If you do not want to post so that it can be easily read, you are much
better off with writing a diary.
PointedEars
--
Prototype.js was written by people who don't know javascript for people
who don't know javascript. People who don't know javascript are not
the best source of advice on designing systems that use javascript.
-- Richard Cornford, cljs, <f806at$ail$1$8300...@news.demon.co.uk>
As I said, that was pretty much a code dump, not a review. And don't
you worry about my readers as I am about to launch a site that
summarizes all of this stuff in one easy to find place (and that place
will not resemble GG). ;)
>
> If you do not want to post so that it can be easily read, you are much
> better off with writing a diary.
So you feel my voice isn't being heard? :)
> Thomas 'PointedEars' Lahn wrote:
>> David Mark wrote:
>> > Thomas 'PointedEars' Lahn wrote:
>> >> Please do everyone a favor and, as your New Year's
>> >> resolution, do not waste more bandwidth like this again.
>>
>> > No, I'm sorry, To hell with the bandwidth.
>>
>> And to hell with your readers? So you are just a poser after all?
>
> As I said, that was pretty much a code dump, not a review. And don't
> you worry about my readers as I am about to launch a site that
> summarizes all of this stuff in one easy to find place (and that place
We (I think I can speak for all subscribers regarding this) do not need
*such* "code dumps" here, thank you very much.
>> If you do not want to post so that it can be easily read, you are much
>> better off with writing a diary.
>
> So you feel my voice isn't being heard? :)
That is beside the point. Your voice would certainly be heard better and
more clear if you would come to your senses and post something better
readable than this.
EOD
PointedEars
--
var bugRiddenCrashPronePieceOfJunk = (
navigator.userAgent.indexOf('MSIE 5') != -1
&& navigator.userAgent.indexOf('Mac') != -1
) // Plone, register_function.js:16
Ah, the royal "we". I don't think you speak for all "subscribers" at
all. I'd just as soon I speak for them. Thank you very much. :)
>
> >> If you do not want to post so that it can be easily read, you are much
> >> better off with writing a diary.
>
> > So you feel my voice isn't being heard? Â :)
>
> That is beside the point.
Then I must have missed your point.
> Your voice would certainly be heard better and
> more clear if you would come to your senses and post something better
> readable than this.
Yes.
>
> EOD
Mad as a mongoose named Maddie on a particularly mad day.
Good reviews take time. I can try and take a partial review:
Looking at the datastore:
http://github.com/sproutit/sproutcore/blob/master/frameworks/datastore/models/record.js
That depends on SC.Object.extend, defined here:-
http://github.com/sproutit/sproutcore/blob/master/frameworks/runtime/system/object.js
It is well-commented, I'll give it that.
I'm not accustomed to where everything is defined and don't find it all
right away (the packaging is not intuitive). It is hard to follow method
calls across several files and it is unclear which file the method is
defined in. Things are added to Function.prototype in various places,
but it is uncertain where.
I see global identifiers, such as `YES and `NO` (silly), global
identifiers in IE, via NFE. I see cases not considering older browsers
(hasOwnProperty).
The design of many functions/methods leaks implementation details out
using fake private. This is unnecessary and usually not very hard to avoid.
I also see some benchmarking interspersed with the code. What does
benchmarking have to do with extending objects?
http://github.com/sproutit/sproutcore/blob/master/frameworks/runtime/system/object.js
My inline comments as "// (GS) ... ".
extend: function(props) {
// (GS) What does benchmarking have to do with extending objects?
// (GS) I suggest removing the benchmarking. You might want to put it in
// (GS) completely separate AOP layer. Or just get rid of it (I would).
var bench = SC.BENCHMARK_OBJECTS ;
if (bench) SC.Benchmark.start('SC.Object.extend') ;
// build a new constructor and copy class methods. Do this before
// adding any other properties so they are not overwritten by the
// copy.
// (GS) This looks like you're building up a big global SC.Object with
// (GS) more properties coming from anyone who should call
// (GS) `SC.Object.extend`. What is SC.Object defining?
//
// (GS) Why the underscore here? This is a globally-accessible
// (GS) SC.Object.prototype._object_init; it is not really private.
var prop, ret = function(props) { return this._object_init(props);};
for(prop in this) {
if (!this.hasOwnProperty(prop)) continue ;
// (GS) Avoid referencing `this` in static context.
ret[prop] = this[prop];
}
// (GS) `hasOwnProperty` won't work in some implementations.
// (GS) Also, `toString` is not the only problematic one; Did you
// (GS) consider `valueOf`?
// manually copy toString() because some JS engines do not enumerate it
if (this.hasOwnProperty('toString')) ret.toString = this.toString;
// now setup superclass, guid
ret.superclass = this ;
SC.generateGuid(ret); // setup guid
ret.subclasses = SC.Set.create();
this.subclasses.add(ret); // now we can walk a class hierarchy
// setup new prototype and add properties to it
var base = (ret.prototype = SC.beget(this.prototype));
var idx, len = arguments.length;
for(idx=0;idx<len;idx++) SC._object_extend(base, arguments[idx]) ;
base.constructor = ret; // save constructor
// (GS) Again with the benchmarking.
if (bench) SC.Benchmark.end('SC.Object.extend') ;
return ret ;
},
I see that function calls various other functions. I see a call to
SC._object_extend. I've modified the code to wrap at 72 chars.
// (GS) Named FunctionExpression will add a global `_object_extend`
// (GS) property in JScript <= 5.8. I suggest not doing that.
SC._object_extend = function _object_extend(base, ext) {
// (GS) Suggest throwing an object. That helps some Debuggers get a
// (GS) stack trace (error.stack).
if (!ext) throw "SC.Object.extend expects a non-null value. "
+ "Did you forget to 'sc_require' something? Or were you passing a "
+ " Protocol to extend() as if it were a mixin?";
// (GS) There is not need to leak implementation details to the base
// (GS) object. I suggest avoiding doing that, so that these
// (GS) implementation details remain hidden, and can never be relied
// (GS) on.
// set _kvo_cloned for later use
base._kvo_cloned = null;
I've given enough suggestions. There is enough complexity to confuse me.
I managed to find SC.Set.
http://github.com/sproutit/sproutcore/blob/master/frameworks/runtime/system/set.js
End.
How's that?
It's so funny and ridiculous and seems sooo stupid that the same guys
that advocate turning off JS in the browser (many cljs regulars), feel
themselves as an authority so as to judge somebody else's work whose
main goal/underlying idea don't even understand (e.g., you don't know
a word of cocoa), just by looking at a few lines in their JS source.
--
Jorge.
I don't agree that "many" cljs regulars recommend turning off javascript
on a regular basis. It is certainly worth doing on sites that throw
script errors or are otherwise unusable.
Unfortunately many sites are needlessly dependent on script so turning
script support off is not always a useful an option. However, plugins
like NoScript allow users to selectively run scripts so that they can
accomplish what they want without running all scripts that a site has.
> feel
> themselves as an authority so as to judge somebody else's work whose
> main goal/underlying idea don't even understand
The subject of this thread is from Sproutcore's home page, which also
states:
"Create fast, native-style applications in any modern web browser
without plugins."
It also claims to be a "JavaScript HTML5 Application Framework"
<URL: http://www.sproutcore.com/home/ >
Cljs is *the* place to discuss technical issues related to it.
> (e.g., you don't know
> a word of cocoa),
Utterly irrelevant. Apple's Cocoa is a "collection of frameworks, APIs,
and accompanying runtimes"[1] specifically for Mac OS X developers. That
is unrelated to a script library that is supposed to be suitable for web
applications and presumably platforms other than Safari on Mac OS.
> just by looking at a few lines in their JS source.
Those who have commented here have looked at more than "a few lines" -
SproutCore is tens of thousand of lines of code, it is incredibly
verbose. No one should post a review of the entire library here.
1. <URL: http://developer.apple.com/cocoa/ >
--
Rob
In case you didn't know, SproutCore is Cocoa for the Web.
--
Jorge.
Sadly, in higher profile forums, cljs is seen more and more as a bunch
of clueless idiots. Garret is helping a lot with that, for in every
other forum he dares to put a feet on -where he invariably tries to
impersonate as the author on the cljs faq (*)- it's just to annoy them
with pointless, arrogant, ridiculous posts of little or no value at
all, except for his great success in pissing off the regulars.
(*)See his signature, and the 1st line in the cljs faq states "by"
him. Given the negative image he projects wherever he goes, I wonder
whether -for the good of cljs- his name ought to be there at all to
begin with.
--
Jorge.
After that, I would want to look at the lowest level core and see the
actual code.
I want to know that the library is using abstractions that are
well-written. The core file has browser detection, global identifiers,
recommendations to use either PrototypeJS or jQuery.
I see some higher level parts of the framework relying on modifications
to Function.prototype, for example. I saw some place that defined
certain modifications to Function.prototype, but not the modifications
that were used in the datastore's renderer.
I have also noticed recent commits in GitHub with things like:-
Commit comment:
"Make it work a bit better in IE"
Where "a bit better" is a euphemism for BUGFIX.
The previous code was:-
| if (SC.none(newLayout[key])) delete style[key];
And the new code is:-
| if (SC.none(newLayout[key])) style[key] = ""; // because IE is stupid
|// and can't handle delete or debug.
What is debug?
Calling `delete` on a host object results in Errors in IE.
It is good that the author did recognize and fix the bug. But it would
be hard to notice the bug without at least trying once in IE. Also, the
comment should not be calling IE "stupid" for what is perfectly legal
behavior. IE throwing on delete for host object is legal in ES3,
through vague wording, and legal in ES5 through explicit wording via
internal [[Delete]] (P, Throw).
Setting a style property to `null` IE, as another comment indicated was
attempted, might also throw "Invalid Argument" errors. The program
should only supply that are legal CSS values. Literal `null` might
convert to domstring "null", which would either illegal CSS value (or
useless things like "font family", where it would be legal).
I also see things in random places such as:-
http://github.com/sproutit/sproutcore/blob/master/frameworks/designer/css/css_style_sheet.js
My inline comments follow:
| init: function() {
| // (GS) See note below on Transcoded Function call.
| sc_super() ;
|
| var ss = this.styleSheet ;
|
| if (!ss) {
| // (GS) Extract this branch to a hidden-in-scope function.
| // create the stylesheet object the hard way (works everywhere)
| ss = this.styleSheet = document.createElement('style') ;
| ss.type = 'text/css' ;
| var head = document.getElementsByTagName('head')[0] ;
|
| // (GS) What does this fix for Opera?
| if (!head) head = document.documentElement ; // fix for Opera
| head.appendChild(ss) ;
| }
|
| // (GS) Move this "get or create" Factory logic elsewhere. It does not
| // (GS) belong in init().
| // cache this object for later
| var ssObjects = this.constructor.styleSheets ;
| if (!ssObjects) ssObjects = this.constructor.styleSheets = {} ;
| ssObjects[SC.guidFor(ss)] ;
|
| // (GS) This is either undefined or an IE `rules` collection.
| // create rules array
|
| var rules = ss.rules || SC.EMPTY_ARRAY ;
| var array = SC.SparseArray.create(rules.length) ;
|
| // (GS) Avoid leaking implementation details to the system.
| array.delegate = this ;
| this.rules = array ;
|
| return this ;
| },
The transcoded function call, mentioned the first review comment, is
apparently changed to:- arguments.callee.base.apply(this, arguments);
That statement, used in the `init` method below, means that
`arguments.callee` *is* the `init` method. init.base is not defined in
`SC.CSSStyleSheet`. It seems as though it is defined as an extension to
`Function.prototype`, though at this point, it might be transcoded to
something else.
Transcoding sc_super() creates a confusing coupling with the build tool.
That confusion and complexity is not justified by the syntactic sugar it
provides.
To the author: Replace that statement with real code and stop trying to
be clever.
We also see that in the actual function, there is a caching mechanism.
This "get or create" can be useful, but I don't think it belongs there
in `init`.
There is also the problem in that this method will only work in a
browser that has an IE `rules` collection. That includes IE and Safari,
and I don't know what else. Instead, the standard `cssRules` property
should be used with `rules` as a fallback.
I did not look at SC.SparseArray.create. I assume it is about on quality
with everything else seen so far.
You're posting on cljs so that must mean you are also a clueless idiot.
> other forum he dares to put a feet on -where he invariably tries to
> impersonate as the author on the cljs faq (*)- it's just to annoy them
> with pointless, arrogant, ridiculous posts of little or no value at
> all, except for his great success in pissing off the regulars.
So he's not allowed to dare point out faults in sproutcore but you feel
justified in doing a character assassination?
> (*)See his signature, and the 1st line in the cljs faq states "by"
> him. Given the negative image he projects wherever he goes, I wonder
> whether -for the good of cljs- his name ought to be there at all to
> begin with.
When a house is built the architect will say its there's, the build will
say its there's, the actual owner will say its there's, anyone leasing
the house will say its there's, and anyone living there will say its
there's. So claiming ownership of something you are responsible for is
not unnatural.
Andrew Poulos
You've been drinking the Kool-Aid. That is a line introduced by Apple's
marketing team back in mid-2008 when they announced the new MobileMe
site based on SproutCore. It makes as much sense as calling it .NET for
the web.
The fact that Apple's MobileMe site doesn't even work with their own
mobile devices (iPhone and iPod Touch) gives you some idea of how
accurate marketing terms are.
Have a play with the SproutCore site on an iPhone, you'll notice the
following:
- The SproutCore home page takes 20 seconds or longer to load (iPhone
over broadband and WiFi) and throws an error about "ready() is not yet
supported on Safari 3.1 and earlier" as does every page using SproutCore
- The demo page takes over 20 seconds to load
- Going forward and backward between the above two pages takes over 20
seconds so caching appears to work
- You can't scroll to the demos below "user_defaults" (so much for their
cross-platform widgets)
- The bullet images may or may not appear
- Selecting a particular demo is a lottery - the list may or may not
respond to touches
- I have no idea what the iPhone demo is supposed to do, it does nothing
- The user_defaults demo does not work at all, the suggestion text is
cropped by incorrect style settings (it works OK in Firefox)
I could go on. And all that from a demo page for a framework that is
supposed to include mobile devices and specifically target iPhone.
It claims to be "small(ish)" yet is bloated. It claims to do more with
less code (where have we heard that before?) but doesn't. The clock demo
can be written in far less code and be more functional.
SproutCore also embeds most of the styling in the code, so the supposed
abstraction of script and content is completely broken. Have a look at
statements like:
Clock.mainPage=SC.Page.design({mainPane:SC.MainPane.design().layout({centerX:0,centerY:0,width:320,height:120}).classNames("clock").childView(SC.LabelView.design().layout({left:10,right:10,centerY:0,height:48}).tagName("h1").bind("value","Clock.clockController.value")).childView(SC.CheckboxView.design().layout({centerX:0,width:130,bottom:10,height:18}).prop("title","Show
Greeting").bind("value","Clock.clockController.showGreeting"))});
My stab at pretty-printing it:
Clock.mainPage = SC.Page.design({
mainPane: SC.MainPane.design().layout({
centerX: 0,
centerY: 0,
width: 320,
height: 120
}).classNames("clock").childView(SC.LabelView.design().layout({
left: 10,
right: 10,
centerY: 0,
height: 48}).tagName("h1").bind("value",
"Clock.clockController.value"))
.childView(SC.CheckboxView.design().layout({
centerX: 0,
width: 130,
bottom: 10,
height: 18}).prop("title", "Show Greeting")
.bind("value", "Clock.clockController.showGreeting")
)
});
Not to mention that the clock itself uses "invokeLater" (which I presume
is simply a call to setTimeout) with an interval of 1000 and therefore
runs up to 1 second slow. It will slowly drift and occasionaly skip a
second.
--
Rob
http://www.google.com/search?q=cocoa+site:sproutcore.com
--
Jorge.
Thanks for agreeing.
Your point was that a person can't do a worthwhile review of
SproutCore unless they have a good knowledge of Cocoa. Your basis for
that seems to be a bunch of marketing material that uses Cocoa as a
similie for an MVC framework.
There is no need to know about Cocoa at all when reviewing the library
code used by SproutCore, criticisms were based purely on its use of
javascript. If you can show that a specific criticim is not justified
based on some principle of MVC architecture, design pattern, code
style or some other relevant point, please do so.
Otherwise your point is irrelevant.
--
Rob
Jorge posts generally have a very low signal/noise ratio.
That is a line introduced by Apple's
> marketing team back in mid-2008 when they announced the new MobileMe
> site based on SproutCore. It makes as much sense as calling it .NET for
> the web.
>
".Net for the web" would probably not be good salesmanship for Apple.
> The fact that Apple's MobileMe site doesn't even work with their own
> mobile devices (iPhone and iPod Touch) gives you some idea of how
> accurate marketing terms are.
>
MobileMe? Isn't that a pay site that allows the user to sign up for
push-notifications of email and syncing photos and stuff?
http://www.apple.com/mobileme/
I think I see.
Does MobileMe use the standard iPhone notifications? Those notifications
interrupt user process to present a modal dialog. Modal dialogs can be
really annoying when trying to do something important, like make a
time-sensitive call. Such modal design actually violates Apples UI
design principles, actually.
Well, iPhone is about hype, and the phone itself, as a phone, is of very
poor quality.
In a way, SproutCore and iPhone match up.
> Have a play with the SproutCore site on an iPhone, you'll notice the
> following:
>
> - The SproutCore home page takes 20 seconds or longer to load (iPhone
> over broadband and WiFi) and throws an error about "ready() is not yet
> supported on Safari 3.1 and earlier" as does every page using SproutCore
>
> - The demo page takes over 20 seconds to load
>
> - Going forward and backward between the above two pages takes over 20
> seconds so caching appears to work
>
> - You can't scroll to the demos below "user_defaults" (so much for their
> cross-platform widgets)
>
> - The bullet images may or may not appear
>
They're using list-style for mobile? That won't work on a lot of devices.
> - Selecting a particular demo is a lottery - the list may or may not
> respond to touches
>
> - I have no idea what the iPhone demo is supposed to do, it does nothing
>
> - The user_defaults demo does not work at all, the suggestion text is
> cropped by incorrect style settings (it works OK in Firefox)
>
> I could go on. And all that from a demo page for a framework that is
> supposed to include mobile devices and specifically target iPhone.
>
That sounds awful. After looking at the code, I am not surprised that it
has such problems. I've seen places where I can spot exactly how it will
fail (using the `rules` property, using `userAgent` checks). I'm really
surprised that such a large codebase was designed for mobile.
> It claims to be "small(ish)" yet is bloated. It claims to do more with
> less code (where have we heard that before?) but doesn't. The clock demo
> can be written in far less code and be more functional.
>
Small is a relative term.
Our Sun is much smaller than the anticipated SuperNova Betelgeuse.
Dojo: Small, fast, deep.
Ext:
Ext Core is a cross-browser JavaScript library for building dynamic web
pages. It includes:
* High performance, lightweight
This is called marketing lingo.
> SproutCore also embeds most of the styling in the code, so the supposed
> abstraction of script and content is completely broken. Have a look at
> statements like:
>
>
[snip]
That code is a mess. Did anybody at Apple review any of this code before
paying for sponsorship? Or were the reviewees unable to make assessments?
I've seen the demos for the 280 north cappucino (same guys). While the
code is atrocious, they speak and present well.
Agree. :-)
> > The fact that Apple's MobileMe site doesn't even work with their own
> > mobile devices (iPhone and iPod Touch) gives you some idea of how
> > accurate marketing terms are.
>
> MobileMe? Isn't that a pay site that allows the user to sign up for
> push-notifications of email and syncing photos and stuff?
>
> http://www.apple.com/mobileme/
>
> I think I see.
Yes, it is an implementation using SproutCore and an example of the
quality of Apple web sites. They look terrific, but the performance is
sluggish and underneath the technology seems flawed.
Apple seems to have changed the WebObjects foundation of their main
web site and used Prototype.js and scriptaculous.js for browser
functionality. I think playing with SproutCore is an attempt to get
something more integrated, like WO used to be.
Apparently Apple has been working on a new js framework to be bundled
with WebObjects called Gianduia, it seems to be similar to SproutCore
(and also has been called "browser-side Cocoa") so perhaps they are
are still trying to find their web development nirvana.
> Does MobileMe use the standard iPhone notifications? Those notifications
> interrupt user process to present a modal dialog.
MobileMe is the website that iPhone uses it to synchronise application
data (mail, calendar, bookmarks, etc.) with desktop apps using the
internet (the same functionality is provided by the dock or cable
connector). MobileMe doesn't do large files like iTunes songs or
videos, though other applications like FileMagnet do. Alerts and
dialogs are from the applications and yes, they can be modal and
interrupt other applications. But that is a consequence of the
application design, it is not MobileMe per se.
[...]
> Well, iPhone is about hype, and the phone itself, as a phone, is of very
> poor quality.
Maybe, but it sure gave the "smart phone" market a kick in the right
direction. :-)
> In a way, SproutCore and iPhone match up.
Sadly, yes.
> > Have a play with the SproutCore site on an iPhone, you'll notice the
> > following:
[...]
> > I could go on. And all that from a demo page for a framework that is
> > supposed to include mobile devices and specifically target iPhone.
>
> That sounds awful. After looking at the code, I am not surprised that it
> has such problems.
To me it is a quality issue. The demos may or may not reflect the
quality of the underlying SproutCore framework, but their shabbiness
is a reflection on the development team's commitment to quality. They
are a terrible advertisement.
> I've seen places where I can spot exactly how it will
> fail (using the `rules` property, using `userAgent` checks). I'm really
> surprised that such a large codebase was designed for mobile.
Yeah, around 600kb minified. Given that the framework includes MVC and
server-side components, I would have expected it to minimise what is
sent to the client and maximise efficiency. It appears to follow the
old Access database idea of shovelling everything off to the client.
It was a bad strategy then for much the same reasons it is a bad
strategy now. A couple of the main ones are that it hogs bandwidth and
is hugely dependent on the client behaving - and browsers are known to
be very badly behaved.
But that seems to be where web applications are headed - instead of
HTML pages with a bit of script to help out, the entire page is
generated by script, with constant AJAX calls in the background to
sync with the server or get more data. It seems like an incredible
waste of resources to me and is utterly dependent on users having
fast, modern machines, one of a limited number of recent browsers (IE
6 is out), and plenty of fast bandwidth.
Many web applications I've developed have had to run in IE 6 over a
64k connection - frameworks like SproutCore are dead in the water.
> > It claims to be "small(ish)" yet is bloated. It claims to do more with
> > less code (where have we heard that before?) but doesn't. The clock demo
> > can be written in far less code and be more functional.
>
> Small is a relative term.
Yes, but even in "modern" script library terms, 645KB minified is big.
Where "small" really means large, "small(ish)" means enormous.
[...]
> I've seen the demos for the 280 north cappucino (same guys). While the
> code is atrocious, they speak and present well.
I contacted them about their demos (which were similarly dismal) ages
ago. They didn't seem to think it was an issue. There seems to be
something of a disconnect between the public and web personas, perhaps
that is what raises my hackles.
--
Rob
Just pointing out this error. Sproutcore and Cappuccino have nothing
to do with each other. Not sure where this "same guys" idea came from.
Also not sure if the rest of these comments are supposed to be about
Cappuccino or about Sproutcore.
OK.
> Not sure where this "same guys" idea came from.
> Also not sure if the rest of these comments are supposed to be about
> Cappuccino or about Sproutcore.
SproutCore. The only comments specifically about Cappuccino are in
that last paragraph.
--
Rob
About the demos? I can't recall any conversation we might have had,
but I'll agree with you. We haven't been keeping them up to date with
the framework, and we haven't made the time to create more. They are
all on Github, and we've started to collect other projects there as
well, which is a step in the right direction. We're planning a new
community site which will also make it easier to find things.
I see.
I believed that both were using Objective-J. Both use some sort of
compiling technology, but Objective-J is used by Cappucino, while
Sproutcore has a different compiling technology. Correct?
> Also not sure if the rest of these comments are supposed to be about
> Cappuccino or about Sproutcore.
The code being discussed here, in this thread, was Cappucino.
This NG has had code posted from Cappucino before. It has all the same
silly global variables YES, NO, etc.
Thanks for setting the record straight.
>> Also not sure if the rest of these comments are supposed to be about
>> Cappuccino or about Sproutcore.
> The code being discussed here, in this thread, was Cappucino.
>
No, Sproutcore was being discussed.
I can't believe I wrote that. And posted it.
The entire thread has been about the subject "SproutCore--over 20000
lines of new code!" and the code samples taken from Sproutcore.
Sorry for the mixup.
That's because you don't think before you talk.
--
Jorge.
Lets see. Mr Smith had an error he made pointed out to him and he
acknowledged it. There have been numerous errors and shortcomings in
SproutCore pointed out, but for you the "bad" is still Mr Smith?
Andrew Poulos
I'm glad to see that finally, you're beginning to "get it" -albeit
superficially-, "it" being what the library you're criticizing is
about. Because ISTM that a basic -at the very least- understanding of
whatever you're talking about is always a good thing to have before
criticizing. For example, had you known beforehand that sproutcore was
about emulating OSX's Cocoa MVC model and basic framework's
functionality (and no, nothing to do with .NET), you might have
guessed better -given the caliber of the project- that to achieve that
it takes -necessarily- more than a few of lines of JS. Then maybe, as
a second thought, you could have said e.g. that -in your opinion- the
web is not ready for such things yet (I would not agree), instead of
blindly ditching something that you don't even know what is. IOW, you
and the Smith ought to think before you talk.
--
Jorge.
Mr. Smith does much more than "an error".
--
Jorge.
s/much/many/
--
Jorge.
So you think the fact that the title of the thread is drawn from the
SproutCore web site, that specific examples have been drawn from the
site and published demos and that it requires downloading and
installing the framework to inspect the code means we're just making
it all up?
And that someone could do all that and still have no idea what it's
all about?
> Because ISTM that a basic -at the very least- understanding of
> whatever you're talking about is always a good thing to have before
> criticizing. For example, had you known beforehand that sproutcore was
> about emulating OSX's Cocoa MVC model and basic framework's
> functionality (and no, nothing to do with .NET),
Apparently you haven't understood a single word I've said, and clearly
have no idea that just because SproutCore might be trying to "emulate"
Cocoa, it doesn't make it above criticism of its technical merit.
> you might have
> guessed better -given the caliber of the project- that to achieve that
> it takes -necessarily- more than a few of lines of JS. Then maybe, as
> a second thought, you could have said e.g. that -in your opinion- the
> web is not ready for such things yet (I would not agree), instead of
> blindly ditching something that you don't even know what is. IOW, you
> and the Smith ought to think before you talk.
You have been asked several times to show how the criticisms mentioned
here are invalid, yet you haven't posted a single, logical point in
rebuttal. If you think an MVC architecture necessarily requires large
amounts of client-side processing, or the need for large dumps of data
to the client, you haven't explained why you think so despite having
several opportunities.
This discussion is pointless.
--
Rob
Never mind Rob, have a nice day.
--
Jorge.
The similarities between Sproutcore include influence from Cocoa,
compiling javascript, and variables such as:
var YES = true,
No = false,
etc.
Although Sproutcore and Cappucino have some similarities, they are not
written by the same people.
Late night messages tend to have more typos and bungled edits. For some,
late messages can be more emotional. Me, I tend to be more of a hothead
in the AM, which is why I like to put myself in an environment where
that is suitable (lift heavy weight).
The message in respons to Ross' correction was sent out late, and was
immediately followed by a correction.
The YES, NO issue isn't worth much discussion. It is there to make
people coming from a Cocoa background more comfortable. I can't speak
for the Sproutcore team, but Objective-J is a programming language,
and one of the design goals of that language is compatibility with
Objective-C, so there's no reason not to have similar constants. The
arguments against it are stylistic and subjective, but most
importantly it's a completely inconsequential part of both frameworks.
I think the YES and NO variables are useless. Useless code should be
removed.
It is there to make
> people coming from a Cocoa background more comfortable.
Are Cocoa developers finding `true` to be too difficult to understand?
I can't speak
> for the Sproutcore team, but Objective-J is a programming language,
> and one of the design goals of that language is compatibility with
> Objective-C, so there's no reason not to have similar constants. The
I disagree. There are reasons to not have similar constants.
They are a waste of space and reduce efficiency. They take more time to
resolve than a primitive value.
Cocoa developers who are new to javascript will likely have false
expectations, preconceptions, and misconceptions about javascript. The
best way to get rid of those misconceptions is to learn the language.
Providing a layer that makes the javascript look like Cocoa might seem
appealing to Cocoa developers, but it really isn't helping them learn
javascript.
Then again, anyone having trouble understanding `true` and `false` is
probably not worth catering too.
> arguments against it are stylistic and subjective, but most
> importantly it's a completely inconsequential part of both frameworks.
It is not completely inconsequential. You have added global YES and NO
variables. Every time one of those identifiers is used, it must be
resolved all the way up the scope chain. The value is then obtained and
used in the context where the identifier appears.
In contrast, a boolean primitive `true` will not need to be resolved up
the scope chain. A boolean primitive value will be interpreted immediately.
The result is going to be slower performance for the identifier.
Some implementations may perform tracing and/or upvar optimizations, but
that is not something that is standard or should be expected; you
shouldn't expect anything more than what the specification defines.
Literal `true` should not be confusing for anyone; not even for
non-programmers. `YES` and `NO` are useless.
Okay. But isn't this beating a dead horse. Nobody sane would build
widgets (or anything else) on top of an old jQuery version. Browsers
browser documents, documents contain elements, elements contain
attributes. Which of these basic building blocks did Sproutcore get
right? (rhetorical, of course).
Who "advocates" turning off JS in the browser (and to whom?) Or do
you mean that you want to forget that JS can be turned off so you
don't have to consider the most basic degradation path? Too bad,
Jorge. Welcome to the "Real World".
> feel
> themselves as an authority so as to judge somebody else's work whose
> main goal/underlying idea don't even understand (e.g., you don't know
> a word of cocoa), just by looking at a few lines in their JS source.
Cocoa? What does that have to do with any of this? Do you understand
the concept of layers at all? They apply to virtually any kind of
construction. If the foundation is faulty, what will happen to the
building?
In case you didn't know, you are mad. It doesn't matter what beverage
you name it after, the scripts are just browser sniffing compendiums.
In other words, it's the sum total of observations made by incompetent
developers over a period of years (see also, YUI, Closure, jQuery,
etc.) All of the comments are about the state of browsers at the time
the scripts were written. They rarely demosntrate any real
understanding of the issues. Why do you think they need a million
monkeys to "keep up" with three or four browsers?
That's the funniest thing I've heard all day. :) Large, slow and
shallow would be my summary (and who knows it better?)
>
> Ext:
> Ext Core is a cross-browser JavaScript library for building dynamic web
> pages. It includes:
> * High performance, lightweight
Yeah, bullshit. That one needs a review. I've already looked at the
code and it is another repository for idiotic assumptions based on
cross-eyed observations by incompetent nincompoops.
>
> This is called marketing lingo.
It's called complete bullshit where I come from. The cinsoft.net site
is going to address such deception directly. It's sickening that
businesses are being fed this crap by the barrel.
>
> > SproutCore also embeds most of the styling in the code, so the supposed
> > abstraction of script and content is completely broken. Have a look at
> > statements like:
>
> [snip]
>
> That code is a mess. Did anybody at Apple review any of this code before
> paying for sponsorship? Or were the reviewees unable to make assessments?
Clearly they didn't have a clue. Same for IBM with Dojo and Yahoo
with YUI. The decision-makers are being duped. The developers just
keeping fucking up year after year, no matter how much the major
browsers converge, reinforcing the myth that browser scripting is
impossible (it is for these bums).
I find it amusing that these same bums are now shrieking about
dropping "support" for IE6/7, which they failed to ever figure out.
How do you drop something you don't have (but desperately need)? I'm
referring to understanding, of course (specifically MSHTML).
The Web developers are revolting? Yes, they certainly are.
>
> I've seen the demos for the 280 north cappucino (same guys).
Yes. As I pointed out some time back, it sucks.
> While the
> code is atrocious, they speak and present well.
I just can't watch twits talk about their latest abominable Website,
library or whatever. Life is too short.
Doesn't really matter. Have you realized that your developers are
clueless and living in the past? Do you understand that you've got a
cracked foundation? If so, you are welcome for that. Now what are
you going to do about it?
FYI, this is a cross-browser foundation:-
http://www.cinsoft.net/mylib.html
The code has no concept of user agents, yet the fairly torturous test
page works (or degrades gracefully) in:-
IE5-8 (all modes)
Opera 5-10
All FF
NN 6-9
Safari 2-4, Chrome, etc., etc.
...and gets faster the further back you go, which bodes well for slow
mobile devices with limited DOM's, don't you think? What do you think
will happen with your endless browser sniffs? Who is going to go back
and rewrite all of that to match today's browsers? How do you plan to
keep it up in the future? I don't see it.
So why are you building on a discarded jQuery script? Masochism? Or
I suppose sadism is more appropriate considering how many people you
touch with your shit. Giving you the benefit of the doubt, what sort
of destructive buffoon would perpetrate such a thing on iPhone users?
You are either evil or stupid. There's really no in-between here.
Don't bother.
This from you "Jorge?" When have you ever made sense?
Both "frameworks" are completely inconsequential. They are just
disjointed collections of bad code. It doesn't matter how many pretty
graphics (or syntacic sugar) you slather on top of their cracked
foundations. They aren't going anywhere but in history's bit bucket.
> Clearly they didn't have a clue. Same for IBM with Dojo and Yahoo
> with YUI.
Yahoo didn't sponsor an external effort. YUI has priority for Yahoo
needs. Don't expect your bugs to get fixed.
I have personally filed bugs on YUI that have gone over 1 year unfixed.
I had a bug regarding fixing e.pageX for UserAction get marked INVALID.
Fixes from YUI come faster if you just patch it. YUI can be forked and
patched, but in order to get those patches accepted back into YUI, you
must first go through a signup process to become a registered external
contributor. Smells like lawyers.
> The Web developers are revolting? Yes, they certainly are.
>
>> I've seen the demos for the 280 north cappucino (same guys).
>
> Yes. As I pointed out some time back, it sucks.
>
That's actually different guys, though. Similar looking code, with the
`YES` and `NO` variables, but different guys.
[...]
Lets be clear about this first: Ross is working on Cappucino:
http://github.com/boucher/cappuccino
I don't see any jQuery there.
It looks a bit like Sproutcore, but nope! It's Cappucino, not Sproutcore.
Here is his Github master:-
http://github.com/boucher/cappuccino/blob/master/Objective-J/constants.js
var MAYBE = 0.5;
;-D Kidding.
My code comments about making js look like Cocoa apply even more
strongly to Cappucino.
I don't expect anything from them. I don't care. ;)
>
> I have personally filed bugs on YUI that have gone over 1 year unfixed.
Same for Dojo. And then you see the same stupid bugs biting people over
and over in the tracker. It's madness.
> I had a bug regarding fixing e.pageX for UserAction get marked INVALID.
That's because the code monkeys probably didn't understand what you were
saying. I've seen that more than a few times. :)
>
> Fixes from YUI come faster if you just patch it. YUI can be forked and
> patched, but in order to get those patches accepted back into YUI, you
> must first go through a signup process to become a registered external
> contributor. Smells like lawyers.
Dojo has some similar "CLA" thing. It's all much ado about nothing if
you ask me. Why is anyone bothering with these things?
>
>> The Web developers are revolting? Yes, they certainly are.
>>
>>> I've seen the demos for the 280 north cappucino (same guys).
>>
>> Yes. As I pointed out some time back, it sucks.
>>
>
> That's actually different guys, though. Similar looking code, with the
> `YES` and `NO` variables, but different guys.
My question is, what is wrong with these guys (all of them?)
Oh that's right. He was the keyboard guy. I thought he was the
"creator" of Sproutcore guy that popped up in this thread a week ago.
My mistake.
>
> I don't see any jQuery there.
Duh.
>
> It looks a bit like Sproutcore, but nope! It's Cappucino, not Sproutcore.
Somebody had mentioned that one relied on the other at some point.
Regardless, I've seen both and both are appalling.
>
> Here is his Github master:-
> http://github.com/boucher/cappuccino/blob/master/Objective-J/constants.js
>
> var MAYBE = 0.5;
>
> ;-D Kidding.
>
> My code comments about making js look like Cocoa apply even more
> strongly to Cappucino.
Yes, they are misguided neophytes, just like the Prototype guys were in
2005. They don't understand the language, so they try to make it look
like a language they do understand. It couldn't be a more foolish
strategy for browser scripting as scripts need to be as simple,
lightweight and efficient as possible. How ignorant can these people
be? It's 2010 and they are stocking up on canned misconceptions
(browser sniffs) from years ago. How will that add up to relevance
today (or even then?)
What a cop-out. How many "guys" are there? Not one can write a
competent demo? And why should you need to "keep them up to date?" It
sounds as if your framework is in a perpetual state of flux.
And when was it that the demos were impressive? What year and browser(s)?
I'll give you that. Neither is the rest of it (as I noted my review a
year or so back). ;)
[...]
> ...it's a completely inconsequential part of both frameworks.
Well, then lets change the subject to consequences. Post a link to your
DOM or event code. We'll get to the bottom of this thing. :)