1 /**
  2  * @fileOverview Functional HTML tag writing.<br/>
  3  *
  4  * <p>This library allows you to write HTML in the form of nested function
  5  * calls.  By default, a function is predefined for each tag, with the function
  6  * name being in all caps.  A dictionary of HTML attributes can optionally be
  7  * passed as a first argument to a tag; other arguments become child tags.
  8  * Attribute names that conflict with JavaScript
  9  * keywords have been renamed; use "className" in place of "class" and
 10  * "htmlFor" in place of "for".</p>
 11  *
 12  * <p>Tag objects inherit from Array, so array methods can be used to
 13  * manipulate a tag's list of child tags.</p>
 14  *
 15  * @example
 16 print(P({id:"sec3"},"Tags are ",B(I("crazy"))," awesome."));
 17  */
 18 
 19 /**
 20  * Functional HTML tag writing.
 21  *
 22  * @class Functional HTML tag writing.
 23  */
 24 var tags = {};
 25 	
 26 var _neverSingletones = {
 27   'TEXTAREA': true,
 28   'SCRIPT': true,
 29   'DIV': true,
 30   'IFRAME': true,
 31   'UL': true
 32 };
 33 
 34 /**
 35  * Imports a specified list of tags. All HTML tags are automatically imported
 36  * by default, but you may wish to use the tag library to write other kinds
 37  * of mark-up.  For each tag you want to import, pass in the name (including
 38  * any punctuation) with the (upper/lower) case you want to use for the function
 39  * (traditionally all uppercase).  The function name will have punctuation
 40  * replaced with underscores, and the printed tag will be all lowercase.
 41  *
 42  * @param {object} scopeObj where to define the tags; to define in the global scope, pass <code>this</code> from the top level (not from inside a function)
 43  * @param {array} tagArray an array of strings, the tags to import
 44 *  @function
 45  * @example
 46 importTags(this, ["MEDIA:TITLE"]);
 47 print(MEDIA_TITLE({type:"html"}, "funny pictures"));
 48 // prints <media:title type="html">funny pictures</media:title>
 49  */
 50 tags.importTags = function(scopeObj, tagArray) {
 51   tagArray.forEach(function(arg) {
 52       var funcName = arg.replace(/:/g, "_").replace(/-/g, "_");
 53       var tagName = arg.toLowerCase();
 54       scopeObj[funcName] = function() {
 55 	var tag = [];
 56 	tag.name = tagName;
 57 	var contents = Array.prototype.slice.call(arguments);
 58 	if (contents.length > 0) {
 59 	  if (contents[0] &&
 60 	      (! contents[0].toHTML) &&
 61 	      ((typeof contents[0]) == "object") &&
 62 	      (! Array.prototype.isPrototypeOf(contents[0])) &&
 63 	      (! Date.prototype.isPrototypeOf(contents[0]))) {
 64 	    // first arg is attributes
 65 	    tag.attribs = contents[0];
 66 	    contents.shift();
 67 	  }
 68 	  else {
 69 	    tag.attribs = {};
 70 	  }
 71 	  contents.forEach(function (content) {
 72 	      tag.push(content);
 73 	    });
 74 	}
 75 	else {
 76 	  tag.attribs = {};
 77 	}
 78 	tag.toString = function() { return this.toHTML(); } // this behavior is relied on
 79 	tag.toHTML = function() {
 80 	  var t = this;
 81 	  var result = [];
 82 	  result.add = function(x) { this.push(x); return this; }
 83 	  result.add('<').add(t.name);
 84 	  if (t.attribs) {
 85 	    eachProperty(t.attribs, function(k,v) {
 86 	      if (k == "className") k = "class";
 87 	      if (k == "htmlFor") k = "for";
 88 	      // escape quotes and newlines in values
 89 	      v = String(v).replace(/\"/g, '\\"').replace(/\n/g, '\\n');
 90 	      result.add(' ').add(k).add('="').add(v).add('"');
 91 	    });
 92 	  }
 93 	  if ((t.length < 1) && (!(t.name.toUpperCase() in _neverSingletones))) {
 94 	    result.add(' />');
 95 	  }
 96 	  else {
 97 	    result.add('>');
 98 	    t.forEach(function (x) {
 99 		result.add(toHTML(x));
100 	      });
101 	    result.add('</').add(t.name).add('\n>');
102 	  }
103 	  return result.join("");
104 	};
105 	return tag;
106       };
107     });
108 }
109 
110 var _html_tags =
111   ["A", "ABBR", "ACRONYM", "ADDRESS", "APPLET", "AREA", "B",
112    "BASE", "BASEFONT", "BDO", "BIG", "BLOCKQUOTE", "BODY",
113    "BR", "BUTTON", "CAPTION", "CENTER", "CITE", "CODE", "COL",
114    "COLGROUP", "DD", "DEL", "DIR", "DIV", "DFN", "DL", "DT",
115    "EM", "FIELDSET", "FONT", "FORM", "FRAME", "FRAMESET",
116    "H1", "H2", "H3", "H4", "H5", "H6",
117    "HEAD", "HR", "HTML", "I", "IFRAME", "IMG", "INPUT",
118    "INS", "ISINDEX", "KBD", "LABEL", "LEGEND", "LI", "LINK",
119    "MAP", "MENU", "META", "NOFRAMES", "NOSCRIPT", "OBJECT",
120    "OL", "OPTGROUP", "OPTION", "P", "PARAM", "PRE", "Q", "S",
121    "SAMP", "SCRIPT", "SELECT", "SMALL", "SPAN", "STRIKE",
122    "STRONG", "STYLE", "SUB", "SUP", "TABLE", "TBODY", "TD",
123    "TEXTAREA", "TFOOT", "TH", "THEAD", "TITLE", "TR", "TT",
124    "U", "UL", "VAR", "XMP"];
125 
126 importTags(this, _html_tags);
127 
128