Web-Snippets.st 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. Smalltalk createPackage: 'Web-Snippets'!
  2. (Smalltalk packageAt: 'Web-Snippets') imports: {'amber/jquery/Wrappers-JQuery'. 'amber_core/Platform-DOM'}!
  3. Object subclass: #HTMLSnippet
  4. instanceVariableNames: '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. ClassBuilder new
  48. installMethod: ([ :htmlReceiver | htmlReceiver snippet: anElement ]
  49. currySelf asCompiledMethod: aString)
  50. forClass: HTMLCanvas
  51. protocol: '**snippets'
  52. ! !
  53. !HTMLSnippet methodsFor: 'private'!
  54. snippetsFromJQuery: aJQuery
  55. ^ (aJQuery find: '[data-snippet]') toArray
  56. ! !
  57. !HTMLSnippet methodsFor: 'snippet installation'!
  58. installSnippetFromJQuery: element
  59. | name |
  60. name := element attr: 'data-snippet'.
  61. name = '*' ifFalse: [
  62. ('^\*' asRegexp test: name)
  63. ifTrue: [
  64. name := name allButFirst.
  65. element attr: 'data-snippet' put: '*' ]
  66. ifFalse: [
  67. element removeAttr: 'data-snippet' ].
  68. self snippetAt: name install: (element detach get: 0) ]
  69. !
  70. snippetAt: aString install: anElement
  71. self snippets at: aString put: anElement.
  72. self snippetAt: aString compile: anElement
  73. ! !
  74. HTMLSnippet class instanceVariableNames: 'current'!
  75. !HTMLSnippet class methodsFor: 'initialization'!
  76. ensureCurrent
  77. current ifNil: [
  78. current := super new
  79. initializeFromJQuery: document asJQuery;
  80. yourself ]
  81. !
  82. initialize
  83. super initialize.
  84. PlatformDom isFeasible ifTrue: [
  85. self ensureCurrent ]
  86. ! !
  87. !HTMLSnippet class methodsFor: 'instance creation'!
  88. current
  89. ^ current
  90. !
  91. new
  92. self shouldNotImplement
  93. ! !
  94. !CharacterArray methodsFor: '*Web-Snippets'!
  95. asSnippet
  96. ^ HTMLSnippet current snippetAt: self asString
  97. ! !
  98. !HTMLCanvas methodsFor: '*Web-Snippets'!
  99. snippet: anElement
  100. "Adds clone of anElement, finds [data-snippet=""*""] subelement
  101. and returns TagBrush as if that subelement was just added.
  102. Rarely needed to use directly, use `html foo` dynamically installed method
  103. for a snippet named foo."
  104. | clone caret |
  105. clone := anElement asJQuery clone.
  106. self with: (TagBrush fromJQuery: clone canvas: self).
  107. caret := clone find: '[data-snippet="*"]'.
  108. caret toArray ifEmpty: [ caret := clone ].
  109. ^ TagBrush fromJQuery: (caret removeAttr: 'data-snippet') canvas: self
  110. ! !