static_highlight.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /* ***** BEGIN LICENSE BLOCK *****
  2. * Distributed under the BSD license:
  3. *
  4. * Copyright (c) 2010, Ajax.org B.V.
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are met:
  9. * * Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * * Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * * Neither the name of Ajax.org B.V. nor the
  15. * names of its contributors may be used to endorse or promote products
  16. * derived from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  19. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  27. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. *
  29. * ***** END LICENSE BLOCK ***** */
  30. define(function(require, exports, module) {
  31. "use strict";
  32. var EditSession = require("../edit_session").EditSession;
  33. var TextLayer = require("../layer/text").Text;
  34. var baseStyles = require("../requirejs/text!./static.css");
  35. var config = require("../config");
  36. var dom = require("../lib/dom");
  37. var SimpleTextLayer = function() {
  38. this.config = {};
  39. };
  40. SimpleTextLayer.prototype = TextLayer.prototype;
  41. var highlight = function(el, opts, callback) {
  42. var m = el.className.match(/lang-(\w+)/);
  43. var mode = opts.mode || m && ("ace/mode/" + m[1]);
  44. if (!mode)
  45. return false;
  46. var theme = opts.theme || "ace/theme/textmate";
  47. var data = "";
  48. var nodes = [];
  49. if (el.firstElementChild) {
  50. var textLen = 0;
  51. for (var i = 0; i < el.childNodes.length; i++) {
  52. var ch = el.childNodes[i];
  53. if (ch.nodeType == 3) {
  54. textLen += ch.data.length;
  55. data += ch.data;
  56. } else {
  57. nodes.push(textLen, ch);
  58. }
  59. }
  60. } else {
  61. data = dom.getInnerText(el);
  62. if (opts.trim)
  63. data = data.trim();
  64. }
  65. highlight.render(data, mode, theme, opts.firstLineNumber, !opts.showGutter, function (highlighted) {
  66. dom.importCssString(highlighted.css, "ace_highlight");
  67. el.innerHTML = highlighted.html;
  68. var container = el.firstChild.firstChild;
  69. for (var i = 0; i < nodes.length; i += 2) {
  70. var pos = highlighted.session.doc.indexToPosition(nodes[i]);
  71. var node = nodes[i + 1];
  72. var lineEl = container.children[pos.row];
  73. lineEl && lineEl.appendChild(node);
  74. }
  75. callback && callback();
  76. });
  77. };
  78. /**
  79. * Transforms a given input code snippet into HTML using the given mode
  80. *
  81. * @param {string} input Code snippet
  82. * @param {string|mode} mode String specifying the mode to load such as
  83. * `ace/mode/javascript` or, a mode loaded from `/ace/mode`
  84. * (use 'ServerSideHiglighter.getMode').
  85. * @param {string|theme} theme String specifying the theme to load such as
  86. * `ace/theme/twilight` or, a theme loaded from `/ace/theme`.
  87. * @param {number} lineStart A number indicating the first line number. Defaults
  88. * to 1.
  89. * @param {boolean} disableGutter Specifies whether or not to disable the gutter.
  90. * `true` disables the gutter, `false` enables the gutter. Defaults to `false`.
  91. * @param {function} callback When specifying the mode or theme as a string,
  92. * this method has no return value and you must specify a callback function. The
  93. * callback will receive the rendered object containing the properties `html`
  94. * and `css`.
  95. * @returns {object} An object containing the properties `html` and `css`.
  96. */
  97. highlight.render = function(input, mode, theme, lineStart, disableGutter, callback) {
  98. var waiting = 1;
  99. var modeCache = EditSession.prototype.$modes;
  100. // if either the theme or the mode were specified as objects
  101. // then we need to lazily load them.
  102. if (typeof theme == "string") {
  103. waiting++;
  104. config.loadModule(['theme', theme], function(m) {
  105. theme = m;
  106. --waiting || done();
  107. });
  108. }
  109. // allow setting mode options e.h {path: "ace/mode/php", inline:true}
  110. var modeOptions;
  111. if (mode && typeof mode === "object" && !mode.getTokenizer) {
  112. modeOptions = mode;
  113. mode = modeOptions.path;
  114. }
  115. if (typeof mode == "string") {
  116. waiting++;
  117. config.loadModule(['mode', mode], function(m) {
  118. if (!modeCache[mode] || modeOptions)
  119. modeCache[mode] = new m.Mode(modeOptions);
  120. mode = modeCache[mode];
  121. --waiting || done();
  122. });
  123. }
  124. // loads or passes the specified mode module then calls renderer
  125. function done() {
  126. var result = highlight.renderSync(input, mode, theme, lineStart, disableGutter);
  127. return callback ? callback(result) : result;
  128. }
  129. return --waiting || done();
  130. };
  131. /**
  132. * Transforms a given input code snippet into HTML using the given mode
  133. * @param {string} input Code snippet
  134. * @param {mode} mode Mode loaded from /ace/mode (use 'ServerSideHiglighter.getMode')
  135. * @param {string} r Code snippet
  136. * @returns {object} An object containing: html, css
  137. */
  138. highlight.renderSync = function(input, mode, theme, lineStart, disableGutter) {
  139. lineStart = parseInt(lineStart || 1, 10);
  140. var session = new EditSession("");
  141. session.setUseWorker(false);
  142. session.setMode(mode);
  143. var textLayer = new SimpleTextLayer();
  144. textLayer.setSession(session);
  145. session.setValue(input);
  146. var stringBuilder = [];
  147. var length = session.getLength();
  148. for(var ix = 0; ix < length; ix++) {
  149. stringBuilder.push("<div class='ace_line'>");
  150. if (!disableGutter)
  151. stringBuilder.push("<span class='ace_gutter ace_gutter-cell' unselectable='on'>" + /*(ix + lineStart) + */ "</span>");
  152. textLayer.$renderLine(stringBuilder, ix, true, false);
  153. stringBuilder.push("\n</div>");
  154. }
  155. // let's prepare the whole html
  156. var html = "<div class='" + theme.cssClass + "'>" +
  157. "<div class='ace_static_highlight" + (disableGutter ? "" : " ace_show_gutter") +
  158. "' style='counter-reset:ace_line " + (lineStart - 1) + "'>" +
  159. stringBuilder.join("") +
  160. "</div>" +
  161. "</div>";
  162. textLayer.destroy();
  163. return {
  164. css: baseStyles + theme.cssText,
  165. html: html,
  166. session: session
  167. };
  168. };
  169. module.exports = highlight;
  170. module.exports.highlight =highlight;
  171. });