Make WordPress Core

Ticket #21170: 21170-1.patch

File 21170-1.patch, 20.5 KB (added by TV productions, 11 years ago)

Implemented the wp hooks from https://github.com/gcorne/WP-JS-Hooks/

  • src/wp-admin/js/word-count.js

     
    1 /* global wordCountL10n */
     1/* global wordCountL10n, wp */
    22var wpWordCount;
    33(function($,undefined) {
    44        wpWordCount = {
     
    3838                }
    3939        };
    4040
    41         $(document).bind( 'wpcountwords', function(e, txt) {
     41        wp.hooks.addAction( 'wpcountwords', function(txt) {
    4242                wpWordCount.wc(txt);
    4343        });
    4444}(jQuery));
  • src/wp-includes/js/wp-hooks.js

     
     1window.wp = window.wp || {};
     2
     3(function(namespace) {
     4        "use strict";
     5
     6        /**
     7         * Handles managing all events for whatever you plug it into. Priorities for
     8         * hooks are based on lowest to highest in that, lowest priority hooks are
     9         * fired first.
     10         */
     11        var EventManager = function() {
     12                /**
     13                 * Maintain a reference to the object scope so our public methods never
     14                 * get confusing.
     15                 */
     16                var MethodsAvailable = {
     17                        removeFilter : removeFilter,
     18                        applyFilters : applyFilters,
     19                        addFilter : addFilter,
     20                        removeAction : removeAction,
     21                        doAction : doAction,
     22                        addAction : addAction
     23                };
     24
     25                /**
     26                 * Contains the hooks that get registered with this EventManager. The
     27                 * array for storage utilizes a "flat" object literal such that looking
     28                 * up the hook utilizes the native object literal hash.
     29                 */
     30                var STORAGE = {
     31                        actions : {},
     32                        filters : {}
     33                };
     34
     35                /**
     36                 * Adds an action to the event manager.
     37                 *
     38                 * @param action
     39                 *            Must contain namespace.identifier
     40                 * @param callback
     41                 *            Must be a valid callback function before this action is
     42                 *            added
     43                 * @param [priority=10]
     44                 *            Used to control when the function is executed in relation
     45                 *            to other callbacks bound to the same hook
     46                 * @param [context]
     47                 *            Supply a value to be used for this
     48                 */
     49                function addAction(action, callback, priority, context) {
     50                        if (typeof action === 'string' && typeof callback === 'function') {
     51                                priority = parseInt((priority || 10), 10);
     52                                _addHook('actions', action, callback, priority, context);
     53                        }
     54
     55                        return MethodsAvailable;
     56                }
     57
     58                /**
     59                 * Performs an action if it exists. You can pass as many arguments as
     60                 * you want to this function; the only rule is that the first argument
     61                 * must always be the action.
     62                 */
     63                function doAction( /* action, arg1, arg2, ... */) {
     64                        var args = Array.prototype.slice.call(arguments);
     65                        var action = args.shift();
     66
     67                        if (typeof action === 'string') {
     68                                _runHook('actions', action, args);
     69                        }
     70
     71                        return MethodsAvailable;
     72                }
     73
     74                /**
     75                 * Removes the specified action if it contains a namespace.identifier &
     76                 * exists.
     77                 *
     78                 * @param action
     79                 *            The action to remove
     80                 * @param [callback]
     81                 *            Callback function to remove
     82                 */
     83                function removeAction(action, callback) {
     84                        if (typeof action === 'string') {
     85                                _removeHook('actions', action, callback);
     86                        }
     87
     88                        return MethodsAvailable;
     89                }
     90
     91                /**
     92                 * Adds a filter to the event manager.
     93                 *
     94                 * @param filter
     95                 *            Must contain namespace.identifier
     96                 * @param callback
     97                 *            Must be a valid callback function before this action is
     98                 *            added
     99                 * @param [priority=10]
     100                 *            Used to control when the function is executed in relation
     101                 *            to other callbacks bound to the same hook
     102                 * @param [context]
     103                 *            Supply a value to be used for this
     104                 */
     105                function addFilter(filter, callback, priority, context) {
     106                        if (typeof filter === 'string' && typeof callback === 'function') {
     107                                priority = parseInt((priority || 10), 10);
     108                                _addHook('filters', filter, callback, priority);
     109                        }
     110
     111                        return MethodsAvailable;
     112                }
     113
     114                /**
     115                 * Performs a filter if it exists. You should only ever pass 1 argument
     116                 * to be filtered. The only rule is that the first argument must always
     117                 * be the filter.
     118                 */
     119                function applyFilters( /* filter, filtered arg, arg2, ... */) {
     120                        var args = Array.prototype.slice.call(arguments);
     121                        var filter = args.shift();
     122
     123                        if (typeof filter === 'string') {
     124                                return _runHook('filters', filter, args);
     125                        }
     126
     127                        return MethodsAvailable;
     128                }
     129
     130                /**
     131                 * Removes the specified filter if it contains a namespace.identifier &
     132                 * exists.
     133                 *
     134                 * @param filter
     135                 *            The action to remove
     136                 * @param [callback]
     137                 *            Callback function to remove
     138                 */
     139                function removeFilter(filter, callback) {
     140                        if (typeof filter === 'string') {
     141                                _removeHook('filters', filter, callback);
     142                        }
     143
     144                        return MethodsAvailable;
     145                }
     146
     147                /**
     148                 * Removes the specified hook by resetting the value of it.
     149                 *
     150                 * @param type
     151                 *            Type of hook, either 'actions' or 'filters'
     152                 * @param hook
     153                 *            The hook (namespace.identifier) to remove
     154                 * @private
     155                 */
     156                function _removeHook(type, hook, callback) {
     157                        var actions, action, index;
     158                        if (STORAGE[type][hook]) {
     159                                if (typeof callback === 'undefined') {
     160                                        STORAGE[type][hook] = [];
     161                                } else {
     162                                        actions = STORAGE[type][hook];
     163                                        for (index = 0; index < actions.length; index++) {
     164                                                action = actions[index];
     165                                                if (action.callback === callback) {
     166                                                        STORAGE[type][hook].splice(index, 1);
     167                                                }
     168                                        }
     169                                }
     170                        }
     171                }
     172
     173                /**
     174                 * Adds the hook to the appropriate storage container
     175                 *
     176                 * @param type
     177                 *            'actions' or 'filters'
     178                 * @param hook
     179                 *            The hook (namespace.identifier) to add to our event
     180                 *            manager
     181                 * @param callback
     182                 *            The function that will be called when the hook is
     183                 *            executed.
     184                 * @param priority
     185                 *            The priority of this hook. Must be an integer.
     186                 * @param [context]
     187                 *            A value to be used for this
     188                 * @private
     189                 */
     190                function _addHook(type, hook, callback, priority, context) {
     191                        var hookObject = {
     192                                callback : callback,
     193                                priority : priority,
     194                                context : context
     195                        };
     196
     197                        // Utilize 'prop itself' :
     198                        // http://jsperf.com/hasownproperty-vs-in-vs-undefined/19
     199                        var hooks = STORAGE[type][hook];
     200                        if (hooks) {
     201                                hooks.push(hookObject);
     202                                hooks = _hookInsertSort(hooks);
     203                        } else {
     204                                hooks = [ hookObject ];
     205                        }
     206
     207                        STORAGE[type][hook] = hooks;
     208                }
     209
     210                /**
     211                 * Use an insert sort for keeping our hooks organized based on priority.
     212                 * This function is ridiculously faster than bubble sort, etc:
     213                 * http://jsperf.com/javascript-sort
     214                 *
     215                 * @param hooks
     216                 *            The custom array containing all of the appropriate hooks
     217                 *            to perform an insert sort on.
     218                 * @private
     219                 */
     220                function _hookInsertSort(hooks) {
     221                        var tmpHook, j, prevHook;
     222                        for ( var i = 1, len = hooks.length; i < len; i++) {
     223                                tmpHook = hooks[i];
     224                                j = i;
     225                                while ((prevHook = hooks[j - 1])
     226                                                && prevHook.priority > tmpHook.priority) {
     227                                        hooks[j] = hooks[j - 1];
     228                                        --j;
     229                                }
     230                                hooks[j] = tmpHook;
     231                        }
     232
     233                        return hooks;
     234                }
     235
     236                /**
     237                 * Runs the specified hook. If it is an action, the value is not
     238                 * modified but if it is a filter, it is.
     239                 *
     240                 * @param type
     241                 *            'actions' or 'filters'
     242                 * @param hook
     243                 *            The hook ( namespace.identifier ) to be ran.
     244                 * @param args
     245                 *            Arguments to pass to the action/filter. If it's a filter,
     246                 *            args is actually a single parameter.
     247                 * @private
     248                 */
     249                function _runHook(type, hook, args) {
     250                        var hooks = STORAGE[type][hook];
     251                        if (typeof hooks === 'undefined') {
     252                                if (type === 'filters') {
     253                                        return args[0];
     254                                }
     255                                return false;
     256                        }
     257
     258                        for ( var i = 0, len = hooks.length; i < len; i++) {
     259                                if (type === 'actions') {
     260                                        hooks[i].callback.apply(hooks[i].context, args);
     261                                } else {
     262                                        args[0] = hooks[i].callback.apply(hooks[i].context, args);
     263                                }
     264                        }
     265
     266                        if (type === 'actions') {
     267                                return true;
     268                        }
     269
     270                        return args[0];
     271                }
     272
     273                // return all of the publicly available methods
     274                return MethodsAvailable;
     275
     276        };
     277        namespace = namespace || {};
     278        namespace.hooks = new EventManager();
     279
     280})(window.wp);
     281 No newline at end of file
  • src/wp-admin/js/post.js

     
    258258        );
    259259};
    260260
    261 $(document).on( 'heartbeat-send.refresh-lock', function( e, data ) {
     261wp.hooks.addAction( 'heartbeat-send', function( data ) {
    262262        var lock = $('#active_post_lock').val(),
    263263                post_id = $('#post_ID').val(),
    264264                send = {};
     
    273273
    274274        data['wp-refresh-post-lock'] = send;
    275275
    276 }).on( 'heartbeat-tick.refresh-lock', function( e, data ) {
     276}).addAction( 'heartbeat-tick', function( data ) {
    277277        // Post locks: update the lock string or show the dialog if somebody has taken over editing
    278278        var received, wrap, avatar;
    279279
     
    287287                        if ( wrap.length && ! wrap.is(':visible') ) {
    288288                                if ( wp.autosave ) {
    289289                                        // Save the latest changes and disable
    290                                         $(document).one( 'heartbeat-tick', function() {
     290                                        wp.hooks.addAction ( 'heartbeat-tick', function() {
    291291                                                wp.autosave.server.suspend();
    292292                                                wrap.removeClass('saving').addClass('saved');
    293293                                                $(window).off( 'beforeunload.edit-post' );
    294                                         });
     294                                        }, 1);
    295295
    296296                                        wrap.addClass('saving');
    297297                                        wp.autosave.server.triggerSave();
     
    309309                        $('#active_post_lock').val( received.new_lock );
    310310                }
    311311        }
    312 }).on( 'after-autosave.update-post-slug', function() {
     312});
     313wp.hooks.addAction ( 'after-autosave', function() {
    313314        // create slug area only if not already there
    314315        if ( ! $('#edit-slug-box > *').length ) {
    315316                $.post( ajaxurl, {
     
    338339                timeout = window.setTimeout( function(){ check = true; }, 300000 );
    339340        }
    340341
    341         $(document).on( 'heartbeat-send.wp-refresh-nonces', function( e, data ) {
     342        wp.hooks.doAction( 'heartbeat-send', function( e, data ) {
    342343                var nonce, post_id;
    343344
    344345                if ( check ) {
     
    349350                                };
    350351                        }
    351352                }
    352         }).on( 'heartbeat-tick.wp-refresh-nonces', function( e, data ) {
     353        }).addAction( 'heartbeat-tick', function( data ) {
    353354                var nonces = data['wp-refresh-post-nonces'];
    354355
    355356                if ( nonces ) {
     
    364365                        if ( nonces.heartbeatNonce )
    365366                                window.heartbeatSettings.nonce = nonces.heartbeatNonce;
    366367                }
    367         }).ready( function() {
     368        })
     369        $(document).ready( function() {
    368370                schedule();
    369371        });
    370372}(jQuery));
     
    511513                });
    512514        }
    513515
    514         $document.on( 'autosave-disable-buttons.edit-post', function() {
     516        wp.hooks.addAction ( 'autosave-disable-buttons', function() {
    515517                $submitButtons.addClass( 'disabled' );
    516         }).on( 'autosave-enable-buttons.edit-post', function() {
     518        }).addAction ( 'autosave-enable-buttons', function() {
    517519                if ( ! wp.heartbeat || ! wp.heartbeat.hasConnectionError() ) {
    518520                        $submitButtons.removeClass( 'disabled' );
    519521                }
    520         }).on( 'before-autosave.edit-post', function() {
     522        }).addAction ( 'before-autosave', function() {
    521523                $( '.autosave-message' ).text( postL10n.savingText );
    522         }).on( 'after-autosave.edit-post', function( event, data ) {
     524        }).addAction( 'after-autosave', function( data ) {
    523525                $( '.autosave-message' ).text( data.message );
    524526        });
    525527
     
    942944
    943945        // word count
    944946        if ( typeof(wpWordCount) != 'undefined' ) {
    945                 $document.triggerHandler('wpcountwords', [ co.val() ]);
     947                wp.hooks.doAction('wpcountwords',  co.val() );
    946948
    947949                co.keyup( function(e) {
    948950                        var k = e.keyCode || e.charCode;
     
    951953                                return true;
    952954
    953955                        if ( 13 == k || 8 == last || 46 == last )
    954                                 $document.triggerHandler('wpcountwords', [ co.val() ]);
     956                                wp.hooks.doAction ('wpcountwords',  co.val() );
    955957
    956958                        last = k;
    957959                        return true;
  • src/wp-includes/js/tinymce/plugins/wordpress/plugin.js

     
    394394                        }
    395395
    396396                        if ( 13 === key || 8 === last || 46 === last ) {
    397                                 window.jQuery( document ).triggerHandler( 'wpcountwords', [ editor.getContent({ format : 'raw' }) ] );
     397                                window.wp.hooks.doAction( 'wpcountwords',  editor.getContent({ format : 'raw' }) );
    398398                        }
    399399
    400400                        last = key;
  • src/wp-includes/js/wp-auth-check.js

     
    1 /* global adminpage */
     1/* global adminpage, wp */
    22// Interim login dialog
    33(function($){
    44        var wrap, next;
     
    8888                next = ( new Date() ).getTime() + ( interval * 1000 );
    8989        }
    9090
    91         $( document ).on( 'heartbeat-tick.wp-auth-check', function( e, data ) {
     91        wp.hooks.addAction( 'heartbeat-tick', function( data ) {
    9292                if ( 'wp-auth-check' in data ) {
    9393                        schedule();
    9494                        if ( ! data['wp-auth-check'] && wrap.hasClass('hidden') ) {
     
    9797                                hide();
    9898                        }
    9999                }
    100         }).on( 'heartbeat-send.wp-auth-check', function( e, data ) {
     100        }).addAction( 'heartbeat-send', function( data ) {
    101101                if ( ( new Date() ).getTime() > next ) {
    102102                        data['wp-auth-check'] = true;
    103103                }
    104         }).ready( function() {
     104        });
     105        $(document).ready( function() {
    105106                schedule();
    106107                wrap = $('#wp-auth-check-wrap');
    107108                wrap.find('.wp-auth-check-close').on( 'click', function() {
  • src/wp-includes/js/heartbeat.js

     
    1919 * - heartbeat_nopriv_tick
    2020 * @see wp_ajax_nopriv_heartbeat(), wp_ajax_heartbeat()
    2121 *
    22  * Custom jQuery events:
     22 * WP-hooks actions:
    2323 * - heartbeat-send
    2424 * - heartbeat-tick
    2525 * - heartbeat-error
     
    251251
    252252                                if ( trigger && ! hasConnectionError() ) {
    253253                                        settings.connectionError = true;
    254                                         $document.trigger( 'heartbeat-connection-lost', [error, status] );
     254                                        wp.hooks.doAction('heartbeat-connection-lost', error, status);
    255255                                }
    256256                        }
    257257                }
     
    270270                        if ( hasConnectionError() ) {
    271271                                settings.errorcount = 0;
    272272                                settings.connectionError = false;
    273                                 $document.trigger( 'heartbeat-connection-restored' );
     273                                wp.hooks.doAction( 'heartbeat-connection-restored' );
    274274                        }
    275275                }
    276276
     
    296296                        // Clear the data queue, anything added after this point will be send on the next tick
    297297                        settings.queue = {};
    298298
    299                         $document.trigger( 'heartbeat-send', [ heartbeatData ] );
     299                        wp.hooks.doAction( 'heartbeat-send', heartbeatData );
    300300
    301301                        ajaxData = {
    302302                                data: heartbeatData,
     
    328328                                clearErrorState();
    329329
    330330                                if ( response.nonces_expired ) {
    331                                         $document.trigger( 'heartbeat-nonces-expired' );
     331                                        wp.hooks.doAction( 'heartbeat-nonces-expired' );
    332332                                        return;
    333333                                }
    334334
     
    338338                                        delete response.heartbeat_interval;
    339339                                }
    340340
    341                                 $document.trigger( 'heartbeat-tick', [response, textStatus, jqXHR] );
     341                                wp.hooks.doAction ( 'heartbeat-tick', response, textStatus, jqXHR );
    342342
    343343                                // Do this last, can trigger the next XHR if connection time > 5 sec. and newInterval == 'fast'
    344344                                if ( newInterval ) {
     
    346346                                }
    347347                        }).fail( function( jqXHR, textStatus, error ) {
    348348                                setErrorState( textStatus || 'unknown', jqXHR.status );
    349                                 $document.trigger( 'heartbeat-error', [jqXHR, textStatus, error] );
     349                                wp.hooks.doAction ( 'heartbeat-error', jqXHR, textStatus, error );
    350350                        });
    351351                }
    352352
     
    660660                 *
    661661                 * As the data is send asynchronously, this function doesn't return the XHR response.
    662662                 * To see the response, use the custom jQuery event 'heartbeat-tick' on the document, example:
    663                  *              $(document).on( 'heartbeat-tick.myname', function( event, data, textStatus, jqXHR ) {
     663                 *              wp.hooks.addAction( 'heartbeat-tick', function( data, textStatus, jqXHR ) {
    664664                 *                      // code
    665665                 *              });
    666666                 * If the same 'handle' is used more than once, the data is not overwritten when the third argument is 'true'.
  • src/wp-includes/js/autosave.js

     
    1 /* global tinymce, wpCookies, autosaveL10n, switchEditors */
     1/* global tinymce, wpCookies, autosaveL10n, switchEditors, wp */
    22// Back-compat: prevent fatal errors
     3
     4/**
     5 * WP-hook actions
     6 * - autosave-disable-buttons
     7 * - autosave-enable-buttons
     8 * - before-autosave
     9 * - after-autosave
     10 * - wpcountwords
     11 *
     12 */
     13
    314window.autosave = function(){};
    415
    516( function( $, window ) {
     
    7788                }
    7889
    7990                function disableButtons() {
    80                         $document.trigger('autosave-disable-buttons');
     91                        wp.hooks.doAction('autosave-disable-buttons');
    8192                        // Re-enable 5 sec later. Just gives autosave a head start to avoid collisions.
    8293                        setTimeout( enableButtons, 5000 );
    8394                }
    8495
    8596                function enableButtons() {
    86                         $document.trigger( 'autosave-enable-buttons' );
     97                        wp.hooks.doAction( 'autosave-enable-buttons' );
    8798                }
    8899
    89100                // Autosave in localStorage
     
    452463                                lastCompareString = previousCompareString;
    453464                                previousCompareString = '';
    454465
    455                                 $document.trigger( 'after-autosave', [data] );
     466                                wp.hooks.doAction( 'after-autosave', data );
    456467                                enableButtons();
    457468
    458469                                if ( data.success ) {
     
    514525                                tempBlockSave();
    515526                                disableButtons();
    516527
    517                                 $document.trigger( 'wpcountwords', [ postData.content ] )
    518                                         .trigger( 'before-autosave', [ postData ] );
     528                                wp.hooks.doAction ( 'wpcountwords', postData.content )
     529                                        .doAction( 'before-autosave',  postData );
    519530
    520531                                postData._wpnonce = $( '#_wpnonce' ).val() || '';
    521532
     
    526537                                nextRun = ( new Date() ).getTime() + ( autosaveL10n.autosaveInterval * 1000 ) || 60000;
    527538                        }
    528539
    529                         $document.on( 'heartbeat-send.autosave', function( event, data ) {
     540                        wp.hooks.addAction( 'heartbeat-send', function( data ) {
    530541                                var autosaveData = save();
    531542
    532543                                if ( autosaveData ) {
    533544                                        data.wp_autosave = autosaveData;
    534545                                }
    535                         }).on( 'heartbeat-tick.autosave', function( event, data ) {
     546                        }).addAction( 'heartbeat-tick', function( data ) {
    536547                                if ( data.wp_autosave ) {
    537548                                        response( data.wp_autosave );
    538549                                }
    539                         }).on( 'heartbeat-connection-lost.autosave', function( event, error, status ) {
     550                        }).addAction( 'heartbeat-connection-lost', function( error, status ) {
    540551                                // When connection is lost, keep user from submitting changes.
    541552                                if ( 'timeout' === error || 603 === status ) {
    542553                                        var $notice = $('#lost-connection-notice');
     
    548559                                        $notice.show();
    549560                                        disableButtons();
    550561                                }
    551                         }).on( 'heartbeat-connection-restored.autosave', function() {
     562                        }).addAction( 'heartbeat-connection-restored', function() {
    552563                                $('#lost-connection-notice').hide();
    553564                                enableButtons();
    554                         }).ready( function() {
     565                        });
     566                        $document.ready( function() {
    555567                                _schedule();
    556568                        });
    557569
  • src/wp-admin/js/inline-edit-post.js

     
    1 /* global inlineEditL10n, ajaxurl, typenow */
     1/* global inlineEditL10n, ajaxurl, typenow, wp */
    22
    33var inlineEditPost;
    44(function($) {
     
    314314$( document ).ready( function(){ inlineEditPost.init(); } );
    315315
    316316// Show/hide locks on posts
    317 $( document ).on( 'heartbeat-tick.wp-check-locked-posts', function( e, data ) {
     317wp.hooks.addAction( 'heartbeat-tick', function( data ) {
    318318        var locked = data['wp-check-locked-posts'] || {};
    319319
    320320        $('#the-list tr').each( function(i, el) {
     
    337337                        row.removeClass('wp-locked').delay(1000).find('.locked-info span').empty();
    338338                }
    339339        });
    340 }).on( 'heartbeat-send.wp-check-locked-posts', function( e, data ) {
     340}).addAction( 'heartbeat-send', function( data ) {
    341341        var check = [];
    342342
    343343        $('#the-list tr').each( function(i, el) {
     
    349349        if ( check.length ) {
    350350                data['wp-check-locked-posts'] = check;
    351351        }
    352 }).ready( function() {
     352});
     353$(document).ready( function() {
    353354        // Set the heartbeat interval to 15 sec.
    354355        if ( typeof wp !== 'undefined' && wp.heartbeat ) {
    355356                wp.heartbeat.interval( 15 );