Make WordPress Core

Ticket #4727: tagsection.php

File tagsection.php, 11.5 KB (added by jhodgdon, 19 years ago)

New plugin to implement some functionality (see comment below)

Line 
1<?php
2/*
3Plugin Name: New Tag Section
4Plugin URI:
5Description: Modified tag entry section for new admin interface
6Version: 1.0
7Author: Jennifer Hodgdon, Poplar ProductivityWare
8Author URI: http://poplarware.com
9
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
14*/
15
16// --- Filters and actions
17
18add_action('admin_print_scripts', 'new_tag_js_header');
19add_action('dbx_post_advanced', 'new_tag_edit_form' );
20$new_tag_initial_txt = __( "Add new tag" );
21
22// --- Functions
23
24// JavaScript for editing screen
25function new_tag_js_header() {
26
27 global $editing, $post, $post_ID;
28 global $new_tag_initial_txt;
29
30 if( !$editing ) {
31 // not on a post/page edit screen
32 return;
33 }
34
35 if( $post && $post->post_type == 'page' ) {
36 // it's a page, not a post -- note that $post is NOT set for a new
37 // page/post, see below
38 return;
39 }
40
41 // check the URL to see if it's a new page screen
42 $req_url = $_SERVER['REQUEST_URI'];
43 if( preg_match( '/page-new.php$/', $req_url )) {
44 // it's the "new page" editing screen, not new post
45 return;
46 }
47
48 // if we get here, we are on a post editing page, so we need the
49 // JavaScript for this page
50
51 // use JQuery library
52 wp_print_scripts( array( 'jquery' ));
53
54 // set up button functions and tag arrays
55
56?>
57<style type="text/css">
58#new_tag_popup ul { list-style: none; color: black; background-color: #eeeeee; border: 1px solid black; margin: 0; padding: 0; width: 150px; }
59#new_tag_popup ul li { margin-left: 0; padding: 2px; text-indent: 0; background: inherit;}
60.ntselected { background: white; font-style: bold;}
61.ntdelbutton { border: 1px solid black; padding: 0;}
62</style>
63<script type="text/javascript">
64 //<![CDATA[
65
66 // put tags from DB into an array
67 var new_tag_all_tags = new Array();
68 var new_tag_new_tags = new Array();
69 var new_tag_initial_txt = "<?php echo $new_tag_initial_txt; ?>";
70
71<?php
72
73 $all_tags = get_terms( 'post_tag', 'hide_empty=0' );
74 $curr_tags = wp_get_object_terms( $post_ID, 'post_tag' );
75
76 echo _new_tag_terms_to_js( $all_tags, $curr_tags, 'new_tag_all_tags' );
77?>
78
79 var new_tag_curr_choices;
80
81 // Pop-up list of tags for type-ahead list
82 function new_tag_list_choices() {
83 new_tag_hide_choices();
84
85 // find what the user is typing
86 var txt = jQuery( '#new_tag_add_tag' ).val();
87
88 // go back to previous comma
89 var start = txt.lastIndexOf(',');
90 if( start ) {
91 txt = txt.substr( start + 1 );
92 }
93 while( txt.charAt(0) == ' ' && txt.length ) {
94 txt = txt.substr( 1 );
95 }
96
97 if( !txt.length ) {
98 // nothing to suggest
99 return;
100 }
101
102 // see which tags match this, and add them to pop-up
103
104 jQuery( '#new_tag_popup' ).html( '<ul></ul>' );
105
106 new_tag_curr_choices = new Array();
107 var count = 0;
108 var i;
109 for( i = 0; i < new_tag_all_tags.length; i++ ) {
110 if( new_tag_all_tags[i][1].indexOf( txt ) == 0 ) {
111 new_tag_curr_choices[ count ] = new_tag_all_tags[i][1];
112 count++;
113 jQuery( '#new_tag_popup ul' ).append( '<li>' + new_tag_all_tags[i][1] + '</li>' );
114 }
115 }
116
117 if( !count ) {
118 return;
119 }
120
121 // Hover action: change class
122 jQuery( '#new_tag_popup ul li' ).hover(
123 function( ) {
124 jQuery( this ).addClass( "ntselected" );
125 },
126 function( ) {
127 jQuery( this ).removeClass( "ntselected" );
128 });
129
130 // Click action: replace text after previous comma with item clicked
131 // and hide pop-up
132 jQuery( '#new_tag_popup ul li' ).click( function() {
133 var prev = jQuery( '#new_tag_add_tag' ).val();
134 if( prev.lastIndexOf( ',' ) > 1 ) {
135 prev = prev.substring( 0, prev.lastIndexOf( ',' ) + 1) + ' ';
136 } else {
137 prev = '';
138 }
139 prev = prev + jQuery( this ).text() + ", ";
140
141 jQuery( '#new_tag_add_tag' ).val( prev );
142 jQuery( '#new_tag_add_tag' ).focus();
143 new_tag_hide_choices();
144 });
145
146 // OK, it's built: display pop-up
147 jQuery( '#new_tag_popup' ).show();
148
149 }
150
151 // Hide list of type-ahead choices
152 function new_tag_hide_choices() {
153 new_tag_curr_choices = new Array();
154 jQuery( '#new_tag_popup' ).hide();
155 }
156
157 // Add some new tags to the current tags list
158 function new_tag_add_curr_tags( newtags ) {
159
160 var i;
161 var j;
162
163 for( i = 0; i < newtags.length; i++ ) {
164 // trim whitespace at both ends
165 var tag = newtags[i].replace(/^\s+/g, '' ).replace( /\s+$/g, '' );
166 if( tag.length ) {
167 var found = 0;
168 for( j = 0; j < new_tag_all_tags.length; j++ ) {
169 if( new_tag_all_tags[j][0] == tag ||
170 new_tag_all_tags[j][1] == tag ) {
171 found = 1;
172 new_tag_all_tags[j][2] = 1;
173 break;
174 }
175 }
176 if( !found ) {
177 new_tag_new_tags[new_tag_new_tags.length] = tag;
178 }
179 }
180 }
181 }
182
183 // Mark a tag as not current when a remove button is clicked
184 function new_tag_remove_tag() {
185 // which one was clicked?
186 var id = jQuery( this ).attr( 'id' );
187 var num = id.substr( 18 );
188
189 // mark as not current and update
190 new_tag_all_tags[num][2] = 0;
191 new_tag_update_curr_tags();
192 }
193
194 // Remove a new tag from array when a remove button is clicked
195 function new_tag_remove_new_tag() {
196 // which one was clicked?
197 var id = jQuery( this ).attr( 'id' );
198 var num = id.substr( 18 );
199
200 // remove from array and update
201 new_tag_new_tags.splice( num, 1 );
202 new_tag_update_curr_tags();
203 }
204
205 // Update main tag entry field and Current Tags section from tags array
206 function new_tag_update_curr_tags() {
207
208 // Update main tags input section with tag slugs
209 // (invisible, but this is what gets saved with post)
210 // Update Current Tags section with delete buttons on each tag
211
212 jQuery( '#new_tag_curr_tags_span' ).html( '' );
213
214 var i;
215 var tagstr = '';
216 var comma = '';
217 for( i = 0; i < new_tag_all_tags.length; i++ ) {
218 // see if this tag is being used...
219 if( new_tag_all_tags[i][2] ) {
220 tagstr += comma + new_tag_all_tags[i][0];
221 comma = ',';
222
223 var id = 'new_tag_del_button' + i;
224 var txt = '<button id="' + id + '" class="ntdelbutton">X</button>&nbsp;' + new_tag_all_tags[i][1] + " ";
225
226 jQuery( '#new_tag_curr_tags_span' ).append( txt );
227
228 jQuery( '#' + id ).click( new_tag_remove_tag );
229 }
230 }
231
232 for( i = 0; i < new_tag_new_tags.length; i++ ) {
233 tagstr += "," + new_tag_new_tags[i];
234
235 var id = 'new_tag_del_button' + i;
236 var txt = '<button id="' + id + '" class="ntdelbutton">X</button>&nbsp;' + new_tag_new_tags[i] + " ";
237
238 jQuery( '#new_tag_curr_tags_span' ).append( txt );
239
240 jQuery( '#' + id ).click( new_tag_remove_new_tag );
241 }
242
243 jQuery( '#tags-input' ).val( tagstr );
244
245 }
246
247
248addLoadEvent( function() {
249 // Hide the regular tag entry field
250 jQuery( '#tagdiv' ).hide();
251
252 // Update curr tags section
253 new_tag_update_curr_tags();
254
255 // When user clicks Add Tag field, clear text if it still says'
256 // "Add New Tag"
257
258 jQuery( '#new_tag_add_tag' ).click( function() {
259 if( jQuery( '#new_tag_add_tag' ).val() == new_tag_initial_txt ) {
260 jQuery( '#new_tag_add_tag' ).val('');
261 }
262 });
263
264 // When user types in Add tag field, manage type-ahead
265 jQuery( '#new_tag_add_tag' ).keyup( function( e ) {
266
267 // which key was clicked? 2 methods to find, to cover browsers...
268 var kc = e.which;
269 if( !e.which ) {
270 kc = window.keyCode;
271 }
272
273 // What to do:
274 // escape/comma -- hide choices
275 // alpha character, or backspace: put up choice list
276
277 if( kc == 27 || kc == 44 || kc == 188 ) {
278 new_tag_hide_choices();
279 } else if(( kc >= 65 &&
280 kc <= 90 ) ||
281 ( kc >= 97 &&
282 kc <= 122 ) ||
283 kc == 8 ) {
284 // note: timeout is to wait for keystroke to be in text field
285 setTimeout( new_tag_list_choices, 100 );
286 }
287
288 });
289
290
291 // When user clicks on Add button, add tags they typed to curr
292 // tags array and update
293 jQuery('#new_tag_add_button' ).click( function() {
294
295 // see what was entered
296 var txt = jQuery( '#new_tag_add_tag' ).val();
297 if( !txt.length ) {
298 alert( "<?php _e( 'No tags entered' ); ?>" );
299 return;
300 }
301
302 // add tags to list and update
303
304 var taglist = txt.split(',');
305 new_tag_add_curr_tags( taglist );
306
307 new_tag_update_curr_tags();
308
309 // clear field
310 jQuery( '#new_tag_add_tag' ).val( '' );
311
312 });
313
314 });
315
316//]]>
317</script>
318<?php
319}
320
321// Post edit screen section for advanced tag entry
322function new_tag_edit_form() {
323 global $post_ID;
324 global $new_tag_initial_txt;
325
326 // this is needed for IE6, which doesn't seem to dynamically
327 // size select lists when elements are added later by jQuery
328 $sel_width = "2.5in";
329
330 // header info
331
332 echo '<div class="dbx-b-ox-wrapper">' . "\n";
333 echo '<fieldset id="new_tag_entry" class="dbx-box">' . "\n";
334 echo '<div class="dbx-h-andle-wrapper"><h3 class="dbx-handle">' .
335 __( "New Tag Entry Section" ) . "</h3></div>";
336
337 echo '<div class="dbx-c-ontent-wrapper"><div class="dbx-content" ' .
338 ' id="new_tag_entry_section">';
339
340 // add tag section
341
342 echo '<input type="text" id="new_tag_add_tag" name="new_tag_add_tag" value="' .
343 $new_tag_initial_txt . '" style="width:90%">';
344
345 echo '<input type="button" name="new_tag_add_button"' .
346 'id="new_tag_add_button" value="' .
347 __( 'Add' ) .
348 '" />' . "\n";
349
350 echo '<br /><div id="new_tag_popup"></div>';
351
352 echo "<br /><small>" . __("Separate tags with commas") . "</small>";
353 echo "</p>\n" ;
354
355 // Current tags on post section
356
357 echo '<p><strong>' ;
358 _e( 'Tags used on this post:' );
359 echo '</strong></p> <span id="new_tag_curr_tags_span"></span>';
360
361 echo "</div></fieldset></div>\n";
362}
363
364// Returns JavaScript for defining an array of tags
365// Each entry is array( slug, display-filtered name,
366// true/false for used/not currently )
367function _new_tag_terms_to_js( $terms, $curr, $jsvar ) {
368
369 $i = 0;
370 $ret = $jsvar . " = new Array();\n";
371
372 // make array of true/false for if term is currently used
373 $arr = array();
374 foreach( $terms as $term ) {
375 $arr[ $term->term_id ] = 0;
376 }
377 foreach( $curr as $term ) {
378 $arr[ $term->term_id ] = 1;
379 }
380
381 // build JS string to define array
382 foreach( $terms as $item ) {
383 $item = sanitize_term( $item, 'post_tag', 'display' );
384
385 $ret .= $jsvar . "[" . $i . "] = new Array( ";
386 $ret .= "'" . _new_tag_js_escape( $item->slug ) . "', " ;
387 $ret .= "'" . _new_tag_js_escape( $item->name ) . "', ";
388 $ret .= $arr[ $item->term_id ];
389 $ret .= " );\n";
390
391 $i++;
392 }
393
394 return $ret;
395}
396
397// Convert quotes for JS usage
398function _new_tag_js_escape( $text ) {
399 $text = str_replace("'", "\\'", $text);
400 return $text;
401}
402
403// Internal function: returns the string with double quotes
404// escaped for HTML use
405function _new_tag_escape_dq( $str ) {
406 return preg_replace( '/"/', '&quot;', $str );
407}
408
409
410?>