First commit
This commit is contained in:
commit
c6e2478c40
13918 changed files with 2303184 additions and 0 deletions
23
modules/book/book-all-books-block.tpl.php
Normal file
23
modules/book/book-all-books-block.tpl.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation for rendering book outlines within a block.
|
||||
*
|
||||
* This template is used only when the block is configured to "show block on all
|
||||
* pages", which presents multiple independent books on all pages.
|
||||
*
|
||||
* Available variables:
|
||||
* - $book_menus: Array of book outlines keyed to the parent book ID. Call
|
||||
* render() on each to print it as an unordered list.
|
||||
*
|
||||
* @see template_preprocess_book_all_books_block()
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
?>
|
||||
<?php foreach ($book_menus as $book_id => $menu): ?>
|
||||
<div id="book-block-menu-<?php print $book_id; ?>" class="book-block-menu">
|
||||
<?php print render($menu); ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
52
modules/book/book-export-html.tpl.php
Normal file
52
modules/book/book-export-html.tpl.php
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation for printed version of book outline.
|
||||
*
|
||||
* Available variables:
|
||||
* - $title: Top level node title.
|
||||
* - $head: Header tags.
|
||||
* - $language: Language code. e.g. "en" for english.
|
||||
* - $language_rtl: TRUE or FALSE depending on right to left language scripts.
|
||||
* - $base_url: URL to home page.
|
||||
* - $contents: Nodes within the current outline rendered through
|
||||
* book-node-export-html.tpl.php.
|
||||
*
|
||||
* @see template_preprocess_book_export_html()
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="<?php print $language->language; ?>" xml:lang="<?php print $language->language; ?>" dir="<?php print $dir; ?>">
|
||||
<head>
|
||||
<title><?php print $title; ?></title>
|
||||
<?php print $head; ?>
|
||||
<base href="<?php print $base_url; ?>" />
|
||||
<link type="text/css" rel="stylesheet" href="misc/print.css" />
|
||||
<?php if ($language_rtl): ?>
|
||||
<link type="text/css" rel="stylesheet" href="misc/print-rtl.css" />
|
||||
<?php endif; ?>
|
||||
</head>
|
||||
<body>
|
||||
<?php
|
||||
/**
|
||||
* The given node is /embedded to its absolute depth in a top level
|
||||
* section/. For example, a child node with depth 2 in the hierarchy is
|
||||
* contained in (otherwise empty) <div> elements corresponding to
|
||||
* depth 0 and depth 1. This is intended to support WYSIWYG output - e.g.,
|
||||
* level 3 sections always look like level 3 sections, no matter their
|
||||
* depth relative to the node selected to be exported as printer-friendly
|
||||
* HTML.
|
||||
*/
|
||||
$div_close = '';
|
||||
?>
|
||||
<?php for ($i = 1; $i < $depth; $i++): ?>
|
||||
<div class="section-<?php print $i; ?>">
|
||||
<?php $div_close .= '</div>'; ?>
|
||||
<?php endfor; ?>
|
||||
<?php print $contents; ?>
|
||||
<?php print $div_close; ?>
|
||||
</body>
|
||||
</html>
|
54
modules/book/book-navigation.tpl.php
Normal file
54
modules/book/book-navigation.tpl.php
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation to navigate books.
|
||||
*
|
||||
* Presented under nodes that are a part of book outlines.
|
||||
*
|
||||
* Available variables:
|
||||
* - $tree: The immediate children of the current node rendered as an unordered
|
||||
* list.
|
||||
* - $current_depth: Depth of the current node within the book outline. Provided
|
||||
* for context.
|
||||
* - $prev_url: URL to the previous node.
|
||||
* - $prev_title: Title of the previous node.
|
||||
* - $parent_url: URL to the parent node.
|
||||
* - $parent_title: Title of the parent node. Not printed by default. Provided
|
||||
* as an option.
|
||||
* - $next_url: URL to the next node.
|
||||
* - $next_title: Title of the next node.
|
||||
* - $has_links: Flags TRUE whenever the previous, parent or next data has a
|
||||
* value.
|
||||
* - $book_id: The book ID of the current outline being viewed. Same as the node
|
||||
* ID containing the entire outline. Provided for context.
|
||||
* - $book_url: The book/node URL of the current outline being viewed. Provided
|
||||
* as an option. Not used by default.
|
||||
* - $book_title: The book/node title of the current outline being viewed.
|
||||
* Provided as an option. Not used by default.
|
||||
*
|
||||
* @see template_preprocess_book_navigation()
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
?>
|
||||
<?php if ($tree || $has_links): ?>
|
||||
<div id="book-navigation-<?php print $book_id; ?>" class="book-navigation">
|
||||
<?php print $tree; ?>
|
||||
|
||||
<?php if ($has_links): ?>
|
||||
<div class="page-links clearfix">
|
||||
<?php if ($prev_url): ?>
|
||||
<a href="<?php print $prev_url; ?>" class="page-previous" title="<?php print t('Go to previous page'); ?>"><?php print t('‹ ') . $prev_title; ?></a>
|
||||
<?php endif; ?>
|
||||
<?php if ($parent_url): ?>
|
||||
<a href="<?php print $parent_url; ?>" class="page-up" title="<?php print t('Go to parent page'); ?>"><?php print t('up'); ?></a>
|
||||
<?php endif; ?>
|
||||
<?php if ($next_url): ?>
|
||||
<a href="<?php print $next_url; ?>" class="page-next" title="<?php print t('Go to next page'); ?>"><?php print $next_title . t(' ›'); ?></a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
<?php endif; ?>
|
25
modules/book/book-node-export-html.tpl.php
Normal file
25
modules/book/book-node-export-html.tpl.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation for a single node in a printer-friendly outline.
|
||||
*
|
||||
* @see book-node-export-html.tpl.php
|
||||
* Where it is collected and printed out.
|
||||
*
|
||||
* Available variables:
|
||||
* - $depth: Depth of the current node inside the outline.
|
||||
* - $title: Node title.
|
||||
* - $content: Node content.
|
||||
* - $children: All the child nodes recursively rendered through this file.
|
||||
*
|
||||
* @see template_preprocess_book_node_export_html()
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
?>
|
||||
<div id="node-<?php print $node->nid; ?>" class="section-<?php print $depth; ?>">
|
||||
<h1 class="book-heading"><?php print $title; ?></h1>
|
||||
<?php print $content; ?>
|
||||
<?php print $children; ?>
|
||||
</div>
|
15
modules/book/book-rtl.css
Normal file
15
modules/book/book-rtl.css
Normal file
|
@ -0,0 +1,15 @@
|
|||
/**
|
||||
* @file
|
||||
* Right-to-Left styling for the Book module.
|
||||
*/
|
||||
|
||||
.book-navigation .menu {
|
||||
padding: 1em 3em 0 0;
|
||||
}
|
||||
|
||||
.book-navigation .page-previous {
|
||||
float: right;
|
||||
}
|
||||
.book-navigation .page-up {
|
||||
float: right;
|
||||
}
|
289
modules/book/book.admin.inc
Normal file
289
modules/book/book.admin.inc
Normal file
|
@ -0,0 +1,289 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Administration page callbacks for the Book module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns an administrative overview of all books.
|
||||
*
|
||||
* @return string
|
||||
* A HTML-formatted string with the administrative page content.
|
||||
*
|
||||
* @see book_menu()
|
||||
*/
|
||||
function book_admin_overview() {
|
||||
$rows = array();
|
||||
|
||||
$headers = array(t('Book'), t('Operations'));
|
||||
|
||||
// Add any recognized books to the table list.
|
||||
foreach (book_get_books() as $book) {
|
||||
$rows[] = array(l($book['title'], $book['href'], $book['options']), l(t('edit order and titles'), 'admin/content/book/' . $book['nid']));
|
||||
}
|
||||
|
||||
return theme('table', array('header' => $headers, 'rows' => $rows, 'empty' => t('No books available.')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Form constructor for the book settings form.
|
||||
*
|
||||
* @see book_admin_settings_validate()
|
||||
*
|
||||
* @ingroup forms
|
||||
*/
|
||||
function book_admin_settings() {
|
||||
$types = node_type_get_names();
|
||||
$form['book_allowed_types'] = array(
|
||||
'#type' => 'checkboxes',
|
||||
'#title' => t('Content types allowed in book outlines'),
|
||||
'#default_value' => variable_get('book_allowed_types', array('book')),
|
||||
'#options' => $types,
|
||||
'#description' => t('Users with the %outline-perm permission can add all content types.', array('%outline-perm' => t('Administer book outlines'))),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
$form['book_child_type'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Content type for child pages'),
|
||||
'#default_value' => variable_get('book_child_type', 'book'),
|
||||
'#options' => $types,
|
||||
'#required' => TRUE,
|
||||
);
|
||||
$form['array_filter'] = array('#type' => 'value', '#value' => TRUE);
|
||||
$form['#validate'][] = 'book_admin_settings_validate';
|
||||
|
||||
return system_settings_form($form);
|
||||
}
|
||||
|
||||
/**
|
||||
* Form validation handler for book_admin_settings().
|
||||
*
|
||||
* @see book_admin_settings_submit()
|
||||
*/
|
||||
function book_admin_settings_validate($form, &$form_state) {
|
||||
$child_type = $form_state['values']['book_child_type'];
|
||||
if (empty($form_state['values']['book_allowed_types'][$child_type])) {
|
||||
form_set_error('book_child_type', t('The content type for the %add-child link must be one of those selected as an allowed book outline type.', array('%add-child' => t('Add child page'))));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Form constructor for administering a single book's hierarchy.
|
||||
*
|
||||
* @see book_admin_edit_submit()
|
||||
*
|
||||
* @param $node
|
||||
* The node of the top-level page in the book.
|
||||
*
|
||||
* @see book_admin_edit_validate()
|
||||
* @see book_admin_edit_submit()
|
||||
* @ingroup forms
|
||||
*/
|
||||
function book_admin_edit($form, $form_state, $node) {
|
||||
drupal_set_title($node->title);
|
||||
$form['#node'] = $node;
|
||||
_book_admin_table($node, $form);
|
||||
$form['save'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Save book pages'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form validation handler for book_admin_edit().
|
||||
*
|
||||
* Checks that the book has not been changed while using the form.
|
||||
*
|
||||
* @see book_admin_edit_submit()
|
||||
*/
|
||||
function book_admin_edit_validate($form, &$form_state) {
|
||||
if ($form_state['values']['tree_hash'] != $form_state['values']['tree_current_hash']) {
|
||||
form_set_error('', t('This book has been modified by another user, the changes could not be saved.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Form submission handler for book_admin_edit().
|
||||
*
|
||||
* This function takes care to save parent menu items before their children.
|
||||
* Saving menu items in the incorrect order can break the menu tree.
|
||||
*
|
||||
* @see book_admin_edit_validate()
|
||||
* @see menu_overview_form_submit()
|
||||
*/
|
||||
function book_admin_edit_submit($form, &$form_state) {
|
||||
// Save elements in the same order as defined in post rather than the form.
|
||||
// This ensures parents are updated before their children, preventing orphans.
|
||||
$order = array_flip(array_keys($form_state['input']['table']));
|
||||
$form['table'] = array_merge($order, $form['table']);
|
||||
|
||||
foreach (element_children($form['table']) as $key) {
|
||||
if ($form['table'][$key]['#item']) {
|
||||
$row = $form['table'][$key];
|
||||
$values = $form_state['values']['table'][$key];
|
||||
|
||||
// Update menu item if moved.
|
||||
if ($row['plid']['#default_value'] != $values['plid'] || $row['weight']['#default_value'] != $values['weight']) {
|
||||
$row['#item']['plid'] = $values['plid'];
|
||||
$row['#item']['weight'] = $values['weight'];
|
||||
menu_link_save($row['#item']);
|
||||
}
|
||||
|
||||
// Update the title if changed.
|
||||
if ($row['title']['#default_value'] != $values['title']) {
|
||||
$node = node_load($values['nid']);
|
||||
$langcode = LANGUAGE_NONE;
|
||||
$node->title = $values['title'];
|
||||
$node->book['link_title'] = $values['title'];
|
||||
$node->revision = 1;
|
||||
$node->log = t('Title changed from %original to %current.', array('%original' => $node->title, '%current' => $values['title']));
|
||||
|
||||
node_save($node);
|
||||
watchdog('content', 'book: updated %title.', array('%title' => $node->title), WATCHDOG_NOTICE, l(t('view'), 'node/' . $node->nid));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drupal_set_message(t('Updated book %title.', array('%title' => $form['#node']->title)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the table portion of the form for the book administration page.
|
||||
*
|
||||
* @param $node
|
||||
* The node of the top-level page in the book.
|
||||
* @param $form
|
||||
* The form that is being modified, passed by reference.
|
||||
*
|
||||
* @see book_admin_edit()
|
||||
*/
|
||||
function _book_admin_table($node, &$form) {
|
||||
$form['table'] = array(
|
||||
'#theme' => 'book_admin_table',
|
||||
'#tree' => TRUE,
|
||||
);
|
||||
|
||||
$tree = book_menu_subtree_data($node->book);
|
||||
$tree = array_shift($tree); // Do not include the book item itself.
|
||||
if ($tree['below']) {
|
||||
$hash = drupal_hash_base64(serialize($tree['below']));
|
||||
// Store the hash value as a hidden form element so that we can detect
|
||||
// if another user changed the book hierarchy.
|
||||
$form['tree_hash'] = array(
|
||||
'#type' => 'hidden',
|
||||
'#default_value' => $hash,
|
||||
);
|
||||
$form['tree_current_hash'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $hash,
|
||||
);
|
||||
_book_admin_table_tree($tree['below'], $form['table']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Helps build the main table in the book administration page form.
|
||||
*
|
||||
* @param $tree
|
||||
* A subtree of the book menu hierarchy.
|
||||
* @param $form
|
||||
* The form that is being modified, passed by reference.
|
||||
*
|
||||
* @return
|
||||
* The modified form array.
|
||||
*
|
||||
* @see book_admin_edit()
|
||||
*/
|
||||
function _book_admin_table_tree($tree, &$form) {
|
||||
// The delta must be big enough to give each node a distinct value.
|
||||
$count = count($tree);
|
||||
$delta = ($count < 30) ? 15 : intval($count / 2) + 1;
|
||||
|
||||
foreach ($tree as $data) {
|
||||
$form['book-admin-' . $data['link']['nid']] = array(
|
||||
'#item' => $data['link'],
|
||||
'nid' => array('#type' => 'value', '#value' => $data['link']['nid']),
|
||||
'depth' => array('#type' => 'value', '#value' => $data['link']['depth']),
|
||||
'href' => array('#type' => 'value', '#value' => $data['link']['href']),
|
||||
'title' => array(
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => $data['link']['link_title'],
|
||||
'#maxlength' => 255,
|
||||
'#size' => 40,
|
||||
),
|
||||
'weight' => array(
|
||||
'#type' => 'weight',
|
||||
'#default_value' => $data['link']['weight'],
|
||||
'#delta' => max($delta, abs($data['link']['weight'])),
|
||||
'#title' => t('Weight for @title', array('@title' => $data['link']['title'])),
|
||||
'#title_display' => 'invisible',
|
||||
),
|
||||
'plid' => array(
|
||||
'#type' => 'hidden',
|
||||
'#default_value' => $data['link']['plid'],
|
||||
),
|
||||
'mlid' => array(
|
||||
'#type' => 'hidden',
|
||||
'#default_value' => $data['link']['mlid'],
|
||||
),
|
||||
);
|
||||
if ($data['below']) {
|
||||
_book_admin_table_tree($data['below'], $form);
|
||||
}
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a book administration form.
|
||||
*
|
||||
* @param $variables
|
||||
* An associative array containing:
|
||||
* - form: A render element representing the form.
|
||||
*
|
||||
* @see book_admin_table()
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_book_admin_table($variables) {
|
||||
$form = $variables['form'];
|
||||
|
||||
drupal_add_tabledrag('book-outline', 'match', 'parent', 'book-plid', 'book-plid', 'book-mlid', TRUE, MENU_MAX_DEPTH - 2);
|
||||
drupal_add_tabledrag('book-outline', 'order', 'sibling', 'book-weight');
|
||||
|
||||
$header = array(t('Title'), t('Weight'), t('Parent'), array('data' => t('Operations'), 'colspan' => '3'));
|
||||
|
||||
$rows = array();
|
||||
$destination = drupal_get_destination();
|
||||
$access = user_access('administer nodes');
|
||||
foreach (element_children($form) as $key) {
|
||||
$nid = $form[$key]['nid']['#value'];
|
||||
$href = $form[$key]['href']['#value'];
|
||||
|
||||
// Add special classes to be used with tabledrag.js.
|
||||
$form[$key]['plid']['#attributes']['class'] = array('book-plid');
|
||||
$form[$key]['mlid']['#attributes']['class'] = array('book-mlid');
|
||||
$form[$key]['weight']['#attributes']['class'] = array('book-weight');
|
||||
|
||||
$data = array(
|
||||
theme('indentation', array('size' => $form[$key]['depth']['#value'] - 2)) . drupal_render($form[$key]['title']),
|
||||
drupal_render($form[$key]['weight']),
|
||||
drupal_render($form[$key]['plid']) . drupal_render($form[$key]['mlid']),
|
||||
l(t('view'), $href),
|
||||
$access ? l(t('edit'), 'node/' . $nid . '/edit', array('query' => $destination)) : ' ',
|
||||
$access ? l(t('delete'), 'node/' . $nid . '/delete', array('query' => $destination) ) : ' ',
|
||||
);
|
||||
$row = array('data' => $data);
|
||||
if (isset($form[$key]['#attributes'])) {
|
||||
$row = array_merge($row, $form[$key]['#attributes']);
|
||||
}
|
||||
$row['class'][] = 'draggable';
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
return theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'book-outline'), 'empty' => t('No book content available.')));
|
||||
}
|
58
modules/book/book.css
Normal file
58
modules/book/book.css
Normal file
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* @file
|
||||
* Styling for the Book module.
|
||||
*/
|
||||
|
||||
.book-navigation .menu {
|
||||
border-top: 1px solid #888;
|
||||
padding: 1em 0 0 3em; /* LTR */
|
||||
}
|
||||
.book-navigation .page-links {
|
||||
border-top: 1px solid #888;
|
||||
border-bottom: 1px solid #888;
|
||||
text-align: center;
|
||||
padding: 0.5em;
|
||||
}
|
||||
.book-navigation .page-previous {
|
||||
text-align: left;
|
||||
width: 42%;
|
||||
display: block;
|
||||
float: left; /* LTR */
|
||||
}
|
||||
.book-navigation .page-up {
|
||||
margin: 0 5%;
|
||||
width: 4%;
|
||||
display: block;
|
||||
float: left; /* LTR */
|
||||
}
|
||||
.book-navigation .page-next {
|
||||
text-align: right;
|
||||
width: 42%;
|
||||
display: block;
|
||||
float: right;
|
||||
}
|
||||
#book-outline {
|
||||
min-width: 56em;
|
||||
}
|
||||
.book-outline-form .form-item {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
html.js #edit-book-pick-book {
|
||||
display: none;
|
||||
}
|
||||
.form-item-book-bid .description {
|
||||
clear: both;
|
||||
}
|
||||
#book-admin-edit select {
|
||||
margin-right: 24px;
|
||||
}
|
||||
#book-admin-edit select.progress-disabled {
|
||||
margin-right: 0;
|
||||
}
|
||||
#book-admin-edit tr.ajax-new-content {
|
||||
background-color: #ffd;
|
||||
}
|
||||
#book-admin-edit .form-item {
|
||||
float: left;
|
||||
}
|
14
modules/book/book.info
Normal file
14
modules/book/book.info
Normal file
|
@ -0,0 +1,14 @@
|
|||
name = Book
|
||||
description = Allows users to create and organize related content in an outline.
|
||||
package = Core
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
files[] = book.test
|
||||
configure = admin/content/book/settings
|
||||
stylesheets[all][] = book.css
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
95
modules/book/book.install
Normal file
95
modules/book/book.install
Normal file
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update and uninstall functions for the book module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_install().
|
||||
*/
|
||||
function book_install() {
|
||||
// Add the node type.
|
||||
_book_install_type_create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_uninstall().
|
||||
*/
|
||||
function book_uninstall() {
|
||||
variable_del('book_allowed_types');
|
||||
variable_del('book_child_type');
|
||||
variable_del('book_block_mode');
|
||||
|
||||
// Delete menu links.
|
||||
db_delete('menu_links')
|
||||
->condition('module', 'book')
|
||||
->execute();
|
||||
menu_cache_clear_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the book content type.
|
||||
*/
|
||||
function _book_install_type_create() {
|
||||
// Create an additional node type.
|
||||
$book_node_type = array(
|
||||
'type' => 'book',
|
||||
'name' => t('Book page'),
|
||||
'base' => 'node_content',
|
||||
'description' => t('<em>Books</em> have a built-in hierarchical navigation. Use for handbooks or tutorials.'),
|
||||
'custom' => 1,
|
||||
'modified' => 1,
|
||||
'locked' => 0,
|
||||
);
|
||||
|
||||
$book_node_type = node_type_set_defaults($book_node_type);
|
||||
node_type_save($book_node_type);
|
||||
node_add_body_field($book_node_type);
|
||||
// Default to not promoted.
|
||||
variable_set('node_options_book', array('status'));
|
||||
// Use this default type for adding content to books.
|
||||
variable_set('book_allowed_types', array('book'));
|
||||
variable_set('book_child_type', 'book');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_schema().
|
||||
*/
|
||||
function book_schema() {
|
||||
$schema['book'] = array(
|
||||
'description' => 'Stores book outline information. Uniquely connects each node in the outline to a link in {menu_links}',
|
||||
'fields' => array(
|
||||
'mlid' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'description' => "The book page's {menu_links}.mlid.",
|
||||
),
|
||||
'nid' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'description' => "The book page's {node}.nid.",
|
||||
),
|
||||
'bid' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'description' => "The book ID is the {book}.nid of the top-level page.",
|
||||
),
|
||||
),
|
||||
'primary key' => array('mlid'),
|
||||
'unique keys' => array(
|
||||
'nid' => array('nid'),
|
||||
),
|
||||
'indexes' => array(
|
||||
'bid' => array('bid'),
|
||||
),
|
||||
);
|
||||
|
||||
return $schema;
|
||||
}
|
27
modules/book/book.js
Normal file
27
modules/book/book.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for the Book module.
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
|
||||
Drupal.behaviors.bookFieldsetSummaries = {
|
||||
attach: function (context) {
|
||||
$('fieldset.book-outline-form', context).drupalSetSummary(function (context) {
|
||||
var $select = $('.form-item-book-bid select');
|
||||
var val = $select.val();
|
||||
|
||||
if (val === '0') {
|
||||
return Drupal.t('Not in book');
|
||||
}
|
||||
else if (val === 'new') {
|
||||
return Drupal.t('New book');
|
||||
}
|
||||
else {
|
||||
return Drupal.checkPlain($select.find(':selected').text());
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery);
|
1437
modules/book/book.module
Normal file
1437
modules/book/book.module
Normal file
File diff suppressed because it is too large
Load diff
247
modules/book/book.pages.inc
Normal file
247
modules/book/book.pages.inc
Normal file
|
@ -0,0 +1,247 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* User page callbacks for the book module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Menu callback: Prints a listing of all books.
|
||||
*
|
||||
* @return string
|
||||
* A HTML-formatted string with the listing of all books content.
|
||||
*
|
||||
* @see book_menu()
|
||||
*/
|
||||
function book_render() {
|
||||
$book_list = array();
|
||||
foreach (book_get_books() as $book) {
|
||||
$book_list[] = l($book['title'], $book['href'], $book['options']);
|
||||
}
|
||||
|
||||
return theme('item_list', array('items' => $book_list));
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback; Generates representations of a book page and its children.
|
||||
*
|
||||
* The function delegates the generation of output to helper functions. The
|
||||
* function name is derived by prepending 'book_export_' to the given output
|
||||
* type. So, e.g., a type of 'html' results in a call to the function
|
||||
* book_export_html().
|
||||
*
|
||||
* @param $type
|
||||
* A string encoding the type of output requested. The following types are
|
||||
* currently supported in book module:
|
||||
* - html: Printer-friendly HTML.
|
||||
* Other types may be supported in contributed modules.
|
||||
* @param $nid
|
||||
* An integer representing the node id (nid) of the node to export
|
||||
*
|
||||
* @return
|
||||
* A string representing the node and its children in the book hierarchy in a
|
||||
* format determined by the $type parameter.
|
||||
*
|
||||
* @see book_menu()
|
||||
*/
|
||||
function book_export($type, $nid) {
|
||||
// Check that the node exists and that the current user has access to it.
|
||||
$node = node_load($nid);
|
||||
if (!$node) {
|
||||
return MENU_NOT_FOUND;
|
||||
}
|
||||
if (!node_access('view', $node)) {
|
||||
return MENU_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
$type = drupal_strtolower($type);
|
||||
|
||||
$export_function = 'book_export_' . $type;
|
||||
|
||||
if (function_exists($export_function)) {
|
||||
print call_user_func($export_function, $nid);
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('Unknown export format.'));
|
||||
drupal_not_found();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates HTML for export when invoked by book_export().
|
||||
*
|
||||
* The given node is embedded to its absolute depth in a top level section. For
|
||||
* example, a child node with depth 2 in the hierarchy is contained in
|
||||
* (otherwise empty) <div> elements corresponding to depth 0 and depth 1.
|
||||
* This is intended to support WYSIWYG output - e.g., level 3 sections always
|
||||
* look like level 3 sections, no matter their depth relative to the node
|
||||
* selected to be exported as printer-friendly HTML.
|
||||
*
|
||||
* @param $nid
|
||||
* An integer representing the node id (nid) of the node to export.
|
||||
*
|
||||
* @return
|
||||
* A string containing HTML representing the node and its children in
|
||||
* the book hierarchy.
|
||||
*/
|
||||
function book_export_html($nid) {
|
||||
if (user_access('access printer-friendly version')) {
|
||||
$node = node_load($nid);
|
||||
if (isset($node->book)) {
|
||||
$tree = book_menu_subtree_data($node->book);
|
||||
$contents = book_export_traverse($tree, 'book_node_export');
|
||||
return theme('book_export_html', array('title' => $node->title, 'contents' => $contents, 'depth' => $node->book['depth']));
|
||||
}
|
||||
else {
|
||||
drupal_not_found();
|
||||
}
|
||||
}
|
||||
else {
|
||||
drupal_access_denied();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback: Shows the outline form for a single node.
|
||||
*
|
||||
* @param $node
|
||||
* The book node for which to show the outline.
|
||||
*
|
||||
* @return string
|
||||
* A HTML-formatted string with the outline form for a single node.
|
||||
*
|
||||
* @see book_menu()
|
||||
*/
|
||||
function book_outline($node) {
|
||||
drupal_set_title($node->title);
|
||||
return drupal_get_form('book_outline_form', $node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Form constructor for the book outline form.
|
||||
*
|
||||
* Allows handling of all book outline operations via the outline tab.
|
||||
*
|
||||
* @param $node
|
||||
* The book node for which to show the outline.
|
||||
*
|
||||
* @see book_outline_form_submit()
|
||||
* @see book_remove_button_submit()
|
||||
* @ingroup forms
|
||||
*/
|
||||
function book_outline_form($form, &$form_state, $node) {
|
||||
if (!isset($node->book)) {
|
||||
// The node is not part of any book yet - set default options.
|
||||
$node->book = _book_link_defaults($node->nid);
|
||||
}
|
||||
else {
|
||||
$node->book['original_bid'] = $node->book['bid'];
|
||||
}
|
||||
|
||||
// Find the depth limit for the parent select.
|
||||
if (!isset($node->book['parent_depth_limit'])) {
|
||||
$node->book['parent_depth_limit'] = _book_parent_depth_limit($node->book);
|
||||
}
|
||||
$form['#node'] = $node;
|
||||
$form['#id'] = 'book-outline';
|
||||
_book_add_form_elements($form, $form_state, $node);
|
||||
|
||||
$form['book']['#collapsible'] = FALSE;
|
||||
|
||||
$form['update'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $node->book['original_bid'] ? t('Update book outline') : t('Add to book outline'),
|
||||
'#weight' => 15,
|
||||
);
|
||||
|
||||
$form['remove'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Remove from book outline'),
|
||||
'#access' => _book_node_is_removable($node),
|
||||
'#weight' => 20,
|
||||
'#submit' => array('book_remove_button_submit'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form submission handler for book_outline_form().
|
||||
*
|
||||
* Redirects to removal confirmation form.
|
||||
*
|
||||
* @see book_outline_form_submit()
|
||||
*/
|
||||
function book_remove_button_submit($form, &$form_state) {
|
||||
$form_state['redirect'] = 'node/' . $form['#node']->nid . '/outline/remove';
|
||||
}
|
||||
|
||||
/**
|
||||
* Form submission handler for book_outline_form().
|
||||
*
|
||||
* @see book_remove_button_submit()
|
||||
*/
|
||||
function book_outline_form_submit($form, &$form_state) {
|
||||
$node = $form['#node'];
|
||||
$form_state['redirect'] = "node/" . $node->nid;
|
||||
$book_link = $form_state['values']['book'];
|
||||
if (!$book_link['bid']) {
|
||||
drupal_set_message(t('No changes were made'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$book_link['menu_name'] = book_menu_name($book_link['bid']);
|
||||
$node->book = $book_link;
|
||||
if (_book_update_outline($node)) {
|
||||
if ($node->book['parent_mismatch']) {
|
||||
// This will usually only happen when JS is disabled.
|
||||
drupal_set_message(t('The post has been added to the selected book. You may now position it relative to other pages.'));
|
||||
$form_state['redirect'] = "node/" . $node->nid . "/outline";
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('The book outline has been updated.'));
|
||||
}
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('There was an error adding the post to the book.'), 'error');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Form constructor to confirm removal of a node from a book.
|
||||
*
|
||||
* @param $node
|
||||
* The node to delete.
|
||||
*
|
||||
* @see book_remove_form_submit()
|
||||
* @ingroup forms
|
||||
*/
|
||||
function book_remove_form($form, &$form_state, $node) {
|
||||
$form['#node'] = $node;
|
||||
$title = array('%title' => $node->title);
|
||||
|
||||
if ($node->book['has_children']) {
|
||||
$description = t('%title has associated child pages, which will be relocated automatically to maintain their connection to the book. To recreate the hierarchy (as it was before removing this page), %title may be added again using the Outline tab, and each of its former child pages will need to be relocated manually.', $title);
|
||||
}
|
||||
else {
|
||||
$description = t('%title may be added to hierarchy again using the Outline tab.', $title);
|
||||
}
|
||||
|
||||
return confirm_form($form, t('Are you sure you want to remove %title from the book hierarchy?', $title), 'node/' . $node->nid, $description, t('Remove'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Form submission handler for book_remove_form().
|
||||
*/
|
||||
function book_remove_form_submit($form, &$form_state) {
|
||||
$node = $form['#node'];
|
||||
if (_book_node_is_removable($node)) {
|
||||
menu_link_delete($node->book['mlid']);
|
||||
db_delete('book')
|
||||
->condition('nid', $node->nid)
|
||||
->execute();
|
||||
drupal_set_message(t('The post has been removed from the book.'));
|
||||
}
|
||||
$form_state['redirect'] = 'node/' . $node->nid;
|
||||
}
|
398
modules/book/book.test
Normal file
398
modules/book/book.test
Normal file
|
@ -0,0 +1,398 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Tests for book.module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tests the functionality of the Book module.
|
||||
*/
|
||||
class BookTestCase extends DrupalWebTestCase {
|
||||
|
||||
/**
|
||||
* A book node.
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $book;
|
||||
|
||||
/**
|
||||
* A user with permission to create and edit books.
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $book_author;
|
||||
|
||||
/**
|
||||
* A user with permission to view a book and access printer-friendly version.
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $web_user;
|
||||
|
||||
/**
|
||||
* A user with permission to create and edit books and to administer blocks.
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $admin_user;
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Book functionality',
|
||||
'description' => 'Create a book, add pages, and test book interface.',
|
||||
'group' => 'Book',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp(array('book', 'node_access_test'));
|
||||
|
||||
// node_access_test requires a node_access_rebuild().
|
||||
node_access_rebuild();
|
||||
|
||||
// Create users.
|
||||
$this->book_author = $this->drupalCreateUser(array('create new books', 'create book content', 'edit own book content', 'add content to books'));
|
||||
$this->web_user = $this->drupalCreateUser(array('access printer-friendly version', 'node test view'));
|
||||
$this->admin_user = $this->drupalCreateUser(array('create new books', 'create book content', 'edit own book content', 'add content to books', 'administer blocks', 'administer permissions', 'administer book outlines', 'node test view'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new book with a page hierarchy.
|
||||
*/
|
||||
function createBook() {
|
||||
// Create new book.
|
||||
$this->drupalLogin($this->book_author);
|
||||
|
||||
$this->book = $this->createBookNode('new');
|
||||
$book = $this->book;
|
||||
|
||||
/*
|
||||
* Add page hierarchy to book.
|
||||
* Book
|
||||
* |- Node 0
|
||||
* |- Node 1
|
||||
* |- Node 2
|
||||
* |- Node 3
|
||||
* |- Node 4
|
||||
*/
|
||||
$nodes = array();
|
||||
$nodes[] = $this->createBookNode($book->nid); // Node 0.
|
||||
$nodes[] = $this->createBookNode($book->nid, $nodes[0]->book['mlid']); // Node 1.
|
||||
$nodes[] = $this->createBookNode($book->nid, $nodes[0]->book['mlid']); // Node 2.
|
||||
$nodes[] = $this->createBookNode($book->nid); // Node 3.
|
||||
$nodes[] = $this->createBookNode($book->nid); // Node 4.
|
||||
|
||||
$this->drupalLogout();
|
||||
|
||||
return $nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests book functionality through node interfaces.
|
||||
*/
|
||||
function testBook() {
|
||||
// Create new book.
|
||||
$nodes = $this->createBook();
|
||||
$book = $this->book;
|
||||
|
||||
$this->drupalLogin($this->web_user);
|
||||
|
||||
// Check that book pages display along with the correct outlines and
|
||||
// previous/next links.
|
||||
$this->checkBookNode($book, array($nodes[0], $nodes[3], $nodes[4]), FALSE, FALSE, $nodes[0], array());
|
||||
$this->checkBookNode($nodes[0], array($nodes[1], $nodes[2]), $book, $book, $nodes[1], array($book));
|
||||
$this->checkBookNode($nodes[1], NULL, $nodes[0], $nodes[0], $nodes[2], array($book, $nodes[0]));
|
||||
$this->checkBookNode($nodes[2], NULL, $nodes[1], $nodes[0], $nodes[3], array($book, $nodes[0]));
|
||||
$this->checkBookNode($nodes[3], NULL, $nodes[2], $book, $nodes[4], array($book));
|
||||
$this->checkBookNode($nodes[4], NULL, $nodes[3], $book, FALSE, array($book));
|
||||
|
||||
$this->drupalLogout();
|
||||
|
||||
// Create a second book, and move an existing book page into it.
|
||||
$this->drupalLogin($this->book_author);
|
||||
$other_book = $this->createBookNode('new');
|
||||
$node = $this->createBookNode($book->nid);
|
||||
$edit = array('book[bid]' => $other_book->nid);
|
||||
$this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
|
||||
|
||||
$this->drupalLogout();
|
||||
$this->drupalLogin($this->web_user);
|
||||
|
||||
// Check that the nodes in the second book are displayed correctly.
|
||||
// First we must set $this->book to the second book, so that the
|
||||
// correct regex will be generated for testing the outline.
|
||||
$this->book = $other_book;
|
||||
$this->checkBookNode($other_book, array($node), FALSE, FALSE, $node, array());
|
||||
$this->checkBookNode($node, NULL, $other_book, $other_book, FALSE, array($other_book));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the outline of sub-pages; previous, up, and next.
|
||||
*
|
||||
* Also checks the printer friendly version of the outline.
|
||||
*
|
||||
* @param $node
|
||||
* Node to check.
|
||||
* @param $nodes
|
||||
* Nodes that should be in outline.
|
||||
* @param $previous
|
||||
* (optional) Previous link node. Defaults to FALSE.
|
||||
* @param $up
|
||||
* (optional) Up link node. Defaults to FALSE.
|
||||
* @param $next
|
||||
* (optional) Next link node. Defaults to FALSE.
|
||||
* @param $breadcrumb
|
||||
* The nodes that should be displayed in the breadcrumb.
|
||||
*/
|
||||
function checkBookNode($node, $nodes, $previous = FALSE, $up = FALSE, $next = FALSE, array $breadcrumb) {
|
||||
// $number does not use drupal_static as it should not be reset
|
||||
// since it uniquely identifies each call to checkBookNode().
|
||||
static $number = 0;
|
||||
$this->drupalGet('node/' . $node->nid);
|
||||
|
||||
// Check outline structure.
|
||||
if ($nodes !== NULL) {
|
||||
$this->assertPattern($this->generateOutlinePattern($nodes), format_string('Node %number outline confirmed.', array('%number' => $number)));
|
||||
}
|
||||
else {
|
||||
$this->pass(format_string('Node %number does not have outline.', array('%number' => $number)));
|
||||
}
|
||||
|
||||
// Check previous, up, and next links.
|
||||
if ($previous) {
|
||||
$this->assertRaw(l('‹ ' . $previous->title, 'node/' . $previous->nid, array('attributes' => array('class' => array('page-previous'), 'title' => t('Go to previous page')))), 'Previous page link found.');
|
||||
}
|
||||
|
||||
if ($up) {
|
||||
$this->assertRaw(l('up', 'node/' . $up->nid, array('attributes' => array('class' => array('page-up'), 'title' => t('Go to parent page')))), 'Up page link found.');
|
||||
}
|
||||
|
||||
if ($next) {
|
||||
$this->assertRaw(l($next->title . ' ›', 'node/' . $next->nid, array('attributes' => array('class' => array('page-next'), 'title' => t('Go to next page')))), 'Next page link found.');
|
||||
}
|
||||
|
||||
// Compute the expected breadcrumb.
|
||||
$expected_breadcrumb = array();
|
||||
$expected_breadcrumb[] = url('');
|
||||
foreach ($breadcrumb as $a_node) {
|
||||
$expected_breadcrumb[] = url('node/' . $a_node->nid);
|
||||
}
|
||||
|
||||
// Fetch links in the current breadcrumb.
|
||||
$links = $this->xpath('//div[@class="breadcrumb"]/a');
|
||||
$got_breadcrumb = array();
|
||||
foreach ($links as $link) {
|
||||
$got_breadcrumb[] = (string) $link['href'];
|
||||
}
|
||||
|
||||
// Compare expected and got breadcrumbs.
|
||||
$this->assertIdentical($expected_breadcrumb, $got_breadcrumb, 'The breadcrumb is correctly displayed on the page.');
|
||||
|
||||
// Check printer friendly version.
|
||||
$this->drupalGet('book/export/html/' . $node->nid);
|
||||
$this->assertText($node->title, 'Printer friendly title found.');
|
||||
$this->assertRaw(check_markup($node->body[LANGUAGE_NONE][0]['value'], $node->body[LANGUAGE_NONE][0]['format']), 'Printer friendly body found.');
|
||||
|
||||
$number++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a regular expression to check for the sub-nodes in the outline.
|
||||
*
|
||||
* @param array $nodes
|
||||
* An array of nodes to check in outline.
|
||||
*
|
||||
* @return
|
||||
* A regular expression that locates sub-nodes of the outline.
|
||||
*/
|
||||
function generateOutlinePattern($nodes) {
|
||||
$outline = '';
|
||||
foreach ($nodes as $node) {
|
||||
$outline .= '(node\/' . $node->nid . ')(.*?)(' . $node->title . ')(.*?)';
|
||||
}
|
||||
|
||||
return '/<div id="book-navigation-' . $this->book->nid . '"(.*?)<ul(.*?)' . $outline . '<\/ul>/s';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a book node.
|
||||
*
|
||||
* @param $book_nid
|
||||
* A book node ID or set to 'new' to create a new book.
|
||||
* @param $parent
|
||||
* (optional) Parent book reference ID. Defaults to NULL.
|
||||
*/
|
||||
function createBookNode($book_nid, $parent = NULL) {
|
||||
// $number does not use drupal_static as it should not be reset
|
||||
// since it uniquely identifies each call to createBookNode().
|
||||
static $number = 0; // Used to ensure that when sorted nodes stay in same order.
|
||||
|
||||
$edit = array();
|
||||
$langcode = LANGUAGE_NONE;
|
||||
$edit["title"] = $number . ' - SimpleTest test node ' . $this->randomName(10);
|
||||
$edit["body[$langcode][0][value]"] = 'SimpleTest test body ' . $this->randomName(32) . ' ' . $this->randomName(32);
|
||||
$edit['book[bid]'] = $book_nid;
|
||||
|
||||
if ($parent !== NULL) {
|
||||
$this->drupalPost('node/add/book', $edit, t('Change book (update list of parents)'));
|
||||
|
||||
$edit['book[plid]'] = $parent;
|
||||
$this->drupalPost(NULL, $edit, t('Save'));
|
||||
}
|
||||
else {
|
||||
$this->drupalPost('node/add/book', $edit, t('Save'));
|
||||
}
|
||||
|
||||
// Check to make sure the book node was created.
|
||||
$node = $this->drupalGetNodeByTitle($edit['title']);
|
||||
$this->assertNotNull(($node === FALSE ? NULL : $node), 'Book node found in database.');
|
||||
$number++;
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests book export ("printer-friendly version") functionality.
|
||||
*/
|
||||
function testBookExport() {
|
||||
// Create a book.
|
||||
$nodes = $this->createBook();
|
||||
|
||||
// Login as web user and view printer-friendly version.
|
||||
$this->drupalLogin($this->web_user);
|
||||
$this->drupalGet('node/' . $this->book->nid);
|
||||
$this->clickLink(t('Printer-friendly version'));
|
||||
|
||||
// Make sure each part of the book is there.
|
||||
foreach ($nodes as $node) {
|
||||
$this->assertText($node->title, 'Node title found in printer friendly version.');
|
||||
$this->assertRaw(check_markup($node->body[LANGUAGE_NONE][0]['value'], $node->body[LANGUAGE_NONE][0]['format']), 'Node body found in printer friendly version.');
|
||||
}
|
||||
|
||||
// Make sure we can't export an unsupported format.
|
||||
$this->drupalGet('book/export/foobar/' . $this->book->nid);
|
||||
$this->assertResponse('404', 'Unsupported export format returned "not found".');
|
||||
|
||||
// Make sure we get a 404 on a not existing book node.
|
||||
$this->drupalGet('book/export/html/123');
|
||||
$this->assertResponse('404', 'Not existing book node returned "not found".');
|
||||
|
||||
// Make sure an anonymous user cannot view printer-friendly version.
|
||||
$this->drupalLogout();
|
||||
|
||||
// Load the book and verify there is no printer-friendly version link.
|
||||
$this->drupalGet('node/' . $this->book->nid);
|
||||
$this->assertNoLink(t('Printer-friendly version'), 'Anonymous user is not shown link to printer-friendly version.');
|
||||
|
||||
// Try getting the URL directly, and verify it fails.
|
||||
$this->drupalGet('book/export/html/' . $this->book->nid);
|
||||
$this->assertResponse('403', 'Anonymous user properly forbidden.');
|
||||
|
||||
// Now grant anonymous users permission to view the printer-friendly
|
||||
// version and verify that node access restrictions still prevent them from
|
||||
// seeing it.
|
||||
user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access printer-friendly version'));
|
||||
$this->drupalGet('book/export/html/' . $this->book->nid);
|
||||
$this->assertResponse('403', 'Anonymous user properly forbidden from seeing the printer-friendly version when denied by node access.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the functionality of the book navigation block.
|
||||
*/
|
||||
function testBookNavigationBlock() {
|
||||
$this->drupalLogin($this->admin_user);
|
||||
|
||||
// Set block title to confirm that the interface is available.
|
||||
$block_title = $this->randomName(16);
|
||||
$this->drupalPost('admin/structure/block/manage/book/navigation/configure', array('title' => $block_title), t('Save block'));
|
||||
$this->assertText(t('The block configuration has been saved.'), 'Block configuration set.');
|
||||
|
||||
// Set the block to a region to confirm block is available.
|
||||
$edit = array();
|
||||
$edit['blocks[book_navigation][region]'] = 'footer';
|
||||
$this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
|
||||
$this->assertText(t('The block settings have been updated.'), 'Block successfully move to footer region.');
|
||||
|
||||
// Give anonymous users the permission 'node test view'.
|
||||
$edit = array();
|
||||
$edit[DRUPAL_ANONYMOUS_RID . '[node test view]'] = TRUE;
|
||||
$this->drupalPost('admin/people/permissions/' . DRUPAL_ANONYMOUS_RID, $edit, t('Save permissions'));
|
||||
$this->assertText(t('The changes have been saved.'), "Permission 'node test view' successfully assigned to anonymous users.");
|
||||
|
||||
// Test correct display of the block.
|
||||
$nodes = $this->createBook();
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertText($block_title, 'Book navigation block is displayed.');
|
||||
$this->assertText($this->book->title, format_string('Link to book root (@title) is displayed.', array('@title' => $nodes[0]->title)));
|
||||
$this->assertNoText($nodes[0]->title, 'No links to individual book pages are displayed.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the book navigation block when an access module is enabled.
|
||||
*/
|
||||
function testNavigationBlockOnAccessModuleEnabled() {
|
||||
$this->drupalLogin($this->admin_user);
|
||||
$edit = array();
|
||||
|
||||
// Set the block title.
|
||||
$block_title = $this->randomName(16);
|
||||
$edit['title'] = $block_title;
|
||||
|
||||
// Set block display to 'Show block only on book pages'.
|
||||
$edit['book_block_mode'] = 'book pages';
|
||||
$this->drupalPost('admin/structure/block/manage/book/navigation/configure', $edit, t('Save block'));
|
||||
$this->assertText(t('The block configuration has been saved.'), 'Block configuration set.');
|
||||
|
||||
// Set the block to a region to confirm block is available.
|
||||
$edit = array();
|
||||
$edit['blocks[book_navigation][region]'] = 'footer';
|
||||
$this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
|
||||
$this->assertText(t('The block settings have been updated.'), 'Block successfully move to footer region.');
|
||||
|
||||
// Give anonymous users the permission 'node test view'.
|
||||
$edit = array();
|
||||
$edit[DRUPAL_ANONYMOUS_RID . '[node test view]'] = TRUE;
|
||||
$this->drupalPost('admin/people/permissions/' . DRUPAL_ANONYMOUS_RID, $edit, t('Save permissions'));
|
||||
$this->assertText(t('The changes have been saved.'), "Permission 'node test view' successfully assigned to anonymous users.");
|
||||
|
||||
// Create a book.
|
||||
$this->createBook();
|
||||
|
||||
// Test correct display of the block to registered users.
|
||||
$this->drupalLogin($this->web_user);
|
||||
$this->drupalGet('node/' . $this->book->nid);
|
||||
$this->assertText($block_title, 'Book navigation block is displayed to registered users.');
|
||||
$this->drupalLogout();
|
||||
|
||||
// Test correct display of the block to anonymous users.
|
||||
$this->drupalGet('node/' . $this->book->nid);
|
||||
$this->assertText($block_title, 'Book navigation block is displayed to anonymous users.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the access for deleting top-level book nodes.
|
||||
*/
|
||||
function testBookDelete() {
|
||||
$nodes = $this->createBook();
|
||||
$this->drupalLogin($this->admin_user);
|
||||
$edit = array();
|
||||
|
||||
// Test access to delete top-level and child book nodes.
|
||||
$this->drupalGet('node/' . $this->book->nid . '/outline/remove');
|
||||
$this->assertResponse('403', 'Deleting top-level book node properly forbidden.');
|
||||
$this->drupalPost('node/' . $nodes[4]->nid . '/outline/remove', $edit, t('Remove'));
|
||||
$node4 = node_load($nodes[4]->nid, NULL, TRUE);
|
||||
$this->assertTrue(empty($node4->book), 'Deleting child book node properly allowed.');
|
||||
|
||||
// Delete all child book nodes and retest top-level node deletion.
|
||||
foreach ($nodes as $node) {
|
||||
$nids[] = $node->nid;
|
||||
}
|
||||
node_delete_multiple($nids);
|
||||
$this->drupalPost('node/' . $this->book->nid . '/outline/remove', $edit, t('Remove'));
|
||||
$node = node_load($this->book->nid, NULL, TRUE);
|
||||
$this->assertTrue(empty($node->book), 'Deleting childless top-level book node properly allowed.');
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue