Tagger 20071023 1507 - Moving alpha2 to RC - still no dragging

git-svn-id: file:///home/shish/svn/shimmie2/trunk@561 7f39781d-f577-437e-ae19-be835c7a54ca
This commit is contained in:
Artanis 2007-10-23 22:08:22 +00:00
parent bcb5eecc56
commit 5d273e6879
4 changed files with 452 additions and 492 deletions

View file

@ -1,93 +1,155 @@
<?php <?php
// Tagger - Advanced Tagging /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// Author: Artanis (Erik Youngren <artanis.00@gmail.com>) * Tagger - Advanced Tagging v2 *
// Do not remove this notice. * Author: Artanis (Erik Youngren <artanis.00@gmail.com>) *
* Do not remove this notice. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
class tagger extends Extension { class Tagger extends Extension {
var $theme; var $theme;
public function receive_event ($event) { public function receive_event ($event) {
if(is_null($this->theme)) if(is_null($this->theme))
$this->theme = get_theme_object("tagger", "taggerTheme"); $this->theme = get_theme_object("tagger", "taggerTheme");
if(is_a($event,"InitExtEvent")) { if(is_a($event,'DisplayingImageEvent')) {
global $config; global $page, $config, $user;
if ($config->get_int("ext-tagger_tags-min") == -1)
$config->set_int("ext-tagger_tags-min",2);
if ($config->get_string("ext-tagger_clear-tagme") == -1) if($config->get_bool("tag_edit_anon") || ($user->id != $config->get_int("anon_id")))
$config->set_bool("ext-tagger_clear-tagme",false); $this->theme->build_tagger($page,$event);
if ($config->get_string("ext-tagger_show-hidden") == -1)
$config->set_bool("ext-tagger_show-hidden",false);
} }
if(is_a($event,"DisplayingImageEvent")) {
//show tagger box
global $database;
global $page;
global $config;
$base_href = $config->get_string('base_href');
$tags_min = (isset($_GET['tagger_min']) && $_GET['tagger_min']>0)?$_GET['tagger_min']:$config->get_int('ext-tagger_tags-min',2);
$hidden = $config->get_string(
'ext-tagger_show-hidden','N')=='N' ?
" AND substring(tag,1,1) != '.' " : null;
$tags = $database->Execute("
SELECT tag
FROM `tags`
WHERE count>=?{$hidden}
ORDER BY tag",array($tags_min));
$this->theme->build($page, $tags);
global $user;
if($tags->_numOfRows > 1000 && $user->is_admin()) {
$page->add_block( new Block (
"Warning - ext/tagger",
"<h4>It is likely that Tagger will not function</h4>
Currently the javascript code chokes on large numbers of
tags. The tag list currently numbers
<b>{$tags->_numOfRows}</b>.<br/>
You can increase the minimum use requirement for the tag
list in the <a href='".make_link('setup')."'>Board Config</a>
to reduce the size of this list.<br/>
This is a limitation of the method in which Tagger operates.
I am working on a solution, I do not know when such a
solution will be ready.",
"main",0));
}
}
if(is_a($event,"PageRequestEvent")) {
if($event->page_name == "about" && $event->get_arg(0) == "tagger") {
global $page;
$this->theme->show_about($page);
}
if($event->page_name == "tagger") {
global $page;
// $this->theme->configTagger($page);
}
}
if(is_a($event, 'UserBlockBuildingEvent')) {
if($event->user->is_admin()) {
// $event->add_link("Tagger Config", make_link("tagger"));
}
}
if(is_a($event, 'SetupBuildingEvent')) {
$sb = new SetupBlock("Tagger - Power Tagging");
$sb->add_bool_option("ext-tagger_show-hidden", "Show Hidden Tags");
$sb->add_bool_option(
"ext-tagger_clear-tagme",
"<br/>Remove '<a href='".make_link("post/list/tagme/1")."'>tagme</a>' on use");
$sb->add_int_option(
"ext-tagger_tags-min",
"<br/>Ignore tags used fewer than "); $sb->add_label("times.");
$event->panel->add_block($sb);
}
} }
} } if(isset($_GET['debug'])) add_event_listener( new tagger());
add_event_listener( new tagger());
// Tagger AJAX back-end
class TaggerXML extends Extension {
public function receive_event($event) {
if(is_a($event,'PageRequestEvent')
&& $event->page_name == "tagger"
&& $event->get_arg(0) == "tags")
{
global $page;
//$match_tags = null;
//$image_tags = null;
$tags=null;
if (isset($_GET['s'])) { // tagger/tags[/...]?s=$string
// return matching tags in XML form
$tags = $this->match_tag_list($_GET['s']);
} else if($event->get_arg(1)) { // tagger/tags/$int
// return arg[1] AS image_id's tag list in XML form
$tags = $this->image_tag_list($event->get_arg(1));
}
$xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n".
"<tags xmlns='http://www.w3.org/1999/xhtml'>".
$tags.
"</tags>";
$page->set_mode("data");
$page->set_type("text/xml");
$page->set_data($xml);
}
}
private function match_tag_list ($s) {
global $database, $config, $event;
$values = array();
// Match
$p = strlen($s) == 1? " ":"\_";
$sq = "%".$p.$s."%";
$match = "concat(?,tag) LIKE ?";
array_push($values,$p,$sq);
// Exclude
// $exclude = $event->get_arg(1)? "AND NOT IN ".$this->image_tags($event->get_arg(1)) : null;
// Hidden Tags
$hidden = $config->get_string('ext-tagger_show-hidden','N')=='N' ?
"AND substring(tag,1,1) != '.'" : null;
$q_where = "WHERE {$match} {$hidden} AND count > 0";
// FROM based on return count
$q_from = null;
$count = $this->count($q_where,$values);
if ($count > 60) {
$q_from = "FROM (SELECT * FROM `tags` {$q_where} ".
"ORDER BY count DESC LIMIT 0,30) AS `c_tags`";
$q_where = null;
$count = array("max"=>$count);
} else {
$q_from = "FROM `tags`";
$count = null;
}
$tags = $database->Execute("
SELECT *
{$q_from}
{$q_where}
ORDER BY tag",
$values);
return $this->list_to_xml($tags,"search",$s,$count);
}
private function image_tag_list ($image_id) {
global $database;
$tags = $database->Execute("
SELECT tags.*
FROM image_tags JOIN tags ON image_tags.tag_id = tags.id
WHERE image_id=? ORDER BY tag", array($image_id));
return $this->list_to_xml($tags,"image",$image_id);
}
private function list_to_xml ($tags,$type,$query,$misc=null) {
$r = $tags->_numOfRows;
$s_misc = "";
if(!is_null($misc))
foreach($misc as $attr => $val) $s_misc .= " ".$attr."=\"".$val."\"";
$result = "<list id=\"$type\" query=\"$query\" rows=\"$r\"{$s_misc}>";
foreach($tags as $tag) {
$result .= $this->tag_to_xml($tag);
}
return $result."</list>";
}
private function tag_to_xml ($tag) {
return
"<tag ".
"id=\"".$tag['id']."\" ".
"count=\"".$tag['count']."\">".
html_escape($tag['tag']).
"</tag>";
}
private function count($query,$values) {
global $database;
return $database->Execute(
"SELECT COUNT(*) FROM `tags` $query",$values)->fields['COUNT(*)'];
}
private function image_tags ($image_id) {
global $database;
$list = "(";
$i_tags = $database->Execute(
"SELECT tag_id FROM `image_tags` WHERE image_id=?",
array($image_id));
$b = false;
foreach($i_tags as $tag) {
if($b)
$list .= ",";
$b = true;
$list .= $tag['tag_id'];
}
$list .= ")";
return $list;
}
} add_event_listener( new taggerXML(),10);
?> ?>

View file

@ -1,210 +1,205 @@
// Tagger - Advanced Tagging
// Author: Artanis (Erik Youngren <artanis.00@gmail.com>)
// Do not remove this notice.
// All other code copyright by their authors, see comments for details.
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Tagger Management * * Tagger - Advanced Tagging v2 *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ * Author: Artanis (Erik Youngren <artanis.00@gmail.com>) *
// Global settings and oft-used objects * Do not remove this notice. *
var remove_tagme = null;
var tags_field = false;
var set_button = false;
// Put everything in a class? better?
function taggerInit() {
// get imgdata hooks
tags_field = getTagsField();
set_button = getSetButton();
// Set up Tagger
// Get last position
c = getCookie('shimmie-tagger-position');
c = c ? c.replace(/px/g,"").split(" ") : new Array(null,null);
taggerResetPos(c[0],c[1]);
tagger_tagIndicators();
DragHandler.attach(byId("tagger_titlebar"));
remove_tagme = byId('tagme');
// save position cookie on unload.
window.onunload = function(e) {
taggerSavePosition();
};
}
function taggerResetPos(x,y) {
tagger = byId("tagger_window");
var pos = new Array();
if(!x || !y) {
tagger.style.top="";
tagger.style.left="";
tagger.style.right="25px";
tagger.style.bottom="25px";
// get location in (left,top) terms
pos = findPos(tagger);
} else {
pos[0] = x;
pos[1] = y;
}
tagger.style.top = pos[1]+"px";
tagger.style.left = pos[0]+"px";
tagger.style.right="";
tagger.style.bottom="";
}
function taggerSavePosition() {
tw = byId('tagger_window');
if (tw) {
xy = tw.style.left +" "+ tw.style.top
setCookie('shimmie-tagger-position',xy);
return true;
}
return false;
}
function tagger_tagIndicators() {
arObjTags = getElementsByTagNames('a',byId('tagger_body'));
for (i in arObjTags) {
objTag = arObjTags[i];
if(tagExists(objTag)) {
objTag.style.fontWeight="bold";
}
}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Tagging *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
function toggleTag(objTag) { /* Tagger Window Object
if(!tagExists(objTag)) { * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
addTag(objTag); function Tagger() {
if (remove_tagme && objTag.getAttribute('tag') != 'tagme') { // components
remTag(remove_tagme); this.t_parent = null;
} this.t_title = null;
} else { this.t_toolbar = null;
remTag(objTag); this.t_menu = null;
this.t_body = null;
this.t_tags = null;
this.t_form = null;
this.t_status = null;
// data
this.searchTags = null;
this.appliedTags = null;
// methods
this.initialize = initialize;
this.submit = submit;
this.tagSearch = tagSearch;
this.searchRequest = searchRequest;
this.searchReceive = searchReceive;
this.tagListReceive = tagListReceive;
this.tagPublish = tagPublish;
this.prepTags = prepTags;
this.createTag = createTag;
this.buildPages = buildPages;
this.tagsToString = tagsToString;
this.toggleTag = toggleTag;
this.setAlert = setAlert;
// definitions
function initialize () {
// components
this.t_parent = document.getElementById("tagger_parent");
this.t_title = document.getElementById("tagger_titlebar");
this.t_toolbar = document.getElementById("tagger_toolbar");
this.t_menu = document.getElementById("tagger_p-menu");
this.t_body = document.getElementById("tagger_body");
this.t_tags = document.getElementById("tagger_tags");
this.t_form = this.t_tags.parentNode;
this.t_status = document.getElementById("tagger_statusbar");
//pages
//this.buildPages();
// initial data
ajaxXML(query+"/"+image_id,tagListReceive);
// reveal
this.t_parent.style.display = "";
} }
t = byId("tagger_new-tag"); function submit() {
if(t.value) { t.select(); } this.t_tags.value = Tagger.tagsToString(Tagger.appliedTags);
}
function addTag (objTag) {
delim = tags_field.value==" "?"":" ";
tags_field.value += delim + objTag.getAttribute('tag');
if(objTag.value != 'Add') {
objTag.style.fontWeight = "bold";
} }
} function tagSearch(s,ms) {
clearTimeout(tagger_filter_timer);
tagger_filter_timer = setTimeout("Tagger.searchRequest('"+s+"')",ms);
}
function searchRequest(s) {
var s_query = !s? query+"?s" : query+"?s="+sqlescape(s);
function remTag (objTag) { if(!this.searchTags) {
aTags = tags_field.value.split(" "); ajaxXML(s_query,searchReceive);
return true;
} else {
var prv_s = this.searchTags.getAttribute('query');
tags_field.value=""; if(s==prv_s) {
for(i in aTags) { return false;
aTag = aTags[i]; }else if(!s || s.length <= 2 || s.length<prv_s.length ||
if(aTag != objTag.getAttribute('tag')) { this.searchTags.getAttribute("max"))
if(tags_field.value=="") { {
tags_field.value += aTag; ajaxXML(s_query,searchReceive);
} else { return true;
tags_field.value += " "+aTag;
} else if(s.length > 2 && s.match(reescape(prv_s))) {
var len = this.searchTags.childNodes.length;
for (var i=len-1; i>=0; i--) {
var tag = this.searchTags.childNodes[i];
var t_name = tag.firstChild.data;
if(!t_name.match(reescape(s))) {
this.searchTags.removeChild(tag);
// TODO: Fix so back searches are not needlessly re-queried.
//tag.setAttribute("style","display:none;");
} else {
//tag.setAttribute("style","");
}
}
if (len != this.searchTags.childNodes.length) {
this.searchTags.setAttribute('query',s);
}
} }
} }
return false;
} }
if(objTag.value != 'Add') { function searchReceive(xml) {
objTag.style.fontWeight = ""; Tagger.searchTags = document.importNode(xml.getElementsByTagName("list")[0],true);
} tagPublish(Tagger.searchTags,document.getElementById("tagger_p-search"));
}
function tagExists(objTag) { if(Tagger.searchTags.getAttribute("max")) {
return tags_field.value.match(reescape(objTag.getAttribute('tag'))); Tagger.setAlert("maxout","Limited to "+Tagger.searchTags.getAttribute("rows")+" of "+Tagger.searchTags.getAttribute("max")+" tags");
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Filtering *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
function tagger_filter() {
var filter = byId('tagger_new-tag');
var arObjTags = getElementsByTagNames('a',byId('tagger_body'));
var prepend = filter.value.length<2? " ":"_";
var search = prepend + reescape(filter.value);
for(i in arObjTags) {
objTag = arObjTags[i];
tag = prepend + objTag.getAttribute('tag');
if(tag.match(search) && taggerFilterMode(objTag)) {
objTag.style.display='';
} else { } else {
objTag.style.display='none'; Tagger.setAlert("maxout",false);
}
}
function tagListReceive(xml) {
Tagger.appliedTags = document.importNode(xml.getElementsByTagName("list")[0],true);
tagPublish(Tagger.appliedTags,document.getElementById("tagger_p-applied"));
}
function tagPublish(tag_list,page) {
page.innerHTML = "";
Tagger.prepTags(tag_list);
page.appendChild(tag_list);
}
function prepTags(tag_list) {
var len = tag_list.childNodes.length;
for(var i=0; i<len;i++) {
var tag = tag_list.childNodes[i];
tag.onclick = function() { toggleTag(this); document.getElementById("tagger_filter").select(); };
tag.style.display="block";
tag.setAttribute("title",tag.getAttribute("count")+" uses");
}
}
function createTag(tag_name) {
if (tag_name.length>0) {
var tag = document.createElement("tag");
tag.setAttribute("count","0");
tag.setAttribute("id","newTag_"+tag_name);
tag.onclick = function() { toggleTag(this); };
tag.appendChild(document.createTextNode(tag_name));
Tagger.appliedTags.appendChild(tag);
}
}
function buildPages () {
var pages = getElementsByTagNames("div",document.getElementById("tagger_body"));
var len = pages.length;
for(var i=0; i<len; i++) {
this.t_menu.innerHTML += "<li onclick='Tagger.togglePages("+
"\""+pages[i].getAttribute("id")+"\")'>"+
pages[i].getAttribute('name')+"</li>";
}
}
function tagsToString(tags) {
var len = tags.childNodes.length;
var str = "";
for (var i=0; i<len; i++) {
str += tags.childNodes[i].firstChild.data+" ";
}
return str;
}
function toggleTag(tag) {
if(tag.parentNode == Tagger.appliedTags) {
Tagger.appliedTags.removeChild(tag);
} else {
Tagger.appliedTags.appendChild(tag);
}
}
function setAlert(type,arg) {
var alert = document.getElementById("tagger_alert_"+type);
if (alert) {
if (arg==false) {
//remove existing
alert.parentNode.removeChild(alert);
return;
}
//update prior
alert.innerHTML = arg;
} else if (arg!=false) {
//create
var status = document.createElement("div");
status.setAttribute("id","tagger_alert_"+type);
status.innerHTML = arg;
Tagger.t_status.appendChild(status);
} }
} }
} }
function taggerToggleMode() {
var obj = byId('tagger_mode');
if(obj.getAttribute('mode')=='all') { /* AJAX
obj.setAttribute('mode', 'applied'); * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
obj.innerHTML = 'View All Tags'; function ajaxXML(url, callback) {
} else { //var http = getHTTPObject();
obj.setAttribute('mode','all'); var http = (new XMLHttpRequest() || new ActiveXObject("Microsoft.XMLHTTP"));
obj.innerHTML = 'View Applied Tags'; http.open("GET", url, true);
} http.onreadystatechange = function() {
tagger_filter(true); if(http.readyState == 4) callback(http.responseXML);
}
function taggerFilterMode(objTag) {
var obj = byId('tagger_mode');
if(obj.getAttribute('mode') == 'all') {
return true;
} else {
return objTag.style.fontWeight=='bold';
} }
http.send(null);
} }
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ /* Miscellaneous Code
* Misc * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
function getTagsField() { // Quirksmode
var nodes = getElementsByTagNames('input,textarea',byId('imgdata')); // http://www.quirksmode.org/dom/getElementsByTagNames.htmlgetElementdocument.getElementById
for (i in nodes) {
node = nodes[i];
if (node.getAttribute('name') == 'tags')
return node;
}
return false;
}
function pushSet(form_id) {
if(set_button) {
set_button.click();
}
}
function getSetButton() {
var form_nodes = getElementsByTagNames('input',byId('imgdata'));
for (i in form_nodes) {
node = form_nodes[i];
if (node.getAttribute('value')=="Set" && node.getAttribute('type')=="submit") {
return node;
}
}
return false;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* quirksmode.org *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// http://www.quirksmode.org/dom/getElementsByTagNames.html
function getElementsByTagNames(list,obj) { function getElementsByTagNames(list,obj) {
if (!obj) var obj = document; if (!obj) var obj = document;
var tagNames = list.split(','); var tagNames = list.split(',');
@ -229,7 +224,6 @@ function getElementsByTagNames(list,obj) {
} }
return resultArray; return resultArray;
} }
// http://www.quirksmode.org/js/findpos.html // http://www.quirksmode.org/js/findpos.html
function findPos(obj) { function findPos(obj) {
var curleft = curtop = 0; var curleft = curtop = 0;
@ -264,3 +258,23 @@ function reescape(str){
} }
return ret return ret
} }
// Modified from above
function sqlescape(str){
var resp="#%&_"
var found=false
var ret=""
for(var i=0;i<str.length;i++) {
found=false
for(var j=0;j<resp.length;j++) {
if(str.charAt(i)==resp.charAt(j)) {
found=true;break
}
}
if(found) {
ret+="\\"
}
ret+=str.charAt(i)
}
return ret
}

View file

@ -1,5 +1,5 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tagger - Advanced Tagging * * Tagger - Advanced Tagging v2 *
* Author: Artanis (Erik Youngren <artanis.00@gmail.com>) * * Author: Artanis (Erik Youngren <artanis.00@gmail.com>) *
* Do not remove this notice. * * Do not remove this notice. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@ -8,65 +8,83 @@
text-align:left; text-align:left;
} }
#tagger_window { #tagger_parent {
position:fixed; position:fixed;
text-align:left; top:25px;
min-width:250px; right:25px;
max-width:300px;
}
#tagger_parent * {
background-color:#EEE;
} }
#tagger_titlebar { #tagger_titlebar {
background-color:#DDDDDD; background-color:#ddd;
background-image:none;
border:2px solid; border:2px solid;
cursor:move; cursor:move;
font-weight:bold; font-weight:bold;
/*margin-bottom:.5em;*/ -moz-border-radius:5px 5px 0 0;
-moz-border-radius:2em 2em 0 0;
padding:.25em; padding:.25em;
position:relative;
text-align:center; text-align:center;
top:-0em;
} }
#tagger_toolbar, #tagger_body {
padding:.25em;
border-style:solid;
border-width: 0px 2px 0px 2px;
}
#tagger_body { #tagger_body {
background-color:#EEEEEE; max-height:250px;
border:2px solid; overflow:auto;
border-top:none; overflow-x:hidden;
overflow:scroll; overflow-y:auto;
padding:1em;
max-height:200px;
} }
#tagger_filter {
background-color:#EEEEEE; #tagger_statusbar {
background-color:#ddd;
border:2px solid; border:2px solid;
border-bottom:none; font-weight: bold;
border-top:none; -moz-border-radius:0 0 5px 5px;
margin-bottom:-1px; padding:.25em;
/*-moz-border-radius:1em 1em 0 0;*/ } #tagger_statusbar * { background-color:#ddd; }
padding:1em;
padding-bottom:1px; #tagger_body div {
text-align:center; padding-bottom:.125em;
margin-bottom:.125em;
border-top:1px solid;
} }
#tagger_filter input {
/* Tagger Styling
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#Tagger form {
display:inline;
}
#Tagger input {
width:auto; width:auto;
} }
#Tagger input[type=text] {
background-color:white;
}
#tagger_body a { /* Custom Element Base Styles
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
list {
display:inherit;
}
tag {
font-size:1.25em; font-size:1.25em;
display:block; display:block;
}
tag:hover {
cursor:pointer; cursor:pointer;
font-weight: bold;
background-color:#ddd;
} }
list[id=image] tag:hover {
#Use #Tagger {
-moz-column-gap:20px;
-moz-column-count:3;
} }
list[id=search] tag:hover {
#Use #Tagger li {
margin-bottom:1em;
max-width:30em;
}
#Tagger .tagger_js {
cursor:pointer;
} }

View file

@ -1,198 +1,64 @@
<?php <?php
// Tagger - Advanced Tagging /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// Author: Artanis (Erik Youngren <artanis.00@gmail.com>) * Tagger - Advanced Tagging v2 *
// Do not remove this notice. * Author: Artanis (Erik Youngren <artanis.00@gmail.com>) *
* Do not remove this notice. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
class taggerTheme extends Themelet { class taggerTheme extends Themelet {
public function build_tagger ($page, $event) {
// Initialization code
// TODO: AJAX test and fallback.
$page->add_block(new Block(null,
"<script type='text/javascript'>
var query = '".make_link("tagger/tags")."';
var image_id = ".$event->get_image()->id.";
var tagger_filter_timer = null;
var Tagger = new Tagger();
Tagger.initialize();
</script>","main",1000));
public function build($event,$tags) { // Tagger block
// When overriding this function, take care that all tag attributes are
// maintained UNCHANGED. There are no attributes in the HTML code below
// that go unused by the javascript. If you fail to do this,
// the extension will BREAK!
//
// Now that that's sunk in, chaniging title attributes is fine.
global $config;
global $page;
// set up data
$base_href = $config->get_string('base_href');
$tagme = $config->get_string(
'ext-tagger_clear-tagme','N')=="Y"?
"<input type='hidden' id='tagme' tag='tagme'></input>":
null;
$url_about = make_link("about/tagger");
// build floater tags
$h_tags = "";
foreach($tags as $tag) {
$h_tags .= $this->tag_to_html($tag);
}
$html = "
<div style='font-size:0.7em;'>
Collapse this block to hide Tagger
</div>
<a href='$url_about'>About Tagger</a>
<hr/>
<button onclick='taggerResetPos();' class='tagger_js'>Default Location</button>".
// Tagger Floater
"<div id='tagger_window'>
<div id='tagger_titlebar' title='Drag to move'>Tagger</div>
<div id='tagger_filter'>
<input type='text' id='tagger_new-tag' value='' size='12'
onfocus='this.select();' onkeyup='tagger_filter();'
focus='' title='Type to search' >
</input>
<input type='button' value='Add' tag='' title='Add typed tag'
onclick='
this.attributes.tag.value=
byId(\"tagger_new-tag\").value;
toggleTag(this);'>
</input>
<input type='button' value='Set' onclick='pushSet();'
title='Save tags'></input>
$tagme
<hr/>
<a id='tagger_mode' class='tagger_js' mode='all'
onclick='taggerToggleMode()'>View Applied Tags</a> |
<a onclick='tagger_tagIndicators(); tagger_filter(true);'
class='tagger_js' >Refresh Filter</a>
</div>
<div id='tagger_body'>$h_tags</div>
<img src='$base_href/ext/tagger/onload.gif' style='display:none;'
onload='taggerInit();' />
</div>";
$page->add_block( new Block( $page->add_block( new Block(
"Tagger", "Tagger",
$html, $this->html($event->get_image()),
"left")); "main"));
$page->add_header(
"<script
src='$base_href/ext/tagger/webtoolkit.drag.js'
type='text/javascript'></script>");
} }
private function html($image) {
$i_image_id = int_escape($image->id);
$h_source = html_escape($image->source);
if(isset($_GET['search'])) {$h_query = "search=".url_escape($_GET['search']);}
else {$h_query = "";}
$url_form = make_link("tag_edit/set");
final public function show_about ($event) { $html = <<< EOD
// The about page for Tagger. No override. Feel free to CSS it, though. <div id="tagger_parent" style="display:none;">
global $page; <div id="tagger_titlebar">Tagger</div>
global $config;
$base_href = $config->get_string('base_href');
$script1 = "$base_href/ext/tagger/script.js"; <div id="tagger_toolbar">
$script2 = "$base_href/ext/tagger/webtoolkit.drag.js"; <input type="text" value="" id="tagger_filter" onkeyup="Tagger.tagSearch(this.value, 500);"></input>
<input type="button" value="Add" onclick="Tagger.createTag(byId('tagger_filter').value);"></input>
<form action="$url_form" method="POST" onsubmit="Tagger.submit();">
<input type='hidden' name='image_id' value='$i_image_id' id="image_id"></input>
<input type='hidden' name='query' value='$h_query'></input>
<input type='hidden' name='source' value='$h_source'></input>
<input type="hidden" name="tags" value="" id="tagger_tags"></input>
$html = str_replace("\"","&quot;",str_replace("\'","&#39;"," <input type="submit" value="Set"></input>
<ul id='Tagger'> </form>
<li> <!--<ul id="tagger_p-menu"></ul>
If Tagger is in your way, click and drag it\'s title bar to move <br style="clear:both;"/>-->
it to a more convienient location. </div>
<li>
Click the links to add the tag to the image\'s tag list, when
done, press the Set button to save the tags.
</li>
<li>
<p>Tagger gets all the tags with 2 or more uses, so the list can
get quite large. If you are having trouble finding the tag you
are looking for, you can enter it into the box at the top and as
you type, Tagger will remove tags that do not match to aid your
search. Usually, you\'ll only need one or two letters to trim
the list down to the tag you are looking for.
</p>
<p>One letter filters will look only at the first letter of the
tag. Two or more letters will search the beginning of every
word in every tag.
</p>
<p>If the tag is not in the list, finish typing out the tag and
click \"Add\" to add the tag to the image\'s tag list.
</p>
<p>Tags must have two uses to appear in Tagger\'s list, so
you'll have to enter the tag for at least one other image for it
to show up.
</p>
</li>
<li><h4>Requirements</h4>
<p>Tagger requires javascript for its functionality. Sorry, but
there\'s no other way to accomplish the tag list
modifications.
</p>
<p>If you have javascript completely disabled, you will not be
able to use Tagger.
</p>
<p>Depending on your method of disabling javascript, you may be
able to whitelist scripts. The script files used by Tagger are
<a href='$script1'>script.js</a> and
<a href='$script2'>webtoolkit.drag.js</a>.
</p>
</li>
</ul>"));
$page->set_title("Shimmie - About / Tagger - Advanced Tagging");
$page->set_heading("About / Tagger - Advanced Tagging");
$page->add_block( new Block("Author",
"Artanis (Erik Youngren &lt;artanis.00@gmail.com&gt;)","main",0));
$page->add_block( new Block("Use", $html,"main",1));
}
function configTagger($page/*,$presets*/) {
$presets = array(
'test_set_01' => 'tag set 01',
'test_set_02' => 'tag set 02',
'tsuryuya' => 'tsuryuya hair_green eyes_yellow suzumiya_haruhi_no_yuutsu',
'suzumiya_haruhi' => 'suzumiya_haruhi hair_brown eyes_brown suzumiya_haruhi_no_yuutsu');
$html="<table>";
$html .= "<tr><th>Set Name</th><th>Tags</th></tr>";
foreach($presets as $keyname => $tags) {
$html .= "<tr><td>$keyname</td><td>$tags</td></tr>";
}
$html .= "</table>";
$page->set_title("Shimmie / Configure / Tagger");
$page->set_heading("Configure / Tagger");
$page->add_block( new Block("Tag Presets",$html,'main',0));
}
final function tag_to_html ($tag) {
// Important for script.js, no override. You can CSS this, though.
// If you must, remove the 'final' keyword, but MAKE SURE the entire <A>
// tag is COPIED TO THE NEW FUNCTION EXACTLY! If you fail to do this,
// the extension will BREAK!
$tag_name = $tag['tag'];
$tag_id = $this->tag_id($tag_name);
$stag = $this->trimTag($tag_name,20,"_");
$html = "
<a id='$tag_id' title='Apply &quot;$tag_name&quot;' tag='$tag_name'
onclick='toggleTag(this)'>$stag</a>";
<div id="tagger_body">
<div id="tagger_p-applied" name="Applied Tags"></div>
<div id="tagger_p-search" name="Searched Tags"></div>
</div>
<div id="tagger_statusbar"></div>
</div>
EOD;
return $html; return $html;
} }
// Important for script.js, no override.
final function tag_id ($tag) {
$tag_id = "";
$m=null;
for($i=0; $i < strlen($tag); $i++) {
$l = substr($tag,$i,1);
$m=null;
preg_match("[\pP]",$l,$m);
$tag_id .= !isset($m[0]) ? $l:"_";
}
return trim(str_replace("__","_",$tag_id)," _");
}
function trimTag($s,$len=80,$br=" ") {
if(strlen($s) > $len) {
$s = substr($s, 0,$len-1);
$s = substr($s,0, strrpos($s,$br))."...";
}
return $s;
}
} }
?> ?>