From 1357e7fc2efb57dbf67109e860c448ff508465e7 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Wed, 11 Mar 2015 22:54:49 +0000 Subject: [PATCH] Add emoji URL support, and Twemoji fallback for displaying slugs in wp-admin, when the browser doesn't natively support emoji. Props pento, SergeyBiryukov and boonebgorges. Fixes #31328 git-svn-id: https://develop.svn.wordpress.org/trunk@31734 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/js/inline-edit-post.js | 16 +++++++++-- src/wp-admin/js/inline-edit-tax.js | 17 +++++++++-- src/wp-admin/js/post.js | 11 +++++++- src/wp-admin/js/tags.js | 4 +++ src/wp-includes/formatting.php | 20 ++++++++----- src/wp-includes/taxonomy.php | 28 ++++++------------- .../data/formatting/utf-8/entitized.txt | 3 +- .../data/formatting/utf-8/u-urlencoded.txt | 11 ++++---- .../data/formatting/utf-8/urlencoded.txt | 11 ++++---- tests/phpunit/data/formatting/utf-8/utf-8.txt | 1 + .../tests/formatting/UrlEncodedToEntities.php | 2 +- tests/phpunit/tests/term.php | 5 ++-- 12 files changed, 81 insertions(+), 48 deletions(-) diff --git a/src/wp-admin/js/inline-edit-post.js b/src/wp-admin/js/inline-edit-post.js index 6d9753455e..1e15a05d7f 100644 --- a/src/wp-admin/js/inline-edit-post.js +++ b/src/wp-admin/js/inline-edit-post.js @@ -117,7 +117,7 @@ inlineEditPost = { }, edit : function(id) { - var t = this, fields, editRow, rowData, status, pageOpt, pageLevel, nextPage, pageLoop = true, nextLevel, cur_format, f; + var t = this, fields, editRow, rowData, status, pageOpt, pageLevel, nextPage, pageLoop = true, nextLevel, cur_format, f, val; t.revert(); if ( typeof(id) === 'object' ) { @@ -155,7 +155,11 @@ inlineEditPost = { }); for ( f = 0; f < fields.length; f++ ) { - $(':input[name="' + fields[f] + '"]', editRow).val( $('.'+fields[f], rowData).text() ); + val = $('.'+fields[f], rowData); + // Deal with Twemoji + val.find( 'img' ).replaceWith( function() { return this.alt; } ); + val = val.text(); + $(':input[name="' + fields[f] + '"]', editRow).val( val ); } if ( $( '.comment_status', rowData ).text() === 'open' ) { @@ -181,11 +185,14 @@ inlineEditPost = { //flat taxonomies $('.tags_input', rowData).each(function(){ - var terms = $(this).text(), + var terms = $(this), taxname = $(this).attr('id').replace('_' + id, ''), textarea = $('textarea.tax_input_' + taxname, editRow), comma = inlineEditL10n.comma; + terms.find( 'img' ).replaceWith( function() { return this.alt; } ); + terms = terms.text(); + if ( terms ) { if ( ',' !== comma ) { terms = terms.replace(/,/g, comma); @@ -265,6 +272,9 @@ inlineEditPost = { if ( -1 !== r.indexOf( ']*?>/g, '' ); diff --git a/src/wp-admin/js/inline-edit-tax.js b/src/wp-admin/js/inline-edit-tax.js index 7f3a5b39f2..dde6082435 100644 --- a/src/wp-admin/js/inline-edit-tax.js +++ b/src/wp-admin/js/inline-edit-tax.js @@ -45,7 +45,7 @@ inlineEditTax = { }, edit : function(id) { - var editRow, rowData, + var editRow, rowData, val, t = this; t.revert(); @@ -58,8 +58,15 @@ inlineEditTax = { $(t.what+id).hide().before(editRow).before(''); - $(':input[name="name"]', editRow).val( $('.name', rowData).text() ); - $(':input[name="slug"]', editRow).val( $('.slug', rowData).text() ); + val = $('.name', rowData); + val.find( 'img' ).replaceWith( function() { return this.alt; } ); + val = val.text(); + $(':input[name="name"]', editRow).val( val ); + + val = $('.slug', rowData); + val.find( 'img' ).replaceWith( function() { return this.alt; } ); + val = val.text(); + $(':input[name="slug"]', editRow).val( val ); $(editRow).attr('id', 'edit-'+id).addClass('inline-editor').show(); $('.ptitle', editRow).eq(0).focus(); @@ -110,6 +117,10 @@ inlineEditTax = { // Update the value in the Parent dropdown. $( '#parent' ).find( 'option[value=' + option_value + ']' ).text( row.find( '.row-title' ).text() ); + if ( WPEmoji ) { + WPEmoji.parse( row.get( 0 ) ); + } + row.hide().fadeIn(); } else { $('#edit-'+id+' .inline-edit-save .error').html(r).show(); diff --git a/src/wp-admin/js/post.js b/src/wp-admin/js/post.js index 178deb3516..7ab9e08a0e 100644 --- a/src/wp-admin/js/post.js +++ b/src/wp-admin/js/post.js @@ -712,7 +712,11 @@ jQuery(document).ready( function($) { revert_slug = real_slug.val(), b = $('#edit-slug-buttons'), revert_b = b.html(), - full = $('#editable-post-name-full').html(); + full = $('#editable-post-name-full'); + + // Deal with Twemoji in the post-name + full.find( 'img' ).replaceWith( function() { return this.alt; } ); + full = full.html(); $('#view-post-btn').hide(); b.html(''+postL10n.ok+' '+postL10n.cancel+''); @@ -736,6 +740,11 @@ jQuery(document).ready( function($) { box.removeClass('hidden'); }); } + + if ( WPEmoji ) { + WPEmoji.parse( box.get( 0 ) ); + } + b.html(revert_b); real_slug.val(new_slug); $('#view-post-btn').show(); diff --git a/src/wp-admin/js/tags.js b/src/wp-admin/js/tags.js index 333a2eb563..4ac6f2ed47 100644 --- a/src/wp-admin/js/tags.js +++ b/src/wp-admin/js/tags.js @@ -49,6 +49,10 @@ jQuery(document).ready(function($) { else $( '.tags' ).prepend( res.responses[0].supplemental.parents ); // As the parent is not visible, Insert the version with Parent - Child - ThisTerm + if ( WPEmoji ) { + WPEmoji.parse( $( '.tags' ).get( 0 ) ); + } + $('.tags .no-items').remove(); if ( form.find('select#parent') ) { diff --git a/src/wp-includes/formatting.php b/src/wp-includes/formatting.php index 448dd931c5..709593915d 100644 --- a/src/wp-includes/formatting.php +++ b/src/wp-includes/formatting.php @@ -785,21 +785,27 @@ function utf8_uri_encode( $utf8_string, $length = 0 ) { $unicode .= chr($value); $unicode_length++; } else { - if ( count( $values ) == 0 ) $num_octets = ( $value < 224 ) ? 2 : 3; + if ( count( $values ) == 0 ) { + if ( $value < 224 ) { + $num_octets = 2; + } elseif ( $value < 240 ) { + $num_octets = 3; + } else { + $num_octets = 4; + } + } $values[] = $value; if ( $length && ( $unicode_length + ($num_octets * 3) ) > $length ) break; if ( count( $values ) == $num_octets ) { - if ($num_octets == 3) { - $unicode .= '%' . dechex($values[0]) . '%' . dechex($values[1]) . '%' . dechex($values[2]); - $unicode_length += 9; - } else { - $unicode .= '%' . dechex($values[0]) . '%' . dechex($values[1]); - $unicode_length += 6; + for ( $j = 0; $j < $num_octets; $j++ ) { + $unicode .= '%' . dechex( $values[ $j ] ); } + $unicode_length += $num_octets * 3; + $values = array(); $num_octets = 1; } diff --git a/src/wp-includes/taxonomy.php b/src/wp-includes/taxonomy.php index f27b7b6aae..c7a923e8da 100644 --- a/src/wp-includes/taxonomy.php +++ b/src/wp-includes/taxonomy.php @@ -2879,13 +2879,7 @@ function wp_insert_term( $term, $taxonomy, $args = array() ) { $slug_provided = ! empty( $args['slug'] ); if ( ! $slug_provided ) { - $_name = trim( $name ); - $existing_term = get_term_by( 'name', $_name, $taxonomy ); - if ( $existing_term ) { - $slug = $existing_term->slug; - } else { - $slug = sanitize_title( $name ); - } + $slug = sanitize_title( $name ); } else { $slug = $args['slug']; } @@ -2910,20 +2904,14 @@ function wp_insert_term( $term, $taxonomy, $args = array() ) { } // Terms with duplicate names are not allowed at the same level of a taxonomy hierarchy. - if ( $exists = term_exists( $slug, $taxonomy ) ) { - $existing_term = get_term( $exists['term_id'], $taxonomy ); - - if ( $name === $existing_term->name ) { - - if ( is_taxonomy_hierarchical( $taxonomy ) ) { - $siblings = get_terms( $taxonomy, array( 'fields' => 'names', 'get' => 'all', 'parent' => $parent ) ); - if ( in_array( $name, $siblings ) ) { - return new WP_Error( 'term_exists', __( 'A term with the name and slug already exists with this parent.' ), $exists['term_id'] ); - } - - } else { - return new WP_Error( 'term_exists', __( 'A term with the name and slug already exists in this taxonomy.' ), $exists['term_id'] ); + if ( $existing_term = get_term_by( 'name', $name, $taxonomy ) ) { + if ( is_taxonomy_hierarchical( $taxonomy ) ) { + $siblings = get_terms( $taxonomy, array( 'fields' => 'names', 'get' => 'all', 'parent' => $parent ) ); + if ( in_array( $name, $siblings ) ) { + return new WP_Error( 'term_exists', __( 'A term with the name already exists with this parent.' ), $existing_term->term_id ); } + } else { + return new WP_Error( 'term_exists', __( 'A term with the name already exists in this taxonomy.' ), $existing_term->term_id ); } } diff --git a/tests/phpunit/data/formatting/utf-8/entitized.txt b/tests/phpunit/data/formatting/utf-8/entitized.txt index a29c9f9216..93d897585f 100644 --- a/tests/phpunit/data/formatting/utf-8/entitized.txt +++ b/tests/phpunit/data/formatting/utf-8/entitized.txt @@ -2,4 +2,5 @@ François Truffaut საქართველო Björk Guðmundsdóttir -宮崎 駿 \ No newline at end of file +宮崎 駿 +👍 \ No newline at end of file diff --git a/tests/phpunit/data/formatting/utf-8/u-urlencoded.txt b/tests/phpunit/data/formatting/utf-8/u-urlencoded.txt index ad4e422c75..d6f77fdc3f 100644 --- a/tests/phpunit/data/formatting/utf-8/u-urlencoded.txt +++ b/tests/phpunit/data/formatting/utf-8/u-urlencoded.txt @@ -1,5 +1,6 @@ -%u7AE0%u5B50%u6021 -%u0046%u0072%u0061%u006E%u00E7%u006F%u0069%u0073%u0020%u0054%u0072%u0075%u0066%u0066%u0061%u0075%u0074 -%u10E1%u10D0%u10E5%u10D0%u10E0%u10D7%u10D5%u10D4%u10DA%u10DD -%u0042%u006A%u00F6%u0072%u006B%u0020%u0047%u0075%u00F0%u006D%u0075%u006E%u0064%u0073%u0064%u00F3%u0074%u0074%u0069%u0072 -%u5BAE%u5D0E%u3000%u99FF +%u7AE0%u5B50%u6021 +%u0046%u0072%u0061%u006E%u00E7%u006F%u0069%u0073%u0020%u0054%u0072%u0075%u0066%u0066%u0061%u0075%u0074 +%u10E1%u10D0%u10E5%u10D0%u10E0%u10D7%u10D5%u10D4%u10DA%u10DD +%u0042%u006A%u00F6%u0072%u006B%u0020%u0047%u0075%u00F0%u006D%u0075%u006E%u0064%u0073%u0064%u00F3%u0074%u0074%u0069%u0072 +%u5BAE%u5D0E%u3000%u99FF +%u1F44D \ No newline at end of file diff --git a/tests/phpunit/data/formatting/utf-8/urlencoded.txt b/tests/phpunit/data/formatting/utf-8/urlencoded.txt index 930bf13ff6..48a642ec25 100644 --- a/tests/phpunit/data/formatting/utf-8/urlencoded.txt +++ b/tests/phpunit/data/formatting/utf-8/urlencoded.txt @@ -1,5 +1,6 @@ -%e7%ab%a0%e5%ad%90%e6%80%a1 -Fran%c3%a7ois Truffaut -%e1%83%a1%e1%83%90%e1%83%a5%e1%83%90%e1%83%a0%e1%83%97%e1%83%95%e1%83%94%e1%83%9a%e1%83%9d -Bj%c3%b6rk Gu%c3%b0mundsd%c3%b3ttir -%e5%ae%ae%e5%b4%8e%e3%80%80%e9%a7%bf +%e7%ab%a0%e5%ad%90%e6%80%a1 +Fran%c3%a7ois Truffaut +%e1%83%a1%e1%83%90%e1%83%a5%e1%83%90%e1%83%a0%e1%83%97%e1%83%95%e1%83%94%e1%83%9a%e1%83%9d +Bj%c3%b6rk Gu%c3%b0mundsd%c3%b3ttir +%e5%ae%ae%e5%b4%8e%e3%80%80%e9%a7%bf +%f0%9f%91%8d \ No newline at end of file diff --git a/tests/phpunit/data/formatting/utf-8/utf-8.txt b/tests/phpunit/data/formatting/utf-8/utf-8.txt index 1596029d20..a2df260b1e 100644 --- a/tests/phpunit/data/formatting/utf-8/utf-8.txt +++ b/tests/phpunit/data/formatting/utf-8/utf-8.txt @@ -3,3 +3,4 @@ François Truffaut საქართველო Björk Guðmundsdóttir 宮崎 駿 +👍 diff --git a/tests/phpunit/tests/formatting/UrlEncodedToEntities.php b/tests/phpunit/tests/formatting/UrlEncodedToEntities.php index 956f67173f..e680352725 100644 --- a/tests/phpunit/tests/formatting/UrlEncodedToEntities.php +++ b/tests/phpunit/tests/formatting/UrlEncodedToEntities.php @@ -8,7 +8,7 @@ class Tests_Formatting_UrlEncodedToEntities extends WP_UnitTestCase { * @dataProvider data */ function test_convert_urlencoded_to_entities( $u_urlencoded, $entity ) { - $this->assertEquals( $entity, preg_replace_callback('/\%u([0-9A-F]{4})/', '_convert_urlencoded_to_entities', $u_urlencoded ), $entity ); + $this->assertEquals( $entity, preg_replace_callback('/\%u([0-9A-F]{4,5})/', '_convert_urlencoded_to_entities', $u_urlencoded ), $entity ); } function data() { diff --git a/tests/phpunit/tests/term.php b/tests/phpunit/tests/term.php index 445713bd92..712663efab 100644 --- a/tests/phpunit/tests/term.php +++ b/tests/phpunit/tests/term.php @@ -174,8 +174,9 @@ class Tests_Term extends WP_UnitTestCase { // Test existing term name with unique slug $term1 = $this->factory->tag->create( array( 'name' => 'Bozo', 'slug' => 'bozo1' ) ); - $this->assertFalse( is_wp_error( $term1 ) ); - $this->assertTrue( empty($term1->errors ) ); + $this->assertTrue( is_wp_error( $term1 ) ); + $this->assertSame( 'term_exists', $term1->get_error_code() ); + $this->assertEquals( $term->term_id, $term1->get_error_data() ); // Test an existing term name $term2 = $this->factory->tag->create( array( 'name' => 'Bozo' ) );