wp/wp-includes/js/wplink.js
changeset 7 cf61fcea0001
parent 5 5e2f62d02dcd
child 9 177826044cd9
equal deleted inserted replaced
6:490d5cc509ed 7:cf61fcea0001
     1 /* global ajaxurl, tinymce, wpLinkL10n, setUserSetting, wpActiveEditor */
       
     2 var wpLink;
     1 var wpLink;
     3 
     2 
     4 ( function( $ ) {
     3 ( function( $, wpLinkL10n, wp ) {
     5 	var editor, searchTimer, River, Query, correctedURL,
     4 	var editor, searchTimer, River, Query, correctedURL, linkNode,
       
     5 		emailRegexp = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,63}$/i,
       
     6 		urlRegexp = /^(https?|ftp):\/\/[A-Z0-9.-]+\.[A-Z]{2,63}[^ "]*$/i,
     6 		inputs = {},
     7 		inputs = {},
     7 		rivers = {},
     8 		rivers = {},
     8 		isTouch = ( 'ontouchend' in document );
     9 		isTouch = ( 'ontouchend' in document );
     9 
    10 
    10 	function getLink() {
    11 	function getLink() {
    11 		return editor.dom.getParent( editor.selection.getNode(), 'a' );
    12 		return linkNode || editor.dom.getParent( editor.selection.getNode(), 'a[href]' );
    12 	}
    13 	}
    13 
    14 
    14 	wpLink = {
    15 	wpLink = {
    15 		timeToTriggerRiver: 150,
    16 		timeToTriggerRiver: 150,
    16 		minRiverAJAXDuration: 200,
    17 		minRiverAJAXDuration: 200,
    17 		riverBottomThreshold: 5,
    18 		riverBottomThreshold: 5,
    18 		keySensitivity: 100,
    19 		keySensitivity: 100,
    19 		lastSearch: '',
    20 		lastSearch: '',
    20 		textarea: '',
    21 		textarea: '',
       
    22 		modalOpen: false,
    21 
    23 
    22 		init: function() {
    24 		init: function() {
    23 			inputs.wrap = $('#wp-link-wrap');
    25 			inputs.wrap = $('#wp-link-wrap');
    24 			inputs.dialog = $( '#wp-link' );
    26 			inputs.dialog = $( '#wp-link' );
    25 			inputs.backdrop = $( '#wp-link-backdrop' );
    27 			inputs.backdrop = $( '#wp-link-backdrop' );
    48 			inputs.dialog.keyup( wpLink.keyup );
    50 			inputs.dialog.keyup( wpLink.keyup );
    49 			inputs.submit.click( function( event ) {
    51 			inputs.submit.click( function( event ) {
    50 				event.preventDefault();
    52 				event.preventDefault();
    51 				wpLink.update();
    53 				wpLink.update();
    52 			});
    54 			});
    53 			inputs.close.add( inputs.backdrop ).add( '#wp-link-cancel a' ).click( function( event ) {
    55 
       
    56 			inputs.close.add( inputs.backdrop ).add( '#wp-link-cancel button' ).click( function( event ) {
    54 				event.preventDefault();
    57 				event.preventDefault();
    55 				wpLink.close();
    58 				wpLink.close();
    56 			});
    59 			});
    57 
       
    58 			$( '#wp-link-search-toggle' ).on( 'click', wpLink.toggleInternalLinking );
       
    59 
    60 
    60 			rivers.elements.on( 'river-select', wpLink.updateFields );
    61 			rivers.elements.on( 'river-select', wpLink.updateFields );
    61 
    62 
    62 			// Display 'hint' message when search field or 'query-results' box are focused
    63 			// Display 'hint' message when search field or 'query-results' box are focused
    63 			inputs.search.on( 'focus.wplink', function() {
    64 			inputs.search.on( 'focus.wplink', function() {
    66 			} ).on( 'blur.wplink', function() {
    67 			} ).on( 'blur.wplink', function() {
    67 				inputs.queryNoticeTextDefault.show();
    68 				inputs.queryNoticeTextDefault.show();
    68 				inputs.queryNoticeTextHint.addClass( 'screen-reader-text' ).hide();
    69 				inputs.queryNoticeTextHint.addClass( 'screen-reader-text' ).hide();
    69 			} );
    70 			} );
    70 
    71 
    71 			inputs.search.keyup( function() {
    72 			inputs.search.on( 'keyup input', function() {
    72 				var self = this;
       
    73 
       
    74 				window.clearTimeout( searchTimer );
    73 				window.clearTimeout( searchTimer );
    75 				searchTimer = window.setTimeout( function() {
    74 				searchTimer = window.setTimeout( function() {
    76 					wpLink.searchInternalLinks.call( self );
    75 					wpLink.searchInternalLinks();
    77 				}, 500 );
    76 				}, 500 );
    78 			});
    77 			});
    79 
    78 
    80 			function correctURL() {
       
    81 				var url = $.trim( inputs.url.val() );
       
    82 
       
    83 				if ( url && correctedURL !== url && ! /^(?:[a-z]+:|#|\?|\.|\/)/.test( url ) ) {
       
    84 					inputs.url.val( 'http://' + url );
       
    85 					correctedURL = url;
       
    86 				}
       
    87 			}
       
    88 
       
    89 			inputs.url.on( 'paste', function() {
    79 			inputs.url.on( 'paste', function() {
    90 				setTimeout( correctURL, 0 );
    80 				setTimeout( wpLink.correctURL, 0 );
    91 			} );
    81 			} );
    92 
    82 
    93 			inputs.url.on( 'blur', correctURL );
    83 			inputs.url.on( 'blur', wpLink.correctURL );
    94 		},
    84 		},
    95 
    85 
    96 		open: function( editorId ) {
    86 		// If URL wasn't corrected last time and doesn't start with http:, https:, ? # or /, prepend http://
    97 			var ed;
    87 		correctURL: function () {
    98 
    88 			var url = $.trim( inputs.url.val() );
    99 			$( document.body ).addClass( 'modal-open' );
    89 
       
    90 			if ( url && correctedURL !== url && ! /^(?:[a-z]+:|#|\?|\.|\/)/.test( url ) ) {
       
    91 				inputs.url.val( 'http://' + url );
       
    92 				correctedURL = url;
       
    93 			}
       
    94 		},
       
    95 
       
    96 		open: function( editorId, url, text, node ) {
       
    97 			var ed,
       
    98 				$body = $( document.body );
       
    99 
       
   100 			$body.addClass( 'modal-open' );
       
   101 			wpLink.modalOpen = true;
       
   102 			linkNode = node;
   100 
   103 
   101 			wpLink.range = null;
   104 			wpLink.range = null;
   102 
   105 
   103 			if ( editorId ) {
   106 			if ( editorId ) {
   104 				window.wpActiveEditor = editorId;
   107 				window.wpActiveEditor = editorId;
   108 				return;
   111 				return;
   109 			}
   112 			}
   110 
   113 
   111 			this.textarea = $( '#' + window.wpActiveEditor ).get( 0 );
   114 			this.textarea = $( '#' + window.wpActiveEditor ).get( 0 );
   112 
   115 
   113 			if ( typeof tinymce !== 'undefined' ) {
   116 			if ( typeof window.tinymce !== 'undefined' ) {
   114 				ed = tinymce.get( wpActiveEditor );
   117 				// Make sure the link wrapper is the last element in the body,
       
   118 				// or the inline editor toolbar may show above the backdrop.
       
   119 				$body.append( inputs.backdrop, inputs.wrap );
       
   120 
       
   121 				ed = window.tinymce.get( window.wpActiveEditor );
   115 
   122 
   116 				if ( ed && ! ed.isHidden() ) {
   123 				if ( ed && ! ed.isHidden() ) {
   117 					editor = ed;
   124 					editor = ed;
   118 				} else {
   125 				} else {
   119 					editor = null;
   126 					editor = null;
   120 				}
   127 				}
   121 
       
   122 				if ( editor && tinymce.isIE ) {
       
   123 					editor.windowManager.bookmark = editor.selection.getBookmark();
       
   124 				}
       
   125 			}
   128 			}
   126 
   129 
   127 			if ( ! wpLink.isMCE() && document.selection ) {
   130 			if ( ! wpLink.isMCE() && document.selection ) {
   128 				this.textarea.focus();
   131 				this.textarea.focus();
   129 				this.range = document.selection.createRange();
   132 				this.range = document.selection.createRange();
   130 			}
   133 			}
   131 
   134 
   132 			inputs.wrap.show();
   135 			inputs.wrap.show();
   133 			inputs.backdrop.show();
   136 			inputs.backdrop.show();
   134 
   137 
   135 			wpLink.refresh();
   138 			wpLink.refresh( url, text );
   136 
   139 
   137 			$( document ).trigger( 'wplink-open', inputs.wrap );
   140 			$( document ).trigger( 'wplink-open', inputs.wrap );
   138 		},
   141 		},
   139 
   142 
   140 		isMCE: function() {
   143 		isMCE: function() {
   141 			return editor && ! editor.isHidden();
   144 			return editor && ! editor.isHidden();
   142 		},
   145 		},
   143 
   146 
   144 		refresh: function() {
   147 		refresh: function( url, text ) {
   145 			var text = '';
   148 			var linkText = '';
   146 
   149 
   147 			// Refresh rivers (clear links, check visibility)
   150 			// Refresh rivers (clear links, check visibility)
   148 			rivers.search.refresh();
   151 			rivers.search.refresh();
   149 			rivers.recent.refresh();
   152 			rivers.recent.refresh();
   150 
   153 
   151 			if ( wpLink.isMCE() ) {
   154 			if ( wpLink.isMCE() ) {
   152 				wpLink.mceRefresh();
   155 				wpLink.mceRefresh( url, text );
   153 			} else {
   156 			} else {
   154 				// For the Text editor the "Link text" field is always shown
   157 				// For the Text editor the "Link text" field is always shown
   155 				if ( ! inputs.wrap.hasClass( 'has-text-field' ) ) {
   158 				if ( ! inputs.wrap.hasClass( 'has-text-field' ) ) {
   156 					inputs.wrap.addClass( 'has-text-field' );
   159 					inputs.wrap.addClass( 'has-text-field' );
   157 				}
   160 				}
   158 
   161 
   159 				if ( document.selection ) {
   162 				if ( document.selection ) {
   160 					// Old IE
   163 					// Old IE
   161 					text = document.selection.createRange().text || '';
   164 					linkText = document.selection.createRange().text || text || '';
   162 				} else if ( typeof this.textarea.selectionStart !== 'undefined' &&
   165 				} else if ( typeof this.textarea.selectionStart !== 'undefined' &&
   163 					( this.textarea.selectionStart !== this.textarea.selectionEnd ) ) {
   166 					( this.textarea.selectionStart !== this.textarea.selectionEnd ) ) {
   164 					// W3C
   167 					// W3C
   165 					text = this.textarea.value.substring( this.textarea.selectionStart, this.textarea.selectionEnd ) || '';
   168 					text = this.textarea.value.substring( this.textarea.selectionStart, this.textarea.selectionEnd ) || text || '';
   166 				}
   169 				}
   167 
   170 
   168 				inputs.text.val( text );
   171 				inputs.text.val( text );
   169 				wpLink.setDefaultValues();
   172 				wpLink.setDefaultValues();
   170 			}
   173 			}
   174 				inputs.url.focus().blur();
   177 				inputs.url.focus().blur();
   175 			} else {
   178 			} else {
   176 				// Focus the URL field and highlight its contents.
   179 				// Focus the URL field and highlight its contents.
   177 				// If this is moved above the selection changes,
   180 				// If this is moved above the selection changes,
   178 				// IE will show a flashing cursor over the dialog.
   181 				// IE will show a flashing cursor over the dialog.
   179 				inputs.url.focus()[0].select();
   182 				window.setTimeout( function() {
       
   183 					inputs.url[0].select();
       
   184 					inputs.url.focus();
       
   185 				} );
   180 			}
   186 			}
   181 
   187 
   182 			// Load the most recent results if this is the first time opening the panel.
   188 			// Load the most recent results if this is the first time opening the panel.
   183 			if ( ! rivers.recent.ul.children().length ) {
   189 			if ( ! rivers.recent.ul.children().length ) {
   184 				rivers.recent.ajax();
   190 				rivers.recent.ajax();
   186 
   192 
   187 			correctedURL = inputs.url.val().replace( /^http:\/\//, '' );
   193 			correctedURL = inputs.url.val().replace( /^http:\/\//, '' );
   188 		},
   194 		},
   189 
   195 
   190 		hasSelectedText: function( linkNode ) {
   196 		hasSelectedText: function( linkNode ) {
   191 			var html = editor.selection.getContent();
   197 			var node, nodes, i, html = editor.selection.getContent();
   192 
   198 
   193 			// Partial html and not a fully selected anchor element
   199 			// Partial html and not a fully selected anchor element
   194 			if ( /</.test( html ) && ( ! /^<a [^>]+>[^<]+<\/a>$/.test( html ) || html.indexOf('href=') === -1 ) ) {
   200 			if ( /</.test( html ) && ( ! /^<a [^>]+>[^<]+<\/a>$/.test( html ) || html.indexOf('href=') === -1 ) ) {
   195 				return false;
   201 				return false;
   196 			}
   202 			}
   197 
   203 
   198 			if ( linkNode ) {
   204 			if ( linkNode ) {
   199 				var nodes = linkNode.childNodes, i;
   205 				nodes = linkNode.childNodes;
   200 
   206 
   201 				if ( nodes.length === 0 ) {
   207 				if ( nodes.length === 0 ) {
   202 					return false;
   208 					return false;
   203 				}
   209 				}
   204 
   210 
   205 				for ( i = nodes.length - 1; i >= 0; i-- ) {
   211 				for ( i = nodes.length - 1; i >= 0; i-- ) {
   206 					if ( nodes[i].nodeType != 3 ) {
   212 					node = nodes[i];
       
   213 
       
   214 					if ( node.nodeType != 3 && ! window.tinymce.dom.BookmarkManager.isBookmarkNode( node ) ) {
   207 						return false;
   215 						return false;
   208 					}
   216 					}
   209 				}
   217 				}
   210 			}
   218 			}
   211 
   219 
   212 			return true;
   220 			return true;
   213 		},
   221 		},
   214 
   222 
   215 		mceRefresh: function() {
   223 		mceRefresh: function( searchStr, text ) {
   216 			var text,
   224 			var linkText, href,
   217 				selectedNode = editor.selection.getNode(),
   225 				linkNode = getLink(),
   218 				linkNode = editor.dom.getParent( selectedNode, 'a[href]' ),
       
   219 				onlyText = this.hasSelectedText( linkNode );
   226 				onlyText = this.hasSelectedText( linkNode );
   220 
   227 
   221 			if ( linkNode ) {
   228 			if ( linkNode ) {
   222 				text = linkNode.innerText || linkNode.textContent;
   229 				linkText = linkNode.textContent || linkNode.innerText;
   223 				inputs.url.val( editor.dom.getAttrib( linkNode, 'href' ) );
   230 				href = editor.dom.getAttrib( linkNode, 'href' );
   224 				inputs.openInNewTab.prop( 'checked', '_blank' === editor.dom.getAttrib( linkNode, 'target' ) );
   231 
   225 				inputs.submit.val( wpLinkL10n.update );
   232 				if ( ! $.trim( linkText ) ) {
       
   233 					linkText = text || '';
       
   234 				}
       
   235 
       
   236 				if ( searchStr && ( urlRegexp.test( searchStr ) || emailRegexp.test( searchStr ) ) ) {
       
   237 					href = searchStr;
       
   238 				}
       
   239 
       
   240 				if ( href !== '_wp_link_placeholder' ) {
       
   241 					inputs.url.val( href );
       
   242 					inputs.openInNewTab.prop( 'checked', '_blank' === editor.dom.getAttrib( linkNode, 'target' ) );
       
   243 					inputs.submit.val( wpLinkL10n.update );
       
   244 				} else {
       
   245 					this.setDefaultValues( linkText );
       
   246 				}
       
   247 
       
   248 				if ( searchStr && searchStr !== href ) {
       
   249 					// The user has typed something in the inline dialog. Trigger a search with it.
       
   250 					inputs.search.val( searchStr );
       
   251 				} else {
       
   252 					inputs.search.val( '' );
       
   253 				}
       
   254 
       
   255 				// Always reset the search
       
   256 				window.setTimeout( function() {
       
   257 					wpLink.searchInternalLinks();
       
   258 				} );
   226 			} else {
   259 			} else {
   227 				text = editor.selection.getContent({ format: 'text' });
   260 				linkText = editor.selection.getContent({ format: 'text' }) || text || '';
   228 				this.setDefaultValues();
   261 				this.setDefaultValues( linkText );
   229 			}
   262 			}
   230 
   263 
   231 			if ( onlyText ) {
   264 			if ( onlyText ) {
   232 				inputs.text.val( text || '' );
   265 				inputs.text.val( linkText );
   233 				inputs.wrap.addClass( 'has-text-field' );
   266 				inputs.wrap.addClass( 'has-text-field' );
   234 			} else {
   267 			} else {
   235 				inputs.text.val( '' );
   268 				inputs.text.val( '' );
   236 				inputs.wrap.removeClass( 'has-text-field' );
   269 				inputs.wrap.removeClass( 'has-text-field' );
   237 			}
   270 			}
   238 		},
   271 		},
   239 
   272 
   240 		close: function() {
   273 		close: function( reset ) {
   241 			$( document.body ).removeClass( 'modal-open' );
   274 			$( document.body ).removeClass( 'modal-open' );
   242 
   275 			wpLink.modalOpen = false;
   243 			if ( ! wpLink.isMCE() ) {
   276 
   244 				wpLink.textarea.focus();
   277 			if ( reset !== 'noReset' ) {
   245 
   278 				if ( ! wpLink.isMCE() ) {
   246 				if ( wpLink.range ) {
   279 					wpLink.textarea.focus();
   247 					wpLink.range.moveToBookmark( wpLink.range.getBookmark() );
   280 
   248 					wpLink.range.select();
   281 					if ( wpLink.range ) {
   249 				}
   282 						wpLink.range.moveToBookmark( wpLink.range.getBookmark() );
   250 			} else {
   283 						wpLink.range.select();
   251 				editor.focus();
   284 					}
       
   285 				} else {
       
   286 					if ( editor.plugins.wplink ) {
       
   287 						editor.plugins.wplink.close();
       
   288 					}
       
   289 
       
   290 					editor.focus();
       
   291 				}
   252 			}
   292 			}
   253 
   293 
   254 			inputs.backdrop.hide();
   294 			inputs.backdrop.hide();
   255 			inputs.wrap.hide();
   295 			inputs.wrap.hide();
   256 
   296 
   258 
   298 
   259 			$( document ).trigger( 'wplink-close', inputs.wrap );
   299 			$( document ).trigger( 'wplink-close', inputs.wrap );
   260 		},
   300 		},
   261 
   301 
   262 		getAttrs: function() {
   302 		getAttrs: function() {
       
   303 			wpLink.correctURL();
       
   304 
   263 			return {
   305 			return {
   264 				href: $.trim( inputs.url.val() ),
   306 				href: $.trim( inputs.url.val() ),
   265 				target: inputs.openInNewTab.prop( 'checked' ) ? '_blank' : ''
   307 				target: inputs.openInNewTab.prop( 'checked' ) ? '_blank' : null
   266 			};
   308 			};
       
   309 		},
       
   310 
       
   311 		buildHtml: function(attrs) {
       
   312 			var html = '<a href="' + attrs.href + '"';
       
   313 
       
   314 			if ( attrs.target ) {
       
   315 				html += ' rel="noopener" target="' + attrs.target + '"';
       
   316 			}
       
   317 
       
   318 			return html + '>';
   267 		},
   319 		},
   268 
   320 
   269 		update: function() {
   321 		update: function() {
   270 			if ( wpLink.isMCE() ) {
   322 			if ( wpLink.isMCE() ) {
   271 				wpLink.mceUpdate();
   323 				wpLink.mceUpdate();
   283 			}
   335 			}
   284 
   336 
   285 			attrs = wpLink.getAttrs();
   337 			attrs = wpLink.getAttrs();
   286 			text = inputs.text.val();
   338 			text = inputs.text.val();
   287 
   339 
       
   340 			var parser = document.createElement( 'a' );
       
   341 			parser.href = attrs.href;
       
   342 
       
   343 			if ( 'javascript:' === parser.protocol || 'data:' === parser.protocol ) { // jshint ignore:line
       
   344 				attrs.href = '';
       
   345 			}
       
   346 
   288 			// If there's no href, return.
   347 			// If there's no href, return.
   289 			if ( ! attrs.href ) {
   348 			if ( ! attrs.href ) {
   290 				return;
   349 				return;
   291 			}
   350 			}
   292 
   351 
   293 			// Build HTML
   352 			html = wpLink.buildHtml(attrs);
   294 			html = '<a href="' + attrs.href + '"';
       
   295 
       
   296 			if ( attrs.target ) {
       
   297 				html += ' target="' + attrs.target + '"';
       
   298 			}
       
   299 
       
   300 			html += '>';
       
   301 
   353 
   302 			// Insert HTML
   354 			// Insert HTML
   303 			if ( document.selection && wpLink.range ) {
   355 			if ( document.selection && wpLink.range ) {
   304 				// IE
   356 				// IE
   305 				// Note: If no text is selected, IE will not place the cursor
   357 				// Note: If no text is selected, IE will not place the cursor
   333 				textarea.selectionStart = textarea.selectionEnd = cursor;
   385 				textarea.selectionStart = textarea.selectionEnd = cursor;
   334 			}
   386 			}
   335 
   387 
   336 			wpLink.close();
   388 			wpLink.close();
   337 			textarea.focus();
   389 			textarea.focus();
       
   390 			$( textarea ).trigger( 'change' );
       
   391 
       
   392 			// Audible confirmation message when a link has been inserted in the Editor.
       
   393 			wp.a11y.speak( wpLinkL10n.linkInserted );
   338 		},
   394 		},
   339 
   395 
   340 		mceUpdate: function() {
   396 		mceUpdate: function() {
   341 			var attrs = wpLink.getAttrs(),
   397 			var attrs = wpLink.getAttrs(),
   342 				link, text;
   398 				$link, text, hasText, $mceCaret;
   343 
   399 
   344 			wpLink.close();
   400 			var parser = document.createElement( 'a' );
   345 			editor.focus();
   401 			parser.href = attrs.href;
   346 
   402 
   347 			if ( tinymce.isIE ) {
   403 			if ( 'javascript:' === parser.protocol || 'data:' === parser.protocol ) { // jshint ignore:line
   348 				editor.selection.moveToBookmark( editor.windowManager.bookmark );
   404 				attrs.href = '';
   349 			}
   405 			}
   350 
   406 
   351 			if ( ! attrs.href ) {
   407 			if ( ! attrs.href ) {
   352 				editor.execCommand( 'unlink' );
   408 				editor.execCommand( 'unlink' );
   353 				return;
   409 				wpLink.close();
   354 			}
   410 				return;
   355 
   411 			}
   356 			link = getLink();
   412 
   357 			text = inputs.text.val();
   413 			$link = editor.$( getLink() );
   358 
   414 
   359 			if ( link ) {
   415 			editor.undoManager.transact( function() {
   360 				if ( text ) {
   416 				if ( ! $link.length ) {
   361 					if ( 'innerText' in link ) {
   417 					editor.execCommand( 'mceInsertLink', false, { href: '_wp_link_placeholder', 'data-wp-temp-link': 1 } );
   362 						link.innerText = text;
   418 					$link = editor.$( 'a[data-wp-temp-link="1"]' ).removeAttr( 'data-wp-temp-link' );
   363 					} else {
   419 					hasText = $.trim( $link.text() );
   364 						link.textContent = text;
   420 				}
       
   421 
       
   422 				if ( ! $link.length ) {
       
   423 					editor.execCommand( 'unlink' );
       
   424 				} else {
       
   425 					if ( inputs.wrap.hasClass( 'has-text-field' ) ) {
       
   426 						text = inputs.text.val();
       
   427 
       
   428 						if ( text ) {
       
   429 							$link.text( text );
       
   430 						} else if ( ! hasText ) {
       
   431 							$link.text( attrs.href );
       
   432 						}
   365 					}
   433 					}
   366 				}
   434 
   367 
   435 					attrs['data-wplink-edit'] = null;
   368 				editor.dom.setAttribs( link, attrs );
   436 					attrs['data-mce-href'] = null; // attrs.href
   369 			} else {
   437 					$link.attr( attrs );
   370 				if ( text ) {
   438 				}
   371 					editor.selection.setNode( editor.dom.create( 'a', attrs, text ) );
   439 			} );
   372 				} else {
   440 
   373 					editor.execCommand( 'mceInsertLink', false, attrs );
   441 			wpLink.close( 'noReset' );
   374 				}
   442 			editor.focus();
   375 			}
   443 
       
   444 			if ( $link.length ) {
       
   445 				$mceCaret = $link.parent( '#_mce_caret' );
       
   446 
       
   447 				if ( $mceCaret.length ) {
       
   448 					$mceCaret.before( $link.removeAttr( 'data-mce-bogus' ) );
       
   449 				}
       
   450 
       
   451 				editor.selection.select( $link[0] );
       
   452 				editor.selection.collapse();
       
   453 
       
   454 				if ( editor.plugins.wplink ) {
       
   455 					editor.plugins.wplink.checkLink( $link[0] );
       
   456 				}
       
   457 			}
       
   458 
       
   459 			editor.nodeChanged();
       
   460 
       
   461 			// Audible confirmation message when a link has been inserted in the Editor.
       
   462 			wp.a11y.speak( wpLinkL10n.linkInserted );
   376 		},
   463 		},
   377 
   464 
   378 		updateFields: function( e, li ) {
   465 		updateFields: function( e, li ) {
   379 			inputs.url.val( li.children( '.item-permalink' ).val() );
   466 			inputs.url.val( li.children( '.item-permalink' ).val() );
   380 		},
   467 		},
   381 
   468 
   382 		setDefaultValues: function() {
   469 		getUrlFromSelection: function( selection ) {
   383 			var selection,
   470 			if ( ! selection ) {
   384 				emailRegexp = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i,
   471 				if ( this.isMCE() ) {
   385 				urlRegexp = /^(https?|ftp):\/\/[A-Z0-9.-]+\.[A-Z]{2,4}[^ "]*$/i;
   472 					selection = editor.selection.getContent({ format: 'text' });
   386 
   473 				} else if ( document.selection && wpLink.range ) {
   387 			if ( this.isMCE() ) {
   474 					selection = wpLink.range.text;
   388 				selection = editor.selection.getContent();
   475 				} else if ( typeof this.textarea.selectionStart !== 'undefined' ) {
   389 			} else if ( document.selection && wpLink.range ) {
   476 					selection = this.textarea.value.substring( this.textarea.selectionStart, this.textarea.selectionEnd );
   390 				selection = wpLink.range.text;
   477 				}
   391 			} else if ( typeof this.textarea.selectionStart !== 'undefined' ) {
   478 			}
   392 				selection = this.textarea.value.substring( this.textarea.selectionStart, this.textarea.selectionEnd );
   479 
   393 			}
   480 			selection = $.trim( selection );
   394 
   481 
   395 			if ( selection && emailRegexp.test( selection ) ) {
   482 			if ( selection && emailRegexp.test( selection ) ) {
   396 				// Selection is email address
   483 				// Selection is email address
   397 				inputs.url.val( 'mailto:' + selection );
   484 				return 'mailto:' + selection;
   398 			} else if ( selection && urlRegexp.test( selection ) ) {
   485 			} else if ( selection && urlRegexp.test( selection ) ) {
   399 				// Selection is URL
   486 				// Selection is URL
   400 				inputs.url.val( selection.replace( /&amp;|&#0?38;/gi, '&' ) );
   487 				return selection.replace( /&amp;|&#0?38;/gi, '&' );
   401 			} else {
   488 			}
   402 				// Set URL to default.
   489 
   403 				inputs.url.val( '' );
   490 			return '';
   404 			}
   491 		},
       
   492 
       
   493 		setDefaultValues: function( selection ) {
       
   494 			inputs.url.val( this.getUrlFromSelection( selection ) );
       
   495 
       
   496 			// Empty the search field and swap the "rivers".
       
   497 			inputs.search.val('');
       
   498 			wpLink.searchInternalLinks();
   405 
   499 
   406 			// Update save prompt.
   500 			// Update save prompt.
   407 			inputs.submit.val( wpLinkL10n.save );
   501 			inputs.submit.val( wpLinkL10n.save );
   408 		},
   502 		},
   409 
   503 
   410 		searchInternalLinks: function() {
   504 		searchInternalLinks: function() {
   411 			var t = $( this ), waiting,
   505 			var waiting,
   412 				search = t.val();
   506 				search = inputs.search.val() || '';
   413 
   507 
   414 			if ( search.length > 2 ) {
   508 			if ( search.length > 2 ) {
   415 				rivers.recent.hide();
   509 				rivers.recent.hide();
   416 				rivers.search.show();
   510 				rivers.search.show();
   417 
   511 
   418 				// Don't search if the keypress didn't change the title.
   512 				// Don't search if the keypress didn't change the title.
   419 				if ( wpLink.lastSearch == search )
   513 				if ( wpLink.lastSearch == search )
   420 					return;
   514 					return;
   421 
   515 
   422 				wpLink.lastSearch = search;
   516 				wpLink.lastSearch = search;
   423 				waiting = t.parent().find( '.spinner' ).addClass( 'is-active' );
   517 				waiting = inputs.search.parent().find( '.spinner' ).addClass( 'is-active' );
   424 
   518 
   425 				rivers.search.change( search );
   519 				rivers.search.change( search );
   426 				rivers.search.ajax( function() {
   520 				rivers.search.ajax( function() {
   427 					waiting.removeClass( 'is-active' );
   521 					waiting.removeClass( 'is-active' );
   428 				});
   522 				});
   441 			rivers.search.prev();
   535 			rivers.search.prev();
   442 			rivers.recent.prev();
   536 			rivers.recent.prev();
   443 		},
   537 		},
   444 
   538 
   445 		keydown: function( event ) {
   539 		keydown: function( event ) {
   446 			var fn, id,
   540 			var fn, id;
   447 				key = $.ui.keyCode;
   541 
   448 
   542 			// Escape key.
   449 			if ( key.ESCAPE === event.keyCode ) {
   543 			if ( 27 === event.keyCode ) {
   450 				wpLink.close();
   544 				wpLink.close();
   451 				event.stopImmediatePropagation();
   545 				event.stopImmediatePropagation();
   452 			} else if ( key.TAB === event.keyCode ) {
   546 			// Tab key.
       
   547 			} else if ( 9 === event.keyCode ) {
   453 				id = event.target.id;
   548 				id = event.target.id;
   454 
   549 
   455 				// wp-link-submit must always be the last focusable element in the dialog.
   550 				// wp-link-submit must always be the last focusable element in the dialog.
   456 				// following focusable elements will be skipped on keyboard navigation.
   551 				// following focusable elements will be skipped on keyboard navigation.
   457 				if ( id === 'wp-link-submit' && ! event.shiftKey ) {
   552 				if ( id === 'wp-link-submit' && ! event.shiftKey ) {
   461 					inputs.submit.focus();
   556 					inputs.submit.focus();
   462 					event.preventDefault();
   557 					event.preventDefault();
   463 				}
   558 				}
   464 			}
   559 			}
   465 
   560 
   466 			if ( event.keyCode !== key.UP && event.keyCode !== key.DOWN ) {
   561 			// Up Arrow and Down Arrow keys.
       
   562 			if ( 38 !== event.keyCode && 40 !== event.keyCode ) {
   467 				return;
   563 				return;
   468 			}
   564 			}
   469 
   565 
   470 			if ( document.activeElement &&
   566 			if ( document.activeElement &&
   471 				( document.activeElement.id === 'link-title-field' || document.activeElement.id === 'url-field' ) ) {
   567 				( document.activeElement.id === 'link-title-field' || document.activeElement.id === 'url-field' ) ) {
   472 				return;
   568 				return;
   473 			}
   569 			}
   474 
   570 
   475 			fn = event.keyCode === key.UP ? 'prev' : 'next';
   571 			// Up Arrow key.
       
   572 			fn = 38 === event.keyCode ? 'prev' : 'next';
   476 			clearInterval( wpLink.keyInterval );
   573 			clearInterval( wpLink.keyInterval );
   477 			wpLink[ fn ]();
   574 			wpLink[ fn ]();
   478 			wpLink.keyInterval = setInterval( wpLink[ fn ], wpLink.keySensitivity );
   575 			wpLink.keyInterval = setInterval( wpLink[ fn ], wpLink.keySensitivity );
   479 			event.preventDefault();
   576 			event.preventDefault();
   480 		},
   577 		},
   481 
   578 
   482 		keyup: function( event ) {
   579 		keyup: function( event ) {
   483 			var key = $.ui.keyCode;
   580 			// Up Arrow and Down Arrow keys.
   484 
   581 			if ( 38 === event.keyCode || 40 === event.keyCode ) {
   485 			if ( event.which === key.UP || event.which === key.DOWN ) {
       
   486 				clearInterval( wpLink.keyInterval );
   582 				clearInterval( wpLink.keyInterval );
   487 				event.preventDefault();
   583 				event.preventDefault();
   488 			}
   584 			}
   489 		},
   585 		},
   490 
   586 
   507 				// Otherwise, wait.
   603 				// Otherwise, wait.
   508 				funcArgs = arguments;
   604 				funcArgs = arguments;
   509 				funcContext = this;
   605 				funcContext = this;
   510 				funcTriggered = true;
   606 				funcTriggered = true;
   511 			};
   607 			};
   512 		},
       
   513 
       
   514 		toggleInternalLinking: function( event ) {
       
   515 			var visible = inputs.wrap.hasClass( 'search-panel-visible' );
       
   516 
       
   517 			inputs.wrap.toggleClass( 'search-panel-visible', ! visible );
       
   518 			setUserSetting( 'wplink', visible ? '0' : '1' );
       
   519 			inputs[ ! visible ? 'search' : 'url' ].focus();
       
   520 			event.preventDefault();
       
   521 		}
   608 		}
   522 	};
   609 	};
   523 
   610 
   524 	River = function( element, search ) {
   611 	River = function( element, search ) {
   525 		var self = this;
   612 		var self = this;
   692 			if ( this.search )
   779 			if ( this.search )
   693 				query.search = this.search;
   780 				query.search = this.search;
   694 
   781 
   695 			this.querying = true;
   782 			this.querying = true;
   696 
   783 
   697 			$.post( ajaxurl, query, function( r ) {
   784 			$.post( window.ajaxurl, query, function( r ) {
   698 				self.page++;
   785 				self.page++;
   699 				self.querying = false;
   786 				self.querying = false;
   700 				self.allLoaded = ! r;
   787 				self.allLoaded = ! r;
   701 				callback( r, query );
   788 				callback( r, query );
   702 			}, 'json' );
   789 			}, 'json' );
   703 		}
   790 		}
   704 	});
   791 	});
   705 
   792 
   706 	$( document ).ready( wpLink.init );
   793 	$( document ).ready( wpLink.init );
   707 })( jQuery );
   794 })( jQuery, window.wpLinkL10n, window.wp );