Merge pull request #12893 from andrewcoder002/main

Allow map target to be an external window
This commit is contained in:
MoonE
2021-11-03 21:20:24 +01:00
committed by GitHub
10 changed files with 347 additions and 156 deletions

View File

@@ -323,7 +323,7 @@ class PluggableMap extends BaseObject {
* @private
* @type {?Array<import("./events.js").EventsKey>}
*/
this.keyHandlerKeys_ = null;
this.targetChangeHandlerKeys_ = null;
/**
* @type {Collection<import("./control/Control.js").default>}
@@ -356,12 +356,6 @@ class PluggableMap extends BaseObject {
*/
this.renderer_ = null;
/**
* @type {undefined|function(Event): void}
* @private
*/
this.handleResize_;
/**
* @private
* @type {!Array<PostRenderFunction>}
@@ -1146,21 +1140,11 @@ class PluggableMap extends BaseObject {
* @private
*/
handleTargetChanged_() {
// target may be undefined, null, a string or an Element.
// If it's a string we convert it to an Element before proceeding.
// If it's not now an Element we remove the viewport from the DOM.
// If it's an Element we append the viewport element to it.
let targetElement;
if (this.getTarget()) {
targetElement = this.getTargetElement();
}
if (this.mapBrowserEventHandler_) {
for (let i = 0, ii = this.keyHandlerKeys_.length; i < ii; ++i) {
unlistenByKey(this.keyHandlerKeys_[i]);
for (let i = 0, ii = this.targetChangeHandlerKeys_.length; i < ii; ++i) {
unlistenByKey(this.targetChangeHandlerKeys_[i]);
}
this.keyHandlerKeys_ = null;
this.targetChangeHandlerKeys_ = null;
this.viewport_.removeEventListener(
EventType.CONTEXTMENU,
this.boundHandleBrowserEvent_
@@ -1169,15 +1153,17 @@ class PluggableMap extends BaseObject {
EventType.WHEEL,
this.boundHandleBrowserEvent_
);
if (this.handleResize_ !== undefined) {
removeEventListener(EventType.RESIZE, this.handleResize_, false);
this.handleResize_ = undefined;
}
this.mapBrowserEventHandler_.dispose();
this.mapBrowserEventHandler_ = null;
removeNode(this.viewport_);
}
// target may be undefined, null, a string or an Element.
// If it's a string we convert it to an Element before proceeding.
// If it's not now an Element we remove the viewport from the DOM.
// If it's an Element we append the viewport element to it.
const targetElement = this.getTargetElement();
if (!targetElement) {
if (this.renderer_) {
clearTimeout(this.postRenderTimeoutHandle_);
@@ -1217,10 +1203,11 @@ class PluggableMap extends BaseObject {
PASSIVE_EVENT_LISTENERS ? {passive: false} : false
);
const defaultView = this.getOwnerDocument().defaultView;
const keyboardEventTarget = !this.keyboardEventTarget_
? targetElement
: this.keyboardEventTarget_;
this.keyHandlerKeys_ = [
this.targetChangeHandlerKeys_ = [
listen(
keyboardEventTarget,
EventType.KEYDOWN,
@@ -1233,12 +1220,8 @@ class PluggableMap extends BaseObject {
this.handleBrowserEvent,
this
),
listen(defaultView, EventType.RESIZE, this.updateSize, this),
];
if (!this.handleResize_) {
this.handleResize_ = this.updateSize.bind(this);
window.addEventListener(EventType.RESIZE, this.handleResize_, false);
}
}
this.updateSize();

View File

@@ -3,8 +3,9 @@
*/
import Control from './Control.js';
import EventType from '../events/EventType.js';
import MapProperty from '../MapProperty.js';
import {CLASS_CONTROL, CLASS_UNSELECTABLE, CLASS_UNSUPPORTED} from '../css.js';
import {listen} from '../events.js';
import {listen, unlistenByKey} from '../events.js';
import {replaceNode} from '../dom.js';
const events = [
@@ -111,6 +112,12 @@ class FullScreen extends Control {
this.cssClassName_ =
options.className !== undefined ? options.className : 'ol-full-screen';
/**
* @private
* @type {Array<import("../events.js").EventsKey>}
*/
this.documentListeners_ = [];
/**
* @private
* @type {Array<string>}
@@ -157,7 +164,6 @@ class FullScreen extends Control {
this.button_ = document.createElement('button');
const tipLabel = options.tipLabel ? options.tipLabel : 'Toggle full-screen';
this.setClassName_(this.button_, isFullScreen());
this.button_.setAttribute('type', 'button');
this.button_.title = tipLabel;
this.button_.appendChild(this.labelNode_);
@@ -168,17 +174,8 @@ class FullScreen extends Control {
false
);
const cssClasses =
this.cssClassName_ +
' ' +
CLASS_UNSELECTABLE +
' ' +
CLASS_CONTROL +
' ' +
(!isFullScreenSupported() ? CLASS_UNSUPPORTED : '');
const element = this.element;
element.className = cssClasses;
element.appendChild(this.button_);
this.element.className = `${this.cssClassName_} ${CLASS_UNSELECTABLE} ${CLASS_CONTROL}`;
this.element.appendChild(this.button_);
/**
* @private
@@ -191,6 +188,17 @@ class FullScreen extends Control {
* @type {HTMLElement|string|undefined}
*/
this.source_ = options.source;
/**
* @type {boolean}
* @private
*/
this.isInFullscreen_ = false;
/**
* @private
*/
this.boundHandleMapTargetChange_ = this.handleMapTargetChange_.bind(this);
}
/**
@@ -206,21 +214,22 @@ class FullScreen extends Control {
* @private
*/
handleFullScreen_() {
if (!isFullScreenSupported()) {
return;
}
const map = this.getMap();
if (!map) {
return;
}
if (isFullScreen()) {
exitFullScreen();
const doc = map.getOwnerDocument();
if (!isFullScreenSupported(doc)) {
return;
}
if (isFullScreen(doc)) {
exitFullScreen(doc);
} else {
let element;
if (this.source_) {
element =
typeof this.source_ === 'string'
? document.getElementById(this.source_)
? doc.getElementById(this.source_)
: this.source_;
} else {
element = map.getTargetElement();
@@ -238,16 +247,20 @@ class FullScreen extends Control {
*/
handleFullScreenChange_() {
const map = this.getMap();
if (isFullScreen()) {
this.setClassName_(this.button_, true);
replaceNode(this.labelActiveNode_, this.labelNode_);
this.dispatchEvent(FullScreenEventType.ENTERFULLSCREEN);
} else {
this.setClassName_(this.button_, false);
replaceNode(this.labelNode_, this.labelActiveNode_);
this.dispatchEvent(FullScreenEventType.LEAVEFULLSCREEN);
if (!map) {
return;
}
if (map) {
const wasInFullscreen = this.isInFullscreen_;
this.isInFullscreen_ = isFullScreen(map.getOwnerDocument());
if (wasInFullscreen !== this.isInFullscreen_) {
this.setClassName_(this.button_, this.isInFullscreen_);
if (this.isInFullscreen_) {
replaceNode(this.labelActiveNode_, this.labelNode_);
this.dispatchEvent(FullScreenEventType.ENTERFULLSCREEN);
} else {
replaceNode(this.labelNode_, this.labelActiveNode_);
this.dispatchEvent(FullScreenEventType.LEAVEFULLSCREEN);
}
map.updateSize();
}
}
@@ -274,37 +287,76 @@ class FullScreen extends Control {
* @api
*/
setMap(map) {
const oldMap = this.getMap();
if (oldMap) {
oldMap.removeChangeListener(
MapProperty.TARGET,
this.boundHandleMapTargetChange_
);
}
super.setMap(map);
this.handleMapTargetChange_();
if (map) {
map.addChangeListener(
MapProperty.TARGET,
this.boundHandleMapTargetChange_
);
}
}
/**
* @private
*/
handleMapTargetChange_() {
const listeners = this.documentListeners_;
for (let i = 0, ii = listeners.length; i < ii; ++i) {
unlistenByKey(listeners[i]);
}
listeners.length = 0;
const map = this.getMap();
if (map) {
const doc = map.getOwnerDocument();
if (isFullScreenSupported(doc)) {
this.element.classList.remove(CLASS_UNSUPPORTED);
} else {
this.element.classList.add(CLASS_UNSUPPORTED);
}
for (let i = 0, ii = events.length; i < ii; ++i) {
this.listenerKeys.push(
listen(document, events[i], this.handleFullScreenChange_, this)
listeners.push(
listen(doc, events[i], this.handleFullScreenChange_, this)
);
}
this.handleFullScreenChange_();
}
}
}
/**
* @param {Document} doc The root document to check.
* @return {boolean} Fullscreen is supported by the current platform.
*/
function isFullScreenSupported() {
const body = document.body;
function isFullScreenSupported(doc) {
const body = doc.body;
return !!(
body['webkitRequestFullscreen'] ||
(body['msRequestFullscreen'] && document['msFullscreenEnabled']) ||
(body.requestFullscreen && document.fullscreenEnabled)
(body['msRequestFullscreen'] && doc['msFullscreenEnabled']) ||
(body.requestFullscreen && doc.fullscreenEnabled)
);
}
/**
* @param {Document} doc The root document to check.
* @return {boolean} Element is currently in fullscreen.
*/
function isFullScreen() {
function isFullScreen(doc) {
return !!(
document['webkitIsFullScreen'] ||
document['msFullscreenElement'] ||
document.fullscreenElement
doc['webkitIsFullScreen'] ||
doc['msFullscreenElement'] ||
doc.fullscreenElement
);
}
@@ -336,14 +388,15 @@ function requestFullScreenWithKeys(element) {
/**
* Exit fullscreen.
* @param {Document} doc The document to exit fullscren from
*/
function exitFullScreen() {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document['msExitFullscreen']) {
document['msExitFullscreen']();
} else if (document['webkitExitFullscreen']) {
document['webkitExitFullscreen']();
function exitFullScreen(doc) {
if (doc.exitFullscreen) {
doc.exitFullscreen();
} else if (doc['msExitFullscreen']) {
doc['msExitFullscreen']();
} else if (doc['webkitExitFullscreen']) {
doc['webkitExitFullscreen']();
}
}

View File

@@ -83,7 +83,9 @@ export const altShiftKeysOnly = function (mapBrowserEvent) {
* @api
*/
export const focus = function (event) {
return event.target.getTargetElement().contains(document.activeElement);
const targetElement = event.map.getTargetElement();
const activeElement = event.map.getOwnerDocument().activeElement;
return targetElement.contains(activeElement);
};
/**