Index: trunk/extensions/VisualEditor/modules/parser/mediawiki.TokenTransformManager.js |
— | — | @@ -780,10 +780,10 @@ |
781 | 781 | // transform the key |
782 | 782 | pipe = this.manager.getAttributePipeline( this.manager.inputType, |
783 | 783 | this.manager.args ); |
784 | | - pipe.addListener( 'chunk', |
| 784 | + pipe.on( 'chunk', |
785 | 785 | this.onChunk.bind( this, this._returnAttributeKey.bind( this, i ) ) |
786 | 786 | ); |
787 | | - pipe.addListener( 'end', |
| 787 | + pipe.on( 'end', |
788 | 788 | this.onEnd.bind( this, this._returnAttributeKey.bind( this, i ) ) |
789 | 789 | ); |
790 | 790 | pipe.process( attributes[i].k.concat([{type:'END'}]) ); |
— | — | @@ -798,10 +798,10 @@ |
799 | 799 | // transform the value |
800 | 800 | pipe = this.manager.getAttributePipeline( this.manager.inputType, |
801 | 801 | this.manager.args ); |
802 | | - pipe.addListener( 'chunk', |
| 802 | + pipe.on( 'chunk', |
803 | 803 | this.onChunk.bind( this, this._returnAttributeValue.bind( this, i ) ) |
804 | 804 | ); |
805 | | - pipe.addListener( 'end', |
| 805 | + pipe.on( 'end', |
806 | 806 | this.onEnd.bind( this, this._returnAttributeValue.bind( this, i ) ) |
807 | 807 | ); |
808 | 808 | //console.warn('starting attribute transform of ' + JSON.stringify( attributes[i].v ) ); |
Index: trunk/extensions/VisualEditor/modules/parser/ext.Util.js |
— | — | @@ -47,7 +47,7 @@ |
48 | 48 | case 'dl': |
49 | 49 | case 'dt': |
50 | 50 | case 'dd': |
51 | | - case 'img': // hmm! |
| 51 | + //case 'img': // hmm! |
52 | 52 | case 'pre': |
53 | 53 | case 'center': |
54 | 54 | case 'blockquote': |
Index: trunk/extensions/VisualEditor/modules/parser/pegTokenizer.pegjs.txt |
— | — | @@ -566,10 +566,7 @@ |
567 | 567 | urllink |
568 | 568 | = ! { return syntaxFlags['extlink'] } |
569 | 569 | target:url { |
570 | | - return [ new TagTk( 'a', [new KV('href', target)] ) |
571 | | - , target |
572 | | - , new EndTagTk( 'a' ) |
573 | | - ]; |
| 570 | + return [ new TagTk( 'urllink', [new KV('href', target)] ) ]; |
574 | 571 | } |
575 | 572 | |
576 | 573 | extlink |
— | — | @@ -588,15 +585,12 @@ |
589 | 586 | text = [ "[" + linkCount + "]" ]; |
590 | 587 | linkCount++; |
591 | 588 | } |
592 | | - var res = [ |
593 | | - new TagTk( 'a', [ |
594 | | - new KV('href', target), |
595 | | - new KV('data-mw-type', 'external') |
596 | | - ] ), |
597 | | - ].concat( text |
598 | | - , [ new EndTagTk( 'a' )]); |
599 | | - //console.warn( JSON.stringify( res, null, 2 ) ); |
600 | | - return res; |
| 589 | + return [ |
| 590 | + new SelfclosingTagTk( 'extlink', [ |
| 591 | + new KV('href', target), |
| 592 | + new KV('content', text) |
| 593 | + ] ) |
| 594 | + ]; |
601 | 595 | } |
602 | 596 | / "[" & { clearFlag('extlink'); return false; } |
603 | 597 | ) |
— | — | @@ -765,7 +759,7 @@ |
766 | 760 | target:wikilink_preprocessor_text |
767 | 761 | lcontent:( |
768 | 762 | & { return posStack.push('lcontent' , pos); } |
769 | | - lcs:( "|" lt:link_text { return lt; } )+ { |
| 763 | + lcs:( "|" lt:link_text { return new KV( '', lt ); } )+ { |
770 | 764 | return { pos: posStack.pop('lcontent' , pos), content: lcs }; |
771 | 765 | } |
772 | 766 | |
— | — | @@ -780,7 +774,7 @@ |
781 | 775 | tail:( ![A-Z \t(),.:-] tc:text_char { return tc } )* { |
782 | 776 | var obj = new SelfclosingTagTk( 'wikilink' ), |
783 | 777 | textTokens = []; |
784 | | - obj.attribs.push( new KV('href', target) ); |
| 778 | + obj.attribs.push( new KV('', target) ); |
785 | 779 | obj.dataAttribs = { |
786 | 780 | sourcePos: posStack.pop( 'wikilink', pos ), |
787 | 781 | contentPos: lcontent.pos |
— | — | @@ -790,10 +784,10 @@ |
791 | 785 | |
792 | 786 | //console.warn('lcontent: ' + JSON.stringify( lcontent, null, 2 ) ); |
793 | 787 | // Deal with content. XXX: Properly support pipe-trick etc |
794 | | - lcontent.tail = tail && tail.join('') || ''; |
| 788 | + //lcontent.tail = tail && tail.join('') || ''; |
795 | 789 | |
796 | | - obj.attribs.push( new KV( 'content', lcontent.content ) ); |
797 | | - obj.attribs.push( new KV( 'tail', lcontent.tail ) ); |
| 790 | + obj.attribs = obj.attribs.concat( lcontent.content ); |
| 791 | + obj.attribs.push( new KV( 'tail', tail && tail.join('') || '' ) ); |
798 | 792 | //console.warn( "XXX:" + pp([obj].concat(textTokens, [new EndTagTk( 'a' )])) ); |
799 | 793 | return [obj]; |
800 | 794 | } |
Index: trunk/extensions/VisualEditor/modules/parser/ext.core.LinkHandler.js |
— | — | @@ -25,7 +25,7 @@ |
26 | 26 | |
27 | 27 | WikiLinkHandler.prototype.onWikiLink = function ( token, manager, cb ) { |
28 | 28 | var env = this.manager.env, |
29 | | - href = env.lookupKV( token.attribs, 'href' ).v, |
| 29 | + href = token.attribs[0].v, |
30 | 30 | tail = env.lookupKV( token.attribs, 'tail' ).v; |
31 | 31 | var title = this.manager.env.makeTitleFromPrefixedText( |
32 | 32 | env.tokensToString( href ) |
— | — | @@ -41,13 +41,13 @@ |
42 | 42 | // |
43 | 43 | //console.warn( 'title: ' + JSON.stringify( title ) ); |
44 | 44 | var obj = new TagTk( 'a', [ new KV( 'href', title.makeLink() ) ] ), |
45 | | - content = this.manager.env.lookupKV( token.attribs, 'content' ).v; |
| 45 | + content = token.attribs.slice(1, -1); |
46 | 46 | //console.warn('content: ' + JSON.stringify( content, null, 2 ) ); |
47 | 47 | // XXX: handle trail |
48 | 48 | if ( content.length ) { |
49 | 49 | var out = [] |
50 | 50 | for ( var i = 0, l = content.length; i < l ; i++ ) { |
51 | | - out = out.concat( content[i] ); |
| 51 | + out = out.concat( content[i].v ); |
52 | 52 | if ( i < l - 1 ) { |
53 | 53 | out.push( '|' ); |
54 | 54 | } |
— | — | @@ -103,7 +103,7 @@ |
104 | 104 | // distinguish media types |
105 | 105 | // if image: parse options |
106 | 106 | |
107 | | - var content = env.lookupKV( token.attribs, 'content' ).v; |
| 107 | + var content = token.attribs.slice(1, -1); |
108 | 108 | |
109 | 109 | // XXX: get /wiki from config! |
110 | 110 | var a = new TagTk( 'a', [ new KV( 'href', '/wiki' + title.makeLink() ) ] ); |
— | — | @@ -188,6 +188,80 @@ |
189 | 189 | } |
190 | 190 | }; |
191 | 191 | |
| 192 | + |
| 193 | +function ExternalLinkHandler( manager, isInclude ) { |
| 194 | + this.manager = manager; |
| 195 | + this.manager.addTransform( this.onUrlLink.bind( this ), this.rank, 'tag', 'urllink' ); |
| 196 | + this.manager.addTransform( this.onExtLink.bind( this ), |
| 197 | + this.rank, 'tag', 'extlink' ); |
| 198 | + // create a new peg parser for image options.. |
| 199 | + if ( !this.imageParser ) { |
| 200 | + // Actually the regular tokenizer, but we'll call it with the |
| 201 | + // img_options production only. |
| 202 | + ExternalLinkHandler.prototype.imageParser = new PegTokenizer(); |
| 203 | + } |
| 204 | +} |
| 205 | + |
| 206 | +ExternalLinkHandler.prototype.rank = 1.15; |
| 207 | +ExternalLinkHandler.prototype._imageExtensions = { |
| 208 | + 'jpg': true, |
| 209 | + 'png': true, |
| 210 | + 'gif': true |
| 211 | +}; |
| 212 | + |
| 213 | +ExternalLinkHandler.prototype._isImageLink = function ( href ) { |
| 214 | + var bits = href.split( '.' ); |
| 215 | + return bits.length > 1 && |
| 216 | + this._imageExtensions[ bits[bits.length - 1] ] && |
| 217 | + href.substr(0, 4) === 'http'; |
| 218 | +}; |
| 219 | + |
| 220 | +ExternalLinkHandler.prototype.onUrlLink = function ( token, manager, cb ) { |
| 221 | + var href = this.manager.env.lookupKV( token.attribs, 'href' ).v; |
| 222 | + if ( this._isImageLink( href ) ) { |
| 223 | + return { token: new SelfclosingTagTk( 'img', |
| 224 | + [ |
| 225 | + new KV( 'alt', href.split('/').last() ), |
| 226 | + new KV( 'src', href ), |
| 227 | + ] |
| 228 | + ) |
| 229 | + }; |
| 230 | + } else { |
| 231 | + return { |
| 232 | + tokens: [ |
| 233 | + new TagTk( 'a', [ new KV( 'href', href ) ] ), |
| 234 | + href, |
| 235 | + new EndTagTk( 'a' ) |
| 236 | + ] |
| 237 | + }; |
| 238 | + } |
| 239 | +}; |
| 240 | + |
| 241 | +// Bracketed external link |
| 242 | +ExternalLinkHandler.prototype.onExtLink = function ( token, manager, cb ) { |
| 243 | + var href = this.manager.env.lookupKV( token.attribs, 'href' ).v, |
| 244 | + content= this.manager.env.lookupKV( token.attribs, 'content' ).v; |
| 245 | + // validate the href |
| 246 | + if ( this.imageParser.parseURL( href ) ) { |
| 247 | + return { |
| 248 | + tokens: |
| 249 | + [ |
| 250 | + |
| 251 | + new TagTk( 'a', [ |
| 252 | + new KV('href', href), |
| 253 | + new KV('data-mw-type', 'external') |
| 254 | + ] ), |
| 255 | + ].concat( content, [ new EndTagTk( 'a' )]) |
| 256 | + }; |
| 257 | + } else { |
| 258 | + return { |
| 259 | + tokens: ['[', href ].concat( content, [']'] ) |
| 260 | + }; |
| 261 | + } |
| 262 | +}; |
| 263 | + |
| 264 | + |
192 | 265 | if (typeof module == "object") { |
193 | 266 | module.exports.WikiLinkHandler = WikiLinkHandler; |
| 267 | + module.exports.ExternalLinkHandler = ExternalLinkHandler; |
194 | 268 | } |
Index: trunk/extensions/VisualEditor/modules/parser/mediawiki.tokenizer.peg.js |
— | — | @@ -71,6 +71,14 @@ |
72 | 72 | return this.parser.parse(text, 'img_options', null, this ); |
73 | 73 | }; |
74 | 74 | |
| 75 | +PegTokenizer.prototype.parseURL = function( text ) { |
| 76 | + try { |
| 77 | + return this.parser.parse(text, 'url', null, this ); |
| 78 | + } catch ( e ) { |
| 79 | + return false; |
| 80 | + } |
| 81 | +}; |
| 82 | + |
75 | 83 | /* |
76 | 84 | * Inline breaks, flag-enabled production which detects end positions for |
77 | 85 | * active higher-level productions in inline and other nested productions. |
Index: trunk/extensions/VisualEditor/modules/parser/mediawiki.parser.js |
— | — | @@ -26,7 +26,9 @@ |
27 | 27 | Sanitizer = require('./ext.core.Sanitizer.js').Sanitizer, |
28 | 28 | TemplateHandler = require('./ext.core.TemplateHandler.js').TemplateHandler, |
29 | 29 | AttributeExpander = require('./ext.core.AttributeExpander.js').AttributeExpander, |
30 | | - WikiLinkHandler = require('./ext.core.LinkHandler.js').WikiLinkHandler, |
| 30 | + LinkHandler = require('./ext.core.LinkHandler.js'), |
| 31 | + WikiLinkHandler = LinkHandler.WikiLinkHandler, |
| 32 | + ExternalLinkHandler = LinkHandler.ExternalLinkHandler, |
31 | 33 | Cite = require('./ext.Cite.js').Cite, |
32 | 34 | FauxHTML5 = require('./mediawiki.HTML5TreeBuilder.node.js').FauxHTML5, |
33 | 35 | DOMPostProcessor = require('./mediawiki.DOMPostProcessor.js').DOMPostProcessor, |
— | — | @@ -167,7 +169,8 @@ |
168 | 170 | // XXX: Should we support further processing after attribute |
169 | 171 | // expansion? |
170 | 172 | AttributeExpander, |
171 | | - WikiLinkHandler |
| 173 | + WikiLinkHandler, |
| 174 | + ExternalLinkHandler |
172 | 175 | /* ExtensionHandler1, */ |
173 | 176 | /* ExtensionHandler2, */ |
174 | 177 | ], |