// This is a ChiliMoon / Roxen module.
// Copyright © Michael Stenitzer, 2004 - 2005, <<jenoe[at]gmx.at>>.
#include <module.h>
inherit "module";
constant cvs_version = "$Id: config.php-default,v 1.8 2003/10/08 07:04:29
tuxmonkey Exp $";
constant thread_safe = 1;
constant module_unique = 1;
constant module_type = MODULE_TAG;
constant module_name = "Tags: WikiMarkup";
constant module_doc = "<p>This module provides a simple WikiMarkup
language</p>";
array shortcuts;
constant shortcuts_separator = ",";
int headerlimit_upper;
int headerlimit_lower;
int convert_lists;
int convert_code;
int convert_quote;
int convert_acronyms;
int convert_header;
int remap_headers;
int convert_format;
int convert_images;
string imgpath;
int c_forcedlinks;
int c_linkify;
int c_nofollow;
class VarUpper
{
inherit Variable.IntChoice;
array get_choice_list( )
{
return ({ 1, 2, 3, 4, 5, 6 })[ .. headerlimit_lower - 1 ];
}
}
class VarLower
{
inherit Variable.IntChoice;
array get_choice_list( )
{
return ({ 1, 2, 3, 4, 5, 6 })[ headerlimit_upper - 1 .. ];
}
}
class VarShortcuts
{
inherit Variable.List;
constant type="ShortcutList";
string render_row( string prefix, mixed val, int width )
{
string res = "<input type=hidden name='" + prefix + "' value='" + prefix +
"' />";
mapping m = decode_shortcuts( val );
res += "<table>";
res += "<tr><td>Pattern</td><td>";
res += ("<input name='"+prefix+"pattern' value='"+
Roxen.html_encode_string(m->pattern||"")+"' size=20/></td></tr>");
res += ("<tr><td>URL</td><td> <input name='"+prefix+"url' value='"+
Roxen.html_encode_string(m->url || "")+"' size=50/></td></tr>");
res += ("<tr><td>Linktext</td><td> <input name='"+prefix+"linktext' value='"+
Roxen.html_encode_string(m->linktext || "")+"' size=50/></td></tr>");
return res+"</table>";
}
string transform_from_form( string v, mapping va )
{
if( v == "" ) return "";
v = v[sizeof(path())..];
return va[v+"pattern"]+""+va[v+"url"]+""+va[v+"linktext"];
}
mapping decode_shortcuts( string s )
{
mapping m = ([]);
array a = s/"";
m->pattern = a[0];
m->url = a[1];
if( sizeof( a ) > 2 )
m->linktext = a[2];
if( !m->linktext || !sizeof( m->linktext ) )
m_delete( m, "linktext" );
return m;
}
array(mapping) get_shortcuts()
{
return map( query(), decode_shortcuts );
}
}
void create()
{
// --------------------- Configuration Interface -----------------------
defvar( "shortcuts", VarShortcuts( ({}), 0, "Default: Link shortcuts",
"You can shortcut links to important destinations like a bug database, FAQs
etc. "
"The pattern string will be simply replaced by the URL, the Linktext is
optional "
"and gives an easy to read link text. You can override this setting with the
"
"attribute <i>shortcuts="..."</i>" ) );
defvar( "convert_format", 1, "Default: Convert character formats",
TYPE_FLAG,
"If enabled, text can be formatted with _italic text_ , *bold text* and
_*bold and italic text*_ . "
"You can override this setting with the attribute
<i>charformat="on|off"</i>.");
defvar( "convert_lists", 1, "Default: Convert lists",
TYPE_FLAG,
"If enabled, lines starting with * or # will be converted into ordered and
unordered XHTML lists. "
"You can override this setting with the attribute
<i>lists="on|off"</i>.");
defvar( "convert_code", 1, "Default: Convert code",
TYPE_FLAG,
"If enabled, lines starting with | will be converted into preformatted code
blocks. "
"You can override this setting with the attribute
<i>code="on|off"</i>.");
defvar( "convert_quote", 1, "Default: Convert blockquote",
TYPE_FLAG,
"If enabled, lines starting with > will be converted into blockquotes. "
"You can override this setting with the attribute
<i>quote="on|off"</i>.");
defvar( "convert_header", 1, "Default: Convert headers",
TYPE_FLAG,
"If enabled, lines starting with a certain number of = will be converted
into a XHTML header. "
"You can override this setting with the attribute
<i>headers="on|off"</i>.");
defvar( "header_upper", VarUpper( 1, ({ }), 0,
"Default: Upper limit for headers", "The upper limit for headers corresponds
to the highest "
"header level allowed. (1 means H1)"))
->set_invisibility_check_callback( lambda( RequestID id, Variable.Variable i
)
{
return ! convert_header;
}
);
defvar( "remap_headers", 1, "Default: Remap headers",
TYPE_FLAG,
"Your headers will automatically be remapped to the highest allowed header
(upper limit)."
"e.g. if you you allow only H3 and lower, a wiki-header of level 1
("=") will"
"be remapped to a H3 in XHTML." )
->set_invisibility_check_callback( lambda( RequestID id, Variable.Variable i
)
{
return ! ( convert_header && headerlimit_upper > 1 );
}
);
defvar( "header_lower", VarLower( 6, ({ }), 0,
"Default: Lower limit for headers", "The lower limit for headers corresponds
to the lowest "
"header level allowed. (6 means H6)"))
->set_invisibility_check_callback( lambda( RequestID id, Variable.Variable i
)
{
return ! convert_header;
}
);
defvar( "convert_acronyms", 1, "Default: Convert acronyms",
TYPE_FLAG,
"If enabled, acronyms defined in the way acronym_(definition) will be
tagged. "
"You can override this setting with the attribute
<i>acronym="on|off"</i>.");
defvar( "forcedlinks", 1, "Default: Allow Links",
TYPE_FLAG,
"If enabled, hyperlinks can be forced by embracing an Url with brackets:
[Url] or [Url Linktext]. "
"You can override this setting with the attribute
<i>forcedlinks="on|off"</i>.");
defvar( "linkify", 1, "Default: Autoconvert Links",
TYPE_FLAG,
"If enabled, typical Url-patterns will be automatically converted to
hyperlinks "
"(e.g. http://www.domain.com, www.domain.com). "
"You can override this setting with the attribute
<i>linkify="on|off"</i>.");
defvar( "nofollow", 0, "Default: Use NOFOLLOW attribute for Urls",
TYPE_FLAG,
"If enabled, all links in the WikiMarkup will get
<i>rel="nofollow"</i>"
"set. This is a new spam prevention method supported by most search engines "
"(<a
href=\"http://www.google.com/googleblog/2005/01/preventing-comment-spam.html\">Information
on preventing comment spam</a>)")
->set_invisibility_check_callback( lambda( RequestID id, Variable.Variable i
)
{
return ! ( c_linkify || c_forcedlinks > 1 );
}
);
defvar( "convert_images", 1, "Default: Convert images",
TYPE_FLAG,
"If enabled, images can inserted with [[image::imgfilename.jpg Alt text]]."
"You can override this setting with the attribute
<i>images="on|off"</i>.");
defvar("imgpath", "/images/", "Default: Default image path",
TYPE_LOCATION,
"Where the images can be found. This can either be a path in your site's
virtual file system "
"or an external URL (which might not be the best idea)."
"You can override this setting with the attribute
<i>imgpath="path|url"</i>.");
}
void start()
{
// Get default values from configuration
shortcuts = getvar( "shortcuts" )->get_shortcuts();
headerlimit_lower = query( "header_lower" );
headerlimit_upper = query( "header_upper" );
convert_lists = query( "convert_lists" );
convert_code = query( "convert_code" );
convert_quote = query( "convert_quote" );
convert_acronyms = query( "convert_acronyms" );
convert_header = query( "convert_header" );
convert_format = query( "convert_format" );
remap_headers = query( "remap_headers" );
c_forcedlinks = query( "forcedlinks" );
c_linkify = query( "linkify" );
c_nofollow = query( "nofollow" );
convert_images = query( "convert_images" );
convert_images = query( "convert_images" );
imgpath = query( "imgpath" );
}
class TagWikimarkup
{
inherit RXML.Tag;
constant name = "wikimarkup";
mapping(string:RXML.Type) req_arg_types = ([ ]);
mapping(string:RXML.Type) opt_arg_types = ([
"shortcuts":RXML.t_text(RXML.PXml), // [pattern,url,linktext,...]
"headers":RXML.t_text(RXML.PXml),
// [on|off]
"headerlimit-upper":RXML.t_text(RXML.PXml), // [1..6]
"headerlimit-lower":RXML.t_text(RXML.PXml), // [1..6]
"remap-headers":RXML.t_text(RXML.PXml), // [on|off]
"lists":RXML.t_text(RXML.PXml),
// [on|off]
"code":RXML.t_text(RXML.PXml),
// [on|off]
"quote":RXML.t_text(RXML.PXml),
// [on|off]
"acronyms":RXML.t_text(RXML.PXml), // [on|off]
"charformat":RXML.t_text(RXML.PXml), // [on|off]
"forcedlinks":RXML.t_text(RXML.PXml), // [on|off]
"linkify":RXML.t_text(RXML.PXml),
// [on|off]
"nofollow":RXML.t_text(RXML.PXml), // [on|off]
"images":RXML.t_text(RXML.PXml),
// [on|off]
"imgpath":RXML.t_text(RXML.PXml),
// [path|url]
"separator":RXML.t_text(RXML.PXml), // [,]
"sandbox":RXML.t_text(RXML.PXml),
//
"userhelp":RXML.t_text(RXML.PXml)
]); // [short|long]
array(RXML.Type) result_types = ({ RXML.t_any(RXML.PXml) });
Regexp acronym = Regexp("[^ \t\n\r]+_\([^\)]+\)");
Regexp forcedlink = Regexp("\[\[[^ \t\[][^\]]*\]\]");
Regexp image = Regexp("image::\[\[[^ \t\[][^\]]*\]\]");
Regexp link_regexp =
Regexp("[ \t\n\r\"]((((http)|(https)|(ftp))://([^ \t\n\r\"\]]+)(\.[^
\t\n\r\"\]]+)+)|"
"(((www)|(ftp))(\.[^ \t\n\r\"\]]+)+))");
mapping lists = ([ "*":"ul", "#":"ol" ]); // available list types
string parsewiki( string s, mapping settings, string sandbox ) // parse
wikiml line by line
{
if ( settings[ "userhelp" ] || settings[ "sandbox" ] )
{
return userdocs( settings, s, sandbox );
}
mapping(string:string)
block = (["current":"", // current blocklevel
"next":"", // new blocklevel
"currentquote":"", // current blockquotelevel
"nextquote":"" ]); // new blockquotelevel
string converted = "";
// escape escaped markup-like patterns
s = replace( s, ({ " **", " __", " **__", " __**", "[[[", "]]]" }),
({ " %*", " %_", " %*_", " %_*", "§%%", "%%§" }) );
// acronyms
if ( settings[ "convert_acronyms" ] )
s = utf8_to_string( acronym->replace( string_to_utf8( s ), lambda( string
l )
{
sscanf( l, "%s_(%s)", string acr, string title );
return "<acronym title=\"" + title + "\">" + acr + "</acronym>";
}
) );
// images
if ( settings[ "convert_images" ] )
s = imageify ( s, settings );
s = linkify ( s, settings );
array lines = (s - "\r" - "" ) / "\n";
array(array(string)) wm_split;
string wm_res;
foreach (lines, string line )
{
line += " "; // if the markup at the end of
the line is missing a blank
if ( settings[ "convert_format" ] ) // Convert inline formats
{
// strong+italic
sscanf(line, "%{%s *_%s_* %}%s", wm_split, wm_res );
line = sprintf("%{%s <strong><em>%s</em></strong> %}%s", wm_split,
wm_res );
sscanf(line, "%{%s _*%s*_ %}%s", wm_split, wm_res );
line = sprintf("%{%s <em><strong>%s</strong></em> %}%s", wm_split,
wm_res );
// strong
sscanf(line, "%{%s *%s* %}%s", wm_split, wm_res );
line = sprintf("%{%s <strong>%s</strong> %}%s", wm_split, wm_res );
// italics
sscanf(line, "%{%s _%s_ %}%s", wm_split, wm_res );
line = sprintf("%{%s <em>%s</em> %}%s", wm_split, wm_res );
}
line = getnextblock( line, block, settings );
if ( sizeof ( block["currentquote"] ) < sizeof ( block["nextquote"] ) )
{ // change in blockquotelevel
converted += closeallblocks ( block ) + openquote( block ) +
openallblocks ( block ) + line;
}
else if ( sizeof ( block["currentquote"] ) > sizeof ( block["nextquote"] )
)
{ // change in blockquotelevel
converted += closeallblocks ( block ) + closequote( block ) +
openallblocks ( block ) + line;
if ( block["next"] == "0" )
block["current"] = "";
}
else if ( block["next"] != "0" ) // not-empty lines
{
if ( block["next"] != "p" || block["current"] != "p" )
{
if ( block["current"] == "" )
converted += openblock( block ) + line;
else
converted += closeblock( block ) + line;
}
else
converted += line;
}
else if ( block["current"] != "" )
converted += closeblock( block );
}
// unescape escaped markup-like patterns, 2nd part
converted = replace( converted, ({ " %*", " %_", " %*_", " %_*", "** ", "__
", "**__ ", "__** ", "§%%", "%%§" }),
({ " *", " _", " *_", "_*", "* ", "_
", "*_ ", "_* ", "[[", "]]" }) );
// close all blocks before you go home
block["next"] = "";
block["nextquote"] = "";
return converted + closeblock( block ) + closequote( block );
}
// returns the new blocktype
string getnextblock ( string s, mapping(string:string) block, mapping settings
)
{
string begin="", temp="";
if ( settings[ "convert_quote" ] ) // first remove blockquotes for
{ // parsing other block elements
sscanf( s, "%[>]", temp );
block["nextquote"] = temp;
int i = 0;
while ( s[i..i+3] == ">" ) // sometimes ">" comes as entity for
validities sake
{
block["nextquote"] += ">";
s = ">" + s[4..];
i++;
}
}
s = s[sizeof(block["nextquote"])..];
if ( s - " " - "\t" == "" ) // emptyline
block["next"] = "0";
else
{
if ( settings[ "convert_header" ] )
{
sscanf( s, "%[=]", temp ); // header block
if ( settings[ "remap_headers" ] )
temp += "=" * ( settings[ "headerlimit_upper" ] - 1 );
if ( sizeof( temp ) >= settings[ "headerlimit_upper" ] && sizeof( temp )
<= settings[ "headerlimit_lower" ])
{
begin += temp;
}
else
{
begin += "";
}
}
if ( settings[ "convert_code" ] )
{
if ( s[0..0] == "|" ) // code block
begin += "|";
}
if ( settings[ "convert_lists" ] )
{
sscanf( s, "%[*#]", temp ); // list block
begin += temp;
}
if ( begin[0..0] == "=" && settings[ "remap_headers" ] ) // strip markup
{
block["next"] = begin;
s = s[sizeof(block["next"]) - settings[ "headerlimit_upper" ] + 1 ..];
}
else if ( begin != "" )
{
block["next"] = begin;
s = s[sizeof(block["next"])..];
}
else
block["next"] = "p";
}
return s;
}
string closeblock( mapping(string:string) block ) // close current block
{
if ( block["current"] == "p" ) // close p
{
block["current"] = "";
return "</p>\n" + openblock( block );
}
if ( block["current"][..0] == "h" ) // close hn
{
string s = "</" + block["current"] + ">\n";
block["current"] = "";
return s + openblock( block );
}
if ( block["next"] == block["current"] ) // no change in block
element
{
if ( block["current"][..0]=="*" || block["current"][..0]=="#" )
return "</li>\n<li>";
else
return "\n";
}
if ( block["current"] == "|" ) // close code
{
block["current"] = "";
return "</code></pre>\n" + openblock( block );
}
if ( block["current"][..0]=="*" || block["current"][..0]=="#" ) //
change in list-level
{
string closelist="";
string addclosetag="";
for ( int i = sizeof( block["current"] ); i>0; i-=1 )
{
if ( block["current"] == block["next"] )
{
return closelist + addclosetag + "<li>";
}
else if( block["current"] == block["next"][..i-1] )
{
block["next"] = block["next"][i..];
return closelist + addclosetag + openblock( block );
}
closelist += "</li>\n</" + lists[ block["current"][i-1..] ] + ">\n";
block["current"] = block["current"][..i-2];
addclosetag = "</li>\n";
}
return closelist + openblock( block );
}
}
string openblock( mapping(string:string) block ) // open next block element
{
string openlist="";
switch ( block["next"][..0] )
{
case "p":
block["current"] = "p";
return "<p>";
case "|":
block["current"] = "|";
return "<pre><code>";
case "=":
block["current"] = "h" + sizeof( block["next"] );
return "<" + block["current"] + ">";
case "*":
case "#":
for ( int i = 0; i < sizeof(block["next"]); i+=1 )
openlist += "<" + lists[block["next"][i..i]] + ">\n<li>";
block["current"] += block["next"];
return openlist;
default:
return "";
}
}
string closequote( mapping(string:string) block ) // close current quote
{
string closelist="";
while ( sizeof( block["currentquote"] ) > sizeof( block["nextquote"] ) )
{
closelist += "</blockquote>\n";
block["currentquote"] = block["currentquote"][1..];
}
return closelist;
}
string openquote( mapping(string:string) block ) // open current quote
{
string openlist="";
do
{
openlist += "<blockquote>\n";
block["currentquote"] += ">";
}
while ( sizeof( block["currentquote"] ) < sizeof( block["nextquote"] ) );
return openlist;
}
string openallblocks( mapping(string:string) block )
{
block["current"] = block["next"];
return openblock( ([ "current":"", "next":block["next"] ]) );
}
string closeallblocks( mapping(string:string) block )
{
return closeblock( ([ "current":block["current"], "next":"" ]) );
}
string imageify( string s, mapping settings )
{
array(array(string)) wm_split;
string wm_res;
string alttext, filename;
sscanf( s, "%%s", wm_split, wm_res );
foreach ( reverse( wm_split ), array i )
{
filename = ( ( i[1] / " " )[0] );
alttext = ( i[1] / " " )[1..] * " ";
wm_res = sprintf("%s<img " + "src=\"%s%s\" alt=\"%s\" />%s", i[0],
settings["imgpath"], filename, alttext, wm_res );
}
return wm_res;
}
string linkify( string s, mapping settings )
{
string fix_link(string l)
{
if(l[0..6] == "http://" || l[0..7] == "https://" || l[0..5] == "ftp://" )
return l;
if(l[0..3] == "ftp.")
return "ftp://"+l;
return "http://"+l;
};
array(array(string)) wm_split;
string wm_res;
string forcedlinktext, forcedurl;
string nofollow_attrib = "rel=\"nofollow\" " * settings[ "c_nofollow" ];
foreach( settings[ "shortcuts" ], mapping shortcut )
{
sscanf( s, "%{%s[[" + shortcut["pattern"] + "%s]]%}%s", wm_split, wm_res
);
foreach ( reverse( wm_split ), array i )
{
forcedurl = ( ( i[1] / " " )[0] );
forcedlinktext = ( i[1] / " " )[1..] * " ";
if ( forcedlinktext == "" )
forcedlinktext = 0;
wm_res = sprintf("%s<a " + nofollow_attrib + "href=\"%s%s\">%s</a>",
i[0], shortcut["url"], forcedurl, forcedlinktext || shortcut["linktext"] || (
shortcut["pattern"] + forcedurl ) ) + wm_res;
}
s = wm_res;
}
if ( settings[ "forcedlinks" ] )
{
s = utf8_to_string( forcedlink->replace( string_to_utf8( s ), lambda(
string l )
{
l = fix_link( l[2..sizeof(l) - 3] );
string linktext = ( l / " ")[1..] * " ";
l = (l / " ")[0];
if ( linktext == "" )
linktext = l - "http://";
return "<a " + nofollow_attrib + "href=\"" + l + "\">" + linktext +
"</a>";
}
) );
}
Parser.HTML parser = Parser.HTML();
if ( settings[ "linkify" ] )
{
parser->add_container( "a", lambda( Parser.HTML p, mapping args )
{ return ({ p->current() }); });
parser->_set_data_callback( lambda( Parser.HTML p, string data )
{ return ({ utf8_to_string( link_regexp->replace( string_to_utf8( data
), lambda( string link )
{
link = link[ 0..0 ] + fix_link( link[ 1.. ] );
return link[ 0..0 ] + "<a " + nofollow_attrib +
"href=\"" + link[ 1.. ] + "\">" + link[ 1.. ] + "</a>";
}) ) }); });
}
return parser->finish( s )->read();
}
class Frame
{
inherit RXML.Frame;
array do_return(RequestID id)
{
content = content||"";
mapping flagconvert = ([ "on":1, "off":0 ]);
mapping settings = ([]);
// --------------------- Tagspecific Configuration -----------------------
if( args->lists )
settings["convert_lists"] = flagconvert[ args->lists ];
else
settings["convert_lists"] = convert_lists;
if( args->code )
settings["convert_code"] = flagconvert[ args->code ];
else
settings["convert_code"] = convert_code;
if( args->quote )
settings["convert_quote"] = flagconvert[ args->quote ];
else
settings["convert_quote"] = convert_quote;
if( args->acronyms )
settings["convert_acronyms"] = flagconvert[ args->acronyms ];
else
settings["convert_acronyms"] = convert_acronyms;
if( args->headers )
settings["convert_header"] = flagconvert[ args->headers ];
else
settings["convert_header"] = convert_header;
if( (int)args["headerlimit-upper"] <= 6 && (int)args["headerlimit-upper"]
>= 1 )
settings["headerlimit_upper"] = (int)args["headerlimit-upper"];
else
settings["headerlimit_upper"] = headerlimit_upper;
if( (int)args["headerlimit-lower"] <= 6 && (int)args["headerlimit-lower"]
>= 1 )
settings["headerlimit_lower"] = (int)args["headerlimit-lower"];
else
settings["headerlimit_lower"] = headerlimit_lower;
if ( settings["headerlimit_lower"] < settings["headerlimit_upper"] )
settings["headerlimit_lower"] = settings["headerlimit_upper"];
if( args["remap-headers"] )
settings["remap_headers"] = flagconvert[ args["remap-headers"] ];
else
settings["remap_headers"] = remap_headers;
if( args->charformat )
settings["convert_format"] = flagconvert[ args->charformat ];
else
settings["convert_format"] = convert_format;
if( args->forcedlinks )
settings["forcedlinks"] = flagconvert[ args->forcedlinks ];
else
settings["forcedlinks"] = c_forcedlinks;
if( args->linkify )
settings["linkify"] = flagconvert[ args->linkify ];
else
settings["linkify"] = c_linkify;
if( args->nofollow )
settings["c_nofollow"] = flagconvert[ args->nofollow ];
else
settings["c_nofollow"] = c_nofollow;
if( args->images)
settings["convert_images"] = flagconvert[ args->images ];
else
settings["convert_images"] = convert_images;
if( args->imgpath)
settings["imgpath"] = args->imgpath;
else
settings["imgpath"] = imgpath;
if( args->separator )
settings["separator"] = args->separator;
else
settings["separator"] = shortcuts_separator;
if( args->shortcuts != "" && args->shortcuts )
{
foreach( ( args->shortcuts / settings["separator"] )/3.0, array sc )
settings["shortcuts"] += ({ ([ "pattern":sc[0], "url":sc[1],
"linktext":sc[2] ]) });
}
else if ( args->shortcuts )
settings["shortcuts"] = ({ });
else
settings["shortcuts"] = shortcuts;
settings["args"] = "";
if( args->userhelp )
settings["userhelp"] = args->userhelp;
if( args->sandbox )
settings["sandbox"] = args->sandbox;
foreach( (array)args, array i )
{
if ( i[0] != "userhelp" && i[0] != "sandbox" )
settings["args"] += " " + i[0] + "=\"" + i[1] + "\"";
}
content = parsewiki( content, settings, id->variables->_sandbox );
return ({ content });
}
}
// --------------------- WikiMarkup Userhelp & Sandbox -----------------------
string userdocs( mapping settings, string s, string sandbox )
{
string help = "";
string example = "";
if ( settings["userhelp"] == "long" )
{
help = "<h2>WikiMarkup Syntax</h2>\n"
"<h4>Paragraphs</h4>\n"
"<p>Paragraphs are separated by empty lines (i.e. two linebreaks). \n"
" A single linebreak within a paragraph has no influence on the
formatting \n"
" of the converted XHTML (i.e. no <tag>br /</tag> is inserted).</p>\n";
if ( settings[ "convert_format" ] ) {
help += "<h4>Character formating: bold and italic text</h4>\n"
"<p>If you want to format text in bold or italic fonts wrap the text
\n"
" in this markup: <strong>" _"</strong> (italic),
<strong>" \n"
" *"</strong> (strong) or <strong>" _*"</strong>
(strong and \n"
" italic). Be careful to combine the markup character always with a
blank \n"
" space.</p>\n";
}
if ( settings[ "convert_lists" ] ) {
help += "<h4>Lists</h4>\n"
"<p>Lists are formated by <strong>*</strong> (unordered lists) \n"
"<strong>#</strong> (ordered lists) at the beginning of a line. Lists
may \n"
" be nested by joining * and # (e.g. **# is an ordered list nested
in an \n"
" unordered list which is again nested in an unordered list.</p>\n";
}
if ( settings[ "convert_code" ] ) {
help += "<h4>Code listings</h4>\n"
"<p>If you want to format blocks of code (codelistings) start the
lines with \n"
" a <strong>|</strong>.</p>\n";
}
if ( settings[ "convert_quote" ] ) {
help += "<h4>Blockquote</h4>\n"
"<p>If you want to format blockquotes start the lines with \n"
" a <strong>></strong>. You can nest blockquotes and use other
block formats inside blockquotes.</p>\n";
}
if ( settings[ "convert_header" ] ) {
help += "<h4>Headers</h4>\n"
"<p>Headers of a certain level are formated with the according number
of \n"
" <strong>=</strong> at the beginning of a line. There are <strong>"
+ ( settings[ "headerlimit_lower" ] - settings[ "headerlimit_upper" ]
+ 1 )
+ " levels of headers available (""
+ "=" * ( settings[ "remap_headers" ] || settings[
"headerlimit_upper" ] )
+ " to " + "=" * ( settings[ "remap_headers" ] * ( settings[
"headerlimit_lower" ]
- settings[ "headerlimit_upper" ] + 1 )
|| settings[ "headerlimit_lower" ] )
+ "").</strong>.</p>\n";
}
if ( settings[ "convert_acronyms" ] ) {
help += "<h4>Acronyms (and Abbreviations)</h4>\n"
"<p>If you want to tag acronyms you can add a definition:\n"
" <strong>acronym_(definition)</strong>.</p>\n";
}
if ( settings[ "linkify" ] ) {
help += "<h4>Automatic link conversion ("linkify")</h4>\n"
" <p>Textlinks of the common link-patterns <strong>http://</strong>,
\n"
" <strong>https://</strong>, <strong>ftp://</strong>,
<strong>www.</strong> or \n"
" <strong>ftp</strong>.</strong> will will automatically converted
into \n"
" clickable hyperlinks.\n";
}
if ( settings[ "forcedlinks" ] ) {
help += "<h4>Forced Links</h4>\n"
" <p>If you want to force text to hyperlink conversion you can do
this with\n"
" the syntax <strong>[[url]]</strong> or <strong>[[url
linktext]]</strong>. \n"
" The text after the first blank will be the visible text on the
link, if\n"
" omitted the url will be shown.</p>\n";
}
if ( sizeof( settings[ "shortcuts" ] ) ) {
help += "<h4>Shortcut links</h4>\n"
"<p>You can use shortcut links to set easily an reference to certain
standard \n"
" link destinations.</p>\n"
" <p>Available shortcut links:</p>\n"
" <table cellspacing=\"0\" cellpadding=\"4\" border=\"1\">\n"
" <tr>\n"
"
<th>Pattern </th><th>Url </th><th>Linktext </th>\n"
" </tr>\n";
foreach( settings[ "shortcuts" ], mapping i )
help += "<tr><td>" + i["pattern"] + " </td><td>" + i["url"] +
" </td><td>" + i["linktext"] + " </td></tr>\n";
help += " </table>\n"
" <p>You can override a predefined linktext by adding a friendly name
after a\n"
" blank: e.g. [[Bug123 This is a link to Bug 123]].</p>\n";
}
help += "<h4>Escaping markup characters</h4>\n"
"<p>If you have to escape markup characters (i.e. if you do not want to
use \n"
" them as markup but as simple text): </p>\n"
" <ul> \n";
if ( settings[ "convert_format" ] )
help += " <li>Duplicate them for character formating (e.g. **, __,
**__)</li>\n";
help += " <li>Prefix them with a blank space for block formatting (*,#,=
or | \n"
" at the beginning of a line)</li>\n";
if ( sizeof( settings[ "shortcuts" ] ) || settings[ "forcedlinks" ] )
help += " <li>If you want to use double square brackets
"[[text]]" triple them "[[[text]]]" in the markup.</li>\n";
help += " </ul>\n";
if ( settings[ "convert_images" ] ) {
help += "<h4>Insert images</h4>\n"
" <p>Images can inserted with <strong>[[image::imgfilename.jpg Alt
text]]</strong>. \n"
" Images should reside in the location <strong>"" + settings[
"imgpath" ] + ""</strong>\n";
}
}
example = "This is a simple paragraph\n"
"which ignores any linebreak. \n";
if ( settings[ "convert_acronyms" ] )
example += "FOAF_(Friend Of A Friend) is an acronym.\n";
example += "\n";
if ( settings[ "convert_lists" ] ) {
example += "* this is an unordered list\n"
"* second list item\n"
"*# containing a nested ordered list\n"
"*# with two items\n"
"\n";
}
if ( settings[ "convert_format" ] ) {
example += "Character formating: _italic,_ *bold* and _*bold and italic
text*_ .\n"
"\n";
}
if ( settings[ "linkify" ] ) {
example += "Automatically converted links: http://roxen.sodazitron.at and
www.chilimoon.org .\n"
"\n";
}
if ( settings[ "forcedlinks" ] ) {
example += "Forced link conversion [chilimoon.sodazitron.com], also with
friedly text on the \n"
"link to [[chilimoon.sodazitron.com/listarchive/ Roxen Mailinglist
Archive]]. \n"
"\n";
}
if ( sizeof( settings[ "shortcuts" ] ) ) {
example += "You can also set shortcuts to some standard link
destinations:\n";
foreach( settings[ "shortcuts" ], mapping i )
example += "* [[" + i["pattern"] + "xyz]], \n";
example += "where xyz is an individual identifier which will be added to
the Url.\n"
"A friendly text can be added after a blank.\n"
"\n";
}
if ( sizeof( settings[ "shortcuts" ] ) || settings[ "forcedlinks" ] ) {
example += "Sometimes you don't want to linkify your [[[text]]].\n"
"\n";
}
if ( settings[ "convert_code" ] ) {
example += "|code = \"a\";\n"
"|code += \" and b\"\n"
"\n";
}
if ( settings[ "convert_quote" ] ) {
example += "> Some quoted text.\n\n";
}
if ( settings[ "convert_header" ] ) {
example += "Available headers:\n";
for( int i = settings[ "headerlimit_upper" ] - settings[ "remap_headers" ]
* ( settings[ "headerlimit_upper" ] - 1 );
i <= settings[ "headerlimit_lower" ] - settings[ "remap_headers" ] *
( settings[ "headerlimit_upper" ] - 1 );
i++ )
example += "=" * i + "Header " + i + "\n";
}
if ( settings["sandbox"] )
{
if ( sizeof( s - " " - "\n" - "\r" ) > 0 )
example = s;
if ( sandbox )
example = sandbox;
example = replace( example , ({ "<", ">", "&" }), ({ "<", ">",
"&"}) );
help = "<h1>Sandbox</h1>\n"
"<form method='POST' action='#'>\n"
"<textarea name='_sandbox' rows='20' cols='80'>" + example +
"</textarea>\n"
"<input type='submit' value='Preview' />\n"
"</form>\n"
"<h3>Preview</h3>\n"
"<div>\n"
"<wikimarkup" + settings["args"] + ">\n"
+ example + "\n</wikimarkup>\n"
"</div>";
}
if ( settings["userhelp"] == "long" || settings["userhelp"] == "short" ) {
help += "<h2>WikiMarkup Example</h2>\n";
if ( sizeof( s - " " - "\n" - "\r" ) == 0 )
{
example = "<wikimarkup" + settings["args"] + ">\n"
+ example + "\n</wikimarkup>\n";
}
else
example = "<wikimarkup" + settings["args"] + ">" + s + "</wikimarkup>";
help += "<table cellspacing='0' cellpadding='4' border='1'>"
"<tr><th><h3>Markup</h3></th></tr>"
"<tr><td><pre>" + replace( example, ({ "<", ">", "&" }),
( ) ) + "</pre>"
"</td></tr>"
"<tr><th><h3>Parsed Result</h3></th></tr>"
"<tr><td>" + example + "</td></tr></table>";
}
return help;
}
}
// --------------------- Documentation -----------------------
TAGDOCUMENTATION;
#ifdef manual
constant tagdoc=([
"wikimarkup":#"<desc type='cont'>
<p><short hide='hide'>
Converts a simple WikiMarkup into XHMTL.</short>
This tag is mostly useful for turning user freetext input from a form
into XHTML by using a simple Wiki-like markup language. Text that looks
like a link will be converted to a XHTML-link (except mailto links).</p>
<h2>Usage of the <tag>wikimarkup</tag>/ container</h2>
<p>The container can be used in a very simple manner - without any required
attributes - to transform its contents from WikiMarkup into XHTML.</p>
<p>To control the translation of certain markup, you could either enable or
disable feaures in the administration interface's "Default"-tab
or override those default values by setting the according tag-attributes.</p>
<p>For the webmaster's convenience there is an help screen for the user
editing and writing in WikiMarkup. This help text can be shown with the
<i>userhelp</i> attribute and shows the appropriate syntax for all enabled
features (via attributes or default values).</p>
<attr name='charformat' value='on|off'><p>Enables or disables simple character
formating markup: <strong>" _"</strong> (italic), <strong>"
*"</strong> (strong) or <strong>" _*"</strong> (strong and
italic).</p>
</attr>
<attr name='lists' value='on|off'><p>Enables or disables list markup:
<strong>*</strong> (unordered lists) and <strong>#</strong> (ordered lists)
at the beginning of a line.</p>
</attr>
<attr name='code' value='on|off'><p>Enables or disables codelisting markup:
<strong>|</strong> at the beginning of a line.</p>
</attr>
<attr name='quote' value='on|off'><p>Enables or disables blockqote markup:
<strong>></strong> at the beginning of a line.
</p></attr>
<attr name='headers' value='on|off'><p>Enables or disables header markup:
a certain number <strong>=</strong> at the beginning of a line indicates the
level of the XHMTL header.</p>
</attr>
<attr name='headerlevel-upper' value='[1-6]' default='1'><p>Sets the highest
available level of headers. Be aware that a higher header level corresponds
with a lower number, 1 equals to H1 and is the default value.
Higher levels will be ignored (i.e. parsed as simple paragraphs). If there is
a conflict with the headerlevel-lower (i.e. headerlevel-lower has a lower
number than headerlevel-upper) headerlevel-upper takes precedence.</p>
</attr>
<attr name='headerlevel-lower' value='[1-6]' default='6'><p>Sets the lowest
available level of headers. Lower levels will be ignored (i.e. parsed as
simple paragraphs).</p>
</attr>
<attr name='remap-headers' value='on|off'><p>Enables or disables header
remapping:
Your headers will automatically be remapped to the highest allowed header
(headerlevel-upper). E.g. if you you allow only H3 and lower, a wiki-header
of level 1 ("=") will be remapped to a H3 in XHTML. This attribute
is only useful, if you have headerlevel-upper different from 1.</p>
</attr>
<attr name='acronyms' value='on|off'><p>Enables or disables tagging of acronyms:
<strong>acronym_(definition)</strong>.
</p></attr>
<attr name='linkify' value='on|off'><p>Enables or disables automatic conversion
of text similar to common link-patterns to hyperlink. Note: there is no
automatic
concersion of email links.</p>
</attr>
<attr name='forcedlinks' value='on|off'><p>Enables or disables a forced text to
hyperlink conversion: all text embraced by "<strong>[[]]</strong>"
double
squared brackets will be transformed into hyperlinks. </p>
</attr>
<attr name='nofollow' value='on|off'><p>If enabled, all links in the WikiMarkup
will get <i>rel="nofollow"</i> set. This is a new spam prevention
method supported by most search engines
(<a
href=\"http://www.google.com/googleblog/2005/01/preventing-comment-spam.html\">
Information on preventing comment spam</a> ) </p>
</attr>
<attr name='shortcuts' value=''
default='string-pattern,url,string-linktext[,...]'>
<p>Sets or overrides shortcut definitions. All definitions should be provided
as triples "pattern,url,linktext" concencated by an seperator-string
(default: ","). The last value (linktext) can be an empty string (or
omitted in the last definition set). Several sets can be concencated by an
seperator-string (defaul: ",").</p>
<p>For information on the usage of shortcut urls see the WikiMarkup
section.</p>
</attr>
<attr name='images' value='on|off'>
<p>Enables or disables the insertion of images in the form of
"<strong>[[image::filename.jpg Alt text]]</strong>".</p>
</p></attr>
<attr name='imgpath' value='' default='path|url'>
<p>Sets the default path for image insertion to an path or external url.</p>
</attr>
<attr name='userhelp' value='long|short'>
<p>With this attribute you can provide syntax information and an example of
usage
for a Wiki-Editor. With the attribute value <strong>"short"</strong>
you will only get an example with unparsed and parsed WikiMarkup. With the
attribute value <strong>"long"</strong> additional syntax information
will be shown. </p>
<p>Examples and syntax will only be provided on the enabled features
(from the "Default"-tab in the administration interface or set by tag
attributes).</p>
<p>If the content of the container is empty, a default example is shown.</p>
</attr>
<attr name='sandbox'>
<p>The sandbox is a helpfult tool to experiment with WikiMarkup. You'll have
a form where you can edit and preview your WikiMarkup.</p>
<p>If the content of the container is empty, a default example is shown
initially.</p>
<p>The default examples will only show the enabled features (from the
"Default"-tab in the administration interface or set by tag
attributes).</p>
</attr>
<!-- <ex><wikimarkup userhelp='long' headers='on' headerlimit-upper='1'
headerlimit-lower='6' lists='on' charformat='on' linkify='on' forcedlinks='on'
code='on' shortcuts='Bug,http://community.roxen.com,Roxens
BugCrunch'></wikimarkup></ex> -->
<h2>WikiMarkup Syntax</h2>
<h4>Paragraphs</h4>
<p>Paragraphs are separated by empty lines (i.e. two linebreaks).
A single linebreak within a paragraph has no influence on the formatting
of the converted XHTML (i.e. no <br /> is inserted).</p>
<h4>Character formating: bold and italic text</h4>
<p>If you want to format text in bold or italic fonts wrap the text
in this markup: <strong>" _"</strong> (italic), <strong>"
*"</strong> (strong) or <strong>" _*"</strong> (strong and
italic). Be careful to combine the markup character always with a blank
space.</p>
<h4>Lists</h4>
<p>Lists are formated by <strong>*</strong> (unordered lists)
<strong>#</strong> (ordered lists) at the beginning of a line. Lists may
be nested by joining * and # (e.g. **# is an ordered list nested in an
unordered list which is again nested in an unordered list.</p>
<h4>Code listings</h4>
<p>If you want to format blocks of code (codelistings) start the lines with
a <strong>|</strong>.</p>
<h4>Blockqotes</h4>
<p>If you want to format blockquotes start the lines with a
<strong>></strong>. You can nest blockquotes and use other block formats
inside blockquotes.</p>
<h4>Headers</h4>
<p>Headers of a certain level are formated with the according number of
<strong>=</strong> at the beginning of a line. The highest level of headers
allowed is <strong>H1 ("=")</strong>. The highest lowest of headers
allowed is <strong>H6 ("======")</strong>.</p>
<h4>Acronyms</h4>
<p>If you want to tag acronyms you you can add a definition:
<strong>acronym_(definition)</strong>.</p>
<h4>Automatic link conversion ("linkify")</h4>
<p>Textlinks of the common link-patterns <strong>http://</strong>,
<strong>https://</strong>, <strong>ftp://</strong>, <strong>www.</strong> or
<strong>ftp</strong>.</strong> will will automatically converted into
clickable hyperlinks.
<h4>Forced Links</h4>
<p>If you want to force text to hyperlink conversion you can do this with
the syntax <strong>[[url]]</strong> or <strong>[[url linktext]]</strong>.
The text after the first blank will be the visible text on the link, if
omitted the url will be shown.</p>
<h4>Shortcut links</h4>
<p>You can use shortcut links to set easily an reference to certain standard
link destinations.
Shortcut syntax has the form [[ABCxyz]] where ABC is a defined pattern to
match with and xyz
is an individual identifier which will be added to your Url.</p>
<p>Example shortcut link:</p>
<xtable>
<row>
<h>Pattern </h><h>Url </h><h>Linktext </h>
</row>
<row><c>Bug </c><c>http://community.roxen.com </c><c>Roxens
BugCrunch </c></row>
</xtable>
<p>This example can be written in your text as [[Bug123]]. You can override a
predefined linktext
by adding a friendly name after a blank: e.g. [[Bug123 This is a link to Bug
123]].</p>
<h4>Inserting images</h4>
<p>You can insert images in the form [[image::filename.jpg Alt text]].</p>
<h4>Escaping markup characters</h4>
<p>If you have to escape markup characters (i.e. if you do not want to use
them as markup but as simple text): </p>
<ul>
<li>Duplicate them for character formating (e.g. **, __, **__)</li>
<li>Prefix them with a blank space for block formatting (*,#,= or |
at the beginning of a line)</li>
<li>If you want to use double square brackets "[[text]]" triple them
"[[[text]]]" in the markup.</li>
</ul>
<h2>WikiMarkup Example</h2>
<xtable>
<row><c>
<pre><wikimarkup
linkify=\"on\"
charformat=\"on\"
headerlimit-lower=\"6\"
headers=\"on\"
code=\"on\"
quote=\"on\"
lists=\"on\"
forcedlinks=\"on\"
headerlimit-upper=\"1\"
shortcuts=\"Bug,http://community.roxen.com,Roxen\'s BugCrunch\">
This is a simple paragraph
which ignores any linebreak.
FOAF_(Friend Of A Friend) is an acronym.
* this is an unordered list
* second list item
*# containing a nested ordered list
*# with two items
Character formating: _italic,_ *bold* and _*bold and italic text*_ .
Automatically converted links: http://roxen.sodazitron.at and www.chilimoon.org .
Forced link conversion [[chilimoon.sodazitron.com]], also with friedly text on
the
link to [[chilimoon.sodazitron.com/listarchive/ Roxen Mailinglist Archive]].
You can also set shortcuts to some standard link destinations:
[[Bugxyz]], where xyz is an individual identifier which will be added to the Url.
A friendly text can be added after a blank.
|code = \"a\";
|code += \" and b\"
> quoted text.
Available headers:
=Header 1
==Header 2
===Header 3
====Header 4
=====Header 5
======Header 6
</wikimarkup>
</pre></c></row><row><c><p>This is a simple paragraph which ignores any
linebreak. <acronym title=\"Friend Of A Friend\">FOAF</acronym> is an
acronym.</p>
<ul>
<li> this is an unordered list </li>
<li> second list item <ol>
<li> containing a nested ordered list </li>
<li> with two items </li>
</ol>
</li>
</ul>
<p>Character formating: <em>italic,</em> <strong>bold</strong> and
<em><strong>bold and italic text</strong></em> . </p>
<p>Automatically converted links: <a
href='http://roxen.sodazitron.at'>http://roxen.sodazitron.at</a> and <a
href='http://www.chilimoon.org'>http://www.chilimoon.org</a> . </p>
<p>Forced link conversion <a
href='http://chilimoon.sodazitron.com'>chilimoon.sodazitron.com</a>, also with
friedly text on the link to <a
href='http://chilimoon.sodazitron.com/listarchive/'>Roxen Mailinglist
Archive</a>. </p>
<p>You can also set shortcuts to some standard link destinations: <a
href='http://community.roxen.com/xyz'>Roxen's BugCrunch</a>, where xyz is an
individual identifier which will be added to the Url. A friendly text can be
added after a blank. </p>
<pre><code>code = \"a\";
code += \" and b\" </code></pre>
<blockqote>quoted text.</blockqote>
<p>Available headers: </p>
<h1>Header 1 </h1>
<h2>Header 2 </h2>
<h3>Header 3 </h3>
<h4>Header 4 </h4>
<h5>Header 5 </h5>
<h6>Header 6 </h6>
</c></row></xtable>
<h2>Security notes</h2>
<p>You might want to use the <tag>noparse</tag>/ container inside the
<tag>wikimarkup</tag>/ container for security reasons.</p>
</desc>", ]);
#endif
|