Trapped-Processors.st 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. Smalltalk current createPackage: 'Trapped-Processors'!
  2. TrappedDataExpectingProcessor subclass: #TrappedProcessorAttribute
  3. instanceVariableNames: 'attrName'
  4. package: 'Trapped-Processors'!
  5. !TrappedProcessorAttribute commentStamp!
  6. I set the data into an attribute speciried when creating me.
  7. No observing and sending back, atm.!
  8. !TrappedProcessorAttribute methodsFor: 'accessing'!
  9. attrName: aString
  10. attrName := aString
  11. ! !
  12. !TrappedProcessorAttribute methodsFor: 'data transformation'!
  13. toView: aDataCarrier
  14. aDataCarrier toTargetAttr: attrName
  15. ! !
  16. !TrappedProcessorAttribute class methodsFor: 'instance creation'!
  17. new: aString
  18. ^self new
  19. attrName: aString;
  20. yourself
  21. ! !
  22. TrappedDataExpectingProcessor subclass: #TrappedProcessorDataAdhoc
  23. instanceVariableNames: 'toViewBlock'
  24. package: 'Trapped-Processors'!
  25. !TrappedProcessorDataAdhoc commentStamp!
  26. I put data into target via contents: in toView:!
  27. !TrappedProcessorDataAdhoc methodsFor: 'accessing'!
  28. toViewBlock: aBlock
  29. toViewBlock := aBlock
  30. ! !
  31. !TrappedProcessorDataAdhoc methodsFor: 'data transformation'!
  32. toView: aDataCarrier
  33. toViewBlock value: aDataCarrier
  34. ! !
  35. !TrappedProcessorDataAdhoc class methodsFor: 'instance creation'!
  36. newToView: aBlock
  37. ^self new
  38. toViewBlock: aBlock;
  39. yourself
  40. ! !
  41. TrappedProcessor subclass: #TrappedProcessorDescend
  42. instanceVariableNames: ''
  43. package: 'Trapped-Processors'!
  44. !TrappedProcessorDescend commentStamp!
  45. I intepret data-trap in descendants of my brush.!
  46. !TrappedProcessorDescend methodsFor: 'data transformation'!
  47. toView: aDataCarrier
  48. Trapped current injectToJQuery: aDataCarrier target asJQuery children
  49. ! !
  50. TrappedProcessor subclass: #TrappedProcessorGuardBase
  51. instanceVariableNames: 'guardPath'
  52. package: 'Trapped-Processors'!
  53. !TrappedProcessorGuardBase commentStamp!
  54. I serve as base class for brush-guarding processors.
  55. I cover instantiation and subclasses have to provide
  56. implementation of toVIew: that react appropriately to guard releasing.!
  57. !TrappedProcessorGuardBase methodsFor: 'accessing'!
  58. guardPath: anArray
  59. guardPath := anArray
  60. ! !
  61. !TrappedProcessorGuardBase methodsFor: 'data transformation'!
  62. toModel: aDataCarrier
  63. "stop"
  64. !
  65. toView: aDataCarrier
  66. self subclassResponsibility
  67. ! !
  68. !TrappedProcessorGuardBase class methodsFor: 'instance creation'!
  69. new: anArray
  70. ^ self new
  71. guardPath: anArray;
  72. yourself
  73. ! !
  74. TrappedProcessorGuardBase subclass: #TrappedProcessorGuardContents
  75. instanceVariableNames: ''
  76. package: 'Trapped-Processors'!
  77. !TrappedProcessorGuardContents commentStamp!
  78. I am used to guard contents of the brush I am installed on.
  79. I save the brush contents, then I observe guard expression in the model,
  80. and when it changes to nil or false, I delete the brush contents;
  81. on the other hand, when it changes to non-nil and non-false,
  82. I restore it from remembered state and interpret all contained
  83. data-trap attributes inside.!
  84. !TrappedProcessorGuardContents methodsFor: 'data transformation'!
  85. toView: aDataCarrier
  86. | frozen contents |
  87. frozen := aDataCarrier copy.
  88. contents := frozen target asJQuery contents detach.
  89. frozen target trapGuard: guardPath contents: [ :html |
  90. html root asJQuery append: contents.
  91. Trapped current injectToJQuery: html root asJQuery ]
  92. ! !
  93. TrappedProcessorGuardBase subclass: #TrappedProcessorGuardProc
  94. instanceVariableNames: ''
  95. package: 'Trapped-Processors'!
  96. !TrappedProcessorGuardProc commentStamp!
  97. I am used to guard contents filling process of the brush I am installed on.
  98. I observe guard expression in the model,
  99. and when it changes to nil or false, I delete the brush contents;
  100. on the other hand, when it changes to non-nil and non-false,
  101. I run the rest on the chain, which should be one-time
  102. that sets up the contents,!
  103. !TrappedProcessorGuardProc methodsFor: 'data transformation'!
  104. toView: aDataCarrier
  105. | frozen |
  106. frozen := aDataCarrier copy.
  107. frozen target trapGuard: guardPath contents: [ frozen copy proceed ]
  108. ! !
  109. TrappedDataExpectingProcessor subclass: #TrappedProcessorInputChecked
  110. instanceVariableNames: ''
  111. package: 'Trapped-Processors'!
  112. !TrappedProcessorInputChecked commentStamp!
  113. I bind to checkbox checked attribute.!
  114. !TrappedProcessorInputChecked methodsFor: 'data transformation'!
  115. toView: aDataCarrier
  116. aDataCarrier toTargetAttr: 'checked'
  117. ! !
  118. !TrappedProcessorInputChecked methodsFor: 'installation'!
  119. installToView: aDataCarrier toModel: anotherDataCarrier
  120. | brush |
  121. brush := aDataCarrier target.
  122. brush onChange: [ anotherDataCarrier copy value: (brush asJQuery attr: 'checked') notNil; proceed ]
  123. ! !
  124. TrappedDataExpectingProcessor subclass: #TrappedProcessorInputValue
  125. instanceVariableNames: ''
  126. package: 'Trapped-Processors'!
  127. !TrappedProcessorInputValue commentStamp!
  128. I bind to input value.!
  129. !TrappedProcessorInputValue methodsFor: 'data transformation'!
  130. toView: aDataCarrier
  131. aDataCarrier toTargetValue
  132. ! !
  133. !TrappedProcessorInputValue methodsFor: 'installation'!
  134. installToView: aDataCarrier toModel: anotherDataCarrier
  135. | brush |
  136. brush := aDataCarrier target.
  137. brush onChange: [ anotherDataCarrier copy value: brush asJQuery val; proceed ]
  138. ! !
  139. TrappedProcessor subclass: #TrappedProcessorLoopBase
  140. instanceVariableNames: ''
  141. package: 'Trapped-Processors'!
  142. !TrappedProcessorLoopBase commentStamp!
  143. I serve as base class for looping processors.
  144. I cover instantiation and subclasses have to provide
  145. implementation of toVIew: that loops appropriately.!
  146. !TrappedProcessorLoopBase methodsFor: 'data transformation'!
  147. toModel: aDataCarrier
  148. "stop"
  149. !
  150. toView: aDataCarrier
  151. self subclassResponsibility
  152. ! !
  153. TrappedProcessorLoopBase subclass: #TrappedProcessorLoopContents
  154. instanceVariableNames: ''
  155. package: 'Trapped-Processors'!
  156. !TrappedProcessorLoopContents commentStamp!
  157. I am used to loop over data and repeat the contents
  158. of the brush I am installed on.
  159. I save the brush contents, then I observe the data in the model,
  160. and when it changes, I loop over it
  161. and restore the contents from remembered state
  162. and interpret all contained data-trap attributes inside
  163. for each element, putting the result _after_ my brush.
  164. My brush itself should be as least visible as possible,
  165. as it only serve as a position flag (use for example
  166. noscript, ins or del).!
  167. !TrappedProcessorLoopContents methodsFor: 'data transformation'!
  168. toView: aDataCarrier
  169. | frozen contents tag |
  170. frozen := aDataCarrier copy.
  171. tag := (frozen target element at: 'tagName') asLowercase.
  172. contents := nil.
  173. tag = 'template' ifTrue: [
  174. contents := (frozen target element at: 'content' ifAbsent: [ nil ]) ifNotNil: [ :content | content asJQuery ] ].
  175. contents ifNil: [ contents := frozen target asJQuery contents detach ].
  176. frozen target trapIter: #() after: [ :html |
  177. html root asJQuery append: contents clone.
  178. Trapped current injectToJQuery: html root asJQuery ]
  179. ! !
  180. TrappedProcessorLoopBase subclass: #TrappedProcessorLoopProc
  181. instanceVariableNames: ''
  182. package: 'Trapped-Processors'!
  183. !TrappedProcessorLoopProc commentStamp!
  184. I am used to loop over data and repeat the contents filling process
  185. of the brush I am installed on.
  186. I observe the data in the model,
  187. and when it changes, I loop over it
  188. and run the rest of the processing chain
  189. for each element, putting the result _after_ my brush.
  190. My brush itself should be as least visible as possible,
  191. as it only serve as a position flag (use for example
  192. noscript, ins or del).!
  193. !TrappedProcessorLoopProc methodsFor: 'data transformation'!
  194. toView: aDataCarrier
  195. | frozen |
  196. frozen := aDataCarrier copy.
  197. frozen target trapIter: #() after: [ :html | frozen copy target: html root; proceed ]
  198. ! !
  199. TrappedProcessor subclass: #TrappedProcessorReplace
  200. instanceVariableNames: 'left right'
  201. package: 'Trapped-Processors'!
  202. !TrappedProcessorReplace commentStamp!
  203. I convert data to string representation and do a regex replace.
  204. I get two parameters, in toView:, first is replaced with second,
  205. and in toModel:, the second is replaced with first.
  206. I remove leading '^' and ending '$' from the string used as replacement,
  207. so it safe to replace ^to with ^To, for example.!
  208. !TrappedProcessorReplace methodsFor: 'accessing'!
  209. left: aString
  210. left := aString
  211. !
  212. right: aString
  213. right := aString
  214. ! !
  215. !TrappedProcessorReplace methodsFor: 'data transformation'!
  216. toModel: aDataCarrier
  217. | replacement old |
  218. replacement := (left replace: '^\^' with: '') replace: '\$$' with: ''.
  219. old := aDataCarrier value asString.
  220. aDataCarrier
  221. value: (old replace: right with: replacement) whenDifferentFrom: old;
  222. proceed
  223. !
  224. toView: aDataCarrier
  225. | replacement old |
  226. replacement := (right replace: '^\^' with: '') replace: '\$$' with: ''.
  227. old := aDataCarrier value asString.
  228. aDataCarrier
  229. value: (old replace: left with: replacement) whenDifferentFrom: old;
  230. proceed
  231. ! !
  232. !TrappedProcessorReplace class methodsFor: 'instance creation'!
  233. new: aString with: anotherString
  234. ^ self new
  235. left: aString asString;
  236. right: anotherString asString;
  237. yourself
  238. ! !
  239. TrappedProcessor subclass: #TrappedProcessorSignal
  240. instanceVariableNames: 'selector'
  241. package: 'Trapped-Processors'!
  242. !TrappedProcessorSignal commentStamp!
  243. Instead of writing data directly to model,
  244. I instead modify it by sending a message specified when instantiating me.!
  245. !TrappedProcessorSignal methodsFor: 'accessing'!
  246. selector: aString
  247. selector := aString
  248. ! !
  249. !TrappedProcessorSignal methodsFor: 'data transformation'!
  250. toModel: aDataCarrier
  251. aDataCarrier modifyTargetByPerforming: selector
  252. !
  253. toView: aDataCarrier
  254. "stop"
  255. ! !
  256. !TrappedProcessorSignal class methodsFor: 'instance creation'!
  257. new: aString
  258. ^self new
  259. selector: aString;
  260. yourself
  261. ! !
  262. TrappedDataExpectingProcessor subclass: #TrappedProcessorToBlackboard
  263. instanceVariableNames: ''
  264. package: 'Trapped-Processors'!
  265. !TrappedProcessorToBlackboard commentStamp!
  266. I save the data to blackboard in toModel:, to position specified by path.!
  267. !TrappedProcessorToBlackboard methodsFor: 'data transformation'!
  268. toModel: aDataCarrier
  269. aDataCarrier target modify: [ aDataCarrier value ]
  270. ! !
  271. TrappedProcessor subclass: #TrappedProcessorUriComponentDecode
  272. instanceVariableNames: ''
  273. package: 'Trapped-Processors'!
  274. !TrappedProcessorUriComponentDecode commentStamp!
  275. I uriComponentDecode in toView:
  276. and encode in toModel:!
  277. !TrappedProcessorUriComponentDecode methodsFor: 'data transformation'!
  278. toModel: aDataCarrier
  279. aDataCarrier
  280. value: aDataCarrier value uriComponentEncoded;
  281. proceed
  282. !
  283. toView: aDataCarrier
  284. aDataCarrier
  285. value: aDataCarrier value uriComponentDecoded;
  286. proceed
  287. ! !
  288. TrappedProcessor subclass: #TrappedProcessorUriComponentEncode
  289. instanceVariableNames: ''
  290. package: 'Trapped-Processors'!
  291. !TrappedProcessorUriComponentEncode commentStamp!
  292. I uriComponentEncode in toView:
  293. and decode in toModel:!
  294. !TrappedProcessorUriComponentEncode methodsFor: 'data transformation'!
  295. toModel: aDataCarrier
  296. aDataCarrier
  297. value: aDataCarrier value uriComponentDecoded;
  298. proceed
  299. !
  300. toView: aDataCarrier
  301. aDataCarrier
  302. value: aDataCarrier value uriComponentEncoded;
  303. proceed
  304. ! !
  305. TrappedProcessor subclass: #TrappedProcessorWhenClicked
  306. instanceVariableNames: ''
  307. package: 'Trapped-Processors'!
  308. !TrappedProcessorWhenClicked commentStamp!
  309. I bind to an element and send true to blackboard when clicked.!
  310. !TrappedProcessorWhenClicked methodsFor: 'installation'!
  311. installToView: aDataCarrier toModel: anotherDataCarrier
  312. aDataCarrier target onClick: [ anotherDataCarrier copy proceed. false ]
  313. ! !
  314. TrappedProcessor subclass: #TrappedProcessorWhenSubmitted
  315. instanceVariableNames: ''
  316. package: 'Trapped-Processors'!
  317. !TrappedProcessorWhenSubmitted commentStamp!
  318. I bind to a form and send true to blackboard when submitted.!
  319. !TrappedProcessorWhenSubmitted methodsFor: 'installation'!
  320. installToView: aDataCarrier toModel: anotherDataCarrier
  321. aDataCarrier target onSubmit: [ anotherDataCarrier copy proceed. false ]
  322. ! !
  323. TrappedProcessor subclass: #TrappedProcessorWidget
  324. instanceVariableNames: 'viewName'
  325. package: 'Trapped-Processors'!
  326. !TrappedProcessorWidget commentStamp!
  327. I insert a widget instance of the class specified when creating me.!
  328. !TrappedProcessorWidget methodsFor: 'accessing'!
  329. viewName: aString
  330. viewName := aString
  331. ! !
  332. !TrappedProcessorWidget methodsFor: 'data transformation'!
  333. toView: aDataCarrier
  334. aDataCarrier target with: (Smalltalk current at: viewName) new
  335. ! !
  336. !TrappedProcessorWidget class methodsFor: 'instance creation'!
  337. new: aString
  338. ^self new
  339. viewName: aString;
  340. yourself
  341. ! !
  342. !TrappedDataCarrier methodsFor: '*Trapped-Processors'!
  343. modifyTarget
  344. self target modify: [ self value ]
  345. !
  346. modifyTargetByPerforming: aString
  347. self target modify: [ :m | m perform: aString ]
  348. !
  349. toTargetAttr: aString
  350. self falseAsNilValue
  351. ifNil: [ self target removeAt: aString ]
  352. ifNotNil: [ :value | self target at: aString put: (value = true ifTrue: [ aString ] ifFalse: [ value ]) ]
  353. !
  354. toTargetContents
  355. self target contents: self value
  356. !
  357. toTargetValue
  358. self target asJQuery val: (self value ifNotNil: [ :o | o value ] ifNil: [[]])
  359. ! !
  360. !TrappedProcessor class methodsFor: '*Trapped-Processors'!
  361. attr: aString
  362. ^TrappedProcessorAttribute new: aString
  363. !
  364. dataToView: aBlock
  365. ^TrappedProcessorDataAdhoc newToView: aBlock
  366. !
  367. deuric
  368. ^TrappedProcessorUriComponentDecoded new
  369. !
  370. guardContents: anArray
  371. ^TrappedProcessorGuardContents new: anArray
  372. !
  373. guardProc: anArray
  374. ^TrappedProcessorGuardProc new: anArray
  375. !
  376. inputChecked
  377. ^TrappedProcessorInputChecked new
  378. !
  379. inputValue
  380. ^TrappedProcessorInputValue new
  381. !
  382. loopContents
  383. ^TrappedProcessorLoopContents new
  384. !
  385. loopProc
  386. ^TrappedProcessorLoopProc new
  387. !
  388. path
  389. ^TrappedProcessorDescend new
  390. !
  391. replace: aString with: anotherString
  392. ^TrappedProcessorReplace new: aString with: anotherString
  393. !
  394. signal: aString
  395. ^TrappedProcessorSignal new: aString
  396. !
  397. toBlackboard
  398. ^TrappedProcessorToBlackboard new
  399. !
  400. uric
  401. ^TrappedProcessorUriComponentEncoded new
  402. !
  403. whenClicked
  404. ^TrappedProcessorWhenClicked new
  405. !
  406. whenSubmitted
  407. ^TrappedProcessorWhenSubmitted new
  408. !
  409. widget: aString
  410. ^TrappedProcessorWidget new: aString
  411. ! !