WordPress.org

Making WordPress.org

Ticket #1905: 1905.1.patch

File 1905.1.patch, 23.0 KB (added by keesiemeijer, 5 years ago)

Adds a tabbed interface for writing and previewing user contributor notes

  • sites/trunk/wordpress.org/public_html/wp-content/themes/pub/wporg-developer/comments.php

     
    6565                <p id="add-user-note" style="display:none;"><a href=""><?php _e( 'Have a note or feedback to contribute?', 'wporg' ); ?></a></p>
    6666
    6767                <?php comment_form( array(
     68                        'class_form'          => 'comment-form tab-container',
    6869                        'comment_field'       => DevHub_User_Submitted_Content::wp_editor_comments(),
    69                         'comment_notes_after' => '<p>' .
     70                        'comment_notes_after' => DevHub_Note_Preview::comment_preview() .
     71                                '<p>' .
    7072                                __( 'Notes should supplement code reference entries, for example examples, tips, explanations, use-cases, and best practices.', 'wporg' ) .
    7173                                '</p><p>' .
    7274                                __( 'Feedback can be to report errors or omissions with the documentation on this page. Such feedback will not be publicly posted.', 'wporg' ) .
     
    8789                        'title_reply'         =>  '', //'Add Example'
    8890                ) ); ?>
    8991
    90                 <!-- Comment Preview -->
    91                 <div id='comment-preview' class='comment byuser depth-1' style='display:none;'>
    92                         <article class='comment-body'>
    93                                 <header class='comment-meta'>
    94                                         <div>
    95                                                 <?php _e( 'Preview', 'wporg' ); ?>
    96                                                 <span class='spinner' style='display:none'></span>
    97                                         </div>
    98                                 </header>
    99                                 <div class='comment-content'></div>
    100                         </article>
    101                 </div>
    102 
    10392        <?php endif; ?>
    10493
    10594        <?php if ( ! \DevHub\is_parsed_post_type() && comments_open() ) : ?>
  • sites/trunk/wordpress.org/public_html/wp-content/themes/pub/wporg-developer/inc/user-content-preview.php

     
    3535         */
    3636        public static function scripts_and_styles() {
    3737                if ( is_singular() ) {
    38                         wp_enqueue_script( 'wporg-developer-preview', get_template_directory_uri() . '/js/user-notes-preview.js', array( 'jquery', 'quicktags', 'wporg-developer-function-reference' ), '20160809', true );
     38                        wp_enqueue_script( 'wporg-developer-tabs', get_template_directory_uri() . '/js/tabs.js', array( 'jquery' ), '20160809', true );
     39                        wp_enqueue_script( 'wporg-developer-preview', get_template_directory_uri() . '/js/user-notes-preview.js', array( 'jquery', 'wporg-developer-function-reference', 'wporg-developer-tabs'  ), '20160809', true );
    3940                        wp_localize_script( 'wporg-developer-preview', 'wporg_note_preview', array(
    40                                 'ajaxurl' => admin_url( 'admin-ajax.php' ),
    41                                 'nonce'   => wp_create_nonce( 'preview_nonce' ),
    42                                 'preview' => __( 'preview note', 'wporg' ),
     41                                'ajaxurl'       => admin_url( 'admin-ajax.php' ),
     42                                'nonce'         => wp_create_nonce( 'preview_nonce' ),
     43                                'preview'       => __( 'preview note', 'wporg' ),
     44                                'preview_empty' => __( 'Nothing to preview', 'wporg' ),
     45                                'is_admin'      => is_admin(),
    4346                        ) );
    4447                }
    4548        }
     
    5457                        wp_send_json_error( array( 'comment' => '' ) );
    5558                }
    5659
    57                 $comment = apply_filters('pre_comment_content', $_POST['preview_comment'] );
     60                $comment = apply_filters( 'pre_comment_content', $_POST['preview_comment'] );
    5861                $comment = wp_unslash( $comment );
    5962                $comment = apply_filters( 'get_comment_text', $comment );
    60                 $comment = apply_filters( 'comment_text', $comment );           
     63                $comment = apply_filters( 'comment_text', $comment );
    6164
    6265                wp_send_json_success( array( 'comment' => $comment ) );
    6366        }
     67
     68        /**
     69         * Captures the comment-preview markup displayed (and populated) below the Add Note form.
     70         *
     71         * @access public
     72         * @static
     73         *
     74         * @return string Comment preview HTML markup.
     75         */
     76        public static function comment_preview() {
     77                if ( !class_exists( 'DevHub_Note_Preview' ) ) {
     78                        return '';
     79                }
     80
     81                ob_start();
     82?>
     83                <div id='comment-preview' class='tab-section comment byuser depth-1 comment-preview' aria-hidden="true">
     84                        <article class='preview-body comment-body'>
     85                                <div class='preview-content comment-content'></div>
     86                        </article>
     87                </div>
     88                <?php
     89
     90                return ob_get_clean();
     91        }
    6492}
    6593
    66 
    6794DevHub_Note_Preview::init();
    68 
  • sites/trunk/wordpress.org/public_html/wp-content/themes/pub/wporg-developer/inc/user-content.php

     
    8989                                wp_enqueue_style( 'syntaxhighlighter-theme-default' );
    9090                        }
    9191
    92                         wp_enqueue_script( 'wporg-developer-user-notes', get_template_directory_uri() . '/js/user-notes.js', array( 'quicktags', 'wporg-developer-preview' ), '20160809', true );
     92                        wp_enqueue_script( 'wporg-developer-user-notes', get_template_directory_uri() . '/js/user-notes.js', array( 'quicktags' ), '20160809', true );
    9393                        if ( get_option( 'thread_comments' ) ) {
    9494                                wp_enqueue_script( 'comment-reply' );
    9595                        }
     
    126126         */
    127127        public static function wp_editor_comments() {
    128128                ob_start();
    129                 echo '<p class="comment-form-comment"><label for="comment">' . _x( 'Add Note or Feedback', 'noun', 'wporg' ) . '</label>';
     129                echo '<h3><label for="comment">' . _x( 'Add Note or Feedback', 'noun', 'wporg' ) . '</label></h3>';
     130
     131                if ( class_exists( 'DevHub_Note_Preview' ) ) {
     132                        echo '<ul class="tablist" style="display:none;">';
     133                        echo '<li><a href="#comment-form-comment">' . __( 'Write', 'wporg' ) . '</a></li>';
     134                        echo '<li><a href="#comment-preview">' . __( 'Preview', 'wporg' ) . '</a></li></ul>';
     135                }
     136
     137                echo '<div class="comment-form-comment tab-section" id="comment-form-comment">';
    130138                wp_editor( '', 'comment', array(
    131139                        'media_buttons' => false,
    132140                        'textarea_name' => 'comment',
     
    137145                        'teeny'         => true,
    138146                        'tinymce'       => false,
    139147                ) );
    140                 echo '</p>';
     148                echo '</div>';
    141149                return ob_get_clean();
    142150        }
    143151
  • sites/trunk/wordpress.org/public_html/wp-content/themes/pub/wporg-developer/js/tabs.js

     
     1/**
     2 * Takes care of hiding and displaying sections with tabs
     3 *
     4 * Allow users to switch focus between the aria-selected tab and the content.
     5 * Change focus between tabs using the left and right arrow keys.
     6 * Use the TAB key as normal to focus the first element inside the visible tab panel.
     7 *
     8 * Html markup needed for a tabbed list
     9 *
     10 * <div class=".tab-container">
     11 *     <ul class="tablist">
     12 *         <li><a href="#section-1">Section 1</a></li>
     13 *         <li><a href="#section-2">Section 2</a></li>
     14 *     </ul>
     15 *     <div id="section-1" class="tab-section">Section 1 content</div>
     16 *     <div id="section-2" class="tab-section">Section 2 content</div>
     17 * </div>
     18 */
     19
     20
     21( function( $ ) {
     22
     23        container = $( '.tab-container' );
     24
     25        if ( container.length ) {
     26
     27                container.each( function() {
     28
     29                        var tablist = $( this ).find( '.tablist' );
     30                        var tabSections = $( this ).find( '.tab-section' );
     31
     32                        if ( tablist.length || tabSections.length ) {
     33                                var tabs = tablist.find( 'a' );
     34
     35                                if ( ( 1 < tabs.length ) && ( tabs.length === tabSections.length ) ) {
     36                                        setupTabs(tablist, tabs, tabSections);
     37                                        tabEvents(tablist, tabs, tabSections);
     38                                }
     39                        }
     40                } );
     41        }
     42
     43        function setupTabs( tablist, tabs, tabSections ) {
     44
     45                tablist.attr( 'role', 'tablist' );
     46                tablist.find( 'li' ).attr( 'role', 'presentation' );
     47
     48                tabs.attr( {
     49                        'role': 'tab',
     50                        'tabindex': '-1'
     51                } );
     52
     53                // Make each aria-controls correspond id of targeted section (re href)
     54                tabs.each( function() {
     55                        $( this ).attr(
     56                                'aria-controls', $( this ).attr( 'href' ).substring( 1 )
     57                        );
     58                } );
     59
     60                // Make the first tab selected by default and allow it focus
     61                tabs.first().attr( {
     62                        'aria-selected': 'true',
     63                        'tabindex': '0'
     64                } );
     65
     66                // Make each section focusable and give it the tabpanel role
     67                tabSections.attr( {
     68                        'role': 'tabpanel'
     69                } );
     70
     71                // Make first child of each panel focusable programmatically
     72                tabSections.children().first().attr( {
     73                        'tabindex': '0'
     74                } );
     75
     76                // Make all but the first section hidden (ARIA state and display CSS)
     77                $( tabSections ).not( ":first" ).attr( {
     78                        'aria-hidden': 'true'
     79                } );
     80        }
     81
     82        function tabEvents( tablist, tabs, tabSections ) {
     83
     84                // Change focus between tabs with arrow keys
     85                tabs.on( 'keydown', function( e ) {
     86
     87                        // define current, previous and next (possible) tabs
     88                        var original = $( this );
     89                        var prev = $( this ).parents( 'li' ).prev().children( '[role="tab"]' );
     90                        var next = $( this ).parents( 'li' ).next().children( '[role="tab"]' );
     91                        var target;
     92
     93                        // find the direction (prev or next)
     94                        switch ( e.keyCode ) {
     95                                case 37:
     96                                        target = prev;
     97                                        break;
     98                                case 39:
     99                                        target = next;
     100                                        break;
     101                                default:
     102                                        target = false
     103                                        break;
     104                        }
     105
     106                        if ( target.length ) {
     107                                original.attr( {
     108                                        'tabindex': '-1',
     109                                        'aria-selected': null
     110                                } );
     111                                target.attr( {
     112                                        'tabindex': '0',
     113                                        'aria-selected': true
     114                                } ).focus();
     115                        }
     116
     117                        // Hide panels
     118                        tabSections.attr( 'aria-hidden', 'true' );
     119
     120                        // Show panel which corresponds to target
     121                        $( '#' + $( document.activeElement ).attr( 'href' ).substring( 1 ) ).attr( 'aria-hidden', null );
     122
     123                } );
     124
     125                // Handle click on tab to show + focus tabpanel
     126                tabs.on( 'click', function( e ) {
     127                        e.preventDefault();
     128
     129                        tabs.attr( {
     130                                'tabindex': '-1',
     131                                'aria-selected': null
     132                        } );
     133
     134                        // replace above on clicked tab
     135                        $( this ).attr( {
     136                                'aria-selected': true,
     137                                'tabindex': '0'
     138                        } );
     139
     140                        // Hide panels
     141                        tabSections.attr( 'aria-hidden', 'true' );
     142
     143                        // show corresponding panel
     144                        $( '#' + $( this ).attr( 'href' ).substring( 1 ) ).attr( 'aria-hidden', null );
     145
     146                } );
     147        }
     148
     149} )( jQuery );
     150 No newline at end of file
  • sites/trunk/wordpress.org/public_html/wp-content/themes/pub/wporg-developer/js/user-notes-preview.js

     
    33 *
    44 */
    55
    6 var wporg_developer_note_preview = ( function( $ ) {
     6( function( $ ) {
    77
    8         var textarea, preview, previewContent, spinner;
     8        var textarea, textareaHeight, text, preview, previewContent, tabs, processing, spinner;
    99
    10         function init( textarea_selector, preview_selector ) {
     10        function init() {
    1111
    12                 textarea = $( textarea_selector );
    13                 preview = $( preview_selector );
     12                if ( undefined === wporg_note_preview ) {
     13                        return;
     14                }
    1415
    15                 if ( textarea.length && preview.length && ( undefined !== wporg_note_preview ) ) {
     16                textarea = $( '.comment-form textarea' );
     17                preview = $( '#comment-preview' );
     18                tabs = $( '#commentform .tablist' ).find( 'a' );
     19                spinner = $( '<span class="spinner" style="display:none;"></span>' );
     20                text = '';
     21                processing = false;
    1622
    17                         previewContent = $( '.comment-content', preview );
    18                         spinner = $( '.spinner', preview );
     23                if ( textarea.length && preview.length && tabs.length ) {
    1924
    20                         if ( previewContent.length && spinner.length ) {
     25                        // Append spinner to preview tab
     26                        tabs.parents( 'li[role="presentation"]:last' ).append( spinner );
    2127
    22                                 add_preview_button();
     28                        previewContent = $( '.preview-content', preview );
    2329
    24                                 var current_text = textarea.val();
     30                        if ( previewContent.length ) {
    2531
    26                                 if ( current_text.length ) {
    27                                         update_preview( current_text );
     32                                if ( !textarea.val().length ) {
     33                                        previewContent.text( wporg_note_preview.preview_empty );
    2834                                }
    2935
    30                                 add_preview_events();
     36                                previewEvents();
    3137                        }
    3238                }
    3339        }
    3440
    35         function add_preview_button() {
    36                 QTags.addButton( 'preview', wporg_note_preview.preview, function() {
    37                         var pos = preview.position();
    38                         $( 'html,body' ).animate( {
    39                                 scrollTop: pos.top
    40                         }, 1000 );
     41        function previewEvents() {
     42
     43                tabs.on( "keydown.note_preview, click.note_preview", function( e ) {
     44
     45                        if ( 'comment-preview' === $( this ).attr( 'aria-controls' ) ) {
     46
     47                                if ( !processing ) {
     48                                        current_text = $.trim( textarea.val() );
     49                                        if ( current_text.length && ( current_text !== wporg_note_preview.preview_empty ) ) {
     50                                                if ( wporg_note_preview.preview_empty === previewContent.text() ) {
     51                                                        // Remove "Nothing to preview" if there's new current text.
     52                                                        previewContent.text( '' );
     53                                                }
     54                                                // Update the preview.
     55                                                updatePreview( current_text );
     56                                        } else {
     57                                                previewContent.text( wporg_note_preview.preview_empty );
     58                                        }
     59                                }
     60
     61                                // Remove outline from tab if clicked.
     62                                if ( "click" === e.type ) {
     63                                        $( this ).blur();
     64                                }
     65                        } else {
     66                                textarea.focus();
     67                        }
    4168                } );
    42         }
    4369
    44         function add_preview_events() {
    45 
    46                 // Update Preview after QuickTag button is clicked.
    47                 var buttons = $( '#qt_comment_toolbar' ).find( 'input' ).not( '#qt_comment_preview' );
    48                 buttons.on( 'click', function() {
    49                         // Set timeout to let the quicktags do it's thing first.
     70                // Set preview heigth when the textarea is visible
     71                $( '#add-user-note, .table-of-contents a[href="#add-note-or-feedback"]' ).click( function( e ) {
     72                        e.preventDefault();
     73                        tabs.parents( '.tablist' ).show();
    5074                        setTimeout( function() {
    51                                 update_preview( textarea.val() );
     75                                textareaHeight = textarea.outerHeight( true );
     76                                if ( 0 < textareaHeight ) {
     77                                        preview.css( 'min-height', textareaHeight + 'px' );
     78                                }
    5279                        }, 500 );
    5380                } );
     81        }
    5482
    55                 // Update Preview after keykup event.
    56                 // Delay updating the preview by 2 seconds to not overload the server.
    57                 textarea.bind( 'keyup', debounce( function( e ) {
    58                         update_preview( $( this ).val() );
    59                 }, 2000 ) );
     83        function updatePreview( content ) {
    6084
    61                 // Display a spinner as soon as the comment form changes input.
    62                 textarea.bind( 'input propertychange selectionchange', function( e ) {
    63                         spinner.show();
    64                 } );
    65         }
     85                // Don't update preview if nothing changed
     86                if ( text == content ) {
     87                        spinner.hide();
     88                        return;
     89                }
    6690
    67         function update_preview( content ) {
    6891                spinner.show();
     92                text = content;
     93                processing = true;
     94
    6995                $.post( wporg_note_preview.ajaxurl, {
    7096                        action: "preview_comment",
    7197                        preview_nonce: wporg_note_preview.nonce,
     
    7399                } )
    74100
    75101                .done( function( response ) {
    76                         update_preview_html( response.data.comment );
     102                        updatePreview_HTML( response.data.comment );
    77103                } )
    78104
    79105                .fail( function( response ) {
     
    82108
    83109                .always( function( response ) {
    84110                        spinner.hide();
     111                        processing = false;
     112
     113                        // Make first child of the preview focusable
     114                        preview.children().first().attr( {
     115                                'tabindex': '0'
     116                        } );
    85117                } );
    86118        }
    87119
    88120        // Add toggle links to source code in preview if needed.
    89         function update_source_code() {
    90 
     121        function updateSourceCode() {
    91122                if ( undefined !== wporg_developer ) {
    92123                        wporg_developer.sourceCodeDisplay( preview );
    93124                }
    94125        }
    95126
    96         function update_preview_html( content ) {
     127        function updatePreview_HTML( content ) {
    97128                // Update preview content
    98129                previewContent.html( content );
    99130
     
    102133                }
    103134
    104135                // Add toggle link to source code in preview if needed.
    105                 update_source_code();
     136                updateSourceCode();
    106137                spinner.hide();
    107138        }
    108139
    109         // https://remysharp.com/2010/07/21/throttling-function-calls
    110         function debounce( fn, delay ) {
    111                 var timer = null;
    112                 return function() {
    113                         var context = this,
    114                                 args = arguments;
    115                         clearTimeout( timer );
    116                         timer = setTimeout( function() {
    117                                 fn.apply( context, args );
    118                         }, delay );
    119                 };
    120         }
     140        init();
    121141
    122         return {
    123                 init: init
    124         }
    125 
    126142} )( jQuery );
    127  No newline at end of file
  • sites/trunk/wordpress.org/public_html/wp-content/themes/pub/wporg-developer/js/user-notes.js

     
    1212        }
    1313
    1414        function showCommentForm() {
    15                 $( '#respond, #add-user-note' ).toggle();
    16                
    17                 var preview = $( '#comment-preview' );
    18                 if( preview.length && ( wporg_developer_note_preview !== undefined ) ) {
    19                         preview.show();
     15                $( '#respond' ).show();
     16                $( '#add-user-note').hide();
    2017
    21                         //Initialize preview with textarea and preview selectors
    22                         wporg_developer_note_preview.init( '.comment-form textarea', '#comment-preview' );
    23                 }
     18                var target = $( '#commentform #add-note-or-feedback' );
     19                if( target.length ) {
     20                        var pos = target.offset();
    2421
    25                 if ( pos = $( '#submit' ).position() ) {
    26                         if ( pos.top < $(window).scrollTop() ) {
    27                                 // Scroll up
    28                                 $( 'html,body' ).animate( {scrollTop:pos.top}, 1000 );
    29                         }
    30                         else if ( pos.top + jQuery("selector").height() > $(window).scrollTop() + (window.innerHeight || document.documentElement.clientHeight) ){
    31                                 // Scroll down
    32                                 $( 'html,body' ).animate( {scrollTop:pos.top - (window.innerHeight || document.documentElement.clientHeight) + $( '#submit' ).height() + 30}, 1000 );
    33                         }
     22                        $( 'html,body' ).animate( {
     23                                scrollTop: pos.top
     24                        }, 1000 );
    3425                }
    3526        }
    3627
    3728        $( '#respond, #add-user-note' ).toggle();
    38         $( '#add-user-note' ).click( function( e ) {
     29        $( '#add-user-note, .table-of-contents a[href="#add-note-or-feedback"]' ).click( function( e ) {
    3930                e.preventDefault();
    4031
    4132                showCommentForm();
  • sites/trunk/wordpress.org/public_html/wp-content/themes/pub/wporg-developer/scss/main.scss

     
    326326                margin: 0 0 1.5em;
    327327        }
    328328
     329        /* =Tabs
     330        ----------------------------------------------- */
     331
     332        .tablist {
     333                margin: 0 0 0 10px;
     334        }
     335        .tablist li {
     336                display: inline-block;
     337                list-style: none;
     338        }
     339        .tablist a {
     340                border-color: none;
     341                background-color: transparent;
     342                border-color: transparent transparent -moz-use-text-color;
     343                border-image: none;
     344                border-style: solid solid none;
     345                border-width: 1px 1px 0;   
     346                display: inline-block;
     347                padding: .5em ;
     348                margin-bottom:-1px;
     349        }
     350        .tablist a[aria-selected],
     351        .tablist a:focus {
     352                background-color: #fff;
     353                border-color: #ddd;
     354                border-radius: 3px 3px 0 0;
     355                color: #333; 
     356        }
     357        .tab-section {
     358                margin-top: 0;
     359                padding: 0;
     360                border: none;
     361        }
     362        .tab-section[aria-hidden="true"] {
     363                display: none;
     364        }
     365        .tab-section:focus {
     366                background: #eee;
     367                outline: thin dotted;
     368        }
     369
    329370        /* =Media
    330371        ----------------------------------------------- */
    331372
     
    11961237                }
    11971238
    11981239                #comment-preview {
     1240                        margin-top: 0;
     1241                        border: 1px solid #ccc;
     1242                        border-radius: 3px;
    11991243                        clear:both;
    12001244                }
    12011245
     
    12031247                        min-height: 6em;
    12041248                }
    12051249
    1206                 #comment-preview .spinner {
     1250                label[for=comment],
     1251                .comment-form-comment,
     1252                .comment-preview {
     1253                        margin-bottom: 1em;     
     1254                }
     1255
     1256                .tablist .spinner {
    12071257                        background: url("/wp-includes/images/spinner-2x.gif") no-repeat scroll 0 50%;
    12081258                        -webkit-background-size: 20px 20px;
    12091259                        background-size: 20px 20px;
  • sites/trunk/wordpress.org/public_html/wp-content/themes/pub/wporg-developer/stylesheets/main.css

     
    287287  /* Clearing */
    288288  /* =Content
    289289        ----------------------------------------------- */
     290  /* =Tabs
     291        ----------------------------------------------- */
    290292  /* =Media
    291293        ----------------------------------------------- */
    292294  /* Make sure embeds and iframes fit their containers */
     
    677679  margin: 0 0 1.5em;
    678680}
    679681
     682.devhub-wrap .tablist {
     683  margin: 0 0 0 10px;
     684}
     685
     686.devhub-wrap .tablist li {
     687  display: inline-block;
     688  list-style: none;
     689}
     690
     691.devhub-wrap .tablist a {
     692  border-color: none;
     693  background-color: transparent;
     694  border-color: transparent transparent -moz-use-text-color;
     695  border-image: none;
     696  border-style: solid solid none;
     697  border-width: 1px 1px 0;
     698  display: inline-block;
     699  padding: .5em;
     700  margin-bottom: -1px;
     701}
     702
     703.devhub-wrap .tablist a[aria-selected],
     704.devhub-wrap .tablist a:focus {
     705  background-color: #fff;
     706  border-color: #ddd;
     707  border-radius: 3px 3px 0 0;
     708  color: #333;
     709}
     710
     711.devhub-wrap .tab-section {
     712  margin-top: 0;
     713  padding: 0;
     714  border: none;
     715}
     716
     717.devhub-wrap .tab-section[aria-hidden="true"] {
     718  display: none;
     719}
     720
     721.devhub-wrap .tab-section:focus {
     722  background: #eee;
     723  outline: thin dotted;
     724}
     725
    680726.devhub-wrap .page-content img.wp-smiley,
    681727.devhub-wrap .entry-content img.wp-smiley,
    682728.devhub-wrap .comment-content img.wp-smiley {
     
    15751621}
    15761622
    15771623.devhub-wrap.single-wp-parser-function #comment-preview, .devhub-wrap.single-wp-parser-method #comment-preview, .devhub-wrap.single-wp-parser-hook #comment-preview, .devhub-wrap.single-wp-parser-class #comment-preview {
     1624  margin-top: 0;
     1625  border: 1px solid #ccc;
     1626  border-radius: 3px;
    15781627  clear: both;
    15791628}
    15801629
     
    15821631  min-height: 6em;
    15831632}
    15841633
    1585 .devhub-wrap.single-wp-parser-function #comment-preview .spinner, .devhub-wrap.single-wp-parser-method #comment-preview .spinner, .devhub-wrap.single-wp-parser-hook #comment-preview .spinner, .devhub-wrap.single-wp-parser-class #comment-preview .spinner {
     1634.devhub-wrap.single-wp-parser-function label[for=comment],
     1635.devhub-wrap.single-wp-parser-function .comment-form-comment,
     1636.devhub-wrap.single-wp-parser-function .comment-preview, .devhub-wrap.single-wp-parser-method label[for=comment],
     1637.devhub-wrap.single-wp-parser-method .comment-form-comment,
     1638.devhub-wrap.single-wp-parser-method .comment-preview, .devhub-wrap.single-wp-parser-hook label[for=comment],
     1639.devhub-wrap.single-wp-parser-hook .comment-form-comment,
     1640.devhub-wrap.single-wp-parser-hook .comment-preview, .devhub-wrap.single-wp-parser-class label[for=comment],
     1641.devhub-wrap.single-wp-parser-class .comment-form-comment,
     1642.devhub-wrap.single-wp-parser-class .comment-preview {
     1643  margin-bottom: 1em;
     1644}
     1645
     1646.devhub-wrap.single-wp-parser-function .tablist .spinner, .devhub-wrap.single-wp-parser-method .tablist .spinner, .devhub-wrap.single-wp-parser-hook .tablist .spinner, .devhub-wrap.single-wp-parser-class .tablist .spinner {
    15861647  background: url("/wp-includes/images/spinner-2x.gif") no-repeat scroll 0 50%;
    15871648  -webkit-background-size: 20px 20px;
    15881649  background-size: 20px 20px;