Danbooru2 theme, initial tag categories extension, tag list update/rework

This commit is contained in:
Daniel Oaks 2013-06-15 01:25:05 +10:00
parent 1264ec5b35
commit bf0146cc41
5 changed files with 429 additions and 67 deletions

118
ext/tag_categories/main.php Normal file
View file

@ -0,0 +1,118 @@
<?php
/**
* Name: Tag Categories
* Author: Daniel Oaks <danneh@danneh.net>
* Link: http://code.shishnet.org/shimmie2/
* Description: Let tags be split into 'categories', like Danbooru's tagging
*/
class TagCategories extends Extension {
public function onInitExt(InitExtEvent $event) {
global $config, $database;
// whether we split out separate categories on post view by default
// note: only takes effect if /post/view shows the image's exact tags
$config->set_default_bool("tag_categories_split_on_view", true);
$database->execute('CREATE TABLE IF NOT EXISTS image_tag_categories (category TEXT PRIMARY KEY, display_singular TEXT, display_multiple SINGULAR, color TEXT(7));');
$number_of_db_rows = $database->execute('SELECT COUNT(*) FROM image_tag_categories;')->fetchColumn();
// if empty, add our default values
if ($number_of_db_rows == 0) {
$database->execute('INSERT INTO image_tag_categories VALUES ("artist", "Artist", "Artists", "#BB6666");');
$database->execute('INSERT INTO image_tag_categories VALUES ("series", "Series", "Series", "#AA00AA");');
$database->execute('INSERT INTO image_tag_categories VALUES ("character", "Character", "Characters", "#66BB66");');
}
}
public function onPageRequest(PageRequestEvent $event) {
global $page, $database, $user;
if($event->page_matches("tags")) {
switch($event->get_arg(0)) {
case 'categories':
if(class_exists("TagCategories") and ($user->is_admin())) {
$this->page_update();
$this->show_tag_categories($page);
}
break;
}
}
}
public function getDict() {
global $database;
$tc_dict = $database->get_all('SELECT * FROM image_tag_categories;');
return $tc_dict;
}
public function getKeyedDict($key_with = 'category') {
$tc_dict = $this->getDict();
$tc_keyed_dict = array();
foreach ($tc_dict as $row) {
$key = $row[$key_with];
$tc_keyed_dict[$key] = $row;
}
return $tc_keyed_dict;
}
public function page_update() {
global $user, $database;
if(!$user->is_admin()) {
return false;
}
if(!isset($_POST['tc_status']) and
!isset($_POST['tc_category']) and
!isset($_POST['tc_display_singular']) and
!isset($_POST['tc_display_multiple']) and
!isset($_POST['tc_color'])) {
return false;
}
if($_POST['tc_status'] == 'edit') {
$is_success = $database->execute('UPDATE image_tag_categories
SET display_singular=:display_singular,
display_multiple=:display_multiple,
color=:color
WHERE category=:category',
array(
'category' => html_escape($_POST['tc_category']),
'display_singular' => html_escape($_POST['tc_display_singular']),
'display_multiple' => html_escape($_POST['tc_display_multiple']),
'color' => html_escape($_POST['tc_color']),
));
}
else if($_POST['tc_status'] == 'new') {
$is_success = $database->execute('INSERT INTO image_tag_categories
VALUES (:category, :display_singular, :display_multiple, :color)',
array(
'category' => html_escape($_POST['tc_category']),
'display_singular' => html_escape($_POST['tc_display_singular']),
'display_multiple' => html_escape($_POST['tc_display_multiple']),
'color' => html_escape($_POST['tc_color']),
));
}
else if($_POST['tc_status'] == 'delete') {
$is_success = $database->execute('DELETE FROM image_tag_categories
WHERE category=:category',
array(
'category' => html_escape($_POST['tc_category'])
));
}
return $is_success;
}
public function show_tag_categories($page) {
$this->theme->show_tag_categories($page, $this->getDict());
}
}
?>

View file

