Pastakhov has uploaded a new change for review. https://gerrit.wikimedia.org/r/249357
Change subject: merge to branch master (v 3.2.1) ...................................................................... merge to branch master (v 3.2.1) Bug: T116829 Change-Id: Id5e434eca4840e6ce9841f43e1299970a61ba8cc --- M CodeMirror.hooks.php M CodeMirror.php M i18n/ast.json A i18n/bn.json M i18n/de.json M i18n/es.json M i18n/fr.json M i18n/gl.json A i18n/gu.json M i18n/it.json A i18n/lb.json M i18n/mk.json M i18n/nl.json M i18n/ru.json M i18n/uk.json A i18n/xmf.json M i18n/zh-hans.json M i18n/zh-hant.json M resources/ext.CodeMirror.js M resources/mode/mediawiki/mediawiki.css M resources/mode/mediawiki/mediawiki.js 21 files changed, 270 insertions(+), 73 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/CodeMirror refs/changes/57/249357/1 diff --git a/CodeMirror.hooks.php b/CodeMirror.hooks.php index dcd6421..ab74eba 100644 --- a/CodeMirror.hooks.php +++ b/CodeMirror.hooks.php @@ -19,7 +19,10 @@ * @return bool Always true */ public static function onResourceLoaderRegisterModules( ResourceLoader $rl ) { - global $wgCodeMirrorResourceTemplate; + $codeMirrorResourceTemplate = array( + 'localBasePath' => __DIR__ . '/resources', + 'remoteExtPath' => 'CodeMirror/resources', + ); self::$extModes = array( 'tag' => array( @@ -53,7 +56,7 @@ 'messages' => array_keys( $extResources['messages'] ), 'dependencies' => array_keys( $extResources['dependencies'] ), 'group' => 'ext.CodeMirror', - ) + $wgCodeMirrorResourceTemplate; + ) + $codeMirrorResourceTemplate; $rl->register( array( 'ext.CodeMirror.other' => $codeMirror ) ); diff --git a/CodeMirror.php b/CodeMirror.php index 6cc452a..d360d17 100644 --- a/CodeMirror.php +++ b/CodeMirror.php @@ -15,7 +15,7 @@ die( 'This file is an extension to MediaWiki and thus not a valid entry point.' ); } -const EXT_CODEMIRROR_VERSION = '3.1.10'; +const EXT_CODEMIRROR_VERSION = '3.2.1'; // Register this extension on Special:Version $wgExtensionCredits['parserhook'][] = array( diff --git a/i18n/ast.json b/i18n/ast.json index 0046d20..6068f11 100644 --- a/i18n/ast.json +++ b/i18n/ast.json @@ -4,5 +4,7 @@ "Xuacu" ] }, - "codemirror-desc": "Ufre sintaxis resaltada nel editor de testu wiki" + "codemirror-desc": "Ufre sintaxis resaltada nel editor de testu wiki", + "codemirror-enable-label": "Activar CodeMirror (resaltáu de sintaxis)", + "codemirror-disable-label": "Desactivar CodeMirror (resaltáu de sintaxis)" } diff --git a/i18n/bn.json b/i18n/bn.json new file mode 100644 index 0000000..1ee6ac4 --- /dev/null +++ b/i18n/bn.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Aftabuzzaman" + ] + }, + "codemirror-enable-label": "কোডমিরর সক্রিয় করো (সিনট্যাক্স হাইলাইট)", + "codemirror-disable-label": "কোডমিরর নিষ্ক্রিয় করো (সিনট্যাক্স হাইলাইট)" +} diff --git a/i18n/de.json b/i18n/de.json index 72ec6e3..bf37de0 100644 --- a/i18n/de.json +++ b/i18n/de.json @@ -4,5 +4,7 @@ "Metalhead64" ] }, - "codemirror-desc": "Ermöglicht Syntax-Hervorhebungen im Wikitext-Editor" + "codemirror-desc": "Ermöglicht Syntax-Hervorhebungen im Wikitext-Editor", + "codemirror-enable-label": "CodeMirror aktivieren (Syntaxhervorhebung)", + "codemirror-disable-label": "CodeMirror deaktivieren (Syntaxhervorhebung)" } diff --git a/i18n/es.json b/i18n/es.json index 7dfd373..e12a4d5 100644 --- a/i18n/es.json +++ b/i18n/es.json @@ -1,8 +1,11 @@ { "@metadata": { "authors": [ - "Fitoschido" + "Fitoschido", + "Macofe" ] }, - "codemirror-desc": "Proporciona resalte de la sintaxis en el editor de código wiki" + "codemirror-desc": "Proporciona resalte de la sintaxis en el editor de código wiki", + "codemirror-enable-label": "Activar CodeMirror (resaltado de sintaxis)", + "codemirror-disable-label": "Desactivar CodeMirror (resaltado de sintaxis)" } diff --git a/i18n/fr.json b/i18n/fr.json index 2372a31..f245b2d 100644 --- a/i18n/fr.json +++ b/i18n/fr.json @@ -4,5 +4,7 @@ "Gomoko" ] }, - "codemirror-desc": "Fournit une mise en évidence de la syntaxe dans l’éditeur wikitexte" + "codemirror-desc": "Fournit une mise en évidence de la syntaxe dans l’éditeur wikitexte", + "codemirror-enable-label": "Activer CodeMirror (Syntaxhighlight)", + "codemirror-disable-label": "Désactiver CodeMirror (Syntaxhighlight)" } diff --git a/i18n/gl.json b/i18n/gl.json index e4c5a03..5894516 100644 --- a/i18n/gl.json +++ b/i18n/gl.json @@ -1,8 +1,11 @@ { "@metadata": { "authors": [ - "Banjo" + "Banjo", + "Toliño" ] }, - "codemirror-desc": "Provee resalte da sintaxe no editor de texto wiki" + "codemirror-desc": "Proporciona un resalte da sintaxe no editor de texto wiki", + "codemirror-enable-label": "Activar CodeMirror (resalte da sintaxe)", + "codemirror-disable-label": "Desactivar CodeMirror (resalte da sintaxe)" } diff --git a/i18n/gu.json b/i18n/gu.json new file mode 100644 index 0000000..7be2758 --- /dev/null +++ b/i18n/gu.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Nisargjhaveri" + ] + }, + "codemirror-enable-label": "CodeMirror (સિન્ટેક્ષ હાઇલાઇટ) ચાલુ કરો", + "codemirror-disable-label": "CodeMirror (સિન્ટેક્ષ હાઇલાઇટ) બંધ કરો" +} diff --git a/i18n/it.json b/i18n/it.json index 07720eb..33572bc 100644 --- a/i18n/it.json +++ b/i18n/it.json @@ -1,8 +1,11 @@ { "@metadata": { "authors": [ - "Beta16" + "Beta16", + "Statix64" ] }, - "codemirror-desc": "Fornisce l'evidenziazione della sintassi nell'editor wikitesto" + "codemirror-desc": "Fornisce l'evidenziazione della sintassi nell'editor wikitesto", + "codemirror-enable-label": "Attiva CodeMirror (Syntaxhighlight)", + "codemirror-disable-label": "Disattiva CodeMirror (Syntaxhighlight)" } diff --git a/i18n/lb.json b/i18n/lb.json new file mode 100644 index 0000000..7ed9f32 --- /dev/null +++ b/i18n/lb.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Robby" + ] + }, + "codemirror-enable-label": "CodeMirror aktivéieren (Syntaxhighlight)", + "codemirror-disable-label": "CodeMirror desaktivéieren (Syntaxhighlight)" +} diff --git a/i18n/mk.json b/i18n/mk.json index 10ab639..bfd567e 100644 --- a/i18n/mk.json +++ b/i18n/mk.json @@ -4,5 +4,7 @@ "Bjankuloski06" ] }, - "codemirror-desc": "Дава потцртување на синтаксата во уредувачот на викитекст" + "codemirror-desc": "Дава потцртување на синтаксата во уредувачот на викитекст", + "codemirror-enable-label": "Вклучи го CodeMirror (подвлекување на синтакса)", + "codemirror-disable-label": "Исклучи го CodeMirror (подвлекување на синтакса)" } diff --git a/i18n/nl.json b/i18n/nl.json index e248378..a8e189d 100644 --- a/i18n/nl.json +++ b/i18n/nl.json @@ -1,8 +1,9 @@ { "@metadata": { "authors": [ - "Esketti" + "Esketti", + "Siebrand" ] }, - "codemirror-desc": "Zorgt voor accentuering van de syntaxis in de wikitext editor" + "codemirror-desc": "Biedt accentuering van tekst in de wikitekst tekstverwerker" } diff --git a/i18n/ru.json b/i18n/ru.json index 8d51ac7..b8010e6 100644 --- a/i18n/ru.json +++ b/i18n/ru.json @@ -5,5 +5,7 @@ "Kaganer" ] }, - "codemirror-desc": "Обеспечивает подсветку синтаксиса в редакторе вики-текста." + "codemirror-desc": "Обеспечивает подсветку синтаксиса в редакторе вики-текста.", + "codemirror-enable-label": "Включить CodeMirror (подсветка синтаксиса)", + "codemirror-disable-label": "Выключить CodeMirror (подсветка синтаксиса)" } diff --git a/i18n/uk.json b/i18n/uk.json index 4662a44..3318c42 100644 --- a/i18n/uk.json +++ b/i18n/uk.json @@ -2,8 +2,11 @@ "@metadata": { "authors": [ "Andriykopanytsia", - "Ата" + "Ата", + "Dars" ] }, - "codemirror-desc": "Забезпечує підсвічування синтаксису у редакторі вікітексту" + "codemirror-desc": "Забезпечує підсвічування синтаксису у редакторі вікітексту", + "codemirror-enable-label": "Задіяти Дзеркало коду (Підсвічування синтаксису)", + "codemirror-disable-label": "Відключити Дзеркало коду (Підсвічування синтаксису)" } diff --git a/i18n/xmf.json b/i18n/xmf.json new file mode 100644 index 0000000..f68b754 --- /dev/null +++ b/i18n/xmf.json @@ -0,0 +1,8 @@ +{ + "@metadata": { + "authors": [ + "Silovan" + ] + }, + "codemirror-disable-label": "CodeMirror-იშ (Syntaxhighlight) გოთიშუა" +} diff --git a/i18n/zh-hans.json b/i18n/zh-hans.json index bf14717..7004f83 100644 --- a/i18n/zh-hans.json +++ b/i18n/zh-hans.json @@ -4,5 +4,7 @@ "Liuxinyu970226" ] }, - "codemirror-desc": "在wiki文本编辑器中提供语法高亮显示" + "codemirror-desc": "在wiki文本编辑器中提供语法高亮显示", + "codemirror-enable-label": "启用CodeMirror(Syntaxhighlight)", + "codemirror-disable-label": "禁用CodeMirror(Syntaxhighlight)" } diff --git a/i18n/zh-hant.json b/i18n/zh-hant.json index aa5369f..b5177fa 100644 --- a/i18n/zh-hant.json +++ b/i18n/zh-hant.json @@ -6,5 +6,7 @@ "Cwlin0416" ] }, - "codemirror-desc": "提供 wikitext 編輯器語法醒目標示" + "codemirror-desc": "提供 wikitext 編輯器語法醒目標示", + "codemirror-enable-label": "開啟 CodeMirror (強調語法顯示)", + "codemirror-disable-label": "關閉 CodeMirror (強調語法顯示)" } diff --git a/resources/ext.CodeMirror.js b/resources/ext.CodeMirror.js index a3e968e..4591f50 100644 --- a/resources/ext.CodeMirror.js +++ b/resources/ext.CodeMirror.js @@ -20,6 +20,10 @@ return codeMirror.doc.getValue(); }, + setContents: function ( newContents ) { + codeMirror.doc.setValue( newContents ); + }, + /** * Get the currently selected text in this textarea. Will focus the textarea * in some browsers (IE/Opera) @@ -232,7 +236,28 @@ } ); } - }; + }, + originHooksTextarea = $.valHooks.textarea; + + // define JQuery hook for searching and replacing text using JS if CodeMirror is enabled, see Bug: T108711 + $.valHooks.textarea = { + get: function( elem ) { + if ( elem.id === 'wpTextbox1' && codeMirror ) { + return codeMirror.doc.getValue(); + } else if ( originHooksTextarea ) { + return originHooksTextarea.get( elem ); + } + return elem.value; + }, + set: function( elem, value ) { + if ( elem.id === 'wpTextbox1' && codeMirror ) { + return codeMirror.doc.setValue( value ); + } else if ( originHooksTextarea ) { + return originHooksTextarea.set( elem, value ); + } + elem.value = value; + } + }; /** * Save CodeMirror enabled pref. diff --git a/resources/mode/mediawiki/mediawiki.css b/resources/mode/mediawiki/mediawiki.css index 197d764..aae2300 100644 --- a/resources/mode/mediawiki/mediawiki.css +++ b/resources/mode/mediawiki/mediawiki.css @@ -19,7 +19,7 @@ .cm-mw-indenting {color: #08f; font-weight: bold; background-color: #ddd;} .cm-mw-mnemonic {color: #090;} .cm-mw-comment {color: #aaa; font-weight: normal;} -.cm-mw-apostrophes {color: #08f;} +.cm-mw-apostrophes-bold, .cm-mw-apostrophes-italic {color: #08f;} pre.cm-mw-section-1 {font-size: 1.8em;} pre.cm-mw-section-2 {font-size: 1.5em;} diff --git a/resources/mode/mediawiki/mediawiki.js b/resources/mode/mediawiki/mediawiki.js index 6680168..303e035 100644 --- a/resources/mode/mediawiki/mediawiki.js +++ b/resources/mode/mediawiki/mediawiki.js @@ -22,23 +22,24 @@ CodeMirror.defineMode( 'mediawiki', function( config/*, parserConfig */ ) { - var urlProtocols = new RegExp( config.mwextUrlProtocols, 'i' ); - var permittedHtmlTags = {'b': true, 'bdi': true, 'del': true, 'i': true, 'ins': true, - 'u': true, 'font': true, 'big': true, 'small': true, 'sub': true, 'sup': true, - 'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true, 'cite': true, - 'code': true, 'em': true, 's': true, 'strike': true, 'strong': true, 'tt': true, - 'var': true, 'div': true, 'center': true, 'blockquote': true, 'ol': true, 'ul': true, - 'dl': true, 'table': true, 'caption': true, 'pre': true, 'ruby': true, 'rb': true, - 'rp': true, 'rt': true, 'rtc': true, 'p': true, 'span': true, 'abbr': true, 'dfn': true, - 'kbd': true, 'samp': true, 'data': true, 'time': true, 'mark': true, 'br': true, - 'wbr': true, 'hr': true, 'li': true, 'dt': true, 'dd': true, 'td': true, 'th': true, - 'tr': true, 'noinclude': true, 'includeonly': true, 'onlyinclude': true}; + var urlProtocols = new RegExp( config.mwextUrlProtocols, 'i' ), + permittedHtmlTags = {'b': true, 'bdi': true, 'del': true, 'i': true, 'ins': true, + 'u': true, 'font': true, 'big': true, 'small': true, 'sub': true, 'sup': true, + 'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true, 'cite': true, + 'code': true, 'em': true, 's': true, 'strike': true, 'strong': true, 'tt': true, + 'var': true, 'div': true, 'center': true, 'blockquote': true, 'ol': true, 'ul': true, + 'dl': true, 'table': true, 'caption': true, 'pre': true, 'ruby': true, 'rb': true, + 'rp': true, 'rt': true, 'rtc': true, 'p': true, 'span': true, 'abbr': true, 'dfn': true, + 'kbd': true, 'samp': true, 'data': true, 'time': true, 'mark': true, 'br': true, + 'wbr': true, 'hr': true, 'li': true, 'dt': true, 'dd': true, 'td': true, 'th': true, + 'tr': true, 'noinclude': true, 'includeonly': true, 'onlyinclude': true}, + isBold, isItalic, firstsingleletterword, firstmultiletterword, firstspace, mBold, mItalic, mTokens = [], mStyle; function makeStyle( style, state, endGround ) { - if ( state.isBold ) { + if ( isBold ) { style += ' strong'; } - if ( state.isItalic ) { + if ( isItalic ) { style += ' em'; } return makeLocalStyle( style, state, endGround ); @@ -268,7 +269,14 @@ state.tokenize = inExternalLinkText; return makeStyle( '', state ); } - if ( stream.match( /[^\s\u00a0\]\{\&~]+/ ) || stream.eatSpace() ) { + if ( stream.match( /[^\s\u00a0\]\{\&~']+/ ) || stream.eatSpace() ) { + if ( stream.peek() === '\'' ) { + if ( stream.match( '\'\'', false ) ) { + state.tokenize = inExternalLinkText; + } else { + stream.next(); + } + } return makeStyle( 'mw-extlink', state ); } return eatWikiText( 'mw-extlink', '' )( stream, state ); @@ -312,7 +320,7 @@ // if ( !stream.eatSpace() ) { // state.ImInBlock.push( 'LinkTrail' ); // } - } + } if ( stream.match( /[\s\u00a0]*[^\s\u00a0#\|\]\&~\{]+/ ) || stream.eatSpace() ) { //FIXME '{{' brokes Link, sample [[z{{page]] return makeStyle( 'mw-link-pagename mw-pagename', state ); } @@ -344,25 +352,25 @@ } function eatLinkText() { - var isBold, isItalic; + var linkIsBold, linkIsItalic; return function ( stream, state ) { if ( stream.match( ']]' ) ) { state.tokenize = state.stack.pop(); return makeLocalStyle( 'mw-link-bracket', state, 'nLink' ); } if ( stream.match( '\'\'\'' ) ) { - isBold = (isBold ? false : true); + linkIsBold = (linkIsBold ? false : true); return makeLocalStyle( 'mw-link-text mw-apostrophes', state ); } if ( stream.match( '\'\'' ) ) { - isItalic = (isItalic ? false : true); + linkIsItalic = (linkIsItalic ? false : true); return makeLocalStyle( 'mw-link-text mw-apostrophes', state ); } var tmpstyle = 'mw-link-text'; - if ( isBold ) { + if ( linkIsBold ) { tmpstyle += ' strong'; } - if ( isItalic ) { + if ( linkIsItalic ) { tmpstyle += ' em'; } if ( stream.match( /[^'\]\{\&~]+/ ) ) { @@ -390,7 +398,7 @@ state.tokenize = state.stack.pop(); return makeLocalStyle( (isHtmlTag ? 'mw-htmltag-name' : 'mw-exttag-name'), state ); } - + if ( isHtmlTag ) { if ( isCloseTag ) { state.tokenize = eatChar( '>', 'mw-htmltag-bracket' ); @@ -450,9 +458,10 @@ function eatExtTagArea( name ) { return function( stream, state ) { - var origString = false, from = stream.pos, to; - var pattern = new RegExp( '</' + name + '\\s*>' ); - var m = pattern.exec( from ? stream.string.slice( from ) : stream.string ); + var origString = false, from = stream.pos, to, + pattern = new RegExp( '</' + name + '\\s*>' ), + m = pattern.exec( from ? stream.string.slice( from ) : stream.string ); + if ( m ) { if ( m.index === 0 ) { state.tokenize = eatExtCloseTag( name ); @@ -467,6 +476,7 @@ origString = stream.string; stream.string = origString.slice( 0, to ); } + state.stack.push( state.tokenize ); state.tokenize = eatExtTokens( origString ); return state.tokenize( stream, state ); @@ -518,13 +528,9 @@ } function inTableCaption( stream, state ) { - if ( stream.sol() ) { - state.isBold = false; - state.isItalic = false; - if ( stream.match( /[\s\u00a0]*[\|!]/, false ) ) { - state.tokenize = inTable; - return inTable( stream, state ); - } + if ( stream.sol() && stream.match( /[\s\u00a0]*[\|!]/, false ) ) { + state.tokenize = inTable; + return inTable( stream, state ); } return eatWikiText( 'mw-table-caption', '' )( stream, state ); } @@ -563,8 +569,6 @@ function eatTableRow( isStart, isHead ) { return function ( stream, state ) { if ( stream.sol() ) { - state.isBold = false; - state.isItalic = false; if ( stream.match( /[\s\u00a0]*[\|!]/, false ) ) { state.tokenize = inTable; return inTable( stream, state ); @@ -574,8 +578,8 @@ return makeStyle( (isHead ? 'strong' : ''), state ); } if ( stream.match( '||' ) || isHead && stream.match( '!!' ) || (isStart && stream.eat( '|' )) ) { - state.isBold = false; - state.isItalic = false; + isBold = false; + isItalic = false; if ( isStart ) { state.tokenize = eatTableRow( false, isHead ); } @@ -595,7 +599,7 @@ function eatFreeExternalLink( stream, state ) { if ( stream.eol() ) { // @todo error message - } else if ( stream.match( /[^\s\u00a0\{\[\]<>~\)\.,]*/ ) ) { + } else if ( stream.match( /[^\s\u00a0\{\[\]<>~\)\.,']*/ ) ) { if ( stream.peek() === '~' ) { if ( !stream.match( /~{3,}/, false ) ) { stream.match( /~*/ ); @@ -603,7 +607,12 @@ } } else if ( stream.peek() === '{' ) { if ( !stream.match( /\{\{/, false ) ) { - stream.eat( '{' ); + stream.next(); + return makeLocalStyle( 'mw-free-extlink', state ); + } + } else if ( stream.peek() === '\'' ) { + if ( !stream.match( '\'\'', false ) ) { + stream.next(); return makeLocalStyle( 'mw-free-extlink', state ); } } else if ( stream.match( /[\)\.,]+(?=[^\s\u00a0\{\[\]<>~\)\.,])/ ) ) { @@ -624,8 +633,6 @@ var ch, sol = stream.sol(); if ( sol ) { - state.isBold = false; - state.isItalic = false; if ( stream.match( urlProtocols ) ) { // highlight free external links, bug T108448 state.stack.push( state.tokenize ); state.tokenize = eatFreeExternalLink; @@ -634,7 +641,7 @@ ch = stream.next(); switch ( ch ) { case '-': - if ( stream.match( '---' ) ) { + if ( stream.match( /----*/ ) ) { return 'mw-hr'; } break; @@ -692,12 +699,18 @@ case '&': return makeStyle( eatMnemonic( stream, style, mnemonicStyle ), state ); case '\'': - if ( stream.match( '\'\'' ) ) { - state.isBold = state.isBold ? false : true; - return makeLocalStyle( 'mw-apostrophes', state ); - } else if ( stream.eat( '\'' ) ) { - state.isItalic = state.isItalic ? false : true; - return makeLocalStyle( 'mw-apostrophes', state ); + if ( stream.match( /'*(?=''''')/ ) || stream.match( /'''(?!')/, false ) ) { // skip the irrelevant apostrophes ( >5 or =4 ) + break; + } + if ( stream.match( '\'\'' ) ) { // bold\ + if ( !(firstsingleletterword || stream.match( '\'\'', false )) ) { + prepareItalicForCorrection( stream ); + } + isBold = isBold ? false : true; + return makeLocalStyle( 'mw-apostrophes-bold', state ); + } else if ( stream.eat( '\'' ) ) { // italic + isItalic = isItalic ? false : true; + return makeLocalStyle( 'mw-apostrophes-italic', state ); } break; case '[': @@ -721,7 +734,7 @@ } break; case '{': - if ( stream.match( '{{' ) ) { // Variable + if ( !stream.match( '{{{{', false ) && stream.match( '{{' ) ) { // Template parameter (skip parameters inside a template transclusion, Bug: T108450) stream.eatSpace(); state.stack.push( state.tokenize ); state.tokenize = inVariable; @@ -803,17 +816,50 @@ }; } + /** + * Remembers position and status for rollbacking. + * It needed for change bold to italic with apostrophe before it if required + * @see https://phabricator.wikimedia.org/T108455 + * @param CodeMirror.StringStream stream + * @returns null + */ + function prepareItalicForCorrection( stream ) { + // see Parser::doQuotes() in MediaWiki core, it works similar + // firstsingleletterword has maximum priority + // firstmultiletterword has medium priority + // firstspace has low priority + var end = stream.pos, + str = stream.string.substr( 0, end - 3 ), + x1 = str.substr( -1, 1 ), + x2 = str.substr( -2, 1 ); + + // firstsingleletterword olways is undefined here + if ( x1 === ' ' ) { + if ( firstmultiletterword || firstspace ) { + return; + } + firstspace = end; + } else if ( x2 === ' ' ) { + firstsingleletterword = end; + } else if ( firstmultiletterword ) { + return; + } else { + firstmultiletterword = end; + } + // remember bold and italic state for restore + mBold = isBold; + mItalic = isItalic; + } + return { startState: function() { - return { tokenize: eatWikiText('', ''), stack: [], InHtmlTag:[], isBold: false, isItalic: false, extName: false, extMode: false, extState: false, nTemplate: 0, nLink: 0, nExt: 0 }; + return { tokenize: eatWikiText('', ''), stack: [], InHtmlTag:[], extName: false, extMode: false, extState: false, nTemplate: 0, nLink: 0, nExt: 0 }; }, copyState: function( state ) { return { tokenize: state.tokenize, stack: state.stack.concat( [] ), InHtmlTag: state.InHtmlTag.concat( [] ), - isBold: state.isBold, - isItalic: state.isItalic, extName: state.extName, extMode: state.extMode, extState: state.extMode !== false && CodeMirror.copyState( state.extMode, state.extState ), @@ -823,7 +869,68 @@ }; }, token: function( stream, state ) { - return state.tokenize( stream, state ); + var style, p, t, f, + readyTokens = [], + tmpTokens = []; + + if ( mTokens.length > 0 ) { // just send saved tokens till they exists + t = mTokens.shift(); + stream.pos = t.pos; + state = t.state; + return t.style; + } + + if ( stream.sol() ) { // reset bold and italic status in every new line + isBold = false; + isItalic = false; + firstsingleletterword = undefined; + firstmultiletterword = undefined; + firstspace = undefined; + } + + do { + style = state.tokenize( stream, state ); // get token style + f = firstsingleletterword || firstmultiletterword || firstspace; + if ( f ) { // rollback point exists + if ( f !== p ) { // new rollbak point + p = f; + if ( tmpTokens.length > 0 ) { // it's not first rollbak point + readyTokens = readyTokens.concat( tmpTokens ); // save tokens + tmpTokens = []; + } + } + tmpTokens.push( { // save token + pos: stream.pos, + style: style, + state: CodeMirror.copyState( state.extMode ? state.extMode : 'mediawiki', state ) + } ); + } else { // rollback point not exists + mStyle = style; // remember style before possible rollback point + return style; // just return token style + } + } while ( !stream.eol() ); + + if ( isBold && isItalic ) { // needs to rollback + isItalic = mItalic; // restore status + isBold = mBold; + firstsingleletterword = undefined; + firstmultiletterword = undefined; + firstspace = undefined; + if ( readyTokens.length > 0 ) { // it contains tickets before the point of rollback + readyTokens[readyTokens.length-1].pos++; // add one apostrophe, next token will be italic (two apostrophes) + mTokens = readyTokens; // for sending tokens till the point of rollback + } else { // there are no tikets before the point of rollback + stream.pos = tmpTokens[0].pos - 2; // eat( '\'') + return mStyle; // send saved Style + } + } else { // not needs to rollback + mTokens = readyTokens.concat( tmpTokens ); // send all saved tokens + } + // return first saved token + t = mTokens.shift(); + stream.pos = t.pos; + state = t.state; + return t.style; }, blankLine: function( state ) { if ( state.extName ) { -- To view, visit https://gerrit.wikimedia.org/r/249357 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Id5e434eca4840e6ce9841f43e1299970a61ba8cc Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/CodeMirror Gerrit-Branch: REL1_24 Gerrit-Owner: Pastakhov <pastak...@yandex.ru> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits