From 5c1db2dbcca702a0bee2171f5659a303a1e62c4b Mon Sep 17 00:00:00 2001 From: nightwing Date: Fri, 12 Apr 2013 00:29:24 +0400 Subject: [PATCH] tweak the popup some more --- demo/kitchen-sink/demo.js | 2 +- lib/ace/autocomplete.js | 234 +++++++++++++----------- lib/ace/mouse/default_gutter_handler.js | 2 +- 3 files changed, 134 insertions(+), 104 deletions(-) diff --git a/demo/kitchen-sink/demo.js b/demo/kitchen-sink/demo.js index 0d8eb5da..1db21a9e 100644 --- a/demo/kitchen-sink/demo.js +++ b/demo/kitchen-sink/demo.js @@ -559,7 +559,7 @@ ace.commands.bindKey("Tab", function(editor) { editor.execCommand("indent"); }) -var Autocompleter = require("./autocompleter").Autocompleter; +var Autocompleter = require("ace/autocomplete").Autocomplete; Autocompleter.addTo(env.editor) }); diff --git a/lib/ace/autocomplete.js b/lib/ace/autocomplete.js index 432fd4e9..face3889 100644 --- a/lib/ace/autocomplete.js +++ b/lib/ace/autocomplete.js @@ -3,7 +3,7 @@ * * Copyright (c) 2012, Ajax.org B.V. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright @@ -14,7 +14,7 @@ * * Neither the name of Ajax.org B.V. nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -35,6 +35,7 @@ var EditSession = require("./edit_session").EditSession; var Renderer = require("./virtual_renderer").VirtualRenderer; var Range = require("./range").Range; var event = require("./lib/event"); +var lang = require("./lib/lang"); var dom = require("./lib/dom"); var HashHandler = require("./keyboard/hash_handler").HashHandler; @@ -46,7 +47,7 @@ var worker = new WorkerClient(["ace"], "ace/autocomplete/autocomplete_worker", " var mode = new TextMode(); mode.$tokenizer = { getLineTokens: function(line) { - + } }; @@ -59,7 +60,6 @@ var Autocomplete = function() { this.$mousedownListener = this.mousedownListener.bind(this); }; - (function() { this.$init = function() { this.popup = new AcePopup(); @@ -67,7 +67,7 @@ var Autocomplete = function() { this.insertMatch(); }.bind(this)); }; - + this.openPopup = function(editor) { if (!this.popup) this.$init(); @@ -81,19 +81,8 @@ var Autocomplete = function() { pos.top += rect.top - renderer.layerConfig.offset; pos.left += rect.left; pos.left += renderer.$gutterLayer.gutterWidth; - - var el = this.popup.container; - if (pos.top > window.innerHeight / 2 + lineHeight) { - el.style.top = "" - el.style.bottom = window.innerHeight - pos.top + "px"; - } else { - pos.top += lineHeight; - el.style.top = pos.top + "px"; - el.style.bottom = "" - } - el.style.left = pos.left + "px"; - el.style.display = ""; + this.popup.show(pos, lineHeight); renderer.updateText(); }; @@ -105,23 +94,23 @@ var Autocomplete = function() { this.editor.removeEventListener("mousedown", this.changeListener); if (this.popup) - this.popup.container.style.display = "none"; + this.popup.hide(); - this.editor.Autocomplete.activated = false; + this.editor.completer.activated = false; }; this.changeListener = function(e) { - if (this.editor.Autocomplete.activated) + if (this.editor.completer.activated) Autocomplete.startCommand.exec(this.editor); else this.detach(); }; - + this.blurListener = function() { if (document.activeElement != this.editor.textInput.getElement()) this.detach(); }; - + this.mousedownListener = function(e) { var mouseX = e.clientX, mouseY = e.clientY; var newRow = this.editor.renderer.pixelToScreenCoordinates(mouseX, mouseY).row; @@ -142,7 +131,7 @@ var Autocomplete = function() { case "start": row = 0; break; case "end": row = max; break } - + this.popup.setRow(row); }; @@ -161,16 +150,16 @@ var Autocomplete = function() { }; this.commands = { - "up": function(editor) { editor.Autocomplete.goTo("up"); }, - "down": function(editor) { editor.Autocomplete.goTo("down"); }, - "ctrl-up": function(editor) { editor.Autocomplete.goTo("start"); }, - "ctrl-down": function(editor) { editor.Autocomplete.goTo("end"); }, + "up": function(editor) { editor.completer.goTo("up"); }, + "down": function(editor) { editor.completer.goTo("down"); }, + "ctrl-up": function(editor) { editor.completer.goTo("start"); }, + "ctrl-down": function(editor) { editor.completer.goTo("end"); }, - "esc": function(editor) { editor.Autocomplete.detach(); }, - "space": function(editor) { editor.Autocomplete.detach(); editor.insert(" ");}, - "Return": function(editor) { editor.Autocomplete.insertMatch(); }, - "Shift-Return": function(editor) { editor.Autocomplete.insertMatch(true); }, - "Tab": function(editor) { editor.Autocomplete.insertMatch(); } + "esc": function(editor) { editor.completer.detach(); }, + "space": function(editor) { editor.completer.detach(); editor.insert(" ");}, + "Return": function(editor) { editor.completer.insertMatch(); }, + "Shift-Return": function(editor) { editor.completer.insertMatch(true); }, + "Tab": function(editor) { editor.completer.insertMatch(); } }; this.complete = function(editor) { @@ -179,10 +168,10 @@ var Autocomplete = function() { var _self = this; this.editor = editor; - if (editor.Autocomplete != this) { - if (editor.Autocomplete) - editor.Autocomplete.detach(); - editor.Autocomplete = this; + if (editor.completer != this) { + if (editor.completer) + editor.completer.detach(); + editor.completer = this; } editor.keyBinding.addKeyboardHandler(this.keyboardHandler); @@ -198,23 +187,23 @@ var Autocomplete = function() { if (matches.length) { _self.completions = new FilteredList(matches); _self.completions.setFilter("a"); - _self.openPopup(editor); + _self.openPopup(editor); } else { _self.detach(); } }); }; - + }).call(Autocomplete.prototype); Autocomplete.startCommand = { name: "startAutocomplete", exec: function(editor) { - if (!editor.Autocomplete) - editor.Autocomplete = new Autocomplete(); - editor.Autocomplete.complete(editor); - editor.Autocomplete.activated = true; + if (!editor.completer) + editor.completer = new Autocomplete(); + editor.completer.complete(editor); + editor.completer.activated = true; }, bindKey: "Ctrl-Space|Shift-Space|Alt-Space" } @@ -229,9 +218,9 @@ var FilteredList = function(array, mutateData) { }; (function(){ this.setFilter = function(str) { - + }; - + }).call(FilteredList.prototype); @@ -257,15 +246,15 @@ var $singleLineEditor = function(el) { renderer.$computeLayerConfig = function() { var config = this.layerConfig; var height = this.session.getScreenLength() * this.lineHeight; - if (config.height != height) { - var maxHeight = this.maxLines * this.lineHeight - var vScroll = height > maxHeight; - - if (vScroll != this.$vScroll || this.lineHeight != config.lineHeight) { + var maxHeight = this.maxLines * this.lineHeight + var desiredHeight = Math.max(this.lineHeight, Math.min(maxHeight, height)) + var vScroll = height > maxHeight; + if (desiredHeight != this.desiredHeight || vScroll != this.$vScroll) { + if (vScroll != this.$vScroll) { if (vScroll) { this.scrollBar.element.style.display = ""; this.scrollBar.width = this.scrollBar.orginalWidth; - this.container.style.height = maxHeight + "px"; + height = maxHeight; this.scrollTop = height - this.maxLines * this.lineHeight; } else { @@ -275,41 +264,19 @@ var $singleLineEditor = function(el) { this.$size.height = 0; this.$size.width = 0; - this.onResize(); + this.$vScroll = vScroll; } - if (this.$vScroll) - return renderer.$computeLayerConfigWithScroll(); - - this.container.style.height = height + "px"; - this.scroller.style.height = height + "px"; - this.content.style.height = height + "px"; - this._emit("resize"); + this.container.style.height = desiredHeight + "px"; + this.onResize(); + this.$loop.changes = 0 + this.desiredHeight = desiredHeight; + this.scroller.style.overflowX="hidden" } - - var longestLine = this.$getLongestLine(); - var firstRow = 0; - var lastRow = this.session.getLength(); - - this.scrollTop = 0; - config.width = longestLine; - config.padding = this.$padding; - config.firstRow = 0; - config.firstRowScreen = 0; - config.lastRow = lastRow; - config.lineHeight = this.lineHeight; - config.characterWidth = this.characterWidth; - config.minHeight = height; - config.maxHeight = height; - config.offset = 0; - config.height = height; - - this.$gutterLayer.element.style.marginTop = 0 + "px"; - this.content.style.marginTop = 0 + "px"; - this.content.style.width = longestLine + 2 * this.$padding + "px"; + return renderer.$computeLayerConfigWithScroll(); }; - + var Editor = require("ace/editor").Editor; var editor = new Editor(renderer); @@ -331,12 +298,12 @@ var AcePopup = function(e) { el.style.display = "none"; popup.renderer.content.style.cursor = "default"; popup.renderer.setStyle("ace_autocomplete"); - + var noop = function(){}; - + popup.focus = noop; popup.$isFocused = true; - + popup.renderer.$cursorLayer.restartTimer = noop; popup.renderer.$cursorLayer.element.style.opacity = 0; @@ -362,38 +329,92 @@ var AcePopup = function(e) { popup.setRow = function(line) { popup.setHighlightActiveLine(line != -1); - popup.gotoLine(line + 1); + popup.selection.clearSelection(); + popup.moveCursorTo(line, 0 || 0); }; - - var hoverMarker = new Range(0,0,0,Infinity); + + var hoverMarker = new Range(-1,0,-1,Infinity); hoverMarker.id = popup.session.addMarker(hoverMarker, "ace_line-hover", "fullLine"); popup.on("mousemove", function(e) { + //if (popup.lastOpened) var row = e.getDocumentPosition().row; hoverMarker.start.row = hoverMarker.end.row = row; popup.session._emit("changeBackMarker"); }); - event.addListener(popup.container, "mouseout", function(e) { + var hideHoverMarker = function() { hoverMarker.start.row = hoverMarker.end.row = -1; popup.session._emit("changeBackMarker"); + }; + event.addListener(popup.container, "mouseout", hideHoverMarker); + popup.on("hide", hideHoverMarker); + popup.on("changeSelection", hideHoverMarker); + popup.on("mousewheel", function(e) { + setTimeout(function() { + popup._signal("mousemove", e); + }) }); - + + popup.data = [] popup.setData = function(list) { - var value = "" - if (list) { - if (typeof list[0] == "string") - value = list.join("\n"); - else - value = list.map(function(x){return x.value}).join("\n"); - } - - this.setValue(value, -1); + popup.data = list || []; + popup.setValue(lang.stringRepeat("\n", list.length), -1); }; - + popup.session.doc.getLength = function() { + return popup.data.length; + }; + popup.session.doc.getLine = function(i) { + var data = popup.data[i]; + if (typeof data == "string") + return data; + return (data && data.value) || ""; + }; + + var bgTokenizer = popup.session.bgTokenizer + bgTokenizer.$tokenizeRow = function(i) { + var data = popup.data[i]; + var tokens = []; + if (!data) + return tokens; + if (typeof data == "string") + data = {type: data, value: data}//return [{type: "", value: data}]; + + tokens.push({type: "", value: data.value}); + if (data.type) { + var maxW = popup.renderer.$size.scrollerWidth / popup.renderer.layerConfig.characterWidth; + if (data.type.length + data.value.length < maxW - 2) + tokens.push({type: "rightAlignedText", value: data.type}); + } + return tokens; + }; + bgTokenizer.$updateOnChange = noop + + // highlight popup.setHighlight = function(re) { - ace.session.highlight(re); - ace.session._emit("changeFrontMarker"); + popup.session.highlight(re); + popup.session._emit("changeFrontMarker"); }; - + + popup.hide = function() { + this.container.style.display = "none"; + this._signal("hide"); + } + + popup.show = function(pos, lineHeight) { + var el = this.container; + if (pos.top > window.innerHeight / 2 + lineHeight) { + el.style.top = "" + el.style.bottom = window.innerHeight - pos.top + "px"; + } else { + pos.top += lineHeight; + el.style.top = pos.top + "px"; + el.style.bottom = "" + } + + el.style.left = pos.left + "px"; + el.style.display = ""; + + this._signal("show"); + } return popup; }; @@ -404,8 +425,17 @@ dom.importCssString("\ .ace_autocomplete.ace-tm .ace_line-hover {\ border: 1px solid #abbffe;\ position: absolute;\ - background: rgb(233,233,232);\ + background: rgba(233,233,253,0.4);\ z-index: 2;\ + margin-top: -1px;\ +}\ +.ace_rightAlignedText {\ + color: gray;\ + display: inline-block;\ + position: absolute;\ + right: 4px;\ + text-align: right;\ + z-index: -1;\ }\ .ace_autocomplete {\ width: 200px;\ diff --git a/lib/ace/mouse/default_gutter_handler.js b/lib/ace/mouse/default_gutter_handler.js index fc971da6..55fcf108 100644 --- a/lib/ace/mouse/default_gutter_handler.js +++ b/lib/ace/mouse/default_gutter_handler.js @@ -38,7 +38,7 @@ function GutterHandler(mouseHandler) { var gutter = editor.renderer.$gutterLayer; mouseHandler.editor.setDefaultHandler("guttermousedown", function(e) { - if (!editor.isFocused()) + if (!editor.isFocused() || e.getButton() != 0) return; var gutterRegion = gutter.getRegion(e);