mirror of
https://github.com/linuxserver/core.git
synced 2026-02-20 05:07:19 +08:00
3481 lines
132 KiB
JavaScript
3481 lines
132 KiB
JavaScript
define("ace/layer/lines",[], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var dom = require("../lib/dom");
|
|
|
|
var Lines = function(element, canvasHeight) {
|
|
this.element = element;
|
|
this.canvasHeight = canvasHeight || 500000;
|
|
this.element.style.height = (this.canvasHeight * 2) + "px";
|
|
|
|
this.cells = [];
|
|
this.cellCache = [];
|
|
this.$offsetCoefficient = 0;
|
|
};
|
|
|
|
(function() {
|
|
|
|
this.moveContainer = function(config) {
|
|
dom.translate(this.element, 0, -((config.firstRowScreen * config.lineHeight) % this.canvasHeight) - config.offset * this.$offsetCoefficient);
|
|
};
|
|
|
|
this.pageChanged = function(oldConfig, newConfig) {
|
|
return (
|
|
Math.floor((oldConfig.firstRowScreen * oldConfig.lineHeight) / this.canvasHeight) !==
|
|
Math.floor((newConfig.firstRowScreen * newConfig.lineHeight) / this.canvasHeight)
|
|
);
|
|
};
|
|
|
|
this.computeLineTop = function(row, config, session) {
|
|
var screenTop = config.firstRowScreen * config.lineHeight;
|
|
var screenPage = Math.floor(screenTop / this.canvasHeight);
|
|
var lineTop = session.documentToScreenRow(row, 0) * config.lineHeight;
|
|
return lineTop - (screenPage * this.canvasHeight);
|
|
};
|
|
|
|
this.computeLineHeight = function(row, config, session) {
|
|
return config.lineHeight * session.getRowLength(row);
|
|
};
|
|
|
|
this.getLength = function() {
|
|
return this.cells.length;
|
|
};
|
|
|
|
this.get = function(index) {
|
|
return this.cells[index];
|
|
};
|
|
|
|
this.shift = function() {
|
|
this.$cacheCell(this.cells.shift());
|
|
};
|
|
|
|
this.pop = function() {
|
|
this.$cacheCell(this.cells.pop());
|
|
};
|
|
|
|
this.push = function(cell) {
|
|
if (Array.isArray(cell)) {
|
|
this.cells.push.apply(this.cells, cell);
|
|
var fragment = dom.createFragment(this.element);
|
|
for (var i=0; i<cell.length; i++) {
|
|
fragment.appendChild(cell[i].element);
|
|
}
|
|
this.element.appendChild(fragment);
|
|
} else {
|
|
this.cells.push(cell);
|
|
this.element.appendChild(cell.element);
|
|
}
|
|
};
|
|
|
|
this.unshift = function(cell) {
|
|
if (Array.isArray(cell)) {
|
|
this.cells.unshift.apply(this.cells, cell);
|
|
var fragment = dom.createFragment(this.element);
|
|
for (var i=0; i<cell.length; i++) {
|
|
fragment.appendChild(cell[i].element);
|
|
}
|
|
if (this.element.firstChild)
|
|
this.element.insertBefore(fragment, this.element.firstChild);
|
|
else
|
|
this.element.appendChild(fragment);
|
|
} else {
|
|
this.cells.unshift(cell);
|
|
this.element.insertAdjacentElement("afterbegin", cell.element);
|
|
}
|
|
};
|
|
|
|
this.last = function() {
|
|
if (this.cells.length)
|
|
return this.cells[this.cells.length-1];
|
|
else
|
|
return null;
|
|
};
|
|
|
|
this.$cacheCell = function(cell) {
|
|
if (!cell)
|
|
return;
|
|
|
|
cell.element.remove();
|
|
this.cellCache.push(cell);
|
|
};
|
|
|
|
this.createCell = function(row, config, session, initElement) {
|
|
var cell = this.cellCache.pop();
|
|
if (!cell) {
|
|
var element = dom.createElement("div");
|
|
if (initElement)
|
|
initElement(element);
|
|
|
|
this.element.appendChild(element);
|
|
|
|
cell = {
|
|
element: element,
|
|
text: "",
|
|
row: row
|
|
};
|
|
}
|
|
cell.row = row;
|
|
|
|
return cell;
|
|
};
|
|
|
|
}).call(Lines.prototype);
|
|
|
|
exports.Lines = Lines;
|
|
|
|
});
|
|
|
|
define("ace/layer/gutter",[], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var dom = require("../lib/dom");
|
|
var oop = require("../lib/oop");
|
|
var lang = require("../lib/lang");
|
|
var EventEmitter = require("../lib/event_emitter").EventEmitter;
|
|
var Lines = require("./lines").Lines;
|
|
|
|
var Gutter = function(parentEl) {
|
|
this.element = dom.createElement("div");
|
|
this.element.className = "ace_layer ace_gutter-layer";
|
|
parentEl.appendChild(this.element);
|
|
this.setShowFoldWidgets(this.$showFoldWidgets);
|
|
|
|
this.gutterWidth = 0;
|
|
|
|
this.$annotations = [];
|
|
this.$updateAnnotations = this.$updateAnnotations.bind(this);
|
|
|
|
this.$lines = new Lines(this.element);
|
|
this.$lines.$offsetCoefficient = 1;
|
|
};
|
|
|
|
(function() {
|
|
|
|
oop.implement(this, EventEmitter);
|
|
|
|
this.setSession = function(session) {
|
|
if (this.session)
|
|
this.session.removeEventListener("change", this.$updateAnnotations);
|
|
this.session = session;
|
|
if (session)
|
|
session.on("change", this.$updateAnnotations);
|
|
};
|
|
|
|
this.addGutterDecoration = function(row, className) {
|
|
if (window.console)
|
|
console.warn && console.warn("deprecated use session.addGutterDecoration");
|
|
this.session.addGutterDecoration(row, className);
|
|
};
|
|
|
|
this.removeGutterDecoration = function(row, className) {
|
|
if (window.console)
|
|
console.warn && console.warn("deprecated use session.removeGutterDecoration");
|
|
this.session.removeGutterDecoration(row, className);
|
|
};
|
|
|
|
this.setAnnotations = function(annotations) {
|
|
this.$annotations = [];
|
|
for (var i = 0; i < annotations.length; i++) {
|
|
var annotation = annotations[i];
|
|
var row = annotation.row;
|
|
var rowInfo = this.$annotations[row];
|
|
if (!rowInfo)
|
|
rowInfo = this.$annotations[row] = {text: []};
|
|
|
|
var annoText = annotation.text;
|
|
annoText = annoText ? lang.escapeHTML(annoText) : annotation.html || "";
|
|
|
|
if (rowInfo.text.indexOf(annoText) === -1)
|
|
rowInfo.text.push(annoText);
|
|
|
|
var type = annotation.type;
|
|
if (type == "error")
|
|
rowInfo.className = " ace_error";
|
|
else if (type == "warning" && rowInfo.className != " ace_error")
|
|
rowInfo.className = " ace_warning";
|
|
else if (type == "info" && (!rowInfo.className))
|
|
rowInfo.className = " ace_info";
|
|
}
|
|
};
|
|
|
|
this.$updateAnnotations = function (delta) {
|
|
if (!this.$annotations.length)
|
|
return;
|
|
var firstRow = delta.start.row;
|
|
var len = delta.end.row - firstRow;
|
|
if (len === 0) {
|
|
} else if (delta.action == 'remove') {
|
|
this.$annotations.splice(firstRow, len + 1, null);
|
|
} else {
|
|
var args = new Array(len + 1);
|
|
args.unshift(firstRow, 1);
|
|
this.$annotations.splice.apply(this.$annotations, args);
|
|
}
|
|
};
|
|
|
|
this.update = function(config) {
|
|
this.config = config;
|
|
|
|
var session = this.session;
|
|
var firstRow = config.firstRow;
|
|
var lastRow = Math.min(config.lastRow + config.gutterOffset, // needed to compensate for hor scollbar
|
|
session.getLength() - 1);
|
|
|
|
this.oldLastRow = lastRow;
|
|
this.config = config;
|
|
|
|
this.$lines.moveContainer(config);
|
|
this.$updateCursorRow();
|
|
|
|
var fold = session.getNextFoldLine(firstRow);
|
|
var foldStart = fold ? fold.start.row : Infinity;
|
|
|
|
var cell = null;
|
|
var index = -1;
|
|
var row = firstRow;
|
|
|
|
var cells = Array.prototype.slice.call(this.element.childNodes, 0);
|
|
|
|
while (true) {
|
|
if (row > foldStart) {
|
|
row = fold.end.row + 1;
|
|
fold = session.getNextFoldLine(row, fold);
|
|
foldStart = fold ? fold.start.row : Infinity;
|
|
}
|
|
if (row > lastRow) {
|
|
while (this.$lines.getLength() > index + 1)
|
|
this.$lines.pop();
|
|
|
|
break;
|
|
}
|
|
|
|
cell = this.$lines.get(++index);
|
|
if (!cell) {
|
|
cell = this.$lines.createCell(row, config, this.session, onCreateCell);
|
|
this.$lines.push(cell);
|
|
}
|
|
|
|
this.$renderCell(cell, config, fold, row);
|
|
row++;
|
|
}
|
|
|
|
this._signal("afterRender");
|
|
this.$updateGutterWidth(config);
|
|
};
|
|
|
|
this.$updateGutterWidth = function(config) {
|
|
var session = this.session;
|
|
|
|
var gutterRenderer = session.gutterRenderer || this.$renderer;
|
|
|
|
var firstLineNumber = session.$firstLineNumber;
|
|
var lastLineText = this.$lines.last() ? this.$lines.last().text : "";
|
|
|
|
if (this.$fixedWidth || session.$useWrapMode)
|
|
lastLineText = session.getLength() + firstLineNumber;
|
|
|
|
var gutterWidth = gutterRenderer
|
|
? gutterRenderer.getWidth(session, lastLineText, config)
|
|
: lastLineText.toString().length * config.characterWidth;
|
|
|
|
var padding = this.$padding || this.$computePadding();
|
|
gutterWidth += padding.left + padding.right;
|
|
if (gutterWidth !== this.gutterWidth && !isNaN(gutterWidth)) {
|
|
this.gutterWidth = gutterWidth;
|
|
this.element.parentNode.style.width =
|
|
this.element.style.width = Math.ceil(this.gutterWidth) + "px";
|
|
this._signal("changeGutterWidth", gutterWidth);
|
|
}
|
|
};
|
|
|
|
this.$updateCursorRow = function() {
|
|
if (!this.$highlightGutterLine)
|
|
return;
|
|
|
|
var position = this.session.selection.getCursor();
|
|
if (this.$cursorRow === position.row)
|
|
return;
|
|
|
|
this.$cursorRow = position.row;
|
|
};
|
|
|
|
this.updateLineHighlight = function() {
|
|
if (!this.$highlightGutterLine)
|
|
return;
|
|
var row = this.session.selection.cursor.row;
|
|
this.$cursorRow = row;
|
|
|
|
if (this.$cursorCell && this.$cursorCell.row == row)
|
|
return;
|
|
if (this.$cursorCell)
|
|
this.$cursorCell.element.className = this.$cursorCell.element.className.replace("ace_gutter-active-line ", "");
|
|
var cells = this.$lines.cells;
|
|
this.$cursorCell = null;
|
|
for (var i = 0; i < cells.length; i++) {
|
|
var cell = cells[i];
|
|
if (cell.row >= this.$cursorRow) {
|
|
if (cell.row > this.$cursorRow) {
|
|
var fold = this.session.getFoldLine(this.$cursorRow);
|
|
if (i > 0 && fold && fold.start.row == cells[i - 1].row)
|
|
cell = cells[i - 1];
|
|
else
|
|
break;
|
|
}
|
|
cell.element.className = "ace_gutter-active-line " + cell.element.className;
|
|
this.$cursorCell = cell;
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
this.scrollLines = function(config) {
|
|
var oldConfig = this.config;
|
|
this.config = config;
|
|
|
|
this.$updateCursorRow();
|
|
if (this.$lines.pageChanged(oldConfig, config))
|
|
return this.update(config);
|
|
|
|
this.$lines.moveContainer(config);
|
|
|
|
var lastRow = Math.min(config.lastRow + config.gutterOffset, // needed to compensate for hor scollbar
|
|
this.session.getLength() - 1);
|
|
var oldLastRow = this.oldLastRow;
|
|
this.oldLastRow = lastRow;
|
|
|
|
if (!oldConfig || oldLastRow < config.firstRow)
|
|
return this.update(config);
|
|
|
|
if (lastRow < oldConfig.firstRow)
|
|
return this.update(config);
|
|
|
|
if (oldConfig.firstRow < config.firstRow)
|
|
for (var row=this.session.getFoldedRowCount(oldConfig.firstRow, config.firstRow - 1); row>0; row--)
|
|
this.$lines.shift();
|
|
|
|
if (oldLastRow > lastRow)
|
|
for (var row=this.session.getFoldedRowCount(lastRow + 1, oldLastRow); row>0; row--)
|
|
this.$lines.pop();
|
|
|
|
if (config.firstRow < oldConfig.firstRow) {
|
|
this.$lines.unshift(this.$renderLines(config, config.firstRow, oldConfig.firstRow - 1));
|
|
}
|
|
|
|
if (lastRow > oldLastRow) {
|
|
this.$lines.push(this.$renderLines(config, oldLastRow + 1, lastRow));
|
|
}
|
|
|
|
this.updateLineHighlight();
|
|
|
|
this._signal("afterRender");
|
|
this.$updateGutterWidth(config);
|
|
};
|
|
|
|
this.$renderLines = function(config, firstRow, lastRow) {
|
|
var fragment = [];
|
|
var row = firstRow;
|
|
var foldLine = this.session.getNextFoldLine(row);
|
|
var foldStart = foldLine ? foldLine.start.row : Infinity;
|
|
|
|
while (true) {
|
|
if (row > foldStart) {
|
|
row = foldLine.end.row+1;
|
|
foldLine = this.session.getNextFoldLine(row, foldLine);
|
|
foldStart = foldLine ? foldLine.start.row : Infinity;
|
|
}
|
|
if (row > lastRow)
|
|
break;
|
|
|
|
var cell = this.$lines.createCell(row, config, this.session, onCreateCell);
|
|
this.$renderCell(cell, config, foldLine, row);
|
|
fragment.push(cell);
|
|
|
|
row++;
|
|
}
|
|
return fragment;
|
|
};
|
|
|
|
this.$renderCell = function(cell, config, fold, row) {
|
|
var element = cell.element;
|
|
|
|
var session = this.session;
|
|
|
|
var textNode = element.childNodes[0];
|
|
var foldWidget = element.childNodes[1];
|
|
|
|
var firstLineNumber = session.$firstLineNumber;
|
|
|
|
var breakpoints = session.$breakpoints;
|
|
var decorations = session.$decorations;
|
|
var gutterRenderer = session.gutterRenderer || this.$renderer;
|
|
var foldWidgets = this.$showFoldWidgets && session.foldWidgets;
|
|
var foldStart = fold ? fold.start.row : Number.MAX_VALUE;
|
|
|
|
var className = "ace_gutter-cell ";
|
|
if (this.$highlightGutterLine) {
|
|
if (row == this.$cursorRow || (fold && row < this.$cursorRow && row >= foldStart && this.$cursorRow <= fold.end.row)) {
|
|
className += "ace_gutter-active-line ";
|
|
if (this.$cursorCell != cell) {
|
|
if (this.$cursorCell)
|
|
this.$cursorCell.element.className = this.$cursorCell.element.className.replace("ace_gutter-active-line ", "");
|
|
this.$cursorCell = cell;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (breakpoints[row])
|
|
className += breakpoints[row];
|
|
if (decorations[row])
|
|
className += decorations[row];
|
|
if (this.$annotations[row])
|
|
className += this.$annotations[row].className;
|
|
if (element.className != className)
|
|
element.className = className;
|
|
|
|
if (foldWidgets) {
|
|
var c = foldWidgets[row];
|
|
if (c == null)
|
|
c = foldWidgets[row] = session.getFoldWidget(row);
|
|
}
|
|
|
|
if (c) {
|
|
var className = "ace_fold-widget ace_" + c;
|
|
if (c == "start" && row == foldStart && row < fold.end.row)
|
|
className += " ace_closed";
|
|
else
|
|
className += " ace_open";
|
|
if (foldWidget.className != className)
|
|
foldWidget.className = className;
|
|
|
|
var foldHeight = config.lineHeight + "px";
|
|
dom.setStyle(foldWidget.style, "height", foldHeight);
|
|
dom.setStyle(foldWidget.style, "display", "inline-block");
|
|
} else {
|
|
if (foldWidget) {
|
|
dom.setStyle(foldWidget.style, "display", "none");
|
|
}
|
|
}
|
|
|
|
var text = (gutterRenderer
|
|
? gutterRenderer.getText(session, row)
|
|
: row + firstLineNumber).toString();
|
|
|
|
if (text !== textNode.data) {
|
|
textNode.data = text;
|
|
}
|
|
|
|
dom.setStyle(cell.element.style, "height", this.$lines.computeLineHeight(row, config, session) + "px");
|
|
dom.setStyle(cell.element.style, "top", this.$lines.computeLineTop(row, config, session) + "px");
|
|
|
|
cell.text = text;
|
|
return cell;
|
|
};
|
|
|
|
this.$fixedWidth = false;
|
|
|
|
this.$highlightGutterLine = true;
|
|
this.$renderer = "";
|
|
this.setHighlightGutterLine = function(highlightGutterLine) {
|
|
this.$highlightGutterLine = highlightGutterLine;
|
|
};
|
|
|
|
this.$showLineNumbers = true;
|
|
this.$renderer = "";
|
|
this.setShowLineNumbers = function(show) {
|
|
this.$renderer = !show && {
|
|
getWidth: function() {return "";},
|
|
getText: function() {return "";}
|
|
};
|
|
};
|
|
|
|
this.getShowLineNumbers = function() {
|
|
return this.$showLineNumbers;
|
|
};
|
|
|
|
this.$showFoldWidgets = true;
|
|
this.setShowFoldWidgets = function(show) {
|
|
if (show)
|
|
dom.addCssClass(this.element, "ace_folding-enabled");
|
|
else
|
|
dom.removeCssClass(this.element, "ace_folding-enabled");
|
|
|
|
this.$showFoldWidgets = show;
|
|
this.$padding = null;
|
|
};
|
|
|
|
this.getShowFoldWidgets = function() {
|
|
return this.$showFoldWidgets;
|
|
};
|
|
|
|
this.$computePadding = function() {
|
|
if (!this.element.firstChild)
|
|
return {left: 0, right: 0};
|
|
var style = dom.computedStyle(this.element.firstChild);
|
|
this.$padding = {};
|
|
this.$padding.left = (parseInt(style.borderLeftWidth) || 0)
|
|
+ (parseInt(style.paddingLeft) || 0) + 1;
|
|
this.$padding.right = (parseInt(style.borderRightWidth) || 0)
|
|
+ (parseInt(style.paddingRight) || 0);
|
|
return this.$padding;
|
|
};
|
|
|
|
this.getRegion = function(point) {
|
|
var padding = this.$padding || this.$computePadding();
|
|
var rect = this.element.getBoundingClientRect();
|
|
if (point.x < padding.left + rect.left)
|
|
return "markers";
|
|
if (this.$showFoldWidgets && point.x > rect.right - padding.right)
|
|
return "foldWidgets";
|
|
};
|
|
|
|
}).call(Gutter.prototype);
|
|
|
|
function onCreateCell(element) {
|
|
var textNode = document.createTextNode('');
|
|
element.appendChild(textNode);
|
|
|
|
var foldWidget = dom.createElement("span");
|
|
element.appendChild(foldWidget);
|
|
|
|
return element;
|
|
}
|
|
|
|
exports.Gutter = Gutter;
|
|
|
|
});
|
|
|
|
define("ace/layer/marker",[], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var Range = require("../range").Range;
|
|
var dom = require("../lib/dom");
|
|
|
|
var Marker = function(parentEl) {
|
|
this.element = dom.createElement("div");
|
|
this.element.className = "ace_layer ace_marker-layer";
|
|
parentEl.appendChild(this.element);
|
|
};
|
|
|
|
(function() {
|
|
|
|
this.$padding = 0;
|
|
|
|
this.setPadding = function(padding) {
|
|
this.$padding = padding;
|
|
};
|
|
this.setSession = function(session) {
|
|
this.session = session;
|
|
};
|
|
|
|
this.setMarkers = function(markers) {
|
|
this.markers = markers;
|
|
};
|
|
|
|
this.elt = function(className, css) {
|
|
var x = this.i != -1 && this.element.childNodes[this.i];
|
|
if (!x) {
|
|
x = document.createElement("div");
|
|
this.element.appendChild(x);
|
|
this.i = -1;
|
|
} else {
|
|
this.i++;
|
|
}
|
|
x.style.cssText = css;
|
|
x.className = className;
|
|
};
|
|
|
|
this.update = function(config) {
|
|
if (!config) return;
|
|
|
|
this.config = config;
|
|
|
|
this.i = 0;
|
|
var html;
|
|
for (var key in this.markers) {
|
|
var marker = this.markers[key];
|
|
|
|
if (!marker.range) {
|
|
marker.update(html, this, this.session, config);
|
|
continue;
|
|
}
|
|
|
|
var range = marker.range.clipRows(config.firstRow, config.lastRow);
|
|
if (range.isEmpty()) continue;
|
|
|
|
range = range.toScreenRange(this.session);
|
|
if (marker.renderer) {
|
|
var top = this.$getTop(range.start.row, config);
|
|
var left = this.$padding + range.start.column * config.characterWidth;
|
|
marker.renderer(html, range, left, top, config);
|
|
} else if (marker.type == "fullLine") {
|
|
this.drawFullLineMarker(html, range, marker.clazz, config);
|
|
} else if (marker.type == "screenLine") {
|
|
this.drawScreenLineMarker(html, range, marker.clazz, config);
|
|
} else if (range.isMultiLine()) {
|
|
if (marker.type == "text")
|
|
this.drawTextMarker(html, range, marker.clazz, config);
|
|
else
|
|
this.drawMultiLineMarker(html, range, marker.clazz, config);
|
|
} else {
|
|
this.drawSingleLineMarker(html, range, marker.clazz + " ace_start" + " ace_br15", config);
|
|
}
|
|
}
|
|
if (this.i !=-1) {
|
|
while (this.i < this.element.childElementCount)
|
|
this.element.removeChild(this.element.lastChild);
|
|
}
|
|
};
|
|
|
|
this.$getTop = function(row, layerConfig) {
|
|
return (row - layerConfig.firstRowScreen) * layerConfig.lineHeight;
|
|
};
|
|
|
|
function getBorderClass(tl, tr, br, bl) {
|
|
return (tl ? 1 : 0) | (tr ? 2 : 0) | (br ? 4 : 0) | (bl ? 8 : 0);
|
|
}
|
|
this.drawTextMarker = function(stringBuilder, range, clazz, layerConfig, extraStyle) {
|
|
var session = this.session;
|
|
var start = range.start.row;
|
|
var end = range.end.row;
|
|
var row = start;
|
|
var prev = 0;
|
|
var curr = 0;
|
|
var next = session.getScreenLastRowColumn(row);
|
|
var lineRange = new Range(row, range.start.column, row, curr);
|
|
for (; row <= end; row++) {
|
|
lineRange.start.row = lineRange.end.row = row;
|
|
lineRange.start.column = row == start ? range.start.column : session.getRowWrapIndent(row);
|
|
lineRange.end.column = next;
|
|
prev = curr;
|
|
curr = next;
|
|
next = row + 1 < end ? session.getScreenLastRowColumn(row + 1) : row == end ? 0 : range.end.column;
|
|
this.drawSingleLineMarker(stringBuilder, lineRange,
|
|
clazz + (row == start ? " ace_start" : "") + " ace_br"
|
|
+ getBorderClass(row == start || row == start + 1 && range.start.column, prev < curr, curr > next, row == end),
|
|
layerConfig, row == end ? 0 : 1, extraStyle);
|
|
}
|
|
};
|
|
this.drawMultiLineMarker = function(stringBuilder, range, clazz, config, extraStyle) {
|
|
var padding = this.$padding;
|
|
var height = config.lineHeight;
|
|
var top = this.$getTop(range.start.row, config);
|
|
var left = padding + range.start.column * config.characterWidth;
|
|
extraStyle = extraStyle || "";
|
|
|
|
this.elt(
|
|
clazz + " ace_br1 ace_start",
|
|
"height:"+ height+ "px;"+ "right:0;"+ "top:"+top+ "px;left:"+ left+ "px;" + (extraStyle || "")
|
|
);
|
|
top = this.$getTop(range.end.row, config);
|
|
var width = range.end.column * config.characterWidth;
|
|
|
|
this.elt(
|
|
clazz + " ace_br12",
|
|
"height:"+ height+ "px;"+
|
|
"width:"+ width+ "px;"+
|
|
"top:"+ top+ "px;"+
|
|
"left:"+ padding+ "px;"+ (extraStyle || "")
|
|
);
|
|
height = (range.end.row - range.start.row - 1) * config.lineHeight;
|
|
if (height <= 0)
|
|
return;
|
|
top = this.$getTop(range.start.row + 1, config);
|
|
|
|
var radiusClass = (range.start.column ? 1 : 0) | (range.end.column ? 0 : 8);
|
|
|
|
this.elt(
|
|
clazz + (radiusClass ? " ace_br" + radiusClass : ""),
|
|
"height:"+ height+ "px;"+
|
|
"right:0;"+
|
|
"top:"+ top+ "px;"+
|
|
"left:"+ padding+ "px;"+ (extraStyle || "")
|
|
);
|
|
};
|
|
this.drawSingleLineMarker = function(stringBuilder, range, clazz, config, extraLength, extraStyle) {
|
|
var height = config.lineHeight;
|
|
var width = (range.end.column + (extraLength || 0) - range.start.column) * config.characterWidth;
|
|
|
|
var top = this.$getTop(range.start.row, config);
|
|
var left = this.$padding + range.start.column * config.characterWidth;
|
|
|
|
this.elt(
|
|
clazz,
|
|
"height:"+ height+ "px;"+
|
|
"width:"+ width+ "px;"+
|
|
"top:"+ top+ "px;"+
|
|
"left:"+ left+ "px;"+ (extraStyle || "")
|
|
);
|
|
};
|
|
|
|
this.drawFullLineMarker = function(stringBuilder, range, clazz, config, extraStyle) {
|
|
var top = this.$getTop(range.start.row, config);
|
|
var height = config.lineHeight;
|
|
if (range.start.row != range.end.row)
|
|
height += this.$getTop(range.end.row, config) - top;
|
|
|
|
this.elt(
|
|
clazz,
|
|
"height:"+ height+ "px;"+
|
|
"top:"+ top+ "px;"+
|
|
"left:0;right:0;"+ (extraStyle || "")
|
|
);
|
|
};
|
|
|
|
this.drawScreenLineMarker = function(stringBuilder, range, clazz, config, extraStyle) {
|
|
var top = this.$getTop(range.start.row, config);
|
|
var height = config.lineHeight;
|
|
|
|
this.elt(
|
|
clazz,
|
|
"height:"+ height+ "px;"+
|
|
"top:"+ top+ "px;"+
|
|
"left:0;right:0;"+ (extraStyle || "")
|
|
);
|
|
};
|
|
|
|
}).call(Marker.prototype);
|
|
|
|
exports.Marker = Marker;
|
|
|
|
});
|
|
|
|
define("ace/layer/text",[], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var oop = require("../lib/oop");
|
|
var dom = require("../lib/dom");
|
|
var lang = require("../lib/lang");
|
|
var Lines = require("./lines").Lines;
|
|
var EventEmitter = require("../lib/event_emitter").EventEmitter;
|
|
|
|
var Text = function(parentEl) {
|
|
this.dom = dom;
|
|
this.element = this.dom.createElement("div");
|
|
this.element.className = "ace_layer ace_text-layer";
|
|
parentEl.appendChild(this.element);
|
|
this.$updateEolChar = this.$updateEolChar.bind(this);
|
|
this.$lines = new Lines(this.element);
|
|
};
|
|
|
|
(function() {
|
|
|
|
oop.implement(this, EventEmitter);
|
|
|
|
this.EOF_CHAR = "\xB6";
|
|
this.EOL_CHAR_LF = "\xAC";
|
|
this.EOL_CHAR_CRLF = "\xa4";
|
|
this.EOL_CHAR = this.EOL_CHAR_LF;
|
|
this.TAB_CHAR = "\u2014"; //"\u21E5";
|
|
this.SPACE_CHAR = "\xB7";
|
|
this.$padding = 0;
|
|
this.MAX_LINE_LENGTH = 10000;
|
|
|
|
this.$updateEolChar = function() {
|
|
var doc = this.session.doc;
|
|
var unixMode = doc.getNewLineCharacter() == "\n" && doc.getNewLineMode() != "windows";
|
|
var EOL_CHAR = unixMode ? this.EOL_CHAR_LF : this.EOL_CHAR_CRLF;
|
|
if (this.EOL_CHAR != EOL_CHAR) {
|
|
this.EOL_CHAR = EOL_CHAR;
|
|
return true;
|
|
}
|
|
};
|
|
|
|
this.setPadding = function(padding) {
|
|
this.$padding = padding;
|
|
this.element.style.margin = "0 " + padding + "px";
|
|
};
|
|
|
|
this.getLineHeight = function() {
|
|
return this.$fontMetrics.$characterSize.height || 0;
|
|
};
|
|
|
|
this.getCharacterWidth = function() {
|
|
return this.$fontMetrics.$characterSize.width || 0;
|
|
};
|
|
|
|
this.$setFontMetrics = function(measure) {
|
|
this.$fontMetrics = measure;
|
|
this.$fontMetrics.on("changeCharacterSize", function(e) {
|
|
this._signal("changeCharacterSize", e);
|
|
}.bind(this));
|
|
this.$pollSizeChanges();
|
|
};
|
|
|
|
this.checkForSizeChanges = function() {
|
|
this.$fontMetrics.checkForSizeChanges();
|
|
};
|
|
this.$pollSizeChanges = function() {
|
|
return this.$pollSizeChangesTimer = this.$fontMetrics.$pollSizeChanges();
|
|
};
|
|
this.setSession = function(session) {
|
|
this.session = session;
|
|
if (session)
|
|
this.$computeTabString();
|
|
};
|
|
|
|
this.showInvisibles = false;
|
|
this.setShowInvisibles = function(showInvisibles) {
|
|
if (this.showInvisibles == showInvisibles)
|
|
return false;
|
|
|
|
this.showInvisibles = showInvisibles;
|
|
this.$computeTabString();
|
|
return true;
|
|
};
|
|
|
|
this.displayIndentGuides = true;
|
|
this.setDisplayIndentGuides = function(display) {
|
|
if (this.displayIndentGuides == display)
|
|
return false;
|
|
|
|
this.displayIndentGuides = display;
|
|
this.$computeTabString();
|
|
return true;
|
|
};
|
|
|
|
this.$tabStrings = [];
|
|
this.onChangeTabSize =
|
|
this.$computeTabString = function() {
|
|
var tabSize = this.session.getTabSize();
|
|
this.tabSize = tabSize;
|
|
var tabStr = this.$tabStrings = [0];
|
|
for (var i = 1; i < tabSize + 1; i++) {
|
|
if (this.showInvisibles) {
|
|
var span = this.dom.createElement("span");
|
|
span.className = "ace_invisible ace_invisible_tab";
|
|
span.textContent = lang.stringRepeat(this.TAB_CHAR, i);
|
|
tabStr.push(span);
|
|
} else {
|
|
tabStr.push(this.dom.createTextNode(lang.stringRepeat(" ", i), this.element));
|
|
}
|
|
}
|
|
if (this.displayIndentGuides) {
|
|
this.$indentGuideRe = /\s\S| \t|\t |\s$/;
|
|
var className = "ace_indent-guide";
|
|
var spaceClass = "";
|
|
var tabClass = "";
|
|
if (this.showInvisibles) {
|
|
className += " ace_invisible";
|
|
spaceClass = " ace_invisible_space";
|
|
tabClass = " ace_invisible_tab";
|
|
var spaceContent = lang.stringRepeat(this.SPACE_CHAR, this.tabSize);
|
|
var tabContent = lang.stringRepeat(this.TAB_CHAR, this.tabSize);
|
|
} else {
|
|
var spaceContent = lang.stringRepeat(" ", this.tabSize);
|
|
var tabContent = spaceContent;
|
|
}
|
|
|
|
var span = this.dom.createElement("span");
|
|
span.className = className + spaceClass;
|
|
span.textContent = spaceContent;
|
|
this.$tabStrings[" "] = span;
|
|
|
|
var span = this.dom.createElement("span");
|
|
span.className = className + tabClass;
|
|
span.textContent = tabContent;
|
|
this.$tabStrings["\t"] = span;
|
|
}
|
|
};
|
|
|
|
this.updateLines = function(config, firstRow, lastRow) {
|
|
if (this.config.lastRow != config.lastRow ||
|
|
this.config.firstRow != config.firstRow) {
|
|
return this.update(config);
|
|
}
|
|
|
|
this.config = config;
|
|
|
|
var first = Math.max(firstRow, config.firstRow);
|
|
var last = Math.min(lastRow, config.lastRow);
|
|
|
|
var lineElements = this.element.childNodes;
|
|
var lineElementsIdx = 0;
|
|
|
|
for (var row = config.firstRow; row < first; row++) {
|
|
var foldLine = this.session.getFoldLine(row);
|
|
if (foldLine) {
|
|
if (foldLine.containsRow(first)) {
|
|
first = foldLine.start.row;
|
|
break;
|
|
} else {
|
|
row = foldLine.end.row;
|
|
}
|
|
}
|
|
lineElementsIdx ++;
|
|
}
|
|
|
|
var heightChanged = false;
|
|
var row = first;
|
|
var foldLine = this.session.getNextFoldLine(row);
|
|
var foldStart = foldLine ? foldLine.start.row : Infinity;
|
|
|
|
while (true) {
|
|
if (row > foldStart) {
|
|
row = foldLine.end.row+1;
|
|
foldLine = this.session.getNextFoldLine(row, foldLine);
|
|
foldStart = foldLine ? foldLine.start.row :Infinity;
|
|
}
|
|
if (row > last)
|
|
break;
|
|
|
|
var lineElement = lineElements[lineElementsIdx++];
|
|
if (lineElement) {
|
|
this.dom.removeChildren(lineElement);
|
|
this.$renderLine(
|
|
lineElement, row, row == foldStart ? foldLine : false
|
|
);
|
|
var height = (config.lineHeight * this.session.getRowLength(row)) + "px";
|
|
if (lineElement.style.height != height) {
|
|
heightChanged = true;
|
|
lineElement.style.height = height;
|
|
}
|
|
}
|
|
row++;
|
|
}
|
|
if (heightChanged) {
|
|
while (lineElementsIdx < this.$lines.cells.length) {
|
|
var cell = this.$lines.cells[lineElementsIdx++];
|
|
cell.element.style.top = this.$lines.computeLineTop(cell.row, config, this.session) + "px";
|
|
}
|
|
}
|
|
};
|
|
|
|
this.scrollLines = function(config) {
|
|
var oldConfig = this.config;
|
|
this.config = config;
|
|
|
|
if (this.$lines.pageChanged(oldConfig, config))
|
|
return this.update(config);
|
|
|
|
this.$lines.moveContainer(config);
|
|
|
|
var lastRow = config.lastRow;
|
|
var oldLastRow = oldConfig ? oldConfig.lastRow : -1;
|
|
|
|
if (!oldConfig || oldLastRow < config.firstRow)
|
|
return this.update(config);
|
|
|
|
if (lastRow < oldConfig.firstRow)
|
|
return this.update(config);
|
|
|
|
if (!oldConfig || oldConfig.lastRow < config.firstRow)
|
|
return this.update(config);
|
|
|
|
if (config.lastRow < oldConfig.firstRow)
|
|
return this.update(config);
|
|
|
|
if (oldConfig.firstRow < config.firstRow)
|
|
for (var row=this.session.getFoldedRowCount(oldConfig.firstRow, config.firstRow - 1); row>0; row--)
|
|
this.$lines.shift();
|
|
|
|
if (oldConfig.lastRow > config.lastRow)
|
|
for (var row=this.session.getFoldedRowCount(config.lastRow + 1, oldConfig.lastRow); row>0; row--)
|
|
this.$lines.pop();
|
|
|
|
if (config.firstRow < oldConfig.firstRow) {
|
|
this.$lines.unshift(this.$renderLinesFragment(config, config.firstRow, oldConfig.firstRow - 1));
|
|
}
|
|
|
|
if (config.lastRow > oldConfig.lastRow) {
|
|
this.$lines.push(this.$renderLinesFragment(config, oldConfig.lastRow + 1, config.lastRow));
|
|
}
|
|
};
|
|
|
|
this.$renderLinesFragment = function(config, firstRow, lastRow) {
|
|
var fragment = [];
|
|
var row = firstRow;
|
|
var foldLine = this.session.getNextFoldLine(row);
|
|
var foldStart = foldLine ? foldLine.start.row : Infinity;
|
|
|
|
while (true) {
|
|
if (row > foldStart) {
|
|
row = foldLine.end.row+1;
|
|
foldLine = this.session.getNextFoldLine(row, foldLine);
|
|
foldStart = foldLine ? foldLine.start.row : Infinity;
|
|
}
|
|
if (row > lastRow)
|
|
break;
|
|
|
|
var line = this.$lines.createCell(row, config, this.session);
|
|
|
|
var lineEl = line.element;
|
|
this.dom.removeChildren(lineEl);
|
|
dom.setStyle(lineEl.style, "height", this.$lines.computeLineHeight(row, config, this.session) + "px");
|
|
dom.setStyle(lineEl.style, "top", this.$lines.computeLineTop(row, config, this.session) + "px");
|
|
this.$renderLine(lineEl, row, row == foldStart ? foldLine : false);
|
|
|
|
if (this.$useLineGroups()) {
|
|
lineEl.className = "ace_line_group";
|
|
} else {
|
|
lineEl.className = "ace_line";
|
|
}
|
|
fragment.push(line);
|
|
|
|
row++;
|
|
}
|
|
return fragment;
|
|
};
|
|
|
|
this.update = function(config) {
|
|
this.$lines.moveContainer(config);
|
|
|
|
this.config = config;
|
|
|
|
var firstRow = config.firstRow;
|
|
var lastRow = config.lastRow;
|
|
|
|
var lines = this.$lines;
|
|
while (lines.getLength())
|
|
lines.pop();
|
|
|
|
lines.push(this.$renderLinesFragment(config, firstRow, lastRow));
|
|
};
|
|
|
|
this.$textToken = {
|
|
"text": true,
|
|
"rparen": true,
|
|
"lparen": true
|
|
};
|
|
|
|
this.$renderToken = function(parent, screenColumn, token, value) {
|
|
var self = this;
|
|
var re = /(\t)|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\uFEFF\uFFF9-\uFFFC]+)|(\u3000)|([\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3001-\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]|[\uD800-\uDBFF][\uDC00-\uDFFF])/g;
|
|
|
|
var valueFragment = this.dom.createFragment(this.element);
|
|
|
|
var m;
|
|
var i = 0;
|
|
while (m = re.exec(value)) {
|
|
var tab = m[1];
|
|
var simpleSpace = m[2];
|
|
var controlCharacter = m[3];
|
|
var cjkSpace = m[4];
|
|
var cjk = m[5];
|
|
|
|
if (!self.showInvisibles && simpleSpace)
|
|
continue;
|
|
|
|
var before = i != m.index ? value.slice(i, m.index) : "";
|
|
|
|
i = m.index + m[0].length;
|
|
|
|
if (before) {
|
|
valueFragment.appendChild(this.dom.createTextNode(before, this.element));
|
|
}
|
|
|
|
if (tab) {
|
|
var tabSize = self.session.getScreenTabSize(screenColumn + m.index);
|
|
valueFragment.appendChild(self.$tabStrings[tabSize].cloneNode(true));
|
|
screenColumn += tabSize - 1;
|
|
} else if (simpleSpace) {
|
|
if (self.showInvisibles) {
|
|
var span = this.dom.createElement("span");
|
|
span.className = "ace_invisible ace_invisible_space";
|
|
span.textContent = lang.stringRepeat(self.SPACE_CHAR, simpleSpace.length);
|
|
valueFragment.appendChild(span);
|
|
} else {
|
|
valueFragment.appendChild(this.com.createTextNode(simpleSpace, this.element));
|
|
}
|
|
} else if (controlCharacter) {
|
|
var span = this.dom.createElement("span");
|
|
span.className = "ace_invisible ace_invisible_space ace_invalid";
|
|
span.textContent = lang.stringRepeat(self.SPACE_CHAR, controlCharacter.length);
|
|
valueFragment.appendChild(span);
|
|
} else if (cjkSpace) {
|
|
var space = self.showInvisibles ? self.SPACE_CHAR : "";
|
|
screenColumn += 1;
|
|
|
|
var span = this.dom.createElement("span");
|
|
span.style.width = (self.config.characterWidth * 2) + "px";
|
|
span.className = self.showInvisibles ? "ace_cjk ace_invisible ace_invisible_space" : "ace_cjk";
|
|
span.textContent = self.showInvisibles ? self.SPACE_CHAR : "";
|
|
valueFragment.appendChild(span);
|
|
} else if (cjk) {
|
|
screenColumn += 1;
|
|
var span = dom.createElement("span");
|
|
span.style.width = (self.config.characterWidth * 2) + "px";
|
|
span.className = "ace_cjk";
|
|
span.textContent = cjk;
|
|
valueFragment.appendChild(span);
|
|
}
|
|
}
|
|
|
|
valueFragment.appendChild(this.dom.createTextNode(i ? value.slice(i) : value, this.element));
|
|
|
|
if (!this.$textToken[token.type]) {
|
|
var classes = "ace_" + token.type.replace(/\./g, " ace_");
|
|
var span = this.dom.createElement("span");
|
|
if (token.type == "fold")
|
|
span.style.width = (token.value.length * this.config.characterWidth) + "px";
|
|
|
|
span.className = classes;
|
|
span.appendChild(valueFragment);
|
|
|
|
parent.appendChild(span);
|
|
}
|
|
else {
|
|
parent.appendChild(valueFragment);
|
|
}
|
|
|
|
return screenColumn + value.length;
|
|
};
|
|
|
|
this.renderIndentGuide = function(parent, value, max) {
|
|
var cols = value.search(this.$indentGuideRe);
|
|
if (cols <= 0 || cols >= max)
|
|
return value;
|
|
if (value[0] == " ") {
|
|
cols -= cols % this.tabSize;
|
|
var count = cols/this.tabSize;
|
|
for (var i=0; i<count; i++) {
|
|
parent.appendChild(this.$tabStrings[" "].cloneNode(true));
|
|
}
|
|
return value.substr(cols);
|
|
} else if (value[0] == "\t") {
|
|
for (var i=0; i<cols; i++) {
|
|
parent.appendChild(this.$tabStrings["\t"].cloneNode(true));
|
|
}
|
|
return value.substr(cols);
|
|
}
|
|
return value;
|
|
};
|
|
|
|
this.$createLineElement = function(parent) {
|
|
var lineEl = this.dom.createElement("div");
|
|
lineEl.className = "ace_line";
|
|
lineEl.style.height = this.config.lineHeight + "px";
|
|
|
|
return lineEl;
|
|
};
|
|
|
|
this.$renderWrappedLine = function(parent, tokens, splits) {
|
|
var chars = 0;
|
|
var split = 0;
|
|
var splitChars = splits[0];
|
|
var screenColumn = 0;
|
|
|
|
var lineEl = this.$createLineElement();
|
|
parent.appendChild(lineEl);
|
|
|
|
for (var i = 0; i < tokens.length; i++) {
|
|
var token = tokens[i];
|
|
var value = token.value;
|
|
if (i == 0 && this.displayIndentGuides) {
|
|
chars = value.length;
|
|
value = this.renderIndentGuide(lineEl, value, splitChars);
|
|
if (!value)
|
|
continue;
|
|
chars -= value.length;
|
|
}
|
|
|
|
if (chars + value.length < splitChars) {
|
|
screenColumn = this.$renderToken(lineEl, screenColumn, token, value);
|
|
chars += value.length;
|
|
} else {
|
|
while (chars + value.length >= splitChars) {
|
|
screenColumn = this.$renderToken(
|
|
lineEl, screenColumn,
|
|
token, value.substring(0, splitChars - chars)
|
|
);
|
|
value = value.substring(splitChars - chars);
|
|
chars = splitChars;
|
|
|
|
lineEl = this.$createLineElement();
|
|
parent.appendChild(lineEl);
|
|
|
|
lineEl.appendChild(this.dom.createTextNode(lang.stringRepeat("\xa0", splits.indent), this.element));
|
|
|
|
split ++;
|
|
screenColumn = 0;
|
|
splitChars = splits[split] || Number.MAX_VALUE;
|
|
}
|
|
if (value.length != 0) {
|
|
chars += value.length;
|
|
screenColumn = this.$renderToken(
|
|
lineEl, screenColumn, token, value
|
|
);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
this.$renderSimpleLine = function(parent, tokens) {
|
|
var screenColumn = 0;
|
|
var token = tokens[0];
|
|
var value = token.value;
|
|
if (this.displayIndentGuides)
|
|
value = this.renderIndentGuide(parent, value);
|
|
if (value)
|
|
screenColumn = this.$renderToken(parent, screenColumn, token, value);
|
|
for (var i = 1; i < tokens.length; i++) {
|
|
token = tokens[i];
|
|
value = token.value;
|
|
if (screenColumn + value.length > this.MAX_LINE_LENGTH)
|
|
return this.$renderOverflowMessage(parent, screenColumn, token, value);
|
|
screenColumn = this.$renderToken(parent, screenColumn, token, value);
|
|
}
|
|
};
|
|
|
|
this.$renderOverflowMessage = function(parent, screenColumn, token, value) {
|
|
this.$renderToken(parent, screenColumn, token,
|
|
value.slice(0, this.MAX_LINE_LENGTH - screenColumn));
|
|
|
|
var overflowEl = this.dom.createElement("span");
|
|
overflowEl.className = "ace_inline_button ace_keyword ace_toggle_wrap";
|
|
overflowEl.style.position = "absolute";
|
|
overflowEl.style.right = "0";
|
|
overflowEl.textContent = "<click to see more...>";
|
|
|
|
parent.appendChild(overflowEl);
|
|
};
|
|
this.$renderLine = function(parent, row, 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);
|
|
|
|
var lastLineEl = parent;
|
|
if (tokens.length) {
|
|
var splits = this.session.getRowSplitData(row);
|
|
if (splits && splits.length) {
|
|
this.$renderWrappedLine(parent, tokens, splits);
|
|
var lastLineEl = parent.lastChild;
|
|
} else {
|
|
var lastLineEl = parent;
|
|
if (this.$useLineGroups()) {
|
|
lastLineEl = this.$createLineElement();
|
|
parent.appendChild(lastLineEl);
|
|
}
|
|
this.$renderSimpleLine(lastLineEl, tokens);
|
|
}
|
|
} else if (this.$useLineGroups()) {
|
|
lastLineEl = this.$createLineElement();
|
|
parent.appendChild(lastLineEl);
|
|
}
|
|
|
|
if (this.showInvisibles && lastLineEl) {
|
|
if (foldLine)
|
|
row = foldLine.end.row;
|
|
|
|
var invisibleEl = this.dom.createElement("span");
|
|
invisibleEl.className = "ace_invisible ace_invisible_eol";
|
|
invisibleEl.textContent = row == this.session.getLength() - 1 ? this.EOF_CHAR : this.EOL_CHAR;
|
|
|
|
lastLineEl.appendChild(invisibleEl);
|
|
}
|
|
};
|
|
|
|
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",[], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var dom = require("../lib/dom");
|
|
|
|
var Cursor = function(parentEl) {
|
|
this.element = dom.createElement("div");
|
|
this.element.className = "ace_layer ace_cursor-layer";
|
|
parentEl.appendChild(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.$updateOpacity.bind(this);
|
|
};
|
|
|
|
(function() {
|
|
|
|
this.$updateOpacity = function(val) {
|
|
var cursors = this.cursors;
|
|
for (var i = cursors.length; i--; )
|
|
dom.setStyle(cursors[i].style, "opacity", val ? "" : "0");
|
|
};
|
|
|
|
this.$startCssAnimation = function() {
|
|
var cursors = this.cursors;
|
|
for (var i = cursors.length; i--; )
|
|
cursors[i].style.animationDuration = this.blinkInterval + "ms";
|
|
|
|
setTimeout(function() {
|
|
dom.addCssClass(this.element, "ace_animate-blinking");
|
|
}.bind(this));
|
|
};
|
|
|
|
this.$stopCssAnimation = function() {
|
|
dom.removeCssClass(this.element, "ace_animate-blinking");
|
|
};
|
|
|
|
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) {
|
|
this.smoothBlinking = smoothBlinking;
|
|
dom.setCssClass(this.element, "ace_smooth-blinking", smoothBlinking);
|
|
this.$updateCursors(true);
|
|
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);
|
|
this.$stopCssAnimation();
|
|
|
|
if (this.smoothBlinking) {
|
|
dom.removeCssClass(this.element, "ace_smooth-blinking");
|
|
}
|
|
|
|
update(true);
|
|
|
|
if (!this.isBlinking || !this.blinkInterval || !this.isVisible) {
|
|
this.$stopCssAnimation();
|
|
return;
|
|
}
|
|
|
|
if (this.smoothBlinking) {
|
|
setTimeout(function(){
|
|
dom.addCssClass(this.element, "ace_smooth-blinking");
|
|
}.bind(this));
|
|
}
|
|
|
|
if (dom.HAS_CSS_ANIMATION) {
|
|
this.$startCssAnimation();
|
|
} else {
|
|
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 + (this.session.$bidiHandler.isBidiRow(pos.row, position.row)
|
|
? this.session.$bidiHandler.getPosLeft(pos.column)
|
|
: pos.column * this.config.characterWidth);
|
|
|
|
var cursorTop = (pos.row - (onScreen ? this.config.firstRowScreen : 0)) *
|
|
this.config.lineHeight;
|
|
|
|
return {left : cursorLeft, top : cursorTop};
|
|
};
|
|
|
|
this.isCursorInView = function(pixelPos, config) {
|
|
return pixelPos.top >= 0 && pixelPos.top < config.maxHeight;
|
|
};
|
|
|
|
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 element = this.cursors[cursorIndex++] || this.addCursor();
|
|
var style = element.style;
|
|
|
|
if (!this.drawCursor) {
|
|
if (!this.isCursorInView(pixelPos, config)) {
|
|
dom.setStyle(style, "display", "none");
|
|
} else {
|
|
dom.setStyle(style, "display", "block");
|
|
dom.translate(element, pixelPos.left, pixelPos.top);
|
|
dom.setStyle(style, "width", Math.round(config.characterWidth) + "px");
|
|
dom.setStyle(style, "height", config.lineHeight + "px");
|
|
}
|
|
} else {
|
|
this.drawCursor(element, 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",[], 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 MAX_SCROLL_H = 0x8000;
|
|
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;
|
|
this.coeff = 1;
|
|
};
|
|
}).call(ScrollBar.prototype);
|
|
var VScrollBar = function(parent, renderer) {
|
|
ScrollBar.call(this, parent);
|
|
this.scrollTop = 0;
|
|
this.scrollHeight = 0;
|
|
renderer.$scrollbarWidth =
|
|
this.width = dom.scrollbarWidth(parent.ownerDocument);
|
|
this.inner.style.width =
|
|
this.element.style.width = (this.width || 15) + 5 + "px";
|
|
this.$minWidth = 0;
|
|
};
|
|
|
|
oop.inherits(VScrollBar, ScrollBar);
|
|
|
|
(function() {
|
|
|
|
this.classSuffix = '-v';
|
|
this.onScroll = function() {
|
|
if (!this.skipEvent) {
|
|
this.scrollTop = this.element.scrollTop;
|
|
if (this.coeff != 1) {
|
|
var h = this.element.clientHeight / this.scrollHeight;
|
|
this.scrollTop = this.scrollTop * (1 - h) / (this.coeff - h);
|
|
}
|
|
this._emit("scroll", {data: this.scrollTop});
|
|
}
|
|
this.skipEvent = false;
|
|
};
|
|
this.getWidth = function() {
|
|
return Math.max(this.isVisible ? this.width : 0, this.$minWidth || 0);
|
|
};
|
|
this.setHeight = function(height) {
|
|
this.element.style.height = height + "px";
|
|
};
|
|
this.setInnerHeight =
|
|
this.setScrollHeight = function(height) {
|
|
this.scrollHeight = height;
|
|
if (height > MAX_SCROLL_H) {
|
|
this.coeff = MAX_SCROLL_H / height;
|
|
height = MAX_SCROLL_H;
|
|
} else if (this.coeff != 1) {
|
|
this.coeff = 1;
|
|
}
|
|
this.inner.style.height = height + "px";
|
|
};
|
|
this.setScrollTop = function(scrollTop) {
|
|
if (this.scrollTop != scrollTop) {
|
|
this.skipEvent = true;
|
|
this.scrollTop = scrollTop;
|
|
this.element.scrollTop = scrollTop * this.coeff;
|
|
}
|
|
};
|
|
|
|
}).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",[], 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.changes) {
|
|
var _self = this;
|
|
|
|
event.nextFrame(function(ts) {
|
|
var changes = _self.changes;
|
|
|
|
if (changes) {
|
|
event.blockIdle(100);
|
|
_self.changes = 0;
|
|
_self.onRender(changes);
|
|
}
|
|
|
|
if (_self.changes)
|
|
_self.schedule();
|
|
});
|
|
}
|
|
};
|
|
|
|
}).call(RenderLoop.prototype);
|
|
|
|
exports.RenderLoop = RenderLoop;
|
|
});
|
|
|
|
define("ace/layer/font_metrics",[], function(require, exports, module) {
|
|
|
|
var oop = require("../lib/oop");
|
|
var dom = require("../lib/dom");
|
|
var lang = require("../lib/lang");
|
|
var event = require("../lib/event");
|
|
var useragent = require("../lib/useragent");
|
|
var EventEmitter = require("../lib/event_emitter").EventEmitter;
|
|
|
|
var CHAR_COUNT = 256;
|
|
var USE_OBSERVER = typeof ResizeObserver == "function";
|
|
var L = 200;
|
|
|
|
var FontMetrics = exports.FontMetrics = function(parentEl) {
|
|
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);
|
|
|
|
this.$measureNode.innerHTML = lang.stringRepeat("X", CHAR_COUNT);
|
|
|
|
this.$characterSize = {width: 0, height: 0};
|
|
|
|
|
|
if (USE_OBSERVER)
|
|
this.$addObserver();
|
|
else
|
|
this.checkForSizeChanges();
|
|
};
|
|
|
|
(function() {
|
|
|
|
oop.implement(this, EventEmitter);
|
|
|
|
this.$characterSize = {width: 0, height: 0};
|
|
|
|
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(size) {
|
|
if (size === undefined)
|
|
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.$addObserver = function() {
|
|
var self = this;
|
|
this.$observer = new window.ResizeObserver(function(e) {
|
|
var rect = e[0].contentRect;
|
|
self.checkForSizeChanges({
|
|
height: rect.height,
|
|
width: rect.width / CHAR_COUNT
|
|
});
|
|
});
|
|
this.$observer.observe(this.$measureNode);
|
|
};
|
|
|
|
this.$pollSizeChanges = function() {
|
|
if (this.$pollSizeChangesTimer || this.$observer)
|
|
return this.$pollSizeChangesTimer;
|
|
var self = this;
|
|
|
|
return this.$pollSizeChangesTimer = event.onIdle(function cb() {
|
|
self.checkForSizeChanges();
|
|
event.onIdle(cb, 500);
|
|
}, 500);
|
|
};
|
|
|
|
this.setPolling = function(val) {
|
|
if (val) {
|
|
this.$pollSizeChanges();
|
|
} else if (this.$pollSizeChangesTimer) {
|
|
clearInterval(this.$pollSizeChangesTimer);
|
|
this.$pollSizeChangesTimer = 0;
|
|
}
|
|
};
|
|
|
|
this.$measureSizes = function(node) {
|
|
var size = {
|
|
height: (node || this.$measureNode).clientHeight,
|
|
width: (node || 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) {
|
|
w = 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);
|
|
};
|
|
|
|
|
|
this.$getZoom = function getZoom(element) {
|
|
if (!element) return 1;
|
|
return (window.getComputedStyle(element).zoom || 1) * getZoom(element.parentElement);
|
|
};
|
|
this.$initTransformMeasureNodes = function() {
|
|
var t = function(t, l) {
|
|
return ["div", {
|
|
style: "position: absolute;top:" + t + "px;left:" + l + "px;"
|
|
}];
|
|
};
|
|
this.els = dom.buildDom([t(0, 0), t(L, 0), t(0, L), t(L, L)], this.el);
|
|
};
|
|
this.transformCoordinates = function(clientPos, elPos) {
|
|
if (clientPos) {
|
|
var zoom = this.$getZoom(this.el);
|
|
clientPos = mul(1 / zoom, clientPos);
|
|
}
|
|
function solve(l1, l2, r) {
|
|
var det = l1[1] * l2[0] - l1[0] * l2[1];
|
|
return [
|
|
(-l2[1] * r[0] + l2[0] * r[1]) / det,
|
|
(+l1[1] * r[0] - l1[0] * r[1]) / det
|
|
];
|
|
}
|
|
function sub(a, b) { return [a[0] - b[0], a[1] - b[1]]; }
|
|
function add(a, b) { return [a[0] + b[0], a[1] + b[1]]; }
|
|
function mul(a, b) { return [a * b[0], a * b[1]]; }
|
|
|
|
if (!this.els)
|
|
this.$initTransformMeasureNodes();
|
|
|
|
function p(el) {
|
|
var r = el.getBoundingClientRect();
|
|
return [r.left, r.top];
|
|
}
|
|
|
|
var a = p(this.els[0]);
|
|
var b = p(this.els[1]);
|
|
var c = p(this.els[2]);
|
|
var d = p(this.els[3]);
|
|
|
|
var h = solve(sub(d, b), sub(d, c), sub(add(b, c), add(d, a)));
|
|
|
|
var m1 = mul(1 + h[0], sub(b, a));
|
|
var m2 = mul(1 + h[1], sub(c, a));
|
|
|
|
if (elPos) {
|
|
var x = elPos;
|
|
var k = h[0] * x[0] / L + h[1] * x[1] / L + 1;
|
|
var ut = add(mul(x[0], m1), mul(x[1], m2));
|
|
return add(mul(1 / k / L, ut), a);
|
|
}
|
|
var u = sub(clientPos, a);
|
|
var f = solve(sub(m1, mul(h[0], u)), sub(m2, mul(h[1], u)), u);
|
|
return mul(L, f);
|
|
};
|
|
|
|
}).call(FontMetrics.prototype);
|
|
|
|
});
|
|
|
|
define("ace/requirejs/text!ace/css/editor.css",[],".ace_editor {\n position: relative;\n overflow: hidden;\n font: 12px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;\n direction: ltr;\n text-align: left;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\n\n.ace_scroller {\n position: absolute;\n overflow: hidden;\n top: 0;\n bottom: 0;\n background-color: inherit;\n -ms-user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n user-select: none;\n cursor: text;\n}\n\n.ace_content {\n position: absolute;\n box-sizing: border-box;\n min-width: 100%;\n contain: style size layout;\n}\n\n.ace_dragging .ace_scroller:before{\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n content: '';\n background: rgba(250, 250, 250, 0.01);\n z-index: 1000;\n}\n.ace_dragging.ace_dark .ace_scroller:before{\n background: rgba(0, 0, 0, 0.01);\n}\n\n.ace_gutter {\n position: absolute;\n overflow : hidden;\n width: auto;\n top: 0;\n bottom: 0;\n left: 0;\n cursor: default;\n z-index: 4;\n -ms-user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n user-select: none;\n contain: style size layout;\n}\n\n.ace_gutter-active-line {\n position: absolute;\n left: 0;\n right: 0;\n}\n\n.ace_scroller.ace_scroll-left {\n box-shadow: 17px 0 16px -16px rgba(0, 0, 0, 0.4) inset;\n}\n\n.ace_gutter-cell {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n padding-left: 19px;\n padding-right: 6px;\n background-repeat: no-repeat;\n}\n\n.ace_gutter-cell.ace_error {\n 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==\");\n background-repeat: no-repeat;\n background-position: 2px center;\n}\n\n.ace_gutter-cell.ace_warning {\n 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==\");\n background-position: 2px center;\n}\n\n.ace_gutter-cell.ace_info {\n background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAJ0Uk5TAAB2k804AAAAPklEQVQY02NgIB68QuO3tiLznjAwpKTgNyDbMegwisCHZUETUZV0ZqOquBpXj2rtnpSJT1AEnnRmL2OgGgAAIKkRQap2htgAAAAASUVORK5CYII=\");\n background-position: 2px center;\n}\n.ace_dark .ace_gutter-cell.ace_info {\n background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAChoaGAgIAqKiq+vr6tra1ZWVmUlJSbm5s8PDxubm56enrdgzg3AAAAAXRSTlMAQObYZgAAAClJREFUeNpjYMAPdsMYHegyJZFQBlsUlMFVCWUYKkAZMxZAGdxlDMQBAG+TBP4B6RyJAAAAAElFTkSuQmCC\");\n}\n\n.ace_scrollbar {\n contain: strict;\n position: absolute;\n right: 0;\n bottom: 0;\n z-index: 6;\n}\n\n.ace_scrollbar-inner {\n position: absolute;\n cursor: text;\n left: 0;\n top: 0;\n}\n\n.ace_scrollbar-v{\n overflow-x: hidden;\n overflow-y: scroll;\n top: 0;\n}\n\n.ace_scrollbar-h {\n overflow-x: scroll;\n overflow-y: hidden;\n left: 0;\n}\n\n.ace_print-margin {\n position: absolute;\n height: 100%;\n}\n\n.ace_text-input {\n position: absolute;\n z-index: 0;\n width: 0.5em;\n height: 1em;\n opacity: 0;\n background: transparent;\n -moz-appearance: none;\n appearance: none;\n border: none;\n resize: none;\n outline: none;\n overflow: hidden;\n font: inherit;\n padding: 0 1px;\n margin: 0 -1px;\n text-indent: -1em;\n -ms-user-select: text;\n -moz-user-select: text;\n -webkit-user-select: text;\n user-select: text;\n white-space: pre!important;\n}\n.ace_text-input.ace_composition {\n background: inherit;\n color: inherit;\n z-index: 1000;\n opacity: 1;\n text-indent: 0;\n}\n[ace_nocontext=true] {\n transform: none!important;\n filter: none!important;\n perspective: none!important;\n clip-path: none!important;\n mask : none!important;\n contain: none!important;\n perspective: none!important;\n mix-blend-mode: initial!important;\n z-index: auto;\n}\n\n.ace_layer {\n z-index: 1;\n position: absolute;\n overflow: hidden;\n word-wrap: normal;\n white-space: pre;\n height: 100%;\n width: 100%;\n box-sizing: border-box;\n pointer-events: none;\n}\n\n.ace_gutter-layer {\n position: relative;\n width: auto;\n text-align: right;\n pointer-events: auto;\n height: 1000000px;\n contain: style size layout;\n}\n\n.ace_text-layer {\n font: inherit !important;\n position: absolute;\n height: 1000000px;\n width: 1000000px;\n contain: style size layout;\n}\n\n.ace_text-layer > .ace_line, .ace_text-layer > .ace_line_group {\n contain: style size layout;\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n}\n\n.ace_hidpi .ace_text-layer,\n.ace_hidpi .ace_gutter-layer,\n.ace_hidpi .ace_content,\n.ace_hidpi .ace_gutter {\n contain: strict;\n will-change: transform;\n}\n.ace_hidpi .ace_text-layer > .ace_line, \n.ace_hidpi .ace_text-layer > .ace_line_group {\n contain: strict;\n}\n\n.ace_cjk {\n display: inline-block;\n text-align: center;\n}\n\n.ace_cursor-layer {\n z-index: 4;\n}\n\n.ace_cursor {\n z-index: 4;\n position: absolute;\n box-sizing: border-box;\n border-left: 2px solid;\n transform: translatez(0);\n}\n\n.ace_multiselect .ace_cursor {\n border-left-width: 1px;\n}\n\n.ace_slim-cursors .ace_cursor {\n border-left-width: 1px;\n}\n\n.ace_overwrite-cursors .ace_cursor {\n border-left-width: 0;\n border-bottom: 1px solid;\n}\n\n.ace_hidden-cursors .ace_cursor {\n opacity: 0.2;\n}\n\n.ace_smooth-blinking .ace_cursor {\n transition: opacity 0.18s;\n}\n\n.ace_animate-blinking .ace_cursor {\n animation-duration: 1000ms;\n animation-timing-function: step-end;\n animation-name: blink-ace-animate;\n animation-iteration-count: infinite;\n}\n\n.ace_animate-blinking.ace_smooth-blinking .ace_cursor {\n animation-duration: 1000ms;\n animation-timing-function: ease-in-out;\n animation-name: blink-ace-animate-smooth;\n}\n \n@keyframes blink-ace-animate {\n from, to { opacity: 1; }\n 60% { opacity: 0; }\n}\n\n@keyframes blink-ace-animate-smooth {\n from, to { opacity: 1; }\n 45% { opacity: 1; }\n 60% { opacity: 0; }\n 85% { opacity: 0; }\n}\n\n.ace_marker-layer .ace_step, .ace_marker-layer .ace_stack {\n position: absolute;\n z-index: 3;\n}\n\n.ace_marker-layer .ace_selection {\n position: absolute;\n z-index: 5;\n}\n\n.ace_marker-layer .ace_bracket {\n position: absolute;\n z-index: 6;\n}\n\n.ace_marker-layer .ace_active-line {\n position: absolute;\n z-index: 2;\n}\n\n.ace_marker-layer .ace_selected-word {\n position: absolute;\n z-index: 4;\n box-sizing: border-box;\n}\n\n.ace_line .ace_fold {\n box-sizing: border-box;\n\n display: inline-block;\n height: 11px;\n margin-top: -2px;\n vertical-align: middle;\n\n background-image:\n url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII=\"),\n url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACJJREFUeNpi+P//fxgTAwPDBxDxD078RSX+YeEyDFMCIMAAI3INmXiwf2YAAAAASUVORK5CYII=\");\n background-repeat: no-repeat, repeat-x;\n background-position: center center, top left;\n color: transparent;\n\n border: 1px solid black;\n border-radius: 2px;\n\n cursor: pointer;\n pointer-events: auto;\n}\n\n.ace_dark .ace_fold {\n}\n\n.ace_fold:hover{\n background-image:\n url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII=\"),\n url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACBJREFUeNpi+P//fz4TAwPDZxDxD5X4i5fLMEwJgAADAEPVDbjNw87ZAAAAAElFTkSuQmCC\");\n}\n\n.ace_tooltip {\n background-color: #FFF;\n background-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.1));\n border: 1px solid gray;\n border-radius: 1px;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);\n color: black;\n max-width: 100%;\n padding: 3px 4px;\n position: fixed;\n z-index: 999999;\n box-sizing: border-box;\n cursor: default;\n white-space: pre;\n word-wrap: break-word;\n line-height: normal;\n font-style: normal;\n font-weight: normal;\n letter-spacing: normal;\n pointer-events: none;\n}\n\n.ace_folding-enabled > .ace_gutter-cell {\n padding-right: 13px;\n}\n\n.ace_fold-widget {\n box-sizing: border-box;\n\n margin: 0 -12px 0 1px;\n display: none;\n width: 11px;\n vertical-align: top;\n\n background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42mWKsQ0AMAzC8ixLlrzQjzmBiEjp0A6WwBCSPgKAXoLkqSot7nN3yMwR7pZ32NzpKkVoDBUxKAAAAABJRU5ErkJggg==\");\n background-repeat: no-repeat;\n background-position: center;\n\n border-radius: 3px;\n \n border: 1px solid transparent;\n cursor: pointer;\n}\n\n.ace_folding-enabled .ace_fold-widget {\n display: inline-block; \n}\n\n.ace_fold-widget.ace_end {\n background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42m3HwQkAMAhD0YzsRchFKI7sAikeWkrxwScEB0nh5e7KTPWimZki4tYfVbX+MNl4pyZXejUO1QAAAABJRU5ErkJggg==\");\n}\n\n.ace_fold-widget.ace_closed {\n background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAGCAYAAAAG5SQMAAAAOUlEQVR42jXKwQkAMAgDwKwqKD4EwQ26sSOkVWjgIIHAzPiCgaqiqnJHZnKICBERHN194O5b9vbLuAVRL+l0YWnZAAAAAElFTkSuQmCCXA==\");\n}\n\n.ace_fold-widget:hover {\n border: 1px solid rgba(0, 0, 0, 0.3);\n background-color: rgba(255, 255, 255, 0.2);\n box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);\n}\n\n.ace_fold-widget:active {\n border: 1px solid rgba(0, 0, 0, 0.4);\n background-color: rgba(0, 0, 0, 0.05);\n box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);\n}\n.ace_dark .ace_fold-widget {\n background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHklEQVQIW2P4//8/AzoGEQ7oGCaLLAhWiSwB146BAQCSTPYocqT0AAAAAElFTkSuQmCC\");\n}\n.ace_dark .ace_fold-widget.ace_end {\n background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAH0lEQVQIW2P4//8/AxQ7wNjIAjDMgC4AxjCVKBirIAAF0kz2rlhxpAAAAABJRU5ErkJggg==\");\n}\n.ace_dark .ace_fold-widget.ace_closed {\n background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAHElEQVQIW2P4//+/AxAzgDADlOOAznHAKgPWAwARji8UIDTfQQAAAABJRU5ErkJggg==\");\n}\n.ace_dark .ace_fold-widget:hover {\n box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);\n background-color: rgba(255, 255, 255, 0.1);\n}\n.ace_dark .ace_fold-widget:active {\n box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);\n}\n\n.ace_inline_button {\n border: 1px solid lightgray;\n display: inline-block;\n margin: -1px 8px;\n padding: 0 5px;\n pointer-events: auto;\n cursor: pointer;\n}\n.ace_inline_button:hover {\n border-color: gray;\n background: rgba(200,200,200,0.2);\n display: inline-block;\n pointer-events: auto;\n}\n\n.ace_fold-widget.ace_invalid {\n background-color: #FFB4B4;\n border-color: #DE5555;\n}\n\n.ace_fade-fold-widgets .ace_fold-widget {\n transition: opacity 0.4s ease 0.05s;\n opacity: 0;\n}\n\n.ace_fade-fold-widgets:hover .ace_fold-widget {\n transition: opacity 0.05s ease 0.05s;\n opacity:1;\n}\n\n.ace_underline {\n text-decoration: underline;\n}\n\n.ace_bold {\n font-weight: bold;\n}\n\n.ace_nobold .ace_bold {\n font-weight: normal;\n}\n\n.ace_italic {\n font-style: italic;\n}\n\n\n.ace_error-marker {\n background-color: rgba(255, 0, 0,0.2);\n position: absolute;\n z-index: 9;\n}\n\n.ace_highlight-marker {\n background-color: rgba(255, 255, 0,0.2);\n position: absolute;\n z-index: 8;\n}\n.ace_br1 {border-top-left-radius : 3px;}\n.ace_br2 {border-top-right-radius : 3px;}\n.ace_br3 {border-top-left-radius : 3px; border-top-right-radius: 3px;}\n.ace_br4 {border-bottom-right-radius: 3px;}\n.ace_br5 {border-top-left-radius : 3px; border-bottom-right-radius: 3px;}\n.ace_br6 {border-top-right-radius : 3px; border-bottom-right-radius: 3px;}\n.ace_br7 {border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px;}\n.ace_br8 {border-bottom-left-radius : 3px;}\n.ace_br9 {border-top-left-radius : 3px; border-bottom-left-radius: 3px;}\n.ace_br10{border-top-right-radius : 3px; border-bottom-left-radius: 3px;}\n.ace_br11{border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-left-radius: 3px;}\n.ace_br12{border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}\n.ace_br13{border-top-left-radius : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}\n.ace_br14{border-top-right-radius : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}\n.ace_br15{border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}\n\n.ace_text-input-ios {\n position: absolute !important;\n top: -100000px !important;\n left: -100000px !important;\n}\n");
|
|
|
|
define("ace/virtual_renderer",[], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var oop = require("./lib/oop");
|
|
var dom = require("./lib/dom");
|
|
var config = require("./config");
|
|
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 = require("./requirejs/text!./css/editor.css");
|
|
|
|
dom.importCssString(editorCss, "ace_editor.css");
|
|
|
|
var VirtualRenderer = function(container, theme) {
|
|
var _self = this;
|
|
|
|
this.container = container || dom.createElement("div");
|
|
|
|
dom.addCssClass(this.container, "ace_editor");
|
|
if (dom.HI_DPI) dom.addCssClass(this.container, "ace_hidpi");
|
|
|
|
this.setTheme(theme);
|
|
|
|
this.$gutter = dom.createElement("div");
|
|
this.$gutter.className = "ace_gutter";
|
|
this.container.appendChild(this.$gutter);
|
|
this.$gutter.setAttribute("aria-hidden", true);
|
|
|
|
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);
|
|
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.margin = {
|
|
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.scrollBarH.scrollLeft = this.scrollBarV.scrollTop = null;
|
|
|
|
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.session.$bidiHandler.setEolChar(this.$textLayer.EOL_CHAR);
|
|
};
|
|
|
|
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;
|
|
|
|
dom.setStyle(this.scrollBarH.element.style, "left", gutterWidth + "px");
|
|
dom.setStyle(this.scroller.style, "left", gutterWidth + this.margin.left + "px");
|
|
size.scrollerWidth = Math.max(0, width - gutterWidth - this.scrollBarV.getWidth() - this.margin.h);
|
|
dom.setStyle(this.$gutter.style, "left", this.margin.left + "px");
|
|
|
|
var right = this.scrollBarV.getWidth() + "px";
|
|
dom.setStyle(this.scrollBarH.element.style, "right", right);
|
|
dom.setStyle(this.scroller.style, "right", right);
|
|
dom.setStyle(this.scroller.style, "bottom", this.scrollBarH.getHeight());
|
|
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(width) {
|
|
var gutterWidth = this.$showGutter ? width : 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.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.session.$bidiHandler.setShowInvisibles(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.$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 = Math.round(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.scroller;
|
|
};
|
|
this.getTextAreaContainer = function() {
|
|
return this.container;
|
|
};
|
|
this.$moveTextAreaToCursor = function() {
|
|
var style = this.textarea.style;
|
|
if (!this.$keepTextAreaAtCursor) {
|
|
dom.translate(this.textarea, -100, 0);
|
|
return;
|
|
}
|
|
if (!this.$cursorLayer.$pixelPos)
|
|
return;
|
|
var config = this.layerConfig;
|
|
var posTop = this.$cursorLayer.$pixelPos.top;
|
|
var posLeft = this.$cursorLayer.$pixelPos.left;
|
|
posTop -= config.offset;
|
|
|
|
var h = this.lineHeight;
|
|
if (posTop < 0 || posTop > config.height - h) {
|
|
dom.translate(this.textarea, 0, 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 + this.margin.left;
|
|
dom.setStyle(style, "height", h + "px");
|
|
dom.setStyle(style, "width", w + "px");
|
|
dom.translate(this.textarea, Math.min(posLeft, this.$size.scrollerWidth - w), Math.min(posTop, this.$size.height - h));
|
|
};
|
|
this.getFirstVisibleRow = function() {
|
|
return this.layerConfig.firstRow;
|
|
};
|
|
this.getFirstFullyVisibleRow = function() {
|
|
return this.layerConfig.firstRow + (this.layerConfig.offset === 0 ? 0 : 1);
|
|
};
|
|
this.getLastFullyVisibleRow = function() {
|
|
var config = this.layerConfig;
|
|
var lastRow = config.lastRow;
|
|
var top = this.session.documentToScreenRow(lastRow, 0) * config.lineHeight;
|
|
if (top - this.session.getScrollTop() > config.height - config.lineHeight)
|
|
return lastRow - 1;
|
|
return lastRow;
|
|
};
|
|
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.setMargin = function(top, bottom, left, right) {
|
|
var sm = this.margin;
|
|
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;
|
|
this.$updateCachedSize(true, this.gutterWidth, this.$size.width, this.$size.height);
|
|
this.updateFull();
|
|
};
|
|
this.getHScrollBarAlwaysVisible = function() {
|
|
return this.$hScrollBarAlwaysVisible;
|
|
};
|
|
this.setHScrollBarAlwaysVisible = function(alwaysVisible) {
|
|
this.setOption("hScrollBarAlwaysVisible", alwaysVisible);
|
|
};
|
|
this.getVScrollBarAlwaysVisible = function() {
|
|
return this.$vScrollBarAlwaysVisible;
|
|
};
|
|
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");
|
|
|
|
if (this.session && this.session.$bidiHandler)
|
|
this.session.$bidiHandler.updateCharacterWidths(this.$fontMetrics);
|
|
|
|
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();
|
|
dom.translate(this.content, -this.scrollLeft, -config.offset);
|
|
|
|
var width = config.width + 2 * this.$padding + "px";
|
|
var height = config.minHeight + "px";
|
|
|
|
dom.setStyle(this.content.style, "width", width);
|
|
dom.setStyle(this.content.style, "height", height);
|
|
}
|
|
if (changes & this.CHANGE_H_SCROLL) {
|
|
dom.translate(this.content, -this.scrollLeft, -config.offset);
|
|
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._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) {
|
|
if (changes & this.CHANGE_GUTTER || changes & this.CHANGE_LINES)
|
|
this.$gutterLayer.update(config);
|
|
else
|
|
this.$gutterLayer.scrollLines(config);
|
|
}
|
|
this.$markerBack.update(config);
|
|
this.$markerFront.update(config);
|
|
this.$cursorLayer.update(config);
|
|
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);
|
|
}
|
|
else if (changes & this.CHANGE_CURSOR) {
|
|
if (this.$highlightGutterLine)
|
|
this.$gutterLayer.updateLineHighlight(config);
|
|
}
|
|
|
|
if (changes & this.CHANGE_CURSOR) {
|
|
this.$cursorLayer.update(config);
|
|
this.$moveTextAreaToCursor();
|
|
}
|
|
|
|
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.min(maxHeight,
|
|
Math.max((this.$minLines || 1) * this.lineHeight, height)
|
|
) + this.scrollMargin.v + (this.$extraHeight || 0);
|
|
if (this.$horizScroll)
|
|
desiredHeight += this.scrollBarH.getHeight();
|
|
if (this.$maxPixelHeight && desiredHeight > this.$maxPixelHeight)
|
|
desiredHeight = this.$maxPixelHeight;
|
|
|
|
var hideScrollbars = desiredHeight <= 2 * this.lineHeight;
|
|
var vScroll = !hideScrollbars && 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() {
|
|
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 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 vScrollBefore = this.$vScroll; // autosize can change vscroll value in which case we need to update longestLine
|
|
if (this.$maxLines && this.lineHeight > 1)
|
|
this.$autosize();
|
|
|
|
var offset = this.scrollTop % this.lineHeight;
|
|
var minHeight = size.scrollerHeight + this.lineHeight;
|
|
|
|
var scrollPastEnd = !this.$maxLines && this.$scrollPastEnd
|
|
? (size.scrollerHeight - this.lineHeight) * this.$scrollPastEnd
|
|
: 0;
|
|
maxHeight += scrollPastEnd;
|
|
|
|
var sm = this.scrollMargin;
|
|
this.session.setScrollTop(Math.max(-sm.top,
|
|
Math.min(this.scrollTop, maxHeight - size.scrollerHeight + sm.bottom)));
|
|
|
|
this.session.setScrollLeft(Math.max(-sm.left, Math.min(this.scrollLeft,
|
|
longestLine + 2 * this.$padding - size.scrollerWidth + sm.right)));
|
|
|
|
var vScroll = !hideScrollbars && (this.$vScrollBarAlwaysVisible ||
|
|
size.scrollerHeight - maxHeight + scrollPastEnd < 0 || this.scrollTop > sm.top);
|
|
var vScrollChanged = vScrollBefore !== 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 || hScrollChanged)
|
|
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 : lineHeight ? Math.max(0, Math.ceil((offset + size.height - size.scrollerHeight) / lineHeight)) : 0,
|
|
height : this.$size.scrollerHeight
|
|
};
|
|
return changes;
|
|
};
|
|
|
|
this.$updateLines = function() {
|
|
if (!this.$changedLines) return;
|
|
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;
|
|
|
|
if (this.$textLayer && charCount > this.$textLayer.MAX_LINE_LENGTH)
|
|
charCount = this.$textLayer.MAX_LINE_LENGTH + 30;
|
|
|
|
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 && scrollTop + topMargin > top + this.lineHeight)
|
|
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 && scrollTop + this.$size.scrollerHeight - bottomMargin < top - this.lineHeight)
|
|
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;
|
|
if (this.$hasCssTransforms) {
|
|
canvasPos = {top:0, left: 0};
|
|
var p = this.$fontMetrics.transformCoordinates([x, y]);
|
|
x = p[1] - this.gutterWidth - this.margin.left;
|
|
y = p[0];
|
|
} else {
|
|
canvasPos = this.scroller.getBoundingClientRect();
|
|
}
|
|
|
|
var offsetX = x + this.scrollLeft - canvasPos.left - this.$padding;
|
|
var offset = offsetX / this.characterWidth;
|
|
var row = Math.floor((y + this.scrollTop - canvasPos.top) / this.lineHeight);
|
|
var col = this.$blockCursor ? Math.floor(offset) : Math.round(offset);
|
|
|
|
return {row: row, column: col, side: offset - col > 0 ? 1 : -1, offsetX: offsetX};
|
|
};
|
|
|
|
this.screenToTextCoordinates = function(x, y) {
|
|
var canvasPos;
|
|
if (this.$hasCssTransforms) {
|
|
canvasPos = {top:0, left: 0};
|
|
var p = this.$fontMetrics.transformCoordinates([x, y]);
|
|
x = p[1] - this.gutterWidth - this.margin.left;
|
|
y = p[0];
|
|
} else {
|
|
canvasPos = this.scroller.getBoundingClientRect();
|
|
}
|
|
|
|
var offsetX = x + this.scrollLeft - canvasPos.left - this.$padding;
|
|
var offset = offsetX / this.characterWidth;
|
|
var col = this.$blockCursor ? Math.floor(offset) : Math.round(offset);
|
|
|
|
var row = Math.floor((y + this.scrollTop - canvasPos.top) / this.lineHeight);
|
|
|
|
return this.session.screenToDocumentPosition(row, Math.max(col, 0), offsetX);
|
|
};
|
|
this.textToScreenCoordinates = function(row, column) {
|
|
var canvasPos = this.scroller.getBoundingClientRect();
|
|
var pos = this.session.documentToScreenPosition(row, column);
|
|
|
|
var x = this.$padding + (this.session.$bidiHandler.isBidiRow(pos.row, row)
|
|
? this.session.$bidiHandler.getPosLeft(pos.column)
|
|
: 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 || !module.cssClass)
|
|
throw new Error("couldn't load module " + theme + " or it didn't call define");
|
|
if (module.$id)
|
|
_self.$themeId = module.$id;
|
|
dom.importCssString(
|
|
module.cssText,
|
|
module.cssClass,
|
|
_self.container
|
|
);
|
|
|
|
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) {
|
|
dom.setStyle(this.scroller.style, "cursor", style);
|
|
};
|
|
this.setMouseCursor = function(cursorStyle) {
|
|
dom.setStyle(this.scroller.style, "cursor", cursorStyle);
|
|
};
|
|
|
|
this.attachToShadowRoot = function() {
|
|
dom.importCssString(editorCss, "ace_editor.css", this.container);
|
|
};
|
|
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);
|
|
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) {
|
|
this.$gutterLayer.setHighlightGutterLine(shouldHighlight);
|
|
this.$loop.schedule(this.CHANGE_GUTTER);
|
|
},
|
|
initialValue: 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();
|
|
}
|
|
},
|
|
maxPixelHeight: {
|
|
set: function(val) {
|
|
this.updateFull();
|
|
},
|
|
initialValue: 0
|
|
},
|
|
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
|
|
},
|
|
hasCssTransforms: {
|
|
}
|
|
});
|
|
|
|
exports.VirtualRenderer = VirtualRenderer;
|
|
});
|
|
|
|
define("ace/split",[], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var oop = require("./lib/oop");
|
|
var lang = require("./lib/lang");
|
|
var EventEmitter = require("./lib/event_emitter").EventEmitter;
|
|
|
|
var Editor = require("./editor").Editor;
|
|
var Renderer = require("./virtual_renderer").VirtualRenderer;
|
|
var EditSession = require("./edit_session").EditSession;
|
|
|
|
|
|
var Split = function(container, theme, splits) {
|
|
this.BELOW = 1;
|
|
this.BESIDE = 0;
|
|
|
|
this.$container = container;
|
|
this.$theme = theme;
|
|
this.$splits = 0;
|
|
this.$editorCSS = "";
|
|
this.$editors = [];
|
|
this.$orientation = this.BESIDE;
|
|
|
|
this.setSplits(splits || 1);
|
|
this.$cEditor = this.$editors[0];
|
|
|
|
|
|
this.on("focus", function(editor) {
|
|
this.$cEditor = editor;
|
|
}.bind(this));
|
|
};
|
|
|
|
(function(){
|
|
|
|
oop.implement(this, EventEmitter);
|
|
|
|
this.$createEditor = function() {
|
|
var el = document.createElement("div");
|
|
el.className = this.$editorCSS;
|
|
el.style.cssText = "position: absolute; top:0px; bottom:0px";
|
|
this.$container.appendChild(el);
|
|
var editor = new Editor(new Renderer(el, this.$theme));
|
|
|
|
editor.on("focus", function() {
|
|
this._emit("focus", editor);
|
|
}.bind(this));
|
|
|
|
this.$editors.push(editor);
|
|
editor.setFontSize(this.$fontSize);
|
|
return editor;
|
|
};
|
|
|
|
this.setSplits = function(splits) {
|
|
var editor;
|
|
if (splits < 1) {
|
|
throw "The number of splits have to be > 0!";
|
|
}
|
|
|
|
if (splits == this.$splits) {
|
|
return;
|
|
} else if (splits > this.$splits) {
|
|
while (this.$splits < this.$editors.length && this.$splits < splits) {
|
|
editor = this.$editors[this.$splits];
|
|
this.$container.appendChild(editor.container);
|
|
editor.setFontSize(this.$fontSize);
|
|
this.$splits ++;
|
|
}
|
|
while (this.$splits < splits) {
|
|
this.$createEditor();
|
|
this.$splits ++;
|
|
}
|
|
} else {
|
|
while (this.$splits > splits) {
|
|
editor = this.$editors[this.$splits - 1];
|
|
this.$container.removeChild(editor.container);
|
|
this.$splits --;
|
|
}
|
|
}
|
|
this.resize();
|
|
};
|
|
this.getSplits = function() {
|
|
return this.$splits;
|
|
};
|
|
this.getEditor = function(idx) {
|
|
return this.$editors[idx];
|
|
};
|
|
this.getCurrentEditor = function() {
|
|
return this.$cEditor;
|
|
};
|
|
this.focus = function() {
|
|
this.$cEditor.focus();
|
|
};
|
|
this.blur = function() {
|
|
this.$cEditor.blur();
|
|
};
|
|
this.setTheme = function(theme) {
|
|
this.$editors.forEach(function(editor) {
|
|
editor.setTheme(theme);
|
|
});
|
|
};
|
|
this.setKeyboardHandler = function(keybinding) {
|
|
this.$editors.forEach(function(editor) {
|
|
editor.setKeyboardHandler(keybinding);
|
|
});
|
|
};
|
|
this.forEach = function(callback, scope) {
|
|
this.$editors.forEach(callback, scope);
|
|
};
|
|
|
|
|
|
this.$fontSize = "";
|
|
this.setFontSize = function(size) {
|
|
this.$fontSize = size;
|
|
this.forEach(function(editor) {
|
|
editor.setFontSize(size);
|
|
});
|
|
};
|
|
|
|
this.$cloneSession = function(session) {
|
|
var s = new EditSession(session.getDocument(), session.getMode());
|
|
|
|
var undoManager = session.getUndoManager();
|
|
s.setUndoManager(undoManager);
|
|
s.setTabSize(session.getTabSize());
|
|
s.setUseSoftTabs(session.getUseSoftTabs());
|
|
s.setOverwrite(session.getOverwrite());
|
|
s.setBreakpoints(session.getBreakpoints());
|
|
s.setUseWrapMode(session.getUseWrapMode());
|
|
s.setUseWorker(session.getUseWorker());
|
|
s.setWrapLimitRange(session.$wrapLimitRange.min,
|
|
session.$wrapLimitRange.max);
|
|
s.$foldData = session.$cloneFoldData();
|
|
|
|
return s;
|
|
};
|
|
this.setSession = function(session, idx) {
|
|
var editor;
|
|
if (idx == null) {
|
|
editor = this.$cEditor;
|
|
} else {
|
|
editor = this.$editors[idx];
|
|
}
|
|
var isUsed = this.$editors.some(function(editor) {
|
|
return editor.session === session;
|
|
});
|
|
|
|
if (isUsed) {
|
|
session = this.$cloneSession(session);
|
|
}
|
|
editor.setSession(session);
|
|
return session;
|
|
};
|
|
this.getOrientation = function() {
|
|
return this.$orientation;
|
|
};
|
|
this.setOrientation = function(orientation) {
|
|
if (this.$orientation == orientation) {
|
|
return;
|
|
}
|
|
this.$orientation = orientation;
|
|
this.resize();
|
|
};
|
|
this.resize = function() {
|
|
var width = this.$container.clientWidth;
|
|
var height = this.$container.clientHeight;
|
|
var editor;
|
|
|
|
if (this.$orientation == this.BESIDE) {
|
|
var editorWidth = width / this.$splits;
|
|
for (var i = 0; i < this.$splits; i++) {
|
|
editor = this.$editors[i];
|
|
editor.container.style.width = editorWidth + "px";
|
|
editor.container.style.top = "0px";
|
|
editor.container.style.left = i * editorWidth + "px";
|
|
editor.container.style.height = height + "px";
|
|
editor.resize();
|
|
}
|
|
} else {
|
|
var editorHeight = height / this.$splits;
|
|
for (var i = 0; i < this.$splits; i++) {
|
|
editor = this.$editors[i];
|
|
editor.container.style.width = width + "px";
|
|
editor.container.style.top = i * editorHeight + "px";
|
|
editor.container.style.left = "0px";
|
|
editor.container.style.height = editorHeight + "px";
|
|
editor.resize();
|
|
}
|
|
}
|
|
};
|
|
|
|
}).call(Split.prototype);
|
|
|
|
exports.Split = Split;
|
|
});
|
|
|
|
define("ace/ext/split",[], function(require, exports, module) {
|
|
"use strict";
|
|
module.exports = require("../split");
|
|
|
|
});
|