Skip to content
panels_node.module 10.5 KiB
Newer Older
<?php
// $Id$


/**
 * @file panels_node.module
 *
 * This module provides the "panel" node type.
 * Panel nodes are useful to add additional content to the content area
 * on a per-node base.
 */

// ---------------------------------------------------------------------------
// General Drupal hooks

/**
 * Implementation of hook_perm().
 */
function panels_node_perm() {
  return array('create panel-nodes', 'edit own panel-nodes', 'administer panel-nodes');
}

/**
 * Implementation of hook_menu().
 */
Earl Miles's avatar
Earl Miles committed
function panels_node_menu() {
/*
  $items['node/add/panel'] = array(
    'title' => 'Panel',
    'access arguments' => array('create panel-nodes'),
    'type' => MENU_NORMAL_ITEM,
  );
*/
  $items['admin/panels/panel-nodes'] = array(
    'title' => 'Panel nodes',
    'access arguments' => array('create panel-nodes'),
    'type' => MENU_NORMAL_ITEM,
    'page callback' => 'panels_node_admin',
Earl Miles's avatar
Earl Miles committed
    'description' => 'Panel nodes are nodes that are laid out with panel displays.',
Earl Miles's avatar
Earl Miles committed
  );
Earl Miles's avatar
Earl Miles committed
  $items['admin/panels/panel-nodes/information'] = array(
    'title' => 'Information',
    'access arguments' => array('create panel-nodes'),
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );

  $items['admin/panels/panel-nodes/settings'] = array(
    'title' => 'Settings',
Earl Miles's avatar
Earl Miles committed
    'description' => 'Configure which content is available to add to panel node displays.',
Earl Miles's avatar
Earl Miles committed
    'access arguments' => array('administer panel-nodes'),
    'page callback' => 'panels_node_settings',
    'type' => MENU_LOCAL_TASK,
  );

  // Avoid some repetition on these:
  $base = array(
    'access callback' => 'node_access',
    'access arguments' => array('update', 1),
    'page arguments' => array(1),
    'type' => MENU_LOCAL_TASK,
  );
  $items['node/%node/panel_layout'] = array(
    'path' => $base . 'layout',
    'title' => 'Panel layout',
    'page callback' => 'panels_node_edit_layout',
    'weight' => 2,
  ) + $base;

  $items['node/%node/panel_settings'] = array(
    'title' => 'Panel layout settings',
    'page callback' => 'panels_node_edit_layout_settings',
    'weight' => 2,
  ) + $base;

  $items['node/%node/panel_layout'] = array(
    'title' => 'Panel content',
    'page callback' => 'panels_node_edit_content',
    'weight' => 3,
  ) + $base;

  $items['node/add/panel/choose-layout'] = array(
    'title' => 'Choose layout',
    'access arguments' => array('create panel-nodes'),
    'page callback' => 'panels_node_add',
    'type' => MENU_CALLBACK,
  );

  return $items;
}

/**
 * Page callback for the very short admin page.
 */
function panels_node_admin() {
  $output = '<p>';
  $output .= t('Panel nodes do not have a normal administrative UI, such as panels pages or mini panels. With this module, a new node type is created: a "panel" node. These are nodes that have panel layouts, but do not have the breadth of features that panel pages do; these features are sacrificed so that you gain all the capabilities of nodes.');
  $output .= '</p><p>';
  $output .= t('You may create a !panel_node using the normal !create_content menu, and you can administer your panel nodes under the normal !administer_nodes menu (administrative permission required).', array(
    '!panel_node' => l(t('panel node'), 'node/add/panel'),
    '!create_content' => l(t('create content'), 'node/add'),
    '!administer_nodes' => l(t('administer nodes'), 'admin/content/node'),
  ));
  $output .= '</p><p>';
  $output .= t('On the !settings page, you may control which panes may be added to panel nodes; this can be very valuable to limit what content is available if your users who can create panel nodes are not administrators.', array(
    '!settings' => l(t('settings'), 'admin/panels/panel-nodes/settings'),
  ));
  $output .= '</p>';
  return $output;
}

// ---------------------------------------------------------------------------
// Node hooks

/**
 * Implementation of hook_node_info().
 */
function panels_node_node_info() {
  return array(
    'panel' => array(
      'name' => t('Panel'),
      'module' => 'panels_node',
      'body_label' => t('Teaser'),
      'description' => t("A panel a page layout broken up into rows and columns."),
    ),
  );
}

/**
 * Implementation of hook_access().
 */
function panels_node_access($op, $node = NULL) {
  if (user_access('administer panel-nodes')) {
    return TRUE;
  }

  if ($op == 'create' && user_access('create panel-nodes')) {
    return TRUE;
  }

  if ($op == 'update' && $node->uid == $user->uid && user_access('edit own panel-nodes')) {
    return TRUE;
  }
}

function panels_node_add() {
  $output = '';

  panels_load_include('plugins');
  // If no layout selected, present a list of choices.
  foreach (panels_get_layouts() as $id => $layout) {
Earl Miles's avatar
Earl Miles committed
    $output .= panels_print_layout_link($id, $layout, 'node/add/panel/' . $id);
  }
  return $output;
}

/**
 * Implementation of hook_form().
 */
