You are here

pagepreview.module in Page Preview 7

Same filename and directory in other branches
  1. 6 pagepreview.module

An alternative node previewing system for the node add/edit form.

File

pagepreview.module
View source
<?php

/**
 * @file
 * An alternative node previewing system for the node add/edit form.
 */

/**
 * Implements hook_menu().
 */
function pagepreview_menu() {
  $items['pagepreview/%'] = array(
    'title' => 'Page Preview',
    'description' => 'Menu callback for rendering a full-page preview.',
    'page callback' => 'pagepreview_deliver_page',
    'page arguments' => array(
      1,
    ),
    'access arguments' => array(
      'access content',
    ),
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Implements hook_form_alter().
 *
 * Replaces the default submit callback for the "Preview" button.
 */
function pagepreview_form_alter(&$form, &$form_state, $form_id) {
  if (!empty($form['#node_edit_form'])) {
    drupal_add_css(drupal_get_path('module', 'pagepreview') . '/pagepreview.css');
    if ($form['actions']['preview']) {
      $form['actions']['preview']['#submit'] = array(
        'pagepreview_node_form_build_preview',
      );
    }
  }
}

/**
 * Alternate submit callback for the node form "Preview" button.
 */
function pagepreview_node_form_build_preview($form, &$form_state) {
  $node = clone node_form_submit_build_node($form, $form_state);
  $node->pagepreview = TRUE;

  // Get the expected URL alias from Pathauto, if applicable.
  if (module_exists('pathauto') && (!isset($node->path['pathauto']) || $node->path['pathauto'])) {
    module_load_include('inc', 'pathauto');
    $src = "node/" . $node->nid;
    $alias = pathauto_create_alias('node', 'return', $src, array(
      'node' => $node,
    ), $node->type, $node->language);
    if ($alias) {
      $node->path['alias'] = $alias;
    }
  }

  // Cache the temporary node and active the preview area of the node form.
  $preview_id = md5(json_encode($form_state['values']) . mt_rand());
  cache_set($preview_id, $node, 'cache_pagepreview', CACHE_TEMPORARY);
  $form_state['node_preview'] = '<iframe class="pagepreview-preview" src="' . base_path() . 'pagepreview/' . $preview_id . '"></iframe>';
  $form_state['rebuild'] = TRUE;
}

/**
 * Menu callback for "pagepreview/%".
 *
 * Directly prints a rendered page based on the cached temporary node.
 *
 * @param string $preview_id
 *   The cache key for the object to be retrieved.
 */
function pagepreview_deliver_page($preview_id) {

  // Get the cached temporary node.
  $node = pagepreview_cache_get($preview_id);

  // If we don't have a valid node for whatever reason, quit here.
  if (!$node) {
    drupal_exit();
  }

  // Change the preview's page title.
  drupal_set_title($node->title);

  // Overrides $_GET['q'] so that other elements on the page can react to the
  // proper path context.
  if ($node->nid) {
    $_GET['q'] = 'node/' . $node->nid;
  }
  elseif (!empty($node->path['alias'])) {
    $_GET['q'] = trim($node->path['alias'], '/');
  }

  // Allow other modules to alter the node or execute code before building the
  // preview.
  drupal_alter('pagepreview_node', $node);
  $preview = pagepreview_build_preview($node);

  // Switch to the anonymous user for page rendering.
  // TODO: make this configurable.
  global $user;
  drupal_save_session(FALSE);
  $user = user_load(0);

  // Suppress fancy stuff like admin and admin_menu.module for the preview.
  module_invoke_all('suppress');

  // Add JS within the preview to prevent clicking through to links.
  drupal_add_js(drupal_get_path('module', 'pagepreview') . '/pagepreview.preview.js');

  // Deliver the page output.
  drupal_deliver_page($preview);

  // Remove the cached preview.
  cache_clear_all($preview_id, 'cache_pagepreview');
}

/**
 * Return a preview object from cache.
 *
 * @param string $preview_id
 *   The cache key for the object to be retrieved.
 *
 * @return object
 *   The cached object, or FALSE if none was found.
 */
function pagepreview_cache_get($preview_id) {
  $cache = cache_get($preview_id, 'cache_pagepreview');
  return $cache ? $cache->data : FALSE;
}

/**
 * Replacement function for node_preview().
 *
 * Instead of calling theme('node_preview') to get the node output, we call
 * node_view directly.
 *
 * @see theme_node_preview()
 */
function pagepreview_build_preview($node) {
  if (node_access('create', $node) || node_access('update', $node)) {
    _field_invoke_multiple('load', 'node', array(
      $node->nid => $node,
    ));

    // Load the user's name when needed.
    if (isset($node->name)) {

      // The use of isset() is mandatory in the context of user IDs, because
      // user ID 0 denotes the anonymous user.
      if ($user = user_load_by_name($node->name)) {
        $node->uid = $user->uid;
        $node->picture = $user->picture;
      }
      else {
        $node->uid = 0;

        // anonymous user
      }
    }
    elseif ($node->uid) {
      $user = user_load($node->uid);
      $node->name = $user->name;
      $node->picture = $user->picture;
    }
    $node->changed = REQUEST_TIME;
    $nodes = array(
      $node->nid => $node,
    );
    field_attach_prepare_view('node', $nodes, 'full');

    // Display a preview of the node.
    if (!form_get_errors()) {
      $node->in_preview = TRUE;

      // If enabled, allow page_manager.module to handle node rendering.
      if (module_exists('page_manager')) {

        // Load my task plugin
        $task = page_manager_get_task('node_view');

        // Load the node into a context.
        ctools_include('context');
        ctools_include('context-task-handler');
        $contexts = ctools_context_handler_get_task_contexts($task, '', array(
          $node,
        ));
        $output = ctools_context_handler_render($task, '', $contexts, array(
          $node->nid,
        ));

        // Page manager is not handeling node_view
        if ($output === FALSE) {
          $output = node_view($node, 'full');
        }
      }
      else {
        $output = node_view($node, 'full');
      }
      unset($node->in_preview);

      // Rather than the default t('Preview') allow user to see more acurate rendering
      drupal_set_title($node->title);
    }
    return $output;
  }
}

Functions

Namesort descending Description
pagepreview_build_preview Replacement function for node_preview().
pagepreview_cache_get Return a preview object from cache.
pagepreview_deliver_page Menu callback for "pagepreview/%".
pagepreview_form_alter Implements hook_form_alter().
pagepreview_menu Implements hook_menu().
pagepreview_node_form_build_preview Alternate submit callback for the node form "Preview" button.