WordPress.org

Plugin Directory

Changeset 1146137


Ignore:
Timestamp:
04/26/15 13:11:37 (3 years ago)
Author:
ffsantos92
Message:

v1.1.1

Location:
rel-nofollow-checkbox
Files:
7 added
4 edited

Legend:

Unmodified
Added
Removed
  • rel-nofollow-checkbox/trunk/readme.txt

    r1144964 r1146137  
    44Requires at least: 3.2 
    55Tested up to: 4.2 
    6 Stable tag: 1.1.0 
     6Stable tag: 1.1.1 
    77License: GPLv2 
    88License URI: http://www.gnu.org/licenses/gpl-2.0.html 
     
    3434== Changelog == 
    3535 
     36= 1.1.1 = 
     37* Minor bugs fixed 
     38 
    3639= 1.1.0 = 
    3740* Compatible with WordPress 4.2 
  • rel-nofollow-checkbox/trunk/rel-nofollow-checkbox.php

    r1144964 r1146137  
    44 * Plugin URI:  https://github.com/ffsantos92/rel-nofollow-checkbox 
    55 * Description: This plugin adds a simple checkbox in the insert/edit link popup for including nofollow attribute. 
    6  * Version:     1.1.0 
     6 * Version:     1.1.1 
    77 * Author:      Fabio Santos 
    8  * Author URI:  http://www.fabiosantos.me 
     8 * Author URI:  http://www.fabiosantos.me. 
    99 */ 
    10 function overwrite_wplink() { 
    11     // Disable wplink 
    12     wp_deregister_script( 'wplink' ); 
     10function overwrite_wplink() 
     11{ 
     12    // Disable wplink 
     13    wp_deregister_script('wplink'); 
    1314 
    14     // Register a new script file to be linked 
    15     wp_register_script( 'wplink', plugins_url( 'wplink.min.js', __FILE__), array( 'jquery', 'wpdialogs' ), false, 1 ); 
     15    // Register a new script file to be linked 
     16    wp_register_script('wplink', plugins_url('wplink.min.js', __FILE__), array( 'jquery', 'wpdialogs' ), false, 1); 
     17 
     18    wp_localize_script('wplink', 'wpLinkL10n', array('title' => __('Insert/edit link'), 'update' => __('Update'), 'save' => __('Add Link'), 'noTitle' => __('(no title)'), 'noMatchesFound' => __('No matches found.') )); 
    1619} 
    17 add_action( 'admin_enqueue_scripts', 'overwrite_wplink', 999 ); 
    18 ?> 
     20add_action('admin_enqueue_scripts', 'overwrite_wplink', 999); 
  • rel-nofollow-checkbox/trunk/wplink.js

    r1144964 r1146137  
    1 /* rel-nofollow-checkbox v1.1.0 | GPLv2 License | by fabiosantos.me */ 
    2 /* global ajaxurl, tinymce, wpLinkL10n, setUserSetting, wpActiveEdietor */ 
     1/* rel-nofollow-checkbox v1.1.1 | GPLv2 License | by fabiosantos.me */ 
     2/* global ajaxurl, tinymce, wpLinkL10n, setUserSetting, wpActiveEditor */ 
    33var wpLink; 
    44 
    5 ( function( $ ) { 
    6     var editor, searchTimer, River, Query, correctedURL, 
    7         inputs = {}, 
    8         rivers = {}, 
    9         isTouch = ( 'ontouchend' in document ); 
    10  
    11     function getLink() { 
    12         return editor.dom.getParent( editor.selection.getNode(), 'a' ); 
    13     } 
    14  
    15     wpLink = { 
    16         timeToTriggerRiver: 150, 
    17         minRiverAJAXDuration: 200, 
    18         riverBottomThreshold: 5, 
    19         keySensitivity: 100, 
    20         lastSearch: '', 
    21         textarea: '', 
    22  
    23         init: function() { 
    24           var fsRelHtml = '<div><label><span> </span><input type="checkbox" id="rel-nofollow-checkbox" /><strong> rel="nofollow"</strong></label></div>'; 
    25       $(fsRelHtml).insertAfter('#wp-link .link-target'); 
    26       $('#wp-link-wrap').css('min-height','310px'); 
    27        
    28             inputs.wrap = $('#wp-link-wrap'); 
    29             inputs.dialog = $( '#wp-link' ); 
    30             inputs.backdrop = $( '#wp-link-backdrop' ); 
    31             inputs.submit = $( '#wp-link-submit' ); 
    32             inputs.close = $( '#wp-link-close' ); 
    33  
    34             // Input 
    35             inputs.text = $( '#wp-link-text' ); 
    36             inputs.url = $( '#wp-link-url' ); 
    37             inputs.nonce = $( '#_ajax_linking_nonce' ); 
    38             inputs.fsRelNofollow = $( '#rel-nofollow-checkbox' ); 
    39             inputs.openInNewTab = $( '#wp-link-target' ); 
    40             inputs.search = $( '#wp-link-search' ); 
    41  
    42             // Build Rivers 
    43             rivers.search = new River( $( '#search-results' ) ); 
    44             rivers.recent = new River( $( '#most-recent-results' ) ); 
    45             rivers.elements = inputs.dialog.find( '.query-results' ); 
    46  
    47             // Get search notice text 
    48             inputs.queryNotice = $( '#query-notice-message' ); 
    49             inputs.queryNoticeTextDefault = inputs.queryNotice.find( '.query-notice-default' ); 
    50             inputs.queryNoticeTextHint = inputs.queryNotice.find( '.query-notice-hint' ); 
    51  
    52             // Bind event handlers 
    53             inputs.dialog.keydown( wpLink.keydown ); 
    54             inputs.dialog.keyup( wpLink.keyup ); 
    55             inputs.submit.click( function( event ) { 
    56                 event.preventDefault(); 
    57                 wpLink.update(); 
    58             }); 
    59             inputs.close.add( inputs.backdrop ).add( '#wp-link-cancel a' ).click( function( event ) { 
    60                 event.preventDefault(); 
    61                 wpLink.close(); 
    62             }); 
    63  
    64             $( '#wp-link-search-toggle' ).on( 'click', wpLink.toggleInternalLinking ); 
    65  
    66             rivers.elements.on( 'river-select', wpLink.updateFields ); 
    67  
    68             // Display 'hint' message when search field or 'query-results' box are focused 
    69             inputs.search.on( 'focus.wplink', function() { 
    70                 inputs.queryNoticeTextDefault.hide(); 
    71                 inputs.queryNoticeTextHint.removeClass( 'screen-reader-text' ).show(); 
    72             } ).on( 'blur.wplink', function() { 
    73                 inputs.queryNoticeTextDefault.show(); 
    74                 inputs.queryNoticeTextHint.addClass( 'screen-reader-text' ).hide(); 
    75             } ); 
    76  
    77             inputs.search.keyup( function() { 
    78                 var self = this; 
    79  
    80                 window.clearTimeout( searchTimer ); 
    81                 searchTimer = window.setTimeout( function() { 
    82                     wpLink.searchInternalLinks.call( self ); 
    83                 }, 500 ); 
    84             }); 
    85  
    86             function correctURL() { 
    87                 var url = $.trim( inputs.url.val() ); 
    88  
    89                 if ( url && correctedURL !== url && ! /^(?:[a-z]+:|#|\?|\.|\/)/.test( url ) ) { 
    90                     inputs.url.val( 'http://' + url ); 
    91                     correctedURL = url; 
    92                 } 
    93             } 
    94  
    95             inputs.url.on( 'paste', function() { 
    96                 setTimeout( correctURL, 0 ); 
    97             } ); 
    98  
    99             inputs.url.on( 'blur', correctURL ); 
    100         }, 
    101  
    102         open: function( editorId ) { 
    103             var ed; 
    104  
    105             $( document.body ).addClass( 'modal-open' ); 
    106  
    107             wpLink.range = null; 
    108  
    109             if ( editorId ) { 
    110                 window.wpActiveEditor = editorId; 
    111             } 
    112  
    113             if ( ! window.wpActiveEditor ) { 
    114                 return; 
    115             } 
    116  
    117             this.textarea = $( '#' + window.wpActiveEditor ).get( 0 ); 
    118  
    119             if ( typeof tinymce !== 'undefined' ) { 
    120                 ed = tinymce.get( wpActiveEditor ); 
    121  
    122                 if ( ed && ! ed.isHidden() ) { 
    123                     editor = ed; 
    124                 } else { 
    125                     editor = null; 
    126                 } 
    127  
    128                 if ( editor && tinymce.isIE ) { 
    129                     editor.windowManager.bookmark = editor.selection.getBookmark(); 
    130                 } 
    131             } 
    132  
    133             if ( ! wpLink.isMCE() && document.selection ) { 
    134                 this.textarea.focus(); 
    135                 this.range = document.selection.createRange(); 
    136             } 
    137  
    138             inputs.wrap.show(); 
    139             inputs.backdrop.show(); 
    140  
    141             wpLink.refresh(); 
    142  
    143             $( document ).trigger( 'wplink-open', inputs.wrap ); 
    144         }, 
    145  
    146         isMCE: function() { 
    147             return editor && ! editor.isHidden(); 
    148         }, 
    149  
    150         refresh: function() { 
    151             var text = ''; 
    152  
    153             // Refresh rivers (clear links, check visibility) 
    154             rivers.search.refresh(); 
    155             rivers.recent.refresh(); 
    156  
    157             if ( wpLink.isMCE() ) { 
    158                 wpLink.mceRefresh(); 
    159             } else { 
    160                 // For the Text editor the "Link text" field is always shown 
    161                 if ( ! inputs.wrap.hasClass( 'has-text-field' ) ) { 
    162                     inputs.wrap.addClass( 'has-text-field' ); 
    163                 } 
    164  
    165                 if ( document.selection ) { 
    166                     // Old IE 
    167                     text = document.selection.createRange().text || ''; 
    168                 } else if ( typeof this.textarea.selectionStart !== 'undefined' && 
    169                     ( this.textarea.selectionStart !== this.textarea.selectionEnd ) ) { 
    170                     // W3C 
    171                     text = this.textarea.value.substring( this.textarea.selectionStart, this.textarea.selectionEnd ) || ''; 
    172                 } 
    173  
    174                 inputs.text.val( text ); 
    175                 wpLink.setDefaultValues(); 
    176             } 
    177  
    178             if ( isTouch ) { 
    179                 // Close the onscreen keyboard 
    180                 inputs.url.focus().blur(); 
    181             } else { 
    182                 // Focus the URL field and highlight its contents. 
    183                 // If this is moved above the selection changes, 
    184                 // IE will show a flashing cursor over the dialog. 
    185                 inputs.url.focus()[0].select(); 
    186             } 
    187  
    188             // Load the most recent results if this is the first time opening the panel. 
    189             if ( ! rivers.recent.ul.children().length ) { 
    190                 rivers.recent.ajax(); 
    191             } 
    192  
    193             correctedURL = inputs.url.val().replace( /^http:\/\//, '' ); 
    194         }, 
    195  
    196         hasSelectedText: function( linkNode ) { 
    197             var html = editor.selection.getContent(); 
    198  
    199             // Partial html and not a fully selected anchor element 
    200             if ( /</.test( html ) && ( ! /^<a [^>]+>[^<]+<\/a>$/.test( html ) || html.indexOf('href=') === -1 ) ) { 
    201                 return false; 
    202             } 
    203  
    204             if ( linkNode ) { 
    205                 var nodes = linkNode.childNodes, i; 
    206  
    207                 if ( nodes.length === 0 ) { 
    208                     return false; 
    209                 } 
    210  
    211                 for ( i = nodes.length - 1; i >= 0; i-- ) { 
    212                     if ( nodes[i].nodeType != 3 ) { 
    213                         return false; 
    214                     } 
    215                 } 
    216             } 
    217  
    218             return true; 
    219         }, 
    220  
    221         mceRefresh: function() { 
    222             var text, 
    223                 selectedNode = editor.selection.getNode(), 
    224                 linkNode = editor.dom.getParent( selectedNode, 'a[href]' ), 
    225                 onlyText = this.hasSelectedText( linkNode ); 
    226  
    227             if ( linkNode ) { 
    228                 text = linkNode.innerText || linkNode.textContent; 
    229                 inputs.url.val( editor.dom.getAttrib( linkNode, 'href' ) ); 
    230                 inputs.openInNewTab.prop( 'checked', '_blank' === editor.dom.getAttrib( linkNode, 'target' ) ); 
    231                 inputs.fsRelNofollow.prop( 'checked', 'nofollow' === editor.dom.getAttrib( linkNode, 'rel' ) ); 
    232                 inputs.submit.val( wpLinkL10n.update ); 
    233             } else { 
    234                 text = editor.selection.getContent({ format: 'text' }); 
    235                 this.setDefaultValues(); 
    236             } 
    237  
    238             if ( onlyText ) { 
    239                 inputs.text.val( text || '' ); 
    240                 inputs.wrap.addClass( 'has-text-field' ); 
    241             } else { 
    242                 inputs.text.val( '' ); 
    243                 inputs.wrap.removeClass( 'has-text-field' ); 
    244             } 
    245         }, 
    246  
    247         close: function() { 
    248             $( document.body ).removeClass( 'modal-open' ); 
    249  
    250             if ( ! wpLink.isMCE() ) { 
    251                 wpLink.textarea.focus(); 
    252  
    253                 if ( wpLink.range ) { 
    254                     wpLink.range.moveToBookmark( wpLink.range.getBookmark() ); 
    255                     wpLink.range.select(); 
    256                 } 
    257             } else { 
    258                 editor.focus(); 
    259             } 
    260  
    261             inputs.backdrop.hide(); 
    262             inputs.wrap.hide(); 
    263  
    264             correctedURL = false; 
    265  
    266             $( document ).trigger( 'wplink-close', inputs.wrap ); 
    267         }, 
    268  
    269         getAttrs: function() { 
    270             return { 
    271                 href: $.trim( inputs.url.val() ), 
    272                 target: inputs.openInNewTab.prop( 'checked' ) ? '_blank' : '', 
    273                 rel: inputs.fsRelNofollow.prop( 'checked' ) ? 'nofollow' : '' 
    274             }; 
    275         }, 
    276  
    277         update: function() { 
    278             if ( wpLink.isMCE() ) { 
    279                 wpLink.mceUpdate(); 
    280             } else { 
    281                 wpLink.htmlUpdate(); 
    282             } 
    283         }, 
    284  
    285         htmlUpdate: function() { 
    286             var attrs, text, html, begin, end, cursor, selection, 
    287                 textarea = wpLink.textarea; 
    288  
    289             if ( ! textarea ) { 
    290                 return; 
    291             } 
    292  
    293             attrs = wpLink.getAttrs(); 
    294             text = inputs.text.val(); 
    295  
    296             // If there's no href, return. 
    297             if ( ! attrs.href ) { 
    298                 return; 
    299             } 
    300  
    301             // Build HTML 
    302             html = '<a href="' + attrs.href + '"'; 
    303  
    304             if ( attrs.target ) { 
    305                 html += ' target="' + attrs.target + '"'; 
    306             } 
    307              
    308             if ( attrs.rel ) { 
    309             html += ' rel="nofollow"'; 
    310             } 
    311  
    312             html += '>'; 
    313  
    314             // Insert HTML 
    315             if ( document.selection && wpLink.range ) { 
    316                 // IE 
    317                 // Note: If no text is selected, IE will not place the cursor 
    318                 //       inside the closing tag. 
    319                 textarea.focus(); 
    320                 wpLink.range.text = html + ( text || wpLink.range.text ) + '</a>'; 
    321                 wpLink.range.moveToBookmark( wpLink.range.getBookmark() ); 
    322                 wpLink.range.select(); 
    323  
    324                 wpLink.range = null; 
    325             } else if ( typeof textarea.selectionStart !== 'undefined' ) { 
    326                 // W3C 
    327                 begin = textarea.selectionStart; 
    328                 end = textarea.selectionEnd; 
    329                 selection = text || textarea.value.substring( begin, end ); 
    330                 html = html + selection + '</a>'; 
    331                 cursor = begin + html.length; 
    332  
    333                 // If no text is selected, place the cursor inside the closing tag. 
    334                 if ( begin === end && ! selection ) { 
    335                     cursor -= 4; 
    336                 } 
    337  
    338                 textarea.value = ( 
    339                     textarea.value.substring( 0, begin ) + 
    340                     html + 
    341                     textarea.value.substring( end, textarea.value.length ) 
    342                 ); 
    343  
    344                 // Update cursor position 
    345                 textarea.selectionStart = textarea.selectionEnd = cursor; 
    346             } 
    347  
    348             wpLink.close(); 
    349             textarea.focus(); 
    350         }, 
    351  
    352         mceUpdate: function() { 
    353             var attrs = wpLink.getAttrs(), 
    354                 link, text; 
    355  
    356             wpLink.close(); 
    357             editor.focus(); 
    358  
    359             if ( tinymce.isIE ) { 
    360                 editor.selection.moveToBookmark( editor.windowManager.bookmark ); 
    361             } 
    362  
    363             if ( ! attrs.href ) { 
    364                 editor.execCommand( 'unlink' ); 
    365                 return; 
    366             } 
    367  
    368             link = getLink(); 
    369             text = inputs.text.val(); 
    370  
    371             if ( link ) { 
    372                 if ( text ) { 
    373                     if ( 'innerText' in link ) { 
    374                         link.innerText = text; 
    375                     } else { 
    376                         link.textContent = text; 
    377                     } 
    378                 } 
    379  
    380                 editor.dom.setAttribs( link, attrs ); 
    381             } else { 
    382                 if ( text ) { 
    383                     editor.selection.setNode( editor.dom.create( 'a', attrs, text ) ); 
    384                 } else { 
    385                     editor.execCommand( 'mceInsertLink', false, attrs ); 
    386                 } 
    387             } 
    388         }, 
    389  
    390         updateFields: function( e, li ) { 
    391             inputs.url.val( li.children( '.item-permalink' ).val() ); 
    392         }, 
    393  
    394         setDefaultValues: function() { 
    395             var selection, 
    396                 emailRegexp = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i, 
    397                 urlRegexp = /^(https?|ftp):\/\/[A-Z0-9.-]+\.[A-Z]{2,4}[^ "]*$/i; 
    398  
    399             if ( this.isMCE() ) { 
    400                 selection = editor.selection.getContent(); 
    401             } else if ( document.selection && wpLink.range ) { 
    402                 selection = wpLink.range.text; 
    403             } else if ( typeof this.textarea.selectionStart !== 'undefined' ) { 
    404                 selection = this.textarea.value.substring( this.textarea.selectionStart, this.textarea.selectionEnd ); 
    405             } 
    406  
    407             if ( selection && emailRegexp.test( selection ) ) { 
    408                 // Selection is email address 
    409                 inputs.url.val( 'mailto:' + selection ); 
    410             } else if ( selection && urlRegexp.test( selection ) ) { 
    411                 // Selection is URL 
    412                 inputs.url.val( selection.replace( /&amp;|&#0?38;/gi, '&' ) ); 
    413             } else { 
    414                 // Set URL to default. 
    415                 inputs.url.val( '' ); 
    416             } 
    417  
    418             // Update save prompt. 
    419             inputs.submit.val( wpLinkL10n.save ); 
    420         }, 
    421  
    422         searchInternalLinks: function() { 
    423             var t = $( this ), waiting, 
    424                 search = t.val(); 
    425  
    426             if ( search.length > 2 ) { 
    427                 rivers.recent.hide(); 
    428                 rivers.search.show(); 
    429  
    430                 // Don't search if the keypress didn't change the title. 
    431                 if ( wpLink.lastSearch == search ) 
    432                     return; 
    433  
    434                 wpLink.lastSearch = search; 
    435                 waiting = t.parent().find( '.spinner' ).addClass( 'is-active' ); 
    436  
    437                 rivers.search.change( search ); 
    438                 rivers.search.ajax( function() { 
    439                     waiting.removeClass( 'is-active' ); 
    440                 }); 
    441             } else { 
    442                 rivers.search.hide(); 
    443                 rivers.recent.show(); 
    444             } 
    445         }, 
    446  
    447         next: function() { 
    448             rivers.search.next(); 
    449             rivers.recent.next(); 
    450         }, 
    451  
    452         prev: function() { 
    453             rivers.search.prev(); 
    454             rivers.recent.prev(); 
    455         }, 
    456  
    457         keydown: function( event ) { 
    458             var fn, id, 
    459                 key = $.ui.keyCode; 
    460  
    461             if ( key.ESCAPE === event.keyCode ) { 
    462                 wpLink.close(); 
    463                 event.stopImmediatePropagation(); 
    464             } else if ( key.TAB === event.keyCode ) { 
    465                 id = event.target.id; 
    466  
    467                 // wp-link-submit must always be the last focusable element in the dialog. 
    468                 // following focusable elements will be skipped on keyboard navigation. 
    469                 if ( id === 'wp-link-submit' && ! event.shiftKey ) { 
    470                     inputs.close.focus(); 
    471                     event.preventDefault(); 
    472                 } else if ( id === 'wp-link-close' && event.shiftKey ) { 
    473                     inputs.submit.focus(); 
    474                     event.preventDefault(); 
    475                 } 
    476             } 
    477  
    478             if ( event.keyCode !== key.UP && event.keyCode !== key.DOWN ) { 
    479                 return; 
    480             } 
    481  
    482             if ( document.activeElement && 
    483                 ( document.activeElement.id === 'link-title-field' || document.activeElement.id === 'url-field' ) ) { 
    484                 return; 
    485             } 
    486  
    487             fn = event.keyCode === key.UP ? 'prev' : 'next'; 
    488             clearInterval( wpLink.keyInterval ); 
    489             wpLink[ fn ](); 
    490             wpLink.keyInterval = setInterval( wpLink[ fn ], wpLink.keySensitivity ); 
    491             event.preventDefault(); 
    492         }, 
    493  
    494         keyup: function( event ) { 
    495             var key = $.ui.keyCode; 
    496  
    497             if ( event.which === key.UP || event.which === key.DOWN ) { 
    498                 clearInterval( wpLink.keyInterval ); 
    499                 event.preventDefault(); 
    500             } 
    501         }, 
    502  
    503         delayedCallback: function( func, delay ) { 
    504             var timeoutTriggered, funcTriggered, funcArgs, funcContext; 
    505  
    506             if ( ! delay ) 
    507                 return func; 
    508  
    509             setTimeout( function() { 
    510                 if ( funcTriggered ) 
    511                     return func.apply( funcContext, funcArgs ); 
    512                 // Otherwise, wait. 
    513                 timeoutTriggered = true; 
    514             }, delay ); 
    515  
    516             return function() { 
    517                 if ( timeoutTriggered ) 
    518                     return func.apply( this, arguments ); 
    519                 // Otherwise, wait. 
    520                 funcArgs = arguments; 
    521                 funcContext = this; 
    522                 funcTriggered = true; 
    523             }; 
    524         }, 
    525  
    526         toggleInternalLinking: function( event ) { 
    527             var visible = inputs.wrap.hasClass( 'search-panel-visible' ); 
    528  
    529             inputs.wrap.toggleClass( 'search-panel-visible', ! visible ); 
    530             setUserSetting( 'wplink', visible ? '0' : '1' ); 
    531             inputs[ ! visible ? 'search' : 'url' ].focus(); 
    532             event.preventDefault(); 
    533         } 
    534     }; 
    535  
    536     River = function( element, search ) { 
    537         var self = this; 
    538         this.element = element; 
    539         this.ul = element.children( 'ul' ); 
    540         this.contentHeight = element.children( '#link-selector-height' ); 
    541         this.waiting = element.find('.river-waiting'); 
    542  
    543         this.change( search ); 
    544         this.refresh(); 
    545  
    546         $( '#wp-link .query-results, #wp-link #link-selector' ).scroll( function() { 
    547             self.maybeLoad(); 
    548         }); 
    549         element.on( 'click', 'li', function( event ) { 
    550             self.select( $( this ), event ); 
    551         }); 
    552     }; 
    553  
    554     $.extend( River.prototype, { 
    555         refresh: function() { 
    556             this.deselect(); 
    557             this.visible = this.element.is( ':visible' ); 
    558         }, 
    559         show: function() { 
    560             if ( ! this.visible ) { 
    561                 this.deselect(); 
    562                 this.element.show(); 
    563                 this.visible = true; 
    564             } 
    565         }, 
    566         hide: function() { 
    567             this.element.hide(); 
    568             this.visible = false; 
    569         }, 
    570         // Selects a list item and triggers the river-select event. 
    571         select: function( li, event ) { 
    572             var liHeight, elHeight, liTop, elTop; 
    573  
    574             if ( li.hasClass( 'unselectable' ) || li == this.selected ) 
    575                 return; 
    576  
    577             this.deselect(); 
    578             this.selected = li.addClass( 'selected' ); 
    579             // Make sure the element is visible 
    580             liHeight = li.outerHeight(); 
    581             elHeight = this.element.height(); 
    582             liTop = li.position().top; 
    583             elTop = this.element.scrollTop(); 
    584  
    585             if ( liTop < 0 ) // Make first visible element 
    586                 this.element.scrollTop( elTop + liTop ); 
    587             else if ( liTop + liHeight > elHeight ) // Make last visible element 
    588                 this.element.scrollTop( elTop + liTop - elHeight + liHeight ); 
    589  
    590             // Trigger the river-select event 
    591             this.element.trigger( 'river-select', [ li, event, this ] ); 
    592         }, 
    593         deselect: function() { 
    594             if ( this.selected ) 
    595                 this.selected.removeClass( 'selected' ); 
    596             this.selected = false; 
    597         }, 
    598         prev: function() { 
    599             if ( ! this.visible ) 
    600                 return; 
    601  
    602             var to; 
    603             if ( this.selected ) { 
    604                 to = this.selected.prev( 'li' ); 
    605                 if ( to.length ) 
    606                     this.select( to ); 
    607             } 
    608         }, 
    609         next: function() { 
    610             if ( ! this.visible ) 
    611                 return; 
    612  
    613             var to = this.selected ? this.selected.next( 'li' ) : $( 'li:not(.unselectable):first', this.element ); 
    614             if ( to.length ) 
    615                 this.select( to ); 
    616         }, 
    617         ajax: function( callback ) { 
    618             var self = this, 
    619                 delay = this.query.page == 1 ? 0 : wpLink.minRiverAJAXDuration, 
    620                 response = wpLink.delayedCallback( function( results, params ) { 
    621                     self.process( results, params ); 
    622                     if ( callback ) 
    623                         callback( results, params ); 
    624                 }, delay ); 
    625  
    626             this.query.ajax( response ); 
    627         }, 
    628         change: function( search ) { 
    629             if ( this.query && this._search == search ) 
    630                 return; 
    631  
    632             this._search = search; 
    633             this.query = new Query( search ); 
    634             this.element.scrollTop( 0 ); 
    635         }, 
    636         process: function( results, params ) { 
    637             var list = '', alt = true, classes = '', 
    638                 firstPage = params.page == 1; 
    639  
    640             if ( ! results ) { 
    641                 if ( firstPage ) { 
    642                     list += '<li class="unselectable no-matches-found"><span class="item-title"><em>' + 
    643                         wpLinkL10n.noMatchesFound + '</em></span></li>'; 
    644                 } 
    645             } else { 
    646                 $.each( results, function() { 
    647                     classes = alt ? 'alternate' : ''; 
    648                     classes += this.title ? '' : ' no-title'; 
    649                     list += classes ? '<li class="' + classes + '">' : '<li>'; 
    650                     list += '<input type="hidden" class="item-permalink" value="' + this.permalink + '" />'; 
    651                     list += '<span class="item-title">'; 
    652                     list += this.title ? this.title : wpLinkL10n.noTitle; 
    653                     list += '</span><span class="item-info">' + this.info + '</span></li>'; 
    654                     alt = ! alt; 
    655                 }); 
    656             } 
    657  
    658             this.ul[ firstPage ? 'html' : 'append' ]( list ); 
    659         }, 
    660         maybeLoad: function() { 
    661             var self = this, 
    662                 el = this.element, 
    663                 bottom = el.scrollTop() + el.height(); 
    664  
    665             if ( ! this.query.ready() || bottom < this.contentHeight.height() - wpLink.riverBottomThreshold ) 
    666                 return; 
    667  
    668             setTimeout(function() { 
    669                 var newTop = el.scrollTop(), 
    670                     newBottom = newTop + el.height(); 
    671  
    672                 if ( ! self.query.ready() || newBottom < self.contentHeight.height() - wpLink.riverBottomThreshold ) 
    673                     return; 
    674  
    675                 self.waiting.addClass( 'is-active' ); 
    676                 el.scrollTop( newTop + self.waiting.outerHeight() ); 
    677  
    678                 self.ajax( function() { 
    679                     self.waiting.removeClass( 'is-active' ); 
    680                 }); 
    681             }, wpLink.timeToTriggerRiver ); 
    682         } 
    683     }); 
    684  
    685     Query = function( search ) { 
    686         this.page = 1; 
    687         this.allLoaded = false; 
    688         this.querying = false; 
    689         this.search = search; 
    690     }; 
    691  
    692     $.extend( Query.prototype, { 
    693         ready: function() { 
    694             return ! ( this.querying || this.allLoaded ); 
    695         }, 
    696         ajax: function( callback ) { 
    697             var self = this, 
    698                 query = { 
    699                     action : 'wp-link-ajax', 
    700                     page : this.page, 
    701                     '_ajax_linking_nonce' : inputs.nonce.val() 
    702                 }; 
    703  
    704             if ( this.search ) 
    705                 query.search = this.search; 
    706  
    707             this.querying = true; 
    708  
    709             $.post( ajaxurl, query, function( r ) { 
    710                 self.page++; 
    711                 self.querying = false; 
    712                 self.allLoaded = ! r; 
    713                 callback( r, query ); 
    714             }, 'json' ); 
    715         } 
    716     }); 
    717  
    718     $( document ).ready( wpLink.init ); 
    719 })( jQuery ); 
     5(function($) { 
     6    var editor, searchTimer, River, Query, correctedURL, 
     7        inputs = {}, 
     8        rivers = {}, 
     9        isTouch = ('ontouchend' in document); 
     10 
     11    function getLink() { 
     12        return editor.dom.getParent(editor.selection.getNode(), 'a'); 
     13    } 
     14 
     15    wpLink = { 
     16        timeToTriggerRiver: 150, 
     17        minRiverAJAXDuration: 200, 
     18        riverBottomThreshold: 5, 
     19        keySensitivity: 100, 
     20        lastSearch: '', 
     21        textarea: '', 
     22 
     23        init: function() { 
     24            var fsRelHtml = '<div><label><span> </span><input type="checkbox" id="rel-nofollow-checkbox" /><strong> rel="nofollow"</strong></label></div>'; 
     25            $(fsRelHtml) 
     26                .insertAfter('#wp-link .link-target'); 
     27            $('#wp-link-wrap') 
     28                .css('min-height', '310px'); 
     29 
     30            inputs.wrap = $('#wp-link-wrap'); 
     31            inputs.dialog = $('#wp-link'); 
     32            inputs.backdrop = $('#wp-link-backdrop'); 
     33            inputs.submit = $('#wp-link-submit'); 
     34            inputs.close = $('#wp-link-close'); 
     35 
     36            // Input 
     37            inputs.text = $('#wp-link-text'); 
     38            inputs.url = $('#wp-link-url'); 
     39            inputs.nonce = $('#_ajax_linking_nonce'); 
     40            inputs.fsRelNofollow = $('#rel-nofollow-checkbox'); 
     41            inputs.openInNewTab = $('#wp-link-target'); 
     42            inputs.search = $('#wp-link-search'); 
     43 
     44            // Build Rivers 
     45            rivers.search = new River($('#search-results')); 
     46            rivers.recent = new River($('#most-recent-results')); 
     47            rivers.elements = inputs.dialog.find('.query-results'); 
     48 
     49            // Get search notice text 
     50            inputs.queryNotice = $('#query-notice-message'); 
     51            inputs.queryNoticeTextDefault = inputs.queryNotice.find('.query-notice-default'); 
     52            inputs.queryNoticeTextHint = inputs.queryNotice.find('.query-notice-hint'); 
     53 
     54            // Bind event handlers 
     55            inputs.dialog.keydown(wpLink.keydown); 
     56            inputs.dialog.keyup(wpLink.keyup); 
     57            inputs.submit.click(function(event) { 
     58                event.preventDefault(); 
     59                wpLink.update(); 
     60            }); 
     61            inputs.close.add(inputs.backdrop) 
     62                .add('#wp-link-cancel a') 
     63                .click(function(event) { 
     64                    event.preventDefault(); 
     65                    wpLink.close(); 
     66                }); 
     67 
     68            $('#wp-link-search-toggle') 
     69                .on('click', wpLink.toggleInternalLinking); 
     70 
     71            rivers.elements.on('river-select', wpLink.updateFields); 
     72 
     73            // Display 'hint' message when search field or 'query-results' box are focused 
     74            inputs.search.on('focus.wplink', function() { 
     75                    inputs.queryNoticeTextDefault.hide(); 
     76                    inputs.queryNoticeTextHint.removeClass('screen-reader-text') 
     77                        .show(); 
     78                }) 
     79                .on('blur.wplink', function() { 
     80                    inputs.queryNoticeTextDefault.show(); 
     81                    inputs.queryNoticeTextHint.addClass('screen-reader-text') 
     82                        .hide(); 
     83                }); 
     84 
     85            inputs.search.keyup(function() { 
     86                var self = this; 
     87 
     88                window.clearTimeout(searchTimer); 
     89                searchTimer = window.setTimeout(function() { 
     90                    wpLink.searchInternalLinks.call(self); 
     91                }, 500); 
     92            }); 
     93 
     94            function correctURL() { 
     95                var url = $.trim(inputs.url.val()); 
     96 
     97                if (url && correctedURL !== url && !/^(?:[a-z]+:|#|\?|\.|\/)/.test(url)) { 
     98                    inputs.url.val('http://' + url); 
     99                    correctedURL = url; 
     100                } 
     101            } 
     102 
     103            inputs.url.on('paste', function() { 
     104                setTimeout(correctURL, 0); 
     105            }); 
     106 
     107            inputs.url.on('blur', correctURL); 
     108        }, 
     109 
     110        open: function(editorId) { 
     111            var ed; 
     112 
     113            $(document.body) 
     114                .addClass('modal-open'); 
     115 
     116            wpLink.range = null; 
     117 
     118            if (editorId) { 
     119                window.wpActiveEditor = editorId; 
     120            } 
     121 
     122            if (!window.wpActiveEditor) { 
     123                return; 
     124            } 
     125 
     126            this.textarea = $('#' + window.wpActiveEditor) 
     127                .get(0); 
     128 
     129            if (typeof tinymce !== 'undefined') { 
     130                ed = tinymce.get(wpActiveEditor); 
     131 
     132                if (ed && !ed.isHidden()) { 
     133                    editor = ed; 
     134                } else { 
     135                    editor = null; 
     136                } 
     137 
     138                if (editor && tinymce.isIE) { 
     139                    editor.windowManager.bookmark = editor.selection.getBookmark(); 
     140                } 
     141            } 
     142 
     143            if (!wpLink.isMCE() && document.selection) { 
     144                this.textarea.focus(); 
     145                this.range = document.selection.createRange(); 
     146            } 
     147 
     148            inputs.wrap.show(); 
     149            inputs.backdrop.show(); 
     150 
     151            wpLink.refresh(); 
     152 
     153            $(document) 
     154                .trigger('wplink-open', inputs.wrap); 
     155        }, 
     156 
     157        isMCE: function() { 
     158            return editor && !editor.isHidden(); 
     159        }, 
     160 
     161        refresh: function() { 
     162            var text = ''; 
     163 
     164            // Refresh rivers (clear links, check visibility) 
     165            rivers.search.refresh(); 
     166            rivers.recent.refresh(); 
     167 
     168            if (wpLink.isMCE()) { 
     169                wpLink.mceRefresh(); 
     170            } else { 
     171                // For the Text editor the "Link text" field is always shown 
     172                if (!inputs.wrap.hasClass('has-text-field')) { 
     173                    inputs.wrap.addClass('has-text-field'); 
     174                } 
     175 
     176                if (document.selection) { 
     177                    // Old IE 
     178                    text = document.selection.createRange() 
     179                        .text || ''; 
     180                } else if (typeof this.textarea.selectionStart !== 'undefined' && 
     181                    (this.textarea.selectionStart !== this.textarea.selectionEnd)) { 
     182                    // W3C 
     183                    text = this.textarea.value.substring(this.textarea.selectionStart, this.textarea.selectionEnd) || ''; 
     184                } 
     185 
     186                inputs.text.val(text); 
     187                wpLink.setDefaultValues(); 
     188            } 
     189 
     190            if (isTouch) { 
     191                // Close the onscreen keyboard 
     192                inputs.url.focus() 
     193                    .blur(); 
     194            } else { 
     195                // Focus the URL field and highlight its contents. 
     196                // If this is moved above the selection changes, 
     197                // IE will show a flashing cursor over the dialog. 
     198                inputs.url.focus()[0].select(); 
     199            } 
     200 
     201            // Load the most recent results if this is the first time opening the panel. 
     202            if (!rivers.recent.ul.children() 
     203                .length) { 
     204                rivers.recent.ajax(); 
     205            } 
     206 
     207            correctedURL = inputs.url.val() 
     208                .replace(/^http:\/\//, ''); 
     209        }, 
     210 
     211        hasSelectedText: function(linkNode) { 
     212            var html = editor.selection.getContent(); 
     213 
     214            // Partial html and not a fully selected anchor element 
     215            if (/</.test(html) && (!/^<a [^>]+>[^<]+<\/a>$/.test(html) || html.indexOf('href=') === -1)) { 
     216                return false; 
     217            } 
     218 
     219            if (linkNode) { 
     220                var nodes = linkNode.childNodes, 
     221                    i; 
     222 
     223                if (nodes.length === 0) { 
     224                    return false; 
     225                } 
     226 
     227                for (i = nodes.length - 1; i >= 0; i--) { 
     228                    if (nodes[i].nodeType != 3) { 
     229                        return false; 
     230                    } 
     231                } 
     232            } 
     233 
     234            return true; 
     235        }, 
     236 
     237        mceRefresh: function() { 
     238            var text, 
     239                selectedNode = editor.selection.getNode(), 
     240                linkNode = editor.dom.getParent(selectedNode, 'a[href]'), 
     241                onlyText = this.hasSelectedText(linkNode); 
     242 
     243            if (linkNode) { 
     244                text = linkNode.innerText || linkNode.textContent; 
     245                inputs.url.val(editor.dom.getAttrib(linkNode, 'href')); 
     246                inputs.openInNewTab.prop('checked', '_blank' === editor.dom.getAttrib(linkNode, 'target')); 
     247                inputs.fsRelNofollow.prop('checked', 'nofollow' === editor.dom.getAttrib(linkNode, 'rel')); 
     248                inputs.submit.val(wpLinkL10n.update); 
     249            } else { 
     250                text = editor.selection.getContent({ 
     251                    format: 'text' 
     252                }); 
     253                this.setDefaultValues(); 
     254            } 
     255 
     256            if (onlyText) { 
     257                inputs.text.val(text || ''); 
     258                inputs.wrap.addClass('has-text-field'); 
     259            } else { 
     260                inputs.text.val(''); 
     261                inputs.wrap.removeClass('has-text-field'); 
     262            } 
     263        }, 
     264 
     265        close: function() { 
     266            $(document.body) 
     267                .removeClass('modal-open'); 
     268 
     269            if (!wpLink.isMCE()) { 
     270                wpLink.textarea.focus(); 
     271 
     272                if (wpLink.range) { 
     273                    wpLink.range.moveToBookmark(wpLink.range.getBookmark()); 
     274                    wpLink.range.select(); 
     275                } 
     276            } else { 
     277                editor.focus(); 
     278            } 
     279 
     280            inputs.backdrop.hide(); 
     281            inputs.wrap.hide(); 
     282 
     283            correctedURL = false; 
     284 
     285            $(document) 
     286                .trigger('wplink-close', inputs.wrap); 
     287        }, 
     288 
     289        getAttrs: function() { 
     290            return { 
     291                href: $.trim(inputs.url.val()), 
     292                target: inputs.openInNewTab.prop('checked') ? '_blank' : '', 
     293                rel: inputs.fsRelNofollow.prop('checked') ? 'nofollow' : '' 
     294            }; 
     295        }, 
     296 
     297        update: function() { 
     298            if (wpLink.isMCE()) { 
     299                wpLink.mceUpdate(); 
     300            } else { 
     301                wpLink.htmlUpdate(); 
     302            } 
     303        }, 
     304 
     305        htmlUpdate: function() { 
     306            var attrs, text, html, begin, end, cursor, selection, 
     307                textarea = wpLink.textarea; 
     308 
     309            if (!textarea) { 
     310                return; 
     311            } 
     312 
     313            attrs = wpLink.getAttrs(); 
     314            text = inputs.text.val(); 
     315 
     316            // If there's no href, return. 
     317            if (!attrs.href) { 
     318                return; 
     319            } 
     320 
     321            // Build HTML 
     322            html = '<a href="' + attrs.href + '"'; 
     323 
     324            if (attrs.target) { 
     325                html += ' target="' + attrs.target + '"'; 
     326            } 
     327 
     328            if (attrs.rel) { 
     329                html += ' rel="nofollow"'; 
     330            } 
     331 
     332            html += '>'; 
     333 
     334            // Insert HTML 
     335            if (document.selection && wpLink.range) { 
     336                // IE 
     337                // Note: If no text is selected, IE will not place the cursor 
     338                //       inside the closing tag. 
     339                textarea.focus(); 
     340                wpLink.range.text = html + (text || wpLink.range.text) + '</a>'; 
     341                wpLink.range.moveToBookmark(wpLink.range.getBookmark()); 
     342                wpLink.range.select(); 
     343 
     344                wpLink.range = null; 
     345            } else if (typeof textarea.selectionStart !== 'undefined') { 
     346                // W3C 
     347                begin = textarea.selectionStart; 
     348                end = textarea.selectionEnd; 
     349                selection = text || textarea.value.substring(begin, end); 
     350                html = html + selection + '</a>'; 
     351                cursor = begin + html.length; 
     352 
     353                // If no text is selected, place the cursor inside the closing tag. 
     354                if (begin === end && !selection) { 
     355                    cursor -= 4; 
     356                } 
     357 
     358                textarea.value = ( 
     359                    textarea.value.substring(0, begin) + 
     360                    html + 
     361                    textarea.value.substring(end, textarea.value.length) 
     362                ); 
     363 
     364                // Update cursor position 
     365                textarea.selectionStart = textarea.selectionEnd = cursor; 
     366            } 
     367 
     368            wpLink.close(); 
     369            textarea.focus(); 
     370        }, 
     371 
     372        mceUpdate: function() { 
     373            var attrs = wpLink.getAttrs(), 
     374                link, text; 
     375 
     376            wpLink.close(); 
     377            editor.focus(); 
     378 
     379            if (tinymce.isIE) { 
     380                editor.selection.moveToBookmark(editor.windowManager.bookmark); 
     381            } 
     382 
     383            if (!attrs.href) { 
     384                editor.execCommand('unlink'); 
     385                return; 
     386            } 
     387 
     388            link = getLink(); 
     389            text = inputs.text.val(); 
     390 
     391            if (link) { 
     392                if (text) { 
     393                    if ('innerText' in link) { 
     394                        link.innerText = text; 
     395                    } else { 
     396                        link.textContent = text; 
     397                    } 
     398                } 
     399 
     400                editor.dom.setAttribs(link, attrs); 
     401            } else { 
     402                if (text) { 
     403                    editor.selection.setNode(editor.dom.create('a', attrs, text)); 
     404                } else { 
     405                    editor.execCommand('mceInsertLink', false, attrs); 
     406                } 
     407            } 
     408        }, 
     409 
     410        updateFields: function(e, li) { 
     411            inputs.url.val(li.children('.item-permalink') 
     412                .val()); 
     413        }, 
     414 
     415        setDefaultValues: function() { 
     416            var selection, 
     417                emailRegexp = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i, 
     418                urlRegexp = /^(https?|ftp):\/\/[A-Z0-9.-]+\.[A-Z]{2,4}[^ "]*$/i; 
     419 
     420            if (this.isMCE()) { 
     421                selection = editor.selection.getContent(); 
     422            } else if (document.selection && wpLink.range) { 
     423                selection = wpLink.range.text; 
     424            } else if (typeof this.textarea.selectionStart !== 'undefined') { 
     425                selection = this.textarea.value.substring(this.textarea.selectionStart, this.textarea.selectionEnd); 
     426            } 
     427 
     428            if (selection && emailRegexp.test(selection)) { 
     429                // Selection is email address 
     430                inputs.url.val('mailto:' + selection); 
     431            } else if (selection && urlRegexp.test(selection)) { 
     432                // Selection is URL 
     433                inputs.url.val(selection.replace(/&amp;|&#0?38;/gi, '&')); 
     434            } else { 
     435                // Set URL to default. 
     436                inputs.url.val(''); 
     437            } 
     438 
     439            // Update save prompt. 
     440            inputs.submit.val(wpLinkL10n.save); 
     441        }, 
     442 
     443        searchInternalLinks: function() { 
     444            var t = $(this), 
     445                waiting, 
     446                search = t.val(); 
     447 
     448            if (search.length > 2) { 
     449                rivers.recent.hide(); 
     450                rivers.search.show(); 
     451 
     452                // Don't search if the keypress didn't change the title. 
     453                if (wpLink.lastSearch == search) 
     454                    return; 
     455 
     456                wpLink.lastSearch = search; 
     457                waiting = t.parent() 
     458                    .find('.spinner') 
     459                    .addClass('is-active'); 
     460 
     461                rivers.search.change(search); 
     462                rivers.search.ajax(function() { 
     463                    waiting.removeClass('is-active'); 
     464                }); 
     465            } else { 
     466                rivers.search.hide(); 
     467                rivers.recent.show(); 
     468            } 
     469        }, 
     470 
     471        next: function() { 
     472            rivers.search.next(); 
     473            rivers.recent.next(); 
     474        }, 
     475 
     476        prev: function() { 
     477            rivers.search.prev(); 
     478            rivers.recent.prev(); 
     479        }, 
     480 
     481        keydown: function(event) { 
     482            var fn, id, 
     483                key = $.ui.keyCode; 
     484 
     485            if (key.ESCAPE === event.keyCode) { 
     486                wpLink.close(); 
     487                event.stopImmediatePropagation(); 
     488            } else if (key.TAB === event.keyCode) { 
     489                id = event.target.id; 
     490 
     491                // wp-link-submit must always be the last focusable element in the dialog. 
     492                // following focusable elements will be skipped on keyboard navigation. 
     493                if (id === 'wp-link-submit' && !event.shiftKey) { 
     494                    inputs.close.focus(); 
     495                    event.preventDefault(); 
     496                } else if (id === 'wp-link-close' && event.shiftKey) { 
     497                    inputs.submit.focus(); 
     498                    event.preventDefault(); 
     499                } 
     500            } 
     501 
     502            if (event.keyCode !== key.UP && event.keyCode !== key.DOWN) { 
     503                return; 
     504            } 
     505 
     506            if (document.activeElement && 
     507                (document.activeElement.id === 'link-title-field' || document.activeElement.id === 'url-field')) { 
     508                return; 
     509            } 
     510 
     511            fn = event.keyCode === key.UP ? 'prev' : 'next'; 
     512            clearInterval(wpLink.keyInterval); 
     513            wpLink[fn](); 
     514            wpLink.keyInterval = setInterval(wpLink[fn], wpLink.keySensitivity); 
     515            event.preventDefault(); 
     516        }, 
     517 
     518        keyup: function(event) { 
     519            var key = $.ui.keyCode; 
     520 
     521            if (event.which === key.UP || event.which === key.DOWN) { 
     522                clearInterval(wpLink.keyInterval); 
     523                event.preventDefault(); 
     524            } 
     525        }, 
     526 
     527        delayedCallback: function(func, delay) { 
     528            var timeoutTriggered, funcTriggered, funcArgs, funcContext; 
     529 
     530            if (!delay) 
     531                return func; 
     532 
     533            setTimeout(function() { 
     534                if (funcTriggered) 
     535                    return func.apply(funcContext, funcArgs); 
     536                // Otherwise, wait. 
     537                timeoutTriggered = true; 
     538            }, delay); 
     539 
     540            return function() { 
     541                if (timeoutTriggered) 
     542                    return func.apply(this, arguments); 
     543                // Otherwise, wait. 
     544                funcArgs = arguments; 
     545                funcContext = this; 
     546                funcTriggered = true; 
     547            }; 
     548        }, 
     549 
     550        toggleInternalLinking: function(event) { 
     551            var visible = inputs.wrap.hasClass('search-panel-visible'); 
     552 
     553            inputs.wrap.toggleClass('search-panel-visible', !visible); 
     554            setUserSetting('wplink', visible ? '0' : '1'); 
     555            inputs[!visible ? 'search' : 'url'].focus(); 
     556            event.preventDefault(); 
     557        } 
     558    }; 
     559 
     560    River = function(element, search) { 
     561        var self = this; 
     562        this.element = element; 
     563        this.ul = element.children('ul'); 
     564        this.contentHeight = element.children('#link-selector-height'); 
     565        this.waiting = element.find('.river-waiting'); 
     566 
     567        this.change(search); 
     568        this.refresh(); 
     569 
     570        $('#wp-link .query-results, #wp-link #link-selector') 
     571            .scroll(function() { 
     572                self.maybeLoad(); 
     573            }); 
     574        element.on('click', 'li', function(event) { 
     575            self.select($(this), event); 
     576        }); 
     577    }; 
     578 
     579    $.extend(River.prototype, { 
     580        refresh: function() { 
     581            this.deselect(); 
     582            this.visible = this.element.is(':visible'); 
     583        }, 
     584        show: function() { 
     585            if (!this.visible) { 
     586                this.deselect(); 
     587                this.element.show(); 
     588                this.visible = true; 
     589            } 
     590        }, 
     591        hide: function() { 
     592            this.element.hide(); 
     593            this.visible = false; 
     594        }, 
     595        // Selects a list item and triggers the river-select event. 
     596        select: function(li, event) { 
     597            var liHeight, elHeight, liTop, elTop; 
     598 
     599            if (li.hasClass('unselectable') || li == this.selected) 
     600                return; 
     601 
     602            this.deselect(); 
     603            this.selected = li.addClass('selected'); 
     604            // Make sure the element is visible 
     605            liHeight = li.outerHeight(); 
     606            elHeight = this.element.height(); 
     607            liTop = li.position() 
     608                .top; 
     609            elTop = this.element.scrollTop(); 
     610 
     611            if (liTop < 0) // Make first visible element 
     612                this.element.scrollTop(elTop + liTop); 
     613            else if (liTop + liHeight > elHeight) // Make last visible element 
     614                this.element.scrollTop(elTop + liTop - elHeight + liHeight); 
     615 
     616            // Trigger the river-select event 
     617            this.element.trigger('river-select', [li, event, this]); 
     618        }, 
     619        deselect: function() { 
     620            if (this.selected) 
     621                this.selected.removeClass('selected'); 
     622            this.selected = false; 
     623        }, 
     624        prev: function() { 
     625            if (!this.visible) 
     626                return; 
     627 
     628            var to; 
     629            if (this.selected) { 
     630                to = this.selected.prev('li'); 
     631                if (to.length) 
     632                    this.select(to); 
     633            } 
     634        }, 
     635        next: function() { 
     636            if (!this.visible) 
     637                return; 
     638 
     639            var to = this.selected ? this.selected.next('li') : $('li:not(.unselectable):first', this.element); 
     640            if (to.length) 
     641                this.select(to); 
     642        }, 
     643        ajax: function(callback) { 
     644            var self = this, 
     645                delay = this.query.page == 1 ? 0 : wpLink.minRiverAJAXDuration, 
     646                response = wpLink.delayedCallback(function(results, params) { 
     647                    self.process(results, params); 
     648                    if (callback) 
     649                        callback(results, params); 
     650                }, delay); 
     651 
     652            this.query.ajax(response); 
     653        }, 
     654        change: function(search) { 
     655            if (this.query && this._search == search) 
     656                return; 
     657 
     658            this._search = search; 
     659            this.query = new Query(search); 
     660            this.element.scrollTop(0); 
     661        }, 
     662        process: function(results, params) { 
     663            var list = '', 
     664                alt = true, 
     665                classes = '', 
     666                firstPage = params.page == 1; 
     667 
     668            if (!results) { 
     669                if (firstPage) { 
     670                    list += '<li class="unselectable no-matches-found"><span class="item-title"><em>' + 
     671                        wpLinkL10n.noMatchesFound + '</em></span></li>'; 
     672                } 
     673            } else { 
     674                $.each(results, function() { 
     675                    classes = alt ? 'alternate' : ''; 
     676                    classes += this.title ? '' : ' no-title'; 
     677                    list += classes ? '<li class="' + classes + '">' : '<li>'; 
     678                    list += '<input type="hidden" class="item-permalink" value="' + this.permalink + '" />'; 
     679                    list += '<span class="item-title">'; 
     680                    list += this.title ? this.title : wpLinkL10n.noTitle; 
     681                    list += '</span><span class="item-info">' + this.info + '</span></li>'; 
     682                    alt = !alt; 
     683                }); 
     684            } 
     685 
     686            this.ul[firstPage ? 'html' : 'append'](list); 
     687        }, 
     688        maybeLoad: function() { 
     689            var self = this, 
     690                el = this.element, 
     691                bottom = el.scrollTop() + el.height(); 
     692 
     693            if (!this.query.ready() || bottom < this.contentHeight.height() - wpLink.riverBottomThreshold) 
     694                return; 
     695 
     696            setTimeout(function() { 
     697                var newTop = el.scrollTop(), 
     698                    newBottom = newTop + el.height(); 
     699 
     700                if (!self.query.ready() || newBottom < self.contentHeight.height() - wpLink.riverBottomThreshold) 
     701                    return; 
     702 
     703                self.waiting.addClass('is-active'); 
     704                el.scrollTop(newTop + self.waiting.outerHeight()); 
     705 
     706                self.ajax(function() { 
     707                    self.waiting.removeClass('is-active'); 
     708                }); 
     709            }, wpLink.timeToTriggerRiver); 
     710        } 
     711    }); 
     712 
     713    Query = function(search) { 
     714        this.page = 1; 
     715        this.allLoaded = false; 
     716        this.querying = false; 
     717        this.search = search; 
     718    }; 
     719 
     720    $.extend(Query.prototype, { 
     721        ready: function() { 
     722            return !(this.querying || this.allLoaded); 
     723        }, 
     724        ajax: function(callback) { 
     725            var self = this, 
     726                query = { 
     727                    action: 'wp-link-ajax', 
     728                    page: this.page, 
     729                    '_ajax_linking_nonce': inputs.nonce.val() 
     730                }; 
     731 
     732            if (this.search) 
     733                query.search = this.search; 
     734 
     735            this.querying = true; 
     736 
     737            $.post(ajaxurl, query, function(r) { 
     738                self.page++; 
     739                self.querying = false; 
     740                self.allLoaded = !r; 
     741                callback(r, query); 
     742            }, 'json'); 
     743        } 
     744    }); 
     745 
     746    $(document) 
     747        .ready(wpLink.init); 
     748})(jQuery); 
  • rel-nofollow-checkbox/trunk/wplink.min.js

    r1144964 r1146137  
    1 /* rel-nofollow-checkbox v1.1.0 | GPLv2 License | by fabiosantos.me */ 
     1/* rel-nofollow-checkbox v1.1.1 | GPLv2 License | by fabiosantos.me */ 
     2/* global ajaxurl, tinymce, wpLinkL10n, setUserSetting, wpActiveEditor */ 
    23var wpLink;!function(e){function t(){return n.dom.getParent(n.selection.getNode(),"a")}var n,i,s,a,r,l={},o={},c="ontouchend"in document;wpLink={timeToTriggerRiver:150,minRiverAJAXDuration:200,riverBottomThreshold:5,keySensitivity:100,lastSearch:"",textarea:"",init:function(){function t(){var t=e.trim(l.url.val());t&&r!==t&&!/^(?:[a-z]+:|#|\?|\.|\/)/.test(t)&&(l.url.val("http://"+t),r=t)}var n='<div><label><span> </span><input type="checkbox" id="rel-nofollow-checkbox" /><strong> rel="nofollow"</strong></label></div>';e(n).insertAfter("#wp-link .link-target"),e("#wp-link-wrap").css("min-height","310px"),l.wrap=e("#wp-link-wrap"),l.dialog=e("#wp-link"),l.backdrop=e("#wp-link-backdrop"),l.submit=e("#wp-link-submit"),l.close=e("#wp-link-close"),l.text=e("#wp-link-text"),l.url=e("#wp-link-url"),l.nonce=e("#_ajax_linking_nonce"),l.fsRelNofollow=e("#rel-nofollow-checkbox"),l.openInNewTab=e("#wp-link-target"),l.search=e("#wp-link-search"),o.search=new s(e("#search-results")),o.recent=new s(e("#most-recent-results")),o.elements=l.dialog.find(".query-results"),l.queryNotice=e("#query-notice-message"),l.queryNoticeTextDefault=l.queryNotice.find(".query-notice-default"),l.queryNoticeTextHint=l.queryNotice.find(".query-notice-hint"),l.dialog.keydown(wpLink.keydown),l.dialog.keyup(wpLink.keyup),l.submit.click(function(e){e.preventDefault(),wpLink.update()}),l.close.add(l.backdrop).add("#wp-link-cancel a").click(function(e){e.preventDefault(),wpLink.close()}),e("#wp-link-search-toggle").on("click",wpLink.toggleInternalLinking),o.elements.on("river-select",wpLink.updateFields),l.search.on("focus.wplink",function(){l.queryNoticeTextDefault.hide(),l.queryNoticeTextHint.removeClass("screen-reader-text").show()}).on("blur.wplink",function(){l.queryNoticeTextDefault.show(),l.queryNoticeTextHint.addClass("screen-reader-text").hide()}),l.search.keyup(function(){var e=this;window.clearTimeout(i),i=window.setTimeout(function(){wpLink.searchInternalLinks.call(e)},500)}),l.url.on("paste",function(){setTimeout(t,0)}),l.url.on("blur",t)},open:function(t){var i;e(document.body).addClass("modal-open"),wpLink.range=null,t&&(window.wpActiveEditor=t),window.wpActiveEditor&&(this.textarea=e("#"+window.wpActiveEditor).get(0),"undefined"!=typeof tinymce&&(i=tinymce.get(wpActiveEditor),n=i&&!i.isHidden()?i:null,n&&tinymce.isIE&&(n.windowManager.bookmark=n.selection.getBookmark())),!wpLink.isMCE()&&document.selection&&(this.textarea.focus(),this.range=document.selection.createRange()),l.wrap.show(),l.backdrop.show(),wpLink.refresh(),e(document).trigger("wplink-open",l.wrap))},isMCE:function(){return n&&!n.isHidden()},refresh:function(){var e="";o.search.refresh(),o.recent.refresh(),wpLink.isMCE()?wpLink.mceRefresh():(l.wrap.hasClass("has-text-field")||l.wrap.addClass("has-text-field"),document.selection?e=document.selection.createRange().text||"":"undefined"!=typeof this.textarea.selectionStart&&this.textarea.selectionStart!==this.textarea.selectionEnd&&(e=this.textarea.value.substring(this.textarea.selectionStart,this.textarea.selectionEnd)||""),l.text.val(e),wpLink.setDefaultValues()),c?l.url.focus().blur():l.url.focus()[0].select(),o.recent.ul.children().length||o.recent.ajax(),r=l.url.val().replace(/^http:\/\//,"")},hasSelectedText:function(e){var t=n.selection.getContent();if(/</.test(t)&&(!/^<a [^>]+>[^<]+<\/a>$/.test(t)||-1===t.indexOf("href=")))return!1;if(e){var i,s=e.childNodes;if(0===s.length)return!1;for(i=s.length-1;i>=0;i--)if(3!=s[i].nodeType)return!1}return!0},mceRefresh:function(){var e,t=n.selection.getNode(),i=n.dom.getParent(t,"a[href]"),s=this.hasSelectedText(i);i?(e=i.innerText||i.textContent,l.url.val(n.dom.getAttrib(i,"href")),l.openInNewTab.prop("checked","_blank"===n.dom.getAttrib(i,"target")),l.fsRelNofollow.prop("checked","nofollow"===n.dom.getAttrib(i,"rel")),l.submit.val(wpLinkL10n.update)):(e=n.selection.getContent({format:"text"}),this.setDefaultValues()),s?(l.text.val(e||""),l.wrap.addClass("has-text-field")):(l.text.val(""),l.wrap.removeClass("has-text-field"))},close:function(){e(document.body).removeClass("modal-open"),wpLink.isMCE()?n.focus():(wpLink.textarea.focus(),wpLink.range&&(wpLink.range.moveToBookmark(wpLink.range.getBookmark()),wpLink.range.select())),l.backdrop.hide(),l.wrap.hide(),r=!1,e(document).trigger("wplink-close",l.wrap)},getAttrs:function(){return{href:e.trim(l.url.val()),target:l.openInNewTab.prop("checked")?"_blank":"",rel:l.fsRelNofollow.prop("checked")?"nofollow":""}},update:function(){wpLink.isMCE()?wpLink.mceUpdate():wpLink.htmlUpdate()},htmlUpdate:function(){var e,t,n,i,s,a,r,o=wpLink.textarea;o&&(e=wpLink.getAttrs(),t=l.text.val(),e.href&&(n='<a href="'+e.href+'"',e.target&&(n+=' target="'+e.target+'"'),e.rel&&(n+=' rel="nofollow"'),n+=">",document.selection&&wpLink.range?(o.focus(),wpLink.range.text=n+(t||wpLink.range.text)+"</a>",wpLink.range.moveToBookmark(wpLink.range.getBookmark()),wpLink.range.select(),wpLink.range=null):"undefined"!=typeof o.selectionStart&&(i=o.selectionStart,s=o.selectionEnd,r=t||o.value.substring(i,s),n=n+r+"</a>",a=i+n.length,i!==s||r||(a-=4),o.value=o.value.substring(0,i)+n+o.value.substring(s,o.value.length),o.selectionStart=o.selectionEnd=a),wpLink.close(),o.focus()))},mceUpdate:function(){var e,i,s=wpLink.getAttrs();return wpLink.close(),n.focus(),tinymce.isIE&&n.selection.moveToBookmark(n.windowManager.bookmark),s.href?(e=t(),i=l.text.val(),void(e?(i&&("innerText"in e?e.innerText=i:e.textContent=i),n.dom.setAttribs(e,s)):i?n.selection.setNode(n.dom.create("a",s,i)):n.execCommand("mceInsertLink",!1,s))):void n.execCommand("unlink")},updateFields:function(e,t){l.url.val(t.children(".item-permalink").val())},setDefaultValues:function(){var e,t=/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i,i=/^(https?|ftp):\/\/[A-Z0-9.-]+\.[A-Z]{2,4}[^ "]*$/i;this.isMCE()?e=n.selection.getContent():document.selection&&wpLink.range?e=wpLink.range.text:"undefined"!=typeof this.textarea.selectionStart&&(e=this.textarea.value.substring(this.textarea.selectionStart,this.textarea.selectionEnd)),l.url.val(e&&t.test(e)?"mailto:"+e:e&&i.test(e)?e.replace(/&amp;|&#0?38;/gi,"&"):""),l.submit.val(wpLinkL10n.save)},searchInternalLinks:function(){var t,n=e(this),i=n.val();if(i.length>2){if(o.recent.hide(),o.search.show(),wpLink.lastSearch==i)return;wpLink.lastSearch=i,t=n.parent().find(".spinner").addClass("is-active"),o.search.change(i),o.search.ajax(function(){t.removeClass("is-active")})}else o.search.hide(),o.recent.show()},next:function(){o.search.next(),o.recent.next()},prev:function(){o.search.prev(),o.recent.prev()},keydown:function(t){var n,i,s=e.ui.keyCode;s.ESCAPE===t.keyCode?(wpLink.close(),t.stopImmediatePropagation()):s.TAB===t.keyCode&&(i=t.target.id,"wp-link-submit"!==i||t.shiftKey?"wp-link-close"===i&&t.shiftKey&&(l.submit.focus(),t.preventDefault()):(l.close.focus(),t.preventDefault())),(t.keyCode===s.UP||t.keyCode===s.DOWN)&&(!document.activeElement||"link-title-field"!==document.activeElement.id&&"url-field"!==document.activeElement.id)&&(n=t.keyCode===s.UP?"prev":"next",clearInterval(wpLink.keyInterval),wpLink[n](),wpLink.keyInterval=setInterval(wpLink[n],wpLink.keySensitivity),t.preventDefault())},keyup:function(t){var n=e.ui.keyCode;(t.which===n.UP||t.which===n.DOWN)&&(clearInterval(wpLink.keyInterval),t.preventDefault())},delayedCallback:function(e,t){var n,i,s,a;return t?(setTimeout(function(){return i?e.apply(a,s):void(n=!0)},t),function(){return n?e.apply(this,arguments):(s=arguments,a=this,void(i=!0))}):e},toggleInternalLinking:function(e){var t=l.wrap.hasClass("search-panel-visible");l.wrap.toggleClass("search-panel-visible",!t),setUserSetting("wplink",t?"0":"1"),l[t?"url":"search"].focus(),e.preventDefault()}},s=function(t,n){var i=this;this.element=t,this.ul=t.children("ul"),this.contentHeight=t.children("#link-selector-height"),this.waiting=t.find(".river-waiting"),this.change(n),this.refresh(),e("#wp-link .query-results, #wp-link #link-selector").scroll(function(){i.maybeLoad()}),t.on("click","li",function(t){i.select(e(this),t)})},e.extend(s.prototype,{refresh:function(){this.deselect(),this.visible=this.element.is(":visible")},show:function(){this.visible||(this.deselect(),this.element.show(),this.visible=!0)},hide:function(){this.element.hide(),this.visible=!1},select:function(e,t){var n,i,s,a;e.hasClass("unselectable")||e==this.selected||(this.deselect(),this.selected=e.addClass("selected"),n=e.outerHeight(),i=this.element.height(),s=e.position().top,a=this.element.scrollTop(),0>s?this.element.scrollTop(a+s):s+n>i&&this.element.scrollTop(a+s-i+n),this.element.trigger("river-select",[e,t,this]))},deselect:function(){this.selected&&this.selected.removeClass("selected"),this.selected=!1},prev:function(){if(this.visible){var e;this.selected&&(e=this.selected.prev("li"),e.length&&this.select(e))}},next:function(){if(this.visible){var t=this.selected?this.selected.next("li"):e("li:not(.unselectable):first",this.element);t.length&&this.select(t)}},ajax:function(e){var t=this,n=1==this.query.page?0:wpLink.minRiverAJAXDuration,i=wpLink.delayedCallback(function(n,i){t.process(n,i),e&&e(n,i)},n);this.query.ajax(i)},change:function(e){this.query&&this._search==e||(this._search=e,this.query=new a(e),this.element.scrollTop(0))},process:function(t,n){var i="",s=!0,a="",r=1==n.page;t?e.each(t,function(){a=s?"alternate":"",a+=this.title?"":" no-title",i+=a?'<li class="'+a+'">':"<li>",i+='<input type="hidden" class="item-permalink" value="'+this.permalink+'" />',i+='<span class="item-title">',i+=this.title?this.title:wpLinkL10n.noTitle,i+='</span><span class="item-info">'+this.info+"</span></li>",s=!s}):r&&(i+='<li class="unselectable no-matches-found"><span class="item-title"><em>'+wpLinkL10n.noMatchesFound+"</em></span></li>"),this.ul[r?"html":"append"](i)},maybeLoad:function(){var e=this,t=this.element,n=t.scrollTop()+t.height();!this.query.ready()||n<this.contentHeight.height()-wpLink.riverBottomThreshold||setTimeout(function(){var n=t.scrollTop(),i=n+t.height();!e.query.ready()||i<e.contentHeight.height()-wpLink.riverBottomThreshold||(e.waiting.addClass("is-active"),t.scrollTop(n+e.waiting.outerHeight()),e.ajax(function(){e.waiting.removeClass("is-active")}))},wpLink.timeToTriggerRiver)}}),a=function(e){this.page=1,this.allLoaded=!1,this.querying=!1,this.search=e},e.extend(a.prototype,{ready:function(){return!(this.querying||this.allLoaded)},ajax:function(t){var n=this,i={action:"wp-link-ajax",page:this.page,_ajax_linking_nonce:l.nonce.val()};this.search&&(i.search=this.search),this.querying=!0,e.post(ajaxurl,i,function(e){n.page++,n.querying=!1,n.allLoaded=!e,t(e,i)},"json")}}),e(document).ready(wpLink.init)}(jQuery); 
Note: See TracChangeset for help on using the changeset viewer.