dumpHeader.html 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. <style>
  2. .cake-debug {
  3. --color-bg: #ecece9;
  4. --color-highlight-bg: #fcf8e3;
  5. --color-control-bg: hsla(0, 0%, 50%, 0.2);
  6. --color-blue: #4070a0;
  7. --color-green: #0b6125;
  8. --color-grey: #5f5f5f;
  9. --color-orange: #c44f24;
  10. --color-violet: #a71d5d;
  11. --color-dark-grey: #222;
  12. --color-cyan: #234aa0;
  13. --color-red: #d33c44;
  14. --indent: 20px;
  15. font-family: monospace;
  16. background: var(--color-bg);
  17. padding: 5px;
  18. line-height: 16px;
  19. font-size: 14px;
  20. margin-bottom: 10px;
  21. position: relative;
  22. }
  23. .cake-debug:last-child {
  24. margin-bottom: 0;
  25. }
  26. .cake-debug-object {
  27. display: inline;
  28. }
  29. .cake-debug-object[data-highlighted=true],
  30. .cake-debug-object[data-highlighted=true] samp {
  31. background: var(--color-highlight-bg);
  32. }
  33. /*
  34. Array item container and each items are blocks so
  35. nesting works.
  36. */
  37. .cake-debug-object-props,
  38. .cake-debug-array-items {
  39. display: block;
  40. }
  41. .cake-debug-prop,
  42. .cake-debug-array-item {
  43. display: block;
  44. padding-left: var(--indent);
  45. min-height: 18px;
  46. }
  47. /** Collapser buttons **/
  48. [data-hidden=true] {
  49. display: none;
  50. }
  51. .cake-debug-collapse {
  52. display: inline-block;
  53. width: 14px;
  54. height: 14px;
  55. vertical-align: middle;
  56. border-radius: 3px;
  57. color: var(--color-blue);
  58. background: var(--color-control-bg);
  59. /* Image is an rawurlencoded SVG */
  60. background-image: url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20height%3D%2212%22%20width%3D%2212%22%20viewBox%3D%220%200%2012%2012%22%3E%3Cpolygon%20points%3D%223%2C1%203%2C11%208%2C6%22 style%3D%22fill%3A%234070a0%3B%22%2F%3E%3C%2Fsvg%3E");
  61. background-position: 2px 1px;
  62. background-repeat: no-repeat;
  63. }
  64. .cake-debug-collapse[data-open=true] {
  65. transform: rotate(90deg);
  66. }
  67. /* Copy button */
  68. .cake-debug-copy {
  69. position: absolute;
  70. top: 0;
  71. right: 0;
  72. padding: 6px;
  73. background: var(--color-control-bg);
  74. color: var(--color-blue);
  75. border-radius: 0 0 0 3px;
  76. }
  77. /* Textual elements */
  78. .cake-debug-class {
  79. color: var(--color-cyan);
  80. }
  81. .cake-debug-property {
  82. color: var(--color-dark-grey);
  83. }
  84. .cake-debug-visibility {
  85. color: var(--color-violet);
  86. }
  87. .cake-debug-punct {
  88. color: var(--color-grey);
  89. }
  90. .cake-debug-string {
  91. color: var(--color-green);
  92. white-space: pre-wrap;
  93. }
  94. .cake-debug-number {
  95. color: var(--color-blue);
  96. font-weight: bold;
  97. }
  98. .cake-debug-const {
  99. color: var(--color-orange);
  100. font-weight: bold;
  101. }
  102. .cake-debug-ref {
  103. color: var(--color-red);
  104. }
  105. .cake-debug-special {
  106. color: var(--color-red);
  107. font-style: italic;
  108. }
  109. </style>
  110. <script>
  111. ( function( win, doc ) {
  112. function initialize() {
  113. createCollapsibles( doc.querySelectorAll( '.cake-debug-array-items' ) );
  114. createCollapsibles( doc.querySelectorAll( '.cake-debug-object-props' ) );
  115. attachRefEvents( doc.querySelectorAll( '.cake-debug' ) );
  116. openBlocks( doc.querySelectorAll( '.cake-debug[data-open-all="true"]' ) );
  117. attachCopyButton( doc.querySelectorAll( '.cake-debug' ) );
  118. }
  119. // Add a name on window so DebugKit can add controls to dump blocks
  120. win.__cakeDebugBlockInit = initialize;
  121. /**
  122. * Open all the collapsed sections in a block.
  123. */
  124. function openBlocks( blocks ) {
  125. blocks.forEach( function( block ) {
  126. block.querySelectorAll( '.cake-debug-collapse[data-open="false"]' ).forEach( function( el ) {
  127. el.click();
  128. } );
  129. } );
  130. }
  131. /**
  132. * Create collapse toggles and attach events
  133. */
  134. function createCollapsibles( nodes ) {
  135. nodes.forEach( function( node ) {
  136. // Hide the childnode container if it is not
  137. // a direct parent of the container.
  138. if( !node.parentNode.parentNode.classList.contains( 'cake-debug' ) ) {
  139. node.dataset.hidden = true;
  140. }
  141. // Don't show toggles for empty arrays/objects
  142. if( node.childNodes.length == 0 ) {
  143. return;
  144. }
  145. let collapser = doc.createElement( 'a' );
  146. collapser.classList.add( 'cake-debug-collapse' );
  147. collapser.dataset.open = !node.dataset.hidden;
  148. collapser.setAttribute( 'href', '#' )
  149. collapser.setAttribute( 'title', 'Toggle items' );
  150. // Add open/close behavior
  151. collapser.addEventListener( 'click', function( event ) {
  152. event.preventDefault();
  153. event.stopPropagation();
  154. node.dataset.hidden = node.dataset.hidden === 'true' ? 'false' : 'true';
  155. collapser.dataset.open = collapser.dataset.open === 'true' ? 'false' : 'true';
  156. } );
  157. node.parentNode.insertBefore( collapser, node );
  158. } );
  159. }
  160. /**
  161. * When ref links are clicked open the path to that
  162. * element and highlight the reference
  163. */
  164. function attachRefEvents( nodes ) {
  165. nodes.forEach( function( container ) {
  166. let refLinks = container.querySelectorAll( '.cake-debug-ref' );
  167. refLinks.forEach( function( ref ) {
  168. ref.addEventListener( 'click', function( event ) {
  169. event.preventDefault();
  170. event.stopPropagation();
  171. let target = document.getElementById( ref.getAttribute( 'href' ).substr( 1 ) );
  172. openPath( container, target );
  173. } );
  174. } );
  175. } );
  176. }
  177. function openPath( container, target ) {
  178. // Open the target element
  179. let expander = target.querySelector( '.cake-debug-collapse' );
  180. if( expander.dataset.open === 'false' ) {
  181. expander.click();
  182. }
  183. container.querySelectorAll( '.cake-debug-object' ).forEach( function( el ) {
  184. el.dataset.highlighted = 'false';
  185. } )
  186. target.dataset.highlighted = 'true';
  187. let current = target;
  188. // Traverse up the tree opening all closed containers.
  189. while( true ) {
  190. let parent = current.parentNode;
  191. if( parent == container ) {
  192. break;
  193. }
  194. if( parent.classList.contains( 'cake-debug-object' ) || parent.classList.contains( 'cake-debug-array' ) ) {
  195. expander = parent.querySelector( '.cake-debug-collapse' );
  196. if( expander.dataset.open === 'false' ) {
  197. expander.click();
  198. }
  199. }
  200. current = parent;
  201. }
  202. }
  203. // https://www.30secondsofcode.org/js/s/copy-to-clipboard
  204. function copyToClipboard( str ) {
  205. let el = document.createElement( 'textarea' );
  206. el.value = str;
  207. el.setAttribute( 'readonly', '' );
  208. el.style.position = 'absolute';
  209. el.style.left = '-9999px';
  210. document.body.appendChild( el );
  211. let selected = document.getSelection().rangeCount > 0 ? document.getSelection().getRangeAt( 0 ) : false;
  212. el.select();
  213. document.execCommand( 'copy' );
  214. document.body.removeChild( el );
  215. if( selected ) {
  216. document.getSelection().removeAllRanges();
  217. document.getSelection().addRange( selected );
  218. }
  219. }
  220. function attachCopyButton( nodes ) {
  221. nodes.forEach( function( container ) {
  222. let copy = doc.createElement( 'a' );
  223. copy.classList.add( 'cake-debug-copy' );
  224. copy.setAttribute( 'href', '#' );
  225. copy.setAttribute( 'title', 'Copy contents of debug output' );
  226. copy.appendChild( doc.createTextNode( 'Copy' ) );
  227. // Add copy behavior
  228. copy.addEventListener( 'click', function( event ) {
  229. event.preventDefault();
  230. event.stopPropagation();
  231. let lineNo = '';
  232. if( container.parentNode && container.parentNode.classList.contains( 'cake-debug' ) ) {
  233. let line = container.parentNode.querySelector( 'span' );
  234. lineNo = line.textContent + "\n";
  235. }
  236. // Chop off last 4 to exclude copy button text.
  237. copyToClipboard( lineNo + container.textContent.substring( 0, container.textContent.length - 4 ) );
  238. } );
  239. container.appendChild( copy );
  240. } );
  241. }
  242. doc.addEventListener( 'DOMContentLoaded', initialize );
  243. }( window, document ) )
  244. </script>