diff --git a/spec/workspace-element-spec.coffee b/spec/workspace-element-spec.coffee deleted file mode 100644 index ec24242ac..000000000 --- a/spec/workspace-element-spec.coffee +++ /dev/null @@ -1,208 +0,0 @@ -{ipcRenderer} = require 'electron' -path = require 'path' -temp = require('temp').track() -{Disposable} = require 'event-kit' - -describe "WorkspaceElement", -> - afterEach -> - temp.cleanupSync() - - describe "when the workspace element is focused", -> - it "transfers focus to the active pane", -> - workspaceElement = atom.views.getView(atom.workspace) - jasmine.attachToDOM(workspaceElement) - activePaneElement = atom.views.getView(atom.workspace.getActivePane()) - document.body.focus() - expect(document.activeElement).not.toBe(activePaneElement) - workspaceElement.focus() - expect(document.activeElement).toBe(activePaneElement) - - describe "the scrollbar visibility class", -> - it "has a class based on the style of the scrollbar", -> - observeCallback = null - scrollbarStyle = require 'scrollbar-style' - spyOn(scrollbarStyle, 'observePreferredScrollbarStyle').andCallFake (cb) -> - observeCallback = cb - new Disposable(->) - - workspaceElement = atom.views.getView(atom.workspace) - observeCallback('legacy') - expect(workspaceElement.className).toMatch 'scrollbars-visible-always' - - observeCallback('overlay') - expect(workspaceElement).toHaveClass 'scrollbars-visible-when-scrolling' - - describe "editor font styling", -> - [editor, editorElement, workspaceElement] = [] - - beforeEach -> - waitsForPromise -> atom.workspace.open('sample.js') - - runs -> - workspaceElement = atom.views.getView(atom.workspace) - jasmine.attachToDOM(workspaceElement) - editor = atom.workspace.getActiveTextEditor() - editorElement = atom.views.getView(editor) - - it "updates the font-size based on the 'editor.fontSize' config value", -> - initialCharWidth = editor.getDefaultCharWidth() - expect(getComputedStyle(editorElement).fontSize).toBe atom.config.get('editor.fontSize') + 'px' - atom.config.set('editor.fontSize', atom.config.get('editor.fontSize') + 5) - expect(getComputedStyle(editorElement).fontSize).toBe atom.config.get('editor.fontSize') + 'px' - expect(editor.getDefaultCharWidth()).toBeGreaterThan initialCharWidth - - it "updates the font-family based on the 'editor.fontFamily' config value", -> - initialCharWidth = editor.getDefaultCharWidth() - fontFamily = atom.config.get('editor.fontFamily') - expect(getComputedStyle(editorElement).fontFamily).toBe fontFamily - - atom.config.set('editor.fontFamily', 'sans-serif') - fontFamily = atom.config.get('editor.fontFamily') - expect(getComputedStyle(editorElement).fontFamily).toBe fontFamily - expect(editor.getDefaultCharWidth()).not.toBe initialCharWidth - - it "updates the line-height based on the 'editor.lineHeight' config value", -> - initialLineHeight = editor.getLineHeightInPixels() - atom.config.set('editor.lineHeight', '30px') - expect(getComputedStyle(editorElement).lineHeight).toBe atom.config.get('editor.lineHeight') - expect(editor.getLineHeightInPixels()).not.toBe initialLineHeight - - it "increases or decreases the font size when a ctrl-mousewheel event occurs", -> - atom.config.set('editor.zoomFontWhenCtrlScrolling', true) - atom.config.set('editor.fontSize', 12) - - # Zoom out - editorElement.querySelector('span').dispatchEvent(new WheelEvent('mousewheel', { - wheelDeltaY: -10, - ctrlKey: true - })) - expect(atom.config.get('editor.fontSize')).toBe(11) - - # Zoom in - editorElement.querySelector('span').dispatchEvent(new WheelEvent('mousewheel', { - wheelDeltaY: 10, - ctrlKey: true - })) - expect(atom.config.get('editor.fontSize')).toBe(12) - - # Not on an atom-text-editor - workspaceElement.dispatchEvent(new WheelEvent('mousewheel', { - wheelDeltaY: 10, - ctrlKey: true - })) - expect(atom.config.get('editor.fontSize')).toBe(12) - - # No ctrl key - editorElement.querySelector('span').dispatchEvent(new WheelEvent('mousewheel', { - wheelDeltaY: 10, - })) - expect(atom.config.get('editor.fontSize')).toBe(12) - - atom.config.set('editor.zoomFontWhenCtrlScrolling', false) - editorElement.querySelector('span').dispatchEvent(new WheelEvent('mousewheel', { - wheelDeltaY: 10, - ctrlKey: true - })) - expect(atom.config.get('editor.fontSize')).toBe(12) - - describe 'panel containers', -> - it 'inserts panel container elements in the correct places in the DOM', -> - workspaceElement = atom.views.getView(atom.workspace) - - leftContainer = workspaceElement.querySelector('atom-panel-container.left') - rightContainer = workspaceElement.querySelector('atom-panel-container.right') - expect(leftContainer.nextSibling).toBe workspaceElement.verticalAxis - expect(rightContainer.previousSibling).toBe workspaceElement.verticalAxis - - topContainer = workspaceElement.querySelector('atom-panel-container.top') - bottomContainer = workspaceElement.querySelector('atom-panel-container.bottom') - expect(topContainer.nextSibling).toBe workspaceElement.paneContainer - expect(bottomContainer.previousSibling).toBe workspaceElement.paneContainer - - headerContainer = workspaceElement.querySelector('atom-panel-container.header') - footerContainer = workspaceElement.querySelector('atom-panel-container.footer') - expect(headerContainer.nextSibling).toBe workspaceElement.horizontalAxis - expect(footerContainer.previousSibling).toBe workspaceElement.horizontalAxis - - modalContainer = workspaceElement.querySelector('atom-panel-container.modal') - expect(modalContainer.parentNode).toBe workspaceElement - - it 'stretches header/footer panels to the workspace width', -> - workspaceElement = atom.views.getView(atom.workspace) - jasmine.attachToDOM(workspaceElement) - expect(workspaceElement.offsetWidth).toBeGreaterThan(0) - - headerItem = document.createElement('div') - atom.workspace.addHeaderPanel({item: headerItem}) - expect(headerItem.offsetWidth).toEqual(workspaceElement.offsetWidth) - - footerItem = document.createElement('div') - atom.workspace.addFooterPanel({item: footerItem}) - expect(footerItem.offsetWidth).toEqual(workspaceElement.offsetWidth) - - it 'shrinks horizontal axis according to header/footer panels height', -> - workspaceElement = atom.views.getView(atom.workspace) - workspaceElement.style.height = '100px' - horizontalAxisElement = workspaceElement.querySelector('atom-workspace-axis.horizontal') - jasmine.attachToDOM(workspaceElement) - - originalHorizontalAxisHeight = horizontalAxisElement.offsetHeight - expect(workspaceElement.offsetHeight).toBeGreaterThan(0) - expect(originalHorizontalAxisHeight).toBeGreaterThan(0) - - headerItem = document.createElement('div') - headerItem.style.height = '10px' - atom.workspace.addHeaderPanel({item: headerItem}) - expect(headerItem.offsetHeight).toBeGreaterThan(0) - - footerItem = document.createElement('div') - footerItem.style.height = '15px' - atom.workspace.addFooterPanel({item: footerItem}) - expect(footerItem.offsetHeight).toBeGreaterThan(0) - - expect(horizontalAxisElement.offsetHeight).toEqual(originalHorizontalAxisHeight - headerItem.offsetHeight - footerItem.offsetHeight) - - describe "the 'window:toggle-invisibles' command", -> - it "shows/hides invisibles in all open and future editors", -> - workspaceElement = atom.views.getView(atom.workspace) - expect(atom.config.get('editor.showInvisibles')).toBe false - atom.commands.dispatch(workspaceElement, 'window:toggle-invisibles') - expect(atom.config.get('editor.showInvisibles')).toBe true - atom.commands.dispatch(workspaceElement, 'window:toggle-invisibles') - expect(atom.config.get('editor.showInvisibles')).toBe false - - describe "the 'window:run-package-specs' command", -> - it "runs the package specs for the active item's project path, or the first project path", -> - workspaceElement = atom.views.getView(atom.workspace) - spyOn(ipcRenderer, 'send') - - # No project paths. Don't try to run specs. - atom.commands.dispatch(workspaceElement, "window:run-package-specs") - expect(ipcRenderer.send).not.toHaveBeenCalledWith("run-package-specs") - - projectPaths = [temp.mkdirSync("dir1-"), temp.mkdirSync("dir2-")] - atom.project.setPaths(projectPaths) - - # No active item. Use first project directory. - atom.commands.dispatch(workspaceElement, "window:run-package-specs") - expect(ipcRenderer.send).toHaveBeenCalledWith("run-package-specs", path.join(projectPaths[0], "spec")) - ipcRenderer.send.reset() - - # Active item doesn't implement ::getPath(). Use first project directory. - item = document.createElement("div") - atom.workspace.getActivePane().activateItem(item) - atom.commands.dispatch(workspaceElement, "window:run-package-specs") - expect(ipcRenderer.send).toHaveBeenCalledWith("run-package-specs", path.join(projectPaths[0], "spec")) - ipcRenderer.send.reset() - - # Active item has no path. Use first project directory. - item.getPath = -> null - atom.commands.dispatch(workspaceElement, "window:run-package-specs") - expect(ipcRenderer.send).toHaveBeenCalledWith("run-package-specs", path.join(projectPaths[0], "spec")) - ipcRenderer.send.reset() - - # Active item has path. Use project path for item path. - item.getPath = -> path.join(projectPaths[1], "a-file.txt") - atom.commands.dispatch(workspaceElement, "window:run-package-specs") - expect(ipcRenderer.send).toHaveBeenCalledWith("run-package-specs", path.join(projectPaths[1], "spec")) - ipcRenderer.send.reset() diff --git a/spec/workspace-element-spec.js b/spec/workspace-element-spec.js new file mode 100644 index 000000000..a7f6957a0 --- /dev/null +++ b/spec/workspace-element-spec.js @@ -0,0 +1,232 @@ +'use strict' + +/* global getComputedStyle, WheelEvent */ + +const {ipcRenderer} = require('electron') +const path = require('path') +const temp = require('temp').track() +const {Disposable} = require('event-kit') + +describe('WorkspaceElement', () => { + afterEach(() => { temp.cleanupSync() }) + + describe('when the workspace element is focused', () => { + it('transfers focus to the active pane', () => { + const workspaceElement = atom.views.getView(atom.workspace) + jasmine.attachToDOM(workspaceElement) + const activePaneElement = atom.views.getView(atom.workspace.getActivePane()) + document.body.focus() + expect(document.activeElement).not.toBe(activePaneElement) + workspaceElement.focus() + expect(document.activeElement).toBe(activePaneElement) + }) + }) + + describe('the scrollbar visibility class', () => { + it('has a class based on the style of the scrollbar', () => { + let observeCallback + const scrollbarStyle = require('scrollbar-style') + spyOn(scrollbarStyle, 'observePreferredScrollbarStyle').andCallFake(cb => { + observeCallback = cb + return new Disposable(() => {}) + }) + + const workspaceElement = atom.views.getView(atom.workspace) + observeCallback('legacy') + expect(workspaceElement.className).toMatch('scrollbars-visible-always') + + observeCallback('overlay') + expect(workspaceElement).toHaveClass('scrollbars-visible-when-scrolling') + }) + }) + + describe('editor font styling', () => { + let editor, editorElement, workspaceElement + + beforeEach(() => { + waitsForPromise(() => atom.workspace.open('sample.js')) + + runs(() => { + workspaceElement = atom.views.getView(atom.workspace) + jasmine.attachToDOM(workspaceElement) + editor = atom.workspace.getActiveTextEditor() + editorElement = atom.views.getView(editor) + }) + }) + + it("updates the font-size based on the 'editor.fontSize' config value", () => { + const initialCharWidth = editor.getDefaultCharWidth() + expect(getComputedStyle(editorElement).fontSize).toBe(atom.config.get('editor.fontSize') + 'px') + atom.config.set('editor.fontSize', atom.config.get('editor.fontSize') + 5) + expect(getComputedStyle(editorElement).fontSize).toBe(atom.config.get('editor.fontSize') + 'px') + expect(editor.getDefaultCharWidth()).toBeGreaterThan(initialCharWidth) + }) + + it("updates the font-family based on the 'editor.fontFamily' config value", () => { + const initialCharWidth = editor.getDefaultCharWidth() + let fontFamily = atom.config.get('editor.fontFamily') + expect(getComputedStyle(editorElement).fontFamily).toBe(fontFamily) + + atom.config.set('editor.fontFamily', 'sans-serif') + fontFamily = atom.config.get('editor.fontFamily') + expect(getComputedStyle(editorElement).fontFamily).toBe(fontFamily) + expect(editor.getDefaultCharWidth()).not.toBe(initialCharWidth) + }) + + it("updates the line-height based on the 'editor.lineHeight' config value", () => { + const initialLineHeight = editor.getLineHeightInPixels() + atom.config.set('editor.lineHeight', '30px') + expect(getComputedStyle(editorElement).lineHeight).toBe(atom.config.get('editor.lineHeight')) + expect(editor.getLineHeightInPixels()).not.toBe(initialLineHeight) + }) + + it('increases or decreases the font size when a ctrl-mousewheel event occurs', () => { + atom.config.set('editor.zoomFontWhenCtrlScrolling', true) + atom.config.set('editor.fontSize', 12) + + // Zoom out + editorElement.querySelector('span').dispatchEvent(new WheelEvent('mousewheel', { + wheelDeltaY: -10, + ctrlKey: true + })) + expect(atom.config.get('editor.fontSize')).toBe(11) + + // Zoom in + editorElement.querySelector('span').dispatchEvent(new WheelEvent('mousewheel', { + wheelDeltaY: 10, + ctrlKey: true + })) + expect(atom.config.get('editor.fontSize')).toBe(12) + + // Not on an atom-text-editor + workspaceElement.dispatchEvent(new WheelEvent('mousewheel', { + wheelDeltaY: 10, + ctrlKey: true + })) + expect(atom.config.get('editor.fontSize')).toBe(12) + + // No ctrl key + editorElement.querySelector('span').dispatchEvent(new WheelEvent('mousewheel', { + wheelDeltaY: 10 + })) + expect(atom.config.get('editor.fontSize')).toBe(12) + + atom.config.set('editor.zoomFontWhenCtrlScrolling', false) + editorElement.querySelector('span').dispatchEvent(new WheelEvent('mousewheel', { + wheelDeltaY: 10, + ctrlKey: true + })) + expect(atom.config.get('editor.fontSize')).toBe(12) + }) + }) + + describe('panel containers', () => { + it('inserts panel container elements in the correct places in the DOM', () => { + const workspaceElement = atom.views.getView(atom.workspace) + + const leftContainer = workspaceElement.querySelector('atom-panel-container.left') + const rightContainer = workspaceElement.querySelector('atom-panel-container.right') + expect(leftContainer.nextSibling).toBe(workspaceElement.verticalAxis) + expect(rightContainer.previousSibling).toBe(workspaceElement.verticalAxis) + + const topContainer = workspaceElement.querySelector('atom-panel-container.top') + const bottomContainer = workspaceElement.querySelector('atom-panel-container.bottom') + expect(topContainer.nextSibling).toBe(workspaceElement.paneContainer) + expect(bottomContainer.previousSibling).toBe(workspaceElement.paneContainer) + + const headerContainer = workspaceElement.querySelector('atom-panel-container.header') + const footerContainer = workspaceElement.querySelector('atom-panel-container.footer') + expect(headerContainer.nextSibling).toBe(workspaceElement.horizontalAxis) + expect(footerContainer.previousSibling).toBe(workspaceElement.horizontalAxis) + + const modalContainer = workspaceElement.querySelector('atom-panel-container.modal') + expect(modalContainer.parentNode).toBe(workspaceElement) + }) + + it('stretches header/footer panels to the workspace width', () => { + const workspaceElement = atom.views.getView(atom.workspace) + jasmine.attachToDOM(workspaceElement) + expect(workspaceElement.offsetWidth).toBeGreaterThan(0) + + const headerItem = document.createElement('div') + atom.workspace.addHeaderPanel({item: headerItem}) + expect(headerItem.offsetWidth).toEqual(workspaceElement.offsetWidth) + + const footerItem = document.createElement('div') + atom.workspace.addFooterPanel({item: footerItem}) + expect(footerItem.offsetWidth).toEqual(workspaceElement.offsetWidth) + }) + + it('shrinks horizontal axis according to header/footer panels height', () => { + const workspaceElement = atom.views.getView(atom.workspace) + workspaceElement.style.height = '100px' + const horizontalAxisElement = workspaceElement.querySelector('atom-workspace-axis.horizontal') + jasmine.attachToDOM(workspaceElement) + + const originalHorizontalAxisHeight = horizontalAxisElement.offsetHeight + expect(workspaceElement.offsetHeight).toBeGreaterThan(0) + expect(originalHorizontalAxisHeight).toBeGreaterThan(0) + + const headerItem = document.createElement('div') + headerItem.style.height = '10px' + atom.workspace.addHeaderPanel({item: headerItem}) + expect(headerItem.offsetHeight).toBeGreaterThan(0) + + const footerItem = document.createElement('div') + footerItem.style.height = '15px' + atom.workspace.addFooterPanel({item: footerItem}) + expect(footerItem.offsetHeight).toBeGreaterThan(0) + + expect(horizontalAxisElement.offsetHeight).toEqual(originalHorizontalAxisHeight - headerItem.offsetHeight - footerItem.offsetHeight) + }) + }) + + describe("the 'window:toggle-invisibles' command", () => { + it('shows/hides invisibles in all open and future editors', () => { + const workspaceElement = atom.views.getView(atom.workspace) + expect(atom.config.get('editor.showInvisibles')).toBe(false) + atom.commands.dispatch(workspaceElement, 'window:toggle-invisibles') + expect(atom.config.get('editor.showInvisibles')).toBe(true) + atom.commands.dispatch(workspaceElement, 'window:toggle-invisibles') + expect(atom.config.get('editor.showInvisibles')).toBe(false) + }) + }) + + describe("the 'window:run-package-specs' command", () => { + it("runs the package specs for the active item's project path, or the first project path", () => { + const workspaceElement = atom.views.getView(atom.workspace) + spyOn(ipcRenderer, 'send') + + // No project paths. Don't try to run specs. + atom.commands.dispatch(workspaceElement, 'window:run-package-specs') + expect(ipcRenderer.send).not.toHaveBeenCalledWith('run-package-specs') + + const projectPaths = [temp.mkdirSync('dir1-'), temp.mkdirSync('dir2-')] + atom.project.setPaths(projectPaths) + + // No active item. Use first project directory. + atom.commands.dispatch(workspaceElement, 'window:run-package-specs') + expect(ipcRenderer.send).toHaveBeenCalledWith('run-package-specs', path.join(projectPaths[0], 'spec')) + ipcRenderer.send.reset() + + // Active item doesn't implement ::getPath(). Use first project directory. + const item = document.createElement('div') + atom.workspace.getActivePane().activateItem(item) + atom.commands.dispatch(workspaceElement, 'window:run-package-specs') + expect(ipcRenderer.send).toHaveBeenCalledWith('run-package-specs', path.join(projectPaths[0], 'spec')) + ipcRenderer.send.reset() + + // Active item has no path. Use first project directory. + item.getPath = () => null + atom.commands.dispatch(workspaceElement, 'window:run-package-specs') + expect(ipcRenderer.send).toHaveBeenCalledWith('run-package-specs', path.join(projectPaths[0], 'spec')) + ipcRenderer.send.reset() + + // Active item has path. Use project path for item path. + item.getPath = () => path.join(projectPaths[1], 'a-file.txt') + atom.commands.dispatch(workspaceElement, 'window:run-package-specs') + expect(ipcRenderer.send).toHaveBeenCalledWith('run-package-specs', path.join(projectPaths[1], 'spec')) + ipcRenderer.send.reset() + }) + }) +}) diff --git a/src/workspace-element.coffee b/src/workspace-element.coffee deleted file mode 100644 index 6defe33da..000000000 --- a/src/workspace-element.coffee +++ /dev/null @@ -1,149 +0,0 @@ -{ipcRenderer} = require 'electron' -path = require 'path' -fs = require 'fs-plus' -{CompositeDisposable} = require 'event-kit' -scrollbarStyle = require 'scrollbar-style' - -module.exports = -class WorkspaceElement extends HTMLElement - globalTextEditorStyleSheet: null - - attachedCallback: -> - @focus() - - detachedCallback: -> - @subscriptions.dispose() - - initializeContent: -> - @classList.add 'workspace' - @setAttribute 'tabindex', -1 - - @verticalAxis = document.createElement('atom-workspace-axis') - @verticalAxis.classList.add('vertical') - - @horizontalAxis = document.createElement('atom-workspace-axis') - @horizontalAxis.classList.add('horizontal') - @horizontalAxis.appendChild(@verticalAxis) - - @appendChild(@horizontalAxis) - - observeScrollbarStyle: -> - @subscriptions.add scrollbarStyle.observePreferredScrollbarStyle (style) => - switch style - when 'legacy' - @classList.remove('scrollbars-visible-when-scrolling') - @classList.add("scrollbars-visible-always") - when 'overlay' - @classList.remove('scrollbars-visible-always') - @classList.add("scrollbars-visible-when-scrolling") - - observeTextEditorFontConfig: -> - @updateGlobalTextEditorStyleSheet() - @subscriptions.add @config.onDidChange 'editor.fontSize', @updateGlobalTextEditorStyleSheet.bind(this) - @subscriptions.add @config.onDidChange 'editor.fontFamily', @updateGlobalTextEditorStyleSheet.bind(this) - @subscriptions.add @config.onDidChange 'editor.lineHeight', @updateGlobalTextEditorStyleSheet.bind(this) - - updateGlobalTextEditorStyleSheet: -> - styleSheetSource = """ - atom-text-editor { - font-size: #{@config.get('editor.fontSize')}px; - font-family: #{@config.get('editor.fontFamily')}; - line-height: #{@config.get('editor.lineHeight')}; - } - """ - @styles.addStyleSheet(styleSheetSource, sourcePath: 'global-text-editor-styles') - @views.performDocumentPoll() - - initialize: (@model, {@views, @workspace, @project, @config, @styles}) -> - throw new Error("Must pass a views parameter when initializing WorskpaceElements") unless @views? - throw new Error("Must pass a workspace parameter when initializing WorskpaceElements") unless @workspace? - throw new Error("Must pass a project parameter when initializing WorskpaceElements") unless @project? - throw new Error("Must pass a config parameter when initializing WorskpaceElements") unless @config? - throw new Error("Must pass a styles parameter when initializing WorskpaceElements") unless @styles? - - @subscriptions = new CompositeDisposable - @initializeContent() - @observeScrollbarStyle() - @observeTextEditorFontConfig() - - @paneContainer = @views.getView(@model.paneContainer) - @verticalAxis.appendChild(@paneContainer) - @addEventListener 'focus', @handleFocus.bind(this) - - @addEventListener 'mousewheel', @handleMousewheel.bind(this), true - - @panelContainers = - top: @views.getView(@model.panelContainers.top) - left: @views.getView(@model.panelContainers.left) - right: @views.getView(@model.panelContainers.right) - bottom: @views.getView(@model.panelContainers.bottom) - header: @views.getView(@model.panelContainers.header) - footer: @views.getView(@model.panelContainers.footer) - modal: @views.getView(@model.panelContainers.modal) - - @horizontalAxis.insertBefore(@panelContainers.left, @verticalAxis) - @horizontalAxis.appendChild(@panelContainers.right) - - @verticalAxis.insertBefore(@panelContainers.top, @paneContainer) - @verticalAxis.appendChild(@panelContainers.bottom) - - @insertBefore(@panelContainers.header, @horizontalAxis) - @appendChild(@panelContainers.footer) - - @appendChild(@panelContainers.modal) - - this - - getModel: -> @model - - handleMousewheel: (event) -> - if event.ctrlKey and @config.get('editor.zoomFontWhenCtrlScrolling') and event.target.closest('atom-text-editor')? - if event.wheelDeltaY > 0 - @model.increaseFontSize() - else if event.wheelDeltaY < 0 - @model.decreaseFontSize() - event.preventDefault() - event.stopPropagation() - - handleFocus: (event) -> - @model.getActivePane().activate() - - focusPaneViewAbove: -> @paneContainer.focusPaneViewAbove() - - focusPaneViewBelow: -> @paneContainer.focusPaneViewBelow() - - focusPaneViewOnLeft: -> @paneContainer.focusPaneViewOnLeft() - - focusPaneViewOnRight: -> @paneContainer.focusPaneViewOnRight() - - moveActiveItemToPaneAbove: (params) -> @paneContainer.moveActiveItemToPaneAbove(params) - - moveActiveItemToPaneBelow: (params) -> @paneContainer.moveActiveItemToPaneBelow(params) - - moveActiveItemToPaneOnLeft: (params) -> @paneContainer.moveActiveItemToPaneOnLeft(params) - - moveActiveItemToPaneOnRight: (params) -> @paneContainer.moveActiveItemToPaneOnRight(params) - - runPackageSpecs: -> - if activePath = @workspace.getActivePaneItem()?.getPath?() - [projectPath] = @project.relativizePath(activePath) - else - [projectPath] = @project.getPaths() - if projectPath - specPath = path.join(projectPath, 'spec') - testPath = path.join(projectPath, 'test') - if not fs.existsSync(specPath) and fs.existsSync(testPath) - specPath = testPath - - ipcRenderer.send('run-package-specs', specPath) - - runBenchmarks: -> - if activePath = @workspace.getActivePaneItem()?.getPath?() - [projectPath] = @project.relativizePath(activePath) - else - [projectPath] = @project.getPaths() - - if projectPath - ipcRenderer.send('run-benchmarks', path.join(projectPath, 'benchmarks')) - -module.exports = WorkspaceElement = document.registerElement 'atom-workspace', prototype: WorkspaceElement.prototype diff --git a/src/workspace-element.js b/src/workspace-element.js new file mode 100644 index 000000000..65333e7d3 --- /dev/null +++ b/src/workspace-element.js @@ -0,0 +1,184 @@ +'use strict' + +/* global HTMLElement */ + +const {ipcRenderer} = require('electron') +const path = require('path') +const fs = require('fs-plus') +const {CompositeDisposable} = require('event-kit') +const scrollbarStyle = require('scrollbar-style') + +class WorkspaceElement extends HTMLElement { + attachedCallback () { + this.focus() + } + + detachedCallback () { + this.subscriptions.dispose() + } + + initializeContent () { + this.classList.add('workspace') + this.setAttribute('tabindex', -1) + + this.verticalAxis = document.createElement('atom-workspace-axis') + this.verticalAxis.classList.add('vertical') + + this.horizontalAxis = document.createElement('atom-workspace-axis') + this.horizontalAxis.classList.add('horizontal') + this.horizontalAxis.appendChild(this.verticalAxis) + + this.appendChild(this.horizontalAxis) + } + + observeScrollbarStyle () { + this.subscriptions.add(scrollbarStyle.observePreferredScrollbarStyle(style => { + switch (style) { + case 'legacy': + this.classList.remove('scrollbars-visible-when-scrolling') + this.classList.add('scrollbars-visible-always') + break + case 'overlay': + this.classList.remove('scrollbars-visible-always') + this.classList.add('scrollbars-visible-when-scrolling') + break + } + })) + } + + observeTextEditorFontConfig () { + this.updateGlobalTextEditorStyleSheet() + this.subscriptions.add(this.config.onDidChange('editor.fontSize', this.updateGlobalTextEditorStyleSheet.bind(this))) + this.subscriptions.add(this.config.onDidChange('editor.fontFamily', this.updateGlobalTextEditorStyleSheet.bind(this))) + this.subscriptions.add(this.config.onDidChange('editor.lineHeight', this.updateGlobalTextEditorStyleSheet.bind(this))) + } + + updateGlobalTextEditorStyleSheet () { + const styleSheetSource = `atom-text-editor { + font-size: ${this.config.get('editor.fontSize')}px; + font-family: ${this.config.get('editor.fontFamily')}; + line-height: ${this.config.get('editor.lineHeight')}; +}` + this.styles.addStyleSheet(styleSheetSource, {sourcePath: 'global-text-editor-styles'}) + this.views.performDocumentPoll() + } + + initialize (model, {views, workspace, project, config, styles}) { + this.model = model + this.views = views + this.workspace = workspace + this.project = project + this.config = config + this.styles = styles + if (this.views == null) { throw new Error('Must pass a views parameter when initializing WorskpaceElements') } + if (this.workspace == null) { throw new Error('Must pass a workspace parameter when initializing WorskpaceElements') } + if (this.project == null) { throw new Error('Must pass a project parameter when initializing WorskpaceElements') } + if (this.config == null) { throw new Error('Must pass a config parameter when initializing WorskpaceElements') } + if (this.styles == null) { throw new Error('Must pass a styles parameter when initializing WorskpaceElements') } + + this.subscriptions = new CompositeDisposable() + this.initializeContent() + this.observeScrollbarStyle() + this.observeTextEditorFontConfig() + + this.paneContainer = this.views.getView(this.model.paneContainer) + this.verticalAxis.appendChild(this.paneContainer) + this.addEventListener('focus', this.handleFocus.bind(this)) + + this.addEventListener('mousewheel', this.handleMousewheel.bind(this), true) + + this.panelContainers = { + top: this.views.getView(this.model.panelContainers.top), + left: this.views.getView(this.model.panelContainers.left), + right: this.views.getView(this.model.panelContainers.right), + bottom: this.views.getView(this.model.panelContainers.bottom), + header: this.views.getView(this.model.panelContainers.header), + footer: this.views.getView(this.model.panelContainers.footer), + modal: this.views.getView(this.model.panelContainers.modal) + } + + this.horizontalAxis.insertBefore(this.panelContainers.left, this.verticalAxis) + this.horizontalAxis.appendChild(this.panelContainers.right) + + this.verticalAxis.insertBefore(this.panelContainers.top, this.paneContainer) + this.verticalAxis.appendChild(this.panelContainers.bottom) + + this.insertBefore(this.panelContainers.header, this.horizontalAxis) + this.appendChild(this.panelContainers.footer) + + this.appendChild(this.panelContainers.modal) + + return this + } + + getModel () { return this.model } + + handleMousewheel (event) { + if (event.ctrlKey && this.config.get('editor.zoomFontWhenCtrlScrolling') && (event.target.closest('atom-text-editor') != null)) { + if (event.wheelDeltaY > 0) { + this.model.increaseFontSize() + } else if (event.wheelDeltaY < 0) { + this.model.decreaseFontSize() + } + event.preventDefault() + event.stopPropagation() + } + } + + handleFocus (event) { + this.model.getActivePane().activate() + } + + focusPaneViewAbove () { this.paneContainer.focusPaneViewAbove() } + + focusPaneViewBelow () { this.paneContainer.focusPaneViewBelow() } + + focusPaneViewOnLeft () { this.paneContainer.focusPaneViewOnLeft() } + + focusPaneViewOnRight () { this.paneContainer.focusPaneViewOnRight() } + + moveActiveItemToPaneAbove (params) { this.paneContainer.moveActiveItemToPaneAbove(params) } + + moveActiveItemToPaneBelow (params) { this.paneContainer.moveActiveItemToPaneBelow(params) } + + moveActiveItemToPaneOnLeft (params) { this.paneContainer.moveActiveItemToPaneOnLeft(params) } + + moveActiveItemToPaneOnRight (params) { this.paneContainer.moveActiveItemToPaneOnRight(params) } + + runPackageSpecs () { + const activePaneItem = this.workspace.getActivePaneItem() + const activePath = activePaneItem && typeof activePaneItem.getPath === 'function' ? activePaneItem.getPath() : null + let projectPath + if (activePath != null) { + [projectPath] = this.project.relativizePath(activePath) + } else { + [projectPath] = this.project.getPaths() + } + if (projectPath) { + let specPath = path.join(projectPath, 'spec') + const testPath = path.join(projectPath, 'test') + if (!fs.existsSync(specPath) && fs.existsSync(testPath)) { + specPath = testPath + } + + ipcRenderer.send('run-package-specs', specPath) + } + } + + runBenchmarks () { + const activePaneItem = this.workspace.getActivePaneItem() + const activePath = activePaneItem && typeof activePaneItem.getPath === 'function' ? activePaneItem.getPath() : null + let projectPath + if (activePath) { + [projectPath] = this.project.relativizePath(activePath) + } else { + [projectPath] = this.project.getPaths() + } + + if (projectPath) { + ipcRenderer.send('run-benchmarks', path.join(projectPath, 'benchmarks')) + } + } +} + +module.exports = document.registerElement('atom-workspace', {prototype: WorkspaceElement.prototype})