Skip to content

Commit f621dff

Browse files
committed
Refactor: move mutation observer utility to DomSupport
1 parent bb9fbc0 commit f621dff

File tree

4 files changed

+43
-44
lines changed

4 files changed

+43
-44
lines changed

form-runner-web/src/main/scala/org/orbeon/xbl/Select1Search.scala

+5-33
Original file line numberDiff line numberDiff line change
@@ -148,19 +148,19 @@ private class Select1SearchCompanion(containerElem: html.Element) extends XBLCom
148148
if (isDatabound) {
149149
updateValueLabel()
150150
updateOpenSelection()
151-
onAttributeChange(elementWithData, DataValue , updateValueLabel)
152-
onAttributeChange(elementWithData, DataLabel , updateValueLabel)
153-
onAttributeChange(elementWithData, DataIsOpenSelection, updateOpenSelection)
151+
mutationObservers = DomSupport.onAttributeChange(elementWithData, DataValue , updateValueLabel) :: mutationObservers
152+
mutationObservers = DomSupport.onAttributeChange(elementWithData, DataLabel , updateValueLabel) :: mutationObservers
153+
mutationObservers = DomSupport.onAttributeChange(elementWithData, DataIsOpenSelection, updateOpenSelection) :: mutationObservers
154154
} else {
155155
// Register and remember listener on value change
156156
val listener: js.Function = onXFormsSelect1ValueChange _
157157
onXFormsSelect1ValueChangeJs = Some(listener)
158158
Controls.afterValueChange.subscribe(listener)
159159
}
160160

161-
onAttributeChange(elementWithData, DataPlaceholder, updatePlaceholder)
161+
mutationObservers = DomSupport.onAttributeChange(elementWithData, DataPlaceholder, updatePlaceholder) :: mutationObservers
162+
mutationObservers = DomSupport.onElementAdded(containerElem, ".select2-selection__clear", makeClearAccessible) :: mutationObservers
162163
makeClearAccessible()
163-
onElementAdded(containerElem, ".select2-selection__clear", makeClearAccessible)
164164

165165
// Workaround for Select2 not closing itself on click below the `<body>`
166166
EventSupport.addListener(
@@ -281,34 +281,6 @@ private class Select1SearchCompanion(containerElem: html.Element) extends XBLCom
281281
private def querySelect = containerElem.querySelector("select").asInstanceOf[html.Select]
282282
private def servicePerformsSearch = Option(queryElementWithData.getAttribute(DataServicePerformsSearch)).contains("true")
283283

284-
// TODO: not specific to the autocomplete, should be moved to a utility class
285-
private def onAttributeChange(element: dom.Element, attributeName: String, listener: () => Unit): Unit = {
286-
val observer = new MutationObserver((_, _) => listener())
287-
mutationObservers = observer :: mutationObservers
288-
289-
observer.observe(element, new MutationObserverInit {
290-
attributes = true
291-
attributeFilter = js.Array(attributeName)
292-
})
293-
}
294-
295-
private def onElementAdded(container: dom.Element, selector: String, listener: () => Unit): Unit = {
296-
val observer = new MutationObserver((mutations, _) => {
297-
mutations.foreach { mutation =>
298-
mutation.addedNodes.foreach { node =>
299-
if (node.nodeType == dom.Node.ELEMENT_NODE && node.asInstanceOf[dom.Element].matches(selector)) {
300-
listener()
301-
}
302-
}
303-
}
304-
})
305-
mutationObservers = observer :: mutationObservers
306-
307-
val config = new MutationObserverInit { childList = true ; subtree = true }
308-
observer.observe(container, config)
309-
}
310-
311-
312284
// For the non-databound case, when the value of the underlying dropdown changed, typically because it set based
313285
// on that the server tells the client, tell the Select2 component that the value has changed
314286
private def onXFormsSelect1ValueChange(event: js.Dynamic): Unit = {

form-runner-web/src/main/scala/org/orbeon/xbl/TinyMCE.scala

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ object TinyMCE {
4040
"tox-tinymce-aux" // Dialog, e.g. link editor
4141
)
4242

43+
// TODO: see if we can use the `MutationObserver` code in `DomSupport.scala`
4344
val observer = new MutationObserver({ (mutations, _) =>
4445
mutations.foreach { mutation =>
4546
mutation.addedNodes.foreach {

web-support/src/main/scala/org/orbeon/web/DomSupport.scala

+35-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package org.orbeon.web
33
import org.orbeon.oxf.util.CollectionUtils.*
44
import org.orbeon.web.DomEventNames.*
55
import org.scalajs.dom
6-
import org.scalajs.dom.{DocumentReadyState, Event, HTMLCollection, document, html}
6+
import org.scalajs.dom.{DocumentReadyState, Event, HTMLCollection, MutationObserver, MutationObserverInit, document, html}
77

88
import scala.annotation.tailrec
99
import scala.concurrent.{Future, Promise}
@@ -231,4 +231,38 @@ object DomSupport {
231231
)
232232
}
233233
}
234+
235+
def onAttributeChange(
236+
element : dom.Element,
237+
attributeName : String,
238+
listener : () => Unit
239+
): MutationObserver = {
240+
val observer = new MutationObserver((_, _) => listener())
241+
observer.observe(element, new MutationObserverInit {
242+
attributes = true
243+
attributeFilter = js.Array(attributeName)
244+
})
245+
observer
246+
}
247+
248+
def onElementAdded(
249+
container : dom.Element,
250+
selector : String,
251+
listener : () => Unit
252+
): MutationObserver = {
253+
val observer = new MutationObserver((mutations, _) => {
254+
mutations.foreach { mutation =>
255+
mutation.addedNodes.foreach { node =>
256+
if (node.nodeType == dom.Node.ELEMENT_NODE && node.asInstanceOf[dom.Element].matches(selector)) {
257+
listener()
258+
}
259+
}
260+
}
261+
})
262+
263+
val config = new MutationObserverInit { childList = true ; subtree = true }
264+
observer.observe(container, config)
265+
266+
observer
267+
}
234268
}

xforms-web/src/main/scala/org/orbeon/xforms/Language.scala

+2-10
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
*/
1414
package org.orbeon.xforms
1515

16+
import org.orbeon.web.DomSupport
1617
import org.orbeon.xforms.Constants.HtmlLangAttr
1718
import org.scalajs.dom
1819
import org.scalajs.dom.{Element, MutationObserver, MutationRecord}
@@ -39,16 +40,7 @@ object Language {
3940

4041
def onLangChange(listenerId: String, listener: String => Unit): Unit =
4142
langElement.foreach { elem =>
42-
val callback =
43-
(_: js.Array[MutationRecord], _: MutationObserver) => listener(getLang())
44-
val mutationObserver = new MutationObserver(callback)
45-
mutationObserver.observe(
46-
target = elem,
47-
options = new dom.MutationObserverInit {
48-
attributes = true
49-
attributeFilter = js.Array(HtmlLangAttr)
50-
}
51-
)
43+
val mutationObserver = DomSupport.onAttributeChange(elem, HtmlLangAttr, () => listener(getLang()))
5244
langListeners.put(listenerId, mutationObserver)
5345
}
5446

0 commit comments

Comments
 (0)