PageRenderTime 57ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/web-app/js/dojo/1.7.2/dojox/html/format.js.uncompressed.js

https://github.com/cfxram/grails-dojo
JavaScript | 478 lines | 454 code | 2 blank | 22 comment | 0 complexity | b7eed773fe9198d418b0dba2e2f0e20a MD5 | raw file
  1. //>>built
  2. define("dojox/html/format", ["dojo/_base/kernel", "./entities", "dojo/_base/array", "dojo/_base/window", "dojo/_base/sniff"],
  3. function(lang, Entities, ArrayUtil, Window, has) {
  4. var dhf = lang.getObject("dojox.html.format",true);
  5. dhf.prettyPrint = function(html/*String*/, indentBy /*Integer?*/, maxLineLength /*Integer?*/, map/*Array?*/, /*boolean*/ xhtml){
  6. // summary:
  7. // Function for providing a 'pretty print' version of HTML content from
  8. // the provided string. It's nor perfect by any means, but it does
  9. // a 'reasonable job'.
  10. // html: String
  11. // The string of HTML to try and generate a 'pretty' formatting.
  12. // indentBy: Integer
  13. // Optional input for the number of spaces to use when indenting.
  14. // If not defined, zero, negative, or greater than 10, will just use tab
  15. // as the indent.
  16. // maxLineLength: Integer
  17. // Optional input for the number of characters a text line should use in
  18. // the document, including the indent if possible.
  19. // map: Array
  20. // Optional array of entity mapping characters to use when processing the
  21. // HTML Text content. By default it uses the default set used by the
  22. // dojox.html.entities.encode function.
  23. // xhtml: boolean
  24. // Optional parameter that declares that the returned HTML should try to be 'xhtml' compatible.
  25. // This means normally unclosed tags are terminated with /> instead of >. Example: <hr> -> <hr />
  26. var content = [];
  27. var indentDepth = 0;
  28. var closeTags = [];
  29. var iTxt = "\t";
  30. var textContent = "";
  31. var inlineStyle = [];
  32. var i;
  33. // Compile regexps once for this call.
  34. var rgxp_fixIEAttrs = /[=]([^"']+?)(\s|>)/g;
  35. var rgxp_styleMatch = /style=("[^"]*"|'[^']*'|\S*)/gi;
  36. var rgxp_attrsMatch = /[\w-]+=("[^"]*"|'[^']*'|\S*)/gi;
  37. // Check to see if we want to use spaces for indent instead
  38. // of tab.
  39. if(indentBy && indentBy > 0 && indentBy < 10){
  40. iTxt = "";
  41. for(i = 0; i < indentBy; i++){
  42. iTxt += " ";
  43. }
  44. }
  45. //Build the content outside of the editor so we can walk
  46. //via DOM and build a 'pretty' output.
  47. var contentDiv = Window.doc.createElement("div");
  48. contentDiv.innerHTML = html;
  49. // Use the entity encode/decode functions, they cache on the map,
  50. // so it won't multiprocess a map.
  51. var encode = Entities.encode;
  52. var decode = Entities.decode;
  53. /** Define a bunch of formatters to format the output. **/
  54. var isInlineFormat = function(tag){
  55. // summary:
  56. // Function to determine if the current tag is an inline
  57. // element that does formatting, as we don't want to
  58. // break/indent around it, as it can screw up text.
  59. // tag:
  60. // The tag to examine
  61. switch(tag){
  62. case "a":
  63. case "b":
  64. case "strong":
  65. case "s":
  66. case "strike":
  67. case "i":
  68. case "u":
  69. case "em":
  70. case "sup":
  71. case "sub":
  72. case "span":
  73. case "font":
  74. case "big":
  75. case "cite":
  76. case "q":
  77. case "small":
  78. return true;
  79. default:
  80. return false;
  81. }
  82. };
  83. //Create less divs.
  84. var div = contentDiv.ownerDocument.createElement("div");
  85. var outerHTML = function(node){
  86. // summary:
  87. // Function to return the outer HTML of a node.
  88. // Yes, IE has a function like this, but using cloneNode
  89. // allows avoiding looking at any child nodes, because in this
  90. // case, we don't want them.
  91. var clone = node.cloneNode(false);
  92. div.appendChild(clone);
  93. var html = div.innerHTML;
  94. div.innerHTML = "";
  95. return html;
  96. };
  97. var sizeIndent = function(){
  98. var i, txt = "";
  99. for(i = 0; i < indentDepth; i++){
  100. txt += iTxt;
  101. }
  102. return txt.length;
  103. }
  104. var indent = function(){
  105. // summary:
  106. // Function to handle indent depth.
  107. var i;
  108. for(i = 0; i < indentDepth; i++){
  109. content.push(iTxt);
  110. }
  111. };
  112. var newline = function(){
  113. // summary:
  114. // Function to handle newlining.
  115. content.push("\n");
  116. };
  117. var processTextNode = function(n){
  118. // summary:
  119. // Function to process the text content for doc
  120. // insertion
  121. // n:
  122. // The text node to process.
  123. textContent += encode(n.nodeValue, map);
  124. };
  125. var formatText = function(txt){
  126. // summary:
  127. // Function for processing the text content encountered up to a
  128. // point and inserting it into the formatted document output.
  129. // txt:
  130. // The text to format.
  131. var i;
  132. var _iTxt;
  133. // Clean up any indention organization since we're going to rework it
  134. // anyway.
  135. var _lines = txt.split("\n");
  136. for(i = 0; i < _lines.length; i++){
  137. _lines[i] = lang.trim(_lines[i]);
  138. }
  139. txt = _lines.join(" ");
  140. txt = lang.trim(txt);
  141. if(txt !== ""){
  142. var lines = [];
  143. if(maxLineLength && maxLineLength > 0){
  144. var indentSize = sizeIndent();
  145. var maxLine = maxLineLength;
  146. if(maxLineLength > indentSize){
  147. maxLine -= indentSize;
  148. }
  149. while(txt){
  150. if(txt.length > maxLineLength){
  151. for(i = maxLine; (i > 0 && txt.charAt(i) !== " "); i--){
  152. // Do nothing, we're just looking for a space to split at.
  153. }
  154. if(!i){
  155. // Couldn't find a split going back, so go forward.
  156. for(i = maxLine; (i < txt.length && txt.charAt(i) !== " "); i++){
  157. // Do nothing, we're just looking for a space to split at.
  158. }
  159. }
  160. var line = txt.substring(0, i);
  161. line = lang.trim(line);
  162. // Shift up the text string to the next chunk.
  163. txt = lang.trim(txt.substring((i == txt.length)?txt.length:i + 1, txt.length));
  164. if(line){
  165. _iTxt = "";
  166. for(i = 0; i < indentDepth; i++){
  167. _iTxt += iTxt;
  168. }
  169. line = _iTxt + line + "\n";
  170. }
  171. lines.push(line);
  172. }else{
  173. // Line is shorter than out desired length, so use it.
  174. // as/is
  175. _iTxt = "";
  176. for(i = 0; i < indentDepth; i++){
  177. _iTxt += iTxt;
  178. }
  179. txt = _iTxt + txt + "\n";
  180. lines.push(txt);
  181. txt = null;
  182. }
  183. }
  184. return lines.join("");
  185. }else{
  186. _iTxt = "";
  187. for(i = 0; i < indentDepth; i++){
  188. _iTxt += iTxt;
  189. }
  190. txt = _iTxt + txt + "\n";
  191. return txt;
  192. }
  193. }else{
  194. return "";
  195. }
  196. };
  197. var processScriptText = function(txt){
  198. // summary:
  199. // Function to clean up potential escapes in the script code.
  200. if(txt){
  201. txt = txt.replace(/&quot;/gi, "\"");
  202. txt = txt.replace(/&gt;/gi, ">");
  203. txt = txt.replace(/&lt;/gi, "<");
  204. txt = txt.replace(/&amp;/gi, "&");
  205. }
  206. return txt;
  207. };
  208. var formatScript = function(txt){
  209. // summary:
  210. // Function to rudimentary formatting of script text.
  211. // Not perfect, but it helps get some level of organization
  212. // in there.
  213. // txt:
  214. // The script text to try to format a bit.
  215. if(txt){
  216. txt = processScriptText(txt);
  217. var i, t, c, _iTxt;
  218. var indent = 0;
  219. var scriptLines = txt.split("\n");
  220. var newLines = [];
  221. for (i = 0; i < scriptLines.length; i++){
  222. var line = scriptLines[i];
  223. var hasNewlines = (line.indexOf("\n") > -1);
  224. line = lang.trim(line);
  225. if(line){
  226. var iLevel = indent;
  227. // Not all blank, so we need to process.
  228. for(c = 0; c < line.length; c++){
  229. var ch = line.charAt(c);
  230. if(ch === "{"){
  231. indent++;
  232. }else if(ch === "}"){
  233. indent--;
  234. // We want to back up a bit before the
  235. // line is written.
  236. iLevel = indent;
  237. }
  238. }
  239. _iTxt = "";
  240. for(t = 0; t < indentDepth + iLevel; t++){
  241. _iTxt += iTxt;
  242. }
  243. newLines.push(_iTxt + line + "\n");
  244. }else if(hasNewlines && i === 0){
  245. // Just insert a newline for blank lines as
  246. // long as it's not the first newline (we
  247. // already inserted that in the openTag handler)
  248. newLines.push("\n");
  249. }
  250. }
  251. // Okay, create the script text, hopefully reasonably
  252. // formatted.
  253. txt = newLines.join("");
  254. }
  255. return txt;
  256. };
  257. var openTag = function(node){
  258. // summary:
  259. // Function to open a new tag for writing content.
  260. var name = node.nodeName.toLowerCase();
  261. // Generate the outer node content (tag with attrs)
  262. var nText = lang.trim(outerHTML(node));
  263. var tag = nText.substring(0, nText.indexOf(">") + 1);
  264. // Also thanks to IE, we need to check for quotes around
  265. // attributes and insert if missing.
  266. tag = tag.replace(rgxp_fixIEAttrs,'="$1"$2');
  267. // And lastly, thanks IE for changing style casing and end
  268. // semi-colon and webkit adds spaces, so lets clean it up by
  269. // sorting, etc, while we're at it.
  270. tag = tag.replace(rgxp_styleMatch, function(match){
  271. var sL = match.substring(0,6);
  272. var style = match.substring(6, match.length);
  273. var closure = style.charAt(0);
  274. style = lang.trim(style.substring(1,style.length -1));
  275. style = style.split(";");
  276. var trimmedStyles = [];
  277. ArrayUtil.forEach(style, function(s){
  278. s = lang.trim(s);
  279. if(s){
  280. // Lower case the style name, leave the value alone. Mainly a fixup for IE.
  281. s = s.substring(0, s.indexOf(":")).toLowerCase() + s.substring(s.indexOf(":"), s.length);
  282. trimmedStyles.push(s);
  283. }
  284. });
  285. trimmedStyles = trimmedStyles.sort();
  286. // Reassemble and return the styles in sorted order.
  287. style = trimmedStyles.join("; ");
  288. var ts = lang.trim(style);
  289. if(!ts || ts === ";"){
  290. // Just remove any style attrs that are empty.
  291. return "";
  292. }else{
  293. style += ";";
  294. return sL + closure + style + closure;
  295. }
  296. });
  297. // Try and sort the attributes while we're at it.
  298. var attrs = [];
  299. tag = tag.replace(rgxp_attrsMatch, function(attr){
  300. attrs.push(lang.trim(attr));
  301. return "";
  302. });
  303. attrs = attrs.sort();
  304. // Reassemble the tag with sorted attributes!
  305. tag = "<" + name;
  306. if(attrs.length){
  307. tag += " " + attrs.join(" ");
  308. }
  309. // Determine closure status. If xhtml,
  310. // then close the tag properly as needed.
  311. if(nText.indexOf("</") != -1){
  312. closeTags.push(name);
  313. tag += ">";
  314. }else{
  315. if(xhtml){
  316. tag += " />";
  317. }else{
  318. tag += ">";
  319. }
  320. closeTags.push(false);
  321. }
  322. var inline = isInlineFormat(name);
  323. inlineStyle.push(inline);
  324. if(textContent && !inline){
  325. // Process any text content we have that occurred
  326. // before the open tag of a non-inline.
  327. content.push(formatText(textContent));
  328. textContent = "";
  329. }
  330. // Determine if this has a closing tag or not!
  331. if(!inline){
  332. indent();
  333. content.push(tag);
  334. newline();
  335. indentDepth++;
  336. }else{
  337. textContent += tag;
  338. }
  339. };
  340. var closeTag = function(){
  341. // summary:
  342. // Function to close out a tag if necessary.
  343. var inline = inlineStyle.pop();
  344. if(textContent && !inline){
  345. // Process any text content we have that occurred
  346. // before the close tag.
  347. content.push(formatText(textContent));
  348. textContent = "";
  349. }
  350. var ct = closeTags.pop();
  351. if(ct){
  352. ct = "</" + ct + ">";
  353. if(!inline){
  354. indentDepth--;
  355. indent();
  356. content.push(ct);
  357. newline();
  358. }else{
  359. textContent += ct;
  360. }
  361. }else{
  362. indentDepth--;
  363. }
  364. };
  365. var processCommentNode = function(n){
  366. // summary:
  367. // Function to handle processing a comment node.
  368. // n:
  369. // The comment node to process.
  370. //Make sure contents aren't double-encoded.
  371. var commentText = decode(n.nodeValue, map);
  372. indent();
  373. content.push("<!--");
  374. newline();
  375. indentDepth++;
  376. content.push(formatText(commentText));
  377. indentDepth--;
  378. indent();
  379. content.push("-->");
  380. newline();
  381. };
  382. var processNode = function(node) {
  383. // summary:
  384. // Entrypoint for processing all the text!
  385. var children = node.childNodes;
  386. if(children){
  387. var i;
  388. for(i = 0; i < children.length; i++){
  389. var n = children[i];
  390. if(n.nodeType === 1){
  391. var tg = lang.trim(n.tagName.toLowerCase());
  392. if(has("ie") && n.parentNode != node){
  393. // IE is broken. DOMs are supposed to be a tree.
  394. // But in the case of malformed HTML, IE generates a graph
  395. // meaning one node ends up with multiple references
  396. // (multiple parents). This is totally wrong and invalid, but
  397. // such is what it is. We have to keep track and check for
  398. // this because otherwise the source output HTML will have dups.
  399. continue;
  400. }
  401. if(tg && tg.charAt(0) === "/"){
  402. // IE oddity. Malformed HTML can put in odd tags like:
  403. // </ >, </span>. It treats a mismatched closure as a new
  404. // start tag. So, remove them.
  405. continue;
  406. }else{
  407. //Process non-dup, seemingly wellformed elements!
  408. openTag(n);
  409. if(tg === "script"){
  410. content.push(formatScript(n.innerHTML));
  411. }else if(tg === "pre"){
  412. var preTxt = n.innerHTML;
  413. if(has("mozilla")){
  414. //Mozilla screws this up, so fix it up.
  415. preTxt = preTxt.replace("<br>", "\n");
  416. preTxt = preTxt.replace("<pre>", "");
  417. preTxt = preTxt.replace("</pre>", "");
  418. }
  419. // Add ending newline, if needed.
  420. if(preTxt.charAt(preTxt.length - 1) !== "\n"){
  421. preTxt += "\n";
  422. }
  423. content.push(preTxt);
  424. }else{
  425. processNode(n);
  426. }
  427. closeTag();
  428. }
  429. }else if(n.nodeType === 3 || n.nodeType === 4){
  430. processTextNode(n);
  431. }else if(n.nodeType === 8){
  432. processCommentNode(n);
  433. }
  434. }
  435. }
  436. };
  437. //Okay, finally process the input string.
  438. processNode(contentDiv);
  439. if(textContent){
  440. // Insert any trailing text. See: #10854
  441. content.push(formatText(textContent));
  442. textContent = "";
  443. }
  444. return content.join(""); //String
  445. };
  446. return dhf;
  447. });