Переглянути джерело

binders off; old example works on new processors system

Herbert Vojčík 11 роки тому
батько
коміт
a03417edc5
4 змінених файлів з 249 додано та 338 видалено
  1. 5 6
      js/Trapped-Demo.js
  2. 186 250
      js/Trapped-Frontend.js
  3. 2 2
      st/Trapped-Demo.st
  4. 56 80
      st/Trapped-Frontend.st

+ 5 - 6
js/Trapped-Demo.js

@@ -286,8 +286,8 @@ $6=_st(html)._input();
 $ctx5.sendIdx["input"]=1;
 _st($6)._type_("checkbox");
 $ctx5.sendIdx["type:"]=1;
-$7=_st($6)._trap_(["done"]);
-$ctx5.sendIdx["trap:"]=4;
+$7=_st($6)._trap_processors_(["done"],["inputChecked"]);
+$ctx5.sendIdx["trap:processors:"]=1;
 $7;
 $8=_st(html)._span();
 _st($8)._trap_read_(["done"],(function(model){
@@ -296,7 +296,6 @@ return _st(_st(html)._root())._class_("done-".__comma(model));
 $ctx6.sendIdx["class:"]=1;
 }, function($ctx6) {$ctx6.fillBlock({model:model},$ctx5,7)})}));
 $9=_st($8)._trap_(["text"]);
-$ctx5.sendIdx["trap:"]=5;
 return $9;
 }, function($ctx5) {$ctx5.fillBlock({each:each},$ctx4,6)})}));
 }, function($ctx4) {$ctx4.fillBlock({},$ctx3,5)})}));
@@ -316,7 +315,7 @@ $12=_st(html)._input();
 $ctx4.sendIdx["input"]=2;
 _st($12)._type_("text");
 $ctx4.sendIdx["type:"]=2;
-_st($12)._trap_([["todoText"]]);
+_st($12)._trap_processors_([["todoText"]],["inputValue"]);
 _st($12)._at_put_("size",(30));
 $13=_st($12)._placeholder_("add new todo here");
 $13;
@@ -333,8 +332,8 @@ return _st(_st(html)._p())._trapGuard_contents_([["todos"], ["isNil"]],"Loading
 }, function($ctx2) {$ctx2.fillBlock({snap:snap},$ctx1,1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"renderOn:",{html:html},smalltalk.AppView)})},
 args: ["html"],
-source: "renderOn: html\x0a    #() trapDescend: [ :snap |\x0a\x09html h2 trap: #((title)).\x0a    html div trapGuard: #((todos) (notNil)) contents: [\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        ]; with: 'archive'.\x0a        html with: ' ]'.\x0a        html ul with: [ html 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        ]; 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    ].\x0a\x09html p trapGuard: #((todos) (isNil)) contents: 'Loading ...'.\x0a\x09]",
-messageSends: ["trapDescend:", "trap:", "h2", "trapGuard:contents:", "div", "span", "with:", "href:", "a", "onClick:", "modify:", "archive", "ul", "trapIter:tag:do:", "empty", "root", "type:", "input", "trap:read:", "class:", ",", "onSubmit:", "form", "addTodo", "at:put:", "placeholder:", "value:", "p"],
+source: "renderOn: html\x0a    #() trapDescend: [ :snap |\x0a\x09html h2 trap: #((title)).\x0a    html div trapGuard: #((todos) (notNil)) contents: [\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        ]; with: 'archive'.\x0a        html with: ' ]'.\x0a        html ul with: [ html trapIter: #((todos)) tag: #li do: [ :each |\x0a            html root empty.\x0a            html input type: 'checkbox'; trap: #('done') processors: #(inputChecked).\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        ]; with: [\x0a            html input type: 'text'; trap: #((todoText)) processors: #(inputValue); at: 'size' put: 30; placeholder: 'add new todo here'.\x0a            html input class: 'btn-primary'; type: 'submit'; value: 'add'.\x0a        ].\x0a    ].\x0a\x09html p trapGuard: #((todos) (isNil)) contents: 'Loading ...'.\x0a\x09]",
+messageSends: ["trapDescend:", "trap:", "h2", "trapGuard:contents:", "div", "span", "with:", "href:", "a", "onClick:", "modify:", "archive", "ul", "trapIter:tag:do:", "empty", "root", "type:", "input", "trap:processors:", "trap:read:", "class:", ",", "onSubmit:", "form", "addTodo", "at:put:", "placeholder:", "value:", "p"],
 referencedClasses: []
 }),
 smalltalk.AppView);

