static_highlight.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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 highlight = function(el, opts, callback) {
  38. var m = el.className.match(/lang-(\w+)/);
  39. var mode = opts.mode || m && ("ace/mode/" + m[1]);
  40. if (!mode)
  41. return false;
  42. var theme = opts.theme || "ace/theme/textmate";
  43. var data = "";
  44. var nodes = [];
  45. if (el.firstElementChild) {
  46. var textLen = 0;
  47. for (var i = 0; i < el.childNodes.length; i++) {
  48. var ch = el.childNodes[i];
  49. if (ch.nodeType == 3) {
  50. textLen += ch.data.length;
  51. data += ch.data;
  52. } else {
  53. nodes.push(textLen, ch);
  54. }
  55. }
  56. } else {
  57. data = dom.getInnerText(el);
  58. if (opts.trim)
  59. data = data.trim();
  60. }
  61. highlight.render(data, mode, theme, opts.firstLineNumber, !opts.showGutter, function (highlighted) {
  62. dom.importCssString(highlighted.css, "ace_highlight");
  63. el.innerHTML = highlighted.html;
  64. var container = el.firstChild.firstChild;
  65. for (var i = 0; i < nodes.length; i += 2) {
  66. var pos = highlighted.session.doc.indexToPosition(nodes[i]);
  67. var node = nodes[i + 1];
  68. var lineEl = container.children[pos.row];
  69. lineEl && lineEl.appendChild(node);
  70. }
  71. callback && callback();
  72. });
  73. };
  74. /**
  75. * Transforms a given input code snippet into HTML using the given mode
  76. *
  77. * @param {string} input Code snippet
  78. * @param {string|mode} mode String specifying the mode to load such as
  79. * `ace/mode/javascript` or, a mode loaded from `/ace/mode`
  80. * (use 'ServerSideHiglighter.getMode').
  81. * @param {string|theme} theme String specifying the theme to load such as
  82. * `ace/theme/twilight` or, a theme loaded from `/ace/theme`.
  83. * @param {number} lineStart A number indicating the first line number. Defaults
  84. * to 1.
  85. * @param {boolean} disableGutter Specifies whether or not to disable the gutter.
  86. * `true` disables the gutter, `false` enables the gutter. Defaults to `false`.
  87. * @param {function} callback When specifying the mode or theme as a string,
  88. * this method has no return value and you must specify a callback function. The
  89. * callback will receive the rendered object containing the properties `html`
  90. * and `css`.
  91. * @returns {object} An object containing the properties `html` and `css`.
  92. */
  93. highlight.render = function(input, mode, theme, lineStart, disableGutter, callback) {
  94. var waiting = 0;
  95. var modeCache = EditSession.prototype.$modes;
  96. // if either the theme or the mode were specified as objects
  97. // then we need to lazily load them.
  98. if (typeof theme == "string") {
  99. waiting++;
  100. config.loadModule(['theme', theme], function(m) {
  101. theme = m;
  102. --waiting || done();
  103. });
  104. }
  105. if (typeof mode == "string") {
  106. waiting++;
  107. config.loadModule(['mode', mode], function(m) {
  108. if (!modeCache[mode]) modeCache[mode] = new m.Mode();
  109. mode = modeCache[mode];
  110. --waiting || done();
  111. });
  112. }
  113. // loads or passes the specified mode module then calls renderer
  114. function done() {
  115. var result = highlight.renderSync(input, mode, theme, lineStart, disableGutter);
  116. return callback ? callback(result) : result;
  117. }
  118. return waiting || done();
  119. };
  120. /*
  121. * Transforms a given input code snippet into HTML using the given mode
  122. * @param {string} input Code snippet
  123. * @param {mode} mode Mode loaded from /ace/mode (use 'ServerSideHiglighter.getMode')
  124. * @param {string} r Code snippet
  125. * @returns {object} An object containing: html, css
  126. */
  127. highlight.renderSync = function(input, mode, theme, lineStart, disableGutter) {
  128. lineStart = parseInt(lineStart || 1, 10);
  129. var session = new EditSession("");
  130. session.setUseWorker(false);
  131. session.setMode(mode);
  132. var textLayer = new TextLayer(document.createElement("div"));
  133. textLayer.setSession(session);
  134. textLayer.config = {
  135. characterWidth: 10,
  136. lineHeight: 20
  137. };
  138. session.setValue(input);
  139. var stringBuilder = [];
  140. var length = session.getLength();
  141. for(var ix = 0; ix < length; ix++) {
  142. stringBuilder.push("<div class='ace_line'>");
  143. if (!disableGutter)
  144. stringBuilder.push("<span class='ace_gutter ace_gutter-cell' unselectable='on'>" + /*(ix + lineStart) + */ "</span>");
  145. textLayer.$renderLine(stringBuilder, ix, true, false);
  146. stringBuilder.push("\n</div>");
  147. }
  148. // let's prepare the whole html
  149. var html = "<div class='" + theme.cssClass + "'>" +
  150. "<div class='ace_static_highlight' style='counter-reset:ace_line " + (lineStart - 1) + "'>" +
  151. stringBuilder.join("") +
  152. "</div>" +
  153. "</div>";
  154. textLayer.destroy();
  155. return {
  156. css: baseStyles + theme.cssText,
  157. html: html,
  158. session: session
  159. };
  160. };
  161. module.exports = highlight;
  162. module.exports.highlight =highlight;
  163. });