Repository: marktext/marktext
File: src/muya/lib/contentState/updateCtrl.js (JavaScript)

Code before:
    const children = parentCheckbox.parentElement.lastElementChild.children
    for (let i = 0; i < children.length; i++) {
      const checkbox = children[i].firstElementChild
      if (checkbox.checked === false) {
        return false
      }
    }
    return true
  }

  ContentState.prototype.updateParentsCheckBoxState = function (checkbox) {
    let parent = this.getParentCheckBox(checkbox)
    while (parent !== null) {
      const checked = this.cumputeChecboxStatus(parent)
      if (parent.checked !== checked) {
        this.setCheckBoxState(parent, checked)
        parent = this.getParentCheckBox(parent)
      } else {
        break
      }
    }
  }

  ContentState.prototype.updateChildrenCheckBoxState = function (checkbox, checked) {
    const checkboxes = checkbox.parentElement.getElementsByClassName(CLASS_OR_ID.AG_TASK_LIST_ITEM_CHECKBOX)
    for (let i = 1; i < checkboxes.length; i++) {
      const checkbox = checkboxes[i]
      if (checkbox.checked !== checked) {
        this.setCheckBoxState(checkbox, checked)
      }
    }
  }

  // handle task list item checkbox click
  ContentState.prototype.listItemCheckBoxClick = function (checkbox) {
    const { checked } = checkbox
    this.setCheckBoxState(checkbox, checked)

    // A task checked, then related task should be update
    this.updateChildrenCheckBoxState(checkbox, checked)
    this.updateParentsCheckBoxState(checkbox)
  }

  ContentState.prototype.checkSameMarkerOrDelimiter = function (list, markerOrDelimiter) {
    if (!/ol|ul/.test(list.type)) return false
    return list.children[0].bulletMarkerOrDelimiter === markerOrDelimiter
  }

  ContentState.prototype.checkNeedRender = function (cursor = this.cursor) {
    const { labels } = this.stateRender
    const { start: cStart, end: cEnd, anchor, focus } = cursor

Review comment (suggestion):
Prefer store the length of checkboxes in a variable like `len`. so we don't need to retrieve this length every time when run the loop.

Code after:
      if (NO_NEED_TOKEN_REG.test(token.type)) continue
      const { start, end } = token.range
      const textLen = startBlock.text.length
      if (
        conflict([Math.max(0, start - 1), Math.min(textLen, end + 1)], [startOffset, startOffset])
      ) {
        return true
      }
    }
    for (const token of tokenizer(endBlock.text, {
      labels,
      options: this.muya.options
    })) {
      if (NO_NEED_TOKEN_REG.test(token.type)) continue
      const { start, end } = token.range
      const textLen = endBlock.text.length
      if (
        conflict([Math.max(0, start - 1), Math.min(textLen, end + 1)], [endOffset, endOffset])
      ) {
        return true
      }
    }

    return false
  }

  /**
   * block must be span block.
   */
  ContentState.prototype.checkInlineUpdate = function (block) {
    // table cell can not have blocks in it
    if (/figure/.test(block.type)) {
      return false
    }
    if (/cellContent|codeContent|languageInput|footnoteInput/.test(block.functionType)) {
      return false
    }

    let line = null
    const { text } = block
    if (block.type === 'span') {
      line = block
      block = this.getParent(block)
    }
    const listItem = this.getParent(block)
    const [
      match, bullet, tasklist, order, atxHeader,
      setextHeader, blockquote, indentCode, footnote, hr
    ] = text.match(INLINE_UPDATE_REG) || []
    const { footnote: isSupportFootnote } = this.muya.options