Ultimate Nofollow - Version 1.4.3

Version Description

  • Fixes compatibility issue with Wordpress 4.2
  • Thanks to Zoe Corkhill for the fix
Download this release

Release Info

Developer bitacre
Plugin Icon wp plugin Ultimate Nofollow
Version 1.4.3
Comparing to
See all releases

Code changes from version 1.4.2 to 1.4.3

Files changed (4) hide show
  1. nofollow.php +273 -273
  2. readme.txt +110 -103
  3. wplink.js +224 -85
  4. wplink.min.js +1 -1
nofollow.php CHANGED
@@ -1,273 +1,273 @@
1
- <?php
2
- /*
3
- Plugin Name: Ultimate Nofollow
4
- Plugin URI: http://shinraholdings.com/plugins/nofollow
5
- Description: A suite of tools that gives you complete control over the rel=nofollow tag on an individual link basis.
6
- Version: 1.4.2
7
- Author: bitacre
8
- Author URI: http://shinraholdings.com.com
9
- License: GPLv2
10
- Copyright 2012 Shinra Web Holdings (shinraholdings.com)
11
-
12
- This plugin contains several tools in one to significantly increase your control of the nofollow rel tag on every link on your blog, on both an individual and type basis. It is designed to give you fine-grained control of linking for SEO purposes.
13
-
14
- Notice: This plugin is still in beta. While it is stable, not all functions listed are included yet.
15
-
16
- */
17
-
18
- /***********************
19
- * OPTIONS PAGE SECTION *
20
- ************************/
21
-
22
- /* add plugin's options to white list / defaults */
23
- function ultnofo_options_init() {
24
- register_setting( 'ultnofo_options_options', 'ultnofo_item', 'ultnofo_options_validate' );
25
-
26
- // if option doesn't exist, set defaults
27
- if( !get_option( 'ultnofo_item' ) ) add_option( 'ultnofo_item', array( 'nofollow_comments' => 1, 'nofollow_blogroll' => 0 ), '', 'no' );
28
- }
29
-
30
- /* add link to plugin's settings page under 'settings' on the admin menu */
31
- function ultnofo_options_add_page() {
32
- add_options_page( 'Ultimate Nofollow Settings', 'Nofollow', 'manage_options', 'ultimate-nofollow', 'ultnofo_options_do_page' );
33
- }
34
-
35
- /* sanitize and validate input.
36
- accepts an array, returns a sanitized array. */
37
- function ultnofo_options_validate( $input ) {
38
- $input[ 'nofollow_comments' ] = ( $input[ 'nofollow_comments' ] == 1 ? 1 : 0 ); // (checkbox) if 1 then 1, else 0
39
- // $input[ 'test_text_1' ] = wp_filter_nohtml_kses( $input[ 'test_text_1' ] ); // (textbox) safe text, no html
40
- return $input;
41
- }
42
-
43
- /* draw the settings page itself */
44
- function ultnofo_options_do_page() {
45
- ?>
46
- <div class="wrap">
47
- <div class="icon32" id="icon-options-general"><br /></div>
48
- <h2>Ultimate Nofollow Settings</h2>
49
- <form method="post" action="options.php">
50
- <?php settings_fields( 'ultnofo_options_options' ); // nonce settings page ?>
51
- <?php $options = get_option( 'ultnofo_item' ); // populate $options array from database ?>
52
- <table class="form-table">
53
-
54
-
55
- <!-- all comment links -->
56
- <tr valign="top">
57
- <th scope="row">Nofollow all links in comments?</th>
58
- <td><input name="ultnofo_item[nofollow_comments]" type="checkbox" value="1" <?php checked( $options[ 'nofollow_comments' ] ); ?> />
59
- </td>
60
- </tr>
61
-
62
-
63
- <!-- all blogroll links -->
64
- <tr valign="top">
65
- <th scope="row">Nofollow all blogroll links?</th>
66
- <td><input name="ultnofo_item[nofollow_blogroll]" type="checkbox" value="1" <?php checked( $options[ 'nofollow_blogroll' ] ); ?> />
67
- <span style="color:red; font-size:smaller">(warning: will override individual selections!)</span></td>
68
- </tr>
69
-
70
-
71
-
72
- <!-- <tr valign="top"><th scope="row">Text:</th>
73
- <td>
74
- UA-<input type="text" name="ssga_item[sometext1]" value="<?php // echo $options[ 'test_text_1']; ?>" style="width:90px;" maxlength="8" />
75
- </td>
76
- </tr> -->
77
- </table>
78
- <p class="submit">
79
- <input type="submit" class="button-primary" value="<?php _e('Save Changes') ?>" />
80
- </p>
81
- </form>
82
- </div>
83
- <?php
84
- }
85
-
86
- /* define additional plugin meta links */
87
- function set_plugin_meta_ultnofo( $links, $file ) {
88
- $plugin = plugin_basename( __FILE__ ); // '/nofollow/nofollow.php' by default
89
- if ( $file == $plugin ) { // if called for THIS plugin then:
90
- $newlinks = array(
91
- '<a href="options-general.php?page=ultimate-nofollow">Settings</a>',
92
- '<a href="http://shinraholdings.com/plugins/nofollow/help">Help Page</a>'
93
- ); // array of links to add
94
- return array_merge( $links, $newlinks ); // merge new links into existing $links
95
- }
96
- return $links; // return the $links (merged or otherwise)
97
- }
98
-
99
- /* add hooks/filters */
100
- // add meta links to plugin's section on 'plugins' page (10=priority, 2=num of args)
101
- add_filter( 'plugin_row_meta', 'set_plugin_meta_ultnofo', 10, 2 );
102
-
103
- // add plugin's options to white list on admin initialization
104
- add_action('admin_init', 'ultnofo_options_init' );
105
-
106
- // add link to plugin's settings page in 'settings' menu on admin menu initilization
107
- add_action('admin_menu', 'ultnofo_options_add_page');
108
-
109
- /******************************
110
- * NOFOLLOW SHORTCODES SECTION *
111
- *******************************/
112
-
113
- /* valid href starting substring? */
114
- function ultnofo_valid_url( $href ) {
115
- $start_strs = array( // list of accepted url protocols
116
- '/',
117
- 'http://',
118
- 'https://',
119
- 'ftp://',
120
- 'mailto:',
121
- 'magnet:',
122
- 'svn://',
123
- 'irc:',
124
- 'gopher://',
125
- 'telnet://',
126
- 'nntp://',
127
- 'worldwind://',
128
- 'news:',
129
- 'git://',
130
- 'mms://'
131
- );
132
-
133
- foreach( $start_strs as $start_str )
134
- if( substr( $href, 0, strlen( $start_str ) ) == $start_str ) return TRUE;
135
-
136
- return FALSE;
137
- }
138
-
139
- /* return nofollow link html or html error comment */
140
- function ultnofo_nofollow_link( $atts, $content = NULL ) {
141
- extract(
142
- shortcode_atts(
143
- array(
144
- 'href' => NULL,
145
- 'title' => NULL,
146
- 'target' => NULL
147
- ),
148
- $atts
149
- )
150
- );
151
-
152
- // href
153
- if( !ultnofo_valid_url( $href ) ) return '<!-- Ultimate Nofollow Plugin | shortcode insertion failed | given href resource not valid, href must begin with: ' . print_r( $start_strs, TRUE ) . ' -->'; // if url doesn't starts with valid string
154
- else $href_chunk = ' href="' . $href . '"'; // else add href=''
155
-
156
- // title
157
- if( empty( $title ) ) $title_chunk = NULL; // if no $title, omit HTML
158
- else $title_chunk = ' title="' . trim( htmlentities( strip_tags( $title ), ENT_QUOTES ) ) . '"'; // else add title=''
159
-
160
- // target
161
- if( empty( $target ) ) $target_chunk = NULL; // if no $target, omit HTML
162
- else $target_chunk = ' target="' . trim( htmlentities( strip_tags( $target ), ENT_QUOTES ) ) . '"'; // else add target=''
163
-
164
- // content
165
- if( empty( $content ) ) return '<!-- Ultimate Nofollow Plugin | shortcode insertion failed | no link text given -->'; // if url doesn't starts with valid string
166
- else $content_chunk = trim( htmlentities( strip_tags( $content ), ENT_QUOTES ) ); // else add $content
167
-
168
- return '<a' . $href_chunk . $target_chunk . $title_chunk . ' rel="nofollow">' . $content_chunk . '</a>';
169
- }
170
-
171
- /* add hooks/filters */
172
- // add shortcodes
173
- $shortcodes = array(
174
- 'relnofollow',
175
- 'nofollow',
176
- 'nofol',
177
- 'nofo',
178
- 'nf'
179
- );
180
- foreach( $shortcodes as $shortcode ) add_shortcode( $shortcode, 'ultnofo_nofollow_link' );
181
-
182
- /****************************
183
- * BLOGROLL NOFOLLOW SECTION *
184
- *****************************/
185
-
186
- function ultnofo_blogroll_add_meta_box() {
187
- add_meta_box( 'ultnofo_blogroll_nofollow_div', 'Ultimate Nofollow', 'ultnofo_blogroll_inner_meta_box', 'link', 'side','high' );
188
- }
189
-
190
- function ultnofo_blogroll_inner_meta_box ( $post ) {
191
- $bookmark = get_bookmark( $post->ID, 'ARRAY_A' );
192
- if( strpos( $bookmark['link_rel'], 'nofollow' ) !== FALSE ) $checked = ' checked="checked"';
193
- else $checked = '';
194
-
195
- $options = get_option( 'ultnofo_item' );
196
- if( $options['nofollow_blogroll'] ) {
197
- $disabled=' disabled="disabled"';
198
- $message='<br /><span style="color:red; font-size:smaller;">ALL blogroll links nofollowed on the <a href="options-general.php?page=ultimate-nofollow" target="_blank">options</a> page.</span>';
199
- }
200
- else {
201
- $disabled = '';
202
- $message = '';
203
- }
204
-
205
- ?>
206
- <label for="ultnofo_blogroll_nofollow_checkbox">Nofollow this link?</label>
207
- <input value="1" id="ultnofo_blogroll_nofollow_checkbox" name="ultnofo_blogroll_nofollow_checkbox"<?php echo $disabled; ?> type="checkbox"<?php echo $checked; ?> /> <?php echo $message; ?>
208
- <?php
209
- }
210
-
211
- function ultnofo_blogroll_save_meta_box( $link_rel ) {
212
- $rel = trim( str_replace( 'nofollow', '', $link_rel ) );
213
- if( $_POST['ultnofo_blogroll_nofollow_checkbox'] ) $rel .= ' nofollow';
214
- return trim( $rel );
215
- }
216
-
217
- function ultnofo_blogroll_nofollow_all( $links ) {
218
- foreach( $links as $link ) {
219
- $rel = trim( str_replace('nofollow', '', $link->link_rel ) );
220
- $link->link_rel = trim( $rel . ' nofollow' );
221
- }
222
- return $links;
223
- }
224
-
225
- /* add hooks/filters */
226
- add_action( 'add_meta_boxes', 'ultnofo_blogroll_add_meta_box', 1 );
227
- add_filter( 'pre_link_rel', 'ultnofo_blogroll_save_meta_box', 99998, 1);
228
-
229
- $ultnofo_options = get_option( 'ultnofo_item' ); // NOT IN FUNCTION
230
- if( $ultnofo_options['nofollow_blogroll'] ) add_filter( 'get_bookmarks', 'ultnofo_blogroll_nofollow_all', 99999);
231
-
232
-
233
-
234
-
235
- /**********************************************
236
- * ADD LINK DIALOGUE NOFOLLOW CHECKBOX SECTION *
237
- ***********************************************/
238
- function nofollow_redo_wplink() {
239
- wp_deregister_script( 'wplink' );
240
-
241
- $suffix = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';
242
-
243
- wp_register_script( 'wplink', plugins_url( 'wplink' . $suffix . '.js', __FILE__), array( 'jquery', 'wpdialogs' ), false, 1 );
244
-
245
- wp_localize_script( 'wplink', 'wpLinkL10n', array(
246
- 'title' => __('Insert/edit link'),
247
- 'update' => __('Update'),
248
- 'save' => __('Add Link'),
249
- 'noTitle' => __('(no title)'),
250
- 'noMatchesFound' => __('No matches found.')
251
- ) );
252
- }
253
- add_action( 'admin_enqueue_scripts', 'nofollow_redo_wplink', 999 );
254
-
255
-
256
- /************************************
257
- * NOFOLLOW ON COMMENT LINKS SECTION *
258
- *************************************/
259
-
260
- // add/remove nofollow from all comment links
261
- function ultnofo_comment_links( $comment ) {
262
- $options = get_option( 'ultnofo_item' );
263
- if( !$options[ 'nofollow_comments' ] )
264
- $comment = str_replace( 'rel="nofollow"', '', $comment );
265
- elseif( !strpos( $comment, 'rel="nofollow"' ) )
266
- $comment = str_replace( '<a ', '<a rel="nofollow"', $comment );
267
- return $comment;
268
- }
269
-
270
- /* add hooks/filters */
271
- // add/remove nofollow from comment links
272
- add_filter('comment_text', 'ultnofo_comment_links', 10);
273
- ?>
1
+ <?php
2
+ /*
3
+ Plugin Name: Ultimate Nofollow
4
+ Plugin URI: http://shinraholdings.com/plugins/nofollow
5
+ Description: A suite of tools that gives you complete control over the rel=nofollow tag on an individual link basis.
6
+ Version: 1.4.3
7
+ Author: bitacre
8
+ Author URI: http://shinraholdings.com.com
9
+ License: GPLv2
10
+ Copyright 2012 Shinra Web Holdings (shinraholdings.com)
11
+
12
+ This plugin contains several tools in one to significantly increase your control of the nofollow rel tag on every link on your blog, on both an individual and type basis. It is designed to give you fine-grained control of linking for SEO purposes.
13
+
14
+ Notice: This plugin changes WordPress functionality in a way that is not modular and may break with WP-Core updates.
15
+
16
+ */
17
+
18
+ /***********************
19
+ * OPTIONS PAGE SECTION *
20
+ ************************/
21
+
22
+ /* add plugin's options to white list / defaults */
23
+ function ultnofo_options_init() {
24
+ register_setting( 'ultnofo_options_options', 'ultnofo_item', 'ultnofo_options_validate' );
25
+
26
+ // if option doesn't exist, set defaults
27
+ if( !get_option( 'ultnofo_item' ) ) add_option( 'ultnofo_item', array( 'nofollow_comments' => 1, 'nofollow_blogroll' => 0 ), '', 'no' );
28
+ }
29
+
30
+ /* add link to plugin's settings page under 'settings' on the admin menu */
31
+ function ultnofo_options_add_page() {
32
+ add_options_page( 'Ultimate Nofollow Settings', 'Nofollow', 'manage_options', 'ultimate-nofollow', 'ultnofo_options_do_page' );
33
+ }
34
+
35
+ /* sanitize and validate input.
36
+ accepts an array, returns a sanitized array. */
37
+ function ultnofo_options_validate( $input ) {
38
+ $input[ 'nofollow_comments' ] = ( $input[ 'nofollow_comments' ] == 1 ? 1 : 0 ); // (checkbox) if 1 then 1, else 0
39
+ // $input[ 'test_text_1' ] = wp_filter_nohtml_kses( $input[ 'test_text_1' ] ); // (textbox) safe text, no html
40
+ return $input;
41
+ }
42
+
43
+ /* draw the settings page itself */
44
+ function ultnofo_options_do_page() {
45
+ ?>
46
+ <div class="wrap">
47
+ <div class="icon32" id="icon-options-general"><br /></div>
48
+ <h2>Ultimate Nofollow Settings</h2>
49
+ <form method="post" action="options.php">
50
+ <?php settings_fields( 'ultnofo_options_options' ); // nonce settings page ?>
51
+ <?php $options = get_option( 'ultnofo_item' ); // populate $options array from database ?>
52
+ <table class="form-table">
53
+
54
+
55
+ <!-- all comment links -->
56
+ <tr valign="top">
57
+ <th scope="row">Nofollow all links in comments?</th>
58
+ <td><input name="ultnofo_item[nofollow_comments]" type="checkbox" value="1" <?php checked( $options[ 'nofollow_comments' ] ); ?> />
59
+ </td>
60
+ </tr>
61
+
62
+
63
+ <!-- all blogroll links -->
64
+ <tr valign="top">
65
+ <th scope="row">Nofollow all blogroll links?</th>
66
+ <td><input name="ultnofo_item[nofollow_blogroll]" type="checkbox" value="1" <?php checked( $options[ 'nofollow_blogroll' ] ); ?> />
67
+ <span style="color:red; font-size:smaller">(warning: will override individual selections!)</span></td>
68
+ </tr>
69
+
70
+
71
+
72
+ <!-- <tr valign="top"><th scope="row">Text:</th>
73
+ <td>
74
+ UA-<input type="text" name="ssga_item[sometext1]" value="<?php // echo $options[ 'test_text_1']; ?>" style="width:90px;" maxlength="8" />
75
+ </td>
76
+ </tr> -->
77
+ </table>
78
+ <p class="submit">
79
+ <input type="submit" class="button-primary" value="<?php _e('Save Changes') ?>" />
80
+ </p>
81
+ </form>
82
+ </div>
83
+ <?php
84
+ }
85
+
86
+ /* define additional plugin meta links */
87
+ function set_plugin_meta_ultnofo( $links, $file ) {
88
+ $plugin = plugin_basename( __FILE__ ); // '/nofollow/nofollow.php' by default
89
+ if ( $file == $plugin ) { // if called for THIS plugin then:
90
+ $newlinks = array(
91
+ '<a href="options-general.php?page=ultimate-nofollow">Settings</a>',
92
+ '<a href="http://shinraholdings.com/plugins/nofollow/help">Help Page</a>'
93
+ ); // array of links to add
94
+ return array_merge( $links, $newlinks ); // merge new links into existing $links
95
+ }
96
+ return $links; // return the $links (merged or otherwise)
97
+ }
98
+
99
+ /* add hooks/filters */
100
+ // add meta links to plugin's section on 'plugins' page (10=priority, 2=num of args)
101
+ add_filter( 'plugin_row_meta', 'set_plugin_meta_ultnofo', 10, 2 );
102
+
103
+ // add plugin's options to white list on admin initialization
104
+ add_action('admin_init', 'ultnofo_options_init' );
105
+
106
+ // add link to plugin's settings page in 'settings' menu on admin menu initilization
107
+ add_action('admin_menu', 'ultnofo_options_add_page');
108
+
109
+ /******************************
110
+ * NOFOLLOW SHORTCODES SECTION *
111
+ *******************************/
112
+
113
+ /* valid href starting substring? */
114
+ function ultnofo_valid_url( $href ) {
115
+ $start_strs = array( // list of accepted url protocols
116
+ '/',
117
+ 'http://',
118
+ 'https://',
119
+ 'ftp://',
120
+ 'mailto:',
121
+ 'magnet:',
122
+ 'svn://',
123
+ 'irc:',
124
+ 'gopher://',
125
+ 'telnet://',
126
+ 'nntp://',
127
+ 'worldwind://',
128
+ 'news:',
129
+ 'git://',
130
+ 'mms://'
131
+ );
132
+
133
+ foreach( $start_strs as $start_str )
134
+ if( substr( $href, 0, strlen( $start_str ) ) == $start_str ) return TRUE;
135
+
136
+ return FALSE;
137
+ }
138
+
139
+ /* return nofollow link html or html error comment */
140
+ function ultnofo_nofollow_link( $atts, $content = NULL ) {
141
+ extract(
142
+ shortcode_atts(
143
+ array(
144
+ 'href' => NULL,
145
+ 'title' => NULL,
146
+ 'target' => NULL
147
+ ),
148
+ $atts
149
+ )
150
+ );
151
+
152
+ // href
153
+ if( !ultnofo_valid_url( $href ) ) return '<!-- Ultimate Nofollow Plugin | shortcode insertion failed | given href resource not valid, href must begin with: ' . print_r( $start_strs, TRUE ) . ' -->'; // if url doesn't starts with valid string
154
+ else $href_chunk = ' href="' . $href . '"'; // else add href=''
155
+
156
+ // title
157
+ if( empty( $title ) ) $title_chunk = NULL; // if no $title, omit HTML
158
+ else $title_chunk = ' title="' . trim( htmlentities( strip_tags( $title ), ENT_QUOTES ) ) . '"'; // else add title=''
159
+
160
+ // target
161
+ if( empty( $target ) ) $target_chunk = NULL; // if no $target, omit HTML
162
+ else $target_chunk = ' target="' . trim( htmlentities( strip_tags( $target ), ENT_QUOTES ) ) . '"'; // else add target=''
163
+
164
+ // content
165
+ if( empty( $content ) ) return '<!-- Ultimate Nofollow Plugin | shortcode insertion failed | no link text given -->'; // if url doesn't starts with valid string
166
+ else $content_chunk = trim( htmlentities( strip_tags( $content ), ENT_QUOTES ) ); // else add $content
167
+
168
+ return '<a' . $href_chunk . $target_chunk . $title_chunk . ' rel="nofollow">' . $content_chunk . '</a>';
169
+ }
170
+
171
+ /* add hooks/filters */
172
+ // add shortcodes
173
+ $shortcodes = array(
174
+ 'relnofollow',
175
+ 'nofollow',
176
+ 'nofol',
177
+ 'nofo',
178
+ 'nf'
179
+ );
180
+ foreach( $shortcodes as $shortcode ) add_shortcode( $shortcode, 'ultnofo_nofollow_link' );
181
+
182
+ /****************************
183
+ * BLOGROLL NOFOLLOW SECTION *
184
+ *****************************/
185
+
186
+ function ultnofo_blogroll_add_meta_box() {
187
+ add_meta_box( 'ultnofo_blogroll_nofollow_div', 'Ultimate Nofollow', 'ultnofo_blogroll_inner_meta_box', 'link', 'side','high' );
188
+ }
189
+
190
+ function ultnofo_blogroll_inner_meta_box ( $post ) {
191
+ $bookmark = get_bookmark( $post->ID, 'ARRAY_A' );
192
+ if( strpos( $bookmark['link_rel'], 'nofollow' ) !== FALSE ) $checked = ' checked="checked"';
193
+ else $checked = '';
194
+
195
+ $options = get_option( 'ultnofo_item' );
196
+ if( $options['nofollow_blogroll'] ) {
197
+ $disabled=' disabled="disabled"';
198
+ $message='<br /><span style="color:red; font-size:smaller;">ALL blogroll links nofollowed on the <a href="options-general.php?page=ultimate-nofollow" target="_blank">options</a> page.</span>';
199
+ }
200
+ else {
201
+ $disabled = '';
202
+ $message = '';
203
+ }
204
+
205
+ ?>
206
+ <label for="ultnofo_blogroll_nofollow_checkbox">Nofollow this link?</label>
207
+ <input value="1" id="ultnofo_blogroll_nofollow_checkbox" name="ultnofo_blogroll_nofollow_checkbox"<?php echo $disabled; ?> type="checkbox"<?php echo $checked; ?> /> <?php echo $message; ?>
208
+ <?php
209
+ }
210
+
211
+ function ultnofo_blogroll_save_meta_box( $link_rel ) {
212
+ $rel = trim( str_replace( 'nofollow', '', $link_rel ) );
213
+ if( $_POST['ultnofo_blogroll_nofollow_checkbox'] ) $rel .= ' nofollow';
214
+ return trim( $rel );
215
+ }
216
+
217
+ function ultnofo_blogroll_nofollow_all( $links ) {
218
+ foreach( $links as $link ) {
219
+ $rel = trim( str_replace('nofollow', '', $link->link_rel ) );
220
+ $link->link_rel = trim( $rel . ' nofollow' );
221
+ }
222
+ return $links;
223
+ }
224
+
225
+ /* add hooks/filters */
226
+ add_action( 'add_meta_boxes', 'ultnofo_blogroll_add_meta_box', 1 );
227
+ add_filter( 'pre_link_rel', 'ultnofo_blogroll_save_meta_box', 99998, 1);
228
+
229
+ $ultnofo_options = get_option( 'ultnofo_item' ); // NOT IN FUNCTION
230
+ if( $ultnofo_options['nofollow_blogroll'] ) add_filter( 'get_bookmarks', 'ultnofo_blogroll_nofollow_all', 99999);
231
+
232
+
233
+
234
+
235
+ /**********************************************
236
+ * ADD LINK DIALOGUE NOFOLLOW CHECKBOX SECTION *
237
+ ***********************************************/
238
+ function nofollow_redo_wplink() {
239
+ wp_deregister_script( 'wplink' );
240
+
241
+ $suffix = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';
242
+
243
+ wp_register_script( 'wplink', plugins_url( 'wplink' . $suffix . '.js', __FILE__), array( 'jquery', 'wpdialogs' ), false, 1 );
244
+
245
+ wp_localize_script( 'wplink', 'wpLinkL10n', array(
246
+ 'title' => __('Insert/edit link'),
247
+ 'update' => __('Update'),
248
+ 'save' => __('Add Link'),
249
+ 'noTitle' => __('(no title)'),
250
+ 'noMatchesFound' => __('No matches found.')
251
+ ) );
252
+ }
253
+ add_action( 'admin_enqueue_scripts', 'nofollow_redo_wplink', 999 );
254
+
255
+
256
+ /************************************
257
+ * NOFOLLOW ON COMMENT LINKS SECTION *
258
+ *************************************/
259
+
260
+ // add/remove nofollow from all comment links
261
+ function ultnofo_comment_links( $comment ) {
262
+ $options = get_option( 'ultnofo_item' );
263
+ if( !$options[ 'nofollow_comments' ] )
264
+ $comment = str_replace( 'rel="nofollow"', '', $comment );
265
+ elseif( !strpos( $comment, 'rel="nofollow"' ) )
266
+ $comment = str_replace( '<a ', '<a rel="nofollow"', $comment );
267
+ return $comment;
268
+ }
269
+
270
+ /* add hooks/filters */
271
+ // add/remove nofollow from comment links
272
+ add_filter('comment_text', 'ultnofo_comment_links', 10);
273
+ ?>
readme.txt CHANGED
@@ -1,103 +1,110 @@
1
- === Ultimate Nofollow ===
2
- Plugin URI: http://shinraholdings.com/plugins/nofollow
3
- Contributors: bitacre
4
- Donate link: http://shinraholdings.com/donate
5
- Tags: nofollow,link,links,meta,insert,rel nofollow,seo,checkbox,popup,shortcode,blogroll
6
- Requires at least: 2.8
7
- Tested up to: 3.9
8
- Stable tag: 1.4.2
9
-
10
- Adds a checkbox in the insert link popup box for including rel="nofollow" in links as you create them; as well as other tools that provides complete control over the rel="nofollow" tag on your blogroll links and comments.
11
-
12
- == Description ==
13
- This plugin contains several tools in one package to significantly increase your control of the rel="nofollow" tag on every link on your blog, on both an individual and categorical basis. It is designed to give you fine-grained control of linking for SEO purposes.
14
-
15
- The plugin's main features are:
16
-
17
- * The addition of a **nofollow checkbox when inserting links in posts**
18
- * Several **nofollow shortcodes**
19
- * A nofollow option for **individual blogroll links**
20
- * Or a **nofollow for all blogroll links** option
21
- * Add or remove the nofollow tag from **all links in comments**
22
-
23
- == Installation ==
24
- 1. Download the latest zip file and extract the `nofollow` directory.
25
- 2. Upload it to your `/wp-content/plugins/` directory.
26
- 3. Activate `Ultimate Nofollow` on the `Plugins` menu in WordPress.
27
-
28
- == Frequently Asked Questions ==
29
-
30
- = How do I nofollow links I insert in my posts or pages? =
31
- Just check the `add rel="nofollow" to link` option direction under the default `open link in a new window/tab` option.
32
-
33
- = How do I use the shortcode? =
34
- You can use any of these shortcodes to insert a nofollowed link `[relnofollow]`, `[nofollow]`, `[nofol]`, `[nofo]`, or `[nf]` using the following format:
35
-
36
- `[nf href="http://link-url.com"]Link Text[/nf]`
37
-
38
- You can also include the optional <a> attributes `title` and `target`. A full example would look like:
39
-
40
- `[nf href="http://link-url.com" title="Link Title" target="_blank"]Link Text[/nf]`
41
-
42
- == Screenshots ==
43
- 1. Nofollow option on the insert/edit link popup for posts and pages.
44
- 2. Settings page on the Dashboard.
45
- 3. Nofollow checkbox on the add/edit blogroll link page.
46
-
47
- == Changelog ==
48
- = 1.4.2 =
49
- * Fixes compatability issue with WordPress 3.9
50
-
51
- = 1.4.1 =
52
- * Removed forgotten var_dump() left from debugging process
53
-
54
- = 1.4 =
55
- * Official release
56
- * Added nofollow checkbox to individual post links
57
-
58
- = 0.1.3.1 =
59
- * Updates to documentation.
60
-
61
- = 0.1.3 =
62
- * Stable beta version.
63
- * Nofollow checkbox added to the add/edit blogroll links dialogue.
64
- * Adds option to nofollow all blogroll links.
65
-
66
- = 0.1.2 =
67
- * Stable beta version.
68
- * Add/remove nofollow from all links in comments.
69
-
70
- = 0.1.1 =
71
- * Stable beta version.
72
- * Adds full nofollow shortcodes.
73
- * Adds options page.
74
-
75
- = 0.1.0 =
76
- * First released beta version.
77
- * Stable, but not all functions active yet.
78
-
79
- == Upgrade Notice ==
80
- = 1.4.2 =
81
- Required update if using WordPress 3.9 or above.
82
-
83
- = 1.4.1 =
84
- Strongly recommended upgrade, version 1.4 is dumping a NULL variable onto public facing pages.
85
-
86
- = 1.4 =
87
- Strongly recommended upgrade, significant improvement in usefulness.
88
-
89
- = 0.1.3.1 =
90
- Updated documentation.
91
-
92
- == Readme Generator ==
93
- * This plugin's readme.txt file was generated by the [bitacre Readme Generator](http://shinraholdings.com/tools/readme-gen/) for WordPress Plugins.
94
-
95
- == Support ==
96
-
97
- * [Plugin Homepage](http://shinraholdings.com/plugins/nofollow/)
98
- * [Help Page](http://shinraholdings.com/plugins/nofollow/#help)
99
- * [plugins@shinraholdings.com](mailto:plugins@shinraholdings.com)
100
-
101
- == Donations ==
102
-
103
- [Donations](http://shinraholdings.com/donate) are graciously accepted to support the continued development and maintenance of this and other plugins. We currently accept Paypal and kind words.
 
 
 
 
 
 
 
1
+ === Ultimate Nofollow ===
2
+ Plugin URI: http://shinraholdings.com/plugins/nofollow
3
+ Contributors: bitacre
4
+ Donate link: http://shinraholdings.com/donate
5
+ Tags: nofollow,link,links,meta,insert,rel nofollow,seo,checkbox,popup,shortcode,blogroll
6
+ Requires at least: 2.8
7
+ Tested up to: 4.2
8
+ Stable tag: 1.4.3
9
+
10
+ Adds a checkbox in the insert link popup box for including rel="nofollow" in links as you create them; as well as other tools that provides complete control over the rel="nofollow" tag on your blogroll links and comments.
11
+
12
+ == Description ==
13
+ This plugin contains several tools in one package to significantly increase your control of the rel="nofollow" tag on every link on your blog, on both an individual and categorical basis. It is designed to give you fine-grained control of linking for SEO purposes.
14
+
15
+ The plugin's main features are:
16
+
17
+ * The addition of a **nofollow checkbox when inserting links in posts**
18
+ * Several **nofollow shortcodes**
19
+ * A nofollow option for **individual blogroll links**
20
+ * Or a **nofollow for all blogroll links** option
21
+ * Add or remove the nofollow tag from **all links in comments**
22
+
23
+ == Installation ==
24
+ 1. Download the latest zip file and extract the `nofollow` directory.
25
+ 2. Upload it to your `/wp-content/plugins/` directory.
26
+ 3. Activate `Ultimate Nofollow` on the `Plugins` menu in WordPress.
27
+
28
+ == Frequently Asked Questions ==
29
+
30
+ = How do I nofollow links I insert in my posts or pages? =
31
+ Just check the `add rel="nofollow" to link` option direction under the default `open link in a new window/tab` option.
32
+
33
+ = How do I use the shortcode? =
34
+ You can use any of these shortcodes to insert a nofollowed link `[relnofollow]`, `[nofollow]`, `[nofol]`, `[nofo]`, or `[nf]` using the following format:
35
+
36
+ `[nf href="http://link-url.com"]Link Text[/nf]`
37
+
38
+ You can also include the optional <a> attributes `title` and `target`. A full example would look like:
39
+
40
+ `[nf href="http://link-url.com" title="Link Title" target="_blank"]Link Text[/nf]`
41
+
42
+ == Screenshots ==
43
+ 1. Nofollow option on the insert/edit link popup for posts and pages.
44
+ 2. Settings page on the Dashboard.
45
+ 3. Nofollow checkbox on the add/edit blogroll link page.
46
+
47
+ == Changelog ==
48
+ = 1.4.3 =
49
+ * Fixes compatibility issue with Wordpress 4.2
50
+ * Thanks to [Zoe Corkhill](https://profiles.wordpress.org/zoecorkhill/) for the fix
51
+
52
+ = 1.4.2 =
53
+ * Fixes compatability issue with WordPress 3.9
54
+
55
+ = 1.4.1 =
56
+ * Removed forgotten var_dump() left from debugging process
57
+
58
+ = 1.4 =
59
+ * Official release
60
+ * Added nofollow checkbox to individual post links
61
+
62
+ = 0.1.3.1 =
63
+ * Updates to documentation.
64
+
65
+ = 0.1.3 =
66
+ * Stable beta version.
67
+ * Nofollow checkbox added to the add/edit blogroll links dialogue.
68
+ * Adds option to nofollow all blogroll links.
69
+
70
+ = 0.1.2 =
71
+ * Stable beta version.
72
+ * Add/remove nofollow from all links in comments.
73
+
74
+ = 0.1.1 =
75
+ * Stable beta version.
76
+ * Adds full nofollow shortcodes.
77
+ * Adds options page.
78
+
79
+ = 0.1.0 =
80
+ * First released beta version.
81
+ * Stable, but not all functions active yet.
82
+
83
+ == Upgrade Notice ==
84
+ = 1.4.3 =
85
+ Required update if using WordPress 4.2 or above.
86
+
87
+ = 1.4.2 =
88
+ Required update if using WordPress 3.9 or above.
89
+
90
+ = 1.4.1 =
91
+ Strongly recommended upgrade, version 1.4 is dumping a NULL variable onto public facing pages.
92
+
93
+ = 1.4 =
94
+ Strongly recommended upgrade, significant improvement in usefulness.
95
+
96
+ = 0.1.3.1 =
97
+ Updated documentation.
98
+
99
+ == Readme Generator ==
100
+ * This plugin's readme.txt file was generated by the [bitacre Readme Generator](http://shinraholdings.com/tools/readme-gen/) for WordPress Plugins.
101
+
102
+ == Support ==
103
+
104
+ * [Plugin Homepage](http://shinraholdings.com/plugins/nofollow/)
105
+ * [Help Page](http://shinraholdings.com/plugins/nofollow/#help)
106
+ * [plugins@shinraholdings.com](mailto:plugins@shinraholdings.com)
107
+
108
+ == Donations ==
109
+
110
+ [Donations](http://shinraholdings.com/donate) are graciously accepted to support the continued development and maintenance of this and other plugins. We currently accept Paypal and kind words.
wplink.js CHANGED
@@ -1,8 +1,16 @@
1
  /* global ajaxurl, tinymce, wpLinkL10n, setUserSetting, wpActiveEditor */
 
2
  var wpLink;
3
 
4
  ( function( $ ) {
5
- var inputs = {}, rivers = {}, editor, searchTimer, River, Query;
 
 
 
 
 
 
 
6
 
7
  wpLink = {
8
  timeToTriggerRiver: 150,
@@ -11,12 +19,11 @@ var wpLink;
11
  keySensitivity: 100,
12
  lastSearch: '',
13
  textarea: '',
14
-
15
 
16
- // append nofollow checkbox HTML (mod)
17
  append : function() {
18
  var html = '<br /><label><span> </span><input type="checkbox" id="link-nofollow-checkbox" /> Add <code>rel="nofollow"</code> to link</label>';
19
- $('#wp-link .link-target').append( html );
20
  },
21
 
22
  init: function() {
@@ -25,20 +32,25 @@ var wpLink;
25
  inputs.backdrop = $( '#wp-link-backdrop' );
26
  inputs.submit = $( '#wp-link-submit' );
27
  inputs.close = $( '#wp-link-close' );
28
- // URL
29
- inputs.url = $( '#url-field' );
 
 
30
  inputs.nonce = $( '#_ajax_linking_nonce' );
31
- // Secondary options
32
- inputs.title = $( '#link-title-field' );
33
- // Advanced Options
34
- inputs.openInNewTab = $( '#link-target-checkbox' );
35
  inputs.relNofollow = $( '#link-nofollow-checkbox' ); // (mod)
36
- inputs.search = $( '#search-field' );
 
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' );
41
 
 
 
 
 
 
42
  // Bind event handlers
43
  inputs.dialog.keydown( wpLink.keydown );
44
  inputs.dialog.keyup( wpLink.keyup );
@@ -51,10 +63,19 @@ var wpLink;
51
  wpLink.close();
52
  });
53
 
54
- $( '#wp-link-search-toggle' ).click( wpLink.toggleInternalLinking );
55
 
56
  rivers.elements.on( 'river-select', wpLink.updateFields );
57
 
 
 
 
 
 
 
 
 
 
58
  inputs.search.keyup( function() {
59
  var self = this;
60
 
@@ -63,11 +84,28 @@ var wpLink;
63
  wpLink.searchInternalLinks.call( self );
64
  }, 500 );
65
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  },
67
 
68
  open: function( editorId ) {
69
  var ed;
70
-
 
 
71
  wpLink.range = null;
72
 
73
  if ( editorId ) {
@@ -103,6 +141,8 @@ var wpLink;
103
  inputs.backdrop.show();
104
 
105
  wpLink.refresh();
 
 
106
  },
107
 
108
  isMCE: function() {
@@ -110,47 +150,107 @@ var wpLink;
110
  },
111
 
112
  refresh: function() {
 
 
113
  // Refresh rivers (clear links, check visibility)
114
  rivers.search.refresh();
115
  rivers.recent.refresh();
116
 
117
- if ( wpLink.isMCE() )
118
  wpLink.mceRefresh();
119
- else
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  wpLink.setDefaultValues();
 
 
 
 
 
 
 
 
 
 
 
121
 
122
- // Focus the URL field and highlight its contents.
123
- // If this is moved above the selection changes,
124
- // IE will show a flashing cursor over the dialog.
125
- inputs.url.focus()[0].select();
126
  // Load the most recent results if this is the first time opening the panel.
127
- if ( ! rivers.recent.ul.children().length )
128
  rivers.recent.ajax();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  },
130
 
131
  mceRefresh: function() {
132
- var e;
133
-
134
- // If link exists, select proper values.
135
- if ( e = editor.dom.getParent( editor.selection.getNode(), 'A' ) ) {
136
- // Set URL and description.
137
- inputs.url.val( editor.dom.getAttrib( e, 'href' ) );
138
- inputs.title.val( editor.dom.getAttrib( e, 'title' ) );
139
- // Set open in new tab.
140
- inputs.openInNewTab.prop( 'checked', ( '_blank' === editor.dom.getAttrib( e, 'target' ) ) );
141
- // Set rel="nofollow" (mod)
142
- if ( "nofollow" == ed.dom.getAttrib(e, 'rel' ) )
143
  inputs.relNofollow.prop('checked', true);
144
- // Update save prompt.
145
  inputs.submit.val( wpLinkL10n.update );
 
 
 
 
146
 
147
- // If there's no link, set the default values.
 
 
148
  } else {
149
- wpLink.setDefaultValues();
 
150
  }
151
  },
152
 
153
  close: function() {
 
 
154
  if ( ! wpLink.isMCE() ) {
155
  wpLink.textarea.focus();
156
 
@@ -164,51 +264,53 @@ var wpLink;
164
 
165
  inputs.backdrop.hide();
166
  inputs.wrap.hide();
 
 
 
 
167
  },
168
 
169
  getAttrs: function() {
170
  return {
171
- href: inputs.url.val(),
172
- title: inputs.title.val(),
173
  target: inputs.openInNewTab.prop( 'checked' ) ? '_blank' : '',
174
- rel: inputs.relNofollow.prop( 'checked' ) ? 'nofollow' : '' // (mod)
175
  };
176
  },
177
 
178
  update: function() {
179
- if ( wpLink.isMCE() )
180
  wpLink.mceUpdate();
181
- else
182
  wpLink.htmlUpdate();
 
183
  },
184
 
185
  htmlUpdate: function() {
186
- var attrs, html, begin, end, cursor, title, selection,
187
  textarea = wpLink.textarea;
188
 
189
- if ( ! textarea )
190
  return;
 
191
 
192
  attrs = wpLink.getAttrs();
 
193
 
194
  // If there's no href, return.
195
- if ( ! attrs.href || attrs.href == 'http://' )
196
  return;
 
197
 
198
  // Build HTML
199
  html = '<a href="' + attrs.href + '"';
200
 
201
- if ( attrs.title ) {
202
- title = attrs.title.replace( /</g, '&lt;' ).replace( />/g, '&gt;' ).replace( /"/g, '&quot;' );
203
- html += ' title="' + title + '"';
204
- }
205
-
206
  if ( attrs.target ) {
207
  html += ' target="' + attrs.target + '"';
208
  }
209
-
210
- if ( attrs.rel ) { // (mod)
211
- html += ' rel="' + attrs.rel + '"';
212
  }
213
 
214
  html += '>';
@@ -219,25 +321,29 @@ var wpLink;
219
  // Note: If no text is selected, IE will not place the cursor
220
  // inside the closing tag.
221
  textarea.focus();
222
- wpLink.range.text = html + wpLink.range.text + '</a>';
223
  wpLink.range.moveToBookmark( wpLink.range.getBookmark() );
224
  wpLink.range.select();
225
 
226
  wpLink.range = null;
227
  } else if ( typeof textarea.selectionStart !== 'undefined' ) {
228
  // W3C
229
- begin = textarea.selectionStart;
230
- end = textarea.selectionEnd;
231
- selection = textarea.value.substring( begin, end );
232
- html = html + selection + '</a>';
233
- cursor = begin + html.length;
234
 
235
  // If no text is selected, place the cursor inside the closing tag.
236
- if ( begin == end )
237
- cursor -= '</a>'.length;
 
238
 
239
- textarea.value = textarea.value.substring( 0, begin ) + html +
240
- textarea.value.substring( end, textarea.value.length );
 
 
 
241
 
242
  // Update cursor position
243
  textarea.selectionStart = textarea.selectionEnd = cursor;
@@ -248,8 +354,8 @@ var wpLink;
248
  },
249
 
250
  mceUpdate: function() {
251
- var link,
252
- attrs = wpLink.getAttrs();
253
 
254
  wpLink.close();
255
  editor.focus();
@@ -258,36 +364,60 @@ var wpLink;
258
  editor.selection.moveToBookmark( editor.windowManager.bookmark );
259
  }
260
 
261
- link = editor.dom.getParent( editor.selection.getNode(), 'a[href]' );
262
-
263
- // If the values are empty, unlink and return
264
- if ( ! attrs.href || attrs.href == 'http://' ) {
265
  editor.execCommand( 'unlink' );
266
  return;
267
  }
268
 
 
 
 
269
  if ( link ) {
 
 
 
 
 
 
 
 
270
  editor.dom.setAttribs( link, attrs );
271
  } else {
272
- editor.execCommand( 'mceInsertLink', false, attrs );
 
 
 
 
273
  }
274
-
275
- // Move the cursor to the end of the selection
276
- editor.selection.collapse();
277
  },
278
 
279
- updateFields: function( e, li, originalEvent ) {
280
  inputs.url.val( li.children( '.item-permalink' ).val() );
281
- inputs.title.val( li.hasClass( 'no-title' ) ? '' : li.children( '.item-title' ).text() );
282
- if ( originalEvent && originalEvent.type == 'click' )
283
- inputs.url.focus();
284
  },
285
 
286
  setDefaultValues: function() {
287
- // Set URL and description to defaults.
288
- // Leave the new tab setting as-is.
289
- inputs.url.val( 'http://' );
290
- inputs.title.val( '' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
291
 
292
  // Update save prompt.
293
  inputs.submit.val( wpLinkL10n.save );
@@ -306,11 +436,11 @@ var wpLink;
306
  return;
307
 
308
  wpLink.lastSearch = search;
309
- waiting = t.parent().find('.spinner').show();
310
 
311
  rivers.search.change( search );
312
  rivers.search.ajax( function() {
313
- waiting.hide();
314
  });
315
  } else {
316
  rivers.search.hide();
@@ -338,6 +468,8 @@ var wpLink;
338
  } else if ( key.TAB === event.keyCode ) {
339
  id = event.target.id;
340
 
 
 
341
  if ( id === 'wp-link-submit' && ! event.shiftKey ) {
342
  inputs.close.focus();
343
  event.preventDefault();
@@ -351,6 +483,11 @@ var wpLink;
351
  return;
352
  }
353
 
 
 
 
 
 
354
  fn = event.keyCode === key.UP ? 'prev' : 'next';
355
  clearInterval( wpLink.keyInterval );
356
  wpLink[ fn ]();
@@ -390,12 +527,13 @@ var wpLink;
390
  };
391
  },
392
 
393
- toggleInternalLinking: function() {
394
  var visible = inputs.wrap.hasClass( 'search-panel-visible' );
395
 
396
  inputs.wrap.toggleClass( 'search-panel-visible', ! visible );
397
  setUserSetting( 'wplink', visible ? '0' : '1' );
398
  inputs[ ! visible ? 'search' : 'url' ].focus();
 
399
  }
400
  };
401
 
@@ -505,7 +643,7 @@ var wpLink;
505
 
506
  if ( ! results ) {
507
  if ( firstPage ) {
508
- list += '<li class="unselectable"><span class="item-title"><em>' +
509
  wpLinkL10n.noMatchesFound + '</em></span></li>';
510
  }
511
  } else {
@@ -538,11 +676,11 @@ var wpLink;
538
  if ( ! self.query.ready() || newBottom < self.contentHeight.height() - wpLink.riverBottomThreshold )
539
  return;
540
 
541
- self.waiting.show();
542
  el.scrollTop( newTop + self.waiting.outerHeight() );
543
 
544
  self.ajax( function() {
545
- self.waiting.hide();
546
  });
547
  }, wpLink.timeToTriggerRiver );
548
  }
@@ -580,6 +718,7 @@ var wpLink;
580
  }, 'json' );
581
  }
582
  });
 
583
  $( document ).ready( wpLink.append ); // (mod)
584
  $( document ).ready( wpLink.init );
585
- })( jQuery );
1
  /* global ajaxurl, tinymce, wpLinkL10n, setUserSetting, wpActiveEditor */
