=====Footnote Action===== >>==See also:== - Documentation: FootnoteActionInfo ==works with:== - Wikka 1.1.6.2 to 1.2 >>//NOT included in any Wikka version//{{lastedit show="3"}} This is the development page for the Footnote action. ===Installation=== - Save the first code block below as ##actions/footnote.php## - Give it the same file permissions as the other php files in that directory - Add four lines to ##handlers/page/show.php## as shown on the second code block below - Add the line from the third code block below to ##css/wikka.css## === Code === 1. New ##actions/footnote.php## file <<##actions/footnote.php##<< %%(php)$msg
"); } function FNwakka2callback($things) // the only change made to this function (from formatters/wakka.php in version 1.1.6.3) is in the processing of $things='closetags': // instead of directly echoing the HTML closing tags, they are returned as a string { $thing = $things[1]; $result=''; static $oldIndentLevel = 0; static $oldIndentLength= 0; static $indentClosers = array(); static $newIndentSpace= array(); static $br = 1; static $trigger_bold = 0; static $trigger_italic = 0; static $trigger_underline = 0; static $trigger_monospace = 0; static $trigger_notes = 0; static $trigger_strike = 0; static $trigger_inserted = 0; static $trigger_deleted = 0; static $trigger_floatl = 0; static $trigger_keys = 0; static $trigger_strike = 0; static $trigger_inserted = 0; static $trigger_center = 0; static $trigger_l = array(-1, 0, 0, 0, 0, 0); static $output = ''; static $valid_filename = ''; static $invalid = ''; global $wakka; if ((!is_array($things)) && ($things == 'closetags')) { // start of changes to standard wakka2callback $ret = ""; if ($trigger_strike % 2) $ret .= (''); if ($trigger_notes % 2) $ret .= (''); if ($trigger_inserted % 2) $ret .= (''); if ($trigger_underline % 2) $ret .= (''); if ($trigger_floatl % 2) $ret .= (''); if ($trigger_center % 2) $ret .= (''); if ($trigger_italic % 2) $ret .= (''); if ($trigger_monospace % 2) $ret .= (''); if ($trigger_bold % 2) $ret .= (''); for ($i = 1; $i<=5; $i ++) if ($trigger_l[$i] % 2) $ret .= (""); $trigger_bold = $trigger_center = $trigger_floatl = $trigger_inserted = $trigger_deleted = $trigger_italic = $trigger_keys = 0; $trigger_l = array(-1, 0, 0, 0, 0, 0); $trigger_monospace = $trigger_notes = $trigger_strike = $trigger_underline = 0; return $ret; // end of changes to standard wakka2callback } // convert HTML thingies if ($thing == "<") return "<"; else if ($thing == ">") return ">"; // float box left else if ($thing == "<<") { return (++$trigger_floatl % 2 ? "
\n" : "\n
\n"); } // float box right else if ($thing == ">>") { return (++$trigger_floatl % 2 ? "
\n" : "\n
\n"); } // clear floated box else if ($thing == "::c::") { return ("
 
\n"); } // keyboard else if ($thing == "#%") { return (++$trigger_keys % 2 ? "" : ""); } // bold else if ($thing == "**") { return (++$trigger_bold % 2 ? "" : ""); } // italic else if ($thing == "//") { return (++$trigger_italic % 2 ? "" : ""); } // underlinue else if ($thing == "__") { return (++$trigger_underline % 2 ? "" : ""); } // monospace else if ($thing == "##") { return (++$trigger_monospace % 2 ? "" : ""); } // notes else if ($thing == "''") { return (++$trigger_notes % 2 ? "" : ""); } // strikethrough else if ($thing == "++") { return (++$trigger_strike % 2 ? "" : ""); } // additions else if ($thing == "££") { return (++$trigger_inserted % 2 ? "" : ""); } // deletions else if ($thing == "¥¥") { return (++$trigger_deleted % 2 ? "" : ""); } // center else if ($thing == "@@") { return (++$trigger_center % 2 ? "
\n" : "\n
\n"); } // urls else if (preg_match("/^([a-z]+:\/\/\S+?)([^[:alnum:]^\/])?$/", $thing, $matches)) { $url = $matches[1]; /* Inline images are disabled for security reason, use {{image action}} #142 But if you still need this functionality, update this file like below if (preg_match("/\.(gif|jpg|png|svg)$/si", $url)) { return 'image'.$wakka->htmlspecialchars_ent($matches[2]); } else */ // Mind Mapping Mod if (preg_match("/\.(mm)$/si", $url)) { #145 return $wakka->Action("mindmap ".$url); } else return $wakka->Link($url).$matches[2]; } // header level 5 else if ($thing == "==") { $br = 0; return (++$trigger_l[5] % 2 ? "
" : "
\n"); } // header level 4 else if ($thing == "===") { $br = 0; return (++$trigger_l[4] % 2 ? "

