-
Notifications
You must be signed in to change notification settings - Fork 38
/
component.tag.html
194 lines (162 loc) · 6.74 KB
/
component.tag.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
<!--
スプリッタで区切られたウィンドウ
Usage:
<splitter_window splitter_pos="30%" direction="horizontal">
<yield to="first_pane"></yield>
<yield to="splitter"></yield>
<yield to="second_pane"></yield>
</splitter_window>
ハンドラ:
("splitter_pos_updated", splitterPos):
スプリッタ位置が変化した場合に,登録したハンドラが呼ばれる
("update_pane_size", splitterPos):
スプリッタ位置を外部から変更したいときに呼ぶ
-->
<splitter_window class="splitter_window">
<div class="splitter_window_container" ref="container">
<div ref="first_pane">
<yield from="first_pane"/>
</div>
<div ref="splitter">
<yield from="splitter"/>
</div>
<div ref="second_pane">
<yield from="second_pane"/>
</div>
</div>
<style>
/* カスタムタグは デフォルトで inline なので block を指定してやる.
そうしないと,width が効かない */
splitter_window.splitter_window {
width: 100%;
height: 100%;
display: block;
}
.splitter_window_container {
width: 100%;
height: 100%;
display: flex; /* CSS3 flexbox による配置を有効に */
/*flex-direction: row; コード内で指定されうる */
flex: auto;
}
div {
position: relative; /* ここを relative にしておかないと,子要素が外にあふれ出す */
}
</style>
<script>
let self = this;
self.lastPos = 0;
self.inDrag = false;
// 方向
self.isHorizontal = true;
if ("direction" in self.opts) {
if (self.opts.direction == "horizontal") {
self.isHorizontal = true;
}
else if (self.opts.direction == "vertical") {
self.isHorizontal = false;
}
else {
console.log("Unknown direction.");
}
}
self.on("mount", function(){
// ドラッグ始はスプリッタ
let splitter = self.refs.splitter;
splitter.onmousedown = self.onMouseDown;
// splitter 以外からも捉えられるように window に
window.addEventListener("mousemove", self.onMouseMove);
window.addEventListener("mouseup", self.onMouseUp);
// ウィンドウサイズの変更
// window 以外の要素は resizeObserver を使う必要がある
self.resizeObserver.observe(self.refs.container);
// スプリッタ初期位置
let initPos = ("splitter_pos" in self.opts) ? self.opts.splitter_pos : "30%";
if (self.isHorizontal) {
self.refs.first_pane.style.width = initPos;
self.refs.first_pane.style.height = "100%";
self.refs.splitter.style.height = "100%";
self.refs.second_pane.style.height = "100%";
}
else {
self.refs.first_pane.style.height = initPos;
self.refs.first_pane.style.width = "100%";
self.refs.splitter.style.width = "100%";
self.refs.second_pane.style.width = "100%";
}
// flex の配置
self.refs.container.style.flexDirection =
self.isHorizontal ? "row" : "column";
self.update();
});
self.on("unmount", function(){
window.removeEventListener("mousemove", self.onMouseMove);
window.removeEventListener("mouseup", self.onMouseUp);
self.resizeObserver.disconnect(); // 全要素解放
});
self.onMouseDown = function(e){
self.lastPos = self.isHorizontal ? e.clientX : e.clientY;
self.inDrag = true;
// クリック時に他所にフォーカスが奪われるのを防ぐ
e.preventDefault();
};
self.onMouseUp = function(){
self.inDrag = false;
};
self.onMouseMove = function(e){
if (!self.inDrag) {
return;
}
let container = self.refs.container;
// ウィンドウ外にカーソルがでたときのため補正
let containerSize =
self.isHorizontal ? container.offsetWidth : container.offsetHeight;
let mousePos = self.isHorizontal ? e.clientX : e.clientY;
let pos = Math.min(Math.max(mousePos, 0), containerSize);
// 差分を求める
let diff = pos - self.lastPos;
self.lastPos = pos;
// 差分を現在の幅に足す
let first_pane = self.refs.first_pane;
let splitterPos =
self.isHorizontal ? first_pane.offsetWidth : first_pane.offsetHeight;
splitterPos += diff;
//dispatcher.trigger(ACTION.PANE_SPLITTER_MOVE, splitterPos);
self.UpdatePaneSize(splitterPos);
self.trigger("splitter_pos_updated", splitterPos);
//console.log(`move ${pos} ${diff} ${first_pane.offsetWidth} ${splitterPos}`);
//console.log(`mousemove ${self.id}`);
};
self.resizeObserver = new ResizeObserver( // eslint-disable-line
() => {
let first_pane = self.refs.first_pane;
let splitterPos =
self.isHorizontal ? first_pane.offsetWidth : first_pane.offsetHeight;
self.UpdatePaneSize(splitterPos);
self.trigger("splitter_pos_updated", splitterPos);
}
);
self.UpdatePaneSize = function(splitterPos){
let container = self.refs.container;
let left = self.refs.first_pane;
let splitter = self.refs.splitter;
let right = self.refs.second_pane;
// 幅
if (self.isHorizontal) {
left.style.width = `${splitterPos}px`;
right.style.width =
`${container.offsetWidth - splitterPos - splitter.offsetWidth}px`;
}
else {
left.style.height = `${splitterPos}px`;
right.style.height =
`${container.offsetHeight - splitterPos - splitter.offsetHeight}px`;
}
//console.log(`update ${store.window.width} ${store.activeTab.splitterPos} ${right.offsetWidth}`);
self.update();
};
self.on("update_pane_size", (splitterPos) => {
self.UpdatePaneSize(splitterPos);
});
</script>
</splitter_window>