Stack.vue 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. <template>
  2. <div class="stack">
  3. <div class="stack-nav">
  4. <div class="stack-nav-actions">
  5. <div class="stack-nav-arrows">
  6. <button
  7. @click="selectPreviousFrame"
  8. title="Frame up (Key:K)"
  9. class="stack-nav-arrow"
  10. >
  11. <Icon name="arrow-up" />
  12. </button>
  13. <button
  14. @click="selectNextFrame"
  15. title="Frame down (Key:J)"
  16. class="stack-nav-arrow"
  17. >
  18. <Icon name="arrow-down" />
  19. </button>
  20. </div>
  21. <div class="px-4">
  22. <button
  23. v-if="allVendorFramesAreExpanded"
  24. class="ml-auto link-dimmed"
  25. @click="collapseAllVendorFrames"
  26. >
  27. Collapse vendor frames
  28. </button>
  29. <button v-else class="ml-auto link-dimmed" @click="expandAllVendorFrames">
  30. Expand vendor frames
  31. </button>
  32. </div>
  33. </div>
  34. <div class="stack-frames">
  35. <ol class="stack-frames-scroll scrollbar">
  36. <FrameGroup
  37. v-for="(frameGroup, i) in frameGroups"
  38. :key="i"
  39. :frameGroup="frameGroup"
  40. @expand="expandFrameGroup(frameGroup)"
  41. @select="selectFrame"
  42. />
  43. </ol>
  44. </div>
  45. </div>
  46. <Snippet
  47. :selected-frame="selectedFrame"
  48. :selected-range="selectedRange"
  49. @select-range="selectedRange = $event"
  50. />
  51. </div>
  52. </template>
  53. <script>
  54. import Snippet from './Snippet.vue';
  55. import FrameGroup from './FrameGroup.vue';
  56. import {
  57. stackReducer,
  58. allVendorFramesAreExpanded,
  59. createFrameGroups,
  60. getSelectedFrame,
  61. } from '../../stack';
  62. export default {
  63. props: {
  64. frames: { required: true },
  65. },
  66. data() {
  67. return {
  68. state: {
  69. frames: this.frames,
  70. expanded: [],
  71. selected: this.frames.length,
  72. },
  73. selectedRange: null,
  74. };
  75. },
  76. components: {
  77. Snippet,
  78. FrameGroup,
  79. },
  80. created() {
  81. this.state = stackReducer(this.state, { type: 'COLLAPSE_ALL_VENDOR_FRAMES' });
  82. this.dispatch = action => {
  83. this.state = stackReducer(this.state, action);
  84. };
  85. const keydownHandler = e => {
  86. if (e.key === 'j') {
  87. this.selectNextFrame();
  88. }
  89. if (e.key === 'k') {
  90. this.selectPreviousFrame();
  91. }
  92. };
  93. window.addEventListener('keydown', keydownHandler);
  94. this.$once('hook:beforeDestroy', () => {
  95. window.removeEventListener('keydown', keydownHandler);
  96. });
  97. },
  98. computed: {
  99. allVendorFramesAreExpanded() {
  100. return allVendorFramesAreExpanded(this.state);
  101. },
  102. frameGroups() {
  103. return createFrameGroups(this.state);
  104. },
  105. selectedFrame() {
  106. return getSelectedFrame(this.state);
  107. },
  108. },
  109. watch: {
  110. selectedRange(selectedRange) {
  111. if (selectedRange) {
  112. const lineNumber =
  113. selectedRange[0] === selectedRange[1]
  114. ? selectedRange[0]
  115. : `${selectedRange[0]}-${selectedRange[1]}`;
  116. window.history.replaceState(
  117. window.history.state,
  118. '',
  119. `#F${this.state.selected}L${lineNumber}`,
  120. );
  121. }
  122. },
  123. },
  124. methods: {
  125. expandFrameGroup(frameGroup) {
  126. this.dispatch({
  127. type: 'EXPAND_FRAMES',
  128. frames: frameGroup.frames.map(frame => frame.frame_number),
  129. });
  130. },
  131. selectFrame(frame) {
  132. this.dispatch({ type: 'SELECT_FRAME', frame });
  133. },
  134. selectNextFrame() {
  135. this.dispatch({ type: 'SELECT_NEXT_FRAME' });
  136. },
  137. selectPreviousFrame() {
  138. this.dispatch({ type: 'SELECT_PREVIOUS_FRAME' });
  139. },
  140. collapseAllVendorFrames() {
  141. this.dispatch({ type: 'COLLAPSE_ALL_VENDOR_FRAMES' });
  142. },
  143. expandAllVendorFrames() {
  144. this.dispatch({ type: 'EXPAND_ALL_VENDOR_FRAMES' });
  145. },
  146. },
  147. };
  148. </script>