@jswf/core
Version:
JavaScript Window Framework
1,466 lines (1,465 loc) • 52.9 kB
JavaScript
"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 {