// 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' => '
'.fInput('submit', 'submit', smd_tags_gTxt('tbl_install_lbl'), 'smallerbox').'
', 'btnRemoveTbl' => '
'.fInput('submit', 'submit', smd_tags_gTxt('tbl_remove_lbl'), 'smallerbox').'
', 'btnInstall' => '
'.fInput('submit', 'submit', smd_tags_gTxt('pref_install_lbl'), 'smallerbox').'
', 'btnRemove' => '
'.fInput('submit', 'submit', smd_tags_gTxt('pref_remove_lbl'), 'smallerbox').'
', 'btnPrefs' => '
'.fInput('submit', 'submit', smd_tags_gTxt('pref_show_lbl'), 'smallerbox').'
', 'btnManage' => '
'.fInput('submit', 'submit', smd_tags_gTxt('manage_lbl'), 'smallerbox').'
', '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 '
'; $ctr = 1; foreach ($prefset as $pnam => $parr) { $pval = $parr['val']; $out = (isset($smd_tag_prefs[2][$ctr])) ? tr(tdcs(hed($smd_tag_prefs[2][$ctr], 2, ' class="pref-heading"'), 4)) : ''; $label = ''; $out .= tda($label, ' style="text-align: right; vertical-align: middle;"'); switch($pnam) { case "smd_tag_p_enable": $options = smd_tags_pref_explode($pval); $out .= ''; foreach ($options as $opt => $onoff) { $out .= '' . checkbox("enable".$opt, 1, $onoff) . '  '; } $out .= ''; $out .= fInput('hidden', 'smd_tag_p_enable', implode($options),'','','','','','smd_tag_p_enable'); break; case "smd_tag_p_size": case "smd_tag_t_cols": case "smd_tag_t_hilite": case "smd_tag_t_hover": case "smd_tag_t_indent": case "smd_tag_u_pnam": case "smd_tag_u_ptyp": case "smd_tag_u_sec": $out .= tag(fInput('text', $pnam, $pval, 'edit', '', '', 12, '', $pnam), 'td', ' colspan="3"'); break; case "smd_tag_p_qtpath": case "smd_tag_p_qtstyl": $out .= tag(fInput('text', $pnam, $pval, 'edit', '', '', 30, '', $pnam), 'td', ' colspan="3"'); break; case "smd_tag_t_auto": $out .= tdcs(onoffRadio($pnam, $pval),3); break; case "smd_tag_t_colsord": $out .= tdcs(radio($pnam,0,(($pval==0)?1:0)).smd_tags_gTxt('by_column')." " . radio($pnam,1,(($pval==1)?1:0)).smd_tags_gTxt('by_row')." ",3); break; case "smd_tag_t_deltree": $out .= tdcs(radio($pnam,0,(($pval==0)?1:0)).smd_tags_gTxt('children_pro')." " . radio($pnam,1,(($pval==1)?1:0)).smd_tags_gTxt('children_del')." ",3); break; case "smd_tag_t_delused": case "smd_tag_t_count": case "smd_tag_p_linkcat": $out .= tdcs(yesnoRadio($pnam, $pval),3); break; case "smd_tag_p_first": $out .= tdcs(radio($pnam,0,(($pval==0)?1:0)).smd_tags_gTxt('prefs_pane')." " . radio($pnam,1,(($pval==1)?1:0)).smd_tags_gTxt('tags_pane')." ",3); break; case "smd_tag_p_qtag": $out .= tdcs(radio($pnam,0,(($pval==0)?1:0)).gTxt('off')." " . radio($pnam,1,(($pval==1)?1:0)).smd_tags_gTxt('ac_std')." "." " . radio($pnam,2,(($pval==2)?1:0)).smd_tags_gTxt('ac_str')." ",3); break; case "smd_tag_p_input": $out .= tdcs(radio($pnam,0,(($pval==0)?1:0)).smd_tags_gTxt('sel_list')." " . radio($pnam,1,(($pval==1)?1:0)).smd_tags_gTxt('textbox')." ". radio($pnam,2,(($pval==2)?1:0)).smd_tags_gTxt('textlist')." ",3); break; } echo tr($out); $ctr++; } echo tr(tda($btnPrefsSave, $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 hInput('step', ''); echo hInput('smd_tag_id', $smd_tag_id); echo hInput('smd_tag_name', ''); echo hInput('smd_tag_oname', $smd_tag_name); echo hInput('smd_tag_parent', ''); echo hInput('smd_tag_cat', ''); echo hInput('smd_tag_title', ''); echo hInput('smd_tag_type', ''); 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 '
'. n.$out. n.'
'; } */ $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); }