Web Info & Tutorials

August 16th, 2007

TALES OF THE RICH TEXT EDITOR AND SAFARI SUPPORT

I love to hear the stories behind the technology. This way you have a chance of learning from a fellow developers trials and tribulations.

Dav Glass of the YUI team was in charge of building the new Rich Text Editor that was just released, and has documented part of the journey which includes how he managed to get this puppy working on Safari 2:

My development approach was to bend Safari first. I built it to work in Safari 2 before retrofitting it back to Opera, then Firefox and lastly Internet Explorer. I figured that if I could make Safari do what I wanted, the other three would fall into place nicely. And they did. By choosing to make Safari work first I was able to make the others do things in a standard way as well. I hope that Safari will eventually catch up to its A-grade peers and add support for the things that I have “emulated”, so I took that into consideration too.

How did he hack around Safari 2?

Safari 2 is a really good browser, but it was also the most challenging browser to support with the RTE project. It lacks some serious and critical features when it comes to editing HTML content from JavaScript. I will try to explain the main hurdles that Safari presents:

Iframe Focus - One of the biggest issues was actually quite simple to solve. Safari (and Internet Explorer) has an issue with selecting text inside of an embedded iframe. If you select text within the editor’s iframe then click/focus the parent document, the selection within the iframe is lost. Clearly, this makes it rather difficult for a button click to take action on the selection (because the selection is lost when you click the button!). It also makes it difficult to use, say, a YUI Menu Control for a drop down. As I investigated this problem, I determined that if you stop the mousedown event on the button/href the selection doesn’t get lost. However, if something else (say a href in a dropdown menu) gets focus, the selection will still get lost. This leads me to the next Safari trick.

Selection Object - The selection object in Safari is very limited (to say the least). To work around its limitations, the YUI RTE caches a copy of the current selection in the _getSelection method. Then, the next time _getSelection is called I check to see if a cache existed. If the cache is there, I “rebuild” the selection and destroy the cached copy. This little trick is what lets Safari use a YUI Overlay as a menu instead of the more classic approach of a select element. It’s roundabout, but it works.

execCommand limitations - This is the mother of all hacks for Safari (and the others). My biggest problem with the native execCommand method (in all browsers) is that the browser doesn’t tell you what it applied the command to. So there is no real way to get an element reference back after running a command on a selection. The world of JavaScript editors would be so much more civilized if this would happen (hint, hint, nudge, nudge). So what I had to do was implement this feature myself. My current approach may not be the best way to do it (I have some other ideas that I am working through), but it does the job for now. The method is named _createCurrentElement and basically it runs execCommand('fontname', false, 'yui-tmp'); on the given selection (since fontname is supported on all A-Grade browsers). It will then search the document for an element with the font-family/name set to yui-tmp and replace that with a span that has other information in it (attributes about the element that we wanted to create), then it will add the new span to the this.currentElement array, so we now have element references to the elements that were just modified. At this point we can use standard DOM manipulation to change them as we see fit. In short, I’m using the iframe’s DOM to store metadata during editing as a way to enrich the communication that’s possible between the editor and the iframe.

Thanks for sharing the story.

August 16th, 2007

PURPLE INCLUDE 1.9

In July, Brad Neuberg and a group of talented hackers released Purple Include, a library that does transclusions.

Now there is a new version which is a major refactoring that simplifies working with the library and now works across all major browsers.

Brad tells us more:

Purple Include is a client-side JavaScript library that allows you to do client-side transclusions.

What the heck does that mean?

It means that you can include and display fragments of one HTML page in another without copying and pasting any content. For example, you could quote the second paragraph from another person's blog entry by embedding something like:

HTML:
  1.  
  2. <div href="http://foo.com/bar.html#xpath(/p[2])"></div>
  3.  

in your blog page. The expression following the explanation point in the URL is an XPath expression.

If the page you want to transclude has a fragment identifier or a purple number, you can transclude that directly:

HTML:
  1.  
  2. <div href="http://foo.com/purple.html#nid32 "></div>
  3.  

In fact, all you have to do is add an 'href' attribute to any of the following types of HTML tags in order to have that URL transcluded right into the page when the page loads:

HTML:
  1.  
  2. <p href="http://foobar.com#nid32"></p>
  3.  
  4. </blockquote><blockquote href=" http://foobar.com#xpath(/p[2])"></blockquote>
  5.  
  6. <div href="includeme.html#foobar"></div>
  7.  
  8. <span href="../../relativefile.html#foobar"></span>
  9.  
  10. <q href="http://foobar.com#foobar"></q>
  11.  

Here's the great thing about this new release -- there's nothing to install! We do some magic (see the Release Notes below to see how) to make it so that you have absolutely no server to install. I host everything on my webserver now, at codinginparadise.org, even the inclusion service and JavaScript, so all you have to do is add the following JavaScript to the top of your page:

<script src="http://codinginparadise.org/projects/purple-include/purple-include.js"></script>

Plus, Purple Include now works across Safari, Internet Explorer, and Firefox (Opera probably too -- I just haven't tested). The client-side JavaScript is now just about 9K.

See the example page for examples and usage. Also see the README file. You can view the JavaScript file as well if you want.

This is all beta stuff, so as usual, if you see bugs, tell me -- or even better, fix it ;)

