Browse Source

move (reorder) and move updates

raylu 14 years ago
parent
commit
c5856a0d11
9 changed files with 213 additions and 45 deletions
  1. 2 2
      Makefile
  2. 60 0
      db.go
  3. 71 30
      main.go
  4. 21 4
      static/base.css
  5. BIN
      static/down-arrow.png
  6. BIN
      static/remove.png
  7. 53 5
      static/script.js
  8. BIN
      static/up-arrow.png
  9. 6 4
      updates.go

+ 2 - 2
Makefile

@@ -1,7 +1,7 @@
 all: aa
 	
-main.6: main.go updates.go
-	6g main.go updates.go
+main.6: main.go db.go updates.go
+	6g main.go db.go updates.go
 
 aa: main.6
 	6l -o aa main.6

+ 60 - 0
db.go

@@ -0,0 +1,60 @@
+package main
+
+import (
+	"os"
+)
+
+func queryInt(sql string, params ...interface{}) (int, os.Error) {
+	query, err := db.Prepare(sql)
+	if err != nil {
+		return 0, err
+	}
+	err = query.BindParams(params...)
+	if err != nil {
+		return 0, err
+	}
+	err = query.Execute()
+	if err != nil {
+		return 0, err
+	}
+	var result int
+	query.BindResult(&result)
+	eof, err := query.Fetch()
+	if err != nil {
+		return 0, err
+	} else if eof {
+		return 0, os.EOF
+	}
+	err = query.FreeResult()
+	if err != nil {
+		return 0, err
+	}
+	return result, nil
+}
+
+// given an id ('abcd1234'), return the pid (1)
+func getpid(id string) int {
+	query, err := db.Prepare("SELECT `pid` FROM `playlist` WHERE `id` = ?")
+	if err != nil {
+		return -1
+	}
+	err = query.BindParams(id)
+	if err != nil {
+		return -1
+	}
+	err = query.Execute()
+	if err != nil {
+		return -1
+	}
+	var pid int
+	query.BindResult(&pid)
+	_, err = query.Fetch()
+	if err != nil {
+		return -1
+	}
+	err = query.FreeResult()
+	if err != nil {
+		return -1
+	}
+	return pid
+}

+ 71 - 30
main.go

@@ -24,33 +24,6 @@ var templates map[string]*template.Template
 const debug = true
 var db *mysql.Client
 
-// given an id ('abcd1234'), return the pid (1)
-func getpid(id string) int {
-	query, err := db.Prepare("SELECT `pid` FROM `playlist` WHERE `id` = ?;")
-	if err != nil {
-		return -1
-	}
-	err = query.BindParams(id)
-	if err != nil {
-		return -1
-	}
-	err = query.Execute()
-	if err != nil {
-		return -1
-	}
-	var pid int
-	query.BindResult(&pid)
-	_, err = query.Fetch()
-	if err != nil {
-		return -1
-	}
-	err = query.FreeResult()
-	if err != nil {
-		return -1
-	}
-	return pid
-}
-
 func home(w http.ResponseWriter, r *http.Request) {
 	fmt.Fprintf(w, "path is %s", r.URL.Path[1:])
 }
