monkdiscuss
LanX
One of my New Year's resolutions is to release more code, even if it doesn't meet my quality expectations yet... ¹<P>
I'm using this hack for some time now...<P>
It's a nodelet hack which automatically transforms my wiki-ish syntax into monk-code on submit. <P>
This is done transparently because after a reload the monk-code in the textarea is translated back to the original wiki syntax.<P>
Please note that you can still safely use and blend PM-markup as long as you use lowercase characters. The automatically transformed code is always uppercase.<P>
The biggest benefit is that paragraphs <c><P></c> are automatically included between two newlines...<P>
...but I added some more goodies over the years. (see examples further down.)<P>
To activate this for yourself you just need to include the following code into your [id://492700|free nodelet].<P>
<c><script src='?abspart=1;displaytype=displaycode;node_id=1153804;part=3'></script></c><P>
(UPDATE: Additionally the "Free Nodelet" must be activated at [ID://25185])<P>
I hope the mechanism of the code is obvious enough to be adapted to your needs. <P>
<readmore>
<h1>---Code---</h1><P>
<spoiler><P>
<code>
// create toggle for wiki feature
// document.writeln('<form name="wiki"><input type="checkbox" name="on">wiki?</form><br>');
var textarea=get_textarea();
var form_elements = textarea.form.elements;
form_elements[form_elements.length-1].outerHTML += '<span><input type="checkbox" name="wiki_on"> <a href="?node_id=1153804">*Wiki?*</a> </span>';
if ( textarea ) {
// activate wikifeature
//document.forms.wiki.elements.on.checked=true;
form_elements.wiki_on.checked=true;
}
var text;
/*
expand wiki code to monk code with capital letters
*/
var info = {
'version': 1.161,
'was' : {},
'is' : {},
'start' : "<"+"!-- Wiki2Monks ",
'end' : " --"+">",
'extract': function (text) {
var text_new = text.replace(new RegExp( this.start + '(.*?)' + this.end + '$' ) ,'');
if ( text_new.length != text.length) { // match
var JSONs = RegExp.$1.split(this.start); // too many strings ?
var JSON_str = JSONs[JSONs.length-1]; // take last one
// console.log( (text.length - text_new.length ) + ">"+ JSON_str +"<" );
if (! JSON_str) {
JSON_str = {};
}
if (JSON) {
this.was = JSON.parse(JSON_str);
// console.log("Info was: ");
// console.log(this.was);
}
} else {
this.was ={};
}
return text_new;
},
'inject' : function (text) {
text += this.start + this.get_new() + this.end;
return text;
},
'get_new' : function() {
var is = this.was;
is.version = this.version;
var str = '{}';
if (JSON ) {
// is.JSON = true;
str = JSON.stringify(is);
} else { // backup for older browsers
str = '{"version":' + is.version + ', "JSON": false }';
}
this.is = is;
return str;
}
};
function wiki2monks () {
//old document.forms.wiki.elements.on.checked
if ( textarea && form_elements.wiki_on.checked ) {
text=textarea.value;
// constants regex
var singleword = '\\S+' ;
var singleline = '\\S|\\S.*?\\S' ;
//******* protect special areas
text = init_exclusions(text);
text = exclude_all(text);
//******* Replace Inline Markup
//*** normalize newlines
text=text.replace(/\r\n/g,'\n'); // IE sucks!
//****** complete lines but excluded
//*** > quotes -> <I> > ... </I>
text=text.replace(/(^|^\n|\n\n)(> )([^]*?)(?=\n\n|\n$|$)/g,'$1<I>> $3</I>'); // quote
//*** autolinks to modules, pragmas, cpan
text=text.replace(/(\s)(\w+::\w[\w:]*)(\s)/g,link_module);
//*** links to perldoc perldoc.perl.org/perlsyn.html#Loop-Control
// -> [HTTP(S)://perldoc.perl.org/perlsyn.html#Loop-Control|perlsyn#Loop-Control]
text=text.replace(
/(^|\s)(http(s?):\/\/)(perldoc.perl.org)(\/.*?)?\/(\w+).html(#.*?)?(\s|$)/g,
'$1[HTTP$3://$4$5/$6.html$7|$6$7]$8'
);
//*** internal links http(s)://www.perlmonks.org/?node_id=708738 -> [ID://...]
text=text.replace(
/(^|\s)(https?:\/\/)(www\.)?perlmonks\.(org|net|com)\/(?:index\.pl)?\?node_id=(\d+)(\|.*?)?(\s|$)/g,
'$1[ID://$5$6]$7'
);
//*** autolinks for remaining http(s)://u.r.l.s
text=text.replace(
/(^|\s)(http(s?):\/\/)(\S*?)(\s|$)/g,
'$1[HTTP$3://$4]$5'
);
//*** 'inline code' -> '...'
around_words('inline code', 'C', "'", singleline);
text = exclude_all(text); // protect new code areas
//*** ?documentation? -> [DOC://...]
text=text.replace(/(\s)\?(\S+)\?(\s)/g,'$1[DOC://$2|<tt>$2</tt>]$3');
text = exclude_all(text); // protect new doc areas
//*** emphasizer * / _ -> <B><I><U>
around_words('bold', 'B', '*', singleline);
around_words('italic', 'I', '/', singleline);
around_words('underline', 'U', '_', singleline);
/*
//*** emphasizer * / _ -> <B><I><U>
around_words('bold', 'B', '*', singleword);
around_words('italic', 'I', '/', singleword);
around_words('underline', 'U', '_', singleword);
*/
//*** \n=== headlines -> <H6>...</H6>
text = heading(text);
//*** - list items -> <LI>...</LI>
// paragraphs starting with (-)+ = (un)orderd
text=text.replace(/(\n)(\n-\s+[^]*?)(\n\n)/g,'$1<UL\>$2\n<\/UL\>\n'); // bullets unordered
text=text.replace(/(\n)(\n\+\s+[^]*?)(\n\n)/g,'$1<OL\>$2\n<\/OL\>\n'); // bullets ordered
text=text.replace(/^(\-|\+)(\s+.*?)$/gm,'<LI\>$2'); // bullets (simple)
//*** paragraph
text=text.replace(/(\n\n+)/g,'<P\>$1'); // paragraph
//****** reinclude protected areas
text = include_all(text);
//*** insert info as html comment (version and so on)
text = info.inject(text);
textarea.value=text;
}
// return false;
}
/*
replace words surrounded by wikitags with pm markup
eg " *words* " -> " <B>words</B> "
*/
function around_words ( doc, monk_tag, wiki_tag, inner_re) {
var empty = '(^|\\s|$)';
var marker = '(\\' + wiki_tag + ')';
var inner_grp = '(' + inner_re + ')';
var regex = new RegExp( empty + marker + inner_grp + marker + empty, 'g');
var pre_tag = '<' + monk_tag + '>';
var post_tag = '</' + monk_tag + '>';
var substitute = '$1' + pre_tag + '$3' + post_tag + '$5';
// console.log(doc,regex,substitute);
text=text.replace( regex, substitute);
}
function around_paragraph ( doc, monk_tag, wiki_tag, inner_re) {
//stub
}
/*
transform headlines (both ways)
eg "^=== text" <-> <H5>text</H5>
*/
function heading (text,revert) {
var maps =[
['===', 'H5'],
['==' , 'H4'],
['=' , 'H3'],
];
if (revert) {
for (var i=maps.length-1; i>=0 ;i--) {
var map=maps[i];
var tag0 = new RegExp( '<'+ map[1] + '>','g');
text=text.replace(tag0,map[0]);
var tag1 = new RegExp( '</'+ map[1] + '>','g');
text=text.replace(tag1,'');
}
} else {
for (var i=0; i<maps.length;i++) {
var map=maps[i];
var from = new RegExp( '^(' +map[0]+ ')(\\s.*?)$','gm');
var to = '<'+ map[1] + '>$2</' + map[1] +'>';
// console.log(from + ' -> ' + to);
text=text.replace(from,to);
}
}
return text;
}
/* revert PM markup back to wiki markup */
function monks2wiki () {
//old document.forms.wiki.elements.on.checked
if ( textarea && form_elements.wiki_on.checked ) {
var text=textarea.value;
text = info.extract(text);
// protect areas like code sections
text = exclude_all(text);
// delete <P>
text=text.replace(/<P>/g,'');
// no quote
text=text.replace(/(^|\n\n)<I>(> )([^]*?)<\/I>(?=\n\n|$)/g,'$1> $3');
// revert around word markup
text=text.replace(/<\/?I>/g,'/');
text=text.replace(/<\/?B>/g,'*');
text=text.replace(/<\/?U>/g,'_');
// revert listitems
text=text.replace(/<LI>/g,'-');
text=text.replace(/<\/?(U|O)L>/g,'');
// revert <H3>..<H5>
text = heading(text,1);
// reinclude protected areas
text = include_all(text);
// revert ' (was protected)
text=text.replace(/<\/?C>/g,"'");
textarea.value=text;
}
}
function link_module(match, pre, name, post, offset, string) {
var core_modules = {
'B::Deparse' : 1,
};
var protokoll= core_modules[name] ? 'doc' : 'metamod';
return pre+'['+protokoll.toUpperCase()+'://'+name+']'+post;
}
(function (){
var DBG=false;
var counter=0;
// var matches = [];
var exclusions = [];
var delim="\0";
var delim0=delim+"<<";
var delim1=">>"+delim;
init_exclusions =function (text) {
exclusions = [];
counter=0;
text = exclude(text,new RegExp(delim+"+","g"),"delim");
return text;
}
exclude_all = function (text){
text = exclude(text,/<(c|code)>[^]*?<\/\1>/gi, "code" );
text = exclude(text,/<(blockquote)>[^]*?<\/\1>/gi, "blockquote" );
text = exclude(text,/<(pre)>[^]*?<\/\1>/gi, "pre" );
text = exclude(text,/\[(\w+):\/\/.*?\]/g, "link" );
// hide <nowiki> as <!--nowiki--> from display
text = text.replace(/<(\/?nowiki)>/g, "<!--$1-->") ;
text = exclude(text,/<!--nowiki-->[^]*?<!--\/nowiki-->/gi, "nowiki" );
text = exclude(text,/<\w+\s+.+?>/g, "innertag" );
text = exclude(text,new RegExp("<"+"!--[^]*?--"+">","g"), "comment" );
if (DBG) console.log(exclusions);
return text;
}
function exclude(text,pattern,name){
var text_out=text;
var match;
while (match = pattern.exec(text)) {
// if (DBG) console.log(match);
var substring = match[0];
var placeholder = name.toUpperCase();
if (match[1]) placeholder += "_"+match[1];
placeholder = delim0 + placeholder + "_" +counter + delim1;
text_out = text_out.replace( substring, placeholder );
// matches[counter] = substring;
exclusions.push( [placeholder,substring] );
counter++;
}
return text_out;
}
include_all = function (text){
var exclusion;
while ( exclusion = exclusions.pop() ){
var placeholder = exclusion[0];
var substring = exclusion[1];
substring = substring.replace(/\$/g,'$$$$'); // escape $ to avoid interpolation
text = text.replace( placeholder, substring );
}
return text;
}
})();
/* textareas meant for posting discussions have names ending on '_doctext' */
function get_textarea() {
var T=document.getElementsByTagName("textarea");
for (var i in T) {
var n=T[i].name ;
if (n && n.match(/_doctext$/))
return T[i];
}
}
if (textarea) {
// after pageload revert upercase PM markup to original wikicode
window.onload= monks2wiki;
// on submit of form wikisyntax to PM markup
textarea.form.onsubmit = wiki2monks;
}
// ********** test code **********
/* test heading() */
function t_heading () {
var t='= eins\n== zwei\n=== drei';
//console.log(t);
var a=heading(t);
//console.log(a);
var b=heading(a,1);
// console.log(b);
var a=heading(b);
var b=heading(a,1);
if (t!=b) {
console.log('heading test FAILED: \n'+t+'\n->\n'+a+'\n->\n'+b);
} else {
console.log("heading test OK");
}
}
/* END OF WIKIFEATURE */
</code><P>
<!-- old version prior 01.FEB.2016
<code>
// create toggle for wiki feature
document.writeln('<form name="wiki"><input type="checkbox" name="on">wiki?</form><br>');
var textarea=get_textarea();
// obsolet
var allowed_nodes = {479:'perlquestion',480:'perlmeditation',1040:'monkdiscuss', 1597: 'obfuscated',1044:'CUFP'};
if ( textarea ) {
// activate wikifeature
document.forms.wiki.elements.on.checked=true;
// window.alert('wiki enabled!!!');
}
var text;
/*
expand wiki code to monk code with capital letters
*/
function wiki2monks () {
if ( textarea && document.forms.wiki.elements.on.checked) {
text=textarea.value;
// constants regex
var singleword = '\\S+' ;
var singleline = '\\S|\\S.*?\\S' ;
//******* protect special areas
text = init_exclusions(text);
text = exclude_all(text);
//******* Replace Inline Markup
//*** autolinks to modules, pragmas, cpan
text=text.replace(/(\s)(\w+::\w[\w:]*)(\s)/g,link_module);
//*** normalize newlines
text=text.replace(/\r\n/g,'\n'); // IE sucks!
//*** 'inline code' -> '...'
around_words('inline code', 'C', "'", singleline);
text = exclude_all(text); // protect new code areas
//*** ?documentation? -> [DOC://...]
text=text.replace(/(\s)\?(\S+)\?(\s)/g,'$1[DOC://$2|<tt>$2</tt>]$3');
text = exclude_all(text); // protect new doc areas
//*** emphasizer * / _ -> <B><I><U>
around_words('bold', 'B', '*', singleword);
around_words('italic', 'I', '/', singleword);
around_words('underline', 'U', '_', singleword);
//****** complete lines (markup at start of line)
//*** > quotes -> <I> > ... </I>
text=text.replace(/(^|\n\n)(> )([^]*?)(?=\n\n|$)/g,'$1<I>> $3</I>'); // quote
//*** \n=== headlines -> <H6>...</H6>
text = heading(text);
//*** - list items -> <LI>...</LI>
// paragraphs starting with (-)+ = (un)orderd
text=text.replace(/(\n)(\n-\s+[^]*?)(\n\n)/g,'$1<UL\>$2\n<\/UL\>\n'); // bullets unordered
text=text.replace(/(\n)(\n\+\s+[^]*?)(\n\n)/g,'$1<OL\>$2\n<\/OL\>\n'); // bullets ordered
text=text.replace(/^(\-|\+)(\s+.*?)$/gm,'<LI\>$2'); // bullets (simple)
//*** paragraph
text=text.replace(/(\n\n+)/g,'<P\>$1'); // paragraph
//****** reinclude protected areas
text = include_all(text);
textarea.value=text;
}
}
/*
replace words surrounded by wikitags with pm markup
eg " *words* " -> " <B>words</B> "
*/
function around_words ( doc, monk_tag, wiki_tag, inner_re) {
var empty = '(^|\\s|$)';
var marker = '(\\' + wiki_tag + ')';
var inner_grp = '(' + inner_re + ')';
var regex = new RegExp( empty + marker + inner_grp + marker + empty, 'g');
var pre_tag = '<' + monk_tag + '>';
var post_tag = '</' + monk_tag + '>';
var substitute = '$1' + pre_tag + '$3' + post_tag + '$5';
// console.log(doc,regex,substitute);
text=text.replace( regex, substitute);
}
function around_paragraph ( doc, monk_tag, wiki_tag, inner_re) {
//stub
}
/*
transform headlines (both ways)
eg "^=== text" <-> <H5>text</H5>
*/
function heading (text,revert) {
var maps =[
['===', 'H5'],
['==' , 'H4'],
['=' , 'H3'],
];
if (revert) {
for (var i=maps.length-1; i>=0 ;i--) {
var map=maps[i];
var tag0 = new RegExp( '<'+ map[1] + '>','g');
text=text.replace(tag0,map[0]);
var tag1 = new RegExp( '</'+ map[1] + '>','g');
text=text.replace(tag1,'');
}
} else {
for (var i=0; i<maps.length;i++) {
var map=maps[i];
var from = new RegExp( '^(' +map[0]+ ')(\\s.*?)$','gm');
var to = '<'+ map[1] + '>$2</' + map[1] +'>';
// console.log(from + ' -> ' + to);
text=text.replace(from,to);
}
}
return text;
}
/* revert PM markup back to wiki markup */
function monks2wiki () {
if ( textarea && document.forms.wiki.elements.on.checked) {
var text=textarea.value;
// protect areas like code sections
text = exclude_all(text);
// delete <P>
text=text.replace(/<P>/g,'');
// no quote
text=text.replace(/(^|\n\n)<I>(> )([^]*?)<\/I>(?=\n\n|$)/g,'$1> $3');
// revert around word markup
text=text.replace(/<\/?I>/g,'/');
text=text.replace(/<\/?B>/g,'*');
text=text.replace(/<\/?U>/g,'_');
// revert listitems
text=text.replace(/<LI>/g,'-');
text=text.replace(/<\/?(U|O)L>/g,'');
// revert <H3>..<H5>
text = heading(text,1);
// reinclude protected areas
text = include_all(text);
// revert ' (was protected)
text=text.replace(/<\/?C>/g,"'");
textarea.value=text;
}
}
function link_module(match, pre, name, post, offset, string) {
var core_modules = {
'B::Deparse' : 1,
};
var protokoll= core_modules[name] ? 'doc' : 'metamod';
return pre+'['+protokoll.toUpperCase()+'://'+name+']'+post;
}
(function (){
var DBG=false;
var counter=0;
// var matches = [];
var exclusions = [];
var delim="\0";
var delim0=delim+"<<";
var delim1=">>"+delim;
init_exclusions =function (text) {
exclusions = [];
counter=0;
text = exclude(text,new RegExp(delim+"+","g"),"delim");
return text;
}
exclude_all = function (text){
text = exclude(text,/<(c|code)>[^]*?<\/\1>/g,"code");
text = exclude(text,/\[(\w+):\/\/.*?\]/g,"link");
text = exclude(text,/<nowiki>[^]*?<\/nowiki>/g,"nowiki");
text = exclude(text,/<\w+\s+.+?>/g,"innertag");
text = exclude(text,new RegExp("<"+"!--[^]*?--"+">","g"),"comment");
if (DBG) console.log(exclusions);
return text;
}
function exclude(text,pattern,name){
var text_out=text;
var match;
while (match = pattern.exec(text)) {
// if (DBG) console.log(match);
var substring = match[0];
var placeholder = name.toUpperCase();
if (match[1]) placeholder += "_"+match[1];
placeholder = delim0 + placeholder + "_" +counter + delim1;
text_out = text_out.replace( substring, placeholder );
// matches[counter] = substring;
exclusions.push( [placeholder,substring] );
counter++;
}
return text_out;
}
include_all = function (text){
var exclusion;
while ( exclusion = exclusions.pop() ){
var placeholder = exclusion[0];
var substring = exclusion[1];
substring = substring.replace(/\$/g,'$$$$'); // escape $ to avoid interpolation
text = text.replace( placeholder, substring );
}
return text;
}
})();
/* textareas meant for posting discussions have names ending on '_doctext' */
function get_textarea() {
var T=document.getElementsByTagName("textarea");
for (var i in T) {
var n=T[i].name ;
if (n && n.match(/_doctext$/))
return T[i];
}
}
if (textarea) {
// after pageload revert upercase PM markup to original wikicode
window.onload= monks2wiki;
// on submit of form wikisyntax to PM markup
textarea.form.onsubmit = wiki2monks;
}
// ********** test code **********
/* test heading() */
function t_heading () {
var t='= eins\n== zwei\n=== drei';
//console.log(t);
var a=heading(t);
//console.log(a);
var b=heading(a,1);
// console.log(b);
var a=heading(b);
var b=heading(a,1);
if (t!=b) {
console.log('heading test FAILED: \n'+t+'\n->\n'+a+'\n->\n'+b);
} else {
console.log("heading test OK");
}
}
/* END OF WIKIFEATURE */
</code>
--><P>
</spoiler><P>
<h1>---Demo---</h1>
<spoiler>
<h2> Input</h2>
<code>
no
paragraph
(no separating empty line)
auto paragraph after 2 newlines
= headline 1
== headline 2
=== Headline 3
*bold* /italic/ _underlined_
> paragraph with cited text
'inline code'
?doclink?
Module::Name
</code><P>
<h2>Result</h2>
no
paragraph (no separating empty line)<P>
auto paragraph after 2 newlines<P>
<H3> headline 1</H3>
<H4> headline 2</H4>
<H5> Headline 3</H5><P>
<B>bold</B> <I>italic</I> <U>underlined</U><P>
<I>> paragraph with cited text</I><P>
<C>inline code</C><P>
[DOC://doclink|<tt>doclink</tt>] <P>
[METAMOD://Module::Name]
</spoiler><P>
<div class="pmsig"><div class="pmsig-708738">
<p>Cheers Rolf<br>
<sub>(addicted to the Perl Programming Language and [http://i.dailymail.co.uk/i/pix/2014/07/14/article-2690897-1F9F6C0E00000578-463_964x629.jpg|☆☆☆☆] :)
<br> <i>[http://s3.freebeacon.com/up/2015/01/charliehebdo-540x342.png|Je suis Charlie]!</i>
</sub> <P>
</div></div><P>
<H5> update</H5><P>
codelink corrected, including another codearea changed the index to 3<P>
<H5> footnotes</H5><P>
¹) there is a long To-Do list left, but the idea of open source is to attract collaborators and/or forks ... right? ;-)<P>
<H5> bugfixes</H5><P>
<UL>
<LI> surrounded activation of JS events with <C>if(textarea) { ... }</C> to avoid pages without posting forms (like RAT)
</UL>
</readmore>
<!-- Wiki2Monks {"version":1.16} -->