Trapped-Processors.st 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. Smalltalk current createPackage: 'Trapped-Processors'!
  2. TrappedProcessor subclass: #TrappedDataExpectingProcessor
  3. instanceVariableNames: ''
  4. package: 'Trapped-Processors'!
  5. !TrappedDataExpectingProcessor commentStamp!
  6. I answer true to isExpectingModelData and serve as a base class
  7. for processor that present / change model data.
  8. When at least one of my instances is present in the chain,
  9. automatic databinding processor is added at the beginning
  10. (the data-binding scenario); otherwise, the chain
  11. is run immediately with true as data (run-once scenario).!
  12. !TrappedDataExpectingProcessor methodsFor: 'testing'!
  13. isExpectingModelData
  14. ^true
  15. ! !
  16. TrappedDataExpectingProcessor subclass: #TrappedProcessorContents
  17. instanceVariableNames: ''
  18. package: 'Trapped-Processors'!
  19. !TrappedProcessorContents commentStamp!
  20. I put data into target via contents: in toView:!
  21. !TrappedProcessorContents methodsFor: 'data transformation'!
  22. toView: aDataCarrier
  23. aDataCarrier toTargetContents
  24. ! !
  25. TrappedDataExpectingProcessor subclass: #TrappedProcessorDataAdhoc
  26. instanceVariableNames: 'toViewBlock'
  27. package: 'Trapped-Processors'!
  28. !TrappedProcessorDataAdhoc commentStamp!
  29. I put data into target via contents: in toView:!
  30. !TrappedProcessorDataAdhoc methodsFor: 'accessing'!
  31. toViewBlock: aBlock
  32. toViewBlock := aBlock
  33. ! !
  34. !TrappedProcessorDataAdhoc methodsFor: 'data transformation'!
  35. toView: aDataCarrier
  36. toViewBlock value: aDataCarrier
  37. ! !
  38. !TrappedProcessorDataAdhoc class methodsFor: 'instance creation'!
  39. newToView: aBlock
  40. ^self new
  41. toViewBlock: aBlock;
  42. yourself
  43. ! !
  44. TrappedDataExpectingProcessor subclass: #TrappedProcessorInputChecked
  45. instanceVariableNames: ''
  46. package: 'Trapped-Processors'!
  47. !TrappedProcessorInputChecked commentStamp!
  48. I bind to checkbox checked attribute.!
  49. !TrappedProcessorInputChecked methodsFor: 'data transformation'!
  50. toView: aDataCarrier
  51. aDataCarrier toTargetAttr: 'checked'
  52. ! !
  53. !TrappedProcessorInputChecked methodsFor: 'installation'!
  54. installToView: aDataCarrier toModel: anotherDataCarrier
  55. | brush |
  56. brush := aDataCarrier target.
  57. brush onChange: [ anotherDataCarrier copy value: (brush asJQuery attr: 'checked') notNil; proceed ]
  58. ! !
  59. TrappedDataExpectingProcessor subclass: #TrappedProcessorInputValue
  60. instanceVariableNames: ''
  61. package: 'Trapped-Processors'!
  62. !TrappedProcessorInputValue commentStamp!
  63. I bind to input value.!
  64. !TrappedProcessorInputValue methodsFor: 'data transformation'!
  65. toView: aDataCarrier
  66. aDataCarrier toTargetValue
  67. ! !
  68. !TrappedProcessorInputValue methodsFor: 'installation'!
  69. installToView: aDataCarrier toModel: anotherDataCarrier
  70. | brush |
  71. brush := aDataCarrier target.
  72. brush onChange: [ anotherDataCarrier copy value: brush asJQuery val; proceed ]
  73. ! !
  74. TrappedProcessor subclass: #TrappedProcessorBlackboard
  75. instanceVariableNames: ''
  76. package: 'Trapped-Processors'!
  77. !TrappedProcessorBlackboard commentStamp!
  78. I am used internally to fetch data from blackboard
  79. or write it back.
  80. I am added to the beginning of the chain
  81. when the chain contains at least one element
  82. that isExpectingModelData (see TrappedDataExpectingProcessor).!
  83. !TrappedProcessorBlackboard methodsFor: 'data transformation'!
  84. toModel: aDataCarrier
  85. aDataCarrier modifyTarget
  86. ! !
  87. !TrappedProcessorBlackboard methodsFor: 'installation'!
  88. installToView: aDataCarrier toModel: anotherDataCarrier
  89. | snap |
  90. snap := anotherDataCarrier target.
  91. snap watch: [ :data |
  92. (aDataCarrier target asJQuery closest: 'html') toArray isEmpty ifTrue: [ KeyedPubSubUnsubscribe signal ].
  93. snap do: [ aDataCarrier copy value: data; proceed ] ].
  94. aDataCarrier value: false
  95. ! !
  96. TrappedProcessor subclass: #TrappedProcessorDescend
  97. instanceVariableNames: ''
  98. package: 'Trapped-Processors'!
  99. !TrappedProcessorDescend commentStamp!
  100. I intepret data-trap in descendants of my brush.!
  101. !TrappedProcessorDescend methodsFor: 'data transformation'!
  102. toView: aDataCarrier
  103. Trapped current injectToJQuery: aDataCarrier target asJQuery children
  104. ! !
  105. TrappedProcessor subclass: #TrappedProcessorGuardBase
  106. instanceVariableNames: 'guardPath'
  107. package: 'Trapped-Processors'!
  108. !TrappedProcessorGuardBase commentStamp!
  109. I serve as base class for brush-guarding processors.
  110. I cover instantiation and subclasses have to provide
  111. implementation of toVIew: that react appropriately to guard releasing.!
  112. !TrappedProcessorGuardBase methodsFor: 'accessing'!
  113. guardPath: anArray
  114. guardPath := anArray
  115. ! !
  116. !TrappedProcessorGuardBase methodsFor: 'data transformation'!
  117. toModel: aDataCarrier
  118. "stop"
  119. !
  120. toView: aDataCarrier
  121. self subclassResponsibility
  122. ! !
  123. !TrappedProcessorGuardBase class methodsFor: 'instance creation'!
  124. new: anArray
  125. ^ self new
  126. guardPath: anArray;
  127. yourself
  128. ! !
  129. TrappedProcessorGuardBase subclass: #TrappedProcessorGuardContents
  130. instanceVariableNames: ''
  131. package: 'Trapped-Processors'!
  132. !TrappedProcessorGuardContents commentStamp!
  133. I am used to guard contents of the brush I am installed on.
  134. I save the brush contents, then I observe guard expression in the model,
  135. and when it changes to nil or false, I delete the brush contents;
  136. on the other hand, when it changes to non-nil and non-false,
  137. I restore it from remembered state and interpret all contained
  138. data-trap attributes inside.!
  139. !TrappedProcessorGuardContents methodsFor: 'data transformation'!
  140. toView: aDataCarrier
  141. | frozen contents |
  142. frozen := aDataCarrier copy.
  143. contents := frozen target asJQuery contents detach.
  144. frozen target trapGuard: guardPath contents: [ :html |
  145. html root asJQuery append: contents.
  146. Trapped current injectToJQuery: html root asJQuery ]
  147. ! !
  148. TrappedProcessorGuardBase subclass: #TrappedProcessorGuardProc
  149. instanceVariableNames: ''
  150. package: 'Trapped-Processors'!
  151. !TrappedProcessorGuardProc commentStamp!
  152. I am used to guard contents filling process of the brush I am installed on.
  153. I observe guard expression in the model,
  154. and when it changes to nil or false, I delete the brush contents;
  155. on the other hand, when it changes to non-nil and non-false,
  156. I run the rest on the chain, which should be one-time
  157. that sets up the contents,!
  158. !TrappedProcessorGuardProc methodsFor: 'data transformation'!
  159. toView: aDataCarrier
  160. | frozen |
  161. frozen := aDataCarrier copy.
  162. frozen target trapGuard: guardPath contents: [ frozen copy proceed ]
  163. ! !
  164. TrappedProcessor subclass: #TrappedProcessorLoopBase
  165. instanceVariableNames: ''
  166. package: 'Trapped-Processors'!
  167. !TrappedProcessorLoopBase commentStamp!
  168. I serve as base class for looping processors.
  169. I cover instantiation and subclasses have to provide
  170. implementation of toVIew: that loops appropriately.!
  171. !TrappedProcessorLoopBase methodsFor: 'data transformation'!
  172. toModel: aDataCarrier
  173. "stop"
  174. !
  175. toView: aDataCarrier
  176. self subclassResponsibility
  177. ! !
  178. TrappedProcessorLoopBase subclass: #TrappedProcessorLoopContents
  179. instanceVariableNames: ''
  180. package: 'Trapped-Processors'!
  181. !TrappedProcessorLoopContents commentStamp!
  182. I am used to loop over data and repeat the contents
  183. of the brush I am installed on.
  184. I save the brush contents, then I observe the data in the model,
  185. and when it changes, I loop over it
  186. and restore the contents from remembered state
  187. and interpret all contained data-trap attributes inside
  188. for each element, putting the result _after_ my brush.
  189. My brush itself should be as least visible as possible,
  190. as it only serve as a position flag (use for example
  191. noscript, ins or del).!
  192. !TrappedProcessorLoopContents methodsFor: 'data transformation'!
  193. toView: aDataCarrier
  194. | frozen contents |
  195. frozen := aDataCarrier copy.
  196. contents := frozen target asJQuery contents detach.
  197. frozen target trapIter: #() after: [ :html |
  198. html root asJQuery append: contents clone.
  199. Trapped current injectToJQuery: html root asJQuery ]
  200. ! !
  201. TrappedProcessorLoopBase subclass: #TrappedProcessorLoopProc
  202. instanceVariableNames: ''
  203. package: 'Trapped-Processors'!
  204. !TrappedProcessorLoopProc commentStamp!
  205. I am used to loop over data and repeat the contents filling process
  206. of the brush I am installed on.
  207. I observe the data in the model,
  208. and when it changes, I loop over it
  209. and run the rest of the processing chain
  210. for each element, putting the result _after_ my brush.
  211. My brush itself should be as least visible as possible,
  212. as it only serve as a position flag (use for example
  213. noscript, ins or del).!
  214. !TrappedProcessorLoopProc methodsFor: 'data transformation'!
  215. toView: aDataCarrier
  216. | frozen |
  217. frozen := aDataCarrier copy.
  218. frozen target trapIter: #() after: [ :html | frozen copy target: html root; proceed ]
  219. ! !
  220. TrappedProcessor subclass: #TrappedProcessorSignal
  221. instanceVariableNames: 'selector'
  222. package: 'Trapped-Processors'!
  223. !TrappedProcessorSignal commentStamp!
  224. Instead of writing data directly to model,
  225. I instead modify it by sending a message specified when instantiating me.!
  226. !TrappedProcessorSignal methodsFor: 'accessing'!
  227. selector: aString
  228. selector := aString
  229. ! !
  230. !TrappedProcessorSignal methodsFor: 'data transformation'!
  231. toModel: aDataCarrier
  232. aDataCarrier modifyTargetByPerforming: selector
  233. !
  234. toView: aDataCarrier
  235. "stop"
  236. ! !
  237. !TrappedProcessorSignal class methodsFor: 'instance creation'!
  238. new: aString
  239. ^self new
  240. selector: aString;
  241. yourself
  242. ! !
  243. TrappedProcessor subclass: #TrappedProcessorTerminator
  244. instanceVariableNames: ''
  245. package: 'Trapped-Processors'!
  246. !TrappedProcessorTerminator commentStamp!
  247. I do not proceed in toView:.
  248. I am added automatically to end of chain when it does not contain
  249. any element that isExpectingModelData (see TrappedDataExpectingProcessor).!
  250. !TrappedProcessorTerminator methodsFor: 'data transformation'!
  251. toView: aDataCarrier
  252. "stop"
  253. ! !
  254. TrappedProcessor subclass: #TrappedProcessorWhenClicked
  255. instanceVariableNames: ''
  256. package: 'Trapped-Processors'!
  257. !TrappedProcessorWhenClicked commentStamp!
  258. I bind to an element and send true to blackboard when clicked.!
  259. !TrappedProcessorWhenClicked methodsFor: 'installation'!
  260. installToView: aDataCarrier toModel: anotherDataCarrier
  261. aDataCarrier target onClick: [ anotherDataCarrier copy proceed. false ]
  262. ! !
  263. TrappedProcessor subclass: #TrappedProcessorWhenSubmitted
  264. instanceVariableNames: ''
  265. package: 'Trapped-Processors'!
  266. !TrappedProcessorWhenSubmitted commentStamp!
  267. I bind to a form and send true to blackboard when submitted.!
  268. !TrappedProcessorWhenSubmitted methodsFor: 'installation'!
  269. installToView: aDataCarrier toModel: anotherDataCarrier
  270. aDataCarrier target onSubmit: [ anotherDataCarrier copy proceed. false ]
  271. ! !
  272. TrappedProcessor subclass: #TrappedProcessorWidget
  273. instanceVariableNames: 'viewName'
  274. package: 'Trapped-Processors'!
  275. !TrappedProcessorWidget commentStamp!
  276. I insert a widget instance of the class specified when creating me.!
  277. !TrappedProcessorWidget methodsFor: 'accessing'!
  278. viewName: aString
  279. viewName := aString
  280. ! !
  281. !TrappedProcessorWidget methodsFor: 'data transformation'!
  282. toView: aDataCarrier
  283. aDataCarrier target with: (Smalltalk current at: viewName) new
  284. ! !
  285. !TrappedProcessorWidget class methodsFor: 'instance creation'!
  286. new: aString
  287. ^self new
  288. viewName: aString;
  289. yourself
  290. ! !
  291. !TrappedDataCarrier methodsFor: '*Trapped-Processors'!
  292. modifyTarget
  293. self target modify: [ self value ]
  294. !
  295. modifyTargetByPerforming: aString
  296. self target modify: [ :m | m perform: aString ]
  297. !
  298. toTargetAttr: aString
  299. self target asJQuery attr: aString put: (self value ifNotNil: [ :o | o value ] ifNil: [[]])
  300. !
  301. toTargetContents
  302. self target contents: self value
  303. !
  304. toTargetValue
  305. self target asJQuery val: (self value ifNotNil: [ :o | o value ] ifNil: [[]])
  306. ! !