浏览代码

feat(tile-view): double click to pin

j8
Leonard Kim 6 年前
父节点
当前提交
ebcde745ef

+ 1
- 11
modules/UI/UI.js 查看文件

@@ -595,17 +595,7 @@ UI.removeListener = function(type, listener) {
595 595
  */
596 596
 UI.emitEvent = (type, ...options) => eventEmitter.emit(type, ...options);
597 597
 
598
-UI.clickOnVideo = function(videoNumber) {
599
-    const videos = $('#remoteVideos .videocontainer:not(#mixedstream)');
600
-    const videosLength = videos.length;
601
-
602
-    if (videosLength <= videoNumber) {
603
-        return;
604
-    }
605
-    const videoIndex = videoNumber === 0 ? 0 : videosLength - videoNumber;
606
-
607
-    videos[videoIndex].click();
608
-};
598
+UI.clickOnVideo = videoNumber => VideoLayout.togglePin(videoNumber);
609 599
 
610 600
 // Used by torture.
611 601
 UI.showToolbar = timeout => APP.store.dispatch(showToolbox(timeout));

+ 4
- 8
modules/UI/shared_video/SharedVideoThumb.js 查看文件

@@ -15,11 +15,14 @@ export default function SharedVideoThumb(participant, videoType, VideoLayout) {
15 15
     this.videoSpanId = 'sharedVideoContainer';
16 16
     this.container = this.createContainer(this.videoSpanId);
17 17
     this.$container = $(this.container);
18
-    this.container.onclick = this.videoClick.bind(this);
18
+
19 19
     this.bindHoverHandler();
20 20
     SmallVideo.call(this, VideoLayout);
21 21
     this.isVideoMuted = true;
22 22
     this.setDisplayName(participant.name);
23
+
24
+    this.container.onclick = this._onContainerClick;
25
+    this.container.ondblclick = this._onContainerDoubleClick;
23 26
 }
24 27
 SharedVideoThumb.prototype = Object.create(SmallVideo.prototype);
25 28
 SharedVideoThumb.prototype.constructor = SharedVideoThumb;
@@ -61,13 +64,6 @@ SharedVideoThumb.prototype.createContainer = function(spanId) {
61 64
     return container;
62 65
 };
63 66
 
64
-/**
65
- * The thumb click handler.
66
- */
67
-SharedVideoThumb.prototype.videoClick = function() {
68
-    this._togglePin();
69
-};
70
-
71 67
 /**
72 68
  * Removes RemoteVideo from the page.
73 69
  */

+ 2
- 35
modules/UI/videolayout/LocalVideo.js 查看文件

@@ -61,7 +61,8 @@ function LocalVideo(VideoLayout, emitter, streamEndedCallback) {
61 61
     this.addAudioLevelIndicator();
62 62
     this.updateIndicators();
63 63
 
64
-    this.container.onclick = this._onContainerClick.bind(this);
64
+    this.container.onclick = this._onContainerClick;
65
+    this.container.ondblclick = this._onContainerDoubleClick;
65 66
 }
66 67
 
67 68
 LocalVideo.prototype = Object.create(SmallVideo.prototype);
@@ -253,40 +254,6 @@ LocalVideo.prototype.updateDOMLocation = function() {
253 254
     this._updateVideoElement();
254 255
 };
255 256
 
256
-/**
257
- * Callback invoked when the thumbnail is clicked. Will directly call
258
- * VideoLayout to handle thumbnail click if certain elements have not been
259
- * clicked.
260
- *
261
- * @param {MouseEvent} event - The click event to intercept.
262
- * @private
263
- * @returns {void}
264
- */
265
-LocalVideo.prototype._onContainerClick = function(event) {
266
-    // TODO Checking the classes is a workround to allow events to bubble into
267
-    // the DisplayName component if it was clicked. React's synthetic events
268
-    // will fire after jQuery handlers execute, so stop propogation at this
269
-    // point will prevent DisplayName from getting click events. This workaround
270
-    // should be removeable once LocalVideo is a React Component because then
271
-    // the components share the same eventing system.
272
-    const $source = $(event.target || event.srcElement);
273
-    const { classList } = event.target;
274
-
275
-    const clickedOnDisplayName
276
-        = $source.parents('.displayNameContainer').length > 0;
277
-    const clickedOnPopover = $source.parents('.popover').length > 0
278
-            || classList.contains('popover');
279
-    const ignoreClick = clickedOnDisplayName || clickedOnPopover;
280
-
281
-    if (event.stopPropagation && !ignoreClick) {
282
-        event.stopPropagation();
283
-    }
284
-
285
-    if (!ignoreClick) {
286
-        this._togglePin();
287
-    }
288
-};
289
-
290 257
 /**
291 258
  * Renders the React Element for displaying video in {@code LocalVideo}.
292 259
  *

+ 3
- 33
modules/UI/videolayout/RemoteVideo.js 查看文件

@@ -22,8 +22,7 @@ import {
22 22
 } from '../../../react/features/remote-video-menu';
23 23
 import {
24 24
     LAYOUTS,
25
-    getCurrentLayout,
26
-    shouldDisplayTileView
25
+    getCurrentLayout
27 26
 } from '../../../react/features/video-layout';
28 27
 /* eslint-enable no-unused-vars */
29 28
 
@@ -89,7 +88,8 @@ function RemoteVideo(user, VideoLayout, emitter) {
89 88
     this._setAudioVolume = this._setAudioVolume.bind(this);
90 89
     this._stopRemoteControl = this._stopRemoteControl.bind(this);
91 90
 
92
-    this.container.onclick = this._onContainerClick.bind(this);
91
+    this.container.onclick = this._onContainerClick;
92
+    this.container.ondblclick = this._onContainerDoubleClick;
93 93
 }
94 94
 
95 95
 RemoteVideo.prototype = Object.create(SmallVideo.prototype);
@@ -613,36 +613,6 @@ RemoteVideo.prototype.removePresenceLabel = function() {
613 613
     }
614 614
 };
