| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 | Smalltalk createPackage: 'Web-Snippets'!(Smalltalk packageAt: 'Web-Snippets' ifAbsent: [ self error: 'Package not created: Web-Snippets' ]) imports: {'amber/jquery/Wrappers-JQuery'. 'amber_core/Platform-DOM'}!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 elementswith `'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 contentscan be inserted, by 'data-snippet="*"' (a special name for caret).For example:`<li data-snippet='menuelement' class='...'><a data-snippet='*'></a></li>`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:`<li class='...'><a href='/foo'>A foo</a></li>`For a self-careting tags (not very useful, but you do not need to fill class etc.you can use`<div class='lots of classes' attr1='one' attr2='two' data-snippet='*bar'></div>`and in code later do:`html bar with: [ xxx ]`to render`<div class='lots of classes' attr1='one' attr2='two'>...added by xxx...</div>`!!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! !
 |