{"id":71,"date":"2009-10-27T22:37:54","date_gmt":"2009-10-28T02:37:54","guid":{"rendered":"http:\/\/www.useragentman.com\/blog\/?p=71"},"modified":"2009-10-29T00:09:02","modified_gmt":"2009-10-29T04:09:02","slug":"configuring-javascript-applications","status":"publish","type":"post","link":"https:\/\/www.useragentman.com\/blog\/2009\/10\/27\/configuring-javascript-applications\/","title":{"rendered":"Configuring JavaScript Applications With XML"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-283 alignleft whiteImage\" title=\"configurationXML\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2009\/10\/configurationXML.png\" alt=\"Remixed from an image from the Open Clip Art Library\" width=\"250\" height=\"89\" \/><\/p>\n<p>I have been hacking JavaScript for close to 12 years now, and love it.\u00a0 But just like anyone you have been enamored with for a long time, there are bound to be things that drive you crazy about the object of your affection.\u00a0 Sure, your feelings are stronger than when you first met, but sometimes, after you&#8217;ve had an a disagreement after a late night of coding, you catch yourself thinking \u201cwhy in the world does she do things that way!?! Ridiculous!\u00a0 She is driving me crazy with her inflexibility!\u201d\u00a0 You then calm down, and realize that despite her flaws, she is still the exciting, cool and can&#8217;t-live-without-her girl she was when you first met her \u2013 maybe even more so.<\/p>\n<p>Okay, I don&#8217;t mean to equate JavaScript with my wife (that may result with me sleeping on the couch tonight).\u00a0 But sometimes the way JavaScript does things is pretty silly.\u00a0 You&#8217;d figure after all these years, some of these things would have changed, but they haven&#8217;t.<\/p>\n<h2>Long Strings in JavaScript<\/h2>\n<p>Take for example the way that JavaScript likes to handle long, multi-line strings:<\/p>\n<blockquote class=\"code\">\n<pre>var html = \"&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Name&lt;\/th&gt;&lt;th&gt;Address&lt;\/th&gt;&lt;th&gt;City&lt;\/th&gt;\" +\r\n\"&lt;th&gt;Province&lt;\/th&gt;&lt;th&gt;Postal Code&lt;\/th&gt;&lt;th&gt;Telephone&lt;\/th&gt;&lt;\/tr&gt;&lt;\/thead&gt;\";<\/pre>\n<\/blockquote>\n<p>Concatenating strings is a pretty expensive operation, both in <a title=\" String Performance: an Analysis\" href=\"http:\/\/www.sitepen.com\/blog\/2008\/05\/09\/string-performance-an-analysis\/\">memory and processing time<\/a>, and using concatenation\u00a0 it to describe a constant string doesn&#8217;t make too much sense.  But putting this string on one line would make the code quite unwieldy to read.\u00a0 Plus it looks ugly.\u00a0 I may be a slob in real life (my coworkers and my family could go on for hours about that one) , but I love my code neat.<\/p>\n<h2>Hard-Coding Values into Scripts<\/h2>\n<p>Another problem I have with this method of defining strings is that we are hard-coding text into the script. This is not a problem unique to JavaScript by any means, but this breaks the <a title=\"Wikipedia article on Unobtrusive JavaScript\" href=\"http:\/\/en.wikipedia.org\/wiki\/Unobtrusive_JavaScript\">Structure\/View\/Behaviour separation<\/a> model that I like to follow when I code a web application.\u00a0 Furthermore, if we had two pages with the same content but written in different languages (like in Canada, where a lot of sites are in English and French) we either have to have two versions of our script, or have the script broken into two parts: one with all the general code in it and one containing the language specific code.\u00a0\u00a0\u00a0 While the latter is the more desirable of the two, it doesn&#8217;t lend itself to integrate well with some server-side web application frameworks like <a title=\"Java Struts home page.\" href=\"http:\/\/struts.apache.org\/\">Java Struts<\/a>.<\/p>\n<p>Furthermore, I hate hard-coding <strong>any<\/strong> type of value (strings, integers, and any type of objects) directly into my scripts.\u00a0 Scripts should be flexible enough to be used in any type of situation &#8211; your table pagination script may work well with having ten rows on the page at the time in one situation, but in another, you may want 15 or 20.<\/p>\n<p>One comment I hear all the time is <strong>&#8220;Why not use JSON&#8221;?<\/strong> JSON is great, but because it is based on JavaScript, it is still gets ugly when manipulating long strings.<\/p>\n<h2>Enter config.js to the Rescue<\/h2>\n<p>In fact, it was Struts that inspired me to write the config.js JavaScript library.\u00a0 If you aren&#8217;t familiar with it, Struts is a Java Framework that allows developers to configure their server-side web applications easily with a set of XML files.\u00a0 It seemed natural to do the same in JavaScript, given all the DOM and XML processing routines that it has at its disposal, so I built config.js to do this task.\u00a0 With this library, JavaScript developers can configure their own scripts using a block of XML.\u00a0 This block of XML can be either embedded inside the HTML document (via an HTML comment) or in a separate XML file of its own.\u00a0 And this configuration block can contain any number of strings, numbers, arrays or objects that a developer would need to get the job done.<\/p>\n<p>For example, let&#8217;s say you had a JavaScript function that looked like this:<\/p>\n<blockquote class=\"code\">\n<pre>function submitFormEvent(e){\r\n  var amount = document.getElementById(\"amount\").innerHTML;\r\n  var creditCardType = document.getElementById(\"ccType\").value;\r\n  var month = document.getElementById(\"month\").value;\r\n\r\n  var configString = \"Submitting this order will charge \" + amount +\r\n    \" to your \" + creditCardType +\r\n    \" and will be received on your \" + month +\r\n    \" credit card bill.  Are you sure you want to do\" +\r\n    \" this?\");\r\n\r\n  if (window.confirm(configString)) {\r\n    window.location = \"http:\/\/www.mycompany.com\/myApp\/chargeMe.do\";\r\n  }\r\n  return;\r\n}<\/pre>\n<\/blockquote>\n<p>As you can see, the English literals are hard-coded in the script and there is a lot of string concatenation going on.\u00a0 One could refactor the script to use config.js to fix these issues  in four simple steps:<\/p>\n<ol>\n<li>Include the EventHelpers.js and config.js scripts in the &lt;head&gt; of your document (EventHelpers.js is included with the config.js archive):<br \/>\n<blockquote class=\"code\">\n<pre>&lt;script type=\u201dtext\/javascript\u201d src=\u201d\/path\/to\/EventHelpers.js\u201d&gt;&lt;\/script&gt;\r\n&lt;script type=\u201dtext\/javascript\u201d src=\u201d\/path\/to\/config.js\u201d&gt;&lt;\/script&gt;<\/pre>\n<\/blockquote>\n<\/li>\n<li>Insert an XML block that contains the hard-coded strings in an HTML tag with an <code>id<\/code> of <code>config<\/code>:<br \/>\n<blockquote class=\"code\">\n<pre>&lt;div id=\"config\"&gt;\r\n&lt;!--\r\n&lt;config&gt;\r\n  &lt;myApp&gt;\r\n   &lt;confirmCharge&gt;\r\n      &lt;text&gt;\r\nSubmitting this order will charge @amount@  to your\r\n@creditCardType@ and will be received on your @month@\r\ncredit card bill.  Are you sure you want to do this?\r\n      &lt;\/text&gt;\r\n      &lt;url&gt;http:\/\/www.mycompany.com\/myApp\/confirm.do&lt;\/url&gt;\r\n   &lt;\/confirmCharge&gt;\r\n  &lt;\/myApp&gt;\r\n&lt;\/config&gt;\r\n --&gt;\r\n&lt;\/div&gt;<\/pre>\n<\/blockquote>\n<\/li>\n<li>Refactor you code to use config.js routines:<br \/>\n<blockquote class=\"code\">\n<pre>function submitFormEvent(e){\r\n      var amount = document.getElementById(\"amount\").innerHTML;\r\n      var creditCardType = document.getElementById(\"ccType\").value;\r\n      var month = document.getElementById(\"month\").value;\r\n<strong>\r\n      var configString = config.getScriptedValue(\r\n          \"myApp.confirmCharge.text\",\r\n          {\r\n            amount: amount,\r\n            creditCardType: creditCardType,\r\n            month: month\r\n          });\r\n\r\n      if (window.confirm(configString)) {\r\n          window.location = config.getValue(\"myApp.confirmCharge.url\");\r\n      }\r\n<\/strong>\r\n      return;\r\n}<\/pre>\n<\/blockquote>\n<\/li>\n<li>Replace any <code>window.onload<\/code> calls in your code with <code>config.addLoadEvent()<\/code> to ensure that any code that relies on config.js is initialized <strong>after<\/strong> the XML block is loaded into memory:<br \/>\n<blockquote class=\"code\">\n<pre>config.addLoadEvent(exampleConfigForm.init);<\/pre>\n<\/blockquote>\n<\/li>\n<\/ol>\n<p>That&#8217;s it!\u00a0 If you need to internationalize your application, use whatever internationalization framework your server side code uses &#8211; it should integrate well with config.js.\u00a0 I use it with Java Struts all the time.<\/p>\n<p><a class=\"exampleLink\" href=\"\/tests\/config\/example.html\">See an example of the above code in action<\/a><\/p>\n<h2>Use config.js in All Your Scripts<\/h2>\n<p>Have more than one script on a page that you want to use config.js with?\u00a0 No problem!\u00a0 Add another block of XML inside the &lt;config&gt; node right after your other scripts config information:<\/p>\n<blockquote class=\"code\">\n<pre>&lt;div id=\u201dconfig\u201d&gt;\r\n&lt;!--\r\n&lt;config&gt;\r\n  &lt;myApp&gt;\r\n   &lt;confirmCharge&gt;\r\n      &lt;text&gt;\r\nSubmitting this order will charge @amount@  to your\r\n@creditCardType@ and will be received on your @month@\r\ncredit card bill.  Are you sure you want to do this?\r\n      &lt;\/text&gt;\r\n      &lt;url&gt;http:\/\/www.mycompany.com\/myApp\/confirm.do&lt;\/url&gt;\r\n   &lt;\/confirmCharge&gt;\r\n  &lt;\/myApp&gt;\r\n\r\n<span class=\"hilite\">&lt;calendarWidget&gt;\r\n  &lt;instructions&gt;Enter in a valid date after @dateBegin@&lt;\/instructions&gt;\r\n  &lt;errors&gt;\r\n    &lt;notValid&gt;The date you entered is not valid&lt;\/notValid&gt;\r\n    &lt;holiday&gt;\r\nSorry, @date@ is a holiday and we won't be open\r\nat that time.\u00a0 Please try again.\r\n    &lt;\/holiday&gt;\r\n  &lt;\/errors&gt;\r\n&lt;\/calendarWidget&gt;\r\n<\/span>\r\n&lt;\/config&gt;\r\n--&gt;\r\n&lt;\/div&gt;<\/pre>\n<\/blockquote>\n<p>Now, all your configuration information for all your scripts can be in one place.\u00a0 Programmers can now develop the code with place holders for the text, and not worry about accidentally messing up the code when marketing or customer service wants to make some textual changes.<\/p>\n<h2>config.js can also handle HTML<\/h2>\n<p>You can even insert full HTML inside the configuration XML block using a CDATA node:<\/p>\n<blockquote class=\"code\">\n<pre>&lt;config&gt;\r\n&lt;myApp&gt;\r\n  &lt;browserWarning&gt;&lt;![CDATA[\r\n    &lt;div class=\u201dwarning\u201d&gt;\r\n    As of @date@ we will &lt;strong&gt;not&lt;\/strong&gt; be supporting Internet\r\n    Explore 6 or lower.\u00a0 Please &lt;a href=\u201d\/howToUpgradeIE.html\"&gt;upgrade your\r\n    installation of Internet Explorer&lt;\/a&gt;, or install the latest version of one\r\n    &lt;a href=\u201d\/otherChoices.html\u201d&gt;the many alternative browsers available&lt;\/a&gt;.\r\n    &lt;\/div&gt;\r\n  ]]&gt;&lt;\/browserWarning&gt;\r\n  &lt;\/myApp&gt;\r\n&lt;\/config&gt;<\/pre>\n<\/blockquote>\n<p>This makes using an HTML node&#8217;s .innerHTML property even more fun!  You longer do you have to hard-code  long chunks of HTML inside your scripts.  Try that with JSON!<\/p>\n<h2>Framework Independent<\/h2>\n<p>Config.js is not part of a JavaScript framework \u2013 you can use this library whether you use prototype, mootools, Dojo, jQuery or anything else that may come along.  Please feel free to make improvements and changes on it &#8211; if you submit the changes back to me, I&#8217;ll incorporate them into the next official release.<\/p>\n<h2>More Information<\/h2>\n<p>There is way more to config.js than is explained here.  Complete documentation for the library can be found here:<br \/>\n<a class=\"exampleLink\" href=\"\/blog\/config-js-\u2013-a-javascript-cofiguration-library\/\">config.js manual page<\/a><\/p>\n<h2>Download<\/h2>\n<p>You can get full source here:<\/p>\n<p><a class=\"exampleLink\" href=\"\/downloads\/config.zip\">config.js v.2.0 and example code (zip format)<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I have been hacking JavaScript for close to 12 years now, and love it.\u00a0 But just like anyone you have been enamored with for a long time, there are bound to be things that drive you crazy about the object of your affection.\u00a0 Sure, your feelings are stronger than when you first met, but sometimes, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7,11],"tags":[],"class_list":["post-71","post","type-post","status-publish","format-standard","hentry","category-javascript","category-xml"],"_links":{"self":[{"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts\/71","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/comments?post=71"}],"version-history":[{"count":45,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts\/71\/revisions"}],"predecessor-version":[{"id":312,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts\/71\/revisions\/312"}],"wp:attachment":[{"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/media?parent=71"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/categories?post=71"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/tags?post=71"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}