0.1.3 • Published 4 years ago

@anovel/records v0.1.3

Weekly downloads
-
License
MIT
Repository
github
Last release
4 years ago

Records

History record tools for undo/redo custom algorithms.

LocalHistory

Record input for a single local user.

import {LocalHistory} from '@anovel/records';

const recorder = new LocalHistory();

Constructor takes 2 optional parameters.

ParameterTypeDescription
contentstringInitial value of the string. User cannot rollback past this value, which serves as a starting point for the record history.
records(#record-object)An array of records to initialize recorder with. Those records are applied automatically, so they will alter the initial value, if provided. Records with active:false will be ignored.
import {LocalHistory} from '@anovel/records';

const recorder = new LocalHistory('', [
  {to: 'hello', caret: {start: 0, end: 0}, active: true}, // Will be applied.
  {to: 'world', caret: {start: 5, end: 5}, active: false}, // Will not be applied.
  {to: ' ', caret: {start: 5, end: 5}, active: true} // Will not be applied, since no active record should follow a non active one.
]);

// recorder.getValue() will return 'hello'.

Interact with records

Record Object

A record is an object with the following properties:

PropertyTypeRequiredDescription
caret{start: number, end: number}trueIndicates where the alteration took place within the string.
fromstring-The original value that was replaced by the alteration.This key should be used for read only in custom rollback functions, as it is overridden by LocalHistory handlers.
tostringtrueThe value that was added by the alteration. Can be an empty string.
activeboolean-Indicates whether the record is applied or not (on undo, undone record is set to active:false).

Add entry

To add a Record Object to the history, you may use the push method.

// push() may add information or alter the current record.
recordObject = recorder.push(recordObject);

Navigate in history

Recorder provides several ways to interact with your record history.

Basic handlers

You can use apply and revert methods to navigate within your history. Both take a required number parameter.

// Undo the 3 last entries.
recorder.revert(3);

// Redo the 2 last ones.
recorder.apply(2);

// The whole code will have the same effect than recorder.revert(1)

Chained handlers

Chained handlers will allow you to perform undo/redo operations grouped under a certain condition. They both take a single callback argument that returns a boolean.

recorder.applyChain((nextRecord, currentRecord) => boolean);
recorder.revertChain((previousRecord, currentRecord) => boolean);

This will undo/redo first argument while the returned condition is true. It performs at least one undo/redo operation to allow comparison.

Default chainers

LocalHistory provides default chaining static methods. They can be used to quickly setup powerful undo/redo algorithms.

The following examples will use this record chain sample:

'h'                       -> {to: 'h', caret: {start: 0, end: 0}}
'he'                      -> {to: 'e', caret: {start: 1, end: 1}}
'hel'                     -> {to: 'l', caret: {start: 2, end: 2}}
'hell'                    -> {to: 'l', caret: {start: 3, end: 3}}
'hello'                   -> {to: 'o', caret: {start: 4, end: 4}}
'hello '                  -> {to: ' ', caret: {start: 5, end: 5}}
'hello w'                 -> {to: 'w', caret: {start: 6, end: 6}}
'hello wo'                -> {to: 'o', caret: {start: 7, end: 7}}
'hello wor'               -> {to: 'r', caret: {start: 8, end: 8}}
'hello worl'              -> {to: 'l', caret: {start: 9, end: 9}}
'hello world'             -> {to: 'd', caret: {start: 10, end: 10}}
'hellon world'            -> {to: 'n', caret: {start: 5, end: 5}}
'hellone world'           -> {to: 'e', caret: {start: 6, end: 6}}
'hellonew world'          -> {to: 'w', caret: {start: 7, end: 7}}
'hellobnew world'         -> {to: 'b', caret: {start: 5, end: 5}}
'hellobrnew world'        -> {to: 'r', caret: {start: 6, end: 6}}
'hellobranew world'       -> {to: 'a', caret: {start: 7, end: 7}}
'hellobrannew world'      -> {to: 'n', caret: {start: 8, end: 8}}
'hellobrandnew world'     -> {to: 'd', caret: {start: 9, end: 9}}
'hellobrand new world'    -> {to: ' ', caret: {start: 10, end: 10}}
'hello brand new world'   -> {to: ' ', caret: {start: 5, end: 5}}
splitOnBlankSpace

Group characters by words.

// 'hello brand new world' -> 'hellobrand new world'
recorder.revertChain(LocalHistory.splitOnBlankSpace);

// Following calls will produce:
// 'hellobrand new world' -> 'hellobrandnew world'
// 'hellobrandnew world' -> 'hello '
// 'hello ' -> 'hello'
// 'hello' -> ''
keepContinuity

Stop when 2 records aren't siblings.

// 'hello brand new world' -> 'hellobrand new world'
recorder.revertChain(LocalHistory.keepContinuity);

// Following calls will produce:
// 'hellobrand new world' -> 'hellobrandnew world'
// 'hellobrandnew world' -> 'hellonew world'
// 'hellonew world' -> 'hello world'
// 'hello world' -> ''

Accessors

Recorder class variables are made private for security issues, but you can access a copy of them with the following accessors.

// Returns the current value of the input string.
recorder.getValue();

// Returns a copy of the current list of records.
recorder.getRecords();

Special handlers

lastActiveIndex

Returns the index of the last active record. Please be aware to be considered active, a record should only be preceded by active records. Given the following (broken) record chain:

[
  {"to":  "hello", "active": true, ...},
  {"to":  " ", "active": false, ...},
  {"to":  "world", "active": true, ...}
]

recorder.lastActiveIndex() will return 0 (since element at index 2 is preceded by a non active record).

checkIntegrity

Check if the current record history leads to the current value when applied. Returns the correct value in case something went wrong. Should always return blank string.

// Should return ''
const output = recorder.checkIntegrity();

License

Licensed under MIT for A-Novel.

0.1.3

4 years ago

0.1.2

4 years ago

0.1.1

4 years ago

0.1.0

4 years ago