UNPKG

@deephaven/golden-layout

Version:

A multi-screen javascript Layout manager

250 lines (238 loc) • 10.7 kB
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } import $ from 'jquery'; import { getUniqueId, minifyConfig, EventEmitter } from "../utils/index.js"; /** * Pops a content item out into a new browser window. * This is achieved by * * - Creating a new configuration with the content item as root element * - Serializing and minifying the configuration * - Opening the current window's URL with the configuration as a GET parameter * - GoldenLayout when opened in the new window will look for the GET parameter * and use it instead of the provided configuration * * @param config GoldenLayout item config * @param dimensions A map with width, height, top and left * @param parentId The id of the element the item will be appended to on popIn * @param indexInParent The position of this element within its parent * @param layoutManager */ export default class BrowserPopout extends EventEmitter { constructor(config, dimensions, parentId, indexInParent, layoutManager) { super(); _defineProperty(this, "isInitialised", false); _defineProperty(this, "_config", void 0); _defineProperty(this, "_dimensions", void 0); _defineProperty(this, "_parentId", void 0); _defineProperty(this, "_indexInParent", void 0); _defineProperty(this, "_layoutManager", void 0); _defineProperty(this, "_popoutWindow", null); _defineProperty(this, "_id", null); this._config = config; this._dimensions = dimensions; this._parentId = parentId; this._indexInParent = indexInParent; this._layoutManager = layoutManager; this._createWindow(); } toConfig() { var _this$getGlInstance, _this$getGlInstance2, _ref, _this$_popoutWindow$s, _this$_popoutWindow, _this$_popoutWindow2, _ref2, _this$_popoutWindow$s2, _this$_popoutWindow3, _this$_popoutWindow4, _this$getGlInstance3; if (this.isInitialised === false) { throw new Error("Can't create config, layout not yet initialised"); } return { dimensions: { width: (_this$getGlInstance = this.getGlInstance()) === null || _this$getGlInstance === void 0 ? void 0 : _this$getGlInstance.width, height: (_this$getGlInstance2 = this.getGlInstance()) === null || _this$getGlInstance2 === void 0 ? void 0 : _this$getGlInstance2.height, left: (_ref = (_this$_popoutWindow$s = (_this$_popoutWindow = this._popoutWindow) === null || _this$_popoutWindow === void 0 ? void 0 : _this$_popoutWindow.screenX) !== null && _this$_popoutWindow$s !== void 0 ? _this$_popoutWindow$s : (_this$_popoutWindow2 = this._popoutWindow) === null || _this$_popoutWindow2 === void 0 ? void 0 : _this$_popoutWindow2.screenLeft) !== null && _ref !== void 0 ? _ref : 0, top: (_ref2 = (_this$_popoutWindow$s2 = (_this$_popoutWindow3 = this._popoutWindow) === null || _this$_popoutWindow3 === void 0 ? void 0 : _this$_popoutWindow3.screenY) !== null && _this$_popoutWindow$s2 !== void 0 ? _this$_popoutWindow$s2 : (_this$_popoutWindow4 = this._popoutWindow) === null || _this$_popoutWindow4 === void 0 ? void 0 : _this$_popoutWindow4.screenTop) !== null && _ref2 !== void 0 ? _ref2 : 0 }, content: (_this$getGlInstance3 = this.getGlInstance()) === null || _this$getGlInstance3 === void 0 ? void 0 : _this$getGlInstance3.toConfig().content, parentId: this._parentId, indexInParent: this._indexInParent }; } getGlInstance() { var _this$_popoutWindow5; return (_this$_popoutWindow5 = this._popoutWindow) === null || _this$_popoutWindow5 === void 0 ? void 0 : _this$_popoutWindow5.__glInstance; } getWindow() { return this._popoutWindow; } close() { if (this.getGlInstance()) { var _this$getGlInstance4; (_this$getGlInstance4 = this.getGlInstance()) === null || _this$getGlInstance4 === void 0 || _this$getGlInstance4._$closeWindow(); } else { try { var _this$getWindow; (_this$getWindow = this.getWindow()) === null || _this$getWindow === void 0 || _this$getWindow.close(); } catch (e) {} } } /** * Returns the popped out item to its original position. If the original * parent isn't available anymore it falls back to the layout's topmost element */ popIn() { var _parentItem; var index = this._indexInParent; var childConfig = null; var parentItem = null; if (this._parentId) { var _this$getGlInstance5; /* * The $.extend call seems a bit pointless, but it's crucial to * copy the config returned by this.getGlInstance().toConfig() * onto a new object. Internet Explorer keeps the references * to objects on the child window, resulting in the following error * once the child window is closed: * * The callee (server [not server application]) is not available and disappeared */ childConfig = $.extend(true, {}, (_this$getGlInstance5 = this.getGlInstance()) === null || _this$getGlInstance5 === void 0 ? void 0 : _this$getGlInstance5.toConfig()).content[0]; parentItem = this._layoutManager.root.getItemsById(this._parentId)[0]; /* * Fallback if parentItem is not available. Either add it to the topmost * item or make it the topmost item if the layout is empty */ if (!parentItem) { var _this$_layoutManager$; if (((_this$_layoutManager$ = this._layoutManager.root.contentItems.length) !== null && _this$_layoutManager$ !== void 0 ? _this$_layoutManager$ : 0) > 0) { parentItem = this._layoutManager.root.contentItems[0]; } else { parentItem = this._layoutManager.root; } index = 0; } } if (!childConfig) { return; } (_parentItem = parentItem) === null || _parentItem === void 0 || _parentItem.addChild(childConfig, this._indexInParent); this.close(); } /** * Creates the URL and window parameter * and opens a new window */ _createWindow() { var url = this._createUrl(); /** * Bogus title to prevent re-usage of existing window with the * same title. The actual title will be set by the new window's * GoldenLayout instance if it detects that it is in subWindowMode */ var title = Math.floor(Math.random() * 1000000).toString(36); /** * The options as used in the window.open string */ var options = this._serializeWindowOptions({ width: this._dimensions.width, height: this._dimensions.height, innerWidth: this._dimensions.width, innerHeight: this._dimensions.height, menubar: 'no', toolbar: 'no', location: 'no', personalbar: 'no', resizable: 'yes', scrollbars: 'no', status: 'no' }); // I'm not entirely sure how __glInstance is mounted to the popout window this._popoutWindow = window.open(url, title, options); if (!this._popoutWindow) { if (this._layoutManager.config.settings.blockedPopoutsThrowError === true) { var error = new Error('Popout blocked'); error.type = 'popoutBlocked'; throw error; } else { return; } } $(this._popoutWindow).on('load', this._positionWindow.bind(this)).on('unload beforeunload', this._onClose.bind(this)); /** * Polling the childwindow to find out if GoldenLayout has been initialised * doesn't seem optimal, but the alternatives - adding a callback to the parent * window or raising an event on the window object - both would introduce knowledge * about the parent to the child window which we'd rather avoid */ var checkReadyInterval = window.setInterval(() => { var _this$_popoutWindow6; if ((_this$_popoutWindow6 = this._popoutWindow) !== null && _this$_popoutWindow6 !== void 0 && _this$_popoutWindow6.__glInstance && this._popoutWindow.__glInstance.isInitialised) { this._onInitialised(); window.clearInterval(checkReadyInterval); } }, 10); } /** * Serialises a map of key:values to a window options string * * @param windowOptions * * @returns serialised window options */ _serializeWindowOptions(windowOptions) { var windowOptionsString = [], key; for (key in windowOptions) { windowOptionsString.push(key + '=' + windowOptions[key]); } return windowOptionsString.join(','); } /** * Creates the URL for the new window, including the * config GET parameter * * @returns URL */ _createUrl() { var config = { content: this._config }; var storageKey = 'gl-window-config-' + getUniqueId(); config = minifyConfig(config); try { localStorage.setItem(storageKey, JSON.stringify(config)); } catch (e) { throw new Error('Error while writing to localStorage ' + e.toString()); } var urlParts = document.location.href.split('?'); // URL doesn't contain GET-parameters if (urlParts.length === 1) { return urlParts[0] + '?gl-window=' + storageKey; // URL contains GET-parameters } else { return document.location.href + '&gl-window=' + storageKey; } } /** * Move the newly created window roughly to * where the component used to be. */ _positionWindow() { var _this$_popoutWindow7, _this$_popoutWindow8; (_this$_popoutWindow7 = this._popoutWindow) === null || _this$_popoutWindow7 === void 0 || _this$_popoutWindow7.moveTo(this._dimensions.left, this._dimensions.top); (_this$_popoutWindow8 = this._popoutWindow) === null || _this$_popoutWindow8 === void 0 || _this$_popoutWindow8.focus(); } /** * Callback when the new window is opened and the GoldenLayout instance * within it is initialised */ _onInitialised() { var _this$getGlInstance6; this.isInitialised = true; (_this$getGlInstance6 = this.getGlInstance()) === null || _this$getGlInstance6 === void 0 || _this$getGlInstance6.on('popIn', this.popIn, this); this.emit('initialised'); } /** * Invoked 50ms after the window unload event */ _onClose() { setTimeout(this.emit.bind(this, 'closed'), 50); } } //# sourceMappingURL=BrowserPopout.js.map