Trapped-Processors.st 14 KB

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