November 12, 2008

multiple versions of dojo

so, you've inherited a project and it uses an old version of dojo and you really don't have the time to get up to speed with the changes that have happened in dojo since that release and your project ain't broke so you don't really want to fix it but somebody wants a new feature or noticed a small defect and even if this scenario doesn't completely match your circumstances... for some reason you have a need to be running 2 versions of dojo at the same time. if this is the case then keep reading...

first of all, for the attention impaired, here's a link to what we're working towards http://archive.dojotoolkit.org/nightly/dojotoolkit/dojo/tests/_base/_loader/scope/scope04.html. this page shows dojo 0.4.3 from the aol cdn working beside the latest nightly build of dojo.

i recently helped someone who had a project that used dojo 0.4.3 and according to them, on FF3 the initial dialog markup was being displayed as the page was loading even though there was inline styling that was supposed to keep them hidden. i never confirmed this for myself but that is what they were telling me. in this case, they didn't want to migrate their whole project but they just wanted to fix their dialogs. so, it seemed that the path of least resistance was to run 2 versions of dojo side-by-side and leave most of the code alone and just migrate the dialogs.

the book of dojo already has a section about multiple versions of dojo in a page but it doesn't hurt to have another perspective on it. so let's dig into this. the basic idea is leave the old stuff alone and bring in the new stuff in a way that the old stuff is unaware of.

i'll start at the top of the file and work down explaining each part - css, javascript and html.

css
this file links to 3 different style sheets and the first one and the third one are related to the nightly build version of dojo and the 2nd one is specifically related to the dijit tests.

<link rel="stylesheet" type="text/css" href="../../../../resources/dojo.css">
<link rel="stylesheet" type="text/css" href="../../../../../dijit/tests/css/dijitTests.css">
<link rel="stylesheet" type="text/css" href="../../../../../dijit/themes/tundra/tundra.css">

for the guy i was helping, he didn't want any changes to the styling he already had so the only css he had to add was:

<link rel="stylesheet" type="text/css" href="dojoroot/dijit/themes/dijit.css">

this file has the essential styles for the dialog (and other widgets) to function properly.

javascript
since the ability to use multiple versions of dojo was only introduced in 1.1, if we are using a version that is pre 1.1 then we want to load the old version of dojo first. in theory, if both versions you want to use are 1.1 or later then it may be possible to load either version first. the important thing is the one which is loaded without using custom namespaces will be the one that gets the "dojo" namespace (and "dijit" and "dojox" if that version used them). i would recommend that if both versions are 1.1 or later then it would be a good practice to give each one it's own custom namespace so that there is no confusion about which version of dojo you are referring to.

loading the old version of dojo
you shouldn't need to change anything here if you're working with a pre-existing project. if you don't have djConfig defined then there should be no need to define it at this point.

<script type="text/javascript">
//djConfig for 0.4.3 setup.
djConfig = {
isDebug: true
};
</script>
<script type="text/javascript" src="http://o.aolcdn.com/dojo/0.4.3/dojo.js"></script>

loading the new version of dojo
now that the old version has used djConfig and loaded itself, it will be safe for us to make changes to djConfig and load in our 2nd version of dojo - making sure to use a custom namespace for this version. the custom namespace is achieved through djConfig.scopeMap. this tells dojo how to map it's namespaces. in the example below "dojo" maps to "dojo10", "dijit" maps to "dijit10" and "dojox" maps to "dojox10". it is worthwhile noting that djConfig.baseUrl should point to the directory containing the dojo.js file - this is not quite obvious from this example.

<script type="text/javascript">
//Need scope map defined in a script block. It will not work as part of the
//djConfig attribute on the script that loads Dojo.
//Also, just adding properties instead of redefining djConfig, since that
//will wipe out djConfig values set up by the 0.4.3 dojo.
djConfig.parseOnLoad = true;
djConfig.baseUrl = "../../../../";
djConfig.scopeMap = [
["dojo", "dojo10"],
["dijit", "dijit10"],
["dojox", "dojox10"]
];
</script>
<script type="text/javascript" src="../../../../dojo.js"></script>


putting this to use
after getting the groundwork laid, now we can do something with this. to use the old version, we just keep doing things like they were being done before. calling dojo.require or using a dojoType tag or calling dojo.byId or dojo.addOnLoad will all use the 0.4.3 version of dojo since the 0.4.3 version took the "dojo" namespace. to use the new version, we call dojo10.require or use dojo10Type tags, etc. this is because we mapped the newer version of dojo to use the "dojo10", "dijit10" and "dojox10" namespaces. refer to the book of dojo for limitations to this feature.

<script type="text/javascript">
dojo.require("dojo.widget.DropdownDatePicker");
dojo10.require("dijit._Calendar");
dojo10.require("dojo.date.locale");
dojo10.require("dojo.parser"); // scan page for widgets

dojo.addOnLoad(function(){
dojo.byId("output043").innerHTML = dojo.version.toString();
});
dojo10.addOnLoad(function(){
dojo.byId("output10").innerHTML = dojo10.version.toString();
});

function myHandler(id,newValue){
console.debug("onChange for id = " + id + ", value: " + newValue);
}

function foobar(){
dojo.byId("typeOut").innerHTML = (typeof dojo.addClass);
}
setTimeout(foobar, 2000);
</script>


html
finally, we get to the html. the most important thing to notice here is the tags - "dojoType" vs "dojo10Type". you will also notice that class="tundra" was put on the parent of the dijit._Calendar so that the tundra theme would be applied to that widget.

<h1>Multiversion Dojo: 0.4.3 and 1.0</h1>

<p><b>NOTE: This test only works with a built version of Dojo</b></p>

<p>This page loads Dojo 0.4.3 and Dojo 1.0.</p>

<p>Dojo 0.4.3 version: <span id="output043"></span></p>

<p>Dojo 1.0 version: <span id="output10"></span></p>

<p><b>dojo.addClass should be undefined:</b> <span id="typeOut"></span></p>

<p>
<input dojoType="dropdowndatepicker" value="2006-10-31"
containerToggle="wipe" containerToggleDuration="300" >
</p>

<p class="tundra">
<input id="calendar1" dojo10Type="dijit._Calendar" onChange="myHandler(this.id,arguments[0])">
</p>

this was a problem i helped someone solve recently and thought it was worth blogging. feel free to leave comments - good or bad.