<NME> Globals.scala
<BEF> ADDFILE
<MSG> For #3147: move `Globals` to Scala

<DFF> @@ -0,0 +1,58 @@
+/**
+ * Copyright (C) 2019 Orbeon, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it under the terms of the
+ * GNU Lesser General Public License as published by the Free Software Foundation; either version
+ *  2.1 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The full text of the license is available at http://www.gnu.org/copyleft/lesser.html
+ */
+package org.orbeon.xforms
+
+import org.orbeon.facades.Bowser
+import org.scalajs.dom.html
+
+import scala.scalajs.js
+import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel}
+
+@JSExportTopLevel("ORBEON.xforms.Globals")
+@JSExportAll
+object Globals {
+
+  lazy val isRenderingEngineTrident: Boolean                   = Bowser.msie.getOrElse(false) // one usage left to check as of 2019-01-04
+
+  var eventQueue                  : js.Array[AjaxServerEvent] = js.Array()                   // events to be sent to the server
+  var eventsFirstEventTime        : Double                    = 0                            // time when the first event in the queue was added
+  var requestForm                 : html.Form                 = null                         // hTML for the request currently in progress
+  var requestIgnoreErrors         : Boolean                   = false                        // should we ignore errors that result from running this request
+  var requestInProgress           : Boolean                   = false                        // indicates whether an Ajax request is currently in process
+  var requestDocument             : String                    = ""                           // the last Ajax request, so we can resend it if necessary
+  var requestTryCount             : Int                       = 0                            // how many attempts to run the current Ajax request we have done so far
+  var executeEventFunctionQueued  : Int                       = 0                            // number of ORBEON.xforms.server.AjaxServer.executeNextRequest waiting to be executed
+  var maskFocusEvents             : Boolean                   = false                        // avoid catching focus event when we do call setfocus upon server request
+  var maskDialogCloseEvents       : Boolean                   = false                        // avoid catching a dialog close event received from the server, so we don't sent it back to the server
+  var currentFocusControlId       : js.Object                 = null                         // id of the control that got the focus last
+  var currentFocusControlElement  : js.Object                 = null                         // element for the control that got the focus last
+  var yuiCalendar                 : js.Object                 = null                         // reusable calendar widget
+  var tooltipLibraryInitialized   : Boolean                   = false
+  var changedIdsRequest           : js.Dictionary[Int]        = js.Dictionary.empty          // id of controls that have been touched by user since the last response was received
+  var loadingOtherPage            : Boolean                   = false                        // flag set when loading other page that prevents the loading indicator to disappear
+  var activeControl               : js.Object                 = null                         // the currently active control, used to disable hint
+  var dialogs                     : js.Dictionary[js.Dynamic] = js.Dictionary.empty          // map for dialogs: id -> YUI dialog object
+  var hintTooltipForControl       : js.Dictionary[js.Any]     = js.Dictionary.empty          // map from element id -> YUI tooltip or true, that tells us if we have already created a Tooltip for an element
+  var alertTooltipForControl      : js.Dictionary[js.Any]     = js.Dictionary.empty          // map from element id -> YUI alert or true, that tells us if we have already created a Tooltip for an element
+  var helpTooltipForControl       : js.Dictionary[js.Any]     = js.Dictionary.empty          // map from element id -> YUI help or true, that tells us if we have already created a Tooltip for an element
+  var lastEventSentTime           : Double                    = new js.Date().getTime()      // timestamp when the last event was sent to server
+  var sliderYui                   : js.Dictionary[js.Any]     = js.Dictionary.empty          // maps slider id to the YUI object for that slider
+  var lastDialogZIndex            : Int                       = 1050                         // zIndex of the last dialog displayed; gets incremented so the last dialog is always on top of everything else; initial value set to Bootstrap's @zindexModal
+
+  var modalProgressPanel          : js.Object                 = null                         // overlay modal panel for displaying progress bar
+  var modalProgressPanelTimerId   : js.Any                    = null                         // timer id for modal progress panels shown asynchronously (iOS)
+
+  var changeListeners             : js.Dictionary[js.Any]     = js.Dictionary.empty          // maps control id to DOM element for which we have registered a change listener
+  var topLevelListenerRegistered  : Boolean                   = false                        // have we already registered the listeners on the top-level elements, which never change
+}

