WordPress.org

Make WordPress Core

Ticket #14691: tags-with-commas.3.diff

File tags-with-commas.3.diff, 11.4 KB (added by joehoyle, 6 years ago)

Actually added tags

  • tests/qunit/index.html

     
    1313  <!-- Tested files -->
    1414  <script src="../../src/wp-includes/js/zxcvbn.min.js"></script>
    1515  <script src="../../src/wp-admin/js/password-strength-meter.js"></script>
     16  <script src="../../src/wp-admin/js/post.js"></script>
    1617
    1718  <!-- Unit tests -->
    1819  <script src="wp-admin/js/password-strength-meter.js"></script>
     20  <script src="wp-admin/js/post.js"></script>
    1921
    2022</head>
    2123<body>
  • tests/qunit/wp-admin/js/post.js

     
     1var postL10n = {
     2        comma: ','
     3}
     4
     5jQuery( function() {
     6        module( 'post-tags-metabox' );
     7
     8        // mock the tags div
     9        var tagsDiv = jQuery( '<div />' ).addClass('tagsdiv').append(
     10                jQuery( '<textarea>' ).val( 'tag1,tag2,"tag,with,comma"' ).addClass('the-tags')
     11        ).append(
     12                jQuery( '<div />' ).addClass('tagchecklist')
     13        );
     14
     15        test( "tags should be parsed from textarea return ['tag2', 'tag1']", function() {
     16
     17                tagBox.quickClicks( tagsDiv )
     18
     19                ok( tagsDiv.data('tags').indexOf( 'tag2') > -1 )
     20                ok( tagsDiv.data('tags').indexOf( 'tag1') > -1 )
     21                ok( tagsDiv.data('tags').indexOf( 'tag,with,comma') > -1 )
     22                ok( tagsDiv.data('tags').length == 3 )
     23        });
     24
     25        test( "DOM input elements should exist for each tag", function() {
     26                ok( tagsDiv.find( 'input[value="tag1"]' ).length == 1, 'DOM element was not found for tag' )
     27        })
     28
     29        test( "removing a tag should remove from tags data", function() {
     30                tagBox.removeTag(tagsDiv, 'tag1')
     31                ok( tagsDiv.data('tags').indexOf( 'tag1') == -1, 'Tag is still found after removing' )
     32        })
     33
     34        test( "removing a tag should remove the tag DOM input element", function() {
     35                ok( tagsDiv.find( 'input[value="tag1"]' ).length == 0, 'DOM element was still found for removed tag' )
     36        })
     37       
     38        test( "tags should be parsed from textarea using both quotes", function() {
     39
     40                tagsDiv.find( 'textarea' ).val('tag1,"tag,2",\'tag,3\'')
     41                tagBox.quickClicks( tagsDiv )
     42
     43                ok( tagsDiv.data('tags').indexOf( 'tag1') > -1 )
     44                ok( tagsDiv.data('tags').indexOf( 'tag,2') > -1 )
     45                ok( tagsDiv.data('tags').indexOf( 'tag,3') > -1 )
     46                ok( tagsDiv.data('tags').length == 3 )
     47        });
     48
     49        test( "tags should be parsed from textarea when using an i18n comma", function() {
     50
     51                // test using a different comma (arabic comma)
     52                postL10n.comma = "\u060C"
     53
     54                tagsDiv.find( 'textarea' ).val('tag1\u060Ctag2\u060C"tag\u060Cwith\u060Ccomma"')
     55                tagBox.quickClicks( tagsDiv )
     56
     57                ok( tagsDiv.data('tags').indexOf( 'tag2') > -1 )
     58                ok( tagsDiv.data('tags').indexOf( 'tag1') > -1 )
     59                ok( tagsDiv.data('tags').indexOf( 'tag\u060Cwith\u060Ccomma') > -1 )
     60                ok( tagsDiv.data('tags').length == 3 )
     61        });
     62
     63});
  • src/wp-includes/js/jquery/suggest.js

     
    244244                                        } else {
    245245                                                $currentVal = "";
    246246                                        }
    247                                         $input.val( $currentVal + $currentResult.text() + options.multipleSep);
     247
     248                                        if ( $currentResult.text().match( jQuery.trim( options.multipleSep ) ) )
     249                                                $input.val( $currentVal + '"' + $currentResult.text() + '"' + options.multipleSep);
     250                                        else
     251                                                $input.val( $currentVal + $currentResult.text() + options.multipleSep);
    248252                                        $input.focus();
    249253                                } else {
    250254                                        $input.val($currentResult.text());
  • src/wp-admin/includes/taxonomy.php

     
    229229        if ( is_wp_error($tags) )
    230230                return $tags;
    231231
    232         foreach ( $tags as $tag )
    233                 $tag_names[] = $tag->name;
     232        foreach ( $tags as $tag ) {
     233                if ( strpos( $tag->name, ',' ) !== false )
     234                        $tag_names[] = '"' . $tag->name . '"';
     235                else
     236                        $tag_names[] = $tag->name;
     237        }
     238
    234239        $tags_to_edit = join( ',', $tag_names );
    235240        $tags_to_edit = esc_attr( $tags_to_edit );
    236241        $tags_to_edit = apply_filters( 'terms_to_edit', $tags_to_edit, $taxonomy );
  • src/wp-admin/includes/meta-boxes.php

     
    364364        <div class="jaxtag">
    365365        <div class="nojs-tags hide-if-js">
    366366        <p><?php echo $taxonomy->labels->add_or_remove_items; ?></p>
    367         <textarea name="<?php echo "tax_input[$tax_name]"; ?>" rows="3" cols="20" class="the-tags" id="tax-input-<?php echo $tax_name; ?>" <?php disabled( ! $user_can_assign_terms ); ?>><?php echo str_replace( ',', $comma . ' ', get_terms_to_edit( $post->ID, $tax_name ) ); // textarea_escaped by esc_attr() ?></textarea></div>
     367        <textarea name="<?php echo "tax_input[$tax_name]"; ?>" rows="3" cols="20" class="the-tags" id="tax-input-<?php echo $tax_name; ?>" <?php disabled( ! $user_can_assign_terms ); ?>><?php echo get_terms_to_edit( $post->ID, $tax_name ); // textarea_escaped by esc_attr() ?></textarea></div>
    368368        <?php if ( $user_can_assign_terms ) : ?>
    369369        <div class="ajaxtag hide-if-no-js">
    370370                <label class="screen-reader-text" for="new-tag-<?php echo $tax_name; ?>"><?php echo $box['title']; ?></label>
  • src/wp-admin/js/post.js

     
    1414(function($){
    1515
    1616tagBox = {
    17         clean : function(tags) {
    18                 var comma = postL10n.comma;
    19                 if ( ',' !== comma )
    20                         tags = tags.replace(new RegExp(comma, 'g'), ',');
    21                 tags = tags.replace(/\s*,\s*/g, ',').replace(/,+/g, ',').replace(/[,\s]+$/, '').replace(/^[,\s]+/, '');
    22                 if ( ',' !== comma )
    23                         tags = tags.replace(/,/g, comma);
    24                 return tags;
    25         },
    2617
    27         parseTags : function(el) {
    28                 var id = el.id, num = id.split('-check-num-')[1], taxbox = $(el).closest('.tagsdiv'),
    29                         thetags = taxbox.find('.the-tags'), comma = postL10n.comma,
    30                         current_tags = thetags.val().split(comma), new_tags = [];
    31                 delete current_tags[num];
     18        quickClicks : function(el) {
     19               
     20                var thetags = $('.the-tags', el);
     21                var current_tags = this.getTagsFromString( thetags.val(), postL10n.comma );
    3222
    33                 $.each( current_tags, function(key, val) {
    34                         val = $.trim(val);
    35                         if ( val ) {
    36                                 new_tags.push(val);
    37                         }
    38                 });
     23                thetags.html('');
     24                $(el).data( 'tags',[]);
    3925
    40                 thetags.val( this.clean( new_tags.join(comma) ) );
    41 
    42                 this.quickClicks(taxbox);
    43                 return false;
     26                for (var i = current_tags.length - 1; i >= 0; i--) {
     27                        this.addTag( $(el), current_tags[i] );
     28                }
    4429        },
    4530
    46         quickClicks : function(el) {
    47                 var thetags = $('.the-tags', el),
    48                         tagchecklist = $('.tagchecklist', el),
    49                         id = $(el).attr('id'),
    50                         current_tags, disabled;
     31        addTag: function( el, tag ) {
     32                var span, xbutton, thetags = $('.the-tags', el), disabled, t = this;
    5133
    52                 if ( !thetags.length )
     34                tag = $.trim(tag)
     35               
     36                if ( el.data( 'tags' ).indexOf( tag ) > -1 )
    5337                        return;
    5438
     39                el.data( 'tags' ).push( tag )
    5540                disabled = thetags.prop('disabled');
    5641
    57                 current_tags = thetags.val().split(postL10n.comma);
    58                 tagchecklist.empty();
     42                // Create a new span, and ensure the text is properly escaped.
     43                span = $('<span />').text( tag );
     44                span.append( jQuery( '<input type="hidden" name="' + thetags.attr('name') + '[]" />' ).val( tag ) )
    5945
    60                 $.each( current_tags, function( key, val ) {
    61                         var span, xbutton;
     46                // If tags editing isn't disabled, create the X button.
     47                if ( ! disabled ) {
     48                        xbutton = $( '<a class="ntdelbutton">X</a>' );
     49                        xbutton.click( function() {
     50                                t.removeTag(el, tag);
     51                        });
    6252
    63                         val = $.trim( val );
     53                        span.prepend('&nbsp;').prepend( xbutton );
     54                }
    6455
    65                         if ( ! val )
    66                                 return;
     56                el.find('.tagchecklist').append(span);
    6757
    68                         // Create a new span, and ensure the text is properly escaped.
    69                         span = $('<span />').text( val );
     58        },
    7059
    71                         // If tags editing isn't disabled, create the X button.
    72                         if ( ! disabled ) {
    73                                 xbutton = $( '<a id="' + id + '-check-num-' + key + '" class="ntdelbutton">X</a>' );
    74                                 xbutton.click( function(){ tagBox.parseTags(this); });
    75                                 span.prepend('&nbsp;').prepend( xbutton );
    76                         }
     60        removeTag: function( el, tag ) {
    7761
    78                         // Append the span to the tag list.
    79                         tagchecklist.append( span );
    80                 });
     62                el.find( '.tagchecklist input[value="' + tag + '"]').remove();
     63                delete el.data('tags')[el.data('tags').indexOf(tag)];
    8164        },
    8265
    83         flushTags : function(el, a, f) {
    84                 a = a || false;
    85                 var tags = $('.the-tags', el),
    86                         newtag = $('input.newtag', el),
    87                         comma = postL10n.comma,
    88                         newtags, text;
     66        getTagsFromString: function(tags_string, comma) {
    8967
    90                 text = a ? $(a).text() : newtag.val();
    91                 tagsval = tags.val();
    92                 newtags = tagsval ? tagsval + comma + text : text;
     68                // pull out all quoted strings
     69                var quoted_tags = tags_string.match( /("|')(.+?)\1/g );
    9370
    94                 newtags = this.clean( newtags );
    95                 newtags = array_unique_noempty( newtags.split(comma) ).join(comma);
    96                 tags.val(newtags);
    97                 this.quickClicks(el);
     71                if ( quoted_tags ) {
     72                        for (var i = quoted_tags.length - 1; i >= 0; i--) {
     73                                tags_string = tags_string.replace( quoted_tags[i], '' );
     74                                quoted_tags[i] = quoted_tags[i].substr( 1, quoted_tags[i].length - 2 );
     75                        };
     76                }
    9877
    99                 if ( !a )
    100                         newtag.val('');
    101                 if ( 'undefined' == typeof(f) )
    102                         newtag.focus();
     78                var tags = tags_string.split(comma);
    10379
    104                 return false;
     80                if ( quoted_tags )
     81                        return array_unique_noempty( quoted_tags.concat(tags) );
     82
     83                return array_unique_noempty( tags );
    10584        },
    10685
     86        submitAddTag: function(el) {
     87
     88                var newtag = $('input.newtag', el),
     89                        new_tags = this.getTagsFromString( newtag.val(), postL10n.comma )
     90
     91                newtag.val('');
     92
     93                for (var i = new_tags.length - 1; i >= 0; i--) {
     94                        this.addTag( $(el), new_tags[i] );
     95                }
     96        },
     97
    10798        get : function(id) {
    108                 var tax = id.substr(id.indexOf('-')+1);
     99                var tax = id.substr(id.indexOf('-')+1), t = this;
    109100
    110101                $.post(ajaxurl, {'action':'get-tagcloud', 'tax':tax}, function(r, stat) {
    111102                        if ( 0 == r || 'success' != stat )
     
    113104
    114105                        r = $('<p id="tagcloud-'+tax+'" class="the-tagcloud">'+r+'</p>');
    115106                        $('a', r).click(function(){
    116                                 tagBox.flushTags( $(this).closest('.inside').children('.tagsdiv'), this);
     107                                t.addTag( $(this).closest('.inside').children('.tagsdiv'), $(this).text() )
    117108                                return false;
    118109                        });
    119110
     
    129120                });
    130121
    131122                $('input.tagadd', ajaxtag).click(function(){
    132                         t.flushTags( $(this).closest('.tagsdiv') );
     123                        t.submitAddTag( $(this).closest('.tagsdiv') );
    133124                });
    134125
    135126                $('div.taghint', ajaxtag).click(function(){
     
    143134                        $(this).parent().siblings('.taghint').css('visibility', 'hidden');
    144135                }).keyup(function(e){
    145136                        if ( 13 == e.which ) {
    146                                 tagBox.flushTags( $(this).closest('.tagsdiv') );
     137                                tagBox.submitAddTag( $(this).closest('.tagsdiv') );
    147138                                return false;
    148139                        }
    149140                }).keypress(function(e){
     
    159150                // save tags on post save/publish
    160151                $('#post').submit(function(){
    161152                        $('div.tagsdiv').each( function() {
    162                                 tagBox.flushTags(this, false, 1);
     153                                t.submitAddTag($(this));
    163154                        });
    164155                });
    165156
     
    353344jQuery(document).ready( function($) {
    354345        var stamp, visibility, sticky = '', last = 0, co = $('#content');
    355346
     347        if ( typeof postboxes == 'undefined' )
     348                return
     349       
    356350        postboxes.add_postbox_toggles(pagenow);
    357351
    358352        // Post locks: contain focus inside the dialog. If the dialog is shown, focus the first item.