WordPress.org

Make WordPress Core

Ticket #36264: 36264.2.diff

File 36264.2.diff, 36.3 KB (added by obenland, 5 years ago)
  • src/wp-includes/js/wp-lists.js

     
    11/* global ajaxurl, wpAjax */
    2 (function($) {
    3 var fs = {add:'ajaxAdd',del:'ajaxDel',dim:'ajaxDim',process:'process',recolor:'recolor'}, wpList;
    42
     3/**
     4 * @param {jQuery} $ jQuery object.
     5 */
     6( function( $ ) {
     7var functions = {
     8        add:     'ajaxAdd',
     9        del:     'ajaxDel',
     10        dim:     'ajaxDim',
     11        process: 'process',
     12        recolor: 'recolor'
     13}, wpList;
     14
     15/**
     16 * @namespace
     17 */
    518wpList = {
     19
     20        /**
     21         * @member {object}
     22         */
    623        settings: {
    7                 url: ajaxurl, type: 'POST',
     24
     25                /**
     26                 * URL for Ajax requests.
     27                 *
     28                 * @member {string}
     29                 */
     30                url: ajaxurl,
     31
     32                /**
     33                 * The HTTP method to use for Ajax requests.
     34                 *
     35                 * @member {string}
     36                 */
     37                type: 'POST',
     38
     39                /**
     40                 * ID of the element the parsed Ajax response will be stored in.
     41                 *
     42                 * @member {string}
     43                 */
    844                response: 'ajax-response',
    945
     46                /**
     47                 * The type of list.
     48                 *
     49                 * @member {string}
     50                 */
    1051                what: '',
    11                 alt: 'alternate', altOffset: 0,
    12                 addColor: null, delColor: null, dimAddColor: null, dimDelColor: null,
    1352
     53                /**
     54                 * CSS class name for alternate styling.
     55                 *
     56                 * @member {string}
     57                 */
     58                alt: 'alternate',
     59
     60                /**
     61                 * Offset to start alternate styling from.
     62                 *
     63                 * @member {number}
     64                 */
     65                altOffset: 0,
     66
     67                /**
     68                 * Color used in animation when adding an element.
     69                 *
     70                 * Can be 'none' to disable the animation.
     71                 *
     72                 * @member {string}
     73                 */
     74                addColor: '#ffff33',
     75
     76                /**
     77                 * Color used in animation when deleting an element.
     78                 *
     79                 * Can be 'none' to disable the animation.
     80                 *
     81                 * @member {string}
     82                 */
     83                delColor: '#faafaa',
     84
     85                /**
     86                 * Color used in dim add animation.
     87                 *
     88                 * Can be 'none' to disable the animation.
     89                 *
     90                 * @member {string}
     91                 */
     92                dimAddColor: '#ffff33',
     93
     94                /**
     95                 * Color used in dim delete animation.
     96                 *
     97                 * Can be 'none' to disable the animation.
     98                 *
     99                 * @member {string}
     100                 */
     101                dimDelColor: '#ff3333',
     102
     103                /**
     104                 * Callback that's run before a request is made.
     105                 *
     106                 * @callback wpList~confirm
     107                 * @param {object}      this
     108                 * @param {HTMLElement} list            The list DOM element.
     109                 * @param {object}      settings        Settings for the current list.
     110                 * @param {string}      action          The type of action to perform: 'add', 'delete', or 'dim'.
     111                 * @param {string}      backgroundColor Background color of the list's DOM element.
     112                 * @returns {boolean} Whether to proceed with the action or not.
     113                 */
    14114                confirm: null,
    15                 addBefore: null, addAfter: null,
    16                 delBefore: null, delAfter: null,
    17                 dimBefore: null, dimAfter: null
     115
     116                /**
     117                 * Callback that's run before an item gets added to the list.
     118                 *
     119                 * Allows to cancel the request.
     120                 *
     121                 * @callback wpList~addBefore
     122                 * @param {object} settings Settings for the Ajax request.
     123                 * @returns {object|boolean} Settings for the Ajax request or false to abort.
     124                 */
     125                addBefore: null,
     126
     127                /**
     128                 * Callback that's run after an item got added to the list.
     129                 *
     130                 * @callback wpList~addAfter
     131                 * @param {XML}    returnedResponse Raw response returned from the server.
     132                 * @param {object} settings         Settings for the Ajax request.
     133                 * @param {jqXHR}  settings.xml     jQuery XMLHttpRequest object.
     134                 * @param {string} settings.status  Status of the request: 'success', 'notmodified', 'nocontent', 'error',
     135                 *                                  'timeout', 'abort', or 'parsererror'.
     136                 * @param {object} settings.parsed  Parsed response object.
     137                 */
     138                addAfter: null,
     139
     140                /**
     141                 * Callback that's run before an item gets deleted from the list.
     142                 *
     143                 * Allows to cancel the request.
     144                 *
     145                 * @callback wpList~delBefore
     146                 * @param {object}      settings Settings for the Ajax request.
     147                 * @param {HTMLElement} list     The list DOM element.
     148                 * @returns {object|boolean} Settings for the Ajax request or false to abort.
     149                 */
     150                delBefore: null,
     151
     152                /**
     153                 * Callback that's run after an item got deleted from the list.
     154                 *
     155                 * @callback wpList~delAfter
     156                 * @param {XML}    returnedResponse Raw response returned from the server.
     157                 * @param {object} settings         Settings for the Ajax request.
     158                 * @param {jqXHR}  settings.xml     jQuery XMLHttpRequest object.
     159                 * @param {string} settings.status  Status of the request: 'success', 'notmodified', 'nocontent', 'error',
     160                 *                                  'timeout', 'abort', or 'parsererror'.
     161                 * @param {object} settings.parsed  Parsed response object.
     162                 */
     163                delAfter: null,
     164
     165                /**
     166                 * Callback that's run before an item gets dim'd.
     167                 *
     168                 * Allows to cancel the request.
     169                 *
     170                 * @callback wpList~dimBefore
     171                 * @param {object} settings Settings for the Ajax request.
     172                 * @returns {object|boolean} Settings for the Ajax request or false to abort.
     173                 */
     174                dimBefore: null,
     175
     176                /**
     177                 * Callback that's run after an item got dim'd.
     178                 *
     179                 * @callback wpList~dimAfter
     180                 * @param {XML}    returnedResponse Raw response returned from the server.
     181                 * @param {object} settings         Settings for the Ajax request.
     182                 * @param {jqXHR}  settings.xml     jQuery XMLHttpRequest object.
     183                 * @param {string} settings.status  Status of the request: 'success', 'notmodified', 'nocontent', 'error',
     184                 *                                  'timeout', 'abort', or 'parsererror'.
     185                 * @param {object} settings.parsed  Parsed response object.
     186                 */
     187                dimAfter: null
    18188        },
    19189
    20         nonce: function(e,s) {
    21                 var url = wpAjax.unserialize(e.attr('href'));
    22                 return s.nonce || url._ajax_nonce || $('#' + s.element + ' input[name="_ajax_nonce"]').val() || url._wpnonce || $('#' + s.element + ' input[name="_wpnonce"]').val() || 0;
     190        /**
     191         * Finds a nonce.
     192         *
     193         * 1. Nonce in settings.
     194         * 2. `_ajax_nonce` value in element's href attribute.
     195         * 3. `_ajax_nonce` input field that is a descendant of element.
     196         * 4. `_wpnonce` value in element's href attribute.
     197         * 5. `_wpnonce` input field that is a descendant of element.
     198         * 6. 0 if none can be found.
     199         *
     200         * @param {jQuery} element  Element that triggered the request.
     201         * @param {object} settings Settings for the Ajax request.
     202         * @returns {string|number} Nonce
     203         */
     204        nonce: function( element, settings ) {
     205                var url      = wpAjax.unserialize( element.attr( 'href' ) ),
     206                        $element = $( '#' + settings.element );
     207
     208                return settings.nonce || url._ajax_nonce || $element.find( 'input[name="_ajax_nonce"]' ).val() || url._wpnonce || $element.find( 'input[name="_wpnonce"]' ).val() || 0;
    23209        },
    24210
    25211        /**
    26212         * Extract list item data from a DOM element.
    27213         *
    28          * @param  {HTMLElement} e The DOM element.
    29          * @param  {string}      t
    30          * @return {array}
     214         * Example 1: data-wp-lists="delete:the-comment-list:comment-{comment_ID}:66cc66:unspam=1"
     215         * Example 2: data-wp-lists="dim:the-comment-list:comment-{comment_ID}:unapproved:e7e7d3:e7e7d3:new=approved"
     216         *
     217         * Returns an unassociated array with the following data:
     218         * data[0] - Data identifier: 'list', 'add', 'delete', or 'dim'.
     219         * data[1] - ID of the corresponding list. If data[0] is 'list', the type of list ('comment', 'category', etc).
     220         * data[2] - ID of the parent element of all inputs necessary for the request.
     221         * data[3] - Hex color to be used in this request. If data[0] is 'dim', dim class.
     222         * data[4] - Additional arguments in query syntax that are added to the request. Example: 'post_id=1234'.
     223         *           If data[0] is 'dim', dim add color.
     224         * data[5] - Only available if data[0] is 'dim', dim delete color.
     225         * data[6] - Only available if data[0] is 'dim', additional arguments in query syntax that are added to the request.
     226         *
     227         * Result for Example 1:
     228         * data[0] - delete
     229         * data[1] - the-comment-list
     230         * data[2] - comment-{comment_ID}
     231         * data[3] - 66cc66
     232         * data[4] - unspam=1
     233         *
     234         * @param  {HTMLElement} element The DOM element.
     235         * @param  {string}      type    The type of data to look for: 'list', 'add', 'delete', or 'dim'.
     236         * @returns {Array}
    31237         */
    32         parseData: function(e,t) {
    33                 var d = [], wpListsData;
     238        parseData: function( element, type ) {
     239                var data = [], wpListsData;
    34240
    35241                try {
    36                         wpListsData = $(e).attr('data-wp-lists') || '';
    37                         wpListsData = wpListsData.match(new RegExp(t+':[\\S]+'));
     242                        wpListsData = $( element ).data( 'wp-lists' ) || '';
     243                        wpListsData = wpListsData.match( new RegExp( type + ':[\\S]+' ) );
    38244
    39                         if ( wpListsData )
    40                                 d = wpListsData[0].split(':');
    41                 } catch(r) {}
     245                        if ( wpListsData ) {
     246                                data = wpListsData[0].split( ':' );
     247                        }
     248                } catch ( error ) {}
    42249
    43                 return d;
     250                return data;
    44251        },
    45252
    46         pre: function(e,s,a) {
    47                 var bg, r;
     253        /**
     254         * Calls a confirm callback to verify the action that is about to be performed.
     255         *
     256         * @param {HTMLElement} list     The DOM element.
     257         * @param {object}      settings Settings for this list.
     258         * @param {string}      action   The type of action to perform: 'add', 'delete', or 'dim'.
     259         * @returns {object|boolean} Settings if confirmed, false if not.
     260         */
     261        pre: function( list, settings, action ) {
     262                var $element, backgroundColor, confirmed;
    48263
    49                 s = $.extend( {}, this.wpList.settings, {
     264                settings = $.extend( {}, this.wpList.settings, {
    50265                        element: null,
    51                         nonce: 0,
    52                         target: e.get(0)
    53                 }, s || {} );
    54 
    55                 if ( $.isFunction( s.confirm ) ) {
    56                         if ( 'add' != a ) {
    57                                 bg = $('#' + s.element).css('backgroundColor');
    58                                 $('#' + s.element).css('backgroundColor', '#FF9966');
     266                        nonce:   0,
     267                        target:  list.get( 0 )
     268                }, settings || {} );
     269
     270                if ( $.isFunction( settings.confirm ) ) {
     271                        $element = $( '#' + settings.element );
     272
     273                        if ( 'add' !== action ) {
     274                                backgroundColor = $element.css( 'backgroundColor' );
     275                                $element.css( 'backgroundColor', '#ff9966' );
    59276                        }
    60                         r = s.confirm.call(this, e, s, a, bg);
    61277
    62                         if ( 'add' != a )
    63                                 $('#' + s.element).css('backgroundColor', bg );
     278                        confirmed = settings.confirm.call( this, list, settings, action, backgroundColor );
    64279
    65                         if ( !r )
     280                        if ( 'add' !== action ) {
     281                                $element.css( 'backgroundColor', backgroundColor );
     282                        }
     283
     284                        if ( ! confirmed ) {
    66285                                return false;
     286                        }
    67287                }
    68288
    69                 return s;
     289                return settings;
    70290        },
    71291
    72         ajaxAdd: function( e, s ) {
    73                 e = $(e);
    74                 s = s || {};
    75                 var list = this, data = wpList.parseData(e,'add'), es, valid, formData, res, rres;
    76 
    77                 s = wpList.pre.call( list, e, s, 'add' );
     292        /**
     293         * Adds an item to the list via AJAX.
     294         *
     295         * @param {HTMLElement} element  The DOM element.
     296         * @param {object}      settings Settings for this list.
     297         * @returns {boolean}
     298         */
     299        ajaxAdd: function( element, settings ) {
     300                var list     = this,
     301                        $element = $( element ),
     302                        data     = wpList.parseData( $element, 'add' ),
     303                        formValues, formData, parsedResponse, returnedResponse;
    78304
    79                 s.element = data[2] || e.attr( 'id' ) || s.element || null;
     305                settings = settings || {};
     306                settings = wpList.pre.call( list, $element, settings, 'add' );
    80307
    81                 if ( data[3] )
    82                         s.addColor = '#' + data[3];
    83                 else
    84                         s.addColor = s.addColor || '#FFFF33';
     308                settings.element  = data[2] || $element.prop( 'id' ) || settings.element || null;
     309                settings.addColor = data[3] ? '#' + data[3] : settings.addColor;
    85310
    86                 if ( !s )
     311                if ( ! settings ) {
    87312                        return false;
     313                }
    88314
    89                 if ( !e.is('[id="' + s.element + '-submit"]') )
    90                         return !wpList.add.call( list, e, s );
     315                if ( ! $element.is( '[id="' + settings.element + '-submit"]' ) ) {
     316                        return ! wpList.add.call( list, $element, settings );
     317                }
    91318
    92                 if ( !s.element )
     319                if ( ! settings.element ) {
    93320                        return true;
     321                }
    94322
    95                 s.action = 'add-' + s.what;
     323                settings.action = 'add-' + settings.what;
     324                settings.nonce  = wpList.nonce( $element, settings );
    96325
    97                 s.nonce = wpList.nonce(e,s);
     326                if ( ! wpAjax.validateForm( '#' + settings.element ) ) {
     327                        return false;
     328                }
    98329
    99                 es = $('#' + s.element + ' :input').not('[name="_ajax_nonce"], [name="_wpnonce"], [name="action"]');
    100                 valid = wpAjax.validateForm( '#' + s.element );
     330                settings.data = $.param( $.extend( {
     331                        _ajax_nonce: settings.nonce,
     332                        action:      settings.action
     333                }, wpAjax.unserialize( data[4] || '' ) ) );
    101334
    102                 if ( !valid )
    103                         return false;
     335                formValues = $( '#' + settings.element + ' :input' ).not( '[name="_ajax_nonce"], [name="_wpnonce"], [name="action"]' );
     336                formData   = $.isFunction( formValues.fieldSerialize ) ? formValues.fieldSerialize() : formValues.serialize();
    104337
    105                 s.data = $.param( $.extend( { _ajax_nonce: s.nonce, action: s.action }, wpAjax.unserialize( data[4] || '' ) ) );
    106                 formData = $.isFunction(es.fieldSerialize) ? es.fieldSerialize() : es.serialize();
     338                if ( formData ) {
     339                        settings.data += '&' + formData;
     340                }
    107341
    108                 if ( formData )
    109                         s.data += '&' + formData;
     342                if ( $.isFunction( settings.addBefore ) ) {
     343                        settings = settings.addBefore( settings );
    110344
    111                 if ( $.isFunction(s.addBefore) ) {
    112                         s = s.addBefore( s );
    113                         if ( !s )
     345                        if ( ! settings ) {
    114346                                return true;
     347                        }
    115348                }
    116349
    117                 if ( !s.data.match(/_ajax_nonce=[a-f0-9]+/) )
     350                if ( ! settings.data.match( /_ajax_nonce=[a-f0-9]+/ ) ) {
    118351                        return true;
     352                }
    119353
    120                 s.success = function(r) {
    121                         res = wpAjax.parseAjaxResponse(r, s.response, s.element);
    122 
    123                         rres = r;
     354                settings.success = function( response ) {
     355                        parsedResponse   = wpAjax.parseAjaxResponse( response, settings.response, settings.element );
     356                        returnedResponse = response;
    124357
    125                         if ( !res || res.errors )
     358                        if ( ! parsedResponse || parsedResponse.errors ) {
    126359                                return false;
     360                        }
    127361
    128                         if ( true === res )
     362                        if ( true === parsedResponse ) {
    129363                                return true;
     364                        }
    130365
    131                         jQuery.each( res.responses, function() {
    132                                 wpList.add.call( list, this.data, $.extend( {}, s, { // this.firstChild.nodevalue
    133                                         pos: this.position || 0,
    134                                         id: this.id || 0,
    135                                         oldId: this.oldId || null
     366                        $.each( parsedResponse.responses, function() {
     367                                wpList.add.call( list, this.data, $.extend( {}, settings, { // this.firstChild.nodevalue
     368                                        position: this.position || 0,
     369                                        id:       this.id || 0,
     370                                        oldId:    this.oldId || null
    136371                                } ) );
    137372                        } );
    138373
    139374                        list.wpList.recolor();
    140                         $(list).trigger( 'wpListAddEnd', [ s, list.wpList ] );
    141                         wpList.clear.call(list,'#' + s.element);
     375                        $( list ).trigger( 'wpListAddEnd', [ settings, list.wpList ] );
     376                        wpList.clear.call( list, '#' + settings.element );
    142377                };
    143378
    144                 s.complete = function(x, st) {
    145                         if ( $.isFunction(s.addAfter) ) {
    146                                 var _s = $.extend( { xml: x, status: st, parsed: res }, s );
    147                                 s.addAfter( rres, _s );
     379                settings.complete = function( jqXHR, status ) {
     380                        if ( $.isFunction( settings.addAfter ) ) {
     381                                settings.addAfter( returnedResponse, $.extend( {
     382                                        xml:    jqXHR,
     383                                        status: status,
     384                                        parsed: parsedResponse
     385                                }, settings ) );
    148386                        }
    149387                };
    150388
    151                 $.ajax( s );
     389                $.ajax( settings );
     390
    152391                return false;
    153392        },
    154393
    155394        /**
    156395         * Delete an item in the list via AJAX.
    157396         *
    158          * @param  {HTMLElement} e A DOM element containing item data.
    159          * @param  {Object}      s
    160          * @return {boolean}
     397         * @param {HTMLElement} element A DOM element containing item data.
     398         * @param {object}      settings Settings for this list.
     399         * @returns {boolean}
    161400         */
    162         ajaxDel: function( e, s ) {
    163                 e = $(e);
    164                 s = s || {};
    165                 var list = this, data = wpList.parseData(e,'delete'), element, res, rres;
     401        ajaxDel: function( element, settings ) {
     402                var list     = this,
     403                        $element = $( element ),
     404                        data     = wpList.parseData( $element, 'delete' ),
     405                        $eventTarget, parsedResponse, returnedResponse;
    166406
    167                 s = wpList.pre.call( list, e, s, 'delete' );
     407                settings = settings || {};
     408                settings = wpList.pre.call( list, $element, settings, 'delete' );
    168409
    169                 s.element = data[2] || s.element || null;
     410                settings.element  = data[2] || settings.element || null;
     411                settings.delColor = data[3] ? '#' + data[3] : settings.delColor;
    170412
    171                 if ( data[3] )
    172                         s.delColor = '#' + data[3];
    173                 else
    174                         s.delColor = s.delColor || '#faa';
    175 
    176                 if ( !s || !s.element )
     413                if ( ! settings || ! settings.element ) {
    177414                        return false;
     415                }
     416
     417                settings.action = 'delete-' + settings.what;
     418                settings.nonce  = wpList.nonce( $element, settings );
    178419
    179                 s.action = 'delete-' + s.what;
     420                settings.data = $.extend( {
     421                        _ajax_nonce: settings.nonce,
     422                        action:      settings.action,
     423                        id:          settings.element.split( '-' ).pop()
     424                }, wpAjax.unserialize( data[4] || '' ) );
    180425
    181                 s.nonce = wpList.nonce(e,s);
     426                if ( $.isFunction( settings.delBefore ) ) {
     427                        settings = settings.delBefore( settings, list );
    182428
    183                 s.data = $.extend(
    184                         { action: s.action, id: s.element.split('-').pop(), _ajax_nonce: s.nonce },
    185                         wpAjax.unserialize( data[4] || '' )
    186                 );
    187 
    188                 if ( $.isFunction(s.delBefore) ) {
    189                         s = s.delBefore( s, list );
    190                         if ( !s )
     429                        if ( ! settings ) {
    191430                                return true;
     431                        }
    192432                }
    193433
    194                 if ( !s.data._ajax_nonce )
     434                if ( ! settings.data._ajax_nonce ) {
    195435                        return true;
     436                }
    196437
    197                 element = $('#' + s.element);
     438                $eventTarget = $( '#' + settings.element );
    198439
    199                 if ( 'none' != s.delColor ) {
    200                         element.css( 'backgroundColor', s.delColor ).fadeOut( 350, function(){
     440                if ( 'none' !== settings.delColor ) {
     441                        $eventTarget.css( 'backgroundColor', settings.delColor ).fadeOut( 350, function() {
    201442                                list.wpList.recolor();
    202                                 $(list).trigger( 'wpListDelEnd', [ s, list.wpList ] );
    203                         });
     443                                $( list ).trigger( 'wpListDelEnd', [ settings, list.wpList ] );
     444                        } );
    204445                } else {
    205446                        list.wpList.recolor();
    206                         $(list).trigger( 'wpListDelEnd', [ s, list.wpList ] );
     447                        $( list ).trigger( 'wpListDelEnd', [ settings, list.wpList ] );
    207448                }
    208449
    209                 s.success = function(r) {
    210                         res = wpAjax.parseAjaxResponse(r, s.response, s.element);
    211                         rres = r;
     450                settings.success = function( response ) {
     451                        parsedResponse   = wpAjax.parseAjaxResponse( response, settings.response, settings.element );
     452                        returnedResponse = response;
     453
     454                        if ( ! parsedResponse || parsedResponse.errors ) {
     455                                $eventTarget.stop().stop().css( 'backgroundColor', '#faa' ).show().queue( function() {
     456                                        list.wpList.recolor();
     457                                        $( this ).dequeue();
     458                                } );
    212459
    213                         if ( !res || res.errors ) {
    214                                 element.stop().stop().css( 'backgroundColor', '#faa' ).show().queue( function() { list.wpList.recolor(); $(this).dequeue(); } );
    215460                                return false;
    216461                        }
    217462                };
    218463
    219                 s.complete = function(x, st) {
    220                         if ( $.isFunction(s.delAfter) ) {
    221                                 element.queue( function() {
    222                                         var _s = $.extend( { xml: x, status: st, parsed: res }, s );
    223                                         s.delAfter( rres, _s );
    224                                 }).dequeue();
     464                settings.complete = function( jqXHR, status ) {
     465                        if ( $.isFunction( settings.delAfter ) ) {
     466                                $eventTarget.queue( function() {
     467                                        settings.delAfter( returnedResponse, $.extend( {
     468                                                xml:    jqXHR,
     469                                                status: status,
     470                                                parsed: parsedResponse
     471                                        }, settings ) );
     472                                } ).dequeue();
    225473                        }
    226474                };
    227475
    228                 $.ajax( s );
     476                $.ajax( settings );
     477
    229478                return false;
    230479        },
    231480
    232         ajaxDim: function( e, s ) {
    233                 if ( $(e).parent().css('display') == 'none' ) // Prevent hidden links from being clicked by hotkeys
    234                         return false;
    235 
    236                 e = $(e);
    237                 s = s || {};
    238 
    239                 var list = this, data = wpList.parseData(e,'dim'), element, isClass, color, dimColor, res, rres;
    240 
    241                 s = wpList.pre.call( list, e, s, 'dim' );
     481        /**
     482         * Dim an item in the list via AJAX.
     483         *
     484         * @param {HTMLElement} element  A DOM element containing item data.
     485         * @param {object}      settings Settings for this list.
     486         * @returns {boolean}
     487         */
     488        ajaxDim: function( element, settings ) {
     489                var list     = this,
     490                        $element = $( element ),
     491                        data     = wpList.parseData( $element, 'dim' ),
     492                        $eventTarget, isClass, color, dimColor, parsedResponse, returnedResponse;
    242493
    243                 s.element = data[2] || s.element || null;
    244                 s.dimClass =  data[3] || s.dimClass || null;
     494                // Prevent hidden links from being clicked by hotkeys.
     495                if ( 'none' === $element.parent().css( 'display' ) ) {
     496                        return false;
     497                }
    245498
    246                 if ( data[4] )
    247                         s.dimAddColor = '#' + data[4];
    248                 else
    249                         s.dimAddColor = s.dimAddColor || '#FFFF33';
     499                settings = settings || {};
     500                settings = wpList.pre.call( list, $element, settings, 'dim' );
    250501
    251                 if ( data[5] )
    252                         s.dimDelColor = '#' + data[5];
    253                 else
    254                         s.dimDelColor = s.dimDelColor || '#FF3333';
     502                settings.element     = data[2] || settings.element || null;
     503                settings.dimClass    = data[3] || settings.dimClass || null;
     504                settings.dimAddColor = data[4] ? '#' + data[4] : settings.dimAddColor;
     505                settings.dimDelColor = data[5] ? '#' + data[5] : settings.dimDelColor;
    255506
    256                 if ( !s || !s.element || !s.dimClass )
     507                if ( ! settings || ! settings.element || ! settings.dimClass ) {
    257508                        return true;
     509                }
     510
     511                settings.action = 'dim-' + settings.what;
     512                settings.nonce  = wpList.nonce( $element, settings );
    258513
    259                 s.action = 'dim-' + s.what;
     514                settings.data = $.extend( {
     515                        _ajax_nonce: settings.nonce,
     516                        action:      settings.action,
     517                        id:          settings.element.split( '-' ).pop(),
     518                        dimClass:    settings.dimClass
     519                }, wpAjax.unserialize( data[6] || '' ) );
    260520
    261                 s.nonce = wpList.nonce(e,s);
     521                if ( $.isFunction( settings.dimBefore ) ) {
     522                        settings = settings.dimBefore( settings );
    262523
    263                 s.data = $.extend(
    264                         { action: s.action, id: s.element.split('-').pop(), dimClass: s.dimClass, _ajax_nonce : s.nonce },
    265                         wpAjax.unserialize( data[6] || '' )
    266                 );
    267 
    268                 if ( $.isFunction(s.dimBefore) ) {
    269                         s = s.dimBefore( s );
    270                         if ( !s )
     524                        if ( ! settings ) {
    271525                                return true;
     526                        }
    272527                }
    273528
    274                 element = $('#' + s.element);
    275                 isClass = element.toggleClass(s.dimClass).is('.' + s.dimClass);
    276                 color = wpList.getColor( element );
    277                 element.toggleClass( s.dimClass );
    278                 dimColor = isClass ? s.dimAddColor : s.dimDelColor;
     529                $eventTarget = $( '#' + settings.element );
     530                isClass      = $eventTarget.toggleClass( settings.dimClass ).is( '.' + settings.dimClass );
     531                color        = wpList.getColor( $eventTarget );
     532                dimColor     = isClass ? settings.dimAddColor : settings.dimDelColor;
     533                $eventTarget.toggleClass( settings.dimClass );
    279534
    280                 if ( 'none' != dimColor ) {
    281                         element
     535                if ( 'none' !== dimColor ) {
     536                        $eventTarget
    282537                                .animate( { backgroundColor: dimColor }, 'fast' )
    283                                 .queue( function() { element.toggleClass(s.dimClass); $(this).dequeue(); } )
    284                                 .animate( { backgroundColor: color }, { complete: function() {
    285                                                 $(this).css( 'backgroundColor', '' );
    286                                                 $(list).trigger( 'wpListDimEnd', [ s, list.wpList ] );
     538                                .queue( function() {
     539                                        $eventTarget.toggleClass( settings.dimClass );
     540                                        $( this ).dequeue();
     541                                } )
     542                                .animate( { backgroundColor: color }, {
     543                                        complete: function() {
     544                                                $( this ).css( 'backgroundColor', '' );
     545                                                $( list ).trigger( 'wpListDimEnd', [ settings, list.wpList ] );
    287546                                        }
    288                                 });
     547                                } );
    289548                } else {
    290                         $(list).trigger( 'wpListDimEnd', [ s, list.wpList ] );
     549                        $( list ).trigger( 'wpListDimEnd', [ settings, list.wpList ] );
    291550                }
    292551
    293                 if ( !s.data._ajax_nonce )
     552                if ( ! settings.data._ajax_nonce ) {
    294553                        return true;
     554                }
    295555
    296                 s.success = function(r) {
    297                         res = wpAjax.parseAjaxResponse(r, s.response, s.element);
    298                         rres = r;
     556                settings.success = function( response ) {
     557                        parsedResponse   = wpAjax.parseAjaxResponse( response, settings.response, settings.element );
     558                        returnedResponse = response;
    299559
    300                         if ( true === res ) {
     560                        if ( true === parsedResponse ) {
    301561                                return true;
    302562                        }
    303563
    304                         if ( ! res || res.errors ) {
    305                                 element.stop().stop().css( 'backgroundColor', '#FF3333' )[isClass?'removeClass':'addClass'](s.dimClass).show().queue( function() { list.wpList.recolor(); $(this).dequeue(); } );
     564                        if ( ! parsedResponse || parsedResponse.errors ) {
     565                                $eventTarget.stop().stop().css( 'backgroundColor', '#ff3333' )[isClass ? 'removeClass' : 'addClass']( settings.dimClass ).show().queue( function() {
     566                                        list.wpList.recolor();
     567                                        $( this ).dequeue();
     568                                } );
     569
    306570                                return false;
    307571                        }
    308572
    309                         if ( 'undefined' !== typeof res.responses[0].supplemental.comment_link ) {
    310                                 var submittedOn = element.find( '.submitted-on' ),
    311                                         commentLink = submittedOn.find( 'a' );
     573                        /** @property {string} comment_link Link of the comment to be dimmed. */
     574                        if ( 'undefined' !== typeof parsedResponse.responses[0].supplemental.comment_link ) {
     575                                var $submittedOn = $element.find( '.submitted-on' ),
     576                                        $commentLink = $submittedOn.find( 'a' );
    312577
    313578                                // Comment is approved; link the date field.
    314                                 if ( '' !== res.responses[0].supplemental.comment_link ) {
    315                                         submittedOn.html( $('<a></a>').text( submittedOn.text() ).prop( 'href', res.responses[0].supplemental.comment_link ) );
     579                                if ( '' !== parsedResponse.responses[0].supplemental.comment_link ) {
     580                                        $submittedOn.html( $('<a></a>').text( $submittedOn.text() ).prop( 'href', parsedResponse.responses[0].supplemental.comment_link ) );
    316581
    317582                                // Comment is not approved; unlink the date field.
    318                                 } else if ( commentLink.length ) {
    319                                         submittedOn.text( commentLink.text() );
     583                                } else if ( $commentLink.length ) {
     584                                        $submittedOn.text( $commentLink.text() );
    320585                                }
    321586                        }
    322587                };
    323588
    324                 s.complete = function(x, st) {
    325                         if ( $.isFunction(s.dimAfter) ) {
    326                                 element.queue( function() {
    327                                         var _s = $.extend( { xml: x, status: st, parsed: res }, s );
    328                                         s.dimAfter( rres, _s );
    329                                 }).dequeue();
     589                settings.complete = function( jqXHR, status ) {
     590                        if ( $.isFunction( settings.dimAfter ) ) {
     591                                $eventTarget.queue( function() {
     592                                        settings.dimAfter( returnedResponse, $.extend( {
     593                                                xml:    jqXHR,
     594                                                status: status,
     595                                                parsed: parsedResponse
     596                                        }, settings ) );
     597                                } ).dequeue();
    330598                        }
    331599                };
    332600
    333                 $.ajax( s );
     601                $.ajax( settings );
     602
    334603                return false;
    335604        },
    336605
    337         getColor: function( el ) {
    338                 var color = jQuery(el).css('backgroundColor');
    339 
    340                 return color || '#ffffff';
     606        /**
     607         * Returns the background color of the passed element.
     608         *
     609         * @param {jQuery|string} element Element to check.
     610         * @returns {string} Background color value in HEX. Default: '#ffffff'.
     611         */
     612        getColor: function( element ) {
     613                return $( element ).css( 'backgroundColor' ) || '#ffffff';
    341614        },
    342615
    343         add: function( e, s ) {
    344                 if ( 'string' == typeof e ) {
    345                         e = $( $.trim( e ) ); // Trim leading whitespaces
    346                 } else {
    347                         e = $( e );
    348                 }
    349 
    350                 var list = $(this), old = false, _s = { pos: 0, id: 0, oldId: null }, ba, ref, color;
     616        /**
     617         * Adds something.
     618         *
     619         * @param {HTMLElement} element  A DOM element containing item data.
     620         * @param {object}      settings Settings for this list.
     621         * @returns {boolean}
     622         */
     623        add: function( element, settings ) {
     624                var $list    = $( this ),
     625                        $element = $( element ),
     626                        old      = false,
     627                        position, reference;
    351628
    352                 if ( 'string' == typeof s )
    353                         s = { what: s };
     629                if ( 'string' === typeof settings ) {
     630                        settings = { what: settings };
     631                }
    354632
    355                 s = $.extend(_s, this.wpList.settings, s);
     633                settings = $.extend( { position: 0, id: 0, oldId: null }, this.wpList.settings, settings );
    356634
    357                 if ( !e.length || !s.what )
     635                if ( ! $element.length || ! settings.what ) {
    358636                        return false;
     637                }
    359638
    360                 if ( s.oldId )
    361                         old = $('#' + s.what + '-' + s.oldId);
     639                if ( settings.oldId ) {
     640                        old = $( '#' + settings.what + '-' + settings.oldId );
     641                }
    362642
    363                 if ( s.id && ( s.id != s.oldId || !old || !old.length ) )
    364                         $('#' + s.what + '-' + s.id).remove();
     643                if ( settings.id && ( settings.id !== settings.oldId || ! old || ! old.length ) ) {
     644                        $( '#' + settings.what + '-' + settings.id ).remove();
     645                }
    365646
    366647                if ( old && old.length ) {
    367                         old.before(e);
     648                        old.before( $element );
    368649                        old.remove();
    369                 } else if ( isNaN(s.pos) ) {
    370                         ba = 'after';
    371650
    372                         if ( '-' == s.pos.substr(0,1) ) {
    373                                 s.pos = s.pos.substr(1);
    374                                 ba = 'before';
     651                } else if ( isNaN( settings.position ) ) {
     652                        position = 'after';
     653
     654                        if ( '-' === settings.position.substr( 0, 1 ) ) {
     655                                settings.position = settings.position.substr( 1 );
     656                                position = 'before';
    375657                        }
    376658
    377                         ref = list.find( '#' + s.pos );
     659                        reference = $list.find( '#' + settings.position );
    378660
    379                         if ( 1 === ref.length )
    380                                 ref[ba](e);
    381                         else
    382                                 list.append(e);
     661                        if ( 1 === reference.length ) {
     662                                reference[position]( $element );
     663                        } else {
     664                                $list.append( $element );
     665                        }
    383666
    384                 } else if ( 'comment' != s.what || 0 === $('#' + s.element).length ) {
    385                         if ( s.pos < 0 ) {
    386                                 list.prepend(e);
     667                } else if ( 'comment' !== settings.what || 0 === $( '#' + settings.element ).length ) {
     668                        if ( settings.position < 0 ) {
     669                                $list.prepend( $element );
    387670                        } else {
    388                                 list.append(e);
     671                                $list.append( $element );
    389672                        }
    390673                }
    391674
    392                 if ( s.alt ) {
    393                         if ( ( list.children(':visible').index( e[0] ) + s.altOffset ) % 2 ) { e.removeClass( s.alt ); }
    394                         else { e.addClass( s.alt ); }
     675                if ( settings.alt ) {
     676                        $element.toggleClass( settings.alt, ( $list.children( ':visible' ).index( $element[0] ) + settings.altOffset ) % 2 );
    395677                }
    396678
    397                 if ( 'none' != s.addColor ) {
    398                         color = wpList.getColor( e );
    399                         e.css( 'backgroundColor', s.addColor ).animate( { backgroundColor: color }, { complete: function() { $(this).css( 'backgroundColor', '' ); } } );
     679                if ( 'none' !== settings.addColor ) {
     680                        $element.css( 'backgroundColor', settings.addColor ).animate( { backgroundColor: wpList.getColor( $element ) }, {
     681                                complete: function() {
     682                                        $( this ).css( 'backgroundColor', '' );
     683                                }
     684                        } );
    400685                }
    401                 list.each( function() { this.wpList.process( e ); } );
    402                 return e;
    403         },
    404686
    405         clear: function(e) {
    406                 var list = this, t, tag;
     687                // Add event handlers.
     688                $list.each( function( index, list ) {
     689                        list.wpList.process( $element );
     690                } );
    407691
    408                 e = $(e);
     692                return $element;
     693        },
    409694
    410                 if ( list.wpList && e.parents( '#' + list.id ).length )
     695        /**
     696         * Clears all input fields within the element passed.
     697         *
     698         * @param {string} elementId ID of the element to check, including leading #.
     699         */
     700        clear: function( elementId ) {
     701                var list     = this,
     702                        $element = $( elementId ),
     703                        type, tagName;
     704
     705                // Bail if we're within the list.
     706                if ( list.wpList && $element.parents( '#' + list.id ).length ) {
    411707                        return;
     708                }
     709
     710                // Check each input field.
     711                $element.find( ':input' ).each( function( index, input ) {
    412712
    413                 e.find(':input').each( function() {
    414                         if ( $(this).parents('.form-no-clear').length )
     713                        // Bail if the form was marked to not to be cleared.
     714                        if ( $( input ).parents( '.form-no-clear' ).length ) {
    415715                                return;
     716                        }
    416717
    417                         t = this.type.toLowerCase();
    418                         tag = this.tagName.toLowerCase();
     718                        type    = input.type.toLowerCase();
     719                        tagName = input.tagName.toLowerCase();
    419720
    420                         if ( 'text' == t || 'password' == t || 'textarea' == tag )
    421                                 this.value = '';
    422                         else if ( 'checkbox' == t || 'radio' == t )
    423                                 this.checked = false;
    424                         else if ( 'select' == tag )
    425                                 this.selectedIndex = null;
    426                 });
    427         },
    428 
    429         process: function(el) {
    430                 var list = this,
    431                         $el = $(el || document);
    432 
    433                 $el.delegate( 'form[data-wp-lists^="add:' + list.id + ':"]', 'submit', function(){
    434                         return list.wpList.add(this);
    435                 });
    436 
    437                 $el.delegate( 'a[data-wp-lists^="add:' + list.id + ':"], input[data-wp-lists^="add:' + list.id + ':"]', 'click', function(){
    438                         return list.wpList.add(this);
    439                 });
    440 
    441                 $el.delegate( '[data-wp-lists^="delete:' + list.id + ':"]', 'click', function(){
    442                         return list.wpList.del(this);
    443                 });
    444 
    445                 $el.delegate( '[data-wp-lists^="dim:' + list.id + ':"]', 'click', function(){
    446                         return list.wpList.dim(this);
    447                 });
     721                        if ( 'text' === type || 'password' === type || 'textarea' === tagName ) {
     722                                input.value = '';
     723
     724                        } else if ( 'checkbox' === type || 'radio' === type ) {
     725                                input.checked = false;
     726
     727                        } else if ( 'select' === tagName ) {
     728                                input.selectedIndex = null;
     729                        }
     730                } );
     731        },
     732
     733        /**
     734         * Registers event handlers to add, delete, and dim items.
     735         *
     736         * @param {string} elementId
     737         */
     738        process: function( elementId ) {
     739                var list     = this,
     740                        $element = $( elementId || document );
     741
     742                $element.on( 'submit', 'form[data-wp-lists^="add:' + list.id + ':"]', function() {
     743                        return list.wpList.add( this );
     744                } );
     745
     746                $element.on( 'click', 'a[data-wp-lists^="add:' + list.id + ':"], input[data-wp-lists^="add:' + list.id + ':"]', function() {
     747                        return list.wpList.add( this );
     748                } );
     749
     750                $element.on( 'click', '[data-wp-lists^="delete:' + list.id + ':"]', function() {
     751                        return list.wpList.del( this );
     752                } );
     753
     754                $element.on( 'click', '[data-wp-lists^="dim:' + list.id + ':"]', function() {
     755                        return list.wpList.dim( this );
     756                } );
    448757        },
    449758
     759        /**
     760         * Updates list item background colors.
     761         */
    450762        recolor: function() {
    451                 var list = this, items, eo;
     763                var list    = this,
     764                        evenOdd = [':even', ':odd'],
     765                        items;
    452766
    453                 if ( !list.wpList.settings.alt )
     767                // Bail if there is no alternate class name specified.
     768                if ( ! list.wpList.settings.alt ) {
    454769                        return;
     770                }
    455771
    456                 items = $('.list-item:visible', list);
    457 
    458                 if ( !items.length )
    459                         items = $(list).children(':visible');
     772                items = $( '.list-item:visible', list );
    460773
    461                 eo = [':even',':odd'];
     774                if ( ! items.length ) {
     775                        items = $( list ).children( ':visible' );
     776                }
    462777
    463                 if ( list.wpList.settings.altOffset % 2 )
    464                         eo.reverse();
     778                if ( list.wpList.settings.altOffset % 2 ) {
     779                        evenOdd.reverse();
     780                }
    465781
    466                 items.filter(eo[0]).addClass(list.wpList.settings.alt).end().filter(eo[1]).removeClass(list.wpList.settings.alt);
     782                items.filter( evenOdd[0] ).addClass( list.wpList.settings.alt ).end();
     783                items.filter( evenOdd[1] ).removeClass( list.wpList.settings.alt );
    467784        },
    468785
     786        /**
     787         * Sets up `process()` and `recolor()` functions.
     788         */
    469789        init: function() {
    470                 var lists = this;
     790                var $list = this;
    471791
    472                 lists.wpList.process = function(a) {
    473                         lists.each( function() {
    474                                 this.wpList.process(a);
     792                $list.wpList.process = function() {
     793                        $list.each( function( index, element ) {
     794                                this.wpList.process( element );
    475795                        } );
    476796                };
    477797
    478                 lists.wpList.recolor = function() {
    479                         lists.each( function() {
     798                $list.wpList.recolor = function() {
     799                        $list.each( function() {
    480800                                this.wpList.recolor();
    481801                        } );
    482802                };
    483803        }
    484804};
    485805
     806/**
     807 * Initializes wpList object.
     808 *
     809 * @param {Object}           settings
     810 * @param {string}           settings.url         URL for ajax calls. Default: ajaxurl.
     811 * @param {string}           settings.type        The HTTP method to use for Ajax requests. Default: 'POST'.
     812 * @param {string}           settings.response    ID of the element the parsed ajax response will be stored in.
     813 *                                                Default: 'ajax-response'.
     814 *
     815 * @param {string}           settings.what        Default: ''.
     816 * @param {string}           settings.alt         CSS class name for alternate styling. Default: 'alternate'.
     817 * @param {number}           settings.altOffset   Offset to start alternate styling from. Default: 0.
     818 * @param {string}           settings.addColor    Hex code or 'none' to disable animation. Default: '#ffff33'.
     819 * @param {string}           settings.delColor    Hex code or 'none' to disable animation. Default: '#faafaa'.
     820 * @param {string}           settings.dimAddColor Hex code or 'none' to disable animation. Default: '#ffff33'.
     821 * @param {string}           settings.dimDelColor Hex code or 'none' to disable animation. Default: '#ff3333'.
     822 *
     823 * @param {wpList~confirm}   settings.confirm     Callback that's run before a request is made. Default: null.
     824 * @param {wpList~addBefore} settings.addBefore   Callback that's run before an item gets added to the list.
     825 *                                                Default: null.
     826 * @param {wpList~addAfter}  settings.addAfter    Callback that's run after an item got added to the list.
     827 *                                                Default: null.
     828 * @param {wpList~delBefore} settings.delBefore   Callback that's run before an item gets deleted from the list.
     829 *                                                Default: null.
     830 * @param {wpList~delAfter}  settings.delAfter    Callback that's run after an item got deleted from the list.
     831 *                                                Default: null.
     832 * @param {wpList~dimBefore} settings.dimBefore   Callback that's run before an item gets dim'd. Default: null.
     833 * @param {wpList~dimAfter}  settings.dimAfter    Callback that's run after an item got dim'd. Default: null.
     834 * @returns {$.fn}
     835 */
    486836$.fn.wpList = function( settings ) {
    487         this.each( function() {
    488                 var _this = this;
     837        this.each( function( index, list ) {
     838                list.wpList = {
     839                        settings: $.extend( {}, wpList.settings, { what: wpList.parseData( list, 'list' )[1] || '' }, settings )
     840                };
    489841
    490                 this.wpList = { settings: $.extend( {}, wpList.settings, { what: wpList.parseData(this,'list')[1] || '' }, settings ) };
    491                 $.each( fs, function(i,f) { _this.wpList[i] = function( e, s ) { return wpList[f].call( _this, e, s ); }; } );
     842                $.each( functions, function( func, callback ) {
     843                        list.wpList[func] = function( element, setting ) {
     844                                return wpList[callback].call( list, element, setting );
     845                        };
     846                } );
    492847        } );
    493848
    494         wpList.init.call(this);
    495 
     849        wpList.init.call( this );
    496850        this.wpList.process();
    497851
    498852        return this;
    499853};
    500 
    501 })(jQuery);
     854} ) ( jQuery );