Index: trunk/extensions/VisualEditor/tests/parser/parserTests.js |
— | — | @@ -63,7 +63,7 @@ |
64 | 64 | _import(pj('parser', 'mediawiki.HTML5TreeBuilder.node.js'), ['FauxHTML5']); |
65 | 65 | _import(pj('parser', 'mediawiki.DOMPostProcessor.js'), ['DOMPostProcessor']); |
66 | 66 | |
67 | | -_import(pj('parser', 'mediawiki.DOMConverter'), ['DOMConverter']); |
| 67 | +_import(pj('parser', 'mediawiki.DOMConverter.js'), ['DOMConverter']); |
68 | 68 | |
69 | 69 | _import(pj('parser', 'ext.core.QuoteTransformer.js'), ['QuoteTransformer']); |
70 | 70 | |
Index: trunk/extensions/VisualEditor/modules/parser/mediawiki.HTML5TreeBuilder.node.js |
— | — | @@ -55,6 +55,9 @@ |
56 | 56 | this.emit('token', {type: 'StartTag', |
57 | 57 | name: token.name, |
58 | 58 | data: att(token.attribs)}); |
| 59 | + this.emit('token', {type: 'EndTag', |
| 60 | + name: token.name, |
| 61 | + data: att(token.attribs)}); |
59 | 62 | break; |
60 | 63 | case "COMMENT": |
61 | 64 | this.emit('token', {type: 'Comment', |
— | — | @@ -62,7 +65,6 @@ |
63 | 66 | break; |
64 | 67 | case "END": |
65 | 68 | this.emit('end'); |
66 | | - console.log("at end.."); |
67 | 69 | this.document = this.parser.document; |
68 | 70 | if ( ! this.document.body ) { |
69 | 71 | // HACK: This should not be needed really. |
Index: trunk/extensions/VisualEditor/modules/parser/mediawiki.DOMConverter.js |
— | — | @@ -178,7 +178,7 @@ |
179 | 179 | case Node.ELEMENT_NODE: |
180 | 180 | // Call a handler for the particular node type |
181 | 181 | var hi = this.getHTMLHandlerInfo( cnode.nodeName ); |
182 | | - var res = hi.handler.call(this, cnode, 0, hi.type ); |
| 182 | + var res = hi.handler.call(this, cnode, hi.type ); |
183 | 183 | if ( hi.attribs ) { |
184 | 184 | $.extend( res.node.attributes, hi.attribs ); |
185 | 185 | } |
— | — | @@ -208,15 +208,17 @@ |
209 | 209 | * @param {Int} WikiDom offset within a block |
210 | 210 | * @returns {Object} WikiDom object |
211 | 211 | */ |
212 | | -DOMConverter.prototype._convertHTMLBranch = function ( node, offset, type ) { |
| 212 | +DOMConverter.prototype._convertHTMLBranch = function ( node, type ) { |
| 213 | + |
213 | 214 | var children = node.childNodes, |
214 | 215 | wnode = { |
215 | 216 | type: type, |
216 | 217 | attributes: this._HTMLPropertiesToWikiAttributes( node ), |
217 | 218 | children: [] |
218 | | - }; |
219 | | - |
220 | | - var parNode = null; |
| 219 | + }, |
| 220 | + parNode = null, |
| 221 | + offset = 0, |
| 222 | + res; |
221 | 223 | |
222 | 224 | function newPara () { |
223 | 225 | offset = 0; |
— | — | @@ -238,29 +240,29 @@ |
239 | 241 | var annotationtype = this.getHTMLAnnotationType( cnode.nodeName ); |
240 | 242 | if ( annotationtype ) { |
241 | 243 | if ( !parNode ) { |
242 | | - newPara() |
| 244 | + newPara(); |
243 | 245 | } |
244 | | - var res = this._convertHTMLAnnotation( cnode, offset, annotationtype ); |
| 246 | + offset = 0; |
| 247 | + res = this._convertHTMLAnnotation( cnode, 0, annotationtype ); |
245 | 248 | //console.log( 'res leaf: ' + JSON.stringify(res, null, 2)); |
246 | 249 | offset += res.text.length; |
247 | 250 | parNode.content.text += res.text; |
248 | 251 | //console.log( 'res annotations: ' + JSON.stringify(res, null, 2)); |
249 | 252 | parNode.content.annotations = parNode.content.annotations |
250 | 253 | .concat( res.annotations ); |
251 | | - break; |
252 | 254 | } else { |
253 | 255 | // Close last paragraph, if still open. |
254 | 256 | parNode = null; |
255 | 257 | // Call a handler for the particular node type |
256 | 258 | var hi = this.getHTMLHandlerInfo( cnode.nodeName ); |
257 | | - var res = hi.handler.call(this, cnode, 0, hi.type ); |
| 259 | + res = hi.handler.call(this, cnode, hi.type ); |
258 | 260 | if ( hi.attribs ) { |
259 | 261 | $.extend( res.node.attributes, hi.attribs ); |
260 | 262 | } |
261 | 263 | wnode.children.push( res.node ); |
262 | 264 | offset = res.offset; |
263 | | - break; |
264 | 265 | } |
| 266 | + break; |
265 | 267 | case Node.TEXT_NODE: |
266 | 268 | if ( !parNode ) { |
267 | 269 | newPara(); |
— | — | @@ -290,9 +292,8 @@ |
291 | 293 | * @param {Int} WikiDom offset within a block |
292 | 294 | * @returns {Object} WikiDom object |
293 | 295 | */ |
294 | | -DOMConverter.prototype._convertHTMLLeaf = function ( node, offset, type ) { |
295 | | - // XXX Does the offset in every leaf start at zero? |
296 | | - offset = 0; |
| 296 | +DOMConverter.prototype._convertHTMLLeaf = function ( node, type ) { |
| 297 | + var offset = 0; |
297 | 298 | |
298 | 299 | var children = node.childNodes, |
299 | 300 | wnode = { |
— | — | @@ -394,7 +395,6 @@ |
395 | 396 | for ( var i = 0, l = attribs.length; i < l; i++ ) { |
396 | 397 | var attrib = attribs.item(i), |
397 | 398 | key = attrib.name; |
398 | | - console.log('key: ' + key); |
399 | 399 | if ( key.match( /^data-json-/ ) ) { |
400 | 400 | // strip data- prefix from data-* |
401 | 401 | out[key.replace( /^data-json-/, '' )] = JSON.parse(attrib.value); |
— | — | @@ -426,6 +426,9 @@ |
427 | 427 | // XXX: This subsets html DOM |
428 | 428 | if ( ['title'].indexOf(key) != -1 ) { |
429 | 429 | out[key] = attrib.value; |
| 430 | + } else { |
| 431 | + // prefix key with 'html/' |
| 432 | + out['html/' + key] = attrib.value; |
430 | 433 | } |
431 | 434 | } |
432 | 435 | } |
Index: trunk/extensions/VisualEditor/modules/parser/pegTokenizer.pegjs.txt |
— | — | @@ -643,9 +643,12 @@ |
644 | 644 | = "{{" target:template_target |
645 | 645 | params:(newline? "|" newline? p:template_param { return p })* |
646 | 646 | "}}" { |
647 | | - var obj = { type: 'TAG', name: 'template', |
648 | | - attribs: [['data-target', target]], |
649 | | - args: {}} |
| 647 | + var obj = { |
| 648 | + type: 'SELFCLOSINGTAG', |
| 649 | + name: 'template', |
| 650 | + attribs: [['data-target', target]], |
| 651 | + args: {} |
| 652 | + }; |
650 | 653 | if (params && params.length) { |
651 | 654 | var position = 1; |
652 | 655 | for ( var i = 0, l = params.length; i < l; i++ ) { |
— | — | @@ -706,18 +709,19 @@ |
707 | 710 | wikilink |
708 | 711 | = "[[" |
709 | 712 | ! url |
710 | | - target:link_target text:("|" lt:link_text { return lt })* "]]" suffix:text? { |
| 713 | + target:link_target ltext:("|" lt:link_text { return lt })* "]]" |
| 714 | + suffix:(![ \]] text_char)* { |
711 | 715 | var obj = { |
712 | 716 | type: 'TAG', |
713 | 717 | name: 'a', |
714 | 718 | attribs: [['data-type', 'internal']] |
715 | 719 | }; |
716 | 720 | obj.attribs.push(['href', target]); |
717 | | - if (text && text.length) { |
718 | | - var textTokens = text; |
| 721 | + if (ltext && ltext.length) { |
| 722 | + var textTokens = ltext; |
719 | 723 | } else { |
720 | | - if (suffix !== '') { |
721 | | - target += suffix; |
| 724 | + if (suffix) { |
| 725 | + target += suffix.join(''); |
722 | 726 | } |
723 | 727 | var textTokens = [{type: 'TEXT', value: target}]; |
724 | 728 | } |
— | — | @@ -735,13 +739,13 @@ |
736 | 740 | )* { return h.join(''); } |
737 | 741 | |
738 | 742 | link_text |
739 | | - = h:( & { return setFlag('linkdesc'); } |
740 | | - x:inlineline { return x } |
741 | | - )* { |
742 | | - clearFlag('linkdesc') |
743 | | - return h; |
744 | | - } |
745 | | - / & { clearFlag('linkdesc') } { return null; } |
| 743 | + = & { return setFlag('linkdesc'); } |
| 744 | + h:inlineline |
| 745 | + { |
| 746 | + clearFlag('linkdesc'); |
| 747 | + return h; |
| 748 | + } |
| 749 | + / & { clearFlag('linkdesc'); return false } |
746 | 750 | |
747 | 751 | link_end = "]]" |
748 | 752 | |
— | — | @@ -1002,7 +1006,7 @@ |
1003 | 1007 | } |
1004 | 1008 | |
1005 | 1009 | table_firstrow |
1006 | | - = td:table_data+ { |
| 1010 | + = td:(table_data / table_header)+ { |
1007 | 1011 | //dp('firstrow: ' + pp(td)); |
1008 | 1012 | return [{ type: 'TAG', name: 'tr' }] |
1009 | 1013 | .concat(td, [{type: 'ENDTAG', name: 'tr'}]); |
Index: trunk/extensions/VisualEditor/modules/parser/ext.Cite.js |
— | — | @@ -7,6 +7,8 @@ |
8 | 8 | function Cite () { |
9 | 9 | this.refGroups = {}; |
10 | 10 | this.refTokens = []; |
| 11 | + // Within ref block |
| 12 | + this.isActive = false; |
11 | 13 | } |
12 | 14 | |
13 | 15 | /** |
— | — | @@ -111,17 +113,27 @@ |
112 | 114 | |
113 | 115 | var token = tokenCTX.token; |
114 | 116 | // Collect all tokens between ref start and endtag |
115 | | - if ( token.type === 'TAG' && token.name.toLowerCase() === 'ref' ) { |
| 117 | + if ( ! this.isActive && |
| 118 | + token.type === 'TAG' && |
| 119 | + token.name.toLowerCase() === 'ref' ) { |
116 | 120 | this.curRef = tokenCTX.token; |
117 | 121 | // Prepend self for 'any' token type |
118 | 122 | tokenCTX.dispatcher.prependListener(this.onRefCB, 'any' ); |
119 | 123 | tokenCTX.token = null; |
| 124 | + this.isActive = true; |
120 | 125 | return tokenCTX; |
121 | | - } else if ( token.type === 'ENDTAG' && token.name.toLowerCase() === 'ref' ) { |
| 126 | + } else if ( this.isActive && |
| 127 | + // Also accept really broken ref close tags.. |
| 128 | + ['TAG', 'ENDTAG', 'SELFCLOSINGTAG'].indexOf(token.type) >= 0 && |
| 129 | + token.name.toLowerCase() === 'ref' |
| 130 | + ) |
| 131 | + { |
| 132 | + this.isActive = false; |
122 | 133 | tokenCTX.dispatcher.removeListener(this.onRefCB, 'any' ); |
123 | 134 | // fall through for further processing! |
124 | 135 | } else { |
125 | 136 | // Inside ref block: Collect all other tokens in refTokens and abort |
| 137 | + console.log(JSON.stringify(tokenCTX.token, null, 2)); |
126 | 138 | this.refTokens.push(tokenCTX.token); |
127 | 139 | tokenCTX.token = null; |
128 | 140 | return tokenCTX; |
— | — | @@ -287,8 +299,9 @@ |
288 | 300 | // Clean up |
289 | 301 | this.refGroups = {}; |
290 | 302 | this.refTokens = []; |
| 303 | + this.isActive = false; |
291 | 304 | return tokenCTX; |
292 | | -} |
| 305 | +}; |
293 | 306 | |
294 | 307 | if (typeof module == "object") { |
295 | 308 | module.exports.Cite = Cite; |