From 57b205d50896f767a6080bfa966c988063cb026b Mon Sep 17 00:00:00 2001 From: Corey Johnson & Nathan Sobo Date: Fri, 13 Apr 2012 12:49:59 -0600 Subject: [PATCH] When a Pane is removed, layout of #panes div is adjusted appropriately --- spec/app/editor-spec.coffee | 2 +- spec/app/root-view-spec.coffee | 296 ++++++++++++++------------------- src/app/editor.coffee | 8 +- src/app/pane.coffee | 13 +- src/app/root-view.coffee | 1 + 5 files changed, 143 insertions(+), 177 deletions(-) diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index d35cb05cb..6e4a6d696 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -2149,7 +2149,7 @@ describe "Editor", -> describe "when inside a pane", -> fakePane = null beforeEach -> - fakePane = { splitUp: jasmine.createSpy('splitUp') } + fakePane = { splitUp: jasmine.createSpy('splitUp').andReturn {} } spyOn(editor, 'pane').andReturn(fakePane) it "calls the corresponding split method on the containing pane with a copy of the editor", -> diff --git a/spec/app/root-view-spec.coffee b/spec/app/root-view-spec.coffee index 1a57e1156..e84c7c935 100644 --- a/spec/app/root-view-spec.coffee +++ b/spec/app/root-view-spec.coffee @@ -115,229 +115,183 @@ describe "RootView", -> expect(rootView).not.toMatchSelector(':focus') expect(rootView.activeEditor().isFocused).toBeTruthy() - describe "split editor panes", -> - editor1 = null + describe "panes", -> + pane1 = null beforeEach -> rootView.attachToDom() - editor1 = rootView.find('.editor').view() - editor1.setBuffer(new Buffer(require.resolve 'fixtures/sample.js')) - editor1.setCursorScreenPosition([3, 2]) rootView.width(800) rootView.height(600) + pane1 = rootView.find('.pane').view() + pane1.attr('id', 'pane-1') describe "vertical splits", -> - describe "when split-right is triggered on the editor", -> - it "places a new editor to the right of the current editor in a .horizontal div, and focuses the new editor", -> + describe "when .splitRight(view) is called on a pane", -> + it "places a new pane to the right of the current pane in a .row div", -> + expect(rootView.panes.find('.row')).not.toExist() + + pane2 = pane1.splitRight("
New pane content
") + + expect(rootView.panes.find('.row')).toExist() + expect(rootView.panes.find('.row .pane').length).toBe 2 + [leftPane, rightPane] = rootView.panes.find('.row .pane').map -> $(this) + expect(rightPane[0]).toBe pane2[0] + expect(leftPane.attr('id')).toBe 'pane-1' + expect(rightPane.html()).toBe "
New pane content
" + + expectedColumnWidth = Math.floor(rootView.panes.width() / 2) + expect(leftPane.outerWidth()).toBe expectedColumnWidth + expect(rightPane.position().left).toBe expectedColumnWidth + expect(rightPane.outerWidth()).toBe expectedColumnWidth + + pane2.remove() + + expect(rootView.panes.find('.row')).not.toExist() + expect(rootView.panes.find('.pane').length).toBe 1 + expect(pane1.outerWidth()).toBe rootView.panes.width() + + describe "when splitLeft(view) is called on a pane", -> + it "places a new pane to the left of the current pane in a .row div", -> expect(rootView.find('.row')).not.toExist() - editor1.trigger 'split-right' + pane2 = pane1.splitLeft("
New pane content
") expect(rootView.find('.row')).toExist() - expect(rootView.find('.row .pane .editor').length).toBe 2 - expect(rootView.find('.row .editor:eq(0)').view()).toBe editor1 + expect(rootView.find('.row .pane').length).toBe 2 + [leftPane, rightPane] = rootView.find('.row .pane').map -> $(this) + expect(leftPane[0]).toBe pane2[0] + expect(rightPane.attr('id')).toBe 'pane-1' + expect(leftPane.html()).toBe "
New pane content
" - editor2 = rootView.find('.row .editor:eq(1)').view() + expectedColumnWidth = Math.floor(rootView.panes.width() / 2) + expect(leftPane.outerWidth()).toBe expectedColumnWidth + expect(rightPane.position().left).toBe expectedColumnWidth + expect(rightPane.outerWidth()).toBe expectedColumnWidth - expect(editor2.buffer).toBe editor1.buffer - expect(editor2.getCursorScreenPosition()).toEqual [3, 2] + pane2.remove() - [pane1, pane2] = [editor1.parent(), editor2.parent()] - expectedColumnWidth = Math.floor(rootView.width() / 2) - expect(pane1.outerWidth()).toBe expectedColumnWidth - expect(pane2.position().left).toBe expectedColumnWidth - expect(pane2.outerWidth()).toBe expectedColumnWidth - - expect(editor1.has(':focus')).not.toExist() - expect(editor2.has(':focus')).toExist() - - # insertion reflected in both buffers - editor1.buffer.insert([0, 0], 'ABC') - expect(editor1.lines.find('.line:first').text()).toContain 'ABC' - expect(editor2.lines.find('.line:first').text()).toContain 'ABC' - - describe "when split-left is triggered on the editor", -> - it "places a new editor to the left of the current editor in a .row div, and focuses the new editor", -> - expect(rootView.find('.row')).not.toExist() - - editor1.trigger 'split-left' - - expect(rootView.find('.row')).toExist() - expect(rootView.find('.row .editor').length).toBe 2 - expect(rootView.find('.row .editor:eq(1)').view()).toBe editor1 - editor2 = rootView.find('.row .editor:eq(0)').view() - expect(editor2.buffer).toBe editor1.buffer - expect(editor2.getCursorScreenPosition()).toEqual [3, 2] - - [pane1, pane2] = [editor1.parent(), editor2.parent()] - expectedColumnWidth = Math.floor(rootView.width() / 2) - expect(pane2.outerWidth()).toBe expectedColumnWidth - expect(pane1.position().left).toBe expectedColumnWidth - expect(pane1.outerWidth()).toBe expectedColumnWidth - - expect(editor1.has(':focus')).not.toExist() - expect(editor2.has(':focus')).toExist() - - # insertion reflected in both buffers - editor1.buffer.insert([0, 0], 'ABC') - expect(editor1.lines.find('.line:first').text()).toContain 'ABC' - expect(editor2.lines.find('.line:first').text()).toContain 'ABC' + expect(rootView.panes.find('.row')).not.toExist() + expect(rootView.panes.find('.pane').length).toBe 1 + expect(pane1.outerWidth()).toBe rootView.panes.width() describe "horizontal splits", -> - describe "when split-up is triggered on the editor", -> - it "places a new editor below the current editor in a .vertical div, and focuses the new editor", -> - expect(rootView.find('.vertical')).not.toExist() - - editor1.trigger 'split-up' - - expect(rootView.find('.column')).toExist() - expect(rootView.find('.column .editor').length).toBe 2 - expect(rootView.find('.column .editor:eq(1)').view()).toBe editor1 - editor2 = rootView.find('.column .editor:eq(0)').view() - expect(editor2.buffer).toBe editor1.buffer - expect(editor2.getCursorScreenPosition()).toEqual [3, 2] - - [pane1, pane2] = [editor1.parent(), editor2.parent()] - expectedRowHeight = Math.floor(rootView.height() / 2) - expect(pane2.outerHeight()).toBe expectedRowHeight - expect(pane1.position().top).toBe expectedRowHeight - expect(pane1.outerHeight()).toBe expectedRowHeight - - expect(editor1.has(':focus')).not.toExist() - expect(editor2.has(':focus')).toExist() - - # insertion reflected in both buffers - editor1.buffer.insert([0, 0], 'ABC') - expect(editor1.lines.find('.line:first').text()).toContain 'ABC' - expect(editor2.lines.find('.line:first').text()).toContain 'ABC' - - describe "when split-down is triggered on the editor", -> - it "places a new editor below the current editor in a .vertical div, and focuses the new editor", -> + describe "when splitUp(view) is called on a pane", -> + it "places a new pane above the current pane in a .column div", -> expect(rootView.find('.column')).not.toExist() - editor1.trigger 'split-down' + pane2 = pane1.splitUp("
New pane content
") expect(rootView.find('.column')).toExist() - expect(rootView.find('.column .editor').length).toBe 2 - expect(rootView.find('.column .editor:eq(0)').view()).toBe editor1 - editor2 = rootView.find('.column .editor:eq(1)').view() - expect(editor2.buffer).toBe editor1.buffer - expect(editor2.getCursorScreenPosition()).toEqual [3, 2] + expect(rootView.find('.column .pane').length).toBe 2 + [topPane, bottomPane] = rootView.find('.column .pane').map -> $(this) + expect(topPane[0]).toBe pane2[0] + expect(bottomPane.attr('id')).toBe 'pane-1' + expect(topPane.html()).toBe "
New pane content
" - [pane1, pane2] = [editor1.parent(), editor2.parent()] - expectedRowHeight = Math.floor(rootView.height() / 2) - expect(pane1.outerHeight()).toBe expectedRowHeight - expect(pane2.position().top).toBe expectedRowHeight - expect(pane2.outerHeight()).toBe expectedRowHeight + expectedRowHeight = Math.floor(rootView.panes.height() / 2) + expect(topPane.outerHeight()).toBe expectedRowHeight + expect(bottomPane.position().top).toBe expectedRowHeight + expect(bottomPane.outerHeight()).toBe expectedRowHeight - expect(editor1.has(':focus')).not.toExist() - expect(editor2.has(':focus')).toExist() + pane2.remove() - # insertion reflected in both buffers - editor1.buffer.insert([0, 0], 'ABC') - expect(editor1.lines.find('.line:first').text()).toContain 'ABC' - expect(editor2.lines.find('.line:first').text()).toContain 'ABC' + expect(rootView.panes.find('.column')).not.toExist() + expect(rootView.panes.find('.pane').length).toBe 1 + expect(pane1.outerHeight()).toBe rootView.panes.height() + + describe "when splitDown(view) is called on a pane", -> + it "places a new pane below the current pane in a .column div", -> + expect(rootView.find('.column')).not.toExist() + + pane2 = pane1.splitDown("
New pane content
") + + expect(rootView.find('.column')).toExist() + expect(rootView.find('.column .pane').length).toBe 2 + [topPane, bottomPane] = rootView.find('.column .pane').map -> $(this) + expect(bottomPane[0]).toBe pane2[0] + expect(topPane.attr('id')).toBe 'pane-1' + expect(bottomPane.html()).toBe "
New pane content
" + + expectedRowHeight = Math.floor(rootView.panes.height() / 2) + expect(topPane.outerHeight()).toBe expectedRowHeight + expect(bottomPane.position().top).toBe expectedRowHeight + expect(bottomPane.outerHeight()).toBe expectedRowHeight + + pane2.remove() + + expect(rootView.panes.find('.column')).not.toExist() + expect(rootView.panes.find('.pane').length).toBe 1 + expect(pane1.outerHeight()).toBe rootView.panes.height() describe "layout of nested vertical and horizontal splits", -> it "lays out rows and columns with a consistent width", -> - editor = rootView.find('.editor:has(:focus)').view() - editor.trigger 'split-left' - editor = rootView.find('.editor:has(:focus)').view() - editor.trigger 'split-up' - editor = rootView.find('.editor:has(:focus)').view() - editor.trigger 'split-left' - editor = rootView.find('.editor:has(:focus)').view() - editor.trigger 'split-up' + pane1.html("1") + + pane1 + .splitLeft("2") + .splitUp("3") + .splitLeft("4") + .splitDown("5") row1 = rootView.panes.children(':eq(0)') expect(row1.children().length).toBe 2 - column1 = row1.children(':eq(0)') - pane1 = row1.children(':eq(1)') - expect(column1.outerWidth()).toBe Math.floor(2/3 * rootView.width()) + column1 = row1.children(':eq(0)').view() + pane1 = row1.children(':eq(1)').view() + expect(column1.outerWidth()).toBe Math.floor(2/3 * rootView.panes.width()) expect(column1.outerHeight()).toBe rootView.height() - expect(pane1.outerWidth()).toBe Math.floor(1/3 * rootView.width()) + expect(pane1.outerWidth()).toBe Math.floor(1/3 * rootView.panes.width()) expect(pane1.outerHeight()).toBe rootView.height() expect(pane1.position().left).toBe column1.outerWidth() expect(column1.children().length).toBe 2 - row2 = column1.children(':eq(0)') - pane2 = column1.children(':eq(1)') + row2 = column1.children(':eq(0)').view() + pane2 = column1.children(':eq(1)').view() expect(row2.outerWidth()).toBe column1.outerWidth() - expect(row2.height()).toBe Math.floor(2/3 * rootView.height()) + expect(row2.height()).toBe Math.floor(2/3 * rootView.panes.height()) expect(pane2.outerWidth()).toBe column1.outerWidth() - expect(pane2.outerHeight()).toBe Math.floor(1/3 * rootView.height()) + expect(pane2.outerHeight()).toBe Math.floor(1/3 * rootView.panes.height()) expect(pane2.position().top).toBe row2.height() expect(row2.children().length).toBe 2 - column3 = row2.children(':eq(0)') - pane3 = row2.children(':eq(1)') - expect(column3.outerWidth()).toBe Math.floor(1/3 * rootView.width()) + column3 = row2.children(':eq(0)').view() + pane3 = row2.children(':eq(1)').view() + expect(column3.outerWidth()).toBe Math.floor(1/3 * rootView.panes.width()) expect(column3.outerHeight()).toBe row2.outerHeight() - expect(pane3.outerWidth()).toBe Math.floor(1/3 * rootView.width()) + expect(pane3.outerWidth()).toBe Math.floor(1/3 * rootView.panes.width()) expect(pane3.height()).toBe row2.outerHeight() expect(pane3.position().left).toBe column3.width() expect(column3.children().length).toBe 2 - pane4 = column3.children(':eq(0)') - pane5 = column3.children(':eq(1)') + pane4 = column3.children(':eq(0)').view() + pane5 = column3.children(':eq(1)').view() expect(pane4.outerWidth()).toBe column3.width() - expect(pane4.outerHeight()).toBe Math.floor(1/3 * rootView.height()) + expect(pane4.outerHeight()).toBe Math.floor(1/3 * rootView.panes.height()) expect(pane5.outerWidth()).toBe column3.width() expect(pane5.position().top).toBe pane4.outerHeight() - expect(pane5.outerHeight()).toBe Math.floor(1/3 * rootView.height()) + expect(pane5.outerHeight()).toBe Math.floor(1/3 * rootView.panes.height()) - describe "when close is triggered on an editor pane", -> - it "adjusts the layout, focuses the next most-recently active editor, and focuses the RootView when there are no remaining editors", -> - spyOn(window, 'close') - editor = rootView.find('.editor').view() - editor.trigger 'split-right' - editor.trigger 'split-right' - editor.trigger 'split-right' + pane5.remove() - [editor1, editor2, editor3, editor4] = rootView.find('.editor').map -> $(this).view() - [pane1, pane2, pane3, pane4] = [editor1.parent(), editor2.parent(), editor3.parent(), editor4.parent()] + expect(column3.parent()).not.toExist() + expect(pane2.outerHeight()).toBe Math.floor(1/2 * rootView.panes.height()) + expect(pane3.outerHeight()).toBe Math.floor(1/2 * rootView.panes.height()) + expect(pane4.outerHeight()).toBe Math.floor(1/2 * rootView.panes.height()) - editor4.focus() - editor4.trigger 'close' - expect(editor1.isFocused).toBeTruthy() - expect(pane1.outerWidth()).toBe Math.floor(rootView.width() / 3) - expect(pane2.outerWidth()).toBe Math.floor(rootView.width() / 3) - expect(pane3.outerWidth()).toBe Math.floor(rootView.width() / 3) + pane4.remove() + expect(row2.parent()).not.toExist() + expect(pane1.outerWidth()).toBe Math.floor(1/2 * rootView.panes.width()) + expect(pane2.outerWidth()).toBe Math.floor(1/2 * rootView.panes.width()) + expect(pane3.outerWidth()).toBe Math.floor(1/2 * rootView.panes.width()) - editor3.focus() - editor3.trigger 'close' - expect(editor1.isFocused).toBeTruthy() - expect(pane1.outerWidth()).toBe Math.floor(rootView.width() / 2) - expect(pane2.outerWidth()).toBe Math.floor(rootView.width() / 2) + pane3.remove() + expect(column1.parent()).not.toExist() + expect(pane2.outerHeight()).toBe rootView.panes.height() - editor1.trigger 'close' - expect(editor2.isFocused).toBeTruthy() - expect(pane2.outerWidth()).toBe Math.floor(rootView.width()) - - expect(window.close).not.toHaveBeenCalled() - editor2.trigger 'close' - - expect(rootView).toMatchSelector(':focus') - - it "removes a containing row if it becomes empty", -> - editor = rootView.find('.editor').view() - editor.trigger 'split-up' - editor.trigger 'split-left' - - rootView.find('.row .editor').trigger 'close' - expect(rootView.find('.row')).not.toExist() - expect(rootView.find('.column')).toExist() - - it "removes a containing column if it becomes empty", -> - editor = rootView.find('.editor').view() - editor.trigger 'split-left' - editor.trigger 'split-up' - - rootView.find('.column .editor').trigger 'close' - expect(rootView.find('.column')).not.toExist() - expect(rootView.find('.row')).toExist() - - expect(rootView.find('.editor').outerWidth()).toBe rootView.width() + pane2.remove() + expect(row1.parent()).not.toExist() + expect(rootView.panes.children().length).toBe 1 + expect(rootView.panes.children('.pane').length).toBe 1 + expect(pane1.outerWidth()).toBe rootView.panes.width() describe "the file finder", -> describe "when the toggle-file-finder event is triggered", -> diff --git a/src/app/editor.coffee b/src/app/editor.coffee index d6935eac8..5246a52f6 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -494,16 +494,16 @@ class Editor extends View @setCursorBufferPosition(fold.start) splitLeft: -> - @pane()?.splitLeft(@copy()) + @pane()?.splitLeft(@copy()).wrappedView splitRight: -> - @pane()?.splitRight(@copy()) + @pane()?.splitRight(@copy()).wrappedView splitUp: -> - @pane()?.splitUp(@copy()) + @pane()?.splitUp(@copy()).wrappedView splitDown: -> - @pane()?.splitDown(@copy()) + @pane()?.splitDown(@copy()).wrappedView pane: -> @parent('.pane').view() diff --git a/src/app/pane.coffee b/src/app/pane.coffee index 4fb4109bf..286e07a00 100644 --- a/src/app/pane.coffee +++ b/src/app/pane.coffee @@ -44,7 +44,18 @@ class Pane extends View pane = new Pane(view) this[side](pane) @rootView().adjustPaneDimensions() - view + pane + + remove: (selector, keepData) -> + return super if keepData + # find parent elements before removing from dom + parentAxis = @parent('.row, .column') + rootView = @rootView() + super + if parentAxis.children().length == 1 + sibling = parentAxis.children().detach() + parentAxis.replaceWith(sibling) + rootView.adjustPaneDimensions() buildPaneAxis: (axis) -> switch axis diff --git a/src/app/root-view.coffee b/src/app/root-view.coffee index d1ce1c1d5..867a3e36e 100644 --- a/src/app/root-view.coffee +++ b/src/app/root-view.coffee @@ -107,6 +107,7 @@ class RootView extends View adjustPaneDimensions: -> rootPane = @panes.children().first().view() + rootPane?.css(width: '100%', height: '100%') rootPane?.adjustDimensions() toggleFileFinder: ->