Do you like this project? Please support my Mecha CMS project too. Thank you!

Text Editor 4.1.2

Text Editor is a simple JavaScript application that aims to provide accessibility enhancements to the native HTML <textarea> elements, allowing users to control and manipulate their data in the text editor as they wish. It contains very sufficient methods to manipulate the existing text selection range data without providing unnecessary features. This keeps the file size small and the learning curve low, so you can fully focus on the results.


# Usage

Browser

<!DOCTYPE html>
<html dir="ltr">
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <p>
      <textarea></textarea>
    </p>
    <script src="./index.min.js"></script>
    <script>
      const editor = new TextEditor(document.querySelector('textarea'));
    </script>
  </body>
</html>

Node.js

Functions and methods in this application are mostly native JavaScript and are intended for use by the browser. Node.js doesn’t know about the DOM, so this kind of practice will probably be used more often to build new browser packages than to be used directly in the Node.js server.

CommonJS

const TextEditor = require('@taufik-nurrohman/text-editor').default;

const editor = new TextEditor(document.querySelector('textarea'));

ECMAScript

import TextEditor from '@taufik-nurrohman/text-editor';

const editor = new TextEditor(document.querySelector('textarea'));

# Examples

# Constructor

const editor = new TextEditor(self, tab = '\t');
const editor = new TextEditor(self, state = {
    tab: '\t',
    with: []
});

# Parameters

self

The text area element.

tab

The default indent character for editor.pull() and editor.push() method.

state

The configuration data.

state.tab

The default indent character for editor.pull() and editor.push() method.

state.with

List of callable functions or objects containing an attach() method to be invoked each time the application is initialized. A very simple “plugin” system.

# Methods

Instance Methods

Instance methods are methods that are available through the results of a TextEditor construct.

editor.attach(self, state)

Re-initialize the application and its extensions after it has been detached.

editor.attach(editor.self);

editor.blur()

Blur from the <textarea> element.

editor.fire(event, data)

Fire an event.

editor.fire('change', []);

editor.focus(mode = 0)

Focus to the <textarea> element.

editor.focus(); // Focus to the last selection
editor.focus(-1); // Focus to the start of text area value
editor.focus(+1); // Focus to the end of text area value
editor.focus(true); // Select all

editor.detach()

Disable the application methods (except for the attach() method) and execute the detach() method of the extensions, if they are present.

editor.detach();

editor.get()

Get current value of the <textarea> element if not empty, otherwise, return null.

editor.insert(value, mode = 0, clear = false)

Insert value to (replace) the current selection.

editor.insert(':)'); // Insert at selection (replace selection)
editor.insert('<b>', -1); // Insert before selection
editor.insert('</b>', +1); // Insert after selection
editor.insert(':)', -1, true); // Insert before selection and delete selection
editor.insert(':)', +1, true); // Insert after selection and delete selection

editor.let()

Reset value to the initial value of the <textarea> element.

editor.match(pattern, then)

Match current selection with the pattern provided.

if (editor.match(/^\s*:\w+:\s*$/)) {
    alert('Selection is detected as emoji!');
}

Do something with the current matched selection.

let maps = {
    ':happy:': '😀',
    ':sad:': '😩',
    ':wonder:': '😕'
};

editor.match(/^\s*:\w+:\s*$/, function (m) {
    let exists = maps[m[0] = m[0] ? m[0].trim() : ""];
    exists && this.insert(exists);
});

Match to the characters before selection, current selection and characters after selection.

let test = editor.match([/:$/, /^\w+$/, /^:/]);
console.log(test[0] && test[1] && test[2]);
editor.match([/:$/, /^\w+$/, /^:/], function (before, value, after) {
    console.log([before, value, after]);
});

editor.off(event, then)

Remove an event.

editor.off('click', onClick); // Remove `onClick` event from the `click` event container
editor.off('click'); // Remove all events from the `click` event container

editor.on(event, then)

Add an event.

function onClick(e) {
    this.select(true); // Select all on click
}

editor.on('click', onClick);

editor.peel(open, close, wrap = false)

Unwrap current selection from open and close.

editor.peel('<', '>'); // Remove `<` before selection and `>` after selection
editor.peel('<', '>', true); // Remove `<` at selection start and `>` at selection end

