Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

Thursday, May 24, 2012

Namespaces, inheritance and dynamic loading in JavaScript

It is said that every job has its tool. Some of them are yet to be created. Just recently I needed the right tool for some job, namely managing namespaces, inheritance and dynamic loading in JavaScript. I believe the trio is intrinsically linked and as such requires just one tool.

I was quite specific about what that tool should allow me to do. I wanted to:

  • have namespaces that reflect the structure of my code
  • store any values in my namespaces, even primitives
  • load a file simply by requesting a namespace
  • define dependences between different parts of code within the code itself
  • not to worry about including all JavaScript files statically
  • have  inheritance supported by the namespaces
Sadly, I failed to find such a tool.

Luckily, I have created it and it is pretty hot. It does namespaces, dynamic loading and inheritance. The tool is called wn(), after WebNicer. Here's an overview of the most important things I felt I had to get right.

Namespaces

I have read quite a few articles about implementing namespaces in JavaScript and to be fair I haven't found one that would get it right when it comes to nested namespaces. How so? Imagine you have a namespace:

MyApplication.SomeModule

Now, let's say SomeModule represents a constructor function. Then you want to create a child constructor function which inherits after SomeModule. Acting innocently and intuitively you would probably create a child namespace for it like so:

MyApplication.SomeModule.ChildModule

Looks ok but it isn't. ChildModule just became a property of SomeModule constructor function! You didn't want that, right? All you wanted was to create a child namespace and not a property of the function you have assigned to the parent namespace.

That approach is fundamentally wrong.

I had to fix it, so the above example works just fine in wn(). Namespace object is completely separated from the value represented by that namespace. Therefore ChildModule is a child namespace of SomeModule and does not become a property of the constructor function stored in SomeModule. 

Dynamic loading

I think that RequireJS is not a bad piece of software but I don't really like a loader to dictate how I should write or organize my code. I believe that the loader should be helping in the background rather than trying to change my coding preferences.

On the other hand, defining dependences between namespaces rather than files is quite tempting. By doing so you can create code which is more reusable and less prone to environmental issues. It should not mean however, that each dynamically loaded files has to define a namespace. That would be just wrong. What if you wanted to load dynamically jQuery from the Google CDN?

Closely related matter is translating namespaces to URLs. Should the namespaces reflect the directory tree or, for example, represent just the filenames? Maybe. There is no one good answer. I believe that decision should be in discretion of the developer and not necessarily the one implementing the loader.

I wanted wn() to help developers do things, not make them do things. Therefore the mapping is up to you, although the default one is included for you convenience. Dynamically loaded files don't have to define namespaces if you don't want them to. And any file can define multiple namespaces if that is your wish. Some other libraries require just one namespace per file.

Inheritance

The trickiest of them all. Obviously the language has no native mechanism for inheritance, so it needs to be implemented. Therefore there a few different approaches to inheritance in JavaScript. The two most common models are the prototypal and classical inheritance. People fight holy wars trying to argue how one is superior to the other and I strongly believe it to be pointless. They would better spend their time watching paint dry.

Both approaches have advantages and both can be used by the same code only for different things.

For main building blocks of my application I would rather use classical inheritance. I would be able to check if an object is derived from certain constructor function or whether that constructor function is present up the inheritance chain (instanceof). When the code grows, type checking becomes priceless ally of code maintainability.

On the other hand prototypal inheritance is much more useful for ad-hoc objects. One of the best examples in my opinion is default values. Imagine parent constructor's prototype with a property defaults pointing to an object with some default values. Now, in the child constructors's prototype we would like to add one more default value. We don't want to recreate the whole object, though. The easiest and cleanest thing to do - use prototypal inheritance on the defaults object.

As wn() is focused on main building blocks of an application, it supports classical inheritance. Being built around namespaces, wn() allows to express inheritance using namespaces as well. Just an extra sugar.

Again, you can find examples of inheritance on the wn() Wiki.


I hope you will find wn() useful. I made every effort to make it easy to use as well as the examples easy to read and understand. Nothing's perfect but you can help improving the library by simply dropping a line.

Thanks for reading.
Jacek

Wednesday, October 5, 2011

Google Analytics code in external .js file

