298 行
12KB

  1. (function () {
  2. 'use strict';
  3. var findToolbar = function () {
  4. return document.querySelector('#yii-debug-toolbar');
  5. },
  6. ajax = function (url, settings) {
  7. var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
  8. settings = settings || {};
  9. xhr.open(settings.method || 'GET', url, true);
  10. xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
  11. xhr.setRequestHeader('Accept', 'text/html');
  12. xhr.onreadystatechange = function (state) {
  13. if (xhr.readyState === 4) {
  14. if (xhr.status === 200 && settings.success) {
  15. settings.success(xhr);
  16. } else if (xhr.status != 200 && settings.error) {
  17. settings.error(xhr);
  18. }
  19. }
  20. };
  21. xhr.send(settings.data || '');
  22. },
  23. url,
  24. div,
  25. toolbarEl = findToolbar(),
  26. toolbarAnimatingClass = 'yii-debug-toolbar_animating',
  27. barSelector = '.yii-debug-toolbar__bar',
  28. viewSelector = '.yii-debug-toolbar__view',
  29. blockSelector = '.yii-debug-toolbar__block',
  30. toggleSelector = '.yii-debug-toolbar__toggle',
  31. externalSelector = '.yii-debug-toolbar__external',
  32. CACHE_KEY = 'yii-debug-toolbar',
  33. ACTIVE_STATE = 'active',
  34. animationTime = 300,
  35. activeClass = 'yii-debug-toolbar_active',
  36. iframeActiveClass = 'yii-debug-toolbar_iframe_active',
  37. iframeAnimatingClass = 'yii-debug-toolbar_iframe_animating',
  38. titleClass = 'yii-debug-toolbar__title',
  39. blockClass = 'yii-debug-toolbar__block',
  40. blockActiveClass = 'yii-debug-toolbar__block_active',
  41. requestStack = [];
  42. if (toolbarEl) {
  43. url = toolbarEl.getAttribute('data-url');
  44. ajax(url, {
  45. success: function (xhr) {
  46. div = document.createElement('div');
  47. div.innerHTML = xhr.responseText;
  48. toolbarEl.parentNode && toolbarEl.parentNode.replaceChild(div, toolbarEl);
  49. showToolbar(findToolbar());
  50. },
  51. error: function (xhr) {
  52. toolbarEl.innerHTML = xhr.responseText;
  53. }
  54. });
  55. }
  56. function showToolbar(toolbarEl) {
  57. var barEl = toolbarEl.querySelector(barSelector),
  58. viewEl = toolbarEl.querySelector(viewSelector),
  59. toggleEl = toolbarEl.querySelector(toggleSelector),
  60. externalEl = toolbarEl.querySelector(externalSelector),
  61. blockEls = barEl.querySelectorAll(blockSelector),
  62. iframeEl = viewEl.querySelector('iframe'),
  63. iframeHeight = function () {
  64. return (window.innerHeight * 0.7) + 'px';
  65. },
  66. isIframeActive = function () {
  67. return toolbarEl.classList.contains(iframeActiveClass);
  68. },
  69. showIframe = function (href) {
  70. toolbarEl.classList.add(iframeAnimatingClass);
  71. toolbarEl.classList.add(iframeActiveClass);
  72. iframeEl.src = externalEl.href = href;
  73. viewEl.style.height = iframeHeight();
  74. setTimeout(function() {
  75. toolbarEl.classList.remove(iframeAnimatingClass);
  76. }, animationTime);
  77. },
  78. hideIframe = function () {
  79. toolbarEl.classList.add(iframeAnimatingClass);
  80. toolbarEl.classList.remove(iframeActiveClass);
  81. removeActiveBlocksCls();
  82. externalEl.href = '#';
  83. viewEl.style.height = '';
  84. setTimeout(function() {
  85. toolbarEl.classList.remove(iframeAnimatingClass);
  86. }, animationTime);
  87. },
  88. removeActiveBlocksCls = function () {
  89. [].forEach.call(blockEls, function (el) {
  90. el.classList.remove(blockActiveClass);
  91. });
  92. },
  93. toggleToolbarClass = function (className) {
  94. toolbarEl.classList.add(toolbarAnimatingClass);
  95. if (toolbarEl.classList.contains(className)) {
  96. toolbarEl.classList.remove(className);
  97. } else {
  98. toolbarEl.classList.add(className);
  99. }
  100. setTimeout(function () {
  101. toolbarEl.classList.remove(toolbarAnimatingClass);
  102. }, animationTime);
  103. },
  104. toggleStorageState = function (key, value) {
  105. if (window.localStorage) {
  106. var item = localStorage.getItem(key);
  107. if (item) {
  108. localStorage.removeItem(key);
  109. } else {
  110. localStorage.setItem(key, value);
  111. }
  112. }
  113. },
  114. restoreStorageState = function (key) {
  115. if (window.localStorage) {
  116. return localStorage.getItem(key);
  117. }
  118. },
  119. togglePosition = function () {
  120. if (isIframeActive()) {
  121. hideIframe();
  122. } else {
  123. toggleToolbarClass(activeClass);
  124. toggleStorageState(CACHE_KEY, ACTIVE_STATE);
  125. }
  126. };
  127. toolbarEl.style.display = 'block';
  128. if (restoreStorageState(CACHE_KEY) == ACTIVE_STATE) {
  129. toolbarEl.classList.add(activeClass);
  130. }
  131. window.onresize = function () {
  132. if (toolbarEl.classList.contains(iframeActiveClass)) {
  133. viewEl.style.height = iframeHeight();
  134. }
  135. };
  136. barEl.onclick = function (e) {
  137. var target = e.target,
  138. block = findAncestor(target, blockClass);
  139. if (block && !block.classList.contains(titleClass)
  140. && e.which !== 2 && !e.ctrlKey // not mouse wheel and not ctrl+click
  141. ) {
  142. while (target !== this) {
  143. if (target.href) {
  144. removeActiveBlocksCls();
  145. block.classList.add(blockActiveClass);
  146. showIframe(target.href);
  147. }
  148. target = target.parentNode;
  149. }
  150. e.preventDefault();
  151. }
  152. };
  153. toggleEl.onclick = togglePosition;
  154. }
  155. function findAncestor(el, cls) {
  156. while ((el = el.parentElement) && !el.classList.contains(cls));
  157. return el;
  158. }
  159. function renderAjaxRequests() {
  160. var requestCounter = document.getElementsByClassName('yii-debug-toolbar__ajax_counter');
  161. if (!requestCounter.length) {
  162. return;
  163. }
  164. var ajaxToolbarPanel = document.querySelector('.yii-debug-toolbar__ajax');
  165. var tbodies = document.getElementsByClassName('yii-debug-toolbar__ajax_requests');
  166. var state = 'ok';
  167. if (tbodies.length) {
  168. var tbody = tbodies[0];
  169. var rows = document.createDocumentFragment();
  170. if (requestStack.length) {
  171. var firstItem = requestStack.length > 20 ? requestStack.length - 20 : 0;
  172. for (var i = firstItem; i < requestStack.length; i++) {
  173. var request = requestStack[i];
  174. var row = document.createElement('tr');
  175. rows.appendChild(row);
  176. var methodCell = document.createElement('td');
  177. methodCell.innerHTML = request.method;
  178. row.appendChild(methodCell);
  179. var statusCodeCell = document.createElement('td');
  180. var statusCode = document.createElement('span');
  181. if (request.statusCode < 300) {
  182. statusCode.setAttribute('class', 'yii-debug-toolbar__ajax_request_status yii-debug-toolbar__label_success');
  183. } else if (request.statusCode < 400) {
  184. statusCode.setAttribute('class', 'yii-debug-toolbar__ajax_request_status yii-debug-toolbar__label_warning');
  185. } else {
  186. statusCode.setAttribute('class', 'yii-debug-toolbar__ajax_request_status yii-debug-toolbar__label_error');
  187. }
  188. statusCode.textContent = request.statusCode || '-';
  189. statusCodeCell.appendChild(statusCode);
  190. row.appendChild(statusCodeCell);
  191. var pathCell = document.createElement('td');
  192. pathCell.className = 'yii-debug-toolbar__ajax_request_url';
  193. pathCell.innerHTML = request.url;
  194. pathCell.setAttribute('title', request.url);
  195. row.appendChild(pathCell);
  196. var durationCell = document.createElement('td');
  197. durationCell.className = 'yii-debug-toolbar__ajax_request_duration';
  198. if (request.duration) {
  199. durationCell.innerText = request.duration + " ms";
  200. } else {
  201. durationCell.innerText = '-';
  202. }
  203. row.appendChild(durationCell);
  204. row.appendChild(document.createTextNode(' '));
  205. var profilerCell = document.createElement('td');
  206. if (request.profilerUrl) {
  207. var profilerLink = document.createElement('a');
  208. profilerLink.setAttribute('href', request.profilerUrl);
  209. profilerLink.innerText = request.profile;
  210. profilerCell.appendChild(profilerLink);
  211. } else {
  212. profilerCell.innerText = 'n/a';
  213. }
  214. row.appendChild(profilerCell);
  215. if (request.error) {
  216. if (state !== "loading" && i > requestStack.length - 4) {
  217. state = 'error';
  218. }
  219. } else if (request.loading) {
  220. state = 'loading'
  221. }
  222. row.className = 'yii-debug-toolbar__ajax_request';
  223. }
  224. while (tbody.firstChild) {
  225. tbody.removeChild(tbody.firstChild);
  226. }
  227. tbody.appendChild(rows);
  228. }
  229. ajaxToolbarPanel.style.display = 'block';
  230. }
  231. requestCounter[0].innerText = requestStack.length;
  232. var className = 'yii-debug-toolbar__label yii-debug-toolbar__ajax_counter';
  233. if (state == 'ok') {
  234. className += ' yii-debug-toolbar__label_success';
  235. } else if (state == 'error') {
  236. className += ' yii-debug-toolbar__label_error';
  237. }
  238. requestCounter[0].className = className;
  239. };
  240. var proxied = XMLHttpRequest.prototype.open;
  241. XMLHttpRequest.prototype.open = function (method, url, async, user, pass) {
  242. var self = this;
  243. /* prevent logging AJAX calls to static and inline files, like templates */
  244. if (url.substr(0, 1) === '/' && !url.match(new RegExp("{{ excluded_ajax_paths }}"))) {
  245. var stackElement = {
  246. loading: true,
  247. error: false,
  248. url: url,
  249. method: method,
  250. start: new Date()
  251. };
  252. requestStack.push(stackElement);
  253. this.addEventListener("readystatechange", function () {
  254. if (self.readyState == 4) {
  255. stackElement.duration = self.getResponseHeader("X-Debug-Duration") || new Date() - stackElement.start;
  256. stackElement.loading = false;
  257. stackElement.statusCode = self.status;
  258. stackElement.error = self.status < 200 || self.status >= 400;
  259. stackElement.profile = self.getResponseHeader("X-Debug-Tag");
  260. stackElement.profilerUrl = self.getResponseHeader("X-Debug-Link");
  261. renderAjaxRequests();
  262. }
  263. }, false);
  264. renderAjaxRequests();
  265. }
  266. proxied.apply(this, Array.prototype.slice.call(arguments));
  267. };
  268. })();