123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606 |
- Smalltalk createPackage: 'Moka-Core'!
- Object subclass: #MKController
- instanceVariableNames: 'view model'
- package: 'Moka-Core'!
- I implement the Controller part of the MVC pattern in Moka.
- I hold onto my `model` and `view`, set with `MKView >> controller:`.!
- model
- ^ model
- model: aModel
- model := aModel
- view
- ^ view
- view: aView
- view := aView
- onChange: anEvent
- onClick: anEvent
- onDblClick: anEvent
- onKeyDown: anEvent
- onKeyPress: anEvent
- onKeyUp: anEvent
- onMouseEnter: anEvent
- onMouseLeave: anEvent
- onMouseMove: anEvent
- onMouseOut: anEvent
- onMouseOver: anEvent
- MKController subclass: #MKAspectsController
- instanceVariableNames: ''
- package: 'Moka-Core'!
- I am an abstract controller for performing one action using an `aspect` on a model.
- - Use `#aspect:` to plug a selector to be performed on the model
- - Subclasses can either use `#performActionWith:` or `#performAction` to evaluate the `aspect` selector on the model with one or no argument.!
- performAspectAction: aSelector
- self model perform: aSelector
- performAspectAction: aSelector with: anObject
- self model
- perform: aSelector asMutator
- withArguments: { anObject }
- MKAspectsController subclass: #MKSingleAspectController
- instanceVariableNames: ''
- package: 'Moka-Core'!
- I am an abstract controller used with single aspect views.
- My view must hold onto one aspect accessed with `#aspect`.!
- performAspectAction
- ^ self performAspectAction: self view aspect
- performAspectActionWith: anObject
- ^ self
- performAspectAction: self view aspect
- with: anObject
- Object subclass: #MKObservable
- instanceVariableNames: 'announcer'
- package: 'Moka-Core'!
- View models are typically subclasses of me.
- I implement the Observable part of the Observer pattern in Moka.
- The observer pattern is implemented through an `announcer` object.
- - Listening
- Use `#on:do:` or `#on:send:to:` to listen to receiver changes
- - Triggering
- `#changed:` is the builtin method used to trigger `#update:` in views.
- Use `#announce:` in subclasses to trigger announcements to listeners.!
- announce: anAnnouncement
- announcer announce: anAnnouncement
- changed: aSelector
- "Trigger `#update:` to all listening aspect views"
-
- self announce: (MKAspectChanged aspect: aSelector)
- on: anAnnouncement do: aBlock
- announcer on: anAnnouncement do: aBlock
- on: anAnnouncement send: aSelector to: anObject
- announcer on: anAnnouncement send: aSelector to: anObject
- initialize
- super initialize.
- announcer := Announcer new
- MKObservable subclass: #MKView
- instanceVariableNames: 'controller model root extraCssClass'
- package: 'Moka-Core'!
- I implement the View part of the MVC pattern in Moka.
- - Instance can be created with the `MKView class >> model:*` convenience methods
- - rendering is done through `#renderContentOn:`, to be overridden in concrete view classes
- - `#update` provide updating facility, refreshing the entire view
- - subclasses can override `#defaultControllerClass` to provide a default controller specific to a view
- - subclasses can override `#observeModel`
- - Extra css classes can be added with `#extraCssClass:`.!
- children
- "Answer all the sub-views of the receiver"
- ^ #()
- controller
- "Answer the current receiver's controller.
- If no controller is installed yet, install the `defaultController`
- of the receiver and answer it."
-
- controller ifNil: [
- self controller: self defaultController ].
- ^ controller
- controller: aController
- "Install `aController` to be the receiver's controller"
-
- controller := aController.
- aController
- view: self;
- model: self model
- cssClass
- ^ String streamContents: [ :stream |
- stream << 'moka_view'.
- self extraCssClass ifNotEmpty: [
- stream << ' ' << self extraCssClass ] ]
- cssStyle
- ^ ''
- extraCssClass
- ^ extraCssClass ifNil: [ '' ]
- extraCssClass: aString
- extraCssClass := aString
- model
- ^ model
- model: aModel
- model := aModel.
- self observeModel
- tag
- ^ 'div'
- blur
- root ifNotNil: [ root asJQuery blur ]
- focus
- root ifNotNil: [ root asJQuery focus ]
- remove
- "Removes the receiver from the DOM"
- root ifNotNil: [ root asJQuery remove ].
-
- self announce: (MKViewRemoved view: self)
- resized
- "Action triggered when the view has been resized from the outside"
-
- self children do: [ :each | each resized ]
- appendToBrush: aTagBrush
- self appendToJQuery: aTagBrush asJQuery
- appendToJQuery: aJQuery
- self renderOn: (HTMLCanvas onJQuery: aJQuery)
- asJQuery
- ^ root asJQuery
- defaultControllerClass
- ^ MKController
- domPosition
- "Answer the position of the reciever in the page"
-
- | offset |
- offset := self asJQuery offset.
- ^ offset left @ offset top
- domSize
- ^ self asJQuery width @ self asJQuery height
- defaultController
- ^ self defaultControllerClass new
- observeModel
- "No op. Override in subclasses"
- setupEventHandlers
- root
- onClick: [ :event | self controller onClick: event ];
- onDblClick: [ :event | self controller onDblClick: event ];
- onMouseEnter: [ :event | self controller onMouseEnter: event ];
- onMouseLeave: [ :event | self controller onMouseLeave: event ];
- onMouseOver: [ :event | self controller onMouseOver: event ];
- onMouseOut: [ :event | self controller onMouseOut: event ];
- onMouseMove: [ :event | self controller onMouseMove: event ];
- onKeyDown: [ :event | self controller onKeyDown: event ];
- onKeyUp: [ :event | self controller onKeyUp: event ];
- onKeyPress: [ :event | self controller onKeyPress: event ];
- onChange: [ :event | self controller onChange: event ]
- render
- "Append the receiver to the BODY element"
-
- self appendToJQuery: 'body' asJQuery
- renderContentOn: html
- "Main rendering method, override in subclasses."
- renderOn: html
- "Basic rendering method.
- Do not override this method, but `#renderContentOn:`"
-
- root := (html tag: self tag)
- class: self cssClass;
- style: self cssStyle;
- yourself.
- root with: [ self renderContentOn: html ].
-
- self setupEventHandlers
- update
- "Update the view's content. Override in subclasses to fine-tune updating"
-
- root ifNil: [ ^ self ].
-
- root asJQuery empty.
- [ :html | self renderContentOn: html ]
- appendToJQuery: root asJQuery
- model: aModel
- ^ self new
- model: aModel;
- yourself
- model: aModel controller: aController
- ^ (self model: aModel)
- controller: aController;
- yourself
- MKView subclass: #MKLayoutView
- instanceVariableNames: 'layout'
- package: 'Moka-Core'!
- I implement the View part of the MVC pattern in Moka.
- - Instance can be created with the `MKView class >> model:*` convenience methods
- - rendering is done through `#renderContentOn:`, to be overridden in concrete view classes
- - `#update` provide updating facility, refreshing the entire view
- - subclasses can override `#defaultControllerClass` to provide a default controller specific to a view
- - subclasses can override `#observeModel`
- - Extra css classes can be added with `#extraCssClass:`.!
- cssStyle
- ^ self layout asCssString
- layout
- ^ layout ifNil: [ layout := self defaultLayout ]
- defaultLayout
- ^ MKLayout new
- left: 0;
- top: 0;
- right: 0;
- bottom: 0;
- yourself
- bottom
- ^ self layout bottom
- bottom: aNumber
- self layout bottom: aNumber
- centerX
- ^ self layout centerX
- centerX: aNumber
- self layout centerX: aNumber
- centerY
- ^ self layout centerY
- centerY: aNumber
- self layout centerY: aNumber
- height
- ^ self layout height
- height: aNumber
- self layout height: aNumber
- left
- ^ self layout left
- left: aNumber
- self layout left: aNumber
- right
- ^ self layout right
- right: aNumber
- self layout right: aNumber
- top
- ^ self layout top
- top: aNumber
- self layout top: aNumber
- width
- ^ self layout width
- width: aNumber
- self layout width: aNumber
- model: aModel
- ^ self new
- model: aModel;
- yourself
- model: aModel controller: aController
- ^ (self model: aModel)
- controller: aController;
- yourself
- MKLayoutView subclass: #MKAspectsView
- instanceVariableNames: ''
- package: 'Moka-Core'!
- I am an abstract view which state depend on aspects of a model.!
- valueForAspect: aSelector
- ^ self model perform: aSelector
- defaultControllerClass
- ^ MKAspectController
- observeModel
- super observeModel.
-
- self model
- on: MKAspectChanged
- send: 'update:'
- to: self
- update: anAnnouncement
- "Override in subclasses to match the view's aspect(s)"
- MKAspectsView subclass: #MKSingleAspectView
- instanceVariableNames: 'aspect'
- package: 'Moka-Core'!
- I am an abstract view which state depend on an `aspect` of a model.
- - Use the `#aspect:` to listen to a specific aspect of a model. Changes will then trigger `#update`.!
- aspect
- ^ aspect
- aspect: aSelector
- aspect := aSelector
- aspectValue
- ^ self valueForAspect: self aspect
- defaultControllerClass
- ^ MKSingleAspectController
- update: anAnnouncement
- anAnnouncement aspect = self aspect ifTrue: [
- self update ]
- model: aModel aspect: aSelector
- ^ (self model: aModel)
- aspect: aSelector;
- yourself
- MKLayoutView subclass: #MKDecorator
- instanceVariableNames: 'decorated'
- package: 'Moka-Core'!
- I am root class of the decorator pattern in Moka.
- I am used to add rendering and/or behavior to other views.
- To decorate a view, use the class-side `#decorate:` method.!
- children
- ^ { self decorated }
- decorated
- ^ decorated
- decorated: aView
- decorated := aView.
- self observeDecorated
- observeDecorated
- "Override in subclasses"
- renderContentOn: html
- html with: self decorated
- decorate: aView
- ^ self new
- decorated: aView;
- yourself
|