-
Notifications
You must be signed in to change notification settings - Fork 98
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
40 changed files
with
8,199 additions
and
42 deletions.
There are no files selected for viewing
Submodule blink-mind
updated
from 80e41c to ed681e
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
/*--------------------------------------------------------------------------------------------- | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*--------------------------------------------------------------------------------------------*/ | ||
|
||
import { Emitter, Event } from '../common/event'; | ||
import { IDisposable } from '../common/lifecycle'; | ||
import * as platform from '../common/platform'; | ||
|
||
class WindowManager { | ||
|
||
public static readonly INSTANCE = new WindowManager(); | ||
|
||
// --- Zoom Level | ||
private _zoomLevel: number = 0; | ||
private _lastZoomLevelChangeTime: number = 0; | ||
private readonly _onDidChangeZoomLevel = new Emitter<number>(); | ||
|
||
public readonly onDidChangeZoomLevel: Event<number> = this._onDidChangeZoomLevel.event; | ||
public getZoomLevel(): number { | ||
return this._zoomLevel; | ||
} | ||
public getTimeSinceLastZoomLevelChanged(): number { | ||
return Date.now() - this._lastZoomLevelChangeTime; | ||
} | ||
public setZoomLevel(zoomLevel: number, isTrusted: boolean): void { | ||
if (this._zoomLevel === zoomLevel) { | ||
return; | ||
} | ||
|
||
this._zoomLevel = zoomLevel; | ||
// See https://github.com/Microsoft/vscode/issues/26151 | ||
this._lastZoomLevelChangeTime = isTrusted ? 0 : Date.now(); | ||
this._onDidChangeZoomLevel.fire(this._zoomLevel); | ||
} | ||
|
||
// --- Zoom Factor | ||
private _zoomFactor: number = 0; | ||
|
||
public getZoomFactor(): number { | ||
return this._zoomFactor; | ||
} | ||
public setZoomFactor(zoomFactor: number): void { | ||
this._zoomFactor = zoomFactor; | ||
} | ||
|
||
// --- Pixel Ratio | ||
public getPixelRatio(): number { | ||
let ctx = document.createElement('canvas').getContext('2d'); | ||
let dpr = window.devicePixelRatio || 1; | ||
let bsr = (<any>ctx).webkitBackingStorePixelRatio || | ||
(<any>ctx).mozBackingStorePixelRatio || | ||
(<any>ctx).msBackingStorePixelRatio || | ||
(<any>ctx).oBackingStorePixelRatio || | ||
(<any>ctx).backingStorePixelRatio || 1; | ||
return dpr / bsr; | ||
} | ||
|
||
// --- Fullscreen | ||
private _fullscreen: boolean; | ||
private readonly _onDidChangeFullscreen = new Emitter<void>(); | ||
|
||
public readonly onDidChangeFullscreen: Event<void> = this._onDidChangeFullscreen.event; | ||
public setFullscreen(fullscreen: boolean): void { | ||
if (this._fullscreen === fullscreen) { | ||
return; | ||
} | ||
|
||
this._fullscreen = fullscreen; | ||
this._onDidChangeFullscreen.fire(); | ||
} | ||
public isFullscreen(): boolean { | ||
return this._fullscreen; | ||
} | ||
|
||
// --- Accessibility | ||
private _accessibilitySupport = platform.AccessibilitySupport.Unknown; | ||
private readonly _onDidChangeAccessibilitySupport = new Emitter<void>(); | ||
|
||
public readonly onDidChangeAccessibilitySupport: Event<void> = this._onDidChangeAccessibilitySupport.event; | ||
public setAccessibilitySupport(accessibilitySupport: platform.AccessibilitySupport): void { | ||
if (this._accessibilitySupport === accessibilitySupport) { | ||
return; | ||
} | ||
|
||
this._accessibilitySupport = accessibilitySupport; | ||
this._onDidChangeAccessibilitySupport.fire(); | ||
} | ||
public getAccessibilitySupport(): platform.AccessibilitySupport { | ||
return this._accessibilitySupport; | ||
} | ||
} | ||
|
||
/** A zoom index, e.g. 1, 2, 3 */ | ||
export function setZoomLevel(zoomLevel: number, isTrusted: boolean): void { | ||
WindowManager.INSTANCE.setZoomLevel(zoomLevel, isTrusted); | ||
} | ||
export function getZoomLevel(): number { | ||
return WindowManager.INSTANCE.getZoomLevel(); | ||
} | ||
/** Returns the time (in ms) since the zoom level was changed */ | ||
export function getTimeSinceLastZoomLevelChanged(): number { | ||
return WindowManager.INSTANCE.getTimeSinceLastZoomLevelChanged(); | ||
} | ||
export function onDidChangeZoomLevel(callback: (zoomLevel: number) => void): IDisposable { | ||
return WindowManager.INSTANCE.onDidChangeZoomLevel(callback); | ||
} | ||
|
||
/** The zoom scale for an index, e.g. 1, 1.2, 1.4 */ | ||
export function getZoomFactor(): number { | ||
return WindowManager.INSTANCE.getZoomFactor(); | ||
} | ||
export function setZoomFactor(zoomFactor: number): void { | ||
WindowManager.INSTANCE.setZoomFactor(zoomFactor); | ||
} | ||
|
||
export function getPixelRatio(): number { | ||
return WindowManager.INSTANCE.getPixelRatio(); | ||
} | ||
|
||
export function setFullscreen(fullscreen: boolean): void { | ||
WindowManager.INSTANCE.setFullscreen(fullscreen); | ||
} | ||
export function isFullscreen(): boolean { | ||
return WindowManager.INSTANCE.isFullscreen(); | ||
} | ||
export const onDidChangeFullscreen = WindowManager.INSTANCE.onDidChangeFullscreen; | ||
|
||
export function setAccessibilitySupport(accessibilitySupport: platform.AccessibilitySupport): void { | ||
WindowManager.INSTANCE.setAccessibilitySupport(accessibilitySupport); | ||
} | ||
export function getAccessibilitySupport(): platform.AccessibilitySupport { | ||
return WindowManager.INSTANCE.getAccessibilitySupport(); | ||
} | ||
export function onDidChangeAccessibilitySupport(callback: () => void): IDisposable { | ||
return WindowManager.INSTANCE.onDidChangeAccessibilitySupport(callback); | ||
} | ||
|
||
const userAgent = navigator.userAgent; | ||
|
||
export const isIE = (userAgent.indexOf('Trident') >= 0); | ||
export const isEdge = (userAgent.indexOf('Edge/') >= 0); | ||
export const isEdgeOrIE = isIE || isEdge; | ||
|
||
export const isOpera = (userAgent.indexOf('Opera') >= 0); | ||
export const isFirefox = (userAgent.indexOf('Firefox') >= 0); | ||
export const isWebKit = (userAgent.indexOf('AppleWebKit') >= 0); | ||
export const isChrome = (userAgent.indexOf('Chrome') >= 0); | ||
export const isSafari = (!isChrome && (userAgent.indexOf('Safari') >= 0)); | ||
export const isWebkitWebView = (!isChrome && !isSafari && isWebKit); | ||
export const isIPad = (userAgent.indexOf('iPad') >= 0); | ||
export const isEdgeWebView = isEdge && (userAgent.indexOf('WebView/') >= 0); | ||
|
||
export function hasClipboardSupport() { | ||
if (isIE) { | ||
return false; | ||
} | ||
|
||
if (isEdge) { | ||
let index = userAgent.indexOf('Edge/'); | ||
let version = parseInt(userAgent.substring(index + 5, userAgent.indexOf('.', index)), 10); | ||
|
||
if (!version || (version >= 12 && version <= 16)) { | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/*--------------------------------------------------------------------------------------------- | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*--------------------------------------------------------------------------------------------*/ | ||
|
||
import { Event, Emitter } from '../common/event'; | ||
|
||
export type EventHandler = HTMLElement | HTMLDocument | Window; | ||
|
||
export interface IDomEvent { | ||
<K extends keyof HTMLElementEventMap>(element: EventHandler, type: K, useCapture?: boolean): Event<HTMLElementEventMap[K]>; | ||
(element: EventHandler, type: string, useCapture?: boolean): Event<any>; | ||
} | ||
|
||
export const domEvent: IDomEvent = (element: EventHandler, type: string, useCapture?: boolean) => { | ||
const fn = e => emitter.fire(e); | ||
const emitter = new Emitter<any>({ | ||
onFirstListenerAdd: () => { | ||
element.addEventListener(type, fn, useCapture); | ||
}, | ||
onLastListenerRemove: () => { | ||
element.removeEventListener(type, fn, useCapture); | ||
} | ||
}); | ||
|
||
return emitter.event; | ||
}; | ||
|
||
export interface CancellableEvent { | ||
preventDefault(); | ||
stopPropagation(); | ||
} | ||
|
||
export function stop<T extends CancellableEvent>(event: Event<T>): Event<T> { | ||
return Event.map(event, e => { | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
return e; | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
/*--------------------------------------------------------------------------------------------- | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*--------------------------------------------------------------------------------------------*/ | ||
|
||
/** | ||
* Represents a window in a possible chain of iframes | ||
*/ | ||
export interface IWindowChainElement { | ||
/** | ||
* The window object for it | ||
*/ | ||
window: Window; | ||
/** | ||
* The iframe element inside the window.parent corresponding to window | ||
*/ | ||
iframeElement: HTMLIFrameElement | null; | ||
} | ||
|
||
let hasDifferentOriginAncestorFlag: boolean = false; | ||
let sameOriginWindowChainCache: IWindowChainElement[] | null = null; | ||
|
||
function getParentWindowIfSameOrigin(w: Window): Window | null { | ||
if (!w.parent || w.parent === w) { | ||
return null; | ||
} | ||
|
||
// Cannot really tell if we have access to the parent window unless we try to access something in it | ||
try { | ||
let location = w.location; | ||
let parentLocation = w.parent.location; | ||
if (location.protocol !== parentLocation.protocol || location.hostname !== parentLocation.hostname || location.port !== parentLocation.port) { | ||
hasDifferentOriginAncestorFlag = true; | ||
return null; | ||
} | ||
} catch (e) { | ||
hasDifferentOriginAncestorFlag = true; | ||
return null; | ||
} | ||
|
||
return w.parent; | ||
} | ||
|
||
function findIframeElementInParentWindow(parentWindow: Window, childWindow: Window): HTMLIFrameElement | null { | ||
let parentWindowIframes = parentWindow.document.getElementsByTagName('iframe'); | ||
let iframe: HTMLIFrameElement; | ||
for (let i = 0, len = parentWindowIframes.length; i < len; i++) { | ||
iframe = parentWindowIframes[i]; | ||
if (iframe.contentWindow === childWindow) { | ||
return iframe; | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
export class IframeUtils { | ||
|
||
/** | ||
* Returns a chain of embedded windows with the same origin (which can be accessed programmatically). | ||
* Having a chain of length 1 might mean that the current execution environment is running outside of an iframe or inside an iframe embedded in a window with a different origin. | ||
* To distinguish if at one point the current execution environment is running inside a window with a different origin, see hasDifferentOriginAncestor() | ||
*/ | ||
public static getSameOriginWindowChain(): IWindowChainElement[] { | ||
if (!sameOriginWindowChainCache) { | ||
sameOriginWindowChainCache = []; | ||
let w: Window | null = window; | ||
let parent: Window | null; | ||
do { | ||
parent = getParentWindowIfSameOrigin(w); | ||
if (parent) { | ||
sameOriginWindowChainCache.push({ | ||
window: w, | ||
iframeElement: findIframeElementInParentWindow(parent, w) | ||
}); | ||
} else { | ||
sameOriginWindowChainCache.push({ | ||
window: w, | ||
iframeElement: null | ||
}); | ||
} | ||
w = parent; | ||
} while (w); | ||
} | ||
return sameOriginWindowChainCache.slice(0); | ||
} | ||
|
||
/** | ||
* Returns true if the current execution environment is chained in a list of iframes which at one point ends in a window with a different origin. | ||
* Returns false if the current execution environment is not running inside an iframe or if the entire chain of iframes have the same origin. | ||
*/ | ||
public static hasDifferentOriginAncestor(): boolean { | ||
if (!sameOriginWindowChainCache) { | ||
this.getSameOriginWindowChain(); | ||
} | ||
return hasDifferentOriginAncestorFlag; | ||
} | ||
|
||
/** | ||
* Returns the position of `childWindow` relative to `ancestorWindow` | ||
*/ | ||
public static getPositionOfChildWindowRelativeToAncestorWindow(childWindow: Window, ancestorWindow: any) { | ||
|
||
if (!ancestorWindow || childWindow === ancestorWindow) { | ||
return { | ||
top: 0, | ||
left: 0 | ||
}; | ||
} | ||
|
||
let top = 0, left = 0; | ||
|
||
let windowChain = this.getSameOriginWindowChain(); | ||
|
||
for (const windowChainEl of windowChain) { | ||
|
||
if (windowChainEl.window === ancestorWindow) { | ||
break; | ||
} | ||
|
||
if (!windowChainEl.iframeElement) { | ||
break; | ||
} | ||
|
||
let boundingRect = windowChainEl.iframeElement.getBoundingClientRect(); | ||
top += boundingRect.top; | ||
left += boundingRect.left; | ||
} | ||
|
||
return { | ||
top: top, | ||
left: left | ||
}; | ||
} | ||
} |
Oops, something went wrong.