615 615
 
616
-/**
617
- * Callback invoked when the thumbnail is clicked. Will directly call
618
- * VideoLayout to handle thumbnail click if certain elements have not been
619
- * clicked.
620
- *
621
- * @param {MouseEvent} event - The click event to intercept.
622
- * @private
623
- * @returns {void}
624
- */
625
-RemoteVideo.prototype._onContainerClick = function(event) {
626
-    const $source = $(event.target || event.srcElement);
627
-    const { classList } = event.target;
628
-
629
-    const ignoreClick = $source.parents('.popover').length > 0
630
-            || classList.contains('popover');
631
-
632
-    if (!ignoreClick) {
633
-        this._togglePin();
634
-    }
635
-
636
-    // On IE we need to populate this handler on video <object> and it does not
637
-    // give event instance as an argument, so we check here for methods.
638
-    if (event.stopPropagation && event.preventDefault && !ignoreClick) {
639
-        event.stopPropagation();
640
-        event.preventDefault();
641
-    }
642
-
643
-    return false;
644
-};
645
-
646 616
 RemoteVideo.createContainer = function(spanId) {
647 617
     const container = document.createElement('span');
648 618
 

+ 75
- 2
modules/UI/videolayout/SmallVideo.js 查看文件

@@ -142,6 +142,9 @@ function SmallVideo(VideoLayout) {
142 142
     // Bind event handlers so they are only bound once for every instance.
143 143
     this._onPopoverHover = this._onPopoverHover.bind(this);
144 144
     this.updateView = this.updateView.bind(this);
145
+
146
+    this._onContainerClick = this._onContainerClick.bind(this);
147
+    this._onContainerDoubleClick = this._onContainerDoubleClick.bind(this);
145 148
 }
146 149
 
147 150
 /**
@@ -821,12 +824,71 @@ SmallVideo.prototype.updateIndicators = function() {
821 824
 };
822 825
 
823 826
 /**
824
- * Pins the participant displayed by this thumbnail or unpins if already pinned.
827
+ * Callback invoked when the thumbnail is double clicked. Will pin the
828
+ * participant if in tile view.
829
+ *
830
+ * @param {MouseEvent} event - The click event to intercept.
831
+ * @private
832
+ * @returns {void}
833
+ */
834
+SmallVideo.prototype._onContainerDoubleClick = function(event) {
835
+    if (this._pinningRequiresDoubleClick() && this._shouldTriggerPin(event)) {
836
+        APP.store.dispatch(pinParticipant(this.id));
837
+    }
838
+};
839
+
840
+/**
841
+ * Callback invoked when the thumbnail is clicked and potentially trigger
842
+ * pinning of the participant.
825 843
  *
844
+ * @param {MouseEvent} event - The click event to intercept.
826 845
  * @private
827 846
  * @returns {void}
828 847
  */
829
-SmallVideo.prototype._togglePin = function() {
848
+SmallVideo.prototype._onContainerClick = function(event) {
849
+    const triggerPin = this._shouldTriggerPin(event)
850
+        && !this._pinningRequiresDoubleClick();
851
+
852
+    if (event.stopPropagation && triggerPin) {
853
+        event.stopPropagation();
854
+        event.preventDefault();
855
+    }
856
+
857
+    if (triggerPin) {
858
+        this.togglePin();
859
+    }
860
+
861
+    return false;
862
+};
863
+
864
+/**
865
+ * Returns whether or not a click event is targeted at certain elements which
866
+ * should not trigger a pin.
867
+ *
868
+ * @param {MouseEvent} event - The click event to intercept.
869
+ * @private
870
+ * @returns {boolean}
871
+ */
872
+SmallVideo.prototype._shouldTriggerPin = function(event) {
873
+    // TODO Checking the classes is a workround to allow events to bubble into
874
+    // the DisplayName component if it was clicked. React's synthetic events
875
+    // will fire after jQuery handlers execute, so stop propogation at this
876
+    // point will prevent DisplayName from getting click events. This workaround
877
+    // should be removeable once LocalVideo is a React Component because then
878
+    // the components share the same eventing system.
879
+    const $source = $(event.target || event.srcElement);
880
+
881
+    return $source.parents('.displayNameContainer').length === 0
882
+        && $source.parents('.popover').length === 0
883
+        && !event.target.classList.contains('popover');
884
+};
885
+
886
+/**
887
+ * Pins the participant displayed by this thumbnail or unpins if already pinned.
888
+ *
889
+ * @returns {void}
890
+ */
891
+SmallVideo.prototype.togglePin = function() {
830 892
     const pinnedParticipant
831 893
         = getPinnedParticipant(APP.store.getState()) || {};
832 894
     const participantIdToPin
@@ -836,6 +898,17 @@ SmallVideo.prototype._togglePin = function() {
836 898
     APP.store.dispatch(pinParticipant(participantIdToPin));
837 899
 };
838 900
 
901
+/**
902
+ * Returns whether or not clicking to pin the participant needs to be a double
903
+ * click instead of a single click.
904
+ *
905
+ * @private
906
+ * @returns {boolean}
907
+ */
908
+SmallVideo.prototype._pinningRequiresDoubleClick = function() {
909
+    return shouldDisplayTileView(APP.store.getState());
910
+};
911
+
839 912
 /**
840 913
  * Removes the React element responsible for showing connection status, dominant
841 914
  * speaker, and raised hand icons.

+ 13
- 0
modules/UI/videolayout/VideoLayout.js 查看文件

@@ -391,6 +391,19 @@ const VideoLayout = {
391 391
         return id || null;
392 392
     },
393 393
 
394
+    /**
395
+     * Triggers a thumbnail to pin or unpin itself.
396
+     *
397
+     * @param {number} videoNumber - The index of the video to toggle pin on.
398
+     * @private
399
+     */
400
+    togglePin(videoNumber) {
401
+        const videos = getAllThumbnails();
402
+        const videoView = videos[videoNumber];
403
+
404
+        videoView && videoView.togglePin();
405
+    },
406
+
394 407
     /**
395 408
      * Callback invoked to update display when the pin participant has changed.
396 409
      *

正在加载...
取消
保存