+ 186 - 250
js/Trapped-Frontend.js

@@ -2,203 +2,6 @@ define("gh_herby_trapped/Trapped-Frontend", ["amber_vm/smalltalk", "amber_vm/nil
 smalltalk.addPackage('Trapped-Frontend');
 smalltalk.packages["Trapped-Frontend"].transport = {"type":"amd","amdNamespace":"gh_herby_trapped"};
 
-smalltalk.addClass('TrappedBinder', smalltalk.Object, ['brush'], 'Trapped-Frontend');
-smalltalk.addMethod(
-smalltalk.method({
-selector: "brush:",
-category: 'accessing',
-fn: function (aTagBrush){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-self["@brush"]=aTagBrush;
-return self}, function($ctx1) {$ctx1.fill(self,"brush:",{aTagBrush:aTagBrush},smalltalk.TrappedBinder)})},
-args: ["aTagBrush"],
-source: "brush: aTagBrush\x0a\x09brush := aTagBrush",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.TrappedBinder);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "installFor:",
-category: 'action',
-fn: function (path){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-_st(self["@brush"])._trap_read_(path,self._showBlock());
-return self}, function($ctx1) {$ctx1.fill(self,"installFor:",{path:path},smalltalk.TrappedBinder)})},
-args: ["path"],
-source: "installFor: path\x0a\x09brush trap: path read: self showBlock",
-messageSends: ["trap:read:", "showBlock"],
-referencedClasses: []
-}),
-smalltalk.TrappedBinder);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "prim:",
-category: 'converting',
-fn: function (anObject){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-return anObject.valueOf();
-return self}, function($ctx1) {$ctx1.fill(self,"prim:",{anObject:anObject},smalltalk.TrappedBinder)})},
-args: ["anObject"],
-source: "prim: anObject\x0a\x09<return anObject.valueOf()>",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.TrappedBinder);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "showBlock",
-category: 'action',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $2,$4,$5,$3,$1;
-$1=(function(model){
-return smalltalk.withContext(function($ctx2) {
-$2=self["@brush"];
-_st($2)._empty();
-$4=$2;
-if(($receiver = model) == nil || $receiver == null){
-$5=(function(){
-return smalltalk.withContext(function($ctx3) {
-}, function($ctx3) {$ctx3.fillBlock({},$ctx2,3)})});
-} else {
-$5=model;
-};
-$3=_st($4)._with_($5);
-return $3;
-}, function($ctx2) {$ctx2.fillBlock({model:model},$ctx1,1)})});
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"showBlock",{},smalltalk.TrappedBinder)})},
-args: [],
-source: "showBlock\x0a\x09^[ :model | brush empty; with: (model ifNil: [[]]) ]",
-messageSends: ["empty", "with:", "ifNil:"],
-referencedClasses: []
-}),
-smalltalk.TrappedBinder);
-
-
-
-smalltalk.addClass('TrappedCheckedBinder', smalltalk.TrappedBinder, [], 'Trapped-Frontend');
-smalltalk.addMethod(
-smalltalk.method({
-selector: "installFor:",
-category: 'action',
-fn: function (path){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-smalltalk.TrappedCheckedBinder.superclass.fn.prototype._installFor_.apply(_st(self), [path]);
-_st(path)._trapDescend_((function(snap){
-return smalltalk.withContext(function($ctx2) {
-return _st(self["@brush"])._onChange_((function(){
-return smalltalk.withContext(function($ctx3) {
-return _st(snap)._modify_((function(){
-return smalltalk.withContext(function($ctx4) {
-return _st(_st(_st(self["@brush"])._asJQuery())._attr_("checked"))._notNil();
-}, function($ctx4) {$ctx4.fillBlock({},$ctx3,3)})}));
-}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})}));
-}, function($ctx2) {$ctx2.fillBlock({snap:snap},$ctx1,1)})}));
-return self}, function($ctx1) {$ctx1.fill(self,"installFor:",{path:path},smalltalk.TrappedCheckedBinder)})},
-args: ["path"],
-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.TrappedCheckedBinder);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "showBlock",
-category: 'action',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $2,$3,$1;
-$1=(function(model){
-return smalltalk.withContext(function($ctx2) {
-$2=_st(self["@brush"])._asJQuery();
-if(($receiver = model) == nil || $receiver == null){
-$3=false;
-} else {
-$3=self._prim_(model);
-};
-return _st($2)._attr_put_("checked",$3);
-}, function($ctx2) {$ctx2.fillBlock({model:model},$ctx1,1)})});
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"showBlock",{},smalltalk.TrappedCheckedBinder)})},
-args: [],
-source: "showBlock\x0a\x09^[ :model | brush asJQuery attr: 'checked' put: (model ifNotNil: [ self prim: model ] ifNil: [ false ]) ]",
-messageSends: ["attr:put:", "asJQuery", "ifNotNil:ifNil:", "prim:"],
-referencedClasses: []
-}),
-smalltalk.TrappedCheckedBinder);
-
-
-
-smalltalk.addClass('TrappedValBinder', smalltalk.TrappedBinder, [], 'Trapped-Frontend');
-smalltalk.addMethod(
-smalltalk.method({
-selector: "installFor:",
-category: 'action',
-fn: function (path){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-smalltalk.TrappedValBinder.superclass.fn.prototype._installFor_.apply(_st(self), [path]);
-_st(path)._trapDescend_((function(snap){
-return smalltalk.withContext(function($ctx2) {
-return _st(self["@brush"])._onChange_((function(){
-return smalltalk.withContext(function($ctx3) {
-return _st(snap)._modify_((function(){
-return smalltalk.withContext(function($ctx4) {
-return _st(_st(self["@brush"])._asJQuery())._val();
-}, function($ctx4) {$ctx4.fillBlock({},$ctx3,3)})}));
-}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})}));
-}, function($ctx2) {$ctx2.fillBlock({snap:snap},$ctx1,1)})}));
-return self}, function($ctx1) {$ctx1.fill(self,"installFor:",{path:path},smalltalk.TrappedValBinder)})},
-args: ["path"],
-source: "installFor: path\x0a\x09super installFor: path.\x0a    path trapDescend: [ :snap |\x0a\x09    brush onChange: [ snap modify: [\x0a            brush asJQuery val\x0a        ]]\x0a    ]",
-messageSends: ["installFor:", "trapDescend:", "onChange:", "modify:", "val", "asJQuery"],
-referencedClasses: []
-}),
-smalltalk.TrappedValBinder);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "showBlock",
-category: 'action',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $2,$3,$1;
-$1=(function(model){
-return smalltalk.withContext(function($ctx2) {
-$2=_st(self["@brush"])._asJQuery();
-if(($receiver = model) == nil || $receiver == null){
-$3=(function(){
-return smalltalk.withContext(function($ctx3) {
-}, function($ctx3) {$ctx3.fillBlock({},$ctx2,4)})});
-} else {
-$3=self._prim_(model);
-};
-return _st($2)._val_($3);
-}, function($ctx2) {$ctx2.fillBlock({model:model},$ctx1,1)})});
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"showBlock",{},smalltalk.TrappedValBinder)})},
-args: [],
-source: "showBlock\x0a\x09^[ :model | brush asJQuery val: (model ifNotNil: [self prim: model] ifNil: [[]]) ]",
-messageSends: ["val:", "asJQuery", "ifNotNil:ifNil:", "prim:"],
-referencedClasses: []
-}),
-smalltalk.TrappedValBinder);
-
-
-
 smalltalk.addClass('TrappedDataCarrier', smalltalk.Object, ['target', 'model', 'chain'], 'Trapped-Frontend');
 smalltalk.addMethod(
 smalltalk.method({
@@ -269,6 +72,35 @@ referencedClasses: []
 }),
 smalltalk.TrappedDataCarrier);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "toTargetAttr:",
+category: 'action',
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$3,$2;
+$1=_st(self._target())._asJQuery();
+$3=self._value();
+$ctx1.sendIdx["value"]=1;
+if(($receiver = $3) == nil || $receiver == null){
+$2=(function(){
+return smalltalk.withContext(function($ctx2) {
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,3)})});
+} else {
+var o;
+o=$receiver;
+$2=_st(o)._value();
+};
+_st($1)._attr_put_(aString,$2);
+return self}, function($ctx1) {$ctx1.fill(self,"toTargetAttr:",{aString:aString},smalltalk.TrappedDataCarrier)})},
+args: ["aString"],
+source: "toTargetAttr: aString\x0a\x09self target asJQuery attr: aString put: (self value ifNotNil: [ :o | o value ] ifNil: [[]])",
+messageSends: ["attr:put:", "asJQuery", "target", "ifNotNil:ifNil:", "value"],
+referencedClasses: []
+}),
+smalltalk.TrappedDataCarrier);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "toTargetContents",
@@ -285,6 +117,35 @@ referencedClasses: []
 }),
 smalltalk.TrappedDataCarrier);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "toTargetValue",
+category: 'action',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$3,$2;
+$1=_st(self._target())._asJQuery();
+$3=self._value();
+$ctx1.sendIdx["value"]=1;
+if(($receiver = $3) == nil || $receiver == null){
+$2=(function(){
+return smalltalk.withContext(function($ctx2) {
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,3)})});
+} else {
+var o;
+o=$receiver;
+$2=_st(o)._value();
+};
+_st($1)._val_($2);
+return self}, function($ctx1) {$ctx1.fill(self,"toTargetValue",{},smalltalk.TrappedDataCarrier)})},
+args: [],
+source: "toTargetValue\x0a\x09self target asJQuery val: (self value ifNotNil: [ :o | o value ] ifNil: [[]])",
+messageSends: ["val:", "asJQuery", "target", "ifNotNil:ifNil:", "value"],
+referencedClasses: []
+}),
+smalltalk.TrappedDataCarrier);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "value",
@@ -642,6 +503,44 @@ referencedClasses: ["TrappedProcessorContents"]
 }),
 smalltalk.TrappedProcessor.klass);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "inputChecked",