function panels_node_form(&$node, &$param) {
  $form['panels_node']['#tree'] = TRUE;
  if (!$node->nid) {
Earl Miles's avatar
Earl Miles committed
    // Grab our selected layout from the $node, If it doesn't exist, try arg(3)
    // and if that doesn't work present them with a list to pick from.
Earl Miles's avatar
Earl Miles committed
    $panel_layout = isset($node->panel_layout) ? $node->panel_layout : arg(3);
    if (empty($panel_layout)) {
      return drupal_goto('node/add/panel/choose-layout');
    }

    panels_load_include('plugins');
    $layout = panels_get_layout($panel_layout);
    if (empty($layout)) {
      return drupal_not_found();
    }
    $form['panels_node']['layout'] = array(
      '#type' => 'value',
      '#value' => $panel_layout,
    );
  }

  $type = node_get_types('type', $node);

  $form['title'] = array(
    '#type' => 'textfield',
    '#title' => check_plain($type->title_label),
    '#required' => TRUE,
    '#default_value' => $node->title,
  );

  if (!empty($type->body_label)) {
    $form['body'] = array(
      '#type' => 'textarea',
      '#title' => check_plain($type->body_label),
      '#rows' => 10,
      '#required' => TRUE,
      '#description' => t('The teaser is a piece of text to describe when the panel is listed (such as when promoted to front page); the actual content will only be displayed on the full node view.'),
      '#default_value' => $node->body,
    );
  }

//  drupal_set_message('<pre>' . check_plain(var_export($node, true)) . '</pre>');
  $css_id = '';
  if (!empty($node->panels_node['css_id'])) {
    $css_id = $node->panels_node['css_id'];
  }

  $form['panels_node']['css_id'] = array(
    '#type' => 'textfield',
    '#title' => t('CSS ID'),
    '#size' => 30,
    '#description' => t('An ID that can be used by CSS to style the panel.'),
    '#default_value' => $css_id,
  );
  return $form;
}

/**
 * Implementation of hook_validate().
 */
function panels_node_validate($node) {
  if (!$node->nid && empty($node->panels_node['layout'])) {
    form_set_error('', t('Please select a layout.'));
  }
}

/**
 * Implementation of hook_load().
 *
 * Panels does not use revisions for nodes because that would open us up
 * to have completely separate displays, and we'd have to copy them,
 * and that's going to be a LOT of data.
 */
function panels_node_load($node) {
  // We shortcut this because only in some really drastic corruption circumstance will this
  // not work.
  $additions['panels_node'] = db_fetch_array(db_query("SELECT * FROM {panels_node} WHERE nid = %d", $node->nid));
  return $additions;
}

/**
 * Implementation of hook_insert().
 */
function panels_node_insert(&$node) {
  // Create a new display and record that.
  $display = panels_new_display();
  $display->layout = $node->panels_node['layout'];
  panels_save_display($display);
  $css_id = $node->panels_node['css_id'];

  db_query("INSERT INTO {panels_node} (nid, did, css_id) VALUES (%d, %d, '%s')", $node->nid, $display->did, $node->panels_node['css_id']);

  $node->panels_node['did'] = $display->did;
}

/**
 * Implementation of hook_delete().
 */
function panels_node_delete(&$node) {
  db_query("DELETE FROM {panels_node} WHERE nid = %d", $node->nid);
  if (!empty($node->panels_node['did'])) {
    panels_delete_display($node->panels_node['did']);
  }
}

/**
 * Implementation of hook_update().
 */
function panels_node_update($node) {
  db_query("UPDATE {panels_node} SET css_id = '%s' WHERE nid = %d", $node->panels_node['css_id'], $node->nid);
}

/**
 * Implementation of hook_view().
 */
function panels_node_view($node, $teaser = FALSE, $page = FALSE) {
  panels_load_include('plugins');
  if ($teaser) {
    // Do the standard view for teaser.
    $node = node_prepare($node, $teaser);
  }
  else {
    $display = panels_load_display($node->panels_node['did']);
    $display->css_id = $node->panel_node['css_id'];
    // TODO: Find a way to make sure this can't node_view.
    $display->context = array('panel-node' => panels_context_create('node', $node));

    $node->content['body'] = array(
      '#value' => panels_render_display($display),
      '#weight' => 0,
    );
  }

  return $node;
}

// ---------------------------------------------------------------------------
// Administrative pages

/**
 * Settings for panel nodes.
 */
function panels_node_settings() {
  panels_load_include('common');
  return drupal_get_form('panels_common_settings', 'panels_node');
}

// ---------------------------------------------------------------------------
// Meat of the Panels API; almost completely passing through to panels.module

/**
 * Pass through to the panels layout editor.
 */
function panels_node_edit_layout($node) {
  panels_load_include('plugins');
  $display = panels_load_display($node->panels_node['did']);
  $display->context = array('panel-node' => panels_context_create('node', $node));
  return panels_edit_layout($display, t('Save'), "node/$node->nid/panel_layout");
}

/**
 * Pass through to the panels layout settings editor.
 */
function panels_node_edit_layout_settings($node) {
  panels_load_include('plugins');
  $display = panels_load_display($node->panels_node['did']);
  return panels_edit_layout_settings($display, t('Save'), "node/$node->nid/panel_settings");
}

/**
 * Pass through to the panels content editor.
 */
function panels_node_edit_content($node) {
  panels_load_include('plugins');
  $display = panels_load_display($node->panels_node['did']);
  $display->context = array('panel-node' => panels_context_create('node', $node));
  panels_load_include('common');
  $content_types = panels_common_get_allowed_types('panels_node', $display->context);

  // Print this with theme('page') so that blocks are disabled while editing a display.
  // This is important because negative margins in common block layouts (i.e, Garland)
  // messes up the drag & drop.
  print theme('page', panels_edit($display, "node/$node->nid/panel_content", $content_types), FALSE);
}