Bug 1402877 - Part 2. Don't let click event dispatch through media controls to video element. r=jaws draft
authorRay Lin <ralin@mozilla.com>
Tue, 26 Sep 2017 16:19:10 +0800
changeset 685981 621fa873ead226b1fab9fddb6a3d6e6c848478c9
parent 685973 9e63b032c5b3a74e96d282b1735ba2925e6f9a36
child 685982 7689d65ef0633b945f1396194ba493ab54a2c462
push id86055
push userbmo:ralin@mozilla.com
push dateWed, 25 Oct 2017 07:42:55 +0000
reviewersjaws
bugs1402877
milestone58.0a1
Bug 1402877 - Part 2. Don't let click event dispatch through media controls to video element. r=jaws MozReview-Commit-ID: BUW9PDxCSAY
toolkit/content/tests/widgets/test_videocontrols.html
toolkit/content/widgets/videocontrols.xml
--- a/toolkit/content/tests/widgets/test_videocontrols.html
+++ b/toolkit/content/tests/widgets/test_videocontrols.html
@@ -326,16 +326,36 @@ add_task(async function whitespace_pause
 add_task(async function click_and_hold_slider() {
   synthesizeMouse(video, scrubberOffsetX + 10, scrubberCenterY, {type: "mousedown", button: 0});
   await waitForEvent("pause", "seeking", "seeked");
 
   synthesizeMouse(video, scrubberOffsetX + 10, scrubberCenterY, {});
   await waitForEvent("play");
 });
 
+/*
+ * Bug 1402877: Don't let click event dispatch through media controls to video element.
+ */
+add_task(async function click_event_dispatch() {
+  const clientScriptClickHandler = (e) => {
+    ok(false, "Should not receive the event");
+  };
+  video.addEventListener("click", clientScriptClickHandler);
+
+  video.pause();
+  await waitForEvent("pause");
+  video.currentTime = 0.0;
+  await waitForEvent("seeking", "seeked");
+  is(video.paused, true, "checking video play state");
+  synthesizeMouse(video, scrubberOffsetX + 10, scrubberCenterY, {});
+  await waitForEvent("seeking", "seeked");
+
+  video.removeEventListener("click", clientScriptClickHandler);
+});
+
 // Bug 1367194: Always ensure video is paused before finishing the test.
 add_task(async function ensure_video_pause() {
   if (!video.paused) {
     video.pause();
     await waitForEvent("pause");
   }
 });
 
--- a/toolkit/content/widgets/videocontrols.xml
+++ b/toolkit/content/widgets/videocontrols.xml
@@ -705,17 +705,17 @@
             } catch (ex) {}
           }
         }
 
         if (this.controlListeners) {
           for (let element of this.controlListeners) {
             try {
               element.item.removeEventListener(element.event, element.func,
-                { mozSystemGroup: true, capture: element.capture });
+                { mozSystemGroup: element.mozSystemGroup, capture: element.capture });
             } catch (ex) {}
           }
 
           delete this.controlListeners;
         }
 
         this.log("--- videocontrols terminated ---");
       },
@@ -1813,37 +1813,46 @@
 
         var self = this;
         this.controlListeners = [];
 
         // Helper function to add an event listener to the given element
         // Due to this helper function, "Utils" is made available to the event
         // listener functions. Hence declare it as a global for ESLint.
         /* global Utils */
-        function addListener(elem, eventName, func, capture = false) {
+        function addListener(elem, eventName, func, {capture = false, mozSystemGroup = true} = {}) {
           let boundFunc = func.bind(self);
-          self.controlListeners.push({ item: elem, event: eventName, func: boundFunc, capture });
-          elem.addEventListener(eventName, boundFunc, { mozSystemGroup: true, capture });
+          self.controlListeners.push({
+            item: elem,
+            event: eventName,
+            func: boundFunc,
+            capture,
+            mozSystemGroup,
+          });
+          elem.addEventListener(eventName, boundFunc, {mozSystemGroup, capture});
         }
 
         addListener(this.muteButton, "click", this.toggleMute);
         addListener(this.closedCaptionButton, "click", this.toggleClosedCaption);
         addListener(this.fullscreenButton, "click", this.toggleFullscreen);
         addListener(this.playButton, "click", this.clickToPlayClickHandler);
         addListener(this.clickToPlay, "click", this.clickToPlayClickHandler);
         addListener(this.controlsSpacer, "click", this.clickToPlayClickHandler);
         addListener(this.controlsSpacer, "dblclick", this.toggleFullscreen);
 
         addListener(this.videocontrols, "resizevideocontrols", this.adjustControlSize);
         addListener(this.videocontrols, "transitionend", this.onTransitionEnd);
         addListener(this.video.ownerDocument, "mozfullscreenchange", this.onFullscreenChange);
         addListener(this.controlBar, "transitionend", this.onControlBarTransitioned);
         addListener(this.video.ownerDocument, "fullscreenchange", this.onFullscreenChange);
-        addListener(this.video, "keypress", this.keyHandler, true);
-
+        addListener(this.video, "keypress", this.keyHandler, {capture: true});
+        // Prevent any click event within media controls from dispatching through to video.
+        addListener(this.videocontrols, "click", function(event) {
+          event.stopPropagation();
+        }, {mozSystemGroup: false});
         addListener(this.videocontrols, "dragstart", function(event) {
           event.preventDefault(); // prevent dragging of controls image (bug 517114)
         });
 
         if (!this.videocontrols.isTouchControls) {
           addListener(this.scrubber, "input", this.onScrubberInput);
           addListener(this.scrubber, "change", this.onScrubberChange);
           // add mouseup listener additionally to handle the case that `change` event