Make WordPress Core

Ticket #4727: tagsection.php

File tagsection.php, 11.5 KB (added by jhodgdon, 16 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?>