Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
// This file is part of Moodle - http://moodle.org/
2
//
3
// Moodle is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, either version 3 of the License, or
6
// (at your option) any later version.
7
//
8
// Moodle is distributed in the hope that it will be useful,
9
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
// GNU General Public License for more details.
12
//
13
// You should have received a copy of the GNU General Public License
14
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
15
 
16
/**
17
 * Utility functions.
18
 *
19
 * @module core/utils
20
 * @copyright  2019 Ryan Wyllie <ryan@moodle.com>
21
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22
 */
23
 
24
import Pending from 'core/pending';
1441 ariadna 25
import jQuery from 'jquery';
1 efrain 26
 
27
 /**
28
  * Create a wrapper function to throttle the execution of the given
29
  *
30
  * function to at most once every specified period.
31
  *
32
  * If the function is attempted to be executed while it's in cooldown
33
  * (during the wait period) then it'll immediately execute again as
34
  * soon as the cooldown is over.
35
  *
36
  * @method
37
  * @param {Function} func The function to throttle
38
  * @param {Number} wait The number of milliseconds to wait between executions
39
  * @return {Function}
40
  */
41
export const throttle = (func, wait) => {
42
    let onCooldown = false;
43
    let runAgain = null;
44
    const run = function(...args) {
45
        if (runAgain === null) {
46
            // This is the first time the function has been called.
47
            runAgain = false;
48
        } else {
49
            // This function has been called a second time during the wait period
50
            // so re-run it once the wait period is over.
51
            runAgain = true;
52
        }
53
 
54
        if (onCooldown) {
55
            // Function has already run for this wait period.
56
            return;
57
        }
58
 
59
        func.apply(this, args);
60
        onCooldown = true;
61
 
62
        setTimeout(() => {
63
            const recurse = runAgain;
64
            onCooldown = false;
65
            runAgain = null;
66
 
67
            if (recurse) {
68
                run(args);
69
            }
70
        }, wait);
71
    };
72
 
73
    return run;
74
};
75
 
76
/**
77
 * @property {Map} debounceMap A map of functions to their debounced pending promises.
78
 */
79
const debounceMap = new Map();
80
 
81
/**
82
 * Create a wrapper function to debounce the execution of the given
83
 * function. Each attempt to execute the function will reset the cooldown
84
 * period.
85
 *
86
 * @method
87
 * @param {Function} func The function to debounce
88
 * @param {Number} wait The number of milliseconds to wait after the final attempt to execute
89
 * @param {Object} [options]
90
 * @param {boolean} [options.pending=false] Whether to wrap the debounced method in a pending promise
91
 * @param {boolean} [options.cancel=false] Whether to add a cancel method to the debounced function
92
 * @return {Function}
93
 */
94
export const debounce = (
95
    func,
96
    wait,
97
    {
98
        pending = false,
99
        cancel = false,
100
    } = {},
101
) => {
102
    let timeout = null;
103
 
104
    const returnedFunction = (...args) => {
105
        if (pending && !debounceMap.has(returnedFunction)) {
106
            debounceMap.set(returnedFunction, new Pending('core/utils:debounce'));
107
        }
108
        clearTimeout(timeout);
109
        timeout = setTimeout(async () => {
110
            // Get the current pending promise and immediately empty it.
111
            // This is important to allow the function to be debounced again as soon as possible.
112
            // We do not resolve it until later - but that's fine because the promise is appropriately scoped.
113
            const pendingPromise = debounceMap.get(returnedFunction);
114
            debounceMap.delete(returnedFunction);
115
 
116
            // Allow the debounced function to return a Promise.
117
            // This ensures that Behat will not continue until the function has finished executing.
118
            await func.apply(this, args);
119
 
120
            // Resolve the pending promise if it exists.
121
            pendingPromise?.resolve();
122
        }, wait);
123
    };
124
 
125
    if (cancel) {
126
        returnedFunction.cancel = () => {
127
            const pendingPromise = debounceMap.get(returnedFunction);
128
            pendingPromise?.resolve();
129
            clearTimeout(timeout);
130
        };
131
    }
132
 
133
    return returnedFunction;
134
};
135
 
136
/**
137
 * Normalise the provided component such that '', 'moodle', and 'core' are treated consistently.
138
 *
139
 * @param   {String} component
140
 * @returns {String}
141
 */
142
export const getNormalisedComponent = (component) => {
143
    if (component) {
144
        if (component !== 'moodle' && component !== 'core') {
145
            return component;
146
        }
147
    }
148
 
149
    return 'core';
150
};
1441 ariadna 151
 
152
/**
153
 * Wrap a Native Promise in a jQuery Whenable for b/c.
154
 *
155
 * @param {*} promise
156
 * @returns {jQuery}
157
 */
158
export const wrapPromiseInWhenable = (promise) => jQuery.when(promise);