@ -0,0 +1,103 @@
<?php
class TagCategoriesTheme extends Themelet {
var $heading = "";
var $list = "";
public function show_tag_categories($page, $tc_dict) {
$tc_block_index = 0;
$html = '';
foreach ($tc_dict as $row) {
$tc_block_index += 1;
$tag_category = $row['category'];
$tag_single_name = $row['display_singular'];
$tag_multiple_name = $row['display_multiple'];
$tag_color = $row['color'];
$html .= '
<div class="tagcategoryblock">
<form name="input" action="'.make_link("tags/categories").'" method="post">
<table>
<tr>
<td>Category</td>
<td>
<span>'.$tag_category.'</span>
<!--<input type="text" name="tc_category" style="display:none" value="'.$tag_category.'">-->
<input type="hidden" name="tc_category" value="'.$tag_category.'">
</td>
</tr>
<tr>
<td>Name &ndash; Single</td>
<td>
<span>'.$tag_single_name.'</span>
<input type="text" name="tc_display_singular" style="display:none" value="'.$tag_single_name.'">
</td>
</tr>
<tr>
<td>Name &ndash; Multiple</td>
<td>
<span>'.$tag_multiple_name.'</span>
<input type="text" name="tc_display_multiple" style="display:none" value="'.$tag_multiple_name.'">
</td>
</tr>
<tr>
<td>Color</td>
<td>
<span>'.$tag_color.'</span>
<input type="text" name="tc_color" style="display:none" value="'.$tag_color.'">
</td>
</tr>
</table>
<button class="tc_edit" type="button" onclick="$(\'.tagcategoryblock:nth-of-type('.$tc_block_index.') tr + tr td span\').hide(); $(\'.tagcategoryblock:nth-of-type('.$tc_block_index.') td input\').show(); $(\'.tagcategoryblock:nth-of-type('.$tc_block_index.') .tc_edit\').hide(); $(\'.tagcategoryblock:nth-of-type('.$tc_block_index.') .tc_submit\').show();">Edit</button>
<button class="tc_submit" type="submit" style="display:none;" name="tc_status" value="edit">Submit</button>
<button class="tc_submit" type="button" style="display:none.tagcategoryblock:nth-of-type('.$tc_block_index.');" onclick="$(\'.tagcategoryblock:nth-of-type('.$tc_block_index.') .tc_delete\').show(); $(this).hide();">Delete</button>
<button class="tc_delete" type="submit" style="display:none;" name="tc_status" value="delete">Really, really delete</button>
</form>
</div>
';
}
// new
$tag_category = 'example';
$tag_single_name = 'Example';
$tag_multiple_name = 'Examples';
$tag_color = '#EE5542';
$html .= '
<div class="tagcategoryblock">
<form name="input" action="'.make_link("tags/categories").'" method="post">
<table>
<tr>
<td>Category</td>
<td>
<input type="text" name="tc_category" value="'.$tag_category.'">
</td>
</tr>
<tr>
<td>Name &ndash; Single</td>
<td>
<input type="text" name="tc_display_singular" value="'.$tag_single_name.'">
</td>
</tr>
<tr>
<td>Name &ndash; Multiple</td>
<td>
<input type="text" name="tc_display_multiple" value="'.$tag_multiple_name.'">
</td>
</tr>
<tr>
<td>Color</td>
<td>
<input type="text" name="tc_color" value="'.$tag_color.'">
</td>
</tr>
</table>
<button class="tc_submit" type="submit" name="tc_status" value="new">Submit</button>
</form>
</div>
';
// add html to stuffs
$page->add_block(new Block("Editing", $html, "main", 10));
}
}
?>

View file

