<commit_before>import rangy from 'rangy'
import error from './util/error'
import * as nodeType from './node-type'

/**
 * Inspired by the Selection save and restore module for Rangy by <NAME>
 * Saves and restores ranges using invisible marker elements in the DOM.
 */
let boundaryMarkerId = 0

// (U+FEFF) zero width no-break space
const markerTextChar = '\ufeff'

function isChildOf (parent, possibleChild) {
  for (let i = 0; i < parent.children.length; i++) {
    if (parent.children[i] === possibleChild) return true
  }
  return false
}

function isChildAtBeginning (parent, possibleChild) {
  const isChild = isChildOf(parent, possibleChild)
  return isChild && parent.childNodes[0] === possibleChild
}

function isChildAtEnd (parent, possibleChild) {
  const isChild = isChildOf(parent, possibleChild)
  return isChild && parent.childNodes[parent.children.length - 1] === possibleChild
}

export function insertRangeBoundaryMarker (range, atStart) {
  const container = range.commonAncestorContainer
  let trailsStart = false
  let trailsEnd = false
  if (isChildAtEnd(range.startContainer.parentElement, range.endContainer.parentElement)) {
    trailsEnd = true
  } else if (isChildAtBeginning(range.endContainer.parentElement, range.startContainer.parentElement)) {
    trailsStart = true
  }
  // If ownerDocument is null the commonAncestorContainer is window.document
  if (container.ownerDocument === null || container.ownerDocument === undefined) {
    error('Cannot save range: range is emtpy')
  }

  // Create the marker element containing a single
  // invisible character using DOM methods and insert it
  const doc = container.ownerDocument.defaultView.document
  const markerEl = doc.createElement('span')
  markerEl.id = `editable-range-boundary-${++boundaryMarkerId}`
  markerEl.setAttribute('data-editable', 'remove')
  markerEl.style.lineHeight = '0'
  markerEl.style.display = 'none'
  markerEl.appendChild(doc.createTextNode(markerTextChar))

  // if another tag is trailing exactly at the start or end, prepend
  // or append the marker element directly on the parent.
  if (trailsStart && atStart) {
    range.endContainer.parentElement.prepend(markerEl)
  } else if (trailsEnd && !atStart) {
    range.startContainer.parentElement.append(markerEl)
  } else {
    // Clone the Range and collapse to the appropriate boundary point
    const boundaryRange = range.cloneRange()
    boundaryRange.collapse(atStart)
    boundaryRange.insertNode(markerEl)
  }

  return markerEl
}

export function setRangeBoundary (host, range, markerId, atStart) {
  const markerEl = getMarker(host, markerId)
  if (!markerEl) return console.log('Marker element has been removed. Cannot restore selection.')<commit_msg>fix(markers): handle marker before format tags<commit_after>import rangy from 'rangy'
import error from './util/error'
import * as nodeType from './node-type'

/**
 * Inspired by the Selection save and restore module for Rangy by <NAME>
 * Saves and restores ranges using invisible marker elements in the DOM.
 */
let boundaryMarkerId = 0

// (U+FEFF) zero width no-break space
const markerTextChar = '\ufeff'

function isChildOf (parent, possibleChild) {
  for (let i = 0; i < parent.children.length; i++) {
    if (parent.children[i] === possibleChild) return true
  }
  return false
}

function isChildAtBeginning (parent, possibleChild) {
  return isChildOf(parent, possibleChild)
}

function isChildAtEnd (parent, possibleChild) {
  return isChildOf(parent, possibleChild)
}

export function insertRangeBoundaryMarker (range, atStart) {
  const container = range.commonAncestorContainer
  let trailsStart = false
  let trailsEnd = false
  if (isChildAtEnd(range.startContainer.parentElement, range.endContainer.parentElement)) {
    trailsEnd = true
  } else if (isChildAtBeginning(range.endContainer.parentElement, range.startContainer.parentElement)) {
    trailsStart = true
  }
  // If ownerDocument is null the commonAncestorContainer is window.document
  if (container.ownerDocument === null || container.ownerDocument === undefined) {
    error('Cannot save range: range is emtpy')
  }

  // Create the marker element containing a single
  // invisible character using DOM methods and insert it
  const doc = container.ownerDocument.defaultView.document
  const markerEl = doc.createElement('span')
  markerEl.id = `editable-range-boundary-${++boundaryMarkerId}`
  markerEl.setAttribute('data-editable', 'remove')
  markerEl.style.lineHeight = '0'
  markerEl.style.display = 'none'
  markerEl.appendChild(doc.createTextNode(markerTextChar))

  // if another tag is trailing exactly at the start or end, prepend
  // or append the marker element directly on the parent.
  if (trailsStart && atStart) {
    range.endContainer.parentElement.insertBefore(markerEl, range.startContainer.parentElement)
  } else if (trailsEnd && !atStart) {
    // emulating insertAfter with nextSibling
    range.startContainer.parentElement.insertBefore(markerEl, range.endContainer.parentElement.nextSibling)
  } else {
    // Clone the Range and collapse to the appropriate boundary point
    const boundaryRange = range.cloneRange()
    boundaryRange.collapse(atStart)
    boundaryRange.insertNode(markerEl)
  }

  return markerEl
}

export function setRangeBoundary (host, range, markerId, atStart) {
  const markerEl = getMarker(host, markerId)
  if (!markerEl) return console.log('Marker element has been removed. Cannot restore selection.')
{'fraction_non_alphanumeric': 0.09643183897529735, 'fraction_numerical': 0.001463860933211345, 'mean_word_length': 4.571865443425076, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3188513', 'n_tokens_mistral': 1549, 'n_tokens_neox': 1542, 'n_words': 469}