You are here

homebox.module in Homebox 7.3

Homebox main file, takes care of global functions settings constants, etc.

Defines menu elements, callbacks, permissions, hooks, preprocess functions, utility functions

File

homebox.module
View source
<?php

/**
 * @file
 * Homebox main file, takes care of global functions settings constants, etc.
 *
 * Defines menu elements, callbacks, permissions, hooks,
 * preprocess functions, utility functions
 */

// Sets the number of colors that an administrator can set
define('HOMEBOX_NUMBER_OF_COLOURS', 6);

// Default number of regions for new pages
define('HOMEBOX_DEFAULT_REGIONS', 3);

// The version of Homebox
define('HOMEBOX_VERSION', 2);

// The version of jQuery UI we need
define('HOMEBOX_JQUERY_UI_VERSION', 1.6);
define('HOMEBOX_REGION_NONE', -1);

/**
 * Implements hook_menu().
 */
function homebox_menu() {
  $items = array();

  // Created Homebox pages
  $pages = homebox_pages();
  if (is_array($pages) && count($pages) > 0) {
    foreach ($pages as $page) {
      $items[$page->settings['path']] = array(
        'title' => $page->settings['title'],
        'title callback' => 'homebox_build_title',
        'page callback' => 'homebox_build',
        'page arguments' => array(
          $page,
        ),
        'access callback' => '_homebox_user_access_view_homebox',
        'access arguments' => array(
          $page,
        ),
        'type' => $page->settings['menu'] ? MENU_NORMAL_ITEM : MENU_CALLBACK,
      );
      $items[$page->settings['path'] . '/block/%'] = array(
        'title' => $page->settings['title'],
        'page callback' => 'homebox_build_block',
        'page arguments' => array(
          $page,
          count(explode('/', $page->settings['path'])) + 1,
        ),
        'access callback' => '_homebox_user_access_view_homebox',
        'access arguments' => array(
          $page,
        ),
        'type' => $page->settings['menu'] ? MENU_NORMAL_ITEM : MENU_CALLBACK,
      );
    }
  }

  // Optionally add a tab to user profiles
  if ($name = variable_get('homebox_user_tab', '')) {
    $page = homebox_get_page($name);
    if ($page) {
      $items['user/%user/' . $page->settings['path']] = array(
        'title callback' => 'homebox_build_title',
        'title arguments' => array(
          $page->settings['title'],
        ),
        'page callback' => 'homebox_build',
        'page arguments' => array(
          $page,
        ),
        'access callback' => '_homebox_user_access_view_user_homebox',
        'access arguments' => array(
          $page,
          1,
        ),
        'weight' => 1,
        'type' => MENU_LOCAL_TASK,
      );
      $items['user/%user/' . $page->settings['path'] . '/block/%'] = array(
        'page callback' => 'homebox_build_block',
        'page arguments' => array(
          $page,
          4,
        ),
        'access callback' => '_homebox_user_access_view_user_homebox',
        'access arguments' => array(
          $page,
          1,
        ),
        'type' => MENU_CALLBACK,
      );
    }
  }

  // Ajax Callbacks
  $items['homebox/%homebox/restore'] = array(
    'title' => 'Restore',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'homebox_restore_defaults',
      1,
    ),
    'access callback' => '_homebox_user_access_view_homebox',
    'access arguments' => array(
      1,
      TRUE,
    ),
    'type' => MENU_CALLBACK,
  );
  $items['homebox/js/%homebox/add/%/%'] = array(
    'page callback' => 'homebox_add_block',
    'page arguments' => array(
      2,
      4,
      5,
    ),
    'access callback' => 'homebox_edit_access',
    'access arguments' => array(
      2,
    ),
    'type' => MENU_CALLBACK,
  );
  $items['homebox/js/%homebox/save'] = array(
    'page callback' => 'homebox_js_save_user_settings',
    'page arguments' => array(
      2,
    ),
    'access callback' => '_homebox_user_access_view_homebox',
    'access arguments' => array(
      2,
      TRUE,
    ),
    'type' => MENU_CALLBACK,
  );

  // Admin related tasks
  $items['admin/structure/homebox'] = array(
    'title' => 'Homebox',
    'description' => 'List, edit, or add homebox pages.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'homebox_admin_new_page',
    ),
    'access arguments' => array(
      'administer homebox',
    ),
    'file' => 'homebox.admin.inc',
  );
  $items['admin/structure/homebox/edit/%homebox'] = array(
    'title' => 'Edit page',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'homebox_admin_page',
      4,
    ),
    'access arguments' => array(
      'administer homebox',
    ),
    'title callback' => '_homebox_admin_page_title',
    'title arguments' => array(
      4,
    ),
    'type' => MENU_CALLBACK,
    'file' => 'homebox.admin.inc',
  );
  $items['admin/structure/homebox/clone/%homebox'] = array(
    'title' => 'Clone homebox',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'homebox_clone_page',
      4,
    ),
    'access arguments' => array(
      'administer homebox',
    ),
    'title callback' => '_homebox_clone_page_title',
    'title arguments' => array(
      4,
    ),
    'type' => MENU_CALLBACK,
    'file' => 'homebox.admin.inc',
  );
  $items['admin/structure/homebox/layout/%homebox'] = array(
    'title' => 'Layout',
    'description' => 'Edit layout.',
    'page callback' => 'homebox_layout',
    'page arguments' => array(
      4,
    ),
    'access arguments' => array(
      'administer homebox',
    ),
    'file' => 'homebox.admin.inc',
    'type' => MENU_CALLBACK,
  );
  $items['admin/structure/homebox/flush/%homebox'] = array(
    'title' => 'Flush user settings',
    'description' => 'Clear all user\'s settings for a given homebox.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'homebox_admin_flush_form',
      4,
    ),
    'access arguments' => array(
      'administer homebox',
    ),
    'file' => 'homebox.admin.inc',
    'type' => MENU_CALLBACK,
  );
  $items['admin/structure/homebox/settings/%homebox'] = array(
    'title' => 'Settings',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'homebox_configure_form',
      4,
    ),
    'access arguments' => array(
      'administer homebox',
    ),
    'type' => MENU_CALLBACK,
    'file' => 'homebox.admin.inc',
  );
  $items['admin/structure/homebox/export/%homebox'] = array(
    'title' => 'Export',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'homebox_export_form',
      4,
    ),
    'access arguments' => array(
      'administer homebox',
    ),
    'type' => MENU_CALLBACK,
    'file' => 'homebox.admin.inc',
  );
  $items['admin/structure/homebox/delete/%homebox'] = array(
    'title' => 'Delete page',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'homebox_admin_page_delete_confirm',
      4,
    ),
    'access arguments' => array(
      'administer homebox',
    ),
    'type' => MENU_CALLBACK,
    'file' => 'homebox.admin.inc',
  );

  // Admin user settings
  $items['admin/people/homebox'] = array(
    'title' => 'User profile Homebox',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'homebox_user_settings_page',
    ),
    'access arguments' => array(
      'administer homebox',
    ),
    'description' => 'Configure the intergration of Homebox and user profiles.',
    'type' => MENU_LOCAL_TASK,
    'file' => 'homebox.admin.inc',
  );
  return $items;
}

