Make WordPress Core

Ticket #21170: 21170.2.diff

File 21170.2.diff, 8.6 KB (added by adamsilverstein, 8 years ago)
  • src/wp-includes/js/wp-hooks.js

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

     
    8585
    8686        $scripts->add( 'wp-a11y', "/wp-includes/js/wp-a11y$suffix.js", array( 'jquery' ), false, 1 );
    8787
     88        $scripts->add( 'wp-hooks', "/wp-includes/js/wp-hooks$suffix.js", array(), false, 1 );
     89
    8890        $scripts->add( 'sack', "/wp-includes/js/tw-sack$suffix.js", array(), '1.6.1', 1 );
    8991
    9092        $scripts->add( 'quicktags', "/wp-includes/js/quicktags$suffix.js", array(), false, 1 );