WordPress/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js

168 lines
3.6 KiB
JavaScript

/**
* Text pattern plugin for TinyMCE
*
* @since 4.3.0
*
* This plugin can automatically format text patterns as you type. It includes two patterns:
* - Unordered list (`* ` and `- `).
* - Ordered list (`1. ` and `1) `).
*
* 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.
*/
( function( tinymce, setTimeout ) {
tinymce.PluginManager.add( 'wptextpattern', function( editor ) {
var VK = tinymce.util.VK,
canUndo = false,
spacePatterns = [
{ regExp: /^[*-]\s/, cmd: 'InsertUnorderedList' },
{ regExp: /^1[.)]\s/, cmd: 'InsertOrderedList' }
],
enterPatterns = [
{ start: '##', format: 'h2' },
{ start: '###', format: 'h3' },
{ start: '####', format: 'h4' },
{ start: '#####', format: 'h5' },
{ start: '######', format: 'h6' },
{ start: '>', format: 'blockquote' }
];
editor.on( 'selectionchange', function() {
canUndo = false;
} );
editor.on( 'keydown', function( event ) {
if ( canUndo && ( event.keyCode === VK.BACKSPACE || event.keyCode === 27 /* ESCAPE */ ) ) {
editor.undoManager.undo();
event.preventDefault();
}
if ( event.keyCode === VK.ENTER && ! VK.modifierPressed( event ) ) {
enter();
}
}, true );
editor.on( 'keyup', function( event ) {
if ( event.keyCode === VK.SPACEBAR && ! VK.modifierPressed( event ) ) {
space();
}
} );
function firstNode( node ) {
var parent = editor.dom.getParent( node, 'p' ),
child;
if ( ! parent ) {
return;
}
while ( child = parent.firstChild ) {
if ( child.nodeType !== 3 ) {
parent = child;
} else {
break;
}
}
if ( ! child ) {
return;
}
if ( ! child.data ) {
child = child.nextSibling;
}
return child;
}
function space() {
var rng = editor.selection.getRng(),
node = rng.startContainer,
parent,
text;
if ( ! node || firstNode( node ) !== node ) {
return;
}
parent = node.parentNode;
text = node.data;
tinymce.each( spacePatterns, function( pattern ) {
var match = text.match( pattern.regExp );
if ( ! match || rng.startOffset !== match[0].length ) {
return;
}
editor.undoManager.add();
editor.undoManager.transact( function() {
node.deleteData( 0, match[0].length );
if ( ! parent.innerHTML ) {
parent.appendChild( document.createElement( 'br' ) );
}
editor.selection.setCursorLocation( parent );
editor.execCommand( pattern.cmd );
} );
// We need to wait for native events to be triggered.
setTimeout( function() {
canUndo = true;
} );
return false;
} );
}
function enter() {
var selection = editor.selection,
rng = selection.getRng(),
offset = rng.startOffset,
start = rng.startContainer,
node = firstNode( start ),
i = enterPatterns.length,
text, pattern;
if ( ! node ) {
return;
}
text = node.data;
while ( i-- ) {
if ( text.indexOf( enterPatterns[ i ].start ) === 0 ) {
pattern = enterPatterns[ i ];
break;
}
}
if ( ! pattern ) {
return;
}
if ( node === start ) {
if ( tinymce.trim( text ) === pattern.start ) {
return;
}
offset = Math.max( 0, offset - pattern.start.length );
}
editor.undoManager.add();
editor.undoManager.transact( function() {
node.deleteData( 0, pattern.start.length );
editor.formatter.apply( pattern.format, {}, start );
rng.setStart( start, offset );
rng.collapse( true );
selection.setRng( rng );
} );
}
} );
} )( window.tinymce, window.setTimeout );