/ src / panel-container-element.js
panel-container-element.js
  1  'use strict';
  2  
  3  const focusTrap = require('focus-trap');
  4  const { CompositeDisposable } = require('event-kit');
  5  
  6  class PanelContainerElement extends HTMLElement {
  7    createdCallback() {
  8      this.subscriptions = new CompositeDisposable();
  9    }
 10  
 11    attachedCallback() {
 12      if (this.model.dock) {
 13        this.model.dock.elementAttached();
 14      }
 15    }
 16  
 17    initialize(model, viewRegistry) {
 18      this.model = model;
 19      this.viewRegistry = viewRegistry;
 20  
 21      this.subscriptions.add(
 22        this.model.onDidAddPanel(this.panelAdded.bind(this))
 23      );
 24      this.subscriptions.add(this.model.onDidDestroy(this.destroyed.bind(this)));
 25      this.classList.add(this.model.getLocation());
 26  
 27      // Add the dock.
 28      if (this.model.dock != null) {
 29        this.appendChild(this.model.dock.getElement());
 30      }
 31  
 32      return this;
 33    }
 34  
 35    getModel() {
 36      return this.model;
 37    }
 38  
 39    panelAdded({ panel, index }) {
 40      const panelElement = panel.getElement();
 41      panelElement.classList.add(this.model.getLocation());
 42      if (this.model.isModal()) {
 43        panelElement.classList.add('overlay', 'from-top');
 44      } else {
 45        panelElement.classList.add(
 46          'tool-panel',
 47          `panel-${this.model.getLocation()}`
 48        );
 49      }
 50  
 51      if (index >= this.childNodes.length) {
 52        this.appendChild(panelElement);
 53      } else {
 54        const referenceItem = this.childNodes[index];
 55        this.insertBefore(panelElement, referenceItem);
 56      }
 57  
 58      if (this.model.isModal()) {
 59        this.hideAllPanelsExcept(panel);
 60        this.subscriptions.add(
 61          panel.onDidChangeVisible(visible => {
 62            if (visible) {
 63              this.hideAllPanelsExcept(panel);
 64            }
 65          })
 66        );
 67  
 68        if (panel.autoFocus) {
 69          const focusOptions = {
 70            // focus-trap will attempt to give focus to the first tabbable element
 71            // on activation. If there aren't any tabbable elements,
 72            // give focus to the panel element itself
 73            fallbackFocus: panelElement,
 74            // closing is handled by core Atom commands and this already deactivates
 75            // on visibility changes
 76            escapeDeactivates: false
 77          };
 78  
 79          if (panel.autoFocus !== true) {
 80            focusOptions.initialFocus = panel.autoFocus;
 81          }
 82          const modalFocusTrap = focusTrap(panelElement, focusOptions);
 83  
 84          this.subscriptions.add(
 85            panel.onDidChangeVisible(visible => {
 86              if (visible) {
 87                modalFocusTrap.activate();
 88              } else {
 89                modalFocusTrap.deactivate();
 90              }
 91            })
 92          );
 93        }
 94      }
 95    }
 96  
 97    destroyed() {
 98      this.subscriptions.dispose();
 99      if (this.parentNode != null) {
100        this.parentNode.removeChild(this);
101      }
102    }
103  
104    hideAllPanelsExcept(excludedPanel) {
105      for (let panel of this.model.getPanels()) {
106        if (panel !== excludedPanel) {
107          panel.hide();
108        }
109      }
110    }
111  }
112  
113  module.exports = document.registerElement('atom-panel-container', {
114    prototype: PanelContainerElement.prototype
115  });