Make WordPress Core

Ticket #21170: 21170.diff

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

     
    8787
    8888        $scripts->add( 'sack', "/wp-includes/js/tw-sack$suffix.js", array(), '1.6.1', 1 );
    8989
     90        $scripts->add( 'wp-hooks', "/wp-includes/js/wp-hooks$suffix.js", array(), false, 1 );
     91
    9092        $scripts->add( 'quicktags', "/wp-includes/js/quicktags$suffix.js", array(), false, 1 );
    9193        did_action( 'init' ) && $scripts->localize( 'quicktags', 'quicktagsL10n', array(
    9294                'closeAllOpenTags'      => __( 'Close all open tags' ),