insertion-text.js 3.05 KB
'use strict';
/*
 Copyright 2012-2015, Yahoo Inc.
 Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
 */
function InsertionText(text, consumeBlanks) {
    this.text = text;
    this.origLength = text.length;
    this.offsets = [];
    this.consumeBlanks = consumeBlanks;
    this.startPos = this.findFirstNonBlank();
    this.endPos = this.findLastNonBlank();
}

const WHITE_RE = /[ \f\n\r\t\v\u00A0\u2028\u2029]/;

InsertionText.prototype = {
    findFirstNonBlank() {
        let pos = -1;
        const text = this.text;
        const len = text.length;
        let i;
        for (i = 0; i < len; i += 1) {
            if (!text.charAt(i).match(WHITE_RE)) {
                pos = i;
                break;
            }
        }
        return pos;
    },
    findLastNonBlank() {
        const text = this.text;
        const len = text.length;
        let pos = text.length + 1;
        let i;
        for (i = len - 1; i >= 0; i -= 1) {
            if (!text.charAt(i).match(WHITE_RE)) {
                pos = i;
                break;
            }
        }
        return pos;
    },
    originalLength() {
        return this.origLength;
    },

    insertAt(col, str, insertBefore, consumeBlanks) {
        consumeBlanks =
            typeof consumeBlanks === 'undefined'
                ? this.consumeBlanks
                : consumeBlanks;
        col = col > this.originalLength() ? this.originalLength() : col;
        col = col < 0 ? 0 : col;

        if (consumeBlanks) {
            if (col <= this.startPos) {
                col = 0;
            }
            if (col > this.endPos) {
                col = this.origLength;
            }
        }

        const len = str.length;
        const offset = this.findOffset(col, len, insertBefore);
        const realPos = col + offset;
        const text = this.text;
        this.text = text.substring(0, realPos) + str + text.substring(realPos);
        return this;
    },

    findOffset(pos, len, insertBefore) {
        const offsets = this.offsets;
        let offsetObj;
        let cumulativeOffset = 0;
        let i;

        for (i = 0; i < offsets.length; i += 1) {
            offsetObj = offsets[i];
            if (
                offsetObj.pos < pos ||
                (offsetObj.pos === pos && !insertBefore)
            ) {
                cumulativeOffset += offsetObj.len;
            }
            if (offsetObj.pos >= pos) {
                break;
            }
        }
        if (offsetObj && offsetObj.pos === pos) {
            offsetObj.len += len;
        } else {
            offsets.splice(i, 0, { pos, len });
        }
        return cumulativeOffset;
    },

    wrap(startPos, startText, endPos, endText, consumeBlanks) {
        this.insertAt(startPos, startText, true, consumeBlanks);
        this.insertAt(endPos, endText, false, consumeBlanks);
        return this;
    },

    wrapLine(startText, endText) {
        this.wrap(0, startText, this.originalLength(), endText);
    },

    toString() {
        return this.text;
    }
};

module.exports = InsertionText;