'_spaces_ui_menu_item', 'page arguments' => array(), 'access callback' => 'user_access', 'access arguments' => array('administer spaces'), 'type' => PAGE_CALLBACK, ); $items['admin/build/context/%context_ui/edit/spaces'] = array( 'title' => t('Spaces'), 'page callback' => 'drupal_get_form', 'page arguments' => array('spaces_ui_feature_form', 3), 'access callback' => 'user_access', 'access arguments' => array('administer spaces'), 'type' => MENU_LOCAL_TASK, ); $items['admin/build/spaces/features'] = array( 'title' => t('Features'), 'description' => t('Page listing spaces features.'), 'page callback' => 'spaces_ui_features', 'page arguments' => array(), 'access callback' => 'user_access', 'access arguments' => array('administer spaces'), 'type' => MENU_LOCAL_TASK, ); return $items; } /** * Implementation of hook_theme(). */ function spaces_ui_theme() { return array( 'spaces_ui_form_menu' => array(), 'spaces_ui_form_menu_item' => array(), ); } /** * Implementation of hook_context_define(). */ function spaces_ui_context_define() { $items = array(); $result = db_query('SELECT feature, value FROM {spaces_features_ui}'); while ($row = db_fetch_object($result)) { $c = new StdClass(); $c->namespace = 'spaces'; $c->attribute = 'feature'; $c->value = $row->feature; if ($c = context_ui_load($c)) { $c->spaces = unserialize($row->value); // A small change in context_ui now allows modules to // set system/status explicitly -- not recommended except for // cases like this. $c->system = 0; $c->status = 1; $items[] = (array) $c; } } return $items; } /** * Implementation of hook_form_alter(). */ function spaces_ui_form_alter(&$form, &$form_state, $form_id) { switch ($form_id) { // Alter the export form to include spaces information for a spaces feature case 'context_ui_export': $context = (object) $form['export']['#value']; if ($context->namespace == 'spaces' && $context->attribute == 'feature') { $row = db_result(db_query('SELECT value FROM {spaces_features_ui} WHERE feature = "%s"', $context->value)); if ($row) { $context->spaces = unserialize($row); $form['export']['#value'] = (array) $context; } } break; // Remove the stored spaces feature information when a context is deleted case 'context_ui_delete_confirm': $cid = $form['cid']['#value']; $context = context_ui_load($cid); if ($context->namespace == 'spaces' && $context->attribute == 'feature') { $form['spaces_feature'] = array( '#type' => 'value', '#value' => $context->value, ); $form['#submit'][] = 'spaces_ui_feature_delete'; $form['#submit'] = array_reverse($form['#submit']); } break; } } /** * Form for editing spaces feature information. */ function spaces_ui_feature_form($form, $context) { drupal_set_title(t('Edit context: !value', array('!value' => $context->value))); $valid = ($context->namespace == 'spaces' && $context->attribute == 'feature'); $override = db_result(db_query("SELECT count(cid) FROM {context_ui} WHERE namespace = '%s' AND attribute = '%s' AND value = '%s' AND system = 1", $context->namespace, $context->attribute, $context->value)); // Sanity check on this context being a valid spaces feature if ($valid && !$override) { // Load feature information: first attempt from DB, then fallback // to code definition. $feature = array(); $row = db_fetch_object(db_query('SELECT * FROM {spaces_features_ui} WHERE feature = "%s"', $context->value)); if ($row) { $feature = unserialize($row->value); } else { $features = spaces_features(); if (isset($features[$context->value])) { $feature = $features[$context->value]->spaces; } } // Add Feature information to context form $form = array( '#type' => 'fieldset', '#title' => t('Spaces feature'), '#weight' => -5, '#tree' => true, ); $form['feature'] = array( '#type' => 'value', '#value' => $context->value, ); $form['label'] = array( '#type' => 'textfield', '#title' => t('Label'), '#description' => t('Name of the feature.'), '#required' => true, '#maxlength' => 30, '#default_value' => isset($feature['label']) ? $feature['label'] : '', ); $form['description'] = array( '#type' => 'textfield', '#title' => t('Description'), '#description' => t('A brief description of the feature.'), '#required' => true, '#default_value' => isset($feature['description']) ? $feature['description'] : '', ); // Space type compatibility $options = array(0 => t('All spaces')); foreach (spaces_types() as $type => $info) { $options[$type] = $info['title']; } $form['types'] = array( '#type' => 'select', '#title' => t('Compatibility'), '#description' => t('Choose the space type compatible with this feature.'), '#required' => true, '#options' => $options, '#default_value' => isset($feature['types']) ? $feature['types'] : 0, ); // Spaces feature menu $menu_items = isset($feature['menu']) ? array_values($feature['menu']) : array(); $menu_paths = isset($feature['menu']) ? array_keys($feature['menu']) : array(); $form['menu'] = array( '#title' => t('Feature menu'), '#description' => t('Define a menu for this feature. Items will be arranged into a tree based on path. Example: "gallery/browse" will become a child item of "gallery".'), '#type' => 'fieldset', '#tree' => true, ); $form['menu']['items'] = array( '#tree' => true, '#theme' => 'spaces_ui_form_menu', ); if (isset($feature['menu'])) { $i = 0; $base = array( '#type' => 'textfield', '#size' => 30, ); foreach ($feature['menu'] as $path => $item) { $form['menu']['items'][$i]['title'] = $form['menu']['items'][$i]['path'] = $form['menu']['items'][$i]['description'] = $base; $form['menu']['items'][$i]['path']['#title'] = t('Path'); $form['menu']['items'][$i]['title']['#title'] = t('Title'); $form['menu']['items'][$i]['description']['#title'] = t('Description'); $form['menu']['items'][$i]['path']['#default_value'] = $path; $form['menu']['items'][$i]['title']['#default_value'] = isset($item['title']) ? $item['title'] : ''; $form['menu']['items'][$i]['description']['#default_value'] = isset($item['description']) ? $item['description'] : ''; $form['menu']['items'][$i]['#theme'] = 'spaces_ui_form_menu_item'; $i++; } } $form['menu']['add'] = array( '#type' => 'submit', '#value' => t('Add item'), '#ahah' => array( 'event' => 'click', 'path' => 'admin/build/spaces/js/spaces-ui-menu-item', 'wrapper' => 'spaces-feature-menu', 'method' => 'append', ), ); $form['submit'] = array( '#type' => 'submit', '#value' => t('Save'), '#submit' => array('spaces_ui_feature_form_submit'), ); return $form; } else if (!$valid) { drupal_set_message(t('This context definition cannot be used as a Spaces feature. Make sure that the context namespace is spaces and the attribute is feature.')); } else if ($override) { drupal_set_message(t('Spaces UI currently does not support modifying overridden context definitions. Sorry : (')); } return array(); } /** * Submit handler for spaces context_ui form alterations. */ function spaces_ui_feature_form_submit($form, &$form_state) { $feature = $form_state['values']['feature']; $spaces = array(); $spaces['label'] = $form_state['values']['label']; $spaces['description'] = $form_state['values']['description']; // Types if ($form_state['values']['types'] == 0) { $spaces['types'] = array(); } else { $spaces['types'] = array($form_state['values']['types']); } // Menu $spaces['menu'] = array(); foreach ($form_state['values']['menu']['items'] as $item) { if (!empty($item['title']) && !empty($item['path'])) { $spaces['menu'][$item['path']] = array( 'title' => $item['title'], 'description' => $item['description'] ); } } db_query('DELETE FROM {spaces_features_ui} WHERE feature = "%s"', $feature); db_query('INSERT INTO {spaces_features_ui} (feature, value) VALUES ("%s", "%s")', $feature, serialize($spaces)); drupal_set_message(t('The Spaces feature !feature was saved successfully.', array('!feature' => $spaces['label']))); } /** * Delete confirmation submit handler that deletes the spaces feature * values. */ function spaces_ui_feature_delete($form, &$form_state) { $feature = $form_state['values']['spaces_feature']; db_query('DELETE FROM {spaces_features_ui} WHERE feature = "%s"', $feature); } /** * Menu page callback that shows a listing of spaces features. */ function spaces_ui_features() { drupal_set_title(t('Spaces features')); $spaces_types = spaces_types(); $spaces_features = spaces_features(); $output = ''; $rows = array(); foreach ($spaces_features as $id => $feature) { // Load the context object for this feature // @TODO: change context_ui load operation so that it wouldn't // wipe out the spaces extension if loaded. $context = context_ui_load($feature); // Basic information about this feature $label = "". $feature->spaces['label'] .""; $label .= "
". $feature->spaces['description'] ."
"; // Generate action links for this item // @TODO: currently, override contexts also have a "Delete" link -- // it should probably say "Revert". However, there is no easy way // to tell that the context is an override of a code context. This // is probably something that needs to change upstream // (in context_ui). $links = array(); if ($context->system == 0) { $links[] = l(t('Edit'), "admin/build/context/$context->cid/edit/spaces", array('query' => 'destination=admin/build/spaces/features')); $links[] = l(t('Delete'), "admin/build/context/$context->cid/delete", array('query' => 'destination=admin/build/spaces/features')); } else { // @TODO: Override currently isn't supported well by context_ui. // : ( // $links[] = l(t('Override'), 'admin/build/context/clone/'. $context->cid); } $links = implode(' | ', $links); // Generate human readable version of spaces types if (isset($feature->spaces['types']) && count($feature->spaces['types'])) { $types = array(); foreach ($feature->spaces['types'] as $type) { $types[] = $spaces_types[$type]['title']; } $types = implode(', ', $types); } else { $types = t('All spaces'); } $rows[] = array($label, $types, $links); } $header = array(t('Feature'), t('Usable for'), t('Actions')); $output .= theme('table', $header, $rows); return $output; } /** * Custom form theming for spaces feature menu. */ function theme_spaces_ui_form_menu_item($form) { $output = ""; return $output; } /** * Wrapper theme function */ function theme_spaces_ui_form_menu($form) { drupal_add_js(drupal_get_path('module', 'spaces_ui') .'/spaces_ui.js'); drupal_add_css(drupal_get_path('module', 'spaces_ui') .'/spaces.css'); $output = ''; $output .= "
"; $output .= drupal_render($form); $output .= "
"; return $output; } /** * AHAH callback for dynamically adding menu items to a space feature. */ function _spaces_ui_menu_item() { $delta = count($_POST['menu']['items']); // Build our new form element. $element = array( '#theme' => 'spaces_ui_form_menu_item', '#parents' => array('menu', 'items', $delta), ); $base = array( '#type' => 'textfield', '#size' => 30, '#parents' => array('menu', 'items', $delta), ); $element['title'] = $element['path'] = $element['description'] = $base; $element['path']['#title'] = t('Path'); $element['title']['#title'] = t('Title'); $element['description']['#title'] = t('Description'); $element['path']['#parents'][] = 'path'; $element['title']['#parents'][] = 'title'; $element['description']['#parents'][] = 'description'; // Build the new form. $form_state = array('submitted' => FALSE); $form_build_id = $_POST['form_build_id']; // Add the new element to the stored form. Without adding the element to the // form, Drupal is not aware of this new elements existence and will not // process it. We retreive the cached form, add the element, and resave. if (!$form = form_get_cache($form_build_id, $form_state)) { exit(); } $form['menu']['items'][$delta] = $element; form_set_cache($form_build_id, $form, $form_state); $form += array( '#post' => $_POST, '#programmed' => FALSE, ); // Rebuild the form. $form = form_builder('spaces_ui_feature_form', $form, $form_state); // We need to render the element from the rebuilt form -- **NOT** // $element. $output = drupal_render($form['menu']['items'][$delta]); print drupal_to_js(array('status' => TRUE, 'data' => $output)); exit; }