DOMite.st 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. Smalltalk createPackage: 'DOMite'!
  2. ProtoStream subclass: #Domite
  3. instanceVariableNames: 'element reference'
  4. package: 'DOMite'!
  5. !Domite commentStamp!
  6. I am (hopefully thin) wrapper around the notion of "cursor in a page".
  7. I represent a DOM node _and_ a point where
  8. to insert new content into it.
  9. So I play both the role of a container that inserts
  10. as well as the role of an element being inserted.
  11. Creation API:
  12. - `Domite new` creates an insertion point at the bottom of `<body>`.
  13. - `Domite open` is unique way to create pieces of content. It creates an instance "floating in thin air" (wrapper around DOM DocumentFragment) that can be filled with any contents and then inserted in a page.
  14. - `Domite fromElement: aDomElement` wraps an element and set the cursor to its end.
  15. Manipulation API:
  16. - `aDomite insertDomite:` and `aDomite insertString:` insert either a Domite or a text content at the insertion point.
  17. - `aDomite clearHere` deletes contents of the wrapped element.
  18. Cursor moving API:
  19. Take this sample HTML, where `[n]` are just markers, not real content:
  20. ```
  21. <body>
  22. <h1>header</h1>
  23. [4]<p>[2]Hello[1]world[3]</p>[5]
  24. <small>footer</small>
  25. </body>
  26. ```
  27. If `d` is a `Domite` representing `[1]`, then:
  28. - `d seekHereStart` would move `d` to be at `[2]`,
  29. - `d seekHereEnd` would move `d` to be at `[3]`,
  30. - `d seekBeforeHere` would move `d` to be at `[4]`, and
  31. - `d seekAfterHere` would move `d` to be at `[5]`.
  32. It is not presumed one would use `seekXxx`
  33. to actually move around in a single instance.
  34. It is envisioned this API will be used mostly
  35. in combination with `copy`, like
  36. `afterMe := self copy seekAfterHere`.!
  37. !Domite methodsFor: 'accessing'!
  38. attrAt: aString
  39. (element hasAttribute: aString)
  40. ifTrue: [ ^ element getAttribute: aString ]
  41. ifFalse: [ ^ nil ]
  42. !
  43. attrAt: aString put: anotherString
  44. element setAttribute: aString to: anotherString
  45. !
  46. element
  47. ^ element
  48. !
  49. element: anObject
  50. element := anObject
  51. !
  52. propAt: aString
  53. ^ element at: aString
  54. !
  55. propAt: aString put: anObject
  56. ^ element at: aString put: anObject
  57. !
  58. reference
  59. ^ reference
  60. !
  61. reference: anObject
  62. reference := anObject
  63. ! !
  64. !Domite methodsFor: 'deletion'!
  65. resetContents
  66. <
  67. var element = self['@element'], child;
  68. while (child = element.firstChild) element.removeChild(child);
  69. self['@reference'] = null;
  70. >
  71. ! !
  72. !Domite methodsFor: 'events'!
  73. off: aString unbind: aBlock
  74. self removeEventListener: aString block: aBlock useCapture: false
  75. !
  76. on: aString bind: aBlock
  77. self addEventListener: aString block: aBlock useCapture: false
  78. ! !
  79. !Domite methodsFor: 'initialization'!
  80. initialize
  81. super initialize.
  82. element := document body.
  83. reference := nil asJSON
  84. ! !
  85. !Domite methodsFor: 'insertion'!
  86. nextPut: anObject
  87. self nextPutString: anObject printString
  88. !
  89. nextPutDomNode: aDomElement
  90. self element
  91. insertBefore: aDomElement
  92. reference: self reference
  93. !
  94. nextPutString: aString
  95. self nextPutDomNode: (
  96. document createTextNode: aString asString )
  97. ! !
  98. !Domite methodsFor: 'positioning'!
  99. reset
  100. self reference: self element firstChild
  101. !
  102. setToAfter
  103. self
  104. reference: self element nextSibling;
  105. element: self element parentNode
  106. !
  107. setToBefore
  108. self
  109. reference: self element;
  110. element: self element parentNode
  111. !
  112. setToEnd
  113. self reference: nil asJSON "null"
  114. ! !
  115. !Domite methodsFor: 'streaming'!
  116. putOn: aStream
  117. aStream nextPutDomNode: self element
  118. ! !
  119. !Domite methodsFor: 'testing'!
  120. canSetToUpperLevel
  121. ^ self element parentNode notNil
  122. !
  123. isInvalid
  124. ^ self element isNil
  125. ! !
  126. !Domite class methodsFor: 'instance creation'!
  127. fromElement: aDomElement
  128. ^ self new
  129. element: aDomElement;
  130. yourself
  131. !
  132. fromElement: aDomElement cursorBefore: anotherDomElement
  133. ^ self new
  134. element: aDomElement;
  135. referenceElement: anotherDomElement;
  136. yourself
  137. !
  138. fromSelector: aString
  139. ^ self fromElement: (document querySelector: aString)
  140. !
  141. newElement: aString
  142. ^ self fromElement: (document createElement: aString)
  143. !
  144. newStream
  145. ^ self fromElement: document createDocumentFragment
  146. ! !
  147. !ProtoStream methodsFor: '*DOMite'!
  148. nextPutDomNode: aNode
  149. self nextPut: aNode
  150. ! !