$info) { if (isset($info['title'])) { $items['admin/build/block/box-add/'. $key] = array( 'title' => 'Add '. strtolower($info['title']), 'page callback' => 'drupal_get_form', 'page arguments' => array('boxes_add_form', 4), 'access arguments' => array('administer blocks'), 'type' => MENU_LOCAL_TASK, 'file' => 'boxes.admin.inc', ); } } $items['admin/build/block/configure/boxes/%boxes/delete'] = array( 'title' => 'Delete box', 'page callback' => 'drupal_get_form', 'page arguments' => array('boxes_delete_form', 5), 'access arguments' => array('administer blocks'), 'type' => MENU_CALLBACK, 'file' => 'boxes.admin.inc', ); return $items; } /** * Access check for whether current user should be able to administer boxes. */ function boxes_access_admin() { return user_access('administer blocks') || (module_exists('spaces') && spaces_access_admin()); } /** * Implementation of hook_theme(). */ function boxes_theme($existing, $type, $theme, $path) { return array( 'boxes_box' => array( 'arguments' => array('block' => NULL), 'path' => drupal_get_path('module', 'boxes'), 'file' => 'boxes.admin.inc', ), ); } /** * Implementation of hook_block(). */ function boxes_block($op = 'list', $delta = '', $edit = array()) { switch ($op) { case 'list': $boxes = boxes_load(); $blocks = array(); foreach ($boxes as $box) { $blocks[$box->delta]['info'] = $box->description; // Not worth caching. $blocks[$box->delta]['cache'] = BLOCK_NO_CACHE; } // 'Add' blocks for editing a page inline ctools_include('plugins'); $plugins = ctools_get_plugins('boxes', 'plugins'); foreach ($plugins as $key => $info) { if (isset($info['title'])) { $blocks["boxes_add__$key"]['info'] = t('Add custom @title', array('@title' => strtolower($info['title']))); $blocks["boxes_add__$key"]['cache'] = BLOCK_NO_CACHE; } } return $blocks; case 'configure': if ($delta && strpos($delta, 'boxes_add__') !== 0) { if ($box = boxes_load($delta)) { if ($box->options_form()) { $form = boxes_box_form(array('box' => $box)); unset($form['submit']); return $form; } } } break; case 'save': $edit['delta'] = $delta; $box = boxes_factory($edit['plugin_key'], $edit); $box->save(); break; case 'view': // Add boxes JS. boxes_add_js(); ctools_include('export'); // If the 'add' box was requested, replace the delta with a unique delta. if (strpos($delta, 'boxes_add__') === 0) { ctools_include('form'); $plugin_key = str_replace('boxes_add__', '', $delta); $identifier = (module_exists('spaces') && $space = spaces_get_space()) ? "{$space->type}-{$space->id}" : 'box'; $hash = boxes_create_hash($identifier); $delta = $identifier . "-" . $hash; $box = boxes_factory($plugin_key, array('delta' => $delta)); $form_state = array('box' => $box, 'plugin_key' => $plugin_key, 'custom_action' => TRUE, 'no_redirect' => TRUE); $form = ctools_build_form('boxes_box_form', $form_state); $block['delta'] = $delta; $block['content'] = ''; $block['editing'] = $form; $block['content'] = theme('boxes_box', $block); $plugin = ctools_get_plugins('boxes', 'plugins', $plugin_key); $block['subject'] = t('Add custom @title', array('@title' => strtolower($plugin['title']))); return $block; } elseif ($box = boxes_load($delta)) { // Generate content and provide an editing form if user has proper // permissions. $block = $box->render(); if (boxes_access_admin()) { $block['controls'] = theme('links', array( 'edit' => array( 'title' => t('Edit'), 'href' => $_GET['q'], 'query' => 'plugin_key=&boxes_delta=' . $block['delta'], 'attributes' => array('class' => 'ctools-use-ajax'), ), 'cancel' => array('title' => t('Cancel'), 'href' => $_GET['q']), )); } $block['content'] = theme('boxes_box', $block); // Avoid that block module overrides title and set both subject and title. $block['title'] = $block['subject']; return $block; } break; } } /** * Implementation of hook_footer(). * * All ajax requests are targeted back to the current page so that the proper * environment can be re-setup. Here in hook_footer we then detect that this is * an ajax submission and handle it. */ function boxes_footer() { // Besure the page isn't a 404 or 403. $headers = drupal_set_header(); // Support for Pressflow patched drupal_set_header if (!is_array($headers)) { $headers = explode("\n", $headers); } foreach ($headers as $header) { if ($header == "HTTP/1.1 404 Not Found" || $header == "HTTP/1.1 403 Forbidden") { return; } } if (!empty($_GET['boxes_delta']) && boxes_access_admin()) { ctools_include('ajax'); $output = array(); if (isset($_GET['plugin_key'])) { ctools_include('form'); $plugin_key = $_GET['plugin_key']; $delta = $_GET['boxes_delta']; $box = boxes_load($delta); if (!$box && $plugin_key) { $box = boxes_factory($plugin_key, array('delta' => $delta)); $form_state = array( 'box' => $box, 'plugin_key' => $plugin_key, 'custom_action' => TRUE, 'no_redirect' => TRUE, ); } elseif (!$box) { return; } else { $form_state = array('box' => $box, 'no_redirect' => TRUE); } $form = ctools_build_form('boxes_box_form', $form_state); if (empty($form_state['executed'])) { $output[] = ctools_ajax_command_html('#boxes-box-' . $delta . ' .box-editor', $form); } else { $output[] = array( 'command' => 'getBlock', 'delta' => $delta, 'url' => url($_GET['q'], array('absolute' => true)), ); } } else { $block = boxes_block('view', $_GET['boxes_delta']); $block['module'] = 'boxes'; $output[] = ctools_ajax_command_replace('#block-boxes-' . $_GET['boxes_delta'], theme('block', (object)$block)); if (module_exists('context')) { array_unshift($output, array( 'command' => 'preReplaceContextBlock', 'id' => 'block-boxes-' . $_GET['boxes_delta'] )); $output[] = array( 'command' => 'postReplaceContextBlock', 'id' => 'block-boxes-' . $_GET['boxes_delta'] ); } } ctools_ajax_render($output); } } /** * Instantiate box object. * * @param $plugin_key * The string id of the boxes plugin. * @param $values * The values to set on the box. * * @return a box object. */ function boxes_factory($plugin_key, $values = array()) { module_load_include('inc', 'boxes', 'plugins/boxes_box'); return boxes_box::factory($plugin_key, $values); } /** * Load a box. */ function boxes_load($delta = NULL) { module_load_include('inc', 'boxes', 'plugins/boxes_box'); if (isset($delta)) { $box = boxes_box::load($delta); drupal_alter('boxes_load', $box, $delta); return $box; } ctools_include('export'); $boxes = array(); foreach (ctools_export_load_object('box') as $box) { $box = boxes_box::load($box->delta); drupal_alter('boxes_load', $box, $delta); $boxes[$box->delta] = $box; } return $boxes; } /** * Reset boxes load caches. */ function boxes_load_reset() { boxes_box::reset(); } /** * Common element of the box form */ function boxes_box_form($form_state) { $box = $form_state['box']; $form = array(); // For hook_block('save'). $form['plugin_key'] = array( '#type' => 'value', '#value' => $box->plugin_key, ); $form['delta'] = array( '#type' => 'value', '#value' => $box->delta, ); $form['description'] = array( '#type' => 'textfield', '#title' => t('Box description'), '#default_value' => $box->description, '#maxlength' => 64, '#description' => t('A brief description of your box. Used for administrative purposes.'), '#required' => TRUE, '#weight' => -19, ); $form['title'] = array( '#type' => 'textfield', '#title' => t('Box title'), '#maxlength' => 64, '#description' => t('The rendered title of the box as shown to the user.'), '#default_value' => $box->title, '#weight' => -18, ); $form['options'] = $box->options_form(); $form['options']['#weight'] = -17; $form['submit'] = array( '#type' => 'submit', '#value' => t('Save'), '#attributes' => array('class' => 'boxes-ajax'), ); if (!empty($form_state['custom_action'])) { $form['#action'] = url($_GET['q'], array('query' => array( 'boxes_delta' => $box->delta, 'plugin_key' => $form_state['plugin_key'], ))); } return $form; } /** * Submit handler for the inline form. */ function boxes_box_form_submit($form, $form_state) { $box = boxes_factory($form_state['values']['plugin_key'], $form_state['values']); if (module_exists('spaces') && $space = spaces_get_space()) { $space->controllers->boxes->set($box->delta, $box); } else { $box->save(); } } /** * Implementation of hook_form_alter for block_admin_configure. */ function boxes_form_block_admin_configure_alter(&$form, &$form_state) { if ($form['module']['#value'] == 'boxes') { $box = boxes_load($form['delta']['#value']); if (($box->export_type & EXPORT_IN_DATABASE) && ($box->export_type & EXPORT_IN_CODE)) { $form['revert'] = array( '#type' => 'submit', '#value' => t('Revert'), '#submit' => array('boxes_block_delete_submit'), ); } elseif (!($box->export_type & EXPORT_IN_CODE)) { $form['delete'] = array( '#type' => 'submit', '#value' => t('Delete'), '#submit' => array('boxes_block_delete_submit'), ); } } } // Submit handler for box deletion. function boxes_block_delete_submit($form, &$form_state) { drupal_goto('admin/build/block/configure/boxes/'. $form_state['values']['delta'] .'/delete'); } /** * Alters the block admin form to add delete links next to boxes blocks. */ function boxes_form_block_admin_display_form_alter(&$form, $form_state) { foreach (element_children($form) as $i) { if (isset($form[$i]['module']['#value']) && $form[$i]['module']['#value'] == 'boxes') { $delta = $form[$i]['delta']['#value']; if (strpos($delta, 'boxes_add__') !== 0) { $box = boxes_load($delta); if (($box->export_type & EXPORT_IN_DATABASE) && ($box->export_type & EXPORT_IN_CODE)) { $form[$i]['delete'] = array( '#value' => l(t('revert'), 'admin/build/block/configure/boxes/'. $delta .'/delete'), ); } elseif (!($box->export_type & EXPORT_IN_CODE)) { $form[$i]['delete'] = array( '#value' => l(t('delete'), 'admin/build/block/configure/boxes/'. $delta .'/delete'), ); } } } } } /** * Implementation of hook_ctools_plugin_api(). */ function boxes_ctools_plugin_api($module, $api) { if ($module == 'spaces' && $api == 'plugins') { return array('version' => 3); } elseif ($module == 'boxes' && $api == 'plugins') { return array('version' => 1); } } /** * Implementation of hook_ctools_plugin_plugins(). */ function boxes_ctools_plugin_plugins() { return array( 'cache' => TRUE, 'use hooks' => TRUE, ); } /** * Implementation of hook_boxes_plugins(). */ function boxes_boxes_plugins() { $info = array(); $path = drupal_get_path('module', 'boxes') .'/plugins'; $info['box'] = array( 'handler' => array( 'class' => 'boxes_box', 'file' => 'boxes_box.inc', 'path' => $path, ), ); $info['simple'] = array( 'title' => 'Box', 'handler' => array( 'parent' => 'box', 'class' => 'boxes_simple', 'file' => 'boxes_simple.inc', 'path' => $path, ), ); return $info; } /** * Implementation of hook_spaces_plugins */ function boxes_spaces_plugins() { $plugins = array(); $plugins['spaces_controller_boxes'] = array( 'handler' => array( 'path' => drupal_get_path('module', 'boxes') .'/plugins', 'file' => 'spaces_controller_boxes.inc', 'class' => 'spaces_controller_boxes', 'parent' => 'spaces_controler', ), ); return $plugins; } /** * Implementation of hook_spaces_registry(). */ function boxes_spaces_registry() { return array( 'controllers' => array( 'boxes' => array( 'title' => t('Boxes'), 'plugin' => 'spaces_controller_boxes', ), ), ); } /** * Implementation of hook_spaces_dashboard_block_access_alter(). * * Provides access to blocks specific to each space. */ function boxes_spaces_dashboard_block_access_alter(&$access) { foreach (array_keys($access) as $bid) { list($module, $delta) = explode('-', $bid, 2); if ($module === 'boxes') { // This is the add block, give access to admins. if (strpos($delta, 'boxes_add__') === 0) { $access[$bid] = boxes_access_admin(); } // If this box is specific to the current space, allow access. else if (module_exists('spaces') && $space = spaces_get_space()) { $in_space = $space->controllers->boxes->get($delta, 'space'); $access[$bid] = $access[$bid] || !empty($in_space); } // Outside of spaces, give admins access to all boxes. else { $access[$bid] = boxes_access_admin(); } } } } /** * Implementation of hook_context_block_info_alter(). * * Provides spaces integration when working with blocks using context. */ function boxes_context_block_info_alter(&$blocks) { // Add boxes JS. If this is getting called, it's highly likely a context // inline editor is on the page. boxes_add_js(); if (module_exists('spaces') && $space = spaces_get_space()) { $item = menu_get_item(); // Prevent space-specific blocks from appearing on the dashboard settings // page within a space. if (!(isset($item['page_callback'], $item['page_arguments'][0]) && $item['page_callback'] === 'drupal_get_form' && $item['page_arguments'][0] === 'spaces_dashboard_admin_form')) { foreach ($space->controllers->boxes->get() as $box) { $add = new stdClass(); $add->bid = "boxes-{$box->delta}"; $add->delta = $box->delta; $add->info = $box->description; $add->cache = BLOCK_NO_CACHE; $add->module = 'boxes'; $blocks[$add->bid] = $add; } } } } /** * Implementation of hook_boxes_load_alter(). * * Provides spaces integration for per-space overrides of a given box. */ function boxes_boxes_load_alter(&$box, $delta) { if (module_exists('spaces') && $space = spaces_get_space()) { if ($space_box = $space->controllers->boxes->get($delta)) { // Some older overrides may be stored as an array, check for these and // convert them to objects. if (is_array($space_box)) { $space_box = (object)$space_box; } $box = boxes_factory($space_box->plugin_key, $space_box); $box->new = FALSE; } } } /** * Implementation of hook_features_pipe_MODULE_alter(). */ function boxes_features_pipe_block_alter(&$more, $data, $export) { foreach ($data as $bid) { $split = explode('-', $bid); $module = array_shift($split); $delta = implode('-', $split); if ($module == 'boxes') { $more['box'][] = $delta; } } } /** * Add JavaScript to the page. */ function boxes_add_js() { static $added = FALSE; if ($added || !boxes_access_admin()) { return; } $added = TRUE; ctools_include('ajax'); ctools_add_js('ajax-responder'); drupal_add_js(drupal_get_path('module', 'boxes') . '/boxes.js'); drupal_add_js('misc/jquery.form.js'); drupal_add_css(drupal_get_path('module', 'boxes') . '/boxes.css'); drupal_add_js(array('getQ' => $_GET['q']), 'setting'); } /** * Create a hash for a block id. */ function boxes_create_hash($identifier) { global $user; $boxes = boxes_block('list'); $hash = dechex(crc32($user->sid . microtime())); while (isset($boxes["{$identifier}-{$hash}"])) { $hash = dechex(crc32($user->sid . microtime())); } return $hash; }