. */ /** * Category panel. * * @package Admin\Category */ if (!defined('txpinterface')) { die('txpinterface is undefined.'); } if ($event == 'category') { require_privs('category'); $available_steps = array( 'cat_category_list' => false, 'cat_category_multiedit' => true, 'cat_article_create' => true, 'cat_image_create' => true, 'cat_file_create' => true, 'cat_link_create' => true, 'cat_article_save' => true, 'cat_image_save' => true, 'cat_file_save' => true, 'cat_link_save' => true, 'cat_article_edit' => false, 'cat_image_edit' => false, 'cat_file_edit' => false, 'cat_link_edit' => false, ); if ($step && bouncer($step, $available_steps)) { $step(); } else { cat_category_list(); } } /** * Outputs the main panel listing all categories. * * @param string|array $message The activity message */ function cat_category_list($message = "") { pagetop(gTxt('categories'), $message); $out = array(n.'
'. n.tag( hed(gTxt('tab_organise'), 1, array('class' => 'txp-heading')), 'div', array('class' => 'txp-layout-1col') ), n.tag(cat_article_list(), 'section', array( 'class' => 'txp-layout-4col', 'id' => 'categories_article', ) ), n.tag(cat_image_list(), 'section', array( 'class' => 'txp-layout-4col', 'id' => 'categories_image', ) ), n.tag(cat_file_list(), 'section', array( 'class' => 'txp-layout-4col', 'id' => 'categories_file', ) ), n.tag(cat_link_list(), 'section', array( 'class' => 'txp-layout-4col', 'id' => 'categories_link', ) ), n.'
', // End of .txp-layout. script_js(<< array('label' => gTxt('changeparent'), 'html' => $categories), 'deleteforce' => gTxt('deleteforce'), 'delete' => gTxt('delete'), ); if ($array) { return form( join('', $array). hInput('type', $area). multi_edit($methods, 'category', 'cat_category_multiedit', '', '', '', '', '', $area), '', '', 'post', 'category-tree', '', 'category_'.$area.'_form' ); } return; } /** * Processes multi-edit actions. */ function cat_category_multiedit() { $type = ps('type'); $method = ps('edit_method'); $things = ps('selected'); if (is_array($things) and $things and in_array($type, array('article', 'image', 'link', 'file'))) { $things = array_map('assert_int', $things); if ($method == 'delete' || $method == 'deleteforce') { if ($type === 'article') { $used = "name NOT IN (SELECT category1 FROM ".safe_pfx('textpattern').") AND name NOT IN (SELECT category2 FROM ".safe_pfx('textpattern').")"; } else { $used = "name NOT IN (SELECT category FROM ".safe_pfx('txp_'.$type).")"; } $rs = safe_rows("id, name", 'txp_category', "id IN (".join(',', $things).") AND type = '".$type."'".(($method == 'deleteforce') ? '' : " AND rgt - lft = 1 AND ".$used)); if ($rs) { foreach ($rs as $cat) { $catid[] = $cat['id']; $names[] = doSlash($cat['name']); } if (safe_delete('txp_category', "id IN (".join(',', $catid).")")) { if ($method == 'deleteforce') { // Clear the deleted category names from assets. $affected = join("','", $names); if ($type === 'article') { safe_update('textpattern', "category1 = ''", "category1 IN ('$affected')"); safe_update('textpattern', "category2 = ''", "category2 IN ('$affected')"); } else { safe_update('txp_'.$type, "category = ''", "category IN ('$affected')"); } // Promote subcatagories of deleted catagories to root. safe_update('txp_category', "parent = 'root'", "parent IN ('$affected')"); } rebuild_tree_full($type); callback_event('categories_deleted', $type, 0, $catid); $message = gTxt($type.'_categories_deleted', array('{list}' => join(', ', $catid))); return cat_category_list($message); } } } elseif ($method == 'changeparent') { $new_parent = ps('new_parent'); $rs = safe_rows("id, name", 'txp_category', "id IN (".join(',', $things).") AND type = '".$type."'"); if ($rs) { $exists = safe_field("name", 'txp_category', "name = '".doSlash($new_parent)."' AND type = '$type'"); $parent = ($exists === false) ? 'root' : $exists; $to_change = $affected = array(); foreach ($rs as $cat) { // Cannot assign parent to itself. if ($cat['name'] != $new_parent) { $to_change[] = doSlash($cat['name']); $affected[] = $cat['name']; } } $ret = safe_update('txp_category', "parent = '".doSlash($parent)."'", "name IN ('".join("','", $to_change)."') AND type = '".$type."'"); if ($ret) { rebuild_tree_full($type); $message = gTxt('categories_set_parent', array('{type}' => gTxt($type), '{parent}' => $parent, '{list}' => join(', ', $affected))); return cat_category_list($message); } } } } return cat_category_list(); } /** * Renders a list of categories. * * @param string $event Type of category * @return string HTML */ function cat_event_category_list($event) { $rs = getTree('root', $event); $parent = ps('parent_cat'); $heading = 'tab_'.($event == 'article' ? 'list' : $event); $for = $rs ? ' for="'.$event.'_category_parent"' : ''; $out = hed(gTxt($heading).popHelp($event.'_category'), 2). form( graf( tag(gTxt('create_new_category'), 'label', array('for' => $event.'_category_new')).br. fInput('text', 'title', '', '', '', '', INPUT_REGULAR, '', $event.'_category_new') ). (($rs) ? graf(''.gTxt('parent').''.br. treeSelectInput('parent_cat', $rs, $parent, $event.'_category_parent'), array('class' => 'parent')) : '' ). graf( fInput('submit', '', gTxt('Create')). eInput('category'). sInput('cat_'.$event.'_create') ), '', '', 'post', $event); if ($rs) { $total_count = array(); if ($event == 'article') { // Count distinct articles for both categories, avoid duplicates. $rs2 = getRows( "SELECT category, COUNT(*) AS num FROM ( SELECT ID, Category1 AS category FROM ".safe_pfx('textpattern')." UNION SELECT ID, Category2 AS category FROM ".safe_pfx('textpattern')." ) AS t WHERE category != '' GROUP BY category"); if ($rs2 !== false) { foreach ($rs2 as $a) { $total_count[$a['category']] = $a['num']; } } } else { switch ($event) { case 'link': $rs2 = safe_rows_start("category, COUNT(*) AS num", 'txp_link', "1 = 1 GROUP BY category"); break; case 'image': $rs2 = safe_rows_start("category, COUNT(*) AS num", 'txp_image', "1 = 1 GROUP BY category"); break; case 'file': $rs2 = safe_rows_start("category, COUNT(*) AS num", 'txp_file', "1 = 1 GROUP BY category"); break; } while ($a = nextRow($rs2)) { $name = $a['category']; $num = $a['num']; $total_count[$name] = $num; } } $items = array(); foreach ($rs as $a) { extract($a); // Format count. switch ($event) { case 'article': $url = 'index.php?event=list'.a.'search_method=categories'.a.'crit='.$name; break; case 'link': $url = 'index.php?event=link'.a.'search_method=category'.a.'crit='.$name; break; case 'image': $url = 'index.php?event=image'.a.'search_method=category'.a.'crit='.$name; break; case 'file': $url = 'index.php?event=file'.a.'search_method=category'.a.'crit='.$name; break; } $count = isset($total_count[$name]) ? href('('.$total_count[$name].')', $url) : '(0)'; if (empty($title)) { $edit_link = ''.eLink('category', 'cat_'.$event.'_edit', 'id', $id, gTxt('untitled')).''; } else { $edit_link = eLink('category', 'cat_'.$event.'_edit', 'id', $id, $title); } $items[] = graf( checkbox('selected[]', $id, 0).sp.str_repeat(sp.sp, $level * 2).$edit_link.sp.$count, ' class="level-'.$level.'"'); } if ($items) { $out .= cat_article_multiedit_form($event, $items); } } else { $out .= graf( span(null, array('class' => 'ui-icon ui-icon-info')).' '. gTxt('no_categories_exist'), array('class' => 'alert-block information') ); } return $out; } /** * Creates a new category. * * @param string $event The type of category */ function cat_event_category_create($event) { $title = ps('title'); $name = strtolower(sanitizeForUrl($title)); if (!$name) { $message = array(gTxt($event.'_category_invalid', array('{name}' => $title)), E_ERROR); return cat_category_list($message); } $exists = safe_field("name", 'txp_category', "name = '".doSlash($name)."' AND type = '".doSlash($event)."'"); if ($exists !== false) { $message = array(gTxt($event.'_category_already_exists', array('{name}' => $name)), E_ERROR); return cat_category_list($message); } $parent = strtolower(sanitizeForUrl(ps('parent_cat'))); $parent_exists = safe_field("name", 'txp_category', "name = '".doSlash($parent)."' AND type = '".doSlash($event)."'"); $parent = ($parent_exists !== false) ? $parent_exists : 'root'; $q = safe_insert('txp_category', "name = '".doSlash($name)."', title = '".doSlash($title)."', type = '".doSlash($event)."', parent = '".$parent."'"); if ($q) { rebuild_tree_full($event); $message = gTxt($event.'_category_created', array('{name}' => $name)); cat_category_list($message); } else { cat_category_list(array(gTxt('category_save_failed'), E_ERROR)); } } /** * Renders and outputs a category editor panel. * * @param string $evname Type of category */ function cat_event_category_edit($evname, $message = '') { $id = assert_int(gps('id')); $parent = doSlash(gps('parent')); $row = safe_row("*", 'txp_category', "id = $id"); if ($row) { pagetop(gTxt('edit_category'), $message); extract($row); list($parent_widget, $has_parent) = cat_parent_pop($parent, $evname, $id); $out = hed(gTxt('edit_category'), 2). inputLabel( 'category_name', fInput('text', 'name', $name, '', '', '', INPUT_REGULAR, '', 'category_name'), $evname.'_category_name', '', array('class' => 'txp-form-field edit-category-name') ). inputLabel( 'category_parent', $parent_widget, 'parent', '', array('class' => 'txp-form-field edit-category-parent') ). inputLabel( 'category_title', fInput('text', 'title', $title, '', '', '', INPUT_REGULAR, '', 'category_title'), $evname.'_category_title', '', array('class' => 'txp-form-field edit-category-title') ). inputLabel( 'category_description', '', $evname.'_category_description', 'category_description', array('class' => 'txp-form-field txp-form-field-textarea edit-category-description') ). pluggable_ui('category_ui', 'extend_detail_form', '', $row). hInput('id', $id). graf( sLink('category', '', gTxt('cancel'), 'txp-button'). fInput('submit', '', gTxt('save'), 'publish'), array('class' => 'txp-edit-actions') ). eInput('category'). sInput('cat_'.$evname.'_save'). hInput('old_name', $name); echo form($out, '', '', 'post', 'txp-edit'); } else { cat_category_list(array(gTxt('category_not_found'), E_ERROR)); } } /** * Saves a category from HTTP POST data. * * @param string $event Type of category * @param string $table Affected database table */ function cat_event_category_save($event, $table_name) { extract(doSlash(array_map('assert_string', psa(array('id', 'name', 'description', 'old_name', 'parent', 'title'))))); $id = assert_int($id); $rawname = $name; $name = sanitizeForUrl($rawname); // Make sure the name is valid. if (!$name) { $message = array(gTxt($event.'_category_invalid', array('{name}' => $rawname)), E_ERROR); return cat_event_category_edit($event, $message); } // Don't allow rename to clobber an existing category. $existing_id = safe_field("id", 'txp_category', "name = '$name' AND type = '$event'"); if ($existing_id and $existing_id != $id) { $message = array(gTxt($event.'_category_already_exists', array('{name}' => $name)), E_ERROR); return cat_event_category_edit($event, $message); } // TODO: validate parent? $parent = ($parent) ? $parent : 'root'; $message = array(gTxt('category_save_failed'), E_ERROR); if (safe_update('txp_category', "name = '$name', parent = '$parent', title = '$title', description = '$description'", "id = $id") && safe_update('txp_category', "parent = '$name'", "parent = '$old_name' AND type = '$event'")) { rebuild_tree_full($event); if ($event == 'article') { if (safe_update('textpattern', "Category1 = '$name'", "Category1 = '$old_name'") && safe_update('textpattern', "Category2 = '$name'", "Category2 = '$old_name'")) { $message = gTxt($event.'_category_updated', array('{name}' => doStrip($name))); } } else { if (safe_update($table_name, "category = '$name'", "category = '$old_name'")) { $message = gTxt($event.'_category_updated', array('{name}' => doStrip($name))); } } } cat_category_list($message); } /** * Renders a list of file categories. */ function cat_file_list() { return cat_event_category_list('file'); } /** * Processes a saved editor form and creates a file category. */ function cat_file_create() { return cat_event_category_create('file'); } /** * Renders an editor form for file categories. */ function cat_file_edit() { return cat_event_category_edit('file'); } /** * Saves a file category. */ function cat_file_save() { return cat_event_category_save('file', 'txp_file'); }