2
+ /* Thanks to zoecorkhill for the 4.2 fix */
3
  var wpLink;
4
 
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,
19
  keySensitivity: 100,
20
  lastSearch: '',
21
  textarea: '',
 
22
 
23
+ // append nofollow checkbox HTML (mod)
24
  append : function() {
25
  var html = '<br /><label><span> </span><input type="checkbox" id="link-nofollow-checkbox" /> Add <code>rel="nofollow"</code> to link</label>';
26
+ $('#wp-link .link-target').append( html );
27
  },
28
 
29
  init: function() {
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.openInNewTab = $( '#wp-link-target' );
 
 
 
41
  inputs.relNofollow = $( '#link-nofollow-checkbox' ); // (mod)
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 );
63
  wpLink.close();
64
  });
65
 
66
+ $( '#wp-link-search-toggle' ).on( 'click', wpLink.toggleInternalLinking );
67
 
68
  rivers.elements.on( 'river-select', wpLink.updateFields );
69
 
70
+ // Display 'hint' message when search field or 'query-results' box are focused
71
+ inputs.search.on( 'focus.wplink', function() {
72
+ inputs.queryNoticeTextDefault.hide();
73
+ inputs.queryNoticeTextHint.removeClass( 'screen-reader-text' ).show();
74
+ } ).on( 'blur.wplink', function() {
75
+ inputs.queryNoticeTextDefault.show();
76
+ inputs.queryNoticeTextHint.addClass( 'screen-reader-text' ).hide();
77
+ } );
78
+
79
  inputs.search.keyup( function() {
80
  var self = this;
81
 
84
  wpLink.searchInternalLinks.call( self );
85
  }, 500 );