@@ -91,7 +64,7 @@ func add(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	sql :="INSERT INTO `song` (`pid`,`yid`,`title`,`user`) VALUES(%d,'%s','%s','%s')"
+	sql := "INSERT INTO `song` (`pid`,`yid`,`title`,`user`) VALUES(%d,'%s','%s','%s')"
 	sql = fmt.Sprintf(sql, pid,
 			db.Escape(q.Get("yid")),
 			db.Escape(q.Get("title")),
@@ -115,7 +88,7 @@ func remove(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	sql :="DELETE FROM `song` WHERE `pid` = %d AND yid = '%s'"
+	sql := "DELETE FROM `song` WHERE `pid` = %d AND yid = '%s'"
 	sql = fmt.Sprintf(sql, pid, q.Get("yid"))
 	err := db.Query(sql)
 	if err != nil {
@@ -127,11 +100,78 @@ func remove(w http.ResponseWriter, r *http.Request) {
 	addUpdate(pid, removeAction, &Song{Yid: q.Get("yid")})
 }
 
+func move(w http.ResponseWriter, r *http.Request) {
+	q := r.URL.Query()
+	pid := getpid(q.Get("pid"))
+	if pid == -1 {
+		http.Error(w, "invalid pid", http.StatusInternalServerError)
+		return
+	}
+
+	direction, err := strconv.Atoui(q.Get("direction"))
+	if err != nil {
+		http.Error(w, err.String(), http.StatusInternalServerError)
+		return
+	}
+
+	err = db.Start()
+	if err != nil {
+		http.Error(w, err.String(), http.StatusInternalServerError)
+		return
+	}
+
+	order, err := queryInt("SELECT `order` FROM `song` WHERE `yid` = ? AND `pid` = ?",
+		q.Get("yid"), pid)
+	if err != nil {
+		http.Error(w, err.String(), http.StatusInternalServerError)
+		return
+	}
+	newOrder := order
+	if direction == moveUpAction && order > 0 {
+		newOrder--
+	} else if direction == moveDownAction {
+		newOrder++
+	} else {
+		http.Error(w, "invalid direction or cannot move up", http.StatusInternalServerError)
+		return
+	}
+
+	sql := "UPDATE `song` SET `order` = %d WHERE `order` = %d AND pid = %d"
+	sql = fmt.Sprintf(sql, order, newOrder, pid)
+	err = db.Query(sql)
+	if err != nil {
+		http.Error(w, err.String(), http.StatusInternalServerError)
+		return
+	} else if db.AffectedRows != 1 {
+		db.Rollback()
+		http.Error(w, "invalid direction for this song", http.StatusInternalServerError)
+		return
+	}
+	// there are now two songs with that order, so also check yid
+	sql = "UPDATE `song` SET `order` = %d WHERE `order` = %d AND pid = %d AND yid = '%s'"
+	sql = fmt.Sprintf(sql, newOrder, order, pid, q.Get("yid"))
+	err = db.Query(sql)
+	if err != nil {
+		db.Rollback()
+		http.Error(w, err.String(), http.StatusInternalServerError)
+		return
+	}
+
+	err = db.Commit()
+	if err != nil {
+		http.Error(w, err.String(), http.StatusInternalServerError)
+		return
+	}
+
+	w.Write([]byte("1"))
+	addUpdate(pid, direction, &Song{Yid: q.Get("yid")})
+}
+
 func poll(w http.ResponseWriter, r *http.Request) {
 	q := r.URL.Query()
 	timestamp := q.Get("timestamp")
 	if timestamp == "0" {
-		query, err := db.Prepare("SELECT `yid`,`title`,`user` FROM `playlist` JOIN `song` WHERE `id` = ?;")
+		query, err := db.Prepare("SELECT `yid`,`title`,`user` FROM `playlist` JOIN `song` WHERE `id` = ? ORDER BY `order` ASC")
 		if err != nil {
 			http.Error(w, err.String(), http.StatusInternalServerError)
 			return
@@ -227,6 +267,7 @@ func main() {
 	http.HandleFunc("/p/", playlist)
 	http.HandleFunc("/add/", add)
 	http.HandleFunc("/remove/", remove)
+	http.HandleFunc("/move/", move)
 	http.HandleFunc("/poll/", poll)
 	err = http.ListenAndServe("localhost:8000", nil)
 	if err != nil {

+ 21 - 4
static/base.css

@@ -136,14 +136,31 @@ section.song div.info {
 }
 section.song div.user {
 	float: right;
-	margin-right: 8px;
+	margin-right: 20px;
 }
 section.song div.remove {
 	position: absolute;
 	top: 0;
 	right: 5px;
-	font-weight: bold;
-	cursor: pointer;
+}
+section.song div.remove img {
+	opacity: 0.6;
+}
+section.song div.remove img:hover {
+	opacity: 1.0;
+}
+section.song div.reorder {
+	position: absolute;
+	bottom: 0;
+	right: 5px;
+}
+section.song div.reorder img {
+	display: block;
+	margin-bottom: 5px;
+	opacity: 0.6;
+}
+section.song div.reorder img:hover {
+	opacity: 1.0;
 }
 section.song div.thumb {
 	float: left;
@@ -156,7 +173,7 @@ section.song div.thumb img {
 }
 section.song canvas, section.song > img {
 	position: relative;
-	left: 10px;
+	left: 5px;
 }
 section.song > img[src$='pause.png'] {
 	display: none;

BIN
static/down-arrow.png


BIN
static/remove.png


+ 53 - 5
static/script.js

@@ -14,6 +14,10 @@ $(document).ready(function () {
 			case 1:
 				drawRemove(update.yid);
 				break;
+			case 2:
+			case 3:
+				drawMove(update.yid, update.action);
+				break;
 			}
 		}
 	}
@@ -167,12 +171,11 @@ function search(query) {
 }
 
 function add(id, title) {
-	var user = $('#user').val();
 	params = {
 		pid: pid,
 		yid: id,
 		title: title,
-		user: user
+		user: $('#user').val()
 	}
 	$.getJSON('/add/', params);
 }
@@ -187,7 +190,19 @@ function drawAdd(s) {
 				<a href="http://www.youtube.com/watch?v=' + s.yid + '">' + s.title + '</a>\
 			</div>\
 			<div class="user">' + s.user + '</div>\
-			<div class="remove" onclick="remove(\'' + s.yid + '\')">×</div>\
+			<div class="remove">\
+				<a href="javascript:remove(\'' + s.yid + '\')">\
+					<img src="/static/remove.png" alt="remove">\
+				</a>\
+			</div>\
+			<div class="reorder">\
+				<a href="javascript:move(\'' + s.yid + '\', 2)">\
+					<img src="/static/up-arrow.png" alt="up">\
+				</a>\
+				<a href="javascript:move(\'' + s.yid + '\', 3)">\
+					<img src="/static/down-arrow.png" alt="down">\
+				</a>\
+			</div>\
 			<canvas id="c_' + s.yid + '" width="700" height="20"></canvas>\
 			<br>\
 			<img src="/static/player_play.png" alt="Play" onclick="play(\'' + s.yid + '\')" id="play_' + s.yid + '">\
@@ -201,7 +216,6 @@ function drawAdd(s) {
 }
 
 function remove(id) {
-	var user = $('#user').val();
 	params = {
 		pid: pid,
 		yid: id,
@@ -211,8 +225,42 @@ function remove(id) {
 
 function drawRemove(id) {
 	var element = $('#' + id);
+	stop(id);
 	element.slideUp(100, function () {
-		stop(id);
 		element.remove();
 	});
 }
+
+function move(id, dir) {
+	params = {
+		pid: pid,
+		yid: id,
+		direction: dir // see updates.go:moveUpAction
+	}
+	$.getJSON('/move/', params);
+}
+
+function drawMove(id, dir) {
+	var element1 = document.getElementById(id);
+	if (dir == 2) { //up
+		var element2 = element1.previousElementSibling;
+		if (!element2) return;
+		element1 = $('#' + id);
+		element2 = $('#' + element2.id);
+		element1.fadeOut(200, function () {
+			element1.detach();
+			element2.before(element1);
+			element1.fadeIn(200);
+		});
+	} else if (dir == 3) { //down
+		var element2 = element1.nextElementSibling;
+		if (!element2) return;
+		element1 = $('#' + id);
+		element2 = $('#' + element2.id);
+		element1.fadeOut(200, function () {
+			element1.detach();
+			element2.after(element1);
+			element1.fadeIn(200);
+		});
+	}
+}

BIN
static/up-arrow.png


+ 6 - 4
updates.go

@@ -5,12 +5,14 @@ import (
 )
 
 const (
-	addAction    = 0
-	removeAction = 1
+	addAction      = 0
+	removeAction   = 1
+	moveUpAction   = 2
+	moveDownAction = 3
 )
 type Update struct {
 	Song *Song
-	Action uint8
+	Action uint
 	Timestamp int64
 	Next *Update
 }
@@ -22,7 +24,7 @@ func init() {
 	tailUpdates = make(map[int]*Update)
 }
 
-func addUpdate(pid int, action uint8, song *Song) {
+func addUpdate(pid int, action uint, song *Song) {
 	update := new(Update)
 	update.Song = song
 	update.Action = action