Trapped-Frontend.st 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. Smalltalk current createPackage: 'Trapped-Frontend' properties: #{}!
  2. Object subclass: #TrappedBinder
  3. instanceVariableNames: 'brush'
  4. package: 'Trapped-Frontend'!
  5. !TrappedBinder methodsFor: 'accessing'!
  6. brush: aTagBrush
  7. brush := aTagBrush
  8. ! !
  9. !TrappedBinder methodsFor: 'action'!
  10. installFor: path
  11. brush trap: path read: self showBlock
  12. !
  13. showBlock
  14. ^[ :model | brush empty; with: (model ifNil: [[]]) ]
  15. ! !
  16. !TrappedBinder methodsFor: 'converting'!
  17. prim: anObject
  18. <return anObject.valueOf()>
  19. ! !
  20. TrappedBinder subclass: #TrappedCheckedBinder
  21. instanceVariableNames: ''
  22. package: 'Trapped-Frontend'!
  23. !TrappedCheckedBinder methodsFor: 'action'!
  24. installFor: path
  25. super installFor: path.
  26. path trapDescend: [ :snap |
  27. brush onChange: [ snap modify: [
  28. (brush asJQuery attr: 'checked') notNil
  29. ]]
  30. ]
  31. !
  32. showBlock
  33. ^[ :model | brush asJQuery attr: 'checked' put: (model ifNotNil: [ self prim: model ] ifNil: [ false ]) ]
  34. ! !
  35. TrappedBinder subclass: #TrappedValBinder
  36. instanceVariableNames: ''
  37. package: 'Trapped-Frontend'!
  38. !TrappedValBinder methodsFor: 'action'!
  39. installFor: path
  40. super installFor: path.
  41. path trapDescend: [ :snap |
  42. brush onChange: [ snap modify: [
  43. brush asJQuery val
  44. ]]
  45. ]
  46. !
  47. showBlock
  48. ^[ :model | brush asJQuery val: (model ifNotNil: [self prim: model] ifNil: [[]]) ]
  49. ! !
  50. Widget subclass: #TrappedDumbView
  51. instanceVariableNames: ''
  52. package: 'Trapped-Frontend'!
  53. !TrappedDumbView commentStamp!
  54. I just read and show an actual path.!
  55. !TrappedDumbView methodsFor: 'rendering'!
  56. renderOn: html
  57. html root trap: #()
  58. ! !
  59. Object subclass: #TrappedSingleton
  60. instanceVariableNames: ''
  61. package: 'Trapped-Frontend'!
  62. !TrappedSingleton methodsFor: 'action'!
  63. start: args
  64. ^ self subclassResponsibility
  65. ! !
  66. TrappedSingleton class instanceVariableNames: 'current'!
  67. !TrappedSingleton class methodsFor: 'accessing'!
  68. current
  69. ^ current ifNil: [ current := self new ]
  70. ! !
  71. !TrappedSingleton class methodsFor: 'action'!
  72. start: args
  73. self current start: args
  74. ! !
  75. TrappedSingleton subclass: #Trapped
  76. instanceVariableNames: 'registry'
  77. package: 'Trapped-Frontend'!
  78. !Trapped methodsFor: 'accessing'!
  79. byName: aString
  80. ^ registry at: aString
  81. !
  82. register: aListKeyedEntity
  83. self register: aListKeyedEntity name: aListKeyedEntity class name
  84. !
  85. register: aListKeyedEntity name: aString
  86. registry at: aString put: aListKeyedEntity
  87. ! !
  88. !Trapped methodsFor: 'action'!
  89. descend: anArray snapshotDo: aBlock
  90. | tpsc |
  91. tpsc := TrappedPathStack current.
  92. tpsc append: anArray do: [
  93. | path model |
  94. path := tpsc elements copy.
  95. model := self byName: path first.
  96. aBlock value: (TrappedSnapshot new path: path model: model)
  97. ]
  98. !
  99. start: args
  100. args do: [ :each | self register: each ].
  101. '[data-trap]' asJQuery each: [ :index :elem |
  102. | trap jq viewName modelName tokens path |
  103. jq := elem asJQuery.
  104. trap := jq attr: 'data-trap'.
  105. tokens := trap tokenize: ':'.
  106. tokens size = 1 ifTrue: [ tokens := { 'TrappedDumbView' }, tokens ].
  107. viewName := tokens first.
  108. tokens := (tokens second tokenize: ' ') select: [ :each | each notEmpty ].
  109. modelName := tokens first.
  110. path := Trapped parse: tokens allButFirst.
  111. { modelName }, path trapDescend: [(Smalltalk current at: viewName) new appendToJQuery: jq].
  112. ]
  113. ! !
  114. !Trapped methodsFor: 'binders'!
  115. binder: aTagBrush
  116. "Prototype; will select based on tag etc."
  117. | binder tag |
  118. tag := aTagBrush element nodeName.
  119. tag = 'INPUT' ifTrue: [
  120. | type |
  121. type := aTagBrush asJQuery attr: 'type'.
  122. type = 'checkbox' ifTrue: [ binder := TrappedCheckedBinder new ].
  123. type = 'text' ifTrue: [ binder := TrappedValBinder new ]
  124. ].
  125. binder ifNil: [ binder := TrappedBinder new ].
  126. ^ binder brush: aTagBrush; yourself
  127. ! !
  128. !Trapped methodsFor: 'initialization'!
  129. initialize
  130. super initialize.
  131. registry := #{}.
  132. ! !
  133. !Trapped class methodsFor: 'accessing'!
  134. parse: anArray
  135. ^anArray collect: [ :each |
  136. | asNum |
  137. asNum = each asNumber.
  138. asNum = asNum ifTrue: [ asNum ] ifFalse: [
  139. each first = '#' ifTrue: [ each allButFirst asSymbol ] ifFalse: [ each ]]]
  140. ! !
  141. !Trapped class methodsFor: 'private'!
  142. envelope: envelope loop: model before: endjq tag: aSymbol do: aBlock
  143. | envjq |
  144. envjq := envelope asJQuery.
  145. model withIndexDo: [ :item :i |
  146. envelope with: [ :html | (html perform: aSymbol) trap: {i} read: aBlock ].
  147. envjq children detach insertBefore: endjq.
  148. ].
  149. envjq remove
  150. !
  151. loop: model between: start and: end tag: aSymbol do: aBlock
  152. (start asJQuery nextUntil: end element) remove.
  153. start with: [ :html | model ifNotNil: [
  154. self envelope: html div loop: model before: end asJQuery tag: aSymbol do: aBlock
  155. ]]
  156. ! !
  157. TrappedSingleton subclass: #TrappedPathStack
  158. instanceVariableNames: 'elements'
  159. package: 'Trapped-Frontend'!
  160. !TrappedPathStack methodsFor: 'accessing'!
  161. elements
  162. ^elements
  163. ! !
  164. !TrappedPathStack methodsFor: 'descending'!
  165. append: anArray do: aBlock
  166. self with: elements, anArray do: aBlock
  167. !
  168. with: anArray do: aBlock
  169. | old |
  170. old := elements.
  171. [ elements := anArray.
  172. aBlock value ] ensure: [ elements := old ]
  173. ! !
  174. !TrappedPathStack methodsFor: 'initialization'!
  175. initialize
  176. super initialize.
  177. elements := #().
  178. ! !
  179. Object subclass: #TrappedSnapshot
  180. instanceVariableNames: 'path model'
  181. package: 'Trapped-Frontend'!
  182. !TrappedSnapshot methodsFor: 'accessing'!
  183. model
  184. ^model
  185. !
  186. path
  187. ^path
  188. !
  189. path: anArray model: aTrappedMW
  190. path := anArray.
  191. model := aTrappedMW
  192. ! !
  193. !TrappedSnapshot methodsFor: 'action'!
  194. do: aBlock
  195. TrappedPathStack current with: path do: [ aBlock value: model ]
  196. !
  197. modify: aBlock
  198. self model modify: self path allButFirst do: aBlock
  199. ! !
  200. !Array methodsFor: '*Trapped-Frontend'!
  201. trapDescend: aBlock
  202. Trapped current descend: self snapshotDo: aBlock
  203. ! !
  204. !HTMLCanvas methodsFor: '*Trapped-Frontend'!
  205. trapIter: path tag: aSymbol do: aBlock
  206. | start end |
  207. self with: [ :html | start := html script. end := html script ].
  208. start trap: path read: [ :model |
  209. Trapped loop: model between: start and: end tag: aSymbol do: aBlock.
  210. ]
  211. ! !
  212. !TagBrush methodsFor: '*Trapped-Frontend'!
  213. trap: path
  214. (Trapped current binder: self) installFor: path
  215. !
  216. trap: path read: aBlock
  217. path trapDescend: [ :snap |
  218. snap model watch: snap path allButFirst do: [ :data |
  219. (self asJQuery closest: 'html') toArray isEmpty ifTrue: [ KeyedPubSubUnsubscribe signal ].
  220. snap do: [ self with: [ :html | aBlock value: data value: html ] ]
  221. ]
  222. ]
  223. !
  224. trap: path toggle: aBlock
  225. self trap: path toggle: aBlock ifNotPresent: [ self asJQuery hide ]
  226. !
  227. trap: path toggle: aBlock ifNotPresent: anotherBlock
  228. | shown |
  229. shown := nil.
  230. self trap: path read: [ :data : html |
  231. shown = data notNil ifFalse: [
  232. shown := data notNil.
  233. self asJQuery empty; show.
  234. (shown ifTrue: [aBlock] ifFalse: [anotherBlock]) value: data value: html.
  235. ]
  236. ]
  237. ! !