Converting Between Wiki Markup & HTML with Prototype: Part 2 ListsAt
December 19th, 2008At the end of part 1 of the series, the system could easily handle direct replacement of certain html entities with their wiki markup counterparts. Unfortunately this was a pretty limited implementation that could only handle those entities that had a direct, symmetrical relationship with html. In the case of lists, we have to keep track of depth and better cleanup the input text. We also need to enforce default behavior on the input stream.
Since lists are dependent on dedicated whitespace as part of their markup, we need to clear out all unnecessary white space from the html before processing it. To do this, we simply replace all whitespace characters with an innocuous single space to remove any extra new lines.
$(textNode).innerHTML = $(textNode).innerHTML.gsub( '\s', '' );
Next we need to cleanup the recursion. Since we need to know significantly more about the given node to properly assess it. We can replace the Prototype templates with simple curried function calls and migrate the recursion to the curried methods.
var ConverterTable = {
strong: Converter.curry("'''", null, true),
b: Converter.curry("'''" , null, true),
em: Converter.curry( "''" , null, true ),
i: Converter.curry( "''" , null, true ),
h1: Converter.curry( '=' , null, false ),
h2: Converter.curry( '==' , null, false ),
h3: Converter.curry( '===' , null, false ),
h4: Converter.curry( '====' , null, false ),
h5: Converter.curry( '=====' , null, false ),
h6: Converter.curry( '======' , null, false ),
ul: Converter.curry('', {li:Converter.curry(['* ', ''], null, false)}, false),
ol: Converter.curry(”, {li:Converter.curry(['# ', ''], null, false)}, false),
p: Converter.curry(['','\n'], null, false)
};
The parameters passed into the individual rules are
The Markup String or an array of strings for start and end tags
An optional library of child rules. These rules will be applied to any children of the given node before the default rules are applied.
An indication as to the ‘inline-ability’ of the given tag. This controls the bracketing of the resulting markup with ‘\n’ characters.
The modified Converter now looks to apply rules in the following order
If the node is marked as a stopping point, no recursion proceeds on the branch.
If any over-ridden child rules exist for the given tag, those rules are applied and a memo is passed on to child nodes to denote the depth of the recursion.
Any default rules are processed as per the earlier versions of the code. Note. A prototype template is no longer used in favor of simple string construction.
The node itself is removed from the DOM.
function Converter( markupString, nestedRules, inline, textNode, memo ){
var startString, endString;
inline = inline ? ” : ‘\n’;
memo = memo ? memo : ”;
var children = textNode.childElements();
if( typeof markupString == ‘object’){
startString = inline + markupString[0];
endString = markupString[1] + inline;
} else {
startString = inline + markupString;
endString = markupString + inline;
}
for( i in children){
if( typeof children[i] != ‘function’){
if( nestedRules && typeof nestedRules[children[i].tagName.toLowerCase()] == ‘function’){
startString = memo.strip() + startString;
nestedRules[ children[i].tagName.toLowerCase() ]( children[i], startString);
} else if( typeof ConverterTable[children[i].tagName.toLowerCase()] == ‘function’){
ConverterTable[children[i].tagName.toLowerCase() ](children[i]);
} else { Converter( ”, nestedRules, true, children[i]), memo }
}
}
textNode.replace( startString + textNode.innerHTML + endString );
}


