Ajax Bestiary: A Javascript Field Guide
 
Ajax Bestiary: A Javascript Field Guide
 
 

Entries Tagged as 'Article'

Converting Between Wiki Markup & HTML with Prototype: Part 2 ListsAt

Posted by Don Albrecht

At the end of part 1 of the series, the system could easily handle direct replacement of certain html entities with their wiki markup counterparts.  Unfortunately this was a pretty limited implementation that could only handle those entities that had a direct, symmetrical relationship with html.  In the case of lists, we have to keep track of depth and better cleanup the input text.  We also need to enforce default behavior on the input stream.

Since lists are dependent on dedicated whitespace as part of their markup, we need to clear out all unnecessary white space from the html before processing it.  To do this, we simply replace all whitespace characters with an innocuous single space to remove any extra new lines.

$(textNode).innerHTML = $(textNode).innerHTML.gsub( '\s', '' );

Next we need to cleanup the recursion.  Since we need to know significantly more about the given node to properly assess it.  We can replace the Prototype templates with simple curried function calls and migrate the recursion to the curried methods.

var ConverterTable = {
strong: Converter.curry("'''", null, true),
b:  Converter.curry("'''" , null, true),
em: Converter.curry( "''"  , null, true ),
i:  Converter.curry( "''"  , null, true ),
h1: Converter.curry( '='  , null, false ),
h2: Converter.curry( '=='  , null, false ),
h3: Converter.curry( '==='  , null, false ),
h4: Converter.curry( '===='  , null, false ),
h5: Converter.curry( '====='  , null, false ),
h6: Converter.curry( '======' , null, false ),
ul: Converter.curry('', {li:Converter.curry(['* ', ''], null, false)}, false),
ol: Converter.curry(”, {li:Converter.curry(['# ', ''], null, false)}, false),
p:  Converter.curry(['','\n'], null, false)
};

The parameters passed into the individual rules are
The Markup String or an array of strings for start and end tags
An optional library of child rules.  These rules will be applied to any children of the given node before the default rules are applied.
An indication as to the ‘inline-ability’ of the given tag.  This controls the bracketing of the resulting markup with ‘\n’ characters.

The modified Converter now looks to apply rules in the following order
If the node is marked as a stopping point, no recursion proceeds on the branch.
If any over-ridden child rules exist for the given tag, those rules are applied and a memo is passed on to child nodes to denote the depth of the recursion.
Any default rules are processed as per the earlier versions of the code.  Note.  A prototype template is no longer used in favor of simple string construction.
The node itself is removed from the DOM.

function Converter( markupString, nestedRules, inline, textNode, memo ){

var startString, endString;
inline = inline ? ” : ‘\n’;
memo = memo ? memo : ”;
var children =  textNode.childElements();

if( typeof markupString == ‘object’){
startString = inline + markupString[0];
endString = markupString[1] + inline;
} else {
startString = inline + markupString;
endString = markupString + inline;
}

for( i in children){
if( typeof children[i] != ‘function’){
if( nestedRules && typeof nestedRules[children[i].tagName.toLowerCase()] == ‘function’){
startString =  memo.strip() + startString;
nestedRules[ children[i].tagName.toLowerCase() ]( children[i], startString);
} else if( typeof ConverterTable[children[i].tagName.toLowerCase()] == ‘function’){
ConverterTable[children[i].tagName.toLowerCase() ](children[i]);
} else { Converter( ”, nestedRules, true, children[i]), memo }
}
}
textNode.replace(  startString + textNode.innerHTML + endString  );
}

Converting Between Wiki Markup & HTML with Prototype

Posted by Don Albrecht

Wiki’s are amazing and powerful tools, unfortunately their dependence on specialized markup creates a huge barrier to their general adoption in many organizations.  This is a first step at building a wysiwyg editor for wiki markup.  While I will be focussing on the syntax unique to the popular MediaWiki platform, these techniques should be applicable to any wiki system.

The general flow of the converter is as follows:

  1. Converter is passed the root node of an html fragment to translate.
  2. Converter recurses through each of the child nodes and converts them.
  3. Root node tag is replaced with wiki markup.

There’s really only 2 key components involved in this first pass. A converter object and the recursive method.

The Converter Object

The converter object is little more than a collection of name value pairs.  The name corresponds to an html tag.  The value is a Prototype template to use in the direct replacement of the given node. By convention we’ll write all of the tag names for the converter object in lower case.

