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 instanceVariableNames: '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" ClassBuilder new installMethod: ([ :htmlReceiver | htmlReceiver snippet: anElement ] currySelf asCompiledMethod: aString) forClass: HTMLCanvas protocol: '**snippets' ! ! !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 instanceVariableNames: '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 ! !