[ Index ]

PHP Cross Reference of Drupal 6 (yi-drupal)

title

Body

[close]

/sites/all/modules/ctools/plugins/export_ui/ -> ctools_export_ui.class.php (source)

   1  <?php
   2  // $Id: ctools_export_ui.class.php,v 1.1.2.20 2010/10/15 21:05:55 merlinofchaos Exp $
   3  
   4  /**
   5   * Base class for export UI.
   6   */
   7  class ctools_export_ui {
   8    var $plugin;
   9    var $name;
  10    var $options = array();
  11  
  12    /**
  13     * Fake constructor -- this is easier to deal with than the real
  14     * constructor because we are retaining PHP4 compatibility, which
  15     * would require all child classes to implement their own constructor.
  16     */
  17    function init($plugin) {
  18      ctools_include('export');
  19  
  20      $this->plugin = $plugin;
  21    }
  22  
  23    /**
  24     * Get a page title for the current page from our plugin strings.
  25     */
  26    function get_page_title($op, $item = NULL) {
  27      if (empty($this->plugin['strings']['title'][$op])) {
  28        return;
  29      }
  30  
  31      // Replace %title that might be there with the exportable title.
  32      $title = $this->plugin['strings']['title'][$op];
  33      if (!empty($item)) {
  34        $export_key = $this->plugin['export']['key'];
  35        $title = (str_replace('%title', check_plain($item->{$export_key}), $title));
  36      }
  37  
  38      return $title;
  39    }
  40  
  41    /**
  42     * Add text on the top of the page.
  43     */
  44    function help_area($form_state) {
  45        // If needed add advanced help strings.
  46      $output = '';
  47      if (!empty($this->plugin['use advanced help'])) {
  48        $config = $this->plugin['advanced help'];
  49        if ($config['enabled']) {
  50          $output = theme('advanced_help_topic', $config['module'], $config['topic']);
  51          $output .= '&nbsp;' . $this->plugin['strings']['advanced help']['enabled'];
  52        }
  53        else {
  54          $output = $this->plugin['strings']['advanced help']['disabled'];
  55        }
  56      }
  57      return $output;
  58    }
  59  
  60    // ------------------------------------------------------------------------
  61    // Menu item manipulation
  62  
  63    /**
  64     * hook_menu() entry point.
  65     *
  66     * Child implementations that need to add or modify menu items should
  67     * probably call parent::hook_menu($items) and then modify as needed.
  68     */
  69    function hook_menu(&$items) {
  70      // During upgrades, the schema can be empty as this is called prior to
  71      // actual update functions being run. Ensure that we can cope with this
  72      // situation.
  73      if (empty($this->plugin['schema'])) {
  74        return;
  75      }
  76  
  77      $prefix = ctools_export_ui_plugin_base_path($this->plugin);
  78  
  79      if (isset($this->plugin['menu']['items']) && is_array($this->plugin['menu']['items'])) {
  80        $my_items = array();
  81        foreach ($this->plugin['menu']['items'] as $item) {
  82          // Add menu item defaults.
  83          $item += array(
  84            'file' => 'export-ui.inc',
  85            'file path' => drupal_get_path('module', 'ctools') . '/includes',
  86          );
  87  
  88          $path = !empty($item['path']) ? $prefix . '/' . $item['path'] : $prefix;
  89          unset($item['path']);
  90          $my_items[$path] = $item;
  91        }
  92        $items += $my_items;
  93      }
  94    }
  95  
  96    /**
  97     * Menu callback to determine if an operation is accessible.
  98     *
  99     * This function enforces a basic access check on the configured perm
 100     * string, and then additional checks as needed.
 101     *
 102     * @param $op
 103     *   The 'op' of the menu item, which is defined by 'allowed operations'
 104     *   and embedded into the arguments in the menu item.
 105     * @param $item
 106     *   If an op that works on an item, then the item object, otherwise NULL.
 107     *
 108     * @return
 109     *   TRUE if the current user has access, FALSE if not.
 110     */
 111    function access($op, $item) {
 112      if (!user_access($this->plugin['access'])) {
 113        return FALSE;
 114      }
 115  
 116      // More fine-grained access control:
 117      if ($op == 'add' && !user_access($this->plugin['create access'])) {
 118        return FALSE;
 119      }
 120  
 121      // More fine-grained access control:
 122      if (($op == 'revert' || $op == 'delete') && !user_access($this->plugin['delete access'])) {
 123        return FALSE;
 124      }
 125  
 126      // If we need to do a token test, do it here.
 127      if (!empty($this->plugin['allowed operations'][$op]['token']) && (!isset($_GET['token']) || !drupal_valid_token($_GET['token'], $op))) {
 128        return FALSE;
 129      }
 130  
 131      switch ($op) {
 132        case 'import':
 133          return user_access('use PHP for block visibility');
 134        case 'revert':
 135          return ($item->export_type & EXPORT_IN_DATABASE) && ($item->export_type & EXPORT_IN_CODE);
 136        case 'delete':
 137          return ($item->export_type & EXPORT_IN_DATABASE) && !($item->export_type & EXPORT_IN_CODE);
 138        case 'disable':
 139          return empty($item->disabled);
 140        case 'enable':
 141          return !empty($item->disabled);
 142        default:
 143          return TRUE;
 144      }
 145    }
 146  
 147    // ------------------------------------------------------------------------
 148    // These methods are the API for generating the list of exportable items.
 149  
 150    /**
 151     * Master entry point for handling a list.
 152     *
 153     * It is unlikely that a child object will need to override this method,
 154     * unless the listing mechanism is going to be highly specialized.
 155     */
 156    function list_page($js, $input) {
 157      $this->items = ctools_export_crud_load_all($this->plugin['schema'], $js);
 158  
 159      // Respond to a reset command by clearing session and doing a drupal goto
 160      // back to the base URL.
 161      if (isset($input['op']) && $input['op'] == t('Reset')) {
 162        unset($_SESSION['ctools_export_ui'][$this->plugin['name']]);
 163        if (!$js) {
 164          return drupal_goto($_GET['q']);
 165        }
 166        // clear everything but form id, form build id and form token:
 167        $keys = array_keys($input);
 168        foreach ($keys as $id) {
 169          if (!in_array($id, array('form_id', 'form_build_id', 'form_token'))) {
 170            unset($input[$id]);
 171          }
 172        }
 173        $replace_form = TRUE;
 174      }
 175  
 176      // If there is no input, check to see if we have stored input in the
 177      // session.
 178      if (!isset($input['form_id'])) {
 179        if (isset($_SESSION['ctools_export_ui'][$this->plugin['name']]) && is_array($_SESSION['ctools_export_ui'][$this->plugin['name']])) {
 180          $input  = $_SESSION['ctools_export_ui'][$this->plugin['name']];
 181        }
 182      }
 183      else {
 184        $_SESSION['ctools_export_ui'][$this->plugin['name']] = $input;
 185        unset($_SESSION['ctools_export_ui'][$this->plugin['name']]['q']);
 186      }
 187  
 188      // This is where the form will put the output.
 189      $this->rows = array();
 190      $this->sorts = array();
 191  
 192      $form_state = array(
 193        'plugin' => $this->plugin,
 194        'input' => $input,
 195        'rerender' => TRUE,
 196        'no_redirect' => TRUE,
 197        'object' => &$this,
 198      );
 199  
 200      $help_area = $this->help_area($form_state);
 201  
 202      ctools_include('form');
 203      $form = ctools_build_form('ctools_export_ui_list_form', $form_state);
 204  
 205      $output = $this->list_header($form_state) . $this->list_render($form_state) . $this->list_footer($form_state);
 206  
 207      if (!$js) {
 208        $this->list_css();
 209        return $help_area . $form . $output;
 210      }
 211  
 212      ctools_include('ajax');
 213      $commands = array();
 214      $commands[] = ctools_ajax_command_replace('#ctools-export-ui-list-items', $output);
 215      if (!empty($replace_form)) {
 216        $commands[] = ctools_ajax_command_replace('#ctools-export-ui-list-form', $form);
 217      }
 218      ctools_ajax_render($commands);
 219    }
 220  
 221    /**
 222     * Create the filter/sort form at the top of a list of exports.
 223     *
 224     * This handles the very default conditions, and most lists are expected
 225     * to override this and call through to parent::list_form() in order to
 226     * get the base form and then modify it as necessary to add search
 227     * gadgets for custom fields.
 228     */
 229    function list_form(&$form, &$form_state) {
 230      // This forces the form to *always* treat as submitted which is
 231      // necessary to make it work.
 232      $form['#token'] = FALSE;
 233      if (empty($form_state['input'])) {
 234        $form["#post"] = TRUE;
 235      }
 236  
 237      // Add the 'q' in if we are not using clean URLs or it can get lost when
 238      // using this kind of form.
 239      if (!variable_get('clean_url', FALSE)) {
 240        $form['q'] = array(
 241          '#type' => 'hidden',
 242          '#value' => $_GET['q'],
 243        );
 244      }
 245  
 246      $all = array('all' => t('- All -'));
 247  
 248      $form['top row'] = array(
 249        '#prefix' => '<div class="ctools-export-ui-row ctools-export-ui-top-row clear-block">',
 250        '#suffix' => '</div>',
 251      );
 252  
 253      $form['bottom row'] = array(
 254        '#prefix' => '<div class="ctools-export-ui-row ctools-export-ui-bottom-row clear-block">',
 255        '#suffix' => '</div>',
 256      );
 257  
 258      $form['top row']['storage'] = array(
 259        '#type' => 'select',
 260        '#title' => t('Storage'),
 261        '#options' => $all + array(
 262          t('Normal') => t('Normal'),
 263          t('Default') => t('Default'),
 264          t('Overridden') => t('Overridden'),
 265        ),
 266        '#default_value' => 'all',
 267      );
 268  
 269      $form['top row']['disabled'] = array(
 270        '#type' => 'select',
 271        '#title' => t('Enabled'),
 272        '#options' => $all + array(
 273          '0' => t('Enabled'),
 274          '1' => t('Disabled')
 275        ),
 276        '#default_value' => 'all',
 277      );
 278  
 279      $form['top row']['search'] = array(
 280        '#type' => 'textfield',
 281        '#title' => t('Search'),
 282      );
 283  
 284      $form['bottom row']['order'] = array(
 285        '#type' => 'select',
 286        '#title' => t('Sort by'),
 287        '#options' => $this->list_sort_options(),
 288        '#default_value' => 'disabled',
 289      );
 290  
 291      $form['bottom row']['sort'] = array(
 292        '#type' => 'select',
 293        '#title' => t('Order'),
 294        '#options' => array(
 295          'asc' => t('Up'),
 296          'desc' => t('Down'),
 297        ),
 298        '#default_value' => 'asc',
 299      );
 300  
 301      $form['bottom row']['submit'] = array(
 302        '#type' => 'submit',
 303        '#id' => 'ctools-export-ui-list-items-apply',
 304        '#value' => t('Apply'),
 305        '#attributes' => array('class' => 'ctools-use-ajax ctools-auto-submit-click'),
 306      );
 307  
 308      $form['bottom row']['reset'] = array(
 309        '#type' => 'submit',
 310        '#id' => 'ctools-export-ui-list-items-apply',
 311        '#value' => t('Reset'),
 312        '#attributes' => array('class' => 'ctools-use-ajax'),
 313      );
 314  
 315      ctools_add_js('ajax-responder');
 316      ctools_add_js('auto-submit');
 317      drupal_add_js('misc/jquery.form.js');
 318  
 319      $form['#prefix'] = '<div class="clear-block">';
 320      $form['#suffix'] = '</div>';
 321      $form['#attributes'] = array('class' => 'ctools-auto-submit-full-form');
 322    }
 323  
 324    /**
 325     * Validate the filter/sort form.
 326     *
 327     * It is very rare that a filter form needs validation, but if it is
 328     * needed, override this.
 329     */
 330    function list_form_validate(&$form, &$form_state) { }
 331  
 332    /**
 333     * Submit the filter/sort form.
 334     *
 335     * This submit handler is actually responsible for building up all of the
 336     * rows that will later be rendered, since it is doing the filtering and
 337     * sorting.
 338     *
 339     * For the most part, you should not need to override this method, as the
 340     * fiddly bits call through to other functions.
 341     */
 342    function list_form_submit(&$form, &$form_state) {
 343      // Filter and re-sort the pages.
 344      $plugin = $this->plugin;
 345  
 346      $prefix = ctools_export_ui_plugin_base_path($plugin);
 347  
 348      foreach ($this->items as $name => $item) {
 349        // Call through to the filter and see if we're going to render this
 350        // row. If it returns TRUE, then this row is filtered out.
 351        if ($this->list_filter($form_state, $item)) {
 352          continue;
 353        }
 354  
 355        // Note: Creating this list seems a little clumsy, but can't think of
 356        // better ways to do this.
 357        $allowed_operations = drupal_map_assoc(array_keys($plugin['allowed operations']));
 358        $not_allowed_operations = array('import');
 359  
 360        if ($item->type == t('Normal')) {
 361          $not_allowed_operations[] = 'revert';
 362        }
 363        elseif ($item->type == t('Overridden')) {
 364          $not_allowed_operations[] = 'delete';
 365        }
 366        else {
 367          $not_allowed_operations[] = 'revert';
 368          $not_allowed_operations[] = 'delete';
 369        }
 370  
 371        $not_allowed_operations[] = empty($item->disabled) ? 'enable' : 'disable';
 372  
 373        foreach ($not_allowed_operations as $op) {
 374          // Remove the operations that are not allowed for the specific
 375          // exportable.
 376          unset($allowed_operations[$op]);
 377        }
 378  
 379        $operations = array();
 380  
 381        foreach ($allowed_operations as $op) {
 382          $operations[$op] = array(
 383            'title' => $plugin['allowed operations'][$op]['title'],
 384            'href' => ctools_export_ui_plugin_menu_path($plugin, $op, $name),
 385          );
 386          if (!empty($plugin['allowed operations'][$op]['ajax'])) {
 387            $operations[$op]['attributes'] = array('class' => 'ctools-use-ajax');
 388          }
 389          if (!empty($plugin['allowed operations'][$op]['token'])) {
 390            $operations[$op]['query'] = array('token' => drupal_get_token($op));
 391          }
 392        }
 393  
 394        $this->list_build_row($item, $form_state, $operations);
 395      }
 396  
 397      // Now actually sort
 398      if ($form_state['values']['sort'] == 'desc') {
 399        arsort($this->sorts);
 400      }
 401      else {
 402        asort($this->sorts);
 403      }
 404  
 405      // Nuke the original.
 406      $rows = $this->rows;
 407      $this->rows = array();
 408      // And restore.
 409      foreach ($this->sorts as $name => $title) {
 410        $this->rows[$name] = $rows[$name];
 411      }
 412    }
 413  
 414    /**
 415     * Determine if a row should be filtered out.
 416     *
 417     * This handles the default filters for the export UI list form. If you
 418     * added additional filters in list_form() then this is where you should
 419     * handle them.
 420     *
 421     * @return
 422     *   TRUE if the item should be excluded.
 423     */
 424    function list_filter($form_state, $item) {
 425      if ($form_state['values']['storage'] != 'all' && $form_state['values']['storage'] != $item->type) {
 426        return TRUE;
 427      }
 428  
 429      if ($form_state['values']['disabled'] != 'all' && $form_state['values']['disabled'] != !empty($item->disabled)) {
 430        return TRUE;
 431      }
 432  
 433      if ($form_state['values']['search']) {
 434        $search = strtolower($form_state['values']['search']);
 435        foreach ($this->list_search_fields() as $field) {
 436          if (strpos(strtolower($item->$field), $search) !== FALSE) {
 437            $hit = TRUE;
 438            break;
 439          }
 440        }
 441        if (empty($hit)) {
 442          return TRUE;
 443        }
 444      }
 445    }
 446  
 447    /**
 448     * Provide a list of fields to test against for the default "search" widget.
 449     *
 450     * This widget will search against whatever fields are configured here. By
 451     * default it will attempt to search against the name, title and description fields.
 452     */
 453    function list_search_fields() {
 454      $fields = array(
 455        $this->plugin['export']['key'],
 456      );
 457  
 458      if (!empty($this->plugin['export']['admin_title'])) {
 459        $fields[] = $this->plugin['export']['admin_title'];
 460      }
 461      if (!empty($this->plugin['export']['admin_description'])) {
 462        $fields[] = $this->plugin['export']['admin_description'];
 463      }
 464  
 465      return $fields;
 466    }
 467  
 468    /**
 469     * Provide a list of sort options.
 470     *
 471     * Override this if you wish to provide more or change how these work.
 472     * The actual handling of the sorting will happen in build_row().
 473     */
 474    function list_sort_options() {
 475      if (!empty($this->plugin['export']['admin_title'])) {
 476        $options = array(
 477          'disabled' => t('Enabled, title'),
 478          $this->plugin['export']['admin_title'] => t('Title'),
 479        );
 480      }
 481      else {
 482        $options = array(
 483          'disabled' => t('Enabled, name'),
 484        );
 485      }
 486  
 487      $options += array(
 488        'name' => t('Name'),
 489        'storage' => t('Storage'),
 490      );
 491  
 492      return $options;
 493    }
 494  
 495    /**
 496     * Add listing CSS to the page.
 497     *
 498     * Override this if you need custom CSS for your list.
 499     */
 500    function list_css() {
 501      ctools_add_css('export-ui-list');
 502    }
 503  
 504    /**
 505     * Build a row based on the item.
 506     *
 507     * By default all of the rows are placed into a table by the render
 508     * method, so this is building up a row suitable for theme('table').
 509     * This doesn't have to be true if you override both.
 510     */
 511    function list_build_row($item, &$form_state, $operations) {
 512      // Set up sorting
 513      $name = $item->{$this->plugin['export']['key']};
 514  
 515      // Note: $item->type should have already been set up by export.inc so
 516      // we can use it safely.
 517      switch ($form_state['values']['order']) {
 518        case 'disabled':
 519          $this->sorts[$name] = empty($item->disabled) . $name;
 520          break;
 521        case 'title':
 522          $this->sorts[$name] = $item->{$this->plugin['export']['admin_title']};
 523          break;
 524        case 'name':
 525          $this->sorts[$name] = $name;
 526          break;
 527        case 'storage':
 528          $this->sorts[$name] = $item->type . $name;
 529          break;
 530      }
 531  
 532      $this->rows[$name]['data'] = array();
 533      $this->rows[$name]['class'] = !empty($item->disabled) ? 'ctools-export-ui-disabled' : 'ctools-export-ui-enabled';
 534  
 535      // If we have an admin title, make it the first row.
 536      if (!empty($this->plugin['export']['admin_title'])) {
 537        $this->rows[$name]['data'][] = array('data' => check_plain($item->{$this->plugin['export']['admin_title']}), 'class' => 'ctools-export-ui-title');
 538      }
 539      $this->rows[$name]['data'][] = array('data' => check_plain($name), 'class' => 'ctools-export-ui-name');
 540      $this->rows[$name]['data'][] = array('data' => check_plain($item->type), 'class' => 'ctools-export-ui-storage');
 541      $this->rows[$name]['data'][] = array('data' => theme('links', $operations), 'class' => 'ctools-export-ui-operations');
 542  
 543      // Add an automatic mouseover of the description if one exists.
 544      if (!empty($this->plugin['export']['admin_description'])) {
 545        $this->rows[$name]['title'] = $item->{$this->plugin['export']['admin_description']};
 546      }
 547    }
 548  
 549    /**
 550     * Provide the table header.
 551     *
 552     * If you've added columns via list_build_row() but are still using a
 553     * table, override this method to set up the table header.
 554     */
 555    function list_table_header() {
 556      $header = array();
 557      if (!empty($this->plugin['export']['admin_title'])) {
 558        $header[] = array('data' => t('Title'), 'class' => 'ctools-export-ui-title');
 559      }
 560  
 561      $header[] = array('data' => t('Name'), 'class' => 'ctools-export-ui-name');
 562      $header[] = array('data' => t('Storage'), 'class' => 'ctools-export-ui-storage');
 563      $header[] = array('data' => t('Operations'), 'class' => 'ctools-export-ui-operations');
 564  
 565      return $header;
 566    }
 567  
 568    /**
 569     * Render all of the rows together.
 570     *
 571     * By default we place all of the rows in a table, and this should be the
 572     * way most lists will go.
 573     *
 574     * Whatever you do if this method is overridden, the ID is important for AJAX
 575     * so be sure it exists.
 576     */
 577    function list_render(&$form_state) {
 578      return theme('table', $this->list_table_header(), $this->rows, array('id' => 'ctools-export-ui-list-items'));
 579    }
 580  
 581    /**
 582     * Render a header to go before the list.
 583     *
 584     * This will appear after the filter/sort widgets.
 585     */
 586    function list_header($form_state) { }
 587  
 588    /**
 589     * Render a footer to go after thie list.
 590     *
 591     * This is a good place to add additional links.
 592     */
 593    function list_footer($form_state) { }
 594  
 595    // ------------------------------------------------------------------------
 596    // These methods are the API for adding/editing exportable items
 597  
 598    function add_page($js, $input, $step = NULL) {
 599      drupal_set_title($this->get_page_title('add'));
 600  
 601      // If a step not set, they are trying to create a new item. If a step
 602      // is set, they're in the process of creating an item.
 603      if (!empty($this->plugin['use wizard']) && !empty($step)) {
 604        $item = $this->edit_cache_get(NULL, 'add');
 605      }
 606      if (empty($item)) {
 607        $item = ctools_export_crud_new($this->plugin['schema']);
 608      }
 609  
 610      $form_state = array(
 611        'plugin' => $this->plugin,
 612        'object' => &$this,
 613        'ajax' => $js,
 614        'item' => $item,
 615        'op' => 'add',
 616        'form type' => 'add',
 617        'rerender' => TRUE,
 618        'no_redirect' => TRUE,
 619        'step' => $step,
 620        // Store these in case additional args are needed.
 621        'function args' => func_get_args(),
 622      );
 623  
 624      $output = $this->edit_execute_form($form_state);
 625      if (!empty($form_state['executed'])) {
 626        $export_key = $this->plugin['export']['key'];
 627        drupal_goto(str_replace('%ctools_export_ui', $form_state['item']->{$export_key}, $this->plugin['redirect']['add']));
 628      }
 629  
 630      return $output;
 631    }
 632  
 633    /**
 634     * Main entry point to edit an item.
 635     */
 636    function edit_page($js, $input, $item, $step = NULL) {
 637      drupal_set_title($this->get_page_title('edit', $item));
 638  
 639      // Check to see if there is a cached item to get if we're using the wizard.
 640      if (!empty($this->plugin['use wizard'])) {
 641        $cached = $this->edit_cache_get($item, 'edit');
 642        if (!empty($cached)) {
 643          $item = $cached;
 644        }
 645      }
 646  
 647      $form_state = array(
 648        'plugin' => $this->plugin,
 649        'object' => &$this,
 650        'ajax' => $js,
 651        'item' => $item,
 652        'op' => 'edit',
 653        'form type' => 'edit',
 654        'rerender' => TRUE,
 655        'no_redirect' => TRUE,
 656        'step' => $step,
 657        // Store these in case additional args are needed.
 658        'function args' => func_get_args(),
 659      );
 660  
 661      $output = $this->edit_execute_form($form_state);
 662      if (!empty($form_state['executed'])) {
 663        $export_key = $this->plugin['export']['key'];
 664        drupal_goto(str_replace('%ctools_export_ui', $form_state['item']->{$export_key}, $this->plugin['redirect']['edit']));
 665      }
 666  
 667      return $output;
 668    }
 669  
 670    /**
 671     * Main entry point to clone an item.
 672     */
 673    function clone_page($js, $input, $original, $step = NULL) {
 674      drupal_set_title($this->get_page_title('clone', $original));
 675  
 676      // If a step not set, they are trying to create a new clone. If a step
 677      // is set, they're in the process of cloning an item.
 678      if (!empty($this->plugin['use wizard']) && !empty($step)) {
 679        $item = $this->edit_cache_get(NULL, 'clone');
 680      }
 681      if (empty($item)) {
 682        // To make a clone of an item, we first export it and then re-import it.
 683        // Export the handler, which is a fantastic way to clean database IDs out of it.
 684        $export = ctools_export_crud_export($this->plugin['schema'], $original);
 685        $item = ctools_export_crud_import($this->plugin['schema'], $export);
 686        $item->{$this->plugin['export']['key']} = 'clone_of_' . $item->{$this->plugin['export']['key']};
 687      }
 688  
 689      // Tabs and breadcrumb disappearing, this helps alleviate through cheating.
 690      ctools_include('menu');
 691      $trail = ctools_get_menu_trail(ctools_export_ui_plugin_base_path($this->plugin));
 692      menu_set_active_trail($trail);
 693      $name = $original->{$this->plugin['export']['key']};
 694  
 695      $form_state = array(
 696        'plugin' => $this->plugin,
 697        'object' => &$this,
 698        'ajax' => $js,
 699        'item' => $item,
 700        'op' => 'add',
 701        'form type' => 'clone',
 702        'original name' => $name,
 703        'rerender' => TRUE,
 704        'no_redirect' => TRUE,
 705        'step' => $step,
 706        // Store these in case additional args are needed.
 707        'function args' => func_get_args(),
 708      );
 709  
 710      $output = $this->edit_execute_form($form_state);
 711      if (!empty($form_state['executed'])) {
 712        $export_key = $this->plugin['export']['key'];
 713        drupal_goto(str_replace('%ctools_export_ui', $form_state['item']->{$export_key}, $this->plugin['redirect']['clone']));
 714      }
 715  
 716      return $output;
 717    }
 718  
 719    /**
 720     * Execute the form.
 721     *
 722     * Add and Edit both funnel into this, but they have a few different
 723     * settings.
 724     */
 725    function edit_execute_form(&$form_state) {
 726      if (!empty($this->plugin['use wizard'])) {
 727        return $this->edit_execute_form_wizard($form_state);
 728      }
 729      else {
 730        return $this->edit_execute_form_standard($form_state);
 731      }
 732    }
 733  
 734    /**
 735     * Execute the standard form for editing.
 736     *
 737     * By default, export UI will provide a single form for editing an object.
 738     */
 739    function edit_execute_form_standard(&$form_state) {
 740      ctools_include('form');
 741      $output = ctools_build_form('ctools_export_ui_edit_item_form', $form_state);
 742      if (!empty($form_state['executed'])) {
 743        $this->edit_save_form($form_state);
 744      }
 745  
 746      return $output;
 747    }
 748  
 749    /**
 750     * Get the form info for the wizard.
 751     *
 752     * This gets the form info out of the plugin, then adds defaults based on
 753     * how we want edit forms to work.
 754     *
 755     * Overriding this can allow child UIs to tweak this info for specialized
 756     * wizards.
 757     *
 758     * @param array $form_state
 759     *   The already created form state.
 760     */
 761    function get_wizard_info(&$form_state) {
 762      if (!isset($form_state['step'])) {
 763        $form_state['step'] = NULL;
 764      }
 765  
 766      $export_key = $this->plugin['export']['key'];
 767  
 768      // When cloning, the name of the item being cloned is referenced in the
 769      // path, not the name of this item.
 770      if ($form_state['form type'] == 'clone') {
 771        $name = $form_state['original name'];
 772      }
 773      else {
 774        $name = $form_state['item']->{$export_key};
 775      }
 776  
 777      $form_info = !empty($this->plugin['form info']) ? $this->plugin['form info'] : array();
 778      $form_info += array(
 779        'id' => 'ctools_export_ui_edit',
 780        'path' => ctools_export_ui_plugin_menu_path($this->plugin, $form_state['form type'], $name) . '/%step',
 781        'show trail' => TRUE,
 782        'free trail' => TRUE,
 783        'show back' => $form_state['form type'] == 'add',
 784        'show return' => FALSE,
 785        'show cancel' => TRUE,
 786        'finish callback' => 'ctools_export_ui_wizard_finish',
 787        'next callback' => 'ctools_export_ui_wizard_next',
 788        'back callback' => 'ctools_export_ui_wizard_back',
 789        'cancel callback' => 'ctools_export_ui_wizard_cancel',
 790        'order' => array(),
 791        'import order' => array(
 792          'import' => t('Import code'),
 793          'settings' => t('Settings'),
 794        ),
 795      );
 796  
 797      // Set the order of forms based on the op if we have a specific one.
 798      if (isset($form_info[$form_state['form type'] . ' order'])) {
 799        $form_info['order'] = $form_info[$form_state['form type'] . ' order'];
 800      }
 801  
 802      // We have generic fallback forms we can use if they are not specified,
 803      // and they automatically delegate back to the UI object. Use these if
 804      // not specified.
 805      foreach ($form_info['order'] as $key => $title) {
 806        if (empty($form_info['forms'][$key])) {
 807          $form_info['forms'][$key] = array(
 808            'form id' => 'ctools_export_ui_edit_item_wizard_form',
 809          );
 810        }
 811      }
 812  
 813      // 'free trail' means the wizard can freely go back and form from item
 814      // via the trail and not with next/back buttons.
 815      if ($form_state['form type'] == 'add' || ($form_state['form type'] == 'import' && empty($form_state['item']->{$export_key}))) {
 816        $form_info['free trail'] = FALSE;
 817      }
 818  
 819      return $form_info;
 820    }
 821  
 822    /**
 823     * Execute the wizard for editing.
 824     *
 825     * For complex objects, sometimes a wizard is needed. This is normally
 826     * activated by setting 'use wizard' => TRUE in the plugin definition
 827     * and then creating a 'form info' array to feed the wizard the data
 828     * it needs.
 829     *
 830     * When creating this wizard, the plugin is responsible for defining all forms
 831     * that will be utilized with the wizard.
 832     *
 833     * Using 'add order' or 'edit order' can be used to ensure that add/edit order
 834     * is different.
 835     */
 836    function edit_execute_form_wizard(&$form_state) {
 837      $form_info = $this->get_wizard_info($form_state);
 838  
 839      // If there aren't any forms set, fail.
 840      if (empty($form_info['order'])) {
 841        return MENU_NOT_FOUND;
 842      }
 843  
 844      // Figure out if this is a new instance of the wizard
 845      if (empty($form_state['step'])) {
 846        $form_state['step'] = reset(array_keys($form_info['order']));
 847      }
 848  
 849      if (empty($form_info['order'][$form_state['step']]) && empty($form_info['forms'][$form_state['step']])) {
 850        return MENU_NOT_FOUND;
 851      }
 852  
 853      ctools_include('wizard');
 854      $output = ctools_wizard_multistep_form($form_info, $form_state['step'], $form_state);
 855      if (!empty($form_state['complete'])) {
 856        $this->edit_save_form($form_state);
 857      }
 858      else if ($output && !empty($form_state['item']->export_ui_item_is_cached)) {
 859        // @todo this should be in the plugin strings
 860        drupal_set_message(t('You have unsaved changes. These changes will not be made permanent until you click <em>Save</em>.'), 'warning');
 861      }
 862  
 863      // Unset the executed flag if any non-wizard button was pressed. Those
 864      // buttons require special handling by whatever client is operating them.
 865      if (!empty($form_state['executed']) && empty($form_state['clicked_button']['#wizard type'])) {
 866        unset($form_state['executed']);
 867      }
 868      return $output;
 869    }
 870  
 871    /**
 872     * Wizard 'back' callback when using a wizard to edit an item.
 873     *
 874     * The wizard callback delegates this back to the object.
 875     */
 876    function edit_wizard_back(&$form_state) {
 877      // This only exists so child implementations can use it.
 878    }
 879  
 880    /**
 881     * Wizard 'next' callback when using a wizard to edit an item.
 882     *
 883     * The wizard callback delegates this back to the object.
 884     */
 885    function edit_wizard_next(&$form_state) {
 886      $this->edit_cache_set($form_state['item'], $form_state['form type']);
 887    }
 888  
 889    /**
 890     * Wizard 'cancel' callback when using a wizard to edit an item.
 891     *
 892     * The wizard callback delegates this back to the object.
 893     */
 894    function edit_wizard_cancel(&$form_state) {
 895      $this->edit_cache_clear($form_state['item'], $form_state['form type']);
 896    }
 897  
 898    /**
 899     * Wizard 'cancel' callback when using a wizard to edit an item.
 900     *
 901     * The wizard callback delegates this back to the object.
 902     */
 903    function edit_wizard_finish(&$form_state) {
 904      $form_state['complete'] = TRUE;
 905  
 906      // If we are importing, and overwrite was selected, delete the original so
 907      // that this one writes properly.
 908      if ($form_state['form type'] == 'import' && !empty($form_state['item']->export_ui_allow_overwrite)) {
 909        ctools_export_crud_delete($this->plugin['schema'], $form_state['item']);
 910      }
 911  
 912      $this->edit_cache_clear($form_state['item'], $form_state['form type']);
 913    }
 914  
 915    /**
 916     * Retrieve the item currently being edited from the object cache.
 917     */
 918    function edit_cache_get($item, $op = 'edit') {
 919      ctools_include('object-cache');
 920      if (is_string($item)) {
 921        $name = $item;
 922      }
 923      else {
 924        $name = $this->edit_cache_get_key($item, $op);
 925      }
 926  
 927      $cache = ctools_object_cache_get('ctui_' . $this->plugin['name'], $name);
 928      if ($cache) {
 929        $cache->export_ui_item_is_cached = TRUE;
 930        return $cache;
 931      }
 932    }
 933  
 934    /**
 935     * Cache the item currently currently being edited.
 936     */
 937    function edit_cache_set($item, $op = 'edit') {
 938      ctools_include('object-cache');
 939      $name = $this->edit_cache_get_key($item, $op);
 940      return $this->edit_cache_set_key($item, $name);
 941    }
 942  
 943    function edit_cache_set_key($item, $name) {
 944      return ctools_object_cache_set('ctui_' . $this->plugin['name'], $name, $item);
 945    }
 946  
 947    /**
 948     * Clear the object cache for the currently edited item.
 949     */
 950    function edit_cache_clear($item, $op = 'edit') {
 951      ctools_include('object-cache');
 952      $name = $this->edit_cache_get_key($item, $op);
 953      return ctools_object_cache_clear('ctui_' . $this->plugin['name'], $name);
 954    }
 955  
 956    /**
 957     * Figure out what the cache key is for this object.
 958     */
 959    function edit_cache_get_key($item, $op) {
 960      $export_key = $this->plugin['export']['key'];
 961      return $op == 'edit' ? $item->{$this->plugin['export']['key']} : "::$op";
 962    }
 963  
 964    /**
 965     * Called to save the final product from the edit form.
 966     */
 967    function edit_save_form($form_state) {
 968      $item = &$form_state['item'];
 969      $export_key = $this->plugin['export']['key'];
 970  
 971      $result = ctools_export_crud_save($this->plugin['schema'], $item);
 972  
 973      if ($result) {
 974        $message = str_replace('%title', check_plain($item->{$export_key}), $this->plugin['strings']['confirmation'][$form_state['op']]['success']);
 975        drupal_set_message($message);
 976      }
 977      else {
 978        $message = str_replace('%title', check_plain($item->{$export_key}), $this->plugin['strings']['confirmation'][$form_state['op']]['fail']);
 979        drupal_set_message($message, 'error');
 980      }
 981    }
 982  
 983    /**
 984     * Provide the actual editing form.
 985     */
 986    function edit_form(&$form, &$form_state) {
 987      $export_key = $this->plugin['export']['key'];
 988      $item = $form_state['item'];
 989      $schema = ctools_export_get_schema($this->plugin['schema']);
 990  
 991      // TODO: Drupal 7 has a nifty method of auto guessing names from
 992      // titles that is standard. We should integrate that here as a
 993      // nice standard.
 994      // Guess at a couple of our standard fields.
 995      if (!empty($this->plugin['export']['admin_title'])) {
 996        $form['info'][$this->plugin['export']['admin_title']] = array(
 997          '#type' => 'textfield',
 998          '#title' => t('Administrative title'),
 999          '#description' => t('This will appear in the administrative interface to easily identify it.'),
1000          '#default_value' => $item->{$this->plugin['export']['admin_title']},
1001        );
1002      }
1003  
1004      $form['info'][$export_key] = array(
1005        '#title' => t($schema['export']['key name']),
1006        '#type' => 'textfield',
1007        '#default_value' => $item->{$export_key},
1008        '#description' => t('The unique ID for this @export.', array('@export' => $this->plugin['title singular'])),
1009        '#required' => TRUE,
1010        '#maxlength' => 255,
1011      );
1012  
1013      if ($form_state['op'] === 'edit') {
1014        $form['info'][$export_key]['#disabled'] = TRUE;
1015        $form['info'][$export_key]['#value'] = $item->{$export_key};
1016      }
1017      else {
1018        $form['info'][$export_key]['#element_validate'] = array('ctools_export_ui_edit_name_validate');
1019      }
1020  
1021      if (!empty($this->plugin['export']['admin_description'])) {
1022        $form['info'][$this->plugin['export']['admin_description']] = array(
1023          '#type' => 'textarea',
1024          '#title' => t('Administrative description'),
1025          '#default_value' => $item->{$this->plugin['export']['admin_description']},
1026        );
1027      }
1028  
1029      // Add plugin's form definitions.
1030      if (!empty($this->plugin['form']['settings'])) {
1031        // Pass $form by reference.
1032        $this->plugin['form']['settings']($form, $form_state);
1033      }
1034  
1035      // Add the buttons if the wizard is not in use.
1036      if (empty($form_state['form_info'])) {
1037        // Make sure that whatever happens, the buttons go to the bottom.
1038        $form['buttons']['#weight'] = 100;
1039  
1040        // Add buttons.
1041        $form['buttons']['submit'] = array(
1042          '#type' => 'submit',
1043          '#value' => t('Save'),
1044        );
1045  
1046        $form['buttons']['delete'] = array(
1047          '#type' => 'submit',
1048          '#value' => $item->export_type & EXPORT_IN_CODE ? t('Revert') : t('Delete'),
1049          '#access' => $form_state['op'] === 'edit' && $item->export_type & EXPORT_IN_DATABASE,
1050          '#submit' => array('ctools_export_ui_edit_item_form_delete'),
1051        );
1052      }
1053    }
1054  
1055    /**
1056     * Validate callback for the edit form.
1057     */
1058    function edit_form_validate(&$form, &$form_state) {
1059      if (!empty($this->plugin['form']['validate'])) {
1060        // Pass $form by reference.
1061        $this->plugin['form']['validate']($form, $form_state);
1062      }
1063    }
1064  
1065    /**
1066     * Perform a final validation check before allowing the form to be
1067     * finished.
1068     */
1069    function edit_finish_validate(&$form, &$form_state) {
1070      if ($form_state['op'] != 'edit') {
1071        // Validate the name. Fake an element for form_error().
1072        $export_key = $this->plugin['export']['key'];
1073        $element = array(
1074          '#value' => $form_state['item']->{$export_key},
1075          '#parents' => array('name'),
1076        );
1077        $form_state['plugin'] = $this->plugin;
1078        ctools_export_ui_edit_name_validate($element, $form_state);
1079      }
1080    }
1081  
1082    /**
1083     * Handle the submission of the edit form.
1084     *
1085     * At this point, submission is successful. Our only responsibility is
1086     * to copy anything out of values onto the item that we are able to edit.
1087     *
1088     * If the keys all match up to the schema, this method will not need to be
1089     * overridden.
1090     */
1091    function edit_form_submit(&$form, &$form_state) {
1092      if (!empty($this->plugin['form']['submit'])) {
1093        // Pass $form by reference.
1094        $this->plugin['form']['submit']($form, $form_state);
1095      }
1096  
1097      // Transfer data from the form to the $item based upon schema values.
1098      $schema = ctools_export_get_schema($this->plugin['schema']);
1099      foreach (array_keys($schema['fields']) as $key) {
1100        if(isset($form_state['values'][$key])) {
1101          $form_state['item']->{$key} = $form_state['values'][$key];
1102        }
1103      }
1104    }
1105  
1106    // ------------------------------------------------------------------------
1107    // These methods are the API for 'other' stuff with exportables such as
1108    // enable, disable, import, export, delete
1109  
1110    /**
1111     * Callback to enable a page.
1112     */
1113    function enable_page($js, $input, $item) {
1114      return $this->set_item_state(FALSE, $js, $input, $item);
1115    }
1116  
1117    /**
1118     * Callback to disable a page.
1119     */
1120    function disable_page($js, $input, $item) {
1121      return $this->set_item_state(TRUE, $js, $input, $item);
1122    }
1123  
1124    /**
1125     * Set an item's state to enabled or disabled and output to user.
1126     *
1127     * If javascript is in use, this will rebuild the list and send that back
1128     * as though the filter form had been executed.
1129     */
1130    function set_item_state($state, $js, $input, $item) {
1131      ctools_export_set_object_status($item, $state);
1132  
1133      if (!$js) {
1134        drupal_goto(ctools_export_ui_plugin_base_path($this->plugin));
1135      }
1136      else {
1137        return $this->list_page($js, $input);
1138      }
1139    }
1140  
1141    /**
1142     * Page callback to delete an exportable item.
1143     */
1144    function delete_page($js, $input, $item) {
1145      $form_state = array(
1146        'plugin' => $this->plugin,
1147        'object' => &$this,
1148        'ajax' => $js,
1149        'item' => $item,
1150        'op' => $item->export_type & EXPORT_IN_CODE ? 'revert' : 'delete',
1151        'rerender' => TRUE,
1152        'no_redirect' => TRUE,
1153      );
1154  
1155      ctools_include('form');
1156  
1157      $output = ctools_build_form('ctools_export_ui_delete_confirm_form', $form_state);
1158      if (!empty($form_state['executed'])) {
1159        ctools_export_crud_delete($this->plugin['schema'], $item);
1160        $export_key = $this->plugin['export']['key'];
1161        $message = str_replace('%title', check_plain($item->{$export_key}), $this->plugin['strings']['confirmation'][$form_state['op']]['success']);
1162        drupal_set_message($message);
1163        drupal_goto(ctools_export_ui_plugin_base_path($this->plugin));
1164      }
1165  
1166      return $output;
1167    }
1168  
1169    /**
1170     * Page callback to display export information for an exportable item.
1171     */
1172    function export_page($js, $input, $item) {
1173      drupal_set_title($this->get_page_title('export', $item));
1174      return drupal_get_form('ctools_export_form', ctools_export_crud_export($this->plugin['schema'], $item), t('Export'));
1175    }
1176  
1177    /**
1178     * Page callback to import information for an exportable item.
1179     */
1180    function import_page($js, $input, $step = NULL) {
1181      drupal_set_title($this->get_page_title('import'));
1182      // Import is basically a multi step wizard form, so let's go ahead and
1183      // use CTools' wizard.inc for it.
1184  
1185      // If a step not set, they are trying to create a new item. If a step
1186      // is set, they're in the process of creating an item.
1187      if (!empty($step)) {
1188        $item = $this->edit_cache_get(NULL, 'import');
1189      }
1190      if (empty($item)) {
1191        $item = ctools_export_crud_new($this->plugin['schema']);
1192      }
1193  
1194      $form_state = array(
1195        'plugin' => $this->plugin,
1196        'object' => &$this,
1197        'ajax' => $js,
1198        'item' => $item,
1199        'op' => 'add',
1200        'form type' => 'import',
1201        'rerender' => TRUE,
1202        'no_redirect' => TRUE,
1203        'step' => $step,
1204        // Store these in case additional args are needed.
1205        'function args' => func_get_args(),
1206      );
1207  
1208      // import always uses the wizard.
1209      $output = $this->edit_execute_form_wizard($form_state);
1210      if (!empty($form_state['executed'])) {
1211        $export_key = $this->plugin['export']['key'];
1212        drupal_goto(str_replace('%ctools_export_ui', $form_state['item']->{$export_key}, $this->plugin['redirect']['add']));
1213      }
1214  
1215      return $output;
1216    }
1217  
1218    /**
1219     * Import form. Provides simple helptext instructions and textarea for
1220     * pasting a export definition.
1221     */
1222    function edit_form_import(&$form, &$form_state) {
1223      $form['help'] = array(
1224        '#type' => 'item',
1225        '#value' => $this->plugin['strings']['help']['import'],
1226      );
1227  
1228      $form['import'] = array(
1229        '#title' => t('@plugin code', array('@plugin' => $this->plugin['title singular proper'])),
1230        '#type' => 'textarea',
1231        '#rows' => 10,
1232        '#required' => TRUE,
1233        '#default_value' => !empty($form_state['item']->export_ui_code) ? $form_state['item']->export_ui_code : '',
1234      );
1235  
1236      $form['overwrite'] = array(
1237        '#title' => t('Allow import to overwrite an existing record.'),
1238        '#type' => 'checkbox',
1239        '#default_value' => !empty($form_state['item']->export_ui_allow_overwrite) ? $form_state['item']->export_ui_allow_overwrite : FALSE,
1240      );
1241    }
1242  
1243    /**
1244     * Import form validate handler.
1245     *
1246     * Evaluates code and make sure it creates an object before we continue.
1247     */
1248    function edit_form_import_validate($form, &$form_state) {
1249      $item = ctools_export_crud_import($this->plugin['schema'], $form_state['values']['import']);
1250      if (is_string($item)) {
1251        form_error($form['import'], t('Unable to get an import from the code. Errors reported: @errors', array('@errors' => $item)));
1252        return;
1253      }
1254  
1255      $form_state['item'] = $item;
1256      $form_state['item']->export_ui_allow_overwrite = $form_state['values']['overwrite'];
1257      $form_state['item']->export_ui_code = $form_state['values']['import'];
1258    }
1259  
1260    /**
1261     * Submit callback for import form.
1262     *
1263     * Stores the item in the session.
1264     */
1265    function edit_form_import_submit($form, &$form_state) {
1266      // The validate function already imported and stored the item. This
1267      // function exists simply to prevent it from going to the default
1268      // edit_form_submit() method.
1269    }
1270  }
1271  
1272  // -----------------------------------------------------------------------
1273  // Forms to be used with this class.
1274  //
1275  // Since Drupal's forms are completely procedural, these forms will
1276  // mostly just be pass-throughs back to the object.
1277  
1278  /**
1279   * Form callback to handle the filter/sort form when listing items.
1280   *
1281   * This simply loads the object defined in the plugin and hands it off.
1282   */
1283  function ctools_export_ui_list_form(&$form_state) {
1284    $form = array();
1285    $form_state['object']->list_form($form, $form_state);
1286    return $form;
1287  }
1288  
1289  /**
1290   * Validate handler for ctools_export_ui_list_form.
1291   */
1292  function ctools_export_ui_list_form_validate(&$form, &$form_state) {
1293    $form_state['object']->list_form_validate($form, $form_state);
1294  }
1295  
1296  /**
1297   * Submit handler for ctools_export_ui_list_form.
1298   */
1299  function ctools_export_ui_list_form_submit(&$form, &$form_state) {
1300    $form_state['object']->list_form_submit($form, $form_state);
1301  }
1302  
1303  /**
1304   * Form callback to edit an exportable item.
1305   *
1306   * This simply loads the object defined in the plugin and hands it off.
1307   */
1308  function ctools_export_ui_edit_item_form(&$form_state) {
1309    $form = array();
1310    $form_state['object']->edit_form($form, $form_state);
1311    return $form;
1312  }
1313  
1314  /**
1315   * Validate handler for ctools_export_ui_edit_item_form.
1316   */
1317  function ctools_export_ui_edit_item_form_validate(&$form, &$form_state) {
1318    $form_state['object']->edit_form_validate($form, $form_state);
1319  }
1320  
1321  /**
1322   * Submit handler for ctools_export_ui_edit_item_form.
1323   */
1324  function ctools_export_ui_edit_item_form_submit(&$form, &$form_state) {
1325    $form_state['object']->edit_form_submit($form, $form_state);
1326  }
1327  
1328  /**
1329   * Submit handler to delete for ctools_export_ui_edit_item_form
1330   *
1331   * @todo Put this on a callback in the object.
1332   */
1333  function ctools_export_ui_edit_item_form_delete(&$form, &$form_state) {
1334    $export_key = $form_state['plugin']['export']['key'];
1335    $path = $form_state['item']->export_type & EXPORT_IN_CODE ? 'revert' : 'delete';
1336  
1337    drupal_goto(ctools_export_ui_plugin_menu_path($form_state['plugin'], $path, $form_state['item']->{$export_key}), array('cancel_path' => $_GET['q']));
1338  }
1339  
1340  /**
1341   * Validate that an export item name is acceptable and unique during add.
1342   */
1343  function ctools_export_ui_edit_name_validate($element, &$form_state) {
1344    $plugin = $form_state['plugin'];
1345    // Check for string identifier sanity
1346    if (!preg_match('!^[a-z0-9_]+$!', $element['#value'])) {
1347      form_error($element, t('The export id can only consist of lowercase letters, underscores, and numbers.'));
1348      return;
1349    }
1350  
1351    // Check for name collision
1352    if (empty($form_state['item']->export_ui_allow_overwrite) && $exists = ctools_export_crud_load($plugin['schema'], $element['#value'])) {
1353      form_error($element, t('A @plugin with this name already exists. Please choose another name or delete the existing item before creating a new one.', array('@plugin' => $plugin['title singular'])));
1354    }
1355  }
1356  
1357  /**
1358   * Delete/Revert confirm form.
1359   *
1360   * @todo -- call back into the object instead.
1361   */
1362  function ctools_export_ui_delete_confirm_form(&$form_state) {
1363    $plugin = $form_state['plugin'];
1364    $item = $form_state['item'];
1365  
1366    $form = array();
1367  
1368    $export_key = $plugin['export']['key'];
1369    $question = str_replace('%title', check_plain($item->{$export_key}), $plugin['strings']['confirmation'][$form_state['op']]['question']);
1370    $path = empty($_REQUEST['cancel_path']) ? ctools_export_ui_plugin_base_path($plugin) : $_REQUEST['cancel_path'];
1371  
1372    $form = confirm_form($form,
1373      $question,
1374      $path,
1375      $plugin['strings']['confirmation'][$form_state['op']]['information'],
1376      $plugin['allowed operations'][$form_state['op']]['title'], t('Cancel')
1377    );
1378    return $form;
1379  }
1380  
1381  // --------------------------------------------------------------------------
1382  // Forms and callbacks for using the edit system with the wizard.
1383  
1384  /**
1385   * Form callback to edit an exportable item using the wizard
1386   *
1387   * This simply loads the object defined in the plugin and hands it off.
1388   */
1389  function ctools_export_ui_edit_item_wizard_form(&$form, &$form_state) {
1390    $method = 'edit_form_' . $form_state['step'];
1391    if (!method_exists($form_state['object'], $method)) {
1392      $method = 'edit_form';
1393    }
1394  
1395    $form_state['object']->$method($form, $form_state);
1396    return $form;
1397  }
1398  
1399  /**
1400   * Validate handler for ctools_export_ui_edit_item_wizard_form.
1401   */
1402  function ctools_export_ui_edit_item_wizard_form_validate(&$form, &$form_state) {
1403    $method = 'edit_form_' . $form_state['step'] . '_validate';
1404    if (!method_exists($form_state['object'], $method)) {
1405      $method = 'edit_form_validate';
1406    }
1407  
1408    $form_state['object']->$method($form, $form_state);
1409  
1410    // Additionally, if there were no errors from that, and we're finishing,
1411    // perform a final validate to make sure everything is ok.
1412    if (isset($form_state['clicked_button']['#wizard type']) && $form_state['clicked_button']['#wizard type'] == 'finish' && !form_get_errors()) {
1413      $form_state['object']->edit_finish_validate($form, $form_state);
1414    }
1415  }
1416  
1417  /**
1418   * Submit handler for ctools_export_ui_edit_item_wizard_form.
1419   */
1420  function ctools_export_ui_edit_item_wizard_form_submit(&$form, &$form_state) {
1421    $method = 'edit_form_' . $form_state['step'] . '_submit';
1422    if (!method_exists($form_state['object'], $method)) {
1423      $method = 'edit_form_submit';
1424    }
1425  
1426    $form_state['object']->$method($form, $form_state);
1427  }
1428  
1429  /**
1430   * Wizard 'back' callback when using a wizard to edit an item.
1431   */
1432  function ctools_export_ui_wizard_back(&$form_state) {
1433    $form_state['object']->edit_wizard_back($form_state);
1434  }
1435  
1436  /**
1437   * Wizard 'next' callback when using a wizard to edit an item.
1438   */
1439  function ctools_export_ui_wizard_next(&$form_state) {
1440    $form_state['object']->edit_wizard_next($form_state);
1441  }
1442  
1443  /**
1444   * Wizard 'cancel' callback when using a wizard to edit an item.
1445   */
1446  function ctools_export_ui_wizard_cancel(&$form_state) {
1447    $form_state['object']->edit_wizard_cancel($form_state);
1448  }
1449  
1450  /**
1451   * Wizard 'finish' callback when using a wizard to edit an item.
1452   */
1453  function ctools_export_ui_wizard_finish(&$form_state) {
1454    $form_state['object']->edit_wizard_finish($form_state);
1455  }


Generated: Mon Jul 9 18:01:44 2012 Cross-referenced by PHPXref 0.7