marker.js 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  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 Range = require("../range").Range;
  33. var dom = require("../lib/dom");
  34. var Marker = function(parentEl) {
  35. this.element = dom.createElement("div");
  36. this.element.className = "ace_layer ace_marker-layer";
  37. parentEl.appendChild(this.element);
  38. };
  39. (function() {
  40. this.$padding = 0;
  41. this.setPadding = function(padding) {
  42. this.$padding = padding;
  43. };
  44. this.setSession = function(session) {
  45. this.session = session;
  46. };
  47. this.setMarkers = function(markers) {
  48. this.markers = markers;
  49. };
  50. this.update = function(config) {
  51. var config = config || this.config;
  52. if (!config)
  53. return;
  54. this.config = config;
  55. var html = [];
  56. for (var key in this.markers) {
  57. var marker = this.markers[key];
  58. if (!marker.range) {
  59. marker.update(html, this, this.session, config);
  60. continue;
  61. }
  62. var range = marker.range.clipRows(config.firstRow, config.lastRow);
  63. if (range.isEmpty()) continue;
  64. range = range.toScreenRange(this.session);
  65. if (marker.renderer) {
  66. var top = this.$getTop(range.start.row, config);
  67. var left = this.$padding + range.start.column * config.characterWidth;
  68. marker.renderer(html, range, left, top, config);
  69. } else if (marker.type == "fullLine") {
  70. this.drawFullLineMarker(html, range, marker.clazz, config);
  71. } else if (marker.type == "screenLine") {
  72. this.drawScreenLineMarker(html, range, marker.clazz, config);
  73. } else if (range.isMultiLine()) {
  74. if (marker.type == "text")
  75. this.drawTextMarker(html, range, marker.clazz, config);
  76. else
  77. this.drawMultiLineMarker(html, range, marker.clazz, config);
  78. } else {
  79. this.drawSingleLineMarker(html, range, marker.clazz + " ace_start" + " ace_br15", config);
  80. }
  81. }
  82. this.element.innerHTML = html.join("");
  83. };
  84. this.$getTop = function(row, layerConfig) {
  85. return (row - layerConfig.firstRowScreen) * layerConfig.lineHeight;
  86. };
  87. function getBorderClass(tl, tr, br, bl) {
  88. return (tl ? 1 : 0) | (tr ? 2 : 0) | (br ? 4 : 0) | (bl ? 8 : 0);
  89. }
  90. // Draws a marker, which spans a range of text on multiple lines
  91. this.drawTextMarker = function(stringBuilder, range, clazz, layerConfig, extraStyle) {
  92. var session = this.session;
  93. var start = range.start.row;
  94. var end = range.end.row;
  95. var row = start;
  96. var prev = 0;
  97. var curr = 0;
  98. var next = session.getScreenLastRowColumn(row);
  99. var lineRange = new Range(row, range.start.column, row, curr);
  100. for (; row <= end; row++) {
  101. lineRange.start.row = lineRange.end.row = row;
  102. lineRange.start.column = row == start ? range.start.column : session.getRowWrapIndent(row);
  103. lineRange.end.column = next;
  104. prev = curr;
  105. curr = next;
  106. next = row + 1 < end ? session.getScreenLastRowColumn(row + 1) : row == end ? 0 : range.end.column;
  107. this.drawSingleLineMarker(stringBuilder, lineRange,
  108. clazz + (row == start ? " ace_start" : "") + " ace_br"
  109. + getBorderClass(row == start || row == start + 1 && range.start.column, prev < curr, curr > next, row == end),
  110. layerConfig, row == end ? 0 : 1, extraStyle);
  111. }
  112. };
  113. // Draws a multi line marker, where lines span the full width
  114. this.drawMultiLineMarker = function(stringBuilder, range, clazz, config, extraStyle) {
  115. // from selection start to the end of the line
  116. var padding = this.$padding;
  117. var height = config.lineHeight;
  118. var top = this.$getTop(range.start.row, config);
  119. var left = padding + range.start.column * config.characterWidth;
  120. extraStyle = extraStyle || "";
  121. stringBuilder.push(
  122. "<div class='", clazz, " ace_br1 ace_start' style='",
  123. "height:", height, "px;",
  124. "right:0;",
  125. "top:", top, "px;",
  126. "left:", left, "px;", extraStyle, "'></div>"
  127. );
  128. // from start of the last line to the selection end
  129. top = this.$getTop(range.end.row, config);
  130. var width = range.end.column * config.characterWidth;
  131. stringBuilder.push(
  132. "<div class='", clazz, " ace_br12' style='",
  133. "height:", height, "px;",
  134. "width:", width, "px;",
  135. "top:", top, "px;",
  136. "left:", padding, "px;", extraStyle, "'></div>"
  137. );
  138. // all the complete lines
  139. height = (range.end.row - range.start.row - 1) * config.lineHeight;
  140. if (height <= 0)
  141. return;
  142. top = this.$getTop(range.start.row + 1, config);
  143. var radiusClass = (range.start.column ? 1 : 0) | (range.end.column ? 0 : 8);
  144. stringBuilder.push(
  145. "<div class='", clazz, (radiusClass ? " ace_br" + radiusClass : ""), "' style='",
  146. "height:", height, "px;",
  147. "right:0;",
  148. "top:", top, "px;",
  149. "left:", padding, "px;", extraStyle, "'></div>"
  150. );
  151. };
  152. // Draws a marker which covers part or whole width of a single screen line
  153. this.drawSingleLineMarker = function(stringBuilder, range, clazz, config, extraLength, extraStyle) {
  154. var height = config.lineHeight;
  155. var width = (range.end.column + (extraLength || 0) - range.start.column) * config.characterWidth;
  156. var top = this.$getTop(range.start.row, config);
  157. var left = this.$padding + range.start.column * config.characterWidth;
  158. stringBuilder.push(
  159. "<div class='", clazz, "' style='",
  160. "height:", height, "px;",
  161. "width:", width, "px;",
  162. "top:", top, "px;",
  163. "left:", left, "px;", extraStyle || "", "'></div>"
  164. );
  165. };
  166. this.drawFullLineMarker = function(stringBuilder, range, clazz, config, extraStyle) {
  167. var top = this.$getTop(range.start.row, config);
  168. var height = config.lineHeight;
  169. if (range.start.row != range.end.row)
  170. height += this.$getTop(range.end.row, config) - top;
  171. stringBuilder.push(
  172. "<div class='", clazz, "' style='",
  173. "height:", height, "px;",
  174. "top:", top, "px;",
  175. "left:0;right:0;", extraStyle || "", "'></div>"
  176. );
  177. };
  178. this.drawScreenLineMarker = function(stringBuilder, range, clazz, config, extraStyle) {
  179. var top = this.$getTop(range.start.row, config);
  180. var height = config.lineHeight;
  181. stringBuilder.push(
  182. "<div class='", clazz, "' style='",
  183. "height:", height, "px;",
  184. "top:", top, "px;",
  185. "left:0;right:0;", extraStyle || "", "'></div>"
  186. );
  187. };
  188. }).call(Marker.prototype);
  189. exports.Marker = Marker;
  190. });