From 95b24fb933ecbab3becbf9fbcd122feaaa798a7e Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 9 Apr 2014 18:09:23 -0600 Subject: [PATCH] Position the hidden input on the most recent cursor when in view We won't position the hidden input out of the scroll view's bounds to prevent Chromium's autoscrolling behavior. --- spec/editor-component-spec.coffee | 19 +++++++++++++++++++ src/editor-component.coffee | 23 ++++++++++++++++++++++- src/input-component.coffee | 9 +++++---- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/spec/editor-component-spec.coffee b/spec/editor-component-spec.coffee index 402a14f50..bfb0b9b46 100644 --- a/spec/editor-component-spec.coffee +++ b/spec/editor-component-spec.coffee @@ -238,6 +238,25 @@ describe "EditorComponent", -> expect(cursorNode1.classList.contains('blink-off')).toBe false expect(cursorNode2.classList.contains('blink-off')).toBe false + it "renders the hidden input field at the position of the last cursor if it is on screen", -> + inputNode = node.querySelector('.hidden-input') + node.style.height = 5 * lineHeightInPixels + 'px' + node.style.width = 10 * charWidth + 'px' + component.updateAllDimensions() + + expect(editor.getCursorScreenPosition()).toEqual [0, 0] + editor.setScrollTop(3 * lineHeightInPixels) + editor.setScrollLeft(3 * charWidth) + expect(inputNode.offsetTop).toBe 0 + expect(inputNode.offsetLeft).toBe 0 + + editor.setCursorBufferPosition([5, 5]) + cursorRect = editor.getCursor().getPixelRect() + cursorTop = cursorRect.top + cursorLeft = cursorRect.left + expect(inputNode.offsetTop).toBe cursorTop - editor.getScrollTop() + expect(inputNode.offsetLeft).toBe cursorLeft - editor.getScrollLeft() + describe "selection rendering", -> scrollViewClientLeft = null diff --git a/src/editor-component.coffee b/src/editor-component.coffee index 80632ebe5..c8ffeb796 100644 --- a/src/editor-component.coffee +++ b/src/editor-component.coffee @@ -34,7 +34,13 @@ EditorCompont = React.createClass div className: 'gutter', @renderGutterContent() div className: 'scroll-view', ref: 'scrollView', - InputComponent ref: 'input', className: 'hidden-input', onInput: @onInput, onFocus: @onInputFocused, onBlur: @onInputBlurred + InputComponent + ref: 'input' + className: 'hidden-input' + style: @getHiddenInputPosition() + onInput: @onInput + onFocus: @onInputFocused + onBlur: @onInputBlurred @renderScrollViewContent() div className: 'vertical-scrollbar', ref: 'verticalScrollbar', onScroll: @onVerticalScroll, div className: 'scrollbar-content', style: {height: editor.getScrollHeight()} @@ -69,6 +75,21 @@ EditorCompont = React.createClass div className: 'spacer', key: 'bottom-spacer', style: {height: followingHeight} ] + getHiddenInputPosition: -> + {editor} = @props + + if cursor = editor.getCursor() + cursorRect = cursor.getPixelRect() + top = cursorRect.top - editor.getScrollTop() + top = Math.max(0, Math.min(editor.getHeight(), top)) + left = cursorRect.left - editor.getScrollLeft() + left = Math.max(0, Math.min(editor.getWidth(), left)) + else + top = 0 + left = 0 + + {top, left} + renderScrollViewContent: -> {editor} = @props style = diff --git a/src/input-component.coffee b/src/input-component.coffee index 6ea54490c..c1efaaaa8 100644 --- a/src/input-component.coffee +++ b/src/input-component.coffee @@ -1,14 +1,14 @@ punycode = require 'punycode' -{last} = require 'underscore-plus' +{last, isEqual} = require 'underscore-plus' React = require 'react' {input} = require 'reactionary' module.exports = InputComponent = React.createClass render: -> - {className, onFocus, onBlur} = @props + {className, style, onFocus, onBlur} = @props - input {className, onFocus, onBlur} + input {className, style, onFocus, onBlur} getInitialState: -> {lastChar: ''} @@ -27,7 +27,8 @@ InputComponent = React.createClass isPressAndHoldCharacter: (char) -> @state.lastChar.match /[aeiouAEIOU]/ - shouldComponentUpdate: -> false + shouldComponentUpdate: (newProps) -> + not isEqual(newProps.style, @props.style) onInput: (e) -> valueCharCodes = punycode.ucs2.decode(@getDOMNode().value)