14
14
package org .orbeon .fr
15
15
16
16
import org .orbeon .facades .{Ladda , ResizeObserver }
17
- import org .orbeon .web .DomEventNames
17
+ import org .orbeon .web .{ DomEventNames , DomSupport }
18
18
import org .orbeon .web .DomSupport .*
19
19
import org .orbeon .xbl
20
20
import org .orbeon .xforms .*
@@ -26,6 +26,7 @@ import org.scalajs.dom.*
26
26
import scala .scalajs .js
27
27
import scala .scalajs .js .Dynamic .global as g
28
28
import scala .scalajs .js .timers
29
+ import org .scalajs .macrotaskexecutor .MacrotaskExecutor .Implicits .*
29
30
30
31
31
32
// Scala.js starting point for Form Runner
@@ -76,141 +77,139 @@ object FormRunnerApp extends App {
76
77
xbl.ClipboardCopy
77
78
xbl.Trigger
78
79
79
- // TODO: with embedding, unobserve when the form is destroyed
80
- Events .orbeonLoadedEvent.subscribe(() => {
81
-
82
- // Add `scroll-padding-top` and `scroll-padding-bottom` to prevent the focused form field from being below the top navbar or button bar
83
- def addScrollPadding (htmlElement : html.Element , cssClass : String ): Unit = {
84
- val position = window.getComputedStyle(htmlElement).position
85
- if (position == " fixed" || position == " sticky" ) {
86
- val resizeObserver = new ResizeObserver (() => {
87
- val documentElement = document.documentElementT
88
- val scrollPaddingWithMargin = htmlElement.clientHeight + 5 ;
89
- documentElement.style.setProperty(cssClass, s " ${scrollPaddingWithMargin}px " )
90
- })
91
- resizeObserver.observe(htmlElement)
92
- }
93
- }
94
-
95
- document.querySelectorOpt(" .orbeon .navbar-fixed-top" ).foreach(addScrollPadding(_, " scroll-padding-top" ))
96
- document.querySelectorOpt(" .orbeon .fr-buttons" ).foreach(addScrollPadding(_, " scroll-padding-bottom" ))
80
+ DomSupport .atLeastDomReadyStateF(document, DomSupport .DomReadyState .Interactive ) foreach { _ =>
81
+ DomSupport .onElementFoundOrAdded(document.body, " .orbeon .navbar-fixed-top" , addScrollPadding(_, " scroll-padding-top" ))
82
+ DomSupport .onElementFoundOrAdded(document.body, " .orbeon .fr-buttons" , addScrollPadding(_, " scroll-padding-bottom" ))
83
+ DomSupport .onElementFoundOrAdded(document.body, " .orbeon .fr-session-expiration-dialog" , initSessionExpirationDialog)
84
+ }
85
+ }
97
86
98
- initSessionExpirationDialog()
99
- })
87
+ // Add `scroll-padding-top` and `scroll-padding-bottom` to prevent the focused form field from being
88
+ // below the top navbar or button bar
89
+ private def addScrollPadding (htmlElement : html.Element , cssClass : String ): Unit = {
90
+ val position = window.getComputedStyle(htmlElement).position
91
+ if (position == " fixed" || position == " sticky" ) {
92
+ val resizeObserver = new ResizeObserver (() => {
93
+ val documentElement = document.documentElementT
94
+ val scrollPaddingWithMargin = htmlElement.clientHeight + 5 ;
95
+ documentElement.style.setProperty(cssClass, s " ${scrollPaddingWithMargin}px " )
96
+ })
97
+ resizeObserver.observe(htmlElement)
98
+ }
100
99
}
101
100
102
- private def initSessionExpirationDialog (): Unit = {
103
- document.querySelectorOpt(" .fr-session-expiration-dialog" ).collect { case dialog : HTMLDialogElement =>
104
-
105
- // Detecting whether the dialog is shown or not by retrieving its CSS classes is not reliable when aboutToExpire
106
- // is called multiple times in a row (e.g. locally and because of a message from another page), so we keep track
107
- // of it ourselves.
108
- var dialogShown : Boolean = false
109
- var didExpireTimerOpt : Option [timers.SetTimeoutHandle ] = None
110
-
111
- if (dialog.classList.contains(" fr-feature-enabled" )) {
112
- // Remove XForms-level dialog we're replacing
113
- dom.document.querySelectorAllT(s " .xforms-login-detected-dialog " ).foreach(_.remove())
114
-
115
- val renewButton = dialog.querySelectorT(" .fr-renew-button" )
116
- GlobalEventListenerSupport .addListener(renewButton, DomEventNames .Click , (_ : dom.EventTarget ) => {
117
- renewSession()
118
- // Since we sent a heartbeat when the session was renewed, the local newest event time has been updated and
119
- // will be broadcast to other pages.
120
- Session .updateWithLocalNewestEventTime()
121
- })
101
+ private def initSessionExpirationDialog (dialogElem : html.Element ): Unit = {
102
+ val dialog = dialogElem.asInstanceOf [HTMLDialogElement ]
103
+ org.scalajs.dom.console.log(dialog)
104
+
105
+ // Detecting whether the dialog is shown or not by retrieving its CSS classes is not reliable when aboutToExpire
106
+ // is called multiple times in a row (e.g. locally and because of a message from another page), so we keep track
107
+ // of it ourselves.
108
+ var dialogShown : Boolean = false
109
+ var didExpireTimerOpt : Option [timers.SetTimeoutHandle ] = None
110
+
111
+ if (dialog.classList.contains(" fr-feature-enabled" )) {
112
+ // Remove XForms-level dialog we're replacing
113
+ dom.document.querySelectorAllT(s " .xforms-login-detected-dialog " ).foreach(_.remove())
114
+
115
+ val renewButton = dialog.querySelectorT(" .fr-renew-button" )
116
+ GlobalEventListenerSupport .addListener(renewButton, DomEventNames .Click , (_ : dom.EventTarget ) => {
117
+ renewSession()
118
+ // Since we sent a heartbeat when the session was renewed, the local newest event time has been updated and
119
+ // will be broadcast to other pages.
120
+ Session .updateWithLocalNewestEventTime()
121
+ })
122
+
123
+ val reloadButton = dialog.querySelectorT(" .fr-reload-button" )
124
+ val laddaReloadButton = Ladda .create(reloadButton)
125
+ GlobalEventListenerSupport .addListener(
126
+ target = reloadButton,
127
+ name = DomEventNames .Click ,
128
+ fn = (_ : dom.EventTarget ) => {
129
+ laddaReloadButton.start()
130
+ dom.window.location.href = dom.window.location.href
131
+ }
132
+ )
122
133
123
- val reloadButton = dialog.querySelectorT(" .fr-reload-button" )
124
- val laddaReloadButton = Ladda .create(reloadButton)
125
- GlobalEventListenerSupport .addListener(
126
- target = reloadButton,
127
- name = DomEventNames .Click ,
128
- fn = (_ : dom.EventTarget ) => {
129
- laddaReloadButton.start()
130
- dom.window.location.href = dom.window.location.href
131
- }
132
- )
133
-
134
- Session .addSessionUpdateListener(sessionUpdate)
135
- }
134
+ Session .addSessionUpdateListener(sessionUpdate)
135
+ }
136
136
137
- def sessionUpdate (sessionUpdate : SessionUpdate ): Unit =
138
- if (! sessionUpdate.sessionHeartbeatEnabled) {
139
- sessionUpdate.sessionStatus match {
140
- case Session .SessionActive if dialogShown && ! Session .expired =>
141
- renewSession()
137
+ def sessionUpdate (sessionUpdate : SessionUpdate ): Unit =
138
+ if (! sessionUpdate.sessionHeartbeatEnabled) {
139
+ sessionUpdate.sessionStatus match {
140
+ case Session .SessionActive if dialogShown && ! Session .expired =>
141
+ renewSession()
142
142
143
- case Session .SessionAboutToExpire =>
144
- aboutToExpire(sessionUpdate.approxSessionExpiredTimeMillis)
143
+ case Session .SessionAboutToExpire =>
144
+ aboutToExpire(sessionUpdate.approxSessionExpiredTimeMillis)
145
145
146
- case Session .SessionExpired =>
147
- sessionExpired()
146
+ case Session .SessionExpired =>
147
+ sessionExpired()
148
148
149
- case _ =>
150
- // Nothing to do
151
- }
149
+ case _ =>
150
+ // Nothing to do
152
151
}
152
+ }
153
153
154
- def aboutToExpire (approxSessionExpiredTimeMillis : Long ): Unit =
155
- if (! dialogShown) {
156
- AjaxClient .pause()
157
- updateDialog()
158
- showDialog()
159
-
160
- val timeToExpiration = approxSessionExpiredTimeMillis - System .currentTimeMillis()
161
- didExpireTimerOpt.foreach(timers.clearTimeout)
162
- didExpireTimerOpt = Some (timers.setTimeout(timeToExpiration.toDouble) {
163
- Session .sessionHasExpired()
164
- updateDialog()
165
- })
166
- }
154
+ def aboutToExpire (approxSessionExpiredTimeMillis : Long ): Unit =
155
+ if (! dialogShown) {
156
+ AjaxClient .pause()
157
+ updateDialog()
158
+ showDialog()
167
159
168
- def sessionExpired (): Unit =
169
- if (! dialogShown) {
170
- AjaxClient .pause()
171
- updateDialog()
172
- showDialog()
173
- } else {
160
+ val timeToExpiration = approxSessionExpiredTimeMillis - System .currentTimeMillis()
161
+ didExpireTimerOpt.foreach(timers.clearTimeout)
162
+ didExpireTimerOpt = Some (timers.setTimeout(timeToExpiration.toDouble) {
163
+ Session .sessionHasExpired()
174
164
updateDialog()
175
- }
165
+ })
166
+ }
176
167
177
- def updateDialog (): Unit = {
178
- val headerContent = dialog.querySelectorAllT(" .xxforms-dialog-head .xforms-output" )
179
- val bodyContent = dialog.querySelectorAllT(" .xxforms-dialog-body .xforms-mediatype-text-html" )
180
- val renewButton = dialog.querySelectorT (" .fr-renew-button" )
181
- val reloadButton = dialog.querySelectorT (" .fr-reload-button" )
168
+ def sessionExpired (): Unit =
169
+ if (! dialogShown) {
170
+ AjaxClient .pause()
171
+ updateDialog()
172
+ showDialog()
173
+ } else {
174
+ updateDialog()
175
+ }
182
176
183
- val visibleWhenExpiring = List (headerContent.head, bodyContent.head, renewButton)
184
- val visibleWhenExpired = List (headerContent.last, bodyContent.last, reloadButton)
177
+ def updateDialog (): Unit = {
178
+ val headerContent = dialog.querySelectorAllT(" .xxforms-dialog-head .xforms-output" )
179
+ val bodyContent = dialog.querySelectorAllT(" .xxforms-dialog-body .xforms-mediatype-text-html" )
180
+ val renewButton = dialog.querySelectorT (" .fr-renew-button" )
181
+ val reloadButton = dialog.querySelectorT (" .fr-reload-button" )
185
182
186
- def setDisplay ( elements : List [html. Element ], display : String ) : Unit =
187
- elements.foreach(_.style.display = display )
183
+ val visibleWhenExpiring = List (headerContent.head, bodyContent.head, renewButton)
184
+ val visibleWhenExpired = List (headerContent.last, bodyContent.last, reloadButton )
188
185
189
- val (toShow, toHide) = if (Session .expired)
190
- (visibleWhenExpired , visibleWhenExpiring) else
191
- (visibleWhenExpiring, visibleWhenExpired )
186
+ def setDisplay (elements : List [html.Element ], display : String ): Unit =
187
+ elements.foreach(_.style.display = display)
192
188
193
- setDisplay (toShow, " " )
194
- setDisplay(toHide, " none " )
195
- }
189
+ val (toShow, toHide) = if ( Session .expired )
190
+ (visibleWhenExpired , visibleWhenExpiring) else
191
+ (visibleWhenExpiring, visibleWhenExpired )
196
192
197
- def renewSession (): Unit = {
198
- didExpireTimerOpt.foreach(timers.clearTimeout)
199
- didExpireTimerOpt = None
200
- AjaxClient .sendHeartBeat()
201
- AjaxClient .unpause()
202
- hideDialog()
203
- }
193
+ setDisplay(toShow, " " )
194
+ setDisplay(toHide, " none" )
195
+ }
204
196
205
- def showDialog (): Unit = {
206
- dialog.showModal()
207
- dialogShown = true
208
- }
197
+ def renewSession (): Unit = {
198
+ didExpireTimerOpt.foreach(timers.clearTimeout)
199
+ didExpireTimerOpt = None
200
+ AjaxClient .sendHeartBeat()
201
+ AjaxClient .unpause()
202
+ hideDialog()
203
+ }
209
204
210
- def hideDialog (): Unit = {
211
- dialog.close()
212
- dialogShown = false
213
- }
205
+ def showDialog (): Unit = {
206
+ dialog.showModal()
207
+ dialogShown = true
208
+ }
209
+
210
+ def hideDialog (): Unit = {
211
+ dialog.close()
212
+ dialogShown = false
214
213
}
215
214
}
216
215
0 commit comments