Wednesday, November 6, 2013

Yet another Ubuntu laptop - DELL Inspiron 17R

When I had to buy a new laptop I wanted something performing and working nicely with Ubuntu. I am quite fond of DELL laptops and luckily, there are plenty which are certified Ubuntu laptops. The one I have chosen however, DELL Inspiron 17R was not on this list:

http://www.ubuntu.com/certification/desktop/make/%20DELL/?category=Laptop

Encouraged by a whole range of DELL laptops on this list, I took a leap of faith and bought it. Unfortunately unspeakable system version 8 was installed on it, but I took little notice, as Ubuntu can happily co-exist with it. I have even curved out a little partition for the joke of an OS, just for giggles.

I have picked Ubuntu 12.04.3 - stable, reliable, well rounded and frequently updated. No problems during installation. Two things worth mentioning though, after installation on my Inspiron:

- For dual display setup I had to remove fglrx drivers. Unfortunately the open source radeon drivers do not support my Radeon HD 8730M. On the plus side there is Intel graphics card integrated into IvyBridge. Good older i915 is doing quite well, so see you later Radeon!

- Dual boot with Windows 8 (flipipng EFI) with nice grub menu at boot time required Boot-Repair (https://help.ubuntu.com/community/Boot-Repair), however automatic settings do the trick just fine.

Picture worth 1000 words... Screenshot totally in the GNU spirit ;)

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

Friday, May 18, 2012

How to add form tag to Typo3 RTE

Obviously it's simple when you know how to do it but it's hard to find on Google. I gave up after seeing a few advices like "use HTML element" or "read documentation". Thing is, I always start with reading documentation. The final resort is usually reading the source which might be a bit more time consuming but always gives definitive answer.

The following solution has been tested in Typo3 version 4.6.4. It should work fine elsewhere. Any feedback welcome, feel free to drop a line in the comments saying "version x.x.x works" or "version x.x.x doesn't work".

Getting to the subject, in order to add form support to RTE in Typo3 you will need to add some TypoScript to your page TSconfig and TypoScript template. The former is to make sure that content is properly saved in the database, the latter to avoid escaping tags in the frontend.

Let's start with page TSconfig:


RTE.default.proc {
  allowTags := addToList(form, fieldset, input, select, option, label)
  allowTagsOutside := addToList(form, fieldset, input, select, option, label)
  denyTags := removeFromList(form, fieldset, input, select, option, label)
  entryHTMLparser_db {
    allowTags < RTE.default.proc.allowTags
  }
}


Feel free to add more tags if you need them.

Now we need to get the frontend sorted. This should go to your TypoScript template:

lib.parseFunc_RTE.allowTags := addToList(form, fieldset, input, select, option, label)


It's a good idea to make sure that the lists of tags from TSconfig and TypoScript template are matching up. Enjoy.

Wednesday, January 11, 2012

How IE6 caused the Dark Decade of the Web

If each developer in the world gave me a penny for every time they were swearing at IE6 then I could possibly be the richest man on the planet. The money spent in web development worldwide just for fighting IE6 bugs could probably buy the Cure For Cancer. Dealing with IE6 was not fun by the slightest. And now, finally, this global generator of frustration is dying a death celebrated by the whole Web Community as well as its own creators. It is really the time to crack a bottle of champagne.


No doubt, we could have been saved from the Dark Decade of the Web. Netscape Navigator was once the best browser on the Web, holding nearly 80% of the market in 1996. It was a strong competitor for IE and competition drives innovation. Unfortunately Netscape couldn't keep up the pace and finally lost the Browser Wars. When the dust settled eventually, we found ourselves left with far from perfection IE6 and on the brink of the decade of frustration.

For nearly 10 years we couldn't do much other then learn how to compensate for IE6 bugs and its devilish quirks. We did care about IE6 not because we liked it. I don't know about you but I still hate it with passion. It gives me nightmares. We cared about IE6 because we cared about our users. What choice did they have after all? With no sensible alternatives at the time it became the most popular browser. The reference experience. The blocker of the Web innovation.

How many times, with pondering heart, were you launching IE6 to view your newest, inventive piece of work and asking yourself: "Will it work in IE?" How many times were you dreading this question so often thrown casually into a conversation by your customer: "That looks cool. Can we have a quick look at it in IE?"And it had to look good in IE. It had to look the same in every browser.

It was going on for so long as to became our second nature. Even after Firefox and then Chrome started gaining popularity and could deliver better experience at a lower price it had always to be the same. We were consciously downgrading the experience in more capable browsers in order to keep it "consistent". Now IE6 is good as dead but will we still carry on? Will we pick another "reference browser", the worst on the market (let me guess... IE7?) to bring our work down to its level?

