From ae18e22598064e56cfac3230fb0727b4a5d19aff Mon Sep 17 00:00:00 2001 From: matt Date: Thu, 3 Jan 2008 01:34:11 +0000 Subject: [PATCH] New tag interface, tag auto-suggest while typing. Rough - suggest and parts of JS should probably be refactored. Hat tip: jhodgdon. git-svn-id: http://svn.automattic.com/wordpress/trunk@6542 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-admin/admin-ajax.php | 13 ++ wp-admin/edit-form-advanced.php | 24 ++- wp-admin/images/xit.gif | Bin 0 -> 181 bytes wp-admin/js/post.js | 77 ++++++++ wp-admin/post-new.php | 2 + wp-admin/post.php | 5 +- wp-admin/wp-admin.css | 87 +++++++-- wp-includes/functions.php | 4 +- wp-includes/js/jquery/suggest.js | 310 +++++++++++++++++++++++++++++++ wp-includes/script-loader.php | 3 + 10 files changed, 500 insertions(+), 25 deletions(-) create mode 100644 wp-admin/images/xit.gif create mode 100644 wp-admin/js/post.js create mode 100644 wp-includes/js/jquery/suggest.js diff --git a/wp-admin/admin-ajax.php b/wp-admin/admin-ajax.php index e0bf8d265..ca7de560d 100644 --- a/wp-admin/admin-ajax.php +++ b/wp-admin/admin-ajax.php @@ -7,6 +7,19 @@ define('DOING_AJAX', true); if ( !is_user_logged_in() ) die('-1'); +if ( 'ajax-tag-search' == $_GET['action'] ) { + if ( !current_user_can( 'manage_categories' ) ) + die('-1'); + + $s = $_GET['q']; // is this slashed already? + + if ( strstr( $s, ',' ) ) + die; // it's a multiple tag insert, we won't find anything + $results = $wpdb->get_col( "SELECT name FROM $wpdb->terms WHERE name LIKE ('%$s%')" ); + echo join( $results, "\n" ); + die; +} + function get_out_now() { exit; } add_action( 'shutdown', 'get_out_now', -1 ); diff --git a/wp-admin/edit-form-advanced.php b/wp-admin/edit-form-advanced.php index 35726f38b..bcef8b9be 100644 --- a/wp-admin/edit-form-advanced.php +++ b/wp-admin/edit-form-advanced.php @@ -157,11 +157,6 @@ if ( $authors && count( $authors ) > 1 ) : -
- -
-
-

@@ -200,14 +195,29 @@ if (current_user_can('upload_files')) {

+
+
+
+

+
+
+
+

+ +

+

+
+
+
+

-
-
+
+
diff --git a/wp-admin/images/xit.gif b/wp-admin/images/xit.gif new file mode 100644 index 0000000000000000000000000000000000000000..6f1cc4f4eb88426e7a54d185c0fbd3772aeb0163 GIT binary patch literal 181 zcmZ?wbhEHb6k*_E*v!E2;K73*Cr*6ZzWv0B6TfcUc=__>wQJWt&ztw`*|VRQFMpam z`Ou+5|NsAIfC0syEMTS%hy+j!W707LS1+Y=f-P)1DV!dSi`E_7V!+X9;O(g4 zvq-JSNupcQX@>!a$R3vX ' + val + ' '; + jQuery( '#tagchecklist' ).append( txt ); + jQuery( '#tag-check-' + key ).click( new_tag_remove_tag ); + shown = true; + } + }); + if ( shown ) + jQuery( '#tagchecklist' ).prepend( 'Tags used on this post:
' ); +} + +function tag_flush_to_text() { + var newtags = jQuery('#tags-input').val() + ',' + jQuery('#newtag').val(); + // massage + newtags = newtags.replace( /\s+,+\s*/g, ',' ).replace( /,+/g, ',' ).replace( /,+\s+,+/g, ',' ).replace( /,+\s*$/g, '' ).replace( /^\s*,+/g, '' ); + jQuery('#tags-input').val( newtags ); + tag_update_quickclicks(); + jQuery('#newtag').val(''); + jQuery('#newtag').blur(); + return false; +} + +function tag_press_key( e ) { + if ( 13 == e.keyCode ) { + tag_flush_to_text(); + return false; + } +} + +addLoadEvent( function() { + jQuery('#tags-input').hide(); + tag_update_quickclicks(); + // add the quickadd form + jQuery('#jaxtag').prepend('Separate tags with commas'); + jQuery('#tagadd').click( tag_flush_to_text ); +// jQuery('#newtag').keydown( tag_press_key ); + jQuery('#newtag').focus(function() { + if ( this.value == 'Add new tag' ) { + this.value = ''; + this.style.color = '#333'; + } + }); + jQuery('#newtag').blur(function() { + if ( this.value == '' ) { + this.value = 'Add new tag'; + this.style.color = '#999' + } + }); + + // auto-suggest stuff + jQuery('#newtag').suggest( 'admin-ajax.php?action=ajax-tag-search', { onSelect: tag_flush_to_text } ); +}); \ No newline at end of file diff --git a/wp-admin/post-new.php b/wp-admin/post-new.php index e51a4f9a5..e3a950727 100644 --- a/wp-admin/post-new.php +++ b/wp-admin/post-new.php @@ -6,6 +6,8 @@ $editing = true; wp_enqueue_script('prototype'); wp_enqueue_script('jquery'); wp_enqueue_script('autosave'); +wp_enqueue_script('post'); + require_once ('./admin-header.php'); if ( ! current_user_can('edit_posts') ) { ?> diff --git a/wp-admin/post.php b/wp-admin/post.php index 4609bae52..d9d2e6673 100644 --- a/wp-admin/post.php +++ b/wp-admin/post.php @@ -58,10 +58,13 @@ case 'edit': exit(); } - if($post->post_status == 'draft') { + wp_enqueue_script('post'); + + if( 'draft' == $post->post_status ) { wp_enqueue_script('prototype'); wp_enqueue_script('autosave'); } + require_once('admin-header.php'); if ( !current_user_can('edit_post', $post_ID) ) diff --git a/wp-admin/wp-admin.css b/wp-admin/wp-admin.css index da94c4042..5f651b0c8 100644 --- a/wp-admin/wp-admin.css +++ b/wp-admin/wp-admin.css @@ -90,7 +90,7 @@ a:hover { body { background: #fff; - color: #000; + color: #333; margin: 0; padding: 0; } @@ -137,11 +137,6 @@ img { border: 0; } -input:focus, textarea:focus, label:focus { - background: #fff; - border: 1px solid #686868; -} - .form-invalid { background-color: #FF9999 !important; } @@ -159,9 +154,6 @@ p, li, dl, dd, dt { } textarea, input, select { - background: #f4f4f4; - border: 1px solid #b2b2b2; - color: #000; font: 13px Verdana, Arial, Helvetica, sans-serif; margin: 1px; padding: 3px; @@ -296,10 +288,8 @@ form#upload #post_content { } .submit input, .submit input:focus, .button, .button:focus { - background: url(images/fade-butt.png); color: #246; - padding: 0.3em; - -moz-border-radius: 4px; + padding: 2px; } .submit, .editform th, #postcustomsubmit { @@ -387,7 +377,7 @@ input.disabled, textarea.disabled { border: none; } -#postdiv, #titlediv, #guiddiv, #tagdiv { +#postdiv, #titlediv, #guiddiv { margin: 0 8px 0 0; padding: 0; } @@ -407,7 +397,7 @@ input.disabled, textarea.disabled { line-height: 140%; } -#titlediv input, #guiddiv input, #tagdiv input { +#titlediv input, #guiddiv input { margin: 0; width: 100%; } @@ -1395,4 +1385,71 @@ a.view-comment-post-link { color: #448abd; font-weight: bold; border-bottom: 1px solid #448abd; -} \ No newline at end of file +} + +/* Post Screen */ + +#tagchecklist { + margin-left: 5px; + font-size: 12px; +} + +#tagchecklist span { + margin-right: 15px; + display: block; + float: left; + font-size: 11px; +} + +#tagchecklist span a { + margin-top: 5px; + cursor: pointer; + width: 10px; + height: 10px; + background: url(images/xit.gif) no-repeat; + display: block; + float: left; + text-indent: -9999px; + overflow: hidden; +} +#tagchecklist span a:hover { + background: url(images/xit.gif) no-repeat -10px 0; +} + +#newtag { + color: #999; +} + +.howto { + font-style: italic; + display: block; + color: #999; +} + +.ac_results { + border: 1px solid gray; + background-color: white; + padding: 0; + margin: 0; + list-style: none; + position: absolute; + z-index: 10000; + display: none; +} + +.ac_results li { + padding: 2px 5px; + white-space: nowrap; + color: #101010; + text-align: left; +} + +.ac_over { + cursor: pointer; + background-color: #F0F0B8; +} + +.ac_match { + text-decoration: underline; + color: black; +} diff --git a/wp-includes/functions.php b/wp-includes/functions.php index e40e8f7f5..997a9bff7 100644 --- a/wp-includes/functions.php +++ b/wp-includes/functions.php @@ -1285,9 +1285,9 @@ function wp_nonce_ays( $action ) { $html .= "\t\t\n"; } $html .= "\t\t\n"; - $html .= "\t\t
\n\t\t

" . wp_specialchars( wp_explain_nonce( $action ) ) . "

\n\t\t

" . __( 'No' ) . "

\n\t\t
\n\t\n"; + $html .= "\t\t
\n\t\t

" . wp_specialchars( wp_explain_nonce( $action ) ) . "

\n\t\t

" . __( 'No' ) . "

\n\t\t
\n\t\n"; } else { - $html .= "\t
\n\t

" . wp_specialchars( wp_explain_nonce( $action ) ) . "

\n\t

" . __( 'No' ) . " " . __( 'Yes' ) . "

\n\t
\n"; + $html .= "\t
\n\t

" . wp_specialchars( wp_explain_nonce( $action ) ) . "

\n\t

" . __( 'No' ) . " " . __( 'Yes' ) . "

\n\t
\n"; } $html .= "\n"; wp_die( $html, $title ); diff --git a/wp-includes/js/jquery/suggest.js b/wp-includes/js/jquery/suggest.js new file mode 100644 index 000000000..656e58b5c --- /dev/null +++ b/wp-includes/js/jquery/suggest.js @@ -0,0 +1,310 @@ +/* + * jquery.suggest 1.1 - 2007-08-06 + * + * Uses code and techniques from following libraries: + * 1. http://www.dyve.net/jquery/?autocomplete + * 2. http://dev.jquery.com/browser/trunk/plugins/interface/iautocompleter.js + * + * All the new stuff written by Peter Vulgaris (www.vulgarisoip.com) + * Feel free to do whatever you want with this file + * + */ + +(function($) { + + $.suggest = function(input, options) { + + var $input = $(input).attr("autocomplete", "off"); + var $results = $(document.createElement("ul")); + + var timeout = false; // hold timeout ID for suggestion results to appear + var prevLength = 0; // last recorded length of $input.val() + var cache = []; // cache MRU list + var cacheSize = 0; // size of cache in chars (bytes?) + + $results.addClass(options.resultsClass).appendTo('body'); + + + resetPosition(); + $(window) + .load(resetPosition) // just in case user is changing size of page while loading + .resize(resetPosition); + + $input.blur(function() { + setTimeout(function() { $results.hide() }, 200); + }); + + + // help IE users if possible + try { + $results.bgiframe(); + } catch(e) { } + + + // I really hate browser detection, but I don't see any other way + if ($.browser.mozilla) + $input.keypress(processKey); // onkeypress repeats arrow keys in Mozilla/Opera + else + $input.keydown(processKey); // onkeydown repeats arrow keys in IE/Safari + + + + + function resetPosition() { + // requires jquery.dimension plugin + var offset = $input.offset(); + $results.css({ + top: (offset.top + input.offsetHeight) + 'px', + left: offset.left + 'px' + }); + } + + + function processKey(e) { + + // handling up/down/escape requires results to be visible + // handling enter/tab requires that AND a result to be selected + if ((/27$|38$|40$/.test(e.keyCode) && $results.is(':visible')) || + (/^13$|^9$/.test(e.keyCode) && getCurrentResult())) { + + if (e.preventDefault) + e.preventDefault(); + if (e.stopPropagation) + e.stopPropagation(); + + e.cancelBubble = true; + e.returnValue = false; + + switch(e.keyCode) { + + case 38: // up + prevResult(); + break; + + case 40: // down + nextResult(); + break; + + case 9: // tab + case 13: // return + selectCurrentResult(); + break; + + case 27: // escape + $results.hide(); + break; + + } + + } else if ($input.val().length != prevLength) { + + if (timeout) + clearTimeout(timeout); + timeout = setTimeout(suggest, options.delay); + prevLength = $input.val().length; + + } + + + } + + + function suggest() { + + var q = $.trim($input.val()); + + if (q.length >= options.minchars) { + + cached = checkCache(q); + + if (cached) { + + displayItems(cached['items']); + + } else { + + $.get(options.source, {q: q}, function(txt) { + + $results.hide(); + + var items = parseTxt(txt, q); + + displayItems(items); + addToCache(q, items, txt.length); + + }); + + } + + } else { + + $results.hide(); + + } + + } + + + function checkCache(q) { + + for (var i = 0; i < cache.length; i++) + if (cache[i]['q'] == q) { + cache.unshift(cache.splice(i, 1)[0]); + return cache[0]; + } + + return false; + + } + + function addToCache(q, items, size) { + + while (cache.length && (cacheSize + size > options.maxCacheSize)) { + var cached = cache.pop(); + cacheSize -= cached['size']; + } + + cache.push({ + q: q, + size: size, + items: items + }); + + cacheSize += size; + + } + + function displayItems(items) { + + if (!items) + return; + + if (!items.length) { + $results.hide(); + return; + } + + var html = ''; + for (var i = 0; i < items.length; i++) + html += '
  • ' + items[i] + '
  • '; + + $results.html(html).show(); + + $results + .children('li') + .mouseover(function() { + $results.children('li').removeClass(options.selectClass); + $(this).addClass(options.selectClass); + }) + .click(function(e) { + e.preventDefault(); + e.stopPropagation(); + selectCurrentResult(); + }); + + } + + function parseTxt(txt, q) { + + var items = []; + var tokens = txt.split(options.delimiter); + + // parse returned data for non-empty items + for (var i = 0; i < tokens.length; i++) { + var token = $.trim(tokens[i]); + if (token) { + token = token.replace( + new RegExp(q, 'ig'), + function(q) { return '' + q + '' } + ); + items[items.length] = token; + } + } + + return items; + } + + function getCurrentResult() { + + if (!$results.is(':visible')) + return false; + + var $currentResult = $results.children('li.' + options.selectClass); + + if (!$currentResult.length) + $currentResult = false; + + return $currentResult; + + } + + function selectCurrentResult() { + + $currentResult = getCurrentResult(); + + if ($currentResult) { + $input.val($currentResult.text()); + $results.hide(); + + if (options.onSelect) + options.onSelect.apply($input[0]); + + } + + } + + function nextResult() { + + $currentResult = getCurrentResult(); + + if ($currentResult) + $currentResult + .removeClass(options.selectClass) + .next() + .addClass(options.selectClass); + else + $results.children('li:first-child').addClass(options.selectClass); + + } + + function prevResult() { + + $currentResult = getCurrentResult(); + + if ($currentResult) + $currentResult + .removeClass(options.selectClass) + .prev() + .addClass(options.selectClass); + else + $results.children('li:last-child').addClass(options.selectClass); + + } + + } + + $.fn.suggest = function(source, options) { + + if (!source) + return; + + options = options || {}; + options.source = source; + options.delay = options.delay || 100; + options.resultsClass = options.resultsClass || 'ac_results'; + options.selectClass = options.selectClass || 'ac_over'; + options.matchClass = options.matchClass || 'ac_match'; + options.minchars = options.minchars || 2; + options.delimiter = options.delimiter || '\n'; + options.onSelect = options.onSelect || false; + options.maxCacheSize = options.maxCacheSize || 65536; + + this.each(function() { + new $.suggest(this, options); + }); + + return this; + + }; + +})(jQuery); \ No newline at end of file diff --git a/wp-includes/script-loader.php b/wp-includes/script-loader.php index ca6cd1a78..f4e6bba0b 100644 --- a/wp-includes/script-loader.php +++ b/wp-includes/script-loader.php @@ -80,6 +80,8 @@ class WP_Scripts { $this->add( 'jquery', '/wp-includes/js/jquery/jquery.js', false, '1.1.4'); $this->add( 'jquery-form', '/wp-includes/js/jquery/jquery.form.js', array('jquery'), '1.0.3'); $this->add( 'interface', '/wp-includes/js/jquery/interface.js', array('jquery'), '1.2'); + $this->add( 'dimensions', '/wp-includes/js/jquery/jquery.dimensions.min.js', array('jquery'), '1.1.2'); + $this->add( 'suggest', '/wp-includes/js/jquery/suggest.js', array('dimensions'), '1.1'); if ( is_admin() ) { global $pagenow; @@ -129,6 +131,7 @@ class WP_Scripts { $this->add( 'admin-users', '/wp-admin/js/users.js', array('wp-lists'), '20070823' ); $this->add( 'xfn', '/wp-admin/js/xfn.js', false, '3517' ); $this->add( 'upload', '/wp-admin/js/upload.js', array('jquery'), '20070518' ); + $this->add( 'post', '/wp-admin/js/post.js', array('suggest'), '20080102' ); $this->localize( 'upload', 'uploadL10n', array( 'browseTitle' => attribute_escape(__('Browse your files')), 'back' => __('« Back'),