@ -40,7 +40,7 @@ class TagList extends Extension {
break;
case 'categories':
$this->theme->set_heading("Popular Categories");
$this->theme->set_tag_list($this->build_tag_categories());
$this->theme->set_tag_list($this->build_tag_list());
break;
}
$this->theme->display_page($page);
@ -81,7 +81,12 @@ class TagList extends Extension {
$this->add_related_block($page, $event->image);
}
else {
$this->add_tags_block($page, $event->image);
if(class_exists("TagCategories") and $config->get_bool('tag_categories_split_on_view')) {
$this->add_split_tags_block($page, $event->image);
}
else {
$this->add_tags_block($page, $event->image);
}
}
}
}
@ -290,7 +295,7 @@ class TagList extends Extension {
return $html;
}
private function build_tag_categories() {
private function build_tag_list() {
global $database;
$tags_min = $this->get_tags_min();
@ -348,6 +353,25 @@ class TagList extends Extension {
}
}
private function add_split_tags_block(Page $page, Image $image) {
global $database;
global $config;
$query = "
SELECT tags.tag, tags.count as calc_count
FROM tags, image_tags
WHERE tags.id = image_tags.tag_id
AND image_tags.image_id = :image_id
ORDER BY calc_count DESC
";
$args = array("image_id"=>$image->id);
$tags = $database->get_all($query, $args);
if(count($tags) > 0) {
$this->theme->display_split_related_block($page, $tags);
}
}
private function add_tags_block(Page $page, Image $image) {
global $database;
global $config;
@ -374,7 +398,7 @@ class TagList extends Extension {
$tags = $database->cache->get("popular_tags");
if(empty($tags)) {
$query = "
SELECT tag, count
SELECT tag, count as calc_count
FROM tags
WHERE count > 0
ORDER BY count DESC

View file

@ -25,6 +25,64 @@ class TagListTheme extends Themelet {
// =======================================================================
/*
* $tag_infos = array(
* array('tag' => $tag, 'count' => $number_of_uses),
* ...
* )
*/
public function display_split_related_block(Page $page, $tag_infos) {
global $config;
if($config->get_string('tag_list_related_sort') == 'alphabetical') asort($tag_infos);
if(class_exists('TagCategories')) {
$this->tagcategories = new TagCategories;
$tag_category_dict = $this->tagcategories->getKeyedDict();
}
else {
$tag_category_dict = array();
}
$tag_categories_html = array();
$tag_categories_count = array();
foreach($tag_infos as $row) {
$split = self::return_tag($row, $tag_category_dict);
$category = $split[0];
$tag_html = $split[1];
if(!isset($tag_categories_html[$category])) {
$tag_categories_html[$category] = '';
}
$tag_categories_html[$category] .= $tag_html . '<br />';
if(!isset($tag_categories_count[$category])) {
$tag_categories_count[$category] = 0;
}
$tag_categories_count[$category] += 1;
}
asort($tag_categories_html);
$main_html = $tag_categories_html[' '];
unset($tag_categories_html[' ']);
foreach(array_keys($tag_categories_html) as $category) {
if($tag_categories_count[$category] < 2) {
$category_display_name = $tag_category_dict[$category]['display_singular'];
}
else{
$category_display_name = $tag_category_dict[$category]['display_multiple'];
}
$page->add_block(new Block($category_display_name, $tag_categories_html[$category], "left", 9));
}
if($config->get_string('tag_list_image_type')=="tags") {
$page->add_block(new Block("Tags", $main_html, "left", 10));
}
else {
$page->add_block(new Block("Related Tags", $main_html, "left", 10));
}
}
/*
* $tag_infos = array(
* array('tag' => $tag, 'count' => $number_of_uses),
@ -34,32 +92,29 @@ class TagListTheme extends Themelet {
public function display_related_block(Page $page, $tag_infos) {
global $config;
$html = "";
$n = 0;
if($config->get_string('tag_list_related_sort') == 'alphabetical') asort($tag_infos);
foreach($tag_infos as $row) {
$tag = $row['tag'];
$h_tag = html_escape($tag);
$h_tag_no_underscores = str_replace("_", " ", $h_tag);
$count = $row['calc_count'];
if($n++) $html .= "\n<br/>";
if(!is_null($config->get_string('info_link'))) {
$link = str_replace('$tag', $tag, $config->get_string('info_link'));
$html .= " <a class='tag_info_link' href='$link'>?</a>";
}
$link = $this->tag_link($row['tag']);
$html .= " <a class='tag_name' href='$link'>$h_tag_no_underscores</a>";
if($config->get_bool("tag_list_numbers")) {
$html .= " <span class='tag_count'>$count</span>";
}
}
if($config->get_string('tag_list_image_type')=="tags") {
$page->add_block(new Block("Tags", $html, "left", 10));
if(class_exists('TagCategories')) {
$this->tagcategories = new TagCategories;
$tag_category_dict = $this->tagcategories->getKeyedDict();
}
else {
$page->add_block(new Block("Related Tags", $html, "left", 10));
$tag_category_dict = array();
}
$main_html = '';
foreach($tag_infos as $row) {
$split = $this->return_tag($row, $tag_category_dict);
$category = $split[0];
$tag_html = $split[1];
$main_html .= $tag_html . '<br />';
}
if($config->get_string('tag_list_image_type')=="tags") {
$page->add_block(new Block("Tags", $main_html, "left", 10));
}
else {
$page->add_block(new Block("Related Tags", $main_html, "left", 10));
}
}
@ -72,34 +127,27 @@ class TagListTheme extends Themelet {
*/
public function display_popular_block(Page $page, $tag_infos) {
global $config;
// store local copies for speed.
$info_link = $config->get_string('info_link');
$tag_list_num = $config->get_bool("tag_list_numbers");
$html = "";
$n = 0;
if($config->get_string('tag_list_popular_sort') == 'alphabetical') asort($tag_infos);
if(class_exists('TagCategories')) {
$this->tagcategories = new TagCategories;
$tag_category_dict = $this->tagcategories->getKeyedDict();
}
else {
$tag_category_dict = array();
}
$main_html = '';
foreach($tag_infos as $row) {
$tag = $row['tag'];
$h_tag = html_escape($tag);
$h_tag_no_underscores = str_replace("_", " ", $h_tag);
$count = $row['count'];
if($n++) $html .= "\n<br/>";
if(!is_null($info_link)) {
$link = str_replace('$tag', $tag, $info_link);
$html .= ' <a class="tag_info_link" href="'.$link.'">?</a>';
}
$link = $this->tag_link($row['tag']);
$html .= ' <a class="tag_name" href="'.$link.'">'.$h_tag_no_underscores.'</a>';
if($tag_list_num) {
$html .= ' <span class="tag_count">'.$count.'</span>';
}
$split = self::return_tag($row, $tag_category_dict);
$category = $split[0];
$tag_html = $split[1];
$main_html .= $tag_html . '<br />';
}
$html .= "<br>&nbsp;<br><a class='more' href='".make_link("tags")."'>Full List</a>\n";
$page->add_block(new Block("Popular Tags", $html, "left", 60));
$main_html .= "&nbsp;<br><a class='more' href='".make_link("tags")."'>Full List</a>\n";
$page->add_block(new Block("Popular Tags", $main_html, "left", 60));
}
/*
@ -112,27 +160,63 @@ class TagListTheme extends Themelet {
public function display_refine_block(Page $page, $tag_infos, $search) {
global $config;
// store local copy for speed.
$info_link = $config->get_string('info_link');
$html = "";
$n = 0;
if($config->get_string('tag_list_popular_sort') == 'alphabetical') asort($tag_infos);
if(class_exists('TagCategories')) {
$this->tagcategories = new TagCategories;
$tag_category_dict = $this->tagcategories->getKeyedDict();
}
else {
$tag_category_dict = array();
}
$main_html = '';
foreach($tag_infos as $row) {
$tag = $row['tag'];
$h_tag = html_escape($tag);
$h_tag_no_underscores = str_replace("_", " ", $h_tag);
if($n++) $html .= "\n<br/>";
if(!is_null($info_link)) {
$link = str_replace('$tag', $tag, $info_link);
$html .= ' <a class="tag_info_link" href="'.$link.'">?</a>';
}
$link = $this->tag_link($row['tag']);
$html .= ' <a class="tag_name" href="'.$link.'">'.$h_tag_no_underscores.'</a>';
$html .= $this->ars($tag, $search);
$split = self::return_tag($row, $tag_category_dict);
$category = $split[0];
$tag_html = $split[1];
$main_html .= $tag_html . '<br />';
}
$page->add_block(new Block("Refine Search", $html, "left", 60));
$main_html .= "&nbsp;<br><a class='more' href='".make_link("tags")."'>Full List</a>\n";
$page->add_block(new Block("refine Search", $main_html, "left", 60));
}
public function return_tag($row, $tag_category_dict) {
global $config;
$display_html = '';
$tag = $row['tag'];
$h_tag = html_escape($tag);
$tag_category_css = '';
$tag_category_style = '';
$h_tag_split = explode(':', html_escape($tag), 2);
$category = ' ';
// we found a tag, see if it's valid!
if((count($h_tag_split) > 1) and array_key_exists($h_tag_split[0], $tag_category_dict)) {
$category = $h_tag_split[0];
$h_tag = $h_tag_split[1];
$tag_category_css .= ' tag_category_'.$category;
$tag_category_style .= 'style="color:'.$tag_category_dict[$category]['color'].';" ';
}
$h_tag_no_underscores = str_replace("_", " ", $h_tag);
$count = $row['calc_count'];
// if($n++) $display_html .= "\n<br/>";
if(!is_null($config->get_string('info_link'))) {
$link = str_replace('$tag', $tag, $config->get_string('info_link'));
$display_html .= ' <a class="tag_info_link'.$tag_category_css.'" '.$tag_category_style.'href="'.$link.'">?</a>';
}
$link = $this->tag_link($row['tag']);
$display_html .= ' <a class="tag_name'.$tag_category_css.'" '.$tag_category_style.'href="'.$link.'">'.$h_tag_no_underscores.'</a>';
if($config->get_bool("tag_list_numbers")) {
$display_html .= " <span class='tag_count'>$count</span>";
}
return [$category, $display_html];
}
protected function ars(/*string*/ $tag, /*array(string)*/ $tags) {

View file

@ -163,3 +163,36 @@ ARTICLE TABLE {
-webkit-box-shadow: 2px 2px 6px rgba(0,0,0,0.6); /* webkit haven't committed yet */
-moz-box-shadow: 2px 2px 6px rgba(0,0,0,0.6); /* mozilla haven't committed yet */
}
.tagcategoryblock {
margin:0.6rem 1rem 0.6rem 0;
padding:0.5rem 0.6rem 0.7rem;
width:18rem;
border:1px solid #AAAAAA;
border-radius:0.25rem;
display:inline-block;
}
.tagcategoryblock table {
width:100%;
border-spacing:0;
}
.tagcategoryblock input, .tagcategoryblock span {
width:100%;
height:100%;
}
.tagcategoryblock td:first-child {
padding:0.3rem 0.7rem 0.4rem 0;
text-align:right;
width:40%;
}
.tagcategoryblock td:last-child {
width:60%;
}
.tagcategoryblock td:last-child span {
padding:0.24rem 0.7rem 0.5rem 0;
display:block;
}
.tagcategoryblock button {
width:100%;
margin-top:0.4rem;
padding:0.2rem 0.6rem;
}