Lively Kernel canvas
//
10000.0499004231926231Wikicontroltrue
10000.13508753683390934Wikicontroltrue
10000.0071931237961425825Wikicontroltrue
10001.8492009431182384e-8Wikicontroltrue
-----falsetruefalse0
fontCourier12:spacewidth7from21xWidth7falsetruefalse0
worldis1:WorldMorph([[0,0,2000,1200]])falsetruefalse0
startingWikiNavigatorfalsetruefalse0
status207onPROPFINDhttp://localhost/lk/webwerkstatt/draft/DraftUndo.xhtmlfalsetruefalse0
http://localhost/lk/webwerkstatt/draft/../anonymous_module_3loadedin37msfalsetruefalse0
http://localhost/lk/webwerkstatt/draft/../anonymous_module_2loadedin980msfalsetruefalse0
fontHelvetica40:spacewidth11from51xWidth20falsetruefalse0
fitWidthfailureonTextMorph.getCharBoundsfalsetruefalse0
fitWidthfailureonTextMorph.getCharBoundsfalsetruefalse0
fitWidthfailureonTextMorph.getCharBoundsfalsetruefalse0
inundefined:[objectEvent],codeundefinedfalsetruefalse0
ResizingSVGcanvasfalsetruefalse0
Moduleloadcheckdone.31modulesloaded.falsetruefalse0
fontHelvetica12:spacewidth3from17xWidth7falsetruefalse0
undofrom7to10falsetruefalse0
undofrom16to1falsetruefalse0
undofrom16to0falsetruefalse0
undofrom17to0falsetruefalse0
undofrom17to1falsetruefalse0
undofrom16to1falsetruefalse0
undofrom15to1falsetruefalse0
undofrom14to1falsetruefalse0
undofrom13to1falsetruefalse0
undofrom12to1falsetruefalse0
undofrom11to1falsetruefalse0
undofrom10to1falsetruefalse0
undofrom9to1falsetruefalse0
undofrom8to1falsetruefalse0
undofrom7to1falsetruefalse0
undofrom6to1falsetruefalse0
undofrom5to1falsetruefalse0
undofrom4to1falsetruefalse0
undofrom3to1falsetruefalse0
undofrom3to0falsetruefalse0
undofrom4to0falsetruefalse0
-------------------------------------------falsetruefalse0
invoke1:WorldMorph([[0,0,2000,1200]])falsetruefalse0
status200onGEThttp://localhost/lk/webwerkstatt/draft/DraftUndo.xhtmlfalsetruefalse0
extendForSerializationundefinedfalsetruefalse01111-1nulltrue0false
truetruefalse
false1truefalse
nullfalse
nullfalse
nullfalse
nullfalsefalsetruetruefalse
truetrue100false
truefalsenull050
nullfalsetruenullfalse
Consolefalsenullfalse
false
false
falsenullfalsefalsenullnullnullnullfalse
10000.0006265787506114637Wikicontroltrue
10005.143153374263595e-10Wikicontroltrue
10000.12641840330743587Wikicontroltrue
DraftingMultipleUndo....40
1505
Runtestsfalsenull>' + result.selector;\n\t\t\tmsg += '\\n';\n\t\t\tmsg += result.err.message;\n\t\t\treturn msg;\n\t\t}).join('\\n---------\\n');\n\t\t$morph('testResult').setExtent(pt(400,20))\n\t\t$morph('testResult').setFill(Color.red);\n\t\t$morph('testResult').setTextString(failStr);\n\t} /* runFinished */"]]>null
truenull
UndoTest
module("lively.Tests.UndoTest").requires().toRun(function(){//newTestRunner().openIn(WorldMorph.current(),pt(500,100))TestCase.subclass("lively.Tests.UndoTest.TextReplacementCommandTest",{setUp:function(){this.text=newTextMorph(newRectangle(100,100,10,10));this.text.renderAfterReplacement=function(){};},testUndoAndRedo:function(){this.text.setTextString("Hello");varcmd=newReplaceTextCommand(this.text,0,"","H");cmd.undo();this.assertEqual(this.text.textString,"ello","undofirstbroken")cmd.redo();this.assertEqual(this.text.textString,"Hello","redofirstbroken")cmd=newReplaceTextCommand(this.text,1,"abcde","ell");cmd.undo();this.assertEqual(this.text.textString,"Habcdeo","undomiddlebroken")cmd.redo();this.assertEqual(this.text.textString,"Hello","redomiddlebroken")cmd=newReplaceTextCommand(this.text,5,"Last","");cmd.undo();this.assertEqual(this.text.textString,"HelloLast","undolastbroken")cmd.redo();this.assertEqual(this.text.textString,"Hello","redolastbroken")},testUndoRichText:function(){this.text.setTextString("Hello");varoldText=newlively.Text.Text("World",{color:Color.green});varcmd=newReplaceTextCommand(this.text,6,oldText,"");cmd.undo();this.assertEqual(this.text.textString,"HelloWorld","undotextStringbroken");this.assertEqual(this.text.textStyle.valueAt(7).color,Color.green,"undotextStringbroken")},testSlicdeRichText:function(){this.text.setTextString("HelloWorldhowareyou?");this.text.setSelectionRange(6,12);this.text.emphasizeSelection({color:Color.green});varstyleSlice=this.text.textStyle.slice(4,14);this.assertEqual(styleSlice.valueAt(0).color,undefined,"0");this.assertEqual(styleSlice.valueAt(3).color,Color.green,"1");this.assert(styleSlice.runs,"norunsinslice");this.assertEqual(styleSlice.runs.length,3,"wrongnumberofruns");varstringSlice=this.text.textString.slice(4,14);vartextObj=newlively.Text.Text(stringSlice,styleSlice);this.text.setSelectionRange(1,2);this.text.replaceSelectionWith(textObj);console.log("text:"+textObj);},});TestCase.subclass("lively.Tests.UndoTest.UndoHistoryTest",{setUp:function(){this.sut=newUndoHistory();},testAddCommand:function(){varcmd=newUndoableCommand();this.sut.addCommand(cmd);this.assertEqual(this.sut.undoStack.length,1)},testUndo:function(){varundoWasRun=false;varcmd=newUndoableCommand();cmd.undo=function(){undoWasRun=true};this.sut.addCommand(cmd);this.sut.undo();this.assertEqual(this.sut.undoStack.length,0);this.assert(undoWasRun,"undowasnotperformed");this.assertEqual(this.sut.redoStack.length,1)},testForgetRedoHistoryAfterNewCommand:function(){this.sut.addCommand(newUndoableCommand());this.sut.undo();this.assertEqual(this.sut.redoStack.length,1);this.sut.addCommand(newUndoableCommand());this.assertEqual(this.sut.undoStack.length,1);this.assertEqual(this.sut.redoStack.length,0);},testRedo:function(){varredoWasRun=false;varcmd=newUndoableCommand();cmd.redo=function(){redoWasRun=true};this.sut.addCommand(cmd);this.sut.undo();this.sut.redo();this.assertEqual(this.sut.undoStack.length,1);this.assert(redoWasRun,"undowasnotperformed");this.assertEqual(this.sut.redoStack.length,0);},testHasUndoableCommand:function(){this.assertEqual(this.sut.hasUndoableCommand(),false);varcmd=newUndoableCommand();this.sut.addCommand(cmd);this.assertEqual(this.sut.hasUndoableCommand(),true);this.sut.undo();this.sut.undo();//emtpy},});TestCase.subclass("lively.Tests.UndoTest.TextWithUndoStackTest",{setUp:function(){this.text=newTextMorph(newRectangle(100,100,10,10));this.text.setWithLayers([UndoLayer]);//textcompositionseemstodependonatextisisactuallydisplayedinaworld//sowedisablethenonworkingpart...this.text.renderAfterReplacement=function(){};//WorldMorph.current().addMorph(this.text);},testSetTextStringProducesCommand:function(){this.text.undoHistory=newUndoHistory();this.text.setTextString("ANewText");this.assert(this.text.undoHistory.hasUndoableCommand(),"noundoablecmd")},testUndoDoesNotProduceAnUndo:function(){this.text.setTextString("OldText");this.text.undoHistory=newUndoHistory();this.text.setTextString("NewText");varaddCommandExecuted=false;this.text.addCommand=function(){addCommandExecuted=true}this.text.undoHistory.undo();this.assert(!addCommandExecuted,"addCommandwasexecutedinundo");this.assertEqual(this.text.undoHistory.undoStack.length,0);this.assertEqual(this.text.textString,"OldText","undodidnotwork")},testMultipleUndoAndRedo:function(){this.text.setTextString("OldText");this.text.undoHistory=newUndoHistory();this.text.setTextString("NewText1");this.text.setTextString("NewText2");this.text.setTextString("NewText3");this.assertEqual(this.text.textString,"NewText3","undodidnotwork");this.text.undoHistory.undo();this.assertEqual(this.text.textString,"NewText2","undodidnotwork");this.text.undoHistory.undo();this.assertEqual(this.text.textString,"NewText1","undodidnotwork");this.text.undoHistory.undo();this.assertEqual(this.text.textString,"OldText","undodidnotwork");this.text.undoHistory.undo();this.assertEqual(this.text.textString,"OldText","undoafteremtydidnotwork");this.text.undoHistory.redo();this.assertEqual(this.text.textString,"NewText1","redodidnotwork");},testReplaceSelectionTriggersUndo:function(){this.text.setTextString("OldText");this.text.undoHistory=newUndoHistory();this.text.setSelectionRange(0,3);this.text.replaceSelectionWith("New");this.assertEqual(this.text.textString,"NewText","replacedidnotwork");this.text.undoHistory.undo();this.assertEqual(this.text.textString,"OldText","undodidnotwork");},testUndoPreservesStyle:function(){this.text.setTextString("OldText");this.text.setSelectionRange(0,3);this.text.emphasizeSelection({color:Color.green});this.assertEqual(this.text.textStyle.valueAt(1).color,Color.green,"stylingbroken");this.text.undoHistory=newUndoHistory();this.text.setSelectionRange(0,3);this.text.replaceSelectionWith("");this.text.undoHistory.undo();this.assertEqual(this.text.textStyle.valueAt(1).color,Color.green,"undoforgetsstyle");},tearDown:function(){//this.text.remove();}});});222truetruefalsetruetruetruefalse
false1truefalsetruetruefalse
nullfalsetruenullfalse
falsenullfalse
false
false
falsenullfalsefalsenullnullnullnullfalse
TheProblemwiththisUndoimplementationis,thattherearestillbugsintheTextMorphwhenithasnotcontents...1
10000.08806521333508795Wikicontroltrue
GroßesEhrenwort!
100010.745763154204413Wikicontroltrue
Object.subclass("UndoHistory",{initialize:function(){this.undoStack=[];this.redoStack=[];},addCommand:function(cmd){this.undoStack.push(cmd);this.redoStack=[];//redostackisinvalidnow},undo:function(){if(!this.hasUndoableCommand())return;varcmd=this.undoStack.pop();cmd.undo();this.redoStack.push(cmd);},redo:function(){if(!this.hasRedoableCommand())return;varcmd=this.redoStack.pop();cmd.redo();this.undoStack.push(cmd);},hasUndoableCommand:function(){returnthis.undoStack.length>0},hasRedoableCommand:function(){returnthis.redoStack.length>0},});Object.subclass("UndoableCommand",{undo:function(){},redo:function(){},});UndoableCommand.subclass("ReplaceTextCommand",{initialize:function(morph,index,oldText,newText){this.morph=morph;this.index=index;this.oldText=oldText;this.newText=newText;},undo:function(){console.log("undofrom"+this.index+"to"+this.newText.size())withoutLayers([UndoLayer],function(){this.morph.setSelectionRange(this.index,this.index+this.newText.size());this.morph.replaceSelectionWith(this.oldText);}.bind(this))},redo:function(){withoutLayers([UndoLayer],function(){this.morph.setSelectionRange(this.index,this.index+this.oldText.size());this.morph.replaceSelectionWith(this.newText);varpos=this.index+this.newText.size();this.morph.setSelectionRange(pos,pos);}.bind(this))},});createLayer("UndoLayer")layerClass(UndoLayer,TextMorph,{getUndoHistory:function(){if(!this.undoHistory)this.undoHistory=newUndoHistory();returnthis.undoHistory},processCommandKeys:function(proceed,evt){varkey=evt.getKeyChar();if(key)key=key.toLowerCase();if(key=='z'&&evt.isShiftDown()){this.doRedo();returntrue;};returnproceed(evt)},doRedo:function(proceed){varundoHistory=this.getUndoHistory();if(undoHistory){returnundoHistory.redo()}},doUndo:function(proceed){varundoHistory=this.getUndoHistory();if(undoHistory){returnundoHistory.undo()}else{returnproceed()}},textSliceFromTo:function(proceed,from,to){varstring=this.textString.substring(from,to+1);if(this.textStyle){varstyle=this.textStyle.slice(from,to+1);}returnnewlively.Text.Text(string,style);},replaceSelectionWith:function(proceed,replacement){varundoHistory=this.getUndoHistory();if(undoHistory){varfrom=this.selectionRange[0];varto=this.selectionRange[1];varoldText=this.textSliceFromTo(from,to);varcmd=newReplaceTextCommand(this,from,oldText,replacement)undoHistory.addCommand(cmd);};withoutLayers([UndoLayer],function(){returnproceed(replacement);})},emphasizeFromTo:function(proceed,emph,from,to){varundoHistory=this.getUndoHistory();varoldText=this.textSliceFromTo(from,to);withoutLayers([UndoLayer],function(){proceed(emph,from,to);})varnewText=this.textSliceFromTo(from,to);if(undoHistory){varcmd=newReplaceTextCommand(this,from,oldText,newText)this.getUndoHistory().addCommand(cmd);}},setTextString:function(proceed,string){varundoHistory=this.getUndoHistory();if(undoHistory){varfrom=0;varto=this.textString.size()-1;varoldText=this.textSliceFromTo(from,to);varcmd=newReplaceTextCommand(this,from,oldText,string)undoHistory.addCommand(cmd);};withoutLayers([UndoLayer],function(){proceed(string);})},}); 0\n\t},\n\n\thasRedoableCommand: function() {\n\t\treturn this.redoStack.length > 0\n\t},\n\n});\n\nObject.subclass(\"UndoableCommand\", {\n\n\tundo: function() {},\n\n\tredo: function() {},\n});\n\nUndoableCommand.subclass(\"ReplaceTextCommand\", {\n\tinitialize: function(morph, index, oldText, newText) {\n\t\tthis.morph = morph;\n\t\tthis.index = index;\n\t\tthis.oldText = oldText;\n\t\tthis.newText = newText;\n\t},\n\n\tundo: function() {\n\t\tconsole.log(\"undo from \" + this.index + \" to \" + this.newText.size())\n\t\twithoutLayers([UndoLayer], function() {\n\t\t\tthis.morph.setSelectionRange(this.index, this.index + this.newText.size());\n\t\t\tthis.morph.replaceSelectionWith(this.oldText);\n\t\t}.bind(this))\n\t},\t\n\tredo: function() {\n\t\twithoutLayers([UndoLayer], function() {\n\t\t\tthis.morph.setSelectionRange(this.index, this.index + this.oldText.size());\n\t\t\tthis.morph.replaceSelectionWith(this.newText);\n\t\t\tvar pos = this.index + this.newText.size();\n\t\t\tthis.morph.setSelectionRange(pos, pos);\n\t\t}.bind(this))\n\t},\t\n});\n\ncreateLayer(\"UndoLayer\")\nlayerClass(UndoLayer, TextMorph, {\n\n\tgetUndoHistory: function() {\n\t\tif (!this.undoHistory)\n\t\t\tthis.undoHistory = new UndoHistory();\n\t\treturn this.undoHistory\n\t},\n\n\tprocessCommandKeys: function(proceed, evt) {\n\t\tvar key = evt.getKeyChar();\n\t\tif (key) key = key.toLowerCase();\n\t\tif (key == 'z' && evt.isShiftDown()) {\n\t\t\tthis.doRedo(); return true;\n\t\t};\n\t\treturn proceed(evt)\n\t},\n\n\tdoRedo: function(proceed) {\n\t\tvar undoHistory = this.getUndoHistory();\n\t\tif (undoHistory) {\n\t\t\treturn undoHistory.redo()\n\t\t}\n\t},\n\n\tdoUndo: function(proceed) {\n\t\tvar undoHistory = this.getUndoHistory();\n\t\tif (undoHistory) {\n\t\t\treturn undoHistory.undo()\n\t\t} else {\n\t\t\treturn proceed()\n\t\t}\n\t},\n\ttextSliceFromTo: function(proceed, from, to) {\n\t\tvar string = this.textString.substring(from, to + 1);\n\t\tif (this.textStyle) {\n\t\t\tvar style = this.textStyle.slice(from, to + 1);\n\t\t}\n\t\treturn new lively.Text.Text(string, style);\n\t},\t\n\n\treplaceSelectionWith: function(proceed, replacement) {\n\t\tvar undoHistory = this.getUndoHistory();\n\t\tif (undoHistory) {\n\t\t\tvar from = this.selectionRange[0];\n\t\t\tvar to = this.selectionRange[1];\n\t\t\tvar oldText = this.textSliceFromTo(from, to);\n\t\t\tvar cmd = new ReplaceTextCommand(this, from, oldText, replacement)\n\t\t\tundoHistory.addCommand(cmd);\n\t\t};\n\t\twithoutLayers([UndoLayer], function(){\n\t\t\treturn proceed(replacement);\n\t\t})\n\t},\n\n\temphasizeFromTo: function(proceed, emph, from, to) {\n\t\tvar undoHistory = this.getUndoHistory();\n\t\tvar oldText = this.textSliceFromTo(from, to);\n\t\twithoutLayers([UndoLayer], function(){\n\t\t\tproceed(emph, from, to);\n\t\t})\n\t\tvar newText = this.textSliceFromTo(from, to);\n\t\tif (undoHistory) {\n\n\t\t\tvar cmd = new ReplaceTextCommand(this, from, oldText, newText)\n\t\t\tthis.getUndoHistory().addCommand(cmd);\n\t\t}\n \t},\n\n\tsetTextString: function(proceed, string) {\n\t\tvar undoHistory = this.getUndoHistory();\n\t\tif (undoHistory) {\n\t\t\tvar from = 0;\n\t\t\tvar to = this.textString.size() - 1;\n\t\t\tvar oldText = this.textSliceFromTo(from, to);\n\t\t\tvar cmd = new ReplaceTextCommand(this, from, oldText, string)\n\t\t\tundoHistory.addCommand(cmd);\n\t\t};\n\t\twithoutLayers([UndoLayer], function(){\n\t\t\tproceed(string);\n\t\t})\n \t},\n});"]]>152truetruefalsetruetruetruefalse
false1truefalsenulltruetruefalse
nullfalsetruenullfalse
falsenullfalse
false
false
falsenullfalsefalsenullnullnullnullfalse
nulltrue$morph('undoTestText').undoHistory=null1truetruefalsetruetruefalse
false1truefalsetruetruefalse
nullfalsetruenullfalse
falsenullfalse
false
false
falsenullfalsefalsenullnullnullnullfalse
null72