From e0ce741f5b99f51c98f676bbfcdfcd04fa404b30 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 14 Jul 2013 07:44:50 +0400 Subject: [PATCH 1/7] convert multi_select to an option --- lib/ace/multi_select.js | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/lib/ace/multi_select.js b/lib/ace/multi_select.js index 41ca9b89..ea4b3198 100644 --- a/lib/ace/multi_select.js +++ b/lib/ace/multi_select.js @@ -867,13 +867,16 @@ exports.onSessionChange = function(e) { // adds multiple selection support to the editor // (note: should be called only once for each editor instance) function MultiSelect(editor) { + if (editor.$multiselectOnSessionChange) + return; editor.$onAddRange = editor.$onAddRange.bind(editor); editor.$onRemoveRange = editor.$onRemoveRange.bind(editor); editor.$onMultiSelect = editor.$onMultiSelect.bind(editor); editor.$onSingleSelect = editor.$onSingleSelect.bind(editor); + editor.$multiselectOnSessionChange = exports.onSessionChange.bind(editor); - exports.onSessionChange.call(editor, editor); - editor.on("changeSession", exports.onSessionChange.bind(editor)); + editor.$multiselectOnSessionChange(editor); + editor.on("changeSession", editor.$multiselectOnSessionChange); editor.on("mousedown", onMouseDown); editor.commands.addCommands(commands.defaultCommands); @@ -908,4 +911,23 @@ function addAltCursorListeners(editor){ exports.MultiSelect = MultiSelect; + +require("./config").defineOptions(Editor.prototype, "editor", { + enableMultiselect: { + set: function(val) { + MultiSelect(this); + if (val) { + this.on("changeSession", this.$multiselectOnSessionChange); + this.on("mousedown", onMouseDown); + } else { + this.off("changeSession", this.$multiselectOnSessionChange); + this.off("mousedown", onMouseDown); + } + }, + value: true + } +}) + + + }); From 7f8a47939c746d4bb91eed9e020a9924713ace39 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 14 Jul 2013 07:47:17 +0400 Subject: [PATCH 2/7] renderer changes from newclient --- lib/ace/mouse/default_gutter_handler.js | 3 +- lib/ace/scrollbar.js | 21 ++-- lib/ace/virtual_renderer.js | 127 +++++++++++++++--------- 3 files changed, 94 insertions(+), 57 deletions(-) diff --git a/lib/ace/mouse/default_gutter_handler.js b/lib/ace/mouse/default_gutter_handler.js index 55fcf108..bf3da956 100644 --- a/lib/ace/mouse/default_gutter_handler.js +++ b/lib/ace/mouse/default_gutter_handler.js @@ -150,7 +150,8 @@ function GutterHandler(mouseHandler) { hideTooltip(); }, 50); }); - + + editor.on("changeSession", hideTooltip); } exports.GutterHandler = GutterHandler; diff --git a/lib/ace/scrollbar.js b/lib/ace/scrollbar.js index 85b69b6f..79af665a 100644 --- a/lib/ace/scrollbar.js +++ b/lib/ace/scrollbar.js @@ -47,7 +47,7 @@ var EventEmitter = require("./lib/event_emitter").EventEmitter; * * @constructor **/ -var ScrollBarV = function(parent) { +var ScrollBarV = function(parent, renderer) { this.element = dom.createElement("div"); this.element.className = "ace_scrollbar"; @@ -62,16 +62,19 @@ var ScrollBarV = function(parent) { // of 0px // in Firefox 6+ scrollbar is hidden if element has the same width as scrollbar // make element a little bit wider to retain scrollbar when page is zoomed - this.width = dom.scrollbarWidth(parent.ownerDocument); - this.fullWidth = this.width; - this.element.style.width = (this.width || 15) + 5 + "px"; + renderer.once("beforeRender", function() { + renderer.$scrollbarWidth = + this.width = dom.scrollbarWidth(parent.ownerDocument); + this.fullWidth = this.width; + this.element.style.width = (this.width || 15) + 5 + "px"; + }.bind(this)); this.setVisible(false); this.element.style.overflowY = "scroll"; event.addListener(this.element, "scroll", this.onScrollV.bind(this)); }; -var ScrollBarH = function(parent) { +var ScrollBarH = function(parent, renderer) { this.element = dom.createElement("div"); this.element.className = "ace_scrollbar-h"; @@ -86,9 +89,11 @@ var ScrollBarH = function(parent) { // of 0px // in Firefox 6+ scrollbar is hidden if element has the same width as scrollbar // make element a little bit wider to retain scrollbar when page is zoomed - this.height = dom.scrollbarWidth(parent.ownerDocument); - this.fullHeight = this.height; - this.element.style.height = (this.height || 15) + 5 + "px"; + renderer.once("beforeRender", function() { + this.height = renderer.$scrollbarWidth; + this.fullHeight = this.height; + this.element.style.height = (this.height || 15) + 5 + "px"; + }.bind(this)); this.setVisible(false); this.element.style.overflowX = "scroll"; diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index 1f641afc..88f8d79a 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -105,8 +105,8 @@ var VirtualRenderer = function(container, theme) { this.$vScroll = false; this.scrollBar = - this.scrollBarV = new ScrollBarV(this.container); - this.scrollBarH = new ScrollBarH(this.container); + this.scrollBarV = new ScrollBarV(this.container, this); + this.scrollBarH = new ScrollBarH(this.container, this); this.scrollBarV.addEventListener("scroll", function(e) { if (!_self.$scrollAnimation) _self.session.setScrollTop(e.data - _self.scrollMargin.top); @@ -210,7 +210,9 @@ var VirtualRenderer = function(container, theme) { this.setStyle("ace_nobold", !this.$allowBoldFonts); } + this.layerConfig.characterWidth = this.characterWidth = this.$textLayer.getCharacterWidth(); + this.layerConfig.lineHeight = this.lineHeight = this.$textLayer.getLineHeight(); this.$updatePrintMargin(); }; @@ -308,6 +310,8 @@ var VirtualRenderer = function(container, theme) { * **/ this.onResize = function(force, gutterWidth, width, height) { + // if (force) + // console.log("force resize requested", width, height) if (this.resizing > 2) return; else if (this.resizing > 0) @@ -318,9 +322,15 @@ var VirtualRenderer = function(container, theme) { height = this.container.clientHeight; if (!width) width = this.container.clientWidth; - var changes = this.$updateCachedSize(force, gutterWidth, width, height); + + // console.log("resizing to", width, height, JSON.stringify(this.$size)) + // setTimeout(function() { + // console.log("actual size ", this.container.clientWidth, this.container.clientHeight) + + // }.bind(this), 500) + if (!this.$size.scrollerHeight) return; @@ -347,7 +357,8 @@ var VirtualRenderer = function(container, theme) { if (this.$horizScroll) size.scrollerHeight -= this.scrollBarH.getHeight(); - this.scrollBarV.setHeight(size.scrollerHeight); + // this.scrollBarV.setHeight(size.scrollerHeight); + this.scrollBarV.element.style.bottom = this.scrollBarH.getHeight() + "px"; if (this.session) { this.session.setScrollTop(this.getScrollTop()); @@ -355,19 +366,24 @@ var VirtualRenderer = function(container, theme) { } } - if (width && (force || this.resizing > 1 || size.width != width)) { + if (width && (force || size.width != width)) { changes = this.CHANGE_SIZE; size.width = width; - - gutterWidth = this.$showGutter ? this.$gutter.offsetWidth : 0; + + if (gutterWidth == null) + gutterWidth = this.$showGutter ? this.$gutter.offsetWidth : 0; + + this.gutterWidth = gutterWidth; + this.scrollBarH.element.style.left = this.scroller.style.left = gutterWidth + "px"; size.scrollerWidth = Math.max(0, width - gutterWidth - this.scrollBarV.getWidth()); - + + this.scrollBarH.element.style.right = this.scroller.style.right = this.scrollBarV.getWidth() + "px"; this.scroller.style.bottom = this.scrollBarH.getHeight() + "px"; - this.scrollBarH.setWidth(size.scrollerWidth); + // this.scrollBarH.element.style.setWidth(size.scrollerWidth); if (this.session && this.session.getUseWrapMode() && this.adjustWrapLimit() || force) changes = changes | this.CHANGE_FULL; @@ -376,17 +392,13 @@ var VirtualRenderer = function(container, theme) { if (changes) this._signal("resize"); - if (this.$changes) { - changes |= this.$changes; - this.$changes = 0; - } - return changes; }; this.onGutterResize = function() { var gutterWidth = this.$showGutter ? this.$gutter.offsetWidth : 0; - this.$updateCachedSize(true, gutterWidth, this.$size.width, this.$size.height); + if (gutterWidth != this.gutterWidth) + this.$updateCachedSize(true, gutterWidth, this.$size.width, this.$size.height); if (this.session.getUseWrapMode() && this.adjustWrapLimit()) this.$loop.schedule(this.CHANGE_FULL); @@ -714,10 +726,15 @@ var VirtualRenderer = function(container, theme) { }; this.$renderChanges = function(changes, force) { - if (!force && (!changes || !this.session || !this.container.offsetWidth)) { - this.$changes = changes; + if ((!this.session || !this.container.offsetWidth) || (!changes && !force)) { + this.$logChanges(changes); + this.$changes |= changes; return; } + if (this.$changes) { + changes |= this.$changes; + this.$changes = 0; + } // this.$logChanges(changes); @@ -730,7 +747,7 @@ var VirtualRenderer = function(container, theme) { changes & this.CHANGE_SCROLL || changes & this.CHANGE_H_SCROLL ) - this.$computeLayerConfig(); + changes |= this.$computeLayerConfig(); // horizontal scrolling if (changes & this.CHANGE_H_SCROLL) { @@ -841,9 +858,6 @@ var VirtualRenderer = function(container, theme) { if (this.$maxLines && this.lineHeight > 1) this.$autosize(); - if (!this.$size.scrollerHeight) - return this.onResize(true); - var session = this.session; var hideScrollbars = this.$size.height <= 2 * this.lineHeight; @@ -933,12 +947,14 @@ var VirtualRenderer = function(container, theme) { this.content.style.width = longestLine + 2 * this.$padding + "px"; this.content.style.height = minHeight + "px"; + var changes = 0; // Horizontal scrollbar visibility may have changed, which changes // the client height of the scroller if (hScrollChanged || vScrollChanged) { - this.onResize(true); + changes = this.$updateCachedSize(true, this.gutterWidth, this.$size.width, this.$size.height); this._signal("scrollbarVisibilityChanged"); } + return changes; }; this.$updateLines = function() { @@ -1070,8 +1086,10 @@ var VirtualRenderer = function(container, theme) { var left = pos.left; var top = pos.top; + + var scrollTop = this.$scrollAnimation ? this.session.getScrollTop() : this.scrollTop; - if (this.scrollTop > top) { + if (scrollTop > top) { if (offset) top -= offset * this.$size.scrollerHeight; if (top == 0) @@ -1079,7 +1097,7 @@ var VirtualRenderer = function(container, theme) { else if (top == 0) top = + this.scrollMargin.bottom; this.session.setScrollTop(top); - } else if (this.scrollTop + this.$size.scrollerHeight < top + this.lineHeight) { + } else if (scrollTop + this.$size.scrollerHeight < top + this.lineHeight) { if (offset) top += offset * this.$size.scrollerHeight; this.session.setScrollTop(top + this.lineHeight - this.$size.scrollerHeight); @@ -1196,31 +1214,44 @@ var VirtualRenderer = function(container, theme) { this.animateScrolling = function(fromValue, callback) { var toValue = this.scrollTop; - if (this.$animatedScroll) { - var _self = this; - var steps = _self.$calcSteps(fromValue, toValue); - this.$scrollAnimation = {from: fromValue, to: toValue}; - - clearInterval(this.$timer); - - _self.session.setScrollTop(steps.shift()); - this.$timer = setInterval(function() { - if (steps.length) { - _self.session.setScrollTop(steps.shift()); - // trick session to think it's already scrolled to not loose toValue - _self.session.$scrollTop = toValue; - } else if (toValue != null) { - _self.session.$scrollTop = -1; - _self.session.setScrollTop(toValue); - toValue = null; - } else { - // do this on separate step to not get spurious scroll event from scrollbar - _self.$timer = clearInterval(_self.$timer); - _self.$scrollAnimation = null; - callback && callback(); - } - }, 10); + 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()); + this.$timer = setInterval(function() { + if (steps.length) { + _self.session.setScrollTop(steps.shift()); + // trick session to think it's already scrolled to not loose toValue + _self.session.$scrollTop = toValue; + } else if (toValue != null) { + _self.session.$scrollTop = -1; + _self.session.setScrollTop(toValue); + toValue = null; + } else { + // do this on separate step to not get spurious scroll event from scrollbar + _self.$timer = clearInterval(_self.$timer); + _self.$scrollAnimation = null; + callback && callback(); + } + }, 10); }; /** From abf5f7492f192bbb2e49ea9c14cc88a24d9bf860 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 14 Jul 2013 08:22:15 +0400 Subject: [PATCH 3/7] recompute longestLine when vScroll changes --- lib/ace/virtual_renderer.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index 88f8d79a..e8c9c402 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -925,6 +925,16 @@ var VirtualRenderer = function(container, theme) { offset = this.scrollTop - firstRowScreen * lineHeight; + var changes = 0; + // Horizontal scrollbar visibility may have changed, which changes + // the client height of the scroller + if (hScrollChanged || vScrollChanged) { + changes = this.$updateCachedSize(true, this.gutterWidth, this.$size.width, this.$size.height); + this._signal("scrollbarVisibilityChanged"); + if (vScrollChanged) + longestLine = this.$getLongestLine(); + } + this.layerConfig = { width : longestLine, padding : this.$padding, @@ -947,13 +957,6 @@ var VirtualRenderer = function(container, theme) { this.content.style.width = longestLine + 2 * this.$padding + "px"; this.content.style.height = minHeight + "px"; - var changes = 0; - // Horizontal scrollbar visibility may have changed, which changes - // the client height of the scroller - if (hScrollChanged || vScrollChanged) { - changes = this.$updateCachedSize(true, this.gutterWidth, this.$size.width, this.$size.height); - this._signal("scrollbarVisibilityChanged"); - } return changes; }; From 26329c2d763baa1807896c77728ecb580aee43fa Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 14 Jul 2013 08:23:10 +0400 Subject: [PATCH 4/7] scrollbars should start as hidden --- lib/ace/scrollbar.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ace/scrollbar.js b/lib/ace/scrollbar.js index 79af665a..77ee5564 100644 --- a/lib/ace/scrollbar.js +++ b/lib/ace/scrollbar.js @@ -67,8 +67,8 @@ var ScrollBarV = function(parent, renderer) { this.width = dom.scrollbarWidth(parent.ownerDocument); this.fullWidth = this.width; this.element.style.width = (this.width || 15) + 5 + "px"; + this.setVisible(false); }.bind(this)); - this.setVisible(false); this.element.style.overflowY = "scroll"; event.addListener(this.element, "scroll", this.onScrollV.bind(this)); @@ -93,8 +93,8 @@ var ScrollBarH = function(parent, renderer) { this.height = renderer.$scrollbarWidth; this.fullHeight = this.height; this.element.style.height = (this.height || 15) + 5 + "px"; - }.bind(this)); - this.setVisible(false); + this.setVisible(false); + }.bind(this)); this.element.style.overflowX = "scroll"; event.addListener(this.element, "scroll", this.onScrollH.bind(this)); From 650fe73386a66b64e7513a01edc813ab6628602f Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 14 Jul 2013 08:27:26 +0400 Subject: [PATCH 5/7] clicking on scrollbar shouldn't focus the editor --- lib/ace/mouse/mouse_handler.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/ace/mouse/mouse_handler.js b/lib/ace/mouse/mouse_handler.js index 00574d24..76fedc3c 100644 --- a/lib/ace/mouse/mouse_handler.js +++ b/lib/ace/mouse/mouse_handler.js @@ -46,11 +46,6 @@ var MouseHandler = function(editor) { new DefaultGutterHandler(this); new DragdropHandler(this); - event.addListener(editor.container, "mousedown", function(e) { - editor.focus(); - return event.preventDefault(e); - }); - var mouseTarget = editor.renderer.getMouseEventTarget(); event.addListener(mouseTarget, "click", this.onMouseEvent.bind(this, "click")); event.addListener(mouseTarget, "mousemove", this.onMouseMove.bind(this, "mousemove")); @@ -62,6 +57,16 @@ var MouseHandler = function(editor) { event.addListener(gutterEl, "click", this.onMouseEvent.bind(this, "gutterclick")); event.addListener(gutterEl, "dblclick", this.onMouseEvent.bind(this, "gutterdblclick")); event.addListener(gutterEl, "mousemove", this.onMouseEvent.bind(this, "guttermousemove")); + + event.addListener(mouseTarget, "mousedown", function(e) { + editor.focus(); + return event.preventDefault(e); + }); + + event.addListener(gutterEl, "mousedown", function(e) { + editor.focus(); + return event.preventDefault(e); + }); }; (function() { From 4e86a104c2a16c023f9cdeea09ba7cef60c957e0 Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 19 Jul 2013 17:44:19 +0400 Subject: [PATCH 6/7] fix autoresizing editor on ie --- lib/ace/scrollbar.js | 22 +++++++++------------- lib/ace/virtual_renderer.js | 23 +++++++++++++---------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/lib/ace/scrollbar.js b/lib/ace/scrollbar.js index 77ee5564..83e6c467 100644 --- a/lib/ace/scrollbar.js +++ b/lib/ace/scrollbar.js @@ -62,13 +62,11 @@ var ScrollBarV = function(parent, renderer) { // of 0px // in Firefox 6+ scrollbar is hidden if element has the same width as scrollbar // make element a little bit wider to retain scrollbar when page is zoomed - renderer.once("beforeRender", function() { - renderer.$scrollbarWidth = - this.width = dom.scrollbarWidth(parent.ownerDocument); - this.fullWidth = this.width; - this.element.style.width = (this.width || 15) + 5 + "px"; - this.setVisible(false); - }.bind(this)); + renderer.$scrollbarWidth = + this.width = dom.scrollbarWidth(parent.ownerDocument); + this.fullWidth = this.width; + this.element.style.width = (this.width || 15) + 5 + "px"; + this.setVisible(false); this.element.style.overflowY = "scroll"; event.addListener(this.element, "scroll", this.onScrollV.bind(this)); @@ -89,12 +87,10 @@ var ScrollBarH = function(parent, renderer) { // of 0px // in Firefox 6+ scrollbar is hidden if element has the same width as scrollbar // make element a little bit wider to retain scrollbar when page is zoomed - renderer.once("beforeRender", function() { - this.height = renderer.$scrollbarWidth; - this.fullHeight = this.height; - this.element.style.height = (this.height || 15) + 5 + "px"; - this.setVisible(false); - }.bind(this)); + this.height = renderer.$scrollbarWidth; + this.fullHeight = this.height; + this.element.style.height = (this.height || 15) + 5 + "px"; + this.setVisible(false); this.element.style.overflowX = "scroll"; event.addListener(this.element, "scroll", this.onScrollH.bind(this)); diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index e8c9c402..9c1efb3b 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -318,10 +318,14 @@ var VirtualRenderer = function(container, theme) { this.resizing++; else this.resizing = force ? 1 : 0; + // `|| el.scrollHeight` is required for outosizing editors on ie + // where elements with clientHeight = 0 alsoe have clientWidth = 0 + var el = this.container; if (!height) - height = this.container.clientHeight; + height = el.clientHeight || el.scrollHeight; if (!width) - width = this.container.clientWidth; + width = el.clientWidth || el.scrollWidth; + var changes = this.$updateCachedSize(force, gutterWidth, width, height); // console.log("resizing to", width, height, JSON.stringify(this.$size)) @@ -332,18 +336,18 @@ var VirtualRenderer = function(container, theme) { // }.bind(this), 500) if (!this.$size.scrollerHeight) - return; + return this.resizing = 0; + + if (force) + this.$gutterLayer.$padding = null; if (force) this.$renderChanges(changes, true); else this.$loop.schedule(changes); - if (force) - this.$gutterLayer.$padding = null; - - if (force) - delete this.resizing; + if (this.resizing) + this.resizing = 0; }; this.$updateCachedSize = function(force, gutterWidth, width, height) { @@ -398,7 +402,7 @@ var VirtualRenderer = function(container, theme) { this.onGutterResize = function() { var gutterWidth = this.$showGutter ? this.$gutter.offsetWidth : 0; if (gutterWidth != this.gutterWidth) - this.$updateCachedSize(true, gutterWidth, this.$size.width, this.$size.height); + this.$changes != this.$updateCachedSize(true, gutterWidth, this.$size.width, this.$size.height); if (this.session.getUseWrapMode() && this.adjustWrapLimit()) this.$loop.schedule(this.CHANGE_FULL); @@ -727,7 +731,6 @@ var VirtualRenderer = function(container, theme) { this.$renderChanges = function(changes, force) { if ((!this.session || !this.container.offsetWidth) || (!changes && !force)) { - this.$logChanges(changes); this.$changes |= changes; return; } From f447430c105130997cbc249168068a042744bba9 Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 19 Jul 2013 17:59:37 +0400 Subject: [PATCH 7/7] automatically hide activeLine highlight if editor height is one line --- demo/kitchen-sink/layout.js | 1 - lib/ace/editor.js | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/demo/kitchen-sink/layout.js b/demo/kitchen-sink/layout.js index 4729af44..e43915bb 100644 --- a/demo/kitchen-sink/layout.js +++ b/demo/kitchen-sink/layout.js @@ -119,7 +119,6 @@ exports.singleLineEditor = function(el) { new MultiSelect(editor); editor.session.setUndoManager(new UndoManager()); - editor.setHighlightActiveLine(false); editor.setShowPrintMargin(false); editor.renderer.setShowGutter(false); editor.renderer.setHighlightGutterLine(false); diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 69d8f126..6aa2b2cc 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -624,6 +624,8 @@ var Editor = function(renderer, session) { if (this.$highlightActiveLine) { if ((this.$selectionStyle != "line" || !this.selection.isMultiLine())) highlight = this.getCursorPosition(); + if (this.renderer.$maxLines && this.session.getLength() === 1) + highlight = false; } if (session.$highlightLineMarker && !highlight) {