1
|
|
|
/* This file is based on WebProfilerBundle/Resources/views/Profiler/base_js.html.twig. |
2
|
|
|
If you make any change in this file, verify the same change is needed in the other file. */ |
3
|
|
|
/*<![CDATA[*/ |
4
|
|
|
if (typeof Sfjs === 'undefined') { |
|
|
|
|
5
|
|
|
Sfjs = (function() { |
|
|
|
|
6
|
|
|
"use strict"; |
7
|
|
|
|
8
|
|
|
if ('classList' in document.documentElement) { |
9
|
|
|
var hasClass = function (el, cssClass) { return el.classList.contains(cssClass); }; |
10
|
|
|
var removeClass = function(el, cssClass) { el.classList.remove(cssClass); }; |
11
|
|
|
var addClass = function(el, cssClass) { el.classList.add(cssClass); }; |
12
|
|
|
var toggleClass = function(el, cssClass) { el.classList.toggle(cssClass); }; |
13
|
|
|
} else { |
14
|
|
|
var hasClass = function (el, cssClass) { return el.className.match(new RegExp('\\b' + cssClass + '\\b')); }; |
|
|
|
|
15
|
|
|
var removeClass = function(el, cssClass) { el.className = el.className.replace(new RegExp('\\b' + cssClass + '\\b'), ' '); }; |
|
|
|
|
16
|
|
|
var addClass = function(el, cssClass) { if (!hasClass(el, cssClass)) { el.className += " " + cssClass; } }; |
|
|
|
|
17
|
|
|
var toggleClass = function(el, cssClass) { hasClass(el, cssClass) ? removeClass(el, cssClass) : addClass(el, cssClass); }; |
|
|
|
|
18
|
|
|
} |
19
|
|
|
|
20
|
|
|
var addEventListener; |
21
|
|
|
|
22
|
|
|
var el = document.createElement('div'); |
23
|
|
|
if (!('addEventListener' in el)) { |
24
|
|
|
addEventListener = function (element, eventName, callback) { |
25
|
|
|
element.attachEvent('on' + eventName, callback); |
26
|
|
|
}; |
27
|
|
|
} else { |
28
|
|
|
addEventListener = function (element, eventName, callback) { |
29
|
|
|
element.addEventListener(eventName, callback, false); |
30
|
|
|
}; |
31
|
|
|
} |
32
|
|
|
|
33
|
|
|
if (navigator.clipboard) { |
|
|
|
|
34
|
|
|
document.querySelectorAll('[data-clipboard-text]').forEach(function(element) { |
35
|
|
|
removeClass(element, 'hidden'); |
36
|
|
|
element.addEventListener('click', function() { |
37
|
|
|
navigator.clipboard.writeText(element.getAttribute('data-clipboard-text')); |
|
|
|
|
38
|
|
|
}) |
39
|
|
|
}); |
40
|
|
|
} |
41
|
|
|
|
42
|
|
|
return { |
43
|
|
|
addEventListener: addEventListener, |
44
|
|
|
|
45
|
|
|
createTabs: function() { |
46
|
|
|
var tabGroups = document.querySelectorAll('.sf-tabs:not([data-processed=true])'); |
47
|
|
|
|
48
|
|
|
/* create the tab navigation for each group of tabs */ |
49
|
|
|
for (var i = 0; i < tabGroups.length; i++) { |
50
|
|
|
var tabs = tabGroups[i].querySelectorAll(':scope > .tab'); |
51
|
|
|
var tabNavigation = document.createElement('ul'); |
52
|
|
|
tabNavigation.className = 'tab-navigation'; |
53
|
|
|
|
54
|
|
|
var selectedTabId = 'tab-' + i + '-0'; /* select the first tab by default */ |
55
|
|
|
for (var j = 0; j < tabs.length; j++) { |
56
|
|
|
var tabId = 'tab-' + i + '-' + j; |
57
|
|
|
var tabTitle = tabs[j].querySelector('.tab-title').innerHTML; |
58
|
|
|
|
59
|
|
|
var tabNavigationItem = document.createElement('li'); |
60
|
|
|
tabNavigationItem.setAttribute('data-tab-id', tabId); |
61
|
|
|
if (hasClass(tabs[j], 'active')) { selectedTabId = tabId; } |
62
|
|
|
if (hasClass(tabs[j], 'disabled')) { addClass(tabNavigationItem, 'disabled'); } |
63
|
|
|
tabNavigationItem.innerHTML = tabTitle; |
64
|
|
|
tabNavigation.appendChild(tabNavigationItem); |
65
|
|
|
|
66
|
|
|
var tabContent = tabs[j].querySelector('.tab-content'); |
67
|
|
|
tabContent.parentElement.setAttribute('id', tabId); |
68
|
|
|
} |
69
|
|
|
|
70
|
|
|
tabGroups[i].insertBefore(tabNavigation, tabGroups[i].firstChild); |
71
|
|
|
addClass(document.querySelector('[data-tab-id="' + selectedTabId + '"]'), 'active'); |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
/* display the active tab and add the 'click' event listeners */ |
75
|
|
|
for (i = 0; i < tabGroups.length; i++) { |
76
|
|
|
tabNavigation = tabGroups[i].querySelectorAll(':scope >.tab-navigation li'); |
77
|
|
|
|
78
|
|
|
for (j = 0; j < tabNavigation.length; j++) { |
79
|
|
|
tabId = tabNavigation[j].getAttribute('data-tab-id'); |
80
|
|
|
document.getElementById(tabId).querySelector('.tab-title').className = 'hidden'; |
81
|
|
|
|
82
|
|
|
if (hasClass(tabNavigation[j], 'active')) { |
83
|
|
|
document.getElementById(tabId).className = 'block'; |
84
|
|
|
} else { |
85
|
|
|
document.getElementById(tabId).className = 'hidden'; |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
tabNavigation[j].addEventListener('click', function(e) { |
89
|
|
|
var activeTab = e.target || e.srcElement; |
90
|
|
|
|
91
|
|
|
/* needed because when the tab contains HTML contents, user can click */ |
92
|
|
|
/* on any of those elements instead of their parent '<li>' element */ |
93
|
|
|
while (activeTab.tagName.toLowerCase() !== 'li') { |
94
|
|
|
activeTab = activeTab.parentNode; |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/* get the full list of tabs through the parent of the active tab element */ |
98
|
|
|
var tabNavigation = activeTab.parentNode.children; |
99
|
|
|
for (var k = 0; k < tabNavigation.length; k++) { |
100
|
|
|
var tabId = tabNavigation[k].getAttribute('data-tab-id'); |
101
|
|
|
document.getElementById(tabId).className = 'hidden'; |
102
|
|
|
removeClass(tabNavigation[k], 'active'); |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
addClass(activeTab, 'active'); |
106
|
|
|
var activeTabId = activeTab.getAttribute('data-tab-id'); |
107
|
|
|
document.getElementById(activeTabId).className = 'block'; |
108
|
|
|
}); |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
tabGroups[i].setAttribute('data-processed', 'true'); |
112
|
|
|
} |
113
|
|
|
}, |
114
|
|
|
|
115
|
|
|
createToggles: function() { |
116
|
|
|
var toggles = document.querySelectorAll('.sf-toggle:not([data-processed=true])'); |
117
|
|
|
|
118
|
|
|
for (var i = 0; i < toggles.length; i++) { |
119
|
|
|
var elementSelector = toggles[i].getAttribute('data-toggle-selector'); |
120
|
|
|
var element = document.querySelector(elementSelector); |
121
|
|
|
|
122
|
|
|
addClass(element, 'sf-toggle-content'); |
123
|
|
|
|
124
|
|
|
if (toggles[i].hasAttribute('data-toggle-initial') && toggles[i].getAttribute('data-toggle-initial') == 'display') { |
125
|
|
|
addClass(toggles[i], 'sf-toggle-on'); |
126
|
|
|
addClass(element, 'sf-toggle-visible'); |
127
|
|
|
} else { |
128
|
|
|
addClass(toggles[i], 'sf-toggle-off'); |
129
|
|
|
addClass(element, 'sf-toggle-hidden'); |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
addEventListener(toggles[i], 'click', function(e) { |
133
|
|
|
e.preventDefault(); |
134
|
|
|
|
135
|
|
|
if ('' !== window.getSelection().toString()) { |
136
|
|
|
/* Don't do anything on text selection */ |
137
|
|
|
return; |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
var toggle = e.target || e.srcElement; |
141
|
|
|
|
142
|
|
|
/* needed because when the toggle contains HTML contents, user can click */ |
143
|
|
|
/* on any of those elements instead of their parent '.sf-toggle' element */ |
144
|
|
|
while (!hasClass(toggle, 'sf-toggle')) { |
145
|
|
|
toggle = toggle.parentNode; |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
var element = document.querySelector(toggle.getAttribute('data-toggle-selector')); |
149
|
|
|
|
150
|
|
|
toggleClass(toggle, 'sf-toggle-on'); |
151
|
|
|
toggleClass(toggle, 'sf-toggle-off'); |
152
|
|
|
toggleClass(element, 'sf-toggle-hidden'); |
153
|
|
|
toggleClass(element, 'sf-toggle-visible'); |
154
|
|
|
|
155
|
|
|
/* the toggle doesn't change its contents when clicking on it */ |
156
|
|
|
if (!toggle.hasAttribute('data-toggle-alt-content')) { |
157
|
|
|
return; |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
if (!toggle.hasAttribute('data-toggle-original-content')) { |
161
|
|
|
toggle.setAttribute('data-toggle-original-content', toggle.innerHTML); |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
var currentContent = toggle.innerHTML; |
165
|
|
|
var originalContent = toggle.getAttribute('data-toggle-original-content'); |
166
|
|
|
var altContent = toggle.getAttribute('data-toggle-alt-content'); |
167
|
|
|
toggle.innerHTML = currentContent !== altContent ? altContent : originalContent; |
168
|
|
|
}); |
169
|
|
|
|
170
|
|
|
/* Prevents from disallowing clicks on links inside toggles */ |
171
|
|
|
var toggleLinks = toggles[i].querySelectorAll('a'); |
172
|
|
|
for (var j = 0; j < toggleLinks.length; j++) { |
173
|
|
|
addEventListener(toggleLinks[j], 'click', function(e) { |
174
|
|
|
e.stopPropagation(); |
175
|
|
|
}); |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
/* Prevents from disallowing clicks on "copy to clipboard" elements inside toggles */ |
179
|
|
|
var copyToClipboardElements = toggles[i].querySelectorAll('span[data-clipboard-text]'); |
180
|
|
|
for (var k = 0; k < copyToClipboardElements.length; k++) { |
181
|
|
|
addEventListener(copyToClipboardElements[k], 'click', function(e) { |
182
|
|
|
e.stopPropagation(); |
183
|
|
|
}); |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
toggles[i].setAttribute('data-processed', 'true'); |
187
|
|
|
} |
188
|
|
|
}, |
189
|
|
|
|
190
|
|
|
createFilters: function() { |
191
|
|
|
document.querySelectorAll('[data-filters] [data-filter]').forEach(function (filter) { |
192
|
|
|
var filters = filter.closest('[data-filters]'), |
193
|
|
|
type = 'choice', |
194
|
|
|
name = filter.dataset.filter, |
195
|
|
|
ucName = name.charAt(0).toUpperCase()+name.slice(1), |
196
|
|
|
list = document.createElement('ul'), |
197
|
|
|
values = filters.dataset['filter'+ucName] || filters.querySelectorAll('[data-filter-'+name+']'), |
198
|
|
|
labels = {}, |
199
|
|
|
defaults = null, |
200
|
|
|
indexed = {}, |
201
|
|
|
processed = {}; |
202
|
|
|
if (typeof values === 'string') { |
203
|
|
|
type = 'level'; |
204
|
|
|
labels = values.split(','); |
205
|
|
|
values = values.toLowerCase().split(','); |
206
|
|
|
defaults = values.length - 1; |
207
|
|
|
} |
208
|
|
|
addClass(list, 'filter-list'); |
209
|
|
|
addClass(list, 'filter-list-'+type); |
210
|
|
|
values.forEach(function (value, i) { |
211
|
|
|
if (value instanceof HTMLElement) { |
|
|
|
|
212
|
|
|
value = value.dataset['filter'+ucName]; |
213
|
|
|
} |
214
|
|
|
if (value in processed) { |
215
|
|
|
return; |
216
|
|
|
} |
217
|
|
|
var option = document.createElement('li'), |
218
|
|
|
label = i in labels ? labels[i] : value, |
219
|
|
|
active = false, |
220
|
|
|
matches; |
221
|
|
|
if ('' === label) { |
222
|
|
|
option.innerHTML = '<em>(none)</em>'; |
223
|
|
|
} else { |
224
|
|
|
option.innerText = label; |
225
|
|
|
} |
226
|
|
|
option.dataset.filter = value; |
227
|
|
|
option.setAttribute('title', 1 === (matches = filters.querySelectorAll('[data-filter-'+name+'="'+value+'"]').length) ? 'Matches 1 row' : 'Matches '+matches+' rows'); |
228
|
|
|
indexed[value] = i; |
229
|
|
|
list.appendChild(option); |
230
|
|
|
addEventListener(option, 'click', function () { |
231
|
|
|
if ('choice' === type) { |
232
|
|
|
filters.querySelectorAll('[data-filter-'+name+']').forEach(function (row) { |
233
|
|
|
if (option.dataset.filter === row.dataset['filter'+ucName]) { |
234
|
|
|
toggleClass(row, 'filter-hidden-'+name); |
235
|
|
|
} |
236
|
|
|
}); |
237
|
|
|
toggleClass(option, 'active'); |
238
|
|
|
} else if ('level' === type) { |
239
|
|
|
if (i === this.parentNode.querySelectorAll('.active').length - 1) { |
240
|
|
|
return; |
241
|
|
|
} |
242
|
|
|
this.parentNode.querySelectorAll('li').forEach(function (currentOption, j) { |
243
|
|
|
if (j <= i) { |
244
|
|
|
addClass(currentOption, 'active'); |
245
|
|
|
if (i === j) { |
246
|
|
|
addClass(currentOption, 'last-active'); |
247
|
|
|
} else { |
248
|
|
|
removeClass(currentOption, 'last-active'); |
249
|
|
|
} |
250
|
|
|
} else { |
251
|
|
|
removeClass(currentOption, 'active'); |
252
|
|
|
removeClass(currentOption, 'last-active'); |
253
|
|
|
} |
254
|
|
|
}); |
255
|
|
|
filters.querySelectorAll('[data-filter-'+name+']').forEach(function (row) { |
256
|
|
|
if (i < indexed[row.dataset['filter'+ucName]]) { |
257
|
|
|
addClass(row, 'filter-hidden-'+name); |
258
|
|
|
} else { |
259
|
|
|
removeClass(row, 'filter-hidden-'+name); |
260
|
|
|
} |
261
|
|
|
}); |
262
|
|
|
} |
263
|
|
|
}); |
264
|
|
|
if ('choice' === type) { |
265
|
|
|
active = null === defaults || 0 <= defaults.indexOf(value); |
266
|
|
|
} else if ('level' === type) { |
267
|
|
|
active = i <= defaults; |
268
|
|
|
if (active && i === defaults) { |
269
|
|
|
addClass(option, 'last-active'); |
270
|
|
|
} |
271
|
|
|
} |
272
|
|
|
if (active) { |
273
|
|
|
addClass(option, 'active'); |
274
|
|
|
} else { |
275
|
|
|
filters.querySelectorAll('[data-filter-'+name+'="'+value+'"]').forEach(function (row) { |
276
|
|
|
toggleClass(row, 'filter-hidden-'+name); |
277
|
|
|
}); |
278
|
|
|
} |
279
|
|
|
processed[value] = true; |
280
|
|
|
}); |
281
|
|
|
|
282
|
|
|
if (1 < list.childNodes.length) { |
283
|
|
|
filter.appendChild(list); |
284
|
|
|
filter.dataset.filtered = ''; |
285
|
|
|
} |
286
|
|
|
}); |
287
|
|
|
} |
288
|
|
|
}; |
289
|
|
|
})(); |
290
|
|
|
|
291
|
|
|
Sfjs.addEventListener(document, 'DOMContentLoaded', function() { |
292
|
|
|
Sfjs.createTabs(); |
293
|
|
|
Sfjs.createToggles(); |
294
|
|
|
Sfjs.createFilters(); |
295
|
|
|
}); |
296
|
|
|
} |
297
|
|
|
/*]]>*/ |
298
|
|
|
|
This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.
To learn more about declaring variables in Javascript, see the MDN.