Keine Beschreibung

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /*
  2. Module dependencies
  3. */
  4. var ElementType = require('domelementtype');
  5. var entities = require('entities');
  6. /*
  7. Boolean Attributes
  8. */
  9. var booleanAttributes = {
  10. __proto__: null,
  11. allowfullscreen: true,
  12. async: true,
  13. autofocus: true,
  14. autoplay: true,
  15. checked: true,
  16. controls: true,
  17. default: true,
  18. defer: true,
  19. disabled: true,
  20. hidden: true,
  21. ismap: true,
  22. loop: true,
  23. multiple: true,
  24. muted: true,
  25. open: true,
  26. readonly: true,
  27. required: true,
  28. reversed: true,
  29. scoped: true,
  30. seamless: true,
  31. selected: true,
  32. typemustmatch: true
  33. };
  34. var unencodedElements = {
  35. __proto__: null,
  36. style: true,
  37. script: true,
  38. xmp: true,
  39. iframe: true,
  40. noembed: true,
  41. noframes: true,
  42. plaintext: true,
  43. noscript: true
  44. };
  45. /*
  46. Format attributes
  47. */
  48. function formatAttrs(attributes, opts) {
  49. if (!attributes) return;
  50. var output = '',
  51. value;
  52. // Loop through the attributes
  53. for (var key in attributes) {
  54. value = attributes[key];
  55. if (output) {
  56. output += ' ';
  57. }
  58. if (!value && booleanAttributes[key]) {
  59. output += key;
  60. } else {
  61. output += key + '="' + (opts.decodeEntities ? entities.encodeXML(value) : value) + '"';
  62. }
  63. }
  64. return output;
  65. }
  66. /*
  67. Self-enclosing tags (stolen from node-htmlparser)
  68. */
  69. var singleTag = {
  70. __proto__: null,
  71. area: true,
  72. base: true,
  73. basefont: true,
  74. br: true,
  75. col: true,
  76. command: true,
  77. embed: true,
  78. frame: true,
  79. hr: true,
  80. img: true,
  81. input: true,
  82. isindex: true,
  83. keygen: true,
  84. link: true,
  85. meta: true,
  86. param: true,
  87. source: true,
  88. track: true,
  89. wbr: true,
  90. };
  91. var render = module.exports = function(dom, opts) {
  92. if (!Array.isArray(dom) && !dom.cheerio) dom = [dom];
  93. opts = opts || {};
  94. var output = '';
  95. for(var i = 0; i < dom.length; i++){
  96. var elem = dom[i];
  97. if (elem.type === 'root')
  98. output += render(elem.children, opts);
  99. else if (ElementType.isTag(elem))
  100. output += renderTag(elem, opts);
  101. else if (elem.type === ElementType.Directive)
  102. output += renderDirective(elem);
  103. else if (elem.type === ElementType.Comment)
  104. output += renderComment(elem);
  105. else if (elem.type === ElementType.CDATA)
  106. output += renderCdata(elem);
  107. else
  108. output += renderText(elem, opts);
  109. }
  110. return output;
  111. };
  112. function renderTag(elem, opts) {
  113. // Handle SVG
  114. if (elem.name === "svg") opts = {decodeEntities: opts.decodeEntities, xmlMode: true};
  115. var tag = '<' + elem.name,
  116. attribs = formatAttrs(elem.attribs, opts);
  117. if (attribs) {
  118. tag += ' ' + attribs;
  119. }
  120. if (
  121. opts.xmlMode
  122. && (!elem.children || elem.children.length === 0)
  123. ) {
  124. tag += '/>';
  125. } else {
  126. tag += '>';
  127. if (elem.children) {
  128. tag += render(elem.children, opts);
  129. }
  130. if (!singleTag[elem.name] || opts.xmlMode) {
  131. tag += '</' + elem.name + '>';
  132. }
  133. }
  134. return tag;
  135. }
  136. function renderDirective(elem) {
  137. return '<' + elem.data + '>';
  138. }
  139. function renderText(elem, opts) {
  140. var data = elem.data || '';
  141. // if entities weren't decoded, no need to encode them back
  142. if (opts.decodeEntities && !(elem.parent && elem.parent.name in unencodedElements)) {
  143. data = entities.encodeXML(data);
  144. }
  145. return data;
  146. }
  147. function renderCdata(elem) {
  148. return '<![CDATA[' + elem.children[0].data + ']]>';
  149. }
  150. function renderComment(elem) {
  151. return '<!--' + elem.data + '-->';
  152. }