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