Trapped-Processors.st 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  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 injectToChildren: aDataCarrier target element
  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: #TrappedProcessorGuard
  75. instanceVariableNames: ''
  76. package: 'Trapped-Processors'!
  77. !TrappedProcessorGuard commentStamp!
  78. I am used to guard contents filling process of the brush I am installed on.
  79. 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 run the rest on the chain, which should be one-time
  83. that sets up the contents,!
  84. !TrappedProcessorGuard methodsFor: 'data transformation'!
  85. toView: aDataCarrier
  86. | frozen xon |
  87. frozen := aDataCarrier copy.
  88. xon := frozen xontent.
  89. frozen target trapGuard: guardPath contents: [ :html | frozen copy target: html root; xontent: xon; proceed ]
  90. ! !
  91. TrappedDataExpectingProcessor subclass: #TrappedProcessorInputChecked
  92. instanceVariableNames: ''
  93. package: 'Trapped-Processors'!
  94. !TrappedProcessorInputChecked commentStamp!
  95. I bind to checkbox checked state.!
  96. !TrappedProcessorInputChecked methodsFor: 'data transformation'!
  97. toView: aDataCarrier
  98. aDataCarrier toTargetProp: 'checked'
  99. ! !
  100. !TrappedProcessorInputChecked methodsFor: 'installation'!
  101. installToView: aDataCarrier toModel: anotherDataCarrier
  102. | brush |
  103. brush := aDataCarrier target.
  104. brush onChange: [ anotherDataCarrier copy value: (brush asJQuery prop: 'checked'); proceed ]
  105. ! !
  106. TrappedDataExpectingProcessor subclass: #TrappedProcessorInputValue
  107. instanceVariableNames: ''
  108. package: 'Trapped-Processors'!
  109. !TrappedProcessorInputValue commentStamp!
  110. I bind to input value.!
  111. !TrappedProcessorInputValue methodsFor: 'data transformation'!
  112. toView: aDataCarrier
  113. aDataCarrier toTargetValue
  114. ! !
  115. !TrappedProcessorInputValue methodsFor: 'installation'!
  116. installToView: aDataCarrier toModel: anotherDataCarrier
  117. | brush |
  118. brush := aDataCarrier target.
  119. brush onChange: [ anotherDataCarrier copy value: brush asJQuery val; proceed ]
  120. ! !
  121. TrappedProcessor subclass: #TrappedProcessorLoopBase
  122. instanceVariableNames: ''
  123. package: 'Trapped-Processors'!
  124. !TrappedProcessorLoopBase commentStamp!
  125. I serve as base class for looping processors.
  126. I cover instantiation and subclasses have to provide
  127. implementation of toVIew: that loops appropriately.!
  128. !TrappedProcessorLoopBase methodsFor: 'data transformation'!
  129. toModel: aDataCarrier
  130. "stop"
  131. !
  132. toView: aDataCarrier
  133. self subclassResponsibility
  134. ! !
  135. TrappedProcessorLoopBase subclass: #TrappedProcessorLoopZ
  136. instanceVariableNames: ''
  137. package: 'Trapped-Processors'!
  138. !TrappedProcessorLoopZ commentStamp!
  139. I am used to loop over data and repeat the contents filling process
  140. of the brush I am installed on.
  141. I observe the data in the model,
  142. and when it changes, I loop over it
  143. and run the rest of the processing chain
  144. for each element, putting the result _after_ my brush.
  145. My brush itself should be as least visible as possible,
  146. as it only serve as a position flag (use for example
  147. script type=application/x-beacon, noscript, ins or del).!
  148. !TrappedProcessorLoopZ methodsFor: 'data transformation'!
  149. toView: aDataCarrier
  150. | frozen xon |
  151. frozen := aDataCarrier copy.
  152. xon := frozen xontent.
  153. frozen target trapIter: #() after: [ :html | frozen copy target: html root; xontent: xon; proceed ]
  154. ! !
  155. TrappedDataExpectingProcessor subclass: #TrappedProcessorOptionValue
  156. instanceVariableNames: ''
  157. package: 'Trapped-Processors'!
  158. !TrappedProcessorOptionValue commentStamp!
  159. I set the option value.
  160. Additionally, when changed (by toView:),
  161. I ping closest <select> with 'trappedselectreplay' event.!
  162. !TrappedProcessorOptionValue methodsFor: 'data transformation'!
  163. toView: aDataCarrier
  164. aDataCarrier toTargetValue.
  165. (aDataCarrier target asJQuery closest: 'select')
  166. trigger: 'trappedselectreplay'
  167. ! !
  168. TrappedProcessor subclass: #TrappedProcessorReplace
  169. instanceVariableNames: 'left right'
  170. package: 'Trapped-Processors'!
  171. !TrappedProcessorReplace commentStamp!
  172. I convert data to string representation and do a regex replace.
  173. I get two parameters, in toView:, first is replaced with second,
  174. and in toModel:, the second is replaced with first.
  175. I remove leading '^' and ending '$' from the string used as replacement,
  176. so it safe to replace ^to with ^To, for example.!
  177. !TrappedProcessorReplace methodsFor: 'accessing'!
  178. left: aString
  179. left := aString
  180. !
  181. right: aString
  182. right := aString
  183. ! !
  184. !TrappedProcessorReplace methodsFor: 'data transformation'!
  185. toModel: aDataCarrier
  186. | replacement old |
  187. replacement := (left replace: '^\^' with: '') replace: '\$$' with: ''.
  188. old := aDataCarrier value asString.
  189. aDataCarrier
  190. value: (old replace: right with: replacement) whenDifferentFrom: old;
  191. proceed
  192. !
  193. toView: aDataCarrier
  194. | replacement old |
  195. replacement := (right replace: '^\^' with: '') replace: '\$$' with: ''.
  196. old := aDataCarrier value asString.
  197. aDataCarrier
  198. value: (old replace: left with: replacement) whenDifferentFrom: old;
  199. proceed
  200. ! !
  201. !TrappedProcessorReplace class methodsFor: 'instance creation'!
  202. new: aString with: anotherString
  203. ^ self new
  204. left: aString asString;
  205. right: anotherString asString;
  206. yourself
  207. ! !
  208. TrappedDataExpectingProcessor subclass: #TrappedProcessorSelectValue
  209. instanceVariableNames: ''
  210. package: 'Trapped-Processors'!
  211. !TrappedProcessorSelectValue commentStamp!
  212. I bind to select value.
  213. When changed (by toView: or by user),
  214. I remember the selected set.
  215. When pinged by 'trappedselectreplay',
  216. I set the remembered value.
  217. This allows to have select-option groups
  218. with later setting of option values
  219. (if those are set via related processor 'optionValue',
  220. which pings me with 'trappedselectreplay').!
  221. !TrappedProcessorSelectValue methodsFor: 'data transformation'!
  222. toView: aDataCarrier
  223. aDataCarrier toTargetValue.
  224. aDataCarrier target asJQuery data: 'trapped.saved.val' put: aDataCarrier value
  225. ! !
  226. !TrappedProcessorSelectValue methodsFor: 'installation'!
  227. installToView: aDataCarrier toModel: anotherDataCarrier
  228. | jq val |
  229. jq := aDataCarrier target asJQuery.
  230. val := jq val.
  231. jq
  232. data: 'trapped.saved.val';
  233. on: 'change' bind: [ anotherDataCarrier copy value: jq val; proceed ];
  234. on: 'trappedselectreplay' bind: [ jq val: (jq data: 'trapped.saved.val') ]
  235. ! !
  236. TrappedProcessor subclass: #TrappedProcessorSignal
  237. instanceVariableNames: 'selector'
  238. package: 'Trapped-Processors'!
  239. !TrappedProcessorSignal commentStamp!
  240. Instead of writing data directly to model,
  241. I instead modify it by sending a message specified when instantiating me.!
  242. !TrappedProcessorSignal methodsFor: 'accessing'!
  243. selector: aString
  244. selector := aString
  245. ! !
  246. !TrappedProcessorSignal methodsFor: 'data transformation'!
  247. toModel: aDataCarrier
  248. aDataCarrier modifyTargetByPerforming: selector
  249. !
  250. toView: aDataCarrier
  251. "stop"
  252. ! !
  253. !TrappedProcessorSignal class methodsFor: 'instance creation'!
  254. new: aString
  255. ^self new
  256. selector: aString;
  257. yourself
  258. ! !
  259. TrappedDataExpectingProcessor subclass: #TrappedProcessorToBlackboard
  260. instanceVariableNames: ''
  261. package: 'Trapped-Processors'!
  262. !TrappedProcessorToBlackboard commentStamp!
  263. I save the data to blackboard in toModel:, to position specified by path.!
  264. !TrappedProcessorToBlackboard methodsFor: 'data transformation'!
  265. toModel: aDataCarrier
  266. aDataCarrier target modify: [ aDataCarrier value ]
  267. ! !
  268. TrappedProcessor subclass: #TrappedProcessorUriComponentDecode
  269. instanceVariableNames: ''
  270. package: 'Trapped-Processors'!
  271. !TrappedProcessorUriComponentDecode commentStamp!
  272. I uriComponentDecode in toView:
  273. and encode in toModel:!
  274. !TrappedProcessorUriComponentDecode methodsFor: 'data transformation'!
  275. toModel: aDataCarrier
  276. aDataCarrier
  277. value: aDataCarrier value uriComponentEncoded;
  278. proceed
  279. !
  280. toView: aDataCarrier
  281. aDataCarrier
  282. value: aDataCarrier value uriComponentDecoded;
  283. proceed
  284. ! !
  285. TrappedProcessor subclass: #TrappedProcessorUriComponentEncode
  286. instanceVariableNames: ''
  287. package: 'Trapped-Processors'!
  288. !TrappedProcessorUriComponentEncode commentStamp!
  289. I uriComponentEncode in toView:
  290. and decode in toModel:!
  291. !TrappedProcessorUriComponentEncode methodsFor: 'data transformation'!
  292. toModel: aDataCarrier
  293. aDataCarrier
  294. value: aDataCarrier value uriComponentDecoded;
  295. proceed
  296. !
  297. toView: aDataCarrier
  298. aDataCarrier
  299. value: aDataCarrier value uriComponentEncoded;
  300. proceed
  301. ! !
  302. TrappedProcessor subclass: #TrappedProcessorWhenClicked
  303. instanceVariableNames: ''
  304. package: 'Trapped-Processors'!
  305. !TrappedProcessorWhenClicked commentStamp!
  306. I bind to an element and send true to blackboard when clicked.!
  307. !TrappedProcessorWhenClicked methodsFor: 'installation'!
  308. installToView: aDataCarrier toModel: anotherDataCarrier
  309. aDataCarrier target onClick: [ anotherDataCarrier copy proceed. false ]
  310. ! !
  311. TrappedProcessor subclass: #TrappedProcessorWhenSubmitted
  312. instanceVariableNames: ''
  313. package: 'Trapped-Processors'!
  314. !TrappedProcessorWhenSubmitted commentStamp!
  315. I bind to a form and send true to blackboard when submitted.!
  316. !TrappedProcessorWhenSubmitted methodsFor: 'installation'!
  317. installToView: aDataCarrier toModel: anotherDataCarrier
  318. aDataCarrier target onSubmit: [ anotherDataCarrier copy proceed. false ]
  319. ! !
  320. TrappedProcessor subclass: #TrappedProcessorWidget
  321. instanceVariableNames: 'viewName'
  322. package: 'Trapped-Processors'!
  323. !TrappedProcessorWidget commentStamp!
  324. I insert a widget instance of the class specified when creating me.!
  325. !TrappedProcessorWidget methodsFor: 'accessing'!
  326. viewName: aString
  327. viewName := aString
  328. ! !
  329. !TrappedProcessorWidget methodsFor: 'data transformation'!
  330. toView: aDataCarrier
  331. aDataCarrier target with: (Smalltalk current at: viewName) new
  332. ! !
  333. !TrappedProcessorWidget class methodsFor: 'instance creation'!
  334. new: aString
  335. ^self new
  336. viewName: aString;
  337. yourself
  338. ! !
  339. TrappedProcessor subclass: #TrappedProcessorXontent
  340. instanceVariableNames: ''
  341. package: 'Trapped-Processors'!
  342. !TrappedProcessorXontent commentStamp!
  343. I am used to show xontent of the brush I am installed on
  344. (see jQuery plugin Xontent for details).
  345. I clone xontent of the brush, put it into HTML
  346. and interpret all contained data-trap attributes.!
  347. !TrappedProcessorXontent methodsFor: 'data transformation'!
  348. toView: aDataCarrier
  349. aDataCarrier target asJQuery append: (Trapped current cloneAndInject: (aDataCarrier xontent get: 0)).
  350. aDataCarrier proceed
  351. ! !
  352. !TrappedDataCarrier methodsFor: '*Trapped-Processors'!
  353. modifyTarget
  354. self target modify: [ self value ]
  355. !
  356. modifyTargetByPerforming: aString
  357. self target modify: [ :m | m perform: aString ]
  358. !
  359. primitive: anObject
  360. <return anObject === nil ? null : anObject.valueOf()>
  361. !
  362. toTargetAttr: aString
  363. self falseAsNilValue
  364. ifNil: [ self target removeAt: aString ]
  365. ifNotNil: [ :bvalue |
  366. | value |
  367. value := self primitive: bvalue.
  368. self target at: aString put: (value = true ifTrue: [ aString ] ifFalse: [ value ]) ]
  369. !
  370. toTargetContents
  371. self target contents: (self primitive: self value)
  372. !
  373. toTargetProp: aString
  374. self target element at: aString put: (self primitive: self value)
  375. !
  376. toTargetValue
  377. self target asJQuery val: (self primitive: self value)
  378. !
  379. xontent
  380. ^self target asJQuery xontent
  381. !
  382. xontent: anObject
  383. self target asJQuery xontent: 'set' data: anObject
  384. ! !
  385. !TrappedProcessor class methodsFor: '*Trapped-Processors'!
  386. attr: aString
  387. ^TrappedProcessorAttribute new: aString
  388. !
  389. dataToView: aBlock
  390. ^TrappedProcessorDataAdhoc newToView: aBlock
  391. !
  392. deuric
  393. ^TrappedProcessorUriComponentDecode new
  394. !
  395. guard: anArray
  396. ^TrappedProcessorGuard new: anArray
  397. !
  398. inputChecked
  399. ^TrappedProcessorInputChecked new
  400. !
  401. inputValue
  402. ^TrappedProcessorInputValue new
  403. !
  404. loopZ
  405. ^TrappedProcessorLoopZ new
  406. !
  407. optionValue
  408. ^TrappedProcessorOptionValue new
  409. !
  410. path
  411. ^TrappedProcessorDescend new
  412. !
  413. replace: aString with: anotherString
  414. ^TrappedProcessorReplace new: aString with: anotherString
  415. !
  416. selectValue
  417. ^TrappedProcessorSelectValue new
  418. !
  419. signal: aString
  420. ^TrappedProcessorSignal new: aString
  421. !
  422. toBlackboard
  423. ^TrappedProcessorToBlackboard new
  424. !
  425. uric
  426. ^TrappedProcessorUriComponentEncode new
  427. !
  428. whenClicked
  429. ^TrappedProcessorWhenClicked new
  430. !
  431. whenSubmitted
  432. ^TrappedProcessorWhenSubmitted new
  433. !
  434. widget: aString
  435. ^TrappedProcessorWidget new: aString
  436. !
  437. xontent
  438. ^TrappedProcessorXontent new
  439. ! !