marker.js 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  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", config);
  80. }
  81. }
  82. this.element = dom.setInnerHtml(this.element, html.join(""));
  83. };
  84. this.$getTop = function(row, layerConfig) {
  85. return (row - layerConfig.firstRowScreen) * layerConfig.lineHeight;
  86. };
  87. // Draws a marker, which spans a range of text on multiple lines
  88. this.drawTextMarker = function(stringBuilder, range, clazz, layerConfig, extraStyle) {
  89. // selection start
  90. var row = range.start.row;
  91. var lineRange = new Range(
  92. row, range.start.column,
  93. row, this.session.getScreenLastRowColumn(row)
  94. );
  95. this.drawSingleLineMarker(stringBuilder, lineRange, clazz + " ace_start", layerConfig, 1, extraStyle);
  96. // selection end
  97. row = range.end.row;
  98. lineRange = new Range(row, 0, row, range.end.column);
  99. this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 0, extraStyle);
  100. for (row = range.start.row + 1; row < range.end.row; row++) {
  101. lineRange.start.row = row;
  102. lineRange.end.row = row;
  103. lineRange.end.column = this.session.getScreenLastRowColumn(row);
  104. this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 1, extraStyle);
  105. }
  106. };
  107. // Draws a multi line marker, where lines span the full width
  108. this.drawMultiLineMarker = function(stringBuilder, range, clazz, config, extraStyle) {
  109. // from selection start to the end of the line
  110. var padding = this.$padding;
  111. var height = config.lineHeight;
  112. var top = this.$getTop(range.start.row, config);
  113. var left = padding + range.start.column * config.characterWidth;
  114. extraStyle = extraStyle || "";
  115. stringBuilder.push(
  116. "<div class='", clazz, " ace_start' style='",
  117. "height:", height, "px;",
  118. "right:0;",
  119. "top:", top, "px;",
  120. "left:", left, "px;", extraStyle, "'></div>"
  121. );
  122. // from start of the last line to the selection end
  123. top = this.$getTop(range.end.row, config);
  124. var width = range.end.column * config.characterWidth;
  125. stringBuilder.push(
  126. "<div class='", clazz, "' style='",
  127. "height:", height, "px;",
  128. "width:", width, "px;",
  129. "top:", top, "px;",
  130. "left:", padding, "px;", extraStyle, "'></div>"
  131. );
  132. // all the complete lines
  133. height = (range.end.row - range.start.row - 1) * config.lineHeight;
  134. if (height < 0)
  135. return;
  136. top = this.$getTop(range.start.row + 1, config);
  137. stringBuilder.push(
  138. "<div class='", clazz, "' style='",
  139. "height:", height, "px;",
  140. "right:0;",
  141. "top:", top, "px;",
  142. "left:", padding, "px;", extraStyle, "'></div>"
  143. );
  144. };
  145. // Draws a marker which covers part or whole width of a single screen line
  146. this.drawSingleLineMarker = function(stringBuilder, range, clazz, config, extraLength, extraStyle) {
  147. var height = config.lineHeight;
  148. var width = (range.end.column + (extraLength || 0) - range.start.column) * config.characterWidth;
  149. var top = this.$getTop(range.start.row, config);
  150. var left = this.$padding + range.start.column * config.characterWidth;
  151. stringBuilder.push(
  152. "<div class='", clazz, "' style='",
  153. "height:", height, "px;",
  154. "width:", width, "px;",
  155. "top:", top, "px;",
  156. "left:", left, "px;", extraStyle || "", "'></div>"
  157. );
  158. };
  159. this.drawFullLineMarker = function(stringBuilder, range, clazz, config, extraStyle) {
  160. var top = this.$getTop(range.start.row, config);
  161. var height = config.lineHeight;
  162. if (range.start.row != range.end.row)
  163. height += this.$getTop(range.end.row, config) - top;
  164. stringBuilder.push(
  165. "<div class='", clazz, "' style='",
  166. "height:", height, "px;",
  167. "top:", top, "px;",
  168. "left:0;right:0;", extraStyle || "", "'></div>"
  169. );
  170. };
  171. this.drawScreenLineMarker = function(stringBuilder, range, clazz, config, extraStyle) {
  172. var top = this.$getTop(range.start.row, config);
  173. var height = config.lineHeight;
  174. stringBuilder.push(
  175. "<div class='", clazz, "' style='",
  176. "height:", height, "px;",
  177. "top:", top, "px;",
  178. "left:0;right:0;", extraStyle || "", "'></div>"
  179. );
  180. };
  181. }).call(Marker.prototype);
  182. exports.Marker = Marker;
  183. });