. */ /** * Images panel. * * @package Admin\Image */ use Textpattern\Validator\CategoryConstraint; use Textpattern\Validator\Validator; use Textpattern\Search\Filter; if (!defined('txpinterface')) { die('txpinterface is undefined.'); } global $extensions; $extensions = get_safe_image_types(); include txpath.'/lib/class.thumb.php'; if ($event == 'image') { require_privs('image'); global $all_image_cats, $all_image_authors; $all_image_cats = getTree('root', 'image'); $all_image_authors = the_privileged('image.edit.own', true); $available_steps = array( 'image_list' => false, 'image_edit' => false, 'image_insert' => true, 'image_replace' => true, 'image_save' => true, 'thumbnail_insert' => true, 'image_change_pageby' => true, 'thumbnail_create' => true, 'thumbnail_delete' => true, 'image_multi_edit' => true, ); if ($step && bouncer($step, $available_steps)) { $step(); } else { image_list(); } } /** * The main panel listing all images. * * @param string|array $message The activity message */ function image_list($message = '') { global $file_max_upload_size, $txp_user, $event; pagetop(gTxt('tab_image'), $message); extract(gpsa(array( 'page', 'sort', 'dir', 'crit', 'search_method', ))); if ($sort === '') { $sort = get_pref('image_sort_column', 'id'); } else { if (!in_array($sort, array('name', 'thumbnail', 'category', 'date', 'author'))) { $sort = 'id'; } set_pref('image_sort_column', $sort, 'image', PREF_HIDDEN, '', 0, PREF_PRIVATE); } if ($dir === '') { $dir = get_pref('image_sort_dir', 'desc'); } else { $dir = ($dir == 'asc') ? "asc" : "desc"; set_pref('image_sort_dir', $dir, 'image', PREF_HIDDEN, '', 0, PREF_PRIVATE); } switch ($sort) { case 'name': $sort_sql = "txp_image.name $dir"; break; case 'thumbnail': $sort_sql = "txp_image.thumbnail $dir, txp_image.id ASC"; break; case 'category': $sort_sql = "txp_category.title $dir, txp_image.id ASC"; break; case 'date': $sort_sql = "txp_image.date $dir, txp_image.id ASC"; break; case 'author': $sort_sql = "txp_users.RealName $dir, txp_image.id ASC"; break; default: $sort = 'id'; $sort_sql = "txp_image.id $dir"; break; } $switch_dir = ($dir == 'desc') ? 'asc' : 'desc'; $search = new Filter($event, array( 'id' => array( 'column' => 'txp_image.id', 'label' => gTxt('id'), 'type' => 'integer', ), 'name' => array( 'column' => 'txp_image.name', 'label' => gTxt('name'), ), 'alt' => array( 'column' => 'txp_image.alt', 'label' => gTxt('alt_text'), ), 'caption' => array( 'column' => 'txp_image.caption', 'label' => gTxt('caption'), ), 'category' => array( 'column' => array('txp_image.category', 'txp_category.title'), 'label' => gTxt('category'), ), 'ext' => array( 'column' => 'txp_image.ext', 'label' => gTxt('extension'), ), 'author' => array( 'column' => array('txp_image.author', 'txp_users.RealName'), 'label' => gTxt('author'), ), 'thumbnail' => array( 'column' => array('txp_image.thumbnail'), 'label' => gTxt('thumbnail'), 'type' => 'boolean', ), ) ); $alias_yes = '1, Yes'; $alias_no = '0, No'; $search->setAliases('thumbnail', array($alias_no, $alias_yes)); list($criteria, $crit, $search_method) = $search->getFilter(array('id' => array('can_list' => true))); $search_render_options = array('placeholder' => 'search_images'); $sql_from = safe_pfx_j('txp_image')." LEFT JOIN ".safe_pfx_j('txp_category')." ON txp_category.name = txp_image.category AND txp_category.type = 'image' LEFT JOIN ".safe_pfx_j('txp_users')." ON txp_users.name = txp_image.author"; if ($crit === '') { $total = getCount('txp_image', $criteria); } else { $total = getThing("SELECT COUNT(*) FROM $sql_from WHERE $criteria"); } $searchBlock = n.tag( $search->renderForm('image_list', $search_render_options), 'div', array( 'class' => 'txp-layout-4col-3span', 'id' => $event.'_control', ) ); $createBlock = array(); if (!is_dir(IMPATH) or !is_writeable(IMPATH)) { $createBlock[] = graf( span(null, array('class' => 'ui-icon ui-icon-alert')).' '. gTxt('img_dir_not_writeable', array('{imgdir}' => IMPATH)), array('class' => 'alert-block warning') ); } elseif (has_privs('image.edit.own')) { $categories = event_category_popup('image', '', 'image_category'); $createBlock[] = n.tag( n.upload_form('upload_image', 'upload_image', 'image_insert[]', 'image', '', $file_max_upload_size, '', 'async', '', array('postinput' => ($categories ? n.tag( n.tag(gTxt('category'), 'label', array('for' => 'image_category')).$categories.n, 'span', array('class' => 'inline-file-uploader-actions')) : '' )), 'image/*' ), 'div', array('class' => 'txp-control-panel') ); } $createBlock = implode(n, $createBlock); $contentBlock = ''; $paginator = new \Textpattern\Admin\Paginator(); $limit = $paginator->getLimit(); list($page, $offset, $numPages) = pager($total, $limit, $page); if ($total < 1) { $contentBlock .= graf( span(null, array('class' => 'ui-icon ui-icon-info')).' '. gTxt($crit === '' ? 'no_images_recorded' : 'no_results_found'), array('class' => 'alert-block information') ); } else { $rs = safe_query( "SELECT txp_image.id, txp_image.name, txp_image.category, txp_image.ext, txp_image.w, txp_image.h, txp_image.alt, txp_image.caption, UNIX_TIMESTAMP(txp_image.date) AS uDate, txp_image.author, txp_image.thumbnail, txp_image.thumb_w, txp_image.thumb_h, txp_users.RealName AS realname, txp_category.Title AS category_title FROM $sql_from WHERE $criteria ORDER BY $sort_sql LIMIT $offset, $limit" ); $contentBlock .= pluggable_ui('image_ui', 'extend_controls', '', $rs); if ($rs && numRows($rs)) { $show_authors = !has_single_author('txp_image'); $contentBlock .= n.tag_start('form', array( 'class' => 'multi_edit_form', 'id' => 'images_form', 'name' => 'longform', 'method' => 'post', 'action' => 'index.php', )). n.tag_start('div', array( 'class' => 'txp-listtables', 'tabindex' => 0, 'aria-label' => gTxt('list'), )). n.tag_start('table', array('class' => 'txp-list')). n.tag_start('thead'). tr( hCell( fInput('checkbox', 'select_all', 0, '', '', '', '', '', 'select_all'), '', ' class="txp-list-col-multi-edit" scope="col" title="'.gTxt('toggle_all_selected').'"' ). column_head( 'ID', 'id', 'image', true, $switch_dir, $crit, $search_method, (('id' == $sort) ? "$dir " : '').'txp-list-col-id' ). column_head( 'name', 'name', 'image', true, $switch_dir, $crit, $search_method, (('name' == $sort) ? "$dir " : '').'txp-list-col-name' ). column_head( 'date', 'date', 'image', true, $switch_dir, $crit, $search_method, (('date' == $sort) ? "$dir " : '').'txp-list-col-created date' ). column_head( 'thumbnail', 'thumbnail', 'image', true, $switch_dir, $crit, $search_method, (('thumbnail' == $sort) ? "$dir " : '').'txp-list-col-thumbnail' ). (has_privs('tag') ? hCell( gTxt('tags'), '', ' class="txp-list-col-tag-build" scope="col"' ) : '' ). column_head( 'category', 'category', 'image', true, $switch_dir, $crit, $search_method, (('category' == $sort) ? "$dir " : '').'txp-list-col-category category' ). ( $show_authors ? column_head('author', 'author', 'image', true, $switch_dir, $crit, $search_method, (('author' == $sort) ? "$dir " : '').'txp-list-col-author name') : '' ) ). n.tag_end('thead'). n.tag_start('tbody'); $validator = new Validator(); while ($a = nextRow($rs)) { extract($a); $edit_url = array( 'event' => 'image', 'step' => 'image_edit', 'id' => $id, 'sort' => $sort, 'dir' => $dir, 'page' => $page, 'search_method' => $search_method, 'crit' => $crit, ); $name = empty($name) ? 'unnamed' : txpspecialchars($name); if ($thumbnail) { if ($ext != '.swf') { $thumbnail = ''; $thumbexists = 1; } else { $thumbnail = ''; $thumbexists = ''; } } else { $thumbnail = gTxt('no'); $thumbexists = ''; } if ($ext != '.swf') { $tagName = 'image'; $tag_url = array( 'id' => $id, 'ext' => $ext, 'w' => $w, 'h' => $h, 'alt' => urlencode($alt), 'caption' => urlencode($caption), 'step' => 'build', ); $tagbuilder = popTag($tagName, 'Textile', array('type' => 'textile') + $tag_url). sp.span('|', array('role' => 'separator')). sp.popTag($tagName, 'Textpattern', array('type' => 'textpattern') + $tag_url). sp.span('|', array('role' => 'separator')). sp.popTag($tagName, 'HTML', array('type' => 'html') + $tag_url); } else { $tagbuilder = sp; } $validator->setConstraints(array(new CategoryConstraint($category, array('type' => 'image')))); $vc = $validator->validate() ? '' : ' error'; if ($category) { $category = span(txpspecialchars($category_title), array('title' => $category)); } $can_view = has_privs('image.edit.own'); $can_edit = has_privs('image.edit') || ($author === $txp_user && $can_view); $contentBlock .= tr( td( $can_edit ? fInput('checkbox', 'selected[]', $id) : ' ', '', 'txp-list-col-multi-edit' ). hCell( ($can_view ? href($id, $edit_url, array('title' => gTxt('edit'))) : $id) , '', array( 'class' => 'txp-list-col-id', 'scope' => 'row', ) ). td( ($can_view ? href($name, $edit_url, ' title="'.gTxt('edit').'"') : $name), '', 'txp-list-col-name txp-contain' ). td( gTime($uDate), '', 'txp-list-col-created date' ). td( pluggable_ui('image_ui', 'thumbnail', ($can_edit ? href($thumbnail, $edit_url) : $thumbnail), $a), '', 'txp-list-col-thumbnail'.($thumbexists ? ' has-thumbnail' : '') ). (has_privs('tag') ? td( $tagbuilder, '', 'txp-list-col-tag-build' ) : '' ). td( $category, '', 'txp-list-col-category category'.$vc ). ( $show_authors ? td(span(txpspecialchars($realname), array('title' => $author)), '', 'txp-list-col-author name') : '' ) ); } $contentBlock .= n.tag_end('tbody'). n.tag_end('table'). n.tag_end('div'). // End of .txp-listtables. image_multiedit_form($page, $sort, $dir, $crit, $search_method). tInput(). n.tag_end('form'); } } $pageBlock = $paginator->render(). nav_form($event, $page, $numPages, $sort, $dir, $crit, $search_method, $total, $limit); $table = new \Textpattern\Admin\Table($event); echo $table->render(compact('total', 'crit'), $searchBlock, $createBlock, $contentBlock, $pageBlock). n.tag( null, 'div', array( 'class' => 'txp-tagbuilder-content', 'id' => 'tagbuild_links', 'aria-label' => gTxt('tagbuilder'), 'title' => gTxt('tagbuilder'), )); } /** * Renders a multi-edit form widget for images. * * @param int $page The page number * @param string $sort The current sort value * @param string $dir The current sort direction * @param string $crit The current search criteria * @param string $search_method The current search method * @return string HTML */ function image_multiedit_form($page, $sort, $dir, $crit, $search_method) { global $all_image_cats, $all_image_authors; $categories = $all_image_cats ? treeSelectInput('category', $all_image_cats, '') : ''; $authors = $all_image_authors ? selectInput('author', $all_image_authors, '', true) : ''; $methods = array( 'changecategory' => array( 'label' => gTxt('changecategory'), 'html' => $categories, ), 'changeauthor' => array( 'label' => gTxt('changeauthor'), 'html' => $authors, ), 'delete' => gTxt('delete'), ); if (!$categories) { unset($methods['changecategory']); } if (has_single_author('txp_image') || !has_privs('image.edit')) { unset($methods['changeauthor']); } if (!has_privs('image.delete.own') && !has_privs('image.delete')) { unset($methods['delete']); } return multi_edit($methods, 'image', 'image_multi_edit', $page, $sort, $dir, $crit, $search_method); } /** * Processes multi-edit actions. */ function image_multi_edit() { global $txp_user, $all_image_cats, $all_image_authors; // Empty entry to permit clearing the category. $categories = array(''); foreach ($all_image_cats as $row) { $categories[] = $row['name']; } $selected = ps('selected'); if (!$selected || !is_array($selected)) { return image_list(); } // Fetch and remove bogus (false) entries to prevent SQL syntax errors being thrown. $selected = array_map('assert_int', $selected); $selected = array_filter($selected); $method = ps('edit_method'); $changed = array(); $key = ''; switch ($method) { case 'delete': return image_delete($selected); break; case 'changecategory': $val = ps('category'); if (in_array($val, $categories)) { $key = 'category'; } break; case 'changeauthor': $val = ps('author'); if (has_privs('image.edit') && isset($all_image_authors[$val])) { $key = 'author'; } break; default: $key = ''; $val = ''; break; } if (!has_privs('image.edit')) { if ($selected && has_privs('image.edit.own')) { $selected = safe_column("id", 'txp_image', "id IN (".join(',', $selected).") AND author = '".doSlash($txp_user)."'"); } else { $selected = array(); } } if ($selected && $key) { foreach ($selected as $id) { if (safe_update('txp_image', "$key = '".doSlash($val)."'", "id = '$id'")) { $changed[] = $id; } } } if ($changed) { update_lastmod('image_updated', $changed); return image_list(gTxt('image_updated', array('{name}' => join(', ', $changed)))); } return image_list(); } /** * Renders and outputs the image editor panel. * * @param string|array $message The activity message * @param int $id The image ID */ function image_edit($message = '', $id = '') { global $file_max_upload_size, $txp_user, $event, $all_image_cats; if (!$id) { $id = gps('id'); } $id = assert_int($id); $rs = safe_row("*, UNIX_TIMESTAMP(date) AS uDate", 'txp_image', "id = '$id'"); if ($rs) { extract($rs); if (!has_privs('image.edit') && !has_privs('image.edit.own')) { require_privs('image.edit'); return; } pagetop(gTxt('edit_image'), $message); extract(gpsa(array( 'page', 'sort', 'dir', 'crit', 'search_method', ))); if ($ext != '.swf') { $aspect = ($h == $w) ? ' square' : (($h > $w) ? ' portrait' : ' landscape'); $img_info = $id.$ext.' ('.$w.' × '.$h.')'; $img = '
'; } else { $img = $aspect = ''; } if ($thumbnail and ($ext != '.swf')) { $thumb_info = $id.'t'.$ext.' ('.$thumb_w.' × '.$thumb_h.')'; $thumb = ''; } else { $thumb = ''; if ($thumb_w == 0) { $thumb_w = get_pref('thumb_w', 0); } if ($thumb_h == 0) { $thumb_h = get_pref('thumb_h', 0); } } $imageBlock = array(); $thumbBlock = array(); $can_edit = has_privs('image.edit') || ($author === $txp_user && has_privs('image.edit.own')); $can_upload = $can_edit && is_dir(IMPATH) && is_writeable(IMPATH); $imageBlock[] = ($can_upload ? pluggable_ui( 'image_ui', 'image_edit', upload_form('replace_image', 'replace_image_form', 'image_replace', 'image', $id, $file_max_upload_size, 'image-upload', ' image-replace', array('div', 'div'), '' ,'image/*'), $rs) : '' ); $imageBlock[] = pluggable_ui( 'image_ui', 'fullsize_image', $img, $rs ); $thumbBlock[] = ($can_upload ? hed(gTxt('create_thumbnail').popHelp('create_thumbnail'), 3) : hed(gTxt('thumbnail'), 3) ); $thumbBlock[] = ($can_upload ? pluggable_ui( 'image_ui', 'thumbnail_edit', upload_form('upload_thumbnail', 'upload_thumbnail', 'thumbnail_insert', 'image', $id, $file_max_upload_size, 'thumbnail-upload', ' thumbnail-upload', array('div', 'div'), '' ,'image/*'), $rs) : '' ); $thumbBlock[] = (check_gd($ext)) ? ($can_upload ? pluggable_ui( 'image_ui', 'thumbnail_create', form( graf( n.''. fInput('text', 'width', @$thumb_w, 'input-xsmall', '', '', INPUT_XSMALL, '', 'width'). n.''.gTxt('swap_values').''. n.''. fInput('text', 'height', @$thumb_h, 'input-xsmall', '', '', INPUT_XSMALL, '', 'height'). n.''. checkbox('crop', 1, get_pref('thumb_crop'), '', 'crop'). fInput('submit', '', gTxt('create')), ' class="edit-alter-thumbnail"' ). hInput('id', $id). eInput('image'). sInput('thumbnail_create'). hInput('sort', $sort). hInput('dir', $dir). hInput('page', $page). hInput('search_method', $search_method). hInput('crit', $crit), '', '', 'post', '', '', 'thumbnail_alter_form'), $rs) : '' ) : ''; $thumbBlock[] = pluggable_ui( 'image_ui', 'thumbnail_image', '