http://www.mediawiki.org/wiki/Special:Code/MediaWiki/88751
Revision: 88751
Author: tparscal
Date: 2011-05-24 21:08:41 +0000 (Tue, 24 May 2011)
Log Message:
-----------
Reorganized wikidom code.
Modified Paths:
--------------
trunk/parsers/wikidom/demos/renderers/index.html
trunk/parsers/wikidom/tests/wikidom.test.js
trunk/parsers/wikidom/wikidom.js
Modified: trunk/parsers/wikidom/demos/renderers/index.html
===================================================================
--- trunk/parsers/wikidom/demos/renderers/index.html 2011-05-24 21:04:50 UTC
(rev 88750)
+++ trunk/parsers/wikidom/demos/renderers/index.html 2011-05-24 21:08:41 UTC
(rev 88751)
@@ -60,12 +60,12 @@
<script>
$( document ).ready( function() {
$.getJSON( 'document.js', function( data ) {
- var htmlRenderer = new HtmlRenderer();
+ var htmlRenderer = new
wiki.HtmlRenderer();
var html = htmlRenderer.render( data );
$( '#html-rendering' ).append( html );
$( '#html-source' ).text( html );
- var wikitextRenderer = new
WikitextRenderer();
+ var wikitextRenderer = new
wiki.WikitextRenderer();
var wikitext = wikitextRenderer.render(
data );
$( '#wikitext-source' ).text( wikitext
);
Modified: trunk/parsers/wikidom/tests/wikidom.test.js
===================================================================
--- trunk/parsers/wikidom/tests/wikidom.test.js 2011-05-24 21:04:50 UTC (rev
88750)
+++ trunk/parsers/wikidom/tests/wikidom.test.js 2011-05-24 21:08:41 UTC (rev
88751)
@@ -1,8 +1,8 @@
module( 'Wikidom Serialization' );
function assertSerializations( tests ) {
- var htmlRenderer = new HtmlRenderer();
- var wikitextRenderer = new WikitextRenderer();
+ var htmlRenderer = new wiki.HtmlRenderer();
+ var wikitextRenderer = new wiki.WikitextRenderer();
for ( var i = 0; i < tests.length; i++ ) {
equals(
htmlRenderer.render( tests[i].dom ),
@@ -38,7 +38,7 @@
{
'subject': 'horizontal rule',
'dom': { 'blocks': [ {
- 'type': 'rule',
+ 'type': 'horizontal-rule',
} ] },
'html': '<hr />',
'wikitext': '----'
Modified: trunk/parsers/wikidom/wikidom.js
===================================================================
--- trunk/parsers/wikidom/wikidom.js 2011-05-24 21:04:50 UTC (rev 88750)
+++ trunk/parsers/wikidom/wikidom.js 2011-05-24 21:08:41 UTC (rev 88751)
@@ -1,250 +1,301 @@
-/* Utilities */
+/*
+ * Wikitext document object models
+ *
+ * document
+ * blocks: Array
+ * attributes: Plain object
+ *
+ * // Blocks
+ *
+ * comment
+ * text: String
+ * horizontal-rule
+ * heading
+ * level: Integer (1..6)
+ * line: Line object
+ * paragraph
+ * lines: Array of line objects
+ * list
+ * style: String ("bullet" or "number")
+ * items: Array of item objects
+ * table
+ * rows: Array of arrays of cell objects
+ * attributes: Plain object
+ *
+ * // Components
+ *
+ * line
+ * text: String
+ * item
+ * line: Line object
+ * lists: Array of list objects
+ * range
+ * offset: Integer
+ * length: Integer
+ * annotation
+ * type: String
+ * range: Range object
+ * data: Plain object
+ * cell
+ * document: Object
+ * attributes: Plain object
+ */
-var Xml = {
- 'esc': function( text ) {
- return text
- .replace( /&/g, '&' )
- .replace( /</g, '<' )
- .replace( />/g, '>' )
- .replace( /"/g, '"' )
- .replace( /'/g, ''' );
- },
- 'attr': function( attributes ) {
- var attr = '';
- if ( attributes ) {
- for ( var name in attributes ) {
- attr += ' ' + name + '="' + attributes[name] +
'"';
- }
+var wiki = {};
+
+/**
+ * Serializes offset-based annotations.
+ */
+wiki.AnnotationRenderer = function() {
+
+ /* Private Members */
+
+ var that = this;
+ var insertions = {};
+
+ /* Methods */
+
+ this.wrapWithText = function( range, pre, post ) {
+ var start = range.offset;
+ if ( !( start in insertions ) ) {
+ insertions[start] = [pre];
+ } else {
+ insertions[start].push( pre );
}
- return attr;
- },
- 'open': function( tag, attributes ) {
- return '<' + tag + Xml.attr( attributes ) + '>';
- },
- 'close': function( tag ) {
- return '</' + tag + '>';
- },
- 'tag': function( tag, attributes, value, escape ) {
- if ( value === false ) {
- return '<' + tag + Xml.attr( attributes ) + ' />';
+ var end = range.offset + range.length;
+ if ( !( end in insertions ) ) {
+ insertions[end] = [post];
} else {
- if ( escape ) {
- value = Xml.esc( value );
- }
- return '<' + tag + Xml.attr( attributes ) + '>' + value
+ '</' + tag + '>';
+ insertions[end].unshift( post );
}
- }
-};
+ };
-function repeat( pattern, count ) {
- if ( count < 1 ) return '';
- var result = '';
- while ( count > 0 ) {
- if ( count & 1 ) result += pattern;
- count >>= 1, pattern += pattern;
+ this.wrapWithXml = function( range, tag, attributes ) {
+ that.wrapWithText(
+ range, wiki.util.xml.open( tag, attributes ),
wiki.util.xml.close( tag )
+ );
};
- return result;
-};
-function AnnotationSerialization() {
- this.insertions = {};
-}
-
-AnnotationSerialization.prototype.wrapWithText = function( range, pre, post ) {
- var start = range.offset;
- if ( !( start in this.insertions ) ) {
- this.insertions[start] = [pre];
- } else {
- this.insertions[start].push( pre );
- }
- var end = range.offset + range.length;
- if ( !( end in this.insertions ) ) {
- this.insertions[end] = [post];
- } else {
- this.insertions[end].unshift( post );
- }
+ this.apply = function( text ) {
+ var out = '';
+ for ( var i = 0, iMax = text.length; i <= iMax; i++ ) {
+ if ( i in insertions ) {
+ out += insertions[i].join( '' );
+ }
+ if ( i < iMax ) {
+ out += text[i];
+ }
+ }
+ return out;
+ };
};
-AnnotationSerialization.prototype.wrapWithXml = function( range, tag,
attributes ) {
- this.wrapWithText( range, Xml.open( tag, attributes ), Xml.close( tag )
);
-};
+/**
+ * Serializes a WikiDom into HTML.
+ */
+wiki.HtmlRenderer = function() {
-AnnotationSerialization.prototype.apply = function( text ) {
- var out = '';
- for ( var i = 0, iMax = text.length; i <= iMax; i++ ) {
- if ( i in this.insertions ) {
- out += this.insertions[i].join( '' );
- }
- if ( i < iMax ) {
- out += text[i];
- }
- }
- return out;
-};
+ /* Private Members */
-/* Renderers */
+ var that = this;
+ var blockRenderers = {
+ 'comment': renderComment,
+ 'horizontal-rule': renderHorizontalRule,
+ 'heading': renderHeading,
+ 'paragraph': renderParagraph,
+ 'list': renderList,
+ 'table': renderTable
+ };
-function HtmlRenderer() { }
+ /* Private Methods */
-HtmlRenderer.prototype.render = function( doc ) {
- return HtmlRenderer.renderers.document( doc );
-};
-
-HtmlRenderer.renderers = {
- 'document': function( doc, rawFirstParagraph ) {
+ function renderDocument( doc, rawFirstParagraph ) {
var out = [];
for ( var b = 0, bMax = doc.blocks.length; b < bMax; b++ ) {
var block = doc.blocks[b];
- if ( block.type in HtmlRenderer.renderers ) {
+ if ( block.type in blockRenderers ) {
if ( block.type === 'paragraph' ) {
out.push(
-
HtmlRenderer.renderers.paragraph( block, rawFirstParagraph && b === 0 )
+ renderParagraph( block,
rawFirstParagraph && b === 0 )
);
} else {
- out.push(
HtmlRenderer.renderers[block.type]( block ) );
+ out.push( blockRenderers[block.type](
block ) );
}
}
}
return out.join( '\n' );
- },
- 'comment': function( comment ) {
+ }
+
+ function renderComment( comment ) {
return '<!--' + comment.text + '-->';
- },
- 'rule': function( rule ) {
- return Xml.tag( 'hr', {}, false );
- },
- 'heading': function( heading ) {
- return Xml.tag( 'h' + heading.level, {},
HtmlRenderer.renderers.line( heading.line ) );
- },
- 'paragraph': function( paragraph, raw ) {
+ }
+
+ function renderHorizontalRule( rule ) {
+ return wiki.util.xml.tag( 'hr', {}, false );
+ }
+
+ function renderHeading( heading ) {
+ return wiki.util.xml.tag( 'h' + heading.level, {}, renderLine(
heading.line ) );
+ }
+
+ function renderParagraph( paragraph, raw ) {
var out = [];
for ( var l = 0, lMax = paragraph.lines.length; l < lMax; l++ )
{
- out.push( HtmlRenderer.renderers.line(
paragraph.lines[l] ) );
+ out.push( renderLine( paragraph.lines[l] ) );
}
if ( raw ) {
return out.join( '\n' );
} else {
- return Xml.tag( 'p', {}, out.join( '\n' ) );
+ return wiki.util.xml.tag( 'p', {}, out.join( '\n' ) );
}
- },
- 'list': function( list ) {
+ }
+
+ function renderList( list ) {
var tags = {
'bullet': 'ul',
'number': 'ol'
};
var out = [];
- out.push( Xml.open( tags[list.style] ) );
+ out.push( wiki.util.xml.open( tags[list.style] ) );
for ( var i = 0, iMax = list.items.length; i < iMax; i++ ) {
- out.push( HtmlRenderer.renderers.item( list.items[i] )
);
+ out.push( renderItem( list.items[i] ) );
}
- out.push( Xml.close( tags[list.style] ) );
+ out.push( wiki.util.xml.close( tags[list.style] ) );
return out.join( '\n' );
- },
- 'table': function( table ) {
+ }
+
+ function renderTable( table ) {
var out = [];
var types = {
'heading': 'th',
'data': 'td'
};
- out.push( Xml.open( 'table', table.attributes ) );
+ out.push( wiki.util.xml.open( 'table', table.attributes ) );
for ( var r = 0, rMax = table.rows.length; r < rMax; r++ ) {
- out.push( Xml.open( 'tr' ) );
+ out.push( wiki.util.xml.open( 'tr' ) );
var row = table.rows[r];
for ( var c = 0, cMax = row.length; c < cMax; c++ ) {
var type = types[row[c].type || 'data'];
- out.push( Xml.tag(
+ out.push( wiki.util.xml.tag(
type,
row[c].attributes,
- HtmlRenderer.renderers.document(
row[c].document, true )
+ renderDocument( row[c].document, true )
) );
}
- out.push( Xml.close( 'tr' ) );
+ out.push( wiki.util.xml.close( 'tr' ) );
}
- out.push( Xml.close( 'table' ) );
+ out.push( wiki.util.xml.close( 'table' ) );
return out.join( '\n' );
- },
- 'item': function( item ) {
+ }
+
+ function renderItem( item ) {
if ( 'lists' in item && item.lists.length ) {
var out = [];
- out.push( Xml.open( 'li' ) +
HtmlRenderer.renderers.line( item.line ) );
+ out.push( wiki.util.xml.open( 'li' ) + renderLine(
item.line ) );
for ( var l = 0, lMax = item.lists.length; l < lMax;
l++ ) {
- out.push( HtmlRenderer.renderers.list(
item.lists[l] ) );
+ out.push( renderList( item.lists[l] ) );
}
- out.push( Xml.close( 'li' ) )
+ out.push( wiki.util.xml.close( 'li' ) )
return out.join( '\n' );
} else {
- return Xml.tag( 'li', {}, HtmlRenderer.renderers.line(
item.line ) );
+ return wiki.util.xml.tag( 'li', {}, renderLine(
item.line ) );
}
- },
- 'line': function( line ) {
+ }
+
+ function renderLine( line ) {
if ( 'annotations' in line && line.annotations.length ) {
- var as = new AnnotationSerialization();
+ var ar = new wiki.AnnotationRenderer();
for ( var a = 0, aMax = line.annotations.length; a <
aMax; a++ ) {
var an = line.annotations[a];
switch ( an.type ) {
case 'bold':
- as.wrapWithXml( an.range,
'strong' );
+ ar.wrapWithXml( an.range,
'strong' );
break;
case 'italic':
- as.wrapWithXml( an.range, 'em'
);
+ ar.wrapWithXml( an.range, 'em'
);
break;
case 'xlink':
- as.wrapWithXml( an.range, 'a',
{ 'href': an.data.url } );
+ ar.wrapWithXml( an.range, 'a',
{ 'href': an.data.url } );
break;
case 'ilink':
- as.wrapWithXml( an.range, 'a',
{ 'href': '/wiki/' + an.data.title } );
+ ar.wrapWithXml( an.range, 'a',
{ 'href': '/wiki/' + an.data.title } );
break;
}
}
- return as.apply( line.text );
+ return ar.apply( line.text );
} else {
return line.text;
}
}
-};
-function WikitextRenderer() { }
+ /* Methods */
-WikitextRenderer.prototype.render = function( doc ) {
- return WikitextRenderer.renderers.document( doc );
+ this.render = function( doc ) {
+ return renderDocument( doc );
+ };
};
-WikitextRenderer.renderers = {
- 'document': function( doc, rawFirstParagraph ) {
+/**
+ * Serializes a WikiDom into Wikitext.
+ */
+wiki.WikitextRenderer = function() {
+
+ /* Private Members */
+
+ var that = this;
+ var blockRenderers = {
+ 'comment': renderComment,
+ 'horizontal-rule': renderHorizontalRule,
+ 'heading': renderHeading,
+ 'paragraph': renderParagraph,
+ 'list': renderList,
+ 'table': renderTable
+ };
+
+ /* Private Methods */
+
+ function renderDocument( doc, rawFirstParagraph ) {
var out = [];
for ( var b = 0, bMax = doc.blocks.length; b < bMax; b++ ) {
var block = doc.blocks[b];
- if ( block.type in WikitextRenderer.renderers ) {
+ if ( block.type in blockRenderers ) {
if ( block.type === 'paragraph' ) {
out.push(
-
WikitextRenderer.renderers.paragraph( block, rawFirstParagraph && b === 0 )
+ renderParagraph( block,
rawFirstParagraph && b === 0 )
);
if ( b + 1 < bMax /* && doc.blocks[b +
1].type === 'paragraph' */ ) {
out.push( '' );
}
} else {
- out.push(
WikitextRenderer.renderers[block.type]( block ) );
+ out.push( blockRenderers[block.type](
block ) );
}
}
}
return out.join( '\n' );
- },
- 'comment': HtmlRenderer.renderers.comment,
- 'rule': function( rule ) {
+ }
+
+ function renderComment( comment ) {
+ return '<!--' + comment.text + '-->';
+ }
+
+ function renderHorizontalRule( rule ) {
return '----';
- },
- 'heading': function( heading ) {
- var symbols = repeat( '=', heading.level );
- return symbols + WikitextRenderer.renderers.line( heading.line
) + symbols;
- },
- 'paragraph': function( paragraph ) {
+ }
+
+ function renderHeading( heading ) {
+ var symbols = wiki.util.str.repeat( '=', heading.level );
+ return symbols + renderLine( heading.line ) + symbols;
+ }
+
+ function renderParagraph( paragraph ) {
var out = [];
for ( var l = 0, lMax = paragraph.lines.length; l < lMax; l++ )
{
- out.push( WikitextRenderer.renderers.line(
paragraph.lines[l] ) );
+ out.push( renderLine( paragraph.lines[l] ) );
}
return out.join( '\n' );
- },
- 'list': function( list, path ) {
+ }
+
+ function renderList( list, path ) {
if ( typeof path === 'undefined' ) {
path = '';
}
@@ -255,17 +306,18 @@
path += symbols[list.style];
var out = [];
for ( var i = 0, iMax = list.items.length; i < iMax; i++ ) {
- out.push( WikitextRenderer.renderers.item(
list.items[i], path ) );
+ out.push( renderItem( list.items[i], path ) );
}
return out.join( '\n' );
- },
- 'table': function( table ) {
+ }
+
+ function renderTable( table ) {
var out = [];
var types = {
'heading': '!',
'data': '|'
};
- out.push( '{|' + Xml.attr( table.attributes ) );
+ out.push( '{|' + wiki.util.xml.attr( table.attributes ) );
for ( var r = 0, rMax = table.rows.length; r < rMax; r++ ) {
var row = table.rows[r];
if ( r ) {
@@ -275,57 +327,110 @@
var type = types[row[c].type || 'data'];
out.push(
type
- + ( row[c].attributes ? Xml.attr(
row[c].attributes ) + '|' : '' )
- + WikitextRenderer.renderers.document(
row[c].document, true )
+ + ( row[c].attributes ?
wiki.util.xml.attr( row[c].attributes ) + '|' : '' )
+ + renderDocument( row[c].document, true
)
);
}
}
out.push( '|}' );
return out.join( '\n' );
- },
- 'item': function( item, path ) {
+ }
+
+ function renderItem( item, path ) {
if ( 'lists' in item && item.lists.length ) {
var out = [];
- out.push( path + ' ' + WikitextRenderer.renderers.line(
item.line ) );
+ out.push( path + ' ' + renderLine( item.line ) );
for ( var l = 0, lMax = item.lists.length; l < lMax;
l++ ) {
- out.push( WikitextRenderer.renderers.list(
item.lists[l], path ) );
+ out.push( renderList( item.lists[l], path ) );
}
return out.join( '\n' );
} else {
- return path + ' ' + WikitextRenderer.renderers.line(
item.line );
+ return path + ' ' + renderLine( item.line );
}
- },
- 'line': function( line ) {
+ }
+
+ function renderLine( line ) {
if ( 'annotations' in line && line.annotations.length ) {
- var as = new AnnotationSerialization();
+ var ar = new wiki.AnnotationRenderer();
for ( var a = 0, aMax = line.annotations.length; a <
aMax; a++ ) {
var an = line.annotations[a];
switch ( an.type ) {
case 'bold':
- as.wrapWithText( an.range,
'\'\'\'', '\'\'\'' );
+ ar.wrapWithText( an.range,
'\'\'\'', '\'\'\'' );
break;
case 'italic':
- as.wrapWithText( an.range,
'\'\'', '\'\'' );
+ ar.wrapWithText( an.range,
'\'\'', '\'\'' );
break;
case 'xlink':
- as.wrapWithText( an.range, '['
+ an.data.url + ' ', ']' );
+ ar.wrapWithText( an.range, '['
+ an.data.url + ' ', ']' );
break;
case 'ilink':
- as.wrapWithText( an.range, '[['
+ an.data.title + '|', ']]' );
+ ar.wrapWithText( an.range, '[['
+ an.data.title + '|', ']]' );
break;
}
}
- return as.apply( line.text );
+ return ar.apply( line.text );
} else {
return line.text;
}
}
-};
-/* Parsers */
+ /* Methods */
-function WikitextParser() { }
+ this.render = function( doc ) {
+ return renderDocument( doc );
+ };
+};
-WikitextParser.prototype.parse = function( text ) {
- //
+/**
+ * Utilities used by WikiDom renderers and parsers.
+ */
+wiki.util = {
+ 'str': {
+ 'repeat': function( pattern, count ) {
+ if ( count < 1 ) return '';
+ var result = '';
+ while ( count > 0 ) {
+ if ( count & 1 ) result += pattern;
+ count >>= 1, pattern += pattern;
+ };
+ return result;
+ }
+ },
+ 'xml': {
+ 'esc': function( text ) {
+ return text
+ .replace( /&/g, '&' )
+ .replace( /</g, '<' )
+ .replace( />/g, '>' )
+ .replace( /"/g, '"' )
+ .replace( /'/g, ''' );
+ },
+ 'attr': function( attributes ) {
+ var attr = '';
+ if ( attributes ) {
+ for ( var name in attributes ) {
+ attr += ' ' + name + '="' +
attributes[name] + '"';
+ }
+ }
+ return attr;
+ },
+ 'open': function( tag, attributes ) {
+ return '<' + tag + wiki.util.xml.attr( attributes ) +
'>';
+ },
+ 'close': function( tag ) {
+ return '</' + tag + '>';
+ },
+ 'tag': function( tag, attributes, value, escape ) {
+ if ( value === false ) {
+ return '<' + tag + wiki.util.xml.attr(
attributes ) + ' />';
+ } else {
+ if ( escape ) {
+ value = wiki.util.xml.esc( value );
+ }
+ return '<' + tag + wiki.util.xml.attr(
attributes ) + '>' + value
+ + '</' + tag + '>';
+ }
+ }
+ }
};
_______________________________________________
MediaWiki-CVS mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs