-
Notifications
You must be signed in to change notification settings - Fork 295
/
Copy pathmisc.js
203 lines (182 loc) · 6.56 KB
/
misc.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
define([
'dojo/has'
], function (has) {
// summary:
// This module defines miscellaneous utility methods for purposes of
// adding styles, and throttling/debouncing function calls.
// establish an extra stylesheet which addCssRule calls will use,
// plus an array to track actual indices in stylesheet for removal
var extraRules = [],
extraSheet,
removeMethod,
rulesProperty,
invalidCssChars = /([^A-Za-z0-9_\u00A0-\uFFFF-])/g,
delayCallback = setTimeout,
cancelDelay = clearTimeout;
has.add('requestidlecallback', function (global) {
return typeof global.requestIdleCallback === 'function';
});
// The presence of the 'requestIdleCallback' method indicates a browser that might
// performance optimize code by delaying execution of the callback passed to
// 'setTimeout', so use 'requestIdleCallback' to improve the likelihood of the
// callback being executed in a timely manner.
// This is not a perfect solution, but has worked well in testing.
// requestIdleCallback is designed to be called successively, performing progressive chunks
// of computation each time until the task is complete.
// setTimeout executes its callback when delay has transpired, *or later*
// requestIdleCallback executes its callback when delay has transpired, *or sooner*
// Fixes https://github.com/SitePen/dgrid/issues/1351
// if (has('requestidlecallback')) {
// delayCallback = function (callback, delay) {
// return requestIdleCallback(callback, { timeout: delay });
// };
// cancelDelay = cancelIdleCallback;
// }
function removeRule(index) {
// Function called by the remove method on objects returned by addCssRule.
var realIndex = extraRules[index],
i, l;
if (realIndex === undefined) {
return; // already removed
}
// remove rule indicated in internal array at index
extraSheet[removeMethod](realIndex);
// Clear internal array item representing rule that was just deleted.
// NOTE: we do NOT splice, since the point of this array is specifically
// to negotiate the splicing that occurs in the stylesheet itself!
extraRules[index] = undefined;
// Then update array items as necessary to downshift remaining rule indices.
// Can start at index + 1, since array is sparse but strictly increasing.
for (i = index + 1, l = extraRules.length; i < l; i++) {
if (extraRules[i] > realIndex) {
extraRules[i]--;
}
}
}
var util = {
// Throttle/debounce functions
defaultDelay: 15,
throttle: function (cb, context, delay) {
// summary:
// Returns a function which calls the given callback at most once per
// delay milliseconds. (Inspired by plugd)
var ran = false;
delay = delay || util.defaultDelay;
return function () {
if (ran) {
return;
}
ran = true;
cb.apply(context, arguments);
delayCallback(function () {
ran = false;
}, delay);
};
},
throttleDelayed: function (cb, context, delay) {
// summary:
// Like throttle, except that the callback runs after the delay,
// rather than before it.
var ran = false;
delay = delay || util.defaultDelay;
return function () {
if (ran) {
return;
}
ran = true;
var a = arguments;
delayCallback(function () {
ran = false;
cb.apply(context, a);
}, delay);
};
},
debounce: function (cb, context, delay) {
// summary:
// Returns a function which calls the given callback only after a
// certain time has passed without successive calls. (Inspired by plugd)
var timer;
delay = delay || util.defaultDelay;
return function () {
if (timer) {
cancelDelay(timer);
timer = null;
}
var a = arguments;
timer = delayCallback(function () {
timer = null;
cb.apply(context, a);
}, delay);
};
},
// Iterative functions
each: function (arrayOrObject, callback, context) {
// summary:
// Given an array or object, iterates through its keys.
// Does not use hasOwnProperty (since even Dojo does not
// consistently use it), but will iterate using a for or for-in
// loop as appropriate.
var i, len;
if (!arrayOrObject) {
return;
}
if (typeof arrayOrObject.length === 'number') {
for (i = 0, len = arrayOrObject.length; i < len; i++) {
callback.call(context, arrayOrObject[i], i, arrayOrObject);
}
}
else {
for (i in arrayOrObject) {
callback.call(context, arrayOrObject[i], i, arrayOrObject);
}
}
},
// CSS-related functions
addCssRule: function (selector, css) {
// summary:
// Dynamically adds a style rule to the document. Returns an object
// with a remove method which can be called to later remove the rule.
if (!extraSheet) {
// First time, create an extra stylesheet for adding rules
extraSheet = document.createElement('style');
document.getElementsByTagName('head')[0].appendChild(extraSheet);
// Keep reference to actual StyleSheet object (`styleSheet` for IE < 9)
extraSheet = extraSheet.sheet || extraSheet.styleSheet;
// Store name of method used to remove rules (`removeRule` for IE < 9)
removeMethod = extraSheet.deleteRule ? 'deleteRule' : 'removeRule';
// Store name of property used to access rules (`rules` for IE < 9)
rulesProperty = extraSheet.cssRules ? 'cssRules' : 'rules';
}
var index = extraRules.length;
extraRules[index] = (extraSheet.cssRules || extraSheet.rules).length;
extraSheet.addRule ?
extraSheet.addRule(selector, css) :
extraSheet.insertRule(selector + '{' + css + '}', extraRules[index]);
return {
get: function (prop) {
return extraSheet[rulesProperty][extraRules[index]].style[prop];
},
set: function (prop, value) {
if (typeof extraRules[index] !== 'undefined') {
extraSheet[rulesProperty][extraRules[index]].style[prop] = value;
}
},
remove: function () {
removeRule(index);
}
};
},
escapeCssIdentifier: function (id, replace) {
// summary:
// Escapes normally-invalid characters in a CSS identifier (such as . or :);
// see http://www.w3.org/TR/CSS2/syndata.html#value-def-identifier
// id: String
// CSS identifier (e.g. tag name, class, or id) to be escaped
// replace: String?
// If specified, indicates that invalid characters should be
// replaced by the given string rather than being escaped
return typeof id === 'string' ? id.replace(invalidCssChars, replace || '\\$1') : id;
}
};
return util;
});