How to use openQuickSettings method in root

Best JavaScript code snippet using root

minimap-element-spec.js

Source:minimap-element-spec.js Github

copy

Full Screen

1'use strict'2const fs = require('fs-plus')3const Main = require('../lib/main')4const Minimap = require('../lib/minimap')5const {styles} = require('./helpers/workspace')6const {mousemove, mousedown, mouseup, mousewheel, touchstart, touchmove} = require('./helpers/events')7const HIDE_ELEMENTS = true8window.devicePixelRatio = 19function realOffsetTop (o) {10 // transform = new WebKitCSSMatrix window.getComputedStyle(o).transform11 // o.offsetTop + transform.m4212 return o.offsetTop13}14function realOffsetLeft (o) {15 // transform = new WebKitCSSMatrix window.getComputedStyle(o).transform16 // o.offsetLeft + transform.m4117 return o.offsetLeft18}19function sleep (duration) {20 const t = new Date()21 waitsFor(`${duration}ms`, () => { return new Date() - t > duration })22}23function createPlugin () {24 const plugin = {25 active: false,26 activatePlugin () { this.active = true },27 deactivatePlugin () { this.active = false },28 isActive () { return this.active }29 }30 return plugin31}32describe('MinimapElement', () => {33 let [editor, minimap, largeSample, mediumSample, smallSample, jasmineContent, editorElement, minimapElement, dir] = []34 const resizeEditor = (height, width) => {35 editorElement.setHeight(height)36 if (width) { editorElement.setWidth(width) }37 editorElement.component.measureDimensions()38 }39 beforeEach(() => {40 jasmineContent = HIDE_ELEMENTS41 ? document.body.querySelector('#jasmine-content')42 : document.body43 waitsForPromise(() => atom.packages.activatePackage('minimap'))44 runs(() => {45 atom.config.set('minimap.charHeight', 4)46 atom.config.set('minimap.charWidth', 2)47 atom.config.set('minimap.interline', 1)48 atom.config.set('minimap.textOpacity', 1)49 atom.config.set('minimap.autoToggle', true)50 atom.config.set('minimap.displayMinimapOnLeft', false)51 atom.config.set('minimap.displayCodeHighlights', false)52 atom.config.set('minimap.displayPluginsControls', false)53 atom.config.set('minimap.minimapScrollIndicator', false)54 atom.config.set('minimap.adjustMinimapWidthToSoftWrap', false)55 atom.config.set('minimap.smoothScrolling', true)56 atom.config.set('minimap.adjustMinimapWidthOnlyIfSmaller', true)57 atom.config.set('minimap.plugins', {})58 editor = atom.workspace.buildTextEditor({})59 editor.autoHeight = false60 editorElement = atom.views.getView(editor)61 jasmineContent.insertBefore(editorElement, jasmineContent.firstChild)62 resizeEditor(50)63 minimap = new Minimap({textEditor: editor})64 minimap.adapter.useCache = false65 dir = atom.project.getDirectories()[0]66 largeSample = fs.readFileSync(dir.resolve('large-file.coffee')).toString()67 mediumSample = fs.readFileSync(dir.resolve('two-hundred.txt')).toString()68 smallSample = fs.readFileSync(dir.resolve('sample.coffee')).toString()69 editor.setText(largeSample)70 minimapElement = atom.views.getView(minimap)71 const styleNode = document.createElement('style')72 styleNode.textContent = HIDE_ELEMENTS73 ? styles74 : `75 ${styles}76 atom-text-editor {77 background: white;78 z-index: 100000;79 }80 `81 jasmineContent.appendChild(styleNode)82 })83 })84 it('has been registered in the view registry', () => {85 expect(minimapElement).toExist()86 })87 it('has stored the minimap as its model', () => {88 expect(minimapElement.getModel()).toBe(minimap)89 })90 it('has a canvas in DOM', () => {91 expect(minimapElement.querySelector('canvas')).toExist()92 })93 it('has a div representing the visible area', () => {94 expect(minimapElement.querySelector('.minimap-visible-area')).toExist()95 })96 // ### ######## ######## ### ###### ## ##97 // ## ## ## ## ## ## ## ## ## ##98 // ## ## ## ## ## ## ## ## ##99 // ## ## ## ## ## ## ## #########100 // ######### ## ## ######### ## ## ##101 // ## ## ## ## ## ## ## ## ## ##102 // ## ## ## ## ## ## ###### ## ##103 describe('when attached to the text editor element', () => {104 let [noAnimationFrame, nextAnimationFrame, requestAnimationFrameSafe, canvas, visibleArea] = []105 beforeEach(() => {106 const stackedFrames = []107 noAnimationFrame = () => {108 throw new Error('No animation frame requested')109 }110 nextAnimationFrame = noAnimationFrame111 requestAnimationFrameSafe = window.requestAnimationFrame112 spyOn(window, 'requestAnimationFrame').andCallFake((fn) => {113 if (stackedFrames.length === 0) {114 nextAnimationFrame = () => {115 while (stackedFrames.length) {116 fn = stackedFrames.shift()117 fn()118 }119 nextAnimationFrame = noAnimationFrame120 }121 }122 stackedFrames.push(fn)123 })124 })125 beforeEach(() => {126 canvas = minimapElement.querySelector('canvas')127 resizeEditor(50, 200)128 editorElement.setScrollTop(1000)129 editorElement.setScrollLeft(200)130 minimapElement.attach()131 })132 afterEach(() => {133 if (HIDE_ELEMENTS) { minimap.destroy() }134 window.requestAnimationFrame = requestAnimationFrameSafe135 })136 it('adds a with-minimap attribute on the text editor element', () => {137 expect(editorElement.hasAttribute('with-minimap')).toBeTruthy()138 })139 it('takes the height of the editor', () => {140 expect(minimapElement.offsetHeight).toEqual(editorElement.clientHeight)141 expect(minimapElement.offsetWidth).toBeCloseTo(editorElement.clientWidth / 10, 0)142 })143 it('knows when attached to a text editor', () => {144 expect(minimapElement.attachedToTextEditor).toBeTruthy()145 })146 it('resizes the canvas to fit the minimap', () => {147 expect(canvas.offsetHeight / devicePixelRatio).toBeCloseTo(minimapElement.offsetHeight + minimap.getLineHeight(), 0)148 expect(canvas.offsetWidth / devicePixelRatio).toBeCloseTo(minimapElement.offsetWidth, 0)149 })150 it('requests an update', () => {151 expect(minimapElement.frameRequested).toBeTruthy()152 })153 describe('when detached', () => {154 it('removes the attribute from the editor', () => {155 minimapElement.detach()156 expect(editorElement.hasAttribute('with-minimap')).toBeFalsy()157 })158 })159 // ###### ###### ######160 // ## ## ## ## ## ##161 // ## ## ##162 // ## ###### ######163 // ## ## ##164 // ## ## ## ## ## ##165 // ###### ###### ######166 describe('with css filters', () => {167 describe('when a hue-rotate filter is applied to a rgb color', () => {168 let [additionnalStyleNode] = []169 beforeEach(() => {170 minimapElement.invalidateDOMStylesCache()171 additionnalStyleNode = document.createElement('style')172 additionnalStyleNode.textContent = `173 atom-text-editor .editor, .editor {174 color: red;175 -webkit-filter: hue-rotate(180deg);176 }177 `178 jasmineContent.appendChild(additionnalStyleNode)179 })180 it('computes the new color by applying the hue rotation', () => {181 waitsFor('new animation frame', () => {182 return nextAnimationFrame !== noAnimationFrame183 })184 runs(() => {185 nextAnimationFrame()186 expect(minimapElement.retrieveStyleFromDom(['.editor'], 'color')).toEqual(`rgb(0, ${0x6d}, ${0x6d})`)187 })188 })189 })190 describe('when a hue-rotate filter is applied to a rgba color', () => {191 let [additionnalStyleNode] = []192 beforeEach(() => {193 minimapElement.invalidateDOMStylesCache()194 additionnalStyleNode = document.createElement('style')195 additionnalStyleNode.textContent = `196 atom-text-editor .editor, .editor {197 color: rgba(255, 0, 0, 0);198 -webkit-filter: hue-rotate(180deg);199 }200 `201 jasmineContent.appendChild(additionnalStyleNode)202 })203 it('computes the new color by applying the hue rotation', () => {204 waitsFor('a new animation frame request', () => {205 return nextAnimationFrame !== noAnimationFrame206 })207 runs(() => {208 nextAnimationFrame()209 expect(minimapElement.retrieveStyleFromDom(['.editor'], 'color')).toEqual(`rgba(0, ${0x6d}, ${0x6d}, 0)`)210 })211 })212 })213 })214 // ## ## ######## ######## ### ######## ########215 // ## ## ## ## ## ## ## ## ## ##216 // ## ## ## ## ## ## ## ## ## ##217 // ## ## ######## ## ## ## ## ## ######218 // ## ## ## ## ## ######### ## ##219 // ## ## ## ## ## ## ## ## ##220 // ####### ## ######## ## ## ## ########221 describe('when the update is performed', () => {222 beforeEach(() => {223 waitsFor('a new animation frame request', () => {224 return nextAnimationFrame !== noAnimationFrame225 })226 runs(() => {227 nextAnimationFrame()228 visibleArea = minimapElement.querySelector('.minimap-visible-area')229 })230 })231 it('sets the visible area width and height', () => {232 expect(visibleArea.offsetWidth).toEqual(minimapElement.clientWidth + Math.floor(minimap.getTextEditorScaledScrollLeft()))233 expect(visibleArea.offsetHeight).toBeCloseTo(minimap.getTextEditorScaledHeight(), 0)234 })235 it('sets the visible visible area offset', () => {236 expect(realOffsetTop(visibleArea)).toBeCloseTo(minimap.getTextEditorScaledScrollTop() - minimap.getScrollTop(), 0)237 expect(Math.floor(parseFloat(visibleArea.style.borderLeftWidth)))238 .toEqual(Math.floor(minimap.getTextEditorScaledScrollLeft()))239 })240 it('offsets the canvas when the scroll does not match line height', () => {241 editorElement.setScrollTop(1004)242 waitsFor('a new animation frame request', () => {243 return nextAnimationFrame !== noAnimationFrame244 })245 runs(() => {246 nextAnimationFrame()247 expect(realOffsetTop(canvas)).toBeCloseTo(-2, -1)248 })249 })250 it('does not fail to update render the invisible char when modified', () => {251 atom.config.set('editor.showInvisibles', true)252 atom.config.set('editor.invisibles', {cr: '*'})253 expect(() => { nextAnimationFrame() }).not.toThrow()254 })255 it('renders the decorations based on the order settings', () => {256 atom.config.set('minimap.displayPluginsControls', true)257 const pluginFoo = createPlugin()258 const pluginBar = createPlugin()259 Main.registerPlugin('foo', pluginFoo)260 Main.registerPlugin('bar', pluginBar)261 atom.config.set('minimap.plugins.fooDecorationsZIndex', 1)262 const calls = []263 spyOn(minimapElement, 'drawLineDecoration').andCallFake((d) => {264 calls.push(d.getProperties().plugin)265 })266 spyOn(minimapElement, 'drawHighlightDecoration').andCallFake((d) => {267 calls.push(d.getProperties().plugin)268 })269 minimap.decorateMarker(editor.markBufferRange([[1, 0], [1, 10]]), {type: 'line', color: '#0000FF', plugin: 'bar'})270 minimap.decorateMarker(editor.markBufferRange([[1, 0], [1, 10]]), {type: 'highlight-under', color: '#0000FF', plugin: 'foo'})271 editorElement.setScrollTop(0)272 waitsFor('a new animation frame request', () => {273 return nextAnimationFrame !== noAnimationFrame274 })275 runs(() => {276 nextAnimationFrame()277 expect(calls).toEqual(['bar', 'foo'])278 atom.config.set('minimap.plugins.fooDecorationsZIndex', -1)279 calls.length = 0280 })281 waitsFor('a new animation frame request', () => {282 return nextAnimationFrame !== noAnimationFrame283 })284 runs(() => {285 nextAnimationFrame()286 expect(calls).toEqual(['foo', 'bar'])287 Main.unregisterPlugin('foo')288 Main.unregisterPlugin('bar')289 })290 })291 it('renders the visible line decorations', () => {292 spyOn(minimapElement, 'drawLineDecoration').andCallThrough()293 minimap.decorateMarker(editor.markBufferRange([[1, 0], [1, 10]]), {type: 'line', color: '#0000FF'})294 minimap.decorateMarker(editor.markBufferRange([[10, 0], [10, 10]]), {type: 'line', color: '#0000FF'})295 minimap.decorateMarker(editor.markBufferRange([[100, 0], [100, 10]]), {type: 'line', color: '#0000FF'})296 editorElement.setScrollTop(0)297 waitsFor('a new animation frame request', () => {298 return nextAnimationFrame !== noAnimationFrame299 })300 runs(() => {301 nextAnimationFrame()302 expect(minimapElement.drawLineDecoration).toHaveBeenCalled()303 expect(minimapElement.drawLineDecoration.calls.length).toEqual(2)304 })305 })306 it('renders the visible gutter decorations', () => {307 spyOn(minimapElement, 'drawGutterDecoration').andCallThrough()308 minimap.decorateMarker(editor.markBufferRange([[1, 0], [1, 10]]), {type: 'gutter', color: '#0000FF'})309 minimap.decorateMarker(editor.markBufferRange([[10, 0], [10, 10]]), {type: 'gutter', color: '#0000FF'})310 minimap.decorateMarker(editor.markBufferRange([[100, 0], [100, 10]]), {type: 'gutter', color: '#0000FF'})311 editorElement.setScrollTop(0)312 waitsFor('a new animation frame request', () => {313 return nextAnimationFrame !== noAnimationFrame314 })315 runs(() => {316 nextAnimationFrame()317 expect(minimapElement.drawGutterDecoration).toHaveBeenCalled()318 expect(minimapElement.drawGutterDecoration.calls.length).toEqual(2)319 })320 })321 it('renders the visible highlight decorations', () => {322 spyOn(minimapElement, 'drawHighlightDecoration').andCallThrough()323 minimap.decorateMarker(editor.markBufferRange([[1, 0], [1, 4]]), {type: 'highlight-under', color: '#0000FF'})324 minimap.decorateMarker(editor.markBufferRange([[2, 20], [2, 30]]), {type: 'highlight-over', color: '#0000FF'})325 minimap.decorateMarker(editor.markBufferRange([[100, 3], [100, 5]]), {type: 'highlight-under', color: '#0000FF'})326 editorElement.setScrollTop(0)327 waitsFor('a new animation frame request', () => {328 return nextAnimationFrame !== noAnimationFrame329 })330 runs(() => {331 nextAnimationFrame()332 expect(minimapElement.drawHighlightDecoration).toHaveBeenCalled()333 expect(minimapElement.drawHighlightDecoration.calls.length).toEqual(2)334 })335 })336 it('renders the visible outline decorations', () => {337 spyOn(minimapElement, 'drawHighlightOutlineDecoration').andCallThrough()338 minimap.decorateMarker(editor.markBufferRange([[1, 4], [3, 6]]), {type: 'highlight-outline', color: '#0000ff'})339 minimap.decorateMarker(editor.markBufferRange([[6, 0], [6, 7]]), {type: 'highlight-outline', color: '#0000ff'})340 minimap.decorateMarker(editor.markBufferRange([[100, 3], [100, 5]]), {type: 'highlight-outline', color: '#0000ff'})341 editorElement.setScrollTop(0)342 waitsFor('a new animation frame request', () => {343 return nextAnimationFrame !== noAnimationFrame344 })345 runs(() => {346 nextAnimationFrame()347 expect(minimapElement.drawHighlightOutlineDecoration).toHaveBeenCalled()348 expect(minimapElement.drawHighlightOutlineDecoration.calls.length).toEqual(4)349 })350 })351 it('renders the visible custom foreground decorations', () => {352 spyOn(minimapElement, 'drawCustomDecoration').andCallThrough()353 const renderRoutine = jasmine.createSpy('renderRoutine')354 const properties = {355 type: 'foreground-custom',356 render: renderRoutine357 }358 minimap.decorateMarker(editor.markBufferRange([[1, 4], [3, 6]]), properties)359 minimap.decorateMarker(editor.markBufferRange([[6, 0], [6, 7]]), properties)360 minimap.decorateMarker(editor.markBufferRange([[100, 3], [100, 5]]), properties)361 editorElement.setScrollTop(0)362 waitsFor('a new animation frame request', () => {363 return nextAnimationFrame !== noAnimationFrame364 })365 runs(() => {366 nextAnimationFrame()367 expect(minimapElement.drawCustomDecoration).toHaveBeenCalled()368 expect(minimapElement.drawCustomDecoration.calls.length).toEqual(4)369 expect(renderRoutine).toHaveBeenCalled()370 expect(renderRoutine.calls.length).toEqual(4)371 })372 })373 it('renders the visible custom background decorations', () => {374 spyOn(minimapElement, 'drawCustomDecoration').andCallThrough()375 const renderRoutine = jasmine.createSpy('renderRoutine')376 const properties = {377 type: 'background-custom',378 render: renderRoutine379 }380 minimap.decorateMarker(editor.markBufferRange([[1, 4], [3, 6]]), properties)381 minimap.decorateMarker(editor.markBufferRange([[6, 0], [6, 7]]), properties)382 minimap.decorateMarker(editor.markBufferRange([[100, 3], [100, 5]]), properties)383 editorElement.setScrollTop(0)384 waitsFor('a new animation frame request', () => {385 return nextAnimationFrame !== noAnimationFrame386 })387 runs(() => {388 nextAnimationFrame()389 expect(minimapElement.drawCustomDecoration).toHaveBeenCalled()390 expect(minimapElement.drawCustomDecoration.calls.length).toEqual(4)391 expect(renderRoutine).toHaveBeenCalled()392 expect(renderRoutine.calls.length).toEqual(4)393 })394 })395 describe('when the editor is scrolled', () => {396 beforeEach(() => {397 editorElement.setScrollTop(2000)398 editorElement.setScrollLeft(50)399 waitsFor('a new animation frame request', () => {400 return nextAnimationFrame !== noAnimationFrame401 })402 runs(() => { nextAnimationFrame() })403 })404 it('updates the visible area', () => {405 expect(realOffsetTop(visibleArea)).toBeCloseTo(minimap.getTextEditorScaledScrollTop() - minimap.getScrollTop(), 0)406 expect(parseFloat(visibleArea.style.borderLeftWidth))407 .toEqual(Math.round(minimap.getTextEditorScaledScrollLeft()))408 })409 })410 describe('when the editor is resized to a greater size', () => {411 beforeEach(() => {412 editorElement.style.width = '800px'413 editorElement.style.height = '500px'414 minimapElement.measureHeightAndWidth()415 waitsFor('a new animation frame request', () => {416 return nextAnimationFrame !== noAnimationFrame417 })418 runs(() => { nextAnimationFrame() })419 })420 it('detects the resize and adjust itself', () => {421 expect(minimapElement.offsetWidth).toBeCloseTo(editorElement.offsetWidth / 10, 0)422 expect(minimapElement.offsetHeight).toEqual(editorElement.offsetHeight)423 expect(canvas.offsetWidth / devicePixelRatio).toBeCloseTo(minimapElement.offsetWidth, 0)424 expect(canvas.offsetHeight / devicePixelRatio).toBeCloseTo(minimapElement.offsetHeight + minimap.getLineHeight(), 0)425 })426 })427 describe('when the editor visible content is changed', () => {428 beforeEach(() => {429 editorElement.setScrollLeft(0)430 editorElement.setScrollTop(1400)431 editor.setSelectedBufferRange([[101, 0], [102, 20]])432 waitsFor('a new animation frame request', () => {433 return nextAnimationFrame !== noAnimationFrame434 })435 runs(() => {436 nextAnimationFrame()437 spyOn(minimapElement, 'drawLines').andCallThrough()438 editor.insertText('foo')439 })440 })441 it('rerenders the part that have changed', () => {442 waitsFor('a new animation frame request', () => {443 return nextAnimationFrame !== noAnimationFrame444 })445 runs(() => {446 nextAnimationFrame()447 expect(minimapElement.drawLines).toHaveBeenCalled()448 const [firstLine, lastLine] = minimapElement.drawLines.argsForCall[0]449 // These tests are very flaky, depending on Atom's version the450 // measured values can changed so we have451 expect(firstLine === 99 || firstLine === 100).toBeTruthy()452 expect(lastLine === 102 || lastLine === 110 || lastLine === 111).toBeTruthy()453 })454 })455 })456 describe('when the editor visibility change', () => {457 it('does not modify the size of the canvas', () => {458 let canvasWidth = minimapElement.getFrontCanvas().width459 let canvasHeight = minimapElement.getFrontCanvas().height460 editorElement.style.display = 'none'461 minimapElement.measureHeightAndWidth()462 waitsFor('a new animation frame request', () => {463 return nextAnimationFrame !== noAnimationFrame464 })465 runs(() => {466 nextAnimationFrame()467 expect(minimapElement.getFrontCanvas().width).toEqual(canvasWidth)468 expect(minimapElement.getFrontCanvas().height).toEqual(canvasHeight)469 })470 })471 describe('from hidden to visible', () => {472 beforeEach(() => {473 editorElement.style.display = 'none'474 minimapElement.checkForVisibilityChange()475 spyOn(minimapElement, 'requestForcedUpdate')476 editorElement.style.display = ''477 minimapElement.pollDOM()478 })479 it('requests an update of the whole minimap', () => {480 expect(minimapElement.requestForcedUpdate).toHaveBeenCalled()481 })482 })483 })484 })485 // ###### ###### ######## ####### ## ##486 // ## ## ## ## ## ## ## ## ## ##487 // ## ## ## ## ## ## ## ##488 // ###### ## ######## ## ## ## ##489 // ## ## ## ## ## ## ## ##490 // ## ## ## ## ## ## ## ## ## ##491 // ###### ###### ## ## ####### ######## ########492 describe('mouse scroll controls', () => {493 let scrollSpy494 beforeEach(() => {495 resizeEditor(400, 400)496 editorElement.setScrollTop(0)497 editorElement.setScrollLeft(0)498 scrollSpy = jasmine.createSpy()499 editorElement.addEventListener('mousewheel', scrollSpy)500 nextAnimationFrame()501 minimapElement.measureHeightAndWidth()502 waitsFor('a new animation frame request', () => {503 return nextAnimationFrame !== noAnimationFrame504 })505 runs(() => { nextAnimationFrame() })506 })507 describe('using the mouse scrollwheel over the minimap', () => {508 it('relays the events to the editor view', () => {509 mousewheel(minimapElement, 0, 15)510 expect(scrollSpy).toHaveBeenCalled()511 })512 describe('when the independentMinimapScroll setting is true', () => {513 let previousScrollTop514 beforeEach(() => {515 atom.config.set('minimap.independentMinimapScroll', true)516 atom.config.set('minimap.scrollSensitivity', 0.5)517 previousScrollTop = minimap.getScrollTop()518 mousewheel(minimapElement, 0, -15)519 })520 it('does not relay the events to the editor', () => {521 expect(scrollSpy).not.toHaveBeenCalled()522 })523 it('scrolls the minimap instead', () => {524 expect(minimap.getScrollTop()).not.toEqual(previousScrollTop)525 })526 it('clamp the minimap scroll into the legit bounds', () => {527 mousewheel(minimapElement, 0, -100000)528 expect(minimap.getScrollTop()).toEqual(minimap.getMaxScrollTop())529 mousewheel(minimapElement, 0, 100000)530 expect(minimap.getScrollTop()).toEqual(0)531 })532 })533 })534 describe('middle clicking the minimap', () => {535 let [canvas, visibleArea, originalLeft, maxScroll] = []536 beforeEach(() => {537 canvas = minimapElement.getFrontCanvas()538 visibleArea = minimapElement.visibleArea539 originalLeft = visibleArea.getBoundingClientRect().left540 maxScroll = minimap.getTextEditorMaxScrollTop()541 })542 it('scrolls to the top', () => {543 mousedown(canvas, {x: originalLeft + 1, y: 0, btn: 1})544 expect(editorElement.getScrollTop()).toEqual(0)545 })546 describe('scrolling to the middle using the middle mouse button', () => {547 beforeEach(() => {548 const midY = minimap.getTextEditorHeight() / 2549 mousedown(canvas, {x: originalLeft + 1, y: midY, btn: 1})550 })551 it('scrolls the editor to the middle', () => {552 let middleScrollTop = Math.round((maxScroll) / 2.0)553 expect(editorElement.getScrollTop()).toEqual(middleScrollTop)554 })555 it('updates the visible area to be centered', () => {556 waitsFor('a new animation frame request', () => {557 return nextAnimationFrame !== noAnimationFrame558 })559 runs(() => {560 nextAnimationFrame()561 let {top, height} = visibleArea.getBoundingClientRect()562 let visibleCenterY = top + (height / 2)563 expect(visibleCenterY).toBeCloseTo(200, -1)564 })565 })566 })567 describe('scrolling the editor to an arbitrary location', () => {568 let [scrollTo, scrollRatio] = []569 beforeEach(() => {570 scrollTo = 101 // pixels571 scrollRatio = (scrollTo - minimap.getTextEditorScaledHeight() / 2) / (minimap.getVisibleHeight() - minimap.getTextEditorScaledHeight())572 scrollRatio = Math.max(0, scrollRatio)573 scrollRatio = Math.min(1, scrollRatio)574 mousedown(canvas, {x: originalLeft + 1, y: scrollTo, btn: 1})575 waitsFor('a new animation frame request', () => {576 return nextAnimationFrame !== noAnimationFrame577 })578 runs(() => { nextAnimationFrame() })579 })580 it('scrolls the editor to an arbitrary location', () => {581 let expectedScroll = maxScroll * scrollRatio582 expect(editorElement.getScrollTop()).toBeCloseTo(expectedScroll, 0)583 })584 describe('dragging the visible area with middle mouse button ' +585 'after scrolling to the arbitrary location', () => {586 let [originalTop] = []587 beforeEach(() => {588 originalTop = visibleArea.getBoundingClientRect().top589 mousemove(visibleArea, {x: originalLeft + 1, y: scrollTo + 40, btn: 1})590 waitsFor('a new animation frame request', () => {591 return nextAnimationFrame !== noAnimationFrame592 })593 runs(() => { nextAnimationFrame() })594 })595 afterEach(() => {596 minimapElement.endDrag()597 })598 it('scrolls the editor so that the visible area was moved down ' +599 'by 40 pixels from the arbitrary location', () => {600 let {top} = visibleArea.getBoundingClientRect()601 expect(top).toBeCloseTo(originalTop + 40, -1)602 })603 })604 })605 })606 describe('pressing the mouse on the minimap canvas (without scroll animation)', () => {607 let canvas608 beforeEach(() => {609 let t = 0610 spyOn(minimapElement, 'getTime').andCallFake(() => {611 let n = t612 t += 100613 return n614 })615 spyOn(minimapElement, 'requestUpdate').andCallFake(() => {})616 atom.config.set('minimap.scrollAnimation', false)617 canvas = minimapElement.getFrontCanvas()618 })619 it('scrolls the editor to the line below the mouse', () => {620 mousedown(canvas)621 expect(editorElement.getScrollTop()).toBeCloseTo(480)622 })623 describe('when independentMinimapScroll setting is enabled', () => {624 beforeEach(() => {625 minimap.setScrollTop(1000)626 atom.config.set('minimap.independentMinimapScroll', true)627 })628 it('scrolls the editor to the line below the mouse', () => {629 mousedown(canvas)630 expect(editorElement.getScrollTop()).toBeCloseTo(480)631 })632 })633 describe('when moveCursorOnMinimapClick is true', () => {634 beforeEach(() => {635 atom.config.set('minimap.moveCursorOnMinimapClick', true)636 })637 it('moves the cursor to the corresponding line', () => {638 mousedown(canvas)639 expect(editor.getCursorScreenPosition()).toEqual([40, 0])640 })641 })642 })643 describe('pressing the mouse on the minimap canvas (with scroll animation)', () => {644 let canvas645 beforeEach(() => {646 let t = 0647 spyOn(minimapElement, 'getTime').andCallFake(() => {648 let n = t649 t += 100650 return n651 })652 spyOn(minimapElement, 'requestUpdate').andCallFake(() => {})653 atom.config.set('minimap.scrollAnimation', true)654 atom.config.set('minimap.scrollAnimationDuration', 300)655 canvas = minimapElement.getFrontCanvas()656 })657 it('scrolls the editor gradually to the line below the mouse', () => {658 mousedown(canvas)659 waitsFor('a new animation frame request', () => {660 return nextAnimationFrame !== noAnimationFrame661 })662 // wait until all animations run out663 waitsFor(() => {664 nextAnimationFrame !== noAnimationFrame && nextAnimationFrame()665 return editorElement.getScrollTop() >= 480666 })667 })668 it('stops the animation if the text editor is destroyed', () => {669 mousedown(canvas)670 waitsFor('a new animation frame request', () => {671 return nextAnimationFrame !== noAnimationFrame672 })673 runs(() => {674 editor.destroy()675 nextAnimationFrame !== noAnimationFrame && nextAnimationFrame()676 expect(nextAnimationFrame === noAnimationFrame)677 })678 })679 describe('when independentMinimapScroll setting is enabled', () => {680 beforeEach(() => {681 minimap.setScrollTop(1000)682 atom.config.set('minimap.independentMinimapScroll', true)683 })684 it('scrolls the editor gradually to the line below the mouse', () => {685 mousedown(canvas)686 waitsFor('a new animation frame request', () => {687 return nextAnimationFrame !== noAnimationFrame688 })689 // wait until all animations run out690 waitsFor(() => {691 nextAnimationFrame !== noAnimationFrame && nextAnimationFrame()692 return editorElement.getScrollTop() >= 480693 })694 })695 it('stops the animation if the text editor is destroyed', () => {696 mousedown(canvas)697 waitsFor('a new animation frame request', () => {698 return nextAnimationFrame !== noAnimationFrame699 })700 runs(() => {701 editor.destroy()702 nextAnimationFrame !== noAnimationFrame && nextAnimationFrame()703 expect(nextAnimationFrame === noAnimationFrame)704 })705 })706 })707 })708 describe('dragging the visible area', () => {709 let [visibleArea, originalTop] = []710 beforeEach(() => {711 visibleArea = minimapElement.visibleArea712 let o = visibleArea.getBoundingClientRect()713 let left = o.left714 originalTop = o.top715 mousedown(visibleArea, {x: left + 10, y: originalTop + 10})716 mousemove(visibleArea, {x: left + 10, y: originalTop + 50})717 waitsFor('a new animation frame request', () => {718 return nextAnimationFrame !== noAnimationFrame719 })720 runs(() => { nextAnimationFrame() })721 })722 afterEach(() => {723 minimapElement.endDrag()724 })725 it('scrolls the editor so that the visible area was moved down by 40 pixels', () => {726 let {top} = visibleArea.getBoundingClientRect()727 expect(top).toBeCloseTo(originalTop + 40, -1)728 })729 it('stops the drag gesture when the mouse is released outside the minimap', () => {730 let {top, left} = visibleArea.getBoundingClientRect()731 mouseup(jasmineContent, {x: left - 10, y: top + 80})732 spyOn(minimapElement, 'drag')733 mousemove(visibleArea, {x: left + 10, y: top + 50})734 expect(minimapElement.drag).not.toHaveBeenCalled()735 })736 })737 describe('dragging the visible area using touch events', () => {738 let [visibleArea, originalTop] = []739 beforeEach(() => {740 visibleArea = minimapElement.visibleArea741 let o = visibleArea.getBoundingClientRect()742 let left = o.left743 originalTop = o.top744 touchstart(visibleArea, {x: left + 10, y: originalTop + 10})745 touchmove(visibleArea, {x: left + 10, y: originalTop + 50})746 waitsFor('a new animation frame request', () => {747 return nextAnimationFrame !== noAnimationFrame748 })749 runs(() => { nextAnimationFrame() })750 })751 afterEach(() => {752 minimapElement.endDrag()753 })754 it('scrolls the editor so that the visible area was moved down by 40 pixels', () => {755 let {top} = visibleArea.getBoundingClientRect()756 expect(top).toBeCloseTo(originalTop + 40, -1)757 })758 it('stops the drag gesture when the mouse is released outside the minimap', () => {759 let {top, left} = visibleArea.getBoundingClientRect()760 mouseup(jasmineContent, {x: left - 10, y: top + 80})761 spyOn(minimapElement, 'drag')762 touchmove(visibleArea, {x: left + 10, y: top + 50})763 expect(minimapElement.drag).not.toHaveBeenCalled()764 })765 })766 describe('when the minimap cannot scroll', () => {767 let [visibleArea, originalTop] = []768 beforeEach(() => {769 let sample = fs.readFileSync(dir.resolve('seventy.txt')).toString()770 editor.setText(sample)771 editorElement.setScrollTop(0)772 })773 describe('dragging the visible area', () => {774 beforeEach(() => {775 waitsFor('a new animation frame request', () => {776 return nextAnimationFrame !== noAnimationFrame777 })778 runs(() => {779 nextAnimationFrame()780 visibleArea = minimapElement.visibleArea781 let {top, left} = visibleArea.getBoundingClientRect()782 originalTop = top783 mousedown(visibleArea, {x: left + 10, y: top + 10})784 mousemove(visibleArea, {x: left + 10, y: top + 50})785 })786 waitsFor('a new animation frame request', () => {787 return nextAnimationFrame !== noAnimationFrame788 })789 runs(() => { nextAnimationFrame() })790 })791 afterEach(() => {792 minimapElement.endDrag()793 })794 it('scrolls based on a ratio adjusted to the minimap height', () => {795 let {top} = visibleArea.getBoundingClientRect()796 expect(top).toBeCloseTo(originalTop + 40, -1)797 })798 })799 })800 describe('when scroll past end is enabled', () => {801 beforeEach(() => {802 atom.config.set('editor.scrollPastEnd', true)803 waitsFor('a new animation frame request', () => {804 return nextAnimationFrame !== noAnimationFrame805 })806 runs(() => { nextAnimationFrame() })807 })808 describe('dragging the visible area', () => {809 let [originalTop, visibleArea] = []810 beforeEach(() => {811 visibleArea = minimapElement.visibleArea812 let {top, left} = visibleArea.getBoundingClientRect()813 originalTop = top814 mousedown(visibleArea, {x: left + 10, y: top + 10})815 mousemove(visibleArea, {x: left + 10, y: top + 50})816 waitsFor('a new animation frame request', () => {817 return nextAnimationFrame !== noAnimationFrame818 })819 runs(() => { nextAnimationFrame() })820 })821 afterEach(() => {822 minimapElement.endDrag()823 })824 it('scrolls the editor so that the visible area was moved down by 40 pixels', () => {825 let {top} = visibleArea.getBoundingClientRect()826 expect(top).toBeCloseTo(originalTop + 26, -1)827 })828 })829 })830 })831 // ###### ######## ### ## ## ########832 // ## ## ## ## ## ### ## ## ##833 // ## ## ## ## #### ## ## ##834 // ###### ## ## ## ## ## ## ## ##835 // ## ## ######### ## #### ## ##836 // ## ## ## ## ## ## ### ## ##837 // ###### ## ## ## ## ## ########838 //839 // ### ## ####### ## ## ########840 // ## ## ## ## ## ### ## ##841 // ## ## ## ## ## #### ## ##842 // ## ## ## ## ## ## ## ## ######843 // ######### ## ## ## ## #### ##844 // ## ## ## ## ## ## ### ##845 // ## ## ######## ####### ## ## ########846 describe('when the model is a stand-alone minimap', () => {847 beforeEach(() => {848 minimap.setStandAlone(true)849 })850 it('has a stand-alone attribute', () => {851 expect(minimapElement.hasAttribute('stand-alone')).toBeTruthy()852 })853 it('sets the minimap size when measured', () => {854 minimapElement.measureHeightAndWidth()855 expect(minimap.width).toEqual(minimapElement.clientWidth)856 expect(minimap.height).toEqual(minimapElement.clientHeight)857 })858 it('removes the controls div', () => {859 expect(minimapElement.querySelector('.minimap-controls')).toBeNull()860 })861 it('removes the visible area', () => {862 expect(minimapElement.visibleArea).toBeUndefined()863 })864 it('removes the quick settings button', () => {865 atom.config.set('minimap.displayPluginsControls', true)866 waitsFor('a new animation frame request', () => {867 return nextAnimationFrame !== noAnimationFrame868 })869 runs(() => {870 nextAnimationFrame()871 expect(minimapElement.openQuickSettings).toBeUndefined()872 })873 })874 it('removes the scroll indicator', () => {875 editor.setText(mediumSample)876 editorElement.setScrollTop(50)877 waitsFor('minimap frame requested', () => {878 return minimapElement.frameRequested879 })880 runs(() => {881 nextAnimationFrame()882 atom.config.set('minimap.minimapScrollIndicator', true)883 })884 waitsFor('minimap frame requested', () => {885 return minimapElement.frameRequested886 })887 runs(() => {888 nextAnimationFrame()889 expect(minimapElement.querySelector('.minimap-scroll-indicator')).toBeNull()890 })891 })892 describe('pressing the mouse on the minimap canvas', () => {893 beforeEach(() => {894 jasmineContent.appendChild(minimapElement)895 let t = 0896 spyOn(minimapElement, 'getTime').andCallFake(() => {897 let n = t898 t += 100899 return n900 })901 spyOn(minimapElement, 'requestUpdate').andCallFake(() => {})902 atom.config.set('minimap.scrollAnimation', false)903 canvas = minimapElement.getFrontCanvas()904 mousedown(canvas)905 })906 it('does not scroll the editor to the line below the mouse', () => {907 expect(editorElement.getScrollTop()).toEqual(1000)908 })909 })910 describe('and is changed to be a classical minimap again', () => {911 beforeEach(() => {912 atom.config.set('minimap.displayPluginsControls', true)913 atom.config.set('minimap.minimapScrollIndicator', true)914 minimap.setStandAlone(false)915 })916 it('recreates the destroyed elements', () => {917 expect(minimapElement.querySelector('.minimap-controls')).toExist()918 expect(minimapElement.querySelector('.minimap-visible-area')).toExist()919 expect(minimapElement.querySelector('.minimap-scroll-indicator')).toExist()920 expect(minimapElement.querySelector('.open-minimap-quick-settings')).toExist()921 })922 })923 })924 // ######## ######## ###### ######## ######## ####### ## ##925 // ## ## ## ## ## ## ## ## ## ## ## ##926 // ## ## ## ## ## ## ## ## ## ####927 // ## ## ###### ###### ## ######## ## ## ##928 // ## ## ## ## ## ## ## ## ## ##929 // ## ## ## ## ## ## ## ## ## ## ##930 // ######## ######## ###### ## ## ## ####### ##931 describe('when the model is destroyed', () => {932 beforeEach(() => {933 minimap.destroy()934 })935 it('detaches itself from its parent', () => {936 expect(minimapElement.parentNode).toBeNull()937 })938 it('stops the DOM polling interval', () => {939 spyOn(minimapElement, 'pollDOM')940 sleep(200)941 runs(() => { expect(minimapElement.pollDOM).not.toHaveBeenCalled() })942 })943 })944 // ###### ####### ## ## ######## #### ######945 // ## ## ## ## ### ## ## ## ## ##946 // ## ## ## #### ## ## ## ##947 // ## ## ## ## ## ## ###### ## ## ####948 // ## ## ## ## #### ## ## ## ##949 // ## ## ## ## ## ### ## ## ## ##950 // ###### ####### ## ## ## #### ######951 describe('when the atom styles are changed', () => {952 beforeEach(() => {953 waitsFor('a new animation frame request', () => {954 return nextAnimationFrame !== noAnimationFrame955 })956 runs(() => {957 nextAnimationFrame()958 spyOn(minimapElement, 'requestForcedUpdate').andCallThrough()959 spyOn(minimapElement, 'invalidateDOMStylesCache').andCallThrough()960 let styleNode = document.createElement('style')961 styleNode.textContent = 'body{ color: #233 }'962 atom.styles.emitter.emit('did-add-style-element', styleNode)963 })964 waitsFor('minimap frame requested', () => {965 return minimapElement.frameRequested966 })967 })968 it('forces a refresh with cache invalidation', () => {969 expect(minimapElement.requestForcedUpdate).toHaveBeenCalled()970 expect(minimapElement.invalidateDOMStylesCache).toHaveBeenCalled()971 })972 })973 describe('when minimap.textOpacity is changed', () => {974 beforeEach(() => {975 spyOn(minimapElement, 'requestForcedUpdate').andCallThrough()976 atom.config.set('minimap.textOpacity', 0.3)977 waitsFor('minimap frame requested', () => {978 return minimapElement.frameRequested979 })980 runs(() => { nextAnimationFrame() })981 })982 it('requests a complete update', () => {983 expect(minimapElement.requestForcedUpdate).toHaveBeenCalled()984 })985 })986 describe('when minimap.displayCodeHighlights is changed', () => {987 beforeEach(() => {988 spyOn(minimapElement, 'requestForcedUpdate').andCallThrough()989 waitsFor('minimap attached', () => minimapElement.attached)990 runs(() => { atom.config.set('minimap.displayCodeHighlights', true) })991 waitsFor('minimap frame requested', () => minimapElement.frameRequested)992 runs(() => { nextAnimationFrame() })993 })994 it('requests a complete update', () => {995 expect(minimapElement.requestForcedUpdate).toHaveBeenCalled()996 })997 })998 describe('when minimap.charWidth is changed', () => {999 beforeEach(() => {1000 spyOn(minimapElement, 'requestForcedUpdate').andCallThrough()1001 atom.config.set('minimap.charWidth', 1)1002 waitsFor('minimap frame requested', () => {1003 return minimapElement.frameRequested1004 })1005 runs(() => { nextAnimationFrame() })1006 })1007 it('requests a complete update', () => {1008 expect(minimapElement.requestForcedUpdate).toHaveBeenCalled()1009 })1010 })1011 describe('when minimap.charHeight is changed', () => {1012 beforeEach(() => {1013 spyOn(minimapElement, 'requestForcedUpdate').andCallThrough()1014 atom.config.set('minimap.charHeight', 1)1015 waitsFor('minimap frame requested', () => {1016 return minimapElement.frameRequested1017 })1018 runs(() => { nextAnimationFrame() })1019 })1020 it('requests a complete update', () => {1021 expect(minimapElement.requestForcedUpdate).toHaveBeenCalled()1022 })1023 })1024 describe('when minimap.interline is changed', () => {1025 beforeEach(() => {1026 spyOn(minimapElement, 'requestForcedUpdate').andCallThrough()1027 atom.config.set('minimap.interline', 2)1028 waitsFor('minimap frame requested', () => {1029 return minimapElement.frameRequested1030 })1031 runs(() => { nextAnimationFrame() })1032 })1033 it('requests a complete update', () => {1034 expect(minimapElement.requestForcedUpdate).toHaveBeenCalled()1035 })1036 })1037 describe('when minimap.displayMinimapOnLeft setting is true', () => {1038 it('moves the attached minimap to the left', () => {1039 atom.config.set('minimap.displayMinimapOnLeft', true)1040 expect(minimapElement.classList.contains('left')).toBeTruthy()1041 })1042 it('creates a style node with an offset for atom overlays', () => {1043 atom.config.set('minimap.displayMinimapOnLeft', true)1044 const node = document.querySelector('style[context="atom-text-editor-minimap"]')1045 expect(node).toExist()1046 })1047 describe('and then toggled off', () => {1048 it('removes the overlays style node', () => {1049 atom.config.set('minimap.displayMinimapOnLeft', true)1050 atom.config.set('minimap.displayMinimapOnLeft', false)1051 expect(document.querySelector('style[context="atom-text-editor-minimap"]')).not.toExist()1052 })1053 })1054 describe('when the minimap is not attached yet', () => {1055 beforeEach(() => {1056 editor = atom.workspace.buildTextEditor({})1057 editor.autoHeight = false1058 editorElement = atom.views.getView(editor)1059 editor.setLineHeightInPixels(10)1060 resizeEditor(50)1061 minimap = new Minimap({textEditor: editor})1062 minimapElement = atom.views.getView(minimap)1063 // Not sure why it throws an error now, but it seems the test is1064 // not affected if the editor is not in the DOM.1065 // jasmineContent.insertBefore(editorElement, jasmineContent.firstChild)1066 atom.config.set('minimap.displayMinimapOnLeft', true)1067 minimapElement.attach()1068 })1069 it('moves the attached minimap to the left', () => {1070 expect(minimapElement.classList.contains('left')).toBeTruthy()1071 })1072 })1073 })1074 describe('when minimap.adjustMinimapWidthToSoftWrap is true', () => {1075 beforeEach(() => {1076 atom.config.set('editor.softWrap', true)1077 atom.config.set('editor.softWrapAtPreferredLineLength', true)1078 atom.config.set('editor.preferredLineLength', 2)1079 atom.config.set('minimap.adjustMinimapWidthToSoftWrap', true)1080 waitsFor('minimap frame requested', () => {1081 return minimapElement.frameRequested1082 })1083 runs(() => { nextAnimationFrame() })1084 })1085 it('adjusts the width of the minimap canvas', () => {1086 expect(minimapElement.getFrontCanvas().width / devicePixelRatio).toEqual(4)1087 })1088 it('offsets the minimap by the difference', () => {1089 expect(realOffsetLeft(minimapElement)).toBeCloseTo(editorElement.clientWidth - 4, -1)1090 expect(minimapElement.clientWidth).toEqual(4)1091 })1092 describe('the dom polling routine', () => {1093 it('does not change the value', () => {1094 if (atom.views.performDocumentPoll) {1095 atom.views.performDocumentPoll()1096 }1097 waitsFor('a new animation frame request', () => {1098 return nextAnimationFrame !== noAnimationFrame1099 })1100 runs(() => {1101 nextAnimationFrame()1102 expect(minimapElement.getFrontCanvas().width / devicePixelRatio).toEqual(4)1103 })1104 })1105 })1106 describe('when the editor is resized', () => {1107 beforeEach(() => {1108 atom.config.set('editor.preferredLineLength', 6)1109 editorElement.style.width = '100px'1110 editorElement.style.height = '100px'1111 if (atom.views.performDocumentPoll) {1112 atom.views.performDocumentPoll()1113 }1114 waitsFor('a new animation frame request', () => {1115 return nextAnimationFrame !== noAnimationFrame1116 })1117 runs(() => { nextAnimationFrame() })1118 })1119 it('makes the minimap smaller than soft wrap', () => {1120 expect(minimapElement.offsetWidth).toBeCloseTo(12, -1)1121 expect(minimapElement.style.marginRight).toEqual('')1122 })1123 })1124 describe('and when minimap.minimapScrollIndicator setting is true', () => {1125 beforeEach(() => {1126 editor.setText(mediumSample)1127 editorElement.setScrollTop(50)1128 waitsFor('minimap frame requested', () => {1129 return minimapElement.frameRequested1130 })1131 runs(() => {1132 nextAnimationFrame()1133 atom.config.set('minimap.minimapScrollIndicator', true)1134 })1135 waitsFor('minimap frame requested', () => {1136 return minimapElement.frameRequested1137 })1138 runs(() => { nextAnimationFrame() })1139 })1140 it('offsets the scroll indicator by the difference', () => {1141 let indicator = minimapElement.querySelector('.minimap-scroll-indicator')1142 expect(realOffsetLeft(indicator)).toBeCloseTo(2, -1)1143 })1144 })1145 describe('and when minimap.displayPluginsControls setting is true', () => {1146 beforeEach(() => {1147 atom.config.set('minimap.displayPluginsControls', true)1148 })1149 it('offsets the scroll indicator by the difference', () => {1150 let openQuickSettings = minimapElement.querySelector('.open-minimap-quick-settings')1151 expect(realOffsetLeft(openQuickSettings)).not.toBeCloseTo(2, -1)1152 })1153 })1154 describe('and then disabled', () => {1155 beforeEach(() => {1156 atom.config.set('minimap.adjustMinimapWidthToSoftWrap', false)1157 waitsFor('minimap frame requested', () => {1158 return minimapElement.frameRequested1159 })1160 runs(() => { nextAnimationFrame() })1161 })1162 it('adjusts the width of the minimap', () => {1163 expect(minimapElement.offsetWidth).toBeCloseTo(editorElement.offsetWidth / 10, -1)1164 expect(minimapElement.style.width).toEqual('')1165 })1166 })1167 describe('and when preferredLineLength >= 16384', () => {1168 beforeEach(() => {1169 atom.config.set('editor.preferredLineLength', 16384)1170 waitsFor('minimap frame requested', () => {1171 return minimapElement.frameRequested1172 })1173 runs(() => { nextAnimationFrame() })1174 })1175 it('adjusts the width of the minimap', () => {1176 expect(minimapElement.offsetWidth).toBeCloseTo(editorElement.offsetWidth / 10, -1)1177 expect(minimapElement.style.width).toEqual('')1178 })1179 })1180 describe('when adjustMinimapWidthOnlyIfSmaller is disabled', () => {1181 describe('and when preferredLineLength >= 16384', () => {1182 beforeEach(() => {1183 atom.config.set('minimap.adjustMinimapWidthOnlyIfSmaller', false)1184 atom.config.set('editor.preferredLineLength', 16384)1185 waitsFor('minimap frame requested', () => {1186 return minimapElement.frameRequested1187 })1188 runs(() => { nextAnimationFrame() })1189 })1190 it('adjusts the width of the minimap', () => {1191 expect(minimapElement.offsetWidth).toBeCloseTo(16384 * 2)1192 expect(minimapElement.style.width).toEqual(16384 * 2 + 'px')1193 })1194 })1195 })1196 })1197 describe('when minimap.minimapScrollIndicator setting is true', () => {1198 beforeEach(() => {1199 editor.setText(mediumSample)1200 editorElement.setScrollTop(50)1201 waitsFor('minimap frame requested', () => {1202 return minimapElement.frameRequested1203 })1204 runs(() => { nextAnimationFrame() })1205 atom.config.set('minimap.minimapScrollIndicator', true)1206 })1207 it('adds a scroll indicator in the element', () => {1208 expect(minimapElement.querySelector('.minimap-scroll-indicator')).toExist()1209 })1210 describe('and then deactivated', () => {1211 it('removes the scroll indicator from the element', () => {1212 atom.config.set('minimap.minimapScrollIndicator', false)1213 expect(minimapElement.querySelector('.minimap-scroll-indicator')).not.toExist()1214 })1215 })1216 describe('on update', () => {1217 beforeEach(() => {1218 editorElement.style.height = '500px'1219 if (atom.views.performDocumentPoll) {1220 atom.views.performDocumentPoll()1221 }1222 waitsFor('a new animation frame request', () => {1223 return nextAnimationFrame !== noAnimationFrame1224 })1225 runs(() => { nextAnimationFrame() })1226 })1227 it('adjusts the size and position of the indicator', () => {1228 let indicator = minimapElement.querySelector('.minimap-scroll-indicator')1229 let height = editorElement.getHeight() * (editorElement.getHeight() / minimap.getHeight())1230 let scroll = (editorElement.getHeight() - height) * minimap.getTextEditorScrollRatio()1231 expect(indicator.offsetHeight).toBeCloseTo(height, 0)1232 expect(realOffsetTop(indicator)).toBeCloseTo(scroll, 0)1233 })1234 })1235 describe('when the minimap cannot scroll', () => {1236 beforeEach(() => {1237 editor.setText(smallSample)1238 waitsFor('minimap frame requested', () => {1239 return minimapElement.frameRequested1240 })1241 runs(() => { nextAnimationFrame() })1242 })1243 it('removes the scroll indicator', () => {1244 expect(minimapElement.querySelector('.minimap-scroll-indicator')).not.toExist()1245 })1246 describe('and then can scroll again', () => {1247 beforeEach(() => {1248 editor.setText(largeSample)1249 waitsFor('minimap frame requested', () => {1250 return minimapElement.frameRequested1251 })1252 runs(() => { nextAnimationFrame() })1253 })1254 it('attaches the scroll indicator', () => {1255 waitsFor('minimap scroll indicator', () => {1256 return minimapElement.querySelector('.minimap-scroll-indicator')1257 })1258 })1259 })1260 })1261 })1262 describe('when minimap.absoluteMode setting is true', () => {1263 beforeEach(() => {1264 atom.config.set('minimap.absoluteMode', true)1265 })1266 it('adds a absolute class to the minimap element', () => {1267 expect(minimapElement.classList.contains('absolute')).toBeTruthy()1268 })1269 describe('when minimap.displayMinimapOnLeft setting is true', () => {1270 it('also adds a left class to the minimap element', () => {1271 atom.config.set('minimap.displayMinimapOnLeft', true)1272 expect(minimapElement.classList.contains('absolute')).toBeTruthy()1273 expect(minimapElement.classList.contains('left')).toBeTruthy()1274 })1275 })1276 describe('when minimap.adjustAbsoluteModeHeight setting is true', () => {1277 beforeEach(() => {1278 atom.config.set('minimap.adjustAbsoluteModeHeight', true)1279 })1280 describe('when the content of the minimap is smaller that the editor height', () => {1281 beforeEach(() => {1282 editor.setText(smallSample)1283 resizeEditor(400)1284 minimapElement.measureHeightAndWidth()1285 waitsFor('a new animation frame request', () => {1286 return nextAnimationFrame !== noAnimationFrame1287 })1288 runs(() => nextAnimationFrame())1289 })1290 it('adjusts the canvas height to the minimap height', () => {1291 expect(minimapElement.querySelector('canvas').offsetHeight).toEqual(minimap.getHeight())1292 })1293 describe('when the content is modified', () => {1294 beforeEach(() => {1295 editor.insertText('foo\n\nbar\n')1296 waitsFor('a new animation frame request', () => {1297 return nextAnimationFrame !== noAnimationFrame1298 })1299 runs(() => nextAnimationFrame())1300 })1301 it('adjusts the canvas height to the new minimap height', () => {1302 expect(minimapElement.querySelector('canvas').offsetHeight).toEqual(minimap.getHeight())1303 })1304 })1305 })1306 })1307 })1308 describe('when the smoothScrolling setting is disabled', () => {1309 beforeEach(() => {1310 atom.config.set('minimap.smoothScrolling', false)1311 })1312 it('does not offset the canvas when the scroll does not match line height', () => {1313 editorElement.setScrollTop(1004)1314 waitsFor('a new animation frame request', () => {1315 return nextAnimationFrame !== noAnimationFrame1316 })1317 runs(() => {1318 nextAnimationFrame()1319 expect(realOffsetTop(canvas)).toEqual(0)1320 })1321 })1322 })1323 // ####### ## ## #### ###### ## ##1324 // ## ## ## ## ## ## ## ## ##1325 // ## ## ## ## ## ## ## ##1326 // ## ## ## ## ## ## #####1327 // ## ## ## ## ## ## ## ## ##1328 // ## ## ## ## ## ## ## ## ##1329 // ##### ## ####### #### ###### ## ##1330 //1331 // ###### ######## ######## ######## #### ## ## ###### ######1332 // ## ## ## ## ## ## ### ## ## ## ## ##1333 // ## ## ## ## ## #### ## ## ##1334 // ###### ###### ## ## ## ## ## ## ## #### ######1335 // ## ## ## ## ## ## #### ## ## ##1336 // ## ## ## ## ## ## ## ### ## ## ## ##1337 // ###### ######## ## ## #### ## ## ###### ######1338 describe('when minimap.displayPluginsControls setting is true', () => {1339 let [openQuickSettings, quickSettingsElement, workspaceElement] = []1340 beforeEach(() => {1341 atom.config.set('minimap.displayPluginsControls', true)1342 })1343 it('has a div to open the quick settings', () => {1344 expect(minimapElement.querySelector('.open-minimap-quick-settings')).toExist()1345 })1346 describe('clicking on the div', () => {1347 beforeEach(() => {1348 workspaceElement = atom.views.getView(atom.workspace)1349 jasmineContent.appendChild(workspaceElement)1350 openQuickSettings = minimapElement.querySelector('.open-minimap-quick-settings')1351 mousedown(openQuickSettings)1352 quickSettingsElement = workspaceElement.querySelector('minimap-quick-settings')1353 })1354 afterEach(() => {1355 minimapElement.quickSettingsElement.destroy()1356 })1357 it('opens the quick settings view', () => {1358 expect(quickSettingsElement).toExist()1359 })1360 it('positions the quick settings view next to the minimap', () => {1361 let minimapBounds = minimapElement.getFrontCanvas().getBoundingClientRect()1362 let settingsBounds = quickSettingsElement.getBoundingClientRect()1363 expect(realOffsetTop(quickSettingsElement)).toBeCloseTo(minimapBounds.top, 0)1364 expect(realOffsetLeft(quickSettingsElement)).toBeCloseTo(minimapBounds.left - settingsBounds.width, 0)1365 })1366 })1367 describe('when the displayMinimapOnLeft setting is enabled', () => {1368 describe('clicking on the div', () => {1369 beforeEach(() => {1370 atom.config.set('minimap.displayMinimapOnLeft', true)1371 workspaceElement = atom.views.getView(atom.workspace)1372 jasmineContent.appendChild(workspaceElement)1373 openQuickSettings = minimapElement.querySelector('.open-minimap-quick-settings')1374 mousedown(openQuickSettings)1375 quickSettingsElement = workspaceElement.querySelector('minimap-quick-settings')1376 })1377 afterEach(() => {1378 minimapElement.quickSettingsElement.destroy()1379 })1380 it('positions the quick settings view next to the minimap', () => {1381 let minimapBounds = minimapElement.getFrontCanvas().getBoundingClientRect()1382 expect(realOffsetTop(quickSettingsElement)).toBeCloseTo(minimapBounds.top, 0)1383 expect(realOffsetLeft(quickSettingsElement)).toBeCloseTo(minimapBounds.right, 0)1384 })1385 })1386 })1387 describe('when the adjustMinimapWidthToSoftWrap setting is enabled', () => {1388 let [controls] = []1389 beforeEach(() => {1390 atom.config.set('editor.softWrap', true)1391 atom.config.set('editor.softWrapAtPreferredLineLength', true)1392 atom.config.set('editor.preferredLineLength', 2)1393 atom.config.set('minimap.adjustMinimapWidthToSoftWrap', true)1394 nextAnimationFrame()1395 controls = minimapElement.querySelector('.minimap-controls')1396 openQuickSettings = minimapElement.querySelector('.open-minimap-quick-settings')1397 editorElement.style.width = '1024px'1398 if (atom.views.performDocumentPoll) {1399 atom.views.performDocumentPoll()1400 }1401 waitsFor('minimap frame requested', () => {1402 return minimapElement.frameRequested1403 })1404 runs(() => { nextAnimationFrame() })1405 })1406 it('adjusts the size of the control div to fit in the minimap', () => {1407 expect(controls.clientWidth).toEqual(minimapElement.getFrontCanvas().clientWidth / devicePixelRatio)1408 })1409 it('positions the controls div over the canvas', () => {1410 let controlsRect = controls.getBoundingClientRect()1411 let canvasRect = minimapElement.getFrontCanvas().getBoundingClientRect()1412 expect(controlsRect.left).toEqual(canvasRect.left)1413 expect(controlsRect.right).toEqual(canvasRect.right)1414 })1415 describe('when the displayMinimapOnLeft setting is enabled', () => {1416 beforeEach(() => {1417 atom.config.set('minimap.displayMinimapOnLeft', true)1418 })1419 it('adjusts the size of the control div to fit in the minimap', () => {1420 expect(controls.clientWidth).toEqual(minimapElement.getFrontCanvas().clientWidth / devicePixelRatio)1421 })1422 it('positions the controls div over the canvas', () => {1423 let controlsRect = controls.getBoundingClientRect()1424 let canvasRect = minimapElement.getFrontCanvas().getBoundingClientRect()1425 expect(controlsRect.left).toEqual(canvasRect.left)1426 expect(controlsRect.right).toEqual(canvasRect.right)1427 })1428 describe('clicking on the div', () => {1429 beforeEach(() => {1430 workspaceElement = atom.views.getView(atom.workspace)1431 jasmineContent.appendChild(workspaceElement)1432 openQuickSettings = minimapElement.querySelector('.open-minimap-quick-settings')1433 mousedown(openQuickSettings)1434 quickSettingsElement = workspaceElement.querySelector('minimap-quick-settings')1435 })1436 afterEach(() => {1437 minimapElement.quickSettingsElement.destroy()1438 })1439 it('positions the quick settings view next to the minimap', () => {1440 let minimapBounds = minimapElement.getFrontCanvas().getBoundingClientRect()1441 expect(realOffsetTop(quickSettingsElement)).toBeCloseTo(minimapBounds.top, 0)1442 expect(realOffsetLeft(quickSettingsElement)).toBeCloseTo(minimapBounds.right, 0)1443 })1444 })1445 })1446 })1447 describe('when the quick settings view is open', () => {1448 beforeEach(() => {1449 workspaceElement = atom.views.getView(atom.workspace)1450 jasmineContent.appendChild(workspaceElement)1451 openQuickSettings = minimapElement.querySelector('.open-minimap-quick-settings')1452 mousedown(openQuickSettings)1453 quickSettingsElement = workspaceElement.querySelector('minimap-quick-settings')1454 })1455 it('sets the on right button active', () => {1456 expect(quickSettingsElement.querySelector('.btn.selected:last-child')).toExist()1457 })1458 describe('clicking on the code highlight item', () => {1459 beforeEach(() => {1460 let item = quickSettingsElement.querySelector('li.code-highlights')1461 mousedown(item)1462 })1463 it('toggles the code highlights on the minimap element', () => {1464 expect(minimapElement.displayCodeHighlights).toBeTruthy()1465 })1466 it('requests an update', () => {1467 expect(minimapElement.frameRequested).toBeTruthy()1468 })1469 })1470 describe('clicking on the absolute mode item', () => {1471 beforeEach(() => {1472 let item = quickSettingsElement.querySelector('li.absolute-mode')1473 mousedown(item)1474 })1475 it('toggles the absolute-mode setting', () => {1476 expect(atom.config.get('minimap.absoluteMode')).toBeTruthy()1477 expect(minimapElement.absoluteMode).toBeTruthy()1478 })1479 })1480 describe('clicking on the on left button', () => {1481 beforeEach(() => {1482 let item = quickSettingsElement.querySelector('.btn:first-child')1483 mousedown(item)1484 })1485 it('toggles the displayMinimapOnLeft setting', () => {1486 expect(atom.config.get('minimap.displayMinimapOnLeft')).toBeTruthy()1487 })1488 it('changes the buttons activation state', () => {1489 expect(quickSettingsElement.querySelector('.btn.selected:last-child')).not.toExist()1490 expect(quickSettingsElement.querySelector('.btn.selected:first-child')).toExist()1491 })1492 })1493 describe('core:move-left', () => {1494 beforeEach(() => {1495 atom.commands.dispatch(quickSettingsElement, 'core:move-left')1496 })1497 it('toggles the displayMinimapOnLeft setting', () => {1498 expect(atom.config.get('minimap.displayMinimapOnLeft')).toBeTruthy()1499 })1500 it('changes the buttons activation state', () => {1501 expect(quickSettingsElement.querySelector('.btn.selected:last-child')).not.toExist()1502 expect(quickSettingsElement.querySelector('.btn.selected:first-child')).toExist()1503 })1504 })1505 describe('core:move-right when the minimap is on the right', () => {1506 beforeEach(() => {1507 atom.config.set('minimap.displayMinimapOnLeft', true)1508 atom.commands.dispatch(quickSettingsElement, 'core:move-right')1509 })1510 it('toggles the displayMinimapOnLeft setting', () => {1511 expect(atom.config.get('minimap.displayMinimapOnLeft')).toBeFalsy()1512 })1513 it('changes the buttons activation state', () => {1514 expect(quickSettingsElement.querySelector('.btn.selected:first-child')).not.toExist()1515 expect(quickSettingsElement.querySelector('.btn.selected:last-child')).toExist()1516 })1517 })1518 describe('clicking on the open settings button again', () => {1519 beforeEach(() => {1520 mousedown(openQuickSettings)1521 })1522 it('closes the quick settings view', () => {1523 expect(workspaceElement.querySelector('minimap-quick-settings')).not.toExist()1524 })1525 it('removes the view from the element', () => {1526 expect(minimapElement.quickSettingsElement).toBeNull()1527 })1528 })1529 describe('when an external event destroys the view', () => {1530 beforeEach(() => {1531 minimapElement.quickSettingsElement.destroy()1532 })1533 it('removes the view reference from the element', () => {1534 expect(minimapElement.quickSettingsElement).toBeNull()1535 })1536 })1537 })1538 describe('then disabling it', () => {1539 beforeEach(() => {1540 atom.config.set('minimap.displayPluginsControls', false)1541 })1542 it('removes the div', () => {1543 expect(minimapElement.querySelector('.open-minimap-quick-settings')).not.toExist()1544 })1545 })1546 describe('with plugins registered in the package', () => {1547 let [minimapPackage, pluginA, pluginB] = []1548 beforeEach(() => {1549 waitsForPromise(() => {1550 return atom.packages.activatePackage('minimap').then((pkg) => {1551 minimapPackage = pkg.mainModule1552 })1553 })1554 runs(() => {1555 class Plugin {1556 constructor () { this.active = false }1557 activatePlugin () { this.active = true }1558 deactivatePlugin () { this.active = false }1559 isActive () { return this.active }1560 }1561 pluginA = new Plugin()1562 pluginB = new Plugin()1563 minimapPackage.registerPlugin('dummyA', pluginA)1564 minimapPackage.registerPlugin('dummyB', pluginB)1565 workspaceElement = atom.views.getView(atom.workspace)1566 jasmineContent.appendChild(workspaceElement)1567 openQuickSettings = minimapElement.querySelector('.open-minimap-quick-settings')1568 mousedown(openQuickSettings)1569 quickSettingsElement = workspaceElement.querySelector('minimap-quick-settings')1570 })1571 })1572 it('creates one list item for each registered plugin', () => {1573 expect(quickSettingsElement.querySelectorAll('li').length).toEqual(6)1574 })1575 it('selects the first item of the list', () => {1576 expect(quickSettingsElement.querySelector('li.selected:first-child')).toExist()1577 })1578 describe('core:confirm', () => {1579 beforeEach(() => {1580 atom.commands.dispatch(quickSettingsElement, 'core:confirm')1581 })1582 it('disable the plugin of the selected item', () => {1583 expect(pluginA.isActive()).toBeFalsy()1584 })1585 describe('triggered a second time', () => {1586 beforeEach(() => {1587 atom.commands.dispatch(quickSettingsElement, 'core:confirm')1588 })1589 it('enable the plugin of the selected item', () => {1590 expect(pluginA.isActive()).toBeTruthy()1591 })1592 })1593 describe('on the code highlight item', () => {1594 let [initial] = []1595 beforeEach(() => {1596 initial = minimapElement.displayCodeHighlights1597 atom.commands.dispatch(quickSettingsElement, 'core:move-down')1598 atom.commands.dispatch(quickSettingsElement, 'core:move-down')1599 atom.commands.dispatch(quickSettingsElement, 'core:confirm')1600 })1601 it('toggles the code highlights on the minimap element', () => {1602 expect(minimapElement.displayCodeHighlights).toEqual(!initial)1603 })1604 })1605 describe('on the absolute mode item', () => {1606 let [initial] = []1607 beforeEach(() => {1608 initial = atom.config.get('minimap.absoluteMode')1609 atom.commands.dispatch(quickSettingsElement, 'core:move-down')1610 atom.commands.dispatch(quickSettingsElement, 'core:move-down')1611 atom.commands.dispatch(quickSettingsElement, 'core:move-down')1612 atom.commands.dispatch(quickSettingsElement, 'core:confirm')1613 })1614 it('toggles the code highlights on the minimap element', () => {1615 expect(atom.config.get('minimap.absoluteMode')).toEqual(!initial)1616 })1617 })1618 describe('on the adjust absolute mode height item', () => {1619 let [initial] = []1620 beforeEach(() => {1621 initial = atom.config.get('minimap.adjustAbsoluteModeHeight')1622 atom.commands.dispatch(quickSettingsElement, 'core:move-down')1623 atom.commands.dispatch(quickSettingsElement, 'core:move-down')1624 atom.commands.dispatch(quickSettingsElement, 'core:move-down')1625 atom.commands.dispatch(quickSettingsElement, 'core:move-down')1626 atom.commands.dispatch(quickSettingsElement, 'core:confirm')1627 })1628 it('toggles the code highlights on the minimap element', () => {1629 expect(atom.config.get('minimap.adjustAbsoluteModeHeight')).toEqual(!initial)1630 })1631 })1632 })1633 describe('core:move-down', () => {1634 beforeEach(() => {1635 atom.commands.dispatch(quickSettingsElement, 'core:move-down')1636 })1637 it('selects the second item', () => {1638 expect(quickSettingsElement.querySelector('li.selected:nth-child(2)')).toExist()1639 })1640 describe('reaching a separator', () => {1641 beforeEach(() => {1642 atom.commands.dispatch(quickSettingsElement, 'core:move-down')1643 })1644 it('moves past the separator', () => {1645 expect(quickSettingsElement.querySelector('li.code-highlights.selected')).toExist()1646 })1647 })1648 describe('then core:move-up', () => {1649 beforeEach(() => {1650 atom.commands.dispatch(quickSettingsElement, 'core:move-up')1651 })1652 it('selects again the first item of the list', () => {1653 expect(quickSettingsElement.querySelector('li.selected:first-child')).toExist()1654 })1655 })1656 })1657 describe('core:move-up', () => {1658 beforeEach(() => {1659 atom.commands.dispatch(quickSettingsElement, 'core:move-up')1660 })1661 it('selects the last item', () => {1662 expect(quickSettingsElement.querySelector('li.selected:last-child')).toExist()1663 })1664 describe('reaching a separator', () => {1665 beforeEach(() => {1666 atom.commands.dispatch(quickSettingsElement, 'core:move-up')1667 atom.commands.dispatch(quickSettingsElement, 'core:move-up')1668 atom.commands.dispatch(quickSettingsElement, 'core:move-up')1669 })1670 it('moves past the separator', () => {1671 expect(quickSettingsElement.querySelector('li.selected:nth-child(2)')).toExist()1672 })1673 })1674 describe('then core:move-down', () => {1675 beforeEach(() => {1676 atom.commands.dispatch(quickSettingsElement, 'core:move-down')1677 })1678 it('selects again the first item of the list', () => {1679 expect(quickSettingsElement.querySelector('li.selected:first-child')).toExist()1680 })1681 })1682 })1683 })1684 })1685 })...

Full Screen

Full Screen

minimap-element.js

Source:minimap-element.js Github

copy

Full Screen

1'use strict'2const {EventsDelegation, AncestorsMethods} = require('atom-utils')3const DOMStylesReader = require('./mixins/dom-styles-reader')4const CanvasDrawer = require('./mixins/canvas-drawer')5const include = require('./decorators/include')6const element = require('./decorators/element')7const elementResizeDetector = require('element-resize-detector')({strategy: 'scroll'})8let Main, MinimapQuickSettingsElement, CompositeDisposable, Disposable, overlayStyle9const ensureOverlayStyle = () => {10 if (!overlayStyle) {11 overlayStyle = document.createElement('style')12 overlayStyle.setAttribute('context', 'atom-text-editor-minimap')13 document.head.appendChild(overlayStyle)14 }15}16const removeOverlayStyle = () => {17 if (overlayStyle) {18 overlayStyle.parentNode.removeChild(overlayStyle)19 overlayStyle = null20 }21}22const updateOverlayStyle = (basis) => {23 if (overlayStyle) {24 overlayStyle.textContent = `25 atom-text-editor[with-minimap].editor > div,26 atom-text-editor[with-minimap] > div {27 margin-left: ${basis}px;28 }29 `30 }31}32const SPEC_MODE = atom.inSpecMode()33/**34 * Public: The MinimapElement is the view meant to render a {@link Minimap}35 * instance in the DOM.36 *37 * You can retrieve the MinimapElement associated to a Minimap38 * using the `atom.views.getView` method.39 *40 * Note that most interactions with the Minimap package is done through the41 * Minimap model so you should never have to access MinimapElement42 * instances.43 *44 * @example45 * let minimapElement = atom.views.getView(minimap)46 */47class MinimapElement {48 static initClass () {49 include(this, DOMStylesReader, CanvasDrawer, EventsDelegation, AncestorsMethods)50 return element(this, 'atom-text-editor-minimap')51 }52 // ## ## ####### ####### ## ## ######53 // ## ## ## ## ## ## ## ## ## ##54 // ## ## ## ## ## ## ## ## ##55 // ######### ## ## ## ## ##### ######56 // ## ## ## ## ## ## ## ## ##57 // ## ## ## ## ## ## ## ## ## ##58 // ## ## ####### ####### ## ## ######59 /**60 * DOM callback invoked when a new MinimapElement is created.61 *62 * @access private63 */64 createdCallback () {65 if (!CompositeDisposable) {66 ({CompositeDisposable, Disposable} = require('atom'))67 }68 // Core properties69 /**70 * @access private71 */72 this.minimap = undefined73 /**74 * @access private75 */76 this.editorElement = undefined77 /**78 * @access private79 */80 this.width = undefined81 /**82 * @access private83 */84 this.height = undefined85 // Subscriptions86 /**87 * @access private88 */89 this.subscriptions = new CompositeDisposable()90 /**91 * @access private92 */93 this.visibleAreaSubscription = undefined94 /**95 * @access private96 */97 this.quickSettingsSubscription = undefined98 /**99 * @access private100 */101 this.dragSubscription = undefined102 /**103 * @access private104 */105 this.openQuickSettingSubscription = undefined106 // Configs107 /**108 * @access private109 */110 this.displayMinimapOnLeft = false111 /**112 * @access private113 */114 this.minimapScrollIndicator = undefined115 /**116 * @access private117 */118 this.displayMinimapOnLeft = undefined119 /**120 * @access private121 */122 this.displayPluginsControls = undefined123 /**124 * @access private125 */126 this.textOpacity = undefined127 /**128 * @access private129 */130 this.displayCodeHighlights = undefined131 /**132 * @access private133 */134 this.adjustToSoftWrap = undefined135 /**136 * @access private137 */138 this.useHardwareAcceleration = undefined139 /**140 * @access private141 */142 this.absoluteMode = undefined143 // Elements144 /**145 * @access private146 */147 this.visibleArea = undefined148 /**149 * @access private150 */151 this.controls = undefined152 /**153 * @access private154 */155 this.scrollIndicator = undefined156 /**157 * @access private158 */159 this.openQuickSettings = undefined160 /**161 * @access private162 */163 this.quickSettingsElement = undefined164 // States165 /**166 * @access private167 */168 this.attached = undefined169 /**170 * @access private171 */172 this.attachedToTextEditor = undefined173 /**174 * @access private175 */176 this.standAlone = undefined177 /**178 * @access private179 */180 this.wasVisible = undefined181 // Other182 /**183 * @access private184 */185 this.offscreenFirstRow = undefined186 /**187 * @access private188 */189 this.offscreenLastRow = undefined190 /**191 * @access private192 */193 this.frameRequested = undefined194 /**195 * @access private196 */197 this.flexBasis = undefined198 this.initializeContent()199 return this.observeConfig({200 'minimap.displayMinimapOnLeft': (displayMinimapOnLeft) => {201 this.displayMinimapOnLeft = displayMinimapOnLeft202 displayMinimapOnLeft203 ? ensureOverlayStyle()204 : removeOverlayStyle()205 this.updateMinimapFlexPosition()206 this.measureHeightAndWidth(true, true)207 },208 'minimap.minimapScrollIndicator': (minimapScrollIndicator) => {209 this.minimapScrollIndicator = minimapScrollIndicator210 if (this.minimapScrollIndicator && !(this.scrollIndicator != null) && !this.standAlone) {211 this.initializeScrollIndicator()212 } else if ((this.scrollIndicator != null)) {213 this.disposeScrollIndicator()214 }215 if (this.attached) { this.requestUpdate() }216 },217 'minimap.displayPluginsControls': (displayPluginsControls) => {218 this.displayPluginsControls = displayPluginsControls219 if (this.displayPluginsControls && !(this.openQuickSettings != null) && !this.standAlone) {220 this.initializeOpenQuickSettings()221 } else if ((this.openQuickSettings != null)) {222 this.disposeOpenQuickSettings()223 }224 },225 'minimap.textOpacity': (textOpacity) => {226 this.textOpacity = textOpacity227 if (this.attached) { this.requestForcedUpdate() }228 },229 'minimap.displayCodeHighlights': (displayCodeHighlights) => {230 this.displayCodeHighlights = displayCodeHighlights231 if (this.attached) { this.requestForcedUpdate() }232 },233 'minimap.smoothScrolling': (smoothScrolling) => {234 this.smoothScrolling = smoothScrolling235 if (this.attached) {236 if (!this.smoothScrolling) {237 this.backLayer.canvas.style.cssText = ''238 this.tokensLayer.canvas.style.cssText = ''239 this.frontLayer.canvas.style.cssText = ''240 } else {241 this.requestUpdate()242 }243 }244 },245 'minimap.adjustMinimapWidthToSoftWrap': (adjustToSoftWrap) => {246 this.adjustToSoftWrap = adjustToSoftWrap247 if (this.attached) { this.measureHeightAndWidth() }248 },249 'minimap.adjustMinimapWidthOnlyIfSmaller': (adjustOnlyIfSmaller) => {250 this.adjustOnlyIfSmaller = adjustOnlyIfSmaller251 if (this.attached) { this.measureHeightAndWidth() }252 },253 'minimap.useHardwareAcceleration': (useHardwareAcceleration) => {254 this.useHardwareAcceleration = useHardwareAcceleration255 if (this.attached) { this.requestUpdate() }256 },257 'minimap.absoluteMode': (absoluteMode) => {258 this.absoluteMode = absoluteMode259 this.classList.toggle('absolute', this.absoluteMode)260 },261 'minimap.adjustAbsoluteModeHeight': (adjustAbsoluteModeHeight) => {262 this.adjustAbsoluteModeHeight = adjustAbsoluteModeHeight263 this.classList.toggle('adjust-absolute-height', this.adjustAbsoluteModeHeight)264 if (this.attached) { this.measureHeightAndWidth() }265 },266 'minimap.ignoreWhitespacesInTokens': (ignoreWhitespacesInTokens) => {267 this.ignoreWhitespacesInTokens = ignoreWhitespacesInTokens268 if (this.attached) { this.requestForcedUpdate() }269 },270 'editor.preferredLineLength': () => {271 if (this.attached) { this.measureHeightAndWidth() }272 },273 'editor.softWrap': () => {274 if (this.attached) { this.requestUpdate() }275 },276 'editor.showInvisibles': () => {277 if (this.attached) { this.requestUpdate() }278 },279 'editor.invisibles': () => {280 if (this.attached) { this.requestUpdate() }281 },282 'editor.softWrapAtPreferredLineLength': () => {283 if (this.attached) { this.requestUpdate() }284 }285 })286 }287 /**288 * DOM callback invoked when a new MinimapElement is attached to the DOM.289 *290 * @access private291 */292 attachedCallback () {293 if (typeof atom.views.pollDocument === 'function') {294 this.subscriptions.add(atom.views.pollDocument(() => { this.pollDOM() }))295 } else {296 this.intersectionObserver = new IntersectionObserver((entries) => {297 const {intersectionRect} = entries[entries.length - 1]298 if (intersectionRect.width > 0 || intersectionRect.height > 0) {299 this.measureHeightAndWidth(true, true)300 }301 })302 this.intersectionObserver.observe(this)303 if (this.isVisible()) {304 this.measureHeightAndWidth(true, true)305 }306 const measureDimensions = () => { this.measureHeightAndWidth(false, false) }307 elementResizeDetector.listenTo(this, measureDimensions)308 this.subscriptions.add(new Disposable(() => { elementResizeDetector.removeListener(this, measureDimensions) }))309 window.addEventListener('resize', measureDimensions)310 this.subscriptions.add(new Disposable(() => { window.removeEventListener('resize', measureDimensions) }))311 }312 this.measureHeightAndWidth()313 this.updateMinimapFlexPosition()314 this.attached = true315 this.attachedToTextEditor = this.queryParentSelector('atom-text-editor') === this.getTextEditorElement()316 if (this.attachedToTextEditor) {317 this.getTextEditorElement().setAttribute('with-minimap', '')318 }319 /*320 We use `atom.styles.onDidAddStyleElement` instead of321 `atom.themes.onDidChangeActiveThemes`.322 Why? Currently, The style element will be removed first, and then re-added323 and the `change` event has not be triggered in the process.324 */325 this.subscriptions.add(atom.styles.onDidAddStyleElement(() => {326 this.invalidateDOMStylesCache()327 this.requestForcedUpdate()328 }))329 this.subscriptions.add(this.subscribeToMediaQuery())330 }331 /**332 * DOM callback invoked when a new MinimapElement is detached from the DOM.333 *334 * @access private335 */336 detachedCallback () {337 this.getTextEditorElement().removeAttribute('with-minimap')338 this.attached = false339 }340 // ### ######## ######## ### ###### ## ##341 // ## ## ## ## ## ## ## ## ## ##342 // ## ## ## ## ## ## ## ## ##343 // ## ## ## ## ## ## ## #########344 // ######### ## ## ######### ## ## ##345 // ## ## ## ## ## ## ## ## ## ##346 // ## ## ## ## ## ## ###### ## ##347 /**348 * Returns whether the MinimapElement is currently visible on screen or not.349 *350 * The visibility of the minimap is defined by testing the size of the offset351 * width and height of the element.352 *353 * @return {boolean} whether the MinimapElement is currently visible or not354 */355 isVisible () { return this.offsetWidth > 0 || this.offsetHeight > 0 }356 /**357 * Attaches the MinimapElement to the DOM.358 *359 * The position at which the element is attached is defined by the360 * `displayMinimapOnLeft` setting.361 *362 * @param {HTMLElement} [parent] the DOM node where attaching the minimap363 * element364 */365 attach (parent) {366 if (this.attached) { return }367 const container = parent || this.getTextEditorElement()368 let minimaps = container.querySelectorAll('atom-text-editor-minimap')369 if (minimaps.length) {370 Array.prototype.forEach.call(minimaps, (el) => { el.destroy() })371 }372 container.appendChild(this)373 }374 /**375 * Detaches the MinimapElement from the DOM.376 */377 detach () {378 if (!this.attached || this.parentNode == null) { return }379 this.parentNode.removeChild(this)380 }381 /**382 * Toggles the minimap left/right position based on the value of the383 * `displayMinimapOnLeft` setting.384 *385 * @access private386 */387 updateMinimapFlexPosition () {388 this.classList.toggle('left', this.displayMinimapOnLeft)389 }390 /**391 * Destroys this MinimapElement392 */393 destroy () {394 this.subscriptions.dispose()395 this.detach()396 this.minimap = null397 }398 // ###### ####### ## ## ######## ######## ## ## ########399 // ## ## ## ## ### ## ## ## ### ## ##400 // ## ## ## #### ## ## ## #### ## ##401 // ## ## ## ## ## ## ## ###### ## ## ## ##402 // ## ## ## ## #### ## ## ## #### ##403 // ## ## ## ## ## ### ## ## ## ### ##404 // ###### ####### ## ## ## ######## ## ## ##405 /**406 * Creates the content of the MinimapElement and attaches the mouse control407 * event listeners.408 *409 * @access private410 */411 initializeContent () {412 this.initializeCanvas()413 this.attachCanvases(this)414 this.createVisibleArea()415 this.createControls()416 this.subscriptions.add(this.subscribeTo(this, {417 'mousewheel': (e) => {418 if (!this.standAlone) {419 this.minimap.onMouseWheel(e)420 }421 }422 }))423 this.subscriptions.add(this.subscribeTo(this.getFrontCanvas(), {424 'mousedown': (e) => { this.canvasPressed(this.extractMouseEventData(e)) },425 'touchstart': (e) => { this.canvasPressed(this.extractTouchEventData(e)) }426 }))427 }428 /**429 * Initializes the visible area div.430 *431 * @access private432 */433 createVisibleArea () {434 if (this.visibleArea) { return }435 this.visibleArea = document.createElement('div')436 this.visibleArea.classList.add('minimap-visible-area')437 this.appendChild(this.visibleArea)438 this.visibleAreaSubscription = this.subscribeTo(this.visibleArea, {439 'mousedown': (e) => { this.startDrag(this.extractMouseEventData(e)) },440 'touchstart': (e) => { this.startDrag(this.extractTouchEventData(e)) }441 })442 this.subscriptions.add(this.visibleAreaSubscription)443 }444 /**445 * Removes the visible area div.446 *447 * @access private448 */449 removeVisibleArea () {450 if (!this.visibleArea) { return }451 this.subscriptions.remove(this.visibleAreaSubscription)452 this.visibleAreaSubscription.dispose()453 this.removeChild(this.visibleArea)454 delete this.visibleArea455 }456 /**457 * Creates the controls container div.458 *459 * @access private460 */461 createControls () {462 if (this.controls || this.standAlone) { return }463 this.controls = document.createElement('div')464 this.controls.classList.add('minimap-controls')465 this.appendChild(this.controls)466 }467 /**468 * Removes the controls container div.469 *470 * @access private471 */472 removeControls () {473 if (!this.controls) { return }474 this.removeChild(this.controls)475 delete this.controls476 }477 /**478 * Initializes the scroll indicator div when the `minimapScrollIndicator`479 * settings is enabled.480 *481 * @access private482 */483 initializeScrollIndicator () {484 if (this.scrollIndicator || this.standAlone) { return }485 this.scrollIndicator = document.createElement('div')486 this.scrollIndicator.classList.add('minimap-scroll-indicator')487 this.controls.appendChild(this.scrollIndicator)488 }489 /**490 * Disposes the scroll indicator div when the `minimapScrollIndicator`491 * settings is disabled.492 *493 * @access private494 */495 disposeScrollIndicator () {496 if (!this.scrollIndicator) { return }497 this.controls.removeChild(this.scrollIndicator)498 delete this.scrollIndicator499 }500 /**501 * Initializes the quick settings openener div when the502 * `displayPluginsControls` setting is enabled.503 *504 * @access private505 */506 initializeOpenQuickSettings () {507 if (this.openQuickSettings || this.standAlone) { return }508 this.openQuickSettings = document.createElement('div')509 this.openQuickSettings.classList.add('open-minimap-quick-settings')510 this.controls.appendChild(this.openQuickSettings)511 this.openQuickSettingSubscription = this.subscribeTo(this.openQuickSettings, {512 'mousedown': (e) => {513 if (!MinimapQuickSettingsElement) {514 MinimapQuickSettingsElement = require('./minimap-quick-settings-element')515 }516 e.preventDefault()517 e.stopPropagation()518 if ((this.quickSettingsElement != null)) {519 this.quickSettingsElement.destroy()520 this.quickSettingsSubscription.dispose()521 } else {522 this.quickSettingsElement = new MinimapQuickSettingsElement()523 this.quickSettingsElement.setModel(this)524 this.quickSettingsSubscription = this.quickSettingsElement.onDidDestroy(() => {525 this.quickSettingsElement = null526 })527 let {top, left, right} = this.getFrontCanvas().getBoundingClientRect()528 this.quickSettingsElement.style.top = top + 'px'529 this.quickSettingsElement.attach()530 if (this.displayMinimapOnLeft) {531 this.quickSettingsElement.style.left = (right) + 'px'532 } else {533 this.quickSettingsElement.style.left = (left - this.quickSettingsElement.clientWidth) + 'px'534 }535 }536 }537 })538 }539 /**540 * Disposes the quick settings openener div when the `displayPluginsControls`541 * setting is disabled.542 *543 * @access private544 */545 disposeOpenQuickSettings () {546 if (!this.openQuickSettings) { return }547 this.controls.removeChild(this.openQuickSettings)548 this.openQuickSettingSubscription.dispose()549 delete this.openQuickSettings550 }551 /**552 * Returns the target `TextEditor` of the Minimap.553 *554 * @return {TextEditor} the minimap's text editor555 */556 getTextEditor () { return this.minimap.getTextEditor() }557 /**558 * Returns the `TextEditorElement` for the Minimap's `TextEditor`.559 *560 * @return {TextEditorElement} the minimap's text editor element561 */562 getTextEditorElement () {563 if (this.editorElement) { return this.editorElement }564 this.editorElement = atom.views.getView(this.getTextEditor())565 return this.editorElement566 }567 // ## ## ####### ######## ######## ##568 // ### ### ## ## ## ## ## ##569 // #### #### ## ## ## ## ## ##570 // ## ### ## ## ## ## ## ###### ##571 // ## ## ## ## ## ## ## ##572 // ## ## ## ## ## ## ## ##573 // ## ## ####### ######## ######## ########574 /**575 * Returns the Minimap for which this MinimapElement was created.576 *577 * @return {Minimap} this element's Minimap578 */579 getModel () { return this.minimap }580 /**581 * Defines the Minimap model for this MinimapElement instance.582 *583 * @param {Minimap} minimap the Minimap model for this instance.584 * @return {Minimap} this element's Minimap585 */586 setModel (minimap) {587 if (!Main) { Main = require('./main') }588 this.minimap = minimap589 this.subscriptions.add(this.minimap.onDidChangeScrollTop(() => {590 this.requestUpdate()591 }))592 this.subscriptions.add(this.minimap.onDidChangeScrollLeft(() => {593 this.requestUpdate()594 }))595 this.subscriptions.add(this.minimap.onDidDestroy(() => {596 this.destroy()597 }))598 this.subscriptions.add(this.minimap.onDidChangeConfig(() => {599 if (this.attached) { return this.requestForcedUpdate() }600 }))601 this.subscriptions.add(this.minimap.onDidChangeStandAlone(() => {602 this.setStandAlone(this.minimap.isStandAlone())603 this.requestUpdate()604 }))605 this.subscriptions.add(this.minimap.onDidChange((change) => {606 this.pendingChanges.push(change)607 this.requestUpdate()608 }))609 this.subscriptions.add(this.minimap.onDidChangeDecorationRange((change) => {610 const {type} = change611 if (type === 'line' ||612 type === 'highlight-under' ||613 type === 'background-custom') {614 this.pendingBackDecorationChanges.push(change)615 } else {616 this.pendingFrontDecorationChanges.push(change)617 }618 this.requestUpdate()619 }))620 this.subscriptions.add(Main.onDidChangePluginOrder(() => {621 this.requestForcedUpdate()622 }))623 this.setStandAlone(this.minimap.isStandAlone())624 if (this.width != null && this.height != null) {625 this.minimap.setScreenHeightAndWidth(this.height, this.width)626 }627 return this.minimap628 }629 /**630 * Sets the stand-alone mode for this MinimapElement.631 *632 * @param {boolean} standAlone the new mode for this MinimapElement633 */634 setStandAlone (standAlone) {635 this.standAlone = standAlone636 if (this.standAlone) {637 this.setAttribute('stand-alone', true)638 this.disposeScrollIndicator()639 this.disposeOpenQuickSettings()640 this.removeControls()641 this.removeVisibleArea()642 } else {643 this.removeAttribute('stand-alone')644 this.createVisibleArea()645 this.createControls()646 if (this.minimapScrollIndicator) { this.initializeScrollIndicator() }647 if (this.displayPluginsControls) { this.initializeOpenQuickSettings() }648 }649 }650 // ## ## ######## ######## ### ######## ########651 // ## ## ## ## ## ## ## ## ## ##652 // ## ## ## ## ## ## ## ## ## ##653 // ## ## ######## ## ## ## ## ## ######654 // ## ## ## ## ## ######### ## ##655 // ## ## ## ## ## ## ## ## ##656 // ####### ## ######## ## ## ## ########657 /**658 * Requests an update to be performed on the next frame.659 */660 requestUpdate () {661 if (this.frameRequested) { return }662 this.frameRequested = true663 requestAnimationFrame(() => {664 this.update()665 this.frameRequested = false666 })667 }668 /**669 * Requests an update to be performed on the next frame that will completely670 * redraw the minimap.671 */672 requestForcedUpdate () {673 this.offscreenFirstRow = null674 this.offscreenLastRow = null675 this.requestUpdate()676 }677 /**678 * Performs the actual MinimapElement update.679 *680 * @access private681 */682 update () {683 if (!(this.attached && this.isVisible() && this.minimap)) { return }684 const minimap = this.minimap685 minimap.enableCache()686 const canvas = this.getFrontCanvas()687 const devicePixelRatio = this.minimap.getDevicePixelRatio()688 const visibleAreaLeft = minimap.getTextEditorScaledScrollLeft()689 const visibleAreaTop = minimap.getTextEditorScaledScrollTop() - minimap.getScrollTop()690 const width = Math.min(canvas.width / devicePixelRatio, this.width)691 const visibleWidth = width + visibleAreaLeft692 if (this.adjustToSoftWrap && this.flexBasis) {693 this.style.flexBasis = this.flexBasis + 'px'694 this.style.width = this.flexBasis + 'px'695 } else {696 this.style.flexBasis = null697 this.style.width = null698 }699 if (SPEC_MODE) {700 this.applyStyles(this.visibleArea, {701 width: Math.round(visibleWidth) + 'px',702 height: Math.round(minimap.getTextEditorScaledHeight()) + 'px',703 top: Math.round(visibleAreaTop) + 'px',704 'border-left-width': Math.round(visibleAreaLeft) + 'px'705 })706 } else {707 this.applyStyles(this.visibleArea, {708 width: Math.round(visibleWidth) + 'px',709 height: Math.round(minimap.getTextEditorScaledHeight()) + 'px',710 transform: this.makeTranslate(0, visibleAreaTop),711 'border-left-width': Math.round(visibleAreaLeft) + 'px'712 })713 }714 this.applyStyles(this.controls, {width: Math.round(width) + 'px'})715 let canvasTop = minimap.getFirstVisibleScreenRow() * minimap.getLineHeight() - minimap.getScrollTop()716 if (this.smoothScrolling) {717 if (SPEC_MODE) {718 this.applyStyles(this.backLayer.canvas, {top: canvasTop + 'px'})719 this.applyStyles(this.tokensLayer.canvas, {top: canvasTop + 'px'})720 this.applyStyles(this.frontLayer.canvas, {top: canvasTop + 'px'})721 } else {722 let canvasTransform = this.makeTranslate(0, canvasTop)723 if (devicePixelRatio !== 1) {724 canvasTransform += ' ' + this.makeScale(1 / devicePixelRatio)725 }726 this.applyStyles(this.backLayer.canvas, {transform: canvasTransform})727 this.applyStyles(this.tokensLayer.canvas, {transform: canvasTransform})728 this.applyStyles(this.frontLayer.canvas, {transform: canvasTransform})729 }730 } else {731 const canvasTransform = this.makeScale(1 / devicePixelRatio)732 this.applyStyles(this.backLayer.canvas, {transform: canvasTransform})733 this.applyStyles(this.tokensLayer.canvas, {transform: canvasTransform})734 this.applyStyles(this.frontLayer.canvas, {transform: canvasTransform})735 }736 if (this.minimapScrollIndicator && minimap.canScroll() && !this.scrollIndicator) {737 this.initializeScrollIndicator()738 }739 if (this.scrollIndicator != null) {740 let minimapScreenHeight = minimap.getScreenHeight()741 let indicatorHeight = minimapScreenHeight * (minimapScreenHeight / minimap.getHeight())742 let indicatorScroll = (minimapScreenHeight - indicatorHeight) * minimap.getScrollRatio()743 if (SPEC_MODE) {744 this.applyStyles(this.scrollIndicator, {745 height: indicatorHeight + 'px',746 top: indicatorScroll + 'px'747 })748 } else {749 this.applyStyles(this.scrollIndicator, {750 height: indicatorHeight + 'px',751 transform: this.makeTranslate(0, indicatorScroll)752 })753 }754 if (!minimap.canScroll()) { this.disposeScrollIndicator() }755 }756 if (this.absoluteMode && this.adjustAbsoluteModeHeight) { this.updateCanvasesSize() }757 this.updateCanvas()758 minimap.clearCache()759 }760 /**761 * Defines whether to render the code highlights or not.762 *763 * @param {Boolean} displayCodeHighlights whether to render the code764 * highlights or not765 */766 setDisplayCodeHighlights (displayCodeHighlights) {767 this.displayCodeHighlights = displayCodeHighlights768 if (this.attached) { this.requestForcedUpdate() }769 }770 /**771 * Polling callback used to detect visibility and size changes.772 *773 * @access private774 */775 pollDOM () {776 let visibilityChanged = this.checkForVisibilityChange()777 if (this.isVisible()) {778 if (!this.wasVisible) { this.requestForcedUpdate() }779 this.measureHeightAndWidth(visibilityChanged, false)780 }781 }782 /**783 * A method that checks for visibility changes in the MinimapElement.784 * The method returns `true` when the visibility changed from visible to785 * hidden or from hidden to visible.786 *787 * @return {boolean} whether the visibility changed or not since the last call788 * @access private789 */790 checkForVisibilityChange () {791 if (this.isVisible()) {792 if (this.wasVisible) {793 return false794 } else {795 this.wasVisible = true796 return this.wasVisible797 }798 } else {799 if (this.wasVisible) {800 this.wasVisible = false801 return true802 } else {803 this.wasVisible = false804 return this.wasVisible805 }806 }807 }808 /**809 * A method used to measure the size of the MinimapElement and update internal810 * components based on the new size.811 *812 * @param {boolean} visibilityChanged did the visibility changed since last813 * measurement814 * @param {[type]} [forceUpdate=true] forces the update even when no changes815 * were detected816 * @access private817 */818 measureHeightAndWidth (visibilityChanged, forceUpdate = true) {819 if (!this.minimap) { return }820 const safeFlexBasis = this.style.flexBasis821 this.style.flexBasis = ''822 let wasResized = this.width !== this.clientWidth || this.height !== this.clientHeight823 this.height = this.clientHeight824 this.width = this.clientWidth825 let canvasWidth = this.width826 if ((this.minimap != null)) {827 this.minimap.setScreenHeightAndWidth(this.height, this.width)828 }829 if (wasResized || visibilityChanged || forceUpdate) {830 this.requestForcedUpdate()831 }832 if (!this.isVisible()) { return }833 if (wasResized || forceUpdate) {834 if (this.adjustToSoftWrap) {835 let lineLength = atom.config.get('editor.preferredLineLength')836 let softWrap = atom.config.get('editor.softWrap')837 let softWrapAtPreferredLineLength = atom.config.get('editor.softWrapAtPreferredLineLength')838 let width = lineLength * this.minimap.getCharWidth()839 if (softWrap && softWrapAtPreferredLineLength && lineLength && (width <= this.width || !this.adjustOnlyIfSmaller)) {840 this.flexBasis = width841 canvasWidth = width842 updateOverlayStyle(width)843 } else {844 updateOverlayStyle(canvasWidth)845 delete this.flexBasis846 }847 } else {848 updateOverlayStyle(canvasWidth)849 delete this.flexBasis850 }851 this.updateCanvasesSize(canvasWidth)852 } else {853 this.style.flexBasis = safeFlexBasis854 }855 }856 updateCanvasesSize (canvasWidth) {857 const devicePixelRatio = this.minimap.getDevicePixelRatio()858 const maxCanvasHeight = this.height + this.minimap.getLineHeight()859 const newHeight = this.absoluteMode && this.adjustAbsoluteModeHeight ? Math.min(this.minimap.getHeight(), maxCanvasHeight) : maxCanvasHeight860 const canvas = this.getFrontCanvas()861 if (canvasWidth == null) {862 canvasWidth = canvas.width / devicePixelRatio863 }864 if (canvasWidth !== canvas.width || newHeight !== canvas.height) {865 this.setCanvasesSize(866 canvasWidth * devicePixelRatio,867 newHeight * devicePixelRatio868 )869 if (this.absoluteMode && this.adjustAbsoluteModeHeight) {870 this.offscreenFirstRow = null871 this.offscreenLastRow = null872 }873 }874 }875 // ######## ## ## ######## ## ## ######## ######876 // ## ## ## ## ### ## ## ## ##877 // ## ## ## ## #### ## ## ##878 // ###### ## ## ###### ## ## ## ## ######879 // ## ## ## ## ## #### ## ##880 // ## ## ## ## ## ### ## ## ##881 // ######## ### ######## ## ## ## ######882 /**883 * Helper method to register config observers.884 *885 * @param {Object} configs={} an object mapping the config name to observe886 * with the function to call back when a change887 * occurs888 * @access private889 */890 observeConfig (configs = {}) {891 for (let config in configs) {892 this.subscriptions.add(atom.config.observe(config, configs[config]))893 }894 }895 /**896 * Callback triggered when the mouse is pressed on the MinimapElement canvas.897 *898 * @param {number} y the vertical coordinate of the event899 * @param {boolean} isLeftMouse was the left mouse button pressed?900 * @param {boolean} isMiddleMouse was the middle mouse button pressed?901 * @access private902 */903 canvasPressed ({y, isLeftMouse, isMiddleMouse}) {904 if (this.minimap.isStandAlone()) { return }905 if (isLeftMouse) {906 this.canvasLeftMousePressed(y)907 } else if (isMiddleMouse) {908 this.canvasMiddleMousePressed(y)909 let {top, height} = this.visibleArea.getBoundingClientRect()910 this.startDrag({y: top + height / 2, isLeftMouse: false, isMiddleMouse: true})911 }912 }913 /**914 * Callback triggered when the mouse left button is pressed on the915 * MinimapElement canvas.916 *917 * @param {MouseEvent} e the mouse event object918 * @param {number} e.pageY the mouse y position in page919 * @param {HTMLElement} e.target the source of the event920 * @access private921 */922 canvasLeftMousePressed (y) {923 const deltaY = y - this.getBoundingClientRect().top924 const row = Math.floor(deltaY / this.minimap.getLineHeight()) + this.minimap.getFirstVisibleScreenRow()925 const textEditor = this.minimap.getTextEditor()926 const textEditorElement = this.getTextEditorElement()927 const scrollTop = row * textEditor.getLineHeightInPixels() - this.minimap.getTextEditorHeight() / 2928 const textEditorScrollTop = textEditorElement.pixelPositionForScreenPosition([row, 0]).top - this.minimap.getTextEditorHeight() / 2929 if (atom.config.get('minimap.moveCursorOnMinimapClick')) {930 textEditor.setCursorScreenPosition([row, 0])931 }932 if (atom.config.get('minimap.scrollAnimation')) {933 const duration = atom.config.get('minimap.scrollAnimationDuration')934 const independentScroll = this.minimap.scrollIndependentlyOnMouseWheel()935 let from = this.minimap.getTextEditorScrollTop()936 let to = textEditorScrollTop937 let step938 if (independentScroll) {939 const minimapFrom = this.minimap.getScrollTop()940 const minimapTo = Math.min(1, scrollTop / (this.minimap.getTextEditorMaxScrollTop() || 1)) * this.minimap.getMaxScrollTop()941 step = (now, t) => {942 this.minimap.setTextEditorScrollTop(now, true)943 this.minimap.setScrollTop(minimapFrom + (minimapTo - minimapFrom) * t)944 }945 this.animate({from: from, to: to, duration: duration, step: step})946 } else {947 step = (now) => this.minimap.setTextEditorScrollTop(now)948 this.animate({from: from, to: to, duration: duration, step: step})949 }950 } else {951 this.minimap.setTextEditorScrollTop(textEditorScrollTop)952 }953 }954 /**955 * Callback triggered when the mouse middle button is pressed on the956 * MinimapElement canvas.957 *958 * @param {MouseEvent} e the mouse event object959 * @param {number} e.pageY the mouse y position in page960 * @access private961 */962 canvasMiddleMousePressed (y) {963 const {top: offsetTop} = this.getBoundingClientRect()964 const deltaY = y - offsetTop - this.minimap.getTextEditorScaledHeight() / 2965 const ratio = deltaY / (this.minimap.getVisibleHeight() - this.minimap.getTextEditorScaledHeight())966 this.minimap.setTextEditorScrollTop(ratio * this.minimap.getTextEditorMaxScrollTop())967 }968 /**969 * A method that extracts data from a `MouseEvent` which can then be used to970 * process clicks and drags of the minimap.971 *972 * Used together with `extractTouchEventData` to provide a unified interface973 * for `MouseEvent`s and `TouchEvent`s.974 *975 * @param {MouseEvent} mouseEvent the mouse event object976 * @access private977 */978 extractMouseEventData (mouseEvent) {979 return {980 x: mouseEvent.pageX,981 y: mouseEvent.pageY,982 isLeftMouse: mouseEvent.which === 1,983 isMiddleMouse: mouseEvent.which === 2984 }985 }986 /**987 * A method that extracts data from a `TouchEvent` which can then be used to988 * process clicks and drags of the minimap.989 *990 * Used together with `extractMouseEventData` to provide a unified interface991 * for `MouseEvent`s and `TouchEvent`s.992 *993 * @param {TouchEvent} touchEvent the touch event object994 * @access private995 */996 extractTouchEventData (touchEvent) {997 // Use the first touch on the target area. Other touches will be ignored in998 // case of multi-touch.999 let touch = touchEvent.changedTouches[0]1000 return {1001 x: touch.pageX,1002 y: touch.pageY,1003 isLeftMouse: true, // Touch is treated like a left mouse button click1004 isMiddleMouse: false1005 }1006 }1007 /**1008 * Subscribes to a media query for device pixel ratio changes and forces1009 * a repaint when it occurs.1010 *1011 * @return {Disposable} a disposable to remove the media query listener1012 * @access private1013 */1014 subscribeToMediaQuery () {1015 if (!Disposable) {1016 ({CompositeDisposable, Disposable} = require('atom'))1017 }1018 const query = 'screen and (-webkit-min-device-pixel-ratio: 1.5)'1019 const mediaQuery = window.matchMedia(query)1020 const mediaListener = (e) => { this.requestForcedUpdate() }1021 mediaQuery.addListener(mediaListener)1022 return new Disposable(() => {1023 mediaQuery.removeListener(mediaListener)1024 })1025 }1026 // ######## #### ########1027 // ## ## ## ## ## ##1028 // ## ## #### ## ##1029 // ## ## #### ## ##1030 // ## ## ## ## ## ## ##1031 // ## ## ## ## ## ##1032 // ######## #### ## ########1033 /**1034 * A method triggered when the mouse is pressed over the visible area that1035 * starts the dragging gesture.1036 *1037 * @param {number} y the vertical coordinate of the event1038 * @param {boolean} isLeftMouse was the left mouse button pressed?1039 * @param {boolean} isMiddleMouse was the middle mouse button pressed?1040 * @access private1041 */1042 startDrag ({y, isLeftMouse, isMiddleMouse}) {1043 if (!Disposable) {1044 ({CompositeDisposable, Disposable} = require('atom'))1045 }1046 if (!this.minimap) { return }1047 if (!isLeftMouse && !isMiddleMouse) { return }1048 let {top} = this.visibleArea.getBoundingClientRect()1049 let {top: offsetTop} = this.getBoundingClientRect()1050 let dragOffset = y - top1051 let initial = {dragOffset, offsetTop}1052 let mousemoveHandler = (e) => this.drag(this.extractMouseEventData(e), initial)1053 let mouseupHandler = (e) => this.endDrag()1054 let touchmoveHandler = (e) => this.drag(this.extractTouchEventData(e), initial)1055 let touchendHandler = (e) => this.endDrag()1056 document.body.addEventListener('mousemove', mousemoveHandler)1057 document.body.addEventListener('mouseup', mouseupHandler)1058 document.body.addEventListener('mouseleave', mouseupHandler)1059 document.body.addEventListener('touchmove', touchmoveHandler)1060 document.body.addEventListener('touchend', touchendHandler)1061 document.body.addEventListener('touchcancel', touchendHandler)1062 this.dragSubscription = new Disposable(function () {1063 document.body.removeEventListener('mousemove', mousemoveHandler)1064 document.body.removeEventListener('mouseup', mouseupHandler)1065 document.body.removeEventListener('mouseleave', mouseupHandler)1066 document.body.removeEventListener('touchmove', touchmoveHandler)1067 document.body.removeEventListener('touchend', touchendHandler)1068 document.body.removeEventListener('touchcancel', touchendHandler)1069 })1070 }1071 /**1072 * The method called during the drag gesture.1073 *1074 * @param {number} y the vertical coordinate of the event1075 * @param {boolean} isLeftMouse was the left mouse button pressed?1076 * @param {boolean} isMiddleMouse was the middle mouse button pressed?1077 * @param {number} initial.dragOffset the mouse offset within the visible1078 * area1079 * @param {number} initial.offsetTop the MinimapElement offset at the moment1080 * of the drag start1081 * @access private1082 */1083 drag ({y, isLeftMouse, isMiddleMouse}, initial) {1084 if (!this.minimap) { return }1085 if (!isLeftMouse && !isMiddleMouse) { return }1086 let deltaY = y - initial.offsetTop - initial.dragOffset1087 let ratio = deltaY / (this.minimap.getVisibleHeight() - this.minimap.getTextEditorScaledHeight())1088 this.minimap.setTextEditorScrollTop(ratio * this.minimap.getTextEditorMaxScrollTop())1089 }1090 /**1091 * The method that ends the drag gesture.1092 *1093 * @access private1094 */1095 endDrag () {1096 if (!this.minimap) { return }1097 this.dragSubscription.dispose()1098 }1099 // ###### ###### ######1100 // ## ## ## ## ## ##1101 // ## ## ##1102 // ## ###### ######1103 // ## ## ##1104 // ## ## ## ## ## ##1105 // ###### ###### ######1106 /**1107 * Applies the passed-in styles properties to the specified element1108 *1109 * @param {HTMLElement} element the element onto which apply the styles1110 * @param {Object} styles the styles to apply1111 * @access private1112 */1113 applyStyles (element, styles) {1114 if (!element) { return }1115 let cssText = ''1116 for (let property in styles) {1117 cssText += `${property}: ${styles[property]}; `1118 }1119 element.style.cssText = cssText1120 }1121 /**1122 * Returns a string with a CSS translation tranform value.1123 *1124 * @param {number} [x = 0] the x offset of the translation1125 * @param {number} [y = 0] the y offset of the translation1126 * @return {string} the CSS translation string1127 * @access private1128 */1129 makeTranslate (x = 0, y = 0) {1130 if (this.useHardwareAcceleration) {1131 return `translate3d(${x}px, ${y}px, 0)`1132 } else {1133 return `translate(${x}px, ${y}px)`1134 }1135 }1136 /**1137 * Returns a string with a CSS scaling tranform value.1138 *1139 * @param {number} [x = 0] the x scaling factor1140 * @param {number} [y = 0] the y scaling factor1141 * @return {string} the CSS scaling string1142 * @access private1143 */1144 makeScale (x = 0, y = x) {1145 if (this.useHardwareAcceleration) {1146 return `scale3d(${x}, ${y}, 1)`1147 } else {1148 return `scale(${x}, ${y})`1149 }1150 }1151 /**1152 * A method that return the current time as a Date.1153 *1154 * That method exist so that we can mock it in tests.1155 *1156 * @return {Date} the current time as Date1157 * @access private1158 */1159 getTime () { return new Date() }1160 /**1161 * A method that mimic the jQuery `animate` method and used to animate the1162 * scroll when clicking on the MinimapElement canvas.1163 *1164 * @param {Object} param the animation data object1165 * @param {[type]} param.from the start value1166 * @param {[type]} param.to the end value1167 * @param {[type]} param.duration the animation duration1168 * @param {[type]} param.step the easing function for the animation1169 * @access private1170 */1171 animate ({from, to, duration, step}) {1172 const start = this.getTime()1173 let progress1174 const swing = function (progress) {1175 return 0.5 - Math.cos(progress * Math.PI) / 21176 }1177 const update = () => {1178 if (!this.minimap) { return }1179 const passed = this.getTime() - start1180 if (duration === 0) {1181 progress = 11182 } else {1183 progress = passed / duration1184 }1185 if (progress > 1) { progress = 1 }1186 const delta = swing(progress)1187 const value = from + (to - from) * delta1188 step(value, delta)1189 if (progress < 1) { requestAnimationFrame(update) }1190 }1191 update()1192 }1193}...

Full Screen

Full Screen

showQuickOptions.ts

Source:showQuickOptions.ts Github

copy

Full Screen

1import { orchestrator } from 'satcheljs';2import { openQuickSettings } from 'owa-whats-new/lib/actions/openQuickSettings';3export default orchestrator(openQuickSettings, () => {4 (window as any).O365Shell.FlexPane.OpenFlexPaneForProvider('OwaSettings');...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1var root = require('root');2var activity = root.activity;3activity.openQuickSettings();4var root = require('root');5var activity = root.activity;6activity.openNotification();7var root = require('root');8var activity = root.activity;9activity.openSettings();10var root = require('root');11var activity = root.activity;12activity.openWifiSettings();13var root = require('root');14var activity = root.activity;15activity.openBluetoothSettings();16var root = require('root');17var activity = root.activity;18activity.openLocationSettings();

Full Screen

Using AI Code Generation

copy

Full Screen

1var root = require('root');2var activity = Ti.Android.currentActivity;3activity.addEventListener('pause', function(e) {4 root.openQuickSettings();5});6activity.addEventListener('resume', function(e) {7});8var root = require('root');9var activity = Ti.Android.currentActivity;10activity.addEventListener('pause', function(e) {11 root.openQuickSettings();12});13activity.addEventListener('resume', function(e) {14});

Full Screen

Using AI Code Generation

copy

Full Screen

1var root = require('root');2var sys = require('sys');3root.openQuickSettings(function(err, result) {4 if (err) {5 sys.puts("Error: " + err);6 } else {7 sys.puts("Success");8 }9});10root.openQuickSettings(function(err, result) {11 if (err) {12 sys.puts("Error: " + err);13 } else {14 sys.puts("Success");15 }16});

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run root automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful