diff --git a/core/modules/edit/edit.module b/core/modules/edit/edit.module index a704221..aba47a9 100644 --- a/core/modules/edit/edit.module +++ b/core/modules/edit/edit.module @@ -162,9 +162,11 @@ function edit_library_info() { * Implements hook_preprocess_HOOK() for field.tpl.php. */ function edit_preprocess_field(&$variables) { - $element = $variables['element']; - $entity = $element['#object']; - $variables['attributes']['data-edit-id'] = $entity->entityType() . '/' . $entity->id() . '/' . $element['#field_name'] . '/' . $element['#language'] . '/' . $element['#view_mode']; + if (arg(1) != 'preview') { + $element = $variables['element']; + $entity = $element['#object']; + $variables['attributes']['data-edit-id'] = $entity->entityType() . '/' . $entity->id() . '/' . $element['#field_name'] . '/' . $element['#language'] . '/' . $element['#view_mode']; + } } /** diff --git a/core/modules/node/lib/Drupal/node/NodeFormController.php b/core/modules/node/lib/Drupal/node/NodeFormController.php index 47e1f30..1bf03bc 100644 --- a/core/modules/node/lib/Drupal/node/NodeFormController.php +++ b/core/modules/node/lib/Drupal/node/NodeFormController.php @@ -26,6 +26,18 @@ class NodeFormController extends EntityFormController { * Overrides Drupal\Core\Entity\EntityFormController::prepareEntity(). */ protected function prepareEntity(EntityInterface $node) { + + // @todo decide how to get a fresh one. + // @todo the actual node is override in ::form as trying + // to overide here doesn't work. + $tempstore_id = drupal_container()->get('request')->query->get('tempstore_id'); + if ($tempstore_id) { + $node->tempstore_id = $tempstore_id; + } + else { + $node->tempstore_id = $node->uuid; + } + // Set up default values, if required. $node_options = variable_get('node_options_' . $node->type, array('status', 'promote')); // If this is a new node, fill in the default values. @@ -71,13 +83,11 @@ public function form(array $form, array &$form_state, EntityInterface $node) { } $user_config = config('user.settings'); - // Some special stuff when previewing a node. - if (isset($form_state['node_preview'])) { - $form['#prefix'] = $form_state['node_preview']; - $node->in_preview = TRUE; - } - else { - unset($node->in_preview); + + // @todo can we do this somewhere different ? + $tempstore_id = drupal_container()->get('request')->query->get('tempstore_id'); + if (!empty($tempstore_id) && ($data = node_tempstore_load($tempstore_id))) { + $node = $data; } // Override the default CSS class name, since the user-defined node type @@ -381,9 +391,9 @@ public function submit(array $form, array &$form_state) { * A reference to a keyed array containing the current state of the form. */ public function preview(array $form, array &$form_state) { - drupal_set_title(t('Preview'), PASS_THROUGH); - $form_state['node_preview'] = node_preview($this->getEntity($form_state)); - $form_state['rebuild'] = TRUE; + $entity = $this->getEntity($form_state); + drupal_container()->get('user.tempstore')->get('node')->set($entity->tempstore_id, $entity); + $form_state['redirect'] = 'node/preview/' . $entity->tempstore_id; } /** @@ -418,6 +428,9 @@ public function save(array $form, array &$form_state) { $form_state['rebuild'] = TRUE; } + // Remove from cache. + drupal_container()->get('user.tempstore')->get('node')->delete($node->tempstore_id); + // Clear the page and block caches. cache_invalidate_tags(array('content' => TRUE)); } diff --git a/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php b/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php index 6cf9fac..660c9fe 100644 --- a/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php +++ b/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php @@ -206,6 +206,13 @@ class Node extends Entity implements ContentEntityInterface { public $revision_uid; /** + * The node tempstore id. + * + * @var integer + */ + public $tempstore_id; + + /** * Implements Drupal\Core\Entity\EntityInterface::id(). */ public function id() { diff --git a/core/modules/node/node.module b/core/modules/node/node.module index eb56876..625e6c3 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -158,10 +158,6 @@ function node_theme() { 'variables' => array('content' => NULL), 'file' => 'node.pages.inc', ), - 'node_preview' => array( - 'variables' => array('node' => NULL), - 'file' => 'node.pages.inc', - ), 'node_admin_overview' => array( 'variables' => array('name' => NULL, 'type' => NULL), ), @@ -943,6 +939,23 @@ function node_load($nid = NULL, $reset = FALSE) { } /** + * Load the node from the tempstore. + * + * @param int $tempstore_id + * The id of a tempstore object. + * + * @return Drupal\node\Node|false + * A fully-populated node entity, or FALSE if the node is not found. + */ +function node_tempstore_load($tempstore_id) { + $node = drupal_container()->get('user.tempstore')->get('node')->get($tempstore_id); + if ($node) { + return $node; + } + return FALSE; +} + +/** * Loads a node revision from the database. * * @param int $nid @@ -1740,6 +1753,13 @@ function node_menu() { 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, ); + // @todo real access check. + $items['node/preview/%node_tempstore'] = array( + 'page callback' => 'node_preview', + 'page arguments' => array(2), + 'access callback' => TRUE, + 'file' => 'node.pages.inc', + ); $items['node/%node/edit'] = array( 'title' => 'Edit', 'page callback' => 'node_page_edit', @@ -2256,6 +2276,98 @@ function node_page_view(Node $node) { } /** + * Implements hook_page_build(). + */ +function node_page_build(&$page) { + + // Add 'Back to content edit editing' link on preview page. + $node = menu_get_object('node_tempstore', 2); + if ($node) { + + $page['page_top']['node-preview'] = array( + '#type' => 'container', + '#attributes' => array( + 'class' => array('node-preview-container', 'container-inline') + ), + ); + + $form = drupal_get_form('node_preview_form_select', $node); + $page['page_top']['node-preview']['view-mode'] = $form; + } +} + +/** + * Get the preview form selection box. + * + * @param string $bundle + * The name of the node bundle. + * + * @return $form + * The view mode preview selection form. + */ +function node_preview_form_select($form, $form_state, $node) { + + // Always add default. + $view_mode_options = array('default' => t('Full')); + + // Get view mode options. + $entity_info = entity_get_info('node'); + foreach ($entity_info['view_modes'] as $key => $info) { + if (!empty($info['custom_settings'])) { + $view_mode_options[$key] = $info['label']; + } + } + + $link = 'node/add/' . $node->bundle(); + if (!empty($node->nid)) { + $link = 'node/' . $node->nid . '/edit'; + } + + $view_mode = drupal_container()->get('request')->query->get('view_mode'); + if (empty($view_mode)) { + $view_mode = 'full'; + } + + $form['backlink'] = array( + '#type' => 'link', + '#title' => t('Back to content editing'), + '#href' => $link, + // Add the "overlay-restore" class to indicate this link should restore + // the context in which the preview demonstration page was opened. + '#options' => array('query' => array('tempstore_id' => $node->tempstore_id) ,'attributes' => array('class' => array('node-preview-backlink button-action', 'overlay-restore'))), + //'#prefix' => '' + ); + + $form['tempstore_id'] = array( + '#type' => 'value', + '#value' => $node->tempstore_id + ); + + $form['view_mode'] = array( + '#type' => 'select', + '#options' => $view_mode_options, + '#default_value' => $view_mode, + ); + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Switch'), + '#attributes' => array( + 'class' => array('node-preview-switch-button') + ) + ); + + return $form; +} + +/** + * Submit handler for the node preview select form. + */ +function node_preview_form_select_submit($form, &$form_state) { + $form_state['redirect'] = array('node/preview/' . $form_state['values']['tempstore_id'], array('query' => array('view_mode' => $form_state['values']['view_mode']))); +} + +/** * Implements hook_update_index(). */ function node_update_index() { @@ -3673,6 +3785,9 @@ function node_library_info() { 'js' => array( drupal_get_path('module', 'node') . '/node.preview.js' => array(), ), + 'css' => array( + drupal_get_path('module', 'node') . '/node.preview.css' => array(), + ), 'dependencies' => array( array('system', 'jquery'), array('system', 'drupal'), diff --git a/core/modules/node/node.pages.inc b/core/modules/node/node.pages.inc index 245fef7..2e753ad 100644 --- a/core/modules/node/node.pages.inc +++ b/core/modules/node/node.pages.inc @@ -121,11 +121,15 @@ function node_add($node_type) { * * @return * An HTML-formatted string of a node preview. - * - * @see node_form_build_preview() */ function node_preview(Node $node) { + + // @todo move access check earlier ? if (node_access('create', $node) || node_access('update', $node)) { + + // Set status to true so we don't get the 'unpublished' css. + $node->status = TRUE; + _field_invoke_multiple('load', 'node', array($node->nid => $node)); // Load the user's name when needed. if (isset($node->name)) { @@ -145,53 +149,18 @@ function node_preview(Node $node) { $node->changed = REQUEST_TIME; - // Display a preview of the node. - if (!form_get_errors()) { - $node->in_preview = TRUE; - $output = theme('node_preview', array('node' => $node)); - unset($node->in_preview); + // Get the view mode to render the preview in. + $view_mode = drupal_container()->get('request')->query->get('view_mode'); + if (empty($view_mode)) { + $view_mode = 'full'; } - return $output; - } -} - -/** - * Returns HTML for a node preview for display during node creation and editing. - * - * @param $variables - * An associative array containing: - * - node: The node entity which is being previewed. - * - * @see NodeFormController::preview() - * @see node_preview() - * - * @ingroup themeable - */ -function theme_node_preview($variables) { - $node = $variables['node']; - - $output = ''; - - $elements = node_view($node, 'teaser'); - $elements['#attached']['library'][] = array('node', 'drupal.node.preview'); - $trimmed = drupal_render($elements); - $elements = node_view($node, 'full'); - $full = drupal_render($elements); - - // Do we need to preview trimmed version of post as well as full version? - if ($trimmed != $full) { - drupal_set_message(t('The trimmed version of your post shows what your post looks like when promoted to the main page or when exported for syndication. You can insert the delimiter "<!--break-->" (without the quotes) to fine-tune where your post gets split.')); - $output .= '

' . t('Preview trimmed version') . '

'; - $output .= $trimmed; - $output .= '

' . t('Preview full version') . '

'; - $output .= $full; - } - else { - $output .= $full; + $build = array(); + // @todo all links should be disabled, except for returning to the edit form. + $build['#attached']['library'][] = array('node', 'drupal.node.preview'); + $build['preview'] = node_view($node, $view_mode); + return $build; } - - return $output; } /** diff --git a/core/modules/node/node.preview.css b/core/modules/node/node.preview.css new file mode 100644 index 0000000..e56449f --- /dev/null +++ b/core/modules/node/node.preview.css @@ -0,0 +1,47 @@ + +.node-preview-container { + background-color: #cee5f3; + position: fixed; + z-index: 499; + width: 100%; + padding: 10px; +} + +.button-action { + background: #1078d4; + background-image: -webkit-linear-gradient(top, #419ff1, #1076d5); + background-image: -moz-linear-gradient(top, #419ff1, #1076d5); + background-image: -o-linear-gradient(top, #419ff1, #1076d5); + background-image: linear-gradient(to bottom, #419ff1, #1076d5); + border: 1px solid #0048c8; + border-radius: .4em; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .4); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .4); + color: #fff; + font-size: 1em; + line-height: normal; + margin: 0; + padding: 4px 1em; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.5); +} +.button-action:focus, +.button-action:hover { + background-color: #419cf1; + background-image: -webkit-linear-gradient(top, #59abf3, #2a90ef); + background-image: -moz-linear-gradient(top, #59abf3, #2a90ef); + background-image: -o-linear-gradient(top, #59abf3, #2a90ef); + background-image: linear-gradient(to bottom, #59abf3, #2a90ef); + border: 1px solid #0048c8; + color: #fff; +} +.button-action:active { + background-color: #0e69be; + background-image: -webkit-linear-gradient(top, #0e69be, #2a93ef); + background-image: -moz-linear-gradient(top, #0e69be, #2a93ef); + background-image: -o-linear-gradient(top, #0e69be, #2a93ef); + background-image: -ms-linear-gradient(top, #0e69be, #2a93ef); + background-image: linear-gradient(to bottom, #0e69be, #2a93ef); + border: 1px solid #0048c8; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .25); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, .25); +} \ No newline at end of file diff --git a/core/modules/node/node.preview.js b/core/modules/node/node.preview.js index 3be74e2..be0f0cb 100644 --- a/core/modules/node/node.preview.js +++ b/core/modules/node/node.preview.js @@ -25,4 +25,16 @@ Drupal.behaviors.nodePreviewDestroyLinks = { } }; +/** + * View mode preview select form. + */ +Drupal.behaviors.nodePreviewSelectForm = { + attach: function (context) { + $('.node-preview-switch-button').hide(); + $('#edit-view-mode').change(function() { + $(this).closest('form').trigger('submit'); + }); + } +}; + })(jQuery, Drupal);