Trapped-Processors.st 14 KB

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