86
  });
87
+
88
+ function correctURL() {
89
+ var url = $.trim( inputs.url.val() );
90
+
91
+ if ( url && correctedURL !== url && ! /^(?:[a-z]+:|#|\?|\.|\/)/.test( url ) ) {
92
+ inputs.url.val( 'http://' + url );
93
+ correctedURL = url;
94
+ }
95
+ }
96
+
97
+ inputs.url.on( 'paste', function() {
98
+ setTimeout( correctURL, 0 );
99
+ } );
100
+
101
+ inputs.url.on( 'blur', correctURL );
102
  },
103
 
104
  open: function( editorId ) {
105
  var ed;
106
+
107
+ $( document.body ).addClass( 'modal-open' );
108
+
109
  wpLink.range = null;
110
 
111
  if ( editorId ) {
141
  inputs.backdrop.show();
142
 
143
  wpLink.refresh();
144
+
145
+ $( document ).trigger( 'wplink-open', inputs.wrap );
146
  },
147
 
148
  isMCE: function() {
150
  },
151
 
152
  refresh: function() {
153
+ var text = '';
154
+
155
  // Refresh rivers (clear links, check visibility)
156
  rivers.search.refresh();
157
  rivers.recent.refresh();
158
 
159
+ if ( wpLink.isMCE() ) {
160
  wpLink.mceRefresh();
161
+ } else {
162
+ // For the Text editor the "Link text" field is always shown
163
+ if ( ! inputs.wrap.hasClass( 'has-text-field' ) ) {
164
+ inputs.wrap.addClass( 'has-text-field' );
165
+ }
166
+
167
+ if ( document.selection ) {
168
+ // Old IE
169
+ text = document.selection.createRange().text || '';
170
+ } else if ( typeof this.textarea.selectionStart !== 'undefined' &&
171
+ ( this.textarea.selectionStart !== this.textarea.selectionEnd ) ) {
172
+ // W3C
173
+ text = this.textarea.value.substring( this.textarea.selectionStart, this.textarea.selectionEnd ) || '';
174
+ }
175
+
176
+ inputs.text.val( text );
177
  wpLink.setDefaultValues();
178
+ }
179
+
180
+ if ( isTouch ) {
181
+ // Close the onscreen keyboard
182
+ inputs.url.focus().blur();
183
+ } else {
184
+ // Focus the URL field and highlight its contents.
185
+ // If this is moved above the selection changes,
186
+ // IE will show a flashing cursor over the dialog.
187
+ inputs.url.focus()[0].select();
188
+ }
189
 
 
 
 
 
190
  // Load the most recent results if this is the first time opening the panel.
191
+ if ( ! rivers.recent.ul.children().length ) {
192
  rivers.recent.ajax();
193
+ }
194
+
195
+ correctedURL = inputs.url.val().replace( /^http:\/\//, '' );
196
+ },
197
+
198
+ hasSelectedText: function( linkNode ) {
199
+ var html = editor.selection.getContent();
200
+
201
+ // Partial html and not a fully selected anchor element
202
+ if ( /</.test( html ) && ( ! /^<a [^>]+>[^<]+<\/a>$/.test( html ) || html.indexOf('href=') === -1 ) ) {
203
+ return false;
204
+ }
205
+
206
+ if ( linkNode ) {
207
+ var nodes = linkNode.childNodes, i;
208
+
209
+ if ( nodes.length === 0 ) {
210
+ return false;
211
+ }
212
+
213
+ for ( i = nodes.length - 1; i >= 0; i-- ) {
214
+ if ( nodes[i].nodeType != 3 ) {
215
+ return false;
216
+ }
217
+ }
218
+ }
219
+
220
+ return true;
221
  },
222
 
223
  mceRefresh: function() {
224
+ var text,
225
+ selectedNode = editor.selection.getNode(),
226
+ linkNode = editor.dom.getParent( selectedNode, 'a[href]' ),
227
+ onlyText = this.hasSelectedText( linkNode );
228
+
229
+ if ( linkNode ) {
230
+ text = linkNode.innerText || linkNode.textContent;
231
+ inputs.url.val( editor.dom.getAttrib( linkNode, 'href' ) );
232
+ inputs.openInNewTab.prop( 'checked', '_blank' === editor.dom.getAttrib( linkNode, 'target' ) );
233
+ // Set rel="nofollow" (mod)
234
+ if ( "nofollow" == ed.dom.getAttrib(e, 'rel' ) )
235
  inputs.relNofollow.prop('checked', true);
 
236
  inputs.submit.val( wpLinkL10n.update );
237
+ } else {
238
+ text = editor.selection.getContent({ format: 'text' });
239
+ this.setDefaultValues();
240
+ }
241
 
242
+ if ( onlyText ) {
243
+ inputs.text.val( text || '' );
244
+ inputs.wrap.addClass( 'has-text-field' );
245
  } else {
246
+ inputs.text.val( '' );
247
+ inputs.wrap.removeClass( 'has-text-field' );
248
  }
249
  },
250
 
251
  close: function() {
252
+ $( document.body ).removeClass( 'modal-open' );
253
+
254
  if ( ! wpLink.isMCE() ) {
255
  wpLink.textarea.focus();
256
 
264
 
265
  inputs.backdrop.hide();
266
  inputs.wrap.hide();
267
+
268
+ correctedURL = false;
269
+
270
+ $( document ).trigger( 'wplink-close', inputs.wrap );
271
  },
272
 
273
  getAttrs: function() {
274
  return {
275
+ href: $.trim( inputs.url.val() ),
 
276
  target: inputs.openInNewTab.prop( 'checked' ) ? '_blank' : '',
277
+ rel: inputs.relNofollow.prop( 'checked' ) ? 'nofollow' : '' // (mod)
278
  };
279
  },
280
 
281
  update: function() {
282
+ if ( wpLink.isMCE() ) {
283
  wpLink.mceUpdate();
284
+ } else {
285
  wpLink.htmlUpdate();
286
+ }
287
  },
288
 
289
  htmlUpdate: function() {
290
+ var attrs, text, html, begin, end, cursor, selection,
291
  textarea = wpLink.textarea;
292
 
293
+ if ( ! textarea ) {
294
  return;
295
+ }
296
 
297
  attrs = wpLink.getAttrs();
298
+ text = inputs.text.val();
299
 
300
  // If there's no href, return.
301
+ if ( ! attrs.href ) {
302
  return;
303
+ }
304
 
305
  // Build HTML
306
  html = '<a href="' + attrs.href + '"';
307
 
 
 
 
 
 
308
  if ( attrs.target ) {
309
  html += ' target="' + attrs.target + '"';
310
  }
311
+
312
+ if ( attrs.rel ) { // (mod)
313
+ html += ' rel="' + attrs.rel + '"';
314
  }
315
 
316
  html += '>';
321
  // Note: If no text is selected, IE will not place the cursor
322
  // inside the closing tag.
323
  textarea.focus();
324
+ wpLink.range.text = html + ( text || wpLink.range.text ) + '</a>';
325
  wpLink.range.moveToBookmark( wpLink.range.getBookmark() );
326
  wpLink.range.select();
327
 
328
  wpLink.range = null;
329
  } else if ( typeof textarea.selectionStart !== 'undefined' ) {
330
  // W3C
331
+ begin = textarea.selectionStart;
332
+ end = textarea.selectionEnd;
333
+ selection = text || textarea.value.substring( begin, end );
334
+ html = html + selection + '</a>';
335
+ cursor = begin + html.length;
336
 
337
  // If no text is selected, place the cursor inside the closing tag.
338
+ if ( begin === end && ! selection ) {
339
+ cursor -= 4;
340
+ }
341
 
342
+ textarea.value = (
343
+ textarea.value.substring( 0, begin ) +
344
+ html +
345
+ textarea.value.substring( end, textarea.value.length )
346
+ );
347
 
348
  // Update cursor position
349
  textarea.selectionStart = textarea.selectionEnd = cursor;
354
  },
355
 
356
  mceUpdate: function() {
357
+ var attrs = wpLink.getAttrs(),
358
+ link, text;
359
 
360
  wpLink.close();
361
  editor.focus();
364
  editor.selection.moveToBookmark( editor.windowManager.bookmark );
365
  }
366
 
367
+ if ( ! attrs.href ) {
 
 
 
368
  editor.execCommand( 'unlink' );
369
  return;
370
  }
371
 
372
+ link = getLink();
373
+ text = inputs.text.val();
374
+
375
  if ( link ) {
376
+ if ( text ) {
377
+ if ( 'innerText' in link ) {
378
+ link.innerText = text;
379
+ } else {
380
+ link.textContent = text;
381
+ }
382
+ }
383
+
384
  editor.dom.setAttribs( link, attrs );
385
  } else {
386
+ if ( text ) {
387
+ editor.selection.setNode( editor.dom.create( 'a', attrs, text ) );
388
+ } else {
389
+ editor.execCommand( 'mceInsertLink', false, attrs );
390
+ }
391
  }
 
 
 
392
  },
393
 
394
+ updateFields: function( e, li ) {
395
  inputs.url.val( li.children( '.item-permalink' ).val() );
 
 
 
396
  },
397
 
398
  setDefaultValues: function() {
399
+ var selection,
400
+ emailRegexp = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i,
401
+ urlRegexp = /^(https?|ftp):\/\/[A-Z0-9.-]+\.[A-Z]{2,4}[^ "]*$/i;
402
+
403
+ if ( this.isMCE() ) {
404
+ selection = editor.selection.getContent();
405
+ } else if ( document.selection && wpLink.range ) {
406
+ selection = wpLink.range.text;
407
+ } else if ( typeof this.textarea.selectionStart !== 'undefined' ) {
408
+ selection = this.textarea.value.substring( this.textarea.selectionStart, this.textarea.selectionEnd );
409
+ }
410
+
411
+ if ( selection && emailRegexp.test( selection ) ) {
412
+ // Selection is email address
413
+ inputs.url.val( 'mailto:' + selection );
414
+ } else if ( selection && urlRegexp.test( selection ) ) {
415
+ // Selection is URL
416
+ inputs.url.val( selection.replace( /&amp;|&#0?38;/gi, '&' ) );
417
+ } else {
418
+ // Set URL to default.
419
+ inputs.url.val( '' );
420
+ }
421
 
422
  // Update save prompt.
423
  inputs.submit.val( wpLinkL10n.save );
436
  return;
437
 
438
  wpLink.lastSearch = search;
439
+ waiting = t.parent().find( '.spinner' ).addClass( 'is-active' );
440
 
441
  rivers.search.change( search );
442
  rivers.search.ajax( function() {
443
+ waiting.removeClass( 'is-active' );
444
  });
445
  } else {
446
  rivers.search.hide();
468
  } else if ( key.TAB === event.keyCode ) {
469
  id = event.target.id;
470
 
471
+ // wp-link-submit must always be the last focusable element in the dialog.
472
+ // following focusable elements will be skipped on keyboard navigation.
473
  if ( id === 'wp-link-submit' && ! event.shiftKey ) {
474
  inputs.close.focus();
475
  event.preventDefault();
483
  return;
484
  }
485
 
486
+ if ( document.activeElement &&
487
+ ( document.activeElement.id === 'link-title-field' || document.activeElement.id === 'url-field' ) ) {
488
+ return;
489
+ }
490
+
491
  fn = event.keyCode === key.UP ? 'prev' : 'next';
492
  clearInterval( wpLink.keyInterval );
493
  wpLink[ fn ]();
527
  };
528
  },
529
 
530
+ toggleInternalLinking: function( event ) {
531
  var visible = inputs.wrap.hasClass( 'search-panel-visible' );
532
 
533
  inputs.wrap.toggleClass( 'search-panel-visible', ! visible );
534
  setUserSetting( 'wplink', visible ? '0' : '1' );
535
  inputs[ ! visible ? 'search' : 'url' ].focus();
536
+ event.preventDefault();
537
  }
538
  };
539
 
643
 
644
  if ( ! results ) {
645
  if ( firstPage ) {
646
+ list += '<li class="unselectable no-matches-found"><span class="item-title"><em>' +
647
  wpLinkL10n.noMatchesFound + '</em></span></li>';
648
  }
649
  } else {
676
  if ( ! self.query.ready() || newBottom < self.contentHeight.height() - wpLink.riverBottomThreshold )
677
  return;
678
 
679
+ self.waiting.addClass( 'is-active' );
680
  el.scrollTop( newTop + self.waiting.outerHeight() );
681
 
682
  self.ajax( function() {
683
+ self.waiting.removeClass( 'is-active' );
684
  });
685
  }, wpLink.timeToTriggerRiver );
686
  }
718
  }, 'json' );
