Browse Source

snap modify:; snapshot passed to trapDescend:

Herbert Vojčík 12 years ago
parent
commit
857a5dc596
6 changed files with 133 additions and 107 deletions
  1. 5 5
      js/Trapped-Demo.deploy.js
  2. 8 8
      js/Trapped-Demo.js
  3. 37 28
      js/Trapped-Frontend.deploy.js
  4. 59 45
      js/Trapped-Frontend.js
  5. 4 5
      st/Trapped-Demo.st
  6. 20 16
      st/Trapped-Frontend.st

+ 5 - 5
js/Trapped-Demo.deploy.js

@@ -137,10 +137,9 @@ selector: "renderOn:",
 fn: function (html){
 var self=this;
 var $1,$2,$3,$4,$5,$6,$7,$9,$10,$11,$12,$8;
-var snap;
+smalltalk.send([],"_trapDescend_",[(function(snap){
 smalltalk.send(smalltalk.send(html,"_h2",[]),"_trap_",[[smalltalk.symbolFor("title")]]);
-snap=smalltalk.send(smalltalk.send((smalltalk.Trapped || Trapped),"_current",[]),"_snapshot",[]);
-smalltalk.send(smalltalk.send(html,"_div",[]),"_trap_toggle_ifNotPresent_",[[smalltalk.symbolFor("todos")],(function(){
+return smalltalk.send(smalltalk.send(html,"_div",[]),"_trap_toggle_ifNotPresent_",[[smalltalk.symbolFor("todos")],(function(){
 return smalltalk.send(snap,"_do_",[(function(){
 smalltalk.send(smalltalk.send(html,"_span",[]),"_trap_",[[smalltalk.symbolFor("remaining")]]);
 smalltalk.send(html,"_with_",[" of "]);
@@ -150,7 +149,7 @@ $1=smalltalk.send(html,"_a",[]);
 smalltalk.send($1,"_href_",[""]);
 smalltalk.send($1,"_onClick_",[(function(){
 return smalltalk.send((function(){
-smalltalk.send(smalltalk.send(snap,"_model",[]),"_modify_do_",[smalltalk.send(smalltalk.send(snap,"_path",[]),"_allButFirst",[]),(function(model){
+smalltalk.send(snap,"_modify_",[(function(model){
 return smalltalk.send(model,"_archive",[]);
 })]);
 return false;
@@ -175,7 +174,7 @@ return $6;
 $7=smalltalk.send(html,"_form",[]);
 smalltalk.send($7,"_onSubmit_",[(function(){
 return smalltalk.send((function(){
-smalltalk.send(smalltalk.send(snap,"_model",[]),"_modify_do_",[smalltalk.send(smalltalk.send(snap,"_path",[]),"_allButFirst",[]),(function(model){
+smalltalk.send(snap,"_modify_",[(function(model){
 return smalltalk.send(model,"_addTodo",[]);
 })]);
 return false;
@@ -199,6 +198,7 @@ return $8;
 }),(function(){
 return smalltalk.send(html,"_with_",["Loading ..."]);
 })]);
+})]);
 return self}
 }),
 smalltalk.AppView);

+ 8 - 8
js/Trapped-Demo.js

@@ -191,10 +191,9 @@ category: 'rendering',
 fn: function (html){
 var self=this;
 var $1,$2,$3,$4,$5,$6,$7,$9,$10,$11,$12,$8;
-var snap;
+smalltalk.send([],"_trapDescend_",[(function(snap){
 smalltalk.send(smalltalk.send(html,"_h2",[]),"_trap_",[[smalltalk.symbolFor("title")]]);
-snap=smalltalk.send(smalltalk.send((smalltalk.Trapped || Trapped),"_current",[]),"_snapshot",[]);
-smalltalk.send(smalltalk.send(html,"_div",[]),"_trap_toggle_ifNotPresent_",[[smalltalk.symbolFor("todos")],(function(){
+return smalltalk.send(smalltalk.send(html,"_div",[]),"_trap_toggle_ifNotPresent_",[[smalltalk.symbolFor("todos")],(function(){
 return smalltalk.send(snap,"_do_",[(function(){
 smalltalk.send(smalltalk.send(html,"_span",[]),"_trap_",[[smalltalk.symbolFor("remaining")]]);
 smalltalk.send(html,"_with_",[" of "]);
@@ -204,7 +203,7 @@ $1=smalltalk.send(html,"_a",[]);
 smalltalk.send($1,"_href_",[""]);
 smalltalk.send($1,"_onClick_",[(function(){
 return smalltalk.send((function(){
-smalltalk.send(smalltalk.send(snap,"_model",[]),"_modify_do_",[smalltalk.send(smalltalk.send(snap,"_path",[]),"_allButFirst",[]),(function(model){
+smalltalk.send(snap,"_modify_",[(function(model){
 return smalltalk.send(model,"_archive",[]);
 })]);
 return false;
@@ -229,7 +228,7 @@ return $6;
 $7=smalltalk.send(html,"_form",[]);
 smalltalk.send($7,"_onSubmit_",[(function(){
 return smalltalk.send((function(){
-smalltalk.send(smalltalk.send(snap,"_model",[]),"_modify_do_",[smalltalk.send(smalltalk.send(snap,"_path",[]),"_allButFirst",[]),(function(model){
+smalltalk.send(snap,"_modify_",[(function(model){
 return smalltalk.send(model,"_addTodo",[]);
 })]);
 return false;
@@ -253,11 +252,12 @@ return $8;
 }),(function(){
 return smalltalk.send(html,"_with_",["Loading ..."]);
 })]);
+})]);
 return self},
 args: ["html"],
-source: "renderOn: html\x0a    | snap |\x0a\x09html h2 trap: #(#title).\x0a    snap := Trapped current snapshot.\x0a    html div trap: #(#todos) toggle: [ snap do: [\x0a        html span trap:#(#remaining).\x0a        html with: ' of '.\x0a        html span trap: #(#todos #size).\x0a        html with: ' remaining [ '.\x0a        html a href:''; onClick: [[\x0a            snap model modify: snap path allButFirst do: [ :model | model archive ].\x0a            false\x0a        ] value \x22amber GH-314 workaround\x22]; with: 'archive'.\x0a        html with: ' ]'.\x0a        html ul trapIter: #(#todos) tag: #li do: [ :each |\x0a            html root empty.\x0a            html input type: 'checkbox'; trap: #('done').\x0a            html span trap: #('done') read: [ :model | html root class: 'done-', model ]; trap: #('text').\x0a        ].\x0a        html form onSubmit: [[\x0a            snap model modify: snap path allButFirst do: [ :model | model addTodo ].\x0a            false\x0a        ] value \x22amber GH-314 workaround\x22]; with: [\x0a            html input type: 'text'; trap: #(#todoText); at: 'size' put: 30; placeholder: 'add new todo here'.\x0a            html input class: 'btn-primary'; type: 'submit'; value: 'add'.\x0a        ].\x0a    ]] ifNotPresent: [ html with: 'Loading ...' ]",
-messageSends: ["trap:", "h2", "snapshot", "current", "trap:toggle:ifNotPresent:", "do:", "span", "with:", "href:", "a", "onClick:", "value", "modify:do:", "allButFirst", "path", "archive", "model", "trapIter:tag:do:", "empty", "root", "type:", "input", "trap:read:", "class:", ",", "ul", "onSubmit:", "addTodo", "form", "at:put:", "placeholder:", "value:", "div"],
-referencedClasses: ["Trapped"]
+source: "renderOn: html\x0a    #() trapDescend: [ :snap |\x0a\x09html h2 trap: #(#title).\x0a    html div trap: #(#todos) toggle: [ snap do: [\x0a        html span trap:#(#remaining).\x0a        html with: ' of '.\x0a        html span trap: #(#todos #size).\x0a        html with: ' remaining [ '.\x0a        html a href:''; onClick: [[\x0a            snap modify: [ :model | model archive ].\x0a            false\x0a        ] value \x22amber GH-314 workaround\x22]; with: 'archive'.\x0a        html with: ' ]'.\x0a        html ul trapIter: #(#todos) tag: #li do: [ :each |\x0a            html root empty.\x0a            html input type: 'checkbox'; trap: #('done').\x0a            html span trap: #('done') read: [ :model | html root class: 'done-', model ]; trap: #('text').\x0a        ].\x0a        html form onSubmit: [[\x0a            snap modify: [ :model | model addTodo ].\x0a            false\x0a        ] value \x22amber GH-314 workaround\x22]; with: [\x0a            html input type: 'text'; trap: #(#todoText); at: 'size' put: 30; placeholder: 'add new todo here'.\x0a            html input class: 'btn-primary'; type: 'submit'; value: 'add'.\x0a        ].\x0a    ]] ifNotPresent: [ html with: 'Loading ...' ]]",
+messageSends: ["trapDescend:", "trap:", "h2", "trap:toggle:ifNotPresent:", "do:", "span", "with:", "href:", "a", "onClick:", "value", "modify:", "archive", "trapIter:tag:do:", "empty", "root", "type:", "input", "trap:read:", "class:", ",", "ul", "onSubmit:", "addTodo", "form", "at:put:", "placeholder:", "value:", "div"],
+referencedClasses: []
 }),
 smalltalk.AppView);
 

+ 37 - 28
js/Trapped-Frontend.deploy.js

@@ -78,12 +78,9 @@ selector: "installFor:",
 fn: function (path){
 var self=this;
 smalltalk.send(self,"_installFor_",[path],smalltalk.TrappedBinder);
-smalltalk.send(path,"_trapDescend_",[(function(){
-var snap;
-snap=smalltalk.send(smalltalk.send((smalltalk.Trapped || Trapped),"_current",[]),"_snapshot",[]);
-snap;
+smalltalk.send(path,"_trapDescend_",[(function(snap){
 return smalltalk.send(self["@brush"],"_onChange_",[(function(){
-return smalltalk.send(smalltalk.send(snap,"_model",[]),"_modify_do_",[smalltalk.send(smalltalk.send(snap,"_path",[]),"_allButFirst",[]),(function(){
+return smalltalk.send(snap,"_modify_",[(function(){
 return smalltalk.send(smalltalk.send(smalltalk.send(self["@brush"],"_asJQuery",[]),"_attr_",["checked"]),"_notNil",[]);
 })]);
 })]);
@@ -403,6 +400,27 @@ return $1;
 }),
 smalltalk.Trapped);
 
+smalltalk.addMethod(
+"_descend_snapshotDo_",
+smalltalk.method({
+selector: "descend:snapshotDo:",
+fn: function (anArray,aBlock){
+var self=this;
+var tpsc;
+tpsc=smalltalk.send((smalltalk.TrappedPathStack || TrappedPathStack),"_current",[]);
+smalltalk.send(tpsc,"_append_do_",[anArray,(function(){
+var path;
+var model;
+path=smalltalk.send(smalltalk.send(tpsc,"_elements",[]),"_copy",[]);
+path;
+model=smalltalk.send(self,"_byName_",[smalltalk.send(path,"_first",[])]);
+model;
+return smalltalk.send(aBlock,"_value_",[smalltalk.send(smalltalk.send((smalltalk.TrappedSnapshot || TrappedSnapshot),"_new",[]),"_path_model_",[path,model])]);
+})]);
+return self}
+}),
+smalltalk.Trapped);
+
 smalltalk.addMethod(
 "_initialize",
 smalltalk.method({
@@ -426,23 +444,6 @@ return self}
 }),
 smalltalk.Trapped);
 
-smalltalk.addMethod(
-"_snapshot",
-smalltalk.method({
-selector: "snapshot",
-fn: function (){
-var self=this;
-var $1;
-var path;
-var model;
-path=smalltalk.send(smalltalk.send((smalltalk.TrappedPathStack || TrappedPathStack),"_current",[]),"_elements",[]);
-model=smalltalk.send(self,"_byName_",[smalltalk.send(path,"_first",[])]);
-$1=smalltalk.send(smalltalk.send((smalltalk.TrappedSnapshot || TrappedSnapshot),"_new",[]),"_path_model_",[path,model]);
-return $1;
-}
-}),
-smalltalk.Trapped);
-
 smalltalk.addMethod(
 "_start",
 smalltalk.method({
@@ -598,6 +599,17 @@ return self["@model"];
 }),
 smalltalk.TrappedSnapshot);
 
+smalltalk.addMethod(
+"_modify_",
+smalltalk.method({
+selector: "modify:",
+fn: function (aBlock){
+var self=this;
+smalltalk.send(smalltalk.send(self,"_model",[]),"_modify_do_",[smalltalk.send(smalltalk.send(self,"_path",[]),"_allButFirst",[]),aBlock]);
+return self}
+}),
+smalltalk.TrappedSnapshot);
+
 smalltalk.addMethod(
 "_path",
 smalltalk.method({
@@ -647,7 +659,7 @@ smalltalk.method({
 selector: "trapDescend:",
 fn: function (aBlock){
 var self=this;
-smalltalk.send(smalltalk.send((smalltalk.TrappedPathStack || TrappedPathStack),"_current",[]),"_append_do_",[self,aBlock]);
+smalltalk.send(smalltalk.send((smalltalk.Trapped || Trapped),"_current",[]),"_descend_snapshotDo_",[self,aBlock]);
 return self}
 }),
 smalltalk.Array);
@@ -658,7 +670,7 @@ smalltalk.method({
 selector: "trapDescend:",
 fn: function (aBlock){
 var self=this;
-smalltalk.send(smalltalk.send((smalltalk.TrappedPathStack || TrappedPathStack),"_current",[]),"_append_do_",[self,aBlock]);
+smalltalk.send(smalltalk.send((smalltalk.Trapped || Trapped),"_current",[]),"_descend_snapshotDo_",[self,aBlock]);
 return self}
 }),
 smalltalk.Array);
@@ -681,10 +693,7 @@ selector: "trap:read:",
 fn: function (path,aBlock){
 var self=this;
 var $1;
-smalltalk.send(path,"_trapDescend_",[(function(){
-var snap;
-snap=smalltalk.send(smalltalk.send((smalltalk.Trapped || Trapped),"_current",[]),"_snapshot",[]);
-snap;
+smalltalk.send(path,"_trapDescend_",[(function(snap){
 return smalltalk.send(smalltalk.send(snap,"_model",[]),"_watch_do_",[smalltalk.send(smalltalk.send(snap,"_path",[]),"_allButFirst",[]),(function(data){
 $1=smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(self,"_asJQuery",[]),"_closest_",["html"]),"_toArray",[]),"_isEmpty",[]);
 if(smalltalk.assert($1)){

+ 59 - 45
js/Trapped-Frontend.js

@@ -104,21 +104,18 @@ category: 'action',
 fn: function (path){
 var self=this;
 smalltalk.send(self,"_installFor_",[path],smalltalk.TrappedBinder);
-smalltalk.send(path,"_trapDescend_",[(function(){
-var snap;
-snap=smalltalk.send(smalltalk.send((smalltalk.Trapped || Trapped),"_current",[]),"_snapshot",[]);
-snap;
+smalltalk.send(path,"_trapDescend_",[(function(snap){
 return smalltalk.send(self["@brush"],"_onChange_",[(function(){
-return smalltalk.send(smalltalk.send(snap,"_model",[]),"_modify_do_",[smalltalk.send(smalltalk.send(snap,"_path",[]),"_allButFirst",[]),(function(){
+return smalltalk.send(snap,"_modify_",[(function(){
 return smalltalk.send(smalltalk.send(smalltalk.send(self["@brush"],"_asJQuery",[]),"_attr_",["checked"]),"_notNil",[]);
 })]);
 })]);
 })]);
 return self},
 args: ["path"],
-source: "installFor: path\x0a\x09super installFor: path.\x0a    path trapDescend: [ | snap |\x0a        snap := Trapped current snapshot.\x0a\x09    brush onChange: [ snap model modify: snap path allButFirst do: [\x0a            (brush asJQuery attr: 'checked') notNil\x0a        ]]\x0a    ]",
-messageSends: ["installFor:", "trapDescend:", "snapshot", "current", "onChange:", "modify:do:", "allButFirst", "path", "notNil", "attr:", "asJQuery", "model"],
-referencedClasses: ["Trapped"]
+source: "installFor: path\x0a\x09super installFor: path.\x0a    path trapDescend: [ :snap |\x0a\x09    brush onChange: [ snap modify: [\x0a            (brush asJQuery attr: 'checked') notNil\x0a        ]]\x0a    ]",
+messageSends: ["installFor:", "trapDescend:", "onChange:", "modify:", "notNil", "attr:", "asJQuery"],
+referencedClasses: []
 }),
 smalltalk.TrappedAttrBinder);
 
@@ -538,6 +535,32 @@ referencedClasses: []
 }),
 smalltalk.Trapped);
 
+smalltalk.addMethod(
+"_descend_snapshotDo_",
+smalltalk.method({
+selector: "descend:snapshotDo:",
+category: 'action',
+fn: function (anArray,aBlock){
+var self=this;
+var tpsc;
+tpsc=smalltalk.send((smalltalk.TrappedPathStack || TrappedPathStack),"_current",[]);
+smalltalk.send(tpsc,"_append_do_",[anArray,(function(){
+var path;
+var model;
+path=smalltalk.send(smalltalk.send(tpsc,"_elements",[]),"_copy",[]);
+path;
+model=smalltalk.send(self,"_byName_",[smalltalk.send(path,"_first",[])]);
+model;
+return smalltalk.send(aBlock,"_value_",[smalltalk.send(smalltalk.send((smalltalk.TrappedSnapshot || TrappedSnapshot),"_new",[]),"_path_model_",[path,model])]);
+})]);
+return self},
+args: ["anArray", "aBlock"],
+source: "descend: anArray snapshotDo: aBlock\x0a\x09| tpsc |\x0a    tpsc := TrappedPathStack current.\x0a    tpsc append: anArray do: [\x0a        | path model |\x0a        path := tpsc elements copy.\x0a   \x09    model := self byName: path first.\x0a        aBlock value: (TrappedSnapshot new path: path model: model)\x0a    ]",
+messageSends: ["current", "append:do:", "copy", "elements", "byName:", "first", "value:", "path:model:", "new"],
+referencedClasses: ["TrappedPathStack", "TrappedSnapshot"]
+}),
+smalltalk.Trapped);
+
 smalltalk.addMethod(
 "_initialize",
 smalltalk.method({
@@ -571,28 +594,6 @@ referencedClasses: []
 }),
 smalltalk.Trapped);
 
-smalltalk.addMethod(
-"_snapshot",
-smalltalk.method({
-selector: "snapshot",
-category: 'snapshotting',
-fn: function (){
-var self=this;
-var $1;
-var path;
-var model;
-path=smalltalk.send(smalltalk.send((smalltalk.TrappedPathStack || TrappedPathStack),"_current",[]),"_elements",[]);
-model=smalltalk.send(self,"_byName_",[smalltalk.send(path,"_first",[])]);
-$1=smalltalk.send(smalltalk.send((smalltalk.TrappedSnapshot || TrappedSnapshot),"_new",[]),"_path_model_",[path,model]);
-return $1;
-},
-args: [],
-source: "snapshot\x0a\x09| path model |\x0a    path := TrappedPathStack current elements.\x0a   \x09model := self byName: path first.\x0a    ^TrappedSnapshot new path: path model: model",
-messageSends: ["elements", "current", "byName:", "first", "path:model:", "new"],
-referencedClasses: ["TrappedPathStack", "TrappedSnapshot"]
-}),
-smalltalk.Trapped);
-
 smalltalk.addMethod(
 "_start",
 smalltalk.method({
@@ -788,6 +789,22 @@ referencedClasses: []
 }),
 smalltalk.TrappedSnapshot);
 
+smalltalk.addMethod(
+"_modify_",
+smalltalk.method({
+selector: "modify:",
+category: 'action',
+fn: function (aBlock){
+var self=this;
+smalltalk.send(smalltalk.send(self,"_model",[]),"_modify_do_",[smalltalk.send(smalltalk.send(self,"_path",[]),"_allButFirst",[]),aBlock]);
+return self},
+args: ["aBlock"],
+source: "modify: aBlock\x0a\x09self model modify: self path allButFirst do: aBlock",
+messageSends: ["modify:do:", "allButFirst", "path", "model"],
+referencedClasses: []
+}),
+smalltalk.TrappedSnapshot);
+
 smalltalk.addMethod(
 "_path",
 smalltalk.method({
@@ -853,12 +870,12 @@ selector: "trapDescend:",
 category: '*Trapped-Frontend',
 fn: function (aBlock){
 var self=this;
-smalltalk.send(smalltalk.send((smalltalk.TrappedPathStack || TrappedPathStack),"_current",[]),"_append_do_",[self,aBlock]);
+smalltalk.send(smalltalk.send((smalltalk.Trapped || Trapped),"_current",[]),"_descend_snapshotDo_",[self,aBlock]);
 return self},
 args: ["aBlock"],
-source: "trapDescend: aBlock\x0a\x09TrappedPathStack current append: self do: aBlock",
-messageSends: ["append:do:", "current"],
-referencedClasses: ["TrappedPathStack"]
+source: "trapDescend: aBlock\x0a\x09Trapped current descend: self snapshotDo: aBlock",
+messageSends: ["descend:snapshotDo:", "current"],
+referencedClasses: ["Trapped"]
 }),
 smalltalk.Array);
 
@@ -869,12 +886,12 @@ selector: "trapDescend:",
 category: '*Trapped-Frontend',
 fn: function (aBlock){
 var self=this;
-smalltalk.send(smalltalk.send((smalltalk.TrappedPathStack || TrappedPathStack),"_current",[]),"_append_do_",[self,aBlock]);
+smalltalk.send(smalltalk.send((smalltalk.Trapped || Trapped),"_current",[]),"_descend_snapshotDo_",[self,aBlock]);
 return self},
 args: ["aBlock"],
-source: "trapDescend: aBlock\x0a\x09TrappedPathStack current append: self do: aBlock",
-messageSends: ["append:do:", "current"],
-referencedClasses: ["TrappedPathStack"]
+source: "trapDescend: aBlock\x0a\x09Trapped current descend: self snapshotDo: aBlock",
+messageSends: ["descend:snapshotDo:", "current"],
+referencedClasses: ["Trapped"]
 }),
 smalltalk.Array);
 
@@ -902,10 +919,7 @@ category: '*Trapped-Frontend',
 fn: function (path,aBlock){
 var self=this;
 var $1;
-smalltalk.send(path,"_trapDescend_",[(function(){
-var snap;
-snap=smalltalk.send(smalltalk.send((smalltalk.Trapped || Trapped),"_current",[]),"_snapshot",[]);
-snap;
+smalltalk.send(path,"_trapDescend_",[(function(snap){
 return smalltalk.send(smalltalk.send(snap,"_model",[]),"_watch_do_",[smalltalk.send(smalltalk.send(snap,"_path",[]),"_allButFirst",[]),(function(data){
 $1=smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(self,"_asJQuery",[]),"_closest_",["html"]),"_toArray",[]),"_isEmpty",[]);
 if(smalltalk.assert($1)){
@@ -920,9 +934,9 @@ return smalltalk.send(aBlock,"_value_value_",[data,html]);
 })]);
 return self},
 args: ["path", "aBlock"],
-source: "trap: path read: aBlock\x0a\x09path trapDescend: [ | snap |\x0a        snap := Trapped current snapshot.\x0a        snap model watch: snap path allButFirst do: [ :data |\x0a            (self asJQuery closest: 'html') toArray isEmpty ifTrue: [ KeyedPubSubUnsubscribe signal ].\x0a        \x09snap do: [ self with: [ :html | aBlock value: data value: html ] ]\x0a    \x09]\x0a    ]",
-messageSends: ["trapDescend:", "snapshot", "current", "watch:do:", "allButFirst", "path", "ifTrue:", "signal", "isEmpty", "toArray", "closest:", "asJQuery", "do:", "with:", "value:value:", "model"],
-referencedClasses: ["Trapped", "KeyedPubSubUnsubscribe"]
+source: "trap: path read: aBlock\x0a\x09path trapDescend: [ :snap |\x0a        snap model watch: snap path allButFirst do: [ :data |\x0a            (self asJQuery closest: 'html') toArray isEmpty ifTrue: [ KeyedPubSubUnsubscribe signal ].\x0a        \x09snap do: [ self with: [ :html | aBlock value: data value: html ] ]\x0a    \x09]\x0a    ]",
+messageSends: ["trapDescend:", "watch:do:", "allButFirst", "path", "ifTrue:", "signal", "isEmpty", "toArray", "closest:", "asJQuery", "do:", "with:", "value:value:", "model"],
+referencedClasses: ["KeyedPubSubUnsubscribe"]
 }),
 smalltalk.TagBrush);
 

+ 4 - 5
st/Trapped-Demo.st

@@ -143,16 +143,15 @@ Widget subclass: #AppView
 !AppView methodsFor: 'rendering'!
 
 renderOn: html
-    | snap |
+    #() trapDescend: [ :snap |
 	html h2 trap: #(#title).
-    snap := Trapped current snapshot.
     html div trap: #(#todos) toggle: [ snap do: [
         html span trap:#(#remaining).
         html with: ' of '.
         html span trap: #(#todos #size).
         html with: ' remaining [ '.
         html a href:''; onClick: [[
-            snap model modify: snap path allButFirst do: [ :model | model archive ].
+            snap modify: [ :model | model archive ].
             false
         ] value "amber GH-314 workaround"]; with: 'archive'.
         html with: ' ]'.
@@ -162,13 +161,13 @@ renderOn: html
             html span trap: #('done') read: [ :model | html root class: 'done-', model ]; trap: #('text').
         ].
         html form onSubmit: [[
-            snap model modify: snap path allButFirst do: [ :model | model addTodo ].
+            snap modify: [ :model | model addTodo ].
             false
         ] value "amber GH-314 workaround"]; with: [
             html input type: 'text'; trap: #(#todoText); at: 'size' put: 30; placeholder: 'add new todo here'.
             html input class: 'btn-primary'; type: 'submit'; value: 'add'.
         ].
-    ]] ifNotPresent: [ html with: 'Loading ...' ]
+    ]] ifNotPresent: [ html with: 'Loading ...' ]]
 ! !
 
 TrappedDispatcher subclass: #TrappedDumbDispatcher

+ 20 - 16
st/Trapped-Frontend.st

@@ -39,9 +39,8 @@ attr: aString
 
 installFor: path
 	super installFor: path.
-    path trapDescend: [ | snap |
-        snap := Trapped current snapshot.
-	    brush onChange: [ snap model modify: snap path allButFirst do: [
+    path trapDescend: [ :snap |
+	    brush onChange: [ snap modify: [
             (brush asJQuery attr: 'checked') notNil
         ]]
     ]
@@ -223,6 +222,17 @@ register: aFly name: aString
 
 !Trapped methodsFor: 'action'!
 
+descend: anArray snapshotDo: aBlock
+	| tpsc |
+    tpsc := TrappedPathStack current.
+    tpsc append: anArray do: [
+        | path model |
+        path := tpsc elements copy.
+   	    model := self byName: path first.
+        aBlock value: (TrappedSnapshot new path: path model: model)
+    ]
+!
+
 start
 	'[data-trap]' asJQuery each: [ :index :elem |
     	| trap jq viewName modelName tokens path |
@@ -258,15 +268,6 @@ initialize
 	registry := #{}.
 ! !
 
-!Trapped methodsFor: 'snapshotting'!
-
-snapshot
-	| path model |
-    path := TrappedPathStack current elements.
-   	model := self byName: path first.
-    ^TrappedSnapshot new path: path model: model
-! !
-
 !Trapped class methodsFor: 'accessing'!
 
 parse: anArray
@@ -330,6 +331,10 @@ path: anArray model: aTrappedMW
 
 do: aBlock
 	TrappedPathStack current with: path do: [ aBlock value: model ]
+!
+
+modify: aBlock
+	self model modify: self path allButFirst do: aBlock
 ! !
 
 KeyedSubscriptionBase subclass: #TrappedSubscription
@@ -345,13 +350,13 @@ accepts: aKey
 !Array methodsFor: '*Trapped-Frontend'!
 
 trapDescend: aBlock
-	TrappedPathStack current append: self do: aBlock
+	Trapped current descend: self snapshotDo: aBlock
 ! !
 
 !Array methodsFor: '*Trapped-Frontend'!
 
 trapDescend: aBlock
-	TrappedPathStack current append: self do: aBlock
+	Trapped current descend: self snapshotDo: aBlock
 ! !
 
 !TagBrush methodsFor: '*Trapped-Frontend'!
@@ -361,8 +366,7 @@ trap: path
 !
 
 trap: path read: aBlock
-	path trapDescend: [ | snap |
-        snap := Trapped current snapshot.
+	path trapDescend: [ :snap |
         snap model watch: snap path allButFirst do: [ :data |
             (self asJQuery closest: 'html') toArray isEmpty ifTrue: [ KeyedPubSubUnsubscribe signal ].
         	snap do: [ self with: [ :html | aBlock value: data value: html ] ]