diff --git a/spec/panel-container-element-spec.coffee b/spec/panel-container-element-spec.coffee new file mode 100644 index 000000000..3dd6b2b18 --- /dev/null +++ b/spec/panel-container-element-spec.coffee @@ -0,0 +1,63 @@ +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 TestPanelContainerItem + constructior: -> + + class TestPanelContainerItemElement extends HTMLElement + createdCallback: -> + @classList.add('test-root') + setModel: (@model) -> + TestPanelContainerItemElement = document.registerElement 'atom-test-container-item-element', prototype: TestPanelContainerItemElement.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: TestPanelContainerItem + viewConstructor: TestPanelContainerItemElement + + container = new PanelContainer({viewRegistry, location: 'left'}) + element = container.getView() + jasmineContent.appendChild(element) + + it 'has a location attribute with value from the model', -> + expect(element.getAttribute('location')).toBe 'left' + + 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 TestPanelContainerItem(), location: 'left'}) + container.addPanel(panel1) + expect(element.childNodes.length).toBe 1 + + expect(element.childNodes[0].tagName).toBe 'ATOM-PANEL' + + panel2 = new Panel({viewRegistry, item: new TestPanelContainerItem(), location: '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..d4356e6b8 --- /dev/null +++ b/spec/panel-container-spec.coffee @@ -0,0 +1,98 @@ +ViewRegistry = require '../src/view-registry' +Panel = require '../src/panel' +PanelContainer = require '../src/panel-container' + +describe "PanelContainer", -> + [container, viewRegistry] = [] + + 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()) + container.addPanel(panel1) + expect(addPanelSpy).toHaveBeenCalledWith({panel: panel1, index: 0}) + + panel2 = new Panel(item: new TestPanelItem()) + 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()) + container.addPanel(panel1) + panel2 = new Panel(item: new TestPanelItem()) + 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}) + + describe "panel priority", -> + describe 'left / top panel container', -> + [initialPanel] = [] + beforeEach -> + # 'left' logic is the same as 'top' + container = new PanelContainer({viewRegistry, location: 'left'}) + initialPanel = new Panel(item: new TestPanelItem()) + container.addPanel(initialPanel) + + describe 'when a panel with low priority is added', -> + it 'is inserted at the beginning of the list', -> + container.onDidAddPanel addPanelSpy = jasmine.createSpy() + panel = new Panel(item: new TestPanelItem(), priority: 0) + container.addPanel(panel) + + expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0}) + expect(container.getPanels()[0]).toBe panel + + describe 'when a panel with priority between two other panels is added', -> + it 'is inserted at the between the two panels', -> + panel = new Panel(item: new TestPanelItem(), priority: 1000) + container.addPanel(panel) + + container.onDidAddPanel addPanelSpy = jasmine.createSpy() + panel = new Panel(item: new TestPanelItem(), priority: 101) + container.addPanel(panel) + + expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 1}) + expect(container.getPanels()[1]).toBe panel + + describe 'right / bottom panel container', -> + [initialPanel] = [] + beforeEach -> + # 'bottom' logic is the same as 'right' + container = new PanelContainer({viewRegistry, location: 'right'}) + initialPanel = new Panel(item: new TestPanelItem()) + container.addPanel(initialPanel) + + describe 'when a panel with high priority is added', -> + it 'is inserted at the beginning of the list', -> + container.onDidAddPanel addPanelSpy = jasmine.createSpy() + panel = new Panel(item: new TestPanelItem(), priority: 1000) + container.addPanel(panel) + + expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0}) + expect(container.getPanels()[0]).toBe panel + + describe 'when a panel with low priority is added', -> + it 'is inserted at the end of the list', -> + container.onDidAddPanel addPanelSpy = jasmine.createSpy() + panel = new Panel(item: new TestPanelItem(), priority: 0) + container.addPanel(panel) + + expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 1}) + expect(container.getPanels()[1]).toBe panel diff --git a/spec/panel-element-spec.coffee b/spec/panel-element-spec.coffee new file mode 100644 index 000000000..7cf7f8d8b --- /dev/null +++ b/spec/panel-element-spec.coffee @@ -0,0 +1,56 @@ +ViewRegistry = require '../src/view-registry' +Panel = require '../src/panel' +PanelElement = require '../src/panel-element' + +describe "PanelElement", -> + [jasmineContent, element, panel, 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: TestPanelItem + viewConstructor: TestPanelItemElement + + it 'removes the element when the panel is destroyed', -> + panel = new Panel({viewRegistry, item: new TestPanelItem}) + element = panel.getView() + jasmineContent.appendChild(element) + + expect(element.parentNode).toBe jasmineContent + panel.destroy() + expect(element.parentNode).not.toBe jasmineContent + + describe "changing panel visibility", -> + it 'initially renders panel created with visibile: false', -> + panel = new Panel({viewRegistry, visible: false, item: new TestPanelItem}) + element = panel.getView() + jasmineContent.appendChild(element) + + expect(element.style.display).toBe 'none' + + it 'hides and shows the panel element when Panel::hide() and Panel::show() are called', -> + panel = new Panel({viewRegistry, item: new TestPanelItem}) + element = panel.getView() + jasmineContent.appendChild(element) + + expect(element.style.display).not.toBe 'none' + + panel.hide() + expect(element.style.display).toBe 'none' + + panel.show() + expect(element.style.display).not.toBe 'none' diff --git a/spec/panel-spec.coffee b/spec/panel-spec.coffee new file mode 100644 index 000000000..fb5945a7a --- /dev/null +++ b/spec/panel-spec.coffee @@ -0,0 +1,23 @@ +Panel = require '../src/panel' + +describe "Panel", -> + [panel] = [] + + class TestPanelItem + constructior: -> + + beforeEach -> + panel = new Panel(item: new TestPanelItem()) + + describe "changing panel visibility", -> + it 'emits an event when visibility changes', -> + panel.onDidChangeVisible spy = jasmine.createSpy() + + panel.hide() + expect(panel.isVisible()).toBe false + expect(spy).toHaveBeenCalledWith(false) + spy.reset() + + panel.show() + expect(panel.isVisible()).toBe true + expect(spy).toHaveBeenCalledWith(true) diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index e8fb048a7..4b05ba88a 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -226,7 +226,7 @@ addCustomMatchers = (spec) -> notText = if @isNot then " not" else "" element = @actual element = element.get(0) if element.jquery - @message = -> return "Expected element '#{element}' or its descendants #{notText} to show." + @message = -> return "Expected element '#{element}' or its descendants#{notText} to show." element.style.display in ['block', 'inline-block', 'static', 'fixed'] window.keyIdentifierForKey = (key) -> diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 5230fe966..e844acecd 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -456,3 +456,39 @@ describe "Workspace", -> expect(item2.isModified()).toBe false expect(atom.setDocumentEdited).toHaveBeenCalledWith(false) + + describe "adding panels", -> + class TestPanel + constructior: -> + + describe '::addLeftPanel(model)', -> + it 'adds a panel to the correct panel container', -> + atom.workspace.panelContainers.left.onDidAddPanel addPanelSpy = jasmine.createSpy() + panel = atom.workspace.addLeftPanel(item: new TestPanel()) + + expect(panel).toBeDefined() + expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0}) + + describe '::addRightPanel(model)', -> + it 'adds a panel to the correct panel container', -> + atom.workspace.panelContainers.right.onDidAddPanel addPanelSpy = jasmine.createSpy() + panel = atom.workspace.addRightPanel(item: new TestPanel()) + + expect(panel).toBeDefined() + expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0}) + + describe '::addTopPanel(model)', -> + it 'adds a panel to the correct panel container', -> + atom.workspace.panelContainers.top.onDidAddPanel addPanelSpy = jasmine.createSpy() + panel = atom.workspace.addTopPanel(item: new TestPanel()) + + expect(panel).toBeDefined() + expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0}) + + describe '::addBottomPanel(model)', -> + it 'adds a panel to the correct panel container', -> + atom.workspace.panelContainers.bottom.onDidAddPanel addPanelSpy = jasmine.createSpy() + panel = atom.workspace.addBottomPanel(item: new TestPanel()) + + expect(panel).toBeDefined() + expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0}) diff --git a/spec/workspace-view-spec.coffee b/spec/workspace-view-spec.coffee index fd8750910..d37281cc0 100644 --- a/spec/workspace-view-spec.coffee +++ b/spec/workspace-view-spec.coffee @@ -270,3 +270,19 @@ describe "WorkspaceView", -> atom.config.set('editor.lineHeight', '30px') expect(getComputedStyle(editorNode).lineHeight).toBe atom.config.get('editor.lineHeight') expect(editor.getLineHeightInPixels()).not.toBe initialLineHeight + + describe 'panel containers', -> + workspaceElement = null + beforeEach -> + workspaceElement = atom.workspace.getView(atom.workspace) + + it 'inserts panel container elements in the correct places in the DOM', -> + leftContainer = workspaceElement.querySelector('atom-panel-container[location="left"]') + rightContainer = workspaceElement.querySelector('atom-panel-container[location="right"]') + expect(leftContainer.nextSibling).toBe workspaceElement.verticalAxis + expect(rightContainer.previousSibling).toBe workspaceElement.verticalAxis + + topContainer = workspaceElement.querySelector('atom-panel-container[location="top"]') + bottomContainer = workspaceElement.querySelector('atom-panel-container[location="bottom"]') + expect(topContainer.nextSibling).toBe workspaceElement.paneContainer + expect(bottomContainer.previousSibling).toBe workspaceElement.paneContainer diff --git a/src/panel-container-element.coffee b/src/panel-container-element.coffee new file mode 100644 index 000000000..fb5c6684e --- /dev/null +++ b/src/panel-container-element.coffee @@ -0,0 +1,30 @@ +{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)) + + @setAttribute('location', @model.getLocation()) + + 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..4bf7e30ba --- /dev/null +++ b/src/panel-container.coffee @@ -0,0 +1,66 @@ +{Emitter, CompositeDisposable} = require 'event-kit' + +module.exports = +class PanelContainer + constructor: ({@viewRegistry, @location}) -> + @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) + + getLocation: -> @location + + getPanels: -> @panels + + addPanel: (panel) -> + @subscriptions.add panel.onDidDestroy(@panelDestoryed.bind(this)) + + index = @getPanelIndex(panel) + if index is @panels.length + @panels.push(panel) + else + @panels.splice(index, 0, panel) + + @emitter.emit 'did-add-panel', {panel, index} + panel + + panelDestoryed: (panel) -> + index = @panels.indexOf(panel) + if index > -1 + @panels.splice(index, 1) + @emitter.emit 'did-remove-panel', {panel, index} + + getPanelIndex: (panel) -> + priority = panel.getPriority() + if @location in ['bottom', 'right'] + for p, i in @panels by -1 + return i + 1 if priority < p.getPriority() + 0 + else + for p, i in @panels + return i if priority < p.getPriority() + @panels.length diff --git a/src/panel-element.coffee b/src/panel-element.coffee new file mode 100644 index 000000000..87d0fdafc --- /dev/null +++ b/src/panel-element.coffee @@ -0,0 +1,31 @@ +{CompositeDisposable} = require 'event-kit' +{callAttachHooks} = require './space-pen-extensions' + +class PanelElement extends HTMLElement + createdCallback: -> + @subscriptions = new CompositeDisposable + + getModel: -> @model + + setModel: (@model) -> + view = @model.getItemView() + @appendChild(view) + callAttachHooks(view) # for backward compatibility with SpacePen views + + @subscriptions.add @model.onDidChangeVisible(@visibleChanged.bind(this)) + @subscriptions.add @model.onDidDestroy(@destroyed.bind(this)) + + attachedCallback: -> + @visibleChanged(@model.isVisible()) + + visibleChanged: (visible) -> + if visible + @style.display = null + else + @style.display = 'none' + + destroyed: -> + @subscriptions.dispose() + @parentNode?.removeChild(this) + +module.exports = PanelElement = document.registerElement 'atom-panel', prototype: PanelElement.prototype diff --git a/src/panel.coffee b/src/panel.coffee new file mode 100644 index 000000000..048d6840e --- /dev/null +++ b/src/panel.coffee @@ -0,0 +1,78 @@ +{Emitter} = require 'event-kit' + +# Extended: A container representing a panel on the edges of the editor window. +# You should not create a `Panel` directly, instead use {Workspace::addTopPanel} +# and friends to add panels. +# +# Examples: [tree-view](https://github.com/atom/tree-view), +# [status-bar](https://github.com/atom/status-bar), +# and [find-and-replace](https://github.com/atom/find-and-replace) all use +# panels. +module.exports = +class Panel + ### + Section: Construction and Destruction + ### + + constructor: ({@viewRegistry, @item, @visible, @priority}) -> + @emitter = new Emitter + @visible ?= true + @priority ?= 100 + + # Public: Destroy and remove this panel from the UI. + destroy: -> + @emitter.emit 'did-destroy', this + + ### + Section: Event Subscription + ### + + # Public: Invoke the given callback when the pane hidden or shown. + # + # * `callback` {Function} to be called when the pane is destroyed. + # * `visible` {Boolean} true when the panel has been shown + # + # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. + onDidChangeVisible: (callback) -> + @emitter.on 'did-change-visible', callback + + # Public: Invoke the given callback when the pane is destroyed. + # + # * `callback` {Function} to be called when the pane is destroyed. + # * `panel` {Panel} this panel + # + # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. + onDidDestroy: (callback) -> + @emitter.on 'did-destroy', callback + + ### + Section: Panel Details + ### + + # Public: Gets this panel model's view DOM node. + # + # Returns an `` {Element} + getView: -> @viewRegistry.getView(this) + + # Public: Gets your panel contents view. + # + # Returns an {Element} or jQuery element, depeneding on how you created the panel. + getItemView: -> @viewRegistry.getView(@item) + + # Public: Returns a {Number} indicating this panel's priority. + getPriority: -> @priority + + # Public: Returns a {Boolean} true when the panel is visible. + isVisible: -> @visible + + # Public: Hide this panel + hide: -> + wasVisible = @visible + @visible = false + @emitter.emit 'did-change-visible', @visible if wasVisible + + # Public: Show this panel + show: -> + wasVisible = @visible + @visible = true + @emitter.emit 'did-change-visible', @visible unless wasVisible diff --git a/src/workspace-element.coffee b/src/workspace-element.coffee index e50ba8879..031f8af45 100644 --- a/src/workspace-element.coffee +++ b/src/workspace-element.coffee @@ -72,6 +72,18 @@ class WorkspaceElement extends HTMLElement window.addEventListener 'focus', handleWindowFocus @subscriptions.add(new Disposable -> window.removeEventListener 'focus', handleWindowFocus) + @panelContainers = + top: @model.panelContainers.top.getView() + left: @model.panelContainers.left.getView() + right: @model.panelContainers.right.getView() + bottom: @model.panelContainers.bottom.getView() + + @horizontalAxis.insertBefore(@panelContainers.left, @verticalAxis) + @horizontalAxis.appendChild(@panelContainers.right) + + @verticalAxis.insertBefore(@panelContainers.top, @paneContainer) + @verticalAxis.appendChild(@panelContainers.bottom) + @__spacePenView.setModel(@model) setTextEditorFontSize: (fontSize) -> diff --git a/src/workspace-view.coffee b/src/workspace-view.coffee index bb54a5345..28ee66b2f 100644 --- a/src/workspace-view.coffee +++ b/src/workspace-view.coffee @@ -141,59 +141,36 @@ class WorkspaceView extends View Section: Adding elements to the workspace ### - # Essential: Prepend an element or view to the panels at the top of the - # workspace. - # - # * `element` jQuery object or DOM element prependToTop: (element) -> + deprecate 'Please use Workspace::addTopPanel() instead' @vertical.prepend(element) - # Essential: Append an element or view to the panels at the top of the workspace. - # - # * `element` jQuery object or DOM element appendToTop: (element) -> + deprecate 'Please use Workspace::addTopPanel() instead' @panes.before(element) - # Essential: Prepend an element or view to the panels at the bottom of the - # workspace. - # - # * `element` jQuery object or DOM element prependToBottom: (element) -> + deprecate 'Please use Workspace::addBottomPanel() instead' @panes.after(element) - # Essential: Append an element or view to the panels at the bottom of the - # workspace. - # - # * `element` jQuery object or DOM element appendToBottom: (element) -> + deprecate 'Please use Workspace::addBottomPanel() instead' @vertical.append(element) - # Essential: Prepend an element or view to the panels at the left of the - # workspace. - # - # * `element` jQuery object or DOM element prependToLeft: (element) -> + deprecate 'Please use Workspace::addLeftPanel() instead' @horizontal.prepend(element) - # Essential: Append an element or view to the panels at the left of the - # workspace. - # - # * `element` jQuery object or DOM element appendToLeft: (element) -> + deprecate 'Please use Workspace::addLeftPanel() instead' @vertical.before(element) - # Essential: Prepend an element or view to the panels at the right of the - # workspace. - # - # * `element` jQuery object or DOM element prependToRight: (element) -> + deprecate 'Please use Workspace::addRightPanel() instead' @vertical.after(element) - # Essential: Append an element or view to the panels at the right of the - # workspace. - # - # * `element` jQuery object or DOM element appendToRight: (element) -> + deprecate 'Please use Workspace::addRightPanel() instead' @horizontal.append(element) ### diff --git a/src/workspace.coffee b/src/workspace.coffee index 7c072ff77..5b640b61b 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -10,6 +10,10 @@ Grim = require 'grim' TextEditor = require './text-editor' PaneContainer = require './pane-container' Pane = require './pane' +Panel = require './panel' +PanelElement = require './panel-element' +PanelContainer = require './panel-container' +PanelContainerElement = require './panel-container-element' ViewRegistry = require './view-registry' WorkspaceElement = require './workspace-element' @@ -45,6 +49,12 @@ class Workspace extends Model @paneContainer ?= new PaneContainer({@viewRegistry}) @paneContainer.onDidDestroyPaneItem(@onPaneItemDestroyed) + @panelContainers = + top: new PanelContainer({@viewRegistry, location: 'top'}) + left: new PanelContainer({@viewRegistry, location: 'left'}) + right: new PanelContainer({@viewRegistry, location: 'right'}) + bottom: new PanelContainer({@viewRegistry, location: 'bottom'}) + @subscribeToActiveItem() @addOpener (filePath) => @@ -62,6 +72,14 @@ class Workspace extends Model modelConstructor: Workspace viewConstructor: WorkspaceElement + @addViewProvider + modelConstructor: PanelContainer + viewConstructor: PanelContainerElement + + @addViewProvider + modelConstructor: Panel + viewConstructor: PanelElement + # Called by the Serializable mixin during deserialization deserializeParams: (params) -> for packageName in params.packagesWithActiveGrammars ? [] @@ -578,6 +596,76 @@ class Workspace extends Model @paneContainer.destroy() @activeItemSubscriptions?.dispose() + + ### + Section: Panels + ### + + # Essential: Adds a panel item to the bottom of the editor window. + # + # * `options` {Object} + # * `item` Your panel content. It can be DOM element, a jQuery element, or + # a model with a view registered via {::addViewProvider}. We recommend the + # latter. See {::addViewProvider} for more information. + # * `visible` (optional) {Boolean} false if you want the panel to initially be hidden + # (default: true) + # * `priority` (optional) {Number} Determines stacking order. Lower priority items are + # forced closer to the edges of the window. (default: 100) + # + # Returns a {Panel} + addBottomPanel: (options) -> + @addPanel('bottom', options) + + # Essential: Adds a panel item to the left of the editor window. + # + # * `options` {Object} + # * `item` Your panel content. It can be DOM element, a jQuery element, or + # a model with a view registered via {::addViewProvider}. We recommend the + # latter. See {::addViewProvider} for more information. + # * `visible` (optional) {Boolean} false if you want the panel to initially be hidden + # (default: true) + # * `priority` (optional) {Number} Determines stacking order. Lower priority items are + # forced closer to the edges of the window. (default: 100) + # + # Returns a {Panel} + addLeftPanel: (options) -> + @addPanel('left', options) + + # Essential: Adds a panel item to the right of the editor window. + # + # * `options` {Object} + # * `item` Your panel content. It can be DOM element, a jQuery element, or + # a model with a view registered via {::addViewProvider}. We recommend the + # latter. See {::addViewProvider} for more information. + # * `visible` (optional) {Boolean} false if you want the panel to initially be hidden + # (default: true) + # * `priority` (optional) {Number} Determines stacking order. Lower priority items are + # forced closer to the edges of the window. (default: 100) + # + # Returns a {Panel} + addRightPanel: (options) -> + @addPanel('right', options) + + # Essential: Adds a panel item to the top of the editor window above the tabs. + # + # * `options` {Object} + # * `item` Your panel content. It can be DOM element, a jQuery element, or + # a model with a view registered via {::addViewProvider}. We recommend the + # latter. See {::addViewProvider} for more information. + # * `visible` (optional) {Boolean} false if you want the panel to initially be hidden + # (default: true) + # * `priority` (optional) {Number} Determines stacking order. Lower priority items are + # forced closer to the edges of the window. (default: 100) + # + # Returns a {Panel} + addTopPanel: (options) -> + @addPanel('top', options) + + addPanel: (location, options) -> + options ?= {} + options.viewRegistry = @viewRegistry + @panelContainers[location].addPanel(new Panel(options)) + ### Section: View Management ### @@ -628,7 +716,7 @@ class Workspace extends Model # makes [HTML 5 custom elements](http://www.html5rocks.com/en/tutorials/webcomponents/customelements/) # an ideal tool for implementing views in Atom. # - # ## Example + # ## Examples # # Text editors are divided into a model and a view layer, so when you interact # with methods like `atom.workspace.getActiveTextEditor()` you're only going diff --git a/static/panels.less b/static/panels.less index ea842dc7d..687245e3c 100644 --- a/static/panels.less +++ b/static/panels.less @@ -1,5 +1,16 @@ @import "ui-variables"; +atom-panel-container[location="left"], +atom-panel-container[location="right"] { + display: -webkit-flex; + -webkit-flex-direction: row; + -webkit-align-items: stretch; + height: 100%; + atom-panel { + height: 100%; + } +} + // Override bootstrap styles here. .panel { border-radius: 0;