Textpattern | PHP Cross Reference | Content Management Systems |
Description: Forms panel.
1 <?php 2 3 /* 4 * Textpattern Content Management System 5 * http://textpattern.com 6 * 7 * Copyright (C) 2005 Dean Allen 8 * Copyright (C) 2016 The Textpattern Development Team 9 * 10 * This file is part of Textpattern. 11 * 12 * Textpattern is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation, version 2. 15 * 16 * Textpattern is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with Textpattern. If not, see <http://www.gnu.org/licenses/>. 23 */ 24 25 /** 26 * Forms panel. 27 * 28 * @package Admin\Form 29 */ 30 31 if (!defined('txpinterface')) { 32 die('txpinterface is undefined.'); 33 } 34 35 /** 36 * List of essential forms. 37 * 38 * @global array $essential_forms 39 */ 40 41 $essential_forms = array( 42 'comments', 43 'comments_display', 44 'comment_form', 45 'default', 46 'plainlinks', 47 'files', 48 ); 49 50 /** 51 * List of form types. 52 * 53 * @global array $form_types 54 */ 55 56 $form_types = array( 57 'article' => gTxt('article'), 58 'misc' => gTxt('misc'), 59 'comment' => gTxt('comment'), 60 'category' => gTxt('category'), 61 'file' => gTxt('file'), 62 'link' => gTxt('link'), 63 'section' => gTxt('section'), 64 ); 65 66 if ($event == 'form') { 67 require_privs('form'); 68 69 bouncer($step, array( 70 'form_edit' => false, 71 'form_create' => false, 72 'form_delete' => true, 73 'form_multi_edit' => true, 74 'form_save' => true, 75 'tagbuild' => false, 76 )); 77 78 switch (strtolower($step)) { 79 case '': 80 form_edit(); 81 break; 82 case 'form_edit': 83 form_edit(); 84 break; 85 case 'form_create': 86 form_create(); 87 break; 88 case 'form_delete': 89 form_delete(); 90 break; 91 case 'form_multi_edit': 92 form_multi_edit(); 93 break; 94 case 'form_save': 95 form_save(); 96 break; 97 case 'tagbuild': 98 echo form_tagbuild(); 99 break; 100 } 101 } 102 103 /** 104 * Renders a list of form templates. 105 * 106 * This function returns a list of form templates, wrapped in a multi-edit 107 * form widget. 108 * 109 * @param string $curname The selected form 110 * @return string HTML 111 */ 112 113 function form_list($curname) 114 { 115 global $essential_forms, $form_types; 116 117 $criteria = 1; 118 $criteria .= callback_event('admin_criteria', 'form_list', 0, $criteria); 119 120 $rs = safe_rows_start( 121 "name, type", 122 'txp_form', 123 "$criteria ORDER BY FIELD(type, ".join(',', quote_list(array_keys($form_types))).") ASC, name ASC" 124 ); 125 126 if ($rs) { 127 $prev_type = null; 128 $group_out = array(); 129 130 while ($a = nextRow($rs)) { 131 extract($a); 132 $active = ($curname === $name); 133 134 if ($prev_type !== $type) { 135 if ($prev_type !== null) { 136 $group_out = tag(n.join(n, $group_out).n, 'ul', array( 137 'class' => 'switcher-list', 138 )); 139 140 $out[] = wrapRegion($prev_type.'_forms_group', $group_out, 'form_'.$prev_type, $form_types[$prev_type], 'form_'.$prev_type); 141 } 142 143 $prev_type = $type; 144 $group_out = array(); 145 } 146 147 $editlink = eLink('form', 'form_edit', 'name', $name, $name); 148 149 if (!in_array($name, $essential_forms)) { 150 $modbox = span( 151 checkbox('selected_forms[]', txpspecialchars($name), false), array('class' => 'switcher-action')); 152 } else { 153 $modbox = ''; 154 } 155 156 $group_out[] = tag(n.$modbox.$editlink.n, 'li', array( 157 'class' => $active ? 'active' : '', 158 )); 159 } 160 161 if ($prev_type !== null) { 162 $group_out = tag(n.join(n, $group_out).n, 'ul', array( 163 'class' => 'switcher-list', 164 )); 165 166 $out[] = wrapRegion($prev_type.'_forms_group', $group_out, 'form_'.$prev_type, $form_types[$prev_type], 'form_'.$prev_type); 167 } 168 169 $methods = array( 170 'changetype' => array('label' => gTxt('changetype'), 'html' => formTypes('', false, 'changetype')), 171 'delete' => gTxt('delete'), 172 ); 173 174 $out[] = multi_edit($methods, 'form', 'form_multi_edit'); 175 176 return form(join('', $out), '', '', 'post', '', '', 'allforms_form'); 177 } 178 } 179 180 /** 181 * Processes multi-edit actions. 182 */ 183 184 function form_multi_edit() 185 { 186 $method = ps('edit_method'); 187 $forms = ps('selected_forms'); 188 $affected = array(); 189 190 if ($forms && is_array($forms)) { 191 if ($method == 'delete') { 192 foreach ($forms as $name) { 193 if (form_delete($name)) { 194 $affected[] = $name; 195 } 196 } 197 198 callback_event('forms_deleted', '', 0, $affected); 199 200 $message = gTxt('forms_deleted', array('{list}' => join(', ', $affected))); 201 202 form_edit($message); 203 } 204 205 if ($method == 'changetype') { 206 $new_type = ps('type'); 207 208 foreach ($forms as $name) { 209 if (form_set_type($name, $new_type)) { 210 $affected[] = $name; 211 } 212 } 213 214 $message = gTxt('forms_updated', array('{list}' => join(', ', $affected))); 215 216 form_edit($message); 217 } 218 } else { 219 form_edit(); 220 } 221 } 222 223 /** 224 * Creates a new form. 225 * 226 * Directs requests back to the main editor panel, armed with a 227 * 'form_create' step. 228 */ 229 230 function form_create() 231 { 232 form_edit(); 233 } 234 235 /** 236 * Renders the main Form editor panel. 237 * 238 * @param string|array $message The activity message 239 */ 240 241 function form_edit($message = '') 242 { 243 global $event, $step, $essential_forms; 244 245 pagetop(gTxt('edit_forms'), $message); 246 247 extract(array_map('assert_string', gpsa(array( 248 'copy', 249 'save_error', 250 'savenew', 251 )))); 252 253 $name = sanitizeForPage(assert_string(gps('name'))); 254 $type = assert_string(gps('type')); 255 $newname = sanitizeForPage(assert_string(gps('newname'))); 256 257 if ($step == 'form_delete' || empty($name) && $step != 'form_create' && !$savenew) { 258 $name = 'default'; 259 } elseif (((($copy || $savenew) && $newname) || ($newname && $newname !== $name)) && !$save_error) { 260 $name = $newname; 261 } 262 263 $Form = gps('Form'); 264 265 if (!$save_error) { 266 $rs = safe_row("*", 'txp_form', "name = '".doSlash($name)."'"); 267 extract($rs); 268 } 269 270 if (in_array($name, $essential_forms)) { 271 $name_widgets = inputLabel( 272 'new_form', 273 fInput('text', 'newname', $name, 'input-medium', '', '', INPUT_MEDIUM, '', 'new_form', true), 274 'form_name', 275 array('', 'instructions_form_name'), 276 array('class' => 'txp-form-field name') 277 ); 278 279 $type_widgets = inputLabel( 280 'type', 281 formTypes($type, false, 'type', true), 282 'form_type', 283 array('', 'instructions_form_type'), 284 array('class' => 'txp-form-field type') 285 ); 286 } else { 287 $name_widgets = inputLabel( 288 'new_form', 289 fInput('text', 'newname', $name, 'input-medium', '', '', INPUT_MEDIUM, '', 'new_form', false, true), 290 'form_name', 291 array('', 'instructions_form_name'), 292 array('class' => 'txp-form-field name') 293 ); 294 295 $type_widgets = inputLabel( 296 'type', 297 formTypes($type, false), 298 'form_type', 299 array('', 'instructions_form_type'), 300 array('class' => 'txp-form-field type') 301 ); 302 } 303 304 if ($name === '') { 305 $name_widgets .= hInput('savenew', 'savenew'); 306 } else { 307 $name_widgets .= hInput('name', $name); 308 } 309 310 $name_widgets .= eInput('form').sInput('form_save'); 311 312 $actionsExtras = ''; 313 314 if ($name) { 315 $actionsExtras .= href('<span class="ui-icon ui-icon-copy"></span> '.gTxt('duplicate'), '#', array( 316 'class' => 'txp-clone', 317 'data-form' => 'form_form', 318 )); 319 } 320 321 $actions = graf( 322 sLink('form', 'form_create', '<span class="ui-icon ui-extra-icon-new-document"></span> '.gTxt('create_new_form'), 'txp-new'). 323 $actionsExtras, 324 array('class' => 'txp-actions txp-actions-inline') 325 ); 326 327 $buttons = graf( 328 tag_void('input', array( 329 'class' => 'publish', 330 'type' => 'submit', 331 'method' => 'post', 332 'value' => gTxt('save'), 333 )), ' class="txp-save"' 334 ); 335 336 $listActions = graf( 337 href('<span class="ui-icon ui-icon-arrowthickstop-1-s"></span> '.gTxt('expand_all'), '#', array( 338 'class' => 'txp-expand-all', 339 'aria-controls' => 'allforms_form', 340 )). 341 href('<span class="ui-icon ui-icon-arrowthickstop-1-n"></span> '.gTxt('collapse_all'), '#', array( 342 'class' => 'txp-collapse-all', 343 'aria-controls' => 'allforms_form', 344 )), array('class' => 'txp-actions') 345 ); 346 347 echo n.'<div class="txp-layout">'. 348 n.tag( 349 hed(gTxt('tab_forms').popHelp('forms_overview'), 1, array('class' => 'txp-heading')), 350 'div', array('class' => 'txp-layout-1col') 351 ); 352 353 // Forms create/switcher column. 354 echo n.tag( 355 $listActions.n. 356 form_list($name).n, 357 'div', array( 358 'class' => 'txp-layout-4col-alt', 359 'id' => 'content_switcher', 360 'role' => 'region', 361 ) 362 ); 363 364 // Forms code columm. 365 echo n.tag( 366 form( 367 $actions. 368 $name_widgets. 369 $type_widgets. 370 inputLabel( 371 'form', 372 '<textarea class="code" id="form" name="Form" cols="'.INPUT_LARGE.'" rows="'.TEXTAREA_HEIGHT_LARGE.'" dir="ltr">'.txpspecialchars($Form).'</textarea>', 373 array( 374 'form_code', 375 n.href('<span class="ui-icon ui-extra-icon-code"></span> '.gTxt('tagbuilder'), '#', array('class' => 'txp-tagbuilder-dialog')), 376 ), 377 array('', 'instructions_form_code'), 378 array('class' => 'txp-form-field'), 379 array('div', 'div') 380 ). 381 $buttons 382 , '', '', 'post', '', '', 'form_form'), 383 'div', array( 384 'class' => 'txp-layout-4col-3span', 385 'id' => 'main_content', 386 'role' => 'region', 387 ) 388 ); 389 390 // Tag builder dialog. 391 echo n.tag( 392 form_tagbuild(), 393 'div', array( 394 'class' => 'txp-tagbuilder-content', 395 'id' => 'tagbuild_links', 396 'aria-label' => gTxt('tagbuilder'), 397 'title' => gTxt('tagbuilder'), 398 )); 399 400 echo n.'</div>'; // End of .txp-layout. 401 } 402 403 /** 404 * Saves a form template. 405 */ 406 407 function form_save() 408 { 409 global $essential_forms, $form_types; 410 411 extract(doSlash(array_map('assert_string', psa(array( 412 'savenew', 413 'Form', 414 'type', 415 'copy', 416 ))))); 417 418 $name = sanitizeForPage(assert_string(ps('name'))); 419 $newname = sanitizeForPage(assert_string(ps('newname'))); 420 421 $save_error = false; 422 $message = ''; 423 424 if (in_array($name, $essential_forms)) { 425 $newname = $name; 426 $type = fetch('type', 'txp_form', 'name', $newname); 427 $_POST['newname'] = $newname; 428 } 429 430 if (!$newname) { 431 $message = array(gTxt('form_name_invalid'), E_ERROR); 432 $save_error = true; 433 } else { 434 if (!isset($form_types[$type])) { 435 $message = array(gTxt('form_type_missing'), E_ERROR); 436 $save_error = true; 437 } else { 438 if ($copy && $name === $newname) { 439 $newname .= '_copy'; 440 $_POST['newname'] = $newname; 441 } 442 443 $exists = safe_field("name", 'txp_form', "name = '".doSlash($newname)."'"); 444 445 if ($newname !== $name && $exists !== false) { 446 $message = array(gTxt('form_already_exists', array('{name}' => $newname)), E_ERROR); 447 if ($savenew) { 448 $_POST['newname'] = ''; 449 } 450 451 $save_error = true; 452 } else { 453 if ($savenew or $copy) { 454 if ($newname) { 455 if (safe_insert( 456 'txp_form', 457 "Form = '$Form', 458 type = '$type', 459 name = '".doSlash($newname)."'" 460 )) { 461 update_lastmod('form_created', compact('newname', 'name', 'type', 'Form')); 462 $message = gTxt('form_created', array('{name}' => $newname)); 463 } else { 464 $message = array(gTxt('form_save_failed'), E_ERROR); 465 $save_error = true; 466 } 467 } else { 468 $message = array(gTxt('form_name_invalid'), E_ERROR); 469 $save_error = true; 470 } 471 } else { 472 if (safe_update( 473 'txp_form', 474 "Form = '$Form', 475 type = '$type', 476 name = '".doSlash($newname)."'", 477 "name = '".doSlash($name)."'" 478 )) { 479 update_lastmod('form_saved', compact('newname', 'name', 'type', 'Form')); 480 $message = gTxt('form_updated', array('{name}' => $name)); 481 } else { 482 $message = array(gTxt('form_save_failed'), E_ERROR); 483 $save_error = true; 484 } 485 } 486 } 487 } 488 } 489 490 if ($save_error === true) { 491 $_POST['save_error'] = '1'; 492 } else { 493 callback_event('form_saved', '', 0, $name, $newname); 494 } 495 496 form_edit($message); 497 } 498 499 /** 500 * Deletes a form template with the given name. 501 * 502 * @param string $name The form template 503 * @return bool FALSE on error 504 */ 505 506 function form_delete($name) 507 { 508 global $essential_forms; 509 510 if (in_array($name, $essential_forms)) { 511 return false; 512 } 513 514 $name = doSlash($name); 515 516 return safe_delete('txp_form', "name = '$name'"); 517 } 518 519 /** 520 * Changes a form template's type. 521 * 522 * @param string $name The form template 523 * @param string $type The new type 524 * @return bool FALSE on error 525 */ 526 527 function form_set_type($name, $type) 528 { 529 global $essential_forms, $form_types; 530 531 if (in_array($name, $essential_forms) || !isset($form_types[$type])) { 532 return false; 533 } 534 535 $name = doSlash($name); 536 $type = doSlash($type); 537 538 return safe_update('txp_form', "type = '$type'", "name = '$name'"); 539 } 540 541 /** 542 * Renders a <select> input listing all form types. 543 * 544 * @param string $type The selected option 545 * @param bool $blank_first If TRUE, the list defaults to an empty selection 546 * @param string $id HTML id attribute value 547 * @param bool $disabled If TRUE renders the select disabled 548 * @return string HTML 549 * @access private 550 */ 551 552 function formTypes($type, $blank_first = true, $id = 'type', $disabled = false) 553 { 554 global $form_types; 555 556 return selectInput('type', $form_types, $type, $blank_first, '', $id, false, $disabled); 557 } 558 559 /** 560 * Return a list of tag builder tags. 561 * 562 * @return HTML 563 */ 564 565 function form_tagbuild() 566 { 567 $listActions = graf( 568 href('<span class="ui-icon ui-icon-arrowthickstop-1-s"></span> '.gTxt('expand_all'), '#', array( 569 'class' => 'txp-expand-all', 570 'aria-controls' => 'tagbuild_links', 571 )). 572 href('<span class="ui-icon ui-icon-arrowthickstop-1-n"></span> '.gTxt('collapse_all'), '#', array( 573 'class' => 'txp-collapse-all', 574 'aria-controls' => 'tagbuild_links', 575 )), array('class' => 'txp-actions') 576 ); 577 578 // Generate the tagbuilder links. 579 // Format of each entry is popTagLink -> array ( gTxt string, class/ID ). 580 $tagbuild_items = array( 581 'article' => array('articles', 'article-tags'), 582 'link' => array('links', 'link-tags'), 583 'comment' => array('comments', 'comment-tags'), 584 'comment_details' => array('comment_details', 'comment-detail-tags'), 585 'comment_form' => array('comment_form', 'comment-form-tags'), 586 'search_result' => array('search_results_form', 'search-result-tags'), 587 'file_download' => array('file_download_tags', 'file-tags'), 588 'category' => array('category_tags', 'category-tags'), 589 'section' => array('section_tags', 'section-tags'), 590 ); 591 592 $tagbuild_links = ''; 593 594 foreach ($tagbuild_items as $tb => $item) { 595 $tagbuild_links .= wrapRegion($item[1].'_group', popTagLinks($tb), $item[1], $item[0], $item[1]); 596 } 597 598 return $listActions.$tagbuild_links; 599 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
title