All files SelectionText.ts

100% Statements 50/50
83.33% Branches 20/24
100% Functions 12/12
100% Lines 49/49

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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            16x 16x 16x 16x 16x     26x 26x 26x 26x 26x 26x       15x 15x 15x 15x 15x     25x 25x           5x 5x 23x 23x 3x 3x     5x       2x 2x 2x 2x 2x     1x 1x 1x 1x 1x       2x         1x     2x 2x 2x 2x 2x 2x 2x 1x   2x       5x               15x 15x      
export class SelectionText {
  elm: HTMLTextAreaElement;
  start: number;
  end: number;
  value: string;
  constructor(elm: HTMLTextAreaElement) {
    const { selectionStart, selectionEnd } = elm;
    this.elm = elm;
    this.start = selectionStart;
    this.end = selectionEnd;
    this.value = this.elm.value;
  }
  position(start?: number, end?: number) {
    const { selectionStart, selectionEnd } = this.elm;
    this.start = typeof start === 'number' && !isNaN(start) ? start : selectionStart;
    this.end = typeof end === 'number' && !isNaN(end) ? end : selectionEnd;
    this.elm.selectionStart = this.start;
    this.elm.selectionEnd = this.end;
    return this;
  }
  insertText(text: string) {
    // Most of the used APIs only work with the field selected
    this.elm.focus();
    this.elm.setRangeText(text);
    this.value = this.elm.value;
    this.position();
    return this;
  }
  getSelectedValue(start?: number, end?: number) {
    const { selectionStart, selectionEnd } = this.elm;
    return this.value.slice(
      typeof start === 'number' && !isNaN(start) ? start : selectionStart,
      typeof end === 'number' && !isNaN(end) ? start : selectionEnd,
    );
  }
  getLineStartNumber() {
    let start = this.start;
    while (start > 0) {
      start--;
      if (this.value.charAt(start) === '\n') {
        start++;
        break;
      }
    }
    return start;
  }
  /** Indent on new lines */
  getIndentText() {
    const start = this.getLineStartNumber();
    const str = this.getSelectedValue(start);
    let indent = '';
    str.replace(/(^(\s)+)/, (str, old) => (indent = old));
    return indent;
  }
  lineStarInstert(text: string) {
    Eif (text) {
      const oldStart = this.start;
      const start = this.getLineStartNumber();
      const str = this.getSelectedValue(start);
      this.position(start, this.end)
        .insertText(
          str
            .split('\n')
            .map((txt) => text + txt)
            .join('\n'),
        )
        .position(oldStart + text.length, this.end);
    }
    return this;
  }
  lineStarRemove(text: string) {
    Eif (text) {
      const oldStart = this.start;
      const start = this.getLineStartNumber();
      const str = this.getSelectedValue(start);
      const reg = new RegExp(`^${text}`, 'g');
      let newStart = oldStart - text.length;
      if (!reg.test(str)) {
        newStart = oldStart;
      }
      this.position(start, this.end)
        .insertText(
          str
            .split('\n')
            .map((txt) => txt.replace(reg, ''))
            .join('\n'),
        )
        .position(newStart, this.end);
    }
  }
  /** Notify any possible listeners of the change */
  notifyChange() {
    const event = new Event('input', { bubbles: true, cancelable: false });
    this.elm.dispatchEvent(event);
  }
}