Ticket #31441: 31441.8.patch
File 31441.8.patch, 11.3 KB (added by , 9 years ago) |
---|
-
src/wp-includes/class-wp-editor.php
367 367 'wpgallery', 368 368 'wplink', 369 369 'wpdialogs', 370 'wpview', 370 'wptextpattern', 371 'wpview' 371 372 ); 372 373 373 374 if ( ! self::$has_medialib ) { -
src/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js
1 ( function( tinymce, setTimeout ) { 2 tinymce.PluginManager.add( 'wptextpattern', function( editor ) { 3 var $$ = editor.$, 4 patterns = [], 5 canUndo = false; 6 7 function add( regExp, callback ) { 8 patterns.push( { 9 regExp: regExp, 10 callback: callback 11 } ); 12 } 13 14 add( /^[*-]\s/, function() { 15 this.execCommand( 'InsertUnorderedList' ); 16 } ); 17 18 add( /^1[.)]\s/, function() { 19 this.execCommand( 'InsertOrderedList' ); 20 } ); 21 22 editor.on( 'selectionchange', function() { 23 canUndo = false; 24 } ); 25 26 editor.on( 'keydown', function( event ) { 27 if ( canUndo && event.keyCode === tinymce.util.VK.BACKSPACE ) { 28 editor.undoManager.undo(); 29 event.preventDefault(); 30 } 31 } ); 32 33 editor.on( 'keyup', function( event ) { 34 var rng, node, text, parent, child; 35 36 if ( event.keyCode !== tinymce.util.VK.SPACEBAR ) { 37 return; 38 } 39 40 rng = editor.selection.getRng(); 41 node = rng.startContainer; 42 text = node.nodeValue; 43 44 if ( node.nodeType !== 3 ) { 45 return; 46 } 47 48 parent = editor.dom.getParent( node, 'p' ); 49 50 if ( ! parent ) { 51 return; 52 } 53 54 while ( child = parent.firstChild ) { 55 if ( child.nodeType !== 3 ) { 56 parent = child; 57 } else { 58 break; 59 } 60 } 61 62 if ( child !== node ) { 63 return; 64 } 65 66 tinymce.each( patterns, function( pattern ) { 67 var replace = text.replace( pattern.regExp, '' ); 68 69 if ( text === replace ) { 70 return; 71 } 72 73 if ( rng.startOffset !== text.length - replace.length ) { 74 return; 75 } 76 77 editor.undoManager.add(); 78 79 editor.undoManager.transact( function() { 80 editor.selection.setCursorLocation( node, 0 ); 81 82 if ( replace ) { 83 $$( node ).replaceWith( document.createTextNode( replace ) ); 84 } else { 85 $$( node.parentNode ).empty().append( '<br>' ); 86 } 87 88 pattern.callback.apply( editor ); 89 } ); 90 91 // We need to wait for native events to be triggered. 92 setTimeout( function() { 93 canUndo = true; 94 } ); 95 96 return false; 97 } ); 98 } ); 99 } ); 100 } )( window.tinymce, window.setTimeout ); -
tests/qunit/editor/js/utils.js
131 131 132 132 // TODO: Replace this with the new event logic in 3.5 133 133 function type(chr) { 134 var editor = tinymce.activeEditor, keyCode, charCode, evt, startElm, rng; 134 var editor = tinymce.activeEditor, keyCode, charCode, evt, startElm, rng, startContainer, startOffset, textNode; 135 136 function charCodeToKeyCode(charCode) { 137 var lookup = { 138 '0': 48, '1': 49, '2': 50, '3': 51, '4': 52, '5': 53, '6': 54, '7': 55, '8': 56, '9': 57,'a': 65, 'b': 66, 'c': 67, 139 'd': 68, 'e': 69, 'f': 70, 'g': 71, 'h': 72, 'i': 73, 'j': 74, 'k': 75, 'l': 76, 'm': 77, 'n': 78, 'o': 79, 'p': 80, 'q': 81, 140 'r': 82, 's': 83, 't': 84, 'u': 85, 'v': 86, 'w': 87, 'x': 88, 'y': 89, ' ': 32, ',': 188, '-': 189, '.': 190, '/': 191, '\\': 220, 141 '[': 219, ']': 221, '\'': 222, ';': 186, '=': 187, ')': 41 142 }; 143 144 return lookup[String.fromCharCode(charCode)]; 145 } 135 146 136 147 function fakeEvent(target, type, evt) { 137 148 editor.dom.fire(target, type, evt); … … 139 150 140 151 // Numeric keyCode 141 152 if (typeof(chr) == "number") { 142 charCode = keyCode = chr; 153 charCode = chr; 154 keyCode = charCodeToKeyCode(charCode); 143 155 } else if (typeof(chr) == "string") { 144 156 // String value 145 157 if (chr == '\b') { … … 150 162 charCode = chr.charCodeAt(0); 151 163 } else { 152 164 charCode = chr.charCodeAt(0); 153 keyCode = charCode ;165 keyCode = charCodeToKeyCode(charCode); 154 166 } 155 167 } else { 156 168 evt = chr; 169 170 if (evt.charCode) { 171 chr = String.fromCharCode(evt.charCode); 172 } 173 174 if (evt.keyCode) { 175 keyCode = evt.keyCode; 176 } 157 177 } 158 178 159 179 evt = evt || {keyCode: keyCode, charCode: charCode}; … … 175 195 rng.execCommand('Delete', false, null); 176 196 } else { 177 197 rng = editor.selection.getRng(); 198 startContainer = rng.startContainer; 178 199 179 if (rng.startContainer.nodeType == 1 && rng.collapsed) { 180 var nodes = rng.startContainer.childNodes, lastNode = nodes[nodes.length - 1]; 200 if (startContainer.nodeType == 1 && rng.collapsed) { 201 var nodes = rng.startContainer.childNodes; 202 startContainer = nodes[nodes.length - 1]; 203 } 181 204 182 // If caret is at <p>abc|</p> and after the abc text node then move it to the end of the text node 183 // Expand the range to include the last char <p>ab[c]</p> since IE 11 doesn't delete otherwise 184 if (rng.startOffset >= nodes.length - 1 && lastNode && lastNode.nodeType == 3 && lastNode.data.length > 0) { 185 rng.setStart(lastNode, lastNode.data.length - 1); 186 rng.setEnd(lastNode, lastNode.data.length); 187 editor.selection.setRng(rng); 188 } 205 // If caret is at <p>abc|</p> and after the abc text node then move it to the end of the text node 206 // Expand the range to include the last char <p>ab[c]</p> since IE 11 doesn't delete otherwise 207 if ( rng.collapsed && startContainer && startContainer.nodeType == 3 && startContainer.data.length > 0) { 208 rng.setStart(startContainer, startContainer.data.length - 1); 209 rng.setEnd(startContainer, startContainer.data.length); 210 editor.selection.setRng(rng); 189 211 } 190 212 191 213 editor.getDoc().execCommand('Delete', false, null); … … 194 216 rng = editor.selection.getRng(true); 195 217 196 218 if (rng.startContainer.nodeType == 3 && rng.collapsed) { 197 rng.startContainer.insertData(rng.startOffset, chr); 198 rng.setStart(rng.startContainer, rng.startOffset + 1); 199 rng.collapse(true); 200 editor.selection.setRng(rng); 219 // `insertData` may alter the range. 220 startContainer = rng.startContainer; 221 startOffset = rng.startOffset; 222 rng.startContainer.insertData( rng.startOffset, chr ); 223 rng.setStart( startContainer, startOffset + 1 ); 201 224 } else { 202 rng.insertNode(editor.getDoc().createTextNode(chr)); 225 textNode = editor.getDoc().createTextNode(chr); 226 rng.insertNode(textNode); 227 rng.setStart(textNode, 1); 203 228 } 229 230 rng.collapse(true); 231 editor.selection.setRng(rng); 204 232 } 205 233 } 206 234 -
tests/qunit/index.html
39 39 <script src="wp-includes/js/shortcode.js"></script> 40 40 <script src="wp-admin/js/customize-controls.js"></script> 41 41 <script src="wp-admin/js/customize-controls-utils.js"></script> 42 43 <!-- TinyMCE --> 44 45 <script src="../../src/wp-includes/js/tinymce/tinymce.js"></script> 46 47 <script src="editor/js/utils.js"></script> 48 49 <script src="wp-includes/js/tinymce/plugins/wptextpattern/plugin.js"></script> 50 42 51 </body> 43 52 </html> -
tests/qunit/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js
1 ( function( $, QUnit, tinymce, _type, setTimeout ) { 2 var editor; 3 4 function type() { 5 var args = arguments; 6 7 setTimeout( function() { 8 if ( typeof args[0] === 'string' ) { 9 args[0] = args[0].split( '' ); 10 } 11 12 if ( typeof args[0] === 'function' ) { 13 args[0](); 14 } else { 15 _type( args[0].shift() ); 16 } 17 18 if ( ! args[0].length ) { 19 [].shift.call( args ); 20 } 21 22 if ( args.length ) { 23 type.apply( null, args ); 24 } 25 } ); 26 } 27 28 QUnit.module( 'tinymce.plugins.wptextpattern', { 29 beforeEach: function( assert ) { 30 var done = assert.async(); 31 32 $( '#qunit-fixture' ).append( '<textarea id="editor">' ); 33 34 tinymce.init( { 35 selector: '#editor', 36 plugins: 'wptextpattern', 37 init_instance_callback: function() { 38 editor = arguments[0]; 39 editor.focus(); 40 editor.selection.setCursorLocation(); 41 setTimeout( done ); 42 } 43 } ); 44 }, 45 afterEach: function() { 46 editor.remove(); 47 } 48 } ); 49 50 QUnit.test( 'Unordered list.', function( assert ) { 51 type( '* test', function() { 52 assert.equal( editor.getContent(), '<ul>\n<li>test</li>\n</ul>' ); 53 }, assert.async() ); 54 } ); 55 56 QUnit.test( 'Ordered list.', function( assert ) { 57 type( '1. test', function() { 58 assert.equal( editor.getContent(), '<ol>\n<li>test</li>\n</ol>' ); 59 }, assert.async() ); 60 } ); 61 62 QUnit.test( 'Ordered list with content.', function( assert ) { 63 editor.setContent( '<p><strong>test</strong></p>' ); 64 editor.selection.setCursorLocation(); 65 66 type( '* ', function() { 67 assert.equal( editor.getContent(), '<ul>\n<li><strong>test</strong></li>\n</ul>' ); 68 }, assert.async() ); 69 } ); 70 71 QUnit.test( 'Only transform inside a P tag.', function( assert ) { 72 editor.setContent( '<h1>test</h1>' ); 73 editor.selection.setCursorLocation(); 74 75 type( '* ', function() { 76 assert.equal( editor.getContent(), '<h1>* test</h1>' ); 77 }, assert.async() ); 78 } ); 79 80 QUnit.test( 'Only transform at the start of a P tag.', function( assert ) { 81 editor.setContent( '<p>test <strong>test</strong></p>' ); 82 editor.selection.setCursorLocation( editor.$( 'strong' )[0].firstChild, 0 ); 83 84 type( '* ', function() { 85 assert.equal( editor.getContent(), '<p>test <strong>* test</strong></p>' ); 86 }, assert.async() ); 87 } ); 88 89 QUnit.test( 'Only transform when at the cursor is at the start.', function( assert ) { 90 editor.setContent( '<p>* test</p>' ); 91 editor.selection.setCursorLocation( editor.$( 'p' )[0].firstChild, 6 ); 92 93 type( ' test', function() { 94 assert.equal( editor.getContent(), '<p>* test test</p>' ); 95 }, assert.async() ); 96 } ); 97 98 QUnit.test( 'Backspace should undo the transformation.', function( assert ) { 99 editor.setContent( '<p>test</p>' ); 100 editor.selection.setCursorLocation(); 101 102 type( '* \b', function() { 103 assert.equal( editor.getContent(), '<p>* test</p>' ); 104 assert.equal( editor.selection.getRng().startOffset, 2 ); 105 }, assert.async() ); 106 } ); 107 108 QUnit.test( 'Backspace should undo the transformation only right after it happened.', function( assert ) { 109 editor.setContent( '<p>test</p>' ); 110 editor.selection.setCursorLocation(); 111 112 type( '* ', function() { 113 editor.selection.setCursorLocation( editor.$( 'li' )[0].firstChild, 4 ); 114 // Gecko. 115 editor.fire( 'click' ); 116 }, '\b', function() { 117 assert.equal( editor.getContent(), '<ul>\n<li>tes</li>\n</ul>' ); 118 }, assert.async() ); 119 } ); 120 } )( window.jQuery, window.QUnit, window.tinymce, window.Utils.type, window.setTimeout );