Repository: marktext/marktext
File: src/muya/lib/selection/index.js (JavaScript)

Code before:
    const { y } = this.getCursorCoords()
    const { height, top } = paragraph.getBoundingClientRect()
    const lineHeight = parseFloat(getComputedStyle(paragraph).lineHeight)
    const topOffset = Math.round((y - top) / lineHeight)
    const bottomOffset = Math.round((top + height - lineHeight - y) / lineHeight)

    return {
      topOffset,
      bottomOffset
    }
  }

  getCursorCoords () {
    const sel = this.doc.getSelection()
    let range
    let x = 0
    let y = 0
    let width = 0

    if (sel.rangeCount) {
      range = sel.getRangeAt(0).cloneRange()
      if (range.getClientRects) {
        // range.collapse(true)
        let rects = range.getClientRects()
        if (rects.length === 0) {
          rects = range.startContainer ? range.startContainer.parentElement.getClientRects()
            : []
          // prevent tiny vibrations
          if (rects.length) {
            const rect = rects[0]
            rect.y = rect.y + 1
          }
        }
        if (rects.length) {
          const { left, top, x: rectX, y: rectY, width: rWidth } = rects[0]
          x = rectX || left
          y = rectY || top
          width = rWidth
        }
      }
    }

    return { x, y, width }
  }

  getSelectionEnd () {
    const node = this.doc.getSelection().focusNode
    const endNode = (node && node.nodeType === 3 ? node.parentNode : node)

    return endNode
  }

Review comment (suggestion):
@MrHeer Thanks, the fix working fine and I hope you could add a check for `ELEMENT_NODE` and `TEXT_NODE` like:

```js
          rects = []
          if (range.startContainer && (range.startContainer.nodeType === Node.ELEMENT_NODE || range.startContainer.nodeType === Node.TEXT_NODE)) {
            rects = range.startContainer.parentElement.getClientRects()
          }

          // Prevent tiny vibrations
```

Code after:
    const { y } = this.getCursorCoords()
    const { height, top } = paragraph.getBoundingClientRect()
    const lineHeight = parseFloat(getComputedStyle(paragraph).lineHeight)
    const topOffset = Math.round((y - top) / lineHeight)
    const bottomOffset = Math.round((top + height - lineHeight - y) / lineHeight)

    return {
      topOffset,
      bottomOffset
    }
  }

  getCursorCoords () {
    const sel = this.doc.getSelection()
    let range
    let x = 0
    let y = 0
    let width = 0

    if (sel.rangeCount) {
      range = sel.getRangeAt(0).cloneRange()
      if (range.getClientRects) {
        // range.collapse(true)
        let rects = range.getClientRects()
        if (rects.length === 0 && range.startContainer && (range.startContainer.nodeType === Node.ELEMENT_NODE || range.startContainer.nodeType === Node.TEXT_NODE)) {
          rects = range.startContainer.parentElement.getClientRects()
          // prevent tiny vibrations
          if (rects.length) {
            const rect = rects[0]
            rect.y = rect.y + 1
          }
        }
        if (rects.length) {
          const { left, top, x: rectX, y: rectY, width: rWidth } = rects[0]
          x = rectX || left
          y = rectY || top
          width = rWidth
        }
      }
    }

    return { x, y, width }
  }

  getSelectionEnd () {
    const node = this.doc.getSelection().focusNode
    const endNode = (node && node.nodeType === 3 ? node.parentNode : node)

    return endNode
  }
}