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