// smd_tags by Stef Dawson
// TODO: list tags by linked cat (i.e. a 'where used' for category->Tag relationships)
// TODO: Resolve what happens if an article is assigned some tags and then the category is changed (the tags remain associated, but are hidden)
// TODO: What happens if on an article list page that is not the 'global' smd_tags page? Should we be able to call tag_list?
// ------------------------
// ADMIN SIDE CODE
if (@txpinterface == 'admin') {
add_privs('smd_tags','1,2');
// Extensions tab
register_tab('extensions', 'smd_tags', smd_tags_gTxt('smd_tags'));
register_callback('smd_tags', 'smd_tags');
// Note the callbacks are ordered with 'save' first
register_callback('smd_tags_multi_edit', 'list', 'list_multi_edit');
register_callback('smd_tags_savelist', 'article', 'create');
register_callback('smd_tags_savelist', 'article', 'edit');
register_callback('smd_tags_loadlist', 'article');
register_callback('smd_tags_multi_edit', 'image', 'image_delete');
register_callback('smd_tags_savelist', 'image', 'image_save');
register_callback('smd_tags_loadlist', 'image');
register_callback('smd_tags_multi_edit', 'file', 'file_delete');
register_callback('smd_tags_savelist', 'file', 'file_save');
register_callback('smd_tags_loadlist', 'file');
register_callback('smd_tags_multi_edit', 'link', 'link_multi_edit');
register_callback('smd_tags_savelist', 'link', 'link_post');
register_callback('smd_tags_savelist', 'link', 'link_save');
register_callback('smd_tags_loadlist', 'link');
// Triple array, output in alphabetical order, sequentially numbered
// 0: list of current prefs + default
// 1: list of legacy prefs that may need removing (default should all be empty)
// 2: position that a heading should be inserted + heading itself
global $smd_tag_prefs;
$smd_tag_prefs = array(
array(
'smd_tag_p_enable' => '1111', // one digit for article/image/file/link. 1=enabled; 0=disabled
'smd_tag_p_first' => '0',
'smd_tag_p_input' => '0', // 0=select, 1=textarea, 2=links
'smd_tag_p_linkcat' => '0',
'smd_tag_p_qtag' => '0', // 0=no autocomplete, 1=std a/c, 2=strict a/c
'smd_tag_p_qtpath' => '', // Dir to js file(s) relative to textpattern dir
'smd_tag_p_qtstyl' => '', // Dir to css file(s)
'smd_tag_p_size' => '6',
'smd_tag_t_auto' => '1',
'smd_tag_t_cols' => '1',
'smd_tag_t_colsord' => '0',
'smd_tag_t_count' => '1',
'smd_tag_t_deltree' => '0',
'smd_tag_t_delused' => '0',
'smd_tag_t_hilite' => 'ffa',
'smd_tag_t_hover' => 'ffc',
'smd_tag_t_indent' => '—',
'smd_tag_u_pnam' => 'smd_tag',
'smd_tag_u_ptyp' => 'smd_tagtype',
'smd_tag_u_sec' => 'smd_tags',
),
array(
'smd_tag_to_remove' => '',
'smd_tag_p_oride' => '',
),
array(
1 => smd_tags_gTxt('prefs_p'),
9 => smd_tags_gTxt('prefs_t'),
18 => smd_tags_gTxt('prefs_u'),
)
);
}
if (!defined('SMD_TAG')) {
define("SMD_TAG", safe_pfx('smd_tags'));
}
if (!defined('SMD_TAGC')) {
define("SMD_TAGC", safe_pfx('smd_tags_cat'));
}
if (!defined('SMD_TAGU')) {
define("SMD_TAGU", safe_pfx('smd_tags_used'));
}
register_callback('smd_tags_url_handler', 'pretext');
// ------------------------
function smd_tags($event, $step) {
global $smd_tag_prefs;
if(!$step or !in_array($step, array(
'smd_tag_create',
'smd_tag_delete',
'smd_tag_catlist',
'smd_tag_parentlist',
'smd_tag_save',
'smd_tags_manage',
'smd_tags_table_install',
'smd_tags_table_remove',
'smd_tags_prefs_display',
'smd_tags_prefs_install',
'smd_tags_prefs_remove',
'smd_tags_prefs_update',
))) {
$pref = smd_tags_pref_get('smd_tag_p_first');
if ($pref) {
switch ($pref['smd_tag_p_first']['val']) {
case 1:
smd_tags_manage('');
break;
case 0:
default:
smd_tags_prefs_show('');
}
} else {
smd_tags_prefs_show('');
}
} else $step();
}
// ------------------------
// Create dropdown and populate it with tags of the relevant type
function smd_multiTreeSelectInput($select_name = '', $tree = '', $tags = '') {
$pref = smd_tags_pref_get('smd_tag_p_size', 1);
$out[] = '';
return join('',$out);
}
// ------------------------
// Called whenever one of the 4 main tabs are used on the admin side. Inserts the input method if required
function smd_tags_loadlist($event, $step) {
if (smd_tags_table_exist()) {
$ctrls = smd_tags_pref_get(array('smd_tag_p_enable', 'smd_tag_p_input', 'smd_tag_p_size', 'smd_tag_p_qtag', 'smd_tag_p_qtpath', 'smd_tag_p_qtstyl', 'smd_tag_p_linkcat'), 1);
$onoff = smd_tags_pref_explode($ctrls['smd_tag_p_enable']['val']);
$iptyp = $ctrls['smd_tag_p_input']['val'];
$selsz = $ctrls['smd_tag_p_size']['val'];
$quick = $ctrls['smd_tag_p_qtag']['val'];
$jsdir = $ctrls['smd_tag_p_qtpath']['val'];
$csdir = $ctrls['smd_tag_p_qtstyl']['val'];
$clink = $ctrls['smd_tag_p_linkcat']['val'];
$jstail = ($jsdir) ? '/' : '';
$cstail = ($csdir) ? '/' : '';
$addIt = false;
$itemID = smd_getID();
$edtBtn = ' ['.eLink('smd_tags', 'smd_tags_manage', 'smd_tag_type', $event, gTxt('edit')).'] ';
$tagtop = '
'.smd_tags_gTxt('title').$edtBtn.'
';
$selist = '';
$selhid = '';
switch ($iptyp) {
case 0:
$ipmeth = $selist;
break;
case 1:
$ipmeth = ''.$selhid;
break;
case 2:
$ipmeth = ''.$selhid;
break;
}
switch ($event) {
case "article":
$addIt = ($onoff[gTxt('tab_list')] == 1) ? true : false;
if ($addIt) {
extract(gpsa(array('view','from_view')));
$view = ($view) ? $view : "text";
$grabcats = 'jQuery("#category-1 option:selected, #category-2 option:selected")';
$jsElem = 'jQuery("#category-2")';
$trigger = 'jQuery("#category-1, #category-2")';
if ($view != 'text') {
$tagtop = $ipmeth = '';
}
}
break;
case "image":
if ($step == "image_edit") {
$addIt = ($onoff[gTxt('tab_image')] == 1) ? true : false;
if ($addIt) {
$grabcats = 'jQuery("#image-category option:selected")';
$jsElem = $trigger = "jQuery('#image-category')";
}
}
break;
case "file":
if ($step == "file_edit") {
$addIt = ($onoff[gTxt('tab_file')] == 1) ? true : false;
if ($addIt) {
$grabcats = 'jQuery("select[@name=\'category\'] option:selected")';
$jsElem = $trigger = 'jQuery("select[@name=\'category\']")';
}
}
break;
case "link":
$addIt = ($onoff[gTxt('tab_link')] == 1) ? true : false;
if ($addIt) {
$tagtop = '';
$ipmeth = tr(fLabelCell(smd_tags_gTxt('title'), '', 'smd_tags') . tda($edtBtn.br.$ipmeth));
$grabcats = 'jQuery("#link-category option:selected")';
$jsElem = $trigger = "jQuery('#link-category').parent()";
}
break;
}
// Add the dropdown and js toggle/clear options if required
if ($addIt) {
$qs = array(
"event" => "smd_tags",
);
$qsVars = "index.php".join_qs($qs);
if ($quick > 0) {
echo <<
EOJS;
}
echo <<
jQuery(function() {
{$jsElem}.parent().after('{$tagtop}{$ipmeth}');
function smd_tagList(typ) {
var grabcats = [];
{$grabcats}.each(function() {
grabcats.push(jQuery(this).val());
});
grabcats = grabcats.join(",");
jQuery.post('{$qsVars}', { step: "smd_tag_parentlist", name: 'smd_tag_parent', type: typ, cat: grabcats, itemid: "{$itemID}" },
function(data) {
jQuery("#smd_tags").html(data);
jQuery("#smd_tags_bylink").empty();
var smd_tagpool = [];
var smd_tagsel = [];
var smd_taglinks = [];
jQuery('#smd_tags select option').each(function() {
var curr = jQuery(this);
var txt = jQuery.trim(curr.text());
smd_tagpool.push(txt);
if (jQuery("#smd_tags_bylink").text() != "") {
jQuery("#smd_tags_bylink").append(" · ");
}
if (curr.attr("selected") == true) {
smd_tagsel.push(txt);
jQuery("#smd_tags_bylink").append(''+txt+'');
} else {
jQuery("#smd_tags_bylink").append(''+txt+'');
}
});
jQuery("#smd_tags_bylink span").click(function() {
jQuery(this).toggleClass("smd_sel");
var ltxt = jQuery(this).text();
jQuery("#smd_tags select option").each(function() {
var curr = jQuery(this);
if (jQuery.trim(curr.text()) == ltxt) {
this.selected = !this.selected;
}
});
});
jQuery("textarea[@name='smd_tags_bytext']").val(smd_tagsel.join(", "));
if ({$quick} > 0) {
jQuery("textarea[@name='smd_tags_bytext']").autocomplete(smd_tagpool, {
multiple: true,
mustMatch: (($quick==2)?true:false),
autoFill: true
});
}
jQuery("textarea[@name='smd_tags_bytext']").keyup(function() {
smd_tagsResyncSelect({$quick});
});
jQuery('#smd_clr').click(function() {
jQuery('#smd_tags select option').attr("selected", "");
});
jQuery('#smd_tog').click(function() {
jQuery('#smd_tags select option').each(function() {
this.selected = !this.selected;
});
});
}
);
}
smd_tagList('{$event}');
if ({$clink}) {
{$trigger}.change(function() {
smd_tagList('{$event}');
});
}
function smd_tagsResyncSelect(lvl) {
var tbTags = jQuery("textarea[@name='smd_tags_bytext']").val().split(/,\s+?/);
jQuery("#smd_tags select option").each(function() {
var curr = jQuery(this);
if(jQuery.inArray(jQuery.trim(curr.text()), tbTags) == -1) {
curr.attr("selected", "");
} else {
curr.attr("selected", true);
}
});
}
});
EOJS;
}
}
}
// ------------------------
// Update the tags used table if some tags have been added/saved
function smd_tags_savelist($event, $step) {
if (smd_tags_table_exist()) {
$ctrls = smd_tags_pref_get(array('smd_tag_p_qtag'), 1);
$quick = $ctrls['smd_tag_p_qtag']['val'];
$itemID = smd_getID();
if ($itemID) {
$saveSteps = array('image_save','file_save','link_save','link_post');
if (ps('save') || in_array($step, $saveSteps))
safe_delete(SMD_TAGU, 'item_id="'.$itemID.'" AND type="'.$event.'"');
$tags = ps('smd_tag_parent');
$tagsText = preg_split("/,\s+?/", ps('smd_tags_bytext'));
if ($tags) {
$vals = array();
foreach($tags as $val){
safe_insert(SMD_TAGU, 'tag_id = "'.$val.'", item_id="'.$itemID.'", type="'.$event.'"');
$vals[] = $val;
}
// If we're in non-STRICT mode and there are any typed tags that are not in the select list, check they exist and add them
if ($quick < 2) {
$added = safe_column("title", SMD_TAG, "id IN ('".join("','",$vals)."') AND type='$event'");
$tagsText = array_diff($tagsText, $added);
foreach($tagsText as $tag) {
if ($tag == "") continue;
$exists = safe_field('id', SMD_TAG, "name = '$tag' AND type = '$event'");
if ($exists) {
safe_insert(SMD_TAGU, 'tag_id = "'.$exists.'", item_id="'.$itemID.'", type="'.$event.'"');
}
}
}
}
}
}
}
// ------------------------
// Handle changes to the tags table during multi-item edits
function smd_tags_multi_edit($event, $step) {
// In TXP 4.0.6 the only tabs to allow multi-edits are the Article (list) and Link tabs. Cheat for now
if (smd_tags_table_exist()) {
switch ($event) {
case "list":
case "link":
$method = ps('edit_method');
$selected = ps('selected');
break;
default:
$method = "delete";
$selected = array(ps('id'));
break;
}
// 'list' is a special case that equates to articles
$type = ($event == "list") ? "article" : $event;
if ($selected) {
switch ($method) {
case "delete":
$ids = array();
foreach ($selected as $id) {
$id = assert_int($id);
if (safe_delete(SMD_TAGU, 'item_id = '.$id.' AND type="'.$type.'"')) {
$ids[] = $id;
}
}
return join(', ', $ids);
break;
}
}
return '';
}
}
// ------------------------
// Grab the current article/image/file/link ID
function smd_getID() {
if(!empty($GLOBALS['ID'])) { // newly-saved item
$itemID = intval($GLOBALS['ID']);
} else {
$itemID = (gps('ID')) ? gps('ID') : gps('id');
}
return $itemID;
}
// ------------------------
function smd_tags_table_exist($all='') {
if ($all) {
$tbls = array(SMD_TAG => 7, SMD_TAGC => 2, SMD_TAGU => 3);
$out = count($tbls);
foreach ($tbls as $tbl => $cols) {
if (count(@safe_show('columns', $tbl)) == $cols) {
$out--;
}
}
return ($out==0) ? 1 : 0;
} else {
return(@safe_show('columns', SMD_TAG));
}
}
// ------------------------
// Add tag tables if not already installed
function smd_tags_table_install() {
$version = mysql_get_server_info();
$GLOBALS['txp_err_count'] = 0;
if ($version < "4.1.2") {
$GLOBALS['txp_err_count']++;
trigger_error("smd_tags requires MySQL v4.1.2 or greater.");
} else {
$ret = '';
$sql = array();
$sql[] = "CREATE TABLE IF NOT EXISTS `".SMD_TAG."` (
`id` int(6) NOT NULL auto_increment,
`name` varchar(64) NOT NULL default '',
`type` varchar(64) NOT NULL default '',
`parent` varchar(64) NOT NULL default '',
`lft` int(6) NOT NULL default '0',
`rgt` int(6) NOT NULL default '0',
`title` varchar(255) NOT NULL default '',
PRIMARY KEY (`id`)
) ENGINE=MyISAM PACK_KEYS=1 AUTO_INCREMENT=5 ";
if (!smd_tags_table_exist()) {
$sql[] = "INSERT INTO `".SMD_TAG."` VALUES (1, 'root', 'article', '', 1, 2, 'root')";
$sql[] = "INSERT INTO `".SMD_TAG."` VALUES (2, 'root', 'link', '', 1, 2, 'root')";
$sql[] = "INSERT INTO `".SMD_TAG."` VALUES (3, 'root', 'image', '', 1, 2, 'root')";
$sql[] = "INSERT INTO `".SMD_TAG."` VALUES (4, 'root', 'file', '', 1, 2, 'root')";
}
$sql[] = "CREATE TABLE IF NOT EXISTS `".SMD_TAGC."` (
`tag_id` int(6) NOT NULL default '0',
`cat_id` int(6) NOT NULL default '0',
PRIMARY KEY (`tag_id`,`cat_id`)
) ENGINE=MyISAM; ";
$sql[] = "CREATE TABLE IF NOT EXISTS `".SMD_TAGU."` (
`item_id` int(11) NOT NULL default '0',
`tag_id` int(6) NOT NULL default '0',
`type` varchar(64) NOT NULL default '',
PRIMARY KEY (`item_id`,`tag_id`)
) ENGINE=MyISAM; ";
foreach ($sql as $qry) {
$ret = safe_query($qry);
if (!$ret) {
$GLOBALS['txp_err_count']++;
echo "".$GLOBALS['txp_err_count'].". ".mysql_error()."
\n";
echo "\n";
}
}
}
if ($GLOBALS['txp_err_count'] == 0) {
$message = smd_tags_gTxt('tbl_installed');
smd_tags_prefs_install($message);
} else {
$message = smd_tags_gTxt('tbl_not_installed');
smd_tags_prefs_show($message);
}
}
// ------------------------
// Drop tag tables if in database
function smd_tags_table_remove() {
$ret = '';
$sql = array();
$GLOBALS['txp_err_count'] = 0;
if (smd_tags_table_exist()) {
$sql[] = "DROP TABLE IF EXISTS " .SMD_TAG. "; ";
$sql[] = "DROP TABLE IF EXISTS " .SMD_TAGU. "; ";
foreach ($sql as $qry) {
$ret = safe_query($qry);
if (!$ret) {
$GLOBALS['txp_err_count']++;
echo "".$GLOBALS['txp_err_count'].". ".mysql_error()."
\n";
echo "\n";
}
}
}
if ($GLOBALS['txp_err_count'] == 0) {
$message = smd_tags_gTxt('tbl_removed');
smd_tags_prefs_remove($message);
} else {
$message = smd_tags_gTxt('tbl_not_removed');
smd_tags_prefs_show($message);
}
}
// ------------------------
// Add plugin preferences to prefs
function smd_tags_prefs_install($message='') {
global $smd_tag_prefs;
$ctr = safe_count('txp_prefs', 'event="smd_tags"') + 1;
foreach ($smd_tag_prefs[0] as $pref => $dflt) {
if (!fetch('name','txp_prefs','name',$pref)) {
$id = safe_insert('txp_prefs','prefs_id=1, name='.doQuote(doSlash($pref)).', val='.doQuote(doSlash($dflt)).', event="smd_tags", position="'.$ctr.'"');
$ctr++;
}
}
$message .= smd_tags_gTxt('prefs_installed');
smd_tags_prefs_show($message);
}
// ------------------------
// Remove plugin preferences from prefs table.
// Note: both parts of smd_tags_prefs array are iterated over to tidy up any legacy settings
function smd_tags_prefs_remove($message='') {
global $smd_tag_prefs;
foreach (array_merge($smd_tag_prefs[0],$smd_tag_prefs[1]) as $pref => $dflt) {
if (fetch('name','txp_prefs','name',$pref)) {
$id = safe_delete('txp_prefs','name='.doQuote(doSlash($pref)));
}
}
$message .= smd_tags_gTxt('prefs_removed');
smd_tags_prefs_show($message);
}
// ------------------------
// Saves plugin preferences
function smd_tags_prefs_update($message = '') {
global $smd_tag_prefs;
$post = doSlash(stripPost());
foreach ($smd_tag_prefs[0] as $pref => $dflt) {
if (isset($post[$pref])) {
safe_update("txp_prefs", "val = '".$post[$pref]."'", "name = '".doSlash($pref)."' and prefs_id = 1");
}
}
$message .= gTxt('preferences_saved');
smd_tags_prefs_show($message);
}
// ------------------------
// Split a multi-char preference value into an array of keys/values.
// Note: value is passed in and not read directly from the prefs array in this function - intentionally
function smd_tags_pref_explode($val) {
$order = array_values(array(gTxt('tab_list'),gTxt('tab_image'),gTxt('tab_file'),gTxt('tab_link')));
$onoff = array_values(preg_split('//', $val, -1, PREG_SPLIT_NO_EMPTY));
$out = array();
foreach($order as $key1 => $value1) {
$out[(string)$value1] = $onoff[$key1];
}
return $out;
}
// ------------------------
// Get values from prefs - pass either a single key or an array.
// If 2nd arg is set and the pref doesn't exist, read it from the plugin default
function smd_tags_pref_get($keys, $dflt=0) {
global $smd_tag_prefs;
if (!is_array($keys)) {
$keys = array($keys);
}
$prefkeys = doQuote(implode("','",doSlash($keys)));
$rs = safe_rows('name,val,html','txp_prefs','name IN ('.$prefkeys.') ORDER BY name');
$prefout = array();
foreach($rs as $pref) {
$prefout[$pref['name']] = array_slice($pref,1);
}
if ($dflt) {
foreach ($keys as $pref) {
if (!isset($prefout[$pref])) {
$prefout[$pref] = $smd_tag_prefs[0][$pref];
}
}
}
return $prefout;
}
// ------------------------
// Common buttons on the admin panel
function smd_tags_prefs_buttons() {
$ret = array (
'btnPrefsSave' => fInput('submit', 'submit', gTxt('save'), 'publish'),
'btnInstallTbl' => '',
'btnRemoveTbl' => '',
'btnInstall' => '',
'btnRemove' => '',
'btnPrefs' => '',
'btnManage' => '',
'btnHelp' => '('. gTxt('help') .')',
'btnCreate' => fInput('submit', 'smd_tag_create', gTxt('create'), 'smallerbox', '', 'smd_tags_step=this.name;smd_presub()'),
'btnSave' => fInput('submit', 'smd_tag_save', gTxt('save'), 'smallerbox', '', 'smd_tags_step=this.name;smd_presub()'),
'btnDelete' => fInput('submit', 'smd_tag_delete', '×', 'smallerbox', '', 'smd_tags_step=this.name;smd_presub()'),
'btnStyle' => ' style="border:0;height:25px"',
);
return $ret;
}
// ------------------------
// A stub that can be called without a $message
function smd_tags_prefs_display() {
smd_tags_prefs_show('');
}
// ------------------------
// Display the prefs panel
function smd_tags_prefs_show($message) {
global $smd_tag_prefs;
pagetop(smd_tags_gTxt('prefs_title'),$message);
extract(smd_tags_prefs_buttons());
// Prefs check
$prefset = smd_tags_pref_get(array_keys($smd_tag_prefs[0]));
$numReqPrefs = count($smd_tag_prefs[0]);
$numPrefs = count($prefset);
echo <<
// Concatenate checkbox options for storage
function smd_presub() {
var smd_out = "";
jQuery(":checkbox").each(function() {
smd_out += (this.checked) ? 1 : 0;
});
jQuery("#smd_tag_p_enable").val(smd_out);
return true;
}
EOJS;
echo startTable('list');
if (smd_tags_table_exist(1)) {
// Tables installed
if ($numPrefs == $numReqPrefs) {
// Prefs all installed
echo tr(tda(strong(smd_tags_gTxt('prefs_title')).' '.$btnHelp, ' colspan="5"'));
echo tr(
fLabelCell(smd_tags_gTxt('control').':')
. tda($btnRemove, $btnStyle)
. tda($btnRemoveTbl, $btnStyle)
. tda($btnManage, $btnStyle)
);
echo '';
} else if ($numPrefs > 0 && $numPrefs < $numReqPrefs) {
// Prefs possibly corrupt, or plugin updated
echo tr(tda(strong(smd_tags_gTxt('prefs_some')).br.br
.smd_tags_gTxt('prefs_some_explain').br.br
.smd_tags_gTxt('prefs_some_opts1'), ' colspan="2"')
);
echo tr(
tda($btnRemove,$btnStyle)
. tda($btnInstall, $btnStyle)
);
} else {
// Prefs not installed
echo tr(tda(smd_tags_gTxt('prefs_not_installed'), ' colspan="2"'));
echo tr(tda($btnInstall, $btnStyle));
}
} else {
// Tables not installed
echo tr(tda(strong(smd_tags_gTxt('prefs_some_tbl')).br.br
.smd_tags_gTxt('prefs_some_explain').br.br
.smd_tags_gTxt('prefs_some_opts2'), ' colspan="2"')
);
echo tr(tda($btnInstallTbl, $btnStyle));
}
echo endTable();
}
// ------------------------
// Manage tags in a similar way to the categories tab
function smd_tags_manage($message='') {
global $smd_tag_prefs;
extract(doSlash(gpsa(array('smd_tag_name', 'smd_tag_title', 'smd_tag_parent', 'smd_tag_cat', 'smd_tag_type', 'smd_tag_id'))));
pagetop(smd_tags_gTxt('manage_lbl'),$message);
extract(smd_tags_prefs_buttons());
// Prefs check
$prefset = smd_tags_pref_get(array_keys($smd_tag_prefs[0]));
$numReqPrefs = count($smd_tag_prefs[0]);
$numPrefs = count($prefset);
$types = array(
'article' => ucfirst(gtxt('article')),
'image' => gtxt('tag_image'),
'file' => gtxt('file'),
'link' => gtxt('tag_link'),
);
// Make up the radio buttons
$smd_tag_type = (!empty($smd_tag_type)) ? $smd_tag_type : 'article';
$radios = array();
foreach ($types as $key => $val) {
$id = 'smd_tags_type-'.$key;
$radios[] = n.t.radio('smd_tags_type', $key, ($smd_tag_type == $key) ? 1 : 0, $id).
'';
}
$radios = join(sp.sp, $radios).n;
// Create all the lists but hide them with CSS. jQuery takes over and switches between them on demand
if (smd_tags_table_exist(1) && $numPrefs == $numReqPrefs) {
$tagCols = ($prefset['smd_tag_t_cols']['val'] > 0) ? $prefset['smd_tag_t_cols']['val'] : 1;
$colOrder = ($prefset['smd_tag_t_colsord']['val'] == 0) ? "bycol" : "byrow";
$counts = $prefset['smd_tag_t_count']['val'];
$clink = $prefset['smd_tag_p_linkcat']['val'];
foreach (array_keys($types) as $type) {
$divtagid = "smd_tags_grp_".$type;
$taglist = "tags_".$type;
$$taglist = smd_tag_list_adm(
array(
"type" => $type,
"wraptag" => "table:".$tagCols.":cols:".$colOrder,
"count" => $counts,
"indent" => $prefset['smd_tag_t_indent']['val']
)
);
//TODO: Find a way to add the divtagid only when needed. At the moment it appears twice on the page (illegal DOM)
$tagout[$type] = ''.$$taglist.'
';
echo ''.$tagout[$type].'
';
}
$qs = array(
"event" => "smd_tags",
);
$qsVars = "index.php".join_qs($qs);
echo <<
var smd_tags_step = '';
// Page initialisation
jQuery(function() {
// Indicate parent list is loading
jQuery(".smd_tags_showpars").ajaxStart(function() {
jQuery(this).fadeTo("normal", 0.33);
}).ajaxStop(function() {
jQuery(this).fadeTo("normal", 1);
});
// Switch between types
jQuery("input[name='smd_tags_type']").change(function () {
var smd_newcontent = jQuery("#smd_tags_grp_"+jQuery(this).val()).html();
jQuery("input[name='smd_tag_id']").val(''); // Changing type forces any 'save' to trigger the 'create' behaviour
jQuery(".smd_tags_showlist").html(smd_newcontent);
var nam = jQuery("input[name='smd_tag_oname']").val();
var tid = jQuery("input[name='smd_tag_id']").val();
var typ = jQuery("input[name='smd_tags_type']:checked").val();
var par = 'root';
var cat = '';
jQuery(".smd_tags_showlist td span[name='smd_tagnam']").each(function() {
if (jQuery(this).text() == nam) {
jQuery(this).parent().addClass('smd_current');
par = jQuery(this).siblings(":eq(2)").text();
cat = jQuery(this).siblings(":eq(3)").text();
tid = (tid == '') ? jQuery(this).siblings(":eq(0)").text() : tid;
} else {
jQuery(this).parent().removeClass('smd_current');
}
});
// Re-insert the ID if this named item exists in the new list
jQuery("input[name='smd_tag_id']").val(tid);
// Update the UI
smd_parentHandler(nam, typ, tid, par);
smd_catHandler(cat, typ);
jQuery(".smd_tags_linkcat select option[value='"+cat+"']").attr("selected", true);
smd_autofocus();
smd_cellHandler();
jQuery("input[name='smd_tags_type']").each(function () {
if (jQuery(this).val() == typ) {
jQuery(this).next().addClass('smd_current');
} else {
jQuery(this).next().removeClass('smd_current');
}
});
});
// Call the onchange handler for the current type
jQuery("input[name='smd_tags_type']:checked").change();
// Autotag - TODO: foreign character dumbdown for URI
if ({$prefset['smd_tag_t_auto']['val']}) {
spcRE = /\s/g;
badRE = /[^a-zA-Z0-9_\-]/g;
jQuery("input[name='smd_tags_newtitle']").keyup(function() {
tagname = jQuery(this).val().replace(spcRE, '-').replace(badRE, '').toLowerCase();
jQuery("input[name='smd_tags_newname']").val(tagname);
});
}
// Bind Enter key to create
jQuery("input[name^='smd_tag']").keyup(function(ev) {
if (ev.keyCode == 13) {
jQuery("input[name='smd_tag_create']").click();
}
});
});
// Keep track of which tag has been clicked so it can be edited/updated
function smd_cellHandler() {
// Cell highlights
jQuery(".smd_tags_showlist td").each(function() {
if (jQuery.trim(jQuery(this).text()) != "") {
jQuery(this).hover(
function () {
jQuery(this).addClass('smd_hover');
},
function () {
jQuery(this).removeClass('smd_hover');
}
)
.click(function() {
var nam = jQuery(this).children(":eq(0)").text();
var tid = jQuery(this).children(":eq(1)").text();
var ttl = jQuery(this).children(":eq(2)").text();
var par = jQuery(this).children(":eq(3)").text();
var cat = jQuery(this).children(":eq(4)").text();
var typ = jQuery("input[name='smd_tags_type']:checked").val()
jQuery("input[name='smd_tag_oname']").val(nam);
jQuery("input[name='smd_tags_newname']").val(nam);
jQuery("input[name='smd_tag_id']").val(tid);
jQuery("input[name='smd_tags_newtitle']").val(ttl);
jQuery(".smd_tags_linkcat select option[value='"+cat+"']").attr("selected", true);
smd_parentHandler(nam, typ, tid, par);
jQuery(".smd_tags_showlist td").removeClass('smd_current');
jQuery(this).addClass('smd_current');
smd_autofocus();
});
}
});
}
// Ask TXP for the parent dropdown without child entries
function smd_parentHandler(nam, typ, tid, par) {
jQuery.post('{$qsVars}', { step: "smd_tag_parentlist", name: nam, type: typ, id: tid },
function(data) {
jQuery(".smd_tags_showpars").html(data);
if (par == "root" || par == "") {
jQuery(".smd_tags_showpars select option:first").attr("selected", true);
} else {
jQuery(".smd_tags_showpars select option[value='"+par+"']").attr("selected", true);
}
}
);
}
// Ask TXP for the category dropdown
function smd_catHandler(cat, typ) {
jQuery(".smd_tags_linkcat").fadeTo("normal", 0.33);
jQuery.post('{$qsVars}', { step: "smd_tag_catlist", name: cat, type: typ },
function(data) {
jQuery(".smd_tags_linkcat").html(data);
if (cat == "root" || cat == "") {
jQuery(".smd_tags_linkcat select option:first").attr("selected", true);
} else {
jQuery(".smd_tags_linkcat select option[value='"+cat+"']").attr("selected", true);
}
jQuery(".smd_tags_linkcat").fadeTo("normal", 1);
}
);
}
function smd_autofocus() {
jQuery("input[name='smd_tags_newtitle']").focus().select();
}
// Make sure what is in the boxes is POSTed via the hidden form
function smd_presub() {
jQuery("input[name='step']").val(smd_tags_step);
jQuery("input[name='smd_tag_name']").val(jQuery("input[name='smd_tags_newname']").val());
jQuery("input[name='smd_tag_title']").val(jQuery("input[name='smd_tags_newtitle']").val());
jQuery("input[name='smd_tag_type']").val(jQuery("input[name='smd_tags_type']:checked").val());
jQuery("input[name='smd_tag_parent']").val(jQuery(".smd_tags_showpars option:selected").val());
jQuery("input[name='smd_tag_cat']").val(jQuery(".smd_tags_linkcat option:selected").val());
jQuery("#smd_postit").submit();
}
EOJS;
}
// The tag management table
echo startTable('control','','',5);
if (smd_tags_table_exist()) {
// Tables installed
if ($numPrefs == $numReqPrefs) {
// Prefs all installed
echo tr(
fLabelCell(smd_tags_gTxt('control').':')
. tda($btnPrefs, $btnStyle)
);
echo endTable();
echo '';
echo startTable('list');
echo tr(tda(strong(smd_tags_gTxt('manage_lbl')).' '.$btnHelp, ' colspan="11"'));
echo tr(
fLabelCell(gTxt('title').':')
. td(fInput('text', 'smd_tags_newtitle', $smd_tag_title))
. td(gTxt('parent').':')
. td('', '', 'smd_tags_showpars')
. (($clink)
? td(smd_tags_gTxt('clink_lbl').':')
. td('', '', 'smd_tags_linkcat')
: td(sp).td(sp)
)
. fLabelCell(gTxt('name').':')
. tda(fInput('text', 'smd_tags_newname', $smd_tag_name))
. tda($btnSave, $btnStyle)
. tda($btnCreate, $btnStyle)
. tda($btnDelete, $btnStyle)
);
echo tr(
fLabelCell(smd_tags_gTxt('filter').':')
. tdcs($radios, 10)
);
echo tr(
td(sp)
. tdcs($tagout[$smd_tag_type], 10, '', 'smd_tags_showlist')
);
} else if ($numPrefs > 0 && $numPrefs < $numReqPrefs) {
// Prefs possibly corrupt, or plugin updated
echo tr(
tda(strong(smd_tags_gTxt('prefs_some')).br.br
.smd_tags_gTxt('prefs_some_explain').br.br
.smd_tags_gTxt('prefs_some_opts1'), ' colspan="2"')
);
echo tr(
tda($btnRemove,$btnStyle)
. tda($btnInstall, $btnStyle)
);
} else {
// Prefs not installed
echo tr(tda(smd_tags_gTxt('prefs_not_installed'), ' colspan="2"'));
echo tr(tda($btnInstall, $btnStyle));
}
} else {
// Tables not installed
echo tr(tda(strong(smd_tags_gTxt('prefs_some_tbl')).br.br
.smd_tags_gTxt('prefs_some_explain').br.br
.smd_tags_gTxt('prefs_some_opts2'), ' colspan="2"')
);
echo tr(tda($btnInstallTbl, $btnStyle));
}
echo endTable();
}
// ------------------------
// Store the tag that is currently being edited
function smd_tag_save() {
extract(doSlash(gpsa(array('smd_tag_oname', 'smd_tag_name', 'smd_tag_title', 'smd_tag_parent', 'smd_tag_cat', 'smd_tag_type', 'smd_tag_id'))));
$message = '';
$smd_tag_parent = (!empty($smd_tag_parent)) ? $smd_tag_parent : 'root';
$smd_tag_name = (!empty($smd_tag_name)) ? sanitizeForUrl($smd_tag_name) : '';
// Can't use safe_upsert() because the WHERE is for ID AND type
if (empty($smd_tag_id)) {
// Create
if (empty($smd_tag_name)) {
$message = smd_tags_gTxt('no_name', array('{type}' => ucfirst($smd_tag_type)));
} else {
$exists = safe_field('name', SMD_TAG, "name = '$smd_tag_name' AND type = '$smd_tag_type'");
$parex = safe_field('name', SMD_TAG, "name = '$smd_tag_parent' AND type = '$smd_tag_type'");
if ($exists) {
$message = smd_tags_gTxt('exists', array('{name}' => $smd_tag_name, '{type}' => ucfirst($smd_tag_type)));
} else {
$smd_tag_id = safe_insert(
SMD_TAG,
"name='$smd_tag_name', title='$smd_tag_title', parent='".(($parex) ? $smd_tag_parent : 'root')."', type='$smd_tag_type'"
);
if ($smd_tag_id > 0) {
if ($smd_tag_cat) {
safe_insert(SMD_TAGC,"tag_id='$smd_tag_id', cat_id=(SELECT id FROM txp_category WHERE name='$smd_tag_cat' AND type='$smd_tag_type')");
}
$message = smd_tags_gTxt('created', array('{name}' => $smd_tag_name, '{type}' => ucfirst($smd_tag_type)));
} else {
$message = smd_tags_gTxt('not_created', array('{name}' => $smd_tag_name, '{type}' => ucfirst($smd_tag_type)));
}
}
}
} else {
// Update - no need to maintain referential integrity unlike txp_cats
// since tags are stored against item IDs
$existing_id = safe_field('id', SMD_TAG, "name = '$smd_tag_name' and type = '$smd_tag_type'");
if ($existing_id and $existing_id != $smd_tag_id) {
$message = smd_tags_gTxt('exists', array('{name}' => $smd_tag_name, '{type}' => ucfirst($smd_tag_type)));
} else {
if (safe_update(
SMD_TAG,
"name='$smd_tag_name', title='$smd_tag_title', parent='$smd_tag_parent'",
"type='$smd_tag_type' AND id=$smd_tag_id"
)) {
safe_update(SMD_TAG, "parent='$smd_tag_name'", "parent='$smd_tag_oname' AND type='$smd_tag_type'");
if ($smd_tag_cat) {
safe_upsert(SMD_TAGC, "cat_id=(SELECT id FROM txp_category WHERE name='$smd_tag_cat' AND type='$smd_tag_type')", "tag_id = '$smd_tag_id'");
} else {
safe_delete(SMD_TAGC, "tag_id=$smd_tag_id");
}
$message = smd_tags_gTxt('updated', array('{name}' => $smd_tag_name, '{type}' => ucfirst($smd_tag_type)));
} else {
$message = smd_tags_gTxt('not_updated', array('{name}' => $smd_tag_name, '{type}' => ucfirst($smd_tag_type)));
}
}
}
rebuild_tree_full($smd_tag_type, SMD_TAG);
// Force smd_tag_id to the new ID so it can be immediately edited
$_POST['smd_tag_id'] = $smd_tag_id;
smd_tags_manage($message);
}
// ------------------------
// Store new tag - uses smd_tag_save without the ID/old_name
function smd_tag_create() {
extract(doSlash(gpsa(array('smd_tag_name', 'smd_tag_title', 'smd_tag_parent', 'smd_tag_type'))));
unset($_POST['smd_tag_id']);
smd_tag_save();
}
// ------------------------
// Delete currently edited tag. Respects noclobber/tree if prefs set
function smd_tag_delete() {
global $smd_tag_prefs;
extract(doSlash(gpsa(array('smd_tag_oname', 'smd_tag_type', 'smd_tag_id'))));
$smd_tag_id = assert_int($smd_tag_id);
$pref = smd_tags_pref_get(array('smd_tag_t_delused', 'smd_tag_t_deltree'));
$message = $msgExtra = '';
list($lft, $rgt) = array_values(safe_row('lft, rgt', SMD_TAG, 'id = '.$smd_tag_id));
$children = ($rgt - $lft - 1) / 2;
$used = safe_count(SMD_TAGU, "tag_id=$smd_tag_id AND type='$smd_tag_type'");
$doit = $pref['smd_tag_t_delused']['val'];
$tree = $pref['smd_tag_t_deltree']['val'];
if ($doit == 0) {
if ($used || $children > 0) {
$message = smd_tags_gTxt('in_use', array('{type}' => ucfirst($smd_tag_type), '{name}' => $smd_tag_oname));
} else {
$doit = 1;
}
}
// Do the delete/tree
if ($doit) {
if ($tree) {
$ids = safe_column('id', SMD_TAG, "type = '$smd_tag_type' AND (lft BETWEEN $lft AND $rgt)");
$msgExtra = smd_tags_gTxt('children_and');
} else {
$ids = array($smd_tag_id);
}
$where = 'id IN ('.doQuote(implode("','",$ids)).')';
$ret = safe_delete(SMD_TAG, $where." AND type='$smd_tag_type'");
if ($ret) {
if (!$tree) {
safe_update(SMD_TAG, "parent='root'", "type='$smd_tag_type' and parent='$smd_tag_oname'");
}
foreach ($ids as $delid) {
safe_delete(SMD_TAGU, "tag_id=$delid AND type='$smd_tag_type'");
safe_delete(SMD_TAGC, "tag_id=$delid");
}
}
if ($ret) {
$message = smd_tags_gTxt('deleted', array('{type}' => ucfirst($smd_tag_type), '{name}' => $smd_tag_oname)).$msgExtra;
// Force all smd_tag_ boxes clear
$_POST['smd_tag_id'] = $_POST['smd_tag_oname'] = $_POST['smd_tag_name'] = $_POST['smd_tag_title'] = $_POST['smd_tag_parent'] = '';
} else {
$message = smd_tags_gTxt('not_deleted', array('{type}' => ucfirst($smd_tag_type), '{name}' => $smd_tag_oname));
}
}
rebuild_tree_full($smd_tag_type, SMD_TAG);
smd_tags_manage($message);
}
// ------------------------
// MIDDLEWARE - ADMIN/PUBLIC GLUE
// ------------------------
// Grab a valid tag parent list. Cannot be done easily from fixed data: AJAX is the only reliable way :-(
function smd_tag_parentlist() {
$trycat = isset($_POST['cat']);
extract(doSlash(gpsa(array('name', 'type', 'id', 'cat', 'itemid'))));
while(@ob_end_clean()); // Get rid of any page so far
$type = ($type == "" || $type == "undefined") ? 'article' : $type;
$cat = ($cat == "" || $cat == "undefined") ? '' : $cat;
$tags = ($itemid == "" || $itemid == "undefined") ? array() : safe_rows("tag_id", SMD_TAGU, "type='$type' AND item_id='$itemid'");
$clrBtn = '['.smd_tags_gTxt('clear').']';
$togBtn = '['.smd_tags_gTxt('toggle').']';
if ($cat) {
$cat = do_list($cat);
$rsid = array();
$rsc = getRows("SELECT txt.id, txt.lft, txt.rgt
FROM ".SMD_TAG." AS txt, txp_category AS txc, ".SMD_TAGC." AS txl
WHERE txt.id = txl.tag_id
AND txl.cat_id = txc.id
AND txc.name IN ('" .implode("','", $cat). "')
AND txt.type = '$type'");
if ($rsc) {
foreach ($rsc as $row) {
$ids = safe_column('id', SMD_TAG, "type = '$type' AND (lft BETWEEN " .$row['lft']. " AND " .$row['rgt']. ")");
$rsid = array_merge($rsid, $ids);
}
}
$cat = ($rsc) ? ' AND id IN ('.doQuote(implode("','",$rsid)).')' : '';
}
if ($id) {
$id = assert_int($id);
list($lft, $rgt) = array_values(safe_row('lft, rgt', SMD_TAG, 'id = '.$id));
$rs = getTree('root', $type, "lft not between $lft and $rgt".$cat, SMD_TAG);
} else {
$rs = getTree('root', $type, "1=1".$cat, SMD_TAG);
}
if ($rs) {
if ($trycat) {
echo smd_multiTreeSelectInput('smd_tag_parent', $rs, $tags).$clrBtn.$togBtn;
} else {
echo treeSelectInput('smd_tag_parent', $rs, $name);
}
} else {
echo smd_tags_gTxt('no_parent');
}
exit(); // Don't call page_end()
}
// ------------------------
// Grab a valid category list
function smd_tag_catlist($cat='') {
extract(doSlash(gpsa(array('name','type'))));
while(@ob_end_clean()); // Get rid of any page so far
$type = ($type == "" || $type == "undefined") ? 'article' : $type;
$rs = getTree('root', $type, "1=1");
if ($rs) {
echo treeSelectInput('smd_catlist', $rs, $name);
} else {
echo gTxt('no_categories_available');
}
exit(); // Don't call page_end()
}
// ------------------------
// Handle fake tag section URL
// TODO: Handle messy URLs
function smd_tags_url_handler($event, $step) {
global $smd_tag_type, $smd_tags, $permlink_mode;
$prefs = smd_tags_pref_get(array('smd_tag_u_sec', 'smd_tag_u_pnam', 'smd_tag_u_ptyp'), 1);
$urlsec = $prefs['smd_tag_u_sec']['val'];
$urlnam = $prefs['smd_tag_u_pnam']['val'];
$urltyp = $prefs['smd_tag_u_ptyp']['val'];
/*
if ($permlink_mode != 'messy') {
return '';
}
*/
$subpath = preg_replace("/https?:\/\/.*(\/.*)/Ui","$1",hu);
$regsafesubpath = preg_quote($subpath, '/');
$req = preg_replace("/^$regsafesubpath/i",'/',$_SERVER['REQUEST_URI']);
$qs = strpos($req, '?');
$qatts = ($qs ? a.substr($req, $qs + 1) : '');
if ($qs) $req = substr($req, 0, $qs);
$parts = array_values(array_filter(split('/', $req)));
$validTypes = array('article','image','file','link');
if ((count($parts) > 1) && ($parts[0] == $urlsec)) {
if (count($parts) == 3) {
$smd_tag_type = $parts[1];
$smd_tag = $parts[2];
} else {
if (in_array($parts[1], $validTypes)) {
$smd_tag_type = $parts[1];
$smd_tag = '';
} else {
$smd_tag_type = $validTypes[0];
$smd_tag = $parts[1];
}
}
smd_tags_set($smd_tag_type, $smd_tag);
$_SERVER['QUERY_STRING'] = $urlnam.'='.$smd_tag .a. $urltyp.'='.$smd_tag_type . $qatts;
$_SERVER['REQUEST_URI'] = $subpath . $urlsec . '/?' . $_SERVER['QUERY_STRING'];
} else if ($parts[0] == $urlsec || gps('s') == $urlsec) {
$smd_tag_type = (in_array(gps($urltyp), $validTypes)) ? gps($urltyp) : '';
$smd_tag = gps($urlnam);
smd_tags_set($smd_tag_type, $smd_tag);
$_SERVER['QUERY_STRING'] = $urlnam.'='.$smd_tag .a. $urltyp.'='.$smd_tag_type . $qatts;
$_SERVER['REQUEST_URI'] = $subpath . $urlsec . '/?' . $_SERVER['QUERY_STRING'];
}
}
// ------------------------
function smd_tags_set($typ, $tag='', $item='') {
global $smd_tags;
$smd_tags = '';
// MONSTER!
$rs = startRows(
"SELECT id, name, txt.type, parent, title, count(item_id) AS count"
.",(SELECT CAST((rgt - lft - 1) / 2 AS UNSIGNED)) AS children"
.",(SELECT COUNT(*) from ".SMD_TAG." WHERE type='$typ' AND name=name AND lft < txt.lft AND rgt > txt.rgt)-1 AS level"
." FROM ".SMD_TAG." AS txt, ".SMD_TAGU." AS txu"
." WHERE txt.type='$typ'"
." AND tag_id = id"
.(($tag) ? " AND name='$tag'" : "")
.(($item) ? " AND item_id='$item'" : "")
." GROUP BY id");
while ($row = nextRow($rs)) {
$smd_tags[$typ][$row['id']] = array('tag_name' => $row['name'], 'tag_title' => $row['title'], 'tag_parent' => $row['parent'], 'tag_count' => $row['count'], 'tag_children' => $row['children'], 'tag_level' => $row['level']);
$smd_tags[$typ]['tag_name'][$row['id']] = $row['name'];
$smd_tags[$typ]['tag_title'][$row['id']] = $row['title'];
$smd_tags[$typ]['tag_parent'][$row['id']] = $row['parent'];
$smd_tags[$typ]['tag_count'][$row['id']] = $row['count'];
$smd_tags[$typ]['tag_children'][$row['id']] = $row['children'];
$smd_tags[$typ]['tag_level'][$row['id']] = $row['level'];
}
}
// ------------------------
// Add tags to the global scope, depending on context.
// Returns the current context
function smd_tags_context() {
global $thisarticle, $thisfile, $thislink, $thisimage, $smd_tag_type, $smd_tag_items, $smd_tags, $smd_thistag;
$ctxt = $smd_tag_type;
$ids = array();
$scp = @$smd_tags[$ctxt];
if (empty($smd_tag_type)) {
// Individual article or list
$id = '';
if (!empty($thisimage)) {
$id = $thisimage['id'];
$ctxt = 'image';
$scp = $thisimage;
} else if(!empty($thisfile)) {
$id = $thisfile['id'];
$ctxt = 'file';
$scp = $thisfile;
} else if(!empty($thislink)) {
$id = $thislink['id'];
$ctxt = 'link';
$scp = $thislink;
} else if(!empty($thisarticle)) {
$id = $thisarticle['thisid'];
$ctxt = 'article';
$scp = $thisarticle;
}
if ($id) {
smd_tags_set($ctxt, '', $id);
}
}
if(!empty($smd_tags)) {
foreach($smd_tags[$ctxt] as $rid => $row) {
if (is_int($rid)) {
$ids[] = $rid;
}
}
}
// TODO: is this needed to overwrite if tag already set?
if (!empty($smd_thistag)) {
$ids = array($smd_thistag['tag_id']);
}
return array('context' => $ctxt, 'scope' => $scp, 'id' => $ids);
}
// ------------------------
// Load current tag into global scope
function smd_tag_populate($row) {
global $smd_thistag;
$smd_thistag['tag_id'] = $row['id'];
$smd_thistag['tag_name'] = $row['name'];
$smd_thistag['tag_type'] = $row['type'];
$smd_thistag['tag_parent'] = $row['parent'];
$smd_thistag['tag_title'] = $row['title'];
$smd_thistag['tag_children'] = $row['children'];
$smd_thistag['tag_level'] = $row['level'];
$smd_thistag['tag_count'] = $row['count'];
}
// ------------------------
// All tags/counts
function smd_tag_list_adm($atts) {
include_once txpath.'/publish/taghandlers.php';
extract(lAtts(array(
'type' => 'article',
'indent' => ' ',
'count' => 1,
'label' => '',
'labeltag' => '',
'wraptag' => '',
'break' => '',
'class' => __FUNCTION__,
'breakclass' => '',
),$atts));
$validTypes = array('list' => 'article', 'image' => 'image', 'file' => 'file', 'link' => 'link');
$rs = getTree('root', $type, '1=1', SMD_TAG);
$rsc = getRows("SELECT txl.tag_id, txc.name
FROM ".SMD_TAG." AS txt, ".SMD_TAGC." AS txl, txp_category AS txc
WHERE txt.type = '$type' AND txt.id = txl.tag_id AND txl.cat_id = txc.id");
$rscout = array();
if ($rsc) {
foreach ($rsc as $idx => $row) {
$rscout[$row['tag_id']] = $row['name'];
}
}
if ($rs) {
$out = array();
$totals = array();
// Tally each tag's usage
if ($count) {
$rsu = safe_rows_start('tag_id, count(*) as num', SMD_TAGU, "type='$type' GROUP BY tag_id");
while ($row = nextRow($rsu)) {
$tagid = $row['tag_id'];
$num = $row['num'];
$ids = safe_column('item_id', SMD_TAGU, "type='$type' AND tag_id='$tagid'");
$totals[$tagid] = array($num, join(",",$ids));
}
}
foreach ($rs as $row) {
extract($row);
$parent = (isset($parent)) ? $parent : ''; // Parent might not be defined
$row['type'] = $type;
if (isset($totals[$id])) {
$row['count'] = $totals[$id][0];
$ev = array_keys($validTypes,$type);
$url = 'index.php?event='.$ev[0].a.'search_method=id'.a.'crit='.$totals[$id][1];
$cntop = ' ('. href($totals[$id][0], $url) .')';
} else {
$row['count'] = 0;
$cntop = ' (0)';
}
$rowdata = ''.$name
.''.$id
.''.$title
.''.$parent
.''.((isset($rscout[$id])) ? $rscout[$id] : '')
.'';
$out[] = $rowdata.str_repeat($indent, $level * 1)
.$title
.(($count) ? $cntop : '').n;
// $smd_thistag = array();
}
if ($out) {
$wrapit = do_list($wraptag, ":");
// Tables are a special case
if ($wrapit[0] == "table") {
$totalItems = $rows = count($rs);
$step = 1;
$cols = 1;
$numopts = count($wrapit);
// Each successive level overrides the previous step so by the end of the ifs,
// 3 values are set up: step, rows and cols
if ($numopts > 1) {
$cols = $wrapit[1];
$rows = ceil($totalItems/$cols);
}
if ($numopts > 2) {
if ($wrapit[2] == "rows") {
$rows = $wrapit[1];
$cols = ceil($totalItems/$rows);
}
}
if ($numopts > 3) {
if ($wrapit[3] == "bycol") {
$step = ($wrapit[2]=="cols") ? ceil($totalItems/$cols) : $rows;
if ($wrapit[2]=="cols") {
$rows = $step;
} else {
$cols = ceil($totalItems/$rows);
}
}
}
// Generate table based on above rules
$tblout = array();
$cellCtr = 0;
$class = (!empty($class)) ? ' class="'.$class.'"' : '';
$breakclass = (!empty($breakclass)) ? ' class="'.$breakclass.'"' : '';
for ($idx = 0; $idx < $rows; $idx++) {
$bld = array();
for ($jdx = 0; $jdx < $cols; $jdx++) {
$offset = ($wrapit[3]=="bycol") ? ($jdx * $step) + $idx : $cellCtr;
$bld[] = (isset($out[$offset])) ? td($out[$offset]) : td('');
$cellCtr++;
}
$tblout[] = tr(join("", $bld), $breakclass);
}
return doLabel($label, $labeltag).tag(join("",$tblout), $wrapit[0], $class);
} else {
return doLabel($label, $labeltag).doWrap($out, $wrapit[0], $break, $class, $breakclass);
}
}
return '';
}
}
// ------------------------
// Plugin-specific replacement strings - localise as required
function smd_tags_gTxt($what, $atts = array()) {
$lang = array(
'ac_std' => 'Standard',
'ac_str' => 'Strict',
'by_column' => 'Column',
'by_row' => 'Row',
'clear' => 'clr',
'clink_lbl' => 'Linked cat',
'control' => 'Plugin control',
'created' => '{type} tag "{name}" created',
'children_and' => ' and its children',
'children_del' => 'Delete children',
'children_pro' => 'Promote children',
'deleted' => '{type} tag "{name}" deleted',
'exists' => '{type} tag "{name}" already exists',
'filter' => 'Filter',
'in_use' => '{type} tag "{name}" is in use',
'manage_lbl' => 'Manage tags',
'no_name' => '{type} tag NOT created: needs a name',
'no_parent' => 'No parent tags',
'not_available' => 'smd_tags tables are not installed',
'not_created' => '{type} tag "{name}" NOT created',
'not_deleted' => '{type} tag "{name}" NOT deleted',
'not_updated' => '{type} tag "{name}" NOT updated',
'pref_install_lbl' => 'Install prefs',
'pref_remove_lbl' => 'Remove prefs',
'pref_show_lbl' => 'Preferences',
'prefs_installed' => 'Preferences installed',
'prefs_not_installed' => 'Preferences not installed.',
'prefs_pane' => 'Prefs',
'prefs_removed' => 'Preferences removed',
'prefs_some' => 'Not all preferences available.',
'prefs_some_explain' => 'This is either a new installation or a different version'.br.'of the plugin to one you had before.',
'prefs_some_opts1' => 'Choose "Remove prefs" to remove them all or "Install prefs" to add'.br.'any new ones, leaving all existing prefs untouched.',
'prefs_some_opts2' => 'Click "Install tables" to add or update the tables'.br.'leaving all existing data untouched.',
'prefs_some_tbl' => 'Not all table info available.',
'prefs_title' => 'smd_tags preferences',
'sel_list' => 'Select list',
'prefs_p' => 'Interface settings',
'prefs_t' => 'Tag management',
'prefs_u' => 'URL management',
'smd_tags' => 'smd_tags',
'smd_tag_p_enable' => 'Enable tags in',
'smd_tag_p_first' => 'Initial pane',
'smd_tag_p_input' => 'Enter tags using',
'smd_tag_p_linkcat' => 'Link tags to categories',
'smd_tag_p_qtag' => 'Quick tag (requires plugin)',
'smd_tag_p_qtpath' => 'JS plugin dir (relative to "textpattern")',
'smd_tag_p_qtstyl' => 'JS style dir (relative to "textpattern")',
'smd_tag_p_size' => 'Select/textarea rows',
'smd_tag_t_auto' => 'Auto name',
'smd_tag_t_cols' => 'Tag columns',
'smd_tag_t_colsord' => 'Order tags by',
'smd_tag_t_count' => 'Show tag usage counts',
'smd_tag_t_deltree' => 'When deleting a parent',
'smd_tag_t_delused' => 'Allow deletion of used tags',
'smd_tag_t_hilite' => 'Clicked RGB colour',
'smd_tag_t_hover' => 'Mouse-over RGB colour',
'smd_tag_t_indent' => 'Sub-tag level indicator',
'smd_tag_u_pnam' => 'URL name parameter',
'smd_tag_u_ptyp' => 'URL type parameter',
'smd_tag_u_sec' => 'Default section for tags',
'textbox' => 'Text area',
'textlist' => 'Text list',
'tbl_install_lbl' => 'Install tables',
'tbl_installed' => 'Tag tables installed. ',
'tbl_not_installed' => 'Tag tables NOT installed. ',
'tbl_not_removed' => 'Tag tables NOT removed. ',
'tbl_remove_lbl' => 'Remove tables',
'tbl_removed' => 'Tag tables removed. ',
'tags_pane' => 'Manage tags',
'title' => 'Tags',
'toggle' => 'tog',
'updated' => '{type} tag "{name}" updated',
);
return strtr($lang[$what], $atts);
}