I sincerely hope we know better than that now. If you had a CRT TV you probably wouldn't expect to watch HD programs on it. With browsers it is not that much different. IE7 is nothing like new Chrome. There is no reason to try and make our websites look and behave identical in both. The experience can downgrade and that is OK. As long as we define and deliver acceptable minimum the rest becomes pure fun. We don't have to worry about how it would look in IE7. We know it will be different. And that is OK.

Even though I am concerned I believe the black scenario is not very likely to happen. The Web becomes less and less desktop-centric. Many more other devices are being used for browsing the Web today and the numbers are growing. Mobile phones, tables, game consoles - they all have different resolutions and provide different experience. The game is no longer about minimum screen resolution. Responsive design becomes a necessity. We are slowly growing used to the fact that the same website can look differently when we switch to another device. From here it takes just a small step to accept that it can also differ depending on the browser we use.

I am sure that the challenges that are yet to be taken are going to be interesting. I imagine designers would be required to provide scalable designs, probably in several variations mitigating scaling stress points. Implementation of those designs would be relying more on scalable CSS3 effects rather than their graphics heavy counterparts. The focus of testing would shift to different resolutions and graceful downgrade of experience in less capable browsers. It's the whole new world.

Seems that the Web has just evolved, we have a lot to learn and even more fun ahead and IE6 is nearly dead. Isn't that exciting?

Jacek


PS.
I would like to thank two remarkable people who inspired me and opened my eyes. Paul Irish, the Lead Developer of Modernizr who gave a presentation on Developing HTML5 in cross-browser world and Ethan Marcotte who contributed to "An Event Apart" (Jan 2012) giving great presentation entitled "A Dao of flexibility".

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!

Saturday, March 12, 2011

iPhone 4.2 and Ubuntu 10.10 - mount problem with dbus

I can't believe it's been nearly half a year since my last post. Anyways. It so happened that I was stuck with a large video on my iPhone. I wanted to download it however my iTunes had different opinion and refused to deal with it. As I'm running Ubuntu 10.10 on my laptop I have decided to try my luck in there.

I have plugged my iPhone in and to my dismay my beloved Ubuntu threw ugly DBus error in my face saying iPhone could not be mounted. I should've taken a screenshot but hey, who wants to remember error messages? Nevertheless after some googling I have discovered that iOS 4.2 requires libimobiledevice1 package upgrade to version 1.0.4. Unfortunately official stable repos offer version 1.0.1 at the moment but it's nothing to worry about, though. Thanks to Paul McEnery you can benefit from your iPhone 4.2 connected successfully to your Ubuntu machine. Just add the PPA in command line:
sudo apt-add-repository ppa:pmcenery/ppa
next do the update:
sudo apt-get update
and then install/upgrade the library and other tools if necessary. Thanks for reading. I hope you found it helpful. Jacek

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!

Thursday, July 1, 2010

How to get SubVersioN on Mac OS X 10.6?

Even if you work on a project on your own it's worth having version control system in place. It helps to keep things tidy and gives you time machine possibilities for working with your code (I am not talking about the trademarked machine). I like SVN which is mature and seems to have it all. Let's have a look how to install that beast on our lovely Macs.

Download SVN for free

First good news - SVN comes with a nice Mac-like installer and is completely free and published under Apache Licence. You can download it from CollabNet website. It requires free registration which at first seems a bit dodgy but CollabNet is the company responsible for creating SVN and it's a good source.

Install SVN on Mac OS X 10.6

Once you have downloaded the package it's time to install it. The installer looks all pretty and takes no longer than just a few moments. It installs the whole svn bunch (server and client) in /opt/subversion directory. The only downside is that you don't get any fancy application like you do for MAMP to control it. After you've finished the installation it all happens in the command line... but cheer up, it's not that scary. You will get it up and running in no time.

Set up evironment

SVN gives you complete freedom of the location of your repositories. It goes like this. You create a directory wherever you wish and tell your svn server to feel at home in there. That directory is then your svn server root directory. Your SVN server will create your repositories in there.

Let's get started then. Since all the svn related programs are located in /opt/subversion/bin you have to specify the path every time you need to run them. It's not handy at all, we would prefer not to worry about where they are. That's not a biggy. Fire up your Terminal (it's that monitor icon in /Applications/Utilities) and edit the file .profile in your home directory. I, for one, like vim but it might be slightly depressing experience at first if you are not familiar with it. In that case use pico, it's really straighforward

