PageSourceSearch

https://rewindclient-707c1.web.app/src/browserAPIsJsInterop.js

js rewindclient-707c1.web.app collected 2026-10-03 12:34:31 UTC 20,479 bytes, 515 lines download raw bytes

1
2var hidden, visibilityChange;
3if (typeof document.hidden !== "undefined") {
4    hidden = "hidden";
5    visibilityChange = "visibilitychange";
6} else if (typeof document.mozHidden !== "undefined") {
7    hidden = "mozHidden";
8    visibilityChange = "mozvisibilitychange";
9} else if (typeof document.msHidden !== "undefined") {
10    hidden = "msHidden";
11    visibilityChange = "msvisibilitychange";
12} else if (typeof document.webkitHidden !== "undefined") {
13    hidden = "webkitHidden";
14    visibilityChange = "webkitvisibilitychange";
15} else {
16    console.error("JavaScript: Page Visibility API not supported");
17}
18
19document.addEventListener(visibilityChange, handleVisibilityChange, false);
20window.addEventListener("blur", focusLost);
21window.addEventListener("focus", focusGained);
22
23function handleVisibilityChange() {
24    handleFocusStateChange(!document[hidden]);
25}
26
27function focusLost() {
28    handleFocusStateChange(false);
29}
30
31function focusGained() {
32    handleFocusStateChange(true);
33}
34
35// If the given onkeyup event indicates a key code of 13 then the element with the given element ID is blurred
36function blurElementOnEnter(event, elementId) {
37    if (event.which == 13) {
38        var target = document.getElementById(elementId);
39        if (target) {
40            target.blur();
41        }
42    }
43}
44
45function handleFocusStateChange(hasFocus) {
46    //console.log("JavaScript: has focus: " + hasFocus);
47    if (dotNetBrowserAPIsCallbackInstance) {
48        dotNetBrowserAPIsCallbackInstance.invokeMethodAsync("JsInteropFocusStateChanged", hasFocus);
49    } else {
50        //console.warn("JavaScript: handleFocusStateChange(): callback target not registered");
51    }
52}
53
54//*********************************************************************************
55
56// The C# object instance reference used for interop callbacks from this code
57var dotNetBrowserAPIsCallbackInstance = null;
58
59// Called by C# to initialize this code for use by JavaScript interop calls
60function initializeBrowserAPIs(callbackInstance) {
61    dotNetBrowserAPIsCallbackInstance = callbackInstance;
62}
63
64// Stops propagation and default handling of the given event
65function stopEvent(theEvent) {
66    theEvent.stopPropagation();
67    theEvent.preventDefault();
68    return(false);
69}
70
71// In order to successfully support a "long-press" event accross all browsers (including Safari and various Web Views)
72// we do not use "oncontextmenu" event and, instead, role our own long-press detection based on more reliable events
73var longPressUseTouch = false;
74var longPressIsLongPress = false;
75var longPressTimerRef = null;
76var longPressScrollTimerRef = null;
77
78function isScrolling() {
79    return (longPressScrollTimerRef != null);
80}
81
82function makeLongPressCallback(callback, event) {
83    if (isScrolling()) { return; }
84    if (dotNetBrowserAPIsCallbackInstance) {
85        var loc = getLocationFromEvent(event);
86        var which = (event && event.which) ? "" + event.which : "";
87        let elements = document.elementsFromPoint(loc.x, loc.y);
88        let ids = [];
89        for (let i = 0; i < elements.length; i++) {
90            if (elements[i].id) {
91                ids.push(elements[i].id);
92            }
93        }
94        dotNetBrowserAPIsCallbackInstance.invokeMethodAsync(callback, loc.x, loc.y, ids, which);
95    }
96}
97
98function pingTimerForScroll() {
99    if (longPressScrollTimerRef != null) { clearTimeout(longPressScrollTimerRef); }
100    longPressScrollTimerRef = setTimeout(() => {
101        longPressScrollTimerRef = null;
102    }, 550);
103}
104
105function startTimerForLongPress(event) {
106    longPressIsLongPress = false;
107    if (longPressTimerRef == null) {
108        longPressTimerRef = setTimeout(() => {
109            longPressIsLongPress = true;
110            makeLongPressCallback("JsiHandleLongPress", event);
111            longPressTimerRef = null;
112        }, 500)
113    }
114}
115
116function handleOnClickForLongPress(event) {
117    //console.error("handleOnClickForLongPress()");
118    if (isScrolling()) { return; }
119    if (longPressUseTouch) { return; }
120    if (longPressIsLongPress) {
121        return;
122    }
123}
124
125function handleOnMouseDownForLongPress(event) {
126    //console.error("handleOnMouseDownForLongPress()");
127    if (isScrolling()) { return; }
128    if (longPressUseTouch) { return; }
129    startTimerForLongPress(event);
130}
131
132function handleOnMouseUpForLongPress(event) {
133    //console.error("handleOnMouseUpForLongPress()");
134    if (isScrolling()) { return; }
135    if (longPressUseTouch) { return; }
136    if (longPressTimerRef != null) {
137        clearTimeout(longPressTimerRef);
138        longPressTimerRef = null;
139    }
140    if (!longPressIsLongPress) {
141        makeLongPressCallback("JsiHandlePress", event);
142    }
143}
144
145function handleOnTouchStartForLongPress(event) {
146    //console.error("handleOnTouchStartForLongPress()");
147    if (isScrolling()) { return; }
148    longPressUseTouch = true;
149    startTimerForLongPress(event);
150}
151
152function handleOnTouchEndForLongPress(event) {
153    //console.error("handleOnTouchEndForLongPress()");
154    if (isScrolling()) { return; }
155    if (longPressIsLongPress) {
156        longPressIsLongPress = false;
157        return;
158    }
159    if (longPressTimerRef != null) {
160        clearTimeout(longPressTimerRef);
161        longPressTimerRef = null;
162    }
163}
164
165function handleOnScroll(event) {
166    //console.error("handleOnScroll()");
167    pingTimerForScroll();
168}
169
170// Registers the given DOM element ID to receive "long press" events
171function registerLongPressTrigger(elementId) {
172    addClassToElement(elementId, "long-press-trigger");
173    var element = document.getElementById(elementId);
174    element.addEventListener("click", handleOnClickForLongPress);
175    element.addEventListener("mousedown", handleOnMouseDownForLongPress);
176    element.addEventListener("mouseup", handleOnMouseUpForLongPress);
177    element.addEventListener("touchstart", handleOnTouchStartForLongPress);
178    element.addEventListener("touchend", handleOnTouchEndForLongPress);
179    element.addEventListener("contextmenu", stopEvent);
180    element.addEventListener("scroll", handleOnScroll);
181}
182
183// Unregisters the given DOM element ID from receiving "long press" events
184function unregisterLongPressTrigger(elementId) {
185    removeClassFromElement(elementId, "long-press-trigger");
186    var element = document.getElementById(elementId);
187    element.removeEventListener("click", handleOnClickForLongPress);
188    element.removeEventListener("mousedown", handleOnMouseDownForLongPress);
189    element.removeEventListener("mouseup", handleOnMouseUpForLongPress);
190    element.removeEventListener("touchstart", handleOnTouchStartForLongPress);
191    element.removeEventListener("touchend", handleOnTouchEndForLongPress);
192    element.removeEventListener("contextmenu", stopEvent);
193    element.removeEventListener("scroll", handleOnScroll);
194}
195
196// Returns the clientX and clientY values as "{x:_ , y:_}" from the given event, supporting click and touch
197function getLocationFromEvent(event) {
198    if (event.clientX) {
199        return ({ x: event.clientX | 0, y: event.clientY | 0 });
200    } else if (event && event.touches[0] && event.touches[0].clientX) {
201        return ({ x: event.touches[0].clientX | 0, y: event.touches[0].clientY | 0 });
202    }
203}
204
205// Puts focus on the given element and stops the relevant event in order to retain focus
206function setFocus(theEvent, elementId) {
207    document.getElementById(elementId).focus();
208    return(stopEvent(theEvent));
209}
210
211// Called by C# to toggle the visibility and space use of an element
212// The given "displayType" is the value used when making the element visible (block, inline, inline-block, etc.)
213function toggleElement(elementId, displayType) {
214    var element = document.getElementById(elementId);
215    if (element) {
216        if (element.style.display == "none") {
217            element.style.display = displayType;
218            element.style.visibility = "visible";
219        } else {
220            element.style.display = "none";
221            element.style.visibility = "hidden";
222        }
223    }
224}
225
226function makeElementVisible(elementId, displayType = "block") {
227    var element = document.getElementById(elementId);
228    if (element) {
229        element.style.display = displayType;
230        element.style.visibility = "visible";
231    } else {
232        console.error("makeElementVisible(" + elementId + "): element not found");
233    }
234}
235
236function makeElementHidden(elementId) {
237    var element = document.getElementById(elementId);
238    if (element) {
239        element.style.display = "none";
240        element.style.visibility = "hidden";
241    } else {
242        console.error("makeElementHidden(" + elementId + "): element not found");
243    }
244}
245
246// Called by C# to set the given element to absolute positioning with the given location
247function setElementLocation(elementId, top, left) {
248    var element = document.getElementById(elementId);
249    if (!setElementLocationViaElement(element, top, left)) {
250        console.error("setElementLocation(" + elementId + "): element not found");
251    }
252}
253
254function setElementLocationViaElement(element, top, left) {
255    if (element) {
256        element.style.position = "fixed";
257        element.style.top = top + "px";
258        element.style.left = left + "px";
259        return (true);
260    }
261    return (false);
262}
263
264// Called by C# to set the given element to absolute positioning with the given location and size
265function setElementRect(elementId, top, left, width, height) {
266    var element = document.getElementById(elementId);
267    if (element) {
268        element.style.position = "fixed";
269        element.style.top = top + "px";
270        element.style.left = left + "px";
271        element.style.width = width + "px";
272        element.style.height = height + "px";
273    }
274}
275
276// Returns the given element's location as { x:_, y:_ }.
277// The function relies on element.style.left and element.style.top to understand element location.
278function getElementLocation(elementId) {
279    var element = document.getElementById(elementId);
280    var result = {
281        "x": parseInt(element.style.left),
282        "y": parseInt(element.style.top)
283    };
284    return (result);
285}
286
287// Returns the given element's location as { x:_, y:_ }.
288// The function relies on element.offsetLeft and element.offsetTop to understand element location.
289function getElementOffsetLocation(elementId) {
290    var element = document.getElementById(elementId);
291    var result = {
292        "x": parseInt(element.offsetLeft),
293        "y": parseInt(element.offsetTop)
294    };
295    return (result);
296}
297
298// Returns:  { "x":_, "y":_, "width":_, "height":_, "top":_, "right":_, "bottom":_, "left":_ }
299function getElementRect(elementId) {
300    return(document.getElementById(elementId).getBoundingClientRect());
301}
302
303function resizeElementUp(elementId, targetHeight) {
304    const element = document.getElementById(elementId);
305    if (element) {
306        const currentTop = parseInt(element.style.top);
307        const currentHeight = getEleementHeightViaElement(element);
308        const yDelta = currentHeight - targetHeight;
309        const targetTop = currentTop + yDelta;
310        element.style.top = targetTop + "px";
311        element.style.height = targetHeight + "px";
312        if (dotNetBrowserAPIsCallbackInstance) {
313            dotNetBrowserAPIsCallbackInstance.invokeMethodAsync("JsiElementUpdated", elementId);
314        }
315    }
316}
317
318function resizeElementDown(elementId, targetHeight) {
319    const element = document.getElementById(elementId);
320    if (element) {
321        element.style.height = targetHeight + "px";
322        if (dotNetBrowserAPIsCallbackInstance) {
323            dotNetBrowserAPIsCallbackInstance.invokeMethodAsync("JsiElementUpdated", elementId);
324        }
325    }
326}
327
328// Executes the given function now and then again after any transitions on the element finish.
329function callBeforeAndAfterTransition(element, functionToCall) {
330    const transitionListener = (event) => {
331        element.removeEventListener("transitionend", transitionListener);
332        functionToCall();
333    };
334    element.addEventListener("transitionend", transitionListener);
335    functionToCall();
336}
337
338// If the given element has a top, right, or bottom edge that is outside the browser window the element is moved so that the relevent edge(s)
339// aligned with the browsers viewport edge. This function accounts for any in-flight transitions and will reposition the element for
340// current state as well as state after any transition is finished. Callbacks to "JsiElementUpdated" are made whenever the element is moved.
341function fitElementOnScreen(elementId) {
342    const element = document.getElementById(elementId);
343    const functionToCall = () => {
344        if ((fitElementOnScreenViaElement(element)) && (dotNetBrowserAPIsCallbackInstance)) {
345            dotNetBrowserAPIsCallbackInstance.invokeMethodAsync("JsiElementUpdated", elementId);
346        }
347    };
348    callBeforeAndAfterTransition(element, functionToCall);
349}
350
351// If the given element has a top, right, or bottom edge that is outside the browser window the 
352// element is moved so that the relevent edge(s) aligned with the browsers viewport edge.
353function fitElementOnScreenViaElement(element) {
354    var height = getEleementHeightViaElement(element);
355    var width = parseInt(element.offsetWidth);
356    //console.error("width:" + width + " height:" + height);
357    var x = parseInt(element.style.left);
358    var y = parseInt(element.style.top);
359    //console.error("loc: " + x + " x " + y);
360    var xDelta = (window.innerWidth - (x + width));
361    var yDelta = (window.innerHeight - (y + height));
362    //console.error("deltas: " + xDelta + " x " + yDelta);
363    if ((xDelta < 0) || (yDelta < 0) || (y < 0) || ((y + yDelta) < 0)) {
364        if (xDelta < 0) { x = x + xDelta; }
365        if (yDelta < 0) { y = y + yDelta; }
366        if (y < 0) { y = 0; }
367        setElementLocationViaElement(element, y, x);
368        return (true);
369    }
370    return (false);
371}
372
373function getEleementHeightViaElement(element) {
374    var elementStyle = getComputedStyle(element);
375    var heightStr = elementStyle.height;
376    if (!heightStr || heightStr.length <= 0) { heightStr = element.offsetHeight; }
377    return(parseInt(heightStr.replace("px", "")));
378}
379
380// Called by C# to toggle a sub-attribute of the CSS class indicated by the given query selector string.
381function toggleClassFromQuerySelector(querySelector, toToggle) {
382    document.querySelector(querySelector).classList.toggle(toToggle);
383}
384
385// Called by C# to set an attribute value on a DOM element
386function setElementStyle(elementId, styleName, value) {
387    var element = document.getElementById(elementId);
388    if (element) { element.style[styleName] = value; }
389}
390
391// Called by C# to set an attribute value on a DOM element
392function setElementAttribute(elementId, attributeName, value) {
393    var element = document.getElementById(elementId);
394    if (element) { element.setAttribute(attributeName, value); }
395}
396
397// Called by C# to set an attribute value on multiple DOM elements with the given class
398function setElementsAttribute(elementsClass, attributeName, value) {
399    var elements = document.getElementsByClassName(elementsClass);
400    for (var i = 0; i < elements.length; i++) {
401        var element = elements[i];
402        if (element) {
403            element.setAttribute(attributeName, value);
404        }
405    }
406}
407
408// Called by C# to set opacity on a DOM element
409function setElementOpacity(elementId, opacity) {
410    var element = document.getElementById(elementId);
411    if (element) { element.style.opacity = opacity; }
412}
413
414// Called by C# to set background on a DOM element
415function setElementBackground(elementId, background) {
416    var elem = document.getElementById(elementId);
417    if(elem) elem.style.background = background;
418}
419
420// Called by C# to set color on a DOM element
421function setElementColor(elementId, color) {
422    var element = document.getElementById(elementId);
423    if (element) { element.style.color = color; }
424}
425
426// Called by C# to set the value on a DOM element (the element must support the ".value" field)
427function setElementValue(elementId, value) {
428    var element = document.getElementById(elementId);
429    if (element) { element.value = value; }
430}
431
432// Called by C# to set the "disabled" value on a DOM element (the element must support the ".disabled" field and the value past must be "true" or "false")
433function setElementDisabled(elementId, isDisabled) {
434    var element = document.getElementById(elementId);
435    if (element) { element.disabled = isDisabled; }
436}
437
438// Called by C# to set the placeholder text of a DOM element (the element must support the ".placeholder" field)
439function setPlaceholderText(elementId, placeholderText) {
440    var element = document.getElementById(elementId);
441    if (element) { element.placeholder = placeholderText; }
442}
443
444// Called by C# to add a CSS class to a DOM element
445function addClassToElement(elementId, className) {
446    var element = document.getElementById(elementId)
447    if (element) {
448        element.classList.add(className);
449    } else {
450        console.error("JavaScript: addClassToElement(): Element ID '" + elementId + "' not found");
451    }
452}
453
454// Called by C# to remove a CSS class from a DOM element
455function removeClassFromElement(elementId, className) {
456    var element = document.getElementById(elementId)
457    if (element) {
458        element.classList.remove(className);
459    } else {
460        console.error("JavaScript: removeClassFromElement(): Element ID '" + elementId + "' not found");
461    }
462}
463
464// If the browser has history to go back to then simply behaves like the browser "back" button, otherwise navigates to the site origin
465function goBackOrHome() {
466    if (history.length > 2) {
467        history.back();
468    } else {
469        window.location.href = window.location.origin;
470    }
471}
472
473// Called by C# to set a DOM element's height to it's scrollHeight minus a given "correction delta", 
474// which allows the caller to correct for things like border, margin, etc.
475function setElementHeightToScrollHeight(elementId, correctionDelta) {
476    var element = document.getElementById(elementId);
477    if (element) {
478        element.style.height = "auto";
479        element.style.height = (element.scrollHeight - correctionDelta) + "px";
480    }
481}
482
483// Simple accessors for properties
484function getNavigatorAppCodeName() { return (navigator.appCodeName.toString()); }
485function getNavigatorAppName() { return (navigator.appName.toString()); }
486function getNavigatorAppVersion() { return (navigator.appVersion.toString()); }
487function getNavigatorCookieEnabled() { return (navigator.cookieEnabled.toString()); }
488function getNavigatorLanguage() { return (navigator.language.toString()); }
489function getNavigatorOnLine() { return (navigator.onLine.toString()); }
490function getNavigatorPlatform() { return (navigator.platform.toString()); }
491function getNavigatorUserAgent() { return (navigator.userAgent.toString()); }
492
493//*********************************************************************************
494// Customize Firebase Auth error UI
495// NOTE: This breaks the "Dismiss" link; need to figure that out before we use this
496function customizeFirebaseAuthErrorUI() {
497    console.log("JavaScript: customizeFirebaseAuthErrorUI()");
498    var container = document.getElementById("firebaseui-auth-container");
499    if (container.addEventListener) {
500        container.addEventListener(
501            "DOMSubtreeModified",
502            function () {
503                var container = document.getElementById("firebaseui-auth-container");
504                var authUiHtml = container.innerHTML;
505                console.log("Error UI updated. '" + authUiHtml + "'");
506                var signInCancelledText = 'Please authorize the required permissions to sign in to the application';
507                if (authUiHtml.includes(signInCancelledText)) {
508                    authUiHtml = authUiHtml.replace(signInCancelledText, "Please sign in to use Rewind.<br>");
509                    container.innerHTML = authUiHtml;
510				}
511            },
512            false);
513        console.log("JavaScript: customizeFirebaseAuthErrorUI() event listener added");
514    }
515}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.