The Wiki module allows users to enter content using PhpWiki, a simple, plain text syntax that is filtered into valid HTML. The filter tips page provides syntax descriptions and examples.

'); } } /** * @name WikiText filters * @{ * Filters implemented by the filter.module. */ /** * Implementation of hook_filter(). Contains a basic set of essential filters. * - WikiText filter: * Processes wiki text and convert to HTML */ function wiki_filter($op, $delta = 0, $format = -1, $text = '') { switch ($op) { case 'list': return array(t('WikiText filter')); case 'description': return t('Converts WikiText to HTML.'); case 'process': return _wiki_filter($text, $format); case 'settings': return _wiki_filter_settings($format); default: return $text; } } /** * Implementation of hook_menu() * /wiki/goto/title redirects to a node or edit form based on title */ function wiki_menu($may_cache) { $items = array(); if ($may_cache) { $items[] = array('path' => 'wiki/goto', 'title' => t('wiki goto'), 'type' => MENU_CALLBACK, 'callback' => 'wiki_goto', 'access' => user_access('access content')); } return $items; } /** * Settings for the WikiText filter. */ function _wiki_filter_settings($format) { $the_form = array(); $the_form['wiki_settings'] = array('#type' => 'fieldset', '#title' => t('WikiText filter'), '#collapsible' => TRUE, '#collapsed' => TRUE); $the_form['wiki_settings']['enable_html_${format}'] = array( '#type' => 'checkbox', '#title' => t('Enable HTML'), '#default_value' => variable_get("enable_html_${format}", 0), '#description' => t('Whether to allow |>-escaped HTML. If enabled, then any HTML goes on each line after the |> escape marker. If disabled, then any HTML tags will be shown as is, unless the HTML Filter has been separately enabled. It is recommended that this be disabled. Turn on the HTML Filter to support HTML, but make sure the HTML filter applies after the WikiText filter.')); return $the_form; } define("WIKI_ZERO_LEVEL", 0); define("WIKI_NESTED_LEVEL", 1); define("WIKI_FIELD_SEPARATOR", "\263"); // allowed protocols for links - be careful not to allow "javascript:" // within a named link [name|uri] one more protocol is defined: phpwiki //define("WIKI_ALLOWED_PROTOCOLS", "http|https|mailto|ftp|news|gopher"); define("WIKI_ALLOWED_PROTOCOLS", "http|https|javascript|mailto|ftp|news|gopher"); // URLs ending with the following extension should be inlined as images define("WIKI_INLINE_IMAGES", "png|jpg|gif"); class _wiki_stack { var $items = array(); var $size = 0; function push($item) { $this->items[$this->size] = $item; $this->size++; return true; } function pop() { if ($this->size == 0) { return false; // stack is empty } $this->size--; return $this->items[$this->size]; } function cnt() { return $this->size; } function top() { if ($this->size) { return $this->items[$this->size - 1]; } else { return ''; } } } // end class definition /** * Find any strings in $str that match $pattern and * store them in $orig, replacing them with tokens * starting at number $ntokens - returns tokenized string */ function _wiki_tokenize($str, $pattern, &$orig, &$ntokens) { $new = ''; while (preg_match("/^(.*?)($pattern)/", $str, $matches)) { $linktoken = WIKI_FIELD_SEPARATOR . WIKI_FIELD_SEPARATOR . ($ntokens++) . WIKI_FIELD_SEPARATOR; $new .= $matches[1] . $linktoken; $orig[] = $matches[2]; $str = substr($str, strlen($matches[0])); } $new .= $str; return $new; } function _wiki_find_node($title) { // I'm surprised there's no Drupal API for finding a node (the do_search // function is way too process intensive for our needs here // As for node security we don't need to worry here. At the time of viewing // the node security will be checked. return db_fetch_object(db_query("SELECT nid FROM {node} WHERE title = '%s' AND status = 1 ORDER BY created DESC", $title)); } function _wiki_link_URL($url, $linktext='') { if (ereg("[<>\"]", $url)) { return 'BAD URL -- remove all of <, >, "'; } if (empty($linktext)) { $linktext = htmlspecialchars($url); } return "$linktext"; } function _wiki_link_image($url, $alt='[Image]') { if (ereg('[<>"]', $url)) { return "BAD URL -- remove all of <, >, ""; } return theme("image", $url, $alt, $title = '', $attr = '', $getsize = false); } function _wiki_link_node($title, $linktext='') { if (empty($linktext)) { $linktext = $title; } return l($linktext, 'wiki/goto/'. rawurlencode($title)); } function wiki_goto() { $dest_raw = arg(2); $dest = rawurldecode($dest_raw); if ($node = _wiki_find_node($dest)) { drupal_goto('node/'. $node->nid); } else { // We need a node type to link to if we're going to do this. // So I picked story, the most basic type of node. drupal_goto('node/add/story', 'edit[title]='. $dest_raw); } } /** * $bracketlink will start and end with brackets; in between * will be either a page name, a URL or both separated by a pipe. */ function _wiki_parse_and_link($bracketlink) { // strip brackets and leading space preg_match("/(\[\s*)(.+?)(\s*\])/", $bracketlink, $match); // match the contents preg_match("/([^|]+)(\|)?([^|]+)?/", $match[2], $matches); if (isset($matches[3])) { // named link of the form "[some link name | http://blippy.com/]" $URL = trim($matches[3]); $linkname = htmlspecialchars(trim($matches[1])); $linktype = 'named'; } else { // unnamed link of the form "[http://blippy.com/] or [wiki page]" $URL = trim($matches[1]); $linkname = ''; $linktype = 'simple'; } if (preg_match("/\.".WIKI_INLINE_IMAGES."$/i", $URL)) { // if it's an image, embed it; otherwise, it's a regular link $link = array('type' => "image-$linktype", 'link' => _wiki_link_image($URL, $linkname)); } elseif (preg_match("#^".WIKI_ALLOWED_PROTOCOLS.":#", $URL)) { $link = array('type' => "url-$linktype", 'link' => _wiki_link_URL($URL, $linkname)); } elseif (preg_match("#^phpwiki:(.*)#", $URL, $match)) { if (empty($linkname)) { $linkname = htmlspecialchars($URL); } $link = array('type' => "url-wiki-$linktype", 'link' => "$linkname"); } elseif (preg_match("#^\d+$#", $URL)) { $link = array('type' => "reference-$linktype", 'link' => $URL); } else { $link = array('type' => "wiki-$linktype", 'link' => _wiki_link_node($URL, $linkname)); } return $link; } /** * Wiki HTML output can, at any given time, be in only one mode. * It will be something like Unordered List, Preformatted Text, * plain text etc. When we change modes we have to issue close tags * for one mode and start tags for another. * * @param $tag HTML tag to insert * @param $tagtype WIKI_ZERO_LEVEL - close all open tags before inserting $tag * WIKI_NESTED_LEVEL - close tags until depths match * @param $level nesting level (depth) of $tag * nesting is arbitrary limited to 10 levels */ function _wiki_set_output_mode($tag, $tagtype, $level) { static $stack; if (!$stack) { $stack = new _wiki_stack; } $retvar = ''; if ($level > 10) { /* * arbitrarily limit tag nesting * We just clamp the the maximum depth. */ $level = 10; } if ($tagtype == WIKI_ZERO_LEVEL) { // empty the stack until $level == 0; if ($tag == $stack->top()) { return; // same tag? -> nothing to do } while ($stack->cnt() > 0) { $closetag = $stack->pop(); $retvar .= "\n"; } if ($tag) { $retvar .= "<$tag>\n"; $stack->push($tag); } } elseif ($tagtype == WIKI_NESTED_LEVEL) { if ($level < $stack->cnt()) { // $tag has fewer nestings (old: tabs) than stack, // reduce stack to that tab count while ($stack->cnt() > $level) { $closetag = $stack->pop(); if ($closetag == FALSE) { //echo "bounds error in tag stack"; break; } $retvar .= "\n"; } // if list type isn't the same, // back up one more and push new tag if ($tag != $stack->top()) { $closetag = $stack->pop(); $retvar .= "<$tag>\n"; $stack->push($tag); } } elseif ($level > $stack->cnt()) { // Test for and close top level elements which are not allowed to contain // other block-level elements. if ($stack->cnt() == 1 and preg_match('/^(p|pre|h\d)$/i', $stack->top())) { $closetag = $stack->pop(); $retvar .= ""; } // we add the diff to the stack // stack might be zero if ($stack->cnt() < $level) { while ($stack->cnt() < $level - 1) { /* * This is a bit of a hack: * * We're not nested deep enough, and have to make up * some kind of block element to nest within. * * Currently, this can only happen for nested list * element (either