Google Analytics JavaScript code does not have to be inline. New, asynchronous GA tracker can be as well invoked from external JavaScript file with no - at least noticeable - impact on performance.

I have read on one of the forums that with putting GA code in an external file you lose the benefit of asynchronous architecture which is quite obviously bollocks. One of the main benefits mentioned on Google Analytics help page is that you can start tracking user events even before the tracking code loads and you still have that! The GA JavaScript still loads in the background and the page load time is as with inline Google Analytics code.
The best thing is that there is nothing special you have to do. Just get the JavaScript code generated in your Google Analytics account and instead of pasting it directly onto the page paste it into .js file and refer to that file from your page. More or less as follows.
On your page
<script src="file_containing_google_analytics.js" type="text/javascript"></script>
Inside the file_containig_google_analytics.js:
  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-XXXXXXX-X']);
  _gaq.push(['_trackPageview']);

(function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
Have fun!

Monday, October 4, 2010

jQuery Event Showcase

Have you ever wondered in what order JavaScript events are fired? What are the event object properties? How events differ in different browsers? Good news - wonder no more, check it out yourself.

The jQuery Event Showcase records the events you cause with your actions and allows you to browse through them. Clear visual indication shows you which element fired each event. You can also see all the event object properties, and if a property is an object or a function - you can also see all the details of it and so on. Better still, at your command remains events filter which helps you focus on the event types you want to investigate.

A few screenshots:

List of events in the Events Log
Event details in the Events Log
Events Filter

Any feedback welcome.

Jacek

Friday, September 10, 2010

JavaScript: best code highlighter I have seen

I needed JavaScript code highlighter for my recent project and having a gut feeling that someone has done it already, I decided to do a search rather than develop it myself. Not so much as a surprise it turned out to be good feeling and soon enough I ended up testing a dozen of different highlighters. I had spent good couple of hours before I found the one. Sharing is caring so here we go.

That beauty is called hightlight.js. You won't be disappointed especially if you are using jQuery, although it's a standalone library. It was created by talented Russian programmer Ivan Sagalaev who claims to be Software Maniac. He put together very simple documentation page which contains everything you need to know. It took me literally 5 minutes to download it, unpack it and get it working. Why do I think highlight.js is the best JavaScript highlighter?
  • supports 32 different types of syntax, including exotic ones like Lua, Lisp or Nginx
  • is a standalone library but is very easy to use with mootools, jQuery, prototype or any other JS library
  • can be used to highlight code injected to the DOM with JS (for some reason that didn't work for me with quite a few other libraries)
  • allows user to choose which nodes should be processed and does not force parsing the whole document
  • does not require being called upon document load event
  • is quite simplistic and is not trying to do 1000 things except from the one that you need; instead it does one thing and does it well: highlights code
Damn it, now I'm tempted to use it on my own old blog pages with code examples. Respect, Ivan!

Tuesday, May 11, 2010

How to put CDATA into script tag in XSLT

You have an XSL template for the website you are working on and you would like to embed some JavaScript in the markup. You care so you would like to keep the XHTML output valid. Easy enough - all it takes is wrapping the actual JavaScript code with CDATA. To make it safe you would also add JS comments around CDATA and move on. But is it really that easy with XSL? Let's have a look.

XSL template for JavaScript

Here is the working solution which allows for safe embedding JavaScript on XHTML pages created with XSL templates.

Example 0
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output
        method="xml"
        encoding="utf-8"
        doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
        doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
        indent="yes"
        cdata-section-elements=""
        omit-xml-declaration="yes" />
 
    <xsl:template name="javascript">
        <xsl:param name="code"/>
            <xsl:text disable-output-escaping="yes">
            &lt;script type="text/javascript"&gt;
            /* &lt;![CDATA[ */ </xsl:text>
            <xsl:value-of select="$code" disable-output-escaping="yes"/>
            <xsl:text disable-output-escaping="yes">
            /* ]]&gt; */
            &lt;/script&gt;
            </xsl:text>
    </xsl:template>
        
    <xsl:template match="/">
        <html>
            <body>
                <xsl:call-template name="javascript">
                    <xsl:with-param name="code">
                        <![CDATA[
                        if (1 > 2) {}
                        ]]>
                    </xsl:with-param>
                </xsl:call-template>
            </body>
        </html>
    </xsl:template>
</xsl:transform>
The above example will output:
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml">
  3. <body>
  4. <script type="text/javascript">
  5. /* <![CDATA[ */
  6. if (1 > 2) {}
  7.  
  8. /* ]]> */
  9. </script>
  10. </body>
  11. </html>
  12.  

Can it be simpler?

Let's start off with the most intuitive approach - add CDATA inside script tag as you would in XHTML.

Example 1
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <xsl:transform version="1.0"
  3. xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  4. <xsl:output
  5. method="xml"
  6. encoding="utf-8"
  7. doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
  8. doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
  9. indent="yes"
  10. cdata-section-elements=""
  11. omit-xml-declaration="yes" />
  12.  
  13. <xsl:template match="/">
  14. <html>
  15. <body>
  16. <script type="text/javascript">
  17. /* <![CDATA[ */
  18. if (1 < 2) {}
  19. /* ]]> */
  20. </script>
  21. </body>
  22. </html>
  23. </xsl:template>
  24. </xsl:transform>
The above example will output:
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml">
  3. <body>
  4. <script type="text/javascript">
  5. /* */
  6. if (1 &lt; 2) {}
  7. /* */
  8. </script>
  9. </body>
  10. </html>
  11.  

CDATA got stripped off and the < sign got replaced with &lt;. Of course! CDATA as an XML specific construct is interpreted in XSL as well. And that helps - try to remove CDATA from the following example and you will see an error. Good old < is the source of trouble here - without CDATA around, it makes XML invalid.

The interpreted CDATA should stay then but another CDATA is required in the output. xls:output has an option which allows to wrap content of certain tags with CDATA. However if you set it up to wrap up content of script tags with CDATA (the rest of the code like in example 1) you will not get what you need. Let's have a look.

Example 2
  1. cdata-section-elements="script"
The above example will output:
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml">
  3. <body>
  4. <script type="text/javascript">
  5. <![CDATA[
  6. /* */
  7. if (1 < 2) {}
  8. /* */
  9. ]]>
  10. </script>
  11. </body>
  12. </html>
  13.  

Ok, now there is CDATA in the output but it is not safely commented out. And it does not seem possible to get it that way. And how about creating CDATA explicitly as a text? Maybe with disabled output escaping that would work? Let's see.

Example 3
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <xsl:transform version="1.0"
  3. xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  4. <xsl:output
  5. method="xml"
  6. encoding="utf-8"
  7. doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
  8. doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
  9. indent="yes"
  10. cdata-section-elements=""
  11. omit-xml-declaration="yes" />
  12.  
  13. <xsl:template match="/">
  14. <html>
  15. <body>
  16. <script type="text/javascript">
  17. <xsl:text disable-output-escaping="yes">
  18. /* &lt;![CDATA[ */
  19. </xsl:text>
  20. <![CDATA[
  21. if (1 < 2) {}
  22. ]]>
  23. <xsl:text disable-output-escaping="yes">
  24. /* ]]&gt; */
  25. </xsl:text>
  26. </script>
  27. </body>
  28. </html>
  29. </xsl:template>
  30. </xsl:transform>
The above example will output:
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml">
  3. <body>
  4. <script type="text/javascript">
  5. /* <![CDATA[ */
  6.  
  7. if (1 &lt; 2) {}
  8.  
  9. /* ]]> */
  10. </script>
  11. </body>
  12. </html>
  13.  

That's definitely some progress, CDATA is in place. Now the &lt; in the JavaScript code should become < again. Why not to put the whole JavaScript code into another xsl:text tag with disable escaping? Well, that's why:

Example 4
  1. <script type="text/javascript">
  2. <xsl:text disable-output-escaping="yes">
  3. /* &lt;![CDATA[ */
  4. </xsl:text>
  5. <xsl:text disable-output-escaping="yes">
  6. <![CDATA[
  7. if (1 < 2) {}
  8. ]]>
  9. </xsl:text>
  10. <xsl:text disable-output-escaping="yes">
  11. /* ]]&gt; */
  12. </xsl:text>
  13. </script>
The above example will output:
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml">
  3. <body>
  4. <script type="text/javascript">
  5. /* <![CDATA[ */
  6.  
  7.  
  8. if (1 &lt; 2) {}
  9.  
  10.  
  11. /* ]]> */
  12. </script>
  13. </body>
  14. </html>
  15.  

Is it a dead end or maybe xsl:text element is not the best choice after all? It has to be something with disable-output-escaping attribute. Another such an element is xsl:value-of. Assuming that the JavaScript code exists only in the template and not in the processed XML structure, value-of needs an xsl:variable to read value from.

Example 5
  1. <xsl:variable name="s1">
  2. <![CDATA[
  3. if (1 < 2) {}
  4. ]]>
  5. </xsl:variable>
  6. <script type="text/javascript">
  7. <xsl:text disable-output-escaping="yes">
  8. /* &lt;![CDATA[ */
  9. </xsl:text>
  10. <xsl:value-of select="$s1" disable-output-escaping="yes"/>
  11. <xsl:text disable-output-escaping="yes">
  12. /* ]]&gt; */
  13. </xsl:text>
  14. </script>
The above example will output:
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml">
  3. <body>
  4. <script type="text/javascript">
  5. /* <![CDATA[ */
  6.  
  7. if (1 < 2) {}
  8.  
  9. /* ]]> */
  10. </script>
  11. </body>
  12. </html>
  13.  

And that worked! It is not very flexible solution, though. Defining variable for every JavaScript in the template seems to be acceptable only if necessary. Luckily xsl:value-of can also read value of a parameter passed to an xsl:template. That's how I got to the template you can find at the top of the page.

Thank you for reading. I hope you found it useful.

Update - 21.05.2010

At the beginning the template looked like this:

  1. <xsl:template name="javascript">
  2. <xsl:param name="code"/>
  3. <script type="text/javascript">
  4. <xsl:text disable-output-escaping="yes">
  5. /* &lt;![CDATA[ */ </xsl:text>
  6. <xsl:value-of select="$code" disable-output-escaping="yes"/>
  7. <xsl:text disable-output-escaping="yes">
  8. /* ]]&gt; */
  9. </xsl:text>
  10. </script>
  11. </xsl:template>

However it turned out that on some PHP installations XSLT adds CDATA inside <script> tag even if it's not specified in the <xsl:output>. Therefore <script> tag has to be generated as a text rather than being part of interpreted XML.

Jacek

Friday, August 21, 2009

Gracefully downgradable javascript for accessibility

JavaScript contributes by a great deal to user experience on the Web and it does not have to be an obstacle for accessibility. The goal is to allow the user access all of the website's content when JS is enabled as well as when it is disabled.

Let's consider two versions of the webpage: one is interactive JavaScript enriched and the other one is just static. I think it is safe bet that both of them initially share same markup and only differences occur in styling.

If we stop to think about it, we have just one markup with two possible stylings applied to it. If we could detect within CSS which version of styling should be applied that would solve the case. Of course CSS on its own have no such ability but that is exactly where the "C" from CSS comes to aid: Cascading.

JavaScript, when enabled, can amend DOM. In particular it can add a class to body tag, say "js-enabled". Having styles for specific areas of the webpage, cascaded down through .js-enabled class allows you to differentiate between JS enabled and disabled state on the CSS level.

The simplest example would be a definition list. We want to display all the terms but not the definitions. The latter would be expanded and visible only when corresponding term was clicked, which needs some simple JavaScript functionality to work. On the other hand, when JS is not available the user should be able to see the whole list: the terms along with the definitions. We could do it using this CSS:
.js-enabled dd {display:none;}
.js-enabled dd.expanded {display: block;}

JavaScript would add the class "expanded" whenever there is a need to show the definition. Simply removing the class would hide the element again. I am not going to go into details of the implementation as it is not very interesting. What is interesting though is when to add the class "js-enabled" to the body tag.

If it was added after the document has been fully loaded (for example from within the "document.onload" event handler), the list would be rendered without the "js-enabled" class at first and both terms and definitions would be visible. Then adding the class would cause hiding all the definitions and as a result ugly jumping of content on the page. To prevent this effect we have to add "js-enabled" class as soon as the body tag is available for manipulating but before the document has been rendered:

<body>
<script type="text/javascript">
try {
document.getElementsByTagName("body")[0].className += " js-enabled";
} catch(e) {}
</script>
...