" : "

\n"); } // header level 3 else if ($thing == "====") { $br = 0; return (++$trigger_l[3] % 2 ? "

" : "

\n"); } // header level 2 else if ($thing == "=====") { $br = 0; return (++$trigger_l[2] % 2 ? "

" : "

\n"); } // header level 1 else if ($thing == "======") { $br = 0; return (++$trigger_l[1] % 2 ? "

" : "

\n"); } // forced line breaks else if ($thing == "---") { return "
"; } // escaped text else if (preg_match("/^\"\"(.*)\"\"$/s", $thing, $matches)) { $allowed_double_doublequote_html = $wakka->GetConfigValue("double_doublequote_html"); if ($allowed_double_doublequote_html == 'safe') { $filtered_output = $wakka->ReturnSafeHTML($matches[1]); return $filtered_output; } elseif ($allowed_double_doublequote_html == 'raw') { return $matches[1]; } else { return $wakka->htmlspecialchars_ent($matches[1]); } } // code text else if (preg_match("/^\%\%(.*?)\%\%$/s", $thing, $matches)) { $output = ''; //reinitialize variable $code = $matches[1]; // if configuration path isn't set, make sure we'll get an invalid path so we // don't match anything in the home directory $geshi_hi_path = isset($wakka->config['geshi_languages_path']) ? $wakka->config['geshi_languages_path'] : '/:/'; $wikka_hi_path = isset($wakka->config['wikka_highlighters_path']) ? $wakka->config['wikka_highlighters_path'] : '/:/'; // check if a language (and an optional starting line or filename) has been specified if (preg_match('/^'.PATTERN_OPEN_BRACKET.PATTERN_FORMATTER.PATTERN_LINE_NUMBER.PATTERN_FILENAME.PATTERN_CLOSE_BRACKET.PATTERN_CODE.'$/s', $code, $matches)) { list(, $language, , $start, , $filename, $invalid, $code) = $matches; } // get rid of newlines at start and end (and preceding/following whitespace) // Note: unlike trim(), this preserves any tabs at the start of the first "real" line $code = preg_replace('/^\s*\n+|\n+\s*$/','',$code); // check if GeSHi path is set and we have a GeSHi highlighter for this language if (isset($language) && isset($wakka->config['geshi_path']) && file_exists($geshi_hi_path.'/'.$language.'.php')) { // check if specified filename is valid and generate code block header if (isset($filename) && strlen($filename) > 0 && strlen($invalid) == 0) # TODO: use central regex library for filename validation { $valid_filename = $filename; // create code block header $output .= '
'; // display filename and start line, if specified $output .= $filename; if (strlen($start)>0) { $output .= ' (line '.$start.')'; } $output .= '
'."\n"; } // use GeSHi for highlighting $output .= $wakka->GeSHi_Highlight($code, $language, $start); } // check Wikka highlighter path is set and if we have an internal Wikka highlighter elseif (isset($language) && isset($wakka->config['wikka_formatter_path']) && file_exists($wikka_hi_path.'/'.$language.'.php') && 'wakka' != $language) { // use internal Wikka highlighter $output = '
'."\n"; $output .= $wakka->Format($code, $language); $output .= "
\n"; } // no language defined or no formatter found: make default code block; // IncludeBuffered() will complain if 'code' formatter doesn't exist else { $output = '
'."\n"; $output .= $wakka->Format($code, 'code'); $output .= "
\n"; } // display grab button if option is set in the config file if ($wakka->config['grabcode_button'] == '1') { $output .= $wakka->FormOpen("grabcode"); // build form $output .= ''; $output .= ''; $output .= ''; $output .= $wakka->FormClose(); } // output return $output; } // forced links // \S : any character that is not a whitespace character // \s : any whitespace character else if (preg_match("/^\[\[(\S*)(\s+(.+))?\]\]$/s", $thing, $matches)) # recognize forced links across lines { list (, $url, , $text) = $matches; if ($url) { //if ($url!=($url=(preg_replace("/@@|££||\[\[/","",$url))))$result=""; if (!$text) $text = $url; //$text=preg_replace("/@@|££|\[\[/","",$text); return $result.$wakka->Link($url, "", $text); } else { return ""; } } // indented text elseif (preg_match("/\n([\t~]+)(-|&|([0-9a-zA-ZÄÖÜßäöü]+)\))?(\n|$)/s", $thing, $matches)) { // new line $result .= ($br ? "
\n" : "\n"); // we definitely want no line break in this one. $br = 0; // find out which indent type we want $newIndentType = $matches[2]; if (!$newIndentType) { $opener = "
"; $closer = "
"; $br = 1; } elseif ($newIndentType == "-") { $opener = ""; $li = 1; } elseif ($newIndentType == "&") { $opener = ""; $li = 1; } #inline comments else { $opener = "
  1. "; $closer = "
"; $li = 1; } // get new indent level $newIndentLevel = strlen($matches[1]); if ($newIndentLevel > $oldIndentLevel) { for ($i = 0; $i < $newIndentLevel - $oldIndentLevel; $i++) { $result .= $opener; array_push($indentClosers, $closer); } } else if ($newIndentLevel < $oldIndentLevel) { for ($i = 0; $i < $oldIndentLevel - $newIndentLevel; $i++) { $result .= array_pop($indentClosers); } } $oldIndentLevel = $newIndentLevel; if (isset($li) && !preg_match("/".str_replace(")", "\)", $opener)."$/", $result)) { $result .= "
  • "; } return $result; } // new lines else if ($thing == "\n") { // if we got here, there was no tab in the next line; this means that we can close all open indents. $c = count($indentClosers); for ($i = 0; $i < $c; $i++) { $result .= array_pop($indentClosers); $br = 0; } $oldIndentLevel = 0; $oldIndentLength= 0; $newIndentSpace=array(); $result .= ($br ? "
    \n" : "\n"); $br = 1; return $result; } // Actions else if (preg_match("/^\{\{(.*?)\}\}$/s", $thing, $matches)) { if ($matches[1]) return $wakka->Action($matches[1]); else return "{{}}"; } // interwiki links! else if (preg_match("/^[A-ZÄÖÜ][A-Za-zÄÖÜßäöü]+[:]\S*$/s", $thing)) { return $wakka->Link($thing); } // wiki links! else if (preg_match("/^[A-ZÄÖÜ]+[a-zßäöü]+[A-Z0-9ÄÖÜ][A-Za-z0-9ÄÖÜßäöü]*$/s", $thing)) { return $wakka->Link($thing); } // separators else if (preg_match("/-{4,}/", $thing, $matches)) { // TODO: This could probably be improved for situations where someone puts text on the same line as a separator. // Which is a stupid thing to do anyway! HAW HAW! Ahem. $br = 0; return "
    \n"; } // mind map xml else if (preg_match("/^$/s", $thing)) { return $wakka->Action("mindmap ".$wakka->Href()."/mindmap.mm"); } // if we reach this point, it must have been an accident. return $thing; } function FNprint (&$thisone, $method, $note_txt='', $base_url='') { if (!isset($footnotes)) { static $footnotes = array(); static $footnotesindex; } $out = ''; if ('addnote' == $method) { // display a single footnote and add it to the page's list of footnotes $footnotesindex = ($footnotesindex) ? $footnotesindex+1 : 1; // no markup for the 'title' attribute $title_text = $thisone->ReturnSafeHTML(preg_replace("/(\*\*|\'\'|\#\#|\#\%|\+\+|__|\/\/|\[\[|\]\])/ms", "", $note_txt)); $out = "" . $footnotesindex . ""; $note_txt = preg_replace("('|')", "'", $note_txt); $note_txt_raw = $thisone->htmlspecialchars_ent($note_txt); $footnotes[$footnotesindex] = $note_txt_raw; } else if ('list' == $method) { // display the list of all the page's footnotes $i = 1; if (isset($footnotes) && !empty($footnotes)) { $out = "
     ". FN_NOTES .' '; foreach ($footnotes as $note_txt_raw) { $out .= "". $i. ": "; // format the footnote's text $note_txt = preg_replace_callback( "/(". "\b[a-z]+:\/\/\S+|". # URL "\[\[[^\[]*?\]\]|". # forced link "\*\*|\'\'|\#\#|\#\%|\+\+|__|\/\/". # Wiki markup ")/ms", "FNwakka2callback", $thisone->htmlspecialchars_ent($note_txt_raw) ); $out .= ($note_txt . FNwakka2callback('closetags') . '
    '); $i++; } $out .= '

    '; $footnotes = array(); $footnotesindex = 0; } } else if ('purge' == $method) { // empty the footnotes array, so they are not displayed at the bottom of the page $footnotes = array(); $footnotesindex = 0; } // do nothing silently if unknown $method return $out; } } // if !function_exists() $output = ''; if (!isset($vars['note'])) { $output .= FNerror(sprintf(FN_ERROR_REQUEST_FORMAT, FN_ERROR_USAGE)); } else { $output .= FNprint($this, 'addnote', $vars['note']); } echo $output; ?> %% 2a. [version 1.1.6.4 only] In ##handlers/page/show.php##, go to line 80 and replace the following code block: %%(php) // display page echo $this->Format($this->page['body'], 'wakka'); echo '
    '."\n"; echo ''."\n"; echo ''."\n"; %% with the following code block: %%(php) // display page echo $this->Format($this->page['body'], 'wakka'); echo '
    '."\n"; // Footnote action if (function_exists('FNprint')) { echo (FNprint($this, 'list', '', $this->Href())); } echo ''."\n"; echo ''."\n"; %% 2b. [versions 1.1.6.2 & 1.1.6.3 only] In ##handlers/page/show.php##, go to line 21 and replace the following code block: %%(php) // display page echo $this->Format($this->page['body'], 'wakka'); // if this is an old revision, display some buttons if ($this->page['latest'] == 'N' && $this->HasAccess('write')) %% with the following code block: %%(php) // display page echo $this->Format($this->page['body'], 'wakka'); // Footnote action if (function_exists('FNprint')) { echo (FNprint($this, 'list', "", $this->Href())); } // if this is an old revision, display some buttons if ($this->page['latest'] == 'N' && $this->HasAccess('write')) %% 2c. [version 1.2 only] In ##handlers/page/show.php##, replace the following code block: %%(php) '."\n"; } // display page if ($raw == 1) { echo '
    '.nl2br($this->htmlspecialchars_ent($this->page["body"], ENT_QUOTES)).'
    '; } else { echo $this->Format($this->page['body'], 'wakka', 'page'); } ?> %% with the following code block %%(php) '."\n"; } // display page if ($raw == 1) { echo '
    '.nl2br($this->htmlspecialchars_ent($this->page["body"], ENT_QUOTES)).'
    '; } else { echo $this->Format($this->page['body'], 'wakka', 'page'); } // Footnote action if (function_exists('FNprint')) { echo (FNprint($this, 'list', '', $this->Href())); } ?> %% 3. Add the following line to ##css/wikka.css##: %%(php) .footnotesbox { background-color: #eeeeee; padding: 10px; margin-top: 15px; border: #666666 1px solid; font-size: 0.9em; } %% ---- CategoryUsercontributions