From 5c2e55861c4820a99494de9e95a356c116eefe53 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Thu, 16 Oct 2014 15:33:28 -0700 Subject: [PATCH] Add panel containers --- spec/panel-container-element-spec.coffee | 58 ++++++++++++++++++++++++ spec/panel-container-spec.coffee | 42 +++++++++++++++++ src/panel-container-element.coffee | 28 ++++++++++++ src/panel-container.coffee | 48 ++++++++++++++++++++ 4 files changed, 176 insertions(+) create mode 100644 spec/panel-container-element-spec.coffee create mode 100644 spec/panel-container-spec.coffee create mode 100644 src/panel-container-element.coffee create mode 100644 src/panel-container.coffee diff --git a/spec/panel-container-element-spec.coffee b/spec/panel-container-element-spec.coffee new file mode 100644 index 000000000..f4cb754f5 --- /dev/null +++ b/spec/panel-container-element-spec.coffee @@ -0,0 +1,58 @@ +ViewRegistry = require '../src/view-registry' +Panel = require '../src/panel' +PanelElement = require '../src/panel-element' +PanelContainer = require '../src/panel-container' +PanelContainerElement = require '../src/panel-container-element' + +describe "PanelContainerElement", -> + [jasmineContent, element, container, viewRegistry] = [] + + class TestPanelItem + constructior: -> + + class TestPanelItemElement extends HTMLElement + createdCallback: -> + @classList.add('test-root') + setModel: (@model) -> + TestPanelItemElement = document.registerElement 'atom-test-item-element', prototype: TestPanelItemElement.prototype + + beforeEach -> + jasmineContent = document.body.querySelector('#jasmine-content') + + viewRegistry = new ViewRegistry + viewRegistry.addViewProvider + modelConstructor: Panel + viewConstructor: PanelElement + viewRegistry.addViewProvider + modelConstructor: PanelContainer + viewConstructor: PanelContainerElement + viewRegistry.addViewProvider + modelConstructor: TestPanelItem + viewConstructor: TestPanelItemElement + + container = new PanelContainer({viewRegistry}) + element = container.getView() + jasmineContent.appendChild(element) + + it 'removes the element when the container is destroyed', -> + expect(element.parentNode).toBe jasmineContent + container.destroy() + expect(element.parentNode).not.toBe jasmineContent + + describe "adding and removing panels", -> + it "adds atom-panel elements when a new panel is added to the container; removes them when the panels are destroyed", -> + expect(element.childNodes.length).toBe 0 + + panel1 = new Panel({viewRegistry, item: new TestPanelItem(), orientation: 'left'}) + container.addPanel(panel1) + expect(element.childNodes.length).toBe 1 + + panel2 = new Panel({viewRegistry, item: new TestPanelItem(), orientation: 'left'}) + container.addPanel(panel2) + expect(element.childNodes.length).toBe 2 + + panel1.destroy() + expect(element.childNodes.length).toBe 1 + + panel2.destroy() + expect(element.childNodes.length).toBe 0 diff --git a/spec/panel-container-spec.coffee b/spec/panel-container-spec.coffee new file mode 100644 index 000000000..8afc7a439 --- /dev/null +++ b/spec/panel-container-spec.coffee @@ -0,0 +1,42 @@ +ViewRegistry = require '../src/view-registry' +Panel = require '../src/panel' +PanelContainer = require '../src/panel-container' + +describe "PanelContainer", -> + [container] = [] + + class TestPanelItem + constructior: -> + + beforeEach -> + viewRegistry = new ViewRegistry + container = new PanelContainer({viewRegistry}) + + describe "::addPanel(panel)", -> + it 'emits an onDidAddPanel event with the index the panel was inserted at', -> + container.onDidAddPanel addPanelSpy = jasmine.createSpy() + + panel1 = new Panel(item: new TestPanelItem(), orientation: 'left') + container.addPanel(panel1) + expect(addPanelSpy).toHaveBeenCalledWith({panel: panel1, index: 0}) + + panel2 = new Panel(item: new TestPanelItem(), orientation: 'left') + container.addPanel(panel2) + expect(addPanelSpy).toHaveBeenCalledWith({panel: panel2, index: 1}) + + describe "when a panel is destroyed", -> + it 'emits an onDidRemovePanel event with the index of the removed item', -> + container.onDidRemovePanel removePanelSpy = jasmine.createSpy() + + panel1 = new Panel(item: new TestPanelItem(), orientation: 'left') + container.addPanel(panel1) + panel2 = new Panel(item: new TestPanelItem(), orientation: 'left') + container.addPanel(panel2) + + expect(removePanelSpy).not.toHaveBeenCalled() + + panel2.destroy() + expect(removePanelSpy).toHaveBeenCalledWith({panel: panel2, index: 1}) + + panel1.destroy() + expect(removePanelSpy).toHaveBeenCalledWith({panel: panel1, index: 0}) diff --git a/src/panel-container-element.coffee b/src/panel-container-element.coffee new file mode 100644 index 000000000..dca4adce3 --- /dev/null +++ b/src/panel-container-element.coffee @@ -0,0 +1,28 @@ +{CompositeDisposable} = require 'event-kit' + +class PanelContainerElement extends HTMLElement + createdCallback: -> + @subscriptions = new CompositeDisposable + + getModel: -> @model + + setModel: (@model) -> + @subscriptions.add @model.onDidAddPanel(@panelAdded.bind(this)) + @subscriptions.add @model.onDidRemovePanel(@panelRemoved.bind(this)) + @subscriptions.add @model.onDidDestroy(@destroyed.bind(this)) + + panelAdded: ({panel, index}) -> + if index >= @childNodes.length + @appendChild(panel.getView()) + else + referenceItem = @childNodes[index + 1] + @insertBefore(panel.getView(), referenceItem) + + panelRemoved: ({panel, index}) -> + @removeChild(@childNodes[index]) + + destroyed: -> + @subscriptions.dispose() + @parentNode?.removeChild(this) + +module.exports = PanelContainerElement = document.registerElement 'atom-panel-container', prototype: PanelContainerElement.prototype diff --git a/src/panel-container.coffee b/src/panel-container.coffee new file mode 100644 index 000000000..3ea807769 --- /dev/null +++ b/src/panel-container.coffee @@ -0,0 +1,48 @@ +{Emitter, CompositeDisposable} = require 'event-kit' + +# Public: +module.exports = +class PanelContainer + constructor: ({@viewRegistry}) -> + @emitter = new Emitter + @subscriptions = new CompositeDisposable + @panels = [] + + destroy: -> + pane.destroy() for pane in @getPanels() + @subscriptions.dispose() + @emitter.emit 'did-destroy', this + @emitter.dispose() + + ### + Section: Event Subscription + ### + + onDidAddPanel: (callback) -> + @emitter.on 'did-add-panel', callback + + onDidRemovePanel: (callback) -> + @emitter.on 'did-remove-panel', callback + + onDidDestroy: (callback) -> + @emitter.on 'did-destroy', callback + + ### + Section: Panels + ### + + getView: -> @viewRegistry.getView(this) + + getPanels: -> @panels + + addPanel: (panel) -> + @subscriptions.add panel.onDidDestroy(@panelDestoryed.bind(this)) + index = @panels.length + @panels.push(panel) + @emitter.emit 'did-add-panel', {panel, index} + + panelDestoryed: (panel) -> + index = @panels.indexOf(panel) + if index > -1 + @panels.splice(index, 1) + @emitter.emit 'did-remove-panel', {panel, index}