/**
 * Implements hook_load().
 */
function homebox_load($names) {
  if (is_array($names)) {
    $loaded_names = array();
    foreach ($names as $nid => $name) {
      $loaded_name = homebox_get_page($name);
      if ($loaded_name) {
        $loaded_names[$nid] = $name;
      }
    }
    return $loaded_names;
  }
  return homebox_get_page($names);
}

/**
 * Implements hook_forms().
 */
function homebox_forms($form_id, $args) {
  if ($form_id === 'homebox_admin_new_page') {
    return array(
      'homebox_admin_new_page' => array(
        'callback' => 'homebox_admin_page',
      ),
    );
  }
  elseif (isset($args[1]) && is_object($args[1]) && isset($args[1]->module) && isset($args[1]->delta) && $form_id === 'homebox_block_edit_' . $args[1]->module . '_' . $args[1]->delta . '_form') {
    return array(
      $form_id => array(
        'callback' => 'homebox_block_edit_form_builder',
      ),
    );
  }
}

/**
 * Implements hook_help().
 */
function homebox_help($path, $arg) {
  switch ($path) {
    case 'admin/structure/homebox':
      return '<p>' . t('Homebox pages are listed below. Each page is accessible from a single url on your site that you specify during page creation. You can create as many pages as you need. Be sure to review all available layout options and settings.') . '</p>';
    case 'admin/structure/homebox/layout/%':
      return '<p>' . t('This page behaves the same way as Drupal block administration page. Drag blocks to whatever column you want to enable it for your users. Note that you can change the number of columns in the <a href="!settings_url">settings page</a>.', array(
        '!settings_url' => url('admin/structure/homebox/settings/' . arg(4)),
      )) . '</p>';
  }
}

/**
 * Implements hook_permission().
 */
function homebox_permission() {
  return array(
    'administer homebox' => array(
      'title' => t('Administer Homebox'),
      'description' => t('Create new Homebox pages and administer homebox block settings.'),
    ),
  );
}

/**
 * Implements hook_hook_info().
 */
function homebox_hook_info() {
  $hooks['homebox'] = array(
    'group' => 'homebox',
  );
  return $hooks;
}

/**
 * Implements hook_theme().
 */
function homebox_theme($existing, $type, $theme, $path) {
  return array(
    // Set hook name: see template_preprocess_homebox()
    'homebox' => array(
      'variables' => array(
        'regions' => NULL,
        'available_blocks' => NULL,
        'column_count' => NULL,
        'page' => NULL,
        'add_links' => NULL,
        'save_form' => NULL,
      ),
      'template' => 'homebox',
    ),
    'homebox_block' => array(
      'variables' => array(
        'block' => NULL,
        'page' => NULL,
      ),
      'template' => 'homebox-block',
    ),
    'homebox_admin_display_form' => array(
      'template' => 'homebox-admin-display-form',
      'file' => 'homebox.admin.inc',
      'render element' => 'form',
    ),
    'homebox_admin_new_page' => array(
      'render element' => 'form',
      'file' => 'homebox.admin.inc',
    ),
  );
}

/**
 * Preprocesses variables for home-box.tpl.php template
 *
 * @param $variables
 *  An array containing variables to used in home-box.tpl.php
 * @return
 *  An array containing preprocessed variables (see home-box.tpl.php)
 */
function template_preprocess_homebox(&$variables) {
  $module_path = drupal_get_path('module', 'homebox');

  // Check to make sure a user is logged in.
  if (user_is_logged_in()) {

    // Add required jQuery UI files
    drupal_add_library('system', 'ui.draggable');
    drupal_add_library('system', 'ui.droppable');
    drupal_add_library('system', 'ui.sortable');

    // Add Homebox JavaScript files
    drupal_add_js($module_path . '/homebox.js', array(
      'type' => 'file',
      'scope' => 'header',
      'group' => JS_DEFAULT,
      'defer' => FALSE,
      'cache' => TRUE,
      'preprocess' => TRUE,
    ));
    if (isset($variables['page']->settings['auto_save']) && $variables['page']->settings['auto_save']) {
      $variables['classes_array'][] = 'homebox-auto-save';
    }
  }

  // Add CSS for homebox
  drupal_add_css($module_path . '/homebox.css', array(
    'type' => 'file',
    'group' => CSS_DEFAULT,
    'media' => 'all',
    'preprocess' => TRUE,
  ));
  $variables['classes_array'][] = 'column-count-' . $variables['column_count'];
  $variables['classes_array'][] = 'homebox-' . $variables['page']->name;
}

/**
 * Return the homebox page path. If it is a tab on the user page, the path is
 * different.
 *
 * @param $page
 *   A homebox page object.
 * @return
 *   The string path.
 */
function homebox_get_path($page) {
  global $user;
  if ($user->uid && $page->name === variable_get('homebox_user_tab', '')) {
    return 'user/' . $user->uid . '/' . $page->settings['path'];
  }
  return $page->settings['path'];
}

/**
 * Menu title callback.
 */
function homebox_build_title($title) {
  return t($title, array(
    '@user' => format_username($GLOBALS['user']),
  ));
}

/**
 * Responsible for firing the hook_theme().
 *
 * @param $page
 *  A page object
 * @return
 *  homebox_theme() call
 */
