' . 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($may_cache) { $items = array(); if ($may_cache) { $items[] = array( 'path' => 'admin/settings/wikitools', 'title' => t('Wikitools'), 'description' => t('Settings for wiki-like behaviour.'), 'access' => user_access('administer site configuration'), 'callback' => 'drupal_get_form', 'callback arguments' => array('wikitools_admin_settings'), 'type' => MENU_NORMAL_ITEM ); } else { $wiki_path = wikitools_wiki_path(); if ($wiki_path) { $items[] = array( 'path' => $wiki_path, 'callback' => 'wikitools_handle_request', 'access' => user_access('access content'), 'type' => MENU_CALLBACK ); } // Override the callback for node deletion if the delete protection option is set. if (arg(0) == 'node' && is_numeric(arg(1))) { $node = node_load(arg(1)); if (wikitools_type_affected($node->type) && wikitools_delete_protection()) { // Hijack delete callback and call custom handler. $items[] = array('path' => 'node/'. arg(1) .'/delete', 'title' => t('Delete'), 'callback' => 'wikitools_delete_protection_delete_confirm', 'callback arguments' => array($node), 'access' => node_access('delete', $node), 'weight' => 1, 'type' => MENU_CALLBACK ); } } // Only hijack freelinking path if an argument is specified, otherwise let the freelinking page show. if (wikitools_hijack_freelinking() && arg(1)) { $items[] = array( 'path' => 'freelinking', 'callback' => 'wikitools_handle_request', 'access' => user_access('access content'), 'type' => MENU_CALLBACK ); } } return $items; } /** * 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, NULL, NULL, TRUE) . (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' => 'select', '#title' => t('Wiki node types'), '#options' => node_get_types('names'), '#size' => count(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 are unique over all wiki node types'), '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_disallowed_characters'] = array( '#type' => 'textfield', '#title' => t('Disallowed characters in titles'), '#description' => t('A list of characters which are not allowed in the title of a wiki page. This setting is important for the wikilink feature to work. Set it so that your input syntax will not be confused by titles. Make sure you don\'t enter a space character unless you really want to disallow spaces in titles. Leave empty to disable this feature.'), '#default_value' => wikitools_disallowed_characters(), ); $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.'), ); return system_settings_form($form); } /** * Implementation of hook_requirements(). */ function wikitools_requirements($phase) { // Don't check when installing if ($phase == 'install') { return; } if (wikitools_hijack_freelinking()) { wikitools_autoadjust(); } } /** * Adjust the module weights for wikitools to load after freelinking module. */ function wikitools_autoadjust() { $modules = array_keys(module_list()); if (array_search('wikitools', $modules) <= array_search('freelinking', $modules)) { $freelinking_module_weight = db_result(db_query("SELECT weight FROM {system} WHERE name='freelinking'")); db_query("UPDATE {system} SET weight=%d WHERE name='wikitools'", $freelinking_module_weight + 1); drupal_set_message(t('Weight of %wikitools module set to %weight.', array('%wikitools' => t('wikitools'), '%weight' => $wikitools_module_weight + 1))); } } /* * 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)) { return variable_get('wikitools_node_types', array()); } 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]; } /** * 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', 'delete protection', 'move protection', 'unique titles', 'auto redirect', 'underscore as space', 'dash 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']; } /** * Is the freelinking path hijacked? */ function wikitools_hijack_freelinking($value = NULL) { if (is_null($value)) { return variable_get('wikitools_hijack_freelinking', TRUE); } variable_set('wikitools_hijack_freelinking', $value); } /* * Operations */ /** * 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() { // Calculate index of first path argument after wiki path. $i = count(explode('/',wikitools_wiki_path())); if (arg($i)) { // Save the path arguments after the wiki path as page name and put the slashes back. $page_name = arg($i++); while (arg($i)) { $page_name .= '/' . arg($i); $i++; } } else { // Use default page title if only wiki path is entered. $page_name = wikitools_main_page_title(); } // Decode page name and remove white space. $page_name = trim(urldecode($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); } $node_types = wikitools_node_types(); $output = ''; // Don't do anything if no node types are active or no page name is available 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); 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)) { if (wikitools_enforce_unique_titles()) { $nid = db_result(db_query("SELECT nid FROM {node} WHERE LOWER(title) = LOWER('%s')", $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', '_', ' '))", $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', '-', ' '))", $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")))); } } $disallowed_characters = wikitools_disallowed_characters(); if ($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; } } } } } /** * Implementation of hook_form_alter(). */ function wikitools_form_alter($form_id, &$form) { // 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['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) { return url("node/add/$type", '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, $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"; } } } } /* * Theme functions */ 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)) .'

'; $output .= theme('wikitools_search_notice' ,$page_name); $output .= theme('wikitools_create_notice', $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 = ''; 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; }