form.html.twig 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730
  1. {% extends '@WebProfiler/Profiler/layout.html.twig' %}
  2. {% from _self import form_tree_entry, form_tree_details %}
  3. {% block toolbar %}
  4. {% if collector.data.nb_errors > 0 or collector.data.forms|length %}
  5. {% set status_color = collector.data.nb_errors ? 'red' : '' %}
  6. {% set icon %}
  7. {{ include('@WebProfiler/Icon/form.svg') }}
  8. <span class="sf-toolbar-value">
  9. {{ collector.data.nb_errors ?: collector.data.forms|length }}
  10. </span>
  11. {% endset %}
  12. {% set text %}
  13. <div class="sf-toolbar-info-piece">
  14. <b>Number of forms</b>
  15. <span class="sf-toolbar-status">{{ collector.data.forms|length }}</span>
  16. </div>
  17. <div class="sf-toolbar-info-piece">
  18. <b>Number of errors</b>
  19. <span class="sf-toolbar-status sf-toolbar-status-{{ collector.data.nb_errors > 0 ? 'red' }}">{{ collector.data.nb_errors }}</span>
  20. </div>
  21. {% endset %}
  22. {{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: profiler_url, status: status_color }) }}
  23. {% endif %}
  24. {% endblock %}
  25. {% block menu %}
  26. <span class="label label-status-{{ collector.data.nb_errors ? 'error' }} {{ collector.data.forms is empty ? 'disabled' }}">
  27. <span class="icon">{{ include('@WebProfiler/Icon/form.svg') }}</span>
  28. <strong>Forms</strong>
  29. {% if collector.data.nb_errors > 0 %}
  30. <span class="count">
  31. <span>{{ collector.data.nb_errors }}</span>
  32. </span>
  33. {% endif %}
  34. </span>
  35. {% endblock %}
  36. {% block head %}
  37. {{ parent() }}
  38. <style>
  39. #tree-menu {
  40. float: left;
  41. padding-right: 10px;
  42. width: 230px;
  43. }
  44. #tree-menu ul {
  45. list-style: none;
  46. margin: 0;
  47. padding-left: 0;
  48. }
  49. #tree-menu li {
  50. margin: 0;
  51. padding: 0;
  52. width: 100%;
  53. }
  54. #tree-menu .empty {
  55. border: 0;
  56. padding: 0;
  57. }
  58. #tree-details-container {
  59. border-left: 1px solid #DDD;
  60. margin-left: 250px;
  61. padding-left: 20px;
  62. }
  63. .tree-details {
  64. padding-bottom: 40px;
  65. }
  66. .tree-details h3 {
  67. font-size: 18px;
  68. position: relative;
  69. }
  70. .toggle-icon {
  71. display: inline-block;
  72. background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAgBAMAAADpp+X/AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QweDgwx4LcKwAAAABVQTFRFAAAA////////////////ZmZm////bvjBwAAAAAV0Uk5TABZwsuCVEUjgAAAAAWJLR0QF+G/pxwAAAE1JREFUGNNjSHMSYGBgUEljSGYAAzMGBwiDhUEBwmBiEIAwGBmwgTQgQGWgA7h2uIFwK+CWwp1BpHvYEqDuATEYkBlY3IOmBq6dCPcAAIT5Eg2IksjQAAAAAElFTkSuQmCC") no-repeat top left #5eb5e0;
  73. }
  74. .closed .toggle-icon, .closed.toggle-icon {
  75. background-position: bottom left;
  76. }
  77. .toggle-icon.empty {
  78. background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAZgBmAGYHukptAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QweDhIf6CA40AAAAFRJREFUOMvtk7ENACEMA61vfx767MROWfO+AdGBHlNyTZrYUZRYDBII4NWE1pNdpFarfgLUbpDaBEgBYRiEVjsvDLa1l6O4Z3wkFWN+OfLKdpisOH/TlICzukmUJwAAAABJRU5ErkJggg==");
  79. }
  80. .tree .tree-inner {
  81. cursor: pointer;
  82. padding: 5px 7px 5px 22px;
  83. position: relative;
  84. }
  85. .tree .toggle-button {
  86. /* provide a bigger clickable area than just 10x10px */
  87. width: 16px;
  88. height: 16px;
  89. margin-left: -18px;
  90. }
  91. .tree .toggle-icon {
  92. width: 10px;
  93. height: 10px;
  94. /* position the icon in the center of the clickable area */
  95. margin-left: 3px;
  96. margin-top: 3px;
  97. background-size: 10px 20px;
  98. background-color: #AAA;
  99. }
  100. .tree .toggle-icon.empty {
  101. width: 10px;
  102. height: 10px;
  103. position: absolute;
  104. top: 50%;
  105. margin-top: -5px;
  106. margin-left: -15px;
  107. background-size: 10px 10px;
  108. }
  109. .tree ul ul .tree-inner {
  110. padding-left: 37px;
  111. }
  112. .tree ul ul ul .tree-inner {
  113. padding-left: 52px;
  114. }
  115. .tree ul ul ul ul .tree-inner {
  116. padding-left: 67px;
  117. }
  118. .tree ul ul ul ul ul .tree-inner {
  119. padding-left: 82px;
  120. }
  121. .tree .tree-inner:hover {
  122. background: #dfdfdf;
  123. }
  124. .tree .tree-inner:hover span:not(.has-error) {
  125. color: var(--base-0);
  126. }
  127. .tree .tree-inner.active, .tree .tree-inner.active:hover {
  128. background: var(--tree-active-background);
  129. font-weight: bold;
  130. }
  131. .tree .tree-inner.active .toggle-icon, .tree .tree-inner:hover .toggle-icon, .tree .tree-inner.active:hover .toggle-icon {
  132. background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAgBAMAAADpp+X/AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QweDhEYXWn+sAAAABhQTFRFAAAA39/f39/f39/f39/fZmZm39/f////gc3YPwAAAAV0Uk5TAAtAc6ZeVyCYAAAAAWJLR0QF+G/pxwAAAE1JREFUGNNjSHMSYGBgUEljSGYAAzMGBwiDhUEBwmBiEIAwGBmwgXIgQGWgA7h2uIFwK+CWwp1BpHvYC6DuATEYkBlY3IOmBq6dCPcAADqLE4MnBi/fAAAAAElFTkSuQmCC");
  133. background-color: #999;
  134. }
  135. .tree .tree-inner.active .toggle-icon.empty, .tree .tree-inner:hover .toggle-icon.empty, .tree .tree-inner.active:hover .toggle-icon.empty {
  136. background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QweDhoucSey4gAAABVQTFRFAAAA39/f39/f39/f39/fZmZm39/fD5Dx2AAAAAV0Uk5TAAtAc6ZeVyCYAAAAAWJLR0QF+G/pxwAAADJJREFUCNdjSHMSYGBgUEljSGYAAzMGBwiDhUEBwmBiEIAwGBnIA3DtcAPhVsAthTkDAFOfBKW9C1iqAAAAAElFTkSuQmCC");
  137. }
  138. .tree-details .toggle-icon {
  139. width: 16px;
  140. height: 16px;
  141. /* vertically center the button */
  142. position: absolute;
  143. top: 50%;
  144. margin-top: -9px;
  145. margin-left: 6px;
  146. }
  147. .badge-error {
  148. float: right;
  149. background: var(--background-error);
  150. color: #FFF;
  151. padding: 1px 4px;
  152. font-size: 10px;
  153. font-weight: bold;
  154. vertical-align: middle;
  155. }
  156. .has-error {
  157. color: var(--color-error);
  158. }
  159. .errors h3 {
  160. color: var(--color-error);
  161. }
  162. .errors th {
  163. background: var(--background-error);
  164. color: #FFF;
  165. }
  166. .errors .toggle-icon {
  167. background-color: var(--background-error);
  168. }
  169. h3 a, h3 a:hover, h3 a:focus {
  170. color: inherit;
  171. text-decoration: inherit;
  172. }
  173. h2 + h3.form-data-type {
  174. margin-top: 0;
  175. }
  176. h3.form-data-type + h3 {
  177. margin-top: 1em;
  178. }
  179. .theme-dark .toggle-icon {
  180. background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAgBAMAAADpp+X/AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAVUExURUdwTH+Ag0lNUZiYmGRmbP///zU5P2n9VV4AAAAFdFJOUwCv+yror0g1sQAAAE1JREFUGNNjSFM0YGBgEEpjSGEAAzcGBQiDiUEAwmBkMIAwmBmwgVAgQGWgA7h2uIFwK+CWwp1BpHtYA6DuATEYkBlY3IOmBq6dCPcAAKMtEEs3tfChAAAAAElFTkSuQmCC');
  181. }
  182. .theme-dark .toggle-icon.empty {
  183. background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAASUExURUdwTDI3OzQ5PS4uLjU3PzU5P4keoyIAAAAFdFJOUwBApgtzrnKGEwAAADJJREFUCNdjCFU0YGBgEAplCGEAA1cGBQiDiUEAwmBkMIAwmBnIA3DtcAPhVsAthTkDACsZBBmrTTSxAAAAAElFTkSuQmCC');
  184. }
  185. .theme-dark .tree .tree-inner.active .toggle-icon, .theme-dark .tree .tree-inner:hover .toggle-icon, .theme-dark .tree .tree-inner.active:hover .toggle-icon {
  186. background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAgBAMAAADpp+X/AAAAD1BMVEVHcEx/gIOYmJiZmZn///+IJ2wIAAAAA3RSTlMAryoIUq0uAAAAUElEQVQY02NgYFQ2NjYWYGBgMAYDBgZmCMOAQRjCMGRQhjCMoEqAipAYLkCAykBXA9cONxBuBdxShDOIc4+JM9Q9IIYxMgOLe9DUwLUT4R4AznguG0qfEa0AAAAASUVORK5CYII=');
  187. background-color: transparent;
  188. }
  189. .theme-dark .tree .tree-inner.active .toggle-icon.empty, .theme-dark .tree .tree-inner:hover .toggle-icon.empty, .theme-dark .tree .tree-inner.active:hover .toggle-icon.empty {
  190. background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAACVBMVEVHcEwyNzuqqqrd9nIgAAAAAnRSTlMAQABPjKgAAAArSURBVAjXY2BctcqBgWvVqgUMWqtWrWDIWrVqJcMqICCGACsGawMbADIKANflJYEoGMqtAAAAAElFTkSuQmCC');
  191. background-color: transparent;
  192. }
  193. </style>
  194. {% endblock %}
  195. {% block panel %}
  196. <h2>Forms</h2>
  197. {% if collector.data.forms|length %}
  198. <div id="tree-menu" class="tree">
  199. <ul>
  200. {% for formName, formData in collector.data.forms %}
  201. {{ form_tree_entry(formName, formData, true) }}
  202. {% endfor %}
  203. </ul>
  204. </div>
  205. <div id="tree-details-container">
  206. {% for formName, formData in collector.data.forms %}
  207. {{ form_tree_details(formName, formData, collector.data.forms_by_hash, loop.first) }}
  208. {% endfor %}
  209. </div>
  210. {% else %}
  211. <div class="empty">
  212. <p>No forms were submitted for this request.</p>
  213. </div>
  214. {% endif %}
  215. <script>
  216. function Toggler(storage) {
  217. "use strict";
  218. var STORAGE_KEY = 'sf_toggle_data',
  219. states = {},
  220. isCollapsed = function (button) {
  221. return Sfjs.hasClass(button, 'closed');
  222. },
  223. isExpanded = function (button) {
  224. return !isCollapsed(button);
  225. },
  226. expand = function (button) {
  227. var targetId = button.dataset.toggleTargetId,
  228. target = document.getElementById(targetId);
  229. if (!target) {
  230. throw "Toggle target " + targetId + " does not exist";
  231. }
  232. if (isCollapsed(button)) {
  233. Sfjs.removeClass(button, 'closed');
  234. Sfjs.removeClass(target, 'hidden');
  235. states[targetId] = 1;
  236. storage.setItem(STORAGE_KEY, states);
  237. }
  238. },
  239. collapse = function (button) {
  240. var targetId = button.dataset.toggleTargetId,
  241. target = document.getElementById(targetId);
  242. if (!target) {
  243. throw "Toggle target " + targetId + " does not exist";
  244. }
  245. if (isExpanded(button)) {
  246. Sfjs.addClass(button, 'closed');
  247. Sfjs.addClass(target, 'hidden');
  248. states[targetId] = 0;
  249. storage.setItem(STORAGE_KEY, states);
  250. }
  251. },
  252. toggle = function (button) {
  253. if (Sfjs.hasClass(button, 'closed')) {
  254. expand(button);
  255. } else {
  256. collapse(button);
  257. }
  258. },
  259. initButtons = function (buttons) {
  260. states = storage.getItem(STORAGE_KEY, {});
  261. // must be an object, not an array or anything else
  262. // `typeof` returns "object" also for arrays, so the following
  263. // check must be done
  264. // see http://stackoverflow.com/questions/4775722/check-if-object-is-array
  265. if ('[object Object]' !== Object.prototype.toString.call(states)) {
  266. states = {};
  267. }
  268. for (var i = 0, l = buttons.length; i < l; ++i) {
  269. var targetId = buttons[i].dataset.toggleTargetId,
  270. target = document.getElementById(targetId);
  271. if (!target) {
  272. throw "Toggle target " + targetId + " does not exist";
  273. }
  274. // correct the initial state of the button
  275. if (Sfjs.hasClass(target, 'hidden')) {
  276. Sfjs.addClass(buttons[i], 'closed');
  277. }
  278. // attach listener for expanding/collapsing the target
  279. clickHandler(buttons[i], toggle);
  280. if (states.hasOwnProperty(targetId)) {
  281. // open or collapse based on stored data
  282. if (0 === states[targetId]) {
  283. collapse(buttons[i]);
  284. } else {
  285. expand(buttons[i]);
  286. }
  287. }
  288. }
  289. };
  290. return {
  291. initButtons: initButtons,
  292. toggle: toggle,
  293. isExpanded: isExpanded,
  294. isCollapsed: isCollapsed,
  295. expand: expand,
  296. collapse: collapse
  297. };
  298. }
  299. function JsonStorage(storage) {
  300. var setItem = function (key, data) {
  301. storage.setItem(key, JSON.stringify(data));
  302. },
  303. getItem = function (key, defaultValue) {
  304. var data = storage.getItem(key);
  305. if (null !== data) {
  306. try {
  307. return JSON.parse(data);
  308. } catch(e) {
  309. }
  310. }
  311. return defaultValue;
  312. };
  313. return {
  314. setItem: setItem,
  315. getItem: getItem
  316. };
  317. }
  318. function TabView() {
  319. "use strict";
  320. var activeTab = null,
  321. activeTarget = null,
  322. select = function (tab) {
  323. var targetId = tab.dataset.tabTargetId,
  324. target = document.getElementById(targetId);
  325. if (!target) {
  326. throw "Tab target " + targetId + " does not exist";
  327. }
  328. if (activeTab) {
  329. Sfjs.removeClass(activeTab, 'active');
  330. }
  331. if (activeTarget) {
  332. Sfjs.addClass(activeTarget, 'hidden');
  333. }
  334. Sfjs.addClass(tab, 'active');
  335. Sfjs.removeClass(target, 'hidden');
  336. activeTab = tab;
  337. activeTarget = target;
  338. },
  339. initTabs = function (tabs) {
  340. for (var i = 0, l = tabs.length; i < l; ++i) {
  341. var targetId = tabs[i].dataset.tabTargetId,
  342. target = document.getElementById(targetId);
  343. if (!target) {
  344. throw "Tab target " + targetId + " does not exist";
  345. }
  346. clickHandler(tabs[i], select);
  347. Sfjs.addClass(target, 'hidden');
  348. }
  349. if (tabs.length > 0) {
  350. select(tabs[0]);
  351. }
  352. };
  353. return {
  354. initTabs: initTabs,
  355. select: select
  356. };
  357. }
  358. var tabTarget = new TabView(),
  359. toggler = new Toggler(new JsonStorage(sessionStorage)),
  360. clickHandler = function (element, callback) {
  361. Sfjs.addEventListener(element, 'click', function (e) {
  362. if (!e) {
  363. e = window.event;
  364. }
  365. callback(this);
  366. if (e.preventDefault) {
  367. e.preventDefault();
  368. } else {
  369. e.returnValue = false;
  370. }
  371. e.stopPropagation();
  372. return false;
  373. });
  374. };
  375. tabTarget.initTabs(document.querySelectorAll('.tree .tree-inner'));
  376. toggler.initButtons(document.querySelectorAll('a.toggle-button'));
  377. </script>
  378. {% endblock %}
  379. {% macro form_tree_entry(name, data, is_root) %}
  380. {% import _self as tree %}
  381. {% set has_error = data.errors is defined and data.errors|length > 0 %}
  382. <li>
  383. <div class="tree-inner" data-tab-target-id="{{ data.id }}-details">
  384. {% if has_error %}
  385. <div class="badge-error">{{ data.errors|length }}</div>
  386. {% endif %}
  387. {% if data.children is not empty %}
  388. <a class="toggle-button" data-toggle-target-id="{{ data.id }}-children" href="#"><span class="toggle-icon"></span></a>
  389. {% else %}
  390. <div class="toggle-icon empty"></div>
  391. {% endif %}
  392. <span {% if has_error or data.has_children_error|default(false) %}class="has-error"{% endif %}>
  393. {{ name|default('(no name)') }}
  394. </span>
  395. </div>
  396. {% if data.children is not empty %}
  397. <ul id="{{ data.id }}-children" {% if not is_root and not data.has_children_error|default(false) %}class="hidden"{% endif %}>
  398. {% for childName, childData in data.children %}
  399. {{ tree.form_tree_entry(childName, childData, false) }}
  400. {% endfor %}
  401. </ul>
  402. {% endif %}
  403. </li>
  404. {% endmacro %}
  405. {% macro form_tree_details(name, data, forms_by_hash, show) %}
  406. {% import _self as tree %}
  407. <div class="tree-details{% if not show|default(false) %} hidden{% endif %}" {% if data.id is defined %}id="{{ data.id }}-details"{% endif %}>
  408. <h2>{{ name|default('(no name)') }}</h2>
  409. {% if data.type_class is defined %}
  410. <h3 class="dump-inline form-data-type">{{ profiler_dump(data.type_class) }}</h3>
  411. {% endif %}
  412. {% if data.errors is defined and data.errors|length > 0 %}
  413. <div class="errors">
  414. <h3>
  415. <a class="toggle-button" data-toggle-target-id="{{ data.id }}-errors" href="#">
  416. Errors <span class="toggle-icon"></span>
  417. </a>
  418. </h3>
  419. <table id="{{ data.id }}-errors">
  420. <thead>
  421. <tr>
  422. <th>Message</th>
  423. <th>Origin</th>
  424. <th>Cause</th>
  425. </tr>
  426. </thead>
  427. <tbody>
  428. {% for error in data.errors %}
  429. <tr>
  430. <td>{{ error.message }}</td>
  431. <td>
  432. {% if error.origin is empty %}
  433. <em>This form.</em>
  434. {% elseif forms_by_hash[error.origin] is not defined %}
  435. <em>Unknown.</em>
  436. {% else %}
  437. {{ forms_by_hash[error.origin].name }}
  438. {% endif %}
  439. </td>
  440. <td>
  441. {% if error.trace %}
  442. <span class="newline">Caused by:</span>
  443. {% for stacked in error.trace %}
  444. {{ profiler_dump(stacked) }}
  445. {% endfor %}
  446. {% else %}
  447. <em>Unknown.</em>
  448. {% endif %}
  449. </td>
  450. </tr>
  451. {% endfor %}
  452. </tbody>
  453. </table>
  454. </div>
  455. {% endif %}
  456. {% if data.default_data is defined %}
  457. <h3>
  458. <a class="toggle-button" data-toggle-target-id="{{ data.id }}-default_data" href="#">
  459. Default Data <span class="toggle-icon"></span>
  460. </a>
  461. </h3>
  462. <div id="{{ data.id }}-default_data">
  463. <table>
  464. <thead>
  465. <tr>
  466. <th width="180">Property</th>
  467. <th>Value</th>
  468. </tr>
  469. </thead>
  470. <tbody>
  471. <tr>
  472. <th class="font-normal" scope="row">Model Format</th>
  473. <td>
  474. {% if data.default_data.model is defined %}
  475. {{ profiler_dump(data.default_data.seek('model')) }}
  476. {% else %}
  477. <em class="font-normal text-muted">same as normalized format</em>
  478. {% endif %}
  479. </td>
  480. </tr>
  481. <tr>
  482. <th class="font-normal" scope="row">Normalized Format</th>
  483. <td>{{ profiler_dump(data.default_data.seek('norm')) }}</td>
  484. </tr>
  485. <tr>
  486. <th class="font-normal" scope="row">View Format</th>
  487. <td>
  488. {% if data.default_data.view is defined %}
  489. {{ profiler_dump(data.default_data.seek('view')) }}
  490. {% else %}
  491. <em class="font-normal text-muted">same as normalized format</em>
  492. {% endif %}
  493. </td>
  494. </tr>
  495. </tbody>
  496. </table>
  497. </div>
  498. {% endif %}
  499. {% if data.submitted_data is defined %}
  500. <h3>
  501. <a class="toggle-button" data-toggle-target-id="{{ data.id }}-submitted_data" href="#">
  502. Submitted Data <span class="toggle-icon"></span>
  503. </a>
  504. </h3>
  505. <div id="{{ data.id }}-submitted_data">
  506. {% if data.submitted_data.norm is defined %}
  507. <table>
  508. <thead>
  509. <tr>
  510. <th width="180">Property</th>
  511. <th>Value</th>
  512. </tr>
  513. </thead>
  514. <tbody>
  515. <tr>
  516. <th class="font-normal" scope="row">View Format</th>
  517. <td>
  518. {% if data.submitted_data.view is defined %}
  519. {{ profiler_dump(data.submitted_data.seek('view')) }}
  520. {% else %}
  521. <em class="font-normal text-muted">same as normalized format</em>
  522. {% endif %}
  523. </td>
  524. </tr>
  525. <tr>
  526. <th class="font-normal" scope="row">Normalized Format</th>
  527. <td>{{ profiler_dump(data.submitted_data.seek('norm')) }}</td>
  528. </tr>
  529. <tr>
  530. <th class="font-normal" scope="row">Model Format</th>
  531. <td>
  532. {% if data.submitted_data.model is defined %}
  533. {{ profiler_dump(data.submitted_data.seek('model')) }}
  534. {% else %}
  535. <em class="font-normal text-muted">same as normalized format</em>
  536. {% endif %}
  537. </td>
  538. </tr>
  539. </tbody>
  540. </table>
  541. {% else %}
  542. <div class="empty">
  543. <p>This form was not submitted.</p>
  544. </div>
  545. {% endif %}
  546. </div>
  547. {% endif %}
  548. {% if data.passed_options is defined %}
  549. <h3>
  550. <a class="toggle-button" data-toggle-target-id="{{ data.id }}-passed_options" href="#">
  551. Passed Options <span class="toggle-icon"></span>
  552. </a>
  553. </h3>
  554. <div id="{{ data.id }}-passed_options">
  555. {% if data.passed_options|length %}
  556. <table>
  557. <thead>
  558. <tr>
  559. <th width="180">Option</th>
  560. <th>Passed Value</th>
  561. <th>Resolved Value</th>
  562. </tr>
  563. </thead>
  564. <tbody>
  565. {% for option, value in data.passed_options %}
  566. <tr>
  567. <th>{{ option }}</th>
  568. <td>{{ profiler_dump(value) }}</td>
  569. <td>
  570. {# values can be stubs #}
  571. {% set option_value = value.value|default(value) %}
  572. {% set resolved_option_value = data.resolved_options[option].value|default(data.resolved_options[option]) %}
  573. {% if resolved_option_value == option_value %}
  574. <em class="font-normal text-muted">same as passed value</em>
  575. {% else %}
  576. {{ profiler_dump(data.resolved_options.seek(option)) }}
  577. {% endif %}
  578. </td>
  579. </tr>
  580. {% endfor %}
  581. </tbody>
  582. </table>
  583. {% else %}
  584. <div class="empty">
  585. <p>No options were passed when constructing this form.</p>
  586. </div>
  587. {% endif %}
  588. </div>
  589. {% endif %}
  590. {% if data.resolved_options is defined %}
  591. <h3>
  592. <a class="toggle-button" data-toggle-target-id="{{ data.id }}-resolved_options" href="#">
  593. Resolved Options <span class="toggle-icon"></span>
  594. </a>
  595. </h3>
  596. <div id="{{ data.id }}-resolved_options" class="hidden">
  597. <table>
  598. <thead>
  599. <tr>
  600. <th width="180">Option</th>
  601. <th>Value</th>
  602. </tr>
  603. </thead>
  604. <tbody>
  605. {% for option, value in data.resolved_options %}
  606. <tr>
  607. <th scope="row">{{ option }}</th>
  608. <td>{{ profiler_dump(value) }}</td>
  609. </tr>
  610. {% endfor %}
  611. </tbody>
  612. </table>
  613. </div>
  614. {% endif %}
  615. {% if data.view_vars is defined %}
  616. <h3>
  617. <a class="toggle-button" data-toggle-target-id="{{ data.id }}-view_vars" href="#">
  618. View Variables <span class="toggle-icon"></span>
  619. </a>
  620. </h3>
  621. <div id="{{ data.id }}-view_vars" class="hidden">
  622. <table>
  623. <thead>
  624. <tr>
  625. <th width="180">Variable</th>
  626. <th>Value</th>
  627. </tr>
  628. </thead>
  629. <tbody>
  630. {% for variable, value in data.view_vars %}
  631. <tr>
  632. <th scope="row">{{ variable }}</th>
  633. <td>{{ profiler_dump(value) }}</td>
  634. </tr>
  635. {% endfor %}
  636. </tbody>
  637. </table>
  638. </div>
  639. {% endif %}
  640. </div>
  641. {% for childName, childData in data.children %}
  642. {{ tree.form_tree_details(childName, childData, forms_by_hash) }}
  643. {% endfor %}
  644. {% endmacro %}