From f652b4e35738480247be4a12ba2d1ee7416e54bc Mon Sep 17 00:00:00 2001 From: Corey Johnson & Nathan Sobo Date: Fri, 20 Apr 2012 17:18:07 -0600 Subject: [PATCH] Position autocomplete menu above cursor if there isn't room below --- benchmark/benchmark-bootstrap.coffee | 2 +- spec/app/autocomplete-spec.coffee | 32 ++++++++++++++++++++-------- spec/app/editor-spec.coffee | 8 +++---- spec/spec-helper.coffee | 2 +- src/app/autocomplete.coffee | 15 ++++++++++--- static/autocomplete.css | 3 +-- 6 files changed, 42 insertions(+), 20 deletions(-) diff --git a/benchmark/benchmark-bootstrap.coffee b/benchmark/benchmark-bootstrap.coffee index ca8cb3929..591aa1adf 100644 --- a/benchmark/benchmark-bootstrap.coffee +++ b/benchmark/benchmark-bootstrap.coffee @@ -1,4 +1,4 @@ {runSpecSuite} = require 'jasmine-helper' document.title = "Benchmark Suite" -runSpecSuite("benchmark-suite", false) \ No newline at end of file +runSpecSuite("benchmark-suite", false) diff --git a/spec/app/autocomplete-spec.coffee b/spec/app/autocomplete-spec.coffee index 15968cef5..8b4001ebc 100644 --- a/spec/app/autocomplete-spec.coffee +++ b/spec/app/autocomplete-spec.coffee @@ -15,9 +15,6 @@ describe "Autocomplete", -> autocomplete = new Autocomplete(editor) miniEditor = autocomplete.miniEditor - afterEach -> - autocomplete.remove() - describe "@activate(rootView)", -> it "activates autocomplete on all existing and future editors (but not on autocomplete's own mini editor)", -> rootView = new RootView(pathToOpen: require.resolve('fixtures/sample.js')) @@ -370,14 +367,31 @@ describe "Autocomplete", -> describe ".attach()", -> beforeEach -> - editor.setCursorBufferPosition [1, 1] editor.attachToDom() - autocomplete.attach() + setEditorHeightInLines(editor, 8) + editor.setCursorBufferPosition [1, 1] - it "adds the autocomplete view to the editor", -> - expect(editor.find('.autocomplete')).toExist() - expect(autocomplete.position().top).toBeGreaterThan 0 - expect(autocomplete.position().left).toBeGreaterThan 0 + describe "when the autocomplete view fits below the cursor", -> + it "adds the autocomplete view to the editor below the cursor", -> + cursorPixelPosition = editor.pixelPositionForScreenPosition(editor.getCursorScreenPosition()) + autocomplete.attach() + expect(editor.find('.autocomplete')).toExist() + + expect(autocomplete.position().top).toBe cursorPixelPosition.top + editor.lineHeight + expect(autocomplete.position().left).toBe cursorPixelPosition.left + + describe "when the autocomplete view does not fit below the cursor", -> + it "adds the autocomplete view to the editor above the cursor", -> + editor.setCursorScreenPosition([6, 0]) + editor.insertText('t ') + editor.setCursorScreenPosition([6, 0]) + cursorPixelPosition = editor.pixelPositionForScreenPosition(editor.getCursorScreenPosition()) + autocomplete.attach() + + expect(autocomplete.parent()).toExist() + autocompleteBottom = autocomplete.position().top + autocomplete.outerHeight() + expect(autocompleteBottom).toBe cursorPixelPosition.top + expect(autocomplete.position().left).toBe cursorPixelPosition.left describe ".detach()", -> it "clears the mini-editor and unbinds autocomplete event handlers for move-up and move-down", -> diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index d00eb58ec..bfef64e30 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -620,7 +620,7 @@ describe "Editor", -> expect(editor.scroller.scrollTop()).toBe(0) it "reduces scroll margins when there isn't enough height to maintain them and scroll smoothly", -> - setEditorHeightInChars(editor, 5) + setEditorHeightInLines(editor, 5) _.times 3, -> editor.moveCursorDown() @@ -719,7 +719,7 @@ describe "Editor", -> it "only attempts to scroll when a cursor is visible", -> setEditorWidthInChars(editor, 20) - setEditorHeightInChars(editor, 10) + setEditorHeightInLines(editor, 10) editor.setCursorBufferPosition([11,0]) editor.addCursorAtBufferPosition([6,50]) editor.addCursorAtBufferPosition([0,0]) @@ -734,7 +734,7 @@ describe "Editor", -> it "only attempts to scroll once when multiple cursors are visible", -> setEditorWidthInChars(editor, 20) - setEditorHeightInChars(editor, 10) + setEditorHeightInLines(editor, 10) editor.setCursorBufferPosition([11,0]) editor.addCursorAtBufferPosition([0,0]) editor.addCursorAtBufferPosition([6,0]) @@ -1068,7 +1068,7 @@ describe "Editor", -> describe "multiple cursors", -> it "places multiple cursor with meta-click", -> editor.attachToDom() - setEditorHeightInChars(editor, 5) + setEditorHeightInLines(editor, 5) editor.lines.trigger mousedownEvent(editor: editor, point: [3, 0]) editor.scroller.scrollTop(editor.lineHeight * 6) diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index 1e126047d..5ed7221a7 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -110,7 +110,7 @@ window.tokensText = (tokens) -> window.setEditorWidthInChars = (editor, widthInChars, charWidth=editor.charWidth) -> editor.width(charWidth * widthInChars + editor.lines.position().left) -window.setEditorHeightInChars = (editor, heightInChars, charHeight=editor.lineHeight) -> +window.setEditorHeightInLines = (editor, heightInChars, charHeight=editor.lineHeight) -> editor.height(charHeight * heightInChars + editor.lines.position().top) $.fn.resultOfTrigger = (type) -> diff --git a/src/app/autocomplete.coffee b/src/app/autocomplete.coffee index 96b836b2d..cd24cf9f9 100644 --- a/src/app/autocomplete.coffee +++ b/src/app/autocomplete.coffee @@ -100,12 +100,12 @@ class Autocomplete extends View @originalSelectionBufferRange = @editor.getSelection().getBufferRange() @allMatches = @findMatchesForCurrentSelection() - cursorScreenPosition = @editor.getCursorScreenPosition() - {left, top} = @editor.pixelPositionForScreenPosition(cursorScreenPosition) - @css {left: left, top: top + @editor.lineHeight} + originalCursorPosition = @editor.getCursorScreenPosition() @filterMatches() @editor.lines.append(this) + @setPosition(originalCursorPosition) + @miniEditor.focus() detach: -> @@ -114,6 +114,15 @@ class Autocomplete extends View super @miniEditor.buffer.setText('') + setPosition: (originalCursorPosition) -> + { left, top } = @editor.pixelPositionForScreenPosition(originalCursorPosition) + potentialTop = top + @editor.lineHeight + potentialBottom = potentialTop + @outerHeight() + if potentialBottom > @editor.scroller.scrollBottom() + @css(left: left, bottom: @editor.lines.height() - top, top: 'inherit') + else + @css(left: left, top: potentialTop, bottom: 'inherit') + selectPreviousMatch: -> previousIndex = @currentMatchIndex - 1 previousIndex = @filteredMatches.length - 1 if previousIndex < 0 diff --git a/static/autocomplete.css b/static/autocomplete.css index 462945a37..6d247eaf0 100644 --- a/static/autocomplete.css +++ b/static/autocomplete.css @@ -5,8 +5,7 @@ background-color: #444; border: 2px solid #222; color: #eee; - -webkit-box-shadow: 0 0 5px 5px #222; - margin: 5px; + -webkit-box-shadow: 0 0 3px 3px rgba(0, 0, 0, .5); } .autocomplete ol {