Browse Source

Trapped-Common package, TrappedDispatcher introduced.

Herbert Vojčík 12 years ago
parent
commit
cd604627d5
7 changed files with 556 additions and 175 deletions
  1. 1 1
      demo.html
  2. 151 0
      js/Trapped-Common.deploy.js
  3. 203 0
      js/Trapped-Common.js
  4. 31 56
      js/Trapped-Frontend.deploy.js
  5. 52 87
      js/Trapped-Frontend.js
  6. 92 0
      st/Trapped-Common.st
  7. 26 31
      st/Trapped-Frontend.st

+ 1 - 1
demo.html

@@ -6,7 +6,7 @@
 <body>
 <script type="text/javascript">
     loadAmber({
-        files:['Trapped-Frontend.js', 'Trapped-Demo.js'],
+        packages:['Trapped-Common', 'Trapped-Frontend', 'Trapped-Demo'],
         packageHome:'./',
         ready:function () {
             $(function() {

+ 151 - 0
js/Trapped-Common.deploy.js

@@ -0,0 +1,151 @@
+smalltalk.addPackage('Trapped-Common', {});
+smalltalk.addClass('TrappedDispatcher', smalltalk.Object, [], 'Trapped-Common');
+smalltalk.addMethod(
+"_changed_",
+smalltalk.method({
+selector: "changed:",
+fn: function (path){
+var self=this;
+var $1;
+var needsToRun;
+needsToRun=false;
+smalltalk.send(self,"_do_",[(function(each){
+var aPath;
+var lesser;
+aPath=smalltalk.send(each,"_second",[]);
+aPath;
+lesser=smalltalk.send(smalltalk.send(aPath,"_size",[]),"_min_",[smalltalk.send(path,"_size",[])]);
+lesser;
+$1=smalltalk.send(smalltalk.send(path,"_copyFrom_to_",[(1),lesser]),"__eq",[smalltalk.send(aPath,"_copyFrom_to_",[(1),lesser])]);
+if(smalltalk.assert($1)){
+smalltalk.send(each,"_at_put_",[(1),true]);
+needsToRun=true;
+return needsToRun;
+};
+})]);
+return needsToRun;
+}
+}),
+smalltalk.TrappedDispatcher);
+
+smalltalk.addMethod(
+"_run",
+smalltalk.method({
+selector: "run",
+fn: function (){
+var self=this;
+var $1;
+smalltalk.send(self,"_do_",[(function(each){
+$1=smalltalk.send(each,"_first",[]);
+if(smalltalk.assert($1)){
+return smalltalk.send((function(){
+return smalltalk.send(smalltalk.send(each,"_third",[]),"_value",[]);
+}),"_ensure_",[(function(){
+return smalltalk.send(each,"_at_put_",[(1),false]);
+})]);
+};
+})]);
+return self}
+}),
+smalltalk.TrappedDispatcher);
+
+
+
+smalltalk.addClass('TrappedModelWrapper', smalltalk.Object, ['dispatcher', 'payload'], 'Trapped-Common');
+smalltalk.addMethod(
+"_dispatcher",
+smalltalk.method({
+selector: "dispatcher",
+fn: function (){
+var self=this;
+return self["@dispatcher"];
+}
+}),
+smalltalk.TrappedModelWrapper);
+
+smalltalk.addMethod(
+"_dispatcher_",
+smalltalk.method({
+selector: "dispatcher:",
+fn: function (aDispatcher){
+var self=this;
+self["@dispatcher"]=aDispatcher;
+return self}
+}),
+smalltalk.TrappedModelWrapper);
+
+smalltalk.addMethod(
+"_name",
+smalltalk.method({
+selector: "name",
+fn: function (){
+var self=this;
+var $1;
+$1=smalltalk.send(smalltalk.send(self,"_class",[]),"_name",[]);
+return $1;
+}
+}),
+smalltalk.TrappedModelWrapper);
+
+smalltalk.addMethod(
+"_payload",
+smalltalk.method({
+selector: "payload",
+fn: function (){
+var self=this;
+return self["@payload"];
+}
+}),
+smalltalk.TrappedModelWrapper);
+
+smalltalk.addMethod(
+"_payload_",
+smalltalk.method({
+selector: "payload:",
+fn: function (anObject){
+var self=this;
+self["@payload"]=anObject;
+return self}
+}),
+smalltalk.TrappedModelWrapper);
+
+smalltalk.addMethod(
+"_start",
+smalltalk.method({
+selector: "start",
+fn: function (){
+var self=this;
+smalltalk.send(smalltalk.send((smalltalk.Trapped || Trapped),"_current",[]),"_register_name_",[self,smalltalk.send(self,"_name",[])]);
+return self}
+}),
+smalltalk.TrappedModelWrapper);
+
+smalltalk.addMethod(
+"_watch_do_",
+smalltalk.method({
+selector: "watch:do:",
+fn: function (path,aBlock){
+var self=this;
+smalltalk.send(smalltalk.send(self,"_dispatcher",[]),"_add_",[[true,path,(function(){
+return smalltalk.send(self,"_read_do_",[path,aBlock]);
+})]]);
+smalltalk.send((function(){
+return smalltalk.send(smalltalk.send(self,"_dispatcher",[]),"_run",[]);
+}),"_fork",[]);
+return self}
+}),
+smalltalk.TrappedModelWrapper);
+
+
+smalltalk.addMethod(
+"_start",
+smalltalk.method({
+selector: "start",
+fn: function (){
+var self=this;
+smalltalk.send(smalltalk.send(self,"_new",[]),"_start",[]);
+return self}
+}),
+smalltalk.TrappedModelWrapper.klass);
+
+

+ 203 - 0
js/Trapped-Common.js

@@ -0,0 +1,203 @@
+smalltalk.addPackage('Trapped-Common', {});
+smalltalk.addClass('TrappedDispatcher', smalltalk.Object, [], 'Trapped-Common');
+smalltalk.TrappedDispatcher.comment="I am base class for change event dispatchers.\x0aI manage changed path - action block subscriptions.\x0aThese subscription must be three-element arrays\x0a\x09{ dirty. path. block }\x0a\x0aMy subclasses need to provide implementation for:\x0a\x09add:\x0a    do:\x0a    (optionally) run\x0a"
+smalltalk.addMethod(
+"_changed_",
+smalltalk.method({
+selector: "changed:",
+category: 'action',
+fn: function (path){
+var self=this;
+var $1;
+var needsToRun;
+needsToRun=false;
+smalltalk.send(self,"_do_",[(function(each){
+var aPath;
+var lesser;
+aPath=smalltalk.send(each,"_second",[]);
+aPath;
+lesser=smalltalk.send(smalltalk.send(aPath,"_size",[]),"_min_",[smalltalk.send(path,"_size",[])]);
+lesser;
+$1=smalltalk.send(smalltalk.send(path,"_copyFrom_to_",[(1),lesser]),"__eq",[smalltalk.send(aPath,"_copyFrom_to_",[(1),lesser])]);
+if(smalltalk.assert($1)){
+smalltalk.send(each,"_at_put_",[(1),true]);
+needsToRun=true;
+return needsToRun;
+};
+})]);
+return needsToRun;
+},
+args: ["path"],
+source: "changed: path\x0a\x09| needsToRun |\x0a    needsToRun := false.\x0a\x09self do: [ :each |\x0a\x09\x09| aPath lesser |\x0a\x09\x09aPath := each second.\x0a\x09\x09lesser := aPath size min: path size.\x0a\x09\x09(path copyFrom: 1 to: lesser) = (aPath copyFrom: 1 to: lesser) ifTrue: [\x0a\x09\x09\x09each at: 1 put: true.\x0a            needsToRun := true.\x0a\x09\x09]\x0a\x09].\x0a\x09^needsToRun",
+messageSends: ["do:", "second", "min:", "size", "ifTrue:", "at:put:", "=", "copyFrom:to:"],
+referencedClasses: []
+}),
+smalltalk.TrappedDispatcher);
+
+smalltalk.addMethod(
+"_run",
+smalltalk.method({
+selector: "run",
+category: 'action',
+fn: function (){
+var self=this;
+var $1;
+smalltalk.send(self,"_do_",[(function(each){
+$1=smalltalk.send(each,"_first",[]);
+if(smalltalk.assert($1)){
+return smalltalk.send((function(){
+return smalltalk.send(smalltalk.send(each,"_third",[]),"_value",[]);
+}),"_ensure_",[(function(){
+return smalltalk.send(each,"_at_put_",[(1),false]);
+})]);
+};
+})]);
+return self},
+args: [],
+source: "run\x0a\x09self do: [ :each |\x0a\x09\x09each first ifTrue: [[ each third value ] ensure: [ each at: 1 put: false ]]\x0a\x09]",
+messageSends: ["do:", "ifTrue:", "ensure:", "at:put:", "value", "third", "first"],
+referencedClasses: []
+}),
+smalltalk.TrappedDispatcher);
+
+
+
+smalltalk.addClass('TrappedModelWrapper', smalltalk.Object, ['dispatcher', 'payload'], 'Trapped-Common');
+smalltalk.TrappedModelWrapper.comment="I am base class for model wrappers.\x0aI wrap a model which can be any object.\x0a\x0aMy subclasses need to provide implementation for:\x0a\x09read:do:\x0a\x09(optionally) name\x0a\x0aand must initialize:\x0a\x09payload\x0a\x09dispatcher\x0a"
+smalltalk.addMethod(
+"_dispatcher",
+smalltalk.method({
+selector: "dispatcher",
+category: 'accessing',
+fn: function (){
+var self=this;
+return self["@dispatcher"];
+},
+args: [],
+source: "dispatcher\x0a\x09^dispatcher",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.TrappedModelWrapper);
+
+smalltalk.addMethod(
+"_dispatcher_",
+smalltalk.method({
+selector: "dispatcher:",
+category: 'accessing',
+fn: function (aDispatcher){
+var self=this;
+self["@dispatcher"]=aDispatcher;
+return self},
+args: ["aDispatcher"],
+source: "dispatcher: aDispatcher\x0a\x09dispatcher := aDispatcher",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.TrappedModelWrapper);
+
+smalltalk.addMethod(
+"_name",
+smalltalk.method({
+selector: "name",
+category: 'accessing',
+fn: function (){
+var self=this;
+var $1;
+$1=smalltalk.send(smalltalk.send(self,"_class",[]),"_name",[]);
+return $1;
+},
+args: [],
+source: "name\x0a\x09^ self class name",
+messageSends: ["name", "class"],
+referencedClasses: []
+}),
+smalltalk.TrappedModelWrapper);
+
+smalltalk.addMethod(
+"_payload",
+smalltalk.method({
+selector: "payload",
+category: 'accessing',
+fn: function (){
+var self=this;
+return self["@payload"];
+},
+args: [],
+source: "payload\x0a\x09^payload",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.TrappedModelWrapper);
+
+smalltalk.addMethod(
+"_payload_",
+smalltalk.method({
+selector: "payload:",
+category: 'accessing',
+fn: function (anObject){
+var self=this;
+self["@payload"]=anObject;
+return self},
+args: ["anObject"],
+source: "payload: anObject\x0a\x09payload := anObject",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.TrappedModelWrapper);
+
+smalltalk.addMethod(
+"_start",
+smalltalk.method({
+selector: "start",
+category: 'action',
+fn: function (){
+var self=this;
+smalltalk.send(smalltalk.send((smalltalk.Trapped || Trapped),"_current",[]),"_register_name_",[self,smalltalk.send(self,"_name",[])]);
+return self},
+args: [],
+source: "start\x0a\x09Trapped current register: self name: self name",
+messageSends: ["register:name:", "name", "current"],
+referencedClasses: ["Trapped"]
+}),
+smalltalk.TrappedModelWrapper);
+
+smalltalk.addMethod(
+"_watch_do_",
+smalltalk.method({
+selector: "watch:do:",
+category: 'action',
+fn: function (path,aBlock){
+var self=this;
+smalltalk.send(smalltalk.send(self,"_dispatcher",[]),"_add_",[[true,path,(function(){
+return smalltalk.send(self,"_read_do_",[path,aBlock]);
+})]]);
+smalltalk.send((function(){
+return smalltalk.send(smalltalk.send(self,"_dispatcher",[]),"_run",[]);
+}),"_fork",[]);
+return self},
+args: ["path", "aBlock"],
+source: "watch: path do: aBlock\x0a\x09self dispatcher add: { true. path. [ self read: path do: aBlock ] }.\x0a    [ self dispatcher run ] fork",
+messageSends: ["add:", "read:do:", "dispatcher", "fork", "run"],
+referencedClasses: []
+}),
+smalltalk.TrappedModelWrapper);
+
+
+smalltalk.addMethod(
+"_start",
+smalltalk.method({
+selector: "start",
+category: 'action',
+fn: function (){
+var self=this;
+smalltalk.send(smalltalk.send(self,"_new",[]),"_start",[]);
+return self},
+args: [],
+source: "start\x0a\x09self new start",
+messageSends: ["start", "new"],
+referencedClasses: []
+}),
+smalltalk.TrappedModelWrapper.klass);
+
+

+ 31 - 56
js/Trapped-Frontend.deploy.js

@@ -1,79 +1,67 @@
 smalltalk.addPackage('Trapped-Frontend', {});
-smalltalk.addClass('TrappedDumbView', smalltalk.Widget, [], 'Trapped-Frontend');
+smalltalk.addClass('TrappedDumbDispatcher', smalltalk.TrappedDispatcher, ['queue'], 'Trapped-Frontend');
 smalltalk.addMethod(
-"_renderOn_",
+"_add_",
 smalltalk.method({
-selector: "renderOn:",
-fn: function (html){
+selector: "add:",
+fn: function (aTriplet){
 var self=this;
-smalltalk.send(smalltalk.send(html,"_root",[]),"_trapShow_",[[]]);
+smalltalk.send(self["@queue"],"_add_",[aTriplet]);
 return self}
 }),
-smalltalk.TrappedDumbView);
-
+smalltalk.TrappedDumbDispatcher);
 
-
-smalltalk.addClass('TrappedModelWrapper', smalltalk.Object, ['payload'], 'Trapped-Frontend');
 smalltalk.addMethod(
-"_name",
+"_do_",
 smalltalk.method({
-selector: "name",
-fn: function (){
+selector: "do:",
+fn: function (aBlock){
 var self=this;
-var $1;
-$1=smalltalk.send(smalltalk.send(self,"_class",[]),"_name",[]);
-return $1;
-}
+smalltalk.send(self["@queue"],"_do_",[aBlock]);
+return self}
 }),
-smalltalk.TrappedModelWrapper);
+smalltalk.TrappedDumbDispatcher);
 
 smalltalk.addMethod(
-"_payload",
+"_initialize",
 smalltalk.method({
-selector: "payload",
+selector: "initialize",
 fn: function (){
 var self=this;
-return self["@payload"];
-}
-}),
-smalltalk.TrappedModelWrapper);
-
-smalltalk.addMethod(
-"_payload_",
-smalltalk.method({
-selector: "payload:",
-fn: function (anObject){
-var self=this;
-self["@payload"]=anObject;
+self["@queue"]=smalltalk.send((smalltalk.OrderedCollection || OrderedCollection),"_new",[]);
 return self}
 }),
-smalltalk.TrappedModelWrapper);
+smalltalk.TrappedDumbDispatcher);
+
 
+
+smalltalk.addClass('TrappedDumbView', smalltalk.Widget, [], 'Trapped-Frontend');
 smalltalk.addMethod(
-"_start",
+"_renderOn_",
 smalltalk.method({
-selector: "start",
-fn: function (){
+selector: "renderOn:",
+fn: function (html){
 var self=this;
-smalltalk.send(smalltalk.send((smalltalk.Trapped || Trapped),"_current",[]),"_register_name_",[self,smalltalk.send(self,"_name",[])]);
+smalltalk.send(smalltalk.send(html,"_root",[]),"_trapShow_",[[]]);
 return self}
 }),
-smalltalk.TrappedModelWrapper);
+smalltalk.TrappedDumbView);
 
 
+
+smalltalk.addClass('TrappedPlainModel', smalltalk.TrappedModelWrapper, [], 'Trapped-Frontend');
 smalltalk.addMethod(
-"_start",
+"_initialize",
 smalltalk.method({
-selector: "start",
+selector: "initialize",
 fn: function (){
 var self=this;
-smalltalk.send(smalltalk.send(self,"_new",[]),"_start",[]);
+smalltalk.send(self,"_initialize",[],smalltalk.TrappedModelWrapper);
+smalltalk.send(self,"_dispatcher_",[smalltalk.send((smalltalk.TrappedDumbDispatcher || TrappedDumbDispatcher),"_new",[])]);
 return self}
 }),
-smalltalk.TrappedModelWrapper.klass);
-
+smalltalk.TrappedPlainModel);
 
-smalltalk.addClass('TrappedPlainModel', smalltalk.TrappedModelWrapper, [], 'Trapped-Frontend');
 smalltalk.addMethod(
 "_read_do_",
 smalltalk.method({
@@ -89,19 +77,6 @@ return self}
 }),
 smalltalk.TrappedPlainModel);
 
-smalltalk.addMethod(
-"_watch_do_",
-smalltalk.method({
-selector: "watch:do:",
-fn: function (path,aBlock){
-var self=this;
-smalltalk.send((function(){
-return smalltalk.send(self,"_read_do_",[path,aBlock]);
-}),"_fork",[]);
-return self}
-}),
-smalltalk.TrappedPlainModel);
-
 
 smalltalk.addMethod(
 "_start",

+ 52 - 87
js/Trapped-Frontend.js

@@ -1,110 +1,93 @@
 smalltalk.addPackage('Trapped-Frontend', {});
-smalltalk.addClass('TrappedDumbView', smalltalk.Widget, [], 'Trapped-Frontend');
-smalltalk.TrappedDumbView.comment="I just read and show an actual path."
+smalltalk.addClass('TrappedDumbDispatcher', smalltalk.TrappedDispatcher, ['queue'], 'Trapped-Frontend');
 smalltalk.addMethod(
-"_renderOn_",
+"_add_",
 smalltalk.method({
-selector: "renderOn:",
-category: 'rendering',
-fn: function (html){
+selector: "add:",
+category: 'accessing',
+fn: function (aTriplet){
 var self=this;
-smalltalk.send(smalltalk.send(html,"_root",[]),"_trapShow_",[[]]);
+smalltalk.send(self["@queue"],"_add_",[aTriplet]);
 return self},
-args: ["html"],
-source: "renderOn: html\x0a\x09html root trapShow: #()",
-messageSends: ["trapShow:", "root"],
+args: ["aTriplet"],
+source: "add: aTriplet\x0a\x09queue add: aTriplet\x0a\x09",
+messageSends: ["add:"],
 referencedClasses: []
 }),
-smalltalk.TrappedDumbView);
-
-
+smalltalk.TrappedDumbDispatcher);
 
-smalltalk.addClass('TrappedModelWrapper', smalltalk.Object, ['payload'], 'Trapped-Frontend');
 smalltalk.addMethod(
-"_name",
+"_do_",
 smalltalk.method({
-selector: "name",
-category: 'action',
-fn: function (){
+selector: "do:",
+category: 'enumeration',
+fn: function (aBlock){
 var self=this;
-var $1;
-$1=smalltalk.send(smalltalk.send(self,"_class",[]),"_name",[]);
-return $1;
-},
-args: [],
-source: "name\x0a\x09^ self class name",
-messageSends: ["name", "class"],
+smalltalk.send(self["@queue"],"_do_",[aBlock]);
+return self},
+args: ["aBlock"],
+source: "do: aBlock\x0a\x09queue do: aBlock",
+messageSends: ["do:"],
 referencedClasses: []
 }),
-smalltalk.TrappedModelWrapper);
+smalltalk.TrappedDumbDispatcher);
 
 smalltalk.addMethod(
-"_payload",
+"_initialize",
 smalltalk.method({
-selector: "payload",
-category: 'accessing',
+selector: "initialize",
+category: 'initialization',
 fn: function (){
 var self=this;
-return self["@payload"];
-},
+self["@queue"]=smalltalk.send((smalltalk.OrderedCollection || OrderedCollection),"_new",[]);
+return self},
 args: [],
-source: "payload\x0a\x09^payload",
-messageSends: [],
-referencedClasses: []
+source: "initialize\x0a\x09queue := OrderedCollection new",
+messageSends: ["new"],
+referencedClasses: ["OrderedCollection"]
 }),
-smalltalk.TrappedModelWrapper);
+smalltalk.TrappedDumbDispatcher);
+
 
+
+smalltalk.addClass('TrappedDumbView', smalltalk.Widget, [], 'Trapped-Frontend');
+smalltalk.TrappedDumbView.comment="I just read and show an actual path."
 smalltalk.addMethod(
-"_payload_",
+"_renderOn_",
 smalltalk.method({
-selector: "payload:",
-category: 'accessing',
-fn: function (anObject){
+selector: "renderOn:",
+category: 'rendering',
+fn: function (html){
 var self=this;
-self["@payload"]=anObject;
+smalltalk.send(smalltalk.send(html,"_root",[]),"_trapShow_",[[]]);
 return self},
-args: ["anObject"],
-source: "payload: anObject\x0a\x09payload := anObject",
-messageSends: [],
+args: ["html"],
+source: "renderOn: html\x0a\x09html root trapShow: #()",
+messageSends: ["trapShow:", "root"],
 referencedClasses: []
 }),
-smalltalk.TrappedModelWrapper);
+smalltalk.TrappedDumbView);
 
-smalltalk.addMethod(
-"_start",
-smalltalk.method({
-selector: "start",
-category: 'action',
-fn: function (){
-var self=this;
-smalltalk.send(smalltalk.send((smalltalk.Trapped || Trapped),"_current",[]),"_register_name_",[self,smalltalk.send(self,"_name",[])]);
-return self},
-args: [],
-source: "start\x0a\x09Trapped current register: self name: self name",
-messageSends: ["register:name:", "name", "current"],
-referencedClasses: ["Trapped"]
-}),
-smalltalk.TrappedModelWrapper);
 
 
+smalltalk.addClass('TrappedPlainModel', smalltalk.TrappedModelWrapper, [], 'Trapped-Frontend');
 smalltalk.addMethod(
-"_start",
+"_initialize",
 smalltalk.method({
-selector: "start",
-category: 'action',
+selector: "initialize",
+category: 'initialization',
 fn: function (){
 var self=this;
-smalltalk.send(smalltalk.send(self,"_new",[]),"_start",[]);
+smalltalk.send(self,"_initialize",[],smalltalk.TrappedModelWrapper);
+smalltalk.send(self,"_dispatcher_",[smalltalk.send((smalltalk.TrappedDumbDispatcher || TrappedDumbDispatcher),"_new",[])]);
 return self},
 args: [],
-source: "start\x0a\x09self new start",
-messageSends: ["start", "new"],
-referencedClasses: []
+source: "initialize\x0a\x09super initialize.\x0a    self dispatcher: TrappedDumbDispatcher new",
+messageSends: ["initialize", "dispatcher:", "new"],
+referencedClasses: ["TrappedDumbDispatcher"]
 }),
-smalltalk.TrappedModelWrapper.klass);
-
+smalltalk.TrappedPlainModel);
 
-smalltalk.addClass('TrappedPlainModel', smalltalk.TrappedModelWrapper, [], 'Trapped-Frontend');
 smalltalk.addMethod(
 "_read_do_",
 smalltalk.method({
@@ -125,24 +108,6 @@ referencedClasses: []
 }),
 smalltalk.TrappedPlainModel);
 
-smalltalk.addMethod(
-"_watch_do_",
-smalltalk.method({
-selector: "watch:do:",
-category: 'action',
-fn: function (path,aBlock){
-var self=this;
-smalltalk.send((function(){
-return smalltalk.send(self,"_read_do_",[path,aBlock]);
-}),"_fork",[]);
-return self},
-args: ["path", "aBlock"],
-source: "watch: path do: aBlock\x0a\x09[ self read: path do: aBlock ] fork",
-messageSends: ["fork", "read:do:"],
-referencedClasses: []
-}),
-smalltalk.TrappedPlainModel);
-
 
 smalltalk.addMethod(
 "_start",

+ 92 - 0
st/Trapped-Common.st

@@ -0,0 +1,92 @@
+Smalltalk current createPackage: 'Trapped-Common' properties: #{}!
+Object subclass: #TrappedDispatcher
+	instanceVariableNames: ''
+	package: 'Trapped-Common'!
+!TrappedDispatcher commentStamp!
+I am base class for change event dispatchers.
+I manage changed path - action block subscriptions.
+These subscription must be three-element arrays
+	{ dirty. path. block }
+
+My subclasses need to provide implementation for:
+	add:
+    do:
+    (optionally) run!
+
+!TrappedDispatcher methodsFor: 'action'!
+
+changed: path
+	| needsToRun |
+    needsToRun := false.
+	self do: [ :each |
+		| aPath lesser |
+		aPath := each second.
+		lesser := aPath size min: path size.
+		(path copyFrom: 1 to: lesser) = (aPath copyFrom: 1 to: lesser) ifTrue: [
+			each at: 1 put: true.
+            needsToRun := true.
+		]
+	].
+	^needsToRun
+!
+
+run
+	self do: [ :each |
+		each first ifTrue: [[ each third value ] ensure: [ each at: 1 put: false ]]
+	]
+! !
+
+Object subclass: #TrappedModelWrapper
+	instanceVariableNames: 'dispatcher payload'
+	package: 'Trapped-Common'!
+!TrappedModelWrapper commentStamp!
+I am base class for model wrappers.
+I wrap a model which can be any object.
+
+My subclasses need to provide implementation for:
+	read:do:
+	(optionally) name
+
+and must initialize:
+	payload
+	dispatcher!
+
+!TrappedModelWrapper methodsFor: 'accessing'!
+
+dispatcher
+	^dispatcher
+!
+
+dispatcher: aDispatcher
+	dispatcher := aDispatcher
+!
+
+name
+	^ self class name
+!
+
+payload
+	^payload
+!
+
+payload: anObject
+	payload := anObject
+! !
+
+!TrappedModelWrapper methodsFor: 'action'!
+
+start
+	Trapped current register: self name: self name
+!
+
+watch: path do: aBlock
+	self dispatcher add: { true. path. [ self read: path do: aBlock ] }.
+    [ self dispatcher run ] fork
+! !
+
+!TrappedModelWrapper class methodsFor: 'action'!
+
+start
+	self new start
+! !
+

+ 26 - 31
st/Trapped-Frontend.st

@@ -1,44 +1,36 @@
 Smalltalk current createPackage: 'Trapped-Frontend' properties: #{}!
-Widget subclass: #TrappedDumbView
-	instanceVariableNames: ''
+TrappedDispatcher subclass: #TrappedDumbDispatcher
+	instanceVariableNames: 'queue'
 	package: 'Trapped-Frontend'!
-!TrappedDumbView commentStamp!
-I just read and show an actual path.!
 
-!TrappedDumbView methodsFor: 'rendering'!
+!TrappedDumbDispatcher methodsFor: 'accessing'!
 
-renderOn: html
-	html root trapShow: #()
+add: aTriplet
+	queue add: aTriplet
 ! !
 
-Object subclass: #TrappedModelWrapper
-	instanceVariableNames: 'payload'
-	package: 'Trapped-Frontend'!
-
-!TrappedModelWrapper methodsFor: 'accessing'!
-
-payload
-	^payload
-!
+!TrappedDumbDispatcher methodsFor: 'enumeration'!
 
-payload: anObject
-	payload := anObject
+do: aBlock
+	queue do: aBlock
 ! !
 
-!TrappedModelWrapper methodsFor: 'action'!
-
-name
-	^ self class name
-!
+!TrappedDumbDispatcher methodsFor: 'initialization'!
 
-start
-	Trapped current register: self name: self name
+initialize
+	queue := OrderedCollection new
 ! !
 
-!TrappedModelWrapper class methodsFor: 'action'!
+Widget subclass: #TrappedDumbView
+	instanceVariableNames: ''
+	package: 'Trapped-Frontend'!
+!TrappedDumbView commentStamp!
+I just read and show an actual path.!
 
-start
-	self new start
+!TrappedDumbView methodsFor: 'rendering'!
+
+renderOn: html
+	html root trapShow: #()
 ! !
 
 TrappedModelWrapper subclass: #TrappedPlainModel
@@ -52,10 +44,13 @@ read: path do: aBlock
     data := path inject: self payload
     	into: [ :soFar :segment | soFar at: segment ].
 	aBlock value: data.
-!
+! !
 
-watch: path do: aBlock
-	[ self read: path do: aBlock ] fork
+!TrappedPlainModel methodsFor: 'initialization'!
+
+initialize
+	super initialize.
+    self dispatcher: TrappedDumbDispatcher new
 ! !
 
 !TrappedPlainModel class methodsFor: 'action'!