loleaflet/build/deps.js               |    2 
 loleaflet/src/control/Control.Tabs.js |   52 ++++++-----
 loleaflet/src/dom/DomEvent.LongTap.js |  148 ++++++++++++++++++++++++++++++++++
 3 files changed, 177 insertions(+), 25 deletions(-)

New commits:
commit 42e7cd146575f0406964211761e83c8e2633c022
Author:     Iván Sánchez Ortega <ivan.sanc...@collabora.com>
AuthorDate: Fri May 10 11:54:52 2019 +0200
Commit:     Szymon Kłos <szymon.k...@collabora.com>
CommitDate: Mon May 13 14:07:38 2019 +0200

    loleaflet: Make Calc sheet context menu work on iOS safari
    
    This is done with a combination of a 'contextment' event shim in
    loleaflet/src/dom/DomEvent.LongTap.js, mimicking the technique from
    loleaflet/src/map/handler/Map.Tap.js, and triggering the jQuery
    contextmenu manually from such a shimmed 'contextmenu'.
    
    Change-Id: I5cba975b7a5559315c91a8bf4c9a5ced00dfc6e1
    Reviewed-on: https://gerrit.libreoffice.org/72115
    Reviewed-by: Szymon Kłos <szymon.k...@collabora.com>
    Tested-by: Szymon Kłos <szymon.k...@collabora.com>
    (cherry picked from commit d6fe8ff0856170d922d29dbb869496dd24aab233)
    Reviewed-on: https://gerrit.libreoffice.org/72119
    Reviewed-by: Iván Sánchez Ortega <ivan.sanc...@collabora.com>

