One of the main things we use Prototype for is DOM manipulation. Whenever a view’s state changes, Prototype help’s SproutCore change CSS classes, edit styles and change element nodes.
Now that we are trying to make SproutCore DOM-library independent, we needed a way for SproutCore’s built-in views to continue to work with the DOM without Prototype installed. The solution we came up with was to create a new component in SproutCore called CoreQuery.
CoreQuery is a strict subset of jQuery. In fact, if SproutCore detects jQuery’s presence when it loads, it will use jQuery instead. By itself, however, CoreQuery is designed to be very small and lightweight. It’s only about 200 lines of code without comments or whitespace. It contains only the bare essentials needed by SproutCore view’s to render DOM.
This means that if you are creating a SproutCore application with no custom views, you could opt to use SproutCore without any other DOM library at all. Or, you could load jQuery, YUI, Prototype, or whatever other library you prefer and use them to help you render your own custom View classes. You could even choose to use CoreQuery yourself with your custom views. SproutCore will work the same in all circumstances.
Using CoreQuery
If you want to try CoreQuery yourself, you can find the CoreQuery object in SproutCore 1.0 (aka “Bitburger”) today at SC.$(). This works just like the $() function in jQuery. (Subject to the limitations described below.)
Also, although this is not in the source yet, each SC.View instance will also have a $() that will return a CoreQuery object matching elements inside the view itself. This will often be the fastest way to work with CoreQuery. For example, if you were creating a custom button and needed to update the button state when it changed, you might write:
// invoked whenever the button state changes...
render: function() {
// set title, enabled state, and selected state...
this.$().text(this.get('title'))
.setClass('disabled', !this.get('isEnabled'))
.setClass('sel', this.get('isSelected'));
},
CoreQuery code, like jQuery, tends to be very clean and concise, which is just what you need for a DOM-manipulation library. It is a good companion to the more state-oriented approach of bindings and observers. I’ll have more to say about how you can combine these kinds of API’s in the future, but suffice to say the code is just beautiful and really fun to write.
CoreQuery Limitations…
So what makes CoreQuery different from jQuery? There are a number of big things left out:
- Complex Selectors. CoreQuery understands simple selectors like “tagname.classname”. None of the pseudo-selectors provided by jQuery will work. Also, you can’t do any of the direct-desendant stuff like “parentag > .child-class”. This is usually not a problem since you often use CoreQuery within the context of a single view and you only need to look for elements with a given class name.
- Event Handling. CoreQuery doesn’t know anything about listening for events on DOM elements since this is handled by SproutCore’s built-in event delegation system already. (Which is much more efficient.)
- All jQuery plugins. Anything not part of jQuery-Core is omitted. If you want the full jQuery with plugins, use jQuery.
- Effects. jQuery’s effects (i.e. animation) library is not as useful for SproutCore-style views. Additionally, we are working on something that makes better use of CSS-transitions.
- Ajax. SproutCore has its own Ajax functions; no need to copy jQuery.
- Script execution. When you insert HTML that contains a <script> tag in jQuery, the JavaScript inside of those tags will be eval’d. This does not fit with typical SproutCore usage and its evil anyway, so CoreQuery does not support it.
CoreQuery’s remaining scope is fairly limited to very basic DOM manipulation. The good news is you generally do not need much else when building SproutCore views. If you do need more, you can always import your favorite DOM library to get it. The code overlap will be very minimal.
…And Benefits
In addition to the basic jQuery functions, CoreQuery will also include some additional plugins designed specifically for working with SproutCore-style views. One such plugin already available is $().setClass(), which will add or remove CSS class names depending on a flag parameter that you pass. $().setClass() is more efficient than $().addClass()/$().removeClass() for common View operations.
In addition to some utilities methods like this one, we’re also working on something to make animation easier. To work well on the iPhone, it is important that any animation library SproutCore supports make use of CSS transitions when available. We’re looking into solutions for this, but the end result will likely be implemented as a CoreQuery plugin.
All enhancement like these are implemented as jQuery-compatible plugins and automatically installed into jQuery if you choose to use it.
Why CoreQuery?
So why create another DOM library? Why not just create some kind of emulation layer that can hook to Prototype, jQuery etc?
The simple fact is that the functionality provided by most of these libraries is really not that complex when you get down to it; at least not the parts needed by SproutCore. We found that simply copying the core pieces of a small, properly namespaced library like jQuery ultimately yielded the best performance and had the lowest code overhead than any other option.
Additionally, I liked the simplicity of making SproutCore standalone. We’re making it much easier to mix and match our framework with others. I expect to see a lot more hybrid applications in the future that use SproutCore to manage their business logic and drop in UI widgets from jQuery-UI, Scriptaculous, YUI, Cappuccino or various other toolkits when needed. No extra code is needed to make this work. Just mashup and go.
A Bright Future
Though CoreQuery is a “hidden technology” used inside of SproutCore, I’m very excited about what it represents for us. It’s a good example of how we constantly rethink SproutCore’s insides to make sure we’re always delivering a high quality development experience in the web browser.
UPDATE: What about Sizzle? A few people have asked about Sizzle, the cross-library DOM selector library being written by jeresig. Sizzle is a great idea, but more relevant to lower-level DOM manipulation libraries like Dojo, Prototype or jQuery (the ones who will adopt it). If you import these libraries and they use Sizzle, then you can use Sizzle with SproutCore.
For SproutCore itself, Sizzle has too much of one thing and not enough of the other. It’s DOM selector-API is far richer than what we need, which adds unnecessary weight to SproutCore. On the other hand, it currently lacks any of the other DOM-manipulation tools found in jQuery, which we would have to rewrite from scratch anyway.
As I understand it, Sizzle is expected to gain some of these added features in the future. If that happens, it is possible CoreQuery will one day be based on Sizzle source instead of jQuery. Until then, a reduced form of jQuery seems to give us the features we need for the least amount of code, which was the objective.
Try out CoreQuery in SproutCore 1.0 today. Checkout the Bitburger branch now!
Tags: New Features by charles
3 Comments »