collapser.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /* -----------------------------------------------------------------------------
  2. | Copyright (c) Jupyter Development Team.
  3. | Distributed under the terms of the Modified BSD License.
  4. |----------------------------------------------------------------------------*/
  5. import { ReactWidget } from '@jupyterlab/apputils';
  6. import { ElementExt } from '@lumino/domutils';
  7. import * as React from 'react';
  8. import { Cell, CodeCell } from './widget';
  9. /**
  10. * The CSS class added to all collapsers.
  11. */
  12. const COLLAPSER_CLASS = 'jp-Collapser';
  13. /**
  14. * The CSS class added to the collapser child.
  15. */
  16. const COLLAPSER_CHILD_CLASS = 'jp-Collapser-child';
  17. /**
  18. * The CSS class added to input collapsers.
  19. */
  20. const INPUT_COLLAPSER = 'jp-InputCollapser';
  21. /**
  22. * The CSS class added to output collapsers.
  23. */
  24. const OUTPUT_COLLAPSER = 'jp-OutputCollapser';
  25. /**
  26. * Abstract collapser base class.
  27. *
  28. * ### Notes
  29. * A collapser is a visible div to the left of a cell's
  30. * input/output that a user can click on to collapse the
  31. * input/output.
  32. */
  33. export abstract class Collapser extends ReactWidget {
  34. /**
  35. * Construct a new collapser.
  36. */
  37. constructor() {
  38. super();
  39. this.addClass(COLLAPSER_CLASS);
  40. }
  41. /**
  42. * Is the input/output of the parent collapsed.
  43. */
  44. get collapsed(): boolean {
  45. return false;
  46. }
  47. /**
  48. * Render the collapser with the virtual DOM.
  49. */
  50. protected render(): React.ReactElement<any> {
  51. const childClass = COLLAPSER_CHILD_CLASS;
  52. return <div className={childClass} onClick={e => this.handleClick(e)} />;
  53. }
  54. /**
  55. * Handle the click event.
  56. */
  57. protected abstract handleClick(e: React.MouseEvent<HTMLDivElement>): void;
  58. }
  59. /**
  60. * A collapser subclass to collapse a cell's input area.
  61. */
  62. export class InputCollapser extends Collapser {
  63. /**
  64. * Construct a new input collapser.
  65. */
  66. constructor() {
  67. super();
  68. this.addClass(INPUT_COLLAPSER);
  69. }
  70. /**
  71. * Is the cell's input collapsed?
  72. */
  73. get collapsed(): boolean {
  74. const cell = this.parent?.parent as Cell | undefined | null;
  75. if (cell) {
  76. return cell.inputHidden;
  77. } else {
  78. return false;
  79. }
  80. }
  81. /**
  82. * Handle a click event for the user to collapse the cell's input.
  83. */
  84. protected handleClick(e: React.MouseEvent<HTMLDivElement>): void {
  85. const cell = this.parent?.parent as Cell | undefined | null;
  86. if (cell) {
  87. cell.inputHidden = !cell.inputHidden;
  88. }
  89. /* We need this until we watch the cell state */
  90. this.update();
  91. }
  92. }
  93. /**
  94. * A collapser subclass to collapse a cell's output area.
  95. */
  96. export class OutputCollapser extends Collapser {
  97. /**
  98. * Construct a new output collapser.
  99. */
  100. constructor() {
  101. super();
  102. this.addClass(OUTPUT_COLLAPSER);
  103. }
  104. /**
  105. * Is the cell's output collapsed?
  106. */
  107. get collapsed(): boolean {
  108. const cell = this.parent?.parent as CodeCell | undefined | null;
  109. if (cell) {
  110. return cell.outputHidden;
  111. } else {
  112. return false;
  113. }
  114. }
  115. /**
  116. * Handle a click event for the user to collapse the cell's output.
  117. */
  118. protected handleClick(e: React.MouseEvent<HTMLDivElement>): void {
  119. const cell = this.parent?.parent as CodeCell | undefined | null;
  120. if (cell) {
  121. cell.outputHidden = !cell.outputHidden;
  122. /* Scroll cell into view after output collapse */
  123. if (cell.outputHidden) {
  124. let area = cell.parent?.node;
  125. if (area) {
  126. ElementExt.scrollIntoViewIfNeeded(area, cell.node);
  127. }
  128. }
  129. }
  130. /* We need this until we watch the cell state */
  131. this.update();
  132. }
  133. }