function homebox_build($page) {
  global $user;

  // If no default block layout is set, return a simple message
  if (empty($page->settings['blocks'])) {
    return t('This page has not yet been configured.');
  }

  // Get every block placed into its region sorted by weight
  $column_count = $page->settings['regions'];
  $regions = array_fill(1, $column_count, array());

  // Extract blocks from the page
  $blocks = $page->settings['blocks'];
  $allowed_blocks = array();
  $info = array();
  foreach ($blocks as $block) {
    if (_homebox_can_view_block((object) $block)) {
      if (!isset($info[$block['module']])) {
        $info[$block['module']] = module_invoke($block['module'], 'block_info');
      }
      if (isset($info[$block['module']][$block['delta']])) {
        $allowed_blocks[$block['module']][$block['delta']] = $info[$block['module']][$block['delta']];
        if (!empty($block['title'])) {
          $allowed_blocks[$block['module']][$block['delta']]['info'] = $block['title'];
        }
      }
    }
  }

  // Get user settings, so custom blocks are placed in regions.
  $user_blocks = _homebox_get_user_settings($page);
  if ($user_blocks !== FALSE) {

    // Add custom blocks.
    foreach ($user_blocks as $key => $block) {
      if (isset($allowed_blocks[$block['module']][$block['delta']])) {
        $blocks[$key] = $user_blocks[$key];
      }
    }
  }

  // Preparing blocks object for theming
  foreach ($blocks as $key => $block_settings) {

    // Adds block to its regions
    if ($block_settings['status']) {
      $block = homebox_prepare_block($key, $page);
      if (!is_null($block)) {

        // If user defined region is greater than real column count put block in
        // the last column/region.
        $regions[min($block->region, $column_count)][$block->weight][] = $block;
        $allowed_blocks[$block->module][$block->delta]['used'] = TRUE;
      }
    }
  }

  // If custom widths aren't set, make each width a percentage of the total available.
  if (!count($page->settings['widths'])) {
    $num_regions = count($regions);
    for ($i = 1; $i <= $num_regions; $i++) {

      // We use a combination of round() and floor() to get this rounded to two decimal places
      // since the $mode argument isn't introducted into round() until PHP 5.3.0.
      $page->settings['widths'][$i] = round(floor(100 / $num_regions * 100) / 100, 2);
    }
  }

  // Sort each region/column based on key value
  // Also separate the regions into rows based on the region widths
  $sum_width = 0;
  $row = 0;
  for ($i = 1; $i <= count($regions); $i++) {
    ksort($regions[$i]);
    if (!empty($page->settings['widths'][$i])) {
      $sum_width += $page->settings['widths'][$i];
      if ($sum_width > 100) {
        $row++;
        $sum_width = $page->settings['widths'][$i];
      }
    }
    $page->settings['rows'][$i] = $row;
  }

  // Add block links
  if ($user->uid) {
    $add_links = array();
    foreach ($allowed_blocks as $module => $blocks) {
      foreach ($blocks as $delta => $info) {
        $options = array();
        if (isset($info['used'])) {
          $options['attributes'] = array(
            'class' => array(
              'used',
            ),
          );
        }
        $add_links[] = homebox_add_link($info['info'], $page, $module, $delta, $options);
      }
    }
    $add_links['restore'] = l(t('Restore to defaults'), 'homebox/' . $page->name . '/restore', array(
      'attributes' => array(
        'class' => array(
          'restore',
        ),
      ),
    ));
    $add_links = theme('item_list', array(
      'items' => $add_links,
      'title' => NULL,
      'type' => 'ul',
      'attributes' => array(
        'class' => array(
          'clearfix',
        ),
      ),
    ));
    $form = drupal_get_form('homebox_save_form', $page);
    $save_form = drupal_render($form);
  }
  else {
    $add_links = NULL;
    $save_form = NULL;
  }

  // Build output
  $output = theme('homebox', array(
    'regions' => $regions,
    'available_blocks' => $allowed_blocks,
    'column_count' => $column_count,
    'page' => $page,
    'add_links' => $add_links,
    'save_form' => $save_form,
  ));

  // Build the page
  if ($page->settings['full']) {

    // TODO Changed based on discussion at http://drupal.org/node/224333#theme_page.
    // print theme('page', $output, FALSE);
    drupal_set_page_content($output);

    // Return page attributes, and add a custom attribute to
    // look for in hook_page_alter().
    $page = element_info('page');
    $page['#homebox_hide_blocks'] = TRUE;
    return $page;
  }
  else {

    // Simply return the page
    return $output;
  }
}

/**
 * Construct a link to add a block to a user dashboard.
 *
 * @param $text
 *   Link text.
 * @param $page
 *   Homebox page argument.
 * @param $module
 *   Module of the block to add.
 * @param $delta
 *   $delta of the block to add.
 * @param $options
 *   $options as you would pass to l(). May include query arguments for
 *   block-specific config.
 *
 * @return
 *   An HTML link.
 */
function homebox_add_link($text, $page, $module, $delta, $options = array()) {
  $options['query']['token'] = homebox_get_token($page);
  return l($text, 'homebox/js/' . $page->name . '/add/' . $module . '/' . $delta, $options);
}
function homebox_save_form($form, &$form_state, $page) {
  $form = array();
  $form['blocks'] = array(
    '#type' => 'hidden',
  );
  $form['page'] = array(
    '#type' => 'value',
    '#value' => $page->name,
  );
  $form['save'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
    '#ajax' => array(
      'callback' => 'homebox/js/' . $page->name . '/save',
      'event' => 'click',
    ),
  );
  $form['messages'] = array(
    '#markup' => '<span id="homebox-minimize-to-save" class="homebox-msg">' . t('Minimize to save') . '</span>' . '<span id="homebox-changes-made" class="homebox-msg">' . t('Unsaved') . '</span>',
  );
  return $form;
}
function homebox_save_form_submit($form, &$form_state) {
  parse_str($form_state['values']['blocks'], $blocks);
  foreach ($blocks as $key => $value) {
    parse_str($value, $block);
    $blocks[$key] = $block;
  }
  _homebox_save_user_settings($form_state['values']['page'], $blocks);
}

/**
 * Prepare a block for rendering with theme('homebox_block').
 *
 * @param $block_key
 *   A string identifying the block. Should match an array key in
 *   $page->settings['blocks'], except for a user's custom block.
 * @param $page
 *   A homebox page object, as loaded by homebox_get_page().
 *
 * @return
 *   A block object that can be passed to theme('homebox_block', $block).
 */