$ pico .profile
and add the following line at the end of the file:
export PATH=/opt/subversion/bin:$PATH
The .profile file is read every time you create new shell, so next time you open your Terminal the change will be applied. Because we don't want to close the Terminal just yet only to reopen it let's cheat a tiny bit:
$ . .profile

Well done! Let's check if it works

$ svn
Type 'svn help' for usage.
If you got similar output you are ready to proceed.

Set up SVN repository

Now it's time to create root directory for the SVN server. You can name it whatever you like and create it even in your home directory if you wish. SVN is not fussy at all. Let's do that then and let's give it meaningful name "svnrepos".

$ mkdir svnrepos
And finally it's time to launch your SVN server. By the way it's not a typo, there is no 'r' at the end:
$ svnserve -d -r svnrepos
There are no repositories. All we have is just SVN server ready for action. Let's give him something to look after. If you want to create a test repository to play with it for a while, just do this:
$ svnadmin create svnrepos/test

Set up privileges

Congratulations! You have just created your repository. Good thing is you don't need to worry about having to do some magic tricks later on to get rid of the test repository whenever you feel like it. Simply delete the directory svnrepost/test and it's gone forever. For now though, it's accesible through the URL svn://localhost/test but you cannot do much with it unless you grant yourself the privileges.

SVN server keeps access control lists per repository, so you need to dive into config directory of your newly created repository and conquer! Sounds like a big job but it isn't. All it takes is adding one line in one file and removing one comment in another one. Go to svnserve/test/conf and edit the file passwd first. Here you will add your preferred username and password. It's easier when you choose your Mac username. For example, my Mac username is "jacek" and my password for the test repository is "test", so I added a line jacek = test.

Next edit the file svnserve.conf and remove comment from the line saying password-db = passwd.

Believe it or not, that's it! Now you can access your repository through your favourite SVN client and do whater SVN clients do. One thing you need to remember is to run

svnserve -d -r svnrepos
every time you start your Mac. Of course it's quite easy to make it happen automagically but that's for another story.

Thanks for reading. I hope you found this guide useful, it worked for you and made you a bit happier. Please don't think twice before you leave your comment.

Jacek

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, April 2, 2010

Zend PHP 5 Certification Exam - review

This time it's about the Zend PHP5 exam itself, not about PHP. I have taken the exam today and singing loudly in my car on the way back home I thought: the guys who are about to take it might want to know how it goes. And this is the story about what happens when you decide to go into the lion's cave armed with your brain and that only.

Well, it's not that bad. People I met in the exam centre were very friendly. I was taking my exam in Feltham, in the test center run by TSM Consultants UK Ltd. Poor folks were working even though it was bank holiday. They said it was all right, though.

They are serving as a test spot for some insane number of vendors, one of them being Zend. It is all very professional. When I booked the exam, I was asked to turn up about 15 minutes before the exam starts. I was also told to have two forms of identification on me, at least one with a picture of my lovely face. I complied, of course, and I am glad I did. It is not just talks - they take it really seriously. No id? Then they wave you goodbye and invite you some other time when you can be bothered to read the instruction before coming.

I was being checked in by a nice lady who asked me to read the terms and conditions. I learned I was not allowed to take anything with me to the examination room - mobile, jacket, rack sack even my beloved coffee had to be left behind. They gave me a locker for my valuables, though, so I put there my coffee. I am joking, my jailbroken iPhone of course. And I had to use the toilet beforehand because if you leave the room once the exam has started there is no coming back.

When I was ready we entered the exam room. It was poket-size with about 5 computers standing around the walls. There was also proper Big Brother equipment. That's right. You are being watched, listened in and recorded during the exam. Who cares after all? If you know you are not going to make it you can always smash a few monitors and hope for becoming famous on YouTube after they release you from custody.

Speaking of the monitors - they were nice biggies, so I had no trouble reading the questions. If the chairs were a bit more comfy I would not complain, though. That's because the room was equipped with budget low-end office chairs. On the other hand the exam lasts for 90 minutes only, so being brave fellow I gritted my teeth and took my seat. The countdown timer started after I accepted the terms and condition and when the first question appeared on the screen.

After a few questions I realised the exam was not very different from the Zend PHP 5 Certification Mock Exam. It is similar type of questions and if you succeeded with a few of these mock exams you should be fine. The whole exam consists of 70 questions served in random order. For each question you may add a comment or mark it for later review. That last feature turned out quite handy when I gave all answers and wanted to come back to those which I was not entirely sure about. Review screen showed me links to all the questions and indicated the marked ones. Finally I decided I was ready and after answering zillion times 'yes' to a question going like: 'are you sure you want to finished the exam?' I saw big, beautiful and smiling at me from the screen:

