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:
parent
bcb5eecc56
commit
5d273e6879
4 changed files with 452 additions and 492 deletions
|
@ -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(isset($_GET['debug'])) add_event_listener( new tagger());
|
||||||
|
|
||||||
if ($config->get_string("ext-tagger_show-hidden") == -1)
|
// Tagger AJAX back-end
|
||||||
$config->set_bool("ext-tagger_show-hidden",false);
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_a($event,"DisplayingImageEvent")) {
|
$xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n".
|
||||||
//show tagger box
|
"<tags xmlns='http://www.w3.org/1999/xhtml'>".
|
||||||
global $database;
|
$tags.
|
||||||
global $page;
|
"</tags>";
|
||||||
global $config;
|
|
||||||
|
|
||||||
$base_href = $config->get_string('base_href');
|
$page->set_mode("data");
|
||||||
$tags_min = (isset($_GET['tagger_min']) && $_GET['tagger_min']>0)?$_GET['tagger_min']:$config->get_int('ext-tagger_tags-min',2);
|
$page->set_type("text/xml");
|
||||||
$hidden = $config->get_string(
|
$page->set_data($xml);
|
||||||
'ext-tagger_show-hidden','N')=='N' ?
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
"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("
|
$tags = $database->Execute("
|
||||||
SELECT tag
|
SELECT *
|
||||||
FROM `tags`
|
{$q_from}
|
||||||
WHERE count>=?{$hidden}
|
{$q_where}
|
||||||
ORDER BY tag",array($tags_min));
|
ORDER BY tag",
|
||||||
|
$values);
|
||||||
|
|
||||||
$this->theme->build($page, $tags);
|
return $this->list_to_xml($tags,"search",$s,$count);
|
||||||
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")) {
|
private function image_tag_list ($image_id) {
|
||||||
if($event->page_name == "about" && $event->get_arg(0) == "tagger") {
|
global $database;
|
||||||
global $page;
|
$tags = $database->Execute("
|
||||||
$this->theme->show_about($page);
|
SELECT tags.*
|
||||||
}
|
FROM image_tags JOIN tags ON image_tags.tag_id = tags.id
|
||||||
if($event->page_name == "tagger") {
|
WHERE image_id=? ORDER BY tag", array($image_id));
|
||||||
global $page;
|
return $this->list_to_xml($tags,"image",$image_id);
|
||||||
// $this->theme->configTagger($page);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_a($event, 'UserBlockBuildingEvent')) {
|
private function list_to_xml ($tags,$type,$query,$misc=null) {
|
||||||
if($event->user->is_admin()) {
|
$r = $tags->_numOfRows;
|
||||||
// $event->add_link("Tagger Config", make_link("tagger"));
|
|
||||||
|
$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>";
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_a($event, 'SetupBuildingEvent')) {
|
private function tag_to_xml ($tag) {
|
||||||
$sb = new SetupBlock("Tagger - Power Tagging");
|
return
|
||||||
$sb->add_bool_option("ext-tagger_show-hidden", "Show Hidden Tags");
|
"<tag ".
|
||||||
$sb->add_bool_option(
|
"id=\"".$tag['id']."\" ".
|
||||||
"ext-tagger_clear-tagme",
|
"count=\"".$tag['count']."\">".
|
||||||
"<br/>Remove '<a href='".make_link("post/list/tagme/1")."'>tagme</a>' on use");
|
html_escape($tag['tag']).
|
||||||
$sb->add_int_option(
|
"</tag>";
|
||||||
"ext-tagger_tags-min",
|
|
||||||
"<br/>Ignore tags used fewer than "); $sb->add_label("times.");
|
|
||||||
$event->panel->add_block($sb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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'];
|
||||||
|
|
||||||
}
|
}
|
||||||
add_event_listener( new tagger());
|
$list .= ")";
|
||||||
|
|
||||||
|
return $list;
|
||||||
|
}
|
||||||
|
} add_event_listener( new taggerXML(),10);
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -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
|
||||||
|
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;
|
||||||
|
|
||||||
function addTag (objTag) {
|
// definitions
|
||||||
delim = tags_field.value==" "?"":" ";
|
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);
|
||||||
|
|
||||||
tags_field.value += delim + objTag.getAttribute('tag');
|
if(!this.searchTags) {
|
||||||
|
ajaxXML(s_query,searchReceive);
|
||||||
if(objTag.value != 'Add') {
|
|
||||||
objTag.style.fontWeight = "bold";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function remTag (objTag) {
|
|
||||||
aTags = tags_field.value.split(" ");
|
|
||||||
|
|
||||||
tags_field.value="";
|
|
||||||
for(i in aTags) {
|
|
||||||
aTag = aTags[i];
|
|
||||||
if(aTag != objTag.getAttribute('tag')) {
|
|
||||||
if(tags_field.value=="") {
|
|
||||||
tags_field.value += aTag;
|
|
||||||
} else {
|
|
||||||
tags_field.value += " "+aTag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(objTag.value != 'Add') {
|
|
||||||
objTag.style.fontWeight = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function tagExists(objTag) {
|
|
||||||
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 {
|
|
||||||
objTag.style.display='none';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function taggerToggleMode() {
|
|
||||||
var obj = byId('tagger_mode');
|
|
||||||
|
|
||||||
if(obj.getAttribute('mode')=='all') {
|
|
||||||
obj.setAttribute('mode', 'applied');
|
|
||||||
obj.innerHTML = 'View All Tags';
|
|
||||||
} else {
|
|
||||||
obj.setAttribute('mode','all');
|
|
||||||
obj.innerHTML = 'View Applied Tags';
|
|
||||||
}
|
|
||||||
tagger_filter(true);
|
|
||||||
}
|
|
||||||
function taggerFilterMode(objTag) {
|
|
||||||
var obj = byId('tagger_mode');
|
|
||||||
if(obj.getAttribute('mode') == 'all') {
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return objTag.style.fontWeight=='bold';
|
var prv_s = this.searchTags.getAttribute('query');
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
|
if(s==prv_s) {
|
||||||
* Misc *
|
|
||||||
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
||||||
|
|
||||||
function getTagsField() {
|
|
||||||
var nodes = getElementsByTagNames('input,textarea',byId('imgdata'));
|
|
||||||
for (i in nodes) {
|
|
||||||
node = nodes[i];
|
|
||||||
if (node.getAttribute('name') == 'tags')
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}else if(!s || s.length <= 2 || s.length<prv_s.length ||
|
||||||
|
this.searchTags.getAttribute("max"))
|
||||||
|
{
|
||||||
|
ajaxXML(s_query,searchReceive);
|
||||||
|
return true;
|
||||||
|
|
||||||
function pushSet(form_id) {
|
} else if(s.length > 2 && s.match(reescape(prv_s))) {
|
||||||
if(set_button) {
|
var len = this.searchTags.childNodes.length;
|
||||||
set_button.click();
|
|
||||||
|
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","");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSetButton() {
|
if (len != this.searchTags.childNodes.length) {
|
||||||
var form_nodes = getElementsByTagNames('input',byId('imgdata'));
|
this.searchTags.setAttribute('query',s);
|
||||||
for (i in form_nodes) {
|
}
|
||||||
node = form_nodes[i];
|
|
||||||
if (node.getAttribute('value')=="Set" && node.getAttribute('type')=="submit") {
|
|
||||||
return node;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
function searchReceive(xml) {
|
||||||
|
Tagger.searchTags = document.importNode(xml.getElementsByTagName("list")[0],true);
|
||||||
|
tagPublish(Tagger.searchTags,document.getElementById("tagger_p-search"));
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
|
if(Tagger.searchTags.getAttribute("max")) {
|
||||||
* quirksmode.org *
|
Tagger.setAlert("maxout","Limited to "+Tagger.searchTags.getAttribute("rows")+" of "+Tagger.searchTags.getAttribute("max")+" tags");
|
||||||
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
} else {
|
||||||
|
Tagger.setAlert("maxout",false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// http://www.quirksmode.org/dom/getElementsByTagNames.html
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* AJAX
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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("\"",""",str_replace("\'","'","
|
<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 <artanis.00@gmail.com>)","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 "$tag_name"' 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
Reference in a new issue