Selaa lähdekoodia

Add drag & drop marker on user query list (#3355)

Before, it was nearly impossible to know exactly where the dragged
item will land when dropping it.
Now, there is a visual marker to show the drop location.

An HR tag is inserted dynamically in the DOM. It's possible to style
it if needed.
Alexis Degrugillier 5 vuotta sitten
vanhempi
commit
e3457f7d7b
3 muutettua tiedostoa jossa 66 lisäystä ja 10 poistoa
  1. 58 10
      p/scripts/user.query.js
  2. 4 0
      p/themes/base-theme/template.css
  3. 4 0
      p/themes/base-theme/template.rtl.css

+ 58 - 10
p/scripts/user.query.js

@@ -2,7 +2,7 @@
 "use strict";
 /* jshint esversion:6, strict:global */
 
-function init_draggable() {
+const init_draggable = function() {
 	if (!window.context) {
 		if (window.console) {
 			console.log('FreshRSS user query waiting for JS…');
@@ -13,32 +13,80 @@ function init_draggable() {
 	
 	let source;
 	const configureQueries = document.querySelector('#configureQueries');
+	const addMarker = (position, element) => {
+		const hr = configureQueries.querySelector('hr.drag-drop-marker');
+		if (null === hr) {
+			element.insertAdjacentHTML(position, '<hr class="drag-drop-marker" />');
+		}
+	};
+	const removeMarker = () => {
+		const hr = configureQueries.querySelector('hr.drag-drop-marker');
+		if (null !== hr) {
+			hr.remove();
+		}
+	};
 
 	configureQueries.addEventListener('dragstart', event => {
 		source = event.target.closest('[draggable="true"]');
 		event.dataTransfer.setData('text/html', source.outerHTML);
 		event.dataTransfer.effectAllowed = 'move';
 	});
-	configureQueries.addEventListener('dragover', event => event.preventDefault());
-	configureQueries.addEventListener('dragleave', event => event.preventDefault());
+	configureQueries.addEventListener('dragover', event => {
+		event.preventDefault();
+		if (!event.target || !event.target.closest) {
+			return;
+		}
+
+		const dropQuery = event.target.closest('[draggable="true"]');
+		if (null === dropQuery || source === dropQuery) {
+			return;
+		}
+
+		const rect = dropQuery.getBoundingClientRect();
+		if (event.clientY < (rect.top + rect.height / 2)) {
+			addMarker('beforebegin', dropQuery);
+		} else {
+			addMarker('afterend', dropQuery);
+		}
+	});
+	configureQueries.addEventListener('dragleave', event => {
+		event.preventDefault();
+		removeMarker();
+	});
 	configureQueries.addEventListener('drop', event => {
 		event.preventDefault();
 		event.stopPropagation();
+		if (!event.target || !event.target.closest) {
+			return;
+		}
+
 		const dropQuery = event.target.closest('[draggable="true"]');
-		if (null === dropQuery) {
-			source.remove();
-			configureQueries.querySelector('legend').insertAdjacentHTML('afterend', event.dataTransfer.getData('text/html'));
-		} else if (source !== dropQuery) {
-			source.remove();
+		if (null === dropQuery || source === dropQuery) {
+			return;
+		}
+
+		const rect = dropQuery.getBoundingClientRect();
+		if (event.clientY < (rect.top + rect.height / 2)) {
+			dropQuery.insertAdjacentHTML('beforebegin', event.dataTransfer.getData('text/html'));
+		} else {
 			dropQuery.insertAdjacentHTML('afterend', event.dataTransfer.getData('text/html'));
 		}
+		source.remove();
+		removeMarker();
 	});
 
 	// This is needed to work around a Firefox bug → https://bugzilla.mozilla.org/show_bug.cgi?id=800050
 	configureQueries.addEventListener('focusin', event => {
-		event.target.closest('input[id^="queries_"][id$="_name"]').select();
+		if (!event.target || !event.target.closest) {
+			return;
+		}
+
+		const queryName = event.target.closest('input[id^="queries_"][id$="_name"]');
+		if (null !== queryName) {
+			queryName.select();
+		}
 	});
-}
+};
 
 if (document.readyState && document.readyState !== 'loading') {
 	init_draggable();

+ 4 - 0
p/themes/base-theme/template.css

@@ -1423,3 +1423,7 @@ input:checked + .slide-container .properties {
 .preview_background {
 	background-color: transparent;
 }
+
+.drag-drop-marker {
+	margin: -1px;
+}

+ 4 - 0
p/themes/base-theme/template.rtl.css

@@ -1421,3 +1421,7 @@ input:checked + .slide-container .properties {
 .preview_background {
 	background-color: transparent;
 }
+
+.drag-drop-marker {
+	margin: -1px;
+}