editor.pull(by = editor.state.tab, withEmptyLines = true)

Outdent current selection from by.

editor.pull(); // Outdent from `\t`
editor.pull('****'); // Outdent from `****`

editor.push(by = editor.state.tab, withEmptyLines = false)

Indent current selection with by.

editor.push(); // Indent with `\t`
editor.push('****'); // Indent with `****`

editor.replace(from, to, mode = 0)

Replace current, before or after selection from from to to.

editor.replace(/<.*?>/g, ""); // Strip HTML tag(s) in selection
editor.replace(/<.*?>/g, "", -1); // Strip HTML tag(s) before selection
editor.replace(/<.*?>/g, "", +1); // Strip HTML tag(s) after selection

editor.select(...lot)

Set selection range.

editor.select(); // Is the same as `editor.focus()`
editor.select(2); // Move caret to the index `2`
editor.select(0, 2); // Select from range `0` to `2`
editor.select(true); // Select all

editor.set(value)

Set value to the <textarea> element.

editor.trim(open = "", close = "", start = "", end = "", tidy = true)

Trim current selection from white-spaces, and optionally insert characters at the specified points.

// `a<open><start>b<end><close>c`

editor.trim(); // Remove any white-space(s) before and after selection, start and end of selection
editor.trim(false, false); // Remove any white-space(s) at the start and end of selection
editor.trim("", "", false, false); // Remove any white-space(s) before and after selection
editor.trim(' ', ' '); // Force a space before and after selection
editor.trim('\n\n', '\n\n'); // Force line-break before and after selection
editor.trim('\n\n', '\n\n', "", "", false); // Ignore empty value before and after selection, just insert that `\n\n` away

editor.wrap(open, close, wrap = false)

Wrap current selection with open and close.

editor.wrap('<', '>'); // Wrap with `<` and `>`
editor.wrap('<', '>', true); // Wrap with `<` and `>` then select

editor.$()

Get current text selection data.

// `abc`
console.log(editor.$()); // `{"after":"c","before":"a","end":2,"length":1,"start":1,"value":"b"}`

Static Methods

Static methods are methods that are directly available on the TextEditor object.

TextEditor.esc(value)

Escape regular expression’s special characters.

# Properties

Instance Properties

Instance properties are properties that are available through the results of a TextEditor construct.

editor.hooks

Return the event containers and their contents.

console.log(editor.hooks);

editor.self

Return the <textarea> element.

editor.self.addEventListener('keydown', e => {
    if (
        (e.key && 'Enter' === e.key) ||
        (e.keyCode && 13 === e.keyCode)
    ) {
        // Do something with `Enter` key!
    }
});

editor.state

Return the application states if any.

editor.value

Proxy that passes to the editor.self.value property.

console.log(editor.value); // Get text area value
editor.value = 'asdf'; // Set text area value

Static Properties

Static properties are properties that are directly available on the TextEditor object.

TextEditor.state

Return the default values of editor.state.

const editor = new TextEditor(document.querySelector('textarea'), {
    foo: ['bar', 'baz', 'qux']
});

console.log([TextEditor.state, editor.state]);

TextEditor.version

Return the application version.

let version = TextEditor.version,
    major = version.split('.')[0];

if (+major < 3) { … }

TextEditor.x

List of regular expression characters to be escaped.

# Extensions

Anatomy of an Extension

Extension as a function:

function Extension(self, state = {}) {
    this.a = 1;
    this.b = function () {};
    return this;
}

Object.defineProperty(Extension, 'name', {
    value: 'Extension'
});

Extension as an object:

const Extension = {
    attach: function (self, state = {}) {},
    detach: function (self, state = {}) {},
    name: 'Extension'
};

Usage of an Extension

As a core extension:

TextEditor.state.with.push(Extension);

As an optional extension:

const editor = new TextEditor(document.querySelector('textarea'), {
    with: [Extension]
});

List of Extensions

# License

Use it for free, pay if you get paid. So, you’ve just benefited financially after using this project? It’s a good idea to share a little financial support with this open source project too. Your support will motivate me to do any further development, as well as to provide voluntary support to overcome problems related to this project.

Thank you! ❤️