TinyMCE: wptextpattern: Fix inline patterns.
* Allow spaces inside inline pattern text, unless the delimiter stands alone. * Add more unit tests. * Add more inline docs. Part props azaozz. Fixes #37693. Built from https://develop.svn.wordpress.org/trunk@39150 git-svn-id: http://core.svn.wordpress.org/trunk@39090 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
5ea1e6fd80
commit
c1ff206bac
|
@ -3,12 +3,46 @@
|
|||
*
|
||||
* @since 4.3.0
|
||||
*
|
||||
* This plugin can automatically format text patterns as you type. It includes two patterns:
|
||||
* This plugin can automatically format text patterns as you type. It includes several groups of patterns.
|
||||
*
|
||||
* Start of line patterns:
|
||||
* As-you-type:
|
||||
* - Unordered list (`* ` and `- `).
|
||||
* - Ordered list (`1. ` and `1) `).
|
||||
*
|
||||
* On enter:
|
||||
* - h2 (## ).
|
||||
* - h3 (### ).
|
||||
* - h4 (#### ).
|
||||
* - h5 (##### ).
|
||||
* - h6 (###### ).
|
||||
* - blockquote (> ).
|
||||
* - hr (---).
|
||||
*
|
||||
* Inline patterns:
|
||||
* - <code> (`) (backtick).
|
||||
*
|
||||
* If the transformation in unwanted, the user can undo the change by pressing backspace,
|
||||
* using the undo shortcut, or the undo button in the toolbar.
|
||||
*
|
||||
* Setting for the patterns can be overridden by plugins by using the `tiny_mce_before_init` PHP filter.
|
||||
* The setting name is `wptextpattern` and the value is an object containing override arrays for each
|
||||
* patterns group. There are three groups: "space", "enter", and "inline". Example (PHP):
|
||||
*
|
||||
* add_filter( 'tiny_mce_before_init', 'my_mce_init_wptextpattern' );
|
||||
* function my_mce_init_wptextpattern( $init ) {
|
||||
* $init['wptextpattern'] = wp_json_encode( array(
|
||||
* 'inline' => array(
|
||||
* array( 'delimiter' => '**', 'format' => 'bold' ),
|
||||
* array( 'delimiter' => '__', 'format' => 'italic' ),
|
||||
* ),
|
||||
* ) );
|
||||
*
|
||||
* return $init;
|
||||
* }
|
||||
*
|
||||
* Note that setting this will override the default text patterns. You will need to include them
|
||||
* in your settings array if you want to keep them working.
|
||||
*/
|
||||
( function( tinymce, setTimeout ) {
|
||||
if ( tinymce.Env.ie && tinymce.Env.ie < 9 ) {
|
||||
|
@ -46,19 +80,10 @@
|
|||
];
|
||||
|
||||
var inlinePatterns = settings.inline || [
|
||||
{ start: '`', end: '`', format: 'code' }
|
||||
{ delimiter: '`', format: 'code' }
|
||||
];
|
||||
|
||||
var canUndo;
|
||||
var chars = [];
|
||||
|
||||
tinymce.each( inlinePatterns, function( pattern ) {
|
||||
tinymce.each( ( pattern.start + pattern.end ).split( '' ), function( c ) {
|
||||
if ( tinymce.inArray( chars, c ) === -1 ) {
|
||||
chars.push( c );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
|
||||
editor.on( 'selectionchange', function() {
|
||||
canUndo = null;
|
||||
|
@ -100,28 +125,44 @@
|
|||
return;
|
||||
}
|
||||
|
||||
// The ending character should exist in the patterns registered.
|
||||
if ( tinymce.inArray( chars, node.data.charAt( offset - 1 ) ) === -1 ) {
|
||||
var string = node.data.slice( 0, offset );
|
||||
var lastChar = node.data.charAt( offset - 1 );
|
||||
|
||||
tinymce.each( inlinePatterns, function( p ) {
|
||||
// Character before selection should be delimiter.
|
||||
if ( lastChar !== p.delimiter.slice( -1 ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var string = node.data.slice( 0, offset );
|
||||
|
||||
tinymce.each( inlinePatterns, function( p ) {
|
||||
var regExp = new RegExp( escapeRegExp( p.start ) + '\\S+' + escapeRegExp( p.end ) + '$' );
|
||||
var escDelimiter = escapeRegExp( p.delimiter );
|
||||
var delimiterFirstChar = p.delimiter.charAt( 0 );
|
||||
var regExp = new RegExp( '(.*)' + escDelimiter + '.+' + escDelimiter + '$' );
|
||||
var match = string.match( regExp );
|
||||
|
||||
if ( ! match ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't allow pattern characters in the text.
|
||||
if ( node.data.slice( match.index + p.start.length, offset - p.end.length ).indexOf( p.start.slice( 0, 1 ) ) !== -1 ) {
|
||||
startOffset = match[1].length;
|
||||
endOffset = offset - p.delimiter.length;
|
||||
|
||||
var before = string.charAt( startOffset - 1 );
|
||||
var after = string.charAt( startOffset + p.delimiter.length );
|
||||
|
||||
// test*test* => format applied
|
||||
// test *test* => applied
|
||||
// test* test* => not applied
|
||||
if ( startOffset && /\S/.test( before ) ) {
|
||||
if ( /\s/.test( after ) || before === delimiterFirstChar ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Do not replace when only whitespace and delimiter characters.
|
||||
if ( ( new RegExp( '^[\\s' + escapeRegExp( delimiterFirstChar ) + ']+$' ) ).test( string.slice( startOffset, endOffset ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
startOffset = match.index;
|
||||
endOffset = offset - p.end.length;
|
||||
pattern = p;
|
||||
|
||||
return false;
|
||||
|
@ -142,8 +183,8 @@
|
|||
node = node.splitText( startOffset );
|
||||
zero = node.splitText( offset - startOffset );
|
||||
|
||||
node.deleteData( 0, pattern.start.length );
|
||||
node.deleteData( node.data.length - pattern.end.length, pattern.end.length );
|
||||
node.deleteData( 0, pattern.delimiter.length );
|
||||
node.deleteData( node.data.length - pattern.delimiter.length, pattern.delimiter.length );
|
||||
|
||||
editor.formatter.apply( pattern.format, {}, node );
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
!function(a,b){function c(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}a.Env.ie&&a.Env.ie<9||a.PluginManager.add("wptextpattern",function(d){function e(){var e,f,g,h,i,k=d.selection.getRng(),l=k.startContainer,m=k.startOffset;if(l&&3===l.nodeType&&l.data.length&&m&&a.inArray(p,l.data.charAt(m-1))!==-1){var n=l.data.slice(0,m);a.each(o,function(a){var b=new RegExp(c(a.start)+"\\S+"+c(a.end)+"$"),d=n.match(b);if(d&&l.data.slice(d.index+a.start.length,m-a.end.length).indexOf(a.start.slice(0,1))===-1)return e=d.index,f=m-a.end.length,g=a,!1}),g&&(h=d.formatter.get(g.format),h&&h[0].inline&&(d.undoManager.add(),d.undoManager.transact(function(){l.insertData(m,"\ufeff"),l=l.splitText(e),i=l.splitText(m-e),l.deleteData(0,g.start.length),l.deleteData(l.data.length-g.end.length,g.end.length),d.formatter.apply(g.format,{},l),d.selection.setCursorLocation(i,1)}),b(function(){j="space",d.once("selectionchange",function(){var a;i&&(a=i.data.indexOf("\ufeff"),a!==-1&&i.deleteData(a,a+1))})})))}}function f(a){var b,c=d.dom.getParent(a,"p");if(c){for(;(b=c.firstChild)&&3!==b.nodeType;)c=b;if(b)return b.data||(b=b.nextSibling&&3===b.nextSibling.nodeType?b.nextSibling:null),b}}function g(){var c,e,g=d.selection.getRng(),h=g.startContainer;h&&f(h)===h&&(c=h.parentNode,e=h.data,a.each(m,function(a){var f=e.match(a.regExp);if(f&&g.startOffset===f[0].length)return d.undoManager.add(),d.undoManager.transact(function(){h.deleteData(0,f[0].length),c.innerHTML||c.appendChild(document.createElement("br")),d.selection.setCursorLocation(c),d.execCommand(a.cmd)}),b(function(){j="space"}),!1}))}function h(){var c,e,g,h=d.selection.getRng(),k=h.startContainer,l=f(k),m=n.length;if(l){for(c=l.data;m--;)if(n[m].start){if(0===c.indexOf(n[m].start)){e=n[m];break}}else if(n[m].regExp&&n[m].regExp.test(c)){e=n[m];break}e&&(l===k&&a.trim(c)===e.start||d.once("keyup",function(){d.undoManager.add(),d.undoManager.transact(function(){e.format?(d.formatter.apply(e.format,{},l),l.replaceData(0,l.data.length,i(l.data.slice(e.start.length)))):e.element&&(g=l.parentNode&&l.parentNode.parentNode,g&&g.replaceChild(document.createElement(e.element),l.parentNode))}),b(function(){j="enter"})}))}}function i(a){return a?a.replace(/^\s+/,""):""}var j,k=a.util.VK,l=d.settings.wptextpattern||{},m=l.space||[{regExp:/^[*-]\s/,cmd:"InsertUnorderedList"},{regExp:/^1[.)]\s/,cmd:"InsertOrderedList"}],n=l.enter||[{start:"##",format:"h2"},{start:"###",format:"h3"},{start:"####",format:"h4"},{start:"#####",format:"h5"},{start:"######",format:"h6"},{start:">",format:"blockquote"},{regExp:/^(-){3,}$/,element:"hr"}],o=l.inline||[{start:"`",end:"`",format:"code"}],p=[];a.each(o,function(b){a.each((b.start+b.end).split(""),function(b){a.inArray(p,b)===-1&&p.push(b)})}),d.on("selectionchange",function(){j=null}),d.on("keydown",function(a){(j&&27===a.keyCode||"space"===j&&a.keyCode===k.BACKSPACE)&&(d.undoManager.undo(),a.preventDefault(),a.stopImmediatePropagation()),k.metaKeyPressed(a)||(a.keyCode===k.ENTER?h():a.keyCode===k.SPACEBAR?b(g):a.keyCode>47&&!(a.keyCode>=91&&a.keyCode<=93)&&b(e))},!0)})}(window.tinymce,window.setTimeout);
|
||||
!function(a,b){function c(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}a.Env.ie&&a.Env.ie<9||a.PluginManager.add("wptextpattern",function(d){function e(){var e,f,g,h,i,k=d.selection.getRng(),l=k.startContainer,m=k.startOffset;if(l&&3===l.nodeType&&l.data.length&&m){var n=l.data.slice(0,m),p=l.data.charAt(m-1);a.each(o,function(a){if(p===a.delimiter.slice(-1)){var b=c(a.delimiter),d=a.delimiter.charAt(0),h=new RegExp("(.*)"+b+".+"+b+"$"),i=n.match(h);if(i){e=i[1].length,f=m-a.delimiter.length;var j=n.charAt(e-1),k=n.charAt(e+a.delimiter.length);if(!(e&&/\S/.test(j)&&(/\s/.test(k)||j===d)||new RegExp("^[\\s"+c(d)+"]+$").test(n.slice(e,f))))return g=a,!1}}}),g&&(h=d.formatter.get(g.format),h&&h[0].inline&&(d.undoManager.add(),d.undoManager.transact(function(){l.insertData(m,"\ufeff"),l=l.splitText(e),i=l.splitText(m-e),l.deleteData(0,g.delimiter.length),l.deleteData(l.data.length-g.delimiter.length,g.delimiter.length),d.formatter.apply(g.format,{},l),d.selection.setCursorLocation(i,1)}),b(function(){j="space",d.once("selectionchange",function(){var a;i&&(a=i.data.indexOf("\ufeff"),a!==-1&&i.deleteData(a,a+1))})})))}}function f(a){var b,c=d.dom.getParent(a,"p");if(c){for(;(b=c.firstChild)&&3!==b.nodeType;)c=b;if(b)return b.data||(b=b.nextSibling&&3===b.nextSibling.nodeType?b.nextSibling:null),b}}function g(){var c,e,g=d.selection.getRng(),h=g.startContainer;h&&f(h)===h&&(c=h.parentNode,e=h.data,a.each(m,function(a){var f=e.match(a.regExp);if(f&&g.startOffset===f[0].length)return d.undoManager.add(),d.undoManager.transact(function(){h.deleteData(0,f[0].length),c.innerHTML||c.appendChild(document.createElement("br")),d.selection.setCursorLocation(c),d.execCommand(a.cmd)}),b(function(){j="space"}),!1}))}function h(){var c,e,g,h=d.selection.getRng(),k=h.startContainer,l=f(k),m=n.length;if(l){for(c=l.data;m--;)if(n[m].start){if(0===c.indexOf(n[m].start)){e=n[m];break}}else if(n[m].regExp&&n[m].regExp.test(c)){e=n[m];break}e&&(l===k&&a.trim(c)===e.start||d.once("keyup",function(){d.undoManager.add(),d.undoManager.transact(function(){e.format?(d.formatter.apply(e.format,{},l),l.replaceData(0,l.data.length,i(l.data.slice(e.start.length)))):e.element&&(g=l.parentNode&&l.parentNode.parentNode,g&&g.replaceChild(document.createElement(e.element),l.parentNode))}),b(function(){j="enter"})}))}}function i(a){return a?a.replace(/^\s+/,""):""}var j,k=a.util.VK,l=d.settings.wptextpattern||{},m=l.space||[{regExp:/^[*-]\s/,cmd:"InsertUnorderedList"},{regExp:/^1[.)]\s/,cmd:"InsertOrderedList"}],n=l.enter||[{start:"##",format:"h2"},{start:"###",format:"h3"},{start:"####",format:"h4"},{start:"#####",format:"h5"},{start:"######",format:"h6"},{start:">",format:"blockquote"},{regExp:/^(-){3,}$/,element:"hr"}],o=l.inline||[{delimiter:"`",format:"code"}];d.on("selectionchange",function(){j=null}),d.on("keydown",function(a){(j&&27===a.keyCode||"space"===j&&a.keyCode===k.BACKSPACE)&&(d.undoManager.undo(),a.preventDefault(),a.stopImmediatePropagation()),k.metaKeyPressed(a)||(a.keyCode===k.ENTER?h():a.keyCode===k.SPACEBAR?b(g):a.keyCode>47&&!(a.keyCode>=91&&a.keyCode<=93)&&b(e))},!0)})}(window.tinymce,window.setTimeout);
|
Binary file not shown.
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* @global string $wp_version
|
||||
*/
|
||||
$wp_version = '4.7-beta2-39149';
|
||||
$wp_version = '4.7-beta2-39150';
|
||||
|
||||
/**
|
||||
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
||||
|
|
Loading…
Reference in New Issue