# HG changeset patch # User terom # Date 1200791222 0 # Node ID 001f52cd057ef853de9f682dc32faff9e3c16f40 # Parent 10841abbc01fb4370f954f4ba1557f2aebed58a9 tagging/untagging should now work fully in taggr diff -r 10841abbc01f -r 001f52cd057e de-cgi-bin/taggr2.py --- a/de-cgi-bin/taggr2.py Thu Jan 17 01:56:04 2008 +0000 +++ b/de-cgi-bin/taggr2.py Sun Jan 20 01:07:02 2008 +0000 @@ -26,7 +26,6 @@ from lib import db, shorturl, settings, utils, template, req - tpl = template.Template("taggr") act = req.get_str("act", None) @@ -55,9 +54,11 @@ dirs.append((fname, fpath)) elif utils.isImage(fname) : - key = shorturl.int2key(db.select("""SELECT id FROM images WHERE dirpath=? AND filename=?""", path, fname).fetchone()[0]) + id = db.select("""SELECT id FROM images WHERE dirpath=? AND filename=?""", path, fname).fetchone()[0] - imgs.append((key, os.path.join(path, settings.THUMB_DIR, fname))) + tags = [tag for type, tag in db.select("""SELECT type, tag FROM tags WHERE image=?""", id)] + + imgs.append((id, os.path.join(path, settings.THUMB_DIR, fname), tags)) dirs.sort() imgs.sort() @@ -72,6 +73,22 @@ images = imgs, ) +elif act == "tag" : + img_list = req.get_int_list("img") + tag = req.get_str("tag") + + db.insert_many("""INSERT INTO tags (image, tag) VALUES (?, ?)""", ((img, tag) for img in img_list)) + + print "OK" + +elif act == "untag" : + img = req.get_int("img") + tag = req.get_str("tag") + + db.delete("""DELETE FROM tags WHERE image=? AND tag=?""", img, tag) + + print "OK" + elif act == None : dirs, imgs = dirlist(".") @@ -80,7 +97,7 @@ open_dir_contents = dirlist(path) else : open_dir = open_dir_contents = None - + print template.Template("taggr").render( stylesheet_url = utils.url("style.css", up=1), title = "Taggr", diff -r 10841abbc01f -r 001f52cd057e degal.py --- a/degal.py Thu Jan 17 01:56:04 2008 +0000 +++ b/degal.py Sun Jan 20 01:07:02 2008 +0000 @@ -1,4 +1,4 @@ -#!/usr/bin/env python2.4 +#!/usr/bin/env python2.5 # # DeGAL - A pretty simple web image gallery # Copyright (C) 2007 Tero Marttila diff -r 10841abbc01f -r 001f52cd057e javascript/taggr.js --- a/javascript/taggr.js Thu Jan 17 01:56:04 2008 +0000 +++ b/javascript/taggr.js Sun Jan 20 01:07:02 2008 +0000 @@ -1,11 +1,24 @@ +/* + * dir-list manipulation + */ function toggle_dir (header_a_tag) { var div = Element.next(header_a_tag); if (div._have_contents) { - if (div.visible()) + if (div.visible()) { Effect.BlindUp(div, {duration: 0.5}); - else + func = hide_tag_image; + } else { Effect.BlindDown(div, {duration: 0.5}); + func = show_tag_image; + } + + Element.up(header_a_tag)._images.each(function(key){ + $("img_" + key)._tags.each(function(tag){ + func(tag, key); + }); + }); + } else { new Ajax.Updater(div, "taggr2.py", { @@ -22,37 +35,296 @@ } } -function new_tag (tag_name) { - var tag_images = Builder.node("td", {className:"tag_images"}); +var g_last_select; +function image_click (img, ev) { + var updiv = img.up(2); - $("tag_table").appendChild( - Builder.node("tr", [ - Builder.node("td", {className:"tag"}, [ - tag_name - ]), - tag_images - ]) - ); + if (img.hasClassName("selection")) { + img.removeClassName("selection"); + + } else if (ev.shiftKey && g_last_select && g_last_select.up(2) == updiv) { + var from = Math.min(img._offset, g_last_select._offset); + var to = Math.max(img._offset, g_last_select._offset); + + for (var i = from; i <= to; i++) { + $("img_" + updiv._images[i]).addClassName("selection"); + } + + g_last_select = img; + } else { + + g_last_select = img; + img.addClassName("selection"); + } } -function image_dropped (img, tag, e) { -} - -function image_loaded (img) { +function selection_clear () { + $$(".selection").each(function(e){ + e.removeClassName("selection"); + }); } -function image_click (img, ev) { +/* + * image-loading callback + */ +function image_info (img, offset, key, tags) { + img._key = key; + img._tags = $A(tags); + img._offset = offset; + + img._tags.each(function(tag){ + if (!$('tag_' + tag + '_images')) + new_tag(tag); + tag_add_image(img, null, tag, false); + }); + + var dir = img.up(2); + + if (!dir._images) + dir._images = new Array(); + + dir._images.push(img._key); } -function init () { +/* + * tag list manipulation code + */ +function _tag_name (tag_name) { + var tag_name_p = Builder.node("p", {id:"tag_" + tag_name + "_name", className: "draggable tag_name"}, [tag_name]); + + tag_name_p._tag = tag_name; + + return tag_name_p; } +function new_tag (tag_name) { + var tag_images = Builder.node("td", {className:"tag_images", id:"tag_" + tag_name + "_images"}); + + tag_images._tag = tag_name; + tag_images._visibleCount = 0; + tag_images._images = new Array(); + + var tag_row = Builder.node("tr", {className:"tag_row", id:"tag_" + tag_name}, [ + Builder.node("td", {className:"tag", id:"tag_" + tag_name + "_tags"}, [ + _tag_name(tag_name) + ]), + tag_images + ]); + + tag_row._tag = tag_name; + tag_row._tags = new Array(tag_name); + + $("tag_table").appendChild(tag_row); +} + +function tag_add_tag (new_tag, tag) { + var tag_row = $("tag_" + tag); + + if (tag_row._tags.indexOf(new_tag) != -1) + return false; + + tag_row._tags.push(new_tag); + + $("tag_" + tag + "_tags").appendChild(_tag_name(new_tag)); + +/* + new Ajax.Request("taggr2.py", { + parameters: { + act: 'tag', + tag: new_tag, + img: $("tag_" + tag + "_images")._images, + }, + method: 'get' + }); +*/ +} + +function tag_remove_tag (tag_name) { + var tag_row = $("tag_" + tag_name + "_name").up(1); + array_remove(tag_row._tags, tag_name); + + $("tag_" + tag_row._tag + "_tags").removeChild($("tag_" + tag_name + "_name")); + + if (tag_row._tags.length == 0) + $("tag_table").removeChild(tag_row); +} + +function get_tag (tag_name, postfix) { + return $("tag_" + $("tag_" + tag_name).up(1)._tag + "_" + postfix); +} + +function tag_add_image (orig_img, copy_img, tag, saveToDB) { + var tag_images = $('tag_' + tag + '_images'); + + if (tag_images._images.indexOf(orig_img._key) != -1) + return false; + + if (!copy_img) + copy_img = image_copy(orig_img); + + tag_images._images.push(orig_img._key) + orig_img._tags.push(tag); + + copy_img.id = "tag_" + tag + "_img_" + orig_img._key + copy_img._tag = tag; + + tag_images.appendChild(copy_img); + tag_images._visibleCount++; + + if (saveToDB) { + new Ajax.Request("taggr2.py", { + parameters: { + act: 'tag', + img: orig_img._key, + tag: tag, + }, + method: 'get' + + }); + } +} + +function tag_add_images (images, tag_name) { + var tag_images = $('tag_' + tag_name + '_images'); + var copy_img, img_keys = new Array(); + + images.each(function(orig_img){ + tag_add_image(orig_img, null, tag_name, false); + img_keys.push(orig_img._key); + }); + + new Ajax.Request("taggr2.py", { + parameters: { + act: 'tag', + img: img_keys, + tag: tag_name, + }, + method: 'get' + + }); +} + +function tag_remove_image (img_key, tag_name) { + var tag_images = $("tag_" + tag_name + "_images"); + + tag_images.removeChild($("tag_" + tag_name + "_img_" + img_key)); + array_remove(tag_images._images, img_key); + + if (tag_images._images.length == 0) + $("tag_" + tag_name).hide(); + + new Ajax.Request("taggr2.py", { + parameters: { + act: 'untag', + img: img_key, + tag: tag_name, + }, + method: 'get', + }); +} + +function hide_tag_image (tag, img) { + $("tagimg_" + tag + "_" + img).hide(); + + if (--$("tag_" + tag + "_images")._visibleCount == 0) + $("tag_" + tag).hide(); +} + +function show_tag_image (tag, img) { + $("tagimg_" + tag + "_" + img).hide(); + + if ($("tag_" + tag + "_images")._visibleCount++ == 0) + $("tag_" + tag).show(); +} + +/* + * Frontend image drag code + */ +var g_ghost; +function drag_start (e) { + if (e.hasClassName("image") || e.hasClassName("tag_image")) + g_ghost = image_copy(e); + else { + var name; + + if (e.hasClassName("tag_name")) + name = e._tag; + else + name = $F($('new_tag')); + + g_ghost = Builder.node("span", {className: 'dragged'}, [name]); + } + + $('taggr').appendChild(g_ghost); + + g_ghost.style.position = "absolute"; +} + +function drag_move (e, ev) { + g_ghost.style.left = ev.pointerX() - g_offset.left + "px"; + g_ghost.style.top = ev.pointerY() - g_offset.top + "px"; +} + +function drag_end_drop (e, s, ev) { + g_ghost.style.position = "static"; + $('taggr').removeChild(g_ghost); + + if (e.hasClassName("image") || e.hasClassName("tag_image")) { + var selection = $$(".selection"); + + if (selection.length) + tag_add_images($$(".selection"), s._tag); + else + tag_add_image(e, g_ghost, s._tag, true); + +/* + if (!tag_add_image(e, g_ghost, s._tag, true)) + // it was already in there + Effect.Shake("tagimg_" + s._tag + "_" + g_ghost._key); +*/ + } else if (e.hasClassName("tag_name")) { + null; // breakpoint + } else { + tag_add_tag($F($('new_tag')), s._tag); + } +} + +function drag_end_fail (e, ev) { + if (e.hasClassName("tag_image")) { + tag_remove_image(e._key, e._tag); + $('taggr').removeChild(g_ghost); + } else if (e.hasClassName("tag_name")) { + tag_remove_tag(e._tag); + } else { + $('taggr').removeChild(g_ghost); + } +} + +function drag_cleanup (e, ev) { + g_ghost = null; +} + +function drag_hover (e, s, ev) { + s.addClassName("hover"); +} + +function drag_unhover (e, s, ev) { + s.removeClassName("hover"); +} + +/* + * Backend image click/drag code + */ + var g_drag, g_hover, g_start, g_offset, g_targets; function check_mouse_down (ev) { var e = ev.element(); + + if (!ev.isLeftClick()) + return true; - if (e.hasClassName("image")) { + if (e.hasClassName("image") || e.hasClassName("draggable") || e.hasClassName("tag_image")) { g_drag = e; g_start = false; @@ -65,7 +337,7 @@ g_hover = null; - g_targets = $$(".tag_images"); + g_targets = $$(".tag_row"); } else if (e.hasClassName("directory_link")) { toggle_dir(e); @@ -88,8 +360,13 @@ drag_end_fail(g_drag, ev); drag_cleanup(g_drag); - } else - image_click(g_drag, ev); + } else if (g_drag.hasClassName("image") || g_drag.hasClassName("tag_image")) { + // in case image_click blocks and we get a mouse_move during it + var tmp = g_drag; + g_drag = null; + + image_click(tmp, ev); + } g_start = null; g_drag = null; @@ -124,6 +401,7 @@ if (Position.withinIncludingScrolloffsets(g_targets[i], px, py)) { drag_hover(g_drag, g_targets[i], ev); g_hover = g_targets[i]; + break; } } @@ -133,10 +411,10 @@ } function check_drag_hover (ev) { - var e = ev.element(); if (g_start) { + var e = ev.element(); - if (e.hasClassName("tag_images")) { + if (e.hasClassName("tag_row")) { drag_hover(g_drag, e, ev); g_hover = e; } @@ -144,8 +422,8 @@ } function check_drag_nohover (ev) { + if (g_start) { var e = ev.element(); - if (g_start) { if (g_hover && e == g_hover) { drag_unhover(g_drag, g_hover, ev); @@ -154,64 +432,33 @@ } } -var g_ghost; -function drag_start (e) { - g_ghost = Builder.node("img", { - src: e.src +/* + * utility code + */ +function image_copy (img) { + copy = Builder.node("img", { + src: img.src, + className: "tag_image", }); - g_ghost._key = e.id; - - $('taggr').appendChild(g_ghost); - - g_ghost.style.position = "absolute"; -} - -function drag_move (e, ev) { - g_ghost.style.left = ev.pointerX() - g_offset.left + "px"; - g_ghost.style.top = ev.pointerY() - g_offset.top + "px"; + copy._key = img._key; + copy._tags = img._tags; + + return copy; } -function drag_end_drop (e, s, ev) { - if (!s.images) - s.images = new Array(); - - if (s.images.indexOf(g_ghost._key) != -1) - return drag_end_fail(); - - g_ghost.id = s.id + "_" + g_ghost._key - - s.images.push(g_ghost._key) - - $('taggr').removeChild(g_ghost); - s.appendChild(g_ghost); - - g_ghost.style.position = "static"; +function array_remove (a, i) { + a.splice(a.indexOf(i), 1); } -function drag_end_fail (e, ev) { - $('taggr').removeChild(g_ghost); -} - -function drag_cleanup (e, ev) { - g_ghost = null; -} - -function drag_hover (e, s, ev) { - s.addClassName("hover"); -} - -function drag_unhover (e, s, ev) { - s.removeClassName("hover"); -} - -Event.observe(window, "load", init); +/* + * events + */ Event.observe(document, "mousedown", check_mouse_down); Event.observe(document, "mouseup", check_mouse_up); Event.observe(document, "mousemove", check_mouse_move); Event.observe(document, "mouseover", check_drag_hover); Event.observe(document, "mouseout", check_drag_nohover); -Event.observe(document, "dragenter", check_drag_hover); +Event.observe(document, "dragenter", check_drag_hover); // worth a try... Event.observe(document, "dragexit", check_drag_nohover); - diff -r 10841abbc01f -r 001f52cd057e lib/db.py --- a/lib/db.py Thu Jan 17 01:56:04 2008 +0000 +++ b/lib/db.py Sun Jan 20 01:07:02 2008 +0000 @@ -20,7 +20,7 @@ import sqlite3 -conn = sqlite3.connect("degal.db") +conn = sqlite3.connect("db/degal.db") def execute (expr, *args) : c = conn.cursor() @@ -28,10 +28,33 @@ return c -def insert (expr, *args) : - return execute(expr, *args).rowcount +def execute_many (expr, iter) : + c = conn.cursor() + c.executemany(expr, iter) + + return c + +def commit (cursor) : + try : + cursor.execute("COMMIT") + except sqlite3.OperationalError : + pass # ffs. INSERT just doesn't do anything otherwise + + return cursor.rowcount + +def execute_commit (expr, *args) : + return commit(execute(expr, *args)) + +def execute_commit_many (expr, iter) : + return commit(execute_many(expr, iter)) select = execute +delete = execute_commit +insert = execute_commit + +delete_many = execute_commit_many +insert_many = execute_commit_many + cursor = conn.cursor diff -r 10841abbc01f -r 001f52cd057e lib/req.py --- a/lib/req.py Thu Jan 17 01:56:04 2008 +0000 +++ b/lib/req.py Sun Jan 20 01:07:02 2008 +0000 @@ -48,3 +48,10 @@ else : return default +def get_int_list (key, default=REQUIRED_PARAM) : + if key in vars : + return [int(val) for val in vars.getlist(key)] + elif default is REQUIRED_PARAM : + raise ValueError("Required param %s" % key) + else : + return default diff -r 10841abbc01f -r 001f52cd057e templates/taggr.html --- a/templates/taggr.html Thu Jan 17 01:56:04 2008 +0000 +++ b/templates/taggr.html Sun Jan 20 01:07:02 2008 +0000 @@ -4,62 +4,14 @@
- - - - - - - - - - - - - - - - -
- otaniemi - - - -
- otaranta - - - - -
- sik - - - -
-
    -
  • sky
  • -
  • clouds
  • -
-
- -
- - - -
- +
+ +
<%include file="taggr_dir.html" />
diff -r 10841abbc01f -r 001f52cd057e templates/taggr_dir.html --- a/templates/taggr_dir.html Thu Jan 17 01:56:04 2008 +0000 +++ b/templates/taggr_dir.html Sun Jan 20 01:07:02 2008 +0000 @@ -12,8 +12,8 @@ % endif
-% for key, image in images : - +% for i, (id, image, tags) in enumerate(images) : + % endfor