bug #24281 [TwigBundle] Remove profiler related scripting (ro0NL, javiereguiluz)

This PR was merged into the 3.3 branch.

Discussion
----------

[TwigBundle] Remove profiler related scripting

| Q             | A
| ------------- | ---
| Branch?       | 3.3
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #... <!-- #-prefixed issue number(s), if any -->
| License       | MIT
| Doc PR        | symfony/symfony-docs#... <!--highly recommended for new features-->

For sanity.

Also in case of an exception page we conflict with the profiler scripting/css.

```
Uncaught TypeError: Cannot set property 'className' of null
```

Happens because `Sfjs.createTabs` from the profiler tries to process tabs again, which twig has already done. The code doesnt handle this gracefully.

In case of ajax request (edgy yes) we see the CSS conflicting;

![image](https://user-images.githubusercontent.com/1047696/30712781-7680c8d2-9f0d-11e7-8a6c-27f460c1e780.png)

Note the table borders. Not sure how and if we want to solve this nor what it might affect otherwise; open for now.

Commits
-------

eb520e1e5b Minor reword
02dcdca014 [TwigBundle] Remove profiler related scripting
This commit is contained in:
Fabien Potencier 2017-09-26 16:51:28 -07:00
commit beb3fe1b2b
2 changed files with 6 additions and 364 deletions

View File

@ -1,5 +1,5 @@
{# This file is duplicated in WebProfilerBundle/Resources/views/Profiler/base_js.html.twig.
If you make any change in this file, do the same change in the other file. #}
{# This file is based on WebProfilerBundle/Resources/views/Profiler/base_js.html.twig.
If you make any change in this file, verify the same change is needed in the other file. #}
<script{% if csp_script_nonce is defined and csp_script_nonce %} nonce={{ csp_script_nonce }}{% endif %}>/*<![CDATA[*/
{# Caution: the contents of this file are processed by Twig before loading
them as JavaScript source code. Always use '/*' comments instead
@ -8,9 +8,7 @@
Sfjs = (function() {
"use strict";
var classListIsSupported = 'classList' in document.documentElement;
if (classListIsSupported) {
if ('classList' in document.documentElement) {
var hasClass = function (el, cssClass) { return el.classList.contains(cssClass); };
var removeClass = function(el, cssClass) { el.classList.remove(cssClass); };
var addClass = function(el, cssClass) { el.classList.add(cssClass); };
@ -22,206 +20,6 @@
var toggleClass = function(el, cssClass) { hasClass(el, cssClass) ? removeClass(el, cssClass) : addClass(el, cssClass); };
}
var noop = function() {};
var profilerStorageKey = 'sf2/profiler/';
var request = function(url, onSuccess, onError, payload, options) {
var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
options = options || {};
options.maxTries = options.maxTries || 0;
xhr.open(options.method || 'GET', url, true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(state) {
if (4 !== xhr.readyState) {
return null;
}
if (xhr.status == 404 && options.maxTries > 1) {
setTimeout(function(){
options.maxTries--;
request(url, onSuccess, onError, payload, options);
}, 500);
return null;
}
if (200 === xhr.status) {
(onSuccess || noop)(xhr);
} else {
(onError || noop)(xhr);
}
};
xhr.send(payload || '');
};
var getPreference = function(name) {
if (!window.localStorage) {
return null;
}
return localStorage.getItem(profilerStorageKey + name);
};
var setPreference = function(name, value) {
if (!window.localStorage) {
return null;
}
localStorage.setItem(profilerStorageKey + name, value);
};
var requestStack = [];
var extractHeaders = function(xhr, stackElement) {
/* Here we avoid to call xhr.getResponseHeader in order to */
/* prevent polluting the console with CORS security errors */
var allHeaders = xhr.getAllResponseHeaders();
var ret;
if (ret = allHeaders.match(/^x-debug-token:\s+(.*)$/im)) {
stackElement.profile = ret[1];
}
if (ret = allHeaders.match(/^x-debug-token-link:\s+(.*)$/im)) {
stackElement.profilerUrl = ret[1];
}
};
var successStreak = 4;
var pendingRequests = 0;
var renderAjaxRequests = function() {
var requestCounter = document.querySelector('.sf-toolbar-ajax-request-counter');
if (!requestCounter) {
return;
}
requestCounter.textContent = requestStack.length;
var infoSpan = document.querySelector(".sf-toolbar-ajax-info");
if (infoSpan) {
infoSpan.textContent = requestStack.length + ' AJAX request' + (requestStack.length !== 1 ? 's' : '');
}
var ajaxToolbarPanel = document.querySelector('.sf-toolbar-block-ajax');
if (requestStack.length) {
ajaxToolbarPanel.style.display = 'block';
} else {
ajaxToolbarPanel.style.display = 'none';
}
if (pendingRequests > 0) {
addClass(ajaxToolbarPanel, 'sf-ajax-request-loading');
} else if (successStreak < 4) {
addClass(ajaxToolbarPanel, 'sf-toolbar-status-red');
removeClass(ajaxToolbarPanel, 'sf-ajax-request-loading');
} else {
removeClass(ajaxToolbarPanel, 'sf-ajax-request-loading');
removeClass(ajaxToolbarPanel, 'sf-toolbar-status-red');
}
};
var startAjaxRequest = function(index) {
var tbody = document.querySelector('.sf-toolbar-ajax-request-list');
if (!tbody) {
return;
}
var request = requestStack[index];
pendingRequests++;
var row = document.createElement('tr');
request.DOMNode = row;
var methodCell = document.createElement('td');
methodCell.textContent = request.method;
row.appendChild(methodCell);
var typeCell = document.createElement('td');
typeCell.textContent = request.type;
row.appendChild(typeCell);
var statusCodeCell = document.createElement('td');
var statusCode = document.createElement('span');
statusCode.textContent = 'n/a';
statusCodeCell.appendChild(statusCode);
row.appendChild(statusCodeCell);
var pathCell = document.createElement('td');
pathCell.className = 'sf-ajax-request-url';
if ('GET' === request.method) {
var pathLink = document.createElement('a');
pathLink.setAttribute('href', request.url);
pathLink.textContent = request.url;
pathCell.appendChild(pathLink);
} else {
pathCell.textContent = request.url;
}
pathCell.setAttribute('title', request.url);
row.appendChild(pathCell);
var durationCell = document.createElement('td');
durationCell.className = 'sf-ajax-request-duration';
durationCell.textContent = 'n/a';
row.appendChild(durationCell);
var profilerCell = document.createElement('td');
profilerCell.textContent = 'n/a';
row.appendChild(profilerCell);
row.className = 'sf-ajax-request sf-ajax-request-loading';
tbody.insertBefore(row, tbody.firstChild);
renderAjaxRequests();
};
var finishAjaxRequest = function(index) {
var request = requestStack[index];
if (!request.DOMNode) {
return;
}
pendingRequests--;
var row = request.DOMNode;
/* Unpack the children from the row */
var methodCell = row.children[0];
var statusCodeCell = row.children[2];
var statusCodeElem = statusCodeCell.children[0];
var durationCell = row.children[4];
var profilerCell = row.children[5];
if (request.error) {
row.className = 'sf-ajax-request sf-ajax-request-error';
methodCell.className = 'sf-ajax-request-error';
successStreak = 0;
} else {
row.className = 'sf-ajax-request sf-ajax-request-ok';
successStreak++;
}
if (request.statusCode) {
if (request.statusCode < 300) {
statusCodeElem.setAttribute('class', 'sf-toolbar-status');
} else if (request.statusCode < 400) {
statusCodeElem.setAttribute('class', 'sf-toolbar-status sf-toolbar-status-yellow');
} else {
statusCodeElem.setAttribute('class', 'sf-toolbar-status sf-toolbar-status-red');
}
statusCodeElem.textContent = request.statusCode;
} else {
statusCodeElem.setAttribute('class', 'sf-toolbar-status sf-toolbar-status-red');
}
if (request.duration) {
durationCell.textContent = request.duration + 'ms';
}
if (request.profilerUrl) {
profilerCell.textContent = '';
var profilerLink = document.createElement('a');
profilerLink.setAttribute('href', request.profilerUrl);
profilerLink.textContent = request.profile;
profilerCell.appendChild(profilerLink);
}
renderAjaxRequests();
};
var addEventListener;
var el = document.createElement('div');
@ -235,163 +33,9 @@
};
}
{% if excluded_ajax_paths is defined %}
if (window.fetch && window.fetch.polyfill === undefined) {
var oldFetch = window.fetch;
window.fetch = function () {
var promise = oldFetch.apply(this, arguments);
var url = arguments[0];
var params = arguments[1];
var paramType = Object.prototype.toString.call(arguments[0]);
if (paramType === '[object Request]') {
url = arguments[0].url;
params = {
method: arguments[0].method,
credentials: arguments[0].credentials,
headers: arguments[0].headers,
mode: arguments[0].mode,
redirect: arguments[0].redirect
};
}
if (!url.match(new RegExp({{ excluded_ajax_paths|json_encode|raw }}))) {
var method = 'GET';
if (params && params.method !== undefined) {
method = params.method;
}
var stackElement = {
error: false,
url: url,
method: method,
type: 'fetch',
start: new Date()
};
var idx = requestStack.push(stackElement) - 1;
promise.then(function (r) {
stackElement.duration = new Date() - stackElement.start;
stackElement.error = r.status < 200 || r.status >= 400;
stackElement.statusCode = r.status;
stackElement.profile = r.headers.get('x-debug-token');
stackElement.profilerUrl = r.headers.get('x-debug-token-link');
finishAjaxRequest(idx);
}, function (e){
stackElement.error = true;
finishAjaxRequest(idx);
});
startAjaxRequest(idx);
}
return promise;
};
}
if (window.XMLHttpRequest && XMLHttpRequest.prototype.addEventListener) {
var proxied = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {
var self = this;
/* prevent logging AJAX calls to static and inline files, like templates */
var path = url;
if (url.substr(0, 1) === '/') {
if (0 === url.indexOf('{{ request.basePath|e('js') }}')) {
path = url.substr({{ request.basePath|length }});
}
}
else if (0 === url.indexOf('{{ (request.schemeAndHttpHost ~ request.basePath)|e('js') }}')) {
path = url.substr({{ (request.schemeAndHttpHost ~ request.basePath)|length }});
}
if (!path.match(new RegExp({{ excluded_ajax_paths|json_encode|raw }}))) {
var stackElement = {
error: false,
url: url,
method: method,
type: 'xhr',
start: new Date()
};
var idx = requestStack.push(stackElement) - 1;
this.addEventListener('readystatechange', function() {
if (self.readyState == 4) {
stackElement.duration = new Date() - stackElement.start;
stackElement.error = self.status < 200 || self.status >= 400;
stackElement.statusCode = self.status;
extractHeaders(self, stackElement);
finishAjaxRequest(idx);
}
}, false);
startAjaxRequest(idx);
}
proxied.apply(this, Array.prototype.slice.call(arguments));
};
}
{% endif %}
return {
hasClass: hasClass,
removeClass: removeClass,
addClass: addClass,
toggleClass: toggleClass,
getPreference: getPreference,
setPreference: setPreference,
addEventListener: addEventListener,
request: request,
renderAjaxRequests: renderAjaxRequests,
load: function(selector, url, onSuccess, onError, options) {
var el = document.getElementById(selector);
if (el && el.getAttribute('data-sfurl') !== url) {
request(
url,
function(xhr) {
el.innerHTML = xhr.responseText;
el.setAttribute('data-sfurl', url);
removeClass(el, 'loading');
for (var i = 0; i < requestStack.length; i++) {
startAjaxRequest(i);
if (requestStack[i].duration) {
finishAjaxRequest(i);
}
}
(onSuccess || noop)(xhr, el);
},
function(xhr) { (onError || noop)(xhr, el); },
'',
options
);
}
return this;
},
toggle: function(selector, elOn, elOff) {
var tmp = elOn.style.display,
el = document.getElementById(selector);
elOn.style.display = elOff.style.display;
elOff.style.display = tmp;
if (el) {
el.style.display = 'none' === tmp ? 'none' : 'block';
}
return this;
},
createTabs: function() {
var tabGroups = document.querySelectorAll('.sf-tabs');

View File

@ -1,5 +1,5 @@
{# This file is duplicated in TwigBundle/Resources/views/base_js.html.twig. If you
make any change in this file, do the same change in the other file. #}
{# This file is partially duplicated in TwigBundle/Resources/views/base_js.html.twig. If you
make any change in this file, verify the same change is needed in the other file. #}
<script{% if csp_script_nonce is defined and csp_script_nonce %} nonce={{ csp_script_nonce }}{% endif %}>/*<![CDATA[*/
{# Caution: the contents of this file are processed by Twig before loading
them as JavaScript source code. Always use '/*' comments instead
@ -8,9 +8,7 @@
Sfjs = (function() {
"use strict";
var classListIsSupported = 'classList' in document.documentElement;
if (classListIsSupported) {
if ('classList' in document.documentElement) {
var hasClass = function (el, cssClass) { return el.classList.contains(cssClass); };
var removeClass = function(el, cssClass) { el.classList.remove(cssClass); };
var addClass = function(el, cssClass) { el.classList.add(cssClass); };