Web-Snippets.st 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. Smalltalk createPackage: 'Web-Snippets'!
  2. (Smalltalk packageAt: 'Web-Snippets' ifAbsent: [ self error: 'Package not created: Web-Snippets' ]) imports: {'amber/core/Platform-DOM'. 'amber/web/Web-JQuery'}!
  3. Object subclass: #HTMLSnippet
  4. slots: {#snippets}
  5. package: 'Web-Snippets'!
  6. !HTMLSnippet commentStamp!
  7. My sole instance is the registry of html snippets.
  8. `HTMLSnippet current` is the public singleton instance.
  9. On startup, it scans the document for any html elements
  10. with `'data-snippet="foo"'` attribute and takes them off the document,
  11. remembering them in the store under the specified name.
  12. It also install method #foo into HTMLCanvas dynamically.
  13. Every html snippet should mark a 'caret', a place where contents
  14. can be inserted, by 'data-snippet="*"' (a special name for caret).
  15. For example:
  16. `<li data-snippet='menuelement' class='...'><a data-snippet='*'></a></li>`
  17. defines a list element with a link inside; the link itself is marked as a caret.
  18. You can later issue
  19. `html menuelement href: '/foo'; with: 'A foo'`
  20. to insert the whole snippet and directly manipulate the caret, so it renders:
  21. `<li class='...'><a href='/foo'>A foo</a></li>`
  22. For a self-careting tags (not very useful, but you do not need to fill class etc.
  23. you can use
  24. `<div class='lots of classes' attr1='one' attr2='two' data-snippet='*bar'></div>`
  25. and in code later do:
  26. `html bar with: [ xxx ]`
  27. to render
  28. `<div class='lots of classes' attr1='one' attr2='two'>...added by xxx...</div>`!
  29. !HTMLSnippet methodsFor: 'accessing'!
  30. snippetAt: aString
  31. ^ self snippets at: aString
  32. !
  33. snippets
  34. ^ snippets ifNil: [ snippets := #{} ]
  35. ! !
  36. !HTMLSnippet methodsFor: 'initialization'!
  37. initializeFromJQuery: aJQuery
  38. "Finds and takes out all snippets out of aJQuery.
  39. Installs it into self."
  40. (self snippetsFromJQuery: aJQuery) do: [ :each |
  41. self installSnippetFromJQuery: each asJQuery ]
  42. ! !
  43. !HTMLSnippet methodsFor: 'method generation'!
  44. snippetAt: aString compile: anElement
  45. "Method generation for the snippet.
  46. The selector is aString, the method block uses anElement"
  47. HTMLCanvas addCompiledMethod:
  48. (([ :htmlReceiver | htmlReceiver snippet: anElement ]
  49. currySelf asCompiledMethod: aString) protocol: '**snippets'; yourself)
  50. ! !
  51. !HTMLSnippet methodsFor: 'private'!
  52. snippetsFromJQuery: aJQuery
  53. ^ (aJQuery find: '[data-snippet]') toArray
  54. ! !
  55. !HTMLSnippet methodsFor: 'snippet installation'!
  56. installSnippetFromJQuery: element
  57. | name |
  58. name := element attr: 'data-snippet'.
  59. name = '*' ifFalse: [
  60. ('^\*' asRegexp test: name)
  61. ifTrue: [
  62. name := name allButFirst.
  63. element attr: 'data-snippet' put: '*' ]
  64. ifFalse: [
  65. element removeAttr: 'data-snippet' ].
  66. self snippetAt: name install: (element detach get: 0) ]
  67. !
  68. snippetAt: aString install: anElement
  69. self snippets at: aString put: anElement.
  70. self snippetAt: aString compile: anElement
  71. ! !
  72. HTMLSnippet class slots: {#current}!
  73. !HTMLSnippet class methodsFor: 'initialization'!
  74. ensureCurrent
  75. current ifNil: [
  76. current := super new
  77. initializeFromJQuery: document asJQuery;
  78. yourself ]
  79. !
  80. initialize
  81. super initialize.
  82. PlatformDom isFeasible ifTrue: [
  83. self ensureCurrent ]
  84. ! !
  85. !HTMLSnippet class methodsFor: 'instance creation'!
  86. current
  87. ^ current
  88. !
  89. new
  90. self shouldNotImplement
  91. ! !
  92. !HTMLCanvas methodsFor: '*Web-Snippets'!
  93. snippet: anElement
  94. "Adds clone of anElement, finds [data-snippet=""*""] subelement
  95. and returns TagBrush as if that subelement was just added.
  96. Rarely needed to use directly, use `html foo` dynamically installed method
  97. for a snippet named foo."
  98. | clone caret |
  99. clone := anElement asJQuery clone.
  100. self with: (TagBrush fromJQuery: clone canvas: self).
  101. caret := clone find: '[data-snippet="*"]'.
  102. caret toArray ifEmpty: [ caret := clone ].
  103. ^ TagBrush fromJQuery: (caret removeAttr: 'data-snippet') canvas: self
  104. ! !
  105. !String methodsFor: '*Web-Snippets'!
  106. asSnippet
  107. ^ HTMLSnippet current snippetAt: self asString
  108. ! !