UNPKG

@jswf/core

Version:

JavaScript Window Framework

1,466 lines (1,465 loc) 52.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /* eslint-disable @typescript-eslint/class-name-casing */ /* eslint-disable no-dupe-class-members */ require("../scss/Window.scss"); var WindowManager_1 = require("./WindowManager"); //各サイズ var FRAME_SIZE = 10; //フレーム枠のサイズ var TITLE_SIZE = 24; //タイトルバーのサイズ /** *ウインドウ基本クラス * * @export * @class Window */ var BaseView = /** @class */ (function () { /** * Creates an instance of Window. * @param {{ frame?: boolean, title?: boolean, layer?: number}} [params] ウインドウ作成用パラメータ * { frame?:boolean, * title?:boolean, * layer?:number * } * @memberof Window */ function BaseView(params) { var _this = this; this.removers = []; this.listeners = {}; this.JData = { x: 0, y: 0, width: 400, height: 300, frameSize: 0, titleSize: 0, redraw: true, parent: null, orderTop: false, orderLayer: 0, layoutFlag: false, clientArea: null, style: null, visible: true, minimize: false, normalX: 0, normalY: 0, normalWidth: 0, normalHeight: 0, margin: { x1: 0, y1: 0, x2: 0, y2: 0 }, padding: { x1: 0, y1: 0, x2: 0, y2: 0 }, moveable: false, reshow: true, noActive: false, animation: {}, animationEnable: true, autoSizeNode: null, instructionSize: { width: -1, height: -1 } }; //ウインドウ用ノードの作成 var hNode = document.createElement("DIV"); hNode.Jwf = this; this.hNode = hNode; hNode.dataset.jwf = "Window"; hNode.dataset.jwfWindowName = this.constructor.name; //位置を絶対位置指定 hNode.style.zIndex = "10000"; hNode.style.position = "absolute"; hNode.style.visibility = "hidden"; //クライアント領域を作成 var client = document.createElement("div"); this.JData.clientArea = client; client.dataset.jwfType = "client"; hNode.appendChild(client); //パラメータに従いウインドウの作成 if (params) { if (params.frame) { this.addFrame(params.title == null ? true : params.title); if (params.layer == null) this.setOrderLayer(10); if (params.overlap == null) this.setOverlap(true); this.JData.animation["show"] = "JWFFrameShow 0.5s ease 0s 1 normal"; this.JData.animation["close"] = "JWFclose 0.2s ease 0s 1 forwards"; this.JData.animation["maximize"] = "JWFmaximize 0.2s ease 0s 1 forwards"; this.JData.animation["minimize"] = "JWFminimize 0.2s ease 0s 1 forwards"; this.JData.animation["maxrestore"] = "JWFmaxrestore 0.2s ease 0s 1 forwards"; this.JData.animation["restore"] = "JWFrestore 0.2s ease 0s 1 forwards"; } if (params.layer) { this.setOrderLayer(params.layer); } if (params.overlap) { this.setOverlap(params.overlap); } if (params.visible === false) { this.hNode.style.visibility = "hidden"; this.JData.visible = false; } } hNode.addEventListener("animationend", function () { _this.layout(); }); //移動に備えて、必要な情報を収集 hNode.addEventListener("touchstart", this.onMouseDown.bind(this), { passive: false }); hNode.addEventListener("mousedown", this.onMouseDown.bind(this)); hNode.addEventListener("move", this.onMouseMove.bind(this)); //タイトルバーアイコンの機能設定 hNode.addEventListener("JWFclose", this.close.bind(this)); hNode.addEventListener("JWFmax", this.setMaximize.bind(this, true)); hNode.addEventListener("JWFnormal", this.setMaximize.bind(this, false)); hNode.addEventListener("JWFmin", this.setMinimize.bind(this, true)); hNode.addEventListener("JWFrestore", this.setMinimize.bind(this, false)); //ノードを本文へ追加 document.body.appendChild(hNode); //表示 this.show(true); //更新要求 this.layout(); //新規ウインドウをフォアグラウンドにする this.foreground(false); } BaseView.prototype.setOverlap = function (flag) { this.hNode.style.position = flag ? "fixed" : "absolute"; }; BaseView.prototype.isOverlap = function () { return this.hNode.style.position === "fixed"; }; BaseView.prototype.setJwfStyle = function (style) { this.getClient().dataset.jwfStyle = style; }; BaseView.prototype.getJwfStyle = function () { return this.getNode().dataset.jwfStyle || null; }; BaseView.prototype.setWindowId = function (id) { this.getNode().dataset.jwfId = id; }; // public static findWindow<T extends BaseView>( // win: {new ():T} // ): T | undefined { // const windows = this.findWindows(win.name); // if (windows.length) return windows[0] as T; // return undefined; // } BaseView.findWindow = function (windowName) { var windows = this.findWindows(windowName); if (windows.length) return windows[0]; return undefined; }; BaseView.findWindows = function (windowName) { var elements = document.querySelectorAll("[data-jwf=Window][data-jwf-window-name=" + windowName + "]"); var views = []; for (var length_1 = elements.length, i = 0; i < length_1; i++) { var node = elements[i]; views.push(node.Jwf); } return views; }; //フレーム追加処理 BaseView.prototype.addFrame = function (titleFlag) { this.getClient().dataset.jwfClient = "true"; this.hNode.dataset.jwfType = "Frame"; //タイトルの設定 this.JData.titleSize = titleFlag ? TITLE_SIZE : 0; this.hNode.style.minHeight = this.JData.titleSize + "px"; //各パーツのスタイル設定 var frameStyles = [ [ "border", "cursor:n-resize; left:0px;top:-{0}px;right:0px;height:{0}px;" ], [ "border", "cursor:e-resize; top:0px;right:-{0}px;bottom:0px;width:{0}px;" ], [ "border", "cursor:s-resize; left:0px;right:0px;height:{0}px;bottom:-{0}px;" ], [ "border", "cursor:w-resize; top:0px;left:-{0}px;bottom:0px;width:{0}px;" ], [ "border", "cursor:nw-resize;left:-{0}px;top:-{0}px;width:{0}px;height:{0}px;" ], [ "border", "cursor:ne-resize;right:-{0}px;top:-{0}px;width:{0}px;height:{0}px;" ], [ "border", "cursor:sw-resize;left:-{0}px;bottom:-{0}px;width:{0}px;height:{0}px;" ], [ "border", "cursor:se-resize;right:-{0}px;bottom:-{0}px;width:{0}px;height:{0}px;" ], ["title", "left:0px;top:0px;right:0px;height:{1}px"] //タイトル ]; //フレームクリックイベントの処理 function onFrame() { if (WindowManager_1.WindowManager.frame == null) WindowManager_1.WindowManager.frame = this.dataset.index != null ? parseInt(this.dataset.index) : null; //EDGEはここでイベントを止めないとテキスト選択が入る //if (WindowManager.frame < 9) // if (e.preventDefault) e.preventDefault(); else e.returnValue = false } //フレームとタイトル、クライアント領域の作成 for (var i = 0; i < frameStyles.length; i++) { var frame = document.createElement("div"); frame.style.cssText = frameStyles[i][1] .replace(/\{0\}/g, FRAME_SIZE.toString()) .replace(/\{1\}/g, this.JData.titleSize.toString()); frame.dataset.index = i.toString(); frame.dataset.jwfType = frameStyles[i][0]; this.hNode.appendChild(frame); frame.addEventListener("touchstart", onFrame, { passive: false }); frame.addEventListener("touchend", function () { WindowManager_1.WindowManager.frame = null; }, { passive: false }); frame.addEventListener("mousedown", onFrame, false); frame.addEventListener("mouseup", function () { WindowManager_1.WindowManager.frame = null; }, false); } this.JData.frameSize = 1; this.getClient().style.top = this.JData.titleSize + "px"; var node = this.hNode; //タイトルバーの作成 var title = node.childNodes[9]; var titleText = WindowManager_1.WindowManager.createElement("div", { dataset: { jwfType: "text" } }); title.appendChild(titleText); //アイコンの作成 var icons = ["min", "max", "close"]; for (var index in icons) { var icon = WindowManager_1.WindowManager.createElement("div", { style: { width: this.JData.titleSize + "px", height: this.JData.titleSize + "px" }, dataset: { jwfType: "icon", jwfKind: icons[index] } }); title.appendChild(icon); icon.addEventListener("click", function () { WindowManager_1.WindowManager.callEvent(node, "JWF" + this.dataset.jwfKind); }); } }; BaseView.prototype.onMouseDown = function (e) { if (WindowManager_1.WindowManager.moveNode == null) { this.foreground(); WindowManager_1.WindowManager.moveNode = this.hNode; var p = WindowManager_1.WindowManager.getPos(e); WindowManager_1.WindowManager.baseX = p.x; WindowManager_1.WindowManager.baseY = p.y; WindowManager_1.WindowManager.nodeX = this.getPosX(); WindowManager_1.WindowManager.nodeY = this.getPosY(); WindowManager_1.WindowManager.nodeWidth = this.getWidth(); WindowManager_1.WindowManager.nodeHeight = this.getHeight(); e.stopPropagation(); return false; } else { e.preventDefault(); } }; BaseView.prototype.onMouseMove = function (e) { if (WindowManager_1.WindowManager.frame == null) return; var p = e.params; var x = this.getPosX(); var y = this.getPosY(); var width = this.getWidth(); var height = this.getHeight(); //選択されている場所によって挙動を変える var frameIndex = WindowManager_1.WindowManager.frame; switch (frameIndex) { case 0: //上 y = p.nodePoint.y + p.nowPoint.y - p.basePoint.y; height = WindowManager_1.WindowManager.nodeHeight - (p.nowPoint.y - p.basePoint.y); break; case 1: //右 width = WindowManager_1.WindowManager.nodeWidth + (p.nowPoint.x - p.basePoint.x); break; case 2: //下 height = WindowManager_1.WindowManager.nodeHeight + (p.nowPoint.y - p.basePoint.y); break; case 3: //左 x = p.nodePoint.x + p.nowPoint.x - p.basePoint.x; width = WindowManager_1.WindowManager.nodeWidth - (p.nowPoint.x - p.basePoint.x); break; case 4: //左上 x = p.nodePoint.x + p.nowPoint.x - p.basePoint.x; y = p.nodePoint.y + p.nowPoint.y - p.basePoint.y; width = WindowManager_1.WindowManager.nodeWidth - (p.nowPoint.x - p.basePoint.x); height = WindowManager_1.WindowManager.nodeHeight - (p.nowPoint.y - p.basePoint.y); break; case 5: //右上 y = p.nodePoint.y + p.nowPoint.y - p.basePoint.y; width = WindowManager_1.WindowManager.nodeWidth + (p.nowPoint.x - p.basePoint.x); height = WindowManager_1.WindowManager.nodeHeight - (p.nowPoint.y - p.basePoint.y); break; case 6: //左下 x = p.nodePoint.x + p.nowPoint.x - p.basePoint.x; width = WindowManager_1.WindowManager.nodeWidth - (p.nowPoint.x - p.basePoint.x); height = WindowManager_1.WindowManager.nodeHeight + (p.nowPoint.y - p.basePoint.y); break; case 7: //右下 width = WindowManager_1.WindowManager.nodeWidth + (p.nowPoint.x - p.basePoint.x); height = WindowManager_1.WindowManager.nodeHeight + (p.nowPoint.y - p.basePoint.y); break; case 8: //タイトル x = p.nodePoint.x + p.nowPoint.x - p.basePoint.x; y = p.nodePoint.y + p.nowPoint.y - p.basePoint.y; break; default: //クライアント領域 if (!this.JData.moveable) break; } //位置とサイズの設定 this.setPos(x, y); this.setSize(width, height); //移動フレーム処理時はイベントを止める if (frameIndex < 9 || this.JData.moveable) { p.event.preventDefault(); try { var selection = window.getSelection(); if (selection) selection.removeAllRanges(); } catch (e) { // } } }; BaseView.prototype.addRemover = function () { var remover = []; for (var _i = 0; _i < arguments.length; _i++) { remover[_i] = arguments[_i]; } if (!remover) return; var removers = this.removers; for (var _a = 0, remover_1 = remover; _a < remover_1.length; _a++) { var r = remover_1[_a]; if (removers.indexOf(r) === -1) removers.push(r); } }; /** *イベントの受け取り * * @param {string} type イベントタイプ * @param {*} listener コールバックリスナー * @memberof Window */ // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility BaseView.prototype.addEventListener = function (name, proc) { var listener = this.listeners[name]; if (!listener) { this.listeners[name] = [proc]; return; } if (listener.indexOf(proc) >= 0) return; listener.push(proc); }; /** *イベントの削除 * * @template K * @param {(K | string)} type イベントタイプ * @param {(this: BaseView, ev: WINDOW_EVENT_MAP[K]) => unknown} listener コールバックリスナー * @memberof Window */ // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility BaseView.prototype.removeEventListener = function (name, proc) { var listener = this.listeners[name]; if (!listener) { this.listeners[name] = [proc]; return; } var index = listener.indexOf(proc); if (index < 0) return; listener.splice(index, 1); }; // /** *イベントの要求 * * @param {string} type イベントタイプ * @param {*} params パラメータ * @memberof Window */ BaseView.prototype.callEvent = function (name) { var params = []; for (var _i = 1; _i < arguments.length; _i++) { params[_i - 1] = arguments[_i]; } var listener = this.listeners[name]; if (listener) { for (var _a = 0, listener_1 = listener; _a < listener_1.length; _a++) { var proc = listener_1[_a]; proc.apply(void 0, params); } } }; /** *ウインドウのノードを得る * * @returns {HTMLElement} ウインドウノード * @memberof Window */ BaseView.prototype.getNode = function () { return this.hNode; }; /** *ウインドウの移動 * * @param {number} x * @param {number} y * @memberof Window */ BaseView.prototype.movePos = function (x, y) { this.JData.x = this.JData.x + x; this.JData.y = this.JData.y + y; this.layout(); }; BaseView.prototype.setNoActive = function (flag) { this.JData.noActive = flag; }; /** *ウインドウの位置設定 *引数を省略した場合は親のサイズを考慮して中央へ * @param {number} [x] * @param {number} [y] * @memberof Window */ BaseView.prototype.setPos = function (x, y) { if (x == null) { var parentWidth = this.getParentWidth2(); var width = this.getWidth(); if (parentWidth < width) x = 0; else x = (parentWidth - width) / 2; var parent_1 = this.getParent(); if (this.getNode().style.position === "fixed" && parent_1) x += parent_1.getPosX(); } if (y == null) { var parentHeight = this.getParentHeight2(); var height = this.getHeight(); if (parentHeight < height) y = 0; else y = (parentHeight - height) / 2; var parent_2 = this.getParent(); if (this.getNode().style.position === "fixed" && parent_2) y += parent_2.getPosY(); } if (this.JData.x === x && this.JData.y === y) return; this.JData.x = x; this.JData.y = y; this.layout(); }; BaseView.prototype.getNearFrame = function () { var win = this; do { if (win.hNode.dataset.jwfType === "Frame") return win; } while ((win = win.getParent())); return null; }; /** *X座標の設定 * * @param {number} x * @memberof Window */ BaseView.prototype.setPosX = function (x) { if (this.JData.x === x) return; this.JData.x = x; this.layout(); }; /** *Y座標の設定 * * @param {number} y * @memberof Window */ BaseView.prototype.setPosY = function (y) { if (this.JData.y === y) return; this.JData.y = y; this.layout(); }; /** *親ウインドウの取得 * * @returns {BaseView} 親ウインドウ * @memberof Window */ BaseView.prototype.getParent = function () { return this.JData.parent; }; /** *クライアント領域のドラッグによる移動の許可 * * @param {boolean} moveable true:許可 false:不許可 * @memberof Window */ BaseView.prototype.setMoveable = function (moveable) { this.JData.moveable = moveable; }; /** *X座標を返す * * @returns {number} * @memberof Window */ BaseView.prototype.getPosX = function () { return this.JData.x; }; /** *Y座標を返す * * @returns {number} * @memberof Window */ BaseView.prototype.getPosY = function () { return this.JData.y; }; /** *ウインドウの幅を返す * * @returns * @memberof Window */ BaseView.prototype.getWidth = function () { return this.JData.width; }; /** *ウインドウの高さを返す * * @returns * @memberof Window */ BaseView.prototype.getHeight = function () { return this.JData.height; }; /** *ウインドウサイズの設定 * * @param {number} width * @param {number} height * @memberof Window */ BaseView.prototype.setSize = function (width, height) { if (this.JData.width === width && this.JData.height === height) return; var parent = this.getParent(); if (parent) { parent.layout(); } this.JData.width = width; this.JData.height = height; this.layout(); }; /** *ウインドウの幅の設定 * * @param {number} width * @memberof Window */ BaseView.prototype.setWidth = function (width) { if (this.JData.width === width) return; this.JData.width = width; this.layout(); var parent = this.getParent(); if (parent) parent.layout(); }; /** *ウインドウの高さの設定 * * @param {number} height * @memberof Window */ BaseView.prototype.setHeight = function (height) { if (this.JData.height === height) return; this.JData.height = height; var parent = this.getParent(); if (parent) parent.layout(); }; // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility BaseView.prototype.setPadding = function (p1, p2, p3, p4) { if (typeof p2 === "undefined") { this.JData.padding.x1 = p1; this.JData.padding.y1 = p1; this.JData.padding.x2 = p1; this.JData.padding.y2 = p1; } else if (typeof p3 !== "undefined" && typeof p4 !== "undefined") { this.JData.padding.x1 = p1; this.JData.padding.y1 = p2; this.JData.padding.x2 = p3; this.JData.padding.y2 = p4; } }; // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility BaseView.prototype.setMargin = function (p1, p2, p3, p4) { if (typeof p2 === "undefined") { this.JData.margin.x1 = p1; this.JData.margin.y1 = p1; this.JData.margin.x2 = p1; this.JData.margin.y2 = p1; } else if (typeof p3 !== "undefined" && typeof p4 !== "undefined") { this.JData.margin.x1 = p1; this.JData.margin.y1 = p2; this.JData.margin.x2 = p3; this.JData.margin.y2 = p4; } }; /** *ウインドウの可視状態の取得 * * @returns {boolean} * @memberof Window */ BaseView.prototype.isVisible = function () { if (!this.JData.visible) return false; var parent = this.getParent(); if (!parent) return false; while ((parent = parent.getParent())) { if (!parent.isVisible()) return false; } return true; }; /** *ウインドウの可視状態の設定 * * @param {boolean} flag * @memberof Window */ BaseView.prototype.setVisible = function (flag) { var _this = this; var node = this.getNode(); if (!node.parentNode) { document.body.appendChild(node); } else if (this.JData.visible === flag) return; if (flag) this.hNode.style.visibility = ""; if (flag) { node.style.display = ""; var animation = this.JData.animationEnable ? this.JData.animation["show"] : ""; var animationEnd_1 = function () { _this.callEvent("visibled", { visible: true }); node.removeEventListener("animationend", animationEnd_1); node.style.animation = ""; node.style.display = ""; }; if (animation) { node.addEventListener("animationend", animationEnd_1); node.style.animation = animation; } else { node.style.animation = ""; animationEnd_1.bind(node)(); } } else { var animationEnd_2 = function () { var nodes = node.querySelectorAll('[data-jwf="Window"]'); var count = nodes.length; for (var i = 0; i < count; i++) { nodes[i].Jwf.layout(); } node.style.display = "none"; node.removeEventListener("animationend", animationEnd_2); node.style.animation = ""; _this.callEvent("visibled", { visible: false }); }; var animation = this.JData.animationEnable ? this.JData.animation["close"] : ""; var parent_3 = this.getParent(); if (animation && parent_3 && parent_3.isVisible()) { node.addEventListener("animationend", animationEnd_2); node.style.animation = animation; } else { animationEnd_2.bind(node)(); } } this.JData.visible = flag; var parent = this.getParent(); if (parent) parent.layout(); }; /** *ウインドウの重ね合わせを最上位に設定 * * @param {boolean} flag * @memberof Window */ BaseView.prototype.setOrderTop = function (flag) { this.JData.orderTop = flag; var parent = this.getParent(); if (parent) parent.layout(); }; /** *ウインドウの重ね合わせ順位の設定 *値が大きいほど上位 * @param {number} level デフォルト:0 FrameWindow:10 * @memberof Window */ BaseView.prototype.setOrderLayer = function (level) { this.JData.orderLayer = level; }; /** *レイアウトの再構成要求 * * @memberof Window */ BaseView.prototype.layout = function () { if (this.JData.layoutFlag) return; this.JData.layoutFlag = true; this.JData.redraw = true; WindowManager_1.WindowManager.layout(false); this.JData.layoutFlag = false; }; /** *ウインドウをアクティブにする(重ね合わせ順序は変更しない) * * @param {boolean} [flag] * @memberof Window */ BaseView.prototype.active = function (flag) { if (!this.JData.noActive) this.getNode().dataset.jwfActive = flag || flag == null ? "true" : "false"; }; /** *親のクライアント領域を返す * * @returns * @memberof Window */ BaseView.prototype.getParentWidth = function () { var node = this.hNode; if (node.style.position === "fixed") return window.innerWidth; var parent = node.parentNode; if (parent.Jwf) return parent.Jwf.getWidth(); return parent.offsetWidth; }; BaseView.prototype.getParentWidth2 = function () { var parent = this.getParent(); if (parent) return parent.getWidth(); return window.innerWidth; }; /** *親のクライアント領域を返す * * @returns * @memberof Window */ BaseView.prototype.getParentHeight = function () { var node = this.hNode; if (node.style.position === "fixed") return window.innerHeight; var parent = node.parentNode; if (parent.Jwf) return parent.Jwf.getHeight(); return parent.offsetHeight; }; BaseView.prototype.getParentHeight2 = function () { var parent = this.getParent(); if (parent) return parent.getHeight(); return window.innerHeight; }; /** *子ウインドウのサイズを再計算 * * @param {boolean} flag true:強制再計算 false:必要があれば再計算 * @returns {boolean} 再計算の必要を行ったかどうか * @memberof Window */ BaseView.prototype.onMeasure = function (flag) { var jdata = this.JData; //表示状態の更新 if (jdata.reshow || flag) { jdata.reshow = false; if (jdata.visible) { this.hNode.style.visibility = ""; var animation = jdata.animationEnable ? jdata.animation["show"] : ""; if (animation) this.hNode.style.animation = animation; } } var client = this.getClient(); // for (let i = 0, length = client.childNodes.length; i < length; i++) { // let node = client.childNodes[i] as JNode; // if (node.dataset && node.dataset.jwf === "Window") // flag = node.Jwf.onMeasure(flag) || flag; // } // if (!flag && !jdata.redraw) return false; if (!this.isAutoSize()) return false; this.callEvent("measure"); //client.style.position = "static"; if (jdata.instructionSize.width >= 0) client.style.width = jdata.instructionSize.width + "px"; else client.style.removeProperty("widht"); if (jdata.instructionSize.height >= 0) client.style.height = jdata.instructionSize.height + "px"; else client.style.removeProperty("height"); var width = 0; var height = 0; var childNodes = client.childNodes; for (var i = childNodes.length - 1; i >= 0; i--) { var child = childNodes[i]; var style = window.getComputedStyle(child); width = Math.max(width, child.offsetLeft + child.offsetWidth + parseInt(style.marginRight)); height = Math.max(height, child.offsetTop + child.offsetHeight + parseInt(style.marginBottom)); } var clientWidth = this.getClientWidth(); var clientHeight = this.getClientHeight(); //client.style.position = "absolute"; if ((jdata.instructionSize.width !== -1 && width > clientWidth) || (jdata.instructionSize.height !== -1 && height > clientHeight) || (jdata.instructionSize.width === -1 && width !== clientWidth) || (jdata.instructionSize.height === -1 && height !== clientHeight)) { this.setClientSize(width, height); // console.log("0 %d/%d %d/%d", width, clientWidth, height, clientHeight); // this.setClientSize(width, height); // const clientWidth2 = this.getClientWidth(); // const clientHeight2 = this.getClientHeight(); // console.log("1 %d/%d %d/%d", width, clientWidth2, height, clientHeight2); return true; } return false; }; /** *位置やサイズの確定処理 *非同期で必要なときに呼び出されるので、基本的には直接呼び出さないこと * @param {boolean} flag true:強制 false:必要なら * @memberof Window */ BaseView.prototype.onLayout = function (flag) { if (flag || this.JData.redraw) { var JData = this.JData; if (this.isOverlap()) { var pwidth = window.innerWidth; var pheight = window.innerHeight; if (JData.width > pwidth) JData.width = pwidth; if (JData.height > pheight) JData.height = pheight; if (JData.x < 0) JData.x = 0; if (JData.y < 0) JData.y = 0; if (JData.x + JData.width > pwidth) JData.x = pwidth - JData.width; if (JData.y + JData.height > pheight) JData.y = pheight - JData.height; } //this.onMeasure(false); //直下の子リスト if (this.hNode.dataset.jwfStat == "maximize") { this.setPos(0, 0); this.setSize(this.getParentWidth(), this.getParentHeight()); } this.hNode.style.left = this.JData.x + "px"; this.hNode.style.top = this.JData.y + "px"; this.hNode.style.width = this.JData.width + "px"; this.hNode.style.height = this.JData.height + "px"; flag = true; this.callEvent("layout"); } var client = this.getClient(); var nodes = []; for (var i = 0; i < client.childNodes.length; i++) { var node = client.childNodes[i]; if ("Jwf" in node && node.dataset && node.dataset.jwf === "Window") nodes.push(node); } var count = nodes.length; //配置順序リスト nodes.sort(function (anode, bnode) { var priority = { top: 10, bottom: 10, left: 8, right: 8, client: 5 }; var a = anode.Jwf.JData.style; var b = bnode.Jwf.JData.style; return priority[b] - priority[a]; }); //let retry; //do { //retry = false; var padding = this.JData.padding; var width = this.getClientWidth(); var height = this.getClientHeight(); var x1 = padding.x1; var y1 = padding.y1; var x2 = x1 + width; var y2 = y1 + height; for (var i = 0; i < count; i++) { var child = nodes[i]; var win = child.Jwf; if (child.dataset.visible === "false") continue; var jdata = win.JData; var margin = jdata.margin; var px1 = x1 + margin.x1; var py1 = y1 + margin.y1; var px2 = x2 - margin.x2; var py2 = y2 - margin.y2; var width_1 = -1; var height_1 = -1; switch (jdata.style) { case "top": width_1 = px2 - px1; win.setPos(px1, py1); win.setWidth(width_1); y1 += win.getHeight() + margin.y1 + margin.y2; break; case "bottom": width_1 = px2 - px1; win.setPos(px1, py2 - win.getHeight()); win.setWidth(width_1); y2 = py2 - win.getHeight() - margin.y1; break; case "left": height_1 = y2 - y1; win.setPos(px1, py1); win.setHeight(height_1); x1 += win.getWidth() + margin.x1 + margin.x2; break; case "right": height_1 = py2 - py1; win.setPos(px2 - win.getWidth(), py1); win.setHeight(height_1); x2 = px2 - win.getWidth() - margin.x2; break; case "client": width_1 = px2 - px1; height_1 = py2 - py1; win.setPos(px1, py1); win.setSize(width_1, height_1); break; } jdata.instructionSize = { width: width_1, height: height_1 }; win.onMeasure(false); //if (win.onMeasure(false)) retry = true; win.onLayout(flag); } //} while (retry); this.orderSort(client); if (this.JData.redraw || flag) this.callEvent("layouted"); this.JData.redraw = false; }; BaseView.prototype.orderSort = function (client) { var nodes = []; for (var i = 0; i < client.childNodes.length; i++) { var node = client.childNodes[i]; if ("Jwf" in node && node.dataset && node.dataset.jwf === "Window") nodes.push(node); } //重ね合わせソート nodes.sort(function (anode, bnode) { var a = anode.Jwf.JData; var b = bnode.Jwf.JData; if (a.orderTop) return 1; if (b.orderTop) return -1; var layer = a.orderLayer - b.orderLayer; if (layer) return layer; var aIndex = anode.style.zIndex ? parseInt(anode.style.zIndex) : 0; var bIndex = bnode.style.zIndex ? parseInt(bnode.style.zIndex) : 0; var aOrder = anode.dataset.order === "true" ? 10000 : 0; var bOrder = bnode.dataset.order === "true" ? 10000 : 0; return aIndex + aOrder - (bIndex + bOrder); }); var flag = false; //Zオーダーの再附番 for (var i = 0; i < nodes.length; i++) { var index = i.toString(); var node = nodes[i]; node.dataset.order = ""; if (node.style.zIndex !== index) { flag = true; node.style.zIndex = index; } } //順位が変わったので更新要求 if (flag) this.layout(); return flag; }; /** *ウインドウの表示/非表示 * * @param {boolean} flag true:表示 false:非表示 * @memberof Window */ BaseView.prototype.show = function (flag) { if (flag == null || flag) { this.hNode.style.zIndex = "10000"; this.JData.reshow = true; } else { this.hNode.style.visibility = "hidden"; } }; /** *ウインドウの重ね合わせ順位を上位に持って行く * * @param {boolean} [flag] ウインドウをアクティブにするかどうか * @memberof Window */ BaseView.prototype.foreground = function (flag) { if (this.JData.noActive) return; //親をフォアグラウンドに設定 var activeNodes = new Set(); var p = this.hNode; do { if ((flag || flag == null) && p.dataset) { activeNodes.add(p); p.dataset.jwfActive = "true"; p.dataset.order = "true"; if (p.Jwf) p.Jwf.callEvent("active", { active: true }); } this.orderSort(p); } while ((p = p.parentNode)); if (flag || flag == null) { var activeWindows = document.querySelectorAll('[data-jwf="Window"][data-jwf-active="true"]'); for (var i = 0, l = activeWindows.length; i < l; i++) { var w = activeWindows[i]; if (!activeNodes.has(w)) { w.dataset.jwfActive = "false"; w.Jwf.callEvent("active", { active: false }); } } } }; /** *クライアント領域のスクロールの可否 * * @param {boolean} flag * @memberof Window */ BaseView.prototype.setScroll = function (flag) { this.getClient().style.overflow = flag ? "auto" : "hidden"; }; /** *クライアント領域のスクロールが有効かどうか * * @returns {boolean} * @memberof Window */ BaseView.prototype.isScroll = function () { return this.getClient().style.overflow === "auto"; }; /** *ウインドウを閉じる * * @memberof Window */ BaseView.prototype.close = function () { var that = this; function animationEnd() { var nodes = this.querySelectorAll('[data-jwf="Window"]'); var count = nodes.length; for (var i = 0; i < count; i++) { nodes[i].Jwf.layout(); } if (this.parentNode) this.parentNode.removeChild(this); this.removeEventListener("animationend", animationEnd); //終了処理のコールバック var remoers = that.removers; for (var _i = 0, remoers_1 = remoers; _i < remoers_1.length; _i++) { var remover = remoers_1[_i]; remover.remove(); } that.callEvent("closed"); } var animation = this.JData.animationEnable ? this.JData.animation["close"] : null; if (animation) { this.hNode.addEventListener("animationend", animationEnd); this.hNode.style.animation = animation; } else { animationEnd.bind(this.hNode)(); } }; /** *アニメーションの設定 * * @param {string} name アニメーション名 * @param {string} value アニメーションパラメータ * @memberof Window */ BaseView.prototype.setAnimation = function (name, value) { this.JData.animation[name] = value; }; /** *絶対位置の取得 * * @returns * @memberof Window */ BaseView.prototype.getAbsX = function () { var px = this.JData.x; var parent = this; while ((parent = parent.getParent())) { px += this.getClient().offsetLeft + parent.getClientX() + parent.JData.x; } return px; }; /** *絶対位置の取得 * * @returns * @memberof Window */ BaseView.prototype.getAbsY = function () { var py = this.JData.y; var parent = this; while ((parent = parent.getParent())) { py += this.getClient().offsetTop + parent.getClientX() + parent.JData.y; } return py; }; /** *クライアントノードを返す * @returns {HTMLElement} * @memberof Window */ BaseView.prototype.getClient = function () { return this.JData.clientArea; }; /** *クライアント領域の基準位置を返す * * @returns * @memberof Window */ BaseView.prototype.getClientX = function () { return this.JData.padding.x1; }; /** *クライアント領域の基準位置を返す * * @returns * @memberof Window */ BaseView.prototype.getClientY = function () { return this.JData.padding.y1; }; /** *クライアントサイズを元にウインドウサイズを設定 * * @param {number} width * @param {number} height * @memberof Window */ BaseView.prototype.setClientSize = function (width, height) { this.setSize(width + this.JData.frameSize * 2 + this.JData.padding.x1 + this.JData.padding.x2, height + this.JData.frameSize * 2 + this.JData.padding.y1 + this.JData.padding.y2 + this.JData.titleSize); }; /** *クライアントサイズを元にウインドウサイズを設定 * * @param {number} width * @memberof Window */ BaseView.prototype.setClientWidth = function (width) { this.setWidth(width + this.JData.frameSize * 2 + this.JData.padding.x1 + this.JData.padding.x2); }; /** *クライアントサイズを元にウインドウサイズを設定 * * @param {number} height * @memberof Window */ BaseView.prototype.setClientHeight = function (height) { this.setWidth(height + this.JData.frameSize * 2 + this.JData.padding.y1 + this.JData.padding.y2 + this.JData.titleSize); }; /** *クライアントサイズを取得 * * @returns {number} * @memberof Window */ BaseView.prototype.getClientWidth = function () { return (this.getWidth() - this.JData.frameSize * 2 - this.JData.padding.x1 - this.JData.padding.x2); }; /** *クライアントサイズを取得 * * @returns {number} * @memberof Window */ BaseView.prototype.getClientHeight = function () { return (this.getHeight() - this.JData.frameSize * 2 - this.JData.padding.y1 - this.JData.padding.y2 - this.JData.titleSize); }; /** *子ノードの追加 * * @param {BaseView} child 子ウインドウ * @param {('left' | 'right' | 'top' | 'bottom' | 'client' | null)} [style] ドッキング位置 * @memberof Window */ BaseView.prototype.addFrameChild = function (child, style) { var frame = this.getNearFrame(); if (frame) frame.addChild(child, style); }; BaseView.prototype.addChild = function (child, style) { if (style) child.setChildStyle(style); child.JData.parent = this; this.getClient().appendChild(child.hNode); this.layout(); }; /** *ドッキングスタイルの設定 * * @param {('left' | 'right' | 'top' | 'bottom' | 'client' | null)} style ドッキング位置 * @memberof Window */ BaseView.prototype.setChildStyle = function (style) { this.JData.style = style; var parent = this.getParent(); if (parent) parent.layout(); }; /** *子ウインドウを全て切り離す * * @memberof Window */ BaseView.prototype.removeChildAll = function () { var client = this.getClient(); var childList = client.childNodes; for (var i = childList.length - 1; i >= 0; i--) { var child = childList[i]; if (child.dataset.jwf === "Window") { child.Jwf.JData.parent = null; client.removeChild(child); } } this.layout(); }; /** *子ウインドウを切り離す * * @param {BaseView} child * @returns * @memberof Window */ BaseView.prototype.removeChild = function (child) { if (child.getParent() !== this) return; child.JData.parent = null; this.getClient().removeChild(child.hNode); this.layout(); }; /** *自動サイズ調整の状態を取得 * * @returns * @memberof Window */ BaseView.prototype.isAutoSize = function () { return this.getClient().dataset.scale === "auto"; }; /** *自動サイズ調整を設定 * * @param {boolean} scale * @memberof Window */ BaseView.prototype.setAutoSize = function (scale) { this.getClient().dataset.scale = scale ? "auto" : ""; }; /** *タイトル設定 * * @param {string} title * @memberof Window */ BaseView.prototype.setTitle = function (title) { if (this.hNode.childNodes[9]) { this.hNode.childNodes[9].childNodes[0].textContent = title; } }; /** *タイトル取得 * * @returns {string} * @memberof Window */ BaseView.prototype.getTitle = function () { if (this.hNode.childNodes[9]) { return this.hNode.childNodes[9].childNodes[0].textContent || ""; } return ""; }; /** *ウインドウの最大化 * * @param {boolean} flag * @memberof Window */ BaseView.prototype.setMaximize = function (flag) { var that = this; function animationEnd() { this.style.minWidth = null; this.style.minHeight = that.JData.titleSize + "px"; this.removeEventListener("animationend", animationEnd); } if (this.hNode.dataset.jwfStat != "maximize") { this.JData.normalX = this.JData.x; this.JData.normalY = this.JData.y; this.JData.normalWidth = this.JData.width; this.JData.normalHeight = this.JData.height; this.hNode.dataset.jwfStat = "maximize"; this.hNode.style.minWidth = this.JData.width + "px"; this.hNode.style.minHeight = this.JData.height + "px"; var animation = this.JData.animationEnable ? this.JData.animation["maximize"] : ""; this.hNode.style.animation = animation; if (animation) this.hNode.addEventListener("animationend", animationEnd); else animationEnd.bind(this.hNode)(); } else { this.JData.x = this.JData.normalX; this.JData.y = this.JData.normalY; this.JData.width = this.JData.normalWidth; this.JData.height = this.JData.normalHeight; this.hNode.dataset.jwfStat = "normal"; var animation = this.JData.animationEnable ? this.JData.animation["maxrestore"] : ""; this.hNode.style.animation = animation; } if (flag) { var icon = this.hNode.querySelector("*>[data-jwf-type=title]>[data-jwf-type=icon][data-jwf-kind=max]"); if (icon) icon.dataset.jwfKind = "normal"; } else { var icon = this.hNode.querySelector("*>[data-jwf-type=title]>[data-jwf-type=icon][data-jwf-kind=normal]"); if (icon) icon.dataset.jwfKind = "max"; } this.layout(); }; /** *ウインドウの最小化 * * @param {boolean} flag * @memberof Window */ BaseView.prototype.setMinimize = function (flag) { var that = this; this.hNode.addEventListener("animationend", function () { that.layout(); }); if (this.hNode.dataset.jwfStat != "minimize") { //client.style.animation="Jwfminimize 0.2s ease 0s 1 forwards" var animation = this.JData.animationEnable ? this.JData.animation["minimize"] : ""; this.hNode.style.animation = animation; this.hNode.dataset.jwfStat = "minimize"; } else { //client.style.animation="Jwfrestore 0.2s ease 0s 1 backwards" var animation = this.JData.animationEnable ? this.JData.animation["restore"] : ""; this.hNode.style.animation = animation; this.hNode.dataset.jwfStat = "normal"; } if (flag) { var icon = this.hNode.querySelector("*>[data-jwf-type=title]>[data-jwf-type=icon][data-jwf-kind=min]"); icon.dataset.jwfKind = "restore"; } else {