From 1bf4f6d3cdcf1445c2a40959f286a73485eb31c8 Mon Sep 17 00:00:00 2001
From: undisclosed
Date: Mon, 09 Jan 2023 18:45:56 +0000
Subject: [PATCH] Drag and drop fuer Abspiellisten eingebaut

---
 www/data/tpl/titel_liste.txt                  |    2 
 src/de/uhilger/tango/api/ListHandler.java     |   81 +++++++++++++++++--
 src/de/uhilger/tango/entity/Abspielliste.java |    8 ++
 www/js/app.js                                 |   94 +++++++++++++++++++++--
 src/de/uhilger/tango/api/AbstractHandler.java |    2 
 www/app.css                                   |   10 ++
 6 files changed, 175 insertions(+), 22 deletions(-)

diff --git a/src/de/uhilger/tango/api/AbstractHandler.java b/src/de/uhilger/tango/api/AbstractHandler.java
index 891b06d..ec47802 100644
--- a/src/de/uhilger/tango/api/AbstractHandler.java
+++ b/src/de/uhilger/tango/api/AbstractHandler.java
@@ -130,7 +130,7 @@
     return "nicht unterstuetzt";
   }
 
-  protected String post(HttpExchange e) {
+  protected String post(HttpExchange e) throws IOException {
     setReturnCode(RTC_NOT_FOUND);
     return "nicht unterstuetzt";
   }
diff --git a/src/de/uhilger/tango/api/ListHandler.java b/src/de/uhilger/tango/api/ListHandler.java
index 13b7f7c..efb5d4e 100644
--- a/src/de/uhilger/tango/api/ListHandler.java
+++ b/src/de/uhilger/tango/api/ListHandler.java
@@ -19,13 +19,13 @@
 
 import com.google.gson.Gson;
 import com.sun.net.httpserver.HttpExchange;
-import de.uhilger.tango.App;
 import de.uhilger.tango.Server;
 import de.uhilger.tango.entity.Abspielliste;
 import de.uhilger.tango.entity.Entity;
 import de.uhilger.tango.entity.Titel;
 import de.uhilger.tango.store.FileStorage;
 import java.io.IOException;
+import java.util.List;
 import java.util.logging.Logger;
 
 /**
@@ -34,13 +34,12 @@
  * GET /mz/api/alist/[pl-name]          die Titel-Objekte der Liste [pl-name] liefern
  * PUT /mz/api/alist/[pl-name]          den Titel im Body anfuegen an die Liste [pl-name]
  * PUT /mz/api/alist/[pl-name]/[nr]     an der Position nr der Liste [pl-name] den Titel im Body einfuegen
- * Neu: PUT /mz/api/alist/[pl-name]/[nr]/up  den Titel an der Position nr der Liste [pl-name] eins nach oben
- * Neu: PUT /mz/api/alist/[pl-name]/[nr]/dn  den Titel an der Position nr der Liste [pl-name] eins nach unten
+ * PUT /mz/api/alist/[pl-name]/[nrVon]/[nrNach]   den Titel von seiner aktuellen Position an eine 
+ *                                                 andere Position der Liste [pl-name] verschieben
  * DELETE /mz/api/alist/[pl-name]/[nr]  den Titel an der Position [nr] aus der Liste [pl-name] entfernen  
  * DELETE /mz/api/alist/[pl-name]/alle  alle Titel aus der Liste [pl-name] entfernen  
  * 
  * TODO (2.1.2023):
- * - Titel eins nach oben/unten
  * - Liste ab Titel spielen
  * - Ganzes Album der Liste hinzufuegen
  *
@@ -80,8 +79,75 @@
         break;
         
       case 6:
-        response = "Einfuegen noch nicht fertig.";
+        response = insertTitel(e, elems[4], Integer.parseInt(elems[5]));
         break;
+        
+      case 7:
+        response = moveTitel(e, elems[4], Integer.parseInt(elems[5]), Integer.parseInt(elems[6]));
+        break;
+    }
+    return response;
+  }
+  
+  /**
+   * Den Titel im Body von seiner aktuellen Position an die angegebene 
+   * Position setzen. Der Titel an der angegebenen Position rueckt nach 
+   * unten.
+   * 
+   * Annahme: Die Abspielliste enthaelt keine Titel mehrfach.
+   * 
+   * @param e
+   * @param plname
+   * @param zielPos
+   * @return
+   * @throws IOException 
+   */
+  private String moveTitel(HttpExchange e, String plname, int pos, int zielPos) throws IOException {
+    FileStorage fs = new FileStorage(conf);
+    Entity entity = fs.read(FileStorage.ST_ABSPIELLISTE, plname);
+    String response = "Titel konnte nicht verschoben werden.";
+    if(entity instanceof Abspielliste) {
+      if(pos < zielPos) {
+        --zielPos;
+      }
+      Abspielliste aliste = (Abspielliste) entity;
+      List<Titel> liste = aliste.getTitel();
+      Titel t = liste.get(pos);
+      liste.remove(pos);
+      liste.add(zielPos, t);
+      fs.write(aliste, true);
+      response = "Titel " + t.getName() + " der Liste " + aliste.getName() + 
+              " an Position " + zielPos + " verschoben.";
+    }
+    return response;
+  }
+  
+  /**
+   * Den Titel im Body an Position anPos einfuegen. Der Titel an anPos 
+   * rueckt nach unten.
+   * 
+   * @param e
+   * @param plname
+   * @param anPos
+   * @return
+   * @throws IOException 
+   */
+  private String insertTitel(HttpExchange e, String plname, int anPos) throws IOException {
+    FileStorage fs = new FileStorage(conf);
+    Entity entity = fs.read(FileStorage.ST_ABSPIELLISTE, plname);
+    String response = "Titel konnte nicht hinzugefuegt werden.";
+    if(entity instanceof Abspielliste) {
+      Abspielliste aliste = (Abspielliste) entity;
+      String titelJson = bodyLesen(e);
+      Gson gson = new Gson();
+      Object o = gson.fromJson(titelJson, fs.typeFromName(Titel.class.getSimpleName()).getType());
+      if(o instanceof Titel) {
+        Titel titel = (Titel) o;
+        aliste.putTitel(titel, anPos);
+        fs.write(aliste, true);
+        response = "Titel " + titel.getName() + " der Liste " + aliste.getName() + 
+                " an Position " + anPos + " hinzugefuegt.";
+      }
     }
     return response;
   }
@@ -103,11 +169,6 @@
       }
     }
     return response;
