")
+
+ this.$renderLine(html, row, false, row == foldStart ? foldLine : false);
+
+ if (this.$useLineGroups())
+ html.push("
"); // end the line group
+
+ row++;
+ }
+ this.element.innerHTML = html.join("");
+ };
+
+ this.$textToken = {
+ "text": true,
+ "rparen": true,
+ "lparen": true
+ };
+
+ this.$renderToken = function(stringBuilder, screenColumn, token, value) {
+ var self = this;
+ var replaceReg = /\t|&|<|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\u3000\uFEFF])|[\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3000-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]/g;
+ var replaceFunc = function(c, a, b, tabIdx, idx4) {
+ if (a) {
+ return self.showInvisibles ?
+ ""
+ );
+ }
+
+ split ++;
+ screenColumn = 0;
+ splitChars = splits[split] || Number.MAX_VALUE;
+ }
+ if (value.length != 0) {
+ chars += value.length;
+ screenColumn = this.$renderToken(
+ stringBuilder, screenColumn, token, value
+ );
+ }
+ }
+ }
+ };
+
+ this.$renderSimpleLine = function(stringBuilder, tokens) {
+ var screenColumn = 0;
+ var token = tokens[0];
+ var value = token.value;
+ if (this.displayIndentGuides)
+ value = this.renderIndentGuide(stringBuilder, value);
+ if (value)
+ screenColumn = this.$renderToken(stringBuilder, screenColumn, token, value);
+ for (var i = 1; i < tokens.length; i++) {
+ token = tokens[i];
+ value = token.value;
+ screenColumn = this.$renderToken(stringBuilder, screenColumn, token, value);
+ }
+ };
+ this.$renderLine = function(stringBuilder, row, onlyContents, foldLine) {
+ if (!foldLine && foldLine != false)
+ foldLine = this.session.getFoldLine(row);
+
+ if (foldLine)
+ var tokens = this.$getFoldLineTokens(row, foldLine);
+ else
+ var tokens = this.session.getTokens(row);
+
+
+ if (!onlyContents) {
+ stringBuilder.push(
+ "
"
+ );
+ }
+
+ if (tokens.length) {
+ var splits = this.session.getRowSplitData(row);
+ if (splits && splits.length)
+ this.$renderWrappedLine(stringBuilder, tokens, splits, onlyContents);
+ else
+ this.$renderSimpleLine(stringBuilder, tokens);
+ }
+
+ if (this.showInvisibles) {
+ if (foldLine)
+ row = foldLine.end.row
+
+ stringBuilder.push(
+ "",
+ row == this.session.getLength() - 1 ? this.EOF_CHAR : this.EOL_CHAR,
+ ""
+ );
+ }
+ if (!onlyContents)
+ stringBuilder.push("
");
+ };
+
+ this.$getFoldLineTokens = function(row, foldLine) {
+ var session = this.session;
+ var renderTokens = [];
+
+ function addTokens(tokens, from, to) {
+ var idx = 0, col = 0;
+ while ((col + tokens[idx].value.length) < from) {
+ col += tokens[idx].value.length;
+ idx++;
+
+ if (idx == tokens.length)
+ return;
+ }
+ if (col != from) {
+ var value = tokens[idx].value.substring(from - col);
+ if (value.length > (to - from))
+ value = value.substring(0, to - from);
+
+ renderTokens.push({
+ type: tokens[idx].type,
+ value: value
+ });
+
+ col = from + value.length;
+ idx += 1;
+ }
+
+ while (col < to && idx < tokens.length) {
+ var value = tokens[idx].value;
+ if (value.length + col > to) {
+ renderTokens.push({
+ type: tokens[idx].type,
+ value: value.substring(0, to - col)
+ });
+ } else
+ renderTokens.push(tokens[idx]);
+ col += value.length;
+ idx += 1;
+ }
+ }
+
+ var tokens = session.getTokens(row);
+ foldLine.walk(function(placeholder, row, column, lastColumn, isNewRow) {
+ if (placeholder != null) {
+ renderTokens.push({
+ type: "fold",
+ value: placeholder
+ });
+ } else {
+ if (isNewRow)
+ tokens = session.getTokens(row);
+
+ if (tokens.length)
+ addTokens(tokens, lastColumn, column);
+ }
+ }, foldLine.end.row, this.session.getLine(foldLine.end.row).length);
+
+ return renderTokens;
+ };
+
+ this.$useLineGroups = function() {
+ return this.session.getUseWrapMode();
+ };
+
+ this.destroy = function() {
+ clearInterval(this.$pollSizeChangesTimer);
+ if (this.$measureNode)
+ this.$measureNode.parentNode.removeChild(this.$measureNode);
+ delete this.$measureNode;
+ };
+
+}).call(Text.prototype);
+
+exports.Text = Text;
+
+});
+
+define("ace/layer/cursor",["require","exports","module","ace/lib/dom"], function(require, exports, module) {
+"use strict";
+
+var dom = require("../lib/dom");
+var IE8;
+
+var Cursor = function(parentEl) {
+ this.element = dom.createElement("div");
+ this.element.className = "ace_layer ace_cursor-layer";
+ parentEl.appendChild(this.element);
+
+ if (IE8 === undefined)
+ IE8 = "opacity" in this.element;
+
+ this.isVisible = false;
+ this.isBlinking = true;
+ this.blinkInterval = 1000;
+ this.smoothBlinking = false;
+
+ this.cursors = [];
+ this.cursor = this.addCursor();
+ dom.addCssClass(this.element, "ace_hidden-cursors");
+ this.$updateCursors = this.$updateVisibility.bind(this);
+};
+
+(function() {
+
+ this.$updateVisibility = function(val) {
+ var cursors = this.cursors;
+ for (var i = cursors.length; i--; )
+ cursors[i].style.visibility = val ? "" : "hidden";
+ };
+ this.$updateOpacity = function(val) {
+ var cursors = this.cursors;
+ for (var i = cursors.length; i--; )
+ cursors[i].style.opacity = val ? "" : "0";
+ };
+
+
+ this.$padding = 0;
+ this.setPadding = function(padding) {
+ this.$padding = padding;
+ };
+
+ this.setSession = function(session) {
+ this.session = session;
+ };
+
+ this.setBlinking = function(blinking) {
+ if (blinking != this.isBlinking){
+ this.isBlinking = blinking;
+ this.restartTimer();
+ }
+ };
+
+ this.setBlinkInterval = function(blinkInterval) {
+ if (blinkInterval != this.blinkInterval){
+ this.blinkInterval = blinkInterval;
+ this.restartTimer();
+ }
+ };
+
+ this.setSmoothBlinking = function(smoothBlinking) {
+ if (smoothBlinking != this.smoothBlinking && !IE8) {
+ this.smoothBlinking = smoothBlinking;
+ dom.setCssClass(this.element, "ace_smooth-blinking", smoothBlinking);
+ this.$updateCursors(true);
+ this.$updateCursors = (smoothBlinking
+ ? this.$updateOpacity
+ : this.$updateVisibility).bind(this);
+ this.restartTimer();
+ }
+ };
+
+ this.addCursor = function() {
+ var el = dom.createElement("div");
+ el.className = "ace_cursor";
+ this.element.appendChild(el);
+ this.cursors.push(el);
+ return el;
+ };
+
+ this.removeCursor = function() {
+ if (this.cursors.length > 1) {
+ var el = this.cursors.pop();
+ el.parentNode.removeChild(el);
+ return el;
+ }
+ };
+
+ this.hideCursor = function() {
+ this.isVisible = false;
+ dom.addCssClass(this.element, "ace_hidden-cursors");
+ this.restartTimer();
+ };
+
+ this.showCursor = function() {
+ this.isVisible = true;
+ dom.removeCssClass(this.element, "ace_hidden-cursors");
+ this.restartTimer();
+ };
+
+ this.restartTimer = function() {
+ var update = this.$updateCursors;
+ clearInterval(this.intervalId);
+ clearTimeout(this.timeoutId);
+ if (this.smoothBlinking) {
+ dom.removeCssClass(this.element, "ace_smooth-blinking");
+ }
+
+ update(true);
+
+ if (!this.isBlinking || !this.blinkInterval || !this.isVisible)
+ return;
+
+ if (this.smoothBlinking) {
+ setTimeout(function(){
+ dom.addCssClass(this.element, "ace_smooth-blinking");
+ }.bind(this));
+ }
+
+ var blink = function(){
+ this.timeoutId = setTimeout(function() {
+ update(false);
+ }, 0.6 * this.blinkInterval);
+ }.bind(this);
+
+ this.intervalId = setInterval(function() {
+ update(true);
+ blink();
+ }, this.blinkInterval);
+
+ blink();
+ };
+
+ this.getPixelPosition = function(position, onScreen) {
+ if (!this.config || !this.session)
+ return {left : 0, top : 0};
+
+ if (!position)
+ position = this.session.selection.getCursor();
+ var pos = this.session.documentToScreenPosition(position);
+ var cursorLeft = this.$padding + pos.column * this.config.characterWidth;
+ var cursorTop = (pos.row - (onScreen ? this.config.firstRowScreen : 0)) *
+ this.config.lineHeight;
+
+ return {left : cursorLeft, top : cursorTop};
+ };
+
+ this.update = function(config) {
+ this.config = config;
+
+ var selections = this.session.$selectionMarkers;
+ var i = 0, cursorIndex = 0;
+
+ if (selections === undefined || selections.length === 0){
+ selections = [{cursor: null}];
+ }
+
+ for (var i = 0, n = selections.length; i < n; i++) {
+ var pixelPos = this.getPixelPosition(selections[i].cursor, true);
+ if ((pixelPos.top > config.height + config.offset ||
+ pixelPos.top < 0) && i > 1) {
+ continue;
+ }
+
+ var style = (this.cursors[cursorIndex++] || this.addCursor()).style;
+
+ if (!this.drawCursor) {
+ style.left = pixelPos.left + "px";
+ style.top = pixelPos.top + "px";
+ style.width = config.characterWidth + "px";
+ style.height = config.lineHeight + "px";
+ } else {
+ this.drawCursor(style, pixelPos, config, selections[i], this.session);
+ }
+ }
+ while (this.cursors.length > cursorIndex)
+ this.removeCursor();
+
+ var overwrite = this.session.getOverwrite();
+ this.$setOverwrite(overwrite);
+ this.$pixelPos = pixelPos;
+ this.restartTimer();
+ };
+
+ this.drawCursor = null;
+
+ this.$setOverwrite = function(overwrite) {
+ if (overwrite != this.overwrite) {
+ this.overwrite = overwrite;
+ if (overwrite)
+ dom.addCssClass(this.element, "ace_overwrite-cursors");
+ else
+ dom.removeCssClass(this.element, "ace_overwrite-cursors");
+ }
+ };
+
+ this.destroy = function() {
+ clearInterval(this.intervalId);
+ clearTimeout(this.timeoutId);
+ };
+
+}).call(Cursor.prototype);
+
+exports.Cursor = Cursor;
+
+});
+
+define("ace/scrollbar",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/event","ace/lib/event_emitter"], function(require, exports, module) {
+"use strict";
+
+var oop = require("./lib/oop");
+var dom = require("./lib/dom");
+var event = require("./lib/event");
+var EventEmitter = require("./lib/event_emitter").EventEmitter;
+var ScrollBar = function(parent) {
+ this.element = dom.createElement("div");
+ this.element.className = "ace_scrollbar ace_scrollbar" + this.classSuffix;
+
+ this.inner = dom.createElement("div");
+ this.inner.className = "ace_scrollbar-inner";
+ this.element.appendChild(this.inner);
+
+ parent.appendChild(this.element);
+
+ this.setVisible(false);
+ this.skipEvent = false;
+
+ event.addListener(this.element, "scroll", this.onScroll.bind(this));
+ event.addListener(this.element, "mousedown", event.preventDefault);
+};
+
+(function() {
+ oop.implement(this, EventEmitter);
+
+ this.setVisible = function(isVisible) {
+ this.element.style.display = isVisible ? "" : "none";
+ this.isVisible = isVisible;
+ };
+}).call(ScrollBar.prototype);
+var VScrollBar = function(parent, renderer) {
+ ScrollBar.call(this, parent);
+ this.scrollTop = 0;
+ renderer.$scrollbarWidth =
+ this.width = dom.scrollbarWidth(parent.ownerDocument);
+ this.inner.style.width =
+ this.element.style.width = (this.width || 15) + 5 + "px";
+};
+
+oop.inherits(VScrollBar, ScrollBar);
+
+(function() {
+
+ this.classSuffix = '-v';
+ this.onScroll = function() {
+ if (!this.skipEvent) {
+ this.scrollTop = this.element.scrollTop;
+ this._emit("scroll", {data: this.scrollTop});
+ }
+ this.skipEvent = false;
+ };
+ this.getWidth = function() {
+ return this.isVisible ? this.width : 0;
+ };
+ this.setHeight = function(height) {
+ this.element.style.height = height + "px";
+ };
+ this.setInnerHeight = function(height) {
+ this.inner.style.height = height + "px";
+ };
+ this.setScrollHeight = function(height) {
+ this.inner.style.height = height + "px";
+ };
+ this.setScrollTop = function(scrollTop) {
+ if (this.scrollTop != scrollTop) {
+ this.skipEvent = true;
+ this.scrollTop = this.element.scrollTop = scrollTop;
+ }
+ };
+
+}).call(VScrollBar.prototype);
+var HScrollBar = function(parent, renderer) {
+ ScrollBar.call(this, parent);
+ this.scrollLeft = 0;
+ this.height = renderer.$scrollbarWidth;
+ this.inner.style.height =
+ this.element.style.height = (this.height || 15) + 5 + "px";
+};
+
+oop.inherits(HScrollBar, ScrollBar);
+
+(function() {
+
+ this.classSuffix = '-h';
+ this.onScroll = function() {
+ if (!this.skipEvent) {
+ this.scrollLeft = this.element.scrollLeft;
+ this._emit("scroll", {data: this.scrollLeft});
+ }
+ this.skipEvent = false;
+ };
+ this.getHeight = function() {
+ return this.isVisible ? this.height : 0;
+ };
+ this.setWidth = function(width) {
+ this.element.style.width = width + "px";
+ };
+ this.setInnerWidth = function(width) {
+ this.inner.style.width = width + "px";
+ };
+ this.setScrollWidth = function(width) {
+ this.inner.style.width = width + "px";
+ };
+ this.setScrollLeft = function(scrollLeft) {
+ if (this.scrollLeft != scrollLeft) {
+ this.skipEvent = true;
+ this.scrollLeft = this.element.scrollLeft = scrollLeft;
+ }
+ };
+
+}).call(HScrollBar.prototype);
+
+
+exports.ScrollBar = VScrollBar; // backward compatibility
+exports.ScrollBarV = VScrollBar; // backward compatibility
+exports.ScrollBarH = HScrollBar; // backward compatibility
+
+exports.VScrollBar = VScrollBar;
+exports.HScrollBar = HScrollBar;
+});
+
+define("ace/renderloop",["require","exports","module","ace/lib/event"], function(require, exports, module) {
+"use strict";
+
+var event = require("./lib/event");
+
+
+var RenderLoop = function(onRender, win) {
+ this.onRender = onRender;
+ this.pending = false;
+ this.changes = 0;
+ this.window = win || window;
+};
+
+(function() {
+
+
+ this.schedule = function(change) {
+ this.changes = this.changes | change;
+ if (!this.pending && this.changes) {
+ this.pending = true;
+ var _self = this;
+ event.nextFrame(function() {
+ _self.pending = false;
+ var changes;
+ while (changes = _self.changes) {
+ _self.changes = 0;
+ _self.onRender(changes);
+ }
+ }, this.window);
+ }
+ };
+
+}).call(RenderLoop.prototype);
+
+exports.RenderLoop = RenderLoop;
+});
+
+define("ace/layer/font_metrics",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/lang","ace/lib/useragent","ace/lib/event_emitter"], function(require, exports, module) {
+
+var oop = require("../lib/oop");
+var dom = require("../lib/dom");
+var lang = require("../lib/lang");
+var useragent = require("../lib/useragent");
+var EventEmitter = require("../lib/event_emitter").EventEmitter;
+
+var CHAR_COUNT = 0;
+
+var FontMetrics = exports.FontMetrics = function(parentEl, interval) {
+ this.el = dom.createElement("div");
+ this.$setMeasureNodeStyles(this.el.style, true);
+
+ this.$main = dom.createElement("div");
+ this.$setMeasureNodeStyles(this.$main.style);
+
+ this.$measureNode = dom.createElement("div");
+ this.$setMeasureNodeStyles(this.$measureNode.style);
+
+
+ this.el.appendChild(this.$main);
+ this.el.appendChild(this.$measureNode);
+ parentEl.appendChild(this.el);
+
+ if (!CHAR_COUNT)
+ this.$testFractionalRect();
+ this.$measureNode.innerHTML = lang.stringRepeat("X", CHAR_COUNT);
+
+ this.$characterSize = {width: 0, height: 0};
+ this.checkForSizeChanges();
+};
+
+(function() {
+
+ oop.implement(this, EventEmitter);
+
+ this.$characterSize = {width: 0, height: 0};
+
+ this.$testFractionalRect = function() {
+ var el = dom.createElement("div");
+ this.$setMeasureNodeStyles(el.style);
+ el.style.width = "0.2px";
+ document.documentElement.appendChild(el);
+ var w = el.getBoundingClientRect().width;
+ if (w > 0 && w < 1)
+ CHAR_COUNT = 50;
+ else
+ CHAR_COUNT = 100;
+ el.parentNode.removeChild(el);
+ };
+
+ this.$setMeasureNodeStyles = function(style, isRoot) {
+ style.width = style.height = "auto";
+ style.left = style.top = "0px";
+ style.visibility = "hidden";
+ style.position = "absolute";
+ style.whiteSpace = "pre";
+
+ if (useragent.isIE < 8) {
+ style["font-family"] = "inherit";
+ } else {
+ style.font = "inherit";
+ }
+ style.overflow = isRoot ? "hidden" : "visible";
+ };
+
+ this.checkForSizeChanges = function() {
+ var size = this.$measureSizes();
+ if (size && (this.$characterSize.width !== size.width || this.$characterSize.height !== size.height)) {
+ this.$measureNode.style.fontWeight = "bold";
+ var boldSize = this.$measureSizes();
+ this.$measureNode.style.fontWeight = "";
+ this.$characterSize = size;
+ this.charSizes = Object.create(null);
+ this.allowBoldFonts = boldSize && boldSize.width === size.width && boldSize.height === size.height;
+ this._emit("changeCharacterSize", {data: size});
+ }
+ };
+
+ this.$pollSizeChanges = function() {
+ if (this.$pollSizeChangesTimer)
+ return this.$pollSizeChangesTimer;
+ var self = this;
+ return this.$pollSizeChangesTimer = setInterval(function() {
+ self.checkForSizeChanges();
+ }, 500);
+ };
+
+ this.setPolling = function(val) {
+ if (val) {
+ this.$pollSizeChanges();
+ } else {
+ if (this.$pollSizeChangesTimer)
+ this.$pollSizeChangesTimer;
+ }
+ };
+
+ this.$measureSizes = function() {
+ if (CHAR_COUNT === 50) {
+ var rect = null;
+ try {
+ rect = this.$measureNode.getBoundingClientRect();
+ } catch(e) {
+ rect = {width: 0, height:0 };
+ };
+ var size = {
+ height: rect.height,
+ width: rect.width / CHAR_COUNT
+ };
+ } else {
+ var size = {
+ height: this.$measureNode.clientHeight,
+ width: this.$measureNode.clientWidth / CHAR_COUNT
+ };
+ }
+ if (size.width === 0 || size.height === 0)
+ return null;
+ return size;
+ };
+
+ this.$measureCharWidth = function(ch) {
+ this.$main.innerHTML = lang.stringRepeat(ch, CHAR_COUNT);
+ var rect = this.$main.getBoundingClientRect();
+ return rect.width / CHAR_COUNT;
+ };
+
+ this.getCharacterWidth = function(ch) {
+ var w = this.charSizes[ch];
+ if (w === undefined) {
+ this.charSizes[ch] = this.$measureCharWidth(ch) / this.$characterSize.width;
+ }
+ return w;
+ };
+
+ this.destroy = function() {
+ clearInterval(this.$pollSizeChangesTimer);
+ if (this.el && this.el.parentNode)
+ this.el.parentNode.removeChild(this.el);
+ };
+
+}).call(FontMetrics.prototype);
+
+});
+
+define("ace/virtual_renderer",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/config","ace/lib/useragent","ace/layer/gutter","ace/layer/marker","ace/layer/text","ace/layer/cursor","ace/scrollbar","ace/scrollbar","ace/renderloop","ace/layer/font_metrics","ace/lib/event_emitter"], function(require, exports, module) {
+"use strict";
+
+var oop = require("./lib/oop");
+var dom = require("./lib/dom");
+var config = require("./config");
+var useragent = require("./lib/useragent");
+var GutterLayer = require("./layer/gutter").Gutter;
+var MarkerLayer = require("./layer/marker").Marker;
+var TextLayer = require("./layer/text").Text;
+var CursorLayer = require("./layer/cursor").Cursor;
+var HScrollBar = require("./scrollbar").HScrollBar;
+var VScrollBar = require("./scrollbar").VScrollBar;
+var RenderLoop = require("./renderloop").RenderLoop;
+var FontMetrics = require("./layer/font_metrics").FontMetrics;
+var EventEmitter = require("./lib/event_emitter").EventEmitter;
+var editorCss = ".ace_editor {\
+position: relative;\
+overflow: hidden;\
+font: 12px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;\
+direction: ltr;\
+}\
+.ace_scroller {\
+position: absolute;\
+overflow: hidden;\
+top: 0;\
+bottom: 0;\
+background-color: inherit;\
+-ms-user-select: none;\
+-moz-user-select: none;\
+-webkit-user-select: none;\
+user-select: none;\
+cursor: text;\
+}\
+.ace_content {\
+position: absolute;\
+-moz-box-sizing: border-box;\
+-webkit-box-sizing: border-box;\
+box-sizing: border-box;\
+min-width: 100%;\
+}\
+.ace_dragging .ace_scroller:before{\
+position: absolute;\
+top: 0;\
+left: 0;\
+right: 0;\
+bottom: 0;\
+content: '';\
+background: rgba(250, 250, 250, 0.01);\
+z-index: 1000;\
+}\
+.ace_dragging.ace_dark .ace_scroller:before{\
+background: rgba(0, 0, 0, 0.01);\
+}\
+.ace_selecting, .ace_selecting * {\
+cursor: text !important;\
+}\
+.ace_gutter {\
+position: absolute;\
+overflow : hidden;\
+width: auto;\
+top: 0;\
+bottom: 0;\
+left: 0;\
+cursor: default;\
+z-index: 4;\
+-ms-user-select: none;\
+-moz-user-select: none;\
+-webkit-user-select: none;\
+user-select: none;\
+}\
+.ace_gutter-active-line {\
+position: absolute;\
+left: 0;\
+right: 0;\
+}\
+.ace_scroller.ace_scroll-left {\
+box-shadow: 17px 0 16px -16px rgba(0, 0, 0, 0.4) inset;\
+}\
+.ace_gutter-cell {\
+padding-left: 19px;\
+padding-right: 6px;\
+background-repeat: no-repeat;\
+}\
+.ace_gutter-cell.ace_error {\
+background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABOFBMVEX/////////QRswFAb/Ui4wFAYwFAYwFAaWGAfDRymzOSH/PxswFAb/SiUwFAYwFAbUPRvjQiDllog5HhHdRybsTi3/Tyv9Tir+Syj/UC3////XurebMBIwFAb/RSHbPx/gUzfdwL3kzMivKBAwFAbbvbnhPx66NhowFAYwFAaZJg8wFAaxKBDZurf/RB6mMxb/SCMwFAYwFAbxQB3+RB4wFAb/Qhy4Oh+4QifbNRcwFAYwFAYwFAb/QRzdNhgwFAYwFAbav7v/Uy7oaE68MBK5LxLewr/r2NXewLswFAaxJw4wFAbkPRy2PyYwFAaxKhLm1tMwFAazPiQwFAaUGAb/QBrfOx3bvrv/VC/maE4wFAbRPBq6MRO8Qynew8Dp2tjfwb0wFAbx6eju5+by6uns4uH9/f36+vr/GkHjAAAAYnRSTlMAGt+64rnWu/bo8eAA4InH3+DwoN7j4eLi4xP99Nfg4+b+/u9B/eDs1MD1mO7+4PHg2MXa347g7vDizMLN4eG+Pv7i5evs/v79yu7S3/DV7/498Yv24eH+4ufQ3Ozu/v7+y13sRqwAAADLSURBVHjaZc/XDsFgGIBhtDrshlitmk2IrbHFqL2pvXf/+78DPokj7+Fz9qpU/9UXJIlhmPaTaQ6QPaz0mm+5gwkgovcV6GZzd5JtCQwgsxoHOvJO15kleRLAnMgHFIESUEPmawB9ngmelTtipwwfASilxOLyiV5UVUyVAfbG0cCPHig+GBkzAENHS0AstVF6bacZIOzgLmxsHbt2OecNgJC83JERmePUYq8ARGkJx6XtFsdddBQgZE2nPR6CICZhawjA4Fb/chv+399kfR+MMMDGOQAAAABJRU5ErkJggg==\");\
+background-repeat: no-repeat;\
+background-position: 2px center;\
+}\
+.ace_gutter-cell.ace_warning {\
+background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAmVBMVEX///8AAAD///8AAAAAAABPSzb/5sAAAAB/blH/73z/ulkAAAAAAAD85pkAAAAAAAACAgP/vGz/rkDerGbGrV7/pkQICAf////e0IsAAAD/oED/qTvhrnUAAAD/yHD/njcAAADuv2r/nz//oTj/p064oGf/zHAAAAA9Nir/tFIAAAD/tlTiuWf/tkIAAACynXEAAAAAAAAtIRW7zBpBAAAAM3RSTlMAABR1m7RXO8Ln31Z36zT+neXe5OzooRDfn+TZ4p3h2hTf4t3k3ucyrN1K5+Xaks52Sfs9CXgrAAAAjklEQVR42o3PbQ+CIBQFYEwboPhSYgoYunIqqLn6/z8uYdH8Vmdnu9vz4WwXgN/xTPRD2+sgOcZjsge/whXZgUaYYvT8QnuJaUrjrHUQreGczuEafQCO/SJTufTbroWsPgsllVhq3wJEk2jUSzX3CUEDJC84707djRc5MTAQxoLgupWRwW6UB5fS++NV8AbOZgnsC7BpEAAAAABJRU5ErkJggg==\");\
+background-position: 2px center;\
+}\
+.ace_gutter-cell.ace_info {\
+background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAJ0Uk5TAAB2k804AAAAPklEQVQY02NgIB68QuO3tiLznjAwpKTgNyDbMegwisCHZUETUZV0ZqOquBpXj2rtnpSJT1AEnnRmL2OgGgAAIKkRQap2htgAAAAASUVORK5CYII=\");\
+background-position: 2px center;\
+}\
+.ace_dark .ace_gutter-cell.ace_info {\
+background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAChoaGAgIAqKiq+vr6tra1ZWVmUlJSbm5s8PDxubm56enrdgzg3AAAAAXRSTlMAQObYZgAAAClJREFUeNpjYMAPdsMYHegyJZFQBlsUlMFVCWUYKkAZMxZAGdxlDMQBAG+TBP4B6RyJAAAAAElFTkSuQmCC\");\
+}\
+.ace_scrollbar {\
+position: absolute;\
+right: 0;\
+bottom: 0;\
+z-index: 6;\
+}\
+.ace_scrollbar-inner {\
+position: absolute;\
+cursor: text;\
+left: 0;\
+top: 0;\
+}\
+.ace_scrollbar-v{\
+overflow-x: hidden;\
+overflow-y: scroll;\
+top: 0;\
+}\
+.ace_scrollbar-h {\
+overflow-x: scroll;\
+overflow-y: hidden;\
+left: 0;\
+}\
+.ace_print-margin {\
+position: absolute;\
+height: 100%;\
+}\
+.ace_text-input {\
+position: absolute;\
+z-index: 0;\
+width: 0.5em;\
+height: 1em;\
+opacity: 0;\
+background: transparent;\
+-moz-appearance: none;\
+appearance: none;\
+border: none;\
+resize: none;\
+outline: none;\
+overflow: hidden;\
+font: inherit;\
+padding: 0 1px;\
+margin: 0 -1px;\
+text-indent: -1em;\
+-ms-user-select: text;\
+-moz-user-select: text;\
+-webkit-user-select: text;\
+user-select: text;\
+}\
+.ace_text-input.ace_composition {\
+background: inherit;\
+color: inherit;\
+z-index: 1000;\
+opacity: 1;\
+text-indent: 0;\
+}\
+.ace_layer {\
+z-index: 1;\
+position: absolute;\
+overflow: hidden;\
+white-space: pre;\
+height: 100%;\
+width: 100%;\
+-moz-box-sizing: border-box;\
+-webkit-box-sizing: border-box;\
+box-sizing: border-box;\
+pointer-events: none;\
+}\
+.ace_gutter-layer {\
+position: relative;\
+width: auto;\
+text-align: right;\
+pointer-events: auto;\
+}\
+.ace_text-layer {\
+font: inherit !important;\
+}\
+.ace_cjk {\
+display: inline-block;\
+text-align: center;\
+}\
+.ace_cursor-layer {\
+z-index: 4;\
+}\
+.ace_cursor {\
+z-index: 4;\
+position: absolute;\
+-moz-box-sizing: border-box;\
+-webkit-box-sizing: border-box;\
+box-sizing: border-box;\
+border-left: 2px solid\
+}\
+.ace_slim-cursors .ace_cursor {\
+border-left-width: 1px;\
+}\
+.ace_overwrite-cursors .ace_cursor {\
+border-left-width: 0;\
+border-bottom: 1px solid;\
+}\
+.ace_hidden-cursors .ace_cursor {\
+opacity: 0.2;\
+}\
+.ace_smooth-blinking .ace_cursor {\
+-webkit-transition: opacity 0.18s;\
+transition: opacity 0.18s;\
+}\
+.ace_editor.ace_multiselect .ace_cursor {\
+border-left-width: 1px;\
+}\
+.ace_marker-layer .ace_step, .ace_marker-layer .ace_stack {\
+position: absolute;\
+z-index: 3;\
+}\
+.ace_marker-layer .ace_selection {\
+position: absolute;\
+z-index: 5;\
+}\
+.ace_marker-layer .ace_bracket {\
+position: absolute;\
+z-index: 6;\
+}\
+.ace_marker-layer .ace_active-line {\
+position: absolute;\
+z-index: 2;\
+}\
+.ace_marker-layer .ace_selected-word {\
+position: absolute;\
+z-index: 4;\
+-moz-box-sizing: border-box;\
+-webkit-box-sizing: border-box;\
+box-sizing: border-box;\
+}\
+.ace_line .ace_fold {\
+-moz-box-sizing: border-box;\
+-webkit-box-sizing: border-box;\
+box-sizing: border-box;\
+display: inline-block;\
+height: 11px;\
+margin-top: -2px;\
+vertical-align: middle;\
+background-image:\
+url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII=\"),\
+url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACJJREFUeNpi+P//fxgTAwPDBxDxD078RSX+YeEyDFMCIMAAI3INmXiwf2YAAAAASUVORK5CYII=\");\
+background-repeat: no-repeat, repeat-x;\
+background-position: center center, top left;\
+color: transparent;\
+border: 1px solid black;\
+border-radius: 2px;\
+cursor: pointer;\
+pointer-events: auto;\
+}\
+.ace_dark .ace_fold {\
+}\
+.ace_fold:hover{\
+background-image:\
+url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII=\"),\
+url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACBJREFUeNpi+P//fz4TAwPDZxDxD5X4i5fLMEwJgAADAEPVDbjNw87ZAAAAAElFTkSuQmCC\");\
+}\
+.ace_tooltip {\
+background-color: #FFF;\
+background-image: -webkit-linear-gradient(top, transparent, rgba(0, 0, 0, 0.1));\
+background-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.1));\
+border: 1px solid gray;\
+border-radius: 1px;\
+box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);\
+color: black;\
+max-width: 100%;\
+padding: 3px 4px;\
+position: fixed;\
+z-index: 999999;\
+-moz-box-sizing: border-box;\
+-webkit-box-sizing: border-box;\
+box-sizing: border-box;\
+cursor: default;\
+white-space: pre;\
+word-wrap: break-word;\
+line-height: normal;\
+font-style: normal;\
+font-weight: normal;\
+letter-spacing: normal;\
+pointer-events: none;\
+}\
+.ace_folding-enabled > .ace_gutter-cell {\
+padding-right: 13px;\
+}\
+.ace_fold-widget {\
+-moz-box-sizing: border-box;\
+-webkit-box-sizing: border-box;\
+box-sizing: border-box;\
+margin: 0 -12px 0 1px;\
+display: none;\
+width: 11px;\
+vertical-align: top;\
+background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42mWKsQ0AMAzC8ixLlrzQjzmBiEjp0A6WwBCSPgKAXoLkqSot7nN3yMwR7pZ32NzpKkVoDBUxKAAAAABJRU5ErkJggg==\");\
+background-repeat: no-repeat;\
+background-position: center;\
+border-radius: 3px;\
+border: 1px solid transparent;\
+cursor: pointer;\
+}\
+.ace_folding-enabled .ace_fold-widget {\
+display: inline-block; \
+}\
+.ace_fold-widget.ace_end {\
+background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42m3HwQkAMAhD0YzsRchFKI7sAikeWkrxwScEB0nh5e7KTPWimZki4tYfVbX+MNl4pyZXejUO1QAAAABJRU5ErkJggg==\");\
+}\
+.ace_fold-widget.ace_closed {\
+background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAGCAYAAAAG5SQMAAAAOUlEQVR42jXKwQkAMAgDwKwqKD4EwQ26sSOkVWjgIIHAzPiCgaqiqnJHZnKICBERHN194O5b9vbLuAVRL+l0YWnZAAAAAElFTkSuQmCCXA==\");\
+}\
+.ace_fold-widget:hover {\
+border: 1px solid rgba(0, 0, 0, 0.3);\
+background-color: rgba(255, 255, 255, 0.2);\
+box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);\
+}\
+.ace_fold-widget:active {\
+border: 1px solid rgba(0, 0, 0, 0.4);\
+background-color: rgba(0, 0, 0, 0.05);\
+box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);\
+}\
+.ace_dark .ace_fold-widget {\
+background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHklEQVQIW2P4//8/AzoGEQ7oGCaLLAhWiSwB146BAQCSTPYocqT0AAAAAElFTkSuQmCC\");\
+}\
+.ace_dark .ace_fold-widget.ace_end {\
+background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAH0lEQVQIW2P4//8/AxQ7wNjIAjDMgC4AxjCVKBirIAAF0kz2rlhxpAAAAABJRU5ErkJggg==\");\
+}\
+.ace_dark .ace_fold-widget.ace_closed {\
+background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAHElEQVQIW2P4//+/AxAzgDADlOOAznHAKgPWAwARji8UIDTfQQAAAABJRU5ErkJggg==\");\
+}\
+.ace_dark .ace_fold-widget:hover {\
+box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);\
+background-color: rgba(255, 255, 255, 0.1);\
+}\
+.ace_dark .ace_fold-widget:active {\
+box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);\
+}\
+.ace_fold-widget.ace_invalid {\
+background-color: #FFB4B4;\
+border-color: #DE5555;\
+}\
+.ace_fade-fold-widgets .ace_fold-widget {\
+-webkit-transition: opacity 0.4s ease 0.05s;\
+transition: opacity 0.4s ease 0.05s;\
+opacity: 0;\
+}\
+.ace_fade-fold-widgets:hover .ace_fold-widget {\
+-webkit-transition: opacity 0.05s ease 0.05s;\
+transition: opacity 0.05s ease 0.05s;\
+opacity:1;\
+}\
+.ace_underline {\
+text-decoration: underline;\
+}\
+.ace_bold {\
+font-weight: bold;\
+}\
+.ace_nobold .ace_bold {\
+font-weight: normal;\
+}\
+.ace_italic {\
+font-style: italic;\
+}\
+.ace_error-marker {\
+background-color: rgba(255, 0, 0,0.2);\
+position: absolute;\
+z-index: 9;\
+}\
+.ace_highlight-marker {\
+background-color: rgba(255, 255, 0,0.2);\
+position: absolute;\
+z-index: 8;\
+}\
+";
+
+dom.importCssString(editorCss, "ace_editor");
+
+var VirtualRenderer = function(container, theme) {
+ var _self = this;
+
+ this.container = container || dom.createElement("div");
+ this.$keepTextAreaAtCursor = !useragent.isOldIE;
+
+ dom.addCssClass(this.container, "ace_editor");
+
+ this.setTheme(theme);
+
+ this.$gutter = dom.createElement("div");
+ this.$gutter.className = "ace_gutter";
+ this.container.appendChild(this.$gutter);
+
+ this.scroller = dom.createElement("div");
+ this.scroller.className = "ace_scroller";
+ this.container.appendChild(this.scroller);
+
+ this.content = dom.createElement("div");
+ this.content.className = "ace_content";
+ this.scroller.appendChild(this.content);
+
+ this.$gutterLayer = new GutterLayer(this.$gutter);
+ this.$gutterLayer.on("changeGutterWidth", this.onGutterResize.bind(this));
+
+ this.$markerBack = new MarkerLayer(this.content);
+
+ var textLayer = this.$textLayer = new TextLayer(this.content);
+ this.canvas = textLayer.element;
+
+ this.$markerFront = new MarkerLayer(this.content);
+
+ this.$cursorLayer = new CursorLayer(this.content);
+ this.$horizScroll = false;
+ this.$vScroll = false;
+
+ this.scrollBar =
+ this.scrollBarV = new VScrollBar(this.container, this);
+ this.scrollBarH = new HScrollBar(this.container, this);
+ this.scrollBarV.addEventListener("scroll", function(e) {
+ if (!_self.$scrollAnimation)
+ _self.session.setScrollTop(e.data - _self.scrollMargin.top);
+ });
+ this.scrollBarH.addEventListener("scroll", function(e) {
+ if (!_self.$scrollAnimation)
+ _self.session.setScrollLeft(e.data - _self.scrollMargin.left);
+ });
+
+ this.scrollTop = 0;
+ this.scrollLeft = 0;
+
+ this.cursorPos = {
+ row : 0,
+ column : 0
+ };
+
+ this.$fontMetrics = new FontMetrics(this.container, 500);
+ this.$textLayer.$setFontMetrics(this.$fontMetrics);
+ this.$textLayer.addEventListener("changeCharacterSize", function(e) {
+ _self.updateCharacterSize();
+ _self.onResize(true, _self.gutterWidth, _self.$size.width, _self.$size.height);
+ _self._signal("changeCharacterSize", e);
+ });
+
+ this.$size = {
+ width: 0,
+ height: 0,
+ scrollerHeight: 0,
+ scrollerWidth: 0,
+ $dirty: true
+ };
+
+ this.layerConfig = {
+ width : 1,
+ padding : 0,
+ firstRow : 0,
+ firstRowScreen: 0,
+ lastRow : 0,
+ lineHeight : 0,
+ characterWidth : 0,
+ minHeight : 1,
+ maxHeight : 1,
+ offset : 0,
+ height : 1,
+ gutterOffset: 1
+ };
+
+ this.scrollMargin = {
+ left: 0,
+ right: 0,
+ top: 0,
+ bottom: 0,
+ v: 0,
+ h: 0
+ };
+
+ this.$loop = new RenderLoop(
+ this.$renderChanges.bind(this),
+ this.container.ownerDocument.defaultView
+ );
+ this.$loop.schedule(this.CHANGE_FULL);
+
+ this.updateCharacterSize();
+ this.setPadding(4);
+ config.resetOptions(this);
+ config._emit("renderer", this);
+};
+
+(function() {
+
+ this.CHANGE_CURSOR = 1;
+ this.CHANGE_MARKER = 2;
+ this.CHANGE_GUTTER = 4;
+ this.CHANGE_SCROLL = 8;
+ this.CHANGE_LINES = 16;
+ this.CHANGE_TEXT = 32;
+ this.CHANGE_SIZE = 64;
+ this.CHANGE_MARKER_BACK = 128;
+ this.CHANGE_MARKER_FRONT = 256;
+ this.CHANGE_FULL = 512;
+ this.CHANGE_H_SCROLL = 1024;
+
+ oop.implement(this, EventEmitter);
+
+ this.updateCharacterSize = function() {
+ if (this.$textLayer.allowBoldFonts != this.$allowBoldFonts) {
+ this.$allowBoldFonts = this.$textLayer.allowBoldFonts;
+ this.setStyle("ace_nobold", !this.$allowBoldFonts);
+ }
+
+ this.layerConfig.characterWidth =
+ this.characterWidth = this.$textLayer.getCharacterWidth();
+ this.layerConfig.lineHeight =
+ this.lineHeight = this.$textLayer.getLineHeight();
+ this.$updatePrintMargin();
+ };
+ this.setSession = function(session) {
+ if (this.session)
+ this.session.doc.off("changeNewLineMode", this.onChangeNewLineMode);
+
+ this.session = session;
+ if (session && this.scrollMargin.top && session.getScrollTop() <= 0)
+ session.setScrollTop(-this.scrollMargin.top);
+
+ this.$cursorLayer.setSession(session);
+ this.$markerBack.setSession(session);
+ this.$markerFront.setSession(session);
+ this.$gutterLayer.setSession(session);
+ this.$textLayer.setSession(session);
+ if (!session)
+ return;
+
+ this.$loop.schedule(this.CHANGE_FULL);
+ this.session.$setFontMetrics(this.$fontMetrics);
+
+ this.onChangeNewLineMode = this.onChangeNewLineMode.bind(this);
+ this.onChangeNewLineMode()
+ this.session.doc.on("changeNewLineMode", this.onChangeNewLineMode);
+ };
+ this.updateLines = function(firstRow, lastRow, force) {
+ if (lastRow === undefined)
+ lastRow = Infinity;
+
+ if (!this.$changedLines) {
+ this.$changedLines = {
+ firstRow: firstRow,
+ lastRow: lastRow
+ };
+ }
+ else {
+ if (this.$changedLines.firstRow > firstRow)
+ this.$changedLines.firstRow = firstRow;
+
+ if (this.$changedLines.lastRow < lastRow)
+ this.$changedLines.lastRow = lastRow;
+ }
+ if (this.$changedLines.lastRow < this.layerConfig.firstRow) {
+ if (force)
+ this.$changedLines.lastRow = this.layerConfig.lastRow;
+ else
+ return;
+ }
+ if (this.$changedLines.firstRow > this.layerConfig.lastRow)
+ return;
+ this.$loop.schedule(this.CHANGE_LINES);
+ };
+
+ this.onChangeNewLineMode = function() {
+ this.$loop.schedule(this.CHANGE_TEXT);
+ this.$textLayer.$updateEolChar();
+ };
+
+ this.onChangeTabSize = function() {
+ this.$loop.schedule(this.CHANGE_TEXT | this.CHANGE_MARKER);
+ this.$textLayer.onChangeTabSize();
+ };
+ this.updateText = function() {
+ this.$loop.schedule(this.CHANGE_TEXT);
+ };
+ this.updateFull = function(force) {
+ if (force)
+ this.$renderChanges(this.CHANGE_FULL, true);
+ else
+ this.$loop.schedule(this.CHANGE_FULL);
+ };
+ this.updateFontSize = function() {
+ this.$textLayer.checkForSizeChanges();
+ };
+
+ this.$changes = 0;
+ this.$updateSizeAsync = function() {
+ if (this.$loop.pending)
+ this.$size.$dirty = true;
+ else
+ this.onResize();
+ };
+ this.onResize = function(force, gutterWidth, width, height) {
+ if (this.resizing > 2)
+ return;
+ else if (this.resizing > 0)
+ this.resizing++;
+ else
+ this.resizing = force ? 1 : 0;
+ var el = this.container;
+ if (!height)
+ height = el.clientHeight || el.scrollHeight;
+ if (!width)
+ width = el.clientWidth || el.scrollWidth;
+ var changes = this.$updateCachedSize(force, gutterWidth, width, height);
+
+
+ if (!this.$size.scrollerHeight || (!width && !height))
+ return this.resizing = 0;
+
+ if (force)
+ this.$gutterLayer.$padding = null;
+
+ if (force)
+ this.$renderChanges(changes | this.$changes, true);
+ else
+ this.$loop.schedule(changes | this.$changes);
+
+ if (this.resizing)
+ this.resizing = 0;
+ this.scrollBarV.scrollLeft = this.scrollBarV.scrollTop = null;
+ };
+
+ this.$updateCachedSize = function(force, gutterWidth, width, height) {
+ height -= (this.$extraHeight || 0);
+ var changes = 0;
+ var size = this.$size;
+ var oldSize = {
+ width: size.width,
+ height: size.height,
+ scrollerHeight: size.scrollerHeight,
+ scrollerWidth: size.scrollerWidth
+ };
+ if (height && (force || size.height != height)) {
+ size.height = height;
+ changes |= this.CHANGE_SIZE;
+
+ size.scrollerHeight = size.height;
+ if (this.$horizScroll)
+ size.scrollerHeight -= this.scrollBarH.getHeight();
+ this.scrollBarV.element.style.bottom = this.scrollBarH.getHeight() + "px";
+
+ changes = changes | this.CHANGE_SCROLL;
+ }
+
+ if (width && (force || size.width != width)) {
+ changes |= this.CHANGE_SIZE;
+ size.width = width;
+
+ if (gutterWidth == null)
+ gutterWidth = this.$showGutter ? this.$gutter.offsetWidth : 0;
+
+ this.gutterWidth = gutterWidth;
+
+ this.scrollBarH.element.style.left =
+ this.scroller.style.left = gutterWidth + "px";
+ size.scrollerWidth = Math.max(0, width - gutterWidth - this.scrollBarV.getWidth());
+
+ this.scrollBarH.element.style.right =
+ this.scroller.style.right = this.scrollBarV.getWidth() + "px";
+ this.scroller.style.bottom = this.scrollBarH.getHeight() + "px";
+
+ if (this.session && this.session.getUseWrapMode() && this.adjustWrapLimit() || force)
+ changes |= this.CHANGE_FULL;
+ }
+
+ size.$dirty = !width || !height;
+
+ if (changes)
+ this._signal("resize", oldSize);
+
+ return changes;
+ };
+
+ this.onGutterResize = function() {
+ var gutterWidth = this.$showGutter ? this.$gutter.offsetWidth : 0;
+ if (gutterWidth != this.gutterWidth)
+ this.$changes |= this.$updateCachedSize(true, gutterWidth, this.$size.width, this.$size.height);
+
+ if (this.session.getUseWrapMode() && this.adjustWrapLimit()) {
+ this.$loop.schedule(this.CHANGE_FULL);
+ } else if (this.$size.$dirty) {
+ this.$loop.schedule(this.CHANGE_FULL);
+ } else {
+ this.$computeLayerConfig();
+ this.$loop.schedule(this.CHANGE_MARKER);
+ }
+ };
+ this.adjustWrapLimit = function() {
+ var availableWidth = this.$size.scrollerWidth - this.$padding * 2;
+ var limit = Math.floor(availableWidth / this.characterWidth);
+ return this.session.adjustWrapLimit(limit, this.$showPrintMargin && this.$printMarginColumn);
+ };
+ this.setAnimatedScroll = function(shouldAnimate){
+ this.setOption("animatedScroll", shouldAnimate);
+ };
+ this.getAnimatedScroll = function() {
+ return this.$animatedScroll;
+ };
+ this.setShowInvisibles = function(showInvisibles) {
+ this.setOption("showInvisibles", showInvisibles);
+ };
+ this.getShowInvisibles = function() {
+ return this.getOption("showInvisibles");
+ };
+ this.getDisplayIndentGuides = function() {
+ return this.getOption("displayIndentGuides");
+ };
+
+ this.setDisplayIndentGuides = function(display) {
+ this.setOption("displayIndentGuides", display);
+ };
+ this.setShowPrintMargin = function(showPrintMargin) {
+ this.setOption("showPrintMargin", showPrintMargin);
+ };
+ this.getShowPrintMargin = function() {
+ return this.getOption("showPrintMargin");
+ };
+ this.setPrintMarginColumn = function(showPrintMargin) {
+ this.setOption("printMarginColumn", showPrintMargin);
+ };
+ this.getPrintMarginColumn = function() {
+ return this.getOption("printMarginColumn");
+ };
+ this.getShowGutter = function(){
+ return this.getOption("showGutter");
+ };
+ this.setShowGutter = function(show){
+ return this.setOption("showGutter", show);
+ };
+
+ this.getFadeFoldWidgets = function(){
+ return this.getOption("fadeFoldWidgets")
+ };
+
+ this.setFadeFoldWidgets = function(show) {
+ this.setOption("fadeFoldWidgets", show);
+ };
+
+ this.setHighlightGutterLine = function(shouldHighlight) {
+ this.setOption("highlightGutterLine", shouldHighlight);
+ };
+
+ this.getHighlightGutterLine = function() {
+ return this.getOption("highlightGutterLine");
+ };
+
+ this.$updateGutterLineHighlight = function() {
+ var pos = this.$cursorLayer.$pixelPos;
+ var height = this.layerConfig.lineHeight;
+ if (this.session.getUseWrapMode()) {
+ var cursor = this.session.selection.getCursor();
+ cursor.column = 0;
+ pos = this.$cursorLayer.getPixelPosition(cursor, true);
+ height *= this.session.getRowLength(cursor.row);
+ }
+ this.$gutterLineHighlight.style.top = pos.top - this.layerConfig.offset + "px";
+ this.$gutterLineHighlight.style.height = height + "px";
+ };
+
+ this.$updatePrintMargin = function() {
+ if (!this.$showPrintMargin && !this.$printMarginEl)
+ return;
+
+ if (!this.$printMarginEl) {
+ var containerEl = dom.createElement("div");
+ containerEl.className = "ace_layer ace_print-margin-layer";
+ this.$printMarginEl = dom.createElement("div");
+ this.$printMarginEl.className = "ace_print-margin";
+ containerEl.appendChild(this.$printMarginEl);
+ this.content.insertBefore(containerEl, this.content.firstChild);
+ }
+
+ var style = this.$printMarginEl.style;
+ style.left = ((this.characterWidth * this.$printMarginColumn) + this.$padding) + "px";
+ style.visibility = this.$showPrintMargin ? "visible" : "hidden";
+
+ if (this.session && this.session.$wrap == -1)
+ this.adjustWrapLimit();
+ };
+ this.getContainerElement = function() {
+ return this.container;
+ };
+ this.getMouseEventTarget = function() {
+ return this.content;
+ };
+ this.getTextAreaContainer = function() {
+ return this.container;
+ };
+ this.$moveTextAreaToCursor = function() {
+ if (!this.$keepTextAreaAtCursor)
+ return;
+ var config = this.layerConfig;
+ var posTop = this.$cursorLayer.$pixelPos.top;
+ var posLeft = this.$cursorLayer.$pixelPos.left;
+ posTop -= config.offset;
+
+ var style = this.textarea.style;
+ var h = this.lineHeight;
+ if (posTop < 0 || posTop > config.height - h) {
+ style.top = style.left = "0";
+ return;
+ }
+
+ var w = this.characterWidth;
+ if (this.$composition) {
+ var val = this.textarea.value.replace(/^\x01+/, "");
+ w *= (this.session.$getStringScreenWidth(val)[0]+2);
+ h += 2;
+ }
+ posLeft -= this.scrollLeft;
+ if (posLeft > this.$size.scrollerWidth - w)
+ posLeft = this.$size.scrollerWidth - w;
+
+ posLeft += this.gutterWidth;
+ style.height = h + "px";
+ style.width = w + "px";
+ style.left = Math.min(posLeft, this.$size.scrollerWidth - w) + "px";
+ style.top = Math.min(posTop, this.$size.height - h) + "px";
+ };
+ this.getFirstVisibleRow = function() {
+ return this.layerConfig.firstRow;
+ };
+ this.getFirstFullyVisibleRow = function() {
+ return this.layerConfig.firstRow + (this.layerConfig.offset === 0 ? 0 : 1);
+ };
+ this.getLastFullyVisibleRow = function() {
+ var flint = Math.floor((this.layerConfig.height + this.layerConfig.offset) / this.layerConfig.lineHeight);
+ return this.layerConfig.firstRow - 1 + flint;
+ };
+ this.getLastVisibleRow = function() {
+ return this.layerConfig.lastRow;
+ };
+
+ this.$padding = null;
+ this.setPadding = function(padding) {
+ this.$padding = padding;
+ this.$textLayer.setPadding(padding);
+ this.$cursorLayer.setPadding(padding);
+ this.$markerFront.setPadding(padding);
+ this.$markerBack.setPadding(padding);
+ this.$loop.schedule(this.CHANGE_FULL);
+ this.$updatePrintMargin();
+ };
+
+ this.setScrollMargin = function(top, bottom, left, right) {
+ var sm = this.scrollMargin;
+ sm.top = top|0;
+ sm.bottom = bottom|0;
+ sm.right = right|0;
+ sm.left = left|0;
+ sm.v = sm.top + sm.bottom;
+ sm.h = sm.left + sm.right;
+ if (sm.top && this.scrollTop <= 0 && this.session)
+ this.session.setScrollTop(-sm.top);
+ this.updateFull();
+ };
+ this.getHScrollBarAlwaysVisible = function() {
+ return this.$hScrollBarAlwaysVisible;
+ };
+ this.setHScrollBarAlwaysVisible = function(alwaysVisible) {
+ this.setOption("hScrollBarAlwaysVisible", alwaysVisible);
+ };
+ this.getVScrollBarAlwaysVisible = function() {
+ return this.$hScrollBarAlwaysVisible;
+ };
+ this.setVScrollBarAlwaysVisible = function(alwaysVisible) {
+ this.setOption("vScrollBarAlwaysVisible", alwaysVisible);
+ };
+
+ this.$updateScrollBarV = function() {
+ var scrollHeight = this.layerConfig.maxHeight;
+ var scrollerHeight = this.$size.scrollerHeight;
+ if (!this.$maxLines && this.$scrollPastEnd) {
+ scrollHeight -= (scrollerHeight - this.lineHeight) * this.$scrollPastEnd;
+ if (this.scrollTop > scrollHeight - scrollerHeight) {
+ scrollHeight = this.scrollTop + scrollerHeight;
+ this.scrollBarV.scrollTop = null;
+ }
+ }
+ this.scrollBarV.setScrollHeight(scrollHeight + this.scrollMargin.v);
+ this.scrollBarV.setScrollTop(this.scrollTop + this.scrollMargin.top);
+ };
+ this.$updateScrollBarH = function() {
+ this.scrollBarH.setScrollWidth(this.layerConfig.width + 2 * this.$padding + this.scrollMargin.h);
+ this.scrollBarH.setScrollLeft(this.scrollLeft + this.scrollMargin.left);
+ };
+
+ this.$frozen = false;
+ this.freeze = function() {
+ this.$frozen = true;
+ };
+
+ this.unfreeze = function() {
+ this.$frozen = false;
+ };
+
+ this.$renderChanges = function(changes, force) {
+ if (this.$changes) {
+ changes |= this.$changes;
+ this.$changes = 0;
+ }
+ if ((!this.session || !this.container.offsetWidth || this.$frozen) || (!changes && !force)) {
+ this.$changes |= changes;
+ return;
+ }
+ if (this.$size.$dirty) {
+ this.$changes |= changes;
+ return this.onResize(true);
+ }
+ if (!this.lineHeight) {
+ this.$textLayer.checkForSizeChanges();
+ }
+
+ this._signal("beforeRender");
+ var config = this.layerConfig;
+ if (changes & this.CHANGE_FULL ||
+ changes & this.CHANGE_SIZE ||
+ changes & this.CHANGE_TEXT ||
+ changes & this.CHANGE_LINES ||
+ changes & this.CHANGE_SCROLL ||
+ changes & this.CHANGE_H_SCROLL
+ ) {
+ changes |= this.$computeLayerConfig();
+ if (config.firstRow != this.layerConfig.firstRow && config.firstRowScreen == this.layerConfig.firstRowScreen) {
+ var st = this.scrollTop + (config.firstRow - this.layerConfig.firstRow) * this.lineHeight;
+ if (st > 0) {
+ this.scrollTop = st;
+ changes = changes | this.CHANGE_SCROLL;
+ changes |= this.$computeLayerConfig();
+ }
+ }
+ config = this.layerConfig;
+ this.$updateScrollBarV();
+ if (changes & this.CHANGE_H_SCROLL)
+ this.$updateScrollBarH();
+ this.$gutterLayer.element.style.marginTop = (-config.offset) + "px";
+ this.content.style.marginTop = (-config.offset) + "px";
+ this.content.style.width = config.width + 2 * this.$padding + "px";
+ this.content.style.height = config.minHeight + "px";
+ }
+ if (changes & this.CHANGE_H_SCROLL) {
+ this.content.style.marginLeft = -this.scrollLeft + "px";
+ this.scroller.className = this.scrollLeft <= 0 ? "ace_scroller" : "ace_scroller ace_scroll-left";
+ }
+ if (changes & this.CHANGE_FULL) {
+ this.$textLayer.update(config);
+ if (this.$showGutter)
+ this.$gutterLayer.update(config);
+ this.$markerBack.update(config);
+ this.$markerFront.update(config);
+ this.$cursorLayer.update(config);
+ this.$moveTextAreaToCursor();
+ this.$highlightGutterLine && this.$updateGutterLineHighlight();
+ this._signal("afterRender");
+ return;
+ }
+ if (changes & this.CHANGE_SCROLL) {
+ if (changes & this.CHANGE_TEXT || changes & this.CHANGE_LINES)
+ this.$textLayer.update(config);
+ else
+ this.$textLayer.scrollLines(config);
+
+ if (this.$showGutter)
+ this.$gutterLayer.update(config);
+ this.$markerBack.update(config);
+ this.$markerFront.update(config);
+ this.$cursorLayer.update(config);
+ this.$highlightGutterLine && this.$updateGutterLineHighlight();
+ this.$moveTextAreaToCursor();
+ this._signal("afterRender");
+ return;
+ }
+
+ if (changes & this.CHANGE_TEXT) {
+ this.$textLayer.update(config);
+ if (this.$showGutter)
+ this.$gutterLayer.update(config);
+ }
+ else if (changes & this.CHANGE_LINES) {
+ if (this.$updateLines() || (changes & this.CHANGE_GUTTER) && this.$showGutter)
+ this.$gutterLayer.update(config);
+ }
+ else if (changes & this.CHANGE_TEXT || changes & this.CHANGE_GUTTER) {
+ if (this.$showGutter)
+ this.$gutterLayer.update(config);
+ }
+
+ if (changes & this.CHANGE_CURSOR) {
+ this.$cursorLayer.update(config);
+ this.$moveTextAreaToCursor();
+ this.$highlightGutterLine && this.$updateGutterLineHighlight();
+ }
+
+ if (changes & (this.CHANGE_MARKER | this.CHANGE_MARKER_FRONT)) {
+ this.$markerFront.update(config);
+ }
+
+ if (changes & (this.CHANGE_MARKER | this.CHANGE_MARKER_BACK)) {
+ this.$markerBack.update(config);
+ }
+
+ this._signal("afterRender");
+ };
+
+
+ this.$autosize = function() {
+ var height = this.session.getScreenLength() * this.lineHeight;
+ var maxHeight = this.$maxLines * this.lineHeight;
+ var desiredHeight = Math.max(
+ (this.$minLines||1) * this.lineHeight,
+ Math.min(maxHeight, height)
+ ) + this.scrollMargin.v + (this.$extraHeight || 0);
+ var vScroll = height > maxHeight;
+
+ if (desiredHeight != this.desiredHeight ||
+ this.$size.height != this.desiredHeight || vScroll != this.$vScroll) {
+ if (vScroll != this.$vScroll) {
+ this.$vScroll = vScroll;
+ this.scrollBarV.setVisible(vScroll);
+ }
+
+ var w = this.container.clientWidth;
+ this.container.style.height = desiredHeight + "px";
+ this.$updateCachedSize(true, this.$gutterWidth, w, desiredHeight);
+ this.desiredHeight = desiredHeight;
+
+ this._signal("autosize");
+ }
+ };
+
+ this.$computeLayerConfig = function() {
+ if (this.$maxLines && this.lineHeight > 1)
+ this.$autosize();
+
+ var session = this.session;
+ var size = this.$size;
+
+ var hideScrollbars = size.height <= 2 * this.lineHeight;
+ var screenLines = this.session.getScreenLength();
+ var maxHeight = screenLines * this.lineHeight;
+
+ var offset = this.scrollTop % this.lineHeight;
+ var minHeight = size.scrollerHeight + this.lineHeight;
+
+ var longestLine = this.$getLongestLine();
+
+ var horizScroll = !hideScrollbars && (this.$hScrollBarAlwaysVisible ||
+ size.scrollerWidth - longestLine - 2 * this.$padding < 0);
+
+ var hScrollChanged = this.$horizScroll !== horizScroll;
+ if (hScrollChanged) {
+ this.$horizScroll = horizScroll;
+ this.scrollBarH.setVisible(horizScroll);
+ }
+
+ var scrollPastEnd = !this.$maxLines && this.$scrollPastEnd
+ ? (size.scrollerHeight - this.lineHeight) * this.$scrollPastEnd
+ : 0;
+ maxHeight += scrollPastEnd;
+
+ this.session.setScrollTop(Math.max(-this.scrollMargin.top,
+ Math.min(this.scrollTop, maxHeight - size.scrollerHeight + this.scrollMargin.bottom)));
+
+ this.session.setScrollLeft(Math.max(-this.scrollMargin.left, Math.min(this.scrollLeft,
+ longestLine + 2 * this.$padding - size.scrollerWidth + this.scrollMargin.right)));
+
+ var vScroll = !hideScrollbars && (this.$vScrollBarAlwaysVisible ||
+ size.scrollerHeight - maxHeight + scrollPastEnd < 0 || this.scrollTop);
+ var vScrollChanged = this.$vScroll !== vScroll;
+ if (vScrollChanged) {
+ this.$vScroll = vScroll;
+ this.scrollBarV.setVisible(vScroll);
+ }
+
+ var lineCount = Math.ceil(minHeight / this.lineHeight) - 1;
+ var firstRow = Math.max(0, Math.round((this.scrollTop - offset) / this.lineHeight));
+ var lastRow = firstRow + lineCount;
+ var firstRowScreen, firstRowHeight;
+ var lineHeight = this.lineHeight;
+ firstRow = session.screenToDocumentRow(firstRow, 0);
+ var foldLine = session.getFoldLine(firstRow);
+ if (foldLine) {
+ firstRow = foldLine.start.row;
+ }
+
+ firstRowScreen = session.documentToScreenRow(firstRow, 0);
+ firstRowHeight = session.getRowLength(firstRow) * lineHeight;
+
+ lastRow = Math.min(session.screenToDocumentRow(lastRow, 0), session.getLength() - 1);
+ minHeight = size.scrollerHeight + session.getRowLength(lastRow) * lineHeight +
+ firstRowHeight;
+
+ offset = this.scrollTop - firstRowScreen * lineHeight;
+
+ var changes = 0;
+ if (this.layerConfig.width != longestLine)
+ changes = this.CHANGE_H_SCROLL;
+ if (hScrollChanged || vScrollChanged) {
+ changes = this.$updateCachedSize(true, this.gutterWidth, size.width, size.height);
+ this._signal("scrollbarVisibilityChanged");
+ if (vScrollChanged)
+ longestLine = this.$getLongestLine();
+ }
+
+ this.layerConfig = {
+ width : longestLine,
+ padding : this.$padding,
+ firstRow : firstRow,
+ firstRowScreen: firstRowScreen,
+ lastRow : lastRow,
+ lineHeight : lineHeight,
+ characterWidth : this.characterWidth,
+ minHeight : minHeight,
+ maxHeight : maxHeight,
+ offset : offset,
+ gutterOffset : Math.max(0, Math.ceil((offset + size.height - size.scrollerHeight) / lineHeight)),
+ height : this.$size.scrollerHeight
+ };
+
+ return changes;
+ };
+
+ this.$updateLines = function() {
+ var firstRow = this.$changedLines.firstRow;
+ var lastRow = this.$changedLines.lastRow;
+ this.$changedLines = null;
+
+ var layerConfig = this.layerConfig;
+
+ if (firstRow > layerConfig.lastRow + 1) { return; }
+ if (lastRow < layerConfig.firstRow) { return; }
+ if (lastRow === Infinity) {
+ if (this.$showGutter)
+ this.$gutterLayer.update(layerConfig);
+ this.$textLayer.update(layerConfig);
+ return;
+ }
+ this.$textLayer.updateLines(layerConfig, firstRow, lastRow);
+ return true;
+ };
+
+ this.$getLongestLine = function() {
+ var charCount = this.session.getScreenWidth();
+ if (this.showInvisibles && !this.session.$useWrapMode)
+ charCount += 1;
+
+ return Math.max(this.$size.scrollerWidth - 2 * this.$padding, Math.round(charCount * this.characterWidth));
+ };
+ this.updateFrontMarkers = function() {
+ this.$markerFront.setMarkers(this.session.getMarkers(true));
+ this.$loop.schedule(this.CHANGE_MARKER_FRONT);
+ };
+ this.updateBackMarkers = function() {
+ this.$markerBack.setMarkers(this.session.getMarkers());
+ this.$loop.schedule(this.CHANGE_MARKER_BACK);
+ };
+ this.addGutterDecoration = function(row, className){
+ this.$gutterLayer.addGutterDecoration(row, className);
+ };
+ this.removeGutterDecoration = function(row, className){
+ this.$gutterLayer.removeGutterDecoration(row, className);
+ };
+ this.updateBreakpoints = function(rows) {
+ this.$loop.schedule(this.CHANGE_GUTTER);
+ };
+ this.setAnnotations = function(annotations) {
+ this.$gutterLayer.setAnnotations(annotations);
+ this.$loop.schedule(this.CHANGE_GUTTER);
+ };
+ this.updateCursor = function() {
+ this.$loop.schedule(this.CHANGE_CURSOR);
+ };
+ this.hideCursor = function() {
+ this.$cursorLayer.hideCursor();
+ };
+ this.showCursor = function() {
+ this.$cursorLayer.showCursor();
+ };
+
+ this.scrollSelectionIntoView = function(anchor, lead, offset) {
+ this.scrollCursorIntoView(anchor, offset);
+ this.scrollCursorIntoView(lead, offset);
+ };
+ this.scrollCursorIntoView = function(cursor, offset, $viewMargin) {
+ if (this.$size.scrollerHeight === 0)
+ return;
+
+ var pos = this.$cursorLayer.getPixelPosition(cursor);
+
+ var left = pos.left;
+ var top = pos.top;
+
+ var topMargin = $viewMargin && $viewMargin.top || 0;
+ var bottomMargin = $viewMargin && $viewMargin.bottom || 0;
+
+ var scrollTop = this.$scrollAnimation ? this.session.getScrollTop() : this.scrollTop;
+
+ if (scrollTop + topMargin > top) {
+ if (offset)
+ top -= offset * this.$size.scrollerHeight;
+ if (top === 0)
+ top = -this.scrollMargin.top;
+ this.session.setScrollTop(top);
+ } else if (scrollTop + this.$size.scrollerHeight - bottomMargin < top + this.lineHeight) {
+ if (offset)
+ top += offset * this.$size.scrollerHeight;
+ this.session.setScrollTop(top + this.lineHeight - this.$size.scrollerHeight);
+ }
+
+ var scrollLeft = this.scrollLeft;
+
+ if (scrollLeft > left) {
+ if (left < this.$padding + 2 * this.layerConfig.characterWidth)
+ left = -this.scrollMargin.left;
+ this.session.setScrollLeft(left);
+ } else if (scrollLeft + this.$size.scrollerWidth < left + this.characterWidth) {
+ this.session.setScrollLeft(Math.round(left + this.characterWidth - this.$size.scrollerWidth));
+ } else if (scrollLeft <= this.$padding && left - scrollLeft < this.characterWidth) {
+ this.session.setScrollLeft(0);
+ }
+ };
+ this.getScrollTop = function() {
+ return this.session.getScrollTop();
+ };
+ this.getScrollLeft = function() {
+ return this.session.getScrollLeft();
+ };
+ this.getScrollTopRow = function() {
+ return this.scrollTop / this.lineHeight;
+ };
+ this.getScrollBottomRow = function() {
+ return Math.max(0, Math.floor((this.scrollTop + this.$size.scrollerHeight) / this.lineHeight) - 1);
+ };
+ this.scrollToRow = function(row) {
+ this.session.setScrollTop(row * this.lineHeight);
+ };
+
+ this.alignCursor = function(cursor, alignment) {
+ if (typeof cursor == "number")
+ cursor = {row: cursor, column: 0};
+
+ var pos = this.$cursorLayer.getPixelPosition(cursor);
+ var h = this.$size.scrollerHeight - this.lineHeight;
+ var offset = pos.top - h * (alignment || 0);
+
+ this.session.setScrollTop(offset);
+ return offset;
+ };
+
+ this.STEPS = 8;
+ this.$calcSteps = function(fromValue, toValue){
+ var i = 0;
+ var l = this.STEPS;
+ var steps = [];
+
+ var func = function(t, x_min, dx) {
+ return dx * (Math.pow(t - 1, 3) + 1) + x_min;
+ };
+
+ for (i = 0; i < l; ++i)
+ steps.push(func(i / this.STEPS, fromValue, toValue - fromValue));
+
+ return steps;
+ };
+ this.scrollToLine = function(line, center, animate, callback) {
+ var pos = this.$cursorLayer.getPixelPosition({row: line, column: 0});
+ var offset = pos.top;
+ if (center)
+ offset -= this.$size.scrollerHeight / 2;
+
+ var initialScroll = this.scrollTop;
+ this.session.setScrollTop(offset);
+ if (animate !== false)
+ this.animateScrolling(initialScroll, callback);
+ };
+
+ this.animateScrolling = function(fromValue, callback) {
+ var toValue = this.scrollTop;
+ if (!this.$animatedScroll)
+ return;
+ var _self = this;
+
+ if (fromValue == toValue)
+ return;
+
+ if (this.$scrollAnimation) {
+ var oldSteps = this.$scrollAnimation.steps;
+ if (oldSteps.length) {
+ fromValue = oldSteps[0];
+ if (fromValue == toValue)
+ return;
+ }
+ }
+
+ var steps = _self.$calcSteps(fromValue, toValue);
+ this.$scrollAnimation = {from: fromValue, to: toValue, steps: steps};
+
+ clearInterval(this.$timer);
+
+ _self.session.setScrollTop(steps.shift());
+ _self.session.$scrollTop = toValue;
+ this.$timer = setInterval(function() {
+ if (steps.length) {
+ _self.session.setScrollTop(steps.shift());
+ _self.session.$scrollTop = toValue;
+ } else if (toValue != null) {
+ _self.session.$scrollTop = -1;
+ _self.session.setScrollTop(toValue);
+ toValue = null;
+ } else {
+ _self.$timer = clearInterval(_self.$timer);
+ _self.$scrollAnimation = null;
+ callback && callback();
+ }
+ }, 10);
+ };
+ this.scrollToY = function(scrollTop) {
+ if (this.scrollTop !== scrollTop) {
+ this.$loop.schedule(this.CHANGE_SCROLL);
+ this.scrollTop = scrollTop;
+ }
+ };
+ this.scrollToX = function(scrollLeft) {
+ if (this.scrollLeft !== scrollLeft)
+ this.scrollLeft = scrollLeft;
+ this.$loop.schedule(this.CHANGE_H_SCROLL);
+ };
+ this.scrollTo = function(x, y) {
+ this.session.setScrollTop(y);
+ this.session.setScrollLeft(y);
+ };
+ this.scrollBy = function(deltaX, deltaY) {
+ deltaY && this.session.setScrollTop(this.session.getScrollTop() + deltaY);
+ deltaX && this.session.setScrollLeft(this.session.getScrollLeft() + deltaX);
+ };
+ this.isScrollableBy = function(deltaX, deltaY) {
+ if (deltaY < 0 && this.session.getScrollTop() >= 1 - this.scrollMargin.top)
+ return true;
+ if (deltaY > 0 && this.session.getScrollTop() + this.$size.scrollerHeight
+ - this.layerConfig.maxHeight < -1 + this.scrollMargin.bottom)
+ return true;
+ if (deltaX < 0 && this.session.getScrollLeft() >= 1 - this.scrollMargin.left)
+ return true;
+ if (deltaX > 0 && this.session.getScrollLeft() + this.$size.scrollerWidth
+ - this.layerConfig.width < -1 + this.scrollMargin.right)
+ return true;
+ };
+
+ this.pixelToScreenCoordinates = function(x, y) {
+ var canvasPos = this.scroller.getBoundingClientRect();
+
+ var offset = (x + this.scrollLeft - canvasPos.left - this.$padding) / this.characterWidth;
+ var row = Math.floor((y + this.scrollTop - canvasPos.top) / this.lineHeight);
+ var col = Math.round(offset);
+
+ return {row: row, column: col, side: offset - col > 0 ? 1 : -1};
+ };
+
+ this.screenToTextCoordinates = function(x, y) {
+ var canvasPos = this.scroller.getBoundingClientRect();
+
+ var col = Math.round(
+ (x + this.scrollLeft - canvasPos.left - this.$padding) / this.characterWidth
+ );
+
+ var row = (y + this.scrollTop - canvasPos.top) / this.lineHeight;
+
+ return this.session.screenToDocumentPosition(row, Math.max(col, 0));
+ };
+ this.textToScreenCoordinates = function(row, column) {
+ var canvasPos = this.scroller.getBoundingClientRect();
+ var pos = this.session.documentToScreenPosition(row, column);
+
+ var x = this.$padding + Math.round(pos.column * this.characterWidth);
+ var y = pos.row * this.lineHeight;
+
+ return {
+ pageX: canvasPos.left + x - this.scrollLeft,
+ pageY: canvasPos.top + y - this.scrollTop
+ };
+ };
+ this.visualizeFocus = function() {
+ dom.addCssClass(this.container, "ace_focus");
+ };
+ this.visualizeBlur = function() {
+ dom.removeCssClass(this.container, "ace_focus");
+ };
+ this.showComposition = function(position) {
+ if (!this.$composition)
+ this.$composition = {
+ keepTextAreaAtCursor: this.$keepTextAreaAtCursor,
+ cssText: this.textarea.style.cssText
+ };
+
+ this.$keepTextAreaAtCursor = true;
+ dom.addCssClass(this.textarea, "ace_composition");
+ this.textarea.style.cssText = "";
+ this.$moveTextAreaToCursor();
+ };
+ this.setCompositionText = function(text) {
+ this.$moveTextAreaToCursor();
+ };
+ this.hideComposition = function() {
+ if (!this.$composition)
+ return;
+
+ dom.removeCssClass(this.textarea, "ace_composition");
+ this.$keepTextAreaAtCursor = this.$composition.keepTextAreaAtCursor;
+ this.textarea.style.cssText = this.$composition.cssText;
+ this.$composition = null;
+ };
+ this.setTheme = function(theme, cb) {
+ var _self = this;
+ this.$themeId = theme;
+ _self._dispatchEvent('themeChange',{theme:theme});
+
+ if (!theme || typeof theme == "string") {
+ var moduleName = theme || this.$options.theme.initialValue;
+ config.loadModule(["theme", moduleName], afterLoad);
+ } else {
+ afterLoad(theme);
+ }
+
+ function afterLoad(module) {
+ if (_self.$themeId != theme)
+ return cb && cb();
+ if (!module.cssClass)
+ return;
+ dom.importCssString(
+ module.cssText,
+ module.cssClass,
+ _self.container.ownerDocument
+ );
+
+ if (_self.theme)
+ dom.removeCssClass(_self.container, _self.theme.cssClass);
+
+ var padding = "padding" in module ? module.padding
+ : "padding" in (_self.theme || {}) ? 4 : _self.$padding;
+ if (_self.$padding && padding != _self.$padding)
+ _self.setPadding(padding);
+ _self.$theme = module.cssClass;
+
+ _self.theme = module;
+ dom.addCssClass(_self.container, module.cssClass);
+ dom.setCssClass(_self.container, "ace_dark", module.isDark);
+ if (_self.$size) {
+ _self.$size.width = 0;
+ _self.$updateSizeAsync();
+ }
+
+ _self._dispatchEvent('themeLoaded', {theme:module});
+ cb && cb();
+ }
+ };
+ this.getTheme = function() {
+ return this.$themeId;
+ };
+ this.setStyle = function(style, include) {
+ dom.setCssClass(this.container, style, include !== false);
+ };
+ this.unsetStyle = function(style) {
+ dom.removeCssClass(this.container, style);
+ };
+
+ this.setCursorStyle = function(style) {
+ if (this.scroller.style.cursor != style)
+ this.scroller.style.cursor = style;
+ };
+ this.setMouseCursor = function(cursorStyle) {
+ this.scroller.style.cursor = cursorStyle;
+ };
+ this.destroy = function() {
+ this.$textLayer.destroy();
+ this.$cursorLayer.destroy();
+ };
+
+}).call(VirtualRenderer.prototype);
+
+
+config.defineOptions(VirtualRenderer.prototype, "renderer", {
+ animatedScroll: {initialValue: false},
+ showInvisibles: {
+ set: function(value) {
+ if (this.$textLayer.setShowInvisibles(value))
+ this.$loop.schedule(this.CHANGE_TEXT);
+ },
+ initialValue: false
+ },
+ showPrintMargin: {
+ set: function() { this.$updatePrintMargin(); },
+ initialValue: true
+ },
+ printMarginColumn: {
+ set: function() { this.$updatePrintMargin(); },
+ initialValue: 80
+ },
+ printMargin: {
+ set: function(val) {
+ if (typeof val == "number")
+ this.$printMarginColumn = val;
+ this.$showPrintMargin = !!val;
+ this.$updatePrintMargin();
+ },
+ get: function() {
+ return this.$showPrintMargin && this.$printMarginColumn;
+ }
+ },
+ showGutter: {
+ set: function(show){
+ this.$gutter.style.display = show ? "block" : "none";
+ this.$loop.schedule(this.CHANGE_FULL);
+ this.onGutterResize();
+ },
+ initialValue: true
+ },
+ fadeFoldWidgets: {
+ set: function(show) {
+ dom.setCssClass(this.$gutter, "ace_fade-fold-widgets", show);
+ },
+ initialValue: false
+ },
+ showFoldWidgets: {
+ set: function(show) {this.$gutterLayer.setShowFoldWidgets(show)},
+ initialValue: true
+ },
+ showLineNumbers: {
+ set: function(show) {
+ this.$gutterLayer.setShowLineNumbers(show);
+ this.$loop.schedule(this.CHANGE_GUTTER);
+ },
+ initialValue: true
+ },
+ displayIndentGuides: {
+ set: function(show) {
+ if (this.$textLayer.setDisplayIndentGuides(show))
+ this.$loop.schedule(this.CHANGE_TEXT);
+ },
+ initialValue: true
+ },
+ highlightGutterLine: {
+ set: function(shouldHighlight) {
+ if (!this.$gutterLineHighlight) {
+ this.$gutterLineHighlight = dom.createElement("div");
+ this.$gutterLineHighlight.className = "ace_gutter-active-line";
+ this.$gutter.appendChild(this.$gutterLineHighlight);
+ return;
+ }
+
+ this.$gutterLineHighlight.style.display = shouldHighlight ? "" : "none";
+ if (this.$cursorLayer.$pixelPos)
+ this.$updateGutterLineHighlight();
+ },
+ initialValue: false,
+ value: true
+ },
+ hScrollBarAlwaysVisible: {
+ set: function(val) {
+ if (!this.$hScrollBarAlwaysVisible || !this.$horizScroll)
+ this.$loop.schedule(this.CHANGE_SCROLL);
+ },
+ initialValue: false
+ },
+ vScrollBarAlwaysVisible: {
+ set: function(val) {
+ if (!this.$vScrollBarAlwaysVisible || !this.$vScroll)
+ this.$loop.schedule(this.CHANGE_SCROLL);
+ },
+ initialValue: false
+ },
+ fontSize: {
+ set: function(size) {
+ if (typeof size == "number")
+ size = size + "px";
+ this.container.style.fontSize = size;
+ this.updateFontSize();
+ },
+ initialValue: 12
+ },
+ fontFamily: {
+ set: function(name) {
+ this.container.style.fontFamily = name;
+ this.updateFontSize();
+ }
+ },
+ maxLines: {
+ set: function(val) {
+ this.updateFull();
+ }
+ },
+ minLines: {
+ set: function(val) {
+ this.updateFull();
+ }
+ },
+ scrollPastEnd: {
+ set: function(val) {
+ val = +val || 0;
+ if (this.$scrollPastEnd == val)
+ return;
+ this.$scrollPastEnd = val;
+ this.$loop.schedule(this.CHANGE_SCROLL);
+ },
+ initialValue: 0,
+ handlesSet: true
+ },
+ fixedWidthGutter: {
+ set: function(val) {
+ this.$gutterLayer.$fixedWidth = !!val;
+ this.$loop.schedule(this.CHANGE_GUTTER);
+ }
+ },
+ theme: {
+ set: function(val) { this.setTheme(val) },
+ get: function() { return this.$themeId || this.theme; },
+ initialValue: "./theme/textmate",
+ handlesSet: true
+ }
+});
+
+exports.VirtualRenderer = VirtualRenderer;
+});
+
+define("ace/worker/worker_client",["require","exports","module","ace/lib/oop","ace/lib/net","ace/lib/event_emitter","ace/config"], function(require, exports, module) {
+"use strict";
+
+var oop = require("../lib/oop");
+var net = require("../lib/net");
+var EventEmitter = require("../lib/event_emitter").EventEmitter;
+var config = require("../config");
+
+var WorkerClient = function(topLevelNamespaces, mod, classname, workerUrl) {
+ this.$sendDeltaQueue = this.$sendDeltaQueue.bind(this);
+ this.changeListener = this.changeListener.bind(this);
+ this.onMessage = this.onMessage.bind(this);
+ if (require.nameToUrl && !require.toUrl)
+ require.toUrl = require.nameToUrl;
+
+ if (config.get("packaged") || !require.toUrl) {
+ workerUrl = workerUrl || config.moduleUrl(mod, "worker");
+ } else {
+ var normalizePath = this.$normalizePath;
+ workerUrl = workerUrl || normalizePath(require.toUrl("ace/worker/worker.js", null, "_"));
+
+ var tlns = {};
+ topLevelNamespaces.forEach(function(ns) {
+ tlns[ns] = normalizePath(require.toUrl(ns, null, "_").replace(/(\.js)?(\?.*)?$/, ""));
+ });
+ }
+
+ try {
+ this.$worker = new Worker(workerUrl);
+ } catch(e) {
+ if (e instanceof window.DOMException) {
+ var blob = this.$workerBlob(workerUrl);
+ var URL = window.URL || window.webkitURL;
+ var blobURL = URL.createObjectURL(blob);
+
+ this.$worker = new Worker(blobURL);
+ URL.revokeObjectURL(blobURL);
+ } else {
+ throw e;
+ }
+ }
+ this.$worker.postMessage({
+ init : true,
+ tlns : tlns,
+ module : mod,
+ classname : classname
+ });
+
+ this.callbackId = 1;
+ this.callbacks = {};
+
+ this.$worker.onmessage = this.onMessage;
+};
+
+(function(){
+
+ oop.implement(this, EventEmitter);
+
+ this.onMessage = function(e) {
+ var msg = e.data;
+ switch(msg.type) {
+ case "event":
+ this._signal(msg.name, {data: msg.data});
+ break;
+ case "call":
+ var callback = this.callbacks[msg.id];
+ if (callback) {
+ callback(msg.data);
+ delete this.callbacks[msg.id];
+ }
+ break;
+ case "error":
+ this.reportError(msg.data);
+ break;
+ case "log":
+ window.console && console.log && console.log.apply(console, msg.data);
+ break;
+ }
+ };
+
+ this.reportError = function(err) {
+ window.console && console.error && console.error(err);
+ };
+
+ this.$normalizePath = function(path) {
+ return net.qualifyURL(path);
+ };
+
+ this.terminate = function() {
+ this._signal("terminate", {});
+ this.deltaQueue = null;
+ this.$worker.terminate();
+ this.$worker = null;
+ if (this.$doc)
+ this.$doc.off("change", this.changeListener);
+ this.$doc = null;
+ };
+
+ this.send = function(cmd, args) {
+ this.$worker.postMessage({command: cmd, args: args});
+ };
+
+ this.call = function(cmd, args, callback) {
+ if (callback) {
+ var id = this.callbackId++;
+ this.callbacks[id] = callback;
+ args.push(id);
+ }
+ this.send(cmd, args);
+ };
+
+ this.emit = function(event, data) {
+ try {
+ this.$worker.postMessage({event: event, data: {data: data.data}});
+ }
+ catch(ex) {
+ console.error(ex.stack);
+ }
+ };
+
+ this.attachToDocument = function(doc) {
+ if(this.$doc)
+ this.terminate();
+
+ this.$doc = doc;
+ this.call("setValue", [doc.getValue()]);
+ doc.on("change", this.changeListener);
+ };
+
+ this.changeListener = function(e) {
+ if (!this.deltaQueue) {
+ this.deltaQueue = [e.data];
+ setTimeout(this.$sendDeltaQueue, 0);
+ } else
+ this.deltaQueue.push(e.data);
+ };
+
+ this.$sendDeltaQueue = function() {
+ var q = this.deltaQueue;
+ if (!q) return;
+ this.deltaQueue = null;
+ if (q.length > 20 && q.length > this.$doc.getLength() >> 1) {
+ this.call("setValue", [this.$doc.getValue()]);
+ } else
+ this.emit("change", {data: q});
+ };
+
+ this.$workerBlob = function(workerUrl) {
+ var script = "importScripts('" + net.qualifyURL(workerUrl) + "');";
+ try {
+ return new Blob([script], {"type": "application/javascript"});
+ } catch (e) { // Backwards-compatibility
+ var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;
+ var blobBuilder = new BlobBuilder();
+ blobBuilder.append(script);
+ return blobBuilder.getBlob("application/javascript");
+ }
+ };
+
+}).call(WorkerClient.prototype);
+
+
+var UIWorkerClient = function(topLevelNamespaces, mod, classname) {
+ this.$sendDeltaQueue = this.$sendDeltaQueue.bind(this);
+ this.changeListener = this.changeListener.bind(this);
+ this.callbackId = 1;
+ this.callbacks = {};
+ this.messageBuffer = [];
+
+ var main = null;
+ var emitSync = false;
+ var sender = Object.create(EventEmitter);
+ var _self = this;
+
+ this.$worker = {};
+ this.$worker.terminate = function() {};
+ this.$worker.postMessage = function(e) {
+ _self.messageBuffer.push(e);
+ if (main) {
+ if (emitSync)
+ setTimeout(processNext);
+ else
+ processNext();
+ }
+ };
+ this.setEmitSync = function(val) { emitSync = val };
+
+ var processNext = function() {
+ var msg = _self.messageBuffer.shift();
+ if (msg.command)
+ main[msg.command].apply(main, msg.args);
+ else if (msg.event)
+ sender._signal(msg.event, msg.data);
+ };
+
+ sender.postMessage = function(msg) {
+ _self.onMessage({data: msg});
+ };
+ sender.callback = function(data, callbackId) {
+ this.postMessage({type: "call", id: callbackId, data: data});
+ };
+ sender.emit = function(name, data) {
+ this.postMessage({type: "event", name: name, data: data});
+ };
+
+ config.loadModule(["worker", mod], function(Main) {
+ main = new Main[classname](sender);
+ while (_self.messageBuffer.length)
+ processNext();
+ });
+};
+
+UIWorkerClient.prototype = WorkerClient.prototype;
+
+exports.UIWorkerClient = UIWorkerClient;
+exports.WorkerClient = WorkerClient;
+
+});
+
+define("ace/placeholder",["require","exports","module","ace/range","ace/lib/event_emitter","ace/lib/oop"], function(require, exports, module) {
+"use strict";
+
+var Range = require("./range").Range;
+var EventEmitter = require("./lib/event_emitter").EventEmitter;
+var oop = require("./lib/oop");
+
+var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) {
+ var _self = this;
+ this.length = length;
+ this.session = session;
+ this.doc = session.getDocument();
+ this.mainClass = mainClass;
+ this.othersClass = othersClass;
+ this.$onUpdate = this.onUpdate.bind(this);
+ this.doc.on("change", this.$onUpdate);
+ this.$others = others;
+
+ this.$onCursorChange = function() {
+ setTimeout(function() {
+ _self.onCursorChange();
+ });
+ };
+
+ this.$pos = pos;
+ var undoStack = session.getUndoManager().$undoStack || session.getUndoManager().$undostack || {length: -1};
+ this.$undoStackDepth = undoStack.length;
+ this.setup();
+
+ session.selection.on("changeCursor", this.$onCursorChange);
+};
+
+(function() {
+
+ oop.implement(this, EventEmitter);
+ this.setup = function() {
+ var _self = this;
+ var doc = this.doc;
+ var session = this.session;
+ var pos = this.$pos;
+
+ this.selectionBefore = session.selection.toJSON();
+ if (session.selection.inMultiSelectMode)
+ session.selection.toSingleRange();
+
+ this.pos = doc.createAnchor(pos.row, pos.column);
+ this.markerId = session.addMarker(new Range(pos.row, pos.column, pos.row, pos.column + this.length), this.mainClass, null, false);
+ this.pos.on("change", function(event) {
+ session.removeMarker(_self.markerId);
+ _self.markerId = session.addMarker(new Range(event.value.row, event.value.column, event.value.row, event.value.column+_self.length), _self.mainClass, null, false);
+ });
+ this.others = [];
+ this.$others.forEach(function(other) {
+ var anchor = doc.createAnchor(other.row, other.column);
+ _self.others.push(anchor);
+ });
+ session.setUndoSelect(false);
+ };
+ this.showOtherMarkers = function() {
+ if(this.othersActive) return;
+ var session = this.session;
+ var _self = this;
+ this.othersActive = true;
+ this.others.forEach(function(anchor) {
+ anchor.markerId = session.addMarker(new Range(anchor.row, anchor.column, anchor.row, anchor.column+_self.length), _self.othersClass, null, false);
+ anchor.on("change", function(event) {
+ session.removeMarker(anchor.markerId);
+ anchor.markerId = session.addMarker(new Range(event.value.row, event.value.column, event.value.row, event.value.column+_self.length), _self.othersClass, null, false);
+ });
+ });
+ };
+ this.hideOtherMarkers = function() {
+ if(!this.othersActive) return;
+ this.othersActive = false;
+ for (var i = 0; i < this.others.length; i++) {
+ this.session.removeMarker(this.others[i].markerId);
+ }
+ };
+ this.onUpdate = function(event) {
+ var delta = event.data;
+ var range = delta.range;
+ if(range.start.row !== range.end.row) return;
+ if(range.start.row !== this.pos.row) return;
+ if (this.$updating) return;
+ this.$updating = true;
+ var lengthDiff = delta.action === "insertText" ? range.end.column - range.start.column : range.start.column - range.end.column;
+
+ if(range.start.column >= this.pos.column && range.start.column <= this.pos.column + this.length + 1) {
+ var distanceFromStart = range.start.column - this.pos.column;
+ this.length += lengthDiff;
+ if(!this.session.$fromUndo) {
+ if(delta.action === "insertText") {
+ for (var i = this.others.length - 1; i >= 0; i--) {
+ var otherPos = this.others[i];
+ var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart};
+ if(otherPos.row === range.start.row && range.start.column < otherPos.column)
+ newPos.column += lengthDiff;
+ this.doc.insert(newPos, delta.text);
+ }
+ } else if(delta.action === "removeText") {
+ for (var i = this.others.length - 1; i >= 0; i--) {
+ var otherPos = this.others[i];
+ var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart};
+ if(otherPos.row === range.start.row && range.start.column < otherPos.column)
+ newPos.column += lengthDiff;
+ this.doc.remove(new Range(newPos.row, newPos.column, newPos.row, newPos.column - lengthDiff));
+ }
+ }
+ if(range.start.column === this.pos.column && delta.action === "insertText") {
+ setTimeout(function() {
+ this.pos.setPosition(this.pos.row, this.pos.column - lengthDiff);
+ for (var i = 0; i < this.others.length; i++) {
+ var other = this.others[i];
+ var newPos = {row: other.row, column: other.column - lengthDiff};
+ if(other.row === range.start.row && range.start.column < other.column)
+ newPos.column += lengthDiff;
+ other.setPosition(newPos.row, newPos.column);
+ }
+ }.bind(this), 0);
+ }
+ else if(range.start.column === this.pos.column && delta.action === "removeText") {
+ setTimeout(function() {
+ for (var i = 0; i < this.others.length; i++) {
+ var other = this.others[i];
+ if(other.row === range.start.row && range.start.column < other.column) {
+ other.setPosition(other.row, other.column - lengthDiff);
+ }
+ }
+ }.bind(this), 0);
+ }
+ }
+ this.pos._emit("change", {value: this.pos});
+ for (var i = 0; i < this.others.length; i++) {
+ this.others[i]._emit("change", {value: this.others[i]});
+ }
+ }
+ this.$updating = false;
+ };
+
+ this.onCursorChange = function(event) {
+ if (this.$updating || !this.session) return;
+ var pos = this.session.selection.getCursor();
+ if (pos.row === this.pos.row && pos.column >= this.pos.column && pos.column <= this.pos.column + this.length) {
+ this.showOtherMarkers();
+ this._emit("cursorEnter", event);
+ } else {
+ this.hideOtherMarkers();
+ this._emit("cursorLeave", event);
+ }
+ };
+ this.detach = function() {
+ this.session.removeMarker(this.markerId);
+ this.hideOtherMarkers();
+ this.doc.removeEventListener("change", this.$onUpdate);
+ this.session.selection.removeEventListener("changeCursor", this.$onCursorChange);
+ this.pos.detach();
+ for (var i = 0; i < this.others.length; i++) {
+ this.others[i].detach();
+ }
+ this.session.setUndoSelect(true);
+ this.session = null;
+ };
+ this.cancel = function() {
+ if(this.$undoStackDepth === -1)
+ throw Error("Canceling placeholders only supported with undo manager attached to session.");
+ var undoManager = this.session.getUndoManager();
+ var undosRequired = (undoManager.$undoStack || undoManager.$undostack).length - this.$undoStackDepth;
+ for (var i = 0; i < undosRequired; i++) {
+ undoManager.undo(true);
+ }
+ if (this.selectionBefore)
+ this.session.selection.fromJSON(this.selectionBefore);
+ };
+}).call(PlaceHolder.prototype);
+
+
+exports.PlaceHolder = PlaceHolder;
+});
+
+define("ace/mouse/multi_select_handler",["require","exports","module","ace/lib/event","ace/lib/useragent"], function(require, exports, module) {
+
+var event = require("../lib/event");
+var useragent = require("../lib/useragent");
+function isSamePoint(p1, p2) {
+ return p1.row == p2.row && p1.column == p2.column;
+}
+
+function onMouseDown(e) {
+ var ev = e.domEvent;
+ var alt = ev.altKey;
+ var shift = ev.shiftKey;
+ var ctrl = ev.ctrlKey;
+ var accel = e.getAccelKey();
+ var button = e.getButton();
+
+ if (ctrl && useragent.isMac)
+ button = ev.button;
+
+ if (e.editor.inMultiSelectMode && button == 2) {
+ e.editor.textInput.onContextMenu(e.domEvent);
+ return;
+ }
+
+ if (!ctrl && !alt && !accel) {
+ if (button === 0 && e.editor.inMultiSelectMode)
+ e.editor.exitMultiSelectMode();
+ return;
+ }
+
+ if (button !== 0)
+ return;
+
+ var editor = e.editor;
+ var selection = editor.selection;
+ var isMultiSelect = editor.inMultiSelectMode;
+ var pos = e.getDocumentPosition();
+ var cursor = selection.getCursor();
+ var inSelection = e.inSelection() || (selection.isEmpty() && isSamePoint(pos, cursor));
+
+ var mouseX = e.x, mouseY = e.y;
+ var onMouseSelection = function(e) {
+ mouseX = e.clientX;
+ mouseY = e.clientY;
+ };
+
+ var session = editor.session;
+ var screenAnchor = editor.renderer.pixelToScreenCoordinates(mouseX, mouseY);
+ var screenCursor = screenAnchor;
+
+ var selectionMode;
+ if (editor.$mouseHandler.$enableJumpToDef) {
+ if (ctrl && alt || accel && alt)
+ selectionMode = "add";
+ else if (alt)
+ selectionMode = "block";
+ } else {
+ if (accel && !alt) {
+ selectionMode = "add";
+ if (!isMultiSelect && shift)
+ return;
+ } else if (alt) {
+ selectionMode = "block";
+ }
+ }
+
+ if (selectionMode && useragent.isMac && ev.ctrlKey) {
+ editor.$mouseHandler.cancelContextMenu();
+ }
+
+ if (selectionMode == "add") {
+ if (!isMultiSelect && inSelection)
+ return; // dragging
+
+ if (!isMultiSelect) {
+ var range = selection.toOrientedRange();
+ editor.addSelectionMarker(range);
+ }
+
+ var oldRange = selection.rangeList.rangeAtPoint(pos);
+
+
+ editor.$blockScrolling++;
+ editor.inVirtualSelectionMode = true;
+
+ if (shift) {
+ oldRange = null;
+ range = selection.ranges[0];
+ editor.removeSelectionMarker(range);
+ }
+ editor.once("mouseup", function() {
+ var tmpSel = selection.toOrientedRange();
+
+ if (oldRange && tmpSel.isEmpty() && isSamePoint(oldRange.cursor, tmpSel.cursor))
+ selection.substractPoint(tmpSel.cursor);
+ else {
+ if (shift) {
+ selection.substractPoint(range.cursor);
+ } else if (range) {
+ editor.removeSelectionMarker(range);
+ selection.addRange(range);
+ }
+ selection.addRange(tmpSel);
+ }
+ editor.$blockScrolling--;
+ editor.inVirtualSelectionMode = false;
+ });
+
+ } else if (selectionMode == "block") {
+ e.stop();
+ editor.inVirtualSelectionMode = true;
+ var initialRange;
+ var rectSel = [];
+ var blockSelect = function() {
+ var newCursor = editor.renderer.pixelToScreenCoordinates(mouseX, mouseY);
+ var cursor = session.screenToDocumentPosition(newCursor.row, newCursor.column);
+
+ if (isSamePoint(screenCursor, newCursor) && isSamePoint(cursor, selection.lead))
+ return;
+ screenCursor = newCursor;
+
+ editor.$blockScrolling++;
+ editor.selection.moveToPosition(cursor);
+ editor.renderer.scrollCursorIntoView();
+
+ editor.removeSelectionMarkers(rectSel);
+ rectSel = selection.rectangularRangeBlock(screenCursor, screenAnchor);
+ if (editor.$mouseHandler.$clickSelection && rectSel.length == 1 && rectSel[0].isEmpty())
+ rectSel[0] = editor.$mouseHandler.$clickSelection.clone();
+ rectSel.forEach(editor.addSelectionMarker, editor);
+ editor.updateSelectionMarkers();
+ editor.$blockScrolling--;
+ };
+ editor.$blockScrolling++;
+ if (isMultiSelect && !accel) {
+ selection.toSingleRange();
+ } else if (!isMultiSelect && accel) {
+ initialRange = selection.toOrientedRange();
+ editor.addSelectionMarker(initialRange);
+ }
+
+ if (shift)
+ screenAnchor = session.documentToScreenPosition(selection.lead);
+ else
+ selection.moveToPosition(pos);
+ editor.$blockScrolling--;
+
+ screenCursor = {row: -1, column: -1};
+
+ var onMouseSelectionEnd = function(e) {
+ clearInterval(timerId);
+ editor.removeSelectionMarkers(rectSel);
+ if (!rectSel.length)
+ rectSel = [selection.toOrientedRange()];
+ editor.$blockScrolling++;
+ if (initialRange) {
+ editor.removeSelectionMarker(initialRange);
+ selection.toSingleRange(initialRange);
+ }
+ for (var i = 0; i < rectSel.length; i++)
+ selection.addRange(rectSel[i]);
+ editor.inVirtualSelectionMode = false;
+ editor.$mouseHandler.$clickSelection = null;
+ editor.$blockScrolling--;
+ };
+
+ var onSelectionInterval = blockSelect;
+
+ event.capture(editor.container, onMouseSelection, onMouseSelectionEnd);
+ var timerId = setInterval(function() {onSelectionInterval();}, 20);
+
+ return e.preventDefault();
+ }
+}
+
+
+exports.onMouseDown = onMouseDown;
+
+});
+
+define("ace/commands/multi_select_commands",["require","exports","module","ace/keyboard/hash_handler"], function(require, exports, module) {
+exports.defaultCommands = [{
+ name: "addCursorAbove",
+ exec: function(editor) { editor.selectMoreLines(-1); },
+ bindKey: {win: "Ctrl-Alt-Up", mac: "Ctrl-Alt-Up"},
+ scrollIntoView: "cursor",
+ readonly: true
+}, {
+ name: "addCursorBelow",
+ exec: function(editor) { editor.selectMoreLines(1); },
+ bindKey: {win: "Ctrl-Alt-Down", mac: "Ctrl-Alt-Down"},
+ scrollIntoView: "cursor",
+ readonly: true
+}, {
+ name: "addCursorAboveSkipCurrent",
+ exec: function(editor) { editor.selectMoreLines(-1, true); },
+ bindKey: {win: "Ctrl-Alt-Shift-Up", mac: "Ctrl-Alt-Shift-Up"},
+ scrollIntoView: "cursor",
+ readonly: true
+}, {
+ name: "addCursorBelowSkipCurrent",
+ exec: function(editor) { editor.selectMoreLines(1, true); },
+ bindKey: {win: "Ctrl-Alt-Shift-Down", mac: "Ctrl-Alt-Shift-Down"},
+ scrollIntoView: "cursor",
+ readonly: true
+}, {
+ name: "selectMoreBefore",
+ exec: function(editor) { editor.selectMore(-1); },
+ bindKey: {win: "Ctrl-Alt-Left", mac: "Ctrl-Alt-Left"},
+ scrollIntoView: "cursor",
+ readonly: true
+}, {
+ name: "selectMoreAfter",
+ exec: function(editor) { editor.selectMore(1); },
+ bindKey: {win: "Ctrl-Alt-Right", mac: "Ctrl-Alt-Right"},
+ scrollIntoView: "cursor",
+ readonly: true
+}, {
+ name: "selectNextBefore",
+ exec: function(editor) { editor.selectMore(-1, true); },
+ bindKey: {win: "Ctrl-Alt-Shift-Left", mac: "Ctrl-Alt-Shift-Left"},
+ scrollIntoView: "cursor",
+ readonly: true
+}, {
+ name: "selectNextAfter",
+ exec: function(editor) { editor.selectMore(1, true); },
+ bindKey: {win: "Ctrl-Alt-Shift-Right", mac: "Ctrl-Alt-Shift-Right"},
+ scrollIntoView: "cursor",
+ readonly: true
+}, {
+ name: "splitIntoLines",
+ exec: function(editor) { editor.multiSelect.splitIntoLines(); },
+ bindKey: {win: "Ctrl-Alt-L", mac: "Ctrl-Alt-L"},
+ readonly: true
+}, {
+ name: "alignCursors",
+ exec: function(editor) { editor.alignCursors(); },
+ bindKey: {win: "Ctrl-Alt-A", mac: "Ctrl-Alt-A"},
+ scrollIntoView: "cursor"
+}, {
+ name: "findAll",
+ exec: function(editor) { editor.findAll(); },
+ bindKey: {win: "Ctrl-Alt-K", mac: "Ctrl-Alt-G"},
+ scrollIntoView: "cursor",
+ readonly: true
+}];
+exports.multiSelectCommands = [{
+ name: "singleSelection",
+ bindKey: "esc",
+ exec: function(editor) { editor.exitMultiSelectMode(); },
+ scrollIntoView: "cursor",
+ readonly: true,
+ isAvailable: function(editor) {return editor && editor.inMultiSelectMode}
+}];
+
+var HashHandler = require("../keyboard/hash_handler").HashHandler;
+exports.keyboardHandler = new HashHandler(exports.multiSelectCommands);
+
+});
+
+define("ace/multi_select",["require","exports","module","ace/range_list","ace/range","ace/selection","ace/mouse/multi_select_handler","ace/lib/event","ace/lib/lang","ace/commands/multi_select_commands","ace/search","ace/edit_session","ace/editor","ace/config"], function(require, exports, module) {
+
+var RangeList = require("./range_list").RangeList;
+var Range = require("./range").Range;
+var Selection = require("./selection").Selection;
+var onMouseDown = require("./mouse/multi_select_handler").onMouseDown;
+var event = require("./lib/event");
+var lang = require("./lib/lang");
+var commands = require("./commands/multi_select_commands");
+exports.commands = commands.defaultCommands.concat(commands.multiSelectCommands);
+var Search = require("./search").Search;
+var search = new Search();
+
+function find(session, needle, dir) {
+ search.$options.wrap = true;
+ search.$options.needle = needle;
+ search.$options.backwards = dir == -1;
+ return search.find(session);
+}
+var EditSession = require("./edit_session").EditSession;
+(function() {
+ this.getSelectionMarkers = function() {
+ return this.$selectionMarkers;
+ };
+}).call(EditSession.prototype);
+(function() {
+ this.ranges = null;
+ this.rangeList = null;
+ this.addRange = function(range, $blockChangeEvents) {
+ if (!range)
+ return;
+
+ if (!this.inMultiSelectMode && this.rangeCount === 0) {
+ var oldRange = this.toOrientedRange();
+ this.rangeList.add(oldRange);
+ this.rangeList.add(range);
+ if (this.rangeList.ranges.length != 2) {
+ this.rangeList.removeAll();
+ return $blockChangeEvents || this.fromOrientedRange(range);
+ }
+ this.rangeList.removeAll();
+ this.rangeList.add(oldRange);
+ this.$onAddRange(oldRange);
+ }
+
+ if (!range.cursor)
+ range.cursor = range.end;
+
+ var removed = this.rangeList.add(range);
+
+ this.$onAddRange(range);
+
+ if (removed.length)
+ this.$onRemoveRange(removed);
+
+ if (this.rangeCount > 1 && !this.inMultiSelectMode) {
+ this._signal("multiSelect");
+ this.inMultiSelectMode = true;
+ this.session.$undoSelect = false;
+ this.rangeList.attach(this.session);
+ }
+
+ return $blockChangeEvents || this.fromOrientedRange(range);
+ };
+
+ this.toSingleRange = function(range) {
+ range = range || this.ranges[0];
+ var removed = this.rangeList.removeAll();
+ if (removed.length)
+ this.$onRemoveRange(removed);
+
+ range && this.fromOrientedRange(range);
+ };
+ this.substractPoint = function(pos) {
+ var removed = this.rangeList.substractPoint(pos);
+ if (removed) {
+ this.$onRemoveRange(removed);
+ return removed[0];
+ }
+ };
+ this.mergeOverlappingRanges = function() {
+ var removed = this.rangeList.merge();
+ if (removed.length)
+ this.$onRemoveRange(removed);
+ else if(this.ranges[0])
+ this.fromOrientedRange(this.ranges[0]);
+ };
+
+ this.$onAddRange = function(range) {
+ this.rangeCount = this.rangeList.ranges.length;
+ this.ranges.unshift(range);
+ this._signal("addRange", {range: range});
+ };
+
+ this.$onRemoveRange = function(removed) {
+ this.rangeCount = this.rangeList.ranges.length;
+ if (this.rangeCount == 1 && this.inMultiSelectMode) {
+ var lastRange = this.rangeList.ranges.pop();
+ removed.push(lastRange);
+ this.rangeCount = 0;
+ }
+
+ for (var i = removed.length; i--; ) {
+ var index = this.ranges.indexOf(removed[i]);
+ this.ranges.splice(index, 1);
+ }
+
+ this._signal("removeRange", {ranges: removed});
+
+ if (this.rangeCount === 0 && this.inMultiSelectMode) {
+ this.inMultiSelectMode = false;
+ this._signal("singleSelect");
+ this.session.$undoSelect = true;
+ this.rangeList.detach(this.session);
+ }
+
+ lastRange = lastRange || this.ranges[0];
+ if (lastRange && !lastRange.isEqual(this.getRange()))
+ this.fromOrientedRange(lastRange);
+ };
+ this.$initRangeList = function() {
+ if (this.rangeList)
+ return;
+
+ this.rangeList = new RangeList();
+ this.ranges = [];
+ this.rangeCount = 0;
+ };
+ this.getAllRanges = function() {
+ return this.rangeCount ? this.rangeList.ranges.concat() : [this.getRange()];
+ };
+
+ this.splitIntoLines = function () {
+ if (this.rangeCount > 1) {
+ var ranges = this.rangeList.ranges;
+ var lastRange = ranges[ranges.length - 1];
+ var range = Range.fromPoints(ranges[0].start, lastRange.end);
+
+ this.toSingleRange();
+ this.setSelectionRange(range, lastRange.cursor == lastRange.start);
+ } else {
+ var range = this.getRange();
+ var isBackwards = this.isBackwards();
+ var startRow = range.start.row;
+ var endRow = range.end.row;
+ if (startRow == endRow) {
+ if (isBackwards)
+ var start = range.end, end = range.start;
+ else
+ var start = range.start, end = range.end;
+
+ this.addRange(Range.fromPoints(end, end));
+ this.addRange(Range.fromPoints(start, start));
+ return;
+ }
+
+ var rectSel = [];
+ var r = this.getLineRange(startRow, true);
+ r.start.column = range.start.column;
+ rectSel.push(r);
+
+ for (var i = startRow + 1; i < endRow; i++)
+ rectSel.push(this.getLineRange(i, true));
+
+ r = this.getLineRange(endRow, true);
+ r.end.column = range.end.column;
+ rectSel.push(r);
+
+ rectSel.forEach(this.addRange, this);
+ }
+ };
+ this.toggleBlockSelection = function () {
+ if (this.rangeCount > 1) {
+ var ranges = this.rangeList.ranges;
+ var lastRange = ranges[ranges.length - 1];
+ var range = Range.fromPoints(ranges[0].start, lastRange.end);
+
+ this.toSingleRange();
+ this.setSelectionRange(range, lastRange.cursor == lastRange.start);
+ } else {
+ var cursor = this.session.documentToScreenPosition(this.selectionLead);
+ var anchor = this.session.documentToScreenPosition(this.selectionAnchor);
+
+ var rectSel = this.rectangularRangeBlock(cursor, anchor);
+ rectSel.forEach(this.addRange, this);
+ }
+ };
+ this.rectangularRangeBlock = function(screenCursor, screenAnchor, includeEmptyLines) {
+ var rectSel = [];
+
+ var xBackwards = screenCursor.column < screenAnchor.column;
+ if (xBackwards) {
+ var startColumn = screenCursor.column;
+ var endColumn = screenAnchor.column;
+ } else {
+ var startColumn = screenAnchor.column;
+ var endColumn = screenCursor.column;
+ }
+
+ var yBackwards = screenCursor.row < screenAnchor.row;
+ if (yBackwards) {
+ var startRow = screenCursor.row;
+ var endRow = screenAnchor.row;
+ } else {
+ var startRow = screenAnchor.row;
+ var endRow = screenCursor.row;
+ }
+
+ if (startColumn < 0)
+ startColumn = 0;
+ if (startRow < 0)
+ startRow = 0;
+
+ if (startRow == endRow)
+ includeEmptyLines = true;
+
+ for (var row = startRow; row <= endRow; row++) {
+ var range = Range.fromPoints(
+ this.session.screenToDocumentPosition(row, startColumn),
+ this.session.screenToDocumentPosition(row, endColumn)
+ );
+ if (range.isEmpty()) {
+ if (docEnd && isSamePoint(range.end, docEnd))
+ break;
+ var docEnd = range.end;
+ }
+ range.cursor = xBackwards ? range.start : range.end;
+ rectSel.push(range);
+ }
+
+ if (yBackwards)
+ rectSel.reverse();
+
+ if (!includeEmptyLines) {
+ var end = rectSel.length - 1;
+ while (rectSel[end].isEmpty() && end > 0)
+ end--;
+ if (end > 0) {
+ var start = 0;
+ while (rectSel[start].isEmpty())
+ start++;
+ }
+ for (var i = end; i >= start; i--) {
+ if (rectSel[i].isEmpty())
+ rectSel.splice(i, 1);
+ }
+ }
+
+ return rectSel;
+ };
+}).call(Selection.prototype);
+var Editor = require("./editor").Editor;
+(function() {
+ this.updateSelectionMarkers = function() {
+ this.renderer.updateCursor();
+ this.renderer.updateBackMarkers();
+ };
+ this.addSelectionMarker = function(orientedRange) {
+ if (!orientedRange.cursor)
+ orientedRange.cursor = orientedRange.end;
+
+ var style = this.getSelectionStyle();
+ orientedRange.marker = this.session.addMarker(orientedRange, "ace_selection", style);
+
+ this.session.$selectionMarkers.push(orientedRange);
+ this.session.selectionMarkerCount = this.session.$selectionMarkers.length;
+ return orientedRange;
+ };
+ this.removeSelectionMarker = function(range) {
+ if (!range.marker)
+ return;
+ this.session.removeMarker(range.marker);
+ var index = this.session.$selectionMarkers.indexOf(range);
+ if (index != -1)
+ this.session.$selectionMarkers.splice(index, 1);
+ this.session.selectionMarkerCount = this.session.$selectionMarkers.length;
+ };
+
+ this.removeSelectionMarkers = function(ranges) {
+ var markerList = this.session.$selectionMarkers;
+ for (var i = ranges.length; i--; ) {
+ var range = ranges[i];
+ if (!range.marker)
+ continue;
+ this.session.removeMarker(range.marker);
+ var index = markerList.indexOf(range);
+ if (index != -1)
+ markerList.splice(index, 1);
+ }
+ this.session.selectionMarkerCount = markerList.length;
+ };
+
+ this.$onAddRange = function(e) {
+ this.addSelectionMarker(e.range);
+ this.renderer.updateCursor();
+ this.renderer.updateBackMarkers();
+ };
+
+ this.$onRemoveRange = function(e) {
+ this.removeSelectionMarkers(e.ranges);
+ this.renderer.updateCursor();
+ this.renderer.updateBackMarkers();
+ };
+
+ this.$onMultiSelect = function(e) {
+ if (this.inMultiSelectMode)
+ return;
+ this.inMultiSelectMode = true;
+
+ this.setStyle("ace_multiselect");
+ this.keyBinding.addKeyboardHandler(commands.keyboardHandler);
+ this.commands.setDefaultHandler("exec", this.$onMultiSelectExec);
+
+ this.renderer.updateCursor();
+ this.renderer.updateBackMarkers();
+ };
+
+ this.$onSingleSelect = function(e) {
+ if (this.session.multiSelect.inVirtualMode)
+ return;
+ this.inMultiSelectMode = false;
+
+ this.unsetStyle("ace_multiselect");
+ this.keyBinding.removeKeyboardHandler(commands.keyboardHandler);
+
+ this.commands.removeDefaultHandler("exec", this.$onMultiSelectExec);
+ this.renderer.updateCursor();
+ this.renderer.updateBackMarkers();
+ this._emit("changeSelection");
+ };
+
+ this.$onMultiSelectExec = function(e) {
+ var command = e.command;
+ var editor = e.editor;
+ if (!editor.multiSelect)
+ return;
+ if (!command.multiSelectAction) {
+ var result = command.exec(editor, e.args || {});
+ editor.multiSelect.addRange(editor.multiSelect.toOrientedRange());
+ editor.multiSelect.mergeOverlappingRanges();
+ } else if (command.multiSelectAction == "forEach") {
+ result = editor.forEachSelection(command, e.args);
+ } else if (command.multiSelectAction == "forEachLine") {
+ result = editor.forEachSelection(command, e.args, true);
+ } else if (command.multiSelectAction == "single") {
+ editor.exitMultiSelectMode();
+ result = command.exec(editor, e.args || {});
+ } else {
+ result = command.multiSelectAction(editor, e.args || {});
+ }
+ return result;
+ };
+ this.forEachSelection = function(cmd, args, options) {
+ if (this.inVirtualSelectionMode)
+ return;
+ var keepOrder = options && options.keepOrder;
+ var $byLines = options == true || options && options.$byLines
+ var session = this.session;
+ var selection = this.selection;
+ var rangeList = selection.rangeList;
+ var ranges = (keepOrder ? selection : rangeList).ranges;
+ var result;
+
+ if (!ranges.length)
+ return cmd.exec ? cmd.exec(this, args || {}) : cmd(this, args || {});
+
+ var reg = selection._eventRegistry;
+ selection._eventRegistry = {};
+
+ var tmpSel = new Selection(session);
+ this.inVirtualSelectionMode = true;
+ for (var i = ranges.length; i--;) {
+ if ($byLines) {
+ while (i > 0 && ranges[i].start.row == ranges[i - 1].end.row)
+ i--;
+ }
+ tmpSel.fromOrientedRange(ranges[i]);
+ tmpSel.index = i;
+ this.selection = session.selection = tmpSel;
+ var cmdResult = cmd.exec ? cmd.exec(this, args || {}) : cmd(this, args || {});
+ if (!result && cmdResult !== undefined)
+ result = cmdResult;
+ tmpSel.toOrientedRange(ranges[i]);
+ }
+ tmpSel.detach();
+
+ this.selection = session.selection = selection;
+ this.inVirtualSelectionMode = false;
+ selection._eventRegistry = reg;
+ selection.mergeOverlappingRanges();
+
+ var anim = this.renderer.$scrollAnimation;
+ this.onCursorChange();
+ this.onSelectionChange();
+ if (anim && anim.from == anim.to)
+ this.renderer.animateScrolling(anim.from);
+
+ return result;
+ };
+ this.exitMultiSelectMode = function() {
+ if (!this.inMultiSelectMode || this.inVirtualSelectionMode)
+ return;
+ this.multiSelect.toSingleRange();
+ };
+
+ this.getSelectedText = function() {
+ var text = "";
+ if (this.inMultiSelectMode && !this.inVirtualSelectionMode) {
+ var ranges = this.multiSelect.rangeList.ranges;
+ var buf = [];
+ for (var i = 0; i < ranges.length; i++) {
+ buf.push(this.session.getTextRange(ranges[i]));
+ }
+ var nl = this.session.getDocument().getNewLineCharacter();
+ text = buf.join(nl);
+ if (text.length == (buf.length - 1) * nl.length)
+ text = "";
+ } else if (!this.selection.isEmpty()) {
+ text = this.session.getTextRange(this.getSelectionRange());
+ }
+ return text;
+ };
+
+ this.$checkMultiselectChange = function(e, anchor) {
+ if (this.inMultiSelectMode && !this.inVirtualSelectionMode) {
+ var range = this.multiSelect.ranges[0];
+ if (this.multiSelect.isEmpty() && anchor == this.multiSelect.anchor)
+ return;
+ var pos = anchor == this.multiSelect.anchor
+ ? range.cursor == range.start ? range.end : range.start
+ : range.cursor;
+ if (pos.row != anchor.row
+ || this.session.$clipPositionToDocument(pos.row, pos.column).column != anchor.column)
+ this.multiSelect.toSingleRange(this.multiSelect.toOrientedRange());
+ }
+ };
+ this.findAll = function(needle, options, additive) {
+ options = options || {};
+ options.needle = needle || options.needle;
+ if (options.needle == undefined) {
+ var range = this.selection.isEmpty()
+ ? this.selection.getWordRange()
+ : this.selection.getRange();
+ options.needle = this.session.getTextRange(range);
+ }
+ this.$search.set(options);
+
+ var ranges = this.$search.findAll(this.session);
+ if (!ranges.length)
+ return 0;
+
+ this.$blockScrolling += 1;
+ var selection = this.multiSelect;
+
+ if (!additive)
+ selection.toSingleRange(ranges[0]);
+
+ for (var i = ranges.length; i--; )
+ selection.addRange(ranges[i], true);
+ if (range && selection.rangeList.rangeAtPoint(range.start))
+ selection.addRange(range, true);
+
+ this.$blockScrolling -= 1;
+
+ return ranges.length;
+ };
+ this.selectMoreLines = function(dir, skip) {
+ var range = this.selection.toOrientedRange();
+ var isBackwards = range.cursor == range.end;
+
+ var screenLead = this.session.documentToScreenPosition(range.cursor);
+ if (this.selection.$desiredColumn)
+ screenLead.column = this.selection.$desiredColumn;
+
+ var lead = this.session.screenToDocumentPosition(screenLead.row + dir, screenLead.column);
+
+ if (!range.isEmpty()) {
+ var screenAnchor = this.session.documentToScreenPosition(isBackwards ? range.end : range.start);
+ var anchor = this.session.screenToDocumentPosition(screenAnchor.row + dir, screenAnchor.column);
+ } else {
+ var anchor = lead;
+ }
+
+ if (isBackwards) {
+ var newRange = Range.fromPoints(lead, anchor);
+ newRange.cursor = newRange.start;
+ } else {
+ var newRange = Range.fromPoints(anchor, lead);
+ newRange.cursor = newRange.end;
+ }
+
+ newRange.desiredColumn = screenLead.column;
+ if (!this.selection.inMultiSelectMode) {
+ this.selection.addRange(range);
+ } else {
+ if (skip)
+ var toRemove = range.cursor;
+ }
+
+ this.selection.addRange(newRange);
+ if (toRemove)
+ this.selection.substractPoint(toRemove);
+ };
+ this.transposeSelections = function(dir) {
+ var session = this.session;
+ var sel = session.multiSelect;
+ var all = sel.ranges;
+
+ for (var i = all.length; i--; ) {
+ var range = all[i];
+ if (range.isEmpty()) {
+ var tmp = session.getWordRange(range.start.row, range.start.column);
+ range.start.row = tmp.start.row;
+ range.start.column = tmp.start.column;
+ range.end.row = tmp.end.row;
+ range.end.column = tmp.end.column;
+ }
+ }
+ sel.mergeOverlappingRanges();
+
+ var words = [];
+ for (var i = all.length; i--; ) {
+ var range = all[i];
+ words.unshift(session.getTextRange(range));
+ }
+
+ if (dir < 0)
+ words.unshift(words.pop());
+ else
+ words.push(words.shift());
+
+ for (var i = all.length; i--; ) {
+ var range = all[i];
+ var tmp = range.clone();
+ session.replace(range, words[i]);
+ range.start.row = tmp.start.row;
+ range.start.column = tmp.start.column;
+ }
+ };
+ this.selectMore = function(dir, skip, stopAtFirst) {
+ var session = this.session;
+ var sel = session.multiSelect;
+
+ var range = sel.toOrientedRange();
+ if (range.isEmpty()) {
+ range = session.getWordRange(range.start.row, range.start.column);
+ range.cursor = dir == -1 ? range.start : range.end;
+ this.multiSelect.addRange(range);
+ if (stopAtFirst)
+ return;
+ }
+ var needle = session.getTextRange(range);
+
+ var newRange = find(session, needle, dir);
+ if (newRange) {
+ newRange.cursor = dir == -1 ? newRange.start : newRange.end;
+ this.$blockScrolling += 1;
+ this.session.unfold(newRange);
+ this.multiSelect.addRange(newRange);
+ this.$blockScrolling -= 1;
+ this.renderer.scrollCursorIntoView(null, 0.5);
+ }
+ if (skip)
+ this.multiSelect.substractPoint(range.cursor);
+ };
+ this.alignCursors = function() {
+ var session = this.session;
+ var sel = session.multiSelect;
+ var ranges = sel.ranges;
+ var row = -1;
+ var sameRowRanges = ranges.filter(function(r) {
+ if (r.cursor.row == row)
+ return true;
+ row = r.cursor.row;
+ });
+
+ if (!ranges.length || sameRowRanges.length == ranges.length - 1) {
+ var range = this.selection.getRange();
+ var fr = range.start.row, lr = range.end.row;
+ var guessRange = fr == lr;
+ if (guessRange) {
+ var max = this.session.getLength();
+ var line;
+ do {
+ line = this.session.getLine(lr);
+ } while (/[=:]/.test(line) && ++lr < max);
+ do {
+ line = this.session.getLine(fr);
+ } while (/[=:]/.test(line) && --fr > 0);
+
+ if (fr < 0) fr = 0;
+ if (lr >= max) lr = max - 1;
+ }
+ var lines = this.session.doc.removeLines(fr, lr);
+ lines = this.$reAlignText(lines, guessRange);
+ this.session.doc.insert({row: fr, column: 0}, lines.join("\n") + "\n");
+ if (!guessRange) {
+ range.start.column = 0;
+ range.end.column = lines[lines.length - 1].length;
+ }
+ this.selection.setRange(range);
+ } else {
+ sameRowRanges.forEach(function(r) {
+ sel.substractPoint(r.cursor);
+ });
+
+ var maxCol = 0;
+ var minSpace = Infinity;
+ var spaceOffsets = ranges.map(function(r) {
+ var p = r.cursor;
+ var line = session.getLine(p.row);
+ var spaceOffset = line.substr(p.column).search(/\S/g);
+ if (spaceOffset == -1)
+ spaceOffset = 0;
+
+ if (p.column > maxCol)
+ maxCol = p.column;
+ if (spaceOffset < minSpace)
+ minSpace = spaceOffset;
+ return spaceOffset;
+ });
+ ranges.forEach(function(r, i) {
+ var p = r.cursor;
+ var l = maxCol - p.column;
+ var d = spaceOffsets[i] - minSpace;
+ if (l > d)
+ session.insert(p, lang.stringRepeat(" ", l - d));
+ else
+ session.remove(new Range(p.row, p.column, p.row, p.column - l + d));
+
+ r.start.column = r.end.column = maxCol;
+ r.start.row = r.end.row = p.row;
+ r.cursor = r.end;
+ });
+ sel.fromOrientedRange(ranges[0]);
+ this.renderer.updateCursor();
+ this.renderer.updateBackMarkers();
+ }
+ };
+
+ this.$reAlignText = function(lines, forceLeft) {
+ var isLeftAligned = true, isRightAligned = true;
+ var startW, textW, endW;
+
+ return lines.map(function(line) {
+ var m = line.match(/(\s*)(.*?)(\s*)([=:].*)/);
+ if (!m)
+ return [line];
+
+ if (startW == null) {
+ startW = m[1].length;
+ textW = m[2].length;
+ endW = m[3].length;
+ return m;
+ }
+
+ if (startW + textW + endW != m[1].length + m[2].length + m[3].length)
+ isRightAligned = false;
+ if (startW != m[1].length)
+ isLeftAligned = false;
+
+ if (startW > m[1].length)
+ startW = m[1].length;
+ if (textW < m[2].length)
+ textW = m[2].length;
+ if (endW > m[3].length)
+ endW = m[3].length;
+
+ return m;
+ }).map(forceLeft ? alignLeft :
+ isLeftAligned ? isRightAligned ? alignRight : alignLeft : unAlign);
+
+ function spaces(n) {
+ return lang.stringRepeat(" ", n);
+ }
+
+ function alignLeft(m) {
+ return !m[2] ? m[0] : spaces(startW) + m[2]
+ + spaces(textW - m[2].length + endW)
+ + m[4].replace(/^([=:])\s+/, "$1 ");
+ }
+ function alignRight(m) {
+ return !m[2] ? m[0] : spaces(startW + textW - m[2].length) + m[2]
+ + spaces(endW, " ")
+ + m[4].replace(/^([=:])\s+/, "$1 ");
+ }
+ function unAlign(m) {
+ return !m[2] ? m[0] : spaces(startW) + m[2]
+ + spaces(endW)
+ + m[4].replace(/^([=:])\s+/, "$1 ");
+ }
+ };
+}).call(Editor.prototype);
+
+
+function isSamePoint(p1, p2) {
+ return p1.row == p2.row && p1.column == p2.column;
+}
+exports.onSessionChange = function(e) {
+ var session = e.session;
+ if (session && !session.multiSelect) {
+ session.$selectionMarkers = [];
+ session.selection.$initRangeList();
+ session.multiSelect = session.selection;
+ }
+ this.multiSelect = session && session.multiSelect;
+
+ var oldSession = e.oldSession;
+ if (oldSession) {
+ oldSession.multiSelect.off("addRange", this.$onAddRange);
+ oldSession.multiSelect.off("removeRange", this.$onRemoveRange);
+ oldSession.multiSelect.off("multiSelect", this.$onMultiSelect);
+ oldSession.multiSelect.off("singleSelect", this.$onSingleSelect);
+ oldSession.multiSelect.lead.off("change", this.$checkMultiselectChange);
+ oldSession.multiSelect.anchor.off("change", this.$checkMultiselectChange);
+ }
+
+ if (session) {
+ session.multiSelect.on("addRange", this.$onAddRange);
+ session.multiSelect.on("removeRange", this.$onRemoveRange);
+ session.multiSelect.on("multiSelect", this.$onMultiSelect);
+ session.multiSelect.on("singleSelect", this.$onSingleSelect);
+ session.multiSelect.lead.on("change", this.$checkMultiselectChange);
+ session.multiSelect.anchor.on("change", this.$checkMultiselectChange);
+ }
+
+ if (session && this.inMultiSelectMode != session.selection.inMultiSelectMode) {
+ if (session.selection.inMultiSelectMode)
+ this.$onMultiSelect();
+ else
+ this.$onSingleSelect();
+ }
+};
+function MultiSelect(editor) {
+ if (editor.$multiselectOnSessionChange)
+ return;
+ editor.$onAddRange = editor.$onAddRange.bind(editor);
+ editor.$onRemoveRange = editor.$onRemoveRange.bind(editor);
+ editor.$onMultiSelect = editor.$onMultiSelect.bind(editor);
+ editor.$onSingleSelect = editor.$onSingleSelect.bind(editor);
+ editor.$multiselectOnSessionChange = exports.onSessionChange.bind(editor);
+ editor.$checkMultiselectChange = editor.$checkMultiselectChange.bind(editor);
+
+ editor.$multiselectOnSessionChange(editor);
+ editor.on("changeSession", editor.$multiselectOnSessionChange);
+
+ editor.on("mousedown", onMouseDown);
+ editor.commands.addCommands(commands.defaultCommands);
+
+ addAltCursorListeners(editor);
+}
+
+function addAltCursorListeners(editor){
+ var el = editor.textInput.getElement();
+ var altCursor = false;
+ event.addListener(el, "keydown", function(e) {
+ if (e.keyCode == 18 && !(e.ctrlKey || e.shiftKey || e.metaKey)) {
+ if (!altCursor) {
+ editor.renderer.setMouseCursor("crosshair");
+ altCursor = true;
+ }
+ } else if (altCursor) {
+ reset();
+ }
+ });
+
+ event.addListener(el, "keyup", reset);
+ event.addListener(el, "blur", reset);
+ function reset(e) {
+ if (altCursor) {
+ editor.renderer.setMouseCursor("");
+ altCursor = false;
+ }
+ }
+}
+
+exports.MultiSelect = MultiSelect;
+
+
+require("./config").defineOptions(Editor.prototype, "editor", {
+ enableMultiselect: {
+ set: function(val) {
+ MultiSelect(this);
+ if (val) {
+ this.on("changeSession", this.$multiselectOnSessionChange);
+ this.on("mousedown", onMouseDown);
+ } else {
+ this.off("changeSession", this.$multiselectOnSessionChange);
+ this.off("mousedown", onMouseDown);
+ }
+ },
+ value: true
+ }
+});
+
+
+
+});
+
+define("ace/mode/folding/fold_mode",["require","exports","module","ace/range"], function(require, exports, module) {
+"use strict";
+
+var Range = require("../../range").Range;
+
+var FoldMode = exports.FoldMode = function() {};
+
+(function() {
+
+ this.foldingStartMarker = null;
+ this.foldingStopMarker = null;
+ this.getFoldWidget = function(session, foldStyle, row) {
+ var line = session.getLine(row);
+ if (this.foldingStartMarker.test(line))
+ return "start";
+ if (foldStyle == "markbeginend"
+ && this.foldingStopMarker
+ && this.foldingStopMarker.test(line))
+ return "end";
+ return "";
+ };
+
+ this.getFoldWidgetRange = function(session, foldStyle, row) {
+ return null;
+ };
+
+ this.indentationBlock = function(session, row, column) {
+ var re = /\S/;
+ var line = session.getLine(row);
+ var startLevel = line.search(re);
+ if (startLevel == -1)
+ return;
+
+ var startColumn = column || line.length;
+ var maxRow = session.getLength();
+ var startRow = row;
+ var endRow = row;
+
+ while (++row < maxRow) {
+ var level = session.getLine(row).search(re);
+
+ if (level == -1)
+ continue;
+
+ if (level <= startLevel)
+ break;
+
+ endRow = row;
+ }
+
+ if (endRow > startRow) {
+ var endColumn = session.getLine(endRow).length;
+ return new Range(startRow, startColumn, endRow, endColumn);
+ }
+ };
+
+ this.openingBracketBlock = function(session, bracket, row, column, typeRe) {
+ var start = {row: row, column: column + 1};
+ var end = session.$findClosingBracket(bracket, start, typeRe);
+ if (!end)
+ return;
+
+ var fw = session.foldWidgets[end.row];
+ if (fw == null)
+ fw = session.getFoldWidget(end.row);
+
+ if (fw == "start" && end.row > start.row) {
+ end.row --;
+ end.column = session.getLine(end.row).length;
+ }
+ return Range.fromPoints(start, end);
+ };
+
+ this.closingBracketBlock = function(session, bracket, row, column, typeRe) {
+ var end = {row: row, column: column};
+ var start = session.$findOpeningBracket(bracket, end);
+
+ if (!start)
+ return;
+
+ start.column++;
+ end.column--;
+
+ return Range.fromPoints(start, end);
+ };
+}).call(FoldMode.prototype);
+
+});
+
+define("ace/theme/textmate",["require","exports","module","ace/lib/dom"], function(require, exports, module) {
+"use strict";
+
+exports.isDark = false;
+exports.cssClass = "ace-tm";
+exports.cssText = ".ace-tm .ace_gutter {\
+background: #f0f0f0;\
+color: #333;\
+}\
+.ace-tm .ace_print-margin {\
+width: 1px;\
+background: #e8e8e8;\
+}\
+.ace-tm .ace_fold {\
+background-color: #6B72E6;\
+}\
+.ace-tm {\
+background-color: #FFFFFF;\
+color: black;\
+}\
+.ace-tm .ace_cursor {\
+color: black;\
+}\
+.ace-tm .ace_invisible {\
+color: rgb(191, 191, 191);\
+}\
+.ace-tm .ace_storage,\
+.ace-tm .ace_keyword {\
+color: blue;\
+}\
+.ace-tm .ace_constant {\
+color: rgb(197, 6, 11);\
+}\
+.ace-tm .ace_constant.ace_buildin {\
+color: rgb(88, 72, 246);\
+}\
+.ace-tm .ace_constant.ace_language {\
+color: rgb(88, 92, 246);\
+}\
+.ace-tm .ace_constant.ace_library {\
+color: rgb(6, 150, 14);\
+}\
+.ace-tm .ace_invalid {\
+background-color: rgba(255, 0, 0, 0.1);\
+color: red;\
+}\
+.ace-tm .ace_support.ace_function {\
+color: rgb(60, 76, 114);\
+}\
+.ace-tm .ace_support.ace_constant {\
+color: rgb(6, 150, 14);\
+}\
+.ace-tm .ace_support.ace_type,\
+.ace-tm .ace_support.ace_class {\
+color: rgb(109, 121, 222);\
+}\
+.ace-tm .ace_keyword.ace_operator {\
+color: rgb(104, 118, 135);\
+}\
+.ace-tm .ace_string {\
+color: rgb(3, 106, 7);\
+}\
+.ace-tm .ace_comment {\
+color: rgb(76, 136, 107);\
+}\
+.ace-tm .ace_comment.ace_doc {\
+color: rgb(0, 102, 255);\
+}\
+.ace-tm .ace_comment.ace_doc.ace_tag {\
+color: rgb(128, 159, 191);\
+}\
+.ace-tm .ace_constant.ace_numeric {\
+color: rgb(0, 0, 205);\
+}\
+.ace-tm .ace_variable {\
+color: rgb(49, 132, 149);\
+}\
+.ace-tm .ace_xml-pe {\
+color: rgb(104, 104, 91);\
+}\
+.ace-tm .ace_entity.ace_name.ace_function {\
+color: #0000A2;\
+}\
+.ace-tm .ace_heading {\
+color: rgb(12, 7, 255);\
+}\
+.ace-tm .ace_list {\
+color:rgb(185, 6, 144);\
+}\
+.ace-tm .ace_meta.ace_tag {\
+color:rgb(0, 22, 142);\
+}\
+.ace-tm .ace_string.ace_regex {\
+color: rgb(255, 0, 0)\
+}\
+.ace-tm .ace_marker-layer .ace_selection {\
+background: rgb(181, 213, 255);\
+}\
+.ace-tm.ace_multiselect .ace_selection.ace_start {\
+box-shadow: 0 0 3px 0px white;\
+border-radius: 2px;\
+}\
+.ace-tm .ace_marker-layer .ace_step {\
+background: rgb(252, 255, 0);\
+}\
+.ace-tm .ace_marker-layer .ace_stack {\
+background: rgb(164, 229, 101);\
+}\
+.ace-tm .ace_marker-layer .ace_bracket {\
+margin: -1px 0 0 -1px;\
+border: 1px solid rgb(192, 192, 192);\
+}\
+.ace-tm .ace_marker-layer .ace_active-line {\
+background: rgba(0, 0, 0, 0.07);\
+}\
+.ace-tm .ace_gutter-active-line {\
+background-color : #dcdcdc;\
+}\
+.ace-tm .ace_marker-layer .ace_selected-word {\
+background: rgb(250, 250, 255);\
+border: 1px solid rgb(200, 200, 250);\
+}\
+.ace-tm .ace_indent-guide {\
+background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==\") right repeat-y;\
+}\
+";
+
+var dom = require("../lib/dom");
+dom.importCssString(exports.cssText, exports.cssClass);
+});
+
+define("ace/line_widgets",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/range"], function(require, exports, module) {
+"use strict";
+
+var oop = require("./lib/oop");
+var dom = require("./lib/dom");
+var Range = require("./range").Range;
+
+
+function LineWidgets(session) {
+ this.session = session;
+ this.session.widgetManager = this;
+ this.session.getRowLength = this.getRowLength;
+ this.session.$getWidgetScreenLength = this.$getWidgetScreenLength;
+ this.updateOnChange = this.updateOnChange.bind(this);
+ this.renderWidgets = this.renderWidgets.bind(this);
+ this.measureWidgets = this.measureWidgets.bind(this);
+ this.session._changedWidgets = [];
+ this.$onChangeEditor = this.$onChangeEditor.bind(this);
+
+ this.session.on("change", this.updateOnChange);
+ this.session.on("changeEditor", this.$onChangeEditor);
+}
+
+(function() {
+ this.getRowLength = function(row) {
+ var h;
+ if (this.lineWidgets)
+ h = this.lineWidgets[row] && this.lineWidgets[row].rowCount || 0;
+ else
+ h = 0;
+ if (!this.$useWrapMode || !this.$wrapData[row]) {
+ return 1 + h;
+ } else {
+ return this.$wrapData[row].length + 1 + h;
+ }
+ };
+
+ this.$getWidgetScreenLength = function() {
+ var screenRows = 0;
+ this.lineWidgets.forEach(function(w){
+ if (w && w.rowCount)
+ screenRows +=w.rowCount;
+ });
+ return screenRows;
+ };
+
+ this.$onChangeEditor = function(e) {
+ this.attach(e.editor);
+ };
+
+ this.attach = function(editor) {
+ if (editor && editor.widgetManager && editor.widgetManager != this)
+ editor.widgetManager.detach();
+
+ if (this.editor == editor)
+ return;
+
+ this.detach();
+ this.editor = editor;
+
+ if (editor) {
+ editor.widgetManager = this;
+ editor.renderer.on("beforeRender", this.measureWidgets);
+ editor.renderer.on("afterRender", this.renderWidgets);
+ }
+ };
+ this.detach = function(e) {
+ var editor = this.editor;
+ if (!editor)
+ return;
+
+ this.editor = null;
+ editor.widgetManager = null;
+
+ editor.renderer.off("beforeRender", this.measureWidgets);
+ editor.renderer.off("afterRender", this.renderWidgets);
+ var lineWidgets = this.session.lineWidgets;
+ lineWidgets && lineWidgets.forEach(function(w) {
+ if (w && w.el && w.el.parentNode) {
+ w._inDocument = false;
+ w.el.parentNode.removeChild(w.el);
+ }
+ });
+ };
+
+ this.updateOnChange = function(e) {
+ var lineWidgets = this.session.lineWidgets;
+ if (!lineWidgets) return;
+
+ var delta = e.data;
+ var range = delta.range;
+ var startRow = range.start.row;
+ var len = range.end.row - startRow;
+
+ if (len === 0) {
+ } else if (delta.action == "removeText" || delta.action == "removeLines") {
+ var removed = lineWidgets.splice(startRow + 1, len);
+ removed.forEach(function(w) {
+ w && this.removeLineWidget(w);
+ }, this);
+ this.$updateRows();
+ } else {
+ var args = new Array(len);
+ args.unshift(startRow, 0);
+ lineWidgets.splice.apply(lineWidgets, args);
+ this.$updateRows();
+ }
+ };
+
+ this.$updateRows = function() {
+ var lineWidgets = this.session.lineWidgets;
+ if (!lineWidgets) return;
+ var noWidgets = true;
+ lineWidgets.forEach(function(w, i) {
+ if (w) {
+ noWidgets = false;
+ w.row = i;
+ }
+ });
+ if (noWidgets)
+ this.session.lineWidgets = null;
+ };
+
+ this.addLineWidget = function(w) {
+ if (!this.session.lineWidgets)
+ this.session.lineWidgets = new Array(this.session.getLength());
+
+ this.session.lineWidgets[w.row] = w;
+
+ var renderer = this.editor.renderer;
+ if (w.html && !w.el) {
+ w.el = dom.createElement("div");
+ w.el.innerHTML = w.html;
+ }
+ if (w.el) {
+ dom.addCssClass(w.el, "ace_lineWidgetContainer");
+ w.el.style.position = "absolute";
+ w.el.style.zIndex = 5;
+ renderer.container.appendChild(w.el);
+ w._inDocument = true;
+ }
+
+ if (!w.coverGutter) {
+ w.el.style.zIndex = 3;
+ }
+ if (!w.pixelHeight) {
+ w.pixelHeight = w.el.offsetHeight;
+ }
+ if (w.rowCount == null)
+ w.rowCount = w.pixelHeight / renderer.layerConfig.lineHeight;
+
+ this.session._emit("changeFold", {data:{start:{row: w.row}}});
+
+ this.$updateRows();
+ this.renderWidgets(null, renderer);
+ return w;
+ };
+
+ this.removeLineWidget = function(w) {
+ w._inDocument = false;
+ if (w.el && w.el.parentNode)
+ w.el.parentNode.removeChild(w.el);
+ if (w.editor && w.editor.destroy) try {
+ w.editor.destroy();
+ } catch(e){}
+ if (this.session.lineWidgets)
+ this.session.lineWidgets[w.row] = undefined;
+ this.session._emit("changeFold", {data:{start:{row: w.row}}});
+ this.$updateRows();
+ };
+
+ this.onWidgetChanged = function(w) {
+ this.session._changedWidgets.push(w);
+ this.editor && this.editor.renderer.updateFull();
+ };
+
+ this.measureWidgets = function(e, renderer) {
+ var changedWidgets = this.session._changedWidgets;
+ var config = renderer.layerConfig;
+
+ if (!changedWidgets || !changedWidgets.length) return;
+ var min = Infinity;
+ for (var i = 0; i < changedWidgets.length; i++) {
+ var w = changedWidgets[i];
+ if (!w._inDocument) {
+ w._inDocument = true;
+ renderer.container.appendChild(w.el);
+ }
+
+ w.h = w.el.offsetHeight;
+
+ if (!w.fixedWidth) {
+ w.w = w.el.offsetWidth;
+ w.screenWidth = Math.ceil(w.w / config.characterWidth);
+ }
+
+ var rowCount = w.h / config.lineHeight;
+ if (w.coverLine) {
+ rowCount -= this.session.getRowLineCount(w.row);
+ if (rowCount < 0)
+ rowCount = 0;
+ }
+ if (w.rowCount != rowCount) {
+ w.rowCount = rowCount;
+ if (w.row < min)
+ min = w.row;
+ }
+ }
+ if (min != Infinity) {
+ this.session._emit("changeFold", {data:{start:{row: min}}});
+ this.session.lineWidgetWidth = null;
+ }
+ this.session._changedWidgets = [];
+ };
+
+ this.renderWidgets = function(e, renderer) {
+ var config = renderer.layerConfig;
+ var lineWidgets = this.session.lineWidgets;
+ if (!lineWidgets)
+ return;
+ var first = Math.min(this.firstRow, config.firstRow);
+ var last = Math.max(this.lastRow, config.lastRow, lineWidgets.length);
+
+ while (first > 0 && !lineWidgets[first])
+ first--;
+
+ this.firstRow = config.firstRow;
+ this.lastRow = config.lastRow;
+
+ renderer.$cursorLayer.config = config;
+ for (var i = first; i <= last; i++) {
+ var w = lineWidgets[i];
+ if (!w || !w.el) continue;
+
+ if (!w._inDocument) {
+ w._inDocument = true;
+ renderer.container.appendChild(w.el);
+ }
+ var top = renderer.$cursorLayer.getPixelPosition({row: i, column:0}, true).top;
+ if (!w.coverLine)
+ top += config.lineHeight * this.session.getRowLineCount(w.row);
+ w.el.style.top = top - config.offset + "px";
+
+ var left = w.coverGutter ? 0 : renderer.gutterWidth;
+ if (!w.fixedWidth)
+ left -= renderer.scrollLeft;
+ w.el.style.left = left + "px";
+
+ if (w.fixedWidth) {
+ w.el.style.right = renderer.scrollBar.getWidth() + "px";
+ } else {
+ w.el.style.right = "";
+ }
+ }
+ };
+
+}).call(LineWidgets.prototype);
+
+
+exports.LineWidgets = LineWidgets;
+
+});
+
+define("ace/ext/error_marker",["require","exports","module","ace/line_widgets","ace/lib/dom","ace/range"], function(require, exports, module) {
+"use strict";
+var LineWidgets = require("../line_widgets").LineWidgets;
+var dom = require("../lib/dom");
+var Range = require("../range").Range;
+
+function binarySearch(array, needle, comparator) {
+ var first = 0;
+ var last = array.length - 1;
+
+ while (first <= last) {
+ var mid = (first + last) >> 1;
+ var c = comparator(needle, array[mid]);
+ if (c > 0)
+ first = mid + 1;
+ else if (c < 0)
+ last = mid - 1;
+ else
+ return mid;
+ }
+ return -(first + 1);
+}
+
+function findAnnotations(session, row, dir) {
+ var annotations = session.getAnnotations().sort(Range.comparePoints);
+ if (!annotations.length)
+ return;
+
+ var i = binarySearch(annotations, {row: row, column: -1}, Range.comparePoints);
+ if (i < 0)
+ i = -i - 1;
+
+ if (i >= annotations.length - 1)
+ i = dir > 0 ? 0 : annotations.length - 1;
+ else if (i === 0 && dir < 0)
+ i = annotations.length - 1;
+
+ var annotation = annotations[i];
+ if (!annotation || !dir)
+ return;
+
+ if (annotation.row === row) {
+ do {
+ annotation = annotations[i += dir];
+ } while (annotation && annotation.row === row);
+ if (!annotation)
+ return annotations.slice();
+ }
+
+
+ var matched = [];
+ row = annotation.row;
+ do {
+ matched[dir < 0 ? "unshift" : "push"](annotation);
+ annotation = annotations[i += dir];
+ } while (annotation && annotation.row == row);
+ return matched.length && matched;
+}
+
+exports.showErrorMarker = function(editor, dir) {
+ var session = editor.session;
+ if (!session.widgetManager) {
+ session.widgetManager = new LineWidgets(session);
+ session.widgetManager.attach(editor);
+ }
+
+ var pos = editor.getCursorPosition();
+ var row = pos.row;
+ var oldWidget = session.lineWidgets && session.lineWidgets[row];
+ if (oldWidget) {
+ oldWidget.destroy();
+ } else {
+ row -= dir;
+ }
+ var annotations = findAnnotations(session, row, dir);
+ var gutterAnno;
+ if (annotations) {
+ var annotation = annotations[0];
+ pos.column = (annotation.pos && typeof annotation.column != "number"
+ ? annotation.pos.sc
+ : annotation.column) || 0;
+ pos.row = annotation.row;
+ gutterAnno = editor.renderer.$gutterLayer.$annotations[pos.row];
+ } else if (oldWidget) {
+ return;
+ } else {
+ gutterAnno = {
+ text: ["Looks good!"],
+ className: "ace_ok"
+ };
+ }
+ editor.session.unfold(pos.row);
+ editor.selection.moveToPosition(pos);
+
+ var w = {
+ row: pos.row,
+ fixedWidth: true,
+ coverGutter: true,
+ el: dom.createElement("div")
+ };
+ var el = w.el.appendChild(dom.createElement("div"));
+ var arrow = w.el.appendChild(dom.createElement("div"));
+ arrow.className = "error_widget_arrow " + gutterAnno.className;
+
+ var left = editor.renderer.$cursorLayer
+ .getPixelPosition(pos).left;
+ arrow.style.left = left + editor.renderer.gutterWidth - 5 + "px";
+
+ w.el.className = "error_widget_wrapper";
+ el.className = "error_widget " + gutterAnno.className;
+ el.innerHTML = gutterAnno.text.join("
");
+
+ el.appendChild(dom.createElement("div"));
+
+ var kb = function(_, hashId, keyString) {
+ if (hashId === 0 && (keyString === "esc" || keyString === "return")) {
+ w.destroy();
+ return {command: "null"};
+ }
+ };
+
+ w.destroy = function() {
+ if (editor.$mouseHandler.isMousePressed)
+ return;
+ editor.keyBinding.removeKeyboardHandler(kb);
+ session.widgetManager.removeLineWidget(w);
+ editor.off("changeSelection", w.destroy);
+ editor.off("changeSession", w.destroy);
+ editor.off("mouseup", w.destroy);
+ editor.off("change", w.destroy);
+ };
+
+ editor.keyBinding.addKeyboardHandler(kb);
+ editor.on("changeSelection", w.destroy);
+ editor.on("changeSession", w.destroy);
+ editor.on("mouseup", w.destroy);
+ editor.on("change", w.destroy);
+
+ editor.session.widgetManager.addLineWidget(w);
+
+ w.el.onmousedown = editor.focus.bind(editor);
+
+ editor.renderer.scrollCursorIntoView(null, 0.5, {bottom: w.el.offsetHeight});
+};
+
+
+dom.importCssString("\
+ .error_widget_wrapper {\
+ background: inherit;\
+ color: inherit;\
+ border:none\
+ }\
+ .error_widget {\
+ border-top: solid 2px;\
+ border-bottom: solid 2px;\
+ margin: 5px 0;\
+ padding: 10px 40px;\
+ white-space: pre-wrap;\
+ }\
+ .error_widget.ace_error, .error_widget_arrow.ace_error{\
+ border-color: #ff5a5a\
+ }\
+ .error_widget.ace_warning, .error_widget_arrow.ace_warning{\
+ border-color: #F1D817\
+ }\
+ .error_widget.ace_info, .error_widget_arrow.ace_info{\
+ border-color: #5a5a5a\
+ }\
+ .error_widget.ace_ok, .error_widget_arrow.ace_ok{\
+ border-color: #5aaa5a\
+ }\
+ .error_widget_arrow {\
+ position: absolute;\
+ border: solid 5px;\
+ border-top-color: transparent!important;\
+ border-right-color: transparent!important;\
+ border-left-color: transparent!important;\
+ top: -5px;\
+ }\
+", "");
+
+});
+
+define("ace/ace",["require","exports","module","ace/lib/fixoldbrowsers","ace/lib/dom","ace/lib/event","ace/editor","ace/edit_session","ace/undomanager","ace/virtual_renderer","ace/worker/worker_client","ace/keyboard/hash_handler","ace/placeholder","ace/multi_select","ace/mode/folding/fold_mode","ace/theme/textmate","ace/ext/error_marker","ace/config"], function(require, exports, module) {
+"use strict";
+
+require("./lib/fixoldbrowsers");
+
+var dom = require("./lib/dom");
+var event = require("./lib/event");
+
+var Editor = require("./editor").Editor;
+var EditSession = require("./edit_session").EditSession;
+var UndoManager = require("./undomanager").UndoManager;
+var Renderer = require("./virtual_renderer").VirtualRenderer;
+require("./worker/worker_client");
+require("./keyboard/hash_handler");
+require("./placeholder");
+require("./multi_select");
+require("./mode/folding/fold_mode");
+require("./theme/textmate");
+require("./ext/error_marker");
+
+exports.config = require("./config");
+exports.require = require;
+exports.edit = function(el) {
+ if (typeof(el) == "string") {
+ var _id = el;
+ el = document.getElementById(_id);
+ if (!el)
+ throw new Error("ace.edit can't find div #" + _id);
+ }
+
+ if (el && el.env && el.env.editor instanceof Editor)
+ return el.env.editor;
+
+ var value = "";
+ if (el && /input|textarea/i.test(el.tagName)) {
+ var oldNode = el;
+ value = oldNode.value;
+ el = dom.createElement("pre");
+ oldNode.parentNode.replaceChild(el, oldNode);
+ } else {
+ value = dom.getInnerText(el);
+ el.innerHTML = '';
+ }
+
+ var doc = exports.createEditSession(value);
+
+ var editor = new Editor(new Renderer(el));
+ editor.setSession(doc);
+
+ var env = {
+ document: doc,
+ editor: editor,
+ onResize: editor.resize.bind(editor, null)
+ };
+ if (oldNode) env.textarea = oldNode;
+ event.addListener(window, "resize", env.onResize);
+ editor.on("destroy", function() {
+ event.removeListener(window, "resize", env.onResize);
+ env.editor.container.env = null; // prevent memory leak on old ie
+ });
+ editor.container.env = editor.env = env;
+ return editor;
+};
+exports.createEditSession = function(text, mode) {
+ var doc = new EditSession(text, mode);
+ doc.setUndoManager(new UndoManager());
+ return doc;
+}
+exports.EditSession = EditSession;
+exports.UndoManager = UndoManager;
+});
+ (function() {
+ window.require(["ace/ace"], function(a) {
+ a && a.config.init(true);
+ if (!window.ace)
+ window.ace = a;
+ for (var key in a) if (a.hasOwnProperty(key))
+ window.ace[key] = a[key];
+ });
+ })();
+
\ No newline at end of file
diff --git a/panoramix/static/lib/ace/mode-sql.js b/panoramix/static/lib/ace/mode-sql.js
new file mode 100644
index 0000000000000..66c50c1f760af
--- /dev/null
+++ b/panoramix/static/lib/ace/mode-sql.js
@@ -0,0 +1,92 @@
+define("ace/mode/sql_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"], function(require, exports, module) {
+"use strict";
+
+var oop = require("../lib/oop");
+var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
+
+var SqlHighlightRules = function() {
+
+ var keywords = (
+ "select|insert|update|delete|from|where|and|or|group|by|order|limit|offset|having|as|case|" +
+ "when|else|end|type|left|right|join|on|outer|desc|asc|union"
+ );
+
+ var builtinConstants = (
+ "true|false|null"
+ );
+
+ var builtinFunctions = (
+ "count|min|max|avg|sum|rank|now|coalesce"
+ );
+
+ var keywordMapper = this.createKeywordMapper({
+ "support.function": builtinFunctions,
+ "keyword": keywords,
+ "constant.language": builtinConstants
+ }, "identifier", true);
+
+ this.$rules = {
+ "start" : [ {
+ token : "comment",
+ regex : "--.*$"
+ }, {
+ token : "comment",
+ start : "/\\*",
+ end : "\\*/"
+ }, {
+ token : "string", // " string
+ regex : '".*?"'
+ }, {
+ token : "string", // ' string
+ regex : "'.*?'"
+ }, {
+ token : "constant.numeric", // float
+ regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
+ }, {
+ token : keywordMapper,
+ regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
+ }, {
+ token : "keyword.operator",
+ regex : "\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|="
+ }, {
+ token : "paren.lparen",
+ regex : "[\\(]"
+ }, {
+ token : "paren.rparen",
+ regex : "[\\)]"
+ }, {
+ token : "text",
+ regex : "\\s+"
+ } ]
+ };
+ this.normalizeRules();
+};
+
+oop.inherits(SqlHighlightRules, TextHighlightRules);
+
+exports.SqlHighlightRules = SqlHighlightRules;
+});
+
+define("ace/mode/sql",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/sql_highlight_rules","ace/range"], function(require, exports, module) {
+"use strict";
+
+var oop = require("../lib/oop");
+var TextMode = require("./text").Mode;
+var SqlHighlightRules = require("./sql_highlight_rules").SqlHighlightRules;
+var Range = require("../range").Range;
+
+var Mode = function() {
+ this.HighlightRules = SqlHighlightRules;
+};
+oop.inherits(Mode, TextMode);
+
+(function() {
+
+ this.lineCommentStart = "--";
+
+ this.$id = "ace/mode/sql";
+}).call(Mode.prototype);
+
+exports.Mode = Mode;
+
+});
diff --git a/panoramix/static/lib/ace/theme-crimson_editor.js b/panoramix/static/lib/ace/theme-crimson_editor.js
new file mode 100644
index 0000000000000..a71cf6a4b4b54
--- /dev/null
+++ b/panoramix/static/lib/ace/theme-crimson_editor.js
@@ -0,0 +1,118 @@
+define("ace/theme/crimson_editor",["require","exports","module","ace/lib/dom"], function(require, exports, module) {
+exports.isDark = false;
+exports.cssText = ".ace-crimson-editor .ace_gutter {\
+background: #ebebeb;\
+color: #333;\
+overflow : hidden;\
+}\
+.ace-crimson-editor .ace_gutter-layer {\
+width: 100%;\
+text-align: right;\
+}\
+.ace-crimson-editor .ace_print-margin {\
+width: 1px;\
+background: #e8e8e8;\
+}\
+.ace-crimson-editor {\
+background-color: #FFFFFF;\
+color: rgb(64, 64, 64);\
+}\
+.ace-crimson-editor .ace_cursor {\
+color: black;\
+}\
+.ace-crimson-editor .ace_invisible {\
+color: rgb(191, 191, 191);\
+}\
+.ace-crimson-editor .ace_identifier {\
+color: black;\
+}\
+.ace-crimson-editor .ace_keyword {\
+color: blue;\
+}\
+.ace-crimson-editor .ace_constant.ace_buildin {\
+color: rgb(88, 72, 246);\
+}\
+.ace-crimson-editor .ace_constant.ace_language {\
+color: rgb(255, 156, 0);\
+}\
+.ace-crimson-editor .ace_constant.ace_library {\
+color: rgb(6, 150, 14);\
+}\
+.ace-crimson-editor .ace_invalid {\
+text-decoration: line-through;\
+color: rgb(224, 0, 0);\
+}\
+.ace-crimson-editor .ace_fold {\
+}\
+.ace-crimson-editor .ace_support.ace_function {\
+color: rgb(192, 0, 0);\
+}\
+.ace-crimson-editor .ace_support.ace_constant {\
+color: rgb(6, 150, 14);\
+}\
+.ace-crimson-editor .ace_support.ace_type,\
+.ace-crimson-editor .ace_support.ace_class {\
+color: rgb(109, 121, 222);\
+}\
+.ace-crimson-editor .ace_keyword.ace_operator {\
+color: rgb(49, 132, 149);\
+}\
+.ace-crimson-editor .ace_string {\
+color: rgb(128, 0, 128);\
+}\
+.ace-crimson-editor .ace_comment {\
+color: rgb(76, 136, 107);\
+}\
+.ace-crimson-editor .ace_comment.ace_doc {\
+color: rgb(0, 102, 255);\
+}\
+.ace-crimson-editor .ace_comment.ace_doc.ace_tag {\
+color: rgb(128, 159, 191);\
+}\
+.ace-crimson-editor .ace_constant.ace_numeric {\
+color: rgb(0, 0, 64);\
+}\
+.ace-crimson-editor .ace_variable {\
+color: rgb(0, 64, 128);\
+}\
+.ace-crimson-editor .ace_xml-pe {\
+color: rgb(104, 104, 91);\
+}\
+.ace-crimson-editor .ace_marker-layer .ace_selection {\
+background: rgb(181, 213, 255);\
+}\
+.ace-crimson-editor .ace_marker-layer .ace_step {\
+background: rgb(252, 255, 0);\
+}\
+.ace-crimson-editor .ace_marker-layer .ace_stack {\
+background: rgb(164, 229, 101);\
+}\
+.ace-crimson-editor .ace_marker-layer .ace_bracket {\
+margin: -1px 0 0 -1px;\
+border: 1px solid rgb(192, 192, 192);\
+}\
+.ace-crimson-editor .ace_marker-layer .ace_active-line {\
+background: rgb(232, 242, 254);\
+}\
+.ace-crimson-editor .ace_gutter-active-line {\
+background-color : #dcdcdc;\
+}\
+.ace-crimson-editor .ace_meta.ace_tag {\
+color:rgb(28, 2, 255);\
+}\
+.ace-crimson-editor .ace_marker-layer .ace_selected-word {\
+background: rgb(250, 250, 255);\
+border: 1px solid rgb(200, 200, 250);\
+}\
+.ace-crimson-editor .ace_string.ace_regex {\
+color: rgb(192, 0, 192);\
+}\
+.ace-crimson-editor .ace_indent-guide {\
+background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==\") right repeat-y;\
+}";
+
+exports.cssClass = "ace-crimson-editor";
+
+var dom = require("../lib/dom");
+dom.importCssString(exports.cssText, exports.cssClass);
+});
diff --git a/panoramix/static/panoramix.js b/panoramix/static/panoramix.js
index 12e810fd9e6b3..ff4f24d1889b7 100644
--- a/panoramix/static/panoramix.js
+++ b/panoramix/static/panoramix.js
@@ -443,6 +443,62 @@ var px = (function() {
});
}
+ function initSqlEditorView() {
+ var editor = ace.edit("sql");
+ var textarea = $('#sql').hide();
+ editor.setTheme("ace/theme/crimson_editor");
+ editor.setOptions({
+ minLines: 16,
+ maxLines: Infinity,
+ });
+ editor.getSession().setMode("ace/mode/sql");
+ editor.focus();
+
+ $("select").select2({dropdownAutoWidth : true});
+ function showTableMetadata() {
+ $(".metadata").load('/panoramix/table/' + $("#dbtable").val() + '/');
+ }
+ $("#dbtable").on("change", showTableMetadata);
+ showTableMetadata();
+ $("#create_view").click(function(){alert("Not implemented");});
+ $(".sqlcontent").show();
+ $("#select_star").click(function(){
+ $.ajax('/panoramix/select_star/' + $("#dbtable").val() + '/')
+ .done(function(msg){
+ editor.setValue(msg);
+ });
+ });
+ $("#run").click(function() {
+ $('#results').hide(0);
+ $('#loading').show(0);
+ $.ajax({
+ type: "POST",
+ url: '/panoramix/runsql/',
+ data: {
+ 'data': JSON.stringify({
+ 'database_id': $('#database_id').val(),
+ 'sql': editor.getSession().getValue(),
+ })},
+ success: function(data) {
+ $('#loading').hide(0);
+ $('#results').show(0);
+ $('#results').html(data);
+
+ var datatable = $('table.sql_results').DataTable({
+ paging: false,
+ searching: true,
+ aaSorting: [],
+ });
+ },
+ error: function(err, err2) {
+ $('#loading').hide(0);
+ $('#results').show(0);
+ $('#results').html(err.responseText);
+ },
+ });
+ });
+ }
+
function initDashboardView() {
var gridster = $(".gridster ul").gridster({
widget_margins: [5, 5],
@@ -546,5 +602,6 @@ var px = (function() {
timeFormatFactory: timeFormatFactory,
color: color(),
renderSlice: renderSlice,
+ initSqlEditorView: initSqlEditorView,
}
})();
diff --git a/panoramix/templates/panoramix/ajah.html b/panoramix/templates/panoramix/ajah.html
new file mode 100644
index 0000000000000..b5d122680d719
--- /dev/null
+++ b/panoramix/templates/panoramix/ajah.html
@@ -0,0 +1 @@
+{{ content |safe }}
diff --git a/panoramix/templates/panoramix/dashboard.html b/panoramix/templates/panoramix/dashboard.html
index c461c246dd81e..93fb684991d26 100644
--- a/panoramix/templates/panoramix/dashboard.html
+++ b/panoramix/templates/panoramix/dashboard.html
@@ -137,9 +137,6 @@
$(document).ready(function() {
px.initDashboardView();
var dashboard = px.Dashboard({{ dashboard.id }});
- $('#filters').click( function(){
- alert(dashboard.readFilters());
- });
});
{% endblock %}
diff --git a/panoramix/templates/panoramix/sql.html b/panoramix/templates/panoramix/sql.html
index e378d107d96c4..75d480229ced2 100644
--- a/panoramix/templates/panoramix/sql.html
+++ b/panoramix/templates/panoramix/sql.html
@@ -8,8 +8,12 @@
.topsql {
height: 250px;
}
+ .dataTables_filter {
+ padding-top: 5px;
+ padding-right: 5px;
+ }
.bordered {
- padding: 5px 10px;
+ padding: 0px 0px;
border: 1px solid grey;
border-radius: 5px;
background-color: #EEE;
@@ -26,8 +30,8 @@
.fillheight {
height: 100%;
}
- #interactive {
- padding-top: 10px;
+ .interactions {
+ padding-bottom: 10px;
}
#results {
overflow: auto;
@@ -41,7 +45,23 @@
{% endblock %}
{% block content %}
+
db: [{{ db }}]
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
{% endblock %}
{% block tail_js %}
{{ super() }}
+
{% endblock %}
diff --git a/panoramix/views.py b/panoramix/views.py
index a3536465a2b9f..6b1ac686918a6 100644
--- a/panoramix/views.py
+++ b/panoramix/views.py
@@ -113,7 +113,7 @@ class MetricInlineView(CompactCRUDMixin, PanoramixModelView):
class DatabaseView(PanoramixModelView, DeleteMixin):
datamodel = SQLAInterface(models.Database)
- list_columns = ['database_name', 'created_by', 'changed_on_']
+ list_columns = ['database_name', 'sql_link', 'created_by', 'changed_on_']
add_columns = ['database_name', 'sqlalchemy_uri']
search_exclude_columns = ('password',)
edit_columns = add_columns
@@ -135,6 +135,7 @@ def pre_add(self, db):
def pre_update(self, db):
self.pre_add(db)
+
appbuilder.add_view(
DatabaseView,
"Databases",
@@ -562,25 +563,57 @@ def sql(self, database_id):
database_id=database_id,
db=mydb)
+ @has_access
+ @expose("/table//")
+ @utils.log_this
+ def table(self, table_id):
+ t = db.session.query(models.SqlaTable).filter_by(id=table_id).first()
+ return self.render_template(
+ "panoramix/ajah.html",
+ content=t.html)
+
+ @has_access
+ @expose("/select_star//")
+ @utils.log_this
+ def select_star(self, table_id):
+ t = db.session.query(models.SqlaTable).filter_by(id=table_id).first()
+ fields = ", ".join(
+ [c.column_name for c in t.columns if not c.expression] or "*")
+ s = "SELECT\n{fields}\nFROM {t.table_name}\nLIMIT 1000".format(**locals())
+ return self.render_template(
+ "panoramix/ajah.html",
+ content=s)
+
@has_access
@expose("/runsql/", methods=['POST', 'GET'])
@utils.log_this
def runsql(self):
session = db.session()
+ limit = 1000
data = json.loads(request.form.get('data'))
sql = data.get('sql')
database_id = data.get('database_id')
mydb = session.query(models.Database).filter_by(id=database_id).first()
content = ""
if mydb:
- print("SUPER!")
from pandas import read_sql_query
+ from sqlalchemy import select, text
+ from sqlalchemy.sql.expression import TextAsFrom
eng = mydb.get_sqla_engine()
+ if limit:
+ sql = sql.strip().strip(';')
+ qry = (
+ select('*')
+ .select_from(TextAsFrom(text(sql), ['*']).alias('inner_qry'))
+ .limit(limit)
+ )
+ sql= str(qry.compile(eng, compile_kwargs={"literal_binds": True}))
df = read_sql_query(sql=sql, con=eng)
content = df.to_html(
- classes="dataframe table table-striped table-bordered table-condensed")
- else:
- print("ELSE")
+ index=False,
+ classes=(
+ "dataframe table table-striped table-bordered "
+ "table-condensed sql_results"))
session.commit()
return content