PageRenderTime 80ms CodeModel.GetById 33ms RepoModel.GetById 1ms app.codeStats 3ms

/browser/devtools/sourceeditor/orion/orion.js

https://bitbucket.org/soko/mozilla-central
JavaScript | 12303 lines | 9235 code | 215 blank | 2853 comment | 2250 complexity | e11ef20919979de346cbfa2ab72118a6 MD5 | raw file
Possible License(s): GPL-2.0, JSON, 0BSD, LGPL-3.0, AGPL-1.0, MIT, MPL-2.0-no-copyleft-exception, BSD-3-Clause, LGPL-2.1, Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. /*******************************************************************************
  2. * @license
  3. * Copyright (c) 2010, 2011 IBM Corporation and others.
  4. * All rights reserved. This program and the accompanying materials are made
  5. * available under the terms of the Eclipse Public License v1.0
  6. * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
  7. * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
  8. *
  9. * Contributors:
  10. * Felipe Heidrich (IBM Corporation) - initial API and implementation
  11. * Silenio Quarti (IBM Corporation) - initial API and implementation
  12. * Mihai Sucan (Mozilla Foundation) - fix for Bug#364214
  13. */
  14. /*global window */
  15. /**
  16. * Evaluates the definition function and mixes in the returned module with
  17. * the module specified by <code>moduleName</code>.
  18. * <p>
  19. * This function is intented to by used when RequireJS is not available.
  20. * </p>
  21. *
  22. * @param {String} name The mixin module name.
  23. * @param {String[]} deps The array of dependency names.
  24. * @param {Function} callback The definition function.
  25. */
  26. if (!window.define) {
  27. window.define = function(name, deps, callback) {
  28. var module = this;
  29. var split = (name || "").split("/"), i, j;
  30. for (i = 0; i < split.length - 1; i++) {
  31. module = module[split[i]] = (module[split[i]] || {});
  32. }
  33. var depModules = [], depModule;
  34. for (j = 0; j < deps.length; j++) {
  35. depModule = this;
  36. split = deps[j].split("/");
  37. for (i = 0; i < split.length - 1; i++) {
  38. depModule = depModule[split[i]] = (depModule[split[i]] || {});
  39. }
  40. depModules.push(depModule);
  41. }
  42. var newModule = callback.apply(this, depModules);
  43. for (var p in newModule) {
  44. if (newModule.hasOwnProperty(p)) {
  45. module[p] = newModule[p];
  46. }
  47. }
  48. };
  49. }
  50. /**
  51. * Require/get the defined modules.
  52. * <p>
  53. * This function is intented to by used when RequireJS is not available.
  54. * </p>
  55. *
  56. * @param {String[]|String} deps The array of dependency names. This can also be
  57. * a string, a single dependency name.
  58. * @param {Function} [callback] Optional, the callback function to execute when
  59. * multiple dependencies are required. The callback arguments will have
  60. * references to each module in the same order as the deps array.
  61. * @returns {Object|undefined} If the deps parameter is a string, then this
  62. * function returns the required module definition, otherwise undefined is
  63. * returned.
  64. */
  65. if (!window.require) {
  66. window.require = function(deps, callback) {
  67. var depsArr = typeof deps === "string" ? [deps] : deps;
  68. var depModules = [], depModule, split, i, j;
  69. for (j = 0; j < depsArr.length; j++) {
  70. depModule = this;
  71. split = depsArr[j].split("/");
  72. for (i = 0; i < split.length - 1; i++) {
  73. depModule = depModule[split[i]] = (depModule[split[i]] || {});
  74. }
  75. depModules.push(depModule);
  76. }
  77. if (callback) {
  78. callback.apply(this, depModules);
  79. }
  80. return typeof deps === "string" ? depModules[0] : undefined;
  81. };
  82. }/*******************************************************************************
  83. * Copyright (c) 2010, 2011 IBM Corporation and others.
  84. * All rights reserved. This program and the accompanying materials are made
  85. * available under the terms of the Eclipse Public License v1.0
  86. * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
  87. * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
  88. *
  89. * Contributors:
  90. * Felipe Heidrich (IBM Corporation) - initial API and implementation
  91. * Silenio Quarti (IBM Corporation) - initial API and implementation
  92. ******************************************************************************/
  93. /*global define */
  94. define("orion/textview/eventTarget", [], function() {
  95. /**
  96. * Constructs a new EventTarget object.
  97. *
  98. * @class
  99. * @name orion.textview.EventTarget
  100. */
  101. function EventTarget() {
  102. }
  103. /**
  104. * Adds in the event target interface into the specified object.
  105. *
  106. * @param {Object} object The object to add in the event target interface.
  107. */
  108. EventTarget.addMixin = function(object) {
  109. var proto = EventTarget.prototype;
  110. for (var p in proto) {
  111. if (proto.hasOwnProperty(p)) {
  112. object[p] = proto[p];
  113. }
  114. }
  115. };
  116. EventTarget.prototype = /** @lends orion.textview.EventTarget.prototype */ {
  117. /**
  118. * Adds an event listener to this event target.
  119. *
  120. * @param {String} type The event type.
  121. * @param {Function|EventListener} listener The function or the EventListener that will be executed when the event happens.
  122. * @param {Boolean} [useCapture=false] <code>true</code> if the listener should be trigged in the capture phase.
  123. *
  124. * @see #removeEventListener
  125. */
  126. addEventListener: function(type, listener, useCapture) {
  127. if (!this._eventTypes) { this._eventTypes = {}; }
  128. var state = this._eventTypes[type];
  129. if (!state) {
  130. state = this._eventTypes[type] = {level: 0, listeners: []};
  131. }
  132. var listeners = state.listeners;
  133. listeners.push({listener: listener, useCapture: useCapture});
  134. },
  135. /**
  136. * Dispatches the given event to the listeners added to this event target.
  137. * @param {Event} evt The event to dispatch.
  138. */
  139. dispatchEvent: function(evt) {
  140. if (!this._eventTypes) { return; }
  141. var type = evt.type;
  142. var state = this._eventTypes[type];
  143. if (state) {
  144. var listeners = state.listeners;
  145. try {
  146. state.level++;
  147. if (listeners) {
  148. for (var i=0, len=listeners.length; i < len; i++) {
  149. if (listeners[i]) {
  150. var l = listeners[i].listener;
  151. if (typeof l === "function") {
  152. l.call(this, evt);
  153. } else if (l.handleEvent && typeof l.handleEvent === "function") {
  154. l.handleEvent(evt);
  155. }
  156. }
  157. }
  158. }
  159. } finally {
  160. state.level--;
  161. if (state.compact && state.level === 0) {
  162. for (var j=listeners.length - 1; j >= 0; j--) {
  163. if (!listeners[j]) {
  164. listeners.splice(j, 1);
  165. }
  166. }
  167. if (listeners.length === 0) {
  168. delete this._eventTypes[type];
  169. }
  170. state.compact = false;
  171. }
  172. }
  173. }
  174. },
  175. /**
  176. * Returns whether there is a listener for the specified event type.
  177. *
  178. * @param {String} type The event type
  179. *
  180. * @see #addEventListener
  181. * @see #removeEventListener
  182. */
  183. isListening: function(type) {
  184. if (!this._eventTypes) { return false; }
  185. return this._eventTypes[type] !== undefined;
  186. },
  187. /**
  188. * Removes an event listener from the event target.
  189. * <p>
  190. * All the parameters must be the same ones used to add the listener.
  191. * </p>
  192. *
  193. * @param {String} type The event type
  194. * @param {Function|EventListener} listener The function or the EventListener that will be executed when the event happens.
  195. * @param {Boolean} [useCapture=false] <code>true</code> if the listener should be trigged in the capture phase.
  196. *
  197. * @see #addEventListener
  198. */
  199. removeEventListener: function(type, listener, useCapture){
  200. if (!this._eventTypes) { return; }
  201. var state = this._eventTypes[type];
  202. if (state) {
  203. var listeners = state.listeners;
  204. for (var i=0, len=listeners.length; i < len; i++) {
  205. var l = listeners[i];
  206. if (l && l.listener === listener && l.useCapture === useCapture) {
  207. if (state.level !== 0) {
  208. listeners[i] = null;
  209. state.compact = true;
  210. } else {
  211. listeners.splice(i, 1);
  212. }
  213. break;
  214. }
  215. }
  216. if (listeners.length === 0) {
  217. delete this._eventTypes[type];
  218. }
  219. }
  220. }
  221. };
  222. return {EventTarget: EventTarget};
  223. });
  224. /*******************************************************************************
  225. * @license
  226. * Copyright (c) 2011 IBM Corporation and others.
  227. * All rights reserved. This program and the accompanying materials are made
  228. * available under the terms of the Eclipse Public License v1.0
  229. * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
  230. * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
  231. *
  232. * Contributors:
  233. * IBM Corporation - initial API and implementation
  234. *******************************************************************************/
  235. /*global define */
  236. /*jslint browser:true regexp:false*/
  237. /**
  238. * @name orion.editor.regex
  239. * @class Utilities for dealing with regular expressions.
  240. * @description Utilities for dealing with regular expressions.
  241. */
  242. define("orion/editor/regex", [], function() {
  243. /**
  244. * @methodOf orion.editor.regex
  245. * @static
  246. * @description Escapes regex special characters in the input string.
  247. * @param {String} str The string to escape.
  248. * @returns {String} A copy of <code>str</code> with regex special characters escaped.
  249. */
  250. function escape(str) {
  251. return str.replace(/([\\$\^*\/+?\.\(\)|{}\[\]])/g, "\\$&");
  252. }
  253. /**
  254. * @methodOf orion.editor.regex
  255. * @static
  256. * @description Parses a pattern and flags out of a regex literal string.
  257. * @param {String} str The string to parse. Should look something like <code>"/ab+c/"</code> or <code>"/ab+c/i"</code>.
  258. * @returns {Object} If <code>str</code> looks like a regex literal, returns an object with properties
  259. * <code><dl>
  260. * <dt>pattern</dt><dd>{String}</dd>
  261. * <dt>flags</dt><dd>{String}</dd>
  262. * </dl></code> otherwise returns <code>null</code>.
  263. */
  264. function parse(str) {
  265. var regexp = /^\s*\/(.+)\/([gim]{0,3})\s*$/.exec(str);
  266. if (regexp) {
  267. return {
  268. pattern : regexp[1],
  269. flags : regexp[2]
  270. };
  271. }
  272. return null;
  273. }
  274. return {
  275. escape: escape,
  276. parse: parse
  277. };
  278. });
  279. /*******************************************************************************
  280. * @license
  281. * Copyright (c) 2010, 2011 IBM Corporation and others.
  282. * All rights reserved. This program and the accompanying materials are made
  283. * available under the terms of the Eclipse Public License v1.0
  284. * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
  285. * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
  286. *
  287. * Contributors:
  288. * Felipe Heidrich (IBM Corporation) - initial API and implementation
  289. * Silenio Quarti (IBM Corporation) - initial API and implementation
  290. ******************************************************************************/
  291. /*global window define */
  292. define("orion/textview/keyBinding", [], function() {
  293. var isMac = window.navigator.platform.indexOf("Mac") !== -1;
  294. /**
  295. * Constructs a new key binding with the given key code and modifiers.
  296. *
  297. * @param {String|Number} keyCode the key code.
  298. * @param {Boolean} mod1 the primary modifier (usually Command on Mac and Control on other platforms).
  299. * @param {Boolean} mod2 the secondary modifier (usually Shift).
  300. * @param {Boolean} mod3 the third modifier (usually Alt).
  301. * @param {Boolean} mod4 the fourth modifier (usually Control on the Mac).
  302. *
  303. * @class A KeyBinding represents of a key code and a modifier state that can be triggered by the user using the keyboard.
  304. * @name orion.textview.KeyBinding
  305. *
  306. * @property {String|Number} keyCode The key code.
  307. * @property {Boolean} mod1 The primary modifier (usually Command on Mac and Control on other platforms).
  308. * @property {Boolean} mod2 The secondary modifier (usually Shift).
  309. * @property {Boolean} mod3 The third modifier (usually Alt).
  310. * @property {Boolean} mod4 The fourth modifier (usually Control on the Mac).
  311. *
  312. * @see orion.textview.TextView#setKeyBinding
  313. */
  314. function KeyBinding (keyCode, mod1, mod2, mod3, mod4) {
  315. if (typeof(keyCode) === "string") {
  316. this.keyCode = keyCode.toUpperCase().charCodeAt(0);
  317. } else {
  318. this.keyCode = keyCode;
  319. }
  320. this.mod1 = mod1 !== undefined && mod1 !== null ? mod1 : false;
  321. this.mod2 = mod2 !== undefined && mod2 !== null ? mod2 : false;
  322. this.mod3 = mod3 !== undefined && mod3 !== null ? mod3 : false;
  323. this.mod4 = mod4 !== undefined && mod4 !== null ? mod4 : false;
  324. }
  325. KeyBinding.prototype = /** @lends orion.textview.KeyBinding.prototype */ {
  326. /**
  327. * Returns whether this key binding matches the given key event.
  328. *
  329. * @param e the key event.
  330. * @returns {Boolean} <code>true</code> whether the key binding matches the key event.
  331. */
  332. match: function (e) {
  333. if (this.keyCode === e.keyCode) {
  334. var mod1 = isMac ? e.metaKey : e.ctrlKey;
  335. if (this.mod1 !== mod1) { return false; }
  336. if (this.mod2 !== e.shiftKey) { return false; }
  337. if (this.mod3 !== e.altKey) { return false; }
  338. if (isMac && this.mod4 !== e.ctrlKey) { return false; }
  339. return true;
  340. }
  341. return false;
  342. },
  343. /**
  344. * Returns whether this key binding is the same as the given parameter.
  345. *
  346. * @param {orion.textview.KeyBinding} kb the key binding to compare with.
  347. * @returns {Boolean} whether or not the parameter and the receiver describe the same key binding.
  348. */
  349. equals: function(kb) {
  350. if (!kb) { return false; }
  351. if (this.keyCode !== kb.keyCode) { return false; }
  352. if (this.mod1 !== kb.mod1) { return false; }
  353. if (this.mod2 !== kb.mod2) { return false; }
  354. if (this.mod3 !== kb.mod3) { return false; }
  355. if (this.mod4 !== kb.mod4) { return false; }
  356. return true;
  357. }
  358. };
  359. return {KeyBinding: KeyBinding};
  360. });
  361. /*******************************************************************************
  362. * @license
  363. * Copyright (c) 2010, 2011 IBM Corporation and others.
  364. * All rights reserved. This program and the accompanying materials are made
  365. * available under the terms of the Eclipse Public License v1.0
  366. * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
  367. * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
  368. *
  369. * Contributors:
  370. * Felipe Heidrich (IBM Corporation) - initial API and implementation
  371. * Silenio Quarti (IBM Corporation) - initial API and implementation
  372. ******************************************************************************/
  373. /*global define */
  374. define("orion/textview/annotations", ['orion/textview/eventTarget'], function(mEventTarget) {
  375. /**
  376. * @class This object represents a decoration attached to a range of text. Annotations are added to a
  377. * <code>AnnotationModel</code> which is attached to a <code>TextModel</code>.
  378. * <p>
  379. * <b>See:</b><br/>
  380. * {@link orion.textview.AnnotationModel}<br/>
  381. * {@link orion.textview.Ruler}<br/>
  382. * </p>
  383. * @name orion.textview.Annotation
  384. *
  385. * @property {String} type The annotation type (for example, orion.annotation.error).
  386. * @property {Number} start The start offset of the annotation in the text model.
  387. * @property {Number} end The end offset of the annotation in the text model.
  388. * @property {String} html The HTML displayed for the annotation.
  389. * @property {String} title The text description for the annotation.
  390. * @property {orion.textview.Style} style The style information for the annotation used in the annotations ruler and tooltips.
  391. * @property {orion.textview.Style} overviewStyle The style information for the annotation used in the overview ruler.
  392. * @property {orion.textview.Style} rangeStyle The style information for the annotation used in the text view to decorate a range of text.
  393. * @property {orion.textview.Style} lineStyle The style information for the annotation used in the text view to decorate a line of text.
  394. */
  395. /**
  396. * Constructs a new folding annotation.
  397. *
  398. * @param {orion.textview.ProjectionTextModel} projectionModel The projection text model.
  399. * @param {String} type The annotation type.
  400. * @param {Number} start The start offset of the annotation in the text model.
  401. * @param {Number} end The end offset of the annotation in the text model.
  402. * @param {String} expandedHTML The HTML displayed for this annotation when it is expanded.
  403. * @param {orion.textview.Style} expandedStyle The style information for the annotation when it is expanded.
  404. * @param {String} collapsedHTML The HTML displayed for this annotation when it is collapsed.
  405. * @param {orion.textview.Style} collapsedStyle The style information for the annotation when it is collapsed.
  406. *
  407. * @class This object represents a folding annotation.
  408. * @name orion.textview.FoldingAnnotation
  409. */
  410. function FoldingAnnotation (projectionModel, type, start, end, expandedHTML, expandedStyle, collapsedHTML, collapsedStyle) {
  411. this.type = type;
  412. this.start = start;
  413. this.end = end;
  414. this._projectionModel = projectionModel;
  415. this._expandedHTML = this.html = expandedHTML;
  416. this._expandedStyle = this.style = expandedStyle;
  417. this._collapsedHTML = collapsedHTML;
  418. this._collapsedStyle = collapsedStyle;
  419. this.expanded = true;
  420. }
  421. FoldingAnnotation.prototype = /** @lends orion.textview.FoldingAnnotation.prototype */ {
  422. /**
  423. * Collapses the annotation.
  424. */
  425. collapse: function () {
  426. if (!this.expanded) { return; }
  427. this.expanded = false;
  428. this.html = this._collapsedHTML;
  429. this.style = this._collapsedStyle;
  430. var projectionModel = this._projectionModel;
  431. var baseModel = projectionModel.getBaseModel();
  432. this._projection = {
  433. start: baseModel.getLineStart(baseModel.getLineAtOffset(this.start) + 1),
  434. end: baseModel.getLineEnd(baseModel.getLineAtOffset(this.end), true)
  435. };
  436. projectionModel.addProjection(this._projection);
  437. },
  438. /**
  439. * Expands the annotation.
  440. */
  441. expand: function () {
  442. if (this.expanded) { return; }
  443. this.expanded = true;
  444. this.html = this._expandedHTML;
  445. this.style = this._expandedStyle;
  446. this._projectionModel.removeProjection(this._projection);
  447. }
  448. };
  449. /**
  450. * Constructs a new AnnotationTypeList object.
  451. *
  452. * @class
  453. * @name orion.textview.AnnotationTypeList
  454. */
  455. function AnnotationTypeList () {
  456. }
  457. /**
  458. * Adds in the annotation type interface into the specified object.
  459. *
  460. * @param {Object} object The object to add in the annotation type interface.
  461. */
  462. AnnotationTypeList.addMixin = function(object) {
  463. var proto = AnnotationTypeList.prototype;
  464. for (var p in proto) {
  465. if (proto.hasOwnProperty(p)) {
  466. object[p] = proto[p];
  467. }
  468. }
  469. };
  470. AnnotationTypeList.prototype = /** @lends orion.textview.AnnotationTypeList.prototype */ {
  471. /**
  472. * Adds an annotation type to the receiver.
  473. * <p>
  474. * Only annotations of the specified types will be shown by
  475. * the receiver.
  476. * </p>
  477. *
  478. * @param {Object} type the annotation type to be shown
  479. *
  480. * @see #removeAnnotationType
  481. * @see #isAnnotationTypeVisible
  482. */
  483. addAnnotationType: function(type) {
  484. if (!this._annotationTypes) { this._annotationTypes = []; }
  485. this._annotationTypes.push(type);
  486. },
  487. /**
  488. * Gets the annotation type priority. The priority is determined by the
  489. * order the annotation type is added to the receiver. Annotation types
  490. * added first have higher priority.
  491. * <p>
  492. * Returns <code>0</code> if the annotation type is not added.
  493. * </p>
  494. *
  495. * @param {Object} type the annotation type
  496. *
  497. * @see #addAnnotationType
  498. * @see #removeAnnotationType
  499. * @see #isAnnotationTypeVisible
  500. */
  501. getAnnotationTypePriority: function(type) {
  502. if (this._annotationTypes) {
  503. for (var i = 0; i < this._annotationTypes.length; i++) {
  504. if (this._annotationTypes[i] === type) {
  505. return i + 1;
  506. }
  507. }
  508. }
  509. return 0;
  510. },
  511. /**
  512. * Returns an array of annotations in the specified annotation model for the given range of text sorted by type.
  513. *
  514. * @param {orion.textview.AnnotationModel} annotationModel the annotation model.
  515. * @param {Number} start the start offset of the range.
  516. * @param {Number} end the end offset of the range.
  517. * @return {orion.textview.Annotation[]} an annotation array.
  518. */
  519. getAnnotationsByType: function(annotationModel, start, end) {
  520. var iter = annotationModel.getAnnotations(start, end);
  521. var annotation, annotations = [];
  522. while (iter.hasNext()) {
  523. annotation = iter.next();
  524. var priority = this.getAnnotationTypePriority(annotation.type);
  525. if (priority === 0) { continue; }
  526. annotations.push(annotation);
  527. }
  528. var self = this;
  529. annotations.sort(function(a, b) {
  530. return self.getAnnotationTypePriority(a.type) - self.getAnnotationTypePriority(b.type);
  531. });
  532. return annotations;
  533. },
  534. /**
  535. * Returns whether the receiver shows annotations of the specified type.
  536. *
  537. * @param {Object} type the annotation type
  538. * @returns {Boolean} whether the specified annotation type is shown
  539. *
  540. * @see #addAnnotationType
  541. * @see #removeAnnotationType
  542. */
  543. isAnnotationTypeVisible: function(type) {
  544. return this.getAnnotationTypePriority(type) !== 0;
  545. },
  546. /**
  547. * Removes an annotation type from the receiver.
  548. *
  549. * @param {Object} type the annotation type to be removed
  550. *
  551. * @see #addAnnotationType
  552. * @see #isAnnotationTypeVisible
  553. */
  554. removeAnnotationType: function(type) {
  555. if (!this._annotationTypes) { return; }
  556. for (var i = 0; i < this._annotationTypes.length; i++) {
  557. if (this._annotationTypes[i] === type) {
  558. this._annotationTypes.splice(i, 1);
  559. break;
  560. }
  561. }
  562. }
  563. };
  564. /**
  565. * Constructs an annotation model.
  566. *
  567. * @param {textModel} textModel The text model.
  568. *
  569. * @class This object manages annotations for a <code>TextModel</code>.
  570. * <p>
  571. * <b>See:</b><br/>
  572. * {@link orion.textview.Annotation}<br/>
  573. * {@link orion.textview.TextModel}<br/>
  574. * </p>
  575. * @name orion.textview.AnnotationModel
  576. * @borrows orion.textview.EventTarget#addEventListener as #addEventListener
  577. * @borrows orion.textview.EventTarget#removeEventListener as #removeEventListener
  578. * @borrows orion.textview.EventTarget#dispatchEvent as #dispatchEvent
  579. */
  580. function AnnotationModel(textModel) {
  581. this._annotations = [];
  582. var self = this;
  583. this._listener = {
  584. onChanged: function(modelChangedEvent) {
  585. self._onChanged(modelChangedEvent);
  586. }
  587. };
  588. this.setTextModel(textModel);
  589. }
  590. AnnotationModel.prototype = /** @lends orion.textview.AnnotationModel.prototype */ {
  591. /**
  592. * Adds an annotation to the annotation model.
  593. * <p>The annotation model listeners are notified of this change.</p>
  594. *
  595. * @param {orion.textview.Annotation} annotation the annotation to be added.
  596. *
  597. * @see #removeAnnotation
  598. */
  599. addAnnotation: function(annotation) {
  600. if (!annotation) { return; }
  601. var annotations = this._annotations;
  602. var index = this._binarySearch(annotations, annotation.start);
  603. annotations.splice(index, 0, annotation);
  604. var e = {
  605. type: "Changed",
  606. added: [annotation],
  607. removed: [],
  608. changed: []
  609. };
  610. this.onChanged(e);
  611. },
  612. /**
  613. * Returns the text model.
  614. *
  615. * @return {orion.textview.TextModel} The text model.
  616. *
  617. * @see #setTextModel
  618. */
  619. getTextModel: function() {
  620. return this._model;
  621. },
  622. /**
  623. * @class This object represents an annotation iterator.
  624. * <p>
  625. * <b>See:</b><br/>
  626. * {@link orion.textview.AnnotationModel#getAnnotations}<br/>
  627. * </p>
  628. * @name orion.textview.AnnotationIterator
  629. *
  630. * @property {Function} hasNext Determines whether there are more annotations in the iterator.
  631. * @property {Function} next Returns the next annotation in the iterator.
  632. */
  633. /**
  634. * Returns an iterator of annotations for the given range of text.
  635. *
  636. * @param {Number} start the start offset of the range.
  637. * @param {Number} end the end offset of the range.
  638. * @return {orion.textview.AnnotationIterator} an annotation iterartor.
  639. */
  640. getAnnotations: function(start, end) {
  641. var annotations = this._annotations, current;
  642. //TODO binary search does not work for range intersection when there are overlaping ranges, need interval search tree for this
  643. var i = 0;
  644. var skip = function() {
  645. while (i < annotations.length) {
  646. var a = annotations[i++];
  647. if ((start === a.start) || (start > a.start ? start < a.end : a.start < end)) {
  648. return a;
  649. }
  650. if (a.start >= end) {
  651. break;
  652. }
  653. }
  654. return null;
  655. };
  656. current = skip();
  657. return {
  658. next: function() {
  659. var result = current;
  660. if (result) { current = skip(); }
  661. return result;
  662. },
  663. hasNext: function() {
  664. return current !== null;
  665. }
  666. };
  667. },
  668. /**
  669. * Notifies the annotation model that the given annotation has been modified.
  670. * <p>The annotation model listeners are notified of this change.</p>
  671. *
  672. * @param {orion.textview.Annotation} annotation the modified annotation.
  673. *
  674. * @see #addAnnotation
  675. */
  676. modifyAnnotation: function(annotation) {
  677. if (!annotation) { return; }
  678. var index = this._getAnnotationIndex(annotation);
  679. if (index < 0) { return; }
  680. var e = {
  681. type: "Changed",
  682. added: [],
  683. removed: [],
  684. changed: [annotation]
  685. };
  686. this.onChanged(e);
  687. },
  688. /**
  689. * Notifies all listeners that the annotation model has changed.
  690. *
  691. * @param {orion.textview.Annotation[]} added The list of annotation being added to the model.
  692. * @param {orion.textview.Annotation[]} changed The list of annotation modified in the model.
  693. * @param {orion.textview.Annotation[]} removed The list of annotation being removed from the model.
  694. * @param {ModelChangedEvent} textModelChangedEvent the text model changed event that trigger this change, can be null if the change was trigger by a method call (for example, {@link #addAnnotation}).
  695. */
  696. onChanged: function(e) {
  697. return this.dispatchEvent(e);
  698. },
  699. /**
  700. * Removes all annotations of the given <code>type</code>. All annotations
  701. * are removed if the type is not specified.
  702. * <p>The annotation model listeners are notified of this change. Only one changed event is generated.</p>
  703. *
  704. * @param {Object} type the type of annotations to be removed.
  705. *
  706. * @see #removeAnnotation
  707. */
  708. removeAnnotations: function(type) {
  709. var annotations = this._annotations;
  710. var removed, i;
  711. if (type) {
  712. removed = [];
  713. for (i = annotations.length - 1; i >= 0; i--) {
  714. var annotation = annotations[i];
  715. if (annotation.type === type) {
  716. annotations.splice(i, 1);
  717. }
  718. removed.splice(0, 0, annotation);
  719. }
  720. } else {
  721. removed = annotations;
  722. annotations = [];
  723. }
  724. var e = {
  725. type: "Changed",
  726. removed: removed,
  727. added: [],
  728. changed: []
  729. };
  730. this.onChanged(e);
  731. },
  732. /**
  733. * Removes an annotation from the annotation model.
  734. * <p>The annotation model listeners are notified of this change.</p>
  735. *
  736. * @param {orion.textview.Annotation} annotation the annotation to be removed.
  737. *
  738. * @see #addAnnotation
  739. */
  740. removeAnnotation: function(annotation) {
  741. if (!annotation) { return; }
  742. var index = this._getAnnotationIndex(annotation);
  743. if (index < 0) { return; }
  744. var e = {
  745. type: "Changed",
  746. removed: this._annotations.splice(index, 1),
  747. added: [],
  748. changed: []
  749. };
  750. this.onChanged(e);
  751. },
  752. /**
  753. * Removes and adds the specifed annotations to the annotation model.
  754. * <p>The annotation model listeners are notified of this change. Only one changed event is generated.</p>
  755. *
  756. * @param {orion.textview.Annotation} remove the annotations to be removed.
  757. * @param {orion.textview.Annotation} add the annotations to be added.
  758. *
  759. * @see #addAnnotation
  760. * @see #removeAnnotation
  761. */
  762. replaceAnnotations: function(remove, add) {
  763. var annotations = this._annotations, i, index, annotation, removed = [];
  764. if (remove) {
  765. for (i = remove.length - 1; i >= 0; i--) {
  766. annotation = remove[i];
  767. index = this._getAnnotationIndex(annotation);
  768. if (index < 0) { continue; }
  769. annotations.splice(index, 1);
  770. removed.splice(0, 0, annotation);
  771. }
  772. }
  773. if (!add) { add = []; }
  774. for (i = 0; i < add.length; i++) {
  775. annotation = add[i];
  776. index = this._binarySearch(annotations, annotation.start);
  777. annotations.splice(index, 0, annotation);
  778. }
  779. var e = {
  780. type: "Changed",
  781. removed: removed,
  782. added: add,
  783. changed: []
  784. };
  785. this.onChanged(e);
  786. },
  787. /**
  788. * Sets the text model of the annotation model. The annotation
  789. * model listens for changes in the text model to update and remove
  790. * annotations that are affected by the change.
  791. *
  792. * @param {orion.textview.TextModel} textModel the text model.
  793. *
  794. * @see #getTextModel
  795. */
  796. setTextModel: function(textModel) {
  797. if (this._model) {
  798. this._model.removeEventListener("Changed", this._listener.onChanged);
  799. }
  800. this._model = textModel;
  801. if (this._model) {
  802. this._model.addEventListener("Changed", this._listener.onChanged);
  803. }
  804. },
  805. /** @ignore */
  806. _binarySearch: function (array, offset) {
  807. var high = array.length, low = -1, index;
  808. while (high - low > 1) {
  809. index = Math.floor((high + low) / 2);
  810. if (offset <= array[index].start) {
  811. high = index;
  812. } else {
  813. low = index;
  814. }
  815. }
  816. return high;
  817. },
  818. /** @ignore */
  819. _getAnnotationIndex: function(annotation) {
  820. var annotations = this._annotations;
  821. var index = this._binarySearch(annotations, annotation.start);
  822. while (index < annotations.length && annotations[index].start === annotation.start) {
  823. if (annotations[index] === annotation) {
  824. return index;
  825. }
  826. index++;
  827. }
  828. return -1;
  829. },
  830. /** @ignore */
  831. _onChanged: function(modelChangedEvent) {
  832. var start = modelChangedEvent.start;
  833. var addedCharCount = modelChangedEvent.addedCharCount;
  834. var removedCharCount = modelChangedEvent.removedCharCount;
  835. var annotations = this._annotations, end = start + removedCharCount;
  836. //TODO binary search does not work for range intersection when there are overlaping ranges, need interval search tree for this
  837. var startIndex = 0;
  838. if (!(0 <= startIndex && startIndex < annotations.length)) { return; }
  839. var e = {
  840. type: "Changed",
  841. added: [],
  842. removed: [],
  843. changed: [],
  844. textModelChangedEvent: modelChangedEvent
  845. };
  846. var changeCount = addedCharCount - removedCharCount, i;
  847. for (i = startIndex; i < annotations.length; i++) {
  848. var annotation = annotations[i];
  849. if (annotation.start >= end) {
  850. annotation.start += changeCount;
  851. annotation.end += changeCount;
  852. e.changed.push(annotation);
  853. } else if (annotation.end <= start) {
  854. //nothing
  855. } else if (annotation.start < start && end < annotation.end) {
  856. annotation.end += changeCount;
  857. e.changed.push(annotation);
  858. } else {
  859. annotations.splice(i, 1);
  860. e.removed.push(annotation);
  861. i--;
  862. }
  863. }
  864. if (e.added.length > 0 || e.removed.length > 0 || e.changed.length > 0) {
  865. this.onChanged(e);
  866. }
  867. }
  868. };
  869. mEventTarget.EventTarget.addMixin(AnnotationModel.prototype);
  870. /**
  871. * Constructs a new styler for annotations.
  872. *
  873. * @param {orion.textview.TextView} view The styler view.
  874. * @param {orion.textview.AnnotationModel} view The styler annotation model.
  875. *
  876. * @class This object represents a styler for annotation attached to a text view.
  877. * @name orion.textview.AnnotationStyler
  878. * @borrows orion.textview.AnnotationTypeList#addAnnotationType as #addAnnotationType
  879. * @borrows orion.textview.AnnotationTypeList#getAnnotationTypePriority as #getAnnotationTypePriority
  880. * @borrows orion.textview.AnnotationTypeList#getAnnotationsByType as #getAnnotationsByType
  881. * @borrows orion.textview.AnnotationTypeList#isAnnotationTypeVisible as #isAnnotationTypeVisible
  882. * @borrows orion.textview.AnnotationTypeList#removeAnnotationType as #removeAnnotationType
  883. */
  884. function AnnotationStyler (view, annotationModel) {
  885. this._view = view;
  886. this._annotationModel = annotationModel;
  887. var self = this;
  888. this._listener = {
  889. onDestroy: function(e) {
  890. self._onDestroy(e);
  891. },
  892. onLineStyle: function(e) {
  893. self._onLineStyle(e);
  894. },
  895. onChanged: function(e) {
  896. self._onAnnotationModelChanged(e);
  897. }
  898. };
  899. view.addEventListener("Destroy", this._listener.onDestroy);
  900. view.addEventListener("LineStyle", this._listener.onLineStyle);
  901. annotationModel.addEventListener("Changed", this._listener.onChanged);
  902. }
  903. AnnotationStyler.prototype = /** @lends orion.textview.AnnotationStyler.prototype */ {
  904. /**
  905. * Destroys the styler.
  906. * <p>
  907. * Removes all listeners added by this styler.
  908. * </p>
  909. */
  910. destroy: function() {
  911. var view = this._view;
  912. if (view) {
  913. view.removeEventListener("Destroy", this._listener.onDestroy);
  914. view.removeEventListener("LineStyle", this._listener.onLineStyle);
  915. this.view = null;
  916. }
  917. var annotationModel = this._annotationModel;
  918. if (annotationModel) {
  919. annotationModel.removeEventListener("Changed", this._listener.onChanged);
  920. annotationModel = null;
  921. }
  922. },
  923. _mergeStyle: function(result, style) {
  924. if (style) {
  925. if (!result) { result = {}; }
  926. if (result.styleClass && style.styleClass && result.styleClass !== style.styleClass) {
  927. result.styleClass += " " + style.styleClass;
  928. } else {
  929. result.styleClass = style.styleClass;
  930. }
  931. var prop;
  932. if (style.style) {
  933. if (!result.style) { result.style = {}; }
  934. for (prop in style.style) {
  935. if (!result.style[prop]) {
  936. result.style[prop] = style.style[prop];
  937. }
  938. }
  939. }
  940. if (style.attributes) {
  941. if (!result.attributes) { result.attributes = {}; }
  942. for (prop in style.attributes) {
  943. if (!result.attributes[prop]) {
  944. result.attributes[prop] = style.attributes[prop];
  945. }
  946. }
  947. }
  948. }
  949. return result;
  950. },
  951. _mergeStyleRanges: function(ranges, styleRange) {
  952. if (!ranges) { return; }
  953. for (var i=0; i<ranges.length; i++) {
  954. var range = ranges[i];
  955. if (styleRange.end <= range.start) { break; }
  956. if (styleRange.start >= range.end) { continue; }
  957. var mergedStyle = this._mergeStyle({}, range.style);
  958. mergedStyle = this._mergeStyle(mergedStyle, styleRange.style);
  959. if (styleRange.start <= range.start && styleRange.end >= range.end) {
  960. ranges[i] = {start: range.start, end: range.end, style: mergedStyle};
  961. } else if (styleRange.start > range.start && styleRange.end < range.end) {
  962. ranges.splice(i, 1,
  963. {start: range.start, end: styleRange.start, style: range.style},
  964. {start: styleRange.start, end: styleRange.end, style: mergedStyle},
  965. {start: styleRange.end, end: range.end, style: range.style});
  966. i += 2;
  967. } else if (styleRange.start > range.start) {
  968. ranges.splice(i, 1,
  969. {start: range.start, end: styleRange.start, style: range.style},
  970. {start: styleRange.start, end: range.end, style: mergedStyle});
  971. i += 1;
  972. } else if (styleRange.end < range.end) {
  973. ranges.splice(i, 1,
  974. {start: range.start, end: styleRange.end, style: mergedStyle},
  975. {start: styleRange.end, end: range.end, style: range.style});
  976. i += 1;
  977. }
  978. }
  979. },
  980. _onAnnotationModelChanged: function(e) {
  981. if (e.textModelChangedEvent) {
  982. return;
  983. }
  984. var view = this._view;
  985. if (!view) { return; }
  986. var self = this;
  987. var model = view.getModel();
  988. function redraw(changes) {
  989. for (var i = 0; i < changes.length; i++) {
  990. if (!self.isAnnotationTypeVisible(changes[i].type)) { continue; }
  991. var start = changes[i].start;
  992. var end = changes[i].end;
  993. if (model.getBaseModel) {
  994. start = model.mapOffset(start, true);
  995. end = model.mapOffset(end, true);
  996. }
  997. if (start !== -1 && end !== -1) {
  998. view.redrawRange(start, end);
  999. }
  1000. }
  1001. }
  1002. redraw(e.added);
  1003. redraw(e.removed);
  1004. redraw(e.changed);
  1005. },
  1006. _onDestroy: function(e) {
  1007. this.destroy();
  1008. },
  1009. _onLineStyle: function (e) {
  1010. var annotationModel = this._annotationModel;
  1011. var viewModel = this._view.getModel();
  1012. var baseModel = annotationModel.getTextModel();
  1013. var start = e.lineStart;
  1014. var end = e.lineStart + e.lineText.length;
  1015. if (baseModel !== viewModel) {
  1016. start = viewModel.mapOffset(start);
  1017. end = viewModel.mapOffset(end);
  1018. }
  1019. var annotations = annotationModel.getAnnotations(start, end);
  1020. while (annotations.hasNext()) {
  1021. var annotation = annotations.next();
  1022. if (!this.isAnnotationTypeVisible(annotation.type)) { continue; }
  1023. if (annotation.rangeStyle) {
  1024. var annotationStart = annotation.start;
  1025. var annotationEnd = annotation.end;
  1026. if (baseModel !== viewModel) {
  1027. annotationStart = viewModel.mapOffset(annotationStart, true);
  1028. annotationEnd = viewModel.mapOffset(annotationEnd, true);
  1029. }
  1030. this._mergeStyleRanges(e.ranges, {start: annotationStart, end: annotationEnd, style: annotation.rangeStyle});
  1031. }
  1032. if (annotation.lineStyle) {
  1033. e.style = this._mergeStyle({}, e.style);
  1034. e.style = this._mergeStyle(e.style, annotation.lineStyle);
  1035. }
  1036. }
  1037. }
  1038. };
  1039. AnnotationTypeList.addMixin(AnnotationStyler.prototype);
  1040. return {
  1041. FoldingAnnotation: FoldingAnnotation,
  1042. AnnotationTypeList: AnnotationTypeList,
  1043. AnnotationModel: AnnotationModel,
  1044. AnnotationStyler: AnnotationStyler
  1045. };
  1046. });
  1047. /*******************************************************************************
  1048. * @license
  1049. * Copyright (c) 2010, 2011 IBM Corporation and others.
  1050. * All rights reserved. This program and the accompanying materials are made
  1051. * available under the terms of the Eclipse Public License v1.0
  1052. * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
  1053. * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
  1054. *
  1055. * Contributors: IBM Corporation - initial API and implementation
  1056. ******************************************************************************/
  1057. /*global define setTimeout clearTimeout setInterval clearInterval Node */
  1058. define("orion/textview/rulers", ['orion/textview/annotations', 'orion/textview/tooltip'], function(mAnnotations, mTooltip) {
  1059. /**
  1060. * Constructs a new ruler.
  1061. * <p>
  1062. * The default implementation does not implement all the methods in the interface
  1063. * and is useful only for objects implementing rulers.
  1064. * <p/>
  1065. *
  1066. * @param {orion.textview.AnnotationModel} annotationModel the annotation model for the ruler.
  1067. * @param {String} [rulerLocation="left"] the location for the ruler.
  1068. * @param {String} [rulerOverview="page"] the overview for the ruler.
  1069. * @param {orion.textview.Style} [rulerStyle] the style for the ruler.
  1070. *
  1071. * @class This interface represents a ruler for the text view.
  1072. * <p>
  1073. * A Ruler is a graphical element that is placed either on the left or on the right side of
  1074. * the view. It can be used to provide the view with per line decoration such as line numbering,
  1075. * bookmarks, breakpoints, folding disclosures, etc.
  1076. * </p><p>
  1077. * There are two types of rulers: page and document. A page ruler only shows the content for the lines that are
  1078. * visible, while a document ruler always shows the whole content.
  1079. * </p>
  1080. * <b>See:</b><br/>
  1081. * {@link orion.textview.LineNumberRuler}<br/>
  1082. * {@link orion.textview.AnnotationRuler}<br/>
  1083. * {@link orion.textview.OverviewRuler}<br/>
  1084. * {@link orion.textview.TextView}<br/>
  1085. * {@link orion.textview.TextView#addRuler}
  1086. * </p>
  1087. * @name orion.textview.Ruler
  1088. * @borrows orion.textview.AnnotationTypeList#addAnnotationType as #addAnnotationType
  1089. * @borrows orion.textview.AnnotationTypeList#getAnnotationTypePriority as #getAnnotationTypePriority
  1090. * @borrows orion.textview.AnnotationTypeList#getAnnotationsByType as #getAnnotationsByType
  1091. * @borrows orion.textview.AnnotationTypeList#isAnnotationTypeVisible as #isAnnotationTypeVisible
  1092. * @borrows orion.textview.AnnotationTypeList#removeAnnotationType as #removeAnnotationType
  1093. */
  1094. function Ruler (annotationModel, rulerLocation, rulerOverview, rulerStyle) {
  1095. this._location = rulerLocation || "left";
  1096. this._overview = rulerOverview || "page";
  1097. this._rulerStyle = rulerStyle;
  1098. this._view = null;
  1099. var self = this;
  1100. this._listener = {
  1101. onTextModelChanged: function(e) {
  1102. self._onTextModelChanged(e);
  1103. },
  1104. onAnnotationModelChanged: function(e) {
  1105. self._onAnnotationModelChanged(e);
  1106. }
  1107. };
  1108. this.setAnnotationModel(annotationModel);
  1109. }
  1110. Ruler.prototype = /** @lends orion.textview.Ruler.prototype */ {
  1111. /**
  1112. * Returns the annotations for a given line range merging multiple
  1113. * annotations when necessary.
  1114. * <p>
  1115. * This method is called by the text view when the ruler is redrawn.
  1116. * </p>
  1117. *
  1118. * @param {Number} startLine the start line index
  1119. * @param {Number} endLine the end line index
  1120. * @return {orion.textview.Annotation[]} the annotations for the line range. The array might be sparse.
  1121. */
  1122. getAnnotations: function(startLine, endLine) {
  1123. var annotationModel = this._annotationModel;
  1124. if (!annotationModel) { return []; }
  1125. var model = this._view.getModel();
  1126. var start = model.getLineStart(startLine);
  1127. var end = model.getLineEnd(endLine - 1);
  1128. var baseModel = model;
  1129. if (model.getBaseModel) {
  1130. baseModel = model.getBaseModel();
  1131. start = model.mapOffset(start);
  1132. end = model.mapOffset(end);
  1133. }
  1134. var result = [];
  1135. var annotations = this.getAnnotationsByType(annotationModel, start, end);
  1136. for (var i = 0; i < annotations.length; i++) {
  1137. var annotation = annotations[i];
  1138. var annotationLineStart = baseModel.getLineAtOffset(annotation.start);
  1139. var annotationLineEnd = baseModel.getLineAtOffset(Math.max(annotation.start, annotation.end - 1));
  1140. for (var lineIndex = annotationLineStart; lineIndex<=annotationLineEnd; lineIndex++) {
  1141. var visualLineIndex = lineIndex;
  1142. if (model !== baseModel) {
  1143. var ls = baseModel.getLineStart(lineIndex);
  1144. ls = model.mapOffset(ls, true);
  1145. if (ls === -1) { continue; }
  1146. visualLineIndex = model.getLineAtOffset(ls);
  1147. }
  1148. if (!(startLine <= visualLineIndex && visualLineIndex < endLine)) { continue; }
  1149. var rulerAnnotation = this._mergeAnnotation(result[visualLineIndex], annotation, lineIndex - annotationLineStart, annotationLineEnd - annotationLineStart + 1);
  1150. if (rulerAnnotation) {
  1151. result[visualLineIndex] = rulerAnnotation;
  1152. }
  1153. }
  1154. }
  1155. if (!this._multiAnnotation && this._multiAnnotationOverlay) {
  1156. for (var k in result) {
  1157. if (result[k]._multiple) {
  1158. result[k].html = result[k].html + this._multiAnnotationOverlay.html;
  1159. }
  1160. }
  1161. }
  1162. return result;
  1163. },
  1164. /**
  1165. * Returns the annotation model.
  1166. *
  1167. * @returns {orion.textview.AnnotationModel} the ruler annotation model.
  1168. *
  1169. * @see #setAnnotationModel
  1170. */
  1171. getAnnotationModel: function() {
  1172. return this._annotationModel;
  1173. },
  1174. /**
  1175. * Returns the ruler location.
  1176. *
  1177. * @returns {String} the ruler location, which is either "left" or "right".
  1178. *
  1179. * @see #getOverview
  1180. */
  1181. getLocation: function() {
  1182. return this._location;
  1183. },
  1184. /**
  1185. * Returns the ruler overview type.
  1186. *
  1187. * @returns {String} the overview type, which is either "page" or "document".
  1188. *
  1189. * @see #getLocation
  1190. */
  1191. getOverview: function() {
  1192. return this._overview;
  1193. },
  1194. /**
  1195. * Returns the style information for the ruler.
  1196. *
  1197. * @returns {orion.textview.Style} the style information.
  1198. */
  1199. getRulerStyle: function() {
  1200. return this._rulerStyle;
  1201. },
  1202. /**
  1203. * Returns the widest annotation which determines the width of the ruler.
  1204. * <p>
  1205. * If the ruler does not have a fixed width it should provide the widest
  1206. * annotation to avoid the ruler from changing size as the view scrolls.
  1207. * </p>
  1208. * <p>
  1209. * This method is called by the text view when the ruler is redrawn.
  1210. * </p>
  1211. *
  1212. * @returns {orion.textview.Annotation} the widest annotation.
  1213. *
  1214. * @see #getAnnotations
  1215. */
  1216. getWidestAnnotation: function() {
  1217. return null;
  1218. },
  1219. /**
  1220. * Sets the annotation model for the ruler.
  1221. *
  1222. * @param {orion.textview.AnnotationModel} annotationModel the annotation model.
  1223. *
  1224. * @see #getAnnotationModel
  1225. */
  1226. setAnnotationModel: function (annotationModel) {
  1227. if (this._annotationModel) {
  1228. this._annotationModel.removEventListener("Changed", this._listener.onAnnotationModelChanged);
  1229. }
  1230. this._annotationModel = annotationModel;
  1231. if (this._annotationModel) {
  1232. this._annotationModel.addEventListener("Changed", this._listener.onAnnotationModelChanged);
  1233. }
  1234. },
  1235. /**
  1236. * Sets the annotation that is displayed when a given line contains multiple
  1237. * annotations. This annotation is used when there are different types of
  1238. * annotations in a given line.
  1239. *
  1240. * @param {orion.textview.Annotation} annotation the annotation for lines with multiple annotations.
  1241. *
  1242. * @see #setMultiAnnotationOverlay
  1243. */
  1244. setMultiAnnotation: function(annotation) {
  1245. this._multiAnnotation = annotation;
  1246. },
  1247. /**
  1248. * Sets the annotation that overlays a line with multiple annotations. This annotation is displayed on
  1249. * top of the computed annotation for a given line when there are multiple annotations of the same type
  1250. * in the line. It is also used when the multiple annotation is not set.
  1251. *
  1252. * @param {orion.textview.Annotation} annotation the annotation overlay for lines with multiple annotations.
  1253. *
  1254. * @see #setMultiAnnotation
  1255. */
  1256. setMultiAnnotationOverlay: function(annotation) {
  1257. this._multiAnnotationOverlay = annotation;
  1258. },
  1259. /**
  1260. * Sets the view for the ruler.
  1261. * <p>
  1262. * This method is called by the text view when the ruler
  1263. * is added to the view.
  1264. * </p>
  1265. *
  1266. * @param {orion.textview.TextView} view the text view.
  1267. */
  1268. setView: function (view) {
  1269. if (this._onTextModelChanged && this._view) {
  1270. this._view.removeEventListener("ModelChanged", this._listener.onTextModelChanged);
  1271. }
  1272. this._view = view;
  1273. if (this._onTextModelChanged && this._view) {
  1274. this._view.addEventListener("ModelChanged", this._listener.onTextModelChanged);
  1275. }
  1276. },
  1277. /**
  1278. * This event is sent when the user clicks a line annotation.
  1279. *
  1280. * @event
  1281. * @param {Number} lineIndex the line index of the annotation under the pointer.
  1282. * @param {DOMEvent} e the click event.
  1283. */
  1284. onClick: function(lineIndex, e) {
  1285. },
  1286. /**
  1287. * This event is sent when the user double clicks a line annotation.
  1288. *
  1289. * @event
  1290. * @param {Number} lineIndex the line index of the annotation under the pointer.
  1291. * @param {DOMEvent} e the double click event.
  1292. */
  1293. onDblClick: function(lineIndex, e) {
  1294. },
  1295. /**
  1296. * This event is sent when the user moves the mouse over a line annotation.
  1297. *
  1298. * @event
  1299. * @param {Number} lineIndex the line index of the annotation under the pointer.
  1300. * @param {DOMEvent} e the mouse move event.
  1301. */
  1302. onMouseMove: function(lineIndex, e) {
  1303. var tooltip = mTooltip.Tooltip.getTooltip(this._view);
  1304. if (!tooltip) { return; }
  1305. if (tooltip.isVisible() && this._tooltipLineIndex === lineIndex) { return; }
  1306. this._tooltipLineIndex = lineIndex;
  1307. var self = this;
  1308. tooltip.setTarget({
  1309. y: e.clientY,
  1310. getTooltipInfo: function() {
  1311. return self._getTooltipInfo(self._tooltipLineIndex, this.y);
  1312. }
  1313. });
  1314. },
  1315. /**
  1316. * This event is sent when the mouse pointer enters a line annotation.
  1317. *
  1318. * @event
  1319. * @param {Number} lineIndex the line index of the annotation under the pointer.
  1320. * @param {DOMEvent} e the mouse over event.
  1321. */
  1322. onMouseOver: function(lineIndex, e) {
  1323. this.onMouseMove(lineIndex, e);
  1324. },
  1325. /**
  1326. * This event is sent when the mouse pointer exits a line annotation.
  1327. *
  1328. * @event
  1329. * @param {Number} lineIndex the line index of the annotation under the pointer.
  1330. * @param {DOMEvent} e the mouse out event.
  1331. */
  1332. onMouseOut: function(lineIndex, e) {
  1333. var tooltip = mTooltip.Tooltip.getTooltip(this._view);
  1334. if (!tooltip) { return; }
  1335. tooltip.setTarget(null);
  1336. },
  1337. /** @ignore */
  1338. _getTooltipInfo: function(lineIndex, y) {
  1339. if (lineIndex === undefined) { return; }
  1340. var view = this._view;
  1341. var model = view.getModel();
  1342. var annotationModel = this._annotationModel;
  1343. var annotations = [];
  1344. if (annotationModel) {
  1345. var start = model.getLineStart(lineIndex);
  1346. var end = model.getLineEnd(lineIndex);
  1347. if (model.getBaseModel) {
  1348. start = model.mapOffset(start);
  1349. end = model.mapOffset(end);
  1350. }
  1351. annotations = this.getAnnotationsByType(annotationModel, start, end);
  1352. }
  1353. var contents = this._getTooltipContents(lineIndex, annotations);
  1354. if (!contents) { return null; }
  1355. var info = {
  1356. contents: contents,
  1357. anchor: this.getLocation()
  1358. };
  1359. var rect = view.getClientArea();
  1360. if (this.getOverview() === "document") {
  1361. rect.y = view.convert({y: y}, "view", "document").y;
  1362. } else {
  1363. rect.y = view.getLocationAtOffset(model.getLineStart(lineIndex)).y;
  1364. }
  1365. view.convert(rect, "document", "page");
  1366. info.x = rect.x;
  1367. info.y = rect.y;
  1368. if (info.anchor === "right") {
  1369. info.x += rect.width;
  1370. }
  1371. info.maxWidth = rect.width;
  1372. info.maxHeight = rect.height - (rect.y - view._parent.getBoundingClientRect().top);
  1373. return info;
  1374. },
  1375. /** @ignore */
  1376. _getTooltipContents: function(lineIndex, annotations) {
  1377. return annotations;
  1378. },
  1379. /** @ignore */
  1380. _onAnnotationModelChanged: function(e) {
  1381. var view = this._view;
  1382. if (!view) { return; }
  1383. var model = view.getModel(), self = this;
  1384. var lineCount = model.getLineCount();
  1385. if (e.textModelChangedEvent) {
  1386. var start = e.textModelChangedEvent.start;
  1387. if (model.getBaseModel) { start = model.mapOffset(start, true); }
  1388. var startLine = model.getLineAtOffset(start);
  1389. view.redrawLines(startLine, lineCount, self);
  1390. return;
  1391. }
  1392. function redraw(changes) {
  1393. for (var i = 0; i < changes.length; i++) {
  1394. if (!self.isAnnotationTypeVisible(changes[i].type)) { continue; }
  1395. var start = changes[i].start;
  1396. var end = changes[i].end;
  1397. if (model.getBaseModel) {
  1398. start = model.mapOffset(start, true);
  1399. end = model.mapOffset(end, true);
  1400. }
  1401. if (start !== -1 && end !== -1) {
  1402. view.redrawLines(model.getLineAtOffset(start), model.getLineAtOffset(Math.max(start, end - 1)) + 1, self);
  1403. }
  1404. }
  1405. }
  1406. redraw(e.added);
  1407. redraw(e.removed);
  1408. redraw(e.changed);
  1409. },
  1410. /** @ignore */
  1411. _mergeAnnotation: function(result, annotation, annotationLineIndex, annotationLineCount) {
  1412. if (!result) { result = {}; }
  1413. if (annotationLineIndex === 0) {
  1414. if (result.html && annotation.html) {
  1415. if (annotation.html !== result.html) {
  1416. if (!result._multiple && this._multiAnnotation) {
  1417. result.html = this._multiAnnotation.html;
  1418. }
  1419. }
  1420. result._multiple = true;
  1421. } else {
  1422. result.html = annotation.html;
  1423. }
  1424. }
  1425. result.style = this.

Large files files are truncated, but you can click here to view the full file