-  }
-
-  @Override
-  protected String post(HttpExchange e) {
-    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
   }
 
   // DELETE /mz/api/alist/[pl-name]/[nr]  den Titel an der Position [nr] aus der Liste [pl-name] entfernen  
diff --git a/src/de/uhilger/tango/entity/Abspielliste.java b/src/de/uhilger/tango/entity/Abspielliste.java
index e0ebbfe..8bf9aa3 100644
--- a/src/de/uhilger/tango/entity/Abspielliste.java
+++ b/src/de/uhilger/tango/entity/Abspielliste.java
@@ -40,6 +40,14 @@
   public List<Titel> getTitel() {
     return titel;
   }
+  
+  public void putTitel(Titel t, int anPos) {
+    this.titel.set(anPos, t);
+  }
+  
+  public int getIndex(Titel t) {
+    return this.titel.indexOf(t);
+  }
 
   public void setTitel(List titel) {
     this.titel = titel;
diff --git a/www/app.css b/www/app.css
index 837faf4..927f0fc 100644
--- a/www/app.css
+++ b/www/app.css
@@ -296,6 +296,16 @@
   cursor: pointer;
 }
 
+.drag-over {
+  color: blueviolet;
+  border-style: dashed;
+  border-width: 1px;
+}
+
+.hide {
+  display: none;
+}
+
 .entity-eintrag:hover {
   /* background-color: #ececec; */
   color: red;
diff --git a/www/data/tpl/titel_liste.txt b/www/data/tpl/titel_liste.txt
index 02b9158..9e3cd3b 100644
--- a/www/data/tpl/titel_liste.txt
+++ b/www/data/tpl/titel_liste.txt
@@ -2,7 +2,7 @@
 <div class='entity-formular'>
   <ul class='entity-liste'>
     {{#titel}}
-    <li class='entity-eintrag'>{{interpret}}: {{titelAnzName}}</li>
+    <li class='entity-eintrag' draggable='true'>{{interpret}}: {{titelAnzName}}</li>
     {{/titel}}
   </ul>
 </div>
diff --git a/www/js/app.js b/www/js/app.js
index c7f341e..9b634bb 100644
--- a/www/js/app.js
+++ b/www/js/app.js
@@ -402,6 +402,47 @@
           self.removeClassMulti('selected');
           t.classList.add('selected');
         });
+        self.addEvtListener('.entity-eintrag', 'dragstart', function (e) {
+          //console.log("drag started");          
+          e.dataTransfer.setData('text/plain', e.target.textContent);
+          setTimeout(() => {
+                  e.target.classList.add('hide');
+                  e.target.classList.add('drag-elem');
+          }, 0);          
+        });
+        self.addEvtListener('.entity-eintrag', 'dragenter', function (e) {
+          e.preventDefault();
+          //console.log("drag enter");
+          e.target.classList.add('drag-over');
+        });
+        self.addEvtListener('.entity-eintrag', 'dragover', function (e) {
+          e.preventDefault();
+          //console.log("drag over");
+          e.target.classList.add('drag-over');
+        });
+        self.addEvtListener('.entity-eintrag', 'dragleave', function (e) {
+          //console.log("drag leave");
+          e.target.classList.remove('drag-over');
+        });
+        self.addEvtListener('.entity-eintrag', 'drop', function (e) {     
+          e.preventDefault();
+          //console.log("drop");
+          //console.log("index: " + self.getIndexBySelector('drag-over'));
+          const pos = self.getIndexBySelector('drag-elem');
+          const zielPos = self.getIndexBySelector('drag-over');
+          const titeltext = e.dataTransfer.getData('text/plain');
+          const draggable = document.querySelector(".drag-elem");
+          draggable.classList.remove("drag-elem");
+          e.target.classList.remove('drag-over');
+          var plname = document.querySelector('#playlist').value;
+          self.http_put('api/alist/' + plname + "/" + pos + "/" + zielPos, '', function(responseText) {
+            //self.meldung_mit_timeout(responseText, 1500);
+          });
+          ulElem = draggable.parentElement;
+          ulElem.removeChild(draggable);          
+          e.target.insertAdjacentElement('beforebegin', draggable);
+          draggable.classList.remove('hide');
+        });             
       });
     });
   };  
