diff --git a/spec/editor-component-spec.coffee b/spec/editor-component-spec.coffee index 19e639d1d..b89b782e5 100644 --- a/spec/editor-component-spec.coffee +++ b/spec/editor-component-spec.coffee @@ -5,6 +5,8 @@ describe "EditorComponent", -> [editor, component, node, lineHeight, charWidth] = [] beforeEach -> + spyOn(window, 'requestAnimationFrame').andCallFake (fn) -> fn() + editor = atom.project.openSync('sample.js') container = document.querySelector('#jasmine-content') component = React.renderComponent(EditorComponent({editor}), container) @@ -24,7 +26,6 @@ describe "EditorComponent", -> expect(lines[4].textContent).toBe editor.lineForScreenRow(4).text node.querySelector('.vertical-scrollbar').scrollTop = 2.5 * lineHeight - spyOn(window, 'requestAnimationFrame').andCallFake (fn) -> fn() component.onVerticalScroll() expect(node.querySelector('.scrollable-content').style['-webkit-transform']).toBe "translateY(#{-2.5 * lineHeight}px)" @@ -38,14 +39,36 @@ describe "EditorComponent", -> expect(spacers[0].offsetHeight).toBe 2 * lineHeight expect(spacers[1].offsetHeight).toBe (editor.getScreenLineCount() - 7) * lineHeight - it "renders the currently visible selections", -> - editor.setCursorScreenPosition([0, 5]) + it "renders the currently visible cursors", -> + cursor1 = editor.getCursor() + cursor1.setScreenPosition([0, 5]) node.style.height = 4.5 * lineHeight + 'px' component.updateAllDimensions() cursorNodes = node.querySelectorAll('.cursor') + expect(cursorNodes.length).toBe 1 expect(cursorNodes[0].offsetHeight).toBe lineHeight expect(cursorNodes[0].offsetWidth).toBe charWidth expect(cursorNodes[0].offsetTop).toBe 0 expect(cursorNodes[0].offsetLeft).toBe 5 * charWidth + + cursor3 = editor.addCursorAtScreenPosition([6, 11]) + cursor2 = editor.addCursorAtScreenPosition([4, 10]) + + cursorNodes = node.querySelectorAll('.cursor') + expect(cursorNodes.length).toBe 2 + expect(cursorNodes[0].offsetTop).toBe 0 + expect(cursorNodes[0].offsetLeft).toBe 5 * charWidth + expect(cursorNodes[1].offsetTop).toBe 4 * lineHeight + expect(cursorNodes[1].offsetLeft).toBe 10 * charWidth + + node.querySelector('.vertical-scrollbar').scrollTop = 2.5 * lineHeight + component.onVerticalScroll() + + cursorNodes = node.querySelectorAll('.cursor') + expect(cursorNodes.length).toBe 2 + expect(cursorNodes[0].offsetTop).toBe 6 * lineHeight + expect(cursorNodes[0].offsetLeft).toBe 11 * charWidth + expect(cursorNodes[1].offsetTop).toBe 4 * lineHeight + expect(cursorNodes[1].offsetLeft).toBe 10 * charWidth diff --git a/src/editor-component.coffee b/src/editor-component.coffee index 4b95d84e6..b1b768709 100644 --- a/src/editor-component.coffee +++ b/src/editor-component.coffee @@ -4,6 +4,7 @@ SelectionComponent = require './selection-component' InputComponent = require './input-component' CustomEventMixin = require './custom-event-mixin' +SubscriberMixin = require './subscriber-mixin' DummyLineNode = $$ -> @div className: 'line', style: 'position: absolute; visibility: hidden;', -> @span 'x' @@ -14,7 +15,7 @@ EditorCompont = React.createClass statics: {DummyLineNode} - mixins: [CustomEventMixin] + mixins: [CustomEventMixin, SubscriberMixin] render: -> div className: 'editor', @@ -36,7 +37,7 @@ EditorCompont = React.createClass {lineHeight, charWidth} = @state div className: 'overlayer', - for selection in @props.editor.getSelections() + for selection in @props.editor.getSelections() when @selectionIntersectsVisibleRowRange(selection) SelectionComponent({selection, lineHeight, charWidth}) renderVisibleLines: -> @@ -59,8 +60,12 @@ EditorCompont = React.createClass componentDidMount: -> @listenForCustomEvents() - @props.editor.on 'screen-lines-changed', @onScreenLinesChanged @refs.scrollView.getDOMNode().addEventListener 'mousewheel', @onMousewheel + + {editor} = @props + @subscribe editor, 'screen-lines-changed', @onScreenLinesChanged + @subscribe editor, 'selection-added', @onSelectionAdded + @updateAllDimensions() @props.editor.setVisible(true) @refs.hiddenInput.focus() @@ -95,7 +100,10 @@ EditorCompont = React.createClass onScreenLinesChanged: ({start, end}) -> [visibleStart, visibleEnd] = @getVisibleRowRange() - @forceUpdate() unless end < visibleStart or visibleEnd <= start + @forceUpdate() if @intersectsVisibleRowRange(start, end + 1) # TODO: Use closed-open intervals for change events + + onSelectionAdded: (selection) -> + @forceUpdate() if @selectionIntersectsVisibleRowRange(selection) getVisibleRowRange: -> return [0, 0] unless @state.lineHeight > 0 @@ -105,6 +113,14 @@ EditorCompont = React.createClass endRow = Math.ceil(startRow + heightInLines) [startRow, endRow] + intersectsVisibleRowRange: (startRow, endRow) -> + [visibleStart, visibleEnd] = @getVisibleRowRange() + not (endRow <= visibleStart or visibleEnd <= startRow) + + selectionIntersectsVisibleRowRange: (selection) -> + {start, end} = selection.getScreenRange() + @intersectsVisibleRowRange(start.row, end.row + 1) + getScrollHeight: -> @props.editor.getLineCount() * @state.lineHeight