Moka-Controllers.st 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. Smalltalk createPackage: 'Moka-Controllers'!
  2. MKSingleAspectController subclass: #MKAnyKeyInputController
  3. instanceVariableNames: 'lastValue'
  4. package: 'Moka-Controllers'!
  5. !MKAnyKeyInputController commentStamp!
  6. I am the default controller for `MKTextAreaView`. Actions are performed on any key press if the view's value changes.!
  7. !MKAnyKeyInputController methodsFor: 'accessing'!
  8. inputText
  9. ^ self view value
  10. ! !
  11. !MKAnyKeyInputController methodsFor: 'actions'!
  12. onKeyUp: anEvent
  13. self setNewValue
  14. !
  15. setNewValue
  16. | newValue |
  17. newValue := self inputText.
  18. newValue = lastValue ifTrue: [ ^ self ].
  19. lastValue := newValue.
  20. self performAspectActionWith: newValue
  21. ! !
  22. MKAnyKeyInputController subclass: #MKEnterInputController
  23. instanceVariableNames: ''
  24. package: 'Moka-Controllers'!
  25. !MKEnterInputController commentStamp!
  26. I am the default controller for `MKInputView`.
  27. Actions are performed on 'enter' key press.!
  28. !MKEnterInputController methodsFor: 'actions'!
  29. onKeyDown: anEvent
  30. anEvent keyCode = String cr asciiValue ifTrue: [
  31. self setNewValue ]
  32. !
  33. onKeyUp: anEvent
  34. ! !
  35. MKSingleAspectController subclass: #MKButtonController
  36. instanceVariableNames: ''
  37. package: 'Moka-Controllers'!
  38. !MKButtonController commentStamp!
  39. I am the default controller for `MKButtonView`.!
  40. !MKButtonController methodsFor: 'actions'!
  41. onClick: anEvent
  42. self performAspectAction
  43. ! !
  44. MKSingleAspectController subclass: #MKCheckboxController
  45. instanceVariableNames: ''
  46. package: 'Moka-Controllers'!
  47. !MKCheckboxController commentStamp!
  48. I am the default controller for `MKCheckboxView`.!
  49. !MKCheckboxController methodsFor: 'actions'!
  50. onClick: anEvent
  51. self toggle
  52. !
  53. onKeyDown: anEvent
  54. "Avoid scrolling in scrollable views"
  55. anEvent stopPropagation
  56. !
  57. onKeyPress: anEvent
  58. anEvent charCode = ' ' asciiValue ifTrue: [
  59. self toggle.
  60. anEvent stopPropagation; preventDefault ]
  61. !
  62. toggle
  63. self performAspectActionWith: self view checked not
  64. ! !
  65. MKAspectsController subclass: #MKDropdownController
  66. instanceVariableNames: ''
  67. package: 'Moka-Controllers'!
  68. !MKDropdownController commentStamp!
  69. I am the default controller for `MKDropdownView`.!
  70. !MKDropdownController methodsFor: 'actions'!
  71. onClick: anEvent
  72. self view popupList
  73. !
  74. onKeyDown: anEvent
  75. anEvent keyCode = String cr asciiValue ifTrue: [
  76. self view popupList ]
  77. ! !
  78. MKAspectsController subclass: #MKListController
  79. instanceVariableNames: 'downRepeater upRepeater'
  80. package: 'Moka-Controllers'!
  81. !MKListController commentStamp!
  82. I am the default controller for `MKListView`.!
  83. !MKListController methodsFor: 'accessing'!
  84. activeItem
  85. ^ self view activeItem
  86. !
  87. collection
  88. ^ self view collection
  89. !
  90. downRepeater
  91. ^ downRepeater ifNil: [ downRepeater := MKRepeater new ]
  92. !
  93. upRepeater
  94. ^ upRepeater ifNil: [ upRepeater := MKRepeater new ]
  95. ! !
  96. !MKListController methodsFor: 'actions'!
  97. activateItem: anItem
  98. "On item activation, change the model selection"
  99. self selectItem: anItem
  100. !
  101. onClick: anEvent
  102. self selectItem: (self itemForTarget: anEvent target)
  103. !
  104. onKeyDown: anEvent
  105. "Down"
  106. anEvent keyCode = 40 ifTrue: [
  107. anEvent preventDefault; stopPropagation.
  108. self upRepeater stopRepeating.
  109. self downRepeater repeat: [
  110. self activateItem: self nextItem ] ].
  111. "Up"
  112. anEvent keyCode = 38 ifTrue: [
  113. anEvent preventDefault; stopPropagation.
  114. self downRepeater stopRepeating.
  115. self upRepeater repeat: [
  116. self activateItem: self previousItem ] ].
  117. !
  118. onKeyUp: anEvent
  119. self downRepeater stopRepeating.
  120. self upRepeater stopRepeating
  121. !
  122. selectItem: anItem
  123. self
  124. performAspectAction: self view selectionAspect
  125. with: anItem
  126. ! !
  127. !MKListController methodsFor: 'private'!
  128. itemForTarget: aDOMElement
  129. ^ self view findItemFor: aDOMElement
  130. !
  131. nextItem
  132. ^ self collection
  133. at: (self collection indexOf: self activeItem) + 1
  134. ifAbsent: [ self collection last ]
  135. !
  136. previousItem
  137. ^ self view collection
  138. at: (self view collection indexOf: self activeItem) - 1
  139. ifAbsent: [ self view collection first ]
  140. ! !
  141. MKListController subclass: #MKDropdownListController
  142. instanceVariableNames: ''
  143. package: 'Moka-Controllers'!
  144. !MKDropdownListController commentStamp!
  145. I am the default controller for `MKDropdownView`'s popup list.!
  146. !MKDropdownListController methodsFor: 'actions'!
  147. activateItem: anItem
  148. "Select the list item in the view.
  149. No change is done to the model"
  150. self view activateItem: anItem
  151. !
  152. onKeyDown: anEvent
  153. super onKeyDown: anEvent.
  154. anEvent keyCode = String cr asciiValue ifTrue: [
  155. self selectItem: self view activeItem ]
  156. !
  157. onMouseMove: anEvent
  158. (self upRepeater isRepeating or: [ self downRepeater isRepeating ])
  159. ifTrue: [ ^ self ].
  160. self activateItem: (self itemForTarget: anEvent target)
  161. ! !
  162. MKSingleAspectController subclass: #MKModalController
  163. instanceVariableNames: ''
  164. package: 'Moka-Controllers'!
  165. !MKModalController commentStamp!
  166. I am the default controller for `MKModalDecorator`.!
  167. !MKModalController methodsFor: 'actions'!
  168. onClick: anEvent
  169. self view closeOnClick ifTrue: [ self removeView ]
  170. !
  171. onKeyDown: anEvent
  172. self view closeOnEnter ifTrue: [
  173. anEvent keyCode = String cr asciiValue ifTrue: [
  174. self removeView.
  175. anEvent
  176. stopPropagation;
  177. preventDefault ] ].
  178. "ESC"
  179. anEvent keyCode = 27 ifTrue: [
  180. self removeView ]
  181. !
  182. removeView
  183. self view overlay remove
  184. ! !
  185. MKSingleAspectController subclass: #MKOverlayController
  186. instanceVariableNames: ''
  187. package: 'Moka-Controllers'!
  188. !MKOverlayController commentStamp!
  189. I am the default controller for `MKOverlayView`.
  190. On a click to the overlay, it is removed together with it's content view.!
  191. !MKOverlayController methodsFor: 'actions'!
  192. onClick: anEvent
  193. self view remove
  194. ! !
  195. Object subclass: #MKRepeater
  196. instanceVariableNames: 'repeatInterval interval delay'
  197. package: 'Moka-Controllers'!
  198. !MKRepeater commentStamp!
  199. I am an internal class used by controllers to repeat block actions after a `delay` and with an `interval`.!
  200. !MKRepeater methodsFor: 'accessing'!
  201. repeatInterval
  202. ^ repeatInterval ifNil: [ self defaultRepeatInterval ]
  203. !
  204. repeatInterval: aNumber
  205. repeatInterval := aNumber
  206. ! !
  207. !MKRepeater methodsFor: 'actions'!
  208. repeat: aBlock
  209. self isRepeating ifTrue: [ ^ self ].
  210. aBlock value.
  211. delay := [ interval := aBlock valueWithInterval: self repeatInterval ]
  212. valueWithTimeout: 300
  213. !
  214. stopRepeating
  215. interval ifNotNil: [ interval clearInterval ].
  216. delay ifNotNil: [ delay clearTimeout ].
  217. interval := delay := nil
  218. ! !
  219. !MKRepeater methodsFor: 'defaults'!
  220. defaultRepeatInterval
  221. ^ 70
  222. ! !
  223. !MKRepeater methodsFor: 'testing'!
  224. isRepeating
  225. ^ delay notNil
  226. ! !
  227. MKController subclass: #MKScrollController
  228. instanceVariableNames: ''
  229. package: 'Moka-Controllers'!
  230. !MKScrollController commentStamp!
  231. I am the default controller for `MKScrollDecorator`.!
  232. !MKScrollController methodsFor: 'actions'!
  233. onDecoratedScroll
  234. self view updateScrollbarsPosition
  235. !
  236. onHorizontalDrag: anEvent
  237. (self view decorated asJQuery get: 0) at: 'scrollLeft' put: self view domScrollPosition x
  238. !
  239. onMousewheel: anEvent
  240. anEvent deltaY ~= 0 ifTrue: [
  241. self view scrollDeltaY: anEvent deltaY * 10 ].
  242. anEvent deltaX ~= 0 ifTrue: [
  243. self view scrollDeltaX: anEvent deltaX * 10 ]
  244. !
  245. onResize
  246. self view resized
  247. !
  248. onVerticalDrag: anEvent
  249. (self view decorated asJQuery get: 0) at: 'scrollTop' put: self view domScrollPosition y
  250. ! !
  251. MKController subclass: #MKSplitController
  252. instanceVariableNames: ''
  253. package: 'Moka-Controllers'!
  254. !MKSplitController commentStamp!
  255. I am the abstract controller for `MKSplitView`.!
  256. !MKSplitController methodsFor: 'actions'!
  257. onResize: anEvent helper: aJQuery
  258. self placeSplitter: (self positionForSplitter: aJQuery)
  259. !
  260. placeSplitter: aJQuery
  261. self subclassResponsibility
  262. ! !
  263. !MKSplitController methodsFor: 'private'!
  264. positionForSplitter: aJQuery
  265. ^ self subclassResponsibility
  266. ! !
  267. MKSplitController subclass: #MKBottomFixedVerticalSplitController
  268. instanceVariableNames: ''
  269. package: 'Moka-Controllers'!
  270. !MKBottomFixedVerticalSplitController commentStamp!
  271. I am an alternative controller for `MKVerticalSplitView`.
  272. When the splitter is moved, the second view is set a fixed size, thus resizing will preserve the height of the second view, while the first view will be resized.!
  273. !MKBottomFixedVerticalSplitController methodsFor: 'actions'!
  274. placeSplitter: aNumber
  275. | splitter |
  276. splitter := self view splitter asJQuery.
  277. self view secondView asJQuery
  278. css: 'height' put: aNumber asMokaCssString;
  279. css: 'bottom' put: 0.
  280. splitter
  281. css: 'top' put: 'auto';
  282. css: 'bottom' put: (aNumber - splitter height) asMokaCssString.
  283. self view firstView asJQuery css: 'bottom' put: aNumber asMokaCssString
  284. ! !
  285. !MKBottomFixedVerticalSplitController methodsFor: 'private'!
  286. positionForSplitter: aJQuery
  287. ^ ((self view domSize y - aJQuery position top)
  288. max: self view minimumThickness) min: (self view domSize y - self view minimumThickness)
  289. ! !
  290. MKSplitController subclass: #MKLeftFixedHorizontalSplitController
  291. instanceVariableNames: ''
  292. package: 'Moka-Controllers'!
  293. !MKLeftFixedHorizontalSplitController commentStamp!
  294. I am the controller for `MKHorizontalSplitView`.
  295. When the splitter is moved, the left view is set a fixed size, thus resizing will preserve the width of the first view, while the second view will be resized.!
  296. !MKLeftFixedHorizontalSplitController methodsFor: 'actions'!
  297. placeSplitter: aNumber
  298. self view firstView asJQuery css: 'width' put: aNumber asMokaCssString.
  299. self view splitter asJQuery css: 'left' put: aNumber asMokaCssString.
  300. self view secondView asJQuery css: 'left' put: aNumber asMokaCssString
  301. ! !
  302. !MKLeftFixedHorizontalSplitController methodsFor: 'private'!
  303. positionForSplitter: aJQuery
  304. ^ (aJQuery position left max: self view minimumThickness)
  305. min: (self view domSize x - self view minimumThickness)
  306. ! !
  307. MKSplitController subclass: #MKRightFixedHorizontalSplitController
  308. instanceVariableNames: ''
  309. package: 'Moka-Controllers'!
  310. !MKRightFixedHorizontalSplitController commentStamp!
  311. I am an alternative controller for `MKHorizontalSplitView`.
  312. When the splitter is moved, the second view is set a fixed size, thus resizing will preserve the width of the second view, while the first view will be resized.!
  313. !MKRightFixedHorizontalSplitController methodsFor: 'actions'!
  314. placeSplitter: aNumber
  315. | splitter |
  316. splitter := self view splitter asJQuery.
  317. self view secondView asJQuery
  318. css: 'width' put: aNumber asMokaCssString;
  319. css: 'right' put: 0.
  320. splitter
  321. css: 'left' put: 'auto';
  322. css: 'right' put: (aNumber - splitter width) asMokaCssString.
  323. self view firstView asJQuery css: 'right' put: aNumber asMokaCssString
  324. ! !
  325. !MKRightFixedHorizontalSplitController methodsFor: 'private'!
  326. positionForSplitter: aJQuery
  327. ^ ((self view domSize x - aJQuery position left)
  328. max: self view minimumThickness)
  329. min: (self view domSize x - self view minimumThickness)
  330. ! !
  331. MKSplitController subclass: #MKTopFixedVerticalSplitController
  332. instanceVariableNames: ''
  333. package: 'Moka-Controllers'!
  334. !MKTopFixedVerticalSplitController commentStamp!
  335. I am the controller for `MKVerticalSplitView`.
  336. When the splitter is moved, the top view is set a fixed size, thus resizing will preserve the height of the first view, while the second view will be resized.!
  337. !MKTopFixedVerticalSplitController methodsFor: 'actions'!
  338. placeSplitter: aNumber
  339. self view firstView asJQuery css: 'height' put: aNumber asMokaCssString.
  340. self view splitter asJQuery css: 'top' put: aNumber asMokaCssString.
  341. self view secondView asJQuery css: 'top' put: aNumber asMokaCssString
  342. ! !
  343. !MKTopFixedVerticalSplitController methodsFor: 'private'!
  344. positionForSplitter: aJQuery
  345. ^ (aJQuery position top max: self view minimumThickness)
  346. min: (self view domSize y - self view minimumThickness)
  347. ! !