+category: 'factory',
+fn: function (){
+var self=this;
+function $TrappedProcessorInputChecked(){return smalltalk.TrappedProcessorInputChecked||(typeof TrappedProcessorInputChecked=="undefined"?nil:TrappedProcessorInputChecked)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st($TrappedProcessorInputChecked())._new();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"inputChecked",{},smalltalk.TrappedProcessor.klass)})},
+args: [],
+source: "inputChecked\x0a\x09^TrappedProcessorInputChecked new",
+messageSends: ["new"],
+referencedClasses: ["TrappedProcessorInputChecked"]
+}),
+smalltalk.TrappedProcessor.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "inputValue",
+category: 'factory',
+fn: function (){
+var self=this;
+function $TrappedProcessorInputValue(){return smalltalk.TrappedProcessorInputValue||(typeof TrappedProcessorInputValue=="undefined"?nil:TrappedProcessorInputValue)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st($TrappedProcessorInputValue())._new();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"inputValue",{},smalltalk.TrappedProcessor.klass)})},
+args: [],
+source: "inputValue\x0a\x09^TrappedProcessorInputValue new",
+messageSends: ["new"],
+referencedClasses: ["TrappedProcessorInputValue"]
+}),
+smalltalk.TrappedProcessor.klass);
+
 
 smalltalk.addClass('TrappedProcessorBlackboard', smalltalk.TrappedProcessor, [], 'Trapped-Frontend');
 smalltalk.TrappedProcessorBlackboard.comment="I am used internally to fetch data from blackboard\x0aor write it back.";
@@ -717,6 +616,96 @@ smalltalk.TrappedProcessorContents);
 
 
 
