summaryrefslogtreecommitdiff
path: root/modules/tag
diff options
context:
space:
mode:
Diffstat (limited to 'modules/tag')
-rw-r--r--modules/tag/controllers/admin_tags.php8
-rw-r--r--modules/tag/controllers/tags.php19
-rw-r--r--modules/tag/helpers/tag.php40
-rw-r--r--modules/tag/helpers/tag_event.php48
-rw-r--r--modules/tag/helpers/tag_installer.php4
-rw-r--r--modules/tag/helpers/tag_menu.php28
-rw-r--r--modules/tag/helpers/tag_rss.php3
-rw-r--r--modules/tag/helpers/tag_theme.php6
-rw-r--r--modules/tag/js/tag.js15
-rw-r--r--modules/tag/models/tag.php58
-rw-r--r--modules/tag/views/admin_tags.html.php14
-rw-r--r--modules/tag/views/tag_block.html.php14
-rw-r--r--modules/tag/views/tag_cloud.html.php2
13 files changed, 194 insertions, 65 deletions
diff --git a/modules/tag/controllers/admin_tags.php b/modules/tag/controllers/admin_tags.php
index dcdc16b9..8b8dde21 100644
--- a/modules/tag/controllers/admin_tags.php
+++ b/modules/tag/controllers/admin_tags.php
@@ -53,8 +53,8 @@ class Admin_Tags_Controller extends Admin_Controller {
$name = $tag->name;
Database::instance()->delete("items_tags", array("tag_id" => "$tag->id"));
$tag->delete();
- message::success(t("Deleted tag %tag_name", array("tag_name" => p::clean($name))));
- log::success("tags", t("Deleted tag %tag_name", array("tag_name" => p::clean($name))));
+ message::success(t("Deleted tag %tag_name", array("tag_name" => $name)));
+ log::success("tags", t("Deleted tag %tag_name", array("tag_name" => $name)));
print json_encode(
array("result" => "success",
@@ -98,7 +98,7 @@ class Admin_Tags_Controller extends Admin_Controller {
$tag->save();
$message = t("Renamed tag %old_name to %new_name",
- array("old_name" => p::clean($old_name), "new_name" => p::clean($tag->name)));
+ array("old_name" => $old_name, "new_name" => $tag->name));
message::success($message);
log::success("tags", $message);
@@ -106,7 +106,7 @@ class Admin_Tags_Controller extends Admin_Controller {
array("result" => "success",
"location" => url::site("admin/tags"),
"tag_id" => $tag->id,
- "new_tagname" => p::clean($tag->name)));
+ "new_tagname" => html::clean($tag->name)));
} else {
print json_encode(
array("result" => "error",
diff --git a/modules/tag/controllers/tags.php b/modules/tag/controllers/tags.php
index 85f6d16e..c993e374 100644
--- a/modules/tag/controllers/tags.php
+++ b/modules/tag/controllers/tags.php
@@ -53,7 +53,7 @@ class Tags_Controller extends REST_Controller {
$form = tag::get_add_form($item);
if ($form->validate()) {
- foreach (split("[\,\ \;]", $form->add_tag->inputs["name"]->value) as $tag_name) {
+ foreach (split(",", $form->add_tag->inputs["name"]->value) as $tag_name) {
$tag_name = trim($tag_name);
if ($tag_name) {
$tag = tag::add($item, $tag_name);
@@ -78,4 +78,21 @@ class Tags_Controller extends REST_Controller {
return tag::get_add_form($item);
}
+
+ public function autocomplete() {
+ $tags = array();
+ $tag_parts = preg_split("#,#", $this->input->get("q"));
+ $limit = $this->input->get("limit");
+ $tag_part = end($tag_parts);
+ $tag_list = ORM::factory("tag")
+ ->like("name", "{$tag_part}%", false)
+ ->orderby("name", "ASC")
+ ->limit($limit)
+ ->find_all();
+ foreach ($tag_list as $tag) {
+ $tags[] = $tag->name;
+ }
+
+ print implode("\n", $tags);
+ }
}
diff --git a/modules/tag/helpers/tag.php b/modules/tag/helpers/tag.php
index 7c4b56ba..be5461a4 100644
--- a/modules/tag/helpers/tag.php
+++ b/modules/tag/helpers/tag.php
@@ -79,6 +79,24 @@ class tag_Core {
}
}
+
+ /**
+ * Return all the tags for a given item.
+ * @return array
+ */
+ static function item_tags($item) {
+ $tags = array();
+ foreach (Database::instance()
+ ->select("name")
+ ->from("tags")
+ ->join("items_tags", "tags.id", "items_tags.tag_id", "left")
+ ->where("items_tags.item_id", $item->id)
+ ->get() as $row) {
+ $tags[] = $row->name;
+ }
+ return $tags;
+ }
+
static function get_add_form($item) {
$form = new Forge("tags", "", "post", array("id" => "gAddTagForm"));
$label = $item->is_album() ?
@@ -86,7 +104,7 @@ class tag_Core {
($item->is_photo() ? t("Add tag to photo") : t("Add tag to movie"));
$group = $form->group("add_tag")->label("Add Tag");
- $group->input("name")->label($label)->rules("required|length[1,64]");
+ $group->input("name")->label($label)->rules("required");
$group->hidden("item_id")->value($item->id);
$group->submit("")->value(t("Add Tag"));
return $form;
@@ -108,4 +126,24 @@ class tag_Core {
$group->submit("")->value(t("Delete Tag"));
return $form;
}
+
+ /**
+ * Delete all tags associated with an item
+ */
+ static function clear_all($item) {
+ $db = Database::instance();
+ $db->query("UPDATE {tags} SET `count` = `count` - 1 WHERE `count` > 0 " .
+ "AND `id` IN (SELECT `tag_id` from {items_tags} WHERE `item_id` = $item->id)");
+ $db->delete("items_tags", array("item_id" => "$item->id"));
+ }
+
+ /**
+ * Get rid of any tags that have no associated items.
+ */
+ static function compact() {
+ // @todo There's a potential race condition here which we can solve by adding a lock around
+ // this and all the cases where we create/update tags. I'm loathe to do that since it's an
+ // extremely rare case.
+ Database::instance() ->delete("tags", array("count" => 0));
+ }
} \ No newline at end of file
diff --git a/modules/tag/helpers/tag_event.php b/modules/tag/helpers/tag_event.php
index 7a170bf8..57986e40 100644
--- a/modules/tag/helpers/tag_event.php
+++ b/modules/tag/helpers/tag_event.php
@@ -34,8 +34,8 @@ class tag_event_Core {
if (!empty($iptc["2#025"])) {
foreach($iptc["2#025"] as $tag) {
$tag = str_replace("\0", "", $tag);
- foreach (preg_split("/[,;]/", $tag) as $word) {
- $word = preg_replace('/\s+/', '.', trim($word));
+ foreach (preg_split("/,/", $tag) as $word) {
+ $word = trim($word);
if (function_exists("mb_detect_encoding") && mb_detect_encoding($word) != "UTF-8") {
$word = utf8_encode($word);
}
@@ -59,12 +59,42 @@ class tag_event_Core {
return;
}
- static function item_before_delete($item) {
- $db = Database::instance();
- $db->query("UPDATE {tags} SET `count` = `count` - 1 WHERE `count` > 0 " .
- "AND `id` IN (SELECT `tag_id` from {items_tags} WHERE `item_id` = $item->id)");
- $db->query("DELETE FROM {tags} WHERE `count` = 0 AND `id` IN (" .
- "SELECT `tag_id` from {items_tags} WHERE `item_id` = $item->id)");
- $db->delete("items_tags", array("item_id" => "$item->id"));
+ static function item_deleted($item) {
+ tag::clear_all($item);
+ tag::compact();
+ }
+
+ static function item_edit_form($item, $form) {
+ $url = url::site("tags/autocomplete");
+ $form->script("")
+ ->text("$('form input[id=tags]').ready(function() {
+ $('form input[id=tags]').autocomplete(
+ '$url', {max: 30, multiple: true, multipleSeparator: ',', cacheLength: 1});
+ });");
+ $tag_value = implode(", ", tag::item_tags($item));
+ $form->edit_item->input("tags")->label(t("Tags (comma separated)"))
+ ->value($tag_value);
+ }
+
+ static function item_edit_form_completed($item, $form) {
+ tag::clear_all($item);
+ foreach (preg_split("/,/", $form->edit_item->tags->value) as $tag_name) {
+ if ($tag_name) {
+ tag::add($item, trim($tag_name));
+ }
+ }
+ tag::compact();
+ }
+
+ static function admin_menu($menu, $theme) {
+ $menu->get("content_menu")
+ ->append(Menu::factory("link")
+ ->id("tags")
+ ->label(t("Tags"))
+ ->url(url::site("admin/tags")));
+ }
+
+ static function item_index_data($item, $data) {
+ $data[] = join(" ", tag::item_tags($item));
}
}
diff --git a/modules/tag/helpers/tag_installer.php b/modules/tag/helpers/tag_installer.php
index 3c16e3f3..bcb830e4 100644
--- a/modules/tag/helpers/tag_installer.php
+++ b/modules/tag/helpers/tag_installer.php
@@ -26,7 +26,7 @@ class tag_installer {
`count` int(10) unsigned NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY(`name`))
- ENGINE=InnoDB DEFAULT CHARSET=utf8;");
+ DEFAULT CHARSET=utf8;");
$db->query("CREATE TABLE IF NOT EXISTS {items_tags} (
`id` int(9) NOT NULL auto_increment,
@@ -35,7 +35,7 @@ class tag_installer {
PRIMARY KEY (`id`),
KEY(`tag_id`, `id`),
KEY(`item_id`, `id`))
- ENGINE=InnoDB DEFAULT CHARSET=utf8;");
+ DEFAULT CHARSET=utf8;");
module::set_version("tag", 1);
}
diff --git a/modules/tag/helpers/tag_menu.php b/modules/tag/helpers/tag_menu.php
deleted file mode 100644
index e1b61a93..00000000
--- a/modules/tag/helpers/tag_menu.php
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php defined("SYSPATH") or die("No direct script access.");
-/**
- * Gallery - a web based photo album viewer and editor
- * Copyright (C) 2000-2009 Bharat Mediratta
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
- */
-class tag_menu_Core {
- static function admin($menu, $theme) {
- $menu->get("content_menu")
- ->append(Menu::factory("link")
- ->id("tags")
- ->label(t("Tags"))
- ->url(url::site("admin/tags")));
- }
-}
diff --git a/modules/tag/helpers/tag_rss.php b/modules/tag/helpers/tag_rss.php
index f94508cf..de5d6c72 100644
--- a/modules/tag/helpers/tag_rss.php
+++ b/modules/tag/helpers/tag_rss.php
@@ -22,7 +22,7 @@ class tag_rss_Core {
static function available_feeds($item, $tag) {
if ($tag) {
$feeds["tag/tag/{$tag->id}"] =
- t("Tag feed for %tag_name", array("tag_name" => p::clean($tag->name)));
+ t("Tag feed for %tag_name", array("tag_name" => $tag->name));
return $feeds;
}
return array();
@@ -37,7 +37,6 @@ class tag_rss_Core {
$feed->children = $tag->items($limit, $offset, "photo");
$feed->max_pages = ceil($tag->count / $limit);
$feed->title = $tag->name;
- $feed->link = url::abs_site("tags/{$tag->id}");
$feed->description = t("Photos related to %tag_name", array("tag_name" => $tag->name));
return $feed;
diff --git a/modules/tag/helpers/tag_theme.php b/modules/tag/helpers/tag_theme.php
index fe30354f..1bce9bd8 100644
--- a/modules/tag/helpers/tag_theme.php
+++ b/modules/tag/helpers/tag_theme.php
@@ -19,11 +19,13 @@
*/
class tag_theme_Core {
static function head($theme) {
- $theme->script("modules/tag/js/tag.js");
+ $theme->css("jquery.autocomplete.css");
+ $theme->script("jquery.autocomplete.js");
+ $theme->script("tag.js");
}
static function admin_head($theme) {
- $theme->script("modules/tag/js/tag.js");
+ $theme->script("tag.js");
}
static function sidebar_blocks($theme) {
diff --git a/modules/tag/js/tag.js b/modules/tag/js/tag.js
index a1eaeecd..aaae9e72 100644
--- a/modules/tag/js/tag.js
+++ b/modules/tag/js/tag.js
@@ -7,7 +7,7 @@ function ajaxify_tag_form() {
dataType: "json",
success: function(data) {
if (data.result == "success") {
- $.get($("#gTagCloud").attr("src"), function(data, textStatus) {
+ $.get($("#gTagCloud").attr("title"), function(data, textStatus) {
$("#gTagCloud").html(data);
});
}
@@ -23,22 +23,28 @@ function closeEditInPlaceForms() {
$("#gRenameTagForm").parent().html($("#gRenameTagForm").parent().data("revert"));
li.height("");
$(".gEditable", li).bind("click", editInPlace);
- $(".gDialogLink", li).bind("click", handleDialogEvent);
+ $(".gDialogLink", li).gallery_dialog();
}
}
+function str_replace(search_term, replacement, string) {
+ var temp = string.split(search_term);
+ return temp.join(replacement);
+}
+
function editInPlace(element) {
closeEditInPlaceForms();
// create edit form
var tag_id = $(this).attr('id').substr(5);
- var tag_name = $(this).text();
+ var tag_name = $(this).html();
var tag_width = $(this).width();
$(this).parent().data("revert", $(this).parent().html());
var form = '<form id="gRenameTagForm" method="post" class="ui-helper-clearfix" ';
form += 'action="' + TAG_RENAME_URL.replace('__ID__', tag_id) + '">';
form += '<input name="csrf" type="hidden" value="' + csrf_token + '" />';
- form += '<input id="name" name="name" type="text" class="textbox" value="' + tag_name + '" />';
+ form += '<input id="name" name="name" type="text" class="textbox" value="' +
+ str_replace('"', "&quot;", tag_name) + '" />';
form += '<input type="submit" class="submit ui-state-default ui-corner-all" value="' + save_i18n + '" i/>';
form += '<a href="#">' + cancel_i18n + '</a>';
form += '</form>';
@@ -66,3 +72,4 @@ function editInPlace(element) {
};
ajaxify_editInPlaceForm();
}
+
diff --git a/modules/tag/models/tag.php b/modules/tag/models/tag.php
index 7a85dbab..d9488e1c 100644
--- a/modules/tag/models/tag.php
+++ b/modules/tag/models/tag.php
@@ -44,10 +44,62 @@ class Tag_Model extends ORM {
* @return integer
*/
public function items_count($type=null) {
- return ORM::factory("item")
+ $model = ORM::factory("item")
->viewable()
->join("items_tags", "items.id", "items_tags.item_id")
- ->where("items_tags.tag_id", $this->id)
- ->count_all();
+ ->where("items_tags.tag_id", $this->id);
+
+ if ($type) {
+ $model->where("items.type", $type);
+ }
+ return $model->count_all();
+ }
+
+ /**
+ * Overload ORM::save() to trigger an item_related_update event for all items that are related
+ * to this tag. Since items can be added or removed as part of the save, we need to trigger an
+ * event for the union of all related items before and after the save.
+ */
+ public function save() {
+ $db = Database::instance();
+ $related_item_ids = array();
+ foreach ($db->getwhere("items_tags", array("tag_id" => $this->id)) as $row) {
+ $related_item_ids[$row->item_id] = 1;
+ }
+
+ $result = parent::save();
+
+ foreach ($db->getwhere("items_tags", array("tag_id" => $this->id)) as $row) {
+ $related_item_ids[$row->item_id] = 1;
+ }
+
+ if ($related_item_ids) {
+ foreach (ORM::factory("item")->in("id", array_keys($related_item_ids))->find_all() as $item) {
+ module::event("item_related_update", $item);
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Overload ORM::delete() to trigger an item_related_update event for all items that are
+ * related to this tag.
+ */
+ public function delete() {
+ $related_item_ids = array();
+ $db = Database::Instance();
+ foreach ($db->getwhere("items_tags", array("tag_id" => $this->id)) as $row) {
+ $related_item_ids[$row->item_id] = 1;
+ }
+
+ $result = parent::delete();
+
+ if ($related_item_ids) {
+ foreach (ORM::factory("item")->in("id", array_keys($related_item_ids))->find_all() as $item) {
+ module::event("item_related_update", $item);
+ }
+ }
+ return $result;
}
} \ No newline at end of file
diff --git a/modules/tag/views/admin_tags.html.php b/modules/tag/views/admin_tags.html.php
index 7d201da7..8f3693aa 100644
--- a/modules/tag/views/admin_tags.html.php
+++ b/modules/tag/views/admin_tags.html.php
@@ -1,9 +1,9 @@
<?php defined("SYSPATH") or die("No direct script access.") ?>
<script>
- var TAG_RENAME_URL = "<?= url::site("admin/tags/rename/__ID__") ?>";
+ var TAG_RENAME_URL = <?= html::js_string(url::site("admin/tags/rename/__ID__")) ?>;
$("document").ready(function() {
// using JS for adding link titles to avoid running t() for each tag
- $("#gTagAdmin .tag-name").attr("title", "<?= t("Click to edit this tag") ?>");
+ $("#gTagAdmin .tag-name").attr("title", <?= t("Click to edit this tag")->for_js() ?>);
$("#gTagAdmin .delete-link").attr("title", $(".delete-link:first span").html());
// In-place editing for tag admin
@@ -11,8 +11,8 @@
});
// make some values available within tag.js
var csrf_token = "<?= $csrf ?>";
- var save_i18n = '<?= t("save") ?>';
- var cancel_i18n = '<?= t("cancel") ?>';
+ var save_i18n = <?= html::js_string(t("save")->for_html_attr()) ?>;
+ var cancel_i18n = <?= html::js_string(t("cancel")->for_html_attr()) ?>;
</script>
<div class="gBlock">
<h2>
@@ -32,7 +32,7 @@
<? $current_letter = strtoupper(mb_substr($tag->name, 0, 1)) ?>
<? if ($i == 0): /* first letter */ ?>
- <strong><?= $current_letter ?></strong>
+ <strong><?= html::clean($current_letter) ?></strong>
<ul>
<? elseif ($last_letter != $current_letter): /* new letter */ ?>
<? if ($column_tag_count > $tags_per_column): /* new column */ ?>
@@ -42,12 +42,12 @@
<? endif ?>
</ul>
- <strong><?= $current_letter ?></strong>
+ <strong><?= html::clean($current_letter) ?></strong>
<ul>
<? endif ?>
<li>
- <span id="gTag-<?= $tag->id ?>" class="gEditable tag-name"><?= p::clean($tag->name) ?></span>
+ <span id="gTag-<?= $tag->id ?>" class="gEditable tag-name"><?= html::clean($tag->name) ?></span>
<span class="understate">(<?= $tag->count ?>)</span>
<a href="<?= url::site("admin/tags/form_delete/$tag->id") ?>"
class="gDialogLink delete-link gButtonLink">
diff --git a/modules/tag/views/tag_block.html.php b/modules/tag/views/tag_block.html.php
index 9c8f3de5..59a4ef88 100644
--- a/modules/tag/views/tag_block.html.php
+++ b/modules/tag/views/tag_block.html.php
@@ -1,5 +1,17 @@
<?php defined("SYSPATH") or die("No direct script access.") ?>
-<div id="gTagCloud" src="<?= url::site("tags") ?>">
+<script>
+ $("#gAddTagForm").ready(function() {
+ var url = $("#gTagCloud").attr("title") + "/autocomplete";
+ $("#gAddTagForm input:text").autocomplete(
+ url, {
+ max: 30,
+ multiple: true,
+ multipleSeparator: ',',
+ cacheLength: 1}
+ );
+ });
+</script>
+<div id="gTagCloud" title="<?= url::site("tags") ?>">
<?= $cloud ?>
</div>
<?= $form ?> \ No newline at end of file
diff --git a/modules/tag/views/tag_cloud.html.php b/modules/tag/views/tag_cloud.html.php
index eba615fc..d6a0b5f8 100644
--- a/modules/tag/views/tag_cloud.html.php
+++ b/modules/tag/views/tag_cloud.html.php
@@ -3,7 +3,7 @@
<? foreach ($tags as $tag): ?>
<li class="size<?=(int)(($tag->count / $max_count) * 7) ?>">
<span><?= $tag->count ?> photos are tagged with </span>
- <a href="<?= url::site("tags/$tag->id") ?>"><?= p::clean($tag->name) ?></a>
+ <a href="<?= url::site("tags/$tag->id") ?>"><?= html::clean($tag->name) ?></a>
</li>
<? endforeach ?>
</ul>