From 019260af67fef1b6b9bf2c3010ae9ee0a9e84d31 Mon Sep 17 00:00:00 2001 From: Alexander Olsson Date: Tue, 15 Sep 2015 21:16:42 +0200 Subject: [PATCH 1/8] BuildView: build panel orientation setting Allow to attach the build panel to left, right, top or bottom. This allows people with very wide screens to have them to the right, or to the left. Top might be preferrable by some, so add that too. Solves #171 Solves #88 --- lib/build-view.js | 83 +++++++++++++++++++++++++--------- lib/build.js | 8 ++++ spec/build-error-match-spec.js | 1 - styles/build.less | 3 +- 4 files changed, 72 insertions(+), 23 deletions(-) diff --git a/lib/build-view.js b/lib/build-view.js index f743f3e4..567fab0f 100644 --- a/lib/build-view.js +++ b/lib/build-view.js @@ -3,6 +3,7 @@ var _ = require('lodash'); var View = require('atom-space-pen-views').View; +var $ = require('atom-space-pen-views').$; var ansi_up = require('ansi_up'); var cscompatability = require('./cscompatability'); var GoogleAnalytics = require('./google-analytics'); @@ -21,9 +22,12 @@ module.exports = (function() { this.buffer = new Buffer(0); this.links = []; + this._setMonocleIcon(); + atom.config.observe('build.panelVisibility', this.visibleFromConfig.bind(this)); - atom.config.observe('build.monocleHeight', this.heightFromConfig.bind(this)); - atom.config.observe('build.minimizedHeight', this.heightFromConfig.bind(this)); + atom.config.observe('build.panelOrientation', this.orientationFromConfig.bind(this)); + atom.config.observe('build.monocleHeight', this.sizeFromConfig.bind(this)); + atom.config.observe('build.minimizedHeight', this.sizeFromConfig.bind(this)); atom.commands.add('atom-workspace', 'build:toggle-panel', this.toggle.bind(this)); } @@ -62,9 +66,15 @@ module.exports = (function() { if (this.panel) { this.panel.destroy(); } - this.panel = atom.workspace.addBottomPanel({ item: this }); - this.height = this.output.offset().top + this.output.height(); - this.heightFromConfig(); + let addfn = { + Top: atom.workspace.addTopPanel, + Bottom: atom.workspace.addBottomPanel, + Left: atom.workspace.addLeftPanel, + Right: atom.workspace.addRightPanel + }; + let orientation = atom.config.get('build.panelOrientation') || 'Bottom'; + this.panel = addfn[orientation].call(atom.workspace, { item: this }); + this.sizeFromConfig(); }; BuildView.prototype.detach = function(force) { @@ -82,12 +92,8 @@ module.exports = (function() { return !!this.panel; }; - BuildView.prototype.heightFromConfig = function() { - if (this.monocle) { - this.setHeightPercent(atom.config.get('build.monocleHeight')); - } else { - this.setHeightPercent(atom.config.get('build.minimizedHeight')); - } + BuildView.prototype.sizeFromConfig = function() { + this.setSizePercent(atom.config.get(this.monocle ? 'build.monocleHeight' : 'build.minimizedHeight')); }; BuildView.prototype.visibleFromConfig = function(val) { @@ -101,6 +107,15 @@ module.exports = (function() { } }; + BuildView.prototype.orientationFromConfig = function (val) { + let isVisible = this.isVisible(); + this.detach(true); + if (isVisible) { + this.attach(); + this._setMonocleIcon(); + } + }; + BuildView.prototype.reset = function() { clearTimeout(this.titleTimer); this.buffer = new Buffer(0); @@ -137,21 +152,47 @@ module.exports = (function() { atom.commands.dispatch(atom.views.getView(atom.workspace), 'build:trigger'); }; - BuildView.prototype.setHeightPercent = function(percent) { - var newHeight = percent * this.height; - this.output.css('height', newHeight + 'px'); + BuildView.prototype.setSizePercent = function(percent) { + let size = 0, cssKey = 'height'; + switch (atom.config.get('build.panelOrientation')) { + case 'Top': + case 'Bottom': + size = $('atom-workspace-axis.vertical').height(); + cssKey = 'height'; + break; + + case 'Left': + case 'Right': + size = $('atom-workspace-axis.vertical').width(); + if ($('.build').length) { + size += $('.build').get(0).clientWidth; + } + cssKey = 'width'; + break; + } + this.output.css(cssKey, percent * size + 'px'); + }; + + BuildView.prototype._setMonocleIcon = function () { + let iconName = () => { + switch (atom.config.get('build.panelOrientation')) { + case 'Top': return this.monocle ? 'icon-chevron-up' : 'icon-chevron-down'; + case 'Bottom': return this.monocle ? 'icon-chevron-down' : 'icon-chevron-up'; + case 'Right': return this.monocle ? 'icon-chevron-right' : 'icon-chevron-left'; + case 'Left': return this.monocle ? 'icon-chevron-left' : 'icon-chevron-right'; + } + }; + + this.monocleButton + .removeClass('icon-chevron-down icon-chevron-up icon-chevron-left icon-chevron-right') + .addClass(iconName()); }; BuildView.prototype.toggleMonocle = function(event, element) { GoogleAnalytics.sendEvent('view', 'monocle toggled'); - if (!this.monocle) { - this.setHeightPercent(atom.config.get('build.monocleHeight')); - this.monocleButton.removeClass('icon-chevron-up').addClass('icon-chevron-down'); - } else { - this.setHeightPercent(atom.config.get('build.minimizedHeight')); - this.monocleButton.removeClass('icon-chevron-down').addClass('icon-chevron-up'); - } this.monocle = !this.monocle; + this.setSizePercent(atom.config.get(this.monocle ? 'build.monocleHeight' : 'build.minimizedHeight')); + this._setMonocleIcon(); }; BuildView.prototype.buildStarted = function() { diff --git a/lib/build.js b/lib/build.js index 149c42ad..69c59bb5 100644 --- a/lib/build.js +++ b/lib/build.js @@ -80,6 +80,14 @@ module.exports = { minimum: 0.1, maximum: 0.9, order: 7 + }, + panelOrientation: { + title: 'Panel Orientation', + description: 'Where to attach the build panel', + type: 'string', + default: 'Bottom', + enum: [ 'Bottom', 'Top', 'Left', 'Right' ], + order: 8 } }, diff --git a/spec/build-error-match-spec.js b/spec/build-error-match-spec.js index 48362318..fb30c433 100644 --- a/spec/build-error-match-spec.js +++ b/spec/build-error-match-spec.js @@ -1,4 +1,3 @@ -'use babel'; 'use strict'; var fs = require('fs-extra'); diff --git a/styles/build.less b/styles/build.less index 9011589c..729043c4 100644 --- a/styles/build.less +++ b/styles/build.less @@ -30,7 +30,8 @@ } .output { - transition: height 0.5s ease-in-out; + transition: 0.5s ease-in-out; + transition-property: width, height; padding: 10px 0 0 10px; min-height: 100px; overflow-y: auto; From c3c4eea085c1f513b3f3b071351a1b895da75fa2 Mon Sep 17 00:00:00 2001 From: Alexander Olsson Date: Wed, 16 Sep 2015 19:21:16 +0200 Subject: [PATCH 2/8] Build View: Reset width/height When changing the orientation, the width and height needs to be reset to the default value. --- lib/build-view.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/build-view.js b/lib/build-view.js index 567fab0f..0a54e88a 100644 --- a/lib/build-view.js +++ b/lib/build-view.js @@ -170,6 +170,8 @@ module.exports = (function() { cssKey = 'width'; break; } + this.output.css('width', 'auto'); + this.output.css('height', 'auto'); this.output.css(cssKey, percent * size + 'px'); }; From 86d067a45e3f1affed888846da489b01abea6ee0 Mon Sep 17 00:00:00 2001 From: Alexander Olsson Date: Wed, 16 Sep 2015 19:44:02 +0200 Subject: [PATCH 3/8] BuildView: panel orientation specs --- spec/build-view-spec.js | 86 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/spec/build-view-spec.js b/spec/build-view-spec.js index 4b1bc8fa..004d66e8 100644 --- a/spec/build-view-spec.js +++ b/spec/build-view-spec.js @@ -160,4 +160,90 @@ describe('Visible', function() { }); }); }); + + describe('when panel orientation is altered', function () { + it('should show the panel at the bottom spot', function () { + expect(workspaceElement.querySelector('.build')).not.toExist(); + atom.config.set('build.panelOrientation', 'Bottom'); + + fs.writeFileSync(directory + '.atom-build.json', JSON.stringify({ + cmd: 'echo this will fail && exit 1', + })); + atom.commands.dispatch(workspaceElement, 'build:trigger'); + + waitsFor(function() { + return workspaceElement.querySelector('.build .title') && + workspaceElement.querySelector('.build .title').classList.contains('error'); + }); + + runs(function() { + var bottomPanels = atom.workspace.getBottomPanels(); + expect(bottomPanels.length).toEqual(1); + expect(bottomPanels[0].item.constructor.name).toEqual('BuildView'); + }); + }); + + it('should show the panel at the bottom spot', function () { + expect(workspaceElement.querySelector('.build')).not.toExist(); + atom.config.set('build.panelOrientation', 'Left'); + + fs.writeFileSync(directory + '.atom-build.json', JSON.stringify({ + cmd: 'echo this will fail && exit 1', + })); + atom.commands.dispatch(workspaceElement, 'build:trigger'); + + waitsFor(function() { + return workspaceElement.querySelector('.build .title') && + workspaceElement.querySelector('.build .title').classList.contains('error'); + }); + + runs(function() { + var panels = atom.workspace.getLeftPanels(); + expect(panels.length).toEqual(1); + expect(panels[0].item.constructor.name).toEqual('BuildView'); + }); + }); + + it('should show the panel at the bottom spot', function () { + expect(workspaceElement.querySelector('.build')).not.toExist(); + atom.config.set('build.panelOrientation', 'Top'); + + fs.writeFileSync(directory + '.atom-build.json', JSON.stringify({ + cmd: 'echo this will fail && exit 1', + })); + atom.commands.dispatch(workspaceElement, 'build:trigger'); + + waitsFor(function() { + return workspaceElement.querySelector('.build .title') && + workspaceElement.querySelector('.build .title').classList.contains('error'); + }); + + runs(function() { + var panels = atom.workspace.getTopPanels(); + expect(panels.length).toEqual(1); + expect(panels[0].item.constructor.name).toEqual('BuildView'); + }); + }); + + it('should show the panel at the bottom spot', function () { + expect(workspaceElement.querySelector('.build')).not.toExist(); + atom.config.set('build.panelOrientation', 'Right'); + + fs.writeFileSync(directory + '.atom-build.json', JSON.stringify({ + cmd: 'echo this will fail && exit 1', + })); + atom.commands.dispatch(workspaceElement, 'build:trigger'); + + waitsFor(function() { + return workspaceElement.querySelector('.build .title') && + workspaceElement.querySelector('.build .title').classList.contains('error'); + }); + + runs(function() { + var panels = atom.workspace.getRightPanels(); + expect(panels.length).toEqual(1); + expect(panels[0].item.constructor.name).toEqual('BuildView'); + }); + }); + }); }); From 0240d811214c602fc92a8895ba5f93b6b31ebb93 Mon Sep 17 00:00:00 2001 From: Alexander Olsson Date: Wed, 16 Sep 2015 19:48:31 +0200 Subject: [PATCH 4/8] Specs: Correct name of BuildView specs --- spec/build-view-spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/build-view-spec.js b/spec/build-view-spec.js index 004d66e8..d78d85b8 100644 --- a/spec/build-view-spec.js +++ b/spec/build-view-spec.js @@ -5,7 +5,7 @@ var fs = require('fs-extra'); var temp = require('temp'); var specHelpers = require('./spec-helpers'); -describe('Visible', function() { +describe('BuildView', function() { var directory = null; var workspaceElement = null; From ede1473f9a1f5468930f6845fe6af6da69f4c58b Mon Sep 17 00:00:00 2001 From: Alexander Olsson Date: Tue, 22 Sep 2015 19:45:06 +0200 Subject: [PATCH 5/8] BuildView: Force status to bottom The status bar of the build panel should stick to the bottom, no matter where the build panel is placed. --- lib/build-view.js | 2 +- styles/build.less | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/build-view.js b/lib/build-view.js index 0a54e88a..cf73b10d 100644 --- a/lib/build-view.js +++ b/lib/build-view.js @@ -45,7 +45,7 @@ module.exports = (function() { BuildView.div({ class: 'output panel-body', outlet: 'output' }); - BuildView.div(function() { + BuildView.div({ class: 'status' }, function() { BuildView.h1({ class: 'title panel-heading', outlet: 'title' }, function () { BuildView.span({ class: 'build-timer', outlet: 'buildTimer' }, '0.0 s'); BuildView.span({ class: 'title-text', outlet: 'titleText' }, 'Ready'); diff --git a/styles/build.less b/styles/build.less index 729043c4..92d29b73 100644 --- a/styles/build.less +++ b/styles/build.less @@ -1,6 +1,9 @@ @import "ui-variables"; .build { + + height: 100%; + .title { transition: background-color 0.2s ease-in; } @@ -41,6 +44,12 @@ font-family: monospace; } + .status { + position: absolute; + bottom: 0; + width: 100%; + } + a { text-decoration: underline; } From d44eb1a89bb26fb12bc31b98317b6eec2761f96d Mon Sep 17 00:00:00 2001 From: Alexander Olsson Date: Tue, 22 Sep 2015 21:10:39 +0200 Subject: [PATCH 6/8] BuildView: Allow left/right panel to be scrolled --- lib/build-view.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/build-view.js b/lib/build-view.js index cf73b10d..d1c7af18 100644 --- a/lib/build-view.js +++ b/lib/build-view.js @@ -170,8 +170,8 @@ module.exports = (function() { cssKey = 'width'; break; } - this.output.css('width', 'auto'); - this.output.css('height', 'auto'); + this.output.css('width', '100%'); + this.output.css('height', '100%'); this.output.css(cssKey, percent * size + 'px'); }; From 75ca7181e42a9602a5e309a5e4ec3c7f7a95a184 Mon Sep 17 00:00:00 2001 From: Alexander Olsson Date: Wed, 23 Sep 2015 18:46:04 +0200 Subject: [PATCH 7/8] BuildView: Pad to show bottom lines --- lib/build-view.js | 2 +- styles/build.less | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/build-view.js b/lib/build-view.js index d1c7af18..69382a8c 100644 --- a/lib/build-view.js +++ b/lib/build-view.js @@ -170,7 +170,7 @@ module.exports = (function() { cssKey = 'width'; break; } - this.output.css('width', '100%'); + this.output.css('width', 'auto'); this.output.css('height', '100%'); this.output.css(cssKey, percent * size + 'px'); }; diff --git a/styles/build.less b/styles/build.less index 92d29b73..7b267720 100644 --- a/styles/build.less +++ b/styles/build.less @@ -1,4 +1,5 @@ @import "ui-variables"; +@status-panel-height: 3em; .build { @@ -35,19 +36,23 @@ .output { transition: 0.5s ease-in-out; transition-property: width, height; - padding: 10px 0 0 10px; + padding: 10px 0 @status-panel-height 10px; min-height: 100px; - overflow-y: auto; + overflow: auto; word-wrap: break-word; white-space: pre-wrap; - list-style: none; font-family: monospace; } .status { position: absolute; bottom: 0; + height: @status-panel-height; width: 100%; + + h1 { + height: 100%; + } } a { From 506555a6fc45bbb33b328f080750410d2bb7e2c4 Mon Sep 17 00:00:00 2001 From: Alexander Olsson Date: Wed, 23 Sep 2015 19:26:02 +0200 Subject: [PATCH 8/8] ErrorMatch Spec: Scrolling slightly off Scrolling changed a little due to CSS. Should probably not check exact pixel value for this... --- spec/build-error-match-spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/build-error-match-spec.js b/spec/build-error-match-spec.js index fb30c433..5a208db9 100644 --- a/spec/build-error-match-spec.js +++ b/spec/build-error-match-spec.js @@ -348,7 +348,7 @@ describe('Error Match', function() { waits(100); runs(function() { - expect(workspaceElement.querySelector('.build .output').scrollTop).toEqual(135); + expect(workspaceElement.querySelector('.build .output').scrollTop).toEqual(168); atom.commands.dispatch(workspaceElement, 'build:error-match'); }); @@ -381,7 +381,7 @@ describe('Error Match', function() { waits(100); runs(function() { - expect(workspaceElement.querySelector('.build .output').scrollTop).toEqual(135); + expect(workspaceElement.querySelector('.build .output').scrollTop).toEqual(168); atom.commands.dispatch(workspaceElement, 'build:error-match-first'); });