{"id":264,"date":"2009-10-14T00:46:19","date_gmt":"2009-10-14T04:46:19","guid":{"rendered":"http:\/\/www.useragentman.com\/blog\/?page_id=264"},"modified":"2009-10-28T22:53:56","modified_gmt":"2009-10-29T02:53:56","slug":"config-js-%e2%80%93-a-javascript-cofiguration-library","status":"publish","type":"page","link":"https:\/\/www.useragentman.com\/blog\/config-js-%e2%80%93-a-javascript-cofiguration-library\/","title":{"rendered":"Config.js \u2013 a JavaScript cofiguration library"},"content":{"rendered":"<h2>Description<\/h2>\n<p>Config.js allows developers to configure their applications in an XML block instead of hard-coding values inside their scripts or in JSON objects.\u00a0 The XML can be embedded inside an HTML document or in a separate XML file.\u00a0 The configuration block may contain strings, numbers, arrays and HTML.\u00a0 Furthermore, variables can be inserted into these values, allowing developers to use the XML block as a simple templating system for their applications.<\/p>\n<h2>Usage<\/h2>\n<p>For the majority of cases, using the library consists of three simple steps.<\/p>\n<ol>\n<li>Include the EventHelpers.js and config.js script in the &lt;head&gt; of your document:<br \/>\n<blockquote class=\"code\">\n<pre>&lt;script type=\"text\/javascript src=\"\/path\/to\/EventHelpers.js\"&gt;&lt;\/script&gt;\r\n&lt;script type=\"text\/javascript\" src=\"\/path\/to\/config-2.0.js\"&gt;&lt;\/script&gt;<\/pre>\n<\/blockquote>\n<\/li>\n<li>The config block can be inserted into your HTML document by defining any HTML node with an <code>id<\/code> of <code>config<\/code>.\u00a0 The only content inside this node should be an HTML comment with your configuration values inside.\u00a0 Below is an example XML block that defines a configuration property <code>formValidator.errors.mandatoryField<\/code>:<br \/>\n<blockquote class=\"code\">\n<pre>&lt;div id=\u201dconfig\u201d&gt;\r\n&lt;!--\r\n&lt;config&gt;\r\n  &lt;formValidator&gt;\r\n    &lt;errors&gt;\r\n      &lt;mandatoryField&gt;\r\n        The above field is mandatory\r\n      &lt;\/mandatoryField&gt;\r\n    &lt;\/errors&gt;\r\n  &lt;\/formValidator&gt;\r\n&lt;\/config&gt;\r\n--&gt;\r\n&lt;\/div&gt;<\/pre>\n<\/blockquote>\n<\/li>\n<li>Accessing the data inside the configuration block can be done with JavaScript by using the <code>config.getValue()<\/code> function.\u00a0 In the above example, the text inside the <code>mandatoryField<\/code> tag can be accessed inside JavaScript using the <code>config.getValue()<\/code> function like this:<br \/>\n<blockquote class=\"code\">\n<pre>document.getElementById(\"message\") =\r\n  config.getValue(\"formValidator.errors.mandatoryField\");<\/pre>\n<\/blockquote>\n<p><strong>Note:<\/strong> any call to <code>config.getValue()<\/code> must be made <em>after<\/em> config.js loads the XML block into memory.  If you are initializing your own code with a <code>window.onload<\/code>, you should replace it with a call to <code>config.addLoadEvent()<\/code>.<\/p>\n<p>For example, replace<\/p>\n<blockquote class=\"code\">\n<pre>window.onload=myObject.init<\/pre>\n<\/blockquote>\n<p>with:<\/p>\n<blockquote class=\"code\">\n<pre>config.addLoadEvent(myObject.init)<\/pre>\n<\/blockquote>\n<\/li>\n<\/ol>\n<p>You can put as many values inside your XML as you like.\u00a0 For example the values inside the XML configuration block below can be retrieved using <code>config.getValue('<\/code><code>formValidator.errors.mandatoryField<\/code><code>')<\/code>,\u00a0 <code>config.getValue('<\/code><code>formValidator.errors.postalCode<\/code><code>')<\/code> and <code>config.getValue('<\/code><code>formValidator.alerts.success<\/code><code>')<\/code>.<\/p>\n<blockquote class=\"code\">\n<pre>&lt;!--\r\n&lt;config&gt;\r\n  &lt;formValidator&gt;\r\n    &lt;errors&gt;\r\n      &lt;mandatoryField&gt;\r\n        The above field is mandatory\r\n      &lt;\/mandatoryField&gt;\r\n      &lt;postalCodeError&gt;\r\n        You did not format the postal code correctly.\r\n      &lt;\/postalCodeField&gt;\r\n    \u00a0&lt;\/errors&gt;\r\n     &lt;alerts&gt;\r\n      &lt;success&gt;\r\n        Your changes have been submitted.\r\n      &lt;\/success&gt;\r\n     &lt;\/alerts&gt;\r\n  &lt;\/formValidator&gt;\r\n&lt;\/config&gt;\r\n--&gt;\r\n&lt;\/div&gt;<\/pre>\n<\/blockquote>\n<p>Note the object oriented &#8220;dot&#8221; notation of the configuration properties, which corresponds to the XML&#8217;s tree structure.  The usual convention I follow is:<\/p>\n<ol type=\"a\">\n<li>I code all configuration values that have to do with the same script using the same top level object (in this case, the top-level object\u00a0 is called <code>formValidator<\/code> since it is being accessed by a script called formValidator.js).<\/li>\n<li>I then create properties for that top level object that describe logical categories that I want to configure\u00a0 (e.g. templates, errors, urls,\u00a0 etc).<\/li>\n<li>I finally have the third level contain the actual configuration values.<\/li>\n<\/ol>\n<p>While I consider this best practice (insomuch as it works well for me), developers are of course not stuck with this convention, and can format their XML as they please, as long as there are no duplicate property names within an object.<\/p>\n<h2>HTML Values<\/h2>\n<p>Note that a developer can insert HTML inside the XML string by placing the HTML content inside a <code>CDATA<\/code> node:<\/p>\n<blockquote class=\"code\">\n<pre>&lt;config&gt;\r\n  &lt;formValidator&gt;\r\n    &lt;templates&gt;\r\n      &lt;hasError&gt;&lt;![CDATA[\r\n        &lt;div id=\"errorMessage\"&gt;\r\n        &lt;p&gt;There are errors with the information you are trying\r\n        to submit.\u00a0 Please check the form below, correct the\r\n        errors and resubmit.&lt;\/p&gt;\r\n        &lt;\/div&gt;\r\n      ]]&gt;&lt;\/hasError&gt;\r\n      &lt;submissionAlert&gt;\r\n        If this was a real form, the information above would\r\n        have been submitted.\u00a0 Since this isn't, we won't submit\r\n        any of the form information.\r\n      &lt;\/submissionAlert&gt;\r\n    &lt;\/templates&gt;\r\n    &lt;errors&gt;\r\n      &lt;mandatoryField&gt;\r\n        The above field is mandatory\r\n      &lt;\/mandatoryField&gt;\r\n    &lt;\/errors&gt;\r\n  &lt;\/formValidator&gt;\r\n&lt;\/config&gt;<\/pre>\n<\/blockquote>\n<p><strong>Note that the CDATA node has to <em>immediately<\/em> follow the containing tag<\/strong> (in the above example, you&#8217;ll see there are no spaces hasError tag).  This restriction will probably be relaxed in a subsequent release.<\/p>\n<h2>Removing Extraneous Spaces<\/h2>\n<p>Let&#8217;s look at this example:<\/p>\n<blockquote class=\"code\">\n<pre>&lt;config&gt;\r\n  &lt;formValidator&gt;\r\n    &lt;templates&gt;\r\n      &lt;submissionAlert&gt;\r\n      If this was a real form, the information above would\r\n      have been submitted.\u00a0 Since this isn't, we won't submit\r\n      any of the form information.\r\n      &lt;\/submissionAlert&gt;\r\n    &lt;\/templates&gt;\r\n  &lt;\/formValidator&gt;\r\n&lt;\/config&gt;<\/pre>\n<\/blockquote>\n<p>If we tried to execute <code>window.alert(\"formValidator.templates.submissionError\")<\/code>, we would get an alert box that would look something like this:<\/p>\n<p><div id=\"attachment_289\" style=\"width: 572px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-289\" class=\"size-full wp-image-289\" title=\"alertWithBadSpacing\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2009\/10\/alertWithBadSpacing.png\" alt=\"This alert has bad spacing due to the way the XML is formatted.\" width=\"562\" height=\"130\" srcset=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2009\/10\/alertWithBadSpacing.png 562w, https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2009\/10\/alertWithBadSpacing-299x69.png 299w\" sizes=\"auto, (max-width: 562px) 100vw, 562px\" \/><p id=\"caption-attachment-289\" class=\"wp-caption-text\">This alert has bad spacing due to the way the XML is formatted.<\/p><\/div><\/p>\n<p>Doesn&#8217;t that look ugly?\u00a0 This is because the formatting of the text inside it&#8217;s configuration block is indented so that it is readable to the developer when viewing the code (Note that all carriage returns are ignored by config.js, but the spaces are left intact). In order to keep the pretty XML formatting while getting rid of the extra spacing inside the alert box, we can set the <code>removeMultispaces<\/code> attribute of it&#8217;s configuration tag to <code>\"true\"<\/code>:<\/p>\n<blockquote class=\"code\">\n<pre>&lt;config&gt;\r\n  &lt;formValidator&gt;\r\n    &lt;templates&gt;\r\n      &lt;submissionAlert <span class=\"hilite\">removeMultispaces=\"true\"<\/span>&gt;\r\n      If this was a real form, the information above would\r\n      have been submitted.\u00a0 Since this isn't, we won't submit\r\n      any of the form information.\r\n      &lt;\/submissionAlert&gt;\r\n    &lt;\/templates&gt;\r\n  &lt;\/formValidator&gt;\r\n&lt;\/config&gt;<\/pre>\n<\/blockquote>\n<p>This results in an alert box that is formatted as intended:<\/p>\n<p><div id=\"attachment_292\" style=\"width: 572px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-292\" class=\"size-full wp-image-292\" title=\"alertWithGoodSpacing\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2009\/10\/alertWithGoodSpacing.png\" alt=\"All the extraneous spacing has been removed, regardless of where it appears in the XML.\" width=\"562\" height=\"119\" srcset=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2009\/10\/alertWithGoodSpacing.png 562w, https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2009\/10\/alertWithGoodSpacing-299x63.png 299w\" sizes=\"auto, (max-width: 562px) 100vw, 562px\" \/><p id=\"caption-attachment-292\" class=\"wp-caption-text\">All the extraneous spacing has been removed, regardless of where it appears in the XML.<\/p><\/div><\/p>\n<h2>Dynamic Content:<\/h2>\n<p>Injecting variables into the contents of the configuration value can be achieved by using <code>config.getScriptedValue()<\/code>.\u00a0\u00a0 To do so, you first insert the variables into your XML using placeholders surrounded by @-symbols, which we&#8217;ll call <strong>&#8220;at values&#8221;<\/strong>:<\/p>\n<blockquote class=\"code\">\n<pre>&lt;config&gt;\r\n  &lt;formValidator&gt;\r\n\r\n    &lt;submissionAlert&gt;\r\n    If this was a real form, the information above would\r\n    have been submitted.\u00a0 Since this isn't, we won't submit\r\n    any of the form information, including the <span class=\"hilite\">@ccType@<\/span> Credit Card number\r\n    <span class=\"hilite\">@ccNum@<\/span>.\r\n    &lt;\/submissionAlert&gt;\r\n\r\n  &lt;\/formValidator&gt;\r\n&lt;\/config&gt;<\/pre>\n<\/blockquote>\n<p>In this example, <code>@ccType@<\/code> and <code>@ccExp@<\/code> are the at-values that will contain dynamic content. The following JavaScript creates an alert containing the configuration value of <code>formValidator.templates.submissionAlert<\/code>, complete with dynamic content.<\/p>\n<blockquote class=\"code\">\n<pre>var formToValidate = document.getElementById(\"formToValidate\");\r\nvar alertString = config.getScriptedValue(\r\n  \"formValidator.templates.submissionAlert\",\r\n  {\r\n    ccNum: formToValidate.ccNum.value,\r\n    ccType: formToValidate.ccType.value\r\n  });<\/pre>\n<\/blockquote>\n<p>This replaces the at-value placeholders <code>@ccNum@<\/code> and <code>@ccType@<\/code> with the values of the form fields <code>ccNum<\/code> and <code>ccType<\/code>, respectively.<\/p>\n<h2>External XML File<\/h2>\n<p>Instead of having the XML contained within an HTML comment, you can have the file loaded separately by defining the file name inside the config node like this:<\/p>\n<blockquote class=\"code\">\n<pre>&lt;!--\r\nxml=xml\/config.xml\r\n--&gt;\r\n&lt;\/div&gt;<\/pre>\n<\/blockquote>\n<h2>Comments<\/h2>\n<p>If the XML is embedded in an HTML comment, then comments to the embedded XML must be put inside the XML block using JSP style <code>&lt;%-- --%&gt;<\/code> comment notation:<\/p>\n<blockquote class=\"code\">\n<pre>&lt;config&gt;\r\n  &lt;formValidator&gt;\r\n<span class=\"hilite\">    &lt;%--\r\n    This section contains english text that will\r\n    be inserted into the page\r\n    --%&gt;<\/span>\r\n    &lt;templates&gt;\r\n    &lt;hasError&gt;&lt;![CDATA[\r\n      &lt;div id=\"errorMessage\"&gt;\r\n      &lt;p&gt;There are errors with the information you are trying\r\n      to submit.\u00a0 Please check the form below, correct the\r\n      errors and resubmit.&lt;\/p&gt;\r\n      &lt;\/div&gt;\r\n    ]]&gt;&lt;\/hasError&gt;\r\n    &lt;submissionAlert removeMultispaces=\"true\"&gt;\r\n      If this was a real form, the information above would\r\n      have been submitted.\u00a0 Since this isn't, we won't submit\r\n      any of the form information, including the @ccType@ Credit\r\n      Card number @ccNum@.\r\n    &lt;\/submissionAlert&gt;\r\n  &lt;\/templates&gt;\r\n&lt;\/formValidator&gt;\r\n&lt;\/config&gt;<\/pre>\n<\/blockquote>\n<p>If the configuration XML is stored in an external file, use regular XML<code>&lt;!-- --!&gt;<\/code> comment notation:<\/p>\n<blockquote class=\"code\">\n<pre>&lt;config&gt;\r\n  &lt;formValidator&gt;\r\n<span class=\"hilite\">    &lt;!--\r\n    This section contains english text that will\r\n    be inserted into the page\r\n    --!&gt;<\/span>\r\n    &lt;templates&gt;\r\n    &lt;hasError&gt;&lt;![CDATA[\r\n      &lt;div id=\"errorMessage\"&gt;\r\n      &lt;p&gt;There are errors with the information you are trying\r\n      to submit.  Please check the form below, correct the\r\n      errors and resubmit.&lt;\/p&gt;\r\n      &lt;\/div&gt;\r\n    ]]&gt;&lt;\/hasError&gt;\r\n    &lt;submissionAlert removeMultispaces=\"true\"&gt;\r\n      If this was a real form, the information above would\r\n      have been submitted.  Since this isn't, we won't submit\r\n      any of the form information, including the @ccType@ Credit\r\n      Card number @ccNum@.\r\n    &lt;\/submissionAlert&gt;\r\n  &lt;\/templates&gt;\r\n&lt;\/formValidator&gt;\r\n&lt;\/config&gt;<\/pre>\n<\/blockquote>\n<h2>Object Arrays<\/h2>\n<p>Developers can also define arrays inside configuration files as well, by using the <code>datatype<\/code> attribute inside a tag.\u00a0 In the following example, the configuration property <code>formValidator.creditCardForm.inputs<\/code> is an array containing three objects:<\/p>\n<blockquote class=\"code\">\n<pre>&lt;config&gt;\r\n  &lt;formValidator&gt;\r\n    &lt;creditCardForm&gt;\r\n<span class=\"hilite\">      &lt;inputs datatype=\"array\"&gt;\r\n\r\n       &lt;ccType&gt;\r\n        &lt;postalCode&gt;\r\n          &lt;isMandatory&gt;true&lt;\/isMandatory&gt;\r\n          &lt;%-- Note: We assume Canadian postal codes only - -%&gt;\r\n          &lt;pattern&gt;\r\n            ^[a-zA-Z]\\d[a-zA-Z]\\s*\\d[a-zA-Z]\\d$\r\n          &lt;\/pattern&gt;\r\n          &lt;unmatchError&gt;\r\n            The postal code must be in a valid format.\r\n          &lt;\/unmatchError&gt;\r\n        &lt;\/postalCode&gt;\r\n      &lt;\/ccType&gt;\r\n\r\n      &lt;ccNum&gt;\r\n        &lt;isMandatory&gt;true&lt;\/isMandatory&gt;\r\n        &lt;pattern&gt;^\\d{16}$&lt;\/pattern&gt;\r\n        &lt;unmatchError&gt;\r\n          The credit card you entered is not valid.\r\n        &lt;\/unmatchError&gt;\r\n      &lt;\/ccNum&gt;\r\n\r\n      &lt;ccExp&gt;\r\n        &lt;isMandatory&gt;true&lt;\/isMandatory&gt;\r\n        &lt;pattern&gt;^(0[1-9]|1[1-2])\/\\d{2}$&lt;\/pattern&gt;\r\n        &lt;unmatchError&gt;\r\n          The expiry date must be in the form yy\/mm.\r\n        &lt;\/unmatchError&gt;\r\n      &lt;\/ccExp&gt;\r\n\r\n    &lt;\/inputs&gt;<\/span>\r\n  &lt;\/creditCardForm&gt;\r\n&lt;\/formValidator&gt;\r\n&lt;\/config&gt;<\/pre>\n<\/blockquote>\n<p>Each of these elements have three properties (<code>isMandatory<\/code>, <code>pattern<\/code> and <code>unmatchError<\/code>).\u00a0 Note that each element in the array don&#8217;t have to have the same properties, in the same way that a the elements in a JavaScript array doesn&#8217;t have the same type of object.\u00a0 In the above example, we can\u00a0 access these array values with the following script:<\/p>\n<blockquote class=\"code\">\n<pre>var inputs = config.getValue(\"formValidator.creditCardForm.inputs\");\r\nvar ccExp = inputs[\"ccExp\"]\r\nvar ccExpError = ccExp.unmatchError;<\/pre>\n<\/blockquote>\n<div id=\"_mcePaste\" style=\"overflow: hidden; position: absolute; left: -10000px; top: 570px; width: 1px; height: 1px;\">\n<pre>&lt;mandatoryField&gt;\r\n        The above field is mandatory\r\n      &lt;\/mandatoryField&gt;<\/pre>\n<\/div>\n<h2>Examples<\/h2>\n<ul>\n<li>A very simple example can be found on my blog post <a href=\"\/blog\/?p=71\">Configuring JavaScript Applications<\/a>.<\/li>\n<li><a href=\"\/tests\/config\/creditCardForm.html\">A more complicated example<\/a> showing how to do simple client-side form validation with regular expressions.\u00a0 It uses code that is contained in this manual page.<\/li>\n<li>The same example as shown above <a href=\"\/tests\/config\/creditCardFormOutsideConfig.html\">using an external configuration file<\/a> (i.e. not embedded in the HTML page.<\/li>\n<\/ul>\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<p>This code is released under the <a href=\"http:\/\/www.opensource.org\/licenses\/mit-license.php\">MIT License<\/a>.  Although the license doesn&#8217;t compel you to do so, I would be happy to hear how this library is being used.  I would also like to see how people have improved or added to the code so I can share the changes with others.  Again, this is not something the license compels you to do &#8211; just consider it a courtesy.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Description Config.js allows developers to configure their applications in an XML block instead of hard-coding values inside their scripts or in JSON objects.\u00a0 The XML can be embedded inside an HTML document or in a separate XML file.\u00a0 The configuration block may contain strings, numbers, arrays and HTML.\u00a0 Furthermore, variables can be inserted into these [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"open","ping_status":"open","template":"","meta":{"footnotes":""},"class_list":["post-264","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/pages\/264","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/comments?post=264"}],"version-history":[{"count":33,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/pages\/264\/revisions"}],"predecessor-version":[{"id":272,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/pages\/264\/revisions\/272"}],"wp:attachment":[{"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/media?parent=264"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}