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)
$config->set_bool("ext-tagger_clear-tagme",false);
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'); if($config->get_bool("tag_edit_anon") || ($user->id != $config->get_int("anon_id")))
$tags_min = (isset($_GET['tagger_min']) && $_GET['tagger_min']>0)?$_GET['tagger_min']:$config->get_int('ext-tagger_tags-min',2); $this->theme->build_tagger($page,$event);
$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;
t = byId("tagger_new-tag"); this.t_tags = null;
if(t.value) { t.select(); } this.t_form = null;
} this.t_status = null;
// data
function addTag (objTag) { this.searchTags = null;
delim = tags_field.value==" "?"":" "; this.appliedTags = null;
// methods
tags_field.value += delim + objTag.getAttribute('tag'); 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;
if(objTag.value != 'Add') { // definitions
objTag.style.fontWeight = "bold"; 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 = "";
} }
} function submit() {
this.t_tags.value = Tagger.tagsToString(Tagger.appliedTags);
}
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;
tags_field.value=""; } else {
for(i in aTags) { var prv_s = this.searchTags.getAttribute('query');
aTag = aTags[i];
if(aTag != objTag.getAttribute('tag')) { if(s==prv_s) {
if(tags_field.value=="") { return false;
tags_field.value += aTag; }else if(!s || s.length <= 2 || s.length<prv_s.length ||
} else { this.searchTags.getAttribute("max"))
tags_field.value += " "+aTag; {
ajaxXML(s_query,searchReceive);
return true;
} 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"));
}
if(Tagger.searchTags.getAttribute("max")) {
function tagExists(objTag) { Tagger.setAlert("maxout","Limited to "+Tagger.searchTags.getAttribute("rows")+" of "+Tagger.searchTags.getAttribute("max")+" tags");
return tags_field.value.match(reescape(objTag.getAttribute('tag')));
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* 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 taggerToggleMode() {
var obj = byId('tagger_mode');
if(obj.getAttribute('mode')=='all') { function tagListReceive(xml) {
obj.setAttribute('mode', 'applied'); Tagger.appliedTags = document.importNode(xml.getElementsByTagName("list")[0],true);
obj.innerHTML = 'View All Tags'; tagPublish(Tagger.appliedTags,document.getElementById("tagger_p-applied"));
} else {
obj.setAttribute('mode','all');
obj.innerHTML = 'View Applied Tags';
} }
tagger_filter(true); function tagPublish(tag_list,page) {
} page.innerHTML = "";
function taggerFilterMode(objTag) { Tagger.prepTags(tag_list);
var obj = byId('tagger_mode'); page.appendChild(tag_list);
if(obj.getAttribute('mode') == 'all') {
return true;
} else {
return objTag.style.fontWeight=='bold';
} }
} function prepTags(tag_list) {
var len = tag_list.childNodes.length;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Misc * for(var i=0; i<len;i++) {
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ var tag = tag_list.childNodes[i];
tag.onclick = function() { toggleTag(this); document.getElementById("tagger_filter").select(); };
function getTagsField() { tag.style.display="block";
var nodes = getElementsByTagNames('input,textarea',byId('imgdata')); tag.setAttribute("title",tag.getAttribute("count")+" uses");
for (i in nodes) { }
node = nodes[i]; }
if (node.getAttribute('name') == 'tags') function createTag(tag_name) {
return node; if (tag_name.length>0) {
} var tag = document.createElement("tag");
return false; tag.setAttribute("count","0");
} tag.setAttribute("id","newTag_"+tag_name);
tag.onclick = function() { toggleTag(this); };
function pushSet(form_id) { tag.appendChild(document.createTextNode(tag_name));
if(set_button) { Tagger.appliedTags.appendChild(tag);
set_button.click(); }
} }
} function buildPages () {
var pages = getElementsByTagNames("div",document.getElementById("tagger_body"));
function getSetButton() { var len = pages.length;
var form_nodes = getElementsByTagNames('input',byId('imgdata')); for(var i=0; i<len; i++) {
for (i in form_nodes) { this.t_menu.innerHTML += "<li onclick='Tagger.togglePages("+
node = form_nodes[i]; "\""+pages[i].getAttribute("id")+"\")'>"+
if (node.getAttribute('value')=="Set" && node.getAttribute('type')=="submit") { pages[i].getAttribute('name')+"</li>";
return node; }
}
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);
} }
} }
return false;
} }
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ /* AJAX
* quirksmode.org * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ function ajaxXML(url, callback) {
//var http = getHTTPObject();
var http = (new XMLHttpRequest() || new ActiveXObject("Microsoft.XMLHTTP"));
http.open("GET", url, true);
http.onreadystatechange = function() {
if(http.readyState == 4) callback(http.responseXML);
}
http.send(null);
}
// http://www.quirksmode.org/dom/getElementsByTagNames.html /* Miscellaneous Code
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Quirksmode
// http://www.quirksmode.org/dom/getElementsByTagNames.htmlgetElementdocument.getElementById
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) {
public function build($event,$tags) { // Initialization code
// When overriding this function, take care that all tag attributes are // TODO: AJAX test and fallback.
// maintained UNCHANGED. There are no attributes in the HTML code below $page->add_block(new Block(null,
// that go unused by the javascript. If you fail to do this, "<script type='text/javascript'>
// the extension will BREAK! var query = '".make_link("tagger/tags")."';
// var image_id = ".$event->get_image()->id.";
// Now that that's sunk in, chaniging title attributes is fine. var tagger_filter_timer = null;
global $config; var Tagger = new Tagger();
global $page; Tagger.initialize();
</script>","main",1000));
// 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>";
// Tagger block
$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");
$html = <<< EOD
<div id="tagger_parent" style="display:none;">
<div id="tagger_titlebar">Tagger</div>
<div id="tagger_toolbar">
<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>
final public function show_about ($event) { <input type="submit" value="Set"></input>
// The about page for Tagger. No override. Feel free to CSS it, though. </form>
global $page; <!--<ul id="tagger_p-menu"></ul>
global $config; <br style="clear:both;"/>-->
$base_href = $config->get_string('base_href'); </div>
$script1 = "$base_href/ext/tagger/script.js";
$script2 = "$base_href/ext/tagger/webtoolkit.drag.js";
$html = str_replace("\"","&quot;",str_replace("\'","&#39;","
<ul id='Tagger'>
<li>
If Tagger is in your way, click and drag it\'s title bar to move
it to a more convienient location.
<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*/) { <div id="tagger_body">
$presets = array( <div id="tagger_p-applied" name="Applied Tags"></div>
'test_set_01' => 'tag set 01', <div id="tagger_p-search" name="Searched Tags"></div>
'test_set_02' => 'tag set 02', </div>
'tsuryuya' => 'tsuryuya hair_green eyes_yellow suzumiya_haruhi_no_yuutsu', <div id="tagger_statusbar"></div>
'suzumiya_haruhi' => 'suzumiya_haruhi hair_brown eyes_brown suzumiya_haruhi_no_yuutsu'); </div>
EOD;
$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>";
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;
}
} }
?> ?>