backbone.undo.jsというBackboneJS用のUNDOモジュールが有ります。
こちらをTypescriptで使用してみました。うまくいったのでサンプルを掲載しておきます
通常、Typescriptで既存のライブラリを使用する際には、Typescript用に型定義ファイルを作成してやる必要が有ります。
世の中にはいい人がいて、たいていのライブラリは型定義されていたりします。
https://github.com/borisyankov/DefinitelyTyped
しかし、今回使用するbackbone.undo.jsはまだこちらでは定義されていませんでしたので、適当に作成してみました。
https://github.com/anagotan/DefinitelyTyped/tree/master/backbone.undo
これを利用してUndo機能を実装してみます。
仕様としては、addボタンを押すと「name=0,value=0」のボタンが追加されていきます。update_nameおよびupdate_valueのボタンでランダムな数値に置き換わります。
これをもとにundoおよびredoを実装してみました。
- index.html
- app.ts
////// /// /// module sample { var undoButton = $("#undo"); var redoButton = $("#redo"); var addButton = $("#add"); var updateNameButton = $("#update_name"); var updateValueButton = $("#update_value"); export class App { private listview: ItemListView; constructor() { this.listview = new ItemListView({ "collection": new ItemCollection([ new ItemModel({ "name": "0" ,"value":"0"}) , ]) }); var self = this; var manager = new Backbone.UndoManager({ register: [this.listview.collection], track: true }); manager.removeUndoType("change:isChanging"); manager.addUndoType("change:isChanging", { "on": function (model, isChanging, options) { console.log("manager.addUndoType.on"); }, "undo": function (model, before, after, options) { console.log("manager.addUndoType.undo"); model.set(before) }, "redo": function (model, before, after, options) { console.log("manager.addUndoType.redo"); model.set(after) } }); manager.on("all", function (type) { console.log("all.type:" + type); switch (type) { case "undo": { console.log("undo"); break; } case "redo": { console.log("redo"); break; } } }); manager.trigger("undo redo"); manager.stack.on("add", function () { console.log("stack.on.add"); }); undoButton.click(function () { console.log("undoButton.click"); manager.undo(true); }); redoButton.click(function () { console.log("redoButton.click"); manager.redo(true); }); addButton.click(function () { console.log("addButton.click"); self.listview.collection.add(new ItemModel({ "name": "0", "value": "0" })); }); updateNameButton.click(function () { console.log("updateNameButton.click"); self.listview.collection.forEach(function (item) { item.set("name", _.random(100).toString()); }); }); updateValueButton.click(function () { console.log("updateValueButton.click"); self.listview.collection.forEach(function (item) { item.set("value", _.random(100).toString()); }); }); } draw(): void { this.listview.render(); } } class ItemModel extends Backbone.Model { constructor(options?) { if (options) { if (options.name) this.set({ "name": options.name }, { "validate": true }); if (options.value) this.set({ "value": options.value }, { "validate": true }); } super(options); this.bind("change", this.change); } change(): void { console.log("ItemModel.change:name="+this.get("name")+",value="+this.get("value")); } defaults() { return { "id": _.uniqueId(), "name": "", "value":"" } } validate(attrs) { if (!attrs.name || _.isEmpty(attrs.name)) { return "name must not be empty"; } if (!attrs.value || _.isEmpty(attrs.value)) { return "value must not be empty"; } } } class ItemCollection extends Backbone.Collection { constructor(options) { super(options); this.on("change", this.onchange, this); this.on("add", this.onchange, this); } onchange(model,value,options):void { console.log("ItemCollection.change"); } } class ItemView extends Backbone.View { template: (data: any) => string; constructor(options?) { var html = $("#template-item").html(); this.template = _.template(html); this.events = { "click": "onclick", "change":"onchange" }; super(options); this.model.bind("change", this.render, this); } private onclick() { console.log("ItemView.onclick"); } private change() { console.log("ItemView.onchange"); this.render(); } render(): ItemView { var html = this.template(this.model.toJSON()); $(this.el).html(html); return this; } } class ItemListView extends Backbone.View { // list: ItemCollection; constructor(options?) { this.el = "#item-list"; if (options) { if (options.collection) this.collection = options.collection; } super(options); //_.bindAll(this); this.listenTo(this.collection, 'add', this.render); this.listenTo(this.collection, 'remove', this.render); this.listenTo(this.collection, 'reset', this.render); } render(): ItemListView { var el = $(this.el); el.empty(); this.collection.forEach(item=> { console.log("ItemListView.render"); var view=new ItemView({ "model": item }).render(); el.append(view.el); }); return this; } } } new sample.App().draw();
実行する際には別途,jquery,underscore.js,backbone.js を用意しておく必要が有ります
ぜひpull requestください!
参考:http://qiita.com/vvakame/items/1980d4b6cc222e03fdcb