Home Reference Source

js/template/MarkdownControlsTemplate.js

import Template, { TemplateType } from '~/template/Template';
import LanguageTemplate from '~/template/LanguageTemplate';
import KeyManager from '~/models/KeyManager';

/**
 * Template for a markdown control list. Default with no actions.
 */
export default class MarkdownControlsTemplate extends Template {
    /**
     * Creates a markdown control list.
     *
     * @param {HTMLTextArea} source - where md is being edited.
     * @param {MarkdownControl[]} [controls=[]] - List of control templates.
     */
    constructor(source, controls = []) {
        let controlList = <ul></ul>;
        let root = <div class="markdown-controller">{controlList}</div>;

        super(root);

        this._root = root;
        this._list = controlList;
        this._source = source;

        this._keyTriggers = new Map();

        /** @private */
        this.keyManager = new KeyManager(this._source);

        this.addControls(controls);
    }

    /**
     * Adds controls
     * @param {MarkdownControl[]} controls
     */
    addControls(controls) {
        for (let i = 0; i < controls.length; i++) {
            this.addControl(controls[i]);
        }
    }

    /**
     * Adds a control
     */
    addControl(control) {
        if (control._keyName !== null) {
            this.keyManager.registerMeta(control._keyName, () => control.trigger());
        }

        control.setControllingTemplate(this);
        this._list.appendChild(<li>{control.unique()}</li>);
    }

    /**
     * Inserts at a the beginning of where the user is.
     * @param {string} string
     */
    insertAtSelectionStart(string) {
        let { selectionStart: start, selectionEnd: end, value } = this._source;
        let newString = value.substring(0, start) + string + value.substring(start);
        this._source.value = newString;
        this._source.setSelectionRange(start + string.length, end + string.length);
    }

    /**
     * Inserts at a the end of where the user is.
     * @param {string} string
     */
    insertAtSelectionEnd(string) {
        let { selectionStart: start, selectionEnd: end, value } = this._source;
        let newString = value.substring(0, end) + string + value.substring(end);
        this._source.value = newString;
        this._source.setSelectionRange(start, end);
    }

    /**
     * Replaces selection with a string
     * @param {string} string
     */
    insertForSelection(string) {
        let { selectionStart: start, selectionEnd: end, value } = this._source;
        let newString = value.substring(0, start) + string + value.substring(end);
        this._source.value = newString;
        this._source.setSelectionRange(start + string.length);
    }

    /**
     * Checks if a string leads the selection
     * @param {string} string
     * @return {boolean}
     */
    isLeading(string) {
        let { selectionStart: start, value } = this._source;
        return value.substring(start - string.length, start) === string;
    }

    /**
     * Checks if a string trails the selection
     * @param {string} string
     * @return {boolean}
     */
    isTrailing(string) {
        let { selectionEnd: end, value } = this._source;
        return value.substring(end, end + string.length) === string;
    }

    /**
     * Cuts from beginning of selection
     * @param {number} count positive, non-zero integer of a size to cut
     */
    cutStart(count) {
        let { selectionStart: start, selectionEnd: end, value } = this._source;
        this._source.value = value.substring(0, start - count) + value.substring(start);
        this._source.setSelectionRange(start - count, end - count);
    }

    /**
     * Cuts from the end of selection
     * @param {number} count positive, non-zero integer of a size to cut
     */
    cutEnd(count) {
        let { selectionStart: start, selectionEnd: end, value } = this._source;
        this._source.value = value.substring(0, end) + value.substring(end + count);
        this._source.setSelectionRange(start, end);
    }

    /**
     * Value of the selection
     * @type {string}
     */
    get selection() {
        return this._source.value.substring(
            this._source.selectionStart,
            this._source.selectionEnd
        );
    }
}