all files / ui/ AbstractScrollPane.js

0% Statements 0/36
0% Branches 0/12
0% Functions 0/19
0% Lines 0/35
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153                                                                                                                                                                                                                                                                                                                 
import { getSelectionRect, getRelativeMouseBounds, platform } from '../util'
import { DefaultDOMElement } from '../dom'
import { Component } from '../ui'
 
class AbstractScrollPane extends Component {
 
  /*
    Expose scrollPane as a child context
  */
  getChildContext() {
    return {
      scrollPane: this
    }
  }
 
  didMount() {
    if (platform.inBrowser) {
      this.windowEl = DefaultDOMElement.wrapNativeElement(window)
      this.windowEl.on('resize', this.onSelectionPositioned, this)
    }
  }
 
  dispose() {
    if (this.windowEl) {
      this.windowEl.off(this)
    }
  }
 
  getName() {
    return this.props.name
  }
 
  /*
    Determine selection rectangle relative to content element
    and emit a selection:positioned event with positioning hints
  */
  onSelectionPositioned() {
    let contentRect = this._getContentRect()
    let selectionRect = this._getSelectionRect()
    if (!selectionRect) return
    let hints = {
      contentRect,
      selectionRect
    }
    this._emitSelectionPositioned(hints)
    this._scrollSelectionIntoView(selectionRect)
  }
 
  _emitSelectionPositioned(hints) {
    // Allows overlays to do positioning relative to the current
    // selection bounding rectangle.
    this.emit('selection:positioned', hints)
    // TODO: Remove legacy support
    this.emit('dom-selection:rendered', hints)
  }
 
  /*
    Determine mouse bounds relative to content element
    and emit context-menu:opened event with positioning hints
  */
  _onContextMenu(e) {
    e.preventDefault()
    let mouseBounds = this._getMouseBounds(e)
    this.emit('context-menu:opened', {
      mouseBounds: mouseBounds
    })
  }
 
  _scrollSelectionIntoView(selectionRect) {
    let upperBound = this.getScrollPosition()
    let lowerBound = upperBound + this.getHeight()
    let selTop = selectionRect.top
    let selBottom = selectionRect.top + selectionRect.height
    if ((selTop < upperBound && selBottom < upperBound) ||
        (selTop > lowerBound && selBottom > lowerBound)) {
      this.setScrollPosition(selTop)
    }
  }
 
  /**
    Returns the height of scrollPane (inner content overflows)
  */
  getHeight() {
    throw new Error('Abstract method')
  }
 
  /**
    Returns the cumulated height of a panel's content
  */
  getContentHeight() {
    throw new Error('Abstract method')
  }
 
  getContentElement() {
    // TODO: should be wrapped in DefaultDOMElement
    throw new Error('Abstract method')
  }
 
  // /**
  //   Get the `.se-scrollable` element
  // */
  getScrollableElement() {
    throw new Error('Abstract method')
  }
 
  /**
    Get current scroll position (scrollTop) of `.se-scrollable` element
  */
  getScrollPosition() {
    throw new Error('Abstract method')
  }
 
  setScrollPosition() {
    throw new Error('Abstract method')
  }
 
  /**
    Get offset relative to `.se-content`.
 
    @param {DOMNode} el DOM node that lives inside the
  */
  getPanelOffsetForElement(el) { // eslint-disable-line
    throw new Error('Abstract method')
  }
 
  /**
    Scroll to a given sub component.
 
    @param {String} componentId component id, must be present in data-id attribute
  */
  scrollTo(componentId, onlyIfNotVisible) { // eslint-disable-line
    throw new Error('Abstract method')
  }
 
  _getContentRect() {
    return this.getContentElement().getNativeElement().getBoundingClientRect()
  }
 
  /*
    Get selection rectangle relative to panel content element
  */
  _getSelectionRect() {
    return getSelectionRect(this._getContentRect())
  }
 
  _getMouseBounds(e) {
    return getRelativeMouseBounds(e, this.getContentElement().getNativeElement())
  }
 
}
 
export default AbstractScrollPane