diff --git a/css/editor.css b/css/editor.css
index 3676c327..f38c7316 100644
--- a/css/editor.css
+++ b/css/editor.css
@@ -15,6 +15,19 @@
overflow-y: hidden;
}
+.editor .scrollbar {
+ position: absolute;
+ overflow-x: hidden;
+ overflow-y: scroll;
+ right: 0;
+}
+
+.editor .scrollbar div {
+ position: absolute;
+ width: 1px;
+ left: -10px;
+}
+
.layer {
position: absolute;
overflow: hidden;
diff --git a/demo/editor.html b/demo/editor.html
index 5c3c6cfc..5a63f936 100644
--- a/demo/editor.html
+++ b/demo/editor.html
@@ -56,6 +56,7 @@
+
diff --git a/src/Editor.js b/src/Editor.js
index 4854cfa0..a15e7de6 100644
--- a/src/Editor.js
+++ b/src/Editor.js
@@ -7,11 +7,17 @@ ace.Editor = function(renderer, doc) {
this.textInput = new ace.TextInput(container, this);
new ace.KeyBinding(container, this);
+ var self = this;
+ ace.addListener(container, "mousedown", function(e) {
+ self.focus();
+ return ace.stopEvent(e);
+ });
- ace.addListener(container, "mousedown", ace.bind(this.onMouseDown, this));
- ace.addListener(container, "dblclick", ace.bind(this.onMouseDoubleClick, this));
- ace.addTripleClickListener(container, ace.bind(this.onMouseTripleClick, this));
- ace.addMouseWheelListener(container, ace.bind(this.onMouseWheel, this));
+ var mouseTarget = renderer.getMouseEventTarget();
+ ace.addListener(mouseTarget, "mousedown", ace.bind(this.onMouseDown, this));
+ ace.addListener(mouseTarget, "dblclick", ace.bind(this.onMouseDoubleClick, this));
+ ace.addTripleClickListener(mouseTarget, ace.bind(this.onMouseTripleClick, this));
+ ace.addMouseWheelListener(mouseTarget, ace.bind(this.onMouseWheel, this));
this._selectionMarker = null;
this._highlightLineMarker = null;
@@ -196,8 +202,6 @@ ace.Editor.prototype.onDocumentModeChange = function() {
ace.Editor.prototype.onMouseDown = function(e) {
- this.focus();
-
var pageX = ace.getDocumentX(e);
var pageY = ace.getDocumentY(e);
diff --git a/src/ScrollBar.js b/src/ScrollBar.js
new file mode 100644
index 00000000..4f99abef
--- /dev/null
+++ b/src/ScrollBar.js
@@ -0,0 +1,40 @@
+ace.provide("ace.ScrollBar");
+
+ace.ScrollBar = function(parent) {
+ this.$initEvents();
+
+ this.element = document.createElement("div");
+ this.element.className = "scrollbar";
+
+ this.inner = document.createElement("div");
+ this.element.appendChild(this.inner);
+
+ parent.appendChild(this.element);
+
+ this.width = ace.scrollbarWidth();
+ this.element.style.width = this.width;
+
+ ace.addListener(this.element, "scroll", ace.bind(this.onScroll, this));
+};
+
+ace.mixin(ace.ScrollBar.prototype, ace.MEventEmitter);
+
+ace.ScrollBar.prototype.onScroll = function() {
+ this.$dispatchEvent("scroll", {data: this.element.scrollTop});
+};
+
+ace.ScrollBar.prototype.getWidth = function() {
+ return this.width;
+};
+
+ace.ScrollBar.prototype.setHeight = function(height) {
+ this.element.style.height = (height - this.width) + "px";
+};
+
+ace.ScrollBar.prototype.setInnerHeight = function(height) {
+ this.inner.style.height = height + "px";
+};
+
+ace.ScrollBar.prototype.setScrollTop = function(scrollTop) {
+ this.element.scrollTop = scrollTop;
+};
\ No newline at end of file
diff --git a/src/VirtualRenderer.js b/src/VirtualRenderer.js
index 85b4564d..18ee8451 100644
--- a/src/VirtualRenderer.js
+++ b/src/VirtualRenderer.js
@@ -25,6 +25,9 @@ ace.VirtualRenderer = function(container) {
this.layers = [ this.markerLayer, textLayer, this.cursorLayer ];
+ this.scrollBar = new ace.ScrollBar(container);
+ this.scrollBar.addEventListener("scroll", ace.bind(this.onScroll, this));
+
this.scrollTop = 0;
this.cursorPos = {
@@ -50,6 +53,10 @@ ace.VirtualRenderer.prototype.getContainerElement = function() {
return this.container;
};
+ace.VirtualRenderer.prototype.getMouseEventTarget = function() {
+ return this.scroller;
+};
+
ace.VirtualRenderer.prototype.getFirstVisibleRow = function() {
return this.layerConfig.firstRow || 0;
};
@@ -63,24 +70,36 @@ ace.VirtualRenderer.prototype.onResize = function()
var height = ace.getInnerHeight(this.container);
this.gutter.style.height = height + "px";
this.scroller.style.height = height + "px";
+ this.scrollBar.setHeight(height);
var width = ace.getInnerWidth(this.container);
var gutterWidth = this.gutter.offsetWidth;
this.scroller.style.left = gutterWidth + "px";
- this.scroller.style.width = Math.max(0, width - gutterWidth) + "px";
+ this.scroller.style.width = Math.max(0, width - gutterWidth - this.scrollBar.getWidth()) + "px";
if (this.doc) {
+ this._updateScrollBar();
this.scrollToY(this.getScrollTop());
+ this.draw();
}
};
+ace.VirtualRenderer.prototype.onScroll = function(e) {
+ this.scrollToY(e.data);
+};
+
+ace.VirtualRenderer.prototype._updateScrollBar = function() {
+ this.scrollBar.setInnerHeight(this.doc.getLength() * this.lineHeight);
+ this.scrollBar.setScrollTop(this.scrollTop);
+};
+
ace.VirtualRenderer.prototype.updateLines = function(firstRow, lastRow) {
var layerConfig = this.layerConfig;
if (firstRow > layerConfig.lastRow + 1) { return; }
if (lastRow < layerConfig.firstRow) { return; }
- // if the last row is unknow -> redraw everything
+ // if the last row is unknown -> redraw everything
if (lastRow === undefined) {
this.draw();
return;
@@ -96,9 +115,7 @@ ace.VirtualRenderer.prototype.draw = function() {
var offset = this.scrollTop % this.lineHeight;
var minHeight = this.scroller.clientHeight + offset;
- var longestLine = Math.max(this.scroller.clientWidth, Math.round(this.doc
- .getWidth()
- * this.characterWidth));
+ var longestLine = Math.max(this.scroller.clientWidth, Math.round(this.doc.getWidth() * this.characterWidth));
var lineCount = Math.ceil(minHeight / this.lineHeight);
var firstRow = Math.round((this.scrollTop - offset) / this.lineHeight);
@@ -121,12 +138,13 @@ ace.VirtualRenderer.prototype.draw = function() {
style.width = longestLine + "px";
layer.update(layerConfig);
- }
- ;
+ };
this.gutterLayer.element.style.marginTop = (-offset) + "px";
this.gutterLayer.element.style.height = minHeight + "px";
this.gutterLayer.update(layerConfig);
+
+ this._updateScrollBar();
};
ace.VirtualRenderer.prototype.addMarker = function(range, clazz, type) {
@@ -191,6 +209,7 @@ ace.VirtualRenderer.prototype.scrollToY = function(scrollTop) {
if (this.scrollTop !== scrollTop) {
this.scrollTop = scrollTop;
+ this._updateScrollBar();
this.draw();
}
};
diff --git a/src/ace.js b/src/ace.js
index 080725f4..fb0ce76b 100644
--- a/src/ace.js
+++ b/src/ace.js
@@ -97,20 +97,20 @@ ace.computedStyle = function(element, style) {
}
};
-ace.scrollbarHeight = function() {
+ace.scrollbarWidth = function(parent) {
var el = document.createElement("div");
var style = el.style;
style.position = "absolute";
style.left = "-10000px";
style.overflow = "scroll";
- style.height = "100px";
+ style.width = "100px";
- document.body.appendChild(el);
- var height = el.offsetHeight - el.clientHeight;
+ (parent || document.body).appendChild(el);
+ var width = el.offsetWidth - el.clientWidth;
document.body.removeChild(el);
- return height;
+ return width;
};
ace.stringReverse = function(string) {