Silk.st 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. Smalltalk createPackage: 'Silk'!
  2. Domite subclass: #Silk
  3. instanceVariableNames: ''
  4. package: 'Silk'!
  5. !Silk commentStamp!
  6. I am adding convenience APIs to my subclass, `Domite`.
  7. ##Rendering
  8. - `aSilk << anObject` uses double-dispatch via `renderOnSilk:`. This allows creating widgets (no formal superclass, anything with `renderOnSilk:` is a widget), as well as incorporating magic on other objects:
  9. - blocks: `aSilk << aBlock` runs the block, passing aSilk as a parameter.
  10. - associations: `aSilk << (key -> value)` set attribute key to value.
  11. It is good to note that rendering collection has magic
  12. of its own built-in in general: if you `stream << aCollection`, its items are `<<`'d in sequence.
  13. So, de facto, array are deeply flattened
  14. when putting on a stream via `<<`.
  15. ##Convenience
  16. - `aCssSelectorString asSilk` returns Silk wrapping an element at a selector.
  17. - `anObject inSilk` returns anObject rendered in a document fragment.
  18. ##Element creation
  19. These messages use DNU to dynamically create
  20. elements with any (letters-and-numbers) tag name,
  21. Next samples show this on an example of `<div>`.
  22. - `Silk DIV` is shortcut for `Silk newElement: 'div'`.
  23. - `aSilk DIV` is shortcut for `[ |tmp| tmp := Silk DIV. aSilk << tmp. tmp] value`. IOW, it not just creates the element and returns it, but also puts in on aSilk.
  24. - `aSilk DIV: anObject` is shortcut for `aSilk DIV << anObject; yourself`. IOW, it not just creates and insert the element, but puts a content into it.
  25. ##Conclusions
  26. Taken all this together, one can do pretty neat constructs:
  27. ```
  28. aSilk P: { 'id'->'mission'. 'We are the champions.' }
  29. ```
  30. adds `<p id="mission">We are the champions.</p>` into `aSilk`.!
  31. !Silk methodsFor: 'writing'!
  32. doesNotUnderstand: aMessage
  33. "`aSilk DIV` creates a div element and inserts it.
  34. `aSilk DIV: anObject` creates a div element, inserts it
  35. and puts contents in it"
  36. (self class tryMakeDnuElement: aMessage)
  37. ifNil: [ ^ super doesNotUnderstand: aMessage ]
  38. ifNotNil: [ :newElement | self << newElement. ^ newElement ]
  39. !
  40. nextPut: anObject
  41. "Double-dispatches anObject via renderOnSilk: message.
  42. If a message returns nil, this fallbacks to superclass.
  43. Otherwise, it is assumed renderOnSilk: did its job."
  44. (anObject renderOnSilk: self)
  45. ifNil: [ super nextPut: anObject ]
  46. ! !
  47. !Silk class methodsFor: 'instance creation'!
  48. tryMakeDnuElement: aMessage
  49. "`DIV` creates a div element.
  50. `DIV: anObject` creates a div element and puts contents in it"
  51. | selector newElement useArg |
  52. selector := aMessage selector.
  53. selector asUppercase = selector
  54. ifFalse: [ ^ nil ].
  55. selector last = ':'
  56. ifTrue: [ useArg := true. selector := selector allButLast ]
  57. ifFalse: [ useArg := false ].
  58. (selector includes: ':')
  59. ifTrue: [ ^ nil ].
  60. newElement := self newElement: selector asLowercase.
  61. useArg ifTrue: [ newElement << aMessage arguments first ].
  62. ^ newElement
  63. ! !
  64. !Silk class methodsFor: 'message handling'!
  65. doesNotUnderstand: aMessage
  66. "`Silk DIV` creates a div element.
  67. `Silk DIV: anObject` creates a div element and puts contents in it"
  68. (self tryMakeDnuElement: aMessage)
  69. ifNil: [ ^ super doesNotUnderstand: aMessage ]
  70. ifNotNil: [ :newElement | ^ newElement ]
  71. ! !
  72. !Association methodsFor: '*Silk'!
  73. renderOnSilk: aSilk
  74. key attrPut: value on: aSilk
  75. ! !
  76. !BlockClosure methodsFor: '*Silk'!
  77. renderOnSilk: aSilk
  78. self value: aSilk
  79. ! !
  80. !CharacterArray methodsFor: '*Silk'!
  81. asSilk
  82. ^ Silk at: self asString
  83. ! !
  84. !JSObjectProxy methodsFor: '*Silk'!
  85. inSilk
  86. ^ Silk newStream << self; yourself
  87. ! !
  88. !Object methodsFor: '*Silk'!
  89. inSilk
  90. ^ Silk newStream << self; yourself
  91. !
  92. renderOnSilk: aSilk
  93. ^ nil
  94. ! !
  95. !String methodsFor: '*Silk'!
  96. attrPut: anObject on: aSilk
  97. aSilk attrAt: self put: anObject
  98. ! !