Index
A all-function topology editor or 3D
scene editor, undo and redo
function is essential, imagine it, the user struggled to design a data, then accidentally hit the delete
key, if can not be revoked, the user can only cry.
This plug-in provides ht.HistoryManager
class, which listens for changes in the attributes of the data in the DataModel
and provides an API
interface to undo or redo the history. Before you formally use API
, you need to introduce relevant js
files on your page:
<script src="ht.js"></script> <!--Introduce ht.js file first-->
<script src="ht-historymanager.js"></script>
It is very simple to use, just creating a HistoryManager
and binding DataModel
:
var historyManager = new ht.HistoryManager(dataModel);
The property changes of all datas in dataModel
are recorded by the historyManager
object, which is called when the operation is to be undone:
historyManager.undo();
To redo, call the
historyManager.redo();
The user cannot directly operate the API, so the above API
is usually bound to the shortcut on the page:
window.addEventListener('keydown', function (e) {
if (e.ctrlKey) {
if (e.keyCode == 90) {//ctrl + z
historyManager.undo();
} else if (e.keyCode == 89) {//ctrl + y
historyManager.redo();
}
}
})
The API
provided by ht.HistoryManager
is as follows:
dataModel
Is manipulated by setDataModel(dataModel)
and getDataModel()
to monitor and record property changes for all datas in this dataModel
getHistories()
Gets an array of historical recordshistoryIndex
Represents the current record subscript, for example, the user did the 10
operation, the history of the array has 10
records, historyIndex
point to the last record, the value of 9
(the array subscript from 0), do undo
once, historyIndex
moves forward one step, becomes to 8
; do redo
once, historyIndex
moves back one step, becomes to 9
again, and can also directly invoke setHistoryIndex
(newIndex) to jump to the specified history.undo()
Resume operation, historyIndex
move forward one stepredo()
Redo operation, historyIndex
move back one stepbeginTransaction()
Is similar to open a transaction in a database, from beginTransaction()
to endTransaction()
, all modifications can be revoked or redoendTransaction()
Is similar to stop a transaction in a database, from beginTransaction()
to endTransaction()
, all modifications can be revoked or redobeginTransient()
This function have been deletedendTransient()
This function have been deletedmaxHistoryCount
Operates through setMaxHistoryCount(newCount)
and getMaxHistoryCount()
, representing the largest number of history records, the default is 10
, only records user 10
recent actions(old records replaced)clear()
Erase all historyisPropertyRecode(property)
Determines whether property changes are recorded, and returns true by default, and can be overloaded to filter out properties that do not require record historyNext look at an example:
In this case, the upper-left corner is a Palette
component that allows you to drag the Node
into the middle topology to create Node
; the lower-left corner is a TreeView
component that can present a parent-child relationship; the middle is a GraphView
component that can be manipulated by dragging and dropping to change data properties; the upper-right corner is a PropertyView
component that can edit the label
and label
background color; the lower-right corner is a ListView
, showing the history of HistoryManager
, can be selected different records and jumping to that history.
historyManager.mp(function (e) {// Monitor the HistoryManager property changes and synchronize the
// history records to the ListView in the lower-right corner.
var property = e.property;
if (property === 'historyIndex' || property === 'histories') {
var histories = historyManager.getHistories(),
historyIndex = historyManager.getHistoryIndex(),
dataModel = list.dm();
list._betweenUpdate = 1;
dataModel.clear();
var initData = new ht.Data();
initData.setName('init status');
dataModel.add(initData);
histories.forEach(function (history) {
var actions = [];
history.forEach(function (action) {
actions.push(action.type);
});
var actionsStr = actions.join(', ');
var data = new ht.Data();
data.setName(actionsStr);
dataModel.add(data);
});
list.sm().ss(dataModel.getDatas().get(historyIndex + 1));
list._betweenUpdate = 0;
}
});
list.sm().ms(function (e) {// Monitor the HistoryManager property changes and synchronize the
// history records to the ListView in the lower-right corner.
if (!list._betweenUpdate) {
var data = list.sm().ld(),
index = list.dm().getDatas().indexOf(data);
historyManager.setHistoryIndex(index - 1);
}
});
window.addEventListener('keydown', function (e) {//Increase shortcuts support
if (e.ctrlKey) {
if (e.keyCode == 90) {//ctrl+z undo
historyManager.undo();
} else if (e.keyCode == 89) {//ctrl+y redo
historyManager.redo();
}
}
})