diff options
author | raylu <raylu@mixpanel.com> | 2011-08-07 18:48:51 -0700 |
---|---|---|
committer | raylu <raylu@mixpanel.com> | 2011-08-07 18:48:51 -0700 |
commit | c5856a0d115cb46760a359d45a3a734fc1d51b52 (patch) | |
tree | f3cccc20d5f4793490ccc9208de7524896edd6a0 | |
parent | f61e03f7f43536adce71c5783536aa67f63f029d (diff) | |
download | audioaxis-c5856a0d115cb46760a359d45a3a734fc1d51b52.tar.xz |
move (reorder) and move updates
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | db.go | 60 | ||||
-rw-r--r-- | main.go | 101 | ||||
-rw-r--r-- | static/base.css | 25 | ||||
-rw-r--r-- | static/down-arrow.png | bin | 0 -> 540 bytes | |||
-rw-r--r-- | static/remove.png | bin | 0 -> 505 bytes | |||
-rw-r--r-- | static/script.js | 58 | ||||
-rw-r--r-- | static/up-arrow.png | bin | 0 -> 468 bytes | |||
-rw-r--r-- | updates.go | 10 |
9 files changed, 213 insertions, 45 deletions
@@ -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 @@ -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 +} @@ -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 { diff --git a/static/base.css b/static/base.css index fb01a40..438e4c1 100644 --- a/static/base.css +++ b/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; diff --git a/static/down-arrow.png b/static/down-arrow.png Binary files differnew file mode 100644 index 0000000..00c106d --- /dev/null +++ b/static/down-arrow.png diff --git a/static/remove.png b/static/remove.png Binary files differnew file mode 100644 index 0000000..a033c4e --- /dev/null +++ b/static/remove.png diff --git a/static/script.js b/static/script.js index 3be5775..8687b0e 100644 --- a/static/script.js +++ b/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); + }); + } +} diff --git a/static/up-arrow.png b/static/up-arrow.png Binary files differnew file mode 100644 index 0000000..29ca702 --- /dev/null +++ b/static/up-arrow.png @@ -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 |