+smalltalk.addClass('TrappedProcessorInputChecked', smalltalk.TrappedProcessor, [], 'Trapped-Frontend');
+smalltalk.TrappedProcessorInputChecked.comment="I bind to checkbox checked attribute.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "installToView:toModel:",
+category: 'installation',
+fn: function (aDataCarrier,anotherDataCarrier){
+var self=this;
+var brush;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+brush=_st(aDataCarrier)._target();
+_st(brush)._onChange_((function(){
+return smalltalk.withContext(function($ctx2) {
+$1=_st(anotherDataCarrier)._copy();
+_st($1)._value_(_st(_st(_st(brush)._asJQuery())._attr_("checked"))._notNil());
+$2=_st($1)._proceed();
+return $2;
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"installToView:toModel:",{aDataCarrier:aDataCarrier,anotherDataCarrier:anotherDataCarrier,brush:brush},smalltalk.TrappedProcessorInputChecked)})},
+args: ["aDataCarrier", "anotherDataCarrier"],
+source: "installToView: aDataCarrier toModel: anotherDataCarrier\x0a\x09| brush |\x0a\x09brush := aDataCarrier target.\x0a\x09brush onChange: [ anotherDataCarrier copy value: (brush asJQuery attr: 'checked') notNil; proceed ]",
+messageSends: ["target", "onChange:", "value:", "copy", "notNil", "attr:", "asJQuery", "proceed"],
+referencedClasses: []
+}),
+smalltalk.TrappedProcessorInputChecked);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "toView:",
+category: 'data transformation',
+fn: function (aDataCarrier){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(aDataCarrier)._toTargetAttr_("checked");
+return self}, function($ctx1) {$ctx1.fill(self,"toView:",{aDataCarrier:aDataCarrier},smalltalk.TrappedProcessorInputChecked)})},
+args: ["aDataCarrier"],
+source: "toView: aDataCarrier\x0a\x09aDataCarrier toTargetAttr: 'checked'",
+messageSends: ["toTargetAttr:"],
+referencedClasses: []
+}),
+smalltalk.TrappedProcessorInputChecked);
+
+
+
+smalltalk.addClass('TrappedProcessorInputValue', smalltalk.TrappedProcessor, [], 'Trapped-Frontend');
+smalltalk.TrappedProcessorInputValue.comment="I bind to input value.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "installToView:toModel:",
+category: 'installation',
+fn: function (aDataCarrier,anotherDataCarrier){
+var self=this;
+var brush;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+brush=_st(aDataCarrier)._target();
+_st(brush)._onChange_((function(){
+return smalltalk.withContext(function($ctx2) {
+$1=_st(anotherDataCarrier)._copy();
+_st($1)._value_(_st(_st(brush)._asJQuery())._val());
+$2=_st($1)._proceed();
+return $2;
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"installToView:toModel:",{aDataCarrier:aDataCarrier,anotherDataCarrier:anotherDataCarrier,brush:brush},smalltalk.TrappedProcessorInputValue)})},
+args: ["aDataCarrier", "anotherDataCarrier"],
+source: "installToView: aDataCarrier toModel: anotherDataCarrier\x0a\x09| brush |\x0a\x09brush := aDataCarrier target.\x0a\x09brush onChange: [ anotherDataCarrier copy value: brush asJQuery val; proceed ]",
+messageSends: ["target", "onChange:", "value:", "copy", "val", "asJQuery", "proceed"],
+referencedClasses: []
+}),
+smalltalk.TrappedProcessorInputValue);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "toView:",
+category: 'data transformation',
+fn: function (aDataCarrier){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(aDataCarrier)._toTargetValue();
+return self}, function($ctx1) {$ctx1.fill(self,"toView:",{aDataCarrier:aDataCarrier},smalltalk.TrappedProcessorInputValue)})},
+args: ["aDataCarrier"],
+source: "toView: aDataCarrier\x0a\x09aDataCarrier toTargetValue",
+messageSends: ["toTargetValue"],
+referencedClasses: []
+}),
+smalltalk.TrappedProcessorInputValue);
+
+
+
 smalltalk.addClass('TrappedSingleton', smalltalk.Object, [], 'Trapped-Frontend');
 smalltalk.addMethod(
 smalltalk.method({
@@ -780,59 +769,6 @@ smalltalk.TrappedSingleton.klass);
 
 
 smalltalk.addClass('Trapped', smalltalk.TrappedSingleton, ['registry'], 'Trapped-Frontend');
-smalltalk.addMethod(
-smalltalk.method({
-selector: "binder:",
-category: 'binders',
-fn: function (aTagBrush){
-var self=this;
-var binder,tag;
-function $TrappedCheckedBinder(){return smalltalk.TrappedCheckedBinder||(typeof TrappedCheckedBinder=="undefined"?nil:TrappedCheckedBinder)}
-function $TrappedValBinder(){return smalltalk.TrappedValBinder||(typeof TrappedValBinder=="undefined"?nil:TrappedValBinder)}
-function $TrappedBinder(){return smalltalk.TrappedBinder||(typeof TrappedBinder=="undefined"?nil:TrappedBinder)}
-return smalltalk.withContext(function($ctx1) { 
-var $1,$2,$3,$4,$6,$7,$5;
-tag=_st(_st(aTagBrush)._element())._nodeName();
-$1=_st(tag).__eq("INPUT");
-$ctx1.sendIdx["="]=1;
-if(smalltalk.assert($1)){
-var type;
-type=_st(_st(aTagBrush)._asJQuery())._attr_("type");
-type;
-$2=_st(type).__eq("checkbox");
-$ctx1.sendIdx["="]=2;
-if(smalltalk.assert($2)){
-binder=_st($TrappedCheckedBinder())._new();
-$ctx1.sendIdx["new"]=1;
-binder;
-};
-$3=_st(type).__eq("text");
-if(smalltalk.assert($3)){
-binder=_st($TrappedValBinder())._new();
-$ctx1.sendIdx["new"]=2;
-binder;
-};
-};
-$4=binder;
-if(($receiver = $4) == nil || $receiver == null){
-binder=_st($TrappedBinder())._new();
-binder;
-} else {
-$4;
-};
-$6=binder;
-_st($6)._brush_(aTagBrush);
-$7=_st($6)._yourself();
-$5=$7;
-return $5;
-}, function($ctx1) {$ctx1.fill(self,"binder:",{aTagBrush:aTagBrush,binder:binder,tag:tag},smalltalk.Trapped)})},
-args: ["aTagBrush"],
-source: "binder: aTagBrush\x0a    \x22Prototype; will select based on tag etc.\x22\x0a    | binder tag |\x0a    tag := aTagBrush element nodeName.\x0a    tag = 'INPUT' ifTrue: [\x0a        | type |\x0a        type := aTagBrush asJQuery attr: 'type'.\x0a        type = 'checkbox' ifTrue: [ binder := TrappedCheckedBinder new ].\x0a        type = 'text' ifTrue: [ binder := TrappedValBinder new ]\x0a    ].\x0a    binder ifNil: [ binder := TrappedBinder new ].\x0a    ^ binder brush: aTagBrush; yourself",
-messageSends: ["nodeName", "element", "ifTrue:", "=", "attr:", "asJQuery", "new", "ifNil:", "brush:", "yourself"],
-referencedClasses: ["TrappedCheckedBinder", "TrappedValBinder", "TrappedBinder"]
-}),
-smalltalk.Trapped);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "byName:",

+ 2 - 2
st/Trapped-Demo.st

@@ -162,14 +162,14 @@ renderOn: html
         html with: ' ]'.
         html ul with: [ html trapIter: #((todos)) tag: #li do: [ :each |
             html root empty.
-            html input type: 'checkbox'; trap: #('done').
+            html input type: 'checkbox'; trap: #('done') processors: #(inputChecked).
             html span trap: #('done') read: [ :model | html root class: 'done-', model ]; trap: #('text').
         ]].
         html form onSubmit: [
             snap modify: [ :model | model addTodo ].
             false
         ]; with: [
-            html input type: 'text'; trap: #((todoText)); at: 'size' put: 30; placeholder: 'add new todo here'.
+            html input type: 'text'; trap: #((todoText)) processors: #(inputValue); at: 'size' put: 30; placeholder: 'add new todo here'.
             html input class: 'btn-primary'; type: 'submit'; value: 'add'.
         ].
     ].

