Ticket #31441: 31441.6.patch
File 31441.6.patch, 11.5 KB (added by , 10 years ago) |
---|
-
src/wp-includes/class-wp-editor.php
368 368 'wplink', 369 369 'wpdialogs', 370 370 'wpview', 371 'wptextpattern' 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 var done = assert.async(); 52 53 type( '* test', function() { 54 assert.equal( editor.getContent(), '<ul>\n<li>test</li>\n</ul>' ); 55 done(); 56 } ); 57 } ); 58 59 QUnit.test( 'Ordered list.', function( assert ) { 60 var done = assert.async(); 61 62 type( '1. test', function() { 63 assert.equal( editor.getContent(), '<ol>\n<li>test</li>\n</ol>' ); 64 done(); 65 } ); 66 } ); 67 68 QUnit.test( 'Ordered list with content.', function( assert ) { 69 var done = assert.async(); 70 71 editor.setContent( '<p><strong>test</strong></p>' ); 72 editor.selection.setCursorLocation(); 73 74 type( '* ', function() { 75 assert.equal( editor.getContent(), '<ul>\n<li><strong>test</strong></li>\n</ul>' ); 76 done(); 77 } ); 78 } ); 79 80 QUnit.test( 'Only transform inside a P tag.', function( assert ) { 81 var done = assert.async(); 82 83 editor.setContent( '<h1>test</h1>' ); 84 editor.selection.setCursorLocation(); 85 86 type( '* ', function() { 87 assert.equal( editor.getContent(), '<h1>* test</h1>' ); 88 done(); 89 } ); 90 } ); 91 92 QUnit.test( 'Only transform at the start of a P tag.', function( assert ) { 93 var done = assert.async(); 94 95 editor.setContent( '<p>test <strong>test</strong></p>' ); 96 editor.selection.setCursorLocation( editor.$( 'strong' )[0].firstChild, 0 ); 97 98 type( '* ', function() { 99 assert.equal( editor.getContent(), '<p>test <strong>* test</strong></p>' ); 100 done(); 101 } ); 102 } ); 103 104 QUnit.test( 'Only transform when at the cursor is at the start.', function( assert ) { 105 var done = assert.async(); 106 107 editor.setContent( '<p>* test</p>' ); 108 editor.selection.setCursorLocation( editor.$( 'p' )[0].firstChild, 6 ); 109 110 type( ' test', function() { 111 assert.equal( editor.getContent(), '<p>* test test</p>' ); 112 done(); 113 } ); 114 } ); 115 116 QUnit.test( 'Backspace should undo the transformation.', function( assert ) { 117 var done = assert.async(); 118 119 editor.setContent( '<p>test</p>' ); 120 editor.selection.setCursorLocation(); 121 122 type( '* \b', function() { 123 assert.equal( editor.getContent(), '<p>* test</p>' ); 124 assert.equal( editor.selection.getRng().startOffset, 2 ); 125 done(); 126 } ); 127 } ); 128 129 QUnit.test( 'Backspace should undo the transformation only right after it happened.', function( assert ) { 130 var done = assert.async(); 131 132 editor.setContent( '<p>test</p>' ); 133 editor.selection.setCursorLocation(); 134 135 type( '* ', function() { 136 editor.selection.setCursorLocation( editor.$( 'li' )[0].firstChild, 4 ); 137 // Gecko. 138 editor.fire( 'click' ); 139 }, '\b', function() { 140 assert.equal( editor.getContent(), '<ul>\n<li>tes</li>\n</ul>' ); 141 done(); 142 } ); 143 } ); 144 } )( window.jQuery, window.QUnit, window.tinymce, window.Utils.type, window.setTimeout );