WordPress.org

Make WordPress Core

Ticket #21170: 21170.12.diff

File 21170.12.diff, 26.7 KB (added by adamsilverstein, 2 years ago)
  • new file src/wp-includes/js/wp-hooks.js

    diff --git src/wp-includes/js/wp-hooks.js src/wp-includes/js/wp-hooks.js
    new file mode 100644
    index 0000000000..6ae8963a63
    - +  
     1/******/ (function(modules) { // webpackBootstrap
     2/******/        // The module cache
     3/******/        var installedModules = {};
     4/******/
     5/******/        // The require function
     6/******/        function __webpack_require__(moduleId) {
     7/******/
     8/******/                // Check if module is in cache
     9/******/                if(installedModules[moduleId]) {
     10/******/                        return installedModules[moduleId].exports;
     11/******/                }
     12/******/                // Create a new module (and put it into the cache)
     13/******/                var module = installedModules[moduleId] = {
     14/******/                        i: moduleId,
     15/******/                        l: false,
     16/******/                        exports: {}
     17/******/                };
     18/******/
     19/******/                // Execute the module function
     20/******/                modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
     21/******/
     22/******/                // Flag the module as loaded
     23/******/                module.l = true;
     24/******/
     25/******/                // Return the exports of the module
     26/******/                return module.exports;
     27/******/        }
     28/******/
     29/******/
     30/******/        // expose the modules object (__webpack_modules__)
     31/******/        __webpack_require__.m = modules;
     32/******/
     33/******/        // expose the module cache
     34/******/        __webpack_require__.c = installedModules;
     35/******/
     36/******/        // define getter function for harmony exports
     37/******/        __webpack_require__.d = function(exports, name, getter) {
     38/******/                if(!__webpack_require__.o(exports, name)) {
     39/******/                        Object.defineProperty(exports, name, {
     40/******/                                configurable: false,
     41/******/                                enumerable: true,
     42/******/                                get: getter
     43/******/                        });
     44/******/                }
     45/******/        };
     46/******/
     47/******/        // getDefaultExport function for compatibility with non-harmony modules
     48/******/        __webpack_require__.n = function(module) {
     49/******/                var getter = module && module.__esModule ?
     50/******/                        function getDefault() { return module['default']; } :
     51/******/                        function getModuleExports() { return module; };
     52/******/                __webpack_require__.d(getter, 'a', getter);
     53/******/                return getter;
     54/******/        };
     55/******/
     56/******/        // Object.prototype.hasOwnProperty.call
     57/******/        __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
     58/******/
     59/******/        // __webpack_public_path__
     60/******/        __webpack_require__.p = "";
     61/******/
     62/******/        // Load entry module and return exports
     63/******/        return __webpack_require__(__webpack_require__.s = 1);
     64/******/ })
     65/************************************************************************/
     66/******/ ([
     67/* 0 */
     68/***/ (function(module, __webpack_exports__, __webpack_require__) {
     69
     70"use strict";
     71/**
     72 * Contains the registered hooks, keyed by hook type. Each hook type is an
     73 * array of objects with priority and callback of each registered hook.
     74 */
     75const HOOKS = {
     76        actions: {},
     77        filters: {},
     78};
     79
     80/* harmony default export */ __webpack_exports__["a"] = (HOOKS);
     81
     82
     83/***/ }),
     84/* 1 */
     85/***/ (function(module, __webpack_exports__, __webpack_require__) {
     86
     87"use strict";
     88Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
     89/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__hooks__ = __webpack_require__(0);
     90/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1____ = __webpack_require__(2);
     91
     92
     93
     94const hooks = {
     95        addAction: __WEBPACK_IMPORTED_MODULE_1____["a" /* addAction */],
     96        addFilter: __WEBPACK_IMPORTED_MODULE_1____["b" /* addFilter */],
     97        removeAction: __WEBPACK_IMPORTED_MODULE_1____["m" /* removeAction */],
     98        removeFilter: __WEBPACK_IMPORTED_MODULE_1____["p" /* removeFilter */],
     99        removeAllActions: __WEBPACK_IMPORTED_MODULE_1____["n" /* removeAllActions */],
     100        removeAllFilters: __WEBPACK_IMPORTED_MODULE_1____["o" /* removeAllFilters */],
     101        hasAction: __WEBPACK_IMPORTED_MODULE_1____["k" /* hasAction */],
     102        hasFilter: __WEBPACK_IMPORTED_MODULE_1____["l" /* hasFilter */],
     103        doAction: __WEBPACK_IMPORTED_MODULE_1____["h" /* doAction */],
     104        applyFilters: __WEBPACK_IMPORTED_MODULE_1____["c" /* applyFilters */],
     105        currentAction: __WEBPACK_IMPORTED_MODULE_1____["d" /* currentAction */],
     106        currentFilter: __WEBPACK_IMPORTED_MODULE_1____["e" /* currentFilter */],
     107        doingAction: __WEBPACK_IMPORTED_MODULE_1____["i" /* doingAction */],
     108        doingFilter: __WEBPACK_IMPORTED_MODULE_1____["j" /* doingFilter */],
     109        didAction: __WEBPACK_IMPORTED_MODULE_1____["f" /* didAction */],
     110        didFilter: __WEBPACK_IMPORTED_MODULE_1____["g" /* didFilter */]
     111}
     112
     113window.wp = window.wp || {};
     114window.wp.hooks = hooks;
     115
     116
     117/***/ }),
     118/* 2 */
     119/***/ (function(module, __webpack_exports__, __webpack_require__) {
     120
     121"use strict";
     122/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__hooks__ = __webpack_require__(0);
     123/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__createAddHook__ = __webpack_require__(3);
     124/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__createRemoveHook__ = __webpack_require__(4);
     125/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__createHasHook__ = __webpack_require__(5);
     126/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__createRunHook__ = __webpack_require__(6);
     127/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__createDoingHook__ = __webpack_require__(7);
     128/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__createDidHook__ = __webpack_require__(8);
     129
     130
     131
     132
     133
     134
     135
     136
     137// Add action/filter functions.
     138const addAction = Object(__WEBPACK_IMPORTED_MODULE_1__createAddHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].actions );
     139/* harmony export (immutable) */ __webpack_exports__["a"] = addAction;
     140
     141const addFilter = Object(__WEBPACK_IMPORTED_MODULE_1__createAddHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].filters );
     142/* harmony export (immutable) */ __webpack_exports__["b"] = addFilter;
     143
     144
     145// Remove action/filter functions.
     146const removeAction = Object(__WEBPACK_IMPORTED_MODULE_2__createRemoveHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].actions );
     147/* harmony export (immutable) */ __webpack_exports__["m"] = removeAction;
     148
     149const removeFilter = Object(__WEBPACK_IMPORTED_MODULE_2__createRemoveHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].filters );
     150/* harmony export (immutable) */ __webpack_exports__["p"] = removeFilter;
     151
     152
     153// Has action/filter functions.
     154const hasAction = Object(__WEBPACK_IMPORTED_MODULE_3__createHasHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].actions );
     155/* harmony export (immutable) */ __webpack_exports__["k"] = hasAction;
     156
     157const hasFilter = Object(__WEBPACK_IMPORTED_MODULE_3__createHasHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].filters );
     158/* harmony export (immutable) */ __webpack_exports__["l"] = hasFilter;
     159
     160
     161// Remove all actions/filters functions.
     162const removeAllActions = Object(__WEBPACK_IMPORTED_MODULE_2__createRemoveHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].actions, true );
     163/* harmony export (immutable) */ __webpack_exports__["n"] = removeAllActions;
     164
     165const removeAllFilters = Object(__WEBPACK_IMPORTED_MODULE_2__createRemoveHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].filters, true );
     166/* harmony export (immutable) */ __webpack_exports__["o"] = removeAllFilters;
     167
     168
     169// Do action/apply filters functions.
     170const doAction     = Object(__WEBPACK_IMPORTED_MODULE_4__createRunHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].actions );
     171/* harmony export (immutable) */ __webpack_exports__["h"] = doAction;
     172
     173const applyFilters = Object(__WEBPACK_IMPORTED_MODULE_4__createRunHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].filters, true );
     174/* harmony export (immutable) */ __webpack_exports__["c"] = applyFilters;
     175
     176
     177// Current action/filter functions.
     178const currentAction = () => __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].actions.current || null;
     179/* harmony export (immutable) */ __webpack_exports__["d"] = currentAction;
     180
     181const currentFilter = () => __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].filters.current || null;
     182/* harmony export (immutable) */ __webpack_exports__["e"] = currentFilter;
     183
     184
     185// Doing action/filter: true while a hook is being run.
     186const doingAction = Object(__WEBPACK_IMPORTED_MODULE_5__createDoingHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].actions );
     187/* harmony export (immutable) */ __webpack_exports__["i"] = doingAction;
     188
     189const doingFilter = Object(__WEBPACK_IMPORTED_MODULE_5__createDoingHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].filters );
     190/* harmony export (immutable) */ __webpack_exports__["j"] = doingFilter;
     191
     192
     193// Did action/filter functions.
     194const didAction = Object(__WEBPACK_IMPORTED_MODULE_6__createDidHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].actions );
     195/* harmony export (immutable) */ __webpack_exports__["f"] = didAction;
     196
     197const didFilter = Object(__WEBPACK_IMPORTED_MODULE_6__createDidHook__["a" /* default */])( __WEBPACK_IMPORTED_MODULE_0__hooks__["a" /* default */].filters );
     198/* harmony export (immutable) */ __webpack_exports__["g"] = didFilter;
     199
     200
     201
     202/***/ }),
     203/* 3 */
     204/***/ (function(module, __webpack_exports__, __webpack_require__) {
     205
     206"use strict";
     207/**
     208 * Returns a function which, when invoked, will add a hook.
     209 *
     210 * @param  {Object}   hooks Stored hooks, keyed by hook name.
     211 *
     212 * @return {Function}       Function that adds a new hook.
     213 */
     214function createAddHook( hooks ) {
     215        /**
     216         * Adds the hook to the appropriate hooks container.
     217         *
     218         * @param {string}   hookName Name of hook to add
     219         * @param {Function} callback Function to call when the hook is run
     220         * @param {?number}  priority Priority of this hook (default=10)
     221         */
     222        return function addHook( hookName, callback, priority ) {
     223                if ( typeof hookName !== 'string' ) {
     224                        console.error( 'The hook name must be a string.' );
     225                        return;
     226                }
     227
     228                if ( typeof callback !== 'function' ) {
     229                        console.error( 'The hook callback must be a function.' );
     230                        return;
     231                }
     232
     233                // Assign default priority
     234                if ( 'undefined' === typeof priority ) {
     235                        priority = 10;
     236                } else {
     237                        priority = parseInt( priority, 10 );
     238                }
     239
     240                // Validate numeric priority
     241                if ( isNaN( priority ) ) {
     242                        console.error( 'The hook priority must be omitted or a number.' );
     243                        return;
     244                }
     245
     246                const handler = { callback, priority };
     247                let handlers;
     248
     249                if ( hooks.hasOwnProperty( hookName ) ) {
     250                        // Find the correct insert index of the new hook.
     251                        handlers = hooks[ hookName ];
     252                        let i = 0;
     253                        while ( i < handlers.length ) {
     254                                if ( handlers[ i ].priority > priority ) {
     255                                        break;
     256                                }
     257                                i++;
     258                        }
     259                        // Insert (or append) the new hook.
     260                        handlers.splice( i, 0, handler );
     261                } else {
     262                        // This is the first hook of its type.
     263                        handlers = [ handler ];
     264                }
     265
     266                hooks[ hookName ] = handlers;
     267        };
     268}
     269
     270/* harmony default export */ __webpack_exports__["a"] = (createAddHook);
     271
     272
     273/***/ }),
     274/* 4 */
     275/***/ (function(module, __webpack_exports__, __webpack_require__) {
     276
     277"use strict";
     278/**
     279 * Returns a function which, when invoked, will remove a specified hook or all
     280 * hooks by the given name.
     281 *
     282 * @param  {Object}   hooks      Stored hooks, keyed by hook name.
     283 * @param  {bool}     removeAll  Whether to remove all hooked callbacks.
     284 *
     285 * @return {Function}            Function that removes hooks.
     286 */
     287function createRemoveHook( hooks, removeAll ) {
     288        /**
     289         * Removes the specified callback (or all callbacks) from the hook with a
     290         * given name.
     291         *
     292         * @param {string}    hookName The name of the hook to modify.
     293         * @param {?Function} callback The specific callback to be removed.  If
     294         *                             omitted (and `removeAll` is truthy), clears
     295         *                             all callbacks.
     296         */
     297        return function removeHook( hookName, callback ) {
     298                // Bail if no hooks exist by this name
     299                if ( ! hooks.hasOwnProperty( hookName ) ) {
     300                        return;
     301                }
     302
     303                if ( removeAll ) {
     304                        const runs = hooks[ hookName ].runs;
     305                        hooks[ hookName ] = [];
     306                        if ( runs ) {
     307                                hooks[ hookName ].runs = runs;
     308                        }
     309                } else if ( callback ) {
     310                        // Try to find the specified callback to remove.
     311                        const handlers = hooks[ hookName ];
     312                        for ( let i = handlers.length - 1; i >= 0; i-- ) {
     313                                if ( handlers[ i ].callback === callback ) {
     314                                        handlers.splice( i, 1 );
     315                                }
     316                        }
     317                }
     318        };
     319}
     320
     321/* harmony default export */ __webpack_exports__["a"] = (createRemoveHook);
     322
     323
     324/***/ }),
     325/* 5 */
     326/***/ (function(module, __webpack_exports__, __webpack_require__) {
     327
     328"use strict";
     329/**
     330 * Returns a function which, when invoked, will return whether any handlers are
     331 * attached to a particular hook.
     332 *
     333 * @param  {Object}   hooks Stored hooks, keyed by hook name.
     334 *
     335 * @return {Function}       Function that returns whether any handlers are
     336 *                          attached to a particular hook.
     337 */
     338function createHasHook( hooks ) {
     339        /**
     340         * Returns how many handlers are attached for the given hook.
     341         *
     342         * @param  {string}  hookName The name of the hook to check for.
     343         *
     344         * @return {number}           The number of handlers that are attached to
     345         *                            the given hook.
     346         */
     347        return function hasHook( hookName ) {
     348                return hooks.hasOwnProperty( hookName )
     349                        ? hooks[ hookName ].length
     350                        : 0;
     351        };
     352}
     353
     354/* harmony default export */ __webpack_exports__["a"] = (createHasHook);
     355
     356
     357/***/ }),
     358/* 6 */
     359/***/ (function(module, __webpack_exports__, __webpack_require__) {
     360
     361"use strict";
     362/**
     363 * Returns a function which, when invoked, will execute all callbacks
     364 * registered to a hook of the specified type, optionally returning the final
     365 * value of the call chain.
     366 *
     367 * @param  {Object}   hooks          Stored hooks, keyed by hook name.
     368 * @param  {?bool}    returnFirstArg Whether each hook callback is expected to
     369 *                                   return its first argument.
     370 *
     371 * @return {Function}                Function that runs hook callbacks.
     372 */
     373function createRunHook( hooks, returnFirstArg ) {
     374        /**
     375         * Runs all callbacks for the specified hook.
     376         *
     377         * @param  {string} hookName The name of the hook to run.
     378         * @param  {...*}   args     Arguments to pass to the hook callbacks.
     379         *
     380         * @return {*}               Return value of runner, if applicable.
     381         */
     382        return function runHooks( hookName, ...args ) {
     383                const handlers = hooks[ hookName ];
     384                let maybeReturnValue = args[ 0 ];
     385
     386                if ( ! handlers ) {
     387                        return ( returnFirstArg ? maybeReturnValue : undefined );
     388                }
     389
     390                hooks.current = hookName;
     391                handlers.runs = ( handlers.runs || 0 ) + 1;
     392
     393                handlers.forEach( handler => {
     394                        maybeReturnValue = handler.callback.apply( null, args );
     395                        if ( returnFirstArg ) {
     396                                args[ 0 ] = maybeReturnValue;
     397                        }
     398                } );
     399
     400                delete hooks.current;
     401
     402                if ( returnFirstArg ) {
     403                        return maybeReturnValue;
     404                }
     405        };
     406}
     407
     408/* harmony default export */ __webpack_exports__["a"] = (createRunHook);
     409
     410
     411/***/ }),
     412/* 7 */
     413/***/ (function(module, __webpack_exports__, __webpack_require__) {
     414
     415"use strict";
     416/**
     417 * Returns a function which, when invoked, will return whether a hook is
     418 * currently being executed.
     419 *
     420 * @param  {Object}   hooks Stored hooks, keyed by hook name.
     421 *
     422 * @return {Function}       Function that returns whether a hook is currently
     423 *                          being executed.
     424 */
     425function createDoingHook( hooks ) {
     426        /**
     427         * Returns whether a hook is currently being executed.
     428         *
     429         * @param  {?string} hookName The name of the hook to check for.  If
     430         *                            omitted, will check for any hook being executed.
     431         *
     432         * @return {bool}             Whether the hook is being executed.
     433         */
     434        return function doingHook( hookName ) {
     435                // If the hookName was not passed, check for any current hook.
     436                if ( 'undefined' === typeof hookName ) {
     437                        return 'undefined' !== typeof hooks.current;
     438                }
     439
     440                // Return the current hook.
     441                return hooks.current
     442                        ? hookName === hooks.current
     443                        : false;
     444        };
     445}
     446
     447/* harmony default export */ __webpack_exports__["a"] = (createDoingHook);
     448
     449
     450/***/ }),
     451/* 8 */
     452/***/ (function(module, __webpack_exports__, __webpack_require__) {
     453
     454"use strict";
     455/**
     456 * Returns a function which, when invoked, will return the number of times a
     457 * hook has been called.
     458 *
     459 * @param  {Object}   hooks Stored hooks, keyed by hook name.
     460 *
     461 * @return {Function}       Function that returns a hook's call count.
     462 */
     463function createDidHook( hooks ) {
     464        /**
     465         * Returns the number of times an action has been fired.
     466         *
     467         * @param  {string} hookName The hook name to check.
     468         *
     469         * @return {number}          The number of times the hook has run.
     470         */
     471        return function didHook( hookName ) {
     472                return hooks.hasOwnProperty( hookName ) && hooks[ hookName ].runs
     473                        ? hooks[ hookName ].runs
     474                        : 0;
     475        };
     476}
     477
     478/* harmony default export */ __webpack_exports__["a"] = (createDidHook);
     479
     480
     481/***/ })
     482/******/ ]);
  • src/wp-includes/plugin.php

    diff --git src/wp-includes/plugin.php src/wp-includes/plugin.php
    index 86f1c3b319..86f9db8964 100644
    function doing_filter( $filter = null ) { 
    363363}
    364364
    365365/**
    366  * Retrieve the name of an action currently being processed.
     366 * Retrieve whether action currently being processed.
    367367 *
    368368 * @since 3.9.0
    369369 *
  • src/wp-includes/script-loader.php

    diff --git src/wp-includes/script-loader.php src/wp-includes/script-loader.php
    index 0058c5e956..790272188e 100644
    function wp_default_scripts( &$scripts ) { 
    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 );
  • tests/qunit/index.html

    diff --git tests/qunit/index.html tests/qunit/index.html
    index c41fffe63a..183c492d85 100644
     
    7676                <script src="../../src/wp-includes/js/customize-base.js"></script>
    7777                <script src="../../src/wp-includes/js/customize-models.js"></script>
    7878                <script src="../../src/wp-includes/js/shortcode.js"></script>
     79                <script src="../../src/wp-includes/js/wp-hooks.js"></script>
    7980                <script src="../../src/wp-admin/js/customize-controls.js"></script>
    8081                <script src="../../src/wp-includes/js/wp-api.js"></script>
    8182
     
    122123                <script src="wp-admin/js/customize-base.js"></script>
    123124                <script src="wp-admin/js/customize-header.js"></script>
    124125                <script src="wp-includes/js/shortcode.js"></script>
     126                <script src="wp-includes/js/wp-hooks.js"></script>
    125127                <script src="wp-includes/js/wp-api.js"></script>
    126128                <script src="wp-admin/js/customize-controls.js"></script>
    127129                <script src="wp-admin/js/customize-controls-utils.js"></script>
  • new file tests/qunit/wp-includes/js/wp-hooks.js

    diff --git tests/qunit/wp-includes/js/wp-hooks.js tests/qunit/wp-includes/js/wp-hooks.js
    new file mode 100644
    index 0000000000..43c8200c66
    - +  
     1/* global wp */
     2( function( QUnit ) {
     3        QUnit.module( 'wp-hooks' );
     4
     5        function filter_a( str ) {
     6                return str + 'a';
     7        }
     8        function filter_b( str ) {
     9                return str + 'b';
     10        }
     11        function filter_c( str ) {
     12                return str + 'c';
     13        }
     14        function action_a() {
     15                window.actionValue += 'a';
     16        }
     17        function action_b() {
     18                window.actionValue += 'b';
     19        }
     20        function action_c() {
     21                window.actionValue += 'c';
     22        }
     23        function filter_check() {
     24                ok( wp.hooks.doingFilter( 'runtest.filter' ), 'The runtest.filter is running.' );
     25        }
     26        window.actionValue = '';
     27
     28        QUnit.test( 'add and remove a filter', function() {
     29                expect( 1 );
     30                wp.hooks.addFilter( 'test.filter', filter_a );
     31                wp.hooks.removeFilter( 'test.filter', filter_a  );
     32                equal( wp.hooks.applyFilters( 'test.filter', 'test' ), 'test' );
     33        } );
     34
     35        QUnit.test( 'add a filter and run it', function() {
     36                expect( 1 );
     37                wp.hooks.addFilter( 'test.filter', filter_a );
     38                equal( wp.hooks.applyFilters( 'test.filter', 'test' ), 'testa' );
     39                wp.hooks.removeAllFilters( 'test.filter' );
     40        } );
     41
     42        QUnit.test( 'add 2 filters in a row and run them', function() {
     43                expect( 1 );
     44                wp.hooks.addFilter( 'test.filter', filter_a );
     45                wp.hooks.addFilter( 'test.filter', filter_b );
     46                equal( wp.hooks.applyFilters( 'test.filter', 'test' ), 'testab' );
     47                wp.hooks.removeAllFilters( 'test.filter' );
     48        } );
     49
     50        QUnit.test( 'add 3 filters with different priorities and run them', function() {
     51                expect( 1 );
     52                wp.hooks.addFilter( 'test.filter', filter_a );
     53                wp.hooks.addFilter( 'test.filter', filter_b, 2 );
     54                wp.hooks.addFilter( 'test.filter', filter_c, 8 );
     55                equal( wp.hooks.applyFilters( 'test.filter', 'test' ), 'testbca' );
     56                wp.hooks.removeAllFilters( 'test.filter' );
     57        } );
     58
     59        QUnit.test( 'add and remove an action', function() {
     60                expect( 1 );
     61                window.actionValue = '';
     62                wp.hooks.addAction( 'test.action', action_a );
     63                wp.hooks.removeAction( 'test.action', action_a );
     64                wp.hooks.doAction( 'test.action' );
     65                equal( window.actionValue, '' );
     66        } );
     67
     68        QUnit.test( 'add an action and run it', function() {
     69                expect( 1 );
     70                window.actionValue = '';
     71                wp.hooks.addAction( 'test.action', action_a );
     72                wp.hooks.doAction( 'test.action' );
     73                equal( window.actionValue, 'a' );
     74                wp.hooks.removeAllActions( 'test.action' );
     75        } );
     76
     77        QUnit.test( 'add 2 actions in a row and then run them', function() {
     78                expect( 1 );
     79                window.actionValue = '';
     80                wp.hooks.addAction( 'test.action', action_a );
     81                wp.hooks.addAction( 'test.action', action_b );
     82                wp.hooks.doAction( 'test.action' );
     83                equal( window.actionValue, 'ab' );
     84                wp.hooks.removeAllActions( 'test.action' );
     85        } );
     86
     87        QUnit.test( 'add 3 actions with different priorities and run them', function() {
     88                expect( 1 );
     89                window.actionValue = '';
     90                wp.hooks.addAction( 'test.action', action_a );
     91                wp.hooks.addAction( 'test.action', action_b, 2 );
     92                wp.hooks.addAction( 'test.action', action_c, 8 );
     93                wp.hooks.doAction( 'test.action' );
     94                equal( window.actionValue, 'bca' );
     95                wp.hooks.removeAllActions( 'test.action' );
     96        } );
     97
     98        QUnit.test( 'pass in two arguments to an action', function() {
     99                var arg1 = 10,
     100                        arg2 = 20;
     101
     102                expect( 4 );
     103
     104                wp.hooks.addAction( 'test.action', function( a, b ) {
     105                        equal( arg1, a );
     106                        equal( arg2, b );
     107                } );
     108                wp.hooks.doAction( 'test.action', arg1, arg2 );
     109                wp.hooks.removeAllActions( 'test.action' );
     110
     111                equal( arg1, 10 );
     112                equal( arg2, 20 );
     113        } );
     114
     115        QUnit.test( 'fire action multiple times', function() {
     116                var func;
     117                expect( 2 );
     118
     119                func = function() {
     120                        ok( true );
     121                };
     122
     123                wp.hooks.addAction( 'test.action', func );
     124                wp.hooks.doAction( 'test.action' );
     125                wp.hooks.doAction( 'test.action' );
     126                wp.hooks.removeAllActions( 'test.action' );
     127        } );
     128
     129        QUnit.test( 'remove specific action callback', function() {
     130                window.actionValue = '';
     131                wp.hooks.addAction( 'test.action', action_a );
     132                wp.hooks.addAction( 'test.action', action_b, 2 );
     133                wp.hooks.addAction( 'test.action', action_c, 8 );
     134
     135                wp.hooks.removeAction( 'test.action', action_b );
     136                wp.hooks.doAction( 'test.action' );
     137                equal( window.actionValue, 'ca' );
     138                wp.hooks.removeAllActions( 'test.action' );
     139        } );
     140
     141        QUnit.test( 'remove all action callbacks', function() {
     142                window.actionValue = '';
     143                wp.hooks.addAction( 'test.action', action_a );
     144                wp.hooks.addAction( 'test.action', action_b, 2 );
     145                wp.hooks.addAction( 'test.action', action_c, 8 );
     146
     147                wp.hooks.removeAllActions( 'test.action' );
     148                wp.hooks.doAction( 'test.action' );
     149                equal( window.actionValue, '' );
     150        } );
     151
     152        QUnit.test( 'remove specific filter callback', function() {
     153                wp.hooks.addFilter( 'test.filter', filter_a );
     154                wp.hooks.addFilter( 'test.filter', filter_b, 2 );
     155                wp.hooks.addFilter( 'test.filter', filter_c, 8 );
     156
     157                wp.hooks.removeFilter( 'test.filter', filter_b );
     158                equal( wp.hooks.applyFilters( 'test.filter', 'test' ), 'testca' );
     159                wp.hooks.removeAllFilters( 'test.filter' );
     160        } );
     161
     162        QUnit.test( 'remove all filter callbacks', function() {
     163                wp.hooks.addFilter( 'test.filter', filter_a );
     164                wp.hooks.addFilter( 'test.filter', filter_b, 2 );
     165                wp.hooks.addFilter( 'test.filter', filter_c, 8 );
     166
     167                wp.hooks.removeAllFilters( 'test.filter' );
     168                equal( wp.hooks.applyFilters( 'test.filter', 'test' ), 'test' );
     169        } );
     170
     171        // Test doingAction, didAction, hasAction.
     172        QUnit.test( 'Test doingAction, didAction and hasAction.', function() {
     173
     174                // Reset state for testing.
     175                wp.hooks.removeAllActions( 'test.action' );
     176                wp.hooks.addAction( 'another.action', function(){} );
     177                wp.hooks.doAction( 'another.action' );
     178
     179                // Verify no action is running yet.
     180                ok( ! wp.hooks.doingAction( 'test.action' ), 'The test.action is not running.' );
     181                equal( wp.hooks.didAction( 'new.test.action' ), 0, 'The test.action has not run.' );
     182                ok( ! wp.hooks.hasAction( 'test.action' ), 'The test.action is not registered.' );
     183
     184                wp.hooks.addAction( 'test.action', action_a );
     185
     186                // Verify action added, not running yet.
     187                ok( ! wp.hooks.doingAction( 'test.action' ), 'The test.action is not running.' );
     188                equal( wp.hooks.didAction( 'test.action' ), 0, 'The test.action has not run.' );
     189                ok( wp.hooks.hasAction( 'test.action' ), 'The test.action is registered.' );
     190
     191                wp.hooks.doAction( 'test.action' );
     192
     193                // Verify action added and running.
     194                equal( wp.hooks.didAction( 'test.action' ), 1, 'The test.action has run once.' );
     195                ok( wp.hooks.hasAction( 'test.action' ), 'The test.action is registered.' );
     196
     197                wp.hooks.doAction( 'test.action' );
     198                equal( wp.hooks.didAction( 'test.action' ), 2, 'The test.action has run twice.' );
     199
     200                wp.hooks.removeAllActions( 'test.action' );
     201
     202                // Verify state is reset appropriately.
     203                equal( wp.hooks.didAction( 'test.action' ), 2, 'The test.action has run twice.' );
     204                ok( ! wp.hooks.hasAction( 'test.action' ), 'The test.action is not registered.' );
     205
     206                wp.hooks.doAction( 'another.action' );
     207                ok( ! wp.hooks.doingAction( 'test.action' ), 'The test.action is running.' );
     208
     209                // Verify hasAction returns false when no matching action.
     210                ok( ! wp.hooks.hasAction( 'notatest.action' ), 'The notatest.action is registered.' );
     211
     212        } );
     213
     214        QUnit.test( 'Verify doingFilter, didFilter and hasFilter.', function() {
     215                expect( 4 );
     216                wp.hooks.addFilter( 'runtest.filter', filter_check );
     217
     218                // Verify filter added and running.
     219                var test = wp.hooks.applyFilters( 'runtest.filter', true );
     220                equal( wp.hooks.didFilter( 'runtest.filter' ), 1, 'The runtest.filter has run once.' );
     221                ok( wp.hooks.hasFilter( 'runtest.filter' ), 'The runtest.filter is registered.' );
     222                ok( ! wp.hooks.hasFilter( 'notatest.filter' ), 'The notatest.filter is not registered.' );
     223
     224                wp.hooks.removeAllFilters( 'runtest.filter' );
     225        } );
     226
     227} )( window.QUnit );