Index: src/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js
===================================================================
--- src/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js	(revision 37037)
+++ src/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js	(working copy)
@@ -16,32 +16,90 @@
 	}
 
 	tinymce.PluginManager.add( 'wptextpattern', function( editor ) {
-		var VK = tinymce.util.VK;
+		var VK = tinymce.util.VK,
+			settings = editor.settings,
+			extend = tinymce.extend,
+			each = tinymce.each,
+			chars = [],
+			canUndo;
 
-		var spacePatterns = [
-			{ regExp: /^[*-]\s/, cmd: 'InsertUnorderedList' },
-			{ regExp: /^1[.)]\s/, cmd: 'InsertOrderedList' }
-		];
+		/**
+		 * Setting for the patterns can be added or replaced by using the
+		 * 'tiny_mce_before_init' filter (from PHP).
+		 *
+		 * The editor options are: wptextpattern_space_patterns,
+		 * wptextpattern_enter_patterns, and wptextpattern_inline_patterns.
+		 * The format is same as below: an object of objects containing the pattrern settings.
+		 *
+		 * Note: the keys in the settings objects are not signigicant. They can be used
+		 * to override the default settings if needed.
+		 *
+		 * Example:
+		 *     add_filter( 'tiny_mce_before_init', 'textpatterns_test' );
+		 *     function textpatterns_test( $init ) {
+		 *         $init['wptextpattern_inline_patterns'] = '{
+		 *             strong: { start: "*", end: "*", format: "bold" },
+		 *             strong2: { start: "**", end: "**", format: "bold" },
+		 *             em: { start: "_", end: "_", format: "italic" }
+		 *         }';
+		 *
+		 *         return $init;
+		 *     }
+		 */
+		var spacePatterns = extend( {
+				ul: { regExp: /^[*-]\s/, cmd: 'InsertUnorderedList' },
+				ol: { regExp: /^1[.)]\s/, cmd: 'InsertOrderedList' }
+			},
+			settings.wptextpattern_space_patterns || {}
+		);
 
-		var enterPatterns = [
-			{ start: '##', format: 'h2' },
-			{ start: '###', format: 'h3' },
-			{ start: '####', format: 'h4' },
-			{ start: '#####', format: 'h5' },
-			{ start: '######', format: 'h6' },
-			{ start: '>', format: 'blockquote' },
-			{ regExp: /^(-){3,}$/, element: 'hr' }
-		];
+		var enterPatterns = extend( {
+				h2:         { start: '##', format: 'h2' },
+				h3:         { start: '###', format: 'h3' },
+				h4:         { start: '####', format: 'h4' },
+				h5:         { start: '#####', format: 'h5' },
+				h6:         { start: '######', format: 'h6' },
+				blockquote: { start: '>', format: 'blockquote' },
+				hr:         { regExp: /^(-){3,}$/, element: 'hr' }
+			},
+			settings.wptextpattern_enter_patterns || {}
+		);
 
-		var inlinePatterns = [
-			{ start: '`', end: '`', format: 'code' }
-		];
+		var inlinePatterns = extend( {
+				code: { start: '`', end: '`', format: 'code' }
+			},
+			settings.wptextpattern_inline_patterns || {}
+		);
 
-		var canUndo;
-		var chars = [];
+		// Convert to array and sort descending by start length.
+		function toSortedArray( patterns ) {
+			patterns = tinymce.map( patterns, function( pattern ) {
+				return pattern;
+			} );
 
-		tinymce.each( inlinePatterns, function( pattern ) {
-			tinymce.each( ( pattern.start + pattern.end ).split( '' ), function( c ) {
+			patterns.sort( function( a, b ) {
+				if ( a.start && b.start ) {
+					if ( a.start.length > b.start.length ) {
+						return -1;
+					}
+
+					if ( a.start.length < b.start.length ) {
+						return 1;
+					}
+				}
+
+				return 0;
+			});
+
+			return patterns;
+		}
+
+		spacePatterns = toSortedArray( spacePatterns );
+		enterPatterns = toSortedArray( enterPatterns );
+		inlinePatterns = toSortedArray( inlinePatterns );
+
+		each( inlinePatterns, function( pattern ) {
+			each( ( pattern.start + pattern.end ).split( '' ), function( c ) {
 				if ( tinymce.inArray( chars, c ) === -1 ) {
 					chars.push( c );
 				}
@@ -91,17 +149,18 @@
 			}
 
 			function findStart( node ) {
-				var i = inlinePatterns.length;
 				var offset;
 
-				while ( i-- ) {
-					pattern = inlinePatterns[ i ];
+				each( inlinePatterns, function( currentPattern ) {
+					pattern = currentPattern;
 					offset = node.data.indexOf( pattern.end );
 
 					if ( offset !== -1 ) {
-						return offset;
+						return false;
 					}
-				}
+				} );
+
+				return offset;
 			}
 
 			startOffset = findStart( node );
@@ -201,7 +260,7 @@
 			parent = node.parentNode;
 			text = node.data;
 
-			tinymce.each( spacePatterns, function( pattern ) {
+			each( spacePatterns, function( pattern ) {
 				var match = text.match( pattern.regExp );
 
 				if ( ! match || rng.startOffset !== match[0].length ) {
@@ -234,7 +293,6 @@
 			var rng = editor.selection.getRng(),
 				start = rng.startContainer,
 				node = firstTextNode( start ),
-				i = enterPatterns.length,
 				text, pattern, parent;
 
 			if ( ! node ) {
@@ -243,19 +301,19 @@
 
 			text = node.data;
 
-			while ( i-- ) {
-				if ( enterPatterns[ i ].start ) {
-					if ( text.indexOf( enterPatterns[ i ].start ) === 0 ) {
-						pattern = enterPatterns[ i ];
-						break;
+			each( enterPatterns, function( currentPattern ) {
+				if ( currentPattern.start ) {
+					if ( text.indexOf( currentPattern.start ) === 0 ) {
+						pattern = currentPattern;
+						return false;
 					}
-				} else if ( enterPatterns[ i ].regExp ) {
-					if ( enterPatterns[ i ].regExp.test( text ) ) {
-						pattern = enterPatterns[ i ];
-						break;
+				} else if ( currentPattern.regExp ) {
+					if ( currentPattern.regExp.test( text ) ) {
+						pattern = currentPattern;
+						return false;
 					}
 				}
-			}
+			} );
 
 			if ( ! pattern ) {
 				return;