@@ -532,6 +573,17 @@
     });
   };
   
+  /*
+   * {
+   *  "katalogUrl":"/media",
+   *  "pfad":"/Musik/B/Bay-City-Rollers/Original-Album-Classics/3/",
+   *  "name":"3-37-Love-Is.mp3",
+   *  "interpret":"Bay City Rollers",
+   *  "titelAnzName":"Love Is",
+   *  "album":"Original Album Classics"
+   * }
+   * @returns {undefined}
+   */
   this.titelDazu = function() {
     var titel = self.titelErmitteln(document.querySelector(".selected"));
     //var titelName = elem.textContent;
@@ -554,20 +606,22 @@
   };  
   
   this.titelWeg = function() {
-    var elem = document.querySelector(".selected");
-    var parentElem = elem.parentNode;
+    //var elem = document.querySelector(".selected");
+    //var parentElem = elem.parentNode;
     //console.log("elem: " + elem.nodeName + ", parent: " + parentElem.nodeName + ", len: " + parentElem.childNodes.length);
-    var liElems = parentElem.getElementsByTagName(elem.nodeName); // nur die LI Elemente
+    //var liElems = parentElem.getElementsByTagName(elem.nodeName); // nur die LI Elemente
     //console.log("liElems.anz: " + liElems.length);
-    var gefunden = false;
-    for(var i = 0; i < liElems.length && !gefunden; i++) {
+    //var gefunden = false;
+    //for(var i = 0; i < liElems.length && !gefunden; i++) {
       //console.log(liElems.item(i).textContent);
-      if(liElems.item(i).classList.contains("selected")) {
-        gefunden = true;
-        var index = i;
+      //if(liElems.item(i).classList.contains("selected")) {
+        //gefunden = true;
+        //var index = i;
         //console.log(elem.textContent + ' hat Index ' + i);
-      }
-    }
+      //}
+    //}
+    
+    const index = self.getIndexBySelector("selected");
     // /mz/api/alist/[pl-name]/[nr] 
     var plname = document.querySelector('#playlist').value;
     self.http_delete('api/alist/' + plname + '/' + index,'', function(responseText) {
@@ -578,6 +632,26 @@
     
   };
   
+  this.getIndexBySelector = function(selector) {
+    var qSel = '.' + selector;
+    var elem = document.querySelector(qSel);
+    var parentElem = elem.parentNode;
+    //console.log("elem: " + elem.nodeName + ", parent: " + parentElem.nodeName + ", len: " + parentElem.childNodes.length);
+    var liElems = parentElem.getElementsByTagName(elem.nodeName); // nur die LI Elemente
+    //console.log("liElems.anz: " + liElems.length);
+    var gefunden = false;
+    var index = -1;
+    for(var i = 0; i < liElems.length && !gefunden; i++) {
+      //console.log(liElems.item(i).textContent);
+      if(liElems.item(i).classList.contains(selector)) {
+        gefunden = true;
+        index = i;
+        //console.log(elem.textContent + ' hat Index ' + i);
+      }
+    }
+    return index;
+  };
+  
   /* ------------- Helfer fuer Entitaets-Formulare ----------------------- */
   
   /*

--
Gitblit v1.9.3