RELEASE NOTES for August 15th, 2007 Purple Include 1.9

This is a pretty radical refactoring of the Purple Include code. The big highlights in this version:

* Now works cross-browser: Internet Explorer, Firefox, and Safari (Opera should work but has not been tested)

* There are no server-side requirements anymore. Instead, the inclusion service is hosted on my web site at codinginparadise.org and we do a trick in the JavaScript (the JSONP/Script tag trick) in order to do transclusions through a third-party web site. All you have to do is drop the JavaScript into your page and start using it.

* We no longer have an tag; instead, you can simply add an 'href' attribute to many different HTML types and have that type transclude it's contents:

HTML:
  1.  
  2. <p href="http://codinginparadise.org/paperairplane#xpath(//[@id='table_of_contents'] ")</p>
  3.  

This works for the following tags: P, BLOCKQUOTE, Q, PRE, DIV, SPAN

* The client-side script has gotten vastly smaller and simpler -- the script is now only about 9K.

* We now use the notation #xpath(//p) around an XPath expression rather than using an exclamation point, such as #xpath!//p. This is in keeping with the pseudo-standard that has developed around this practice, such as #xpointer() -- it also opens up the possibility of chaining together expressions in the future, such as #xpath(//expression1)xpath(//expression2), which would return the results of both expressions.

* The little roller image, roller.gif, used to be a pain in the butt to configure because it was always relative to the page you are using transclusions on, which therefore required you to specify a relative path or something using a META tag. To cut down on configuration, I now just host this image on my web server -- you can set it to your own path using the META tag 'purple.include.rollerURL' but we default it inside the code to my webserver. This means that all you have to do now to use Purple Include is have the JavaScript file -- that's it.

August 16th, 2007

PROTOTYPE 1.6: THE EVENT OVERHAUL, AND A WHOLE LOT MORE

This is big. Prototype 1.6 is a major upgrade, and the first RC has been released. There is a large number of updates and my pet favourites are:

  • The event system has been cleaned up. It now works the way you would expect, with "this" doing the right thing
  • You can observe and fire custom events on the DOM (a la Dojo)
  • Thanks to the custom events, DOMContentLoaded is normalized across browsers via: document.observe("contentloaded", function() { ... })
  • AOP-lite: Simple interception and function currying
  • Function delay and defer: (function() { $("form").fire("requestSent") }).defer();
  • Ajax.Response: Now you can more easily work with JSON
  • DOM Builder
  • Template API: "#{last}, #{first}".interpolate({ first: "Andrew", last: "Dupont" })
  • Improved support for JavaScript 1.6 and WHATWG 1.0 standards

Be sure to take a detailed look at this puppy.

August 16th, 2007

JQUERY FOR JAVASCRIPT PROGRAMMERS

Simon Willison has followed up his jQuery show with his thoughts on jQuery should be of welfare to old programmers.

He admits to having a assorted analyse of jQuery at first:

Over the time whatever months it’s embellish country to me just how criminal I was. jQuery is an exceptionally adroit example of engineering. It neatly encapsulates an exceptional arrange of ordinary functionality, and provides a adroit plugin API for whatever functionality not included by default. It takes a set abstraction—that of a activity of DOM elements—and extracts as such distance discover of it as possible. Most importantly, it does so in a artefact that obeys prizewinning practices and plays substantially with another JavaScript code.

He then goes into what he likes most jQuery with:

  • Namespacing: Care.
  • The disreputable $ function
  • Selecting whatever elements: At the core
  • Doing clog with them
  • Chaining:
    JAVASCRIPT:

    1.  
    2. $(‘form#login’)
    3.     // conceal every the labels exclusive the modify with the ‘optional’ class
    4.     .find(‘label.optional’).hide().end()
    5.     // add a flushed abut to whatever countersign fields in the form
    6.     .find(‘input:password’).css(‘border’, ‘1px solidified red’).end()
    7.     // add a accede trainer to the form
    8.     .submit(function(){
    9.         return confirm(‘Are you trusty you poverty to submit?’);
    10.  
  • DOM manipulation:
    JAVASCRIPT:

    1.  
    2. var div = jQuery(‘<div>Some text</div>’).addClass(‘inserted’).attr(‘id’, ‘foo’);
    3.  
  • Handling events:
    JAVASCRIPT:

    1.  
    2. jQuery(‘p’).one(‘click’, function() { alert(jQuery(this).html()); });
    3.  
  • Unobtrusive scripting:
    JAVASCRIPT:

    1.  
    2. jQuery(function() {
    3.     alert(‘The DOM is ready!’);
    4. });
    5.  
  • jQuery and Ajax:
    JAVASCRIPT:

    1.  
    2. jQuery.getJSON(‘/some.json’, function(json) {
    3.     alert(‘JSON rocks: ‘ + json.foo + ‘ ‘ + json.bar);
    4. }); // Retrieves and parses /some.json as JSON
    5.  
  • Plugins: Easy to write, thus some of them.