{'commit': 'diff --git a/form-builder/js/src/main/scala/org/orbeon/builder/Position.scala b/form-builder/js/src/main/scala/org/orbeon/builder/Position.scala\nindex a1811b0fba..936e4cb51c 100644\n--- a/form-builder/js/src/main/scala/org/orbeon/builder/Position.scala\n+++ b/form-builder/js/src/main/scala/org/orbeon/builder/Position.scala\n@@ -18,7 +18,7 @@ import org.orbeon.jquery.Offset\n import org.orbeon.oxf.util.CoreUtils.asUnit\n import org.orbeon.oxf.util.StringUtils._\n import org.orbeon.xforms._\n-import org.orbeon.xforms.facade.{Events, Globals}\n+import org.orbeon.xforms.facade.Events\n import org.scalajs.dom.{document, window}\n import org.scalajs.jquery.{JQuery, JQueryEventObject}\n \ndiff --git a/xforms/js/src/main/scala/org/orbeon/xforms/AjaxClient.scala b/xforms/js/src/main/scala/org/orbeon/xforms/AjaxClient.scala\nindex 140bab50f7..940a7d77d2 100644\n--- a/xforms/js/src/main/scala/org/orbeon/xforms/AjaxClient.scala\n+++ b/xforms/js/src/main/scala/org/orbeon/xforms/AjaxClient.scala\n@@ -22,7 +22,7 @@ import org.orbeon.oxf.util.CollectionUtils._\n import org.orbeon.oxf.util.MarkupUtils._\n import org.orbeon.oxf.util.StringUtils._\n import org.orbeon.xforms.EventNames.{DOMActivate, XXFormsUploadProgress, XXFormsValue}\n-import org.orbeon.xforms.facade.{AjaxServer, Globals, Properties}\n+import org.orbeon.xforms.facade.{AjaxServer, Properties}\n import org.scalajs.dom\n import org.scalajs.dom.html\n \ndiff --git a/xforms/js/src/main/scala/org/orbeon/xforms/ErrorPanel.scala b/xforms/js/src/main/scala/org/orbeon/xforms/ErrorPanel.scala\nindex 43350842f6..487611a6b4 100644\n--- a/xforms/js/src/main/scala/org/orbeon/xforms/ErrorPanel.scala\n+++ b/xforms/js/src/main/scala/org/orbeon/xforms/ErrorPanel.scala\n@@ -14,7 +14,7 @@\n package org.orbeon.xforms\n \n import org.orbeon.jquery._\n-import org.orbeon.xforms.facade.{Globals, Utils}\n+import org.orbeon.xforms.facade.Utils\n import org.scalajs.dom\n import org.scalajs.dom.html\n import org.scalajs.jquery.JQueryEventObject\ndiff --git a/xforms/js/src/main/scala/org/orbeon/xforms/Globals.scala b/xforms/js/src/main/scala/org/orbeon/xforms/Globals.scala\nnew file mode 100644\nindex 0000000000..f439161fe2\n--- /dev/null\n+++ b/xforms/js/src/main/scala/org/orbeon/xforms/Globals.scala\n@@ -0,0 +1,58 @@\n+/**\n+ * Copyright (C) 2019 Orbeon, Inc.\n+ *\n+ * This program is free software; you can redistribute it and/or modify it under the terms of the\n+ * GNU Lesser General Public License as published by the Free Software Foundation; either version\n+ *  2.1 of the License, or (at your option) any later version.\n+ *\n+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;\n+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n+ * See the GNU Lesser General Public License for more details.\n+ *\n+ * The full text of the license is available at http://www.gnu.org/copyleft/lesser.html\n+ */\n+package org.orbeon.xforms\n+\n+import org.orbeon.facades.Bowser\n+import org.scalajs.dom.html\n+\n+import scala.scalajs.js\n+import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel}\n+\n+@JSExportTopLevel("ORBEON.xforms.Globals")\n+@JSExportAll\n+object Globals {\n+\n+  lazy val isRenderingEngineTrident: Boolean                   = Bowser.msie.getOrElse(false) // one usage left to check as of 2019-01-04\n+\n+  var eventQueue                  : js.Array[AjaxServerEvent] = js.Array()                   // events to be sent to the server\n+  var eventsFirstEventTime        : Double                    = 0                            // time when the first event in the queue was added\n+  var requestForm                 : html.Form                 = null                         // hTML for the request currently in progress\n+  var requestIgnoreErrors         : Boolean                   = false                        // should we ignore errors that result from running this request\n+  var requestInProgress           : Boolean                   = false                        // indicates whether an Ajax request is currently in process\n+  var requestDocument             : String                    = ""                           // the last Ajax request, so we can resend it if necessary\n+  var requestTryCount             : Int                       = 0                            // how many attempts to run the current Ajax request we have done so far\n+  var executeEventFunctionQueued  : Int                       = 0                            // number of ORBEON.xforms.server.AjaxServer.executeNextRequest waiting to be executed\n+  var maskFocusEvents             : Boolean                   = false                        // avoid catching focus event when we do call setfocus upon server request\n+  var maskDialogCloseEvents       : Boolean                   = false                        // avoid catching a dialog close event received from the server, so we don\'t sent it back to the server\n+  var currentFocusControlId       : js.Object                 = null                         // id of the control that got the focus last\n+  var currentFocusControlElement  : js.Object                 = null                         // element for the control that got the focus last\n+  var yuiCalendar                 : js.Object                 = null                         // reusable calendar widget\n+  var tooltipLibraryInitialized   : Boolean                   = false\n+  var changedIdsRequest           : js.Dictionary[Int]        = js.Dictionary.empty          // id of controls that have been touched by user since the last response was received\n+  var loadingOtherPage            : Boolean                   = false                        // flag set when loading other page that prevents the loading indicator to disappear\n+  var activeControl               : js.Object                 = null                         // the currently active control, used to disable hint\n+  var dialogs                     : js.Dictionary[js.Dynamic] = js.Dictionary.empty          // map for dialogs: id -> YUI dialog object\n+  var hintTooltipForControl       : js.Dictionary[js.Any]     = js.Dictionary.empty          // map from element id -> YUI tooltip or true, that tells us if we have already created a Tooltip for an element\n+  var alertTooltipForControl      : js.Dictionary[js.Any]     = js.Dictionary.empty          // map from element id -> YUI alert or true, that tells us if we have already created a Tooltip for an element\n+  var helpTooltipForControl       : js.Dictionary[js.Any]     = js.Dictionary.empty          // map from element id -> YUI help or true, that tells us if we have already created a Tooltip for an element\n+  var lastEventSentTime           : Double                    = new js.Date().getTime()      // timestamp when the last event was sent to server\n+  var sliderYui                   : js.Dictionary[js.Any]     = js.Dictionary.empty          // maps slider id to the YUI object for that slider\n+  var lastDialogZIndex            : Int                       = 1050                         // zIndex of the last dialog displayed; gets incremented so the last dialog is always on top of everything else; initial value set to Bootstrap\'s @zindexModal\n+\n+  var modalProgressPanel          : js.Object                 = null                         // overlay modal panel for displaying progress bar\n+  var modalProgressPanelTimerId   : js.Any                    = null                         // timer id for modal progress panels shown asynchronously (iOS)\n+\n+  var changeListeners             : js.Dictionary[js.Any]     = js.Dictionary.empty          // maps control id to DOM element for which we have registered a change listener\n+  var topLevelListenerRegistered  : Boolean                   = false                        // have we already registered the listeners on the top-level elements, which never change\n+}\ndiff --git a/xforms/js/src/main/scala/org/orbeon/xforms/LoadingIndicator.scala b/xforms/js/src/main/scala/org/orbeon/xforms/LoadingIndicator.scala\nindex c0fb32f3fc..60d16b15d0 100644\n--- a/xforms/js/src/main/scala/org/orbeon/xforms/LoadingIndicator.scala\n+++ b/xforms/js/src/main/scala/org/orbeon/xforms/LoadingIndicator.scala\n@@ -13,7 +13,7 @@\n   */\n package org.orbeon.xforms\n \n-import org.orbeon.xforms.facade.{ConnectCallbackArgument, Events, Globals, Properties}\n+import org.orbeon.xforms.facade.{ConnectCallbackArgument, Events, Properties}\n \n import scala.scalajs.js\n import scala.scalajs.js.annotation.JSGlobal\ndiff --git a/xforms/js/src/main/scala/org/orbeon/xforms/XFormsApp.scala b/xforms/js/src/main/scala/org/orbeon/xforms/XFormsApp.scala\nindex 0d1cb44fe5..17e0d179fd 100644\n--- a/xforms/js/src/main/scala/org/orbeon/xforms/XFormsApp.scala\n+++ b/xforms/js/src/main/scala/org/orbeon/xforms/XFormsApp.scala\n@@ -22,7 +22,6 @@ object XFormsApp extends App {\n \n   // NOTE: `object`s which have `@JSExportTopLevel` do not need to be explicitly called here.\n   def onOrbeonApiLoaded(): Unit = {\n-    Init.initializeGlobals() // should go away in the future\n     Upload\n     xbl.Date\n   }\ndiff --git a/xforms/js/src/main/scala/org/orbeon/xforms/facade/facades.scala b/xforms/js/src/main/scala/org/orbeon/xforms/facade/facades.scala\nindex 18f6ab8f4b..3ace66efa7 100644\n--- a/xforms/js/src/main/scala/org/orbeon/xforms/facade/facades.scala\n+++ b/xforms/js/src/main/scala/org/orbeon/xforms/facade/facades.scala\n@@ -13,7 +13,7 @@\n   */\n package org.orbeon.xforms.facade\n \n-import org.orbeon.xforms.{AjaxServerEvent, YUICustomEvent}\n+import org.orbeon.xforms.{AjaxServerEvent, Globals, YUICustomEvent}\n import org.scalajs.dom\n import org.scalajs.dom.raw.XMLHttpRequest\n import org.scalajs.dom.{html, raw}\n@@ -127,25 +127,6 @@ object AjaxServerOps {\n   }\n }\n \n-@JSGlobal("ORBEON.xforms.Globals")\n-@js.native\n-object Globals extends js.Object {\n-  var loadingOtherPage           : Boolean                     = js.native\n-  var eventQueue                 : js.Array[AjaxServerEvent]   = js.native\n-  var eventsFirstEventTime       : Double                      = js.native\n-  var lastEventSentTime          : Double                      = js.native\n-  var requestInProgress          : Boolean                     = js.native\n-  val dialogs                    : js.Dictionary[js.Dynamic]   = js.native\n-  var lastDialogZIndex           : Int                         = js.native\n-  var topLevelListenerRegistered : Boolean                     = js.native\n-  var executeEventFunctionQueued : Int                         = js.native\n-  var requestForm                : html.Form                   = js.native\n-  var requestIgnoreErrors        : Boolean                     = js.native\n-  var requestTryCount            : Int                         = js.native\n-  var requestDocument            : String                      = js.native\n-  var changedIdsRequest          : js.Dictionary[Int]          = js.native\n-}\n-\n @js.native\n trait Item extends js.Object {\n   val label                 : String                      = js.native\ndiff --git a/xforms/jvm/src/main/assets/ops/javascript/orbeon/xforms/server/AjaxServer.js b/xforms/jvm/src/main/assets/ops/javascript/orbeon/xforms/server/AjaxServer.js\nindex c85a5ad866..c53b80d578 100644\n--- a/xforms/jvm/src/main/assets/ops/javascript/orbeon/xforms/server/AjaxServer.js\n+++ b/xforms/jvm/src/main/assets/ops/javascript/orbeon/xforms/server/AjaxServer.js\n@@ -69,7 +69,7 @@\n         var timerId = window.setTimeout(function () {\n             var event = new AjaxServer.Event(document.getElementById(formID), null,\n                     serverEvents, "xxforms-server-events", null, null, null, showProgress);\n-            AjaxServer.fireEvents([event]);\n+            AjaxServer.fireEvents([event], false);\n         }, delay);\n         // Save timer id for this discardable timer\n         if (discardable)\n@@ -444,7 +444,7 @@\n                                 });\n \n                                 // Set content of select element\n-                                if (ORBEON.xforms.Globals.renderingEngineTridentOrZero) {\n+                                if (ORBEON.xforms.Globals.isRenderingEngineTrident) {\n \n                                     // TODO: Check if this is still the case with IE11, the only version Orbeon Forms supports\n                                     // as of Orbeon Forms 2018.2.\ndiff --git a/xforms/jvm/src/main/assets/ops/javascript/xforms.js b/xforms/jvm/src/main/assets/ops/javascript/xforms.js\nindex bce770d079..1320c2a417 100644\n--- a/xforms/jvm/src/main/assets/ops/javascript/xforms.js\n+++ b/xforms/jvm/src/main/assets/ops/javascript/xforms.js\n@@ -2867,7 +2867,7 @@ var TEXT_TYPE = document.createTextNode("").nodeType;\n                 if ($(node).is(\'.xforms-activable\')) {\n                     var form = ORBEON.xforms.Controls.getForm(node);\n                     var event = new ORBEON.xforms.server.AjaxServer.Event(form, node.id, null, "DOMActivate");\n-                    ORBEON.xforms.server.AjaxServer.fireEvents([event]);\n+                    ORBEON.xforms.server.AjaxServer.fireEvents([event], false);\n                     break;\n                 }\n \n@@ -2884,7 +2884,7 @@ var TEXT_TYPE = document.createTextNode("").nodeType;\n                             targetId += targetId.indexOf(XF_REPEAT_SEPARATOR) == -1 ? XF_REPEAT_SEPARATOR : XF_REPEAT_INDEX_SEPARATOR;\n                             targetId += delimiterCount;\n                             var event = new ORBEON.xforms.server.AjaxServer.Event(form, targetId, null, "xxforms-repeat-activate");\n-                            ORBEON.xforms.server.AjaxServer.fireEvents([event]);\n+                            ORBEON.xforms.server.AjaxServer.fireEvents([event], false);\n                             foundRepeatBegin = true;\n                             break;\n                         } else if ($(sibling).is(\'.xforms-repeat-delimiter\')) {\n@@ -3289,51 +3289,6 @@ var TEXT_TYPE = document.createTextNode("").nodeType;\n \n     ORBEON.xforms.Init = {\n \n-        initializeGlobals: function () {\n-\n-            _.extend(ORBEON.xforms.Globals, {\n-                // Browser detection\n-                renderingEngineTridentOrZero: YAHOO.env.ua.ie, // One usage left to check as of 2019-01-04.\n-\n-                // Other\n-                eventQueue: [],                      // Events to be sent to the server\n-                eventsFirstEventTime: 0,             // Time when the first event in the queue was added\n-\n-                requestForm: null,                   // HTML for the request currently in progress\n-                requestIgnoreErrors: false,          // Should we ignore errors that result from running this request\n-                requestInProgress: false,            // Indicates whether an Ajax request is currently in process\n-                requestDocument: "",                 // The last Ajax request, so we can resend it if necessary\n-                requestTryCount: 0,                  // How many attempts to run the current Ajax request we have done so far\n-                executeEventFunctionQueued: 0,       // Number of ORBEON.xforms.server.AjaxServer.executeNextRequest waiting to be executed\n-                maskFocusEvents: false,              // Avoid catching focus event when we do call setfocus upon server request\n-                maskDialogCloseEvents: false,        // Avoid catching a dialog close event received from the server, so we don\'t sent it back to the server\n-                currentFocusControlId: null,         // Id of the control that got the focus last\n-                currentFocusControlElement: null,    // Element for the control that got the focus last\n-                htmlAreaNames: [],                   // Names of the HTML editors, which we need to reenable them on Firefox\n-                yuiCalendar: null,                   // Reusable calendar widget\n-                tooltipLibraryInitialized: false,\n-                changedIdsRequest: {},               // Id of controls that have been touched by user since the last response was received\n-                loadingOtherPage: false,             // Flag set when loading other page that prevents the loading indicator to disappear\n-                activeControl: null,                 // The currently active control, used to disable hint\n-                dialogs: {},                         // Map for dialogs: id -> YUI dialog object\n-                hintTooltipForControl: {},           // Map from element id -> YUI tooltip or true, that tells us if we have already created a Tooltip for an element\n-                alertTooltipForControl: {},          // Map from element id -> YUI alert or true, that tells us if we have already created a Tooltip for an element\n-                helpTooltipForControl: {},           // Map from element id -> YUI help or true, that tells us if we have already created a Tooltip for an element\n-                debugDiv: null,                      // Points to the div when debug messages are displayed\n-                lastEventSentTime: new Date().getTime(), // Timestamp when the last event was sent to server\n-                sliderYui: {},                       // Maps slider id to the YUI object for that slider\n-                lastDialogZIndex: 1050,              // zIndex of the last dialog displayed; gets incremented so the last dialog is always on top of everything else; initial value set to Bootstrap\'s @zindexModal\n-\n-\n-                modalProgressPanel: null,            // Overlay modal panel for displaying progress bar\n-                modalProgressPanelTimerId: null,     // Timer id for modal progress panels shown asynchronously (iOS)\n-\n-                changeListeners: {},                 // Maps control id to DOM element for which we have registered a change listener\n-                topLevelListenerRegistered:          // Have we already registered the listeners on the top-level elements, which never change\n-                        ORBEON.xforms.Globals.topLevelListenerRegistered == null ? false : ORBEON.xforms.Globals.topLevelListenerRegistered\n-            });\n-        },\n-\n         // Should move to XBL component, see: https://github.com/orbeon/orbeon-forms/issues/2658.\n         _range: function (range) {\n             range.tabIndex = 0;\n', 'commit_subject': 'For #3147: move `Globals` to Scala', 'repo_name': 'orbeon/orbeon-forms', 'committer': {'name': 'ebruchez', 'email': '67aad48d6511806a4af5612b9998de6a8f7fe611@orbeon.com', 'time_sec': '1576007044', 'tz_offset': '-480', 'date': {'seconds': '1576007044'}}, 'commit_tree': 'cb356b56ca379c9d416eef0ede3f7c4ab8eaa5d3', 'commit_message': 'For #3147: move `Globals` to Scala\n', 'language_name': 'JavaScript', 'license': 'lgpl-2.1', 'hunks': '@@ -0,0 +1,58 @@\n+/**\n+ * Copyright (C) 2019 Orbeon, Inc.\n+ *\n+ * This program is free software; you can redistribute it and/or modify it under the terms of the\n+ * GNU Lesser General Public License as published by the Free Software Foundation; either version\n+ *  2.1 of the License, or (at your option) any later version.\n+ *\n+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;\n+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n+ * See the GNU Lesser General Public License for more details.\n+ *\n+ * The full text of the license is available at http://www.gnu.org/copyleft/lesser.html\n+ */\n+package org.orbeon.xforms\n+\n+import org.orbeon.facades.Bowser\n+import org.scalajs.dom.html\n+\n+import scala.scalajs.js\n+import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel}\n+\n+@JSExportTopLevel("ORBEON.xforms.Globals")\n+@JSExportAll\n+object Globals {\n+\n+  lazy val isRenderingEngineTrident: Boolean                   = Bowser.msie.getOrElse(false) // one usage left to check as of 2019-01-04\n+\n+  var eventQueue                  : js.Array[AjaxServerEvent] = js.Array()                   // events to be sent to the server\n+  var eventsFirstEventTime        : Double                    = 0                            // time when the first event in the queue was added\n+  var requestForm                 : html.Form                 = null                         // hTML for the request currently in progress\n+  var requestIgnoreErrors         : Boolean                   = false                        // should we ignore errors that result from running this request\n+  var requestInProgress           : Boolean                   = false                        // indicates whether an Ajax request is currently in process\n+  var requestDocument             : String                    = ""                           // the last Ajax request, so we can resend it if necessary\n+  var requestTryCount             : Int                       = 0                            // how many attempts to run the current Ajax request we have done so far\n+  var executeEventFunctionQueued  : Int                       = 0                            // number of ORBEON.xforms.server.AjaxServer.executeNextRequest waiting to be executed\n+  var maskFocusEvents             : Boolean                   = false                        // avoid catching focus event when we do call setfocus upon server request\n+  var maskDialogCloseEvents       : Boolean                   = false                        // avoid catching a dialog close event received from the server, so we don\'t sent it back to the server\n+  var currentFocusControlId       : js.Object                 = null                         // id of the control that got the focus last\n+  var currentFocusControlElement  : js.Object                 = null                         // element for the control that got the focus last\n+  var yuiCalendar                 : js.Object                 = null                         // reusable calendar widget\n+  var tooltipLibraryInitialized   : Boolean                   = false\n+  var changedIdsRequest           : js.Dictionary[Int]        = js.Dictionary.empty          // id of controls that have been touched by user since the last response was received\n+  var loadingOtherPage            : Boolean                   = false                        // flag set when loading other page that prevents the loading indicator to disappear\n+  var activeControl               : js.Object                 = null                         // the currently active control, used to disable hint\n+  var dialogs                     : js.Dictionary[js.Dynamic] = js.Dictionary.empty          // map for dialogs: id -> YUI dialog object\n+  var hintTooltipForControl       : js.Dictionary[js.Any]     = js.Dictionary.empty          // map from element id -> YUI tooltip or true, that tells us if we have already created a Tooltip for an element\n+  var alertTooltipForControl      : js.Dictionary[js.Any]     = js.Dictionary.empty          // map from element id -> YUI alert or true, that tells us if we have already created a Tooltip for an element\n+  var helpTooltipForControl       : js.Dictionary[js.Any]     = js.Dictionary.empty          // map from element id -> YUI help or true, that tells us if we have already created a Tooltip for an element\n+  var lastEventSentTime           : Double                    = new js.Date().getTime()      // timestamp when the last event was sent to server\n+  var sliderYui                   : js.Dictionary[js.Any]     = js.Dictionary.empty          // maps slider id to the YUI object for that slider\n+  var lastDialogZIndex            : Int                       = 1050                         // zIndex of the last dialog displayed; gets incremented so the last dialog is always on top of everything else; initial value set to Bootstrap\'s @zindexModal\n+\n+  var modalProgressPanel          : js.Object                 = null                         // overlay modal panel for displaying progress bar\n+  var modalProgressPanelTimerId   : js.Any                    = null                         // timer id for modal progress panels shown asynchronously (iOS)\n+\n+  var changeListeners             : js.Dictionary[js.Any]     = js.Dictionary.empty          // maps control id to DOM element for which we have registered a change listener\n+  var topLevelListenerRegistered  : Boolean                   = false                        // have we already registered the listeners on the top-level elements, which never change\n+}\n', 'addition_count': 58, 'deletion_count': 0, 'src_file': '/dev/null', 'tgt_file': 'b/xforms/js/src/main/scala/org/orbeon/xforms/Globals.scala', 'file_extension': '.scala', 'before_file': 'ADDFILE', 'message': 'For #3147: move `Globals` to Scala\n', 'author_name': 'ebruchez', 'lang': 'scala'}