var Converter = {
strong: new Template("'''#{body}'''"),
b:  new Template("'''#{body}'''"),
em: new Template("''#{body}''"),
i:  new Template("''#{body}''"),
h1: new Template('=#{body}='),
h2: new Template('===#{body}=='),

h3: new Template(’===#{body}===’),
h4: new Template(’====#{body}====’),
h5: new Template(’=====#{body}=====’),
h6: new Template(’======#{body}======’)  }

The Converter Function

The Converter function always performs 2 checks before attempting to convert a given node.  First it ensures that the node is in fact a node and not a stray function from the Prototype enhanced object.  Next it verifies that a converter exists for the tag.  The toLowerCase() on the tagName is necessary due to the inconsistent behavior browsers demonstrate with this attribute.  While all browsers return the variable in all caps for traditional html, they are not reliable about returning lower case values for xhtml markup.

function convertToWiki( textNode ){
//make sure textNode isn't a function on the object
if( typeof textNode != 'function'){

//provide a way to stop execution on select sub trees
if( !textNode.hasClassName( 'stop')){
$(textNode).childElements().each( convertToWiki );
}

//make sure a converter exists for the given tag
if( liteConverter[ textNode.tagName.toLowerCase() ] ){

//replace the text node with a converted version of itself
textNode.replace( liteConverter[textNode.tagName.toLowerCase()]
.evaluate({body:textNode.innerHTML}));
} } }

Ajax24’s Drop Tabs. A Creative Take on The Tab Box for Scriptaculous

Posted by Don Albrecht

Tab Boxes are one of the most ubiquitous and popular of widgets. They pop up in everything from news sites to accounting software and for good reason. After all, tabs are one of the simplest and most efficient ways to cram more into a given block of screen real-estate than would fit otherwise.

Ajax24’s drop tabs replace the normal tab-box behavior concept with a twist. THese tabs pull blocks of content down from a tab bar to make them available and float them above the background content. (think window blinds or drawers as opposed to tabbed sheets of paper). I have a few reservations about the use of a widget with such slightly unconventional behavior. But all in all, the smooth motions of the widget and it’s novelty surely warrant exploration in more playful interfaces.

You can find the widget at

http://www.flash-free.org/en/2008/04/05/e24tabmenu-–-menu-desplegable-ajax/

DamnIT Remote Javscript Error Reporting

Posted by Don Albrecht

Firebug and its kin are awesome for debugging javascript, but once our scripts are in the wild we really don’t have any feedback of any kind about the state of the browser.  DamnIT from JupiterIT attempts to alleviate this by providing an automated feedback system for javascript applications.

How it works:

  1. A box appears prompting you to describe your most recent actions:
  2. One of the following occurs:
    • you type something and click send
    • you click “close”
    • 10 seconds pass with you doing nothing
  3. DamnIT emails you the following information:
    • Browser
    • Page
    • HTML Content
    • Description (if you entered one)
    • Error message
    • File name, line number, and stack (if the browser supports them)

On the surface this is an incredible system.  In practice there are a few key issues that I think need addressed before the product is an ideal fit for every situation.  Basically, I have severe reservations about the email only nature of the system and its dependence on central management.  Both of these are key issues when dealing with sensitive information or large volumes of error messages and I’m sure will be addressed with future versions.  I am going to integrate the system into the next release of BLT and will be providing feedback from those efforts in the near future.  In the short term, you can check out DamnIT here:

https://damnit.jupiterit.com 

Implicit Vs. Explicit Conversion in Javascript

Posted by Don Albrecht

A question emerged out of my boredom on my flight yesterday.  Which is faster, implicit vs explicit conversion.  Most javascript developers use implicit conversion out of habit. For example:

!!x; instead of Boolean( x ); and x + “”; instead of String( x);. 

I decided to try an experiment for myself and record the performance of casting a number to a Boolean or String on my Windows box in Safari 3, Firefox 2, Opera 9 and IE 7.

The Verdict:

Implicit conversion wins handily, demonstrating over a 7 fold performance increase in one test. Overall, the performance gain for using implicit conversion averaged out to 53% across browsers after 10 tests.

The Numbers:

  Implicit Boolean Explicit Boolean Implicit String Explicit String
Firefox 2 0.162 0.312 0.248 0.358
IE 7 0.042 0.100 0.074 0.152
Opera 9 0.030 0.088 0.020 0.142
Safari 3 0.028 0.036 0.074 0.100
Cross Browser Average 0.066 0.134 0.104 0.188

You can find the code I used after the jump.

Keep reading →

Javascript Best Practices: parseInt( x, 10 );

Posted by Don Albrecht

ParseInt is one of the handiest universal functions in javascript. Even though javascript’s ability to cast most any primitive to any other primitive on the fly is handy to say the least, sometimes we need to explicitly parse a string to make sure we have a legitimate number to work with.

ParseInt does this for us. What most developers don’t realize is that parseInt is base agnostic. While it typically assumes base ten, any base between 2 and 36 can be used and is indicated by the optional second argument.

Why is this a problem you might ask? Because octal numbers can be represented by a leading zero. In practice this can cause some interesting effects in your code.

For example:

var x = "010";

console.log( x );

console.log( x - 0 );

console.log( parseInt( x ) );

console.log( parseInt( x , 10 ) );

Returns:


"010"

10

8

10

Note: “010″ is equivalent to 10 in  “x - 0″!

Taking The Web To The Desktop Part 3 Widgets

Posted by Don Albrecht

If you haven’t realized it yet, widgets are here to stay and definitely represent what is currently the most ubiquitous way in which the web has been brought to the desktop. Google Desktop’s Gadgets, Windows Sidebar, OSX’s Dashboard, Opera and the venerable Yahoo Widgets (previously konfabulator) all bring tiny, self contained web pages into the users desktop space. For most people, this is the first thing that comes to mind when you mention taking the web to the desktop.

Widgets, however, are a very small piece of the puzzle. While they overcome some of the limitations of the web by placing your site front and center inside the users normal computing environment and provide some level of escape from the omnipresent security sandbox, widgets just don’t provide much that transcends the traditional web environment.

Widgets do have a role to play in the emerging web ecosystem. They are a lightweight means of integration between sites and they do provide useful tools for the user. Unfortunately, while they do provide a level of convenience, they can also provide a pretty severe level of annoyance to users. Luckily, they are very easy for users to uninstall and users vote with their mice removing any widgets they deem too annoying.

So where do widgets fit in the hybrid web ecosystem? I’m not really sure. They are definitely a motivating force behind the creation of several robust api’s for enabling the integration of disparate platforms and sites. They can also do a great job of providing alternative light weight interfaces for traditional web sites by putting underused tools closer to the daily user experience.

In my mind, I can’t really rule them out for many of my projects. They’re kind of like the gravy at a holiday meal. Even if the turkey is as moist as a swamp in June, you still make it because someone may want it and it isn’t that much more work once you’ve gone to the trouble of cooking the bird.

I’m curious, how are you using Widgets in your projects?

Under The Hood With HTTP: Part 3 Methods

Posted by Don Albrecht

Requests and responses make HTTP work; they are the yin and yang of Client / Server communications.  Last time, I covered some of the most common response codes and what they mean.  Today, I will be covering the different ways in which these communications can be called from the client.GET and POSTGET and POST are the 2 most common request methods.  GET is intended for the retrieval of information while POST is intended for the submission of information as a subordinate of the requested resource.When To Use GETGET should only be used when security is not an issue and all information can be included as part of the URL string.  GET has added the benefit in that it can be used with Cacheable data to reduce network usage.  Most server side environments allow you to include and process information included in the URI of the GET request.  This is generally a bad idea as all information included in the URI is transmitted in a form potentially visible to third parties.  Where security is not an issue that can be a more efficient way of getting information to a server.When To Use POST POST is ideally suited to transmitting dynamic information to the server.  Post supports the following benefits over GET for this purpose.

  • Information is not included in public facing URI request.
  • Larger quantities of data can be transmitted
  • Request data is not cached

Other MethodsThere are several other methods supported by HTTP 1.1 that you may find useful at some point.  Not all of these are readily accessed from within the Browser environment, however.

  • HEAD: Identical to GET except only the header and no body is returned
  • PUT: Requests that the attached body be stored under the requested URI.  If the resource already exists, it should be overwritten by the new version.
  • DELETE: Requests that the resource at the requested URI be deleted.
  • TRACE: A Debugging method, it requests that the request (as received by the server) be transmitted back to the client in the entity body.
  • CONNECT: A reserved name for future support for dynamically switching to tunnel proxies.

Taking the Web to the Desktop, Part 2: Mobile Sites

Posted by Don Albrecht

I know what you’re thinking, mobile aps run on cellphones and smartphones, not PC’s. Mobile sites are one of the most important and pervasive aspects of this hybrid web ecosystem. Unlike desktops and laptops, mobile sites can assume that the cellular device they are displayed on will have a persistent and portable net connection. Because of this benefit, mobile sites can be viewed as intermediaries to be used with a user may not have access to a traditional internet connection.

Unfortunately, mobile platforms are and always will be limited devices. There simply is no way to put all of the screen real estate of even the smallest monitor into a device that will fit into someones pocket without resorting to origami voodoo. Higher screen resolutions help the situation, but there are limits to the human visual system and 6pt font is almost as eligible on paper as it is on any digital screen.

Other restrictions abound surrounding the mobile platform. From a user interface perspective it’s still a bit of the wild west and mobile browsers have tended to be flaky, inconsistent and underpowered. Safari, Opera and Minimo make significant strides towards eliminating these issues and providing a much richer platform on which to develop. Many cellphones also provide API’s to enable mobile aps to look consistent with, act like and interface with the underlying device.

The inconsistencies across platforms still make mobile devices a difficult nut to crack in terms of development. As browsers, bandwidth and processing power improves, expect developing for them to increasingly less frustrating and in higher demand from users.

Under The Hood With HTTP: Part 2 Status Codes

Posted by Don Albrecht

You’re probably already quite familiar with the 404 Status Code for resources that aren’t found.  Knowing the status codes can give you some pretty powerful insight into the server side of your app when things go wrong.All Errors fit into the following categories

  •  1XX Informational Codes
  • 2XX Success Codes
  • 3XX Redirection
  • 4XX Client Error
  • 5XX Server Error

The Codes in More Depth Informational Codes 1XX Informational Codes are unique in that they return no body and terminate immediately after the headers.  The most common encountered is “100 Continue”.   Continue responses are roughly equivalent to the server saying I haven’t forgotten about you.  They imply that everything is fine but that the server isn’t prepared to issue a response yet.  If the client is still transmitting data, the client should continue to do so.  If the client is done transmitting, it can ignore the response.  The server is required to send a normal response in the future.   Success Codes 2XX The most common code in this category is 200 OK.  This is what you expect to receive in any http transaction.  Some other common codes are:

  • 202 Accepted: The Server has accepted the request but hasn’t finished processing.  It should contain a pointer to more information but isn’t required to do so. 
  • 204 No Content: The Server has completed the request but there is no need to return a body entity.  There may be new meta-data to transmit.  Clients should not change their document view when this code is received.
  • 206 Partial Content: On Get Requests, this means that the originating GET request included a Range header field and only that range is returned.

3XX Redirection CodesRedirection codes communicate that the previous request was insufficient to complete the request and further action needs to be taken by the client to do so.

  • 301 Moved Permanently: The resource has been permanently relocated to a different URI.  Any future references should use this new URI.  The Response Body should contain a short note in HTML with a link to the new location.
  • 307 Temporary Redirect: The resource is temporarily relocated at a new URI.  Future references should continue to use the original URI.

4XX Client Error  While we’re all familiar with the infamous 404 not found error.  There are several other client errors that can be encountered on a regular basis.

  • 400 Bad Request: The HTTP Request is malformed.  The Client should not repeat the request without modifications
  • 401 Unauthorized: Authentication is needed to access the resource
  • 403 Forbidden: The Server understood the request but for some reason is refusing to fill it.
  • 408 Request Timeout: The Client didn’t complete request in the time the server was willing to give it.  The client may try again some other time

Error Code 402 is a unique case.  It is reserved for future use and indicated Payment Required

500 Server ErrorsWhile 400 errors imply that the Client was the source of the fault, 500 errors imply a problem with the server.  There are 2 that I find a need to wrangle with regularly

  •  500 Internal Server Error: Something went wrong and the server is crying uncle
  • 503 Service Unavailable: The Server is experiencing technical difficulties.  I usually this is caused by a runaway memory leak in apache or by a sudden spike in load that overwhelms the stack.

While I in no way intend for this to be a comprehensive guide to the http response codes, there’s a much better one available from the W3C.  I thought this might provide a handy refresh and reference.