diff --git a/loleaflet/build/deps.js b/loleaflet/build/deps.js
index a050edf47..c64a05bdf 100644
--- a/loleaflet/build/deps.js
+++ b/loleaflet/build/deps.js
@@ -344,6 +344,8 @@ var deps = {
 
        ControlTabs: {
                src: ['control/Control.js',
+                     'dom/DomEvent.js',
+                     'dom/DomEvent.LongTap.js',
                      'control/Control.Tabs.js'],
                heading: 'Controls',
                desc: 'Tabs for switching sheets'
diff --git a/loleaflet/src/control/Control.Tabs.js 
b/loleaflet/src/control/Control.Tabs.js
index e173c2bac..d120bb08a 100644
--- a/loleaflet/src/control/Control.Tabs.js
+++ b/loleaflet/src/control/Control.Tabs.js
@@ -20,7 +20,7 @@ L.Control.Tabs = L.Control.extend({
                }
                setTimeout(function() {
                        $('.spreadsheet-tab').contextMenu(e.perm === 'edit');
-               }, 1000);
+               }, 100);
 
                if (window.mode.isMobile() == true) {
                        if (e.perm === 'edit') {
@@ -38,36 +38,28 @@ L.Control.Tabs = L.Control.extend({
                this._initialized = true;
                this._tabsInitialized = false;
                this._spreadsheetTabs = {};
+               this._tabForContextMenu = 0;
                var map = this._map;
                var docContainer = map.options.documentContainer;
                this._tabsCont = L.DomUtil.create('div', 
'spreadsheet-tabs-container', docContainer.parentElement);
-               L.DomEvent.on(this._tabsCont, 'touchstart',
-                       function (e) {
-                               if (e && e.touches.length > 1) {
-                                       L.DomEvent.preventDefault(e);
-                               }
-                       },
-                       this);
 
                $.contextMenu({
                        selector: '.spreadsheet-tab',
                        className: 'loleaflet-font',
-                       callback: function(key, options) {
-                               var nPos = 
parseInt(options.$trigger.attr('id').split('spreadsheet-tab')[1]);
-
+                       callback: (function(key) {
                                if (key === 'insertsheetbefore') {
-                                       map.insertPage(nPos);
+                                       map.insertPage(this._tabForContextMenu);
                                }
                                if (key === 'insertsheetafter') {
-                                       map.insertPage(nPos + 1);
+                                       map.insertPage(this._tabForContextMenu 
+ 1);
                                }
-                       },
+                       }).bind(this),
                        items: {
                                'insertsheetbefore': {name: _('Insert sheet 
before this')},
                                'insertsheetafter': {name: _('Insert sheet 
after this')},
                                'deletesheet': {name: _UNO('.uno:Remove', 
'spreadsheet', true),
-                                               callback: function(key, 
options) {
-                                                       var nPos = 
parseInt(options.$trigger.attr('id').split('spreadsheet-tab')[1]);
+                                               callback: (function(key, 
options) {
+                                                       var nPos = 
this._tabForContextMenu;
                                                        vex.dialog.confirm({
                                                                message: _('Are 
you sure you want to delete sheet, %sheet% ?').replace('%sheet%', 
options.$trigger.text()),
                                                                callback: 
function(data) {
@@ -76,11 +68,11 @@ L.Control.Tabs = L.Control.extend({
                                                                        }
                                                                }
                                                        });
-                                               }
+                                               }).bind(this)
                                 },
                                'renamesheet': {name: _UNO('.uno:RenameTable', 
'spreadsheet', true),
-                                                       callback: function(key, 
options) {
-                                                               var nPos = 
parseInt(options.$trigger.attr('id').split('spreadsheet-tab')[1]);
+                                                       callback: 
(function(key, options) {
+                                                               var nPos = 
this._tabForContextMenu;
                                                                
vex.dialog.open({
                                                                        
message: _('Enter new sheet name'),
                                                                        input: 
'<input name="sheetname" type="text" value="' + options.$trigger.text() + '" 
required />',
@@ -88,18 +80,19 @@ L.Control.Tabs = L.Control.extend({
                                                                                
map.renamePage(data.sheetname, nPos);
                                                                        }
                                                                });
-                                                       }},
+                                                       }).bind(this)
+                               } ,
                                'showsheets': {
                                        name: _UNO('.uno:Show', 'spreadsheet', 
true),
-                                       callback: function() {
+                                       callback: (function() {
                                                map.showPage();
-                                       }
+                                       }).bind(this)
                                },
                                'hiddensheets': {
                                        name: _UNO('.uno:Hide', 'spreadsheet', 
true),
-                                       callback: function() {
+                                       callback: (function() {
                                                map.hidePage();
-                                       }
+                                       }).bind(this)
                                }
                        },
                        zIndex: 1000
@@ -138,7 +131,16 @@ L.Control.Tabs = L.Control.extend({
                                        if (e.hiddenParts.indexOf(i) !== -1)
                                                continue;
                                        var id = 'spreadsheet-tab' + i;
-                                       var tab = L.DomUtil.create('div', 
'spreadsheet-tab', ssTabScroll);
+                                       var tab = L.DomUtil.create('button', 
'spreadsheet-tab', ssTabScroll);
+                                       L.DomEvent.enableLongTap(tab);
+                                       
+                                       L.DomEvent.on(tab, 'contextmenu', 
function(j) {
+                                               return function() {
+                                                       this._tabForContextMenu 
= j;
+                                                       $('spreadsheet-tab' + 
j).contextMenu();
+                                               }
+                                       }(i).bind(this));
+                                       
                                        tab.textContent = e.partNames[i];
                                        tab.id = id;
 
diff --git a/loleaflet/src/dom/DomEvent.LongTap.js 
b/loleaflet/src/dom/DomEvent.LongTap.js
new file mode 100644
index 000000000..c0e06ca12
--- /dev/null
+++ b/loleaflet/src/dom/DomEvent.LongTap.js
@@ -0,0 +1,148 @@
+/*
+ * Similar to DomEvent.DoubleTap.js (which implements the 'dblclick' event for
+ * touchscreens), this implements the 'contextmenu' event on long touchscreen
+ * press for combination of browsers/input devices that don't - namely,
+ * Safari on iOS devices.
+ *
+ * This has been mostly copy-pasted from map/handler/Map.Tap.js and should be
+ * refactored somehow.
+ */
+L.DomEvent.enableLongTap = function enableLongTap(el, tolerance, timeout) {
+       // Skip non-touchscreens and browsers which implement PointerEvent
+       if (!L.Browser.touch || L.Browser.pointer) {
+               return;
+       }
+
+       // Prevent double handling
+       if (el._hasLongTapContextMenus) {
+               return;
+       }
+       el._hasLongTapContextMenus = true;
+
+       // Default value for the 'tolerance' parameter: 15 pixels
+       // This is the amount of pixels that the touch can move around during
+       // a long tap, and still fire contextmenu events.
+       if (!tolerance) {
+               tolerance = 15;
+       }
+
+       // Default value for the 'timeout' parameter: 2000 milliseconds
+       // This is how long a user has to hold down the touch to trigger the
+       // contextmenu event
+       if (!timeout) {
+               timeout = 2000;
+       }
+
+       var holdTimeout;
+       var fireClick = true; // Whether to fire a click event on touchup
+       var startPos; // Position of the touch on touchstart
+       var newPos; // Position of the touch on the last touchmove
+
+       function onDown(ev) {
+               if (!ev.touches) {
+                       return;
+               }
+
+               L.DomEvent.preventDefault(ev);
+               fireClick = true;
+
+               // don't simulate click or track longpress if more than 1 touch
+               if (ev.touches.length > 1) {
+                       fireClick = false;
+                       clearTimeout(holdTimeout);
+                       return;
+               }
+
+               var first = ev.touches[0],
+                   target = first.target;
+
+               startPos = newPos = L.point(first.clientX, first.clientY);
+
+               // if touching a link, highlight it
+               if (target.tagName && target.tagName.toLowerCase() === 'a') {
+                       L.DomUtil.addClass(target, 'leaflet-active');
+               }
+
+               // simulate long hold but setting a timeout
+               holdTimeout = setTimeout(function() {
+                       if (isTapValid()) {
+                               fireClick = false;
+                               onUp();
+                               simulateEvent('contextmenu', first);
+                       }
+               }, timeout);
+
+               simulateEvent('mousedown', first);
+
+               L.DomEvent.on(el, {
+                       touchmove: onMove,
+                       touchend: onUp
+               });
+       }
+
+       function isTapValid() {
+               return newPos.distanceTo(startPos) <= tolerance;
+       }
+
+       function onUp(ev) {
+               clearTimeout(holdTimeout);
+
+               L.DomEvent.off(el, {
+                       touchmove: onMove,
+                       touchend: onUp
+               });
+
+               if (fireClick && ev && ev.changedTouches) {
+                       var first = ev.changedTouches[0],
+                           target = first.target;
+
+                       if (target && target.tagName && 
el.tagName.toLowerCase() === 'a') {
+                               L.DomUtil.removeClass(target, 'leaflet-active');
+                       }
+
+                       simulateEvent('mouseup', first);
+
+                       // simulate click if the touch didn't move too much
+                       if (isTapValid()) {
+                               simulateEvent('click', first);
+                       }
+               }
+       }
+
+       function onMove(ev) {
+               var first = ev.touches[0];
+               newPos = new L.Point(first.clientX, first.clientY);
+               simulateEvent('mousemove', first);
+       }
+
+       function simulateEvent(type, ev) {
+               var simulatedEvent = document.createEvent('MouseEvents');
+
+               simulatedEvent._simulated = true;
+               ev.target._simulatedClick = true;
+
+               simulatedEvent.initMouseEvent(
+                       type,
+                       true,
+                       true,
+                       window,
+                       1,
+                       ev.screenX,
+                       ev.screenY,
+                       ev.clientX,
+                       ev.clientY,
+                       false,
+                       false,
+                       false,
+                       false,
+                       0,
+                       null
+               );
+
+               console.log('dispatching simulated contextmenu event: ', 
simulatedEvent);
+
+               ev.target.dispatchEvent(simulatedEvent);
+       }
+
+       L.DomEvent.on(el, 'touchstart', onDown, this);
+};
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to