Wiki source for FootnoteAction


Show raw source

=====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)<?php
#
# Manages and displays footnotes on the page
#
# @package Actions
# @name footnote
#
# @authors DomBonj
#
# @version 0.98
#
# @input Parameters = note='text of the note'
#
# @uses Wakka::Action()
# @uses Wakka::FormClose()
# @uses Wakka::FormOpen()
# @uses Wakka::GeSHi_Highlight()
# @uses Wakka::GetConfigValue()
# @uses Wakka::Href()
# @uses Wakka::Link()
# @uses Wakka::ReturnSafeHTML()
# @uses Wakka::htmlspecialchars_ent()
#

// i18n strings
if (!defined('FN_NOTES')) define('FN_NOTES', 'Notes');
if (!defined('FN_GO_BACK_MSG')) define('FN_GO_BACK_MSG', 'Jump back to page');
if (!defined('FN_ERROR_REQUEST_FORMAT')) define ('FN_ERROR_REQUEST_FORMAT', 'Incorrect parameter; usage: %s');
if (!defined('FN_ERROR_USAGE')) define ('FN_ERROR_USAGE', "footnote note='note_text'");

if (!function_exists('FNprint'))
{
function FNerror ($msg) {
return ("<em class='error'>$msg</em><br />");
}

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 .= ('</span>');
if ($trigger_notes % 2) $ret .= ('</span>');
if ($trigger_inserted % 2) $ret .= ('</span>');
if ($trigger_underline % 2) $ret .= ('</span>');
if ($trigger_floatl % 2) $ret .= ('</div>');
if ($trigger_center % 2) $ret .= ('</div>');
if ($trigger_italic % 2) $ret .= ('</em>');
if ($trigger_monospace % 2) $ret .= ('</tt>');
if ($trigger_bold % 2) $ret .= ('</strong>');
for ($i = 1; $i<=5; $i ++)
if ($trigger_l[$i] % 2) $ret .= ("</h$i>");
$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 ? "<div class=\"floatl\">\n" : "\n</div>\n");
}
// float box right
else if ($thing == ">>")
{
return (++$trigger_floatl % 2 ? "<div class=\"floatr\">\n" : "\n</div>\n");
}
// clear floated box
else if ($thing == "::c::")
{
return ("<div class=\"clear\"> </div>\n");
}
// keyboard
else if ($thing == "#%")
{
return (++$trigger_keys % 2 ? "<kbd class=\"keys\">" : "</kbd>");
}
// bold
else if ($thing == "**")
{
return (++$trigger_bold % 2 ? "<strong>" : "</strong>");
}
// italic
else if ($thing == "//")
{
return (++$trigger_italic % 2 ? "<em>" : "</em>");
}
// underlinue
else if ($thing == "__")
{
return (++$trigger_underline % 2 ? "<span class=\"underline\">" : "</span>");
}
// monospace
else if ($thing == "##")
{
return (++$trigger_monospace % 2 ? "<tt>" : "</tt>");
}
// notes
else if ($thing == "''")
{
return (++$trigger_notes % 2 ? "<span class=\"notes\">" : "</span>");
}
// strikethrough
else if ($thing == "++")
{
return (++$trigger_strike % 2 ? "<span class=\"strikethrough\">" : "</span>");
}
// additions
else if ($thing == "££")
{
return (++$trigger_inserted % 2 ? "<span class=\"additions\">" : "</span>");
}
// deletions
else if ($thing == "¥¥")
{
return (++$trigger_deleted % 2 ? "<span class=\"deletions\">" : "</span>");
}
// center
else if ($thing == "@@")
{
return (++$trigger_center % 2 ? "<div class=\"center\">\n" : "\n</div>\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 '<img src="'.$wakka->Link($url).'" alt="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 ? "<h5>" : "</h5>\n");
}
// header level 4
else if ($thing == "===")
{
$br = 0;
return (++$trigger_l[4] % 2 ? "<h4>" : "</h4>\n");
}
// header level 3
else if ($thing == "====")
{
$br = 0;
return (++$trigger_l[3] % 2 ? "<h3>" : "</h3>\n");
}
// header level 2
else if ($thing == "=====")
{
$br = 0;
return (++$trigger_l[2] % 2 ? "<h2>" : "</h2>\n");
}
// header level 1
else if ($thing == "======")
{
$br = 0;
return (++$trigger_l[1] % 2 ? "<h1>" : "</h1>\n");
}
// forced line breaks
else if ($thing == "---")
{
return "<br />";
}
// 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 .= '<div class="code_header">';
// display filename and start line, if specified
$output .= $filename;
if (strlen($start)>0)
{
$output .= ' (line '.$start.')';
}
$output .= '</div>'."\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 = '<div class="code">'."\n";
$output .= $wakka->Format($code, $language);
$output .= "</div>\n";
}
// no language defined or no formatter found: make default code block;
// IncludeBuffered() will complain if 'code' formatter doesn't exist
else
{
$output = '<div class="code">'."\n";
$output .= $wakka->Format($code, 'code');
$output .= "</div>\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 .= '<input type="submit" class="grabcode" name="save" value="'.GRABCODE_BUTTON_VALUE.'" title="'.rtrim(sprintf(GRABCODE_BUTTON_TITLE, $valid_filename)).'" />';
$output .= '<input type="hidden" name="filename" value="'.urlencode($valid_filename).'" />';
$output .= '<input type="hidden" name="code" value="'.urlencode($code).'" />';
$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="</span>";
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 ? "<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 = "<div class=\"indent\">"; $closer = "</div>"; $br = 1; }
elseif ($newIndentType == "-") { $opener = "<ul><li>"; $closer = "</li></ul>"; $li = 1; }
elseif ($newIndentType == "&") { $opener = "<ul class=\"thread\"><li>"; $closer = "</li></ul>"; $li = 1; } #inline comments
else { $opener = "<ol type=\"". substr($newIndentType, 0, 1)."\"><li>"; $closer = "</li></ol>"; $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 .= "</li><li>";
}

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 ? "<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 "<hr />\n";
}
// mind map xml
else if (preg_match("/^<map.*<\/map>$/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 = "<a href='". $thisone->Href(). '#fn' . $footnotesindex . "' title='". $title_text ."' ><sup id='fnback". $footnotesindex. "'>" . $footnotesindex . "</sup></a>";
$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 = "<fieldset class='footnotesbox'><legend> <strong>". FN_NOTES .' </strong></legend>';
foreach ($footnotes as $note_txt_raw)
{
$out .= "<a id='fn". $i. "' href='". $base_url ."#fnback". $i ."' class='underline' title='". FN_GO_BACK_MSG ."'><span class='underline'>". $i. "</span></a>: ";
// 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') . '<br />');
$i++;
}
$out .= '</fieldset><br />';
$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 '<div style="clear: both"></div>'."\n";

echo '</div>'."\n";
echo '<!--closing page content-->'."\n";
%%
with the following code block:

%%(php)
// display page
echo $this->Format($this->page['body'], 'wakka');
echo '<div style="clear: both"></div>'."\n";

// Footnote action
if (function_exists('FNprint'))
{
echo (FNprint($this, 'list', '', $this->Href()));
}

echo '</div>'."\n";
echo '<!--closing page content-->'."\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)
<?php
}
}
echo '<div class="clear"></div></div>'."\n";
}
// display page
if ($raw == 1)
{
echo '<div class="wikisource">'.nl2br($this->htmlspecialchars_ent($this->page["body"], ENT_QUOTES)).'</div>';
}
else
{
echo $this->Format($this->page['body'], 'wakka', 'page');
}

?>
%%

with the following code block

%%(php)
<?php
}
}
echo '<div class="clear"></div></div>'."\n";
}
// display page
if ($raw == 1)
{
echo '<div class="wikisource">'.nl2br($this->htmlspecialchars_ent($this->page["body"], ENT_QUOTES)).'</div>';
}
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
Valid XHTML :: Valid CSS: :: Powered by WikkaWiki