'. t('The wikitools module allows you to set several options for your content to get a more wiki-like behaviour.') .'

'; return $output; break; } } /* * Setup functions */ /** * Implementation of hook_menu(). */ function wikitools_menu() { $items = array(); $items['admin/settings/wikitools'] = array( 'title' => t('Wikitools'), 'description' => t('Settings for wiki-like behaviour.'), 'access arguments' => array('administer site configuration'), 'page callback' => 'drupal_get_form', 'page arguments' => array('wikitools_admin_settings'), 'type' => MENU_NORMAL_ITEM ); if ($wiki_path = wikitools_wiki_path()) { $items[$wiki_path] = array( 'page callback' => 'wikitools_handle_request', 'access arguments' => array('access content'), 'type' => MENU_CALLBACK ); } if (module_exists('freelinking') && wikitools_hijack_freelinking()) { // Add a new path under the freelinking path. $callbacks['freelinking/%'] = array( 'page callback' => 'wikitools_handle_request', 'access arguments' => array('access content'), 'type' => MENU_CALLBACK ); } return $items; } /** * Implementation of hook_menu_alter(). */ function wikitools_menu_alter(&$callbacks) { // Override the callback for node deletion if the delete protection option is set. if (wikitools_delete_protection()) { // Hijack delete callback and call custom handler. $callbacks['node/%node/delete']['page callback'] = 'wikitools_delete_protection_delete_confirm'; $callbacks['node/%node/delete']['page arguments'] = array(1); } } /** * Builder function for settings form. */ function wikitools_admin_settings() { $form = array(); $form['wikitools_path'] = array( '#type' => 'textfield', '#title' => t('Wiki path'), '#default_value' => wikitools_wiki_path(), '#description' => t('The drupal path for the wiki. Do not include a trailing slash. Leave empty to disable the wiki path.'), '#field_prefix' => url(NULL, array('absolute' => FALSE)) . (variable_get('clean_url', 0) ? '' : '?q=') ); $form['wikitools_main_page_title'] = array( '#type' => 'textfield', '#title' => t('Title of main page'), '#default_value' => wikitools_main_page_title(), '#description' => t('The main page is shown if you type in the wiki path. Leave empty to disable the main page.'), ); $form['wikitools_node_types'] = array( '#type' => 'checkboxes', '#title' => t('Wiki node types'), '#options' => node_get_types('names'), '#default_value' => wikitools_node_types(), '#multiple' => TRUE, '#description' => t('Select the node types which will be affected by the specified options. If you select multiple node types, all nodes of these types will be searched for when a wikipath is entered. If a wikipage doesn\'t exist, an option to create any of these types will be given.'), ); $form['wikitools_options'] = array( '#type' => 'checkboxes', '#title' => t('Options'), '#options' => array( 'node creation' => t('Node Creation: Let users create new nodes when they type in a node name which does not exist.'), 'node search' => t('Node Search: Let users search for nodes when they type in a node name which does not exist.'), 'auto redirect' => t('Automatic Redirect: If a title of a moved page is entered, redirect automatically.'), 'unique titles' => t('Unique Titles: Enforce that titles of new nodes are different from existing ones.'), 'move protection' => t('Move Protection: Disallow change of node titles for users without administer nodes permission.'), 'delete protection' => t('Delete Protection: Disallow deletion of nodes for users without administer nodes permission.'), 'underscore as space' => t('Treat underscores as spaces when looking for node titles.'), 'dash as space' => t('Treat dashes as spaces when looking for node titles.'), ), '#default_value' => wikitools_options(), '#description' => '', ); $form['wikitools_404_type'] = array( '#type' => 'checkboxes', '#title' => t('Wiki 404 type'), '#description' => t('Select the 404 (page not found) type for all pages under the wiki path.'), '#multiple' => TRUE, '#options' => array( 'Link to search' => t('Link to search'), 'Link to creation' => t('Link to creation'), 'Creation form' => t('Creation form'), ), '#default_value' => wikitools_404(), ); $form['wikitools_disallowed_characters'] = array( '#type' => 'textfield', '#title' => t('Disallowed characters in titles'), '#description' => t('Leave empty to disable this feature. Specify a list of characters which are not allowed in the title of a wiki page.'), '#default_value' => wikitools_disallowed_characters(), ); if (module_exists('freelinking')) { $form['wikitools_hijack_freelinking'] = array( '#type' => 'checkbox', '#title' => t('Hijack freelinking filter'), '#default_value' => wikitools_hijack_freelinking(), '#description' => t('If you activate this option, the links of the freelinking filter will be processed by the wikitools module rather than the freelinking module. When active, a link to freelinking/Page Name behaves exactly as a link to wikipath/Page Name.'), ); } $form['subpages'] = array( '#type' => 'fieldset', '#title' => t('Subpages'), '#description' => t('Subpages can be appended to a URL (either directly or via a query string) and will redirect the user to the named subpage.'), ); $form['subpages']['wikitools_subpages_handling'] = array( '#type' => 'radios', '#title' => t('Activation'), '#options' => array( 'disabled' => t('Disabled'), 'url' => t('Enable url suffixes: With url suffixes, you can append the subpage to the URL. For example wikipath/Page/edit.'), 'query' => t('Enable query string: With query strings, you can append the subpage as a query. For example wikipath/Page?wt_action=edit.'), ), '#default_value' => wikitools_subpages_handling(), ); $form['subpages']['wikitools_subpages'] = array( '#type' => 'textfield', '#title' => t('URL subpages'), '#description' => t('A list of available subpages. Only these subpages can be used as url suffixes or with the query string.'), '#default_value' => implode(", ", wikitools_subpages()), ); $form = system_settings_form($form); // Rebuild the menu after updating the settings. $form['#submit'][] = 'menu_rebuild'; return $form; } /* * Settings */ /** * Drupal path of wiki. */ function wikitools_wiki_path($value = NULL) { if (is_null($value)) { return variable_get('wikitools_path', 'wiki'); } variable_set('wikitools_path', $value); } /** * Title of node on root path of wiki. */ function wikitools_main_page_title($value = NULL) { if (is_null($value)) { return variable_get('wikitools_main_page_title', 'Main Page'); } variable_set('wikitools_main_page_title', $value); } /** * Node types of wiki pages. */ function wikitools_node_types($value = NULL) { if (is_null($value)) { static $node_types = NULL; if (is_null($node_types)) { $node_types = array(); foreach(variable_get('wikitools_node_types', array()) as $type => $active) { if ($active) { $node_types[$type] = $type; } } } return $node_types; } variable_set('wikitools_node_types', $value); } /** * Is node type affected by wikitool options? */ function wikitools_type_affected($type) { static $node_types = NULL; if (is_null($node_types)) { $node_types = wikitools_node_types(); } return isset($node_types[$type]) && $node_types[$type]; } /** * What 404 error settings are set? */ function wikitools_404($value = NULL) { if (is_null($value)) { return variable_get('wikitools_404_type', array('Link to search', 'Creation form')); } variable_set('wikitools_404_type', $values); } /** * String of characters which are not allowed in a wiki page title. */ function wikitools_disallowed_characters($value = NULL) { if (is_null($value)) { return variable_get('wikitools_disallowed_characters', '[]{}|'); } variable_set('wikitools_disallowed_characters', $value); } /** * Various wikitool options. */ function wikitools_options($value = NULL) { if (is_null($value)) { return variable_get('wikitools_options', array('node creation', 'node search', 'unique titles', 'underscore as space')); } return variable_set('wikitools_options', $value); } /** * Is node creation activated? */ function wikitools_node_creation() { $options = wikitools_options(); return $options['node creation']; } /** * Is node search activated? */ function wikitools_node_search() { $options = wikitools_options(); return $options['node search']; } /** * Is delete protection activated? */ function wikitools_delete_protection() { $options = wikitools_options(); return $options['delete protection']; } /** * Is move protection activated? */ function wikitools_move_protection() { $options = wikitools_options(); return $options['move protection']; } /** * Is automatic redirection activated? */ function wikitools_auto_redirect() { $options = wikitools_options(); return $options['auto redirect']; } /** * Are unique titles enforced? */ function wikitools_enforce_unique_titles() { $options = wikitools_options(); return $options['unique titles']; } /** * Are underscore characters treated as spaces? */ function wikitools_treat_underscore_as_space() { $options = wikitools_options(); return $options['underscore as space']; } /** * Are dashes treated as spaces? */ function wikitools_treat_dash_as_space() { $options = wikitools_options(); return $options['dash as space']; } /** * The subpage handling used? * @return * 'disabled', 'url' or 'query' */ function wikitools_subpages_handling($value = NULL) { if (is_null($value)) { return variable_get('wikitools_subpages_handling', 'disabled'); } variable_set('wikitools_subpages_handling', $value); } /** * The query string used to specify subpages. */ function wikitools_subpages_query_string() { return 'wt_action'; } /** * Array of URL subpages. */ function wikitools_subpages($value = NULL) { if (is_null($value)) { return preg_split("/[\s,]+/", variable_get('wikitools_subpages', 'edit, delete, view, revisions')); } variable_set('wikitools_subpages', implode(", ", $value)); } /** * Is the freelinking path hijacked? */ function wikitools_hijack_freelinking($value = NULL) { if (is_null($value)) { return variable_get('wikitools_hijack_freelinking', FALSE); } variable_set('wikitools_hijack_freelinking', $value); } /* * Operations */ /** * Decode page name given via URL. */ function wikitools_decode_page_name($encoded_page_name) { $page_name = trim(urldecode($encoded_page_name)); if (wikitools_treat_underscore_as_space()) { $page_name = str_replace('_', ' ', $page_name); } if (wikitools_treat_dash_as_space()) { $page_name = str_replace('-', ' ', $page_name); } return $page_name; } /** * Menu callback for wiki path. * This function is called if a page without an alias is called below the wiki path. */ function wikitools_handle_request() { $output = ''; // Create list of path parts. $args = explode('/', $_GET['q']); // Calculate index of first path argument after wiki path. if (arg(0) != 'freelinking') { $i = count(explode('/', wikitools_wiki_path())); } else { $i = 1; } // Determine subpage. $subpage = NULL; if (wikitools_subpages_handling() == 'query') { // Check if a query string is in the URL with a valid subpage if (isset($_GET[wikitools_subpages_query_string()])) { $subpage = $_GET[wikitools_subpages_query_string()]; if (!in_array($subpage, wikitools_subpages())) { $subpage = NULL; } } } elseif (wikitools_subpages_handling() == 'url') { // Check if there are more than one part, and if the last one is a valid subpage. if (count($args)-$i > 1 && in_array(end($args), wikitools_subpages())) { $subpage = end($args); array_pop($args); } } // Determine page name. if (isset($args[$i])) { $page_name = wikitools_decode_page_name(implode('/', array_slice($args, $i))); } else { // Use default page title if only wiki path is entered. $page_name = wikitools_main_page_title(); } // Don't do anything if no node types are active or no page name is available $node_types = wikitools_node_types(); if (count($node_types) && $page_name) { // Try to find the current page with this name. $result = db_query("SELECT nid, type FROM {node} WHERE LOWER(title) = LOWER('%s')", $page_name); $found_nodes = array(); while ($node = db_fetch_object($result)) { if (wikitools_type_affected($node->type)) { $found_nodes[] = $node; } } if (count($found_nodes) == 1) { // Single match for title. $node = current($found_nodes); if ($subpage) { drupal_goto("node/$node->nid/$subpage"); } else { drupal_goto("node/$node->nid"); } } else if (count($found_nodes) > 1) { // Multiple match for title. drupal_set_title('Page found: '. $page_name); $output .= theme('wikitools_page_found', $page_name, $found_nodes); } else { // No match for title. Try to find an old page with this name $result = db_query("SELECT n.nid, n.type, n.title FROM {node} n LEFT JOIN {node_revisions} r ON n.nid = r.nid WHERE LOWER(r.title) = LOWER('%s') ORDER BY n.vid DESC", $page_name); $moved_nodes = array(); while ($node = db_fetch_object($result)) { if (wikitools_type_affected($node->type)) { $moved_nodes[] = $node; } } if (count($moved_nodes) > 0 && wikitools_auto_redirect() && !isset($_REQUEST['noredirect'])) { $node = current($moved_nodes); drupal_set_message(t('Redirected from %page', array('%page' => $page_name, '@url' => wikitools_wikilink_url($page_name, 'noredirect')))); drupal_goto("node/$node->nid"); } else if (count($moved_nodes) > 0) { drupal_set_title('Page moved: '. $page_name); $output = theme('wikitools_page_moved', $page_name, $moved_nodes); } else { drupal_set_title('Page does not exist: '. $page_name); $output = theme('wikitools_page_does_not_exist', $page_name); } } } return $output; } /** * Implementation of hook_nodeapi(). */ function wikitools_nodeapi(&$node, $op, $form = NULL, $a4 = NULL) { switch ($op) { case 'validate': wikitools_node_validate($node); break; } } /** * Validate check of node edit form. */ function wikitools_node_validate($node) { if (wikitools_type_affected($node->type)) { // Check for unique titles. if (wikitools_enforce_unique_titles()) { // Build node type condition. $types_clause = NULL; foreach(wikitools_node_types() as $type) { if ($types_clause) { $types_clause .= ",'" . db_escape_string($type) . "'"; } else { $types_clause = "type IN ('" . db_escape_string($type) . "'"; } } // There is at least one node type, so this will always be well-formed. $types_clause .= ')'; $nid = db_result(db_query("SELECT nid FROM {node} WHERE LOWER(title) = LOWER('%s') AND $types_clause", $node->title)); if (!$nid && wikitools_treat_underscore_as_space()) { $nid = db_result(db_query("SELECT nid FROM {node} WHERE LOWER(REPLACE(title, '_', ' ')) = LOWER(REPLACE('%s', '_', ' ')) AND $types_clause", $node->title)); } if (!$nid && wikitools_treat_dash_as_space()) { $nid = db_result(db_query("SELECT nid FROM {node} WHERE LOWER(REPLACE(title, '-', ' ')) = LOWER(REPLACE('%s', '-', ' ')) AND $types_clause", $node->title)); } // It is only an error if the node which alredy exists is not the currently edited node. if ($nid && $nid != $node->nid) { form_set_error('title', t('A page with this name alredy exists.', array('@page_url' => url("node/$nid")))); } } // Check for disallowed characters in title. if ($disallowed_characters = wikitools_disallowed_characters()) { for ($i = 0; $i < strlen($node->title); $i++) { if (strpos($disallowed_characters, $node->title[$i]) !== FALSE) { form_set_error('title', t('The character %c is not allowed in a title', array('%c' => $node->title[$i]))); break; } } } // Check for invalid title names if url subpages are enabled and "/" is allowed in titles. if (wikitools_subpages_handling() == 'url' && strpos("/", $disallowed_characters) === FALSE) { $title_parts = explode('/', $node->title); if (count($title_parts) > 1 && in_array(end($title_parts), wikitools_subpages())) { form_set_error('title', t('The title is not allowed to end in: %string', array('%string' => '/' . implode(', /', wikitools_subpages())))); } } } } /** * Implementation of hook_form_alter(). */ function wikitools_form_alter(&$form, $form_state, $form_id) { // Check if it is a node editing form of an affected type. if (isset($form['type']) && $form['type']['#value'] .'_node_form' == $form_id) { if (wikitools_type_affected($form['type']['#value'])) { if ($form['nid']['#value']) { // Node is edited. if (wikitools_delete_protection() && !user_access('administer nodes')) { unset($form['buttons']['delete']); } if (wikitools_move_protection() && !user_access('administer nodes')) { $form['title']['#disabled'] = TRUE; } } else { // Node is new. if (isset($_GET['edit'])) { $form['title']['#default_value'] = urldecode($_GET['edit']['title']); } } } } } /** * Callback of node delete action in protected mode. */ function wikitools_delete_protection_delete_confirm(&$node) { if (!wikitools_type_affected($node->type) || user_access('administer nodes')) { // Call original function. return drupal_get_form('node_delete_confirm', $node); } else { return drupal_access_denied(); } } /** * Build an url to create a new node. * @param $type * type of new node * @param $title * title of new node */ function wikitools_create_url($type, $title) { if (is_object($type)) { $type_url_str = str_replace('_', '-', $type->type); } else { $type_url_str = str_replace('_', '-', $type); } return url("node/add/$type_url_str", array('query' => 'edit[title]='. urlencode($title))); } /** * Build an url to search for a title. * @param $title * title to search for */ function wikitools_search_url($title) { return url('search/node/'. urlencode($title)); } /** * Build an url to link to a page. * @param $title * title to link to * @param $query * an optional query string to append to the link */ function wikitools_wikilink_url($title, $query = NULL) { $drupal_path = wikitools_wikilink_drupal_path($title); if ($drupal_path) { return url($drupal_path, array('query' => $query)); } } /** * Build a Drupal path to link to a page. * @param $title * title to link to * @param $query * an optional query string to append to the link */ function wikitools_wikilink_drupal_path($title) { if (wikitools_treat_underscore_as_space()) { $title = str_replace(' ', '_', $title); } if (wikitools_treat_dash_as_space()) { $title = str_replace(' ', '-', $title); } if ($wiki_path = wikitools_wiki_path()) { return $wiki_path .'/'. urlencode($title); } elseif (wikitools_hijack_freelinking()) { return 'freelinking/'. urlencode($title); } else { // Neither wikitools nor freelinking will handle the link. // Try to find a node with the given name and link directly to the first match. $result = db_query("SELECT nid, type FROM {node} WHERE LOWER(title) = LOWER('%s')", $title); $found_nodes = array(); while ($node = db_fetch_object($result)) { if (wikitools_type_affected($node->type)) { return "node/$node->nid"; } } } } /** * Implementation of hook_theme(). */ function wikitools_theme() { return array( 'wikitools_page_found' => array( 'arguments' => array('page_name' => NULL, 'found_nodes' => NULL), ), 'wikitools_page_moved' => array( 'arguments' => array('page_name' => NULL, 'moved_nodes' => NULL), ), 'wikitools_page_does_not_exist' => array( 'arguments' => array('page_name' => NULL), ), 'wikitools_search_notice' => array( 'arguments' => array('page_name' => NULL), ), 'wikitools_create_notice' => array( 'arguments' => array('page_name' => NULL), ), 'wikitools_create' => array( 'arguments' => array('page_name' => NULL), ), ); } /** * @ingroup themeable */ function theme_wikitools_page_found($page_name, $found_nodes) { $output = '

'. t('Multiple pages have this name:') .'

'; foreach ($found_nodes as $info) { $node = node_load($info->nid); $output .= node_view($node, TRUE, FALSE, FALSE); } $output .= theme('wikitools_search_notice', $page_name); if (!wikitools_enforce_unique_titles()) { $output .= theme('wikitools_create_notice', $page_name); } return $output; } function theme_wikitools_page_moved($page_name, $moved_nodes) { $output = '

'. t('The page %page_name has been moved.', array('%page_name' => $page_name)) .'

'; $node = current($moved_nodes); $output .= '

'. t('The new page name is !new_name', array('!new_name' => l($node->title, "node/$node->nid"))) .'

'; // Todo: show all moved pages $output .= theme('wikitools_search_notice', $page_name); $output .= theme('wikitools_create_notice', $page_name); return $output; } function theme_wikitools_page_does_not_exist($page_name) { $output = '

'. t('The page %page_name does not exist.', array('%page_name' => $page_name)) .'

'; $settings = wikitools_404(); if (isset($settings['Link to search'])) { $output .= theme('wikitools_search_notice', $page_name); } if (isset($settings['Link to creation'])) { $output .= theme('wikitools_create_notice', $page_name); } if (isset($settings['Creation form'])) { $output .= theme('wikitools_create', $page_name); } return $output; } function theme_wikitools_search_notice($page_name) { $output = ''; if (module_exists('search') && user_access('search content') && wikitools_node_search()) { $output .= '

'. t('You can search for %page_name', array('@url' => wikitools_search_url($page_name), '%page_name' => $page_name)) .'

'; } return $output; } function theme_wikitools_create_notice($page_name) { $output = ''; $node_types = wikitools_node_types(); if (wikitools_node_creation() && count($node_types)) { $create = ''; $count = 0; foreach ($node_types as $type) { $type = node_get_types('type', $type); if (node_access('create', $type->type)) { $create .= '
'. $type->name .'
'; $create .= '
'. filter_xss_admin($type->description) .'
'; } } if ($create) { $output .= '

'. t('You can create the page as:') .'

'; $output .= '
'. $create .'
'; } } return $output; } function theme_wikitools_create($page_name) { $node_types = wikitools_node_types(); $form = array(); $output = ''; if (wikitools_node_creation() && count($node_types)) { $output .= '

'. t('You can create the page as:') .'

'; // Collapse the forms initially if there are more than one. $collapsed = count($node_types) > 1 ? ' collapsed' : ''; // The form_alter hooks excpects the preset title in the GET array, so we put it there. $_GET['edit']['title'] = $page_name; foreach ($node_types as $type) { drupal_add_js('misc/collapse.js'); $type = node_get_types('type', $type); if (node_access('create', $type->type)) { $output .= '
'. $type->name .''; if ($router_item = menu_get_item('node/add/'. $type->type)) { if ($router_item['file']) { require_once($router_item['file']); } $output .= call_user_func_array($router_item['page_callback'], $router_item['page_arguments']); } $output .= '
'; } } // Some of the callbacks could have set the page title, so we reset it. drupal_set_title('Page does not exist: '. $page_name); } return $output; }