浏览代码

Hotfix for mobile device

Haocen Xu 7 年之前
父节点
当前提交
43d86d7d5d

+ 6 - 1
client/components/boards/boardBody.js

@@ -1,5 +1,5 @@
 const subManager = new SubsManager();
-const { calculateIndex } = Utils;
+const { calculateIndex, enableClickOnTouch } = Utils;
 
 BlazeComponent.extendComponent({
   onCreated() {
@@ -74,6 +74,11 @@ BlazeComponent.extendComponent({
       },
     });
 
+    // ugly touch event hotfix
+    $('.js-swimlane:not(.placeholder)').each(function() {
+      enableClickOnTouch(this);
+    });
+
     function userIsMember() {
       return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
     }

+ 6 - 1
client/components/cards/checklists.js

@@ -1,4 +1,4 @@
-const { calculateIndexData } = Utils;
+const { calculateIndexData, enableClickOnTouch } = Utils;
 
 function initSorting(items) {
   items.sortable({
@@ -36,6 +36,11 @@ function initSorting(items) {
       checklistItem.move(checklistId, sortIndex.base);
     },
   });
+
+  // ugly touch event hotfix
+  $('.js-checklist-item:not(.placeholder)').each(function() {
+    enableClickOnTouch(this);
+  });
 }
 
 BlazeComponent.extendComponent({

+ 6 - 1
client/components/lists/list.js

@@ -1,4 +1,4 @@
-const { calculateIndex } = Utils;
+const { calculateIndex, enableClickOnTouch } = Utils;
 
 BlazeComponent.extendComponent({
   // Proxy
@@ -83,6 +83,11 @@ BlazeComponent.extendComponent({
       },
     });
 
+    // ugly touch event hotfix
+    $(itemsSelector).each(function() {
+      enableClickOnTouch(this);
+    });
+
     // Disable drag-dropping if the current user is not a board member or is comment only
     this.autorun(() => {
       $cards.sortable('option', 'disabled', !userIsMember());

+ 1 - 1
client/components/main/header.styl

@@ -218,7 +218,7 @@
       position: absolute
       right: 0px
       padding: 10px
-      margin: -10px
+      margin: -10px 0 -10px -10px
 
 .announcement,
 .offline-warning

+ 11 - 7
client/components/mixins/perfectScrollbar.js

@@ -1,12 +1,16 @@
+const { isTouchDevice } = Utils;
+
 Mixins.PerfectScrollbar = BlazeComponent.extendComponent({
   onRendered() {
-    const component = this.mixinParent();
-    const domElement = component.find('.js-perfect-scrollbar');
-    Ps.initialize(domElement);
+    if (!isTouchDevice()) {
+      const component = this.mixinParent();
+      const domElement = component.find('.js-perfect-scrollbar');
+      Ps.initialize(domElement);
 
-    // XXX We should create an event map to be consistent with other components
-    // but since BlazeComponent doesn't merge Mixins events transparently I
-    // prefered to use a jQuery event (which is what an event map ends up doing)
-    component.$(domElement).on('mouseenter', () => Ps.update(domElement));
+      // XXX We should create an event map to be consistent with other components
+      // but since BlazeComponent doesn't merge Mixins events transparently I
+      // prefered to use a jQuery event (which is what an event map ends up doing)
+      component.$(domElement).on('mouseenter', () => Ps.update(domElement));
+    }
   },
 });

+ 6 - 1
client/components/swimlanes/swimlanes.js

@@ -1,4 +1,4 @@
-const { calculateIndex } = Utils;
+const { calculateIndex, enableClickOnTouch } = Utils;
 
 function currentCardIsInThisList(listId, swimlaneId) {
   const currentCard = Cards.findOne(Session.get('currentCard'));
@@ -66,6 +66,11 @@ function initSortable(boardComponent, $listsDom) {
     },
   });
 
+  // ugly touch event hotfix
+  $('.js-list:not(.js-list-composer)').each(function() {
+    enableClickOnTouch(this);
+  });
+
   function userIsMember() {
     return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
   }

+ 46 - 0
client/lib/utils.js

@@ -95,6 +95,52 @@ Utils = {
       increment,
     };
   },
+
+  // Detect touch device
+  isTouchDevice() {
+    const isTouchable = (() => {
+      const prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');
+      const mq = function(query) {
+        return window.matchMedia(query).matches;
+      };
+
+      if (('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch) {
+        return true;
+      }
+
+      // include the 'heartz' as a way to have a non matching MQ to help terminate the join
+      // https://git.io/vznFH
+      const query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join('');
+      return mq(query);
+    })();
+    return isTouchable;
+  },
+
+  calculateTouchDistance(touchA, touchB) {
+    return Math.sqrt(
+      Math.pow(touchA.screenX - touchB.screenX, 2) +
+      Math.pow(touchA.screenY - touchB.screenY, 2)
+    );
+  },
+
+  enableClickOnTouch(element) {
+    let touchStart = null;
+    let lastTouch = null;
+    element.addEventListener('touchstart', function(e) {
+      touchStart = e.touches[0];
+    }, false);
+    element.addEventListener('touchmove', function(e) {
+      const touches = e.touches;
+      lastTouch = touches[touches.length - 1];
+    }, true);
+    element.addEventListener('touchend', function() {
+      if (touchStart && lastTouch && Utils.calculateTouchDistance(touchStart, lastTouch) <= 20) {
+        const clickEvent = document.createEvent('MouseEvents');
+        clickEvent.initEvent('click', true, true);
+        this.dispatchEvent(clickEvent);
+      }
+    }, false);
+  },
 };
 
 // A simple tracker dependency that we invalidate every time the window is