0

I have a exam application using React. I need to run this application in IE11. In this exam app I have added the onblur event that will run when the user switches away from the tab, and when this event is triggered the user is alerted with a popup and the user's lockCount in DB is incremented. The user's exam will be blocked if the LockCount exceeds the limit defined for the exam.

The problem is that the onblur event is triggered when the page is momentarily frozen. Usually this freezing problem occurs when it takes a long time to rerender the page or call any API service. It is working without any problem in Chrome.

I also tried the onBlur event with Mouseleave event, but when the page freezes the mouseleave event also triggers.

How can I prevent the onBlur event from triggering when the page freezes in IE11?

Code for the onBlur and onFocus events:

  const onFocus = () => {
    setIsOnblur(false);
  };

  const onBlur = () => {
    increaseCount();
    setIsOnblur(true);
  };

  useEffect(() => {
    if (props.location.pathname.includes("/Exam/")) {
      window.addEventListener("focus", onFocus);
      window.addEventListener("blur", onBlur);

      return () => {
        window.removeEventListener("focus", onFocus);
        window.removeEventListener("blur", onBlur);
      };
    }
  }, []);
tolgakisin
  • 21
  • 2
  • 6
  • Would responding to the page's visibility events help? https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API – Drew Reese Dec 17 '20 at 08:10
  • I think Andy's answer makes sense. It freezes when render the page or call the API so you can wait the page being fully loaded, then fire the blur event. You can also use F12 dev tools **Performance** tab to try to find the reason why it freezes in IE 11. – Yu Zhou Dec 18 '20 at 05:23

2 Answers2

1

It seems the issue is that the blur listener is sometimes firing before the page is completely loaded. We can be sure the page is fully loaded via the load event.

From MDN:

The load event is fired when the whole page has loaded, including all dependent resources such as stylesheets and images.

I would therefore make the addEventListeners dependent on the window being fully loaded. Something like this should work:

useEffect(() => {
  window.addEventListener("load", () => {
    if (props.location.pathname.includes("/Exam/")) {
      window.addEventListener("focus", onFocus);
      window.addEventListener("blur", onBlur);
    }

    return () => {
      window.removeEventListener("focus", onFocus);
      window.removeEventListener("blur", onBlur);
    };
  });
}, []);
Andy Hoffman
  • 18,436
  • 4
  • 42
  • 61
0

I solved the problem with this(https://stackoverflow.com/a/9502074/9938582) answer. This answer tells that you can use 3 different methods to detect that user lost focus from the webpage.

  1. Page Visibility API
  2. Focus/Blur Event
  3. User Activities

In my case, I solved the problem with user's mouse activity and timeout.

First case: It works when user changes the screen completely from webpage to another page or something. Page Visibility API allows us to detect when page is hidden to the user. It doesn't catch the lost focus when the page is minimized but the page is not hidden completely. It doesn't count.

Second case: Focus-Blur events are working perfectly in normal conditions. But Internet Explorer issue misleads that.

Third case: Mouse events(mouseout,mousein,mouseover) don't work due to this issue above. But if I use all events and especially mouse events with timeout, onBlur event doesn't trigger when the page freezes.

Here is the code:

useEffect(() => {
    if (props.location.pathname.includes("/Exam/")) {
      var doc = document as any;

      // register to the W3C Page Visibility API
      var hidden: any = null;
      var visibilityChange: any = null;
      if (typeof doc.mozHidden !== "undefined") {
        hidden = "mozHidden";
        visibilityChange = "mozvisibilitychange";
      } else if (typeof doc.msHidden !== "undefined") {
        hidden = "msHidden";
        visibilityChange = "msvisibilitychange";
      } else if (typeof doc.webkitHidden !== "undefined") {
        hidden = "webkitHidden";
        visibilityChange = "webkitvisibilitychange";
        // } else if (typeof document.hidden !== "hidden") {
      } else if (doc.hidden) {
        hidden = "hidden";
        visibilityChange = "visibilitychange";
      }
      if (hidden != null && visibilityChange != null) {
        addEvent(doc, visibilityChange, function (event: any) {
          if (doc[hidden]) {
            onBlur();
          }
        });
      }

      // register to the potential page visibility change
      addEvent(doc, "potentialvisilitychange", function (event: any) {
        if (doc.potentialHidden && !doc[hidden]) {
          onBlur();
        }
      });

      var potentialPageVisibility = {
        pageVisibilityChangeThreshold: 3 * 3600, // in seconds
        init: function () {
          var lastActionDate: any = null;
          var hasFocusLocal: any = true;
          var hasMouseOver: any = true;
          doc.potentialHidden = false;
          doc.potentiallyHiddenSince = 0;
          var timeoutHandler: any = null;

          function setAsNotHidden() {
            var dispatchEventRequired = doc.potentialHidden;
            doc.potentialHidden = false;
            doc.potentiallyHiddenSince = 0;
            if (dispatchEventRequired) dispatchPageVisibilityChangeEvent();
          }

          function initPotentiallyHiddenDetection() {
            if (!hasFocusLocal) {
              // the window does not has the focus => check for  user activity in the window
              lastActionDate = new Date();
              if (timeoutHandler != null) {
                clearTimeout(timeoutHandler);
              }
              timeoutHandler = setTimeout(checkPageVisibility, potentialPageVisibility.pageVisibilityChangeThreshold * 1000 + 100); // +100 ms to avoid rounding issues under Firefox
            }
          }

          function dispatchPageVisibilityChangeEvent() {
            var evt = doc.createEvent("Event");
            evt.initEvent("potentialvisilitychange", true, true);
            doc.dispatchEvent(evt);
          }

          function checkPageVisibility() {
            var potentialHiddenDuration = (hasFocusLocal || lastActionDate == null ? 0 : Math.floor((new Date().getTime() - lastActionDate.getTime()) / 1000));
            doc.potentiallyHiddenSince = potentialHiddenDuration;
            if (potentialHiddenDuration >= potentialPageVisibility.pageVisibilityChangeThreshold && !doc.potentialHidden) {
              // page visibility change threshold raiched => raise the even
              doc.potentialHidden = true;
              dispatchPageVisibilityChangeEvent();
            }
          }
          addEvent(doc, "mousemove", function (event: any) {
            lastActionDate = new Date();
          });
          addEvent(doc, "mouseover", function (event: any) {
            hasMouseOver = true;
            setAsNotHidden();
          });
          addEvent(doc, "mouseout", function (event: any) {
            hasMouseOver = false;
            initPotentiallyHiddenDetection();
          });
          addEvent(window, "blur", function (event: any) {
            hasFocusLocal = false;
            initPotentiallyHiddenDetection();
          });
          addEvent(window, "focus", function (event: any) {
            hasFocusLocal = true;
            setAsNotHidden();
          });
          setAsNotHidden();
        }
      }

      potentialPageVisibility.pageVisibilityChangeThreshold = 1; // 4 seconds for testing
      potentialPageVisibility.init();
    }
}, []);
tolgakisin
  • 21
  • 2
  • 6