diff --git a/demo/kitchen-sink/token_tooltip.js b/demo/kitchen-sink/token_tooltip.js index f182824a..9e607f69 100644 --- a/demo/kitchen-sink/token_tooltip.js +++ b/demo/kitchen-sink/token_tooltip.js @@ -32,25 +32,26 @@ define(function(require, exports, module) { "use strict"; var dom = require("ace/lib/dom"); +var oop = require("ace/lib/oop"); var event = require("ace/lib/event"); var Range = require("ace/range").Range; +var Tooltip = require("ace/tooltip").Tooltip; -var tooltipNode; - -var TokenTooltip = function(editor) { +function TokenTooltip (editor) { if (editor.tokenTooltip) return; - editor.tokenTooltip = this; + Tooltip.call(this, editor.container); + editor.tokenTooltip = this; this.editor = editor; - - editor.tooltip = tooltipNode || this.$init(); this.update = this.update.bind(this); this.onMouseMove = this.onMouseMove.bind(this); this.onMouseOut = this.onMouseOut.bind(this); event.addListener(editor.renderer.scroller, "mousemove", this.onMouseMove); event.addListener(editor.renderer.content, "mouseout", this.onMouseOut); -}; +} + +oop.inherits(TokenTooltip, Tooltip); (function(){ this.token = {}; @@ -86,15 +87,10 @@ var TokenTooltip = function(editor) { } if (!token) { session.removeMarker(this.marker); - tooltipNode.style.display = "none"; - this.isOpen = false; + this.hide(); return; } - if (!this.isOpen) { - tooltipNode.style.display = ""; - this.isOpen = true; - } - + var tokenText = token.type; if (token.state) tokenText += "|" + token.state; @@ -102,15 +98,15 @@ var TokenTooltip = function(editor) { tokenText += "\n merge"; if (token.stateTransitions) tokenText += "\n " + token.stateTransitions.join("\n "); - + if (this.tokenText != tokenText) { - tooltipNode.textContent = tokenText; - this.tooltipWidth = tooltipNode.offsetWidth; - this.tooltipHeight = tooltipNode.offsetHeight; + this.setText(tokenText); + this.width = this.getWidth(); + this.height = this.getHeight(); this.tokenText = tokenText; } - - this.updateTooltipPosition(this.x, this.y); + + this.show(null, this.x, this.y); this.token = token; session.removeMarker(this.marker); @@ -123,56 +119,34 @@ var TokenTooltip = function(editor) { this.y = e.clientY; if (this.isOpen) { this.lastT = e.timeStamp; - this.updateTooltipPosition(this.x, this.y); + this.setPosition(this.x, this.y); } if (!this.$timer) this.$timer = setTimeout(this.update, 100); }; - + this.onMouseOut = function(e) { - var t = e && e.relatedTarget; - var ct = e && e.currentTarget; - while(t && (t = t.parentNode)) { - if (t == ct) - return; - } - tooltipNode.style.display = "none"; + if (e && e.currentTarget.contains(e.relatedTarget)) + return; + this.hide(); this.editor.session.removeMarker(this.marker); this.$timer = clearTimeout(this.$timer); - this.isOpen = false; - }; - - this.updateTooltipPosition = function(x, y) { - var st = tooltipNode.style; - if (x + 10 + this.tooltipWidth > this.maxWidth) - x = window.innerWidth - this.tooltipWidth - 10; - if (y > window.innerHeight * 0.75 || y + 20 + this.tooltipHeight > this.maxHeight) - y = y - this.tooltipHeight - 30; - - st.left = x + 10 + "px"; - st.top = y + 20 + "px"; }; - this.$init = function() { - tooltipNode = document.documentElement.appendChild(dom.createElement("div")); - var st = tooltipNode.style; - st.position = "fixed"; - st.display = "none"; - st.background = "lightyellow"; - st.borderRadius = ""; - st.border = "1px solid gray"; - st.padding = "1px"; - st.zIndex = 1000; - st.fontFamily = "monospace"; - st.whiteSpace = "pre-line"; - return tooltipNode; + this.setPosition = function(x, y) { + if (x + 10 + this.width > this.maxWidth) + x = window.innerWidth - this.width - 10; + if (y > window.innerHeight * 0.75 || y + 20 + this.height > this.maxHeight) + y = y - this.height - 30; + + Tooltip.prototype.setPosition.call(this, x + 10, y + 20); }; this.destroy = function() { this.onMouseOut(); event.removeListener(this.editor.renderer.scroller, "mousemove", this.onMouseMove); event.removeListener(this.editor.renderer.content, "mouseout", this.onMouseOut); - delete this.editor.tokenTooltip; + delete this.editor.tokenTooltip; }; }).call(TokenTooltip.prototype); @@ -180,4 +154,3 @@ var TokenTooltip = function(editor) { exports.TokenTooltip = TokenTooltip; }); - diff --git a/lib/ace/css/editor.css b/lib/ace/css/editor.css index c27acfd6..b3a137f3 100644 --- a/lib/ace/css/editor.css +++ b/lib/ace/css/editor.css @@ -301,7 +301,7 @@ background-position: center center, top left; } -.ace_gutter-tooltip { +.ace_tooltip { background-color: #FFF; background-image: -webkit-linear-gradient(top, transparent, rgba(0, 0, 0, 0.1)); background-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.1)); @@ -309,21 +309,22 @@ border-radius: 1px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); color: black; - display: inline-block; - max-width: 500px; - padding: 4px; + display: block; + max-width: 100%; + padding: 3px 4px; position: fixed; z-index: 999999; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; cursor: default; - white-space: pre-line; + white-space: pre; word-wrap: break-word; line-height: normal; font-style: normal; font-weight: normal; letter-spacing: normal; + pointer-events: none; } .ace_folding-enabled > .ace_gutter-cell { diff --git a/lib/ace/keyboard/vim_test.js b/lib/ace/keyboard/vim_test.js new file mode 100644 index 00000000..15aeb568 --- /dev/null +++ b/lib/ace/keyboard/vim_test.js @@ -0,0 +1,532 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2014, 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 + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * 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 + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); +} + +define(function(require, exports, module) { +"use strict"; + +function repeat(str, times) { + return new Array(times + 1).join(str); +} + +var EditSession = require("./../edit_session").EditSession, + Editor = require("./../editor").Editor, + UndoManager = require("./../undomanager").UndoManager, + MockRenderer = require("./../test/mockrenderer").MockRenderer, + assert = require("./../test/assertions"), + keys = require("./../lib/keys"), + vim = require("./vim"), + editor, + keyCodeByFuncKey = {}, + tests = {}; + +//Helper functions + +function initKeyCodeByFuncKey() { + for (var keyCode in keys.FUNCTION_KEYS) { + var funcKey = keys.FUNCTION_KEYS[keyCode]; + keyCodeByFuncKey[funcKey] = keyCode; + } +} + +function initEditor(docString) { + var session = new EditSession(docString.split("\n")); + var undoManager = new UndoManager(); + session.setUndoManager(undoManager); + editor = new Editor(new MockRenderer(), session); + editor.setKeyboardHandler(vim.handler); +} + +function sendKeys() { + //Vim handler needs to be sent a key at a time for undo to work + //Handle any mix of command keys and text input arguments + for (var argInt=0; argInt" + title + ""; + } + tests[testName] = testFunction; +} + +//Define the tests + +initKeyCodeByFuncKey(); + +addTest("Insert text", "02", "2", function() { + var text = "A very intelligent turtle\nFound programming UNIX a hurdle"; + initEditor(""); + sendKeys("i", text, "Esc"); + assertContent(text); + sendKeys("Esc", "Esc"); + assertContent(text); +}); + +addTest("Moving around", "02", "3", function() { + initEditor(" k \nh l\n j "); + sendKeys("hjj"); + assertPosition(2, 0); + sendKeys("jll"); + assertPosition(2, 2); + sendKeys("lkk"); + assertPosition(0, 2); + sendKeys("khh"); + assertPosition(0, 0); +}); + +addTest("Deleting characters", "02", "4", function() { + var text = "A very intelligent turtle\nFound programming UNIX a hurdle"; + initEditor(text); + sendKeys("xxxxxxx"); + assertContent(text.substring(7)); + sendKeys("iA young ", "Esc"); + assertContent("A young intelligent turtle\nFound programming UNIX a hurdle"); + sendKeys("dd"); + assertContent("Found programming UNIX a hurdle"); + sendKeys("ddiA young intelligent\nturtle", "Esc", "kJ"); + assertContent("A young intelligent turtle"); +}); + +addTest("Undo and Redo [PARTIAL]", "02", "5", function() { + var text = "A young intelligent turtle"; + initEditor(text); + sendKeys("ddu"); + assertContent(text); + sendKeys("0xxxxxxx"); + assertContent(text.substring(7)); + for (var i=6; i>=0; i--) { + sendKeys("u"); + assertContent(text.substring(i)); + } + sendKeys("ctrl-r", "ctrl-r"); + assertContent(text.substring(2)); + text = "A very intelligent turtle"; + sendKeys("ddi", text, "Esc"); + sendKeys("0wxxxxxwwxxxxxx"); + assertContent("A intelligent "); +/* "U" fails + sendKeys("U"); + assertContent(text); + sendKeys("u"); + assertContent("A intelligent "); +*/ +}); + +addTest("Other editing commands [PARTIAL]", "02", "6", function() { + var text = "and that's not saying much for the turtle."; + initEditor(text); + sendKeys("$xa!!!", "Esc"); + assertContent(text.slice(0, -1) + "!!!"); + var text1 = "A very intelligent turtle"; + var text2 = "Found programming UNIX a hurdle"; + sendKeys("ddi", text1 + "\n" + text2, "Esc"); + var text3 = "That liked using Vim"; + sendKeys("ko", text3, "Esc"); + assertContent([text1, text3, text2].join("\n")); + sendKeys("O", "Esc"); + assertContent([text1, "", text3, text2].join("\n")); +/* "3a!" fails + sendKeys("3a!", "Esc"); +*/ + sendKeys("a!!!", "Esc"); + assertContent([text1, "!!!", text3, text2].join("\n")); + sendKeys("hhh3x"); + assertContent([text1, "", text3, text2].join("\n")); +}); + +addTest("Getting out [PARTIAL]", "02", "7", function() { + initEditor(""); + sendKeys("ZZ"); + /* + sendKeys("aSome text", "Esc"); + sendKeys(":q", "Return"); + sendKeys(":q!", "Return"); + + sendKeys(":e!", "Return"); + */ +}); + +addTest("Finding help [PARTIAL]", "02", "8", function() { + initEditor(""); + sendKeys(":help", "Return"); + sendKeys("F1"); +}); + +addTest("Word movement [PARTIAL]", "03", "1", function() { + var text = "This is a line with example text"; + initEditor(text); + sendKeys("www3w"); + assertPosition(0, 28); + sendKeys("b2b"); + assertPosition(0, 10); + sendKeys("3le"); + assertPosition(0, 18); +/* "ge" fails + sendKeys("2ge"); + assertPosition(0, 8); + TODO: What iskeyword behavior is assumed for Ace? + Need to test "b,w,ge,e,gE, B, W, E" behaviors + sendKeys("ddaThis is-a line, with special/separated/words (and some more).", "Esc"); + sendKeys("$4b"); + assertPosition(0, 21); +*/ +}); + +addTest("Moving to the start or end of a line [PARTIAL]", "03", "2", function() { + var text = " This is a line with example text"; + var textLength = text.length; + initEditor(text); + sendKeys("$"); + assertPosition(0, 36); + sendKeys("0"); + assertPosition(0, 0); +/* "End" and "Home" fails + sendKeys("End"); + assertPosition(0, 36); + sendKeys("Home"); + assertPosition(0, 0); +*/ + sendKeys("^"); + assertPosition(0, 5); + sendKeys("$^"); + assertPosition(0, 5); + sendKeys("ddaA young intelligent turtle\nFound programming UNIX a hurdle", "Esc", "k0"); + assertPosition(0, 0); +/* $ fails + sendKeys("2$"); + assertPosition(1, 30); +*/ +}); + +addTest("Moving to a character [PARTIAL]", "03", "3", function() { + var text = "To err is human. To really foul up you need a computer."; + initEditor(repeat(text, 2)); + sendKeys("fh"); + assertPosition(0, 10); + sendKeys("3fl"); + assertPosition(0, 31); + sendKeys("Fh"); + assertPosition(0, 10); + sendKeys("Fh"); + assertPosition(0, 10); + sendKeys("2tn"); + assertPosition(0, 39); + sendKeys("Th"); + assertPosition(0, 11); + sendKeys("tn"); + assertPosition(0, 13); + sendKeys(";"); + assertPosition(0, 39); +/* Problem with mockrenderer? + sendKeys(";"); + assertPosition(0, 39); +*/ + sendKeys(","); + assertPosition(0, 15); + sendKeys("0f", "Esc", "w"); + assertPosition(0, 3); +}); + +addTest("Matching a parenthesis", "03", "4", function() { + var text = "if (a == (b * c) / d)\nif [a == [b * c] / d]\nif {a == {b * c} / d}"; + initEditor(text); + sendKeys("%"); + assertPosition(0, 20); + sendKeys("%"); + assertPosition(0, 3); + sendKeys("0j%"); + assertPosition(1, 20); + sendKeys("%"); + assertPosition(1, 3); + sendKeys("0j%"); + assertPosition(2, 20); + sendKeys("%"); + assertPosition(2, 3); +}); + +addTest("Moving to a specific line [PARTIAL]", "03", "5", function() { + var text = "first line of a file\n" + repeat("text text text text\n", 8) + "last line of a file"; + initEditor(text); + sendKeys("7G"); + assertPosition(6, 0); + sendKeys("gg"); + assertPosition(0, 0); + sendKeys("G"); + assertPosition(9, 0); +/* % motion fails + sendKeys("50%"); + assertPosition(4, 0); + sendKeys("90%"); + assertPosition(8, 0); +"H, M, L" motion supported, but mockrenderer.js has no 'getScrollBottomRow', etc. + sendKeys("L"); + assertPosition(9, 0); + sendKeys("M"); + assertPosition(4, 0); + sendKeys("H"); + assertPosition(0, 0); +*/ +}); + +addTest("Telling where you are [PARTIAL]", "03", "6", function() { + // Ctrl-G, :set commands not implemented? +}); + +addTest("Scrolling around [PARTIAL]", "03", "7", function() { + /* Ctrl-D, Ctrl-U, Ctrl-E, Ctrl-Y, zz, zt, zb cannot be tested with mockrenderer + var text = repeat("some text\n", 4) + "\n123456\n7890\n" + repeat("\nexample", 4); + initEditor(text); + sendKeys("Ctrl-D"); + */ +}); + +addTest("Simple searches [PARTIAL]", "03", "8", function() { + var text = repeat("To find the word #include\n", 10); + initEditor(text); +/* Search fails, (is a command line really necessary for this to work? + sendKeys("/include", "Return"); + assertPosition(0, 18); + sendKeys("/#include", "Return"); + assertPosition(1, 17); + sendKeys("nnn"); + assertPosition(4, 17); + sendKeys("3n"); + assertPosition(7, 17); + sendKeys("?word", "Return"); + assertPosition(7, 12); + sendKeys("N"); + assertPosition(8, 12); + sendKeys("/#include", "Return"); + assertPosition(8, 17); + sendKeys("N"); + assertPosition(7, 17); + //Skipping ':set ignorecase' and ':set noignorecase' + //Skipping search history + //TODO additional search tests +*" and "#" searches fail, no getPixelPosition in mockrenderer + sendKeys("gg*"); + assertPosition(1, 5); +*/ +}); + +addTest("Simple search patterns [PARTIAL]", "03", "9", function() { +}); + +addTest("Using marks [PARTIAL]", "03", "10", function() { +/* '', ``, Ctrl-O, Ctrl-I fail + var text1 = "example text\n" + var text2 = "line 33 text\n" + var text3 = "There you are\n" + var text = repeat(text1, 32) + text2 + repeat(text1, 2) + text3 + text1; + initEditor(text); + sendKeys("G"); + sendKeys("``"); + assertPosition(0, 0); + sendKeys("``"); + assertPosition(37, 0); + sendKeys("10k``"); + assertPosition(0, 0); + sendKeys("33G"); + assertPosition(33, 0); + sendKeys("/^The"); + assertPosition((36, 0); + sendKeys("Ctrl-O"); + assertPosition(33, 0); + sendKeys("Ctrl-O"); + assertPosition(0, 0); + sendKeys("Ctrl-I"); + assertPosition(33, 0); + sendKeys("Ctrl-I"); + assertPosition(36, 0); + sendKeys(":0$msG$me's"); + assertPosition(0, 0); + sendKeys("`s"); + assertPosition(0, 11); + sendKeys("'e"); + assertPosition(36, 0); + sendKeys("`e"): + assertPosition(36, 11); +*/ +}); + +addTest("Operators and motions [PARTIAL]", "04", "1", function() { + initEditor("To err is human. To really foul up you need a computer."); + sendKeys("5wd4w"); + assertContent("To err is human. you need a computer."); +/* "de" fails + sendKeys("d2e"); + assertContent("To err is human. a computer."); + + sendKeys("2hd$"); + assertContent("To err is human"); +*/ +}); + +addTest("Changing text [PARTIAL]", "04", "2", function() { + initEditor("To err is human"); +/* +// "cw" fails +// sendKeys("wc2wbe", "Esc"); +// assertContent("To be human"); + sendKeys("uccabc def", "Esc"); + assertContent("abc def"); + sendKeys("0c$123", "Esc"); + assertContent("123"); + sendKeys("hx"); + assertContent("13"); + sendKeys("X"); + assertContent("3"); + sendKeys("a 2 1", "Esc", "0wD"); + assertContent("3 "); + sendKeys("a2 1", "Esc", "0wC4 5", "Esc"); + assertContent("3 4 5"); + sendKeys("0ws6", "Esc"); + assertContent("3 6 5"); + sendKeys("S1 3 2", "Esc"); + assertContent("1 3 2"); + sendKeys("$a4 6 5", "Esc", "03d2w"); + assertContent(""); + sendKeys("athere is somerhing grong here", "Esc", "0rTww4lrtwrw"); + assertContent("There is something wrong here"); + sendKeys("03w5rx"); + assertContent("There is something xxxxx here"); +// "r" fails - also replaces trailing space + sendKeys("r", "Return"); + assertContent("There is something xxxx\n here"); + //TODO - 4r +*/ +}); + +addTest("Repeating a change [PARTIAL]", "04", "3", function() { +/* + initEditor("To generate a table of contents"); + sendKeys("ff<.f<."); //strangeness after this + assertContent("To generate a table of contents");; + sendKeys("dd"); + assertContent(""); +sendKeys("Esc", "Esc"); + sendKeys("afind"); + var text = "find the first \"four\"\n" + + "change the word to \"five\"\n" + + "find the next \"four\"\n" + + "repeat the change to \"five\"\n" + + "find the next \"four\"\n" + + "repeat the change\n" + + "etc."; + sendKeys(text); +assertContent(text); + sendKeys("Esc"); + sendKeys("0"); +// search doesn't work with mockrenderer + sendKeys("/four", "", "cwfive", "Esc", "n.n."); + text.replace(/four/g, "five"); + assertContent(text); +*/ +}); + +addTest("Visual mode [PARTIAL]", "04", "4", function() { +}); + +addTest("Moving text [PARTIAL]", "04", "5", function() { +}); + +addTest("Copying text [PARTIAL]", "04", "6", function() { +}); + +addTest("Using the clipboard [PARTIAL]", "04", "7", function() { +}); + +addTest("Text objects [PARTIAL]", "04", "8", function() { +}); + +addTest("Replace mode [PARTIAL]", "04", "9", function() { +}); + +tests.name = "vim_test.js"; + +module.exports = tests; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} diff --git a/lib/ace/mouse/default_gutter_handler.js b/lib/ace/mouse/default_gutter_handler.js index 1ce8aaab..e846d1be 100644 --- a/lib/ace/mouse/default_gutter_handler.js +++ b/lib/ace/mouse/default_gutter_handler.js @@ -31,11 +31,14 @@ define(function(require, exports, module) { "use strict"; var dom = require("../lib/dom"); +var oop = require("../lib/oop"); var event = require("../lib/event"); +var Tooltip = require("../tooltip").Tooltip; function GutterHandler(mouseHandler) { var editor = mouseHandler.editor; var gutter = editor.renderer.$gutterLayer; + var tooltip = new GutterTooltip(editor.container); mouseHandler.editor.setDefaultHandler("guttermousedown", function(e) { if (!editor.isFocused() || e.getButton() != 0) @@ -63,18 +66,9 @@ function GutterHandler(mouseHandler) { }); - var tooltipTimeout, mouseEvent, tooltip, tooltipAnnotation; - function createTooltip() { - tooltip = dom.createElement("div"); - tooltip.className = "ace_gutter-tooltip"; - tooltip.style.display = "none"; - editor.container.appendChild(tooltip); - } + var tooltipTimeout, mouseEvent, tooltipAnnotation; function showTooltip() { - if (!tooltip) { - createTooltip(); - } var row = mouseEvent.getDocumentPosition().row; var annotation = gutter.$annotations[row]; if (!annotation) @@ -92,8 +86,8 @@ function GutterHandler(mouseHandler) { return; tooltipAnnotation = annotation.text.join("
"); - tooltip.style.display = "block"; - tooltip.innerHTML = tooltipAnnotation; + tooltip.setHtml(tooltipAnnotation); + tooltip.show(); editor.on("mousewheel", hideTooltip); if (mouseHandler.$tooltipFollowsMouse) { @@ -112,23 +106,14 @@ function GutterHandler(mouseHandler) { if (tooltipTimeout) tooltipTimeout = clearTimeout(tooltipTimeout); if (tooltipAnnotation) { - tooltip.style.display = "none"; + tooltip.hide(); tooltipAnnotation = null; editor.removeEventListener("mousewheel", hideTooltip); } } function moveTooltip(e) { - var rect = editor.renderer.$gutter.getBoundingClientRect(); - tooltip.style.left = e.x + 15 + "px"; - if (e.y + 3 * editor.renderer.lineHeight + 15 < rect.bottom) { - tooltip.style.bottom = ""; - tooltip.style.top = e.y + 15 + "px"; - } else { - tooltip.style.top = ""; - var innerHeight = window.innerHeight || document.documentElement.clientHeight; - tooltip.style.bottom = innerHeight - e.y + 5 + "px"; - } + tooltip.setPosition(e.x, e.y); } mouseHandler.editor.setDefaultHandler("guttermousemove", function(e) { @@ -165,6 +150,33 @@ function GutterHandler(mouseHandler) { editor.on("changeSession", hideTooltip); } +function GutterTooltip(parentNode) { + Tooltip.call(this, parentNode); +} + +oop.inherits(GutterTooltip, Tooltip); + +(function(){ + this.setPosition = function(x, y) { + var windowWidth = window.innerWidth || document.documentElement.clientWidth; + var windowHeight = window.innerHeight || document.documentElement.clientHeight; + var width = this.getWidth(); + var height = this.getHeight(); + x += 15; + y += 15; + if (x + width > windowWidth) { + x -= (x + width) - windowWidth; + } + if (y + height > windowHeight) { + y -= 20 + height; + } + Tooltip.prototype.setPosition.call(this, x, y); + }; + +}).call(GutterTooltip.prototype); + + + exports.GutterHandler = GutterHandler; }); diff --git a/lib/ace/mouse/default_handlers.js b/lib/ace/mouse/default_handlers.js index 4e28d9d3..7e895f30 100644 --- a/lib/ace/mouse/default_handlers.js +++ b/lib/ace/mouse/default_handlers.js @@ -235,8 +235,15 @@ function DefaultHandlers(mouseHandler) { }; this.onMouseWheel = function(ev) { - if (ev.getShiftKey() || ev.getAccelKey()) + if (ev.getAccelKey()) return; + + //shift wheel to horiz scroll + if (ev.getShiftKey() && ev.wheelY && !ev.wheelX) { + ev.wheelX = ev.wheelY; + ev.wheelY = 0; + } + var t = ev.domEvent.timeStamp; var dt = t - (this.$lastScrollTime||0); diff --git a/lib/ace/test/all_browser.js b/lib/ace/test/all_browser.js index 72e66de5..db56517c 100644 --- a/lib/ace/test/all_browser.js +++ b/lib/ace/test/all_browser.js @@ -24,6 +24,7 @@ var testNames = [ "ace/incremental_search_test", "ace/keyboard/emacs_test", "ace/keyboard/keybinding_test", + "ace/keyboard/vim_test", "ace/layer/text_test", "ace/lib/event_emitter_test", "ace/mode/coffee/parser_test", diff --git a/lib/ace/tooltip.js b/lib/ace/tooltip.js new file mode 100644 index 00000000..1f5502d6 --- /dev/null +++ b/lib/ace/tooltip.js @@ -0,0 +1,138 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, 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 + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * 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 + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("./lib/oop"); +var dom = require("./lib/dom"); + +/** + * @class Tooltip + **/ + +/** + * @param {Element} parentNode + * + * @constructor + **/ +function Tooltip (parentNode) { + this.isOpen = false; + this.$element = null; + this.$parentNode = parentNode; +} + +(function() { + this.$init = function() { + this.$element = dom.createElement("div"); + this.$element.className = "ace_tooltip"; + this.$element.style.display = "none"; + this.$parentNode.appendChild(this.$element); + return this.$element; + }; + + /** + * @returns {Element} + **/ + this.getElement = function() { + return this.$element || this.$init(); + }; + + /** + * @param {String} text + **/ + this.setText = function(text) { + dom.setInnerText(this.getElement(), text); + }; + + /** + * @param {String} html + **/ + this.setHtml = function(html) { + this.getElement().innerHTML = html; + }; + + /** + * @param {Number} x + * @param {Number} y + **/ + this.setPosition = function(x, y) { + this.getElement().style.left = x + "px"; + this.getElement().style.top = y + "px"; + }; + + /** + * @param {String} className + **/ + this.setClassName = function(className) { + dom.addCssClass(this.getElement(), className); + }; + + /** + * @param {String} text + * @param {Number} x + * @param {Number} y + **/ + this.show = function(text, x, y) { + if (text != null) + this.setText(text); + if (x != null && y != null) + this.setPosition(x, y); + if (!this.isOpen) { + this.getElement().style.display = "block"; + this.isOpen = true; + } + }; + + this.hide = function() { + if (this.isOpen) { + this.getElement().style.display = "none"; + this.isOpen = false; + } + }; + + /** + * @returns {Number} + **/ + this.getHeight = function() { + return this.getElement().offsetHeight; + }; + + /** + * @returns {Number} + **/ + this.getWidth = function() { + return this.getElement().offsetWidth; + }; + +}).call(Tooltip.prototype); + +exports.Tooltip = Tooltip; +});