+ 56 - 80
st/Trapped-Frontend.st

@@ -1,68 +1,4 @@
 Smalltalk current createPackage: 'Trapped-Frontend'!
-Object subclass: #TrappedBinder
-	instanceVariableNames: 'brush'
-	package: 'Trapped-Frontend'!
-
-!TrappedBinder methodsFor: 'accessing'!
-
-brush: aTagBrush
-	brush := aTagBrush
-! !
-
-!TrappedBinder methodsFor: 'action'!
-
-installFor: path
-	brush trap: path read: self showBlock
-!
-
-showBlock
-	^[ :model | brush empty; with: (model ifNil: [[]]) ]
-! !
-
-!TrappedBinder methodsFor: 'converting'!
-
-prim: anObject
-	<return anObject.valueOf()>
-! !
-
-TrappedBinder subclass: #TrappedCheckedBinder
-	instanceVariableNames: ''
-	package: 'Trapped-Frontend'!
-
-!TrappedCheckedBinder methodsFor: 'action'!
-
-installFor: path
-	super installFor: path.
-    path trapDescend: [ :snap |
-	    brush onChange: [ snap modify: [
-            (brush asJQuery attr: 'checked') notNil
-        ]]
-    ]
-!
-
-showBlock
-	^[ :model | brush asJQuery attr: 'checked' put: (model ifNotNil: [ self prim: model ] ifNil: [ false ]) ]
-! !
-
-TrappedBinder subclass: #TrappedValBinder
-	instanceVariableNames: ''
-	package: 'Trapped-Frontend'!
-
-!TrappedValBinder methodsFor: 'action'!
-
-installFor: path
-	super installFor: path.
-    path trapDescend: [ :snap |
-	    brush onChange: [ snap modify: [
-            brush asJQuery val
-        ]]
-    ]
-!
-
-showBlock
-	^[ :model | brush asJQuery val: (model ifNotNil: [self prim: model] ifNil: [[]]) ]
-! !
-
 Object subclass: #TrappedDataCarrier
 	instanceVariableNames: 'target model chain'
 	package: 'Trapped-Frontend'!
