Smalltalk createPackage: 'Web-Snippets'!
(Smalltalk packageAt: 'Web-Snippets' ifAbsent: [ self error: 'Package not created: Web-Snippets' ]) imports: {'amber/core/Platform-DOM'. 'amber/jquery/Wrappers-JQuery'}!
Object subclass: #HTMLSnippet
slots: {#snippets}
package: 'Web-Snippets'!
!HTMLSnippet commentStamp!
My sole instance is the registry of html snippets.
`HTMLSnippet current` is the public singleton instance.
On startup, it scans the document for any html elements
with `'data-snippet="foo"'` attribute and takes them off the document,
remembering them in the store under the specified name.
It also install method #foo into HTMLCanvas dynamically.
Every html snippet should mark a 'caret', a place where contents
can be inserted, by 'data-snippet="*"' (a special name for caret).
For example:
`
`
defines a list element with a link inside; the link itself is marked as a caret.
You can later issue
`html menuelement href: '/foo'; with: 'A foo'`
to insert the whole snippet and directly manipulate the caret, so it renders:
`A foo`
For a self-careting tags (not very useful, but you do not need to fill class etc.
you can use
``
and in code later do:
`html bar with: [ xxx ]`
to render
`...added by xxx...
`!
!HTMLSnippet methodsFor: 'accessing'!
snippetAt: aString
^ self snippets at: aString
!
snippets
^ snippets ifNil: [ snippets := #{} ]
! !
!HTMLSnippet methodsFor: 'initialization'!
initializeFromJQuery: aJQuery
"Finds and takes out all snippets out of aJQuery.
Installs it into self."
(self snippetsFromJQuery: aJQuery) do: [ :each |
self installSnippetFromJQuery: each asJQuery ]
! !
!HTMLSnippet methodsFor: 'method generation'!
snippetAt: aString compile: anElement
"Method generation for the snippet.
The selector is aString, the method block uses anElement"
HTMLCanvas addCompiledMethod:
(([ :htmlReceiver | htmlReceiver snippet: anElement ]
currySelf asCompiledMethod: aString) protocol: '**snippets'; yourself)
! !
!HTMLSnippet methodsFor: 'private'!
snippetsFromJQuery: aJQuery
^ (aJQuery find: '[data-snippet]') toArray
! !
!HTMLSnippet methodsFor: 'snippet installation'!
installSnippetFromJQuery: element
| name |
name := element attr: 'data-snippet'.
name = '*' ifFalse: [
('^\*' asRegexp test: name)
ifTrue: [
name := name allButFirst.
element attr: 'data-snippet' put: '*' ]
ifFalse: [
element removeAttr: 'data-snippet' ].
self snippetAt: name install: (element detach get: 0) ]
!
snippetAt: aString install: anElement
self snippets at: aString put: anElement.
self snippetAt: aString compile: anElement
! !
HTMLSnippet class slots: {#current}!
!HTMLSnippet class methodsFor: 'initialization'!
ensureCurrent
current ifNil: [
current := super new
initializeFromJQuery: document asJQuery;
yourself ]
!
initialize
super initialize.
PlatformDom isFeasible ifTrue: [
self ensureCurrent ]
! !
!HTMLSnippet class methodsFor: 'instance creation'!
current
^ current
!
new
self shouldNotImplement
! !
!HTMLCanvas methodsFor: '*Web-Snippets'!
snippet: anElement
"Adds clone of anElement, finds [data-snippet=""*""] subelement
and returns TagBrush as if that subelement was just added.
Rarely needed to use directly, use `html foo` dynamically installed method
for a snippet named foo."
| clone caret |
clone := anElement asJQuery clone.
self with: (TagBrush fromJQuery: clone canvas: self).
caret := clone find: '[data-snippet="*"]'.
caret toArray ifEmpty: [ caret := clone ].
^ TagBrush fromJQuery: (caret removeAttr: 'data-snippet') canvas: self
! !
!String methodsFor: '*Web-Snippets'!
asSnippet
^ HTMLSnippet current snippetAt: self asString
! !