UNPKG

devexpress-richedit

Version:

DevExpress Rich Text Editor is an advanced word-processing tool designed for working with rich text documents.

126 lines (125 loc) 4.37 kB
import { ControlOptions } from '../../options/control'; import { CompositionHistoryItem } from './history-item'; export class History { static MAX_HISTORY_ITEM_COUNT = 100; historyItems = []; currentIndex = -1; transaction = null; incrementalId = -1; transactionLevel = -1; unmodifiedIndex = -1; options; isProcessingUndo = false; currTransactionId = 0; transactionMap = {}; constructor(options) { this.options = options; } isModified() { if (this.unmodifiedIndex == this.currentIndex) return false; var startIndex = Math.min(this.unmodifiedIndex, this.currentIndex); var endIndex = Math.max(this.unmodifiedIndex, this.currentIndex); for (var i = startIndex + 1; i <= endIndex; i++) { if (this.historyItems[i].changeModified()) return true; } return false; } undo() { if (!this.canUndo()) return; this.isProcessingUndo = true; this.historyItems[this.currentIndex].undo(); this.currentIndex--; this.isProcessingUndo = false; } redo() { if (!this.canRedo()) return; this.currentIndex++; this.historyItems[this.currentIndex].redo(); } canUndo() { return this.currentIndex >= 0 && ControlOptions.isEnabled(this.options.undo); } canRedo() { return this.currentIndex < this.historyItems.length - 1 && ControlOptions.isEnabled(this.options.undo); } beginTransaction() { this.transactionLevel++; if (this.transactionLevel == 0) this.transaction = new CompositionHistoryItem(); const id = this.currTransactionId++; this.transactionMap[id] = this.transaction; return id; } addTransaction(action, isUnderUndo = false) { this.beginTransaction(); action(this); this.endTransaction(isUnderUndo); } endTransaction(isUnderUndo = false) { if (--this.transactionLevel >= 0) return; const transactionLength = this.transaction.historyItems.length; if (transactionLength > 1) this.addInternal(this.transaction, isUnderUndo); else if (transactionLength == 1) this.addInternal(this.transaction.historyItems.pop(), isUnderUndo); this.transaction = null; } addAndRedo(historyItem, isUnderUndo = false) { this.add(historyItem, isUnderUndo); historyItem.redo(); } add(historyItem, isUnderUndo = false) { if (this.transactionLevel >= 0) this.transaction.add(historyItem); else this.addInternal(historyItem, isUnderUndo); } addInternal(historyItem, isUnderUndo) { if (this.isProcessingUndo) { if (isUnderUndo) return; else throw new Error('Add new item is not allowed while undo operation in process.'); } if (this.currentIndex < this.historyItems.length - 1) { this.historyItems.splice(this.currentIndex + 1); this.unmodifiedIndex = Math.min(this.unmodifiedIndex, this.currentIndex); } this.historyItems.push(historyItem); this.currentIndex++; this.deleteOldItems(); } deleteOldItems() { const exceedItemsCount = this.historyItems.length - History.MAX_HISTORY_ITEM_COUNT; if (exceedItemsCount > 0 && this.currentIndex > exceedItemsCount) { this.historyItems.splice(0, exceedItemsCount); this.currentIndex -= exceedItemsCount; } } getNextId() { this.incrementalId++; return this.incrementalId; } clear() { this.currentIndex = -1; this.unmodifiedIndex = -1; this.incrementalId = -1; this.historyItems = []; } resetModified() { this.unmodifiedIndex = this.currentIndex; } getCurrentItemId() { if (this.currentIndex == -1) return -1; var currentItem = this.historyItems[this.currentIndex]; if (currentItem.uniqueId == -1) currentItem.uniqueId = this.getNextId(); return currentItem.uniqueId; } }