diff --git a/keymaps/minimap.cson b/keymaps/minimap.cson
index ccb3b832..6c42f7c4 100644
--- a/keymaps/minimap.cson
+++ b/keymaps/minimap.cson
@@ -11,5 +11,5 @@
# 'ctrl-k ctrl-m': 'minimap:toggle'
# 'ctrl-k ctrl-s': 'minimap:open-quick-settings'
-'.minimap-quick-settings':
- 'space': 'core:validate'
+'minimap-quick-settings':
+ 'space': 'core:confirm'
diff --git a/lib/main.coffee b/lib/main.coffee
index c6d0a177..31fc1c8c 100644
--- a/lib/main.coffee
+++ b/lib/main.coffee
@@ -82,6 +82,12 @@ class Main
type: 'boolean'
default: false
description: "If this option is enabled then when you click the minimap it will scroll to the destination with animation"
+ devicePixelRatio:
+ type: 'number'
+ minimum: 1
+ maximum: 3
+ default: window.devicePixelRatio
+ description: 'The device pixel ratio used to draw the canvas on high-DPI device.'
# Internal: The activation state of the minimap package.
active: false
diff --git a/lib/minimap-element.coffee b/lib/minimap-element.coffee
index d67e97ac..e7578bfc 100644
--- a/lib/minimap-element.coffee
+++ b/lib/minimap-element.coffee
@@ -1,14 +1,16 @@
{debounce} = require 'underscore-plus'
{CompositeDisposable, Disposable} = require 'event-kit'
+{EventsDelegation} = require 'atom-utils'
DOMStylesReader = require './mixins/dom-styles-reader'
CanvasDrawer = require './mixins/canvas-drawer'
-MinimapQuickSettingsView = null
+MinimapQuickSettingsElement = null
# Public:
class MinimapElement extends HTMLElement
DOMStylesReader.includeInto(this)
CanvasDrawer.includeInto(this)
+ EventsDelegation.includeInto(this)
### Public ###
@@ -16,6 +18,7 @@ class MinimapElement extends HTMLElement
domPollingIntervalId: null
domPollingPaused: false
displayMinimapOnLeft: false
+ devicePixelRatio: 1
# ## ## ####### ####### ## ## ######
# ## ## ## ## ## ## ## ## ## ##
@@ -68,6 +71,9 @@ class MinimapElement extends HTMLElement
'minimap.useHardwareAcceleration': (@useHardwareAcceleration) =>
@requestUpdate() if @attached
+ 'minimap.devicePixelRatio': (@devicePixelRatio) =>
+ @requestUpdate() if @attached
+
attachedCallback: ->
@domPollingIntervalId = setInterval((=> @pollDOM()), @domPollingInterval)
@measureHeightAndWidth()
@@ -163,31 +169,39 @@ class MinimapElement extends HTMLElement
@scrollIndicator = undefined
initializeOpenQuickSettings: ->
+ return if @openQuickSettings?
+
@openQuickSettings = document.createElement('div')
@openQuickSettings.classList.add 'open-minimap-quick-settings'
@controls.appendChild(@openQuickSettings)
- @openQuickSettings.addEventListener 'mousedown', (e) =>
- e.preventDefault()
- e.stopPropagation()
-
- if @quickSettingsView?
- @quickSettingsView.destroy()
- @quickSettingsSubscription.dispose()
- else
- MinimapQuickSettingsView ?= require './minimap-quick-settings-view'
- @quickSettingsView = new MinimapQuickSettingsView(this)
- @quickSettingsSubscription = @quickSettingsView.onDidDestroy =>
- @quickSettingsView = null
-
- @quickSettingsView.attach()
- {top, left} = @getBoundingClientRect()
- @quickSettingsView.css({
- top: top + 'px'
- left: (left - @quickSettingsView.width()) + 'px'
- })
+ @openQuickSettingSubscription = @subscribeTo @openQuickSettings,
+ 'mousedown': (e) =>
+ e.preventDefault()
+ e.stopPropagation()
+
+ if @quickSettingsElement?
+ @quickSettingsElement.destroy()
+ @quickSettingsSubscription.dispose()
+ else
+ MinimapQuickSettingsElement ?= require './minimap-quick-settings-element'
+ @quickSettingsElement = new MinimapQuickSettingsElement
+ @quickSettingsElement.setModel(this)
+ @quickSettingsSubscription = @quickSettingsElement.onDidDestroy =>
+ @quickSettingsElement = null
+
+ @quickSettingsElement.attach()
+ {top, left, right} = @canvas.getBoundingClientRect()
+ @quickSettingsElement.style.top = top + 'px'
+
+ if @displayMinimapOnLeft
+ @quickSettingsElement.style.left = (right) + 'px'
+ else
+ @quickSettingsElement.style.left = (left - @quickSettingsElement.clientWidth) + 'px'
disposeOpenQuickSettings: ->
+ return unless @openQuickSettings?
@controls.removeChild(@openQuickSettings)
+ @openQuickSettingSubscription.dispose()
@openQuickSettings = undefined
getTextEditor: -> @minimap.getTextEditor()
@@ -266,12 +280,12 @@ class MinimapElement extends HTMLElement
transform: @makeTranslate(visibleAreaLeft, visibleAreaTop)
@applyStyles @controls,
- width: Math.min(@canvas.width, @width) + 'px'
+ width: Math.min(@canvas.width / devicePixelRatio, @width) + 'px'
canvasTop = @minimap.getFirstVisibleScreenRow() * @minimap.getLineHeight() - @minimap.getScrollTop()
canvasTransform = @makeTranslate(0, canvasTop)
- canvasTransform += " " + @makeScale(1/devicePixelRatio) if devicePixelRatio isnt 1
+ canvasTransform += " " + @makeScale(1 / devicePixelRatio) if devicePixelRatio isnt 1
@applyStyles @canvas, transform: canvasTransform
if @minimapScrollIndicator and @minimap.canScroll() and not @scrollIndicator
@@ -332,8 +346,8 @@ class MinimapElement extends HTMLElement
delete @marginRight
if canvasWidth isnt @canvas.width or @height isnt @canvas.height
- @canvas.width = canvasWidth * devicePixelRatio
- @canvas.height = (@height + @minimap.getLineHeight()) * devicePixelRatio
+ @canvas.width = canvasWidth * @devicePixelRatio
+ @canvas.height = (@height + @minimap.getLineHeight()) * @devicePixelRatio
# ######## ## ## ######## ## ## ######## ######
# ## ## ## ## ### ## ## ## ##
diff --git a/lib/minimap-open-quick-settings-view.coffee b/lib/minimap-open-quick-settings-view.coffee
deleted file mode 100644
index 30dbcb97..00000000
--- a/lib/minimap-open-quick-settings-view.coffee
+++ /dev/null
@@ -1,32 +0,0 @@
-{View} = require 'atom-space-pen-views'
-MinimapQuickSettingsView = require './minimap-quick-settings-view'
-
-module.exports =
-class MinimapOpenQuickSettingsView extends View
- @content: ->
- @div class: 'open-minimap-quick-settings'
-
- dropdown: null
-
- initialize: (minimap) ->
- @on 'mousedown', (e) =>
- e.preventDefault()
- e.stopPropagation()
-
- if @dropdown?
- @dropdown.destroy()
- else
- offset = minimap.offset()
- @dropdown = new MinimapQuickSettingsView(minimap)
-
- css = top: offset.top
- if atom.config.get('minimap.displayMinimapOnLeft')
- css.left = offset.left + minimap.width()
- else
- css.right = window.innerWidth - offset.left
-
- @dropdown.css(css).attach()
-
- @dropdown.onDidDestroy =>
- @dropdown.off()
- @dropdown = null
diff --git a/lib/minimap-quick-settings-element.coffee b/lib/minimap-quick-settings-element.coffee
new file mode 100644
index 00000000..72bd9f5d
--- /dev/null
+++ b/lib/minimap-quick-settings-element.coffee
@@ -0,0 +1,144 @@
+{EventsDelegation, SpacePenDSL} = require 'atom-utils'
+{CompositeDisposable, Emitter} = require 'event-kit'
+
+Main = require './main'
+
+module.exports =
+class MinimapQuickSettingsElement extends HTMLElement
+ SpacePenDSL.includeInto(this)
+ EventsDelegation.includeInto(this)
+
+ @content: ->
+ @div class: 'select-list popover-list minimap-quick-settings', =>
+ @input type: 'text', class: 'hidden-input', outlet: 'hiddenInput'
+ @ol class: 'list-group mark-active', outlet: 'list', =>
+ @li class: 'separator', outlet: 'separator'
+ @li class: '', outlet: 'codeHighlights', 'code-highlights'
+ @div class: 'btn-group', =>
+ @button class: 'btn btn-default', outlet: 'onLeftButton', 'On Left'
+ @button class: 'btn btn-default', outlet: 'onRightButton', 'On Right'
+
+ selectedItem: null
+
+ setModel: (@minimap) ->
+ @emitter = new Emitter
+ @subscriptions = new CompositeDisposable
+ @plugins = {}
+ @itemsActions = new WeakMap
+
+ @subscriptions.add Main.onDidAddPlugin ({name, plugin}) =>
+ @addItemFor(name, plugin)
+ @subscriptions.add Main.onDidRemovePlugin ({name, plugin}) =>
+ @removeItemFor(name, plugin)
+ @subscriptions.add Main.onDidActivatePlugin ({name, plugin}) =>
+ @activateItem(name, plugin)
+ @subscriptions.add Main.onDidDeactivatePlugin ({name, plugin}) =>
+ @deactivateItem(name, plugin)
+
+ @subscriptions.add atom.commands.add 'minimap-quick-settings',
+ 'core:move-up': => @selectPreviousItem()
+ 'core:move-down': => @selectNextItem()
+ 'core:move-left': => atom.config.set('minimap.displayMinimapOnLeft', true)
+ 'core:move-right': => atom.config.set('minimap.displayMinimapOnLeft', false)
+ 'core:cancel': => @destroy()
+ 'core:confirm': => @toggleSelectedItem()
+
+ @codeHighlights.classList.toggle('active', @minimap.displayCodeHighlights)
+ @subscriptions.add @subscribeTo @codeHighlights,
+ 'mousedown': (e) =>
+ e.preventDefault()
+ atom.config.set('minimap.displayCodeHighlights', !@minimap.displayCodeHighlights)
+
+ @itemsActions.set @codeHighlights, =>
+ atom.config.set('minimap.displayCodeHighlights', !@minimap.displayCodeHighlights)
+
+ @subscriptions.add @subscribeTo @hiddenInput,
+ 'focusout': (e) =>
+ @destroy()
+
+ @subscriptions.add @subscribeTo @onLeftButton,
+ 'mousedown': (e) ->
+ e.preventDefault()
+ atom.config.set('minimap.displayMinimapOnLeft', true)
+
+ @subscriptions.add @subscribeTo @onRightButton,
+ 'mousedown': (e) ->
+ e.preventDefault()
+ atom.config.set('minimap.displayMinimapOnLeft', false)
+
+ @subscriptions.add atom.config.observe 'minimap.displayCodeHighlights', (bool) =>
+ @codeHighlights.classList.toggle('active', bool)
+
+ @subscriptions.add atom.config.observe 'minimap.displayMinimapOnLeft', (bool) =>
+ @onLeftButton.classList.toggle('selected', bool)
+ @onRightButton.classList.toggle('selected', not bool)
+
+ @initList()
+
+ onDidDestroy: (callback) ->
+ @emitter.on 'did-destroy', callback
+
+ attach: ->
+ workspaceElement = atom.views.getView(atom.workspace)
+ workspaceElement.appendChild this
+ @hiddenInput.focus()
+
+ destroy: ->
+ @emitter.emit('did-destroy')
+ @subscriptions.dispose()
+ @parentNode.removeChild(this)
+
+ initList: ->
+ @itemsDisposables = new WeakMap
+ @addItemFor(name, plugin) for name, plugin of Main.plugins
+
+ toggleSelectedItem: => @itemsActions.get(@selectedItem)?()
+
+ selectNextItem: ->
+ @selectedItem.classList.remove('selected')
+ if @selectedItem.nextSibling?
+ @selectedItem = @selectedItem.nextSibling
+ @selectedItem = @selectedItem.nextSibling if @selectedItem.matches('.separator')
+ else
+ @selectedItem = @list.firstChild
+ @selectedItem.classList.add('selected')
+
+ selectPreviousItem: ->
+ @selectedItem.classList.remove('selected')
+ if @selectedItem.previousSibling?
+ @selectedItem = @selectedItem.previousSibling
+ @selectedItem = @selectedItem.previousSibling if @selectedItem.matches('.separator')
+ else
+ @selectedItem = @list.lastChild
+ @selectedItem.classList.add('selected')
+
+ addItemFor: (name, plugin) ->
+ item = document.createElement('li')
+ item.classList.add('active') if plugin.isActive()
+ item.textContent = name
+
+ action = => Main.togglePluginActivation(name)
+
+ @itemsActions.set(item, action)
+ @itemsDisposables.set item, @addDisposableEventListener item, 'mousedown', (e) =>
+ e.preventDefault()
+ action()
+
+ @plugins[name] = item
+ @list.insertBefore item, @separator
+
+ unless @selectedItem?
+ @selectedItem = item
+ @selectedItem.classList.add('selected')
+
+ removeItemFor: (name, plugin) ->
+ try @list.removeChild(@plugins[name])
+ delete @plugins[name]
+
+ activateItem: (name, plugin) ->
+ @plugins[name].classList.add('active')
+
+ deactivateItem: (name, plugin) ->
+ @plugins[name].classList.remove('active')
+
+module.exports = MinimapQuickSettingsElement = document.registerElement 'minimap-quick-settings', prototype: MinimapQuickSettingsElement.prototype
diff --git a/lib/minimap-quick-settings-view.coffee b/lib/minimap-quick-settings-view.coffee
deleted file mode 100644
index 02f199c9..00000000
--- a/lib/minimap-quick-settings-view.coffee
+++ /dev/null
@@ -1,107 +0,0 @@
-{$, View} = require 'atom-space-pen-views'
-{CompositeDisposable, Emitter} = require 'event-kit'
-
-Minimap = require './main'
-
-module.exports =
-class MinimapQuickSettingsView extends View
- @content: ->
- @div class: 'select-list popover-list minimap-quick-settings', =>
- @input type: 'text', class: 'hidden-input', outlet: 'hiddenInput'
- @ol class: 'list-group mark-active', outlet: 'list', =>
- @li class: 'separator', outlet: 'separator'
- @li class: '', outlet: 'codeHighlights', 'code-highlights'
-
- selectedItem: null
-
- initialize: (@minimapView) ->
- @emitter = new Emitter
- @subscriptions = new CompositeDisposable
- @plugins = {}
- @subscriptions.add Minimap.onDidAddPlugin ({name, plugin}) =>
- @addItemFor(name, plugin)
- @subscriptions.add Minimap.onDidRemovePlugin ({name, plugin}) =>
- @removeItemFor(name, plugin)
- @subscriptions.add Minimap.onDidActivatePlugin ({name, plugin}) =>
- @activateItem(name, plugin)
- @subscriptions.add Minimap.onDidDeactivatePlugin ({name, plugin}) =>
- @deactivateItem(name, plugin)
-
- @subscriptions.add atom.commands.add '.minimap-quick-settings',
- 'core:move-up': => @selectPreviousItem()
- 'core:move-down': => @selectNextItem()
- 'core:cancel': => @destroy()
- 'core:confirm': => @toggleSelectedItem()
-
- @codeHighlights.toggleClass('active', @minimapView.displayCodeHighlights)
- @codeHighlights.on 'mousedown', (e) =>
- e.preventDefault()
- @minimapView.setDisplayCodeHighlights(!@minimapView.displayCodeHighlights)
- @codeHighlights.toggleClass('active', @minimapView.displayCodeHighlights)
-
- @hiddenInput.on 'focusout', @destroy
-
- @initList()
-
- onDidDestroy: (callback) ->
- @emitter.on 'did-destroy', callback
-
- attach: ->
- workspaceElement = atom.views.getView(atom.workspace)
- workspaceElement.appendChild @element
- @hiddenInput.focus()
-
- destroy: =>
- @emitter.emit('did-destroy')
- @off()
- @hiddenInput.off()
- @codeHighlights.off()
- @subscriptions.dispose()
- @detach()
-
- initList: ->
- @addItemFor(name, plugin) for name, plugin of Minimap.plugins
-
- toggleSelectedItem: =>
- @selectedItem.mousedown()
-
- selectNextItem: =>
- @selectedItem.removeClass('selected')
- if @selectedItem.index() isnt @list.children().length - 1
- @selectedItem = @selectedItem.next()
- @selectedItem = @selectedItem.next() if @selectedItem.is('.separator')
- else
- @selectedItem = @list.children().first()
- @selectedItem.addClass('selected')
-
- selectPreviousItem: =>
- @selectedItem.removeClass('selected')
- if @selectedItem.index() isnt 0
- @selectedItem = @selectedItem.prev()
- @selectedItem = @selectedItem.prev() if @selectedItem.is('.separator')
- else
- @selectedItem = @list.children().last()
- @selectedItem.addClass('selected')
-
- addItemFor: (name, plugin) ->
- cls = if plugin.isActive() then 'active' else ''
- item = $("
#{name}")
- item.on 'mousedown', (e) =>
- e.preventDefault()
- atom.commands.dispatch item[0], "minimap:toggle-#{name}"
-
- @plugins[name] = item
- @separator.before item
- unless @selectedItem?
- @selectedItem = item
- @selectedItem.addClass('selected')
-
- removeItemFor: (name, plugin) ->
- try @list.remove(@plugins[name])
- delete @plugins[name]
-
- activateItem: (name, plugin) ->
- @plugins[name].addClass('active')
-
- deactivateItem: (name, plugin) ->
- @plugins[name].removeClass('active')
diff --git a/lib/mixins/canvas-drawer.coffee b/lib/mixins/canvas-drawer.coffee
index 4bf1e2c4..a289bc25 100644
--- a/lib/mixins/canvas-drawer.coffee
+++ b/lib/mixins/canvas-drawer.coffee
@@ -129,9 +129,9 @@ class CanvasDrawer extends Mixin
return if firstRow > lastRow
lines = @getTextEditor().tokenizedLinesForScreenRows(firstRow, lastRow)
- lineHeight = @minimap.getLineHeight() * devicePixelRatio
- charHeight = @minimap.getCharHeight() * devicePixelRatio
- charWidth = @minimap.getCharWidth() * devicePixelRatio
+ lineHeight = @minimap.getLineHeight() * @devicePixelRatio
+ charHeight = @minimap.getCharHeight() * @devicePixelRatio
+ charWidth = @minimap.getCharWidth() * @devicePixelRatio
canvasWidth = @canvas.width
displayCodeHighlights = @displayCodeHighlights
decorations = @minimap.decorationsForScreenRowRange(firstRow, lastRow)
@@ -260,7 +260,7 @@ class CanvasDrawer extends Mixin
# destRow - The row {Number} on the destination bitmap.
# rowCount - The {Number} of rows to copy.
copyBitmapPart: (context, bitmapCanvas, srcRow, destRow, rowCount) ->
- lineHeight = @minimap.getLineHeight() * devicePixelRatio
+ lineHeight = @minimap.getLineHeight() * @devicePixelRatio
context.drawImage(bitmapCanvas,
0, srcRow * lineHeight,
bitmapCanvas.width, rowCount * lineHeight,
diff --git a/lib/mixins/plugin-management.coffee b/lib/mixins/plugin-management.coffee
index 53c876b3..ddfc1256 100644
--- a/lib/mixins/plugin-management.coffee
+++ b/lib/mixins/plugin-management.coffee
@@ -46,6 +46,14 @@ class PluginManagement extends Mixin
event = {name, plugin}
@emitter.emit('did-remove-plugin', event)
+ togglePluginActivation: (name, boolean=undefined) ->
+ settingsKey = "minimap.plugins.#{name}"
+ if boolean?
+ atom.config.set settingsKey, boolean
+ else
+ atom.config.set settingsKey, not atom.config.get(settingsKey)
+
+ @updatesPluginActivationState(name)
# Internal: Updates the plugin activation state according to the current
# config.
@@ -84,9 +92,7 @@ class PluginManagement extends Mixin
@updatesPluginActivationState(name)
commands = {}
- commands["minimap:toggle-#{name}"] = =>
- atom.config.set settingsKey, not atom.config.get(settingsKey)
- @updatesPluginActivationState(name)
+ commands["minimap:toggle-#{name}"] = => @togglePluginActivation(name)
@pluginsSubscriptions[name].add atom.commands.add 'atom-workspace', commands
diff --git a/package.json b/package.json
index 5f75e667..7cf26e81 100644
--- a/package.json
+++ b/package.json
@@ -27,6 +27,7 @@
"fs-plus": "2.x",
"mixto": "1.x",
"semver": "^4.3.0",
- "underscore-plus": "1.x"
+ "underscore-plus": "1.x",
+ "atom-utils": "0.5.x"
}
}
diff --git a/spec/minimap-element-spec.coffee b/spec/minimap-element-spec.coffee
index d0046da9..eba81d2e 100644
--- a/spec/minimap-element-spec.coffee
+++ b/spec/minimap-element-spec.coffee
@@ -15,7 +15,8 @@ realOffsetLeft = (o) ->
transform = new WebKitCSSMatrix window.getComputedStyle(o).transform
o.offsetLeft + transform.m41
-devicePixelRatio = window.devicePixelRatio || 1
+# Modify the global `devicePixelRatio` variable.
+window.devicePixelRatio = 2
sleep = (duration) ->
t = new Date
@@ -29,6 +30,7 @@ describe 'MinimapElement', ->
atom.config.set 'minimap.charWidth', 2
atom.config.set 'minimap.interline', 1
atom.config.set 'minimap.textOpacity', 1
+ atom.config.set 'minimap.devicePixelRatio', 2
MinimapElement.registerViewProvider()
@@ -72,6 +74,8 @@ describe 'MinimapElement', ->
[noAnimationFrame, nextAnimationFrame, canvas, visibleArea] = []
beforeEach ->
+ # Comment after body below to leave the created text editor and minimap
+ # on DOM after the test run.
jasmineContent = document.body.querySelector('#jasmine-content')
noAnimationFrame = -> throw new Error('No animation frame requested')
@@ -99,6 +103,10 @@ describe 'MinimapElement', ->
background: rgba(0,255,0,0.3);
opacity: 1;
}
+
+ atom-text-editor::shadow atom-text-editor-minimap::shadow .open-minimap-quick-settings {
+ opacity: 1 !important;
+ }
"""
jasmineContent.appendChild(styleNode)
@@ -121,8 +129,8 @@ describe 'MinimapElement', ->
expect(minimapElement.offsetWidth).toBeCloseTo(editorElement.clientWidth / 11, 0)
it 'resizes the canvas to fit the minimap', ->
- expect(canvas.offsetHeight / devicePixelRatio).toEqual(minimapElement.offsetHeight + minimap.getLineHeight())
- expect(canvas.offsetWidth / devicePixelRatio).toEqual(minimapElement.offsetWidth)
+ expect(canvas.offsetHeight / devicePixelRatio).toBeCloseTo(minimapElement.offsetHeight + minimap.getLineHeight(), 0)
+ expect(canvas.offsetWidth / devicePixelRatio).toBeCloseTo(minimapElement.offsetWidth, 0)
it 'requests an update', ->
expect(minimapElement.frameRequested).toBeTruthy()
@@ -204,8 +212,8 @@ describe 'MinimapElement', ->
expect(minimapElement.offsetWidth).toBeCloseTo(editorElement.offsetWidth / 11, 0)
expect(minimapElement.offsetHeight).toEqual(editorElement.offsetHeight)
- expect(canvas.offsetWidth / devicePixelRatio).toEqual(minimapElement.offsetWidth)
- expect(canvas.offsetHeight / devicePixelRatio).toEqual(minimapElement.offsetHeight + minimap.getLineHeight())
+ expect(canvas.offsetWidth / devicePixelRatio).toBeCloseTo(minimapElement.offsetWidth, 0)
+ expect(canvas.offsetHeight / devicePixelRatio).toBeCloseTo(minimapElement.offsetHeight + minimap.getLineHeight(), 0)
describe 'when the editor visible content is changed', ->
beforeEach ->
@@ -406,7 +414,7 @@ describe 'MinimapElement', ->
# ## ## ## ## ## ### ## ## ## ##
# ###### ####### ## ## ## #### ######
- describe 'when the atom them is changed', ->
+ describe 'when the atom themes are changed', ->
beforeEach ->
nextAnimationFrame()
spyOn(minimapElement, 'requestForcedUpdate').andCallThrough()
@@ -640,7 +648,7 @@ describe 'MinimapElement', ->
# ###### ######## ## ## #### ## ## ###### ######
describe 'when minimap.displayPluginsControls setting is true', ->
- [openQuickSettings, quickSettingsView, workspaceElement] = []
+ [openQuickSettings, quickSettingsElement, workspaceElement] = []
beforeEach ->
atom.config.set 'minimap.displayPluginsControls', true
@@ -655,20 +663,105 @@ describe 'MinimapElement', ->
openQuickSettings = minimapElement.shadowRoot.querySelector('.open-minimap-quick-settings')
mousedown(openQuickSettings)
- quickSettingsView = workspaceElement.querySelector('.minimap-quick-settings')
+ quickSettingsElement = workspaceElement.querySelector('minimap-quick-settings')
afterEach ->
- minimapElement.quickSettingsView.destroy()
+ minimapElement.quickSettingsElement.destroy()
it 'opens the quick settings view', ->
- expect(quickSettingsView).toExist()
+ expect(quickSettingsElement).toExist()
it 'positions the quick settings view next to the minimap', ->
- minimapBounds = minimapElement.getBoundingClientRect()
- settingsBounds = quickSettingsView.getBoundingClientRect()
+ minimapBounds = minimapElement.canvas.getBoundingClientRect()
+ settingsBounds = quickSettingsElement.getBoundingClientRect()
+
+ expect(realOffsetTop(quickSettingsElement)).toBeCloseTo(minimapBounds.top, 0)
+ expect(realOffsetLeft(quickSettingsElement)).toBeCloseTo(minimapBounds.left - settingsBounds.width, 0)
+
+ describe 'when the displayMinimapOnLeft setting is enabled', ->
+ describe 'clicking on the div', ->
+ beforeEach ->
+ atom.config.set('minimap.displayMinimapOnLeft', true)
+
+ workspaceElement = atom.views.getView(atom.workspace)
+ jasmineContent.appendChild(workspaceElement)
+
+ openQuickSettings = minimapElement.shadowRoot.querySelector('.open-minimap-quick-settings')
+ mousedown(openQuickSettings)
+
+ quickSettingsElement = workspaceElement.querySelector('minimap-quick-settings')
+
+ afterEach ->
+ minimapElement.quickSettingsElement.destroy()
+
+ it 'positions the quick settings view next to the minimap', ->
+ minimapBounds = minimapElement.canvas.getBoundingClientRect()
+ settingsBounds = quickSettingsElement.getBoundingClientRect()
+
+ expect(realOffsetTop(quickSettingsElement)).toBeCloseTo(minimapBounds.top, 0)
+ expect(realOffsetLeft(quickSettingsElement)).toBeCloseTo(minimapBounds.right, 0)
+
+ describe 'when the adjustMinimapWidthToSoftWrap setting is enabled', ->
+ [controls] = []
+ beforeEach ->
+ atom.config.set 'editor.softWrap', true
+ atom.config.set 'editor.softWrapAtPreferredLineLength', true
+ atom.config.set 'editor.preferredLineLength', 2
+
+ atom.config.set('minimap.adjustMinimapWidthToSoftWrap', true)
+ nextAnimationFrame()
+
+ controls = minimapElement.shadowRoot.querySelector('.minimap-controls')
+ openQuickSettings = minimapElement.shadowRoot.querySelector('.open-minimap-quick-settings')
+
+ editorElement.style.width = '1024px'
+
+ sleep(150)
+ waitsFor -> minimapElement.frameRequested
+ runs -> nextAnimationFrame()
+
+ it 'adjusts the size of the control div to fit in the minimap', ->
+ expect(controls.clientWidth).toEqual(minimapElement.canvas.clientWidth / devicePixelRatio)
+
+ it 'positions the controls div over the canvas', ->
+ controlsRect = controls.getBoundingClientRect()
+ canvasRect = minimapElement.canvas.getBoundingClientRect()
+ expect(controlsRect.left).toEqual(canvasRect.left)
+ expect(controlsRect.right).toEqual(canvasRect.right)
+
+ describe 'when the displayMinimapOnLeft setting is enabled', ->
+ beforeEach ->
+ atom.config.set('minimap.displayMinimapOnLeft', true)
+ nextAnimationFrame()
+
+ it 'adjusts the size of the control div to fit in the minimap', ->
+ expect(controls.clientWidth).toEqual(minimapElement.canvas.clientWidth / devicePixelRatio)
+
+ it 'positions the controls div over the canvas', ->
+ controlsRect = controls.getBoundingClientRect()
+ canvasRect = minimapElement.canvas.getBoundingClientRect()
+ expect(controlsRect.left).toEqual(canvasRect.left)
+ expect(controlsRect.right).toEqual(canvasRect.right)
+
+ describe 'clicking on the div', ->
+ beforeEach ->
+ workspaceElement = atom.views.getView(atom.workspace)
+ jasmineContent.appendChild(workspaceElement)
- expect(realOffsetTop(quickSettingsView)).toBeCloseTo(minimapBounds.top, 0)
- expect(realOffsetLeft(quickSettingsView)).toBeCloseTo(minimapBounds.left - settingsBounds.width, 0)
+ openQuickSettings = minimapElement.shadowRoot.querySelector('.open-minimap-quick-settings')
+ mousedown(openQuickSettings)
+
+ quickSettingsElement = workspaceElement.querySelector('minimap-quick-settings')
+
+ afterEach ->
+ minimapElement.quickSettingsElement.destroy()
+
+ it 'positions the quick settings view next to the minimap', ->
+ minimapBounds = minimapElement.canvas.getBoundingClientRect()
+ settingsBounds = quickSettingsElement.getBoundingClientRect()
+
+ expect(realOffsetTop(quickSettingsElement)).toBeCloseTo(minimapBounds.top, 0)
+ expect(realOffsetLeft(quickSettingsElement)).toBeCloseTo(minimapBounds.right, 0)
describe 'when the quick settings view is open', ->
beforeEach ->
@@ -678,11 +771,14 @@ describe 'MinimapElement', ->
openQuickSettings = minimapElement.shadowRoot.querySelector('.open-minimap-quick-settings')
mousedown(openQuickSettings)
- quickSettingsView = workspaceElement.querySelector('.minimap-quick-settings')
+ quickSettingsElement = workspaceElement.querySelector('minimap-quick-settings')
+
+ it 'sets the on right button active', ->
+ expect(quickSettingsElement.querySelector('.btn.selected:last-child')).toExist()
describe 'clicking on the code highlight item', ->
beforeEach ->
- item = quickSettingsView.querySelector('li:last-child')
+ item = quickSettingsElement.querySelector('li:last-child')
mousedown(item)
it 'toggles the code highlights on the minimap element', ->
@@ -691,22 +787,58 @@ describe 'MinimapElement', ->
it 'requests an update', ->
expect(minimapElement.frameRequested).toBeTruthy()
+ describe 'clicking on the on left button', ->
+ beforeEach ->
+ item = quickSettingsElement.querySelector('.btn:first-child')
+ mousedown(item)
+
+ it 'toggles the displayMinimapOnLeft setting', ->
+ expect(atom.config.get('minimap.displayMinimapOnLeft')).toBeTruthy()
+
+ it 'changes the buttons activation state', ->
+ expect(quickSettingsElement.querySelector('.btn.selected:last-child')).not.toExist()
+ expect(quickSettingsElement.querySelector('.btn.selected:first-child')).toExist()
+
+ describe 'core:move-left', ->
+ beforeEach ->
+ atom.commands.dispatch quickSettingsElement, 'core:move-left'
+
+ it 'toggles the displayMinimapOnLeft setting', ->
+ expect(atom.config.get('minimap.displayMinimapOnLeft')).toBeTruthy()
+
+ it 'changes the buttons activation state', ->
+ expect(quickSettingsElement.querySelector('.btn.selected:last-child')).not.toExist()
+ expect(quickSettingsElement.querySelector('.btn.selected:first-child')).toExist()
+
+ describe 'core:move-right when the minimap is on the right', ->
+ beforeEach ->
+ atom.config.set('minimap.displayMinimapOnLeft', true)
+ atom.commands.dispatch quickSettingsElement, 'core:move-right'
+
+ it 'toggles the displayMinimapOnLeft setting', ->
+ expect(atom.config.get('minimap.displayMinimapOnLeft')).toBeFalsy()
+
+ it 'changes the buttons activation state', ->
+ expect(quickSettingsElement.querySelector('.btn.selected:first-child')).not.toExist()
+ expect(quickSettingsElement.querySelector('.btn.selected:last-child')).toExist()
+
+
describe 'clicking on the open settings button again', ->
beforeEach ->
mousedown(openQuickSettings)
it 'closes the quick settings view', ->
- expect(workspaceElement.querySelector('.minimap-quick-settings')).not.toExist()
+ expect(workspaceElement.querySelector('minimap-quick-settings')).not.toExist()
it 'removes the view from the element', ->
- expect(minimapElement.quickSettingsView).toBeNull()
+ expect(minimapElement.quickSettingsElement).toBeNull()
describe 'when an external event destroys the view', ->
beforeEach ->
- minimapElement.quickSettingsView.destroy()
+ minimapElement.quickSettingsElement.destroy()
it 'removes the view reference from the element', ->
- expect(minimapElement.quickSettingsView).toBeNull()
+ expect(minimapElement.quickSettingsElement).toBeNull()
describe 'then disabling it', ->
beforeEach ->
@@ -714,3 +846,104 @@ describe 'MinimapElement', ->
it 'removes the div', ->
expect(minimapElement.shadowRoot.querySelector('.open-minimap-quick-settings')).not.toExist()
+
+ describe 'with plugins registered in the package', ->
+ [minimapPackage, pluginA, pluginB] = []
+ beforeEach ->
+ waitsForPromise ->
+ atom.packages.activatePackage('minimap').then (pkg) ->
+ minimapPackage = pkg.mainModule
+
+ runs ->
+ class Plugin
+ active: false
+ activatePlugin: -> @active = true
+ deactivatePlugin: -> @active = false
+ isActive: -> @active
+
+ pluginA = new Plugin
+ pluginB = new Plugin
+
+ minimapPackage.registerPlugin('dummyA', pluginA)
+ minimapPackage.registerPlugin('dummyB', pluginB)
+
+ workspaceElement = atom.views.getView(atom.workspace)
+ jasmineContent.appendChild(workspaceElement)
+
+ openQuickSettings = minimapElement.shadowRoot.querySelector('.open-minimap-quick-settings')
+ mousedown(openQuickSettings)
+
+ quickSettingsElement = workspaceElement.querySelector('minimap-quick-settings')
+
+ it 'creates one list item for each registered plugin', ->
+ expect(quickSettingsElement.querySelectorAll('li').length).toEqual(4)
+
+ it 'selects the first item of the list', ->
+ expect(quickSettingsElement.querySelector('li.selected:first-child')).toExist()
+
+ describe 'core:confirm', ->
+ beforeEach ->
+ atom.commands.dispatch quickSettingsElement, 'core:confirm'
+
+ it 'disable the plugin of the selected item', ->
+ expect(pluginA.isActive()).toBeFalsy()
+
+ describe 'triggered a second time', ->
+ beforeEach ->
+ atom.commands.dispatch quickSettingsElement, 'core:confirm'
+
+ it 'enable the plugin of the selected item', ->
+ expect(pluginA.isActive()).toBeTruthy()
+
+ describe 'on the code highlight item', ->
+ [initial] = []
+ beforeEach ->
+ initial = minimapElement.displayCodeHighlights
+ atom.commands.dispatch quickSettingsElement, 'core:move-down'
+ atom.commands.dispatch quickSettingsElement, 'core:move-down'
+ atom.commands.dispatch quickSettingsElement, 'core:confirm'
+
+ it 'toggles the code highlights on the minimap element', ->
+ expect(minimapElement.displayCodeHighlights).toEqual(not initial)
+
+ describe 'core:move-down', ->
+ beforeEach ->
+ atom.commands.dispatch quickSettingsElement, 'core:move-down'
+
+ it 'selects the second item', ->
+ expect(quickSettingsElement.querySelector('li.selected:nth-child(2)')).toExist()
+
+ describe 'reaching a separator', ->
+ beforeEach ->
+ atom.commands.dispatch quickSettingsElement, 'core:move-down'
+
+ it 'moves past the separator', ->
+ expect(quickSettingsElement.querySelector('li.selected:last-child')).toExist()
+
+ describe 'then core:move-up', ->
+ beforeEach ->
+ atom.commands.dispatch quickSettingsElement, 'core:move-up'
+
+ it 'selects again the first item of the list', ->
+ expect(quickSettingsElement.querySelector('li.selected:first-child')).toExist()
+
+ describe 'core:move-up', ->
+ beforeEach ->
+ atom.commands.dispatch quickSettingsElement, 'core:move-up'
+
+ it 'selects the last item', ->
+ expect(quickSettingsElement.querySelector('li.selected:last-child')).toExist()
+
+ describe 'reaching a separator', ->
+ beforeEach ->
+ atom.commands.dispatch quickSettingsElement, 'core:move-up'
+
+ it 'moves past the separator', ->
+ expect(quickSettingsElement.querySelector('li.selected:nth-child(2)')).toExist()
+
+ describe 'then core:move-down', ->
+ beforeEach ->
+ atom.commands.dispatch quickSettingsElement, 'core:move-down'
+
+ it 'selects again the first item of the list', ->
+ expect(quickSettingsElement.querySelector('li.selected:first-child')).toExist()
diff --git a/styles/minimap.less b/styles/minimap.less
index e46582cc..a993f619 100644
--- a/styles/minimap.less
+++ b/styles/minimap.less
@@ -4,14 +4,6 @@ atom-notifications:empty {
pointer-events: none
}
-// ## ## ##
-// ## ## ## ##
-// ## ## ## ##
-// ## ## ## ##
-// ## ## #########
-// ## ## ##
-// ### ##
-
atom-text-editor::shadow, atom-text-editor {
atom-text-editor-minimap {
display: block;
@@ -75,8 +67,6 @@ atom-text-editor::shadow, atom-text-editor {
font-family: 'Octicons Regular';
}
}
-
-
}
&:hover::shadow .open-minimap-quick-settings {
opacity: 1;
@@ -85,37 +75,7 @@ atom-text-editor::shadow, atom-text-editor {
}
}
-// ## ## #######
-// ## ## ## ##
-// ## ## ##
-// ## ## #######
-// ## ## ##
-// ## ## ## ##
-// ### #######
-
-atom-pane.with-minimap {
- atom-text-editor, :host, atom-text-editor, atom-text-editor::shadow {
-
- &:not(.minimap-editor):not(.mini) {
- padding-right: 10%;
- }
- .vertical-scrollbar {
- right: 0 !important;
- }
- }
-}
-
-.zen atom-pane.with-minimap {
- atom-text-editor, atom-text-editor::shadow {
- padding-right: 0 !important;
-
- .vertical-scrollbar {
- right: 0 !important;
- }
- }
-}
-
-.minimap-quick-settings {
+minimap-quick-settings {
position: absolute !important;
.hidden-input {
@@ -142,125 +102,12 @@ atom-pane.with-minimap {
background: @background-color-highlight;
}
}
-}
-
-.open-minimap-quick-settings {
- opacity: 0;
- position: absolute;
- z-index: 1;
- cursor: pointer;
- color: @text-color;
- font-size: 20px;
- text-align: center;
- line-height: 24px;
- width: 24px;
- height: 24px;
- display: block;
- right: 4px;
- transition: opacity 0.4s;
-
- &:before {
- content: '\f02f';
- font-family: 'Octicons Regular';
- }
-}
-
-.minimap:hover .open-minimap-quick-settings {
- opacity: 1;
- transition: opacity 0.1s;
-}
-
-.minimap-on-left {
- atom-pane.with-minimap {
- atom-text-editor, :host, atom-text-editor, atom-text-editor::shadow {
- &:not(.minimap-editor):not(.mini) {
- padding-right: 0;
- padding-left: 10%;
- }
- }
-
- .vertical-scrollbar {
- right: 0;
- }
-
- .minimap {
- left: 0 !important;
- }
- }
-}
-
-.minimap {
- position: absolute;
- right: 0;
- bottom: 0;
- left: initial !important;
-
- width: 10%;
- overflow: hidden;
- box-sizing: border-box;
-
- -webkit-user-select: none;
-
- atom-text-editor {
- padding: 0 !important;
- background: transparent;
- }
-
- .minimap-scroller {
- position: absolute;
- display: none;
- right: 0;
- width: 2px;
- min-height: 2px;
- z-index: 10;
- background: @background-color-selected;
-
- &.visible {
- display: block;
- }
- }
- .minimap-wrapper {
- position: absolute;
+ .btn-group {
width: 100%;
- height: 100%;
- -webkit-transform-origin: 0 0;
- .accelerated;
- }
-
- .minimap-underlayer,
- .minimap-overlayer {
- -webkit-transform-origin: 0 0;
- }
- .minimap-visible-area {
- position: absolute;
- width: 100%;
- background-color: #888;
- opacity: .2;
- cursor: -webkit-grab;
- }
- .minimap-visible-area:active{
- cursor: -webkit-grabbing;
- }
-
- .minimap-editor {
- position: absolute;
- cursor: default;
- height: 100%;
- width: 100%;
- }
-
- .minimap-canvas {
- width: 100%;
- height: 100%;
- }
-
- // Mixins
- .accelerated {
- -webkit-backface-visibility: hidden;
- backface-visibility: hidden;
- -webkit-transform: translateZ(0);
- transform: translateZ(0);
+ .btn {
+ width: 50%;
+ }
}
}