CONGRATULATIONS!
You have passed Zend PHP 5 Certification Exam.

Wednesday, February 17, 2010

PHP: References To Array Elements Are Risky

References to array elements can bite! And it is not only the case with referencing in foreach loop. It seems that creating a reference to an array element replaces that element itself with a reference. If you then copy such an array and change the elements inside copy you can overwrite original value!

All of the presented code was tested on Mac (PHP 5.2.11), Linux (PHP 5.2.6-1+lenny4) and Windows XP (PHP 5.3.0) using PHP cross platform testing lab on Mac based on VirtualBox.

Changing copy affects original array

Sounds impossible? I agree. I couldn't believe it myself. Nevertheless here is the proof:
Example 1
$a = array('one', 'two', 'three', 'four'); 
$a2 = &$a[2]; 
 
$b = $a; 
$b[1] = 'two again'; 
$b[2] = 'reference bites'; 
 
var_dump($a, $b);
The above example will output:
array(4) {
  [0]=>
  string(3) "one"
  [1]=>
  string(3) "two"
  [2]=>
  &string(15) "reference bites"
  [3]=>
  string(4) "four"
}
array(4) {
  [0]=>
  string(3) "one"
  [1]=>
  string(9) "two again"
  [2]=>
  &string(15) "reference bites"
  [3]=>
  string(4) "four"
}

Changing copy of a copy affects original array too

If you look at the dump carefully you will see that $a[2] and $b[2] are displayed as references here. That would mean the element has been replaced with a reference. And if you copy a reference you just get what? Same reference, right? So any copy of $a would contain that reference. Going forward any copy of a copy of $a would contain that same reference. Let's check it:
Example 2
$a = array('one', 'two', 'three', 'four'); 
$a2 = &$a[2]; 
 
$b = $a; 
$c = $b; 
$c[2] = 'references bites more'; 
$b[1] = 'two again'; 
$a[0] = 'one more'; 
var_dump($a, $b, $c);
The above example will output:
array(4) {
  [0]=>
  string(8) "one more"
  [1]=>
  string(3) "two"
  [2]=>
  &string(21) "references bites more"
  [3]=>
  string(4) "four"
}
array(4) {
  [0]=>
  string(3) "one"
  [1]=>
  string(9) "two again"
  [2]=>
  &string(21) "references bites more"
  [3]=>
  string(4) "four"
}
array(4) {
  [0]=>
  string(3) "one"
  [1]=>
  string(3) "two"
  [2]=>
  &string(21) "references bites more"
  [3]=>
  string(4) "four"
}

Tricky "foreach" with reference explained

As you can see, the only element affected is the one referenced. That can lead to serious potential problems. Working on a copy of an array with scalar elements seems to be not as safe as one may thought. However, that explains one of the biggest pitfalls of iterating arrays in PHP: foreach with reference. The following is rather common knowledge:
Example 3
$a = array('one', 'two', 'three', 'four'); 
foreach ($a as &$v) {} 
foreach ($a as $v) {} 
var_dump($a);
The above example will output:
array(4) {
  [0]=>
  string(3) "one"
  [1]=>
  string(3) "two"
  [2]=>
  string(5) "three"
  [3]=>
  &string(5) "three"
}
But what was the explanation for that, again? It is quite clear that $v keeps reference to $a[3] after the foreach loop is finished. So what values does $v (effectively $a[3]) get within the next foreach loop? Let's see:
Example 4
$a = array('one', 'two', 'three', 'four'); 
foreach ($a as &$v) {} 
foreach ($a as $v) { 
 var_dump($a[3]); 
}
The above example will output:
string(3) "one"
string(3) "two"
string(5) "three"
string(5) "three"
Well, it's quite obvious. Or is it? As the foreach manual page states: "unless the array is referenced, foreach operates on a copy of the specified array and not the array itself". I would assume that "array is referenced" means array elements are referenced like this: foreach ($a as &$v) {} Apparently that is not the case with the second loop and it should work on a copy. Let's have a look what exactly would happen if the second foreach loop really worked on a solid copy:
Example 5
$a = array('one', 'two', 'three', 'four'); 
$b = $a; 
foreach ($a as &$v) {} 
foreach ($b as $v) {} 
var_dump($a);
The above example will output:
array(4) {
  [0]=>
  string(3) "one"
  [1]=>
  string(3) "two"
  [2]=>
  string(5) "three"
  [3]=>
  &string(4) "four"
}
I imagine you did expect this result. Beware references to array elements and thanks for reading. I hope you found this article useful. Please don't think twice before you leave your comment.