@@ -95,8 +31,16 @@ modifyTarget
 	self target modify: [ self value ]
 !
 
+toTargetAttr: aString
+	self target asJQuery attr: aString put: (self value ifNotNil: [ :o | o value ] ifNil: [[]])
+!
+
 toTargetContents
 	self target contents: self value
+!
+
+toTargetValue
+	self target asJQuery val: (self value ifNotNil: [ :o | o value ] ifNil: [[]])
 ! !
 
 !TrappedDataCarrier class methodsFor: 'not yet classified'!
@@ -234,6 +178,14 @@ installToView: aDataCarrier toModel: anotherDataCarrier
 
 contents
 	^TrappedProcessorContents new
+!
+
+inputChecked
+	^TrappedProcessorInputChecked new
+!
+
+inputValue
+	^TrappedProcessorInputValue new
 ! !
 
 TrappedProcessor subclass: #TrappedProcessorBlackboard
@@ -271,6 +223,46 @@ toView: aDataCarrier
 	aDataCarrier toTargetContents
 ! !
 
+TrappedProcessor subclass: #TrappedProcessorInputChecked
+	instanceVariableNames: ''
+	package: 'Trapped-Frontend'!
+!TrappedProcessorInputChecked commentStamp!
+I bind to checkbox checked attribute.!
+
+!TrappedProcessorInputChecked methodsFor: 'data transformation'!
+
+toView: aDataCarrier
+	aDataCarrier toTargetAttr: 'checked'
+! !
+
+!TrappedProcessorInputChecked methodsFor: 'installation'!
+
+installToView: aDataCarrier toModel: anotherDataCarrier
+	| brush |
+	brush := aDataCarrier target.
+	brush onChange: [ anotherDataCarrier copy value: (brush asJQuery attr: 'checked') notNil; proceed ]
+! !
+
+TrappedProcessor subclass: #TrappedProcessorInputValue
+	instanceVariableNames: ''
+	package: 'Trapped-Frontend'!
+!TrappedProcessorInputValue commentStamp!
+I bind to input value.!
+
+!TrappedProcessorInputValue methodsFor: 'data transformation'!
+
+toView: aDataCarrier
+	aDataCarrier toTargetValue
+! !
+
+!TrappedProcessorInputValue methodsFor: 'installation'!
+
+installToView: aDataCarrier toModel: anotherDataCarrier
+	| brush |
+	brush := aDataCarrier target.
+	brush onChange: [ anotherDataCarrier copy value: brush asJQuery val; proceed ]
+! !
+
 Object subclass: #TrappedSingleton
 	instanceVariableNames: ''
 	package: 'Trapped-Frontend'!
@@ -342,22 +334,6 @@ start: args
     ]
 ! !
 
-!Trapped methodsFor: 'binders'!
-
-binder: aTagBrush
-    "Prototype; will select based on tag etc."
-    | binder tag |
-    tag := aTagBrush element nodeName.
-    tag = 'INPUT' ifTrue: [
-        | type |
-        type := aTagBrush asJQuery attr: 'type'.
-        type = 'checkbox' ifTrue: [ binder := TrappedCheckedBinder new ].
-        type = 'text' ifTrue: [ binder := TrappedValBinder new ]
-    ].
-    binder ifNil: [ binder := TrappedBinder new ].
-    ^ binder brush: aTagBrush; yourself
-! !
-
 !Trapped methodsFor: 'initialization'!
 
 initialize