Merge pull request #12893 from andrewcoder002/main
Allow map target to be an external window
This commit is contained in:
13
examples/external-map.html
Normal file
13
examples/external-map.html
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
layout: example.html
|
||||
title: External map
|
||||
shortdesc: Move a map to a seperate window.
|
||||
docs: >
|
||||
Move a map to a seperate window.
|
||||
tags: "external, window"
|
||||
sources:
|
||||
- path: resources/external-map-map.html
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<input id="external-map-button" type="button" value="Open external map"></input>
|
||||
<span id="blocker-notice" hidden>Could not open map in external window. If you are using a popup or ad blocker you may need to disable it for this example.</span>
|
||||
112
examples/external-map.js
Normal file
112
examples/external-map.js
Normal file
@@ -0,0 +1,112 @@
|
||||
import Map from '../src/ol/Map.js';
|
||||
import OSM from '../src/ol/source/OSM.js';
|
||||
import TileLayer from '../src/ol/layer/Tile.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import {
|
||||
Control,
|
||||
FullScreen,
|
||||
defaults as defaultControls,
|
||||
} from '../src/ol/control.js';
|
||||
import {fromLonLat} from '../src/ol/proj.js';
|
||||
|
||||
class UnusableMask extends Control {
|
||||
constructor() {
|
||||
super({
|
||||
element: document.createElement('div'),
|
||||
});
|
||||
this.element.setAttribute('hidden', 'hidden');
|
||||
this.element.className = 'ol-mask';
|
||||
this.element.innerHTML = '<div>Map not usable</div>';
|
||||
}
|
||||
}
|
||||
|
||||
const localMapTarget = document.getElementById('map');
|
||||
|
||||
const map = new Map({
|
||||
target: localMapTarget,
|
||||
controls: defaultControls().extend([new FullScreen(), new UnusableMask()]),
|
||||
layers: [
|
||||
new TileLayer({
|
||||
source: new OSM(),
|
||||
}),
|
||||
],
|
||||
view: new View({
|
||||
center: fromLonLat([37.41, 8.82]),
|
||||
zoom: 4,
|
||||
}),
|
||||
});
|
||||
|
||||
let mapWindow;
|
||||
function closeMapWindow() {
|
||||
if (mapWindow) {
|
||||
mapWindow.close();
|
||||
mapWindow = undefined;
|
||||
}
|
||||
}
|
||||
// Close external window in case the main page is closed or reloaded
|
||||
window.addEventListener('pagehide', closeMapWindow);
|
||||
|
||||
const button = document.getElementById('external-map-button');
|
||||
|
||||
function resetMapTarget() {
|
||||
localMapTarget.style.height = '';
|
||||
map.setTarget(localMapTarget);
|
||||
button.disabled = false;
|
||||
}
|
||||
|
||||
function updateOverlay() {
|
||||
if (!mapWindow) {
|
||||
return;
|
||||
}
|
||||
const externalMapTarget = mapWindow.document.getElementById('map');
|
||||
if (!externalMapTarget) {
|
||||
return;
|
||||
}
|
||||
if (document.visibilityState === 'visible') {
|
||||
// Show controls and enable keyboard input
|
||||
externalMapTarget.classList.remove('unusable');
|
||||
externalMapTarget.setAttribute('tabindex', '0');
|
||||
externalMapTarget.focus();
|
||||
} else {
|
||||
// Hide all controls and disable keyboard input
|
||||
externalMapTarget.removeAttribute('tabindex');
|
||||
externalMapTarget.classList.add('unusable');
|
||||
}
|
||||
}
|
||||
window.addEventListener('visibilitychange', updateOverlay);
|
||||
|
||||
button.addEventListener('click', function () {
|
||||
const blockerNotice = document.getElementById('blocker-notice');
|
||||
blockerNotice.setAttribute('hidden', 'hidden');
|
||||
button.disabled = true;
|
||||
|
||||
// Reset button and map target in case window did not load or open
|
||||
let timeoutKey = setTimeout(function () {
|
||||
closeMapWindow();
|
||||
resetMapTarget();
|
||||
blockerNotice.removeAttribute('hidden');
|
||||
timeoutKey = undefined;
|
||||
}, 3000);
|
||||
|
||||
mapWindow = window.open(
|
||||
'resources/external-map-map.html',
|
||||
'MapWindow',
|
||||
'toolbar=0,location=0,menubar=0,width=800,height=600'
|
||||
);
|
||||
mapWindow.addEventListener('DOMContentLoaded', function () {
|
||||
const externalMapTarget = mapWindow.document.getElementById('map');
|
||||
localMapTarget.style.height = '0px';
|
||||
map.setTarget(externalMapTarget);
|
||||
|
||||
if (timeoutKey) {
|
||||
timeoutKey = clearTimeout(timeoutKey);
|
||||
}
|
||||
mapWindow.addEventListener('pagehide', function () {
|
||||
resetMapTarget();
|
||||
// Close window in case user does a page reload
|
||||
closeMapWindow();
|
||||
});
|
||||
|
||||
updateOverlay();
|
||||
});
|
||||
});
|
||||
@@ -6,10 +6,12 @@ docs: >
|
||||
The map in this example is rendered in a web worker, using `OffscreenCanvas`. **Note:** This is currently only supported in Chrome and Edge.
|
||||
tags: "worker, offscreencanvas, vector-tiles"
|
||||
experimental: true
|
||||
sources:
|
||||
- path: offscreen-canvas.worker.js
|
||||
as: worker.js
|
||||
cloak:
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||
|
||||
---
|
||||
<div id="map" class="map">
|
||||
<pre id="info" class="info"/>
|
||||
|
||||
30
examples/resources/external-map-map.html
Normal file
30
examples/resources/external-map-map.html
Normal file
@@ -0,0 +1,30 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="../css/ol.css" type="text/css">
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
.map {
|
||||
height: 100%;
|
||||
}
|
||||
.map.unusable .ol-mask {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
user-select: none;
|
||||
background-color: rgba(0, 0, 0, .7);
|
||||
color: white;
|
||||
font: bold 3rem 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
}
|
||||
.map.unusable .ol-control {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map" class="map"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -211,13 +211,12 @@
|
||||
</html></code></pre>
|
||||
</div>
|
||||
|
||||
{{#if worker.source}}
|
||||
<div class="row-fluid">
|
||||
<h5 class="source-heading">worker.js</h5>
|
||||
<pre><code id="example-worker-source" class="language-js">{{ worker.source }}</code></pre>
|
||||
{{#each extraSources}}
|
||||
<div class="row-fluid extra-source">
|
||||
<h5 class="source-heading">{{./name}}</h5>
|
||||
<pre><code class="language-{{./type}}">{{ ./source }}</code></pre>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{/each}}
|
||||
<div class="row-fluid">
|
||||
<h5 class="source-heading">package.json</h5>
|
||||
<pre><code id="example-pkg-source" class="language-json">{{ pkgJson }}</code></pre>
|
||||
|
||||
@@ -13,7 +13,7 @@ const baseDir = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
const isCssRegEx = /\.css(\?.*)?$/;
|
||||
const isJsRegEx = /\.js(\?.*)?$/;
|
||||
const importRegEx = /^import .* from '(.*)';$/;
|
||||
const importRegEx = /(?:^|\n)import .* from '(.*)';(?:\n|$)/g;
|
||||
const isTemplateJs =
|
||||
/\/(jquery(-\d+\.\d+\.\d+)?|(bootstrap(\.bundle)?))(\.min)?\.js(\?.*)?$/;
|
||||
const isTemplateCss = /\/bootstrap(\.min)?\.css(\?.*)?$/;
|
||||
@@ -134,29 +134,21 @@ function createWordIndex(exampleData) {
|
||||
* @return {Object<string, string>} dependencies
|
||||
*/
|
||||
function getDependencies(jsSource, pkg) {
|
||||
const lines = jsSource.split('\n');
|
||||
const dependencies = {
|
||||
ol: pkg.version,
|
||||
};
|
||||
for (let i = 0, ii = lines.length; i < ii; ++i) {
|
||||
const line = lines[i];
|
||||
const importMatch = line.match(importRegEx);
|
||||
if (importMatch) {
|
||||
|
||||
let importMatch;
|
||||
while ((importMatch = importRegEx.exec(jsSource))) {
|
||||
const imp = importMatch[1];
|
||||
if (!imp.startsWith('ol/') && imp != 'ol') {
|
||||
const parts = imp.split('/');
|
||||
let dep;
|
||||
if (imp.startsWith('@')) {
|
||||
dep = parts.slice(0, 2).join('/');
|
||||
} else {
|
||||
dep = parts[0];
|
||||
}
|
||||
const dep = imp.startsWith('@') ? parts.slice(0, 2).join('/') : parts[0];
|
||||
if (dep in pkg.devDependencies) {
|
||||
dependencies[dep] = pkg.devDependencies[dep];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
@@ -279,80 +271,79 @@ export default class ExampleBuilder {
|
||||
data.jsSource = jsSource;
|
||||
|
||||
// process tags
|
||||
if (data.tags) {
|
||||
data.tags = data.tags.replace(/[\s"]+/g, '').split(',');
|
||||
} else {
|
||||
data.tags = [];
|
||||
}
|
||||
data.tags = data.tags ? data.tags.replace(/[\s"]+/g, '').split(',') : [];
|
||||
return data;
|
||||
}
|
||||
|
||||
transformJsSource(source) {
|
||||
return (
|
||||
source
|
||||
// remove "../src/" prefix and ".js" to have the same import syntax as the documentation
|
||||
.replace(/'\.\.\/src\//g, "'")
|
||||
.replace(/\.js';/g, "';")
|
||||
// Remove worker loader import and modify `new Worker()` to add source
|
||||
.replace(/import Worker from 'worker-loader![^\n]*\n/g, '')
|
||||
.replace('new Worker()', "new Worker('./worker.js', {type: 'module'})")
|
||||
);
|
||||
}
|
||||
|
||||
cloakSource(source, cloak) {
|
||||
if (cloak) {
|
||||
for (const entry of cloak) {
|
||||
source = source.replace(new RegExp(entry.key, 'g'), entry.value);
|
||||
}
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
async render(data) {
|
||||
const assets = {};
|
||||
const readOptions = {encoding: 'utf8'};
|
||||
|
||||
// add in script tag
|
||||
const jsName = `${data.name}.js`;
|
||||
|
||||
// remove "../src/" prefix and ".js" to have the same import syntax as the documentation
|
||||
let jsSource = data.jsSource.replace(/'\.\.\/src\//g, "'");
|
||||
jsSource = jsSource.replace(/\.js';/g, "';");
|
||||
if (data.cloak) {
|
||||
for (const entry of data.cloak) {
|
||||
jsSource = jsSource.replace(new RegExp(entry.key, 'g'), entry.value);
|
||||
}
|
||||
}
|
||||
// Remove worker loader import and modify `new Worker()` to add source
|
||||
jsSource = jsSource.replace(
|
||||
/import Worker from 'worker-loader![^\n]*\n/g,
|
||||
''
|
||||
const jsSource = this.transformJsSource(
|
||||
this.cloakSource(data.jsSource, data.cloak)
|
||||
);
|
||||
jsSource = jsSource.replace('new Worker()', "new Worker('./worker.js')");
|
||||
|
||||
data.js = {
|
||||
tag: `<script src="${this.common}.js"></script>
|
||||
<script src="${jsName}"></script>`,
|
||||
source: jsSource,
|
||||
};
|
||||
|
||||
// check for worker js
|
||||
const workerName = `${data.name}.worker.js`;
|
||||
const workerPath = path.join(data.dir, workerName);
|
||||
let workerSource;
|
||||
try {
|
||||
workerSource = await fse.readFile(workerPath, readOptions);
|
||||
} catch (err) {
|
||||
// pass
|
||||
let jsSources = jsSource;
|
||||
if (data.sources) {
|
||||
data.extraSources = await Promise.all(
|
||||
data.sources.map(async (sourceConfig) => {
|
||||
const fileName = sourceConfig.path;
|
||||
const extraSourcePath = path.join(data.dir, fileName);
|
||||
let source = await fse.readFile(extraSourcePath, readOptions);
|
||||
let ext = fileName.match(/\.(\w+)$/)[1];
|
||||
if (ext === 'mjs') {
|
||||
ext = 'js';
|
||||
}
|
||||
if (workerSource) {
|
||||
// remove "../src/" prefix and ".js" to have the same import syntax as the documentation
|
||||
workerSource = workerSource.replace(/'\.\.\/src\//g, "'");
|
||||
workerSource = workerSource.replace(/\.js';/g, "';");
|
||||
if (data.cloak) {
|
||||
for (const entry of data.cloak) {
|
||||
workerSource = workerSource.replace(
|
||||
new RegExp(entry.key, 'g'),
|
||||
entry.value
|
||||
);
|
||||
if (ext === 'js') {
|
||||
source = this.transformJsSource(source);
|
||||
jsSources += '\n' + source;
|
||||
}
|
||||
}
|
||||
data.worker = {
|
||||
source: workerSource,
|
||||
source = this.cloakSource(source, data.cloak);
|
||||
assets[fileName] = source;
|
||||
return {
|
||||
name: sourceConfig.as ?? fileName,
|
||||
source: source,
|
||||
type: ext,
|
||||
};
|
||||
assets[workerName] = workerSource;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const pkg = await getPackageInfo();
|
||||
|
||||
data.pkgJson = JSON.stringify(
|
||||
{
|
||||
name: data.name,
|
||||
dependencies: getDependencies(
|
||||
jsSource + (workerSource ? `\n${workerSource}` : ''),
|
||||
pkg
|
||||
),
|
||||
dependencies: getDependencies(jsSources, pkg),
|
||||
devDependencies: {
|
||||
parcel: '^2.0.0-beta.1',
|
||||
parcel: '^2.0.0',
|
||||
},
|
||||
scripts: {
|
||||
start: 'parcel index.html',
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
if (!map) {
|
||||
return;
|
||||
}
|
||||
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 {
|
||||
this.setClassName_(this.button_, false);
|
||||
replaceNode(this.labelNode_, this.labelActiveNode_);
|
||||
this.dispatchEvent(FullScreenEventType.LEAVEFULLSCREEN);
|
||||
}
|
||||
if (map) {
|
||||
map.updateSize();
|
||||
}
|
||||
}
|
||||
@@ -274,37 +287,76 @@ class FullScreen extends Control {
|
||||
* @api
|
||||
*/
|
||||
setMap(map) {
|
||||
super.setMap(map);
|
||||
if (map) {
|
||||
for (let i = 0, ii = events.length; i < ii; ++i) {
|
||||
this.listenerKeys.push(
|
||||
listen(document, events[i], this.handleFullScreenChange_, this)
|
||||
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) {
|
||||
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']();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -816,7 +816,7 @@ describe('ol/Map', function () {
|
||||
|
||||
it('removes window listeners', function () {
|
||||
map.dispose();
|
||||
expect(map.handleResize_).to.be(undefined);
|
||||
expect(map.targetChangeHandlerKeys_).to.be(null);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -828,7 +828,7 @@ describe('ol/Map', function () {
|
||||
map = new Map({
|
||||
target: document.createElement('div'),
|
||||
});
|
||||
expect(map.handleResize_).to.be.ok();
|
||||
expect(map.targetChangeHandlerKeys_).to.be.ok();
|
||||
});
|
||||
|
||||
describe('map with target not attached to dom', function () {
|
||||
@@ -840,7 +840,7 @@ describe('ol/Map', function () {
|
||||
describe('call setTarget with null', function () {
|
||||
it('unregisters the viewport resize listener', function () {
|
||||
map.setTarget(null);
|
||||
expect(map.handleResize_).to.be(undefined);
|
||||
expect(map.targetChangeHandlerKeys_).to.be(null);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -848,7 +848,7 @@ describe('ol/Map', function () {
|
||||
it('registers a viewport resize listener', function () {
|
||||
map.setTarget(null);
|
||||
map.setTarget(document.createElement('div'));
|
||||
expect(map.handleResize_).to.be.ok();
|
||||
expect(map.targetChangeHandlerKeys_).to.be.ok();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -877,8 +877,14 @@ describe('ol/Map', function () {
|
||||
hasAttribute: function (attribute) {
|
||||
return hasTabIndex;
|
||||
},
|
||||
contains: function () {
|
||||
return hasFocus;
|
||||
},
|
||||
};
|
||||
},
|
||||
getOwnerDocument: function () {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
originalEvent: {
|
||||
isPrimary: isPrimary,
|
||||
|
||||
Reference in New Issue
Block a user