forked from cyruzzo/AboveVTT
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSidebarPanel.js
241 lines (198 loc) · 8.52 KB
/
SidebarPanel.js
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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
function init_sidebar_tabs() {
// gamelog doesn't use it yet, maybe never
playersPanel = new SidebarPanel("players-panel", false);
$(".sidebar__pane-content").append(playersPanel.build());
playersPanel.hide();
// monsters doesn't use it yet, maybe never
tokensPanel = new SidebarPanel("tokens-panel", false);
$(".sidebar__pane-content").append(tokensPanel.build());
tokensPanel.hide();
soundsPanel = new SidebarPanel("sounds-panel", false);
$(".sidebar__pane-content").append(soundsPanel.build());
soundsPanel.hide();
journalPanel = new SidebarPanel("journal-panel", false);
$(".sidebar__pane-content").append(journalPanel.build());
journalPanel.hide();
settingsPanel = new SidebarPanel("settings-panel", false);
$(".sidebar__pane-content").append(settingsPanel.build());
settingsPanel.hide();
}
function sidebar_modal_is_open() {
return $("#VTTWRAPPER .sidebar-modal").length > 0;
}
function close_sidebar_modal() {
$("#VTTWRAPPER .sidebar-modal").remove();
}
function display_sidebar_modal(sidebarPanel) {
$("#VTTWRAPPER").append(sidebarPanel.build());
}
function current_modal() {
$("#VTTWRAPPER .sidebar-modal");
}
class SidebarPanel {
//#region Class construction and variables
id = "#unknown_panel"; // String: the unique element id of this panel. Examples: #player_panel, #monsters_panel, etc
is_modal = true; // Boolean: true if this panel will be displayed as a modal, false if this panel will be permanently fixed in a sidebar tab
constructor(id, is_modal) {
this.id = id.startsWith("#") ? id.substring(1) : id;
if (is_modal == false) {
// this.is_modal defaults to true. If anything other than false is passed in (such as undefined), just leave it as the default.
this.is_modal = is_modal;
}
}
get container() {
return $(`#${this.id}`);
}
get header() {
return $(`#${this.id} .sidebar-panel-header`);
}
get body() {
return $(`#${this.id} .sidebar-panel-body`);
}
get footer() {
return $(`#${this.id} .sidebar-panel-footer`);
}
// input wrapper is where all inputs should go. When building a sidebar panel with inputs, be sure to add them here
// inputWrapper stacks everything vertically so if you need things side by side, wrap them in a div, and do that there. See build_image_url_input for an example.
get inputWrapper() {
return $(`#${this.id} .sidebar-panel-footer .footer-input-wrapper`);
}
//#endregion Class construction and variables
//#region Class functions
hide() {
this.container.hide();
}
show() {
this.container.show();
}
updateHeader(title = "", subtitle = "", explanationText = "") {
let header = this.header;
header.find(".sidebar-panel-header-title").text(title);
header.find(".sidebar-panel-header-subtitle").text(subtitle);
header.find(".sidebar-panel-header-explanation").text(explanationText);
}
//#endregion Class functions
//#region UI Construction
build() {
let panelContainer = $(`
<div id='${this.id}' class='sidebar-panel-content'>
<div class="sidebar-panel-header">
<div class="sidebar-panel-header-title"></div>
<div class="sidebar-panel-header-subtitle"></div>
<div class="sidebar-panel-header-explanation"></div>
</div>
<div class="sidebar-panel-body"></div>
<div class="sidebar-panel-footer">
<div class="footer-input-wrapper"></div>
</div>
</div>
`);
if (this.is_modal) {
let closeButton = $(`<button class="ddbeb-modal__close-button qa-modal_close" title="Close Modal"><svg class="" xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><g transform="rotate(-45 50 50)"><rect x="0" y="45" width="100" height="10"></rect></g><g transform="rotate(45 50 50)"><rect x="0" y="45" width="100" height="10"></rect></g></svg></button>`);
closeButton.click(close_sidebar_modal);
panelContainer.find(".sidebar-panel-header").prepend(closeButton);
let modalWrapper = this.build_modal_wrapper();
modalWrapper.append(panelContainer)
return modalWrapper;
} else {
return panelContainer;
}
}
build_modal_wrapper() {
let sidebarContent = $(".sidebar__pane-content");
let width = parseInt(sidebarContent.width());
let top = parseInt(sidebarContent.position().top) + 10;
let height = parseInt(sidebarContent.height());
return $(`
<div class="sidebar-modal" style="width:${width}px;top:${top}px;right:0px;left:auto;height:${height}px;position:fixed;">
<div class="sidebar-modal-background"></div>
</div>
`);
}
// imageUrlEntered is a function that takes a string in the form of a url
build_image_url_input(titleText, imageUrlEntered) {
/* This is the general layout of what we're building. A label above an input, both of which are to the left of an "Add" button that spans the entire height
|--------------------|
| Label | Add |
| Input | Button |
|--------------------|
*/
if (typeof imageUrlEntered !== 'function') {
imageUrlEntered = function(newImageUrl) {
console.warn(`Failed to provide a valid function to handle ${newImageUrl}`);
};
}
let inputLabel = $(`<div class="token-image-modal-footer-title">${titleText}</div>`);
let urlInput = $(`<input title="${titleText}" placeholder="https://..." name="addCustomImage" type="text" />`);
urlInput.on('keyup', function(event) {
let imageUrl = event.target.value;
if (event.key == "Enter" && imageUrl != undefined && imageUrl.length > 0) {
if(imageUrl.startsWith("data:")){
alert("You cannot use urls starting with data:");
return;
}
imageUrlEntered(imageUrl);
}
});
let addButton = $(`<button class="sidebar-panel-footer-button token-image-modal-add-button">Add</button>`);
addButton.click(function(event) {
let imageUrl = $(event.target).closest(".token-image-modal-url-label-add-wrapper").find(`input[name="addCustomImage"]`)[0].value;
if (imageUrl != undefined && imageUrl.length > 0) {
if(imageUrl.startsWith("data:")){
alert("You cannot use urls starting with data:");
return;
}
imageUrlEntered(imageUrl);
}
});
let labelAndUrlWrapper = $(`<div class="token-image-modal-url-label-wrapper"></div>`); // this is to keep the label and input stacked vertically
labelAndUrlWrapper.append(inputLabel); // label above input
labelAndUrlWrapper.append(urlInput); // input below label
let addButtonAndLabelUrlWrapper = $(`<div class="token-image-modal-url-label-add-wrapper"></div>`); // this is to keep the add button on the right side of the label and input
addButtonAndLabelUrlWrapper.append(labelAndUrlWrapper); // label/input on the left
addButtonAndLabelUrlWrapper.append(addButton); // add button on the right
return addButtonAndLabelUrlWrapper;
}
build_select_input(labelText, input) {
let wrapper = $(`
<div class="token-image-modal-footer-select-wrapper">
<div class="token-image-modal-footer-title">${labelText}</div>
</div>
`);
wrapper.append(input);
return wrapper;
}
build_toggle_input(name, labelText, enabled, enabledHoverText, disabledHoverText, changeHandler) {
if (typeof changeHandler !== 'function') {
changeHandler = function(){};
}
let wrapper = $(`
<div class="token-image-modal-footer-select-wrapper sidebar-hovertext">
<div class="token-image-modal-footer-title">${labelText}</div>
</div>
`);
let input = $(`<button name="${name}" type="button" role="switch" class="rc-switch"><span class="rc-switch-inner"></span></button>`);
if (enabled) {
input.addClass("rc-switch-checked");
wrapper.attr("data-hover", enabledHoverText);
} else {
wrapper.attr("data-hover", disabledHoverText);
}
wrapper.append(input);
input.click(function(clickEvent) {
if ($(clickEvent.currentTarget).hasClass("rc-switch-checked")) {
// it was checked. now it is no longer checked
$(clickEvent.currentTarget).removeClass("rc-switch-checked");
wrapper.attr("data-hover", disabledHoverText);
changeHandler(name, false);
} else {
// it was not checked. now it is checked
$(clickEvent.currentTarget).addClass("rc-switch-checked");
wrapper.attr("data-hover", enabledHoverText);
changeHandler(name, true);
}
});
return wrapper;
}
//#endregion UI Construction
}