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