[Libreoffice-commits] online.git: Branch 'distro/collabora/collabora-online-4' - loleaflet/build loleaflet/src

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Mon May 13 12:07:56 UTC 2019


 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.sanchez at collabora.com>
AuthorDate: Fri May 10 11:54:52 2019 +0200
Commit:     Szymon Kłos <szymon.klos at 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.klos at collabora.com>
    Tested-by: Szymon Kłos <szymon.klos at collabora.com>
    (cherry picked from commit d6fe8ff0856170d922d29dbb869496dd24aab233)
    Reviewed-on: https://gerrit.libreoffice.org/72119
    Reviewed-by: Iván Sánchez Ortega <ivan.sanchez at 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);
+};


More information about the Libreoffice-commits mailing list