/* ***** BEGIN LICENSE BLOCK ***** * Distributed under the BSD license: * * Copyright (c) 2010, Ajax.org B.V. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Ajax.org B.V. nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * ***** END LICENSE BLOCK ***** */ define(function(require, exports, module) { "use strict"; var dom = require("../lib/dom"); var oop = require("../lib/oop"); var lang = require("../lib/lang"); var EventEmitter = require("../lib/event_emitter").EventEmitter; var Gutter = function(parentEl) { this.element = dom.createElement("div"); this.element.className = "ace_layer ace_gutter-layer"; parentEl.appendChild(this.element); this.setShowFoldWidgets(this.$showFoldWidgets); this.gutterWidth = 0; this.$annotations = []; this.$updateAnnotations = this.$updateAnnotations.bind(this); }; (function() { oop.implement(this, EventEmitter); this.setSession = function(session) { if (this.session) this.session.removeEventListener("change", this.$updateAnnotations); this.session = session; session.on("change", this.$updateAnnotations); }; this.addGutterDecoration = function(row, className){ if (window.console) console.warn && console.warn("deprecated use session.addGutterDecoration"); this.session.addGutterDecoration(row, className); }; this.removeGutterDecoration = function(row, className){ if (window.console) console.warn && console.warn("deprecated use session.removeGutterDecoration"); this.session.removeGutterDecoration(row, className); }; this.setAnnotations = function(annotations) { // iterate over sparse array this.$annotations = [] var rowInfo, row; for (var i = 0; i < annotations.length; i++) { var annotation = annotations[i]; var row = annotation.row; var rowInfo = this.$annotations[row]; if (!rowInfo) rowInfo = this.$annotations[row] = {text: []}; var annoText = annotation.text; annoText = annoText ? lang.escapeHTML(annoText) : annotation.html || ""; if (rowInfo.text.indexOf(annoText) === -1) rowInfo.text.push(annoText); var type = annotation.type; if (type == "error") rowInfo.className = " ace_error"; else if (type == "warning" && rowInfo.className != " ace_error") rowInfo.className = " ace_warning"; else if (type == "info" && (!rowInfo.className)) rowInfo.className = " ace_info"; } }; this.$updateAnnotations = function (e) { if (!this.$annotations.length) return; var delta = e.data; var range = delta.range; var firstRow = range.start.row; var len = range.end.row - firstRow; if (len === 0) { // do nothing } else if (delta.action == "removeText" || delta.action == "removeLines") { this.$annotations.splice(firstRow, len + 1, null); } else { var args = Array(len + 1); args.unshift(firstRow, 1); this.$annotations.splice.apply(this.$annotations, args); } }; this.update = function(config) { var emptyAnno = {className: ""}; var html = []; var i = config.firstRow; var lastRow = config.lastRow; var fold = this.session.getNextFoldLine(i); var foldStart = fold ? fold.start.row : Infinity; var foldWidgets = this.$showFoldWidgets && this.session.foldWidgets; var breakpoints = this.session.$breakpoints; var decorations = this.session.$decorations; var lastLineNumber = 0; while (true) { if(i > foldStart) { i = fold.end.row + 1; fold = this.session.getNextFoldLine(i, fold); foldStart = fold ?fold.start.row :Infinity; } if(i > lastRow) break; var annotation = this.$annotations[i] || emptyAnno; html.push( "
", lastLineNumber = i + 1 ); if (foldWidgets) { var c = foldWidgets[i]; // check if cached value is invalidated and we need to recompute if (c == null) c = foldWidgets[i] = this.session.getFoldWidget(i); if (c) html.push( "" ); } html.push("
"); i++; } this.element = dom.setInnerHtml(this.element, html.join("")); this.element.style.height = config.minHeight + "px"; if (this.session.$useWrapMode) lastLineNumber = this.session.getLength(); var gutterWidth = ("" + lastLineNumber).length * config.characterWidth; var padding = this.$padding || this.$computePadding(); gutterWidth += padding.left + padding.right; if (gutterWidth !== this.gutterWidth) { this.gutterWidth = gutterWidth; this.element.style.width = Math.ceil(this.gutterWidth) + "px"; this._emit("changeGutterWidth", gutterWidth); } }; this.$showFoldWidgets = true; this.setShowFoldWidgets = function(show) { if (show) dom.addCssClass(this.element, "ace_folding-enabled"); else dom.removeCssClass(this.element, "ace_folding-enabled"); this.$showFoldWidgets = show; this.$padding = null; }; this.getShowFoldWidgets = function() { return this.$showFoldWidgets; }; this.$computePadding = function() { if (!this.element.firstChild) return {left: 0, right: 0}; var style = dom.computedStyle(this.element.firstChild); this.$padding = {} this.$padding.left = parseInt(style.paddingLeft) + 1; this.$padding.right = parseInt(style.paddingRight); return this.$padding; }; this.getRegion = function(point) { var padding = this.$padding || this.$computePadding(); var rect = this.element.getBoundingClientRect(); if (point.x < padding.left + rect.left) return "markers"; if (this.$showFoldWidgets && point.x > rect.right - padding.right) return "foldWidgets"; }; }).call(Gutter.prototype); exports.Gutter = Gutter; });