719
  }
720
  });
721
+
722
  $( document ).ready( wpLink.append ); // (mod)
723
  $( document ).ready( wpLink.init );
724
+ })( jQuery );
wplink.min.js CHANGED
@@ -1 +1 @@
1
- var wpLink;(function(e){var t={},n={},r,i,s,o;wpLink={timeToTriggerRiver:150,minRiverAJAXDuration:200,riverBottomThreshold:5,keySensitivity:100,lastSearch:"",textarea:"",append:function(){var t='<br /><label><span> </span><input type="checkbox" id="link-nofollow-checkbox" /> Add <code>rel="nofollow"</code> to link</label>';e("#wp-link .link-target").append(t)},init:function(){t.wrap=e("#wp-link-wrap");t.dialog=e("#wp-link");t.backdrop=e("#wp-link-backdrop");t.submit=e("#wp-link-submit");t.close=e("#wp-link-close");t.url=e("#url-field");t.nonce=e("#_ajax_linking_nonce");t.title=e("#link-title-field");t.openInNewTab=e("#link-target-checkbox");t.relNofollow=e("#link-nofollow-checkbox");t.search=e("#search-field");n.search=new s(e("#search-results"));n.recent=new s(e("#most-recent-results"));n.elements=t.dialog.find(".query-results");t.dialog.keydown(wpLink.keydown);t.dialog.keyup(wpLink.keyup);t.submit.click(function(e){e.preventDefault();wpLink.update()});t.close.add(t.backdrop).add("#wp-link-cancel a").click(function(e){e.preventDefault();wpLink.close()});e("#wp-link-search-toggle").click(wpLink.toggleInternalLinking);n.elements.on("river-select",wpLink.updateFields);t.search.keyup(function(){var e=this;window.clearTimeout(i);i=window.setTimeout(function(){wpLink.searchInternalLinks.call(e)},500)})},open:function(n){var i;wpLink.range=null;if(n){window.wpActiveEditor=n}if(!window.wpActiveEditor){return}this.textarea=e("#"+window.wpActiveEditor).get(0);if(typeof tinymce!=="undefined"){i=tinymce.get(wpActiveEditor);if(i&&!i.isHidden()){r=i}else{r=null}if(r&&tinymce.isIE){r.windowManager.bookmark=r.selection.getBookmark()}}if(!wpLink.isMCE()&&document.selection){this.textarea.focus();this.range=document.selection.createRange()}t.wrap.show();t.backdrop.show();wpLink.refresh()},isMCE:function(){return r&&!r.isHidden()},refresh:function(){n.search.refresh();n.recent.refresh();if(wpLink.isMCE())wpLink.mceRefresh();else wpLink.setDefaultValues();t.url.focus()[0].select();if(!n.recent.ul.children().length)n.recent.ajax()},mceRefresh:function(){var e;if(e=r.dom.getParent(r.selection.getNode(),"A")){t.url.val(r.dom.getAttrib(e,"href"));t.title.val(r.dom.getAttrib(e,"title"));t.openInNewTab.prop("checked","_blank"===r.dom.getAttrib(e,"target"));if("nofollow"==ed.dom.getAttrib(e,"rel"))t.relNofollow.prop("checked",true);t.submit.val(wpLinkL10n.update)}else{wpLink.setDefaultValues()}},close:function(){if(!wpLink.isMCE()){wpLink.textarea.focus();if(wpLink.range){wpLink.range.moveToBookmark(wpLink.range.getBookmark());wpLink.range.select()}}else{r.focus()}t.backdrop.hide();t.wrap.hide()},getAttrs:function(){return{href:t.url.val(),title:t.title.val(),target:t.openInNewTab.prop("checked")?"_blank":"",rel:t.relNofollow.prop("checked")?"nofollow":""}},update:function(){if(wpLink.isMCE())wpLink.mceUpdate();else wpLink.htmlUpdate()},htmlUpdate:function(){var e,t,n,r,i,s,o,u=wpLink.textarea;if(!u)return;e=wpLink.getAttrs();if(!e.href||e.href=="http://")return;t='<a href="'+e.href+'"';if(e.title){s=e.title.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;");t+=' title="'+s+'"'}if(e.target){t+=' target="'+e.target+'"'}if(e.rel){t+=' rel="'+e.rel+'"'}t+=">";if(document.selection&&wpLink.range){u.focus();wpLink.range.text=t+wpLink.range.text+"</a>";wpLink.range.moveToBookmark(wpLink.range.getBookmark());wpLink.range.select();wpLink.range=null}else if(typeof u.selectionStart!=="undefined"){n=u.selectionStart;r=u.selectionEnd;o=u.value.substring(n,r);t=t+o+"</a>";i=n+t.length;if(n==r)i-="</a>".length;u.value=u.value.substring(0,n)+t+u.value.substring(r,u.value.length);u.selectionStart=u.selectionEnd=i}wpLink.close();u.focus()},mceUpdate:function(){var e,t=wpLink.getAttrs();wpLink.close();r.focus();if(tinymce.isIE){r.selection.moveToBookmark(r.windowManager.bookmark)}e=r.dom.getParent(r.selection.getNode(),"a[href]");if(!t.href||t.href=="http://"){r.execCommand("unlink");return}if(e){r.dom.setAttribs(e,t)}else{r.execCommand("mceInsertLink",false,t)}r.selection.collapse()},updateFields:function(e,n,r){t.url.val(n.children(".item-permalink").val());t.title.val(n.hasClass("no-title")?"":n.children(".item-title").text());if(r&&r.type=="click")t.url.focus()},setDefaultValues:function(){t.url.val("http://");t.title.val("");t.submit.val(wpLinkL10n.save)},searchInternalLinks:function(){var t=e(this),r,i=t.val();if(i.length>2){n.recent.hide();n.search.show();if(wpLink.lastSearch==i)return;wpLink.lastSearch=i;r=t.parent().find(".spinner").show();n.search.change(i);n.search.ajax(function(){r.hide()})}else{n.search.hide();n.recent.show()}},next:function(){n.search.next();n.recent.next()},prev:function(){n.search.prev();n.recent.prev()},keydown:function(n){var r,i,s=e.ui.keyCode;if(s.ESCAPE===n.keyCode){wpLink.close();n.stopImmediatePropagation()}else if(s.TAB===n.keyCode){i=n.target.id;if(i==="wp-link-submit"&&!n.shiftKey){t.close.focus();n.preventDefault()}else if(i==="wp-link-close"&&n.shiftKey){t.submit.focus();n.preventDefault()}}if(n.keyCode!==s.UP&&n.keyCode!==s.DOWN){return}r=n.keyCode===s.UP?"prev":"next";clearInterval(wpLink.keyInterval);wpLink[r]();wpLink.keyInterval=setInterval(wpLink[r],wpLink.keySensitivity);n.preventDefault()},keyup:function(t){var n=e.ui.keyCode;if(t.which===n.UP||t.which===n.DOWN){clearInterval(wpLink.keyInterval);t.preventDefault()}},delayedCallback:function(e,t){var n,r,i,s;if(!t)return e;setTimeout(function(){if(r)return e.apply(s,i);n=true},t);return function(){if(n)return e.apply(this,arguments);i=arguments;s=this;r=true}},toggleInternalLinking:function(){var e=t.wrap.hasClass("search-panel-visible");t.wrap.toggleClass("search-panel-visible",!e);setUserSetting("wplink",e?"0":"1");t[!e?"search":"url"].focus()}};s=function(t,n){var r=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(){r.maybeLoad()});t.on("click","li",function(t){r.select(e(this),t)})};e.extend(s.prototype,{refresh:function(){this.deselect();this.visible=this.element.is(":visible")},show:function(){if(!this.visible){this.deselect();this.element.show();this.visible=true}},hide:function(){this.element.hide();this.visible=false},select:function(e,t){var n,r,i,s;if(e.hasClass("unselectable")||e==this.selected)return;this.deselect();this.selected=e.addClass("selected");n=e.outerHeight();r=this.element.height();i=e.position().top;s=this.element.scrollTop();if(i<0)this.element.scrollTop(s+i);else if(i+n>r)this.element.scrollTop(s+i-r+n);this.element.trigger("river-select",[e,t,this])},deselect:function(){if(this.selected)this.selected.removeClass("selected");this.selected=false},prev:function(){if(!this.visible)return;var e;if(this.selected){e=this.selected.prev("li");if(e.length)this.select(e)}},next:function(){if(!this.visible)return;var t=this.selected?this.selected.next("li"):e("li:not(.unselectable):first",this.element);if(t.length)this.select(t)},ajax:function(e){var t=this,n=this.query.page==1?0:wpLink.minRiverAJAXDuration,r=wpLink.delayedCallback(function(n,r){t.process(n,r);if(e)e(n,r)},n);this.query.ajax(r)},change:function(e){if(this.query&&this._search==e)return;this._search=e;this.query=new o(e);this.element.scrollTop(0)},process:function(t,n){var r="",i=true,s="",o=n.page==1;if(!t){if(o){r+='<li class="unselectable"><span class="item-title"><em>'+wpLinkL10n.noMatchesFound+"</em></span></li>"}}else{e.each(t,function(){s=i?"alternate":"";s+=this.title?"":" no-title";r+=s?'<li class="'+s+'">':"<li>";r+='<input type="hidden" class="item-permalink" value="'+this.permalink+'" />';r+='<span class="item-title">';r+=this.title?this.title:wpLinkL10n.noTitle;r+='</span><span class="item-info">'+this.info+"</span></li>";i=!i})}this.ul[o?"html":"append"](r)},maybeLoad:function(){var e=this,t=this.element,n=t.scrollTop()+t.height();if(!this.query.ready()||n<this.contentHeight.height()-wpLink.riverBottomThreshold)return;setTimeout(function(){var n=t.scrollTop(),r=n+t.height();if(!e.query.ready()||r<e.contentHeight.height()-wpLink.riverBottomThreshold)return;e.waiting.show();t.scrollTop(n+e.waiting.outerHeight());e.ajax(function(){e.waiting.hide()})},wpLink.timeToTriggerRiver)}});o=function(e){this.page=1;this.allLoaded=false;this.querying=false;this.search=e};e.extend(o.prototype,{ready:function(){return!(this.querying||this.allLoaded)},ajax:function(n){var r=this,i={action:"wp-link-ajax",page:this.page,_ajax_linking_nonce:t.nonce.val()};if(this.search)i.search=this.search;this.querying=true;e.post(ajaxurl,i,function(e){r.page++;r.querying=false;r.allLoaded=!e;n(e,i)},"json")}});e(document).ready(wpLink.append);e(document).ready(wpLink.init)})(jQuery)
1
+ var wpLink;!function(t){function n(){return i.dom.getParent(i.selection.getNode(),"a")}var i,a,s,r,l,o={},c={},u="ontouchend"in document;wpLink={timeToTriggerRiver:150,minRiverAJAXDuration:200,riverBottomThreshold:5,keySensitivity:100,lastSearch:"",textarea:"",append:function(){var e='<br /><label><span> </span><input type="checkbox" id="link-nofollow-checkbox" /> Add <code>rel="nofollow"</code> to link</label>';t("#wp-link .link-target").append(e)},init:function(){function e(){var e=t.trim(o.url.val());e&&l!==e&&!/^(?:[a-z]+:|#|\?|\.|\/)/.test(e)&&(o.url.val("http://"+e),l=e)}o.wrap=t("#wp-link-wrap"),o.dialog=t("#wp-link"),o.backdrop=t("#wp-link-backdrop"),o.submit=t("#wp-link-submit"),o.close=t("#wp-link-close"),o.text=t("#wp-link-text"),o.url=t("#wp-link-url"),o.nonce=t("#_ajax_linking_nonce"),o.openInNewTab=t("#wp-link-target"),o.relNofollow=t("#link-nofollow-checkbox"),o.search=t("#wp-link-search"),c.search=new s(t("#search-results")),c.recent=new s(t("#most-recent-results")),c.elements=o.dialog.find(".query-results"),o.queryNotice=t("#query-notice-message"),o.queryNoticeTextDefault=o.queryNotice.find(".query-notice-default"),o.queryNoticeTextHint=o.queryNotice.find(".query-notice-hint"),o.dialog.keydown(wpLink.keydown),o.dialog.keyup(wpLink.keyup),o.submit.click(function(e){e.preventDefault(),wpLink.update()}),o.close.add(o.backdrop).add("#wp-link-cancel a").click(function(e){e.preventDefault(),wpLink.close()}),t("#wp-link-search-toggle").on("click",wpLink.toggleInternalLinking),c.elements.on("river-select",wpLink.updateFields),o.search.on("focus.wplink",function(){o.queryNoticeTextDefault.hide(),o.queryNoticeTextHint.removeClass("screen-reader-text").show()}).on("blur.wplink",function(){o.queryNoticeTextDefault.show(),o.queryNoticeTextHint.addClass("screen-reader-text").hide()}),o.search.keyup(function(){var e=this;window.clearTimeout(a),a=window.setTimeout(function(){wpLink.searchInternalLinks.call(e)},500)}),o.url.on("paste",function(){setTimeout(e,0)}),o.url.on("blur",e)},open:function(e){var n;t(document.body).addClass("modal-open"),wpLink.range=null,e&&(window.wpActiveEditor=e),window.wpActiveEditor&&(this.textarea=t("#"+window.wpActiveEditor).get(0),"undefined"!=typeof tinymce&&(n=tinymce.get(wpActiveEditor),i=n&&!n.isHidden()?n:null,i&&tinymce.isIE&&(i.windowManager.bookmark=i.selection.getBookmark())),!wpLink.isMCE()&&document.selection&&(this.textarea.focus(),this.range=document.selection.createRange()),o.wrap.show(),o.backdrop.show(),wpLink.refresh(),t(document).trigger("wplink-open",o.wrap))},isMCE:function(){return i&&!i.isHidden()},refresh:function(){var e="";c.search.refresh(),c.recent.refresh(),wpLink.isMCE()?wpLink.mceRefresh():(o.wrap.hasClass("has-text-field")||o.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)||""),o.text.val(e),wpLink.setDefaultValues()),u?o.url.focus().blur():o.url.focus()[0].select(),c.recent.ul.children().length||c.recent.ajax(),l=o.url.val().replace(/^http:\/\//,"")},hasSelectedText:function(e){var t=i.selection.getContent();if(/</.test(t)&&(!/^<a [^>]+>[^<]+<\/a>$/.test(t)||-1===t.indexOf("href=")))return!1;if(e){var n,a=e.childNodes;if(0===a.length)return!1;for(n=a.length-1;n>=0;n--)if(3!=a[n].nodeType)return!1}return!0},mceRefresh:function(){var t,n=i.selection.getNode(),a=i.dom.getParent(n,"a[href]"),s=this.hasSelectedText(a);a?(t=a.innerText||a.textContent,o.url.val(i.dom.getAttrib(a,"href")),o.openInNewTab.prop("checked","_blank"===i.dom.getAttrib(a,"target")),"nofollow"==ed.dom.getAttrib(e,"rel")&&o.relNofollow.prop("checked",!0),o.submit.val(wpLinkL10n.update)):(t=i.selection.getContent({format:"text"}),this.setDefaultValues()),s?(o.text.val(t||""),o.wrap.addClass("has-text-field")):(o.text.val(""),o.wrap.removeClass("has-text-field"))},close:function(){t(document.body).removeClass("modal-open"),wpLink.isMCE()?i.focus():(wpLink.textarea.focus(),wpLink.range&&(wpLink.range.moveToBookmark(wpLink.range.getBookmark()),wpLink.range.select())),o.backdrop.hide(),o.wrap.hide(),l=!1,t(document).trigger("wplink-close",o.wrap)},getAttrs:function(){return{href:t.trim(o.url.val()),target:o.openInNewTab.prop("checked")?"_blank":"",rel:o.relNofollow.prop("checked")?"nofollow":""}},update:function(){wpLink.isMCE()?wpLink.mceUpdate():wpLink.htmlUpdate()},htmlUpdate:function(){var e,t,n,i,a,s,r,l=wpLink.textarea;l&&(e=wpLink.getAttrs(),t=o.text.val(),e.href&&(n='<a href="'+e.href+'"',e.target&&(n+=' target="'+e.target+'"'),e.rel&&(n+=' rel="'+e.rel+'"'),n+=">",document.selection&&wpLink.range?(l.focus(),wpLink.range.text=n+(t||wpLink.range.text)+"</a>",wpLink.range.moveToBookmark(wpLink.range.getBookmark()),wpLink.range.select(),wpLink.range=null):"undefined"!=typeof l.selectionStart&&(i=l.selectionStart,a=l.selectionEnd,r=t||l.value.substring(i,a),n=n+r+"</a>",s=i+n.length,i!==a||r||(s-=4),l.value=l.value.substring(0,i)+n+l.value.substring(a,l.value.length),l.selectionStart=l.selectionEnd=s),wpLink.close(),l.focus()))},mceUpdate:function(){var e,t,a=wpLink.getAttrs();return wpLink.close(),i.focus(),tinymce.isIE&&i.selection.moveToBookmark(i.windowManager.bookmark),a.href?(e=n(),t=o.text.val(),void(e?(t&&("innerText"in e?e.innerText=t:e.textContent=t),i.dom.setAttribs(e,a)):t?i.selection.setNode(i.dom.create("a",a,t)):i.execCommand("mceInsertLink",!1,a))):void i.execCommand("unlink")},updateFields:function(e,t){o.url.val(t.children(".item-permalink").val())},setDefaultValues:function(){var e,t=/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i,n=/^(https?|ftp):\/\/[A-Z0-9.-]+\.[A-Z]{2,4}[^ "]*$/i;this.isMCE()?e=i.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)),o.url.val(e&&t.test(e)?"mailto:"+e:e&&n.test(e)?e.replace(/&|&#0?38;/gi,"&"):""),o.submit.val(wpLinkL10n.save)},searchInternalLinks:function(){var e,n=t(this),i=n.val();if(i.length>2){if(c.recent.hide(),c.search.show(),wpLink.lastSearch==i)return;wpLink.lastSearch=i,e=n.parent().find(".spinner").addClass("is-active"),c.search.change(i),c.search.ajax(function(){e.removeClass("is-active")})}else c.search.hide(),c.recent.show()},next:function(){c.search.next(),c.recent.next()},prev:function(){c.search.prev(),c.recent.prev()},keydown:function(e){var n,i,a=t.ui.keyCode;a.ESCAPE===e.keyCode?(wpLink.close(),e.stopImmediatePropagation()):a.TAB===e.keyCode&&(i=e.target.id,"wp-link-submit"!==i||e.shiftKey?"wp-link-close"===i&&e.shiftKey&&(o.submit.focus(),e.preventDefault()):(o.close.focus(),e.preventDefault())),(e.keyCode===a.UP||e.keyCode===a.DOWN)&&(!document.activeElement||"link-title-field"!==document.activeElement.id&&"url-field"!==document.activeElement.id)&&(n=e.keyCode===a.UP?"prev":"next",clearInterval(wpLink.keyInterval),wpLink[n](),wpLink.keyInterval=setInterval(wpLink[n],wpLink.keySensitivity),e.preventDefault())},keyup:function(e){var n=t.ui.keyCode;(e.which===n.UP||e.which===n.DOWN)&&(clearInterval(wpLink.keyInterval),e.preventDefault())},delayedCallback:function(e,t){var n,i,a,s;return t?(setTimeout(function(){return i?e.apply(s,a):void(n=!0)},t),function(){return n?e.apply(this,arguments):(a=arguments,s=this,void(i=!0))}):e},toggleInternalLinking:function(e){var t=o.wrap.hasClass("search-panel-visible");o.wrap.toggleClass("search-panel-visible",!t),setUserSetting("wplink",t?"0":"1"),o[t?"url":"search"].focus(),e.preventDefault()}},s=function(e,n){var i=this;this.element=e,this.ul=e.children("ul"),this.contentHeight=e.children("#link-selector-height"),this.waiting=e.find(".river-waiting"),this.change(n),this.refresh(),t("#wp-link .query-results, #wp-link #link-selector").scroll(function(){i.maybeLoad()}),e.on("click","li",function(e){i.select(t(this),e)})},t.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,a,s;e.hasClass("unselectable")||e==this.selected||(this.deselect(),this.selected=e.addClass("selected"),n=e.outerHeight(),i=this.element.height(),a=e.position().top,s=this.element.scrollTop(),0>a?this.element.scrollTop(s+a):a+n>i&&this.element.scrollTop(s+a-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 e=this.selected?this.selected.next("li"):t("li:not(.unselectable):first",this.element);e.length&&this.select(e)}},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 r(e),this.element.scrollTop(0))},process:function(e,n){var i="",a=!0,s="",r=1==n.page;e?t.each(e,function(){s=a?"alternate":"",s+=this.title?"":" no-title",i+=s?'<li class="'+s+'">':"<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>",a=!a}):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)}}),r=function(e){this.page=1,this.allLoaded=!1,this.querying=!1,this.search=e},t.extend(r.prototype,{ready:function(){return!(this.querying||this.allLoaded)},ajax:function(e){var n=this,i={action:"wp-link-ajax",page:this.page,_ajax_linking_nonce:o.nonce.val()};this.search&&(i.search=this.search),this.querying=!0,t.post(ajaxurl,i,function(t){n.page++,n.querying=!1,n.allLoaded=!t,e(t,i)},"json")}}),t(document).ready(wpLink.append),t(document).ready(wpLink.init)}(jQuery);