Ticket #36359: 36359.4.patch
File 36359.4.patch, 26.2 KB (added by , 8 years ago) |
---|
-
src/wp-admin/includes/upgrade.php
1682 1682 if ( $wp_current_db_version < 36679 && is_multisite() ) { 1683 1683 $wpdb->query( "DELETE FROM $wpdb->options WHERE option_name REGEXP '^[0-9]+_new_email$'" ); 1684 1684 } 1685 1686 // Remove unused user setting for wpLink.1687 delete_user_setting( 'wplink' );1688 1685 } 1689 1686 1690 1687 /** -
src/wp-includes/class-wp-editor.php
1402 1402 * @static 1403 1403 */ 1404 1404 public static function wp_link_dialog() { 1405 $search_panel_visible = '1' == get_user_setting( 'wplink', '0' ) ? ' search-panel-visible' : ''; 1406 1405 1407 // display: none is required here, see #WP27605 1406 1408 ?> 1407 1409 <div id="wp-link-backdrop" style="display: none"></div> 1408 <div id="wp-link-wrap" class="wp-core-ui " style="display: none" role="dialog" aria-labelledby="link-modal-title">1410 <div id="wp-link-wrap" class="wp-core-ui<?php echo $search_panel_visible; ?>" style="display: none" role="dialog" aria-labelledby="link-modal-title"> 1409 1411 <form id="wp-link" tabindex="-1"> 1410 1412 <?php wp_nonce_field( 'internal-linking', '_ajax_linking_nonce', false ); ?> 1411 1413 <h1 id="link-modal-title"><?php _e( 'Insert/edit link' ) ?></h1> … … 1412 1414 <button type="button" id="wp-link-close"><span class="screen-reader-text"><?php _e( 'Close' ); ?></span></button> 1413 1415 <div id="link-selector"> 1414 1416 <div id="link-options"> 1417 <p class="howto"><?php _e( 'Enter the destination URL' ); ?></p> 1415 1418 <div> 1416 1419 <label><span><?php _e( 'URL' ); ?></span> 1417 <input id="wp-link-url" type="text" role="combobox" aria-autocomplete="list" aria-expanded="false" placeholder="<?php _e( 'Paste URL or type to search' ); ?>"/></label>1420 <input id="wp-link-url" type="text" /></label> 1418 1421 </div> 1419 1422 <div class="wp-link-text-field"> 1420 1423 <label><span><?php _e( 'Link Text' ); ?></span> … … 1425 1428 <input type="checkbox" id="wp-link-target" /> <?php _e( 'Open link in a new tab' ); ?></label> 1426 1429 </div> 1427 1430 </div> 1431 <p class="howto"><a href="#" id="wp-link-search-toggle"><?php _e( 'Or link to existing content' ); ?></a></p> 1432 <div id="search-panel"> 1433 <div class="link-search-wrapper"> 1434 <label> 1435 <span class="search-label"><?php _e( 'Search' ); ?></span> 1436 <input type="search" id="wp-link-search" class="link-search-field" autocomplete="off" /> 1437 <span class="spinner"></span> 1438 </label> 1439 </div> 1440 <div id="search-results" class="query-results" tabindex="0"> 1441 <ul></ul> 1442 <div class="river-waiting"> 1443 <span class="spinner"></span> 1444 </div> 1445 </div> 1446 <div id="most-recent-results" class="query-results" tabindex="0"> 1447 <div class="query-notice" id="query-notice-message"> 1448 <em class="query-notice-default"><?php _e( 'No search term specified. Showing recent items.' ); ?></em> 1449 <em class="query-notice-hint screen-reader-text"><?php _e( 'Search or use up and down arrow keys to select an item.' ); ?></em> 1450 </div> 1451 <ul></ul> 1452 <div class="river-waiting"> 1453 <span class="spinner"></span> 1454 </div> 1455 </div> 1456 </div> 1428 1457 </div> 1429 1458 <div class="submitbox"> 1430 1459 <div id="wp-link-cancel"> -
src/wp-includes/css/editor.css
95 95 } 96 96 97 97 .mce-textbox, 98 .mce-checkbox i.mce-i-checkbox { 98 .mce-checkbox i.mce-i-checkbox, 99 #wp-link .query-results { 99 100 border: 1px solid #ddd; 100 101 -webkit-border-radius: 0; 101 102 border-radius: 0; … … 1374 1375 height: 100%; 1375 1376 } 1376 1377 1378 #wp-link-wrap.search-panel-visible { 1379 height: 500px; 1380 margin-top: -250px; 1381 } 1382 1377 1383 #wp-link-wrap .wp-link-text-field { 1378 1384 display: none; 1379 1385 } … … 1437 1443 padding: 0 16px 50px; 1438 1444 } 1439 1445 1446 #wp-link-wrap.search-panel-visible #link-selector { 1447 -webkit-overflow-scrolling: touch; 1448 padding: 0 16px; 1449 position: absolute; 1450 top: 36px; 1451 left: 0; 1452 right: 0; 1453 bottom: 44px; 1454 } 1455 1440 1456 #wp-link ol, 1441 1457 #wp-link ul { 1442 1458 list-style: none; … … 1444 1460 padding: 0; 1445 1461 } 1446 1462 1463 #wp-link-search-toggle:after { 1464 display: inline-block; 1465 font: normal 20px/1 dashicons; 1466 vertical-align: top; 1467 speak: none; 1468 -webkit-font-smoothing: antialiased; 1469 -moz-osx-font-smoothing: grayscale; 1470 content: "\f140"; 1471 } 1472 1473 .search-panel-visible #wp-link-search-toggle:after { 1474 content: "\f142"; 1475 } 1476 1447 1477 #wp-link input[type="text"] { 1448 1478 -webkit-box-sizing: border-box; 1449 1479 -moz-box-sizing: border-box; … … 1463 1493 color: inherit; 1464 1494 } 1465 1495 1496 #wp-link-search-toggle { 1497 cursor: pointer; 1498 } 1499 1466 1500 #wp-link label input[type="text"] { 1467 margin : 8px 0 0;1501 margin-top: 5px; 1468 1502 width: 70%; 1469 1503 } 1470 1504 1471 #wp-link #link-options label span { 1505 #wp-link #link-options label span, 1506 #wp-link #search-panel label span.search-label { 1472 1507 display: inline-block; 1473 1508 width: 80px; 1474 1509 text-align: right; … … 1478 1513 word-wrap: break-word; 1479 1514 } 1480 1515 1516 #wp-link .link-search-field { 1517 float: left; 1518 width: 250px; 1519 max-width: 70%; 1520 } 1521 1522 #wp-link .link-search-wrapper { 1523 margin: 5px 0 9px; 1524 display: block; 1525 overflow: hidden; 1526 } 1527 1528 #wp-link .link-search-wrapper span { 1529 float: left; 1530 margin-top: 4px; 1531 } 1532 1533 #wp-link .link-search-wrapper .spinner { 1534 margin-top: 5px; 1535 } 1536 1481 1537 #wp-link .link-target { 1482 1538 padding: 3px 0 0; 1483 1539 white-space: nowrap; … … 1489 1545 max-width: 70%; 1490 1546 } 1491 1547 1548 #wp-link .query-results { 1549 border: 1px #dfdfdf solid; 1550 margin: 0; 1551 background: #fff; 1552 overflow: auto; 1553 position: absolute; 1554 left: 16px; 1555 right: 16px; 1556 bottom: 16px; 1557 top: 172px; 1558 } 1559 1560 .has-text-field #wp-link .query-results { 1561 top: 205px; 1562 } 1563 1564 #wp-link li { 1565 clear: both; 1566 margin-bottom: 0; 1567 border-bottom: 1px solid #f1f1f1; 1568 color: #32373c; 1569 padding: 4px 6px 4px 10px; 1570 cursor: pointer; 1571 position: relative; 1572 } 1573 1574 #wp-link .query-notice { 1575 padding: 0; 1576 border-bottom: 1px solid #dfdfdf; 1577 background-color: #f7fcfe; 1578 color: #000; 1579 } 1580 1581 #wp-link .query-notice .query-notice-default, 1582 #wp-link .query-notice .query-notice-hint { 1583 display: block; 1584 padding: 6px; 1585 border-left: 4px solid #00a0d2; 1586 } 1587 1588 #wp-link .unselectable.no-matches-found { 1589 padding: 0; 1590 border-bottom: 1px solid #dfdfdf; 1591 background-color: #fef7f1; 1592 } 1593 1594 #wp-link .no-matches-found .item-title { 1595 display: block; 1596 padding: 6px; 1597 border-left: 4px solid #d54e21; 1598 } 1599 1600 #wp-link .query-results em { 1601 font-style: normal; 1602 } 1603 1604 #wp-link li:hover { 1605 background: #eaf2fa; 1606 color: #151515; 1607 } 1608 1609 #wp-link li.unselectable { 1610 border-bottom: 1px solid #dfdfdf; 1611 } 1612 1613 #wp-link li.unselectable:hover { 1614 background: #fff; 1615 cursor: auto; 1616 color: #32373c; 1617 } 1618 1619 #wp-link li.selected { 1620 background: #ddd; 1621 color: #32373c; 1622 } 1623 1624 #wp-link li.selected .item-title { 1625 font-weight: bold; 1626 } 1627 1628 #wp-link li:last-child { 1629 border: none; 1630 } 1631 1632 #wp-link .item-title { 1633 display: inline-block; 1634 width: 80%; 1635 width: -webkit-calc(100% - 68px); 1636 width: calc(100% - 68px); 1637 word-wrap: break-word; 1638 } 1639 1640 #wp-link .item-info { 1641 text-transform: uppercase; 1642 color: #666; 1643 font-size: 11px; 1644 position: absolute; 1645 right: 5px; 1646 top: 5px; 1647 } 1648 1649 #wp-link #search-results, 1650 #wp-link #search-panel { 1651 display: none; 1652 } 1653 1654 #wp-link-wrap.search-panel-visible #search-panel { 1655 display: block; 1656 } 1657 1658 #wp-link .river-waiting { 1659 display: none; 1660 padding: 10px 0; 1661 } 1662 1492 1663 #wp-link .submitbox { 1493 1664 padding: 8px 16px; 1494 1665 background: #fcfcfc; … … 1518 1689 margin-top: -140px; 1519 1690 } 1520 1691 1692 #wp-link-wrap.search-panel-visible .query-results { 1693 top: 195px; 1694 } 1695 1696 #wp-link-wrap.search-panel-visible.has-text-field .query-results { 1697 top: 235px; 1698 } 1699 1521 1700 #link-selector { 1522 1701 padding: 0 16px 60px; 1523 1702 } 1524 1703 1704 #wp-link-wrap.search-panel-visible #link-selector { 1705 bottom: 52px; 1706 } 1707 1525 1708 #wp-link-cancel { 1526 1709 line-height: 32px; 1527 1710 } … … 1550 1733 -webkit-transition: none; 1551 1734 transition: none; 1552 1735 } 1736 1737 #wp-link-wrap.search-panel-visible { 1738 height: auto; 1739 margin-top: 0; 1740 top: 10px; 1741 bottom: 10px; 1742 } 1743 1744 .search-panel-visible #link-selector { 1745 overflow: auto; 1746 } 1747 1748 .search-panel-visible #search-panel .query-results { 1749 position: static; 1750 } 1553 1751 } 1554 1752 1555 1753 @media screen and ( max-height: 290px ) { … … 1566 1764 height: calc(100% - 92px); 1567 1765 padding-bottom: 2px; 1568 1766 } 1767 1768 #search-panel .query-results { 1769 position: static; 1770 } 1569 1771 } 1570 1772 1571 1773 div.wp-link-preview { -
src/wp-includes/js/wplink.js
1 2 1 var wpLink; 3 2 4 3 ( function( $, wpLinkL10n, wp ) { 5 var editor, correctedURL, linkNode, 4 var editor, searchTimer, River, Query, correctedURL, linkNode, 5 emailRegexp = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i, 6 urlRegexp = /^(https?|ftp):\/\/[A-Z0-9.-]+\.[A-Z]{2,4}[^ "]*$/i, 6 7 inputs = {}, 8 rivers = {}, 7 9 isTouch = ( 'ontouchend' in document ); 8 10 9 11 function getLink() { … … 11 13 } 12 14 13 15 wpLink = { 16 timeToTriggerRiver: 150, 17 minRiverAJAXDuration: 200, 18 riverBottomThreshold: 5, 19 keySensitivity: 100, 20 lastSearch: '', 14 21 textarea: '', 15 22 16 23 init: function() { … … 23 30 // Input 24 31 inputs.text = $( '#wp-link-text' ); 25 32 inputs.url = $( '#wp-link-url' ); 33 inputs.nonce = $( '#_ajax_linking_nonce' ); 26 34 inputs.openInNewTab = $( '#wp-link-target' ); 35 inputs.search = $( '#wp-link-search' ); 27 36 28 if ( $.ui && $.ui.autocomplete ) { 29 wpLink.setAutocomplete(); 30 } 37 // Build Rivers 38 rivers.search = new River( $( '#search-results' ) ); 39 rivers.recent = new River( $( '#most-recent-results' ) ); 40 rivers.elements = inputs.dialog.find( '.query-results' ); 31 41 32 inputs.dialog.on( 'keydown', wpLink.keydown ); 33 inputs.submit.on( 'click', function( event ) { 42 // Get search notice text 43 inputs.queryNotice = $( '#query-notice-message' ); 44 inputs.queryNoticeTextDefault = inputs.queryNotice.find( '.query-notice-default' ); 45 inputs.queryNoticeTextHint = inputs.queryNotice.find( '.query-notice-hint' ); 46 47 // Bind event handlers 48 inputs.dialog.keydown( wpLink.keydown ); 49 inputs.dialog.keyup( wpLink.keyup ); 50 inputs.submit.click( function( event ) { 34 51 event.preventDefault(); 35 52 wpLink.update(); 36 53 }); … … 40 57 wpLink.close(); 41 58 }); 42 59 43 inputs.url.on( 'paste', function() { 44 setTimeout( wpLink.correctURL, 0 ); 45 } ); 46 }, 60 $( '#wp-link-search-toggle' ).on( 'click', wpLink.toggleInternalLinking ); 47 61 48 setAutocomplete: function() { 49 var $input = inputs.url, 50 cache, last; 62 rivers.elements.on( 'river-select', wpLink.updateFields ); 51 63 52 $input.on( 'keydown', function() {53 $input.removeAttr( 'aria-activedescendant' );54 } ).autocomplete( {55 source: function( request, response ) {56 if ( last === request.term) {57 response( cache);58 return;59 }64 // Display 'hint' message when search field or 'query-results' box are focused 65 inputs.search.on( 'focus.wplink', function() { 66 inputs.queryNoticeTextDefault.hide(); 67 inputs.queryNoticeTextHint.removeClass( 'screen-reader-text' ).show(); 68 } ).on( 'blur.wplink', function() { 69 inputs.queryNoticeTextDefault.show(); 70 inputs.queryNoticeTextHint.addClass( 'screen-reader-text' ).hide(); 71 } ); 60 72 61 if ( /^https?:/.test( request.term ) || request.term.indexOf( '.' ) !== -1 ) { 62 return response(); 63 } 73 inputs.search.on( 'keyup input', function() { 74 window.clearTimeout( searchTimer ); 75 searchTimer = window.setTimeout( function() { 76 wpLink.searchInternalLinks(); 77 }, 500 ); 78 }); 64 79 65 $.post( window.ajaxurl, { 66 action: 'wp-link-ajax', 67 page: 1, 68 search: request.term, 69 _ajax_linking_nonce: $( '#_ajax_linking_nonce' ).val() 70 }, function( data ) { 71 cache = data; 72 response( data ); 73 }, 'json' ); 80 inputs.url.on( 'paste', function() { 81 setTimeout( wpLink.correctURL, 0 ); 82 } ); 74 83 75 last = request.term; 76 }, 77 focus: function( event, ui ) { 78 $input.attr( 'aria-activedescendant', 'mce-wp-autocomplete-' + ui.item.ID ); 79 /* 80 * Don't empty the URL input field, when using the arrow keys to 81 * highlight items. See api.jqueryui.com/autocomplete/#event-focus 82 */ 83 event.preventDefault(); 84 }, 85 select: function( event, ui ) { 86 $input.val( ui.item.permalink ); 87 88 if ( inputs.wrap.hasClass( 'has-text-field' ) && $.trim( inputs.text.val() ) === '' ) { 89 inputs.text.val( ui.item.title ); 90 } 91 92 // Audible confirmation message when a link has been selected. 93 wp.a11y.speak( wpLinkL10n.linkSelected ); 94 95 return false; 96 }, 97 open: function() { 98 $input.attr( 'aria-expanded', 'true' ); 99 }, 100 close: function() { 101 $input.attr( 'aria-expanded', 'false' ); 102 }, 103 minLength: 2, 104 position: { 105 my: 'left top+2' 106 }, 107 messages: { 108 noResults: ( typeof window.uiAutocompleteL10n !== 'undefined' ) ? window.uiAutocompleteL10n.noResults : '', 109 results: function( number ) { 110 if ( typeof window.uiAutocompleteL10n !== 'undefined' ) { 111 if ( number > 1 ) { 112 return window.uiAutocompleteL10n.manyResults.replace( '%d', number ); 113 } 114 115 return window.uiAutocompleteL10n.oneResult; 116 } 117 } 118 } 119 } ).autocomplete( 'instance' )._renderItem = function( ul, item ) { 120 return $( '<li role="option" id="mce-wp-autocomplete-' + item.ID + '">' ) 121 .append( '<span class="item-title">' + item.title + '</span> <span class="item-date alignright">' + item.info + '</span>' ) 122 .appendTo( ul ); 123 }; 124 125 $input.attr( { 126 'aria-owns': $input.autocomplete( 'widget' ).attr( 'id' ) 127 } ) 128 .on( 'focus', function() { 129 var inputValue = $input.val(); 130 /* 131 * Don't trigger a search if the URL field already has a link or is empty. 132 * Also, avoids screen readers announce `No search results`. 133 */ 134 if ( inputValue && ! /^https?:/.test( inputValue ) ) { 135 $input.autocomplete( 'search' ); 136 } 137 } ) 138 .autocomplete( 'widget' ) 139 .addClass( 'wplink-autocomplete' ) 140 .attr( 'role', 'listbox' ) 141 .removeAttr( 'tabindex' ); // Remove the `tabindex=0` attribute added by jQuery UI. 84 inputs.url.on( 'blur', wpLink.correctURL ); 142 85 }, 143 86 144 87 // If URL wasn't corrected last time and doesn't start with http:, https:, ? # or /, prepend http:// … … 208 151 refresh: function( url, text ) { 209 152 var linkText = ''; 210 153 154 // Refresh rivers (clear links, check visibility) 155 rivers.search.refresh(); 156 rivers.recent.refresh(); 157 211 158 if ( wpLink.isMCE() ) { 212 159 wpLink.mceRefresh( url, text ); 213 160 } else { … … 237 184 // If this is moved above the selection changes, 238 185 // IE will show a flashing cursor over the dialog. 239 186 window.setTimeout( function() { 240 inputs.url.focus()[0].select(); 187 inputs.url[0].select(); 188 inputs.url.focus(); 241 189 } ); 242 190 } 243 191 192 // Load the most recent results if this is the first time opening the panel. 193 if ( ! rivers.recent.ul.children().length ) { 194 rivers.recent.ajax(); 195 } 196 244 197 correctedURL = inputs.url.val().replace( /^http:\/\//, '' ); 245 198 }, 246 199 … … 271 224 return true; 272 225 }, 273 226 274 mceRefresh: function( url, text ) {275 var linkText, 227 mceRefresh: function( searchStr, text ) { 228 var linkText, href, 276 229 linkNode = getLink(), 277 230 onlyText = this.hasSelectedText( linkNode ); 278 231 279 232 if ( linkNode ) { 280 233 linkText = linkNode.innerText || linkNode.textContent; 234 href = editor.dom.getAttrib( linkNode, 'href' ); 281 235 282 236 if ( ! $.trim( linkText ) ) { 283 237 linkText = text || ''; 284 238 } 285 239 286 url = url || editor.dom.getAttrib( linkNode, 'href' ); 240 if ( searchStr && ( urlRegexp.test( searchStr ) || emailRegexp.test( searchStr ) ) ) { 241 href = searchStr; 242 } 287 243 288 if ( url!== '_wp_link_placeholder' ) {289 inputs.url.val( url);244 if ( href !== '_wp_link_placeholder' ) { 245 inputs.url.val( href ); 290 246 inputs.openInNewTab.prop( 'checked', '_blank' === editor.dom.getAttrib( linkNode, 'target' ) ); 291 247 inputs.submit.val( wpLinkL10n.update ); 292 248 } else { 293 249 this.setDefaultValues( linkText ); 294 250 } 251 252 if ( searchStr && searchStr !== href ) { 253 // The user has typed something in the inline dialog. Trigger a search with it. 254 inputs.search.val( searchStr ); 255 window.setTimeout( function() { 256 wpLink.searchInternalLinks(); 257 } ); 258 // Show the search panel if hidden. 259 if ( ! inputs.wrap.hasClass( 'search-panel-visible' ) ) { 260 wpLink.toggleInternalLinking(); 261 } 262 } 295 263 } else { 296 264 linkText = editor.selection.getContent({ format: 'text' }) || text || ''; 297 265 this.setDefaultValues( linkText ); … … 424 392 var attrs = wpLink.getAttrs(), 425 393 link, text; 426 394 427 editor.focus();428 429 395 if ( window.tinymce.isIE && editor.windowManager.wplinkBookmark ) { 430 396 editor.selection.moveToBookmark( editor.windowManager.wplinkBookmark ); 431 397 editor.windowManager.wplinkBookmark = null; … … 471 437 wp.a11y.speak( wpLinkL10n.linkInserted ); 472 438 }, 473 439 474 keydown: function( event ) { 475 var id; 476 477 // Escape key. 478 if ( 27 === event.keyCode ) { 479 wpLink.close(); 480 event.stopImmediatePropagation(); 481 // Tab key. 482 } else if ( 9 === event.keyCode ) { 483 id = event.target.id; 484 485 // wp-link-submit must always be the last focusable element in the dialog. 486 // following focusable elements will be skipped on keyboard navigation. 487 if ( id === 'wp-link-submit' && ! event.shiftKey ) { 488 inputs.close.focus(); 489 event.preventDefault(); 490 } else if ( id === 'wp-link-close' && event.shiftKey ) { 491 inputs.submit.focus(); 492 event.preventDefault(); 493 } 494 } 440 updateFields: function( e, li ) { 441 inputs.url.val( li.children( '.item-permalink' ).val() ); 495 442 }, 496 443 497 444 getUrlFromSelection: function( selection ) { 498 var emailRegexp = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i,499 urlRegexp = /^(https?|ftp):\/\/[A-Z0-9.-]+\.[A-Z]{2,4}[^ "]*$/i;500 501 445 if ( ! selection ) { 502 446 if ( this.isMCE() ) { 503 447 selection = editor.selection.getContent({ format: 'text' }); … … 526 470 527 471 // Update save prompt. 528 472 inputs.submit.val( wpLinkL10n.save ); 473 }, 474 475 searchInternalLinks: function() { 476 var waiting, 477 search = inputs.search.val() || ''; 478 479 if ( search.length > 2 ) { 480 rivers.recent.hide(); 481 rivers.search.show(); 482 483 // Don't search if the keypress didn't change the title. 484 if ( wpLink.lastSearch == search ) 485 return; 486 487 wpLink.lastSearch = search; 488 waiting = inputs.search.parent().find( '.spinner' ).addClass( 'is-active' ); 489 490 rivers.search.change( search ); 491 rivers.search.ajax( function() { 492 waiting.removeClass( 'is-active' ); 493 }); 494 } else { 495 rivers.search.hide(); 496 rivers.recent.show(); 497 } 498 }, 499 500 next: function() { 501 rivers.search.next(); 502 rivers.recent.next(); 503 }, 504 505 prev: function() { 506 rivers.search.prev(); 507 rivers.recent.prev(); 508 }, 509 510 keydown: function( event ) { 511 var fn, id; 512 513 // Escape key. 514 if ( 27 === event.keyCode ) { 515 wpLink.close(); 516 event.stopImmediatePropagation(); 517 // Tab key. 518 } else if ( 9 === event.keyCode ) { 519 id = event.target.id; 520 521 // wp-link-submit must always be the last focusable element in the dialog. 522 // following focusable elements will be skipped on keyboard navigation. 523 if ( id === 'wp-link-submit' && ! event.shiftKey ) { 524 inputs.close.focus(); 525 event.preventDefault(); 526 } else if ( id === 'wp-link-close' && event.shiftKey ) { 527 inputs.submit.focus(); 528 event.preventDefault(); 529 } 530 } 531 532 // Up Arrow and Down Arrow keys. 533 if ( 38 !== event.keyCode && 40 !== event.keyCode ) { 534 return; 535 } 536 537 if ( document.activeElement && 538 ( document.activeElement.id === 'link-title-field' || document.activeElement.id === 'url-field' ) ) { 539 return; 540 } 541 542 // Up Arrow key. 543 fn = 38 === event.keyCode ? 'prev' : 'next'; 544 clearInterval( wpLink.keyInterval ); 545 wpLink[ fn ](); 546 wpLink.keyInterval = setInterval( wpLink[ fn ], wpLink.keySensitivity ); 547 event.preventDefault(); 548 }, 549 550 keyup: function( event ) { 551 // Up Arrow and Down Arrow keys. 552 if ( 38 === event.keyCode || 40 === event.keyCode ) { 553 clearInterval( wpLink.keyInterval ); 554 event.preventDefault(); 555 } 556 }, 557 558 delayedCallback: function( func, delay ) { 559 var timeoutTriggered, funcTriggered, funcArgs, funcContext; 560 561 if ( ! delay ) 562 return func; 563 564 setTimeout( function() { 565 if ( funcTriggered ) 566 return func.apply( funcContext, funcArgs ); 567 // Otherwise, wait. 568 timeoutTriggered = true; 569 }, delay ); 570 571 return function() { 572 if ( timeoutTriggered ) 573 return func.apply( this, arguments ); 574 // Otherwise, wait. 575 funcArgs = arguments; 576 funcContext = this; 577 funcTriggered = true; 578 }; 579 }, 580 581 toggleInternalLinking: function( event ) { 582 var visible = inputs.wrap.hasClass( 'search-panel-visible' ); 583 584 inputs.wrap.toggleClass( 'search-panel-visible', ! visible ); 585 window.setUserSetting( 'wplink', visible ? '0' : '1' ); 586 587 if ( event ) { 588 event.preventDefault(); 589 } 529 590 } 530 591 }; 531 592 593 River = function( element, search ) { 594 var self = this; 595 this.element = element; 596 this.ul = element.children( 'ul' ); 597 this.contentHeight = element.children( '#link-selector-height' ); 598 this.waiting = element.find('.river-waiting'); 599 600 this.change( search ); 601 this.refresh(); 602 603 $( '#wp-link .query-results, #wp-link #link-selector' ).scroll( function() { 604 self.maybeLoad(); 605 }); 606 element.on( 'click', 'li', function( event ) { 607 self.select( $( this ), event ); 608 }); 609 }; 610 611 $.extend( River.prototype, { 612 refresh: function() { 613 this.deselect(); 614 this.visible = this.element.is( ':visible' ); 615 }, 616 show: function() { 617 if ( ! this.visible ) { 618 this.deselect(); 619 this.element.show(); 620 this.visible = true; 621 } 622 }, 623 hide: function() { 624 this.element.hide(); 625 this.visible = false; 626 }, 627 // Selects a list item and triggers the river-select event. 628 select: function( li, event ) { 629 var liHeight, elHeight, liTop, elTop; 630 631 if ( li.hasClass( 'unselectable' ) || li == this.selected ) 632 return; 633 634 this.deselect(); 635 this.selected = li.addClass( 'selected' ); 636 // Make sure the element is visible 637 liHeight = li.outerHeight(); 638 elHeight = this.element.height(); 639 liTop = li.position().top; 640 elTop = this.element.scrollTop(); 641 642 if ( liTop < 0 ) // Make first visible element 643 this.element.scrollTop( elTop + liTop ); 644 else if ( liTop + liHeight > elHeight ) // Make last visible element 645 this.element.scrollTop( elTop + liTop - elHeight + liHeight ); 646 647 // Trigger the river-select event 648 this.element.trigger( 'river-select', [ li, event, this ] ); 649 }, 650 deselect: function() { 651 if ( this.selected ) 652 this.selected.removeClass( 'selected' ); 653 this.selected = false; 654 }, 655 prev: function() { 656 if ( ! this.visible ) 657 return; 658 659 var to; 660 if ( this.selected ) { 661 to = this.selected.prev( 'li' ); 662 if ( to.length ) 663 this.select( to ); 664 } 665 }, 666 next: function() { 667 if ( ! this.visible ) 668 return; 669 670 var to = this.selected ? this.selected.next( 'li' ) : $( 'li:not(.unselectable):first', this.element ); 671 if ( to.length ) 672 this.select( to ); 673 }, 674 ajax: function( callback ) { 675 var self = this, 676 delay = this.query.page == 1 ? 0 : wpLink.minRiverAJAXDuration, 677 response = wpLink.delayedCallback( function( results, params ) { 678 self.process( results, params ); 679 if ( callback ) 680 callback( results, params ); 681 }, delay ); 682 683 this.query.ajax( response ); 684 }, 685 change: function( search ) { 686 if ( this.query && this._search == search ) 687 return; 688 689 this._search = search; 690 this.query = new Query( search ); 691 this.element.scrollTop( 0 ); 692 }, 693 process: function( results, params ) { 694 var list = '', alt = true, classes = '', 695 firstPage = params.page == 1; 696 697 if ( ! results ) { 698 if ( firstPage ) { 699 list += '<li class="unselectable no-matches-found"><span class="item-title"><em>' + 700 wpLinkL10n.noMatchesFound + '</em></span></li>'; 701 } 702 } else { 703 $.each( results, function() { 704 classes = alt ? 'alternate' : ''; 705 classes += this.title ? '' : ' no-title'; 706 list += classes ? '<li class="' + classes + '">' : '<li>'; 707 list += '<input type="hidden" class="item-permalink" value="' + this.permalink + '" />'; 708 list += '<span class="item-title">'; 709 list += this.title ? this.title : wpLinkL10n.noTitle; 710 list += '</span><span class="item-info">' + this.info + '</span></li>'; 711 alt = ! alt; 712 }); 713 } 714 715 this.ul[ firstPage ? 'html' : 'append' ]( list ); 716 }, 717 maybeLoad: function() { 718 var self = this, 719 el = this.element, 720 bottom = el.scrollTop() + el.height(); 721 722 if ( ! this.query.ready() || bottom < this.contentHeight.height() - wpLink.riverBottomThreshold ) 723 return; 724 725 setTimeout(function() { 726 var newTop = el.scrollTop(), 727 newBottom = newTop + el.height(); 728 729 if ( ! self.query.ready() || newBottom < self.contentHeight.height() - wpLink.riverBottomThreshold ) 730 return; 731 732 self.waiting.addClass( 'is-active' ); 733 el.scrollTop( newTop + self.waiting.outerHeight() ); 734 735 self.ajax( function() { 736 self.waiting.removeClass( 'is-active' ); 737 }); 738 }, wpLink.timeToTriggerRiver ); 739 } 740 }); 741 742 Query = function( search ) { 743 this.page = 1; 744 this.allLoaded = false; 745 this.querying = false; 746 this.search = search; 747 }; 748 749 $.extend( Query.prototype, { 750 ready: function() { 751 return ! ( this.querying || this.allLoaded ); 752 }, 753 ajax: function( callback ) { 754 var self = this, 755 query = { 756 action : 'wp-link-ajax', 757 page : this.page, 758 '_ajax_linking_nonce' : inputs.nonce.val() 759 }; 760 761 if ( this.search ) 762 query.search = this.search; 763 764 this.querying = true; 765 766 $.post( window.ajaxurl, query, function( r ) { 767 self.page++; 768 self.querying = false; 769 self.allLoaded = ! r; 770 callback( r, query ); 771 }, 'json' ); 772 } 773 }); 774 532 775 $( document ).ready( wpLink.init ); 533 776 })( jQuery, window.wpLinkL10n, window.wp );