function homebox_prepare_block($block_key, $page) {

  // Load block settings.
  $user_settings = _homebox_get_user_settings($page);
  if ($user_settings !== FALSE && isset($user_settings[$block_key])) {

    // Custom blocks only exist in user settings.
    $block_settings = $user_settings[$block_key];
  }
  else {

    // Otherwise, start with the page defaults.
    $block_settings = $page->settings['blocks'][$block_key];
  }
  $block_settings['key'] = $block_key;
  $block = new stdClass();

  // Get the edit form early, in case it changes the block.
  // Before retrieving the full form from drupal_get_form(), ensure the block is
  // configurable. Just checking for the form hook implementation isn't
  // sufficient since one module may provide more than one block.
  if (module_hook($block_settings['module'], 'homebox_block_edit_form') && module_invoke($block_settings['module'], 'homebox_block_keys', (object) $block_settings)) {

    // Save messages not rendered by this block to avoid displaying them here.
    $messages = isset($_SESSION['messages']) ? $_SESSION['messages'] : array();
    $_SESSION['messages'] = array();
    $get_form = drupal_get_form('homebox_block_edit_' . $block_settings['module'] . '_' . $block_settings['delta'] . '_form', $page, (object) $block_settings);
    $block->edit_form = drupal_render($get_form);

    // Prepend messages the form may have generated.
    $block->edit_form = theme('status_messages', array(
      'display' => 'error',
    )) . $block->edit_form;

    // Reset messages to state before rendering block.
    $_SESSION['messages'] = $messages;

    // Apply user settings, they may have changed from the form submission.
    if (isset($_POST['form_id']) && ($user_settings = _homebox_get_user_settings($page))) {
      $block_settings = array_merge($block_settings, $user_settings[$block_key]);
    }
  }

  // Make sure unclosable blocks are not closed.
  if (!$block_settings['closable']) {
    $block_settings['status'] = TRUE;
  }

  // Build the $block object.
  $block->key = $block_key;
  $block->subject = isset($page->settings['blocks'][$block_key]['title']) ? $page->settings['blocks'][$block_key]['title'] : NULL;
  $block->content = isset($block_settings['content']) ? $block_settings['content'] : NULL;
  $block->module = isset($block_settings['module']) ? $block_settings['module'] : NULL;
  $block->delta = isset($block_settings['delta']) ? $block_settings['delta'] : NULL;
  $block->region = isset($block_settings['region']) ? (int) $block_settings['region'] : 0;
  $block->weight = isset($block_settings['weight']) ? (int) $block_settings['weight'] : 0;
  $block->status = isset($block_settings['status']) && $block_settings['status'] ? TRUE : FALSE;
  $block->open = isset($block_settings['open']) && $block_settings['open'] ? TRUE : FALSE;
  $block->closable = (bool) $block_settings['closable'];
  $block->homebox_classes = _homebox_get_css_classes_for_block($block_settings);
  if (module_hook($block->module, 'homebox_block_keys')) {
    foreach (module_invoke($block->module, 'homebox_block_keys', $block) as $key) {
      $block->{$key} = isset($block_settings[$key]) ? $block_settings[$key] : NULL;
    }
  }

  // Check block permissions
  if (!_homebox_can_view_block($block)) {

    // Permission denied, skip to the next block
    return NULL;
  }

  // Attempt to find a block in the cache table.
  if ((bool) $page->settings['cache'] && !count(module_implements('node_grants')) && $_SERVER['REQUEST_METHOD'] == 'GET' && ($cid = homebox_get_cache_id($page, $block)) && ($cache = cache_get($cid, 'cache_block'))) {
    $array = $cache->data;
  }
  else {

    // No cache, fetch the blocks from modules
    $array = module_invoke($block->module, 'block_view', $block->delta, $block);

    // Allow modules to modify the block before it is viewed, via either
    // hook_block_view_alter() or hook_block_view_MODULE_DELTA_alter().
    drupal_alter(array(
      'block_view',
      "block_view_{$block->module}_{$block->delta}",
    ), $array, $block);

    // Block.module will return 'n/a' if a custom block has been deleted
    if (isset($array['content']) && $array['content'] == 'n/a') {

      // If this is the case, skip this block
      return NULL;
    }
    if (isset($cid)) {
      cache_set($cid, $array, 'cache_block', CACHE_TEMPORARY);
    }
  }

  // Render block content
  if (isset($array) && is_array($array)) {
    foreach ($array as $k => $v) {

      // If block has custom title, leave it
      if ($k == 'subject' && !empty($block->subject)) {
        continue;
      }
      $block->{$k} = $v;
    }
  }

  // We don't continue to assign this block since Drupal didn't returned any
  // content which could be permissions rules applied by any module.
  if (!isset($block->content) || !is_array($block->content) && trim($block->content) == "") {
    return NULL;
  }

  // If no title provided we try to get one from blocks table
  if (!$block->subject && isset($block->bid)) {
    $block->subject = db_query("SELECT title FROM {block} WHERE bid = :bid", array(
      ':bid' => $block->bid,
    ))
      ->fetchField();
  }
  if (!$block->subject && $block->module == 'views') {
    $block->subject = _homebox_get_view_name($block);
  }
  if (!$block->subject) {
    $module_blocks = module_invoke($block->module, 'block_info');
    $block->subject = $module_blocks[$block->delta]['info'];
  }

  // Sanitize $block->subject for display, like Drupal core does.
  if ($block->subject) {
    $block->subject = check_plain($block->subject);
  }
  else {
    $block->subject = t('<em>No title defined</em>');
  }
  return $block;
}

/**
 * Get a cache ID suitable for using with homebox.
 *
 * @param $page
 *   A homebox page object.
 * @param $block
 *   A homebox block object.
 */
function homebox_get_cache_id($page, $block) {

  // Get block info for cache setting
  static $infos;
  if (!isset($infos[$block->module])) {
    $infos[$block->module] = module_invoke($block->module, 'block_info');
  }
  if (isset($infos[$block->module][$block->delta]['cache'])) {
    $block->cache = $infos[$block->module][$block->delta]['cache'];
  }
  else {
    $block->cache = DRUPAL_CACHE_PER_ROLE;
  }

  // Cache per-page doesn't do so well when blocks are on homebox pages.
  if ($block->cache & DRUPAL_CACHE_PER_PAGE) {
    $block->cache |= ~DRUPAL_CACHE_PER_PAGE;
  }

  // Use standard block key
  if ($cid = _block_get_cache_id($block)) {

    // But append unique
    if (isset($block->edit_form)) {
      global $user;
      $cid .= ':' . $user->uid . ':' . $page->name . ':' . $block->key;
    }
    return $cid;
  }
  return FALSE;
}

/**
 * Get an edit form from the implementing module and add the standard buttons
 * and submit handling.
 */
function homebox_block_edit_form_builder($form, &$form_state, $page, $block) {
  $form = module_invoke($block->module, 'homebox_block_edit_form', $block);
  $form['#attributes']['class'][] = 'clearfix';
  $form['save'] = array(
    '#type' => 'submit',
    '#id' => 'save-' . $block->key,
    '#value' => t('Save'),
    '#ajax' => array(
      'path' => $_GET['q'] . '/block/' . $block->key,
      'event' => 'click',
      'wrapper' => 'homebox-block-' . $block->key,
      'method' => 'replaceWith',
    ),
  );
  $form['#submit'][] = 'homebox_block_edit_form_builder_submit';
  return $form;
}

/**
 * Save settings for the block and render a replacement with the updated settings.
 */
function homebox_block_edit_form_builder_submit($form, &$form_state) {
  list($page, $block) = $form_state['build_info']['args'];
  $user_blocks = _homebox_get_user_settings($page, TRUE);

  // Make sure needed keys exist.
  $user_blocks += array(
    $block->key => array(),
  );
  $user_blocks[$block->key] = array_merge(array_flip(module_invoke($block->module, 'homebox_block_keys', $block)), $user_blocks[$block->key]);

  // Replace user settings with form values, when keys match.
  $user_blocks[$block->key] = array_merge($user_blocks[$block->key], array_intersect_key($form_state['values'], $user_blocks[$block->key]));
  _homebox_save_user_settings($page, $user_blocks);
  $form_state['redirect'] = FALSE;

  // Clear block-specific cache.
  drupal_theme_initialize();
  $block->edit_form = TRUE;
  cache_clear_all(homebox_get_cache_id($page, $block), 'cache_block');
}

/**
 * Render a single block, for AJAX callbacks.
 */
function homebox_build_block($page, $key) {
  return ajax_deliver(theme('homebox_block', array(
    'block' => homebox_prepare_block($key, $page),
    'page' => $page,
  )));
}

/**
 * Implements hook_block_info().
 */
function homebox_block_info() {
  $blocks['custom'] = array(
    'info' => t('Homebox custom block'),
    'cache' => DRUPAL_NO_CACHE,
  );
  return $blocks;
}

/**
 * Implements hook_block_view().
 */
function homebox_block_view($delta = '', $block) {
  switch ($delta) {
    case 'custom':
      return array(
        'subject' => isset($block->title_custom) ? strip_tags($block->title_custom) : t('Custom block'),
        'content' => isset($block->content) ? filter_xss_admin(_filter_autop($block->content)) : t('Click the gear icon to edit.'),
      );
  }
}
function homebox_homebox_block_keys() {
  return array(
    'title_custom',
    'content',
  );
}
function homebox_homebox_block_edit_form($block) {
  $form = array();
  $form['title_custom'] = array(
    '#type' => 'textfield',
    '#title' => t('Title'),
    '#size' => 25,
    '#default_value' => isset($block->title_custom) ? $block->title_custom : '',
    '#required' => TRUE,
  );
  $form['content'] = array(
    '#type' => 'textarea',
    '#title' => t('Content'),
    '#default_value' => isset($block->content) ? $block->content : '',
    '#required' => TRUE,
  );
  return $form;
}

/**
 * Determine if user has access to view a block
 *
 * @param $block
 *   A block object
 *
 * @return
 *   Boolean value of user's access to the block
 */
function _homebox_can_view_block($block) {
  global $user;

  // Detect valid blocks in the system.
  $valid_blocks =& drupal_static(__FUNCTION__ . ':valid_blocks');
  if (!is_array($valid_blocks)) {
    $valid_blocks = array();
    $results = db_query("SELECT module, delta FROM {block}");
    foreach ($results as $record) {
      $valid_blocks[$record->module][$record->delta] = TRUE;
    }
  }

  // Check if the view access is requested for a valid block.
  if (empty($valid_blocks[$block->module][$block->delta])) {
    return FALSE;
  }

  // Check for roles set at the block level.
  $allowed_roles =& drupal_static(__FUNCTION__ . ':allowed_roles');
  if (!is_array($allowed_roles)) {
    $allowed_roles = array();

    // Since this function is usually called once for each block on a page, and
    // {block_role} doesn't usually contain many records, it's cheaper to cache
    // them all at once. (Especially since no index on module+delta exists.)
    $result = db_query('SELECT module, delta, rid FROM {block_role}');
    foreach ($result as $record) {
      $allowed_roles[$record->module . '-' . $record->delta][$record->rid] = TRUE;
    }
  }
  if (isset($allowed_roles[$block->module . '-' . $block->delta])) {

    // Role restrictions were set on the block. Check whether any of ther user's
    // roles is among them.
    $our_allowed_roles = array_intersect_key($user->roles, $allowed_roles[$block->module . '-' . $block->delta]);
    return !empty($our_allowed_roles);
  }

  // If here, user has access
  return TRUE;
}

/**
 * Helper function to fetch a page from the database or from
 * a module implementing hook_homebox()
 *
 * @param $name
 *   The machine name of the page
 * @return
 *   A page object, or FALSE is one doesn't exist with given $name
 */
function homebox_get_page($name) {
  $names =& drupal_static(__FUNCTION__, array());
  if (isset($names[$name])) {
    return $names[$name];
  }

  // Fetch page from db
  $page = db_query("SELECT * FROM {homebox_pages} WHERE name = :name", array(
    ':name' => $name,
  ))
    ->fetchObject();
  if (is_object($page)) {

    // Unserialize the settings
    $page->settings = unserialize($page->settings);
    $names[$name] = $page;
    return $page;
  }
  else {

    // If not available, check other modules
    $pages = module_invoke_all('homebox');
    foreach ($pages as $id => $data) {

      // Only match page name
      if ($name == $id) {

        // Build page object
        $page = new stdClass();
        $page->name = $id;
        $page->settings = $data;

        // Check the data before using it
        $page = homebox_check_page_object($page);
      }
    }
    $names[$name] = is_object($page) ? $page : FALSE;
    return $names[$name];
  }
}

/**
 * Helper function to save an existing page
 *
 * @param $page
 *   A page object
 * @param $check
 *   Whether or not we should check the page data first
 * @return
 *   Boolean status of the operation
 */
function homebox_save_page($page, $check = FALSE) {
  if ($page->name && is_array($page->settings)) {

    // Should we check the page data?
    if ($check && !homebox_check_page_object($page)) {
      return FALSE;
    }

    // Delete page, if it exists
    db_delete('homebox_pages')
      ->condition('name', $page->name)
      ->execute();

    // Save the new/updated page
    if (!drupal_write_record('homebox_pages', $page)) {
      return FALSE;
    }
  }
  else {
    return FALSE;
  }

  // Clear cached value.
  drupal_static('homebox_get_page', array(), TRUE);
  return TRUE;
}

/**
 * Helper function to delete a page
 *
 * @param $name
 *   The machine name of the page to delete
 * @return
 *   Boolean status of the operation
 */
function homebox_delete_page($name) {

  // Delete the page and corresponding user settings
  $delete_page = db_delete('homebox_pages')
    ->condition('name', $name)
    ->execute();
  $delete_users = db_delete('homebox_users')
    ->condition('name', $name)
    ->execute();

  // Clear cached value.
  drupal_static('homebox_get_page', array(), TRUE);
  return (bool) $delete_page && (bool) $delete_users;
}

/**
 * Validation helper function for page name
 *
 * @param $name
 *   The name to be tested for the page
 * @param $element
 *   Optional, the form element identifier to throw form errors
 * @return
 *   TRUE if name is valid to use, otherwise, FALSE.
 */
function homebox_check_name($name, $element = NULL) {

  // Ensure name fits the rules:
  if (preg_match('/[^a-z0-9_]/', $name)) {
    if ($element) {
      form_set_error($element, t('Machine name must be lowercase alphanumeric or underscores only.'));
    }
    return FALSE;
  }

  // Check for name dupes
  if ((bool) db_query('SELECT 1 FROM {homebox_pages} WHERE name = :name', array(
    ':name' => $name,
  ))
    ->fetchField()) {
    if ($element) {
      form_set_error($element, t('The page name %name already exists. Please choose another page name.', array(
        '%name' => $name,
      )));
    }
    return FALSE;
  }
  return TRUE;
}

/**
 * Validation helper function for page path
 *
 * @param $path
 *   The path to be tested for the page
 * @param $name
 *   Optional, the name of the page we're checking
 * @param $element
 *   Optional, the form element identifier to throw form errors
 * @return
 *   TRUE if path is valid to use, otherwise, FALSE.
 */
function homebox_check_path($path, $name = NULL, $element = NULL) {

  // Ensure path fits the rules:
  if (preg_match('/[^-a-z0-9_\\/]/', $path)) {
    if ($element) {
      form_set_error($element, t('Path must be lowercase alphanumeric, underscores, dashes, or forward-slashes only.'));
    }
    return FALSE;
  }

  // Check path for preceeding or trailing forward slashes
  if (substr($path, 0, 1) == '/' || substr($path, strlen($path) - 1, 1) == '/') {
    if ($element) {
      form_set_error($element, t('Path cannot begin or end with a slash.'));
    }
    return FALSE;
  }

  // Check path against existing Homebox paths
  $pages = db_query("SELECT * FROM {homebox_pages}");
  foreach ($pages as $page) {
    $page->settings = unserialize($page->settings);

    // If this is the page we're checking, skip it
    if ($name && $name == $page->name) {
      continue;
    }
    if ($page->settings['path'] == $path) {
      if ($element) {
        form_set_error($element, t('The chosen path is already in use.'));
      }
      return FALSE;
    }
  }
  return TRUE;
}

/**
 * Validation helper to check a page object
 *
 * @param $homebox
 *   A page object.
 * @param $name
 *   Optionally specify and override the machine name of the page
 * @param $element
 *   Optionally specify a form element name to be used to throw form errors
 * @return
 *   A complete page object, or FALSE if data was invalid
 */
function homebox_check_page_object($homebox, $name = NULL, $element = NULL) {

  // Whether or not the import is valid
  $status = TRUE;

  // Check if data was a valid object
  if (!is_object($homebox)) {
    $status = FALSE;
  }
  else {

    // Check individual settings
    foreach ($homebox->settings as $key => $value) {
      switch ($key) {
        case 'regions':

          // Only allow numbers 1-9
          if ($value > 9 || $value < 1) {
            $status = FALSE;
            break 2;
          }
        case 'menu':
        case 'enabled':
        case 'auto_save':
        case 'cache':
        case 'full':
        case 'color':

          // Check that the previous are numeric values
          if (!is_numeric($value)) {
            $status = FALSE;
            break 2;
          }
          break;
        case 'title':

          // Filter title and make sure it still exists afterwards
          $homebox->settings[$key] = filter_xss($value);
          if (!$homebox->settings[$key]) {
            $status = FALSE;
            break 2;
          }
          break;
        case 'path':
          if (!homebox_check_path($value, NULL, $element)) {
            $status = FALSE;
            break 2;
          }
          break;
        case 'colors':
        case 'roles':
        case 'blocks':
          if (!is_array($value)) {
            $status = FALSE;
            break 2;
          }
          break;
        case 'widths':
          if ($homebox->settings['widths']) {
            if (!is_array($homebox->settings['widths']) || count($homebox->settings['widths']) > $homebox->settings['regions']) {
              $status = FALSE;
              break 2;
            }
            foreach ($homebox->settings['widths'] as $width) {
              if (!is_numeric($width) || $width > 100 || $width < 0) {
                $status = FALSE;
                break 3;
              }
            }
          }
          break;
      }
    }

    // If name is explicitly specified, used it
    $homebox->name = $name ? $name : $homebox->name;

    // Check name
    if ($status && $homebox->name && !homebox_check_name($homebox->name, $element)) {
      $status = FALSE;
    }

    // Make sure the required values actually exist
    $required_keys = array(
      'path',
      'blocks',
      'title',
      'regions',
    );
    if ($status) {
      foreach ($required_keys as $key) {
        if (!array_key_exists($key, $homebox->settings)) {
          $status = FALSE;
          break;
        }
      }
    }
  }

  // If the import isn't valid, and form element provided,
  // then flag a form error
  if (!$status && $element) {
    form_set_error($element, t('Invalid import data provided.'));
  }
  return $status ? $homebox : FALSE;
}

/**
 * Helper function to determine whether or not a page is living
 * in code.
 *
 * @param $name
 *   A page name
 * @return
 *   TRUE if the page is living in code regardless of whether or not
 *   the code made it into the DB because of a save
 */
function homebox_page_is_api($name) {

  // Fetch all pages living in code
  foreach (module_invoke_all('homebox') as $id => $data) {
    if ($name == $id) {
      return TRUE;
    }
  }
  return FALSE;
}

/**
 * Helper function to sort blocks by subject alpha asc
 */
function _homebox_compare_block_subject($a, $b) {
  if ($a['subject'] == $b['subject']) {
    return 0;
  }
  return $a['subject'] < $b['subject'] ? -1 : 1;
}

/**
 * Get the name of the view based on the block
 *
 * @param $block
 *   A block object
 * @return
 *   The name of the view
 */
function _homebox_get_view_name($block) {
  $delta = $block->delta;

  // if this is 32, this should be an md5 hash.
  if (drupal_strlen($delta) == 32) {
    $hashes = variable_get('views_block_hashes', array());
    if (!empty($hashes[$delta])) {
      $delta = $hashes[$delta];
    }
  }

  // This indicates it's a special one.
  if (drupal_substr($delta, 0, 1) == '-') {
    list($nothing, $type, $name, $display_id) = explode('-', $delta);
    if ($view = views_get_view($name) && isset($view->display[$display_id])) {
      $name = $view->display[$display_id]->display_options['block_description'];
      $view
        ->destroy();
    }
  }
  list($name, $display_id) = explode('-', $delta);

  // Load the view
  if ($view = views_get_view($name) && isset($view->display[$display_id])) {
    $name = $view->display[$display_id]->display_options['block_description'];
    $view
      ->destroy();
  }
  return $name;
}

/**
 * Javascript callback
 *
 * Save a users page settings
 */
function homebox_js_save_user_settings($page) {
  $form = drupal_render(drupal_get_form('homebox_save_form', $page));
  print drupal_json_output(array(
    'status' => TRUE,
    'data' => $form,
  ));
}

/**
 * Add a custom block to a user's page.
 */
function homebox_add_block($page, $module, $delta) {
  $user_blocks = _homebox_get_user_settings($page, TRUE);

  // Get default region for the blocks in page settings.
  $region = 1;
  foreach ($page->settings['blocks'] as $item) {
    if ($item['delta'] == $delta) {
      $region = $item['region'];
      break;
    }
  }

  // Build custom block
  $block = array(
    'module' => $module,
    'delta' => $delta,
    'title' => '',
    'open' => 1,
    'color' => 'default',
    'status' => 1,
    'region' => $region,
    'movable' => 1,
    'closable' => 1,
  );
  if (module_hook($block['module'], 'homebox_block_keys')) {
    foreach (module_invoke($module, 'homebox_block_keys', (object) $block) as $key) {
      if (isset($_REQUEST[$key])) {
        $block[$key] = $_REQUEST[$key];
      }
    }
  }

  // Add custom block to user's blocks
  $key = $block['module'] . '_' . $block['delta'];
  $id = 1;
  if (isset($user_blocks[$key])) {
    while (isset($user_blocks[$key . '-' . $id])) {
      $id += 1;
    }
    $key .= '-' . $id;
  }
  $user_blocks = array_merge(array(
    $key => $block,
  ), $user_blocks);
  _homebox_save_user_settings($page, $user_blocks);
  drupal_goto(homebox_get_path($page));
}

/**
 * Helper function which adds CSS classes to block, for jQuery to work properly
 *
 * @param $block
 *  A block array
 * @return
 *  A string containing CSS classes
 */
function _homebox_get_css_classes_for_block($block) {
  $classes = array(
    'homebox-portlet',
  );

  // Is the block movable?
  if (isset($block['movable']) && !($block['movable'] === 0)) {
    $classes[] = 'homebox-draggable';
  }

  // Adds CSS class for collapsed block
  if (isset($block['open']) && !$block['open']) {
    $classes[] = 'homebox-portlet-collapsed';
  }

  // Adds CSS for closed block
  if (isset($block['status']) && !$block['status']) {
    $classes[] = 'homebox-portlet-closed';
  }

  // Adds CSS if block is unclosable
  if (isset($block['closable']) && $block['closable'] === 0) {
    $classes[] = 'homebox-unclosable';
  }

  // Adds color css class
  if (isset($block['color']) && $block['color'] != 'default') {
    $classes[] = 'homebox-color-' . drupal_strtolower($block['color']);
  }
  return implode(" ", $classes);
}

/**
 * Flush all user settings for a given page
 *
 * @param $page
 *   A page object
 * @return
 *   TRUE if the operation was successful, otherwise FALSE
 */
function homebox_flush_settings($page) {
  return (bool) db_delete('homebox_users')
    ->condition('name', $page->name)
    ->execute();
}

/**
 * Retrieve an array of all available pages either in the
 * database or by hook_homebox()
 *
 * @return
 *   An array of page objects
 */
function homebox_pages() {
  $pages = array();

  // Fetch all available pages from database
  $result = db_query("SELECT * FROM {homebox_pages} ORDER BY name");
  foreach ($result as $page) {
    $page->settings = unserialize($page->settings);
    $pages[] = $page;
  }

  // Fetch all available pages from API
  $result = module_invoke_all('homebox');
  foreach ($result as $name => $data) {

    // Build page object
    $page = new stdClass();
    $page->name = $name;
    $page->settings = $data;

    // Check the data before using it
    if ($page = homebox_check_page_object($page)) {
      $pages[] = $page;
    }
  }
  return empty($pages) ? NULL : $pages;
}

/**
 * Fetch user page settings, if they exist.
 *
 * @param $page
 *   A page object
 * @param $init
 *   Make sure the user object is fully initialized, not FALSE. Needed for
 *   adding/editing a single block.
 * @param $_reset
 *   Reload settings from the database.
 *
 * @return
 *   An object representing the user's page settings, or FALSE.
 */
function _homebox_get_user_settings($page, $init = FALSE, $_reset = FALSE) {
  global $user;
  static $cache = array();
  $key = $user->uid . ':' . $page->name;
  if ($_reset) {
    unset($cache[$key]);
  }
  if (!isset($cache[$key]) || $init && $cache[$key] === FALSE) {
    $settings = db_query("SELECT settings FROM {homebox_users}\n      WHERE uid = :uid AND name = :name", array(
      ':uid' => $user->uid,
      ':name' => $page->name,
    ))
      ->fetchField();
    $cache[$key] = $settings ? unserialize($settings) : FALSE;
    if ($cache[$key] === FALSE && $init) {
      _homebox_save_user_settings($page, $page->settings['blocks']);
      $cache[$key] = _homebox_get_user_settings($page);
    }
  }
  return $cache[$key];
}

/**
 * Save the user's page settings
 *
 * @param $page
 *   A page object
 * @param $blocks
 *   An array representing the user's page settings
 */
function _homebox_save_user_settings($page, $blocks) {
  global $user;

  // This function is only called after user status
  // and perms were checked
  if (!is_object($page)) {
    $page = homebox_load($page);
  }
  $user_blocks = _homebox_get_user_settings($page);
  $i = 0;
  foreach ($blocks as $key => $value) {

    // Add weights to blocks if there's not one already set.
    if (!isset($blocks[$key]['weight'])) {
      $blocks[$key]['weight'] = ++$i;
    }

    // Carry over existing settings for defined blocks
    if (isset($page->settings['blocks'][$key])) {
      $blocks[$key] = array_merge($page->settings['blocks'][$key], $blocks[$key]);
    }

    // Carry over settings for block copies since these do not get merged above
    if ($user_blocks !== FALSE && isset($user_blocks[$key])) {
      $blocks[$key] = array_merge($user_blocks[$key], $blocks[$key]);
    }
  }
  if ($user_blocks !== FALSE) {

    // Preserve any existing user blocks, which are page blocks, and not already
    // saved above. These are disabled page defaults, and need to remain to
    // continue overriding the page default.
    foreach (array_intersect_key($user_blocks, array_diff_key($page->settings['blocks'], $blocks)) as $key => $value) {
      $blocks[$key] = $value;
    }
  }

  // Remove any old settings
  db_delete('homebox_users')
    ->condition('uid', $user->uid)
    ->condition('name', $page->name)
    ->execute();

  // Update settings
  $data = new stdClass();
  $data->uid = $user->uid;
  $data->name = $page->name;
  $data->settings = $blocks;
  drupal_write_record('homebox_users', $data);
  _homebox_get_user_settings($page, FALSE, TRUE);
}

/**
 * Purge user settings for a given page. Used to restore a page to default
 * settings.
 *
 * @param $page
 *   A homebox page object.
 */
function homebox_restore_defaults($form, &$form_state, $page) {
  global $user;
  $form = array();
  $form['page'] = array(
    '#type' => 'value',
    '#value' => $page->name,
  );
  return confirm_form($form, t('Restore %title to defaults?', array(
    '%title' => t($page->settings['title'], array(
      '@user' => $user->name,
    )),
  )), homebox_get_path($page));
}

/**
 * Submit function for homebox_restore_defaults.
 *
 * Deletes the user's saved settings for a page, then redirects back to the
 * page.
 */
function homebox_restore_defaults_submit($form, &$form_state) {
  global $user;
  db_delete('homebox_users')
    ->condition('uid', $user->uid)
    ->condition('name', $form_state['values']['page'])
    ->execute();
  $page = homebox_load($form_state['values']['page']);
  $form_state['redirect'] = homebox_get_path($page);
}

/**
 * Check that a request is logged-in, has access to view the homebox, and has a
 * valid token. Use tokens from homebox_get_token().
 */
function homebox_edit_access($page) {
  return _homebox_user_access_view_homebox($page, TRUE) && isset($_REQUEST['token']) && drupal_valid_token($_REQUEST['token'], 'homebox-' . $page->name);
}

/**
 * Return a token to be used in conjuntion with homebox_edit_access().
 */
function homebox_get_token($page) {
  return drupal_get_token('homebox-' . $page->name);
}

/**
 * Helper function to check if the current user can view
 * a given homebox page
 *
 * @param $page
 *   A page object
 */
function _homebox_user_access_view_homebox($page, $require_login = FALSE) {
  global $user;
  if ($require_login && !$user->uid) {
    return FALSE;
  }

  // Admin is always allowed
  if (user_access('administer site configuration') || user_access('administer homebox')) {
    return TRUE;
  }
  elseif (!$page->settings['enabled']) {
    return FALSE;
  }
  elseif ($page->settings['roles']) {

    // Iterate each role to look for a match
    foreach ($page->settings['roles'] as $role) {
      $rl = user_role_load_by_name($role);
      if (array_key_exists($rl->rid, $user->roles)) {
        return TRUE;
      }
    }

    // No matches on restricted role
    return FALSE;
  }
  else {

    // If here, no access
    return FALSE;
  }
}

/**
 * Helper function to check access permissions for user
 * profile Homebox
 *
 * Only show tab if you're viewing your own account
 */
function _homebox_user_access_view_user_homebox($page, $profile) {
  global $user;
  if ($user->uid == $profile->uid && _homebox_user_access_view_homebox($page)) {
    return TRUE;
  }
  else {
    return FALSE;
  }
}

/**
 * Implements hook_features_api().
 */
function homebox_features_api() {
  module_load_include('inc', 'homebox', 'homebox.features');
  return _homebox_features_api();
}

/**
 * Implements hook_page_alter()
 */
function homebox_page_alter(&$page) {

  // If the custom attribute is present, hide the blocks.
  if (isset($page['#homebox_hide_blocks'])) {
    unset($page['sidebar_first'], $page['sidebar_second']);
  }
}

/**
 * Title callback for homebox admin page.
 */
function _homebox_admin_page_title($page = FALSE) {
  if ($page) {
    return t('Edit @title', array(
      '@title' => $page->settings['title'],
    ));
  }
  else {
    return t('Edit homebox');
  }
}

/**
 * Title callback for homebox admin page.
 */
function _homebox_clone_page_title($page = FALSE) {
  if ($page) {
    return t('Clone @title', array(
      '@title' => $page->settings['title'],
    ));
  }
  else {
    return t('Clone homebox');
  }
}

Functions

Namesort descending Description
homebox_add_block Add a custom block to a user's page.
homebox_add_link Construct a link to add a block to a user dashboard.
homebox_block_edit_form_builder Get an edit form from the implementing module and add the standard buttons and submit handling.
homebox_block_edit_form_builder_submit Save settings for the block and render a replacement with the updated settings.
homebox_block_info Implements hook_block_info().
homebox_block_view Implements hook_block_view().
homebox_build Responsible for firing the hook_theme().
homebox_build_block Render a single block, for AJAX callbacks.
homebox_build_title Menu title callback.
homebox_check_name Validation helper function for page name
homebox_check_page_object Validation helper to check a page object
homebox_check_path Validation helper function for page path
homebox_delete_page Helper function to delete a page
homebox_edit_access Check that a request is logged-in, has access to view the homebox, and has a valid token. Use tokens from homebox_get_token().
homebox_features_api Implements hook_features_api().
homebox_flush_settings Flush all user settings for a given page
homebox_forms Implements hook_forms().
homebox_get_cache_id Get a cache ID suitable for using with homebox.
homebox_get_page Helper function to fetch a page from the database or from a module implementing hook_homebox()
homebox_get_path Return the homebox page path. If it is a tab on the user page, the path is different.
homebox_get_token Return a token to be used in conjuntion with homebox_edit_access().
homebox_help Implements hook_help().
homebox_homebox_block_edit_form
homebox_homebox_block_keys
homebox_hook_info Implements hook_hook_info().
homebox_js_save_user_settings Javascript callback
homebox_load Implements hook_load().
homebox_menu Implements hook_menu().
homebox_pages Retrieve an array of all available pages either in the database or by hook_homebox()
homebox_page_alter Implements hook_page_alter()
homebox_page_is_api Helper function to determine whether or not a page is living in code.
homebox_permission Implements hook_permission().
homebox_prepare_block Prepare a block for rendering with theme('homebox_block').
homebox_restore_defaults Purge user settings for a given page. Used to restore a page to default settings.
homebox_restore_defaults_submit Submit function for homebox_restore_defaults.
homebox_save_form
homebox_save_form_submit
homebox_save_page Helper function to save an existing page
homebox_theme Implements hook_theme().
template_preprocess_homebox Preprocesses variables for home-box.tpl.php template
_homebox_admin_page_title Title callback for homebox admin page.
_homebox_can_view_block Determine if user has access to view a block
_homebox_clone_page_title Title callback for homebox admin page.
_homebox_compare_block_subject Helper function to sort blocks by subject alpha asc
_homebox_get_css_classes_for_block Helper function which adds CSS classes to block, for jQuery to work properly
_homebox_get_user_settings Fetch user page settings, if they exist.
_homebox_get_view_name Get the name of the view based on the block
_homebox_save_user_settings Save the user's page settings
_homebox_user_access_view_homebox Helper function to check if the current user can view a given homebox page
_homebox_user_access_view_user_homebox Helper function to check access permissions for user profile Homebox

Constants