-
Notifications
You must be signed in to change notification settings - Fork 82
Expand file tree
/
Copy pathCampaignPage.mjs
More file actions
282 lines (253 loc) · 13.5 KB
/
Copy pathCampaignPage.mjs
File metadata and controls
282 lines (253 loc) · 13.5 KB
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
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
/** CampaignPage.js - functions that only execute on the campaign page */
import { init_audio_mixer } from './audio/index.mjs'
$(function() {
if (is_campaign_page()) {
window.gameIndexedDb = undefined;
let loadingGamelog;
if (is_gamelog_popout()) {
loadingGamelog = build_combat_tracker_loading_indicator('Loading Gamelog...');
$('body').append(loadingGamelog);
}
if(window.DM)
window.globalIndexedDB = undefined;
monitor_console_logs();
harvest_game_id() // find our campaign id
.then(set_game_id) // set it to window.gameId
.then(harvest_campaign_secret) // find our join link
.then(set_campaign_secret) // set it to window.CAMPAIGN_SECRET
.then(store_campaign_info) // store gameId and campaign secret in localStorage for use on other pages
.then(async () => {window.CAMPAIGN_INFO = await DDBApi.fetchCampaignInfo(window.gameId)})
.then(() => {
openCampaignDB(async function() {
if (is_gamelog_popout()) {
window.MB = new MessageBroker();
window.JOURNAL = new JournalManager(window.gameId);
window.diceRoller = new DiceRoller();
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
window.PLAYER_ID = urlParams.get('id');
window.DM = window.PLAYER_ID == 'false';
window.PLAYER_NAME = urlParams.get('player_name');
if (!window.ddbConfigJson){
DDBApi.fetchConfigJson().then(config => {
window.ddbConfigJson = config;
inject_chat_buttons();
setTimeout(function(){
$('body').find(".sidebar-panel-loading-indicator").remove();
}, 500);
});
}
else{
inject_chat_buttons();
setTimeout(function () {
$('body').find(".sidebar-panel-loading-indicator").remove();
}, 500);
}
} else {
inject_instructions();
inject_player_join_buttons();
inject_dm_join_button();
inject_dice();
}
});
})
.catch(error => {
showError(error, "Failed to set up campaign page");
});
}
});
async function openCampaignDB(startUp = function () { }) {
const DBOpenRequest = await indexedDB.open(`AboveVTT-${window.gameId}`, 2); // version 2
DBOpenRequest.onsuccess = (e) => {
window.gameIndexedDb = DBOpenRequest.result;
};
DBOpenRequest.onerror = (e) => {
console.warn(e);
};
DBOpenRequest.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames?.contains('exploredData')) {
const objectStore = db.createObjectStore("exploredData", { keyPath: "exploredId" });
}
if (!db.objectStoreNames?.contains('journalData')) {
const objectStore2 = db.createObjectStore("journalData", { keyPath: "journalId" });
}
};
const DBOpenRequest2 = indexedDB.open(`AboveVTT-Global`, 5);
DBOpenRequest2.onsuccess = (e) => {
window.globalIndexedDB = DBOpenRequest2.result;
startUp()
};
DBOpenRequest2.onerror = (e) => {
console.warn(e);
};
DBOpenRequest2.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames?.contains('customizationData')) {
const objectStore = db.createObjectStore("customizationData", { keyPath: "customizationId" });
}
if (!db.objectStoreNames?.contains('journalData')) {
const objectStore2 = db.createObjectStore("journalData", { keyPath: "journalId" });
}
if (db.objectStoreNames?.contains('avttFilePicker')){
db.deleteObjectStore('avttFilePicker');
}
};
}
function inject_instructions() {
if (!is_campaign_page()) return;
let ddbHeader = $(".ddb-campaigns-detail-header-secondary-sharing");
// SCB: Add a dummy DIV to force the AboutVTT DIV below the standard DDB buttons
ddbHeader.append($("<div style='clear:both'>"));
// SCB:Create a 'content DIV' for AboveVTT to add our controls to, so we can control styling better
const contentDiv = $("<div class='above-vtt-content-div'>");
ddbHeader.append(contentDiv);
// SCB: Append our logo
contentDiv.append(`<img class='above-vtt-logo above-vtt-right-margin-5px' width='120px' src='${window.EXTENSION_PATH}assets/logo.png' alt="above vtt logo" />`);
let instructionsButton = $("<a style='padding:10px 5px;' class='above-vtt-campaignscreen-white-button above-vtt-right-margin-5px instructions btn modal-link ddb-campaigns-detail-body-listing-campaign-link'>Instructions</a>");
contentDiv.append(instructionsButton);
instructionsButton.click(function(e) {
$("#campaign_banner").toggle();
});
let spectatorJoinButton = $("<a style='padding:10px 25px;' class='above-vtt-campaignscreen-blue-button above-vtt-right-margin-5px button joinspectator btn modal-link ddb-campaigns-detail-body-listing-campaign-link'>Spectate</a>");
contentDiv.append(spectatorJoinButton);
spectatorJoinButton.click(function (e) {
e.preventDefault();
$(e.currentTarget).addClass("button-loading");
try {
window.open(`${window.document.location.href}?abovevtt=true&spectator=true`, '_blank');
// pop up blockers can prevent us from opening in a new tab. Tell our users in case this happens to them
let oldText = $(".joinspectator").text();
$(".joinspectator").removeClass("button-loading");
$(".joinspectator").text("Check for blocked pop ups!");
// reset our join button text, so it looks normal the next time they're on this tab
setTimeout(function () {
$(".joinspectator").text(oldText);
}, 2000);
}
catch (error) {
showError(error, "Failed to start AboveVTT from spectate join button");
}
$(e.currentTarget).removeClass("button-loading");
});
const campaign_banner = $("<div id='campaign_banner'></div>");
campaign_banner.append(`
<h4><img class='above-vtt-right-margin-5px' alt='above vtt logo' width='100px' src='${window.EXTENSION_PATH}assets/logo.png'>Basic Instructions!</h4>
<br>If you are the DM, press <b>JOIN AS DM</b> above. If you have a free DnDBeyond account make sure you have 1 free encounter slot to join as DM. Free accounts are limited to 8 encounters.<br><br>
Players, press <b>JOIN AboveVTT</b> next to your character at the bottom, and then wait for your DM to join.<br><br>
Please check that you do not have any other extensions for DndBeyond (like Beyond20) enabled. <b>Disable them</b> or you will not be able to roll dice!<br><br>
If you're looking for tutorials, take a look at our <a target='_blank' href='https://www.youtube.com/channel/UCrVm9Al59iHE19IcqaKqqXA'>YouTube Channel!!</a><br>
If you need help, or just want to send us your feedback, join the <a target='_blank' href='https://discord.gg/cMkYKqGzRh'>AboveVTT Discord Community</a>.<br>
Do you like what you see? Then please support me on <a target='_blank' href='https://www.patreon.com/AboveVTT'>AboveVTT Patreon!</a><br><br>
<b>Deprecation</b> Due to technical changes. You no longer can join as DM if you're not the real DM of the campaign. If you need help recovering your local data for this campaign contact us on discord<br><br>
Use this button to delete all locally held data, to 'clear the cache' as it were: <br>
`);
campaign_banner.hide();
$(".ddb-campaigns-detail-header-secondary-description").first().before(campaign_banner);
const delete_button = $("<a class='above-vtt-campaignscreen-black-button button btn modal-link ddb-campaigns-detail-body-listing-campaign-link' id='above_delete'>Delete AboveVTT Data for this campaign</a>");
delete_button.click(function() {
if (confirm("Are you sure?")) {
let gameId = find_game_id();
localStorage.removeItem("ScenesHandler" + gameId);
localStorage.removeItem("current_source" + gameId);
localStorage.removeItem("current_chapter" + gameId);
localStorage.removeItem("current_scene" + gameId);
localStorage.removeItem("CombatTracker" + gameId);
localStorage.removeItem("Journal" + gameId);
localStorage.removeItem("JournalChapters" + gameId);
localStorage.removeItem("TokenSettings" + gameId);
gameIndexedDb.transaction([`exploredData`], "readwrite").objectStore('exploredData').clear();
gameIndexedDb.transaction([`journalData`], "readwrite").objectStore('journalData').clear();
}
});
campaign_banner.append(delete_button);
const delete_button2 = $("<a class='above-vtt-campaignscreen-black-button button btn modal-link ddb-campaigns-detail-body-listing-campaign-link' id='above_delete2'>Delete Global AboveVTT Data (soundpads, tokens..)</a>");
delete_button2.click(function() {
if (confirm("Are you sure?")) {
localStorage.removeItem("Soundpads");
localStorage.removeItem("CustomTokens");
localStorage.removeItem("TokenCustomizations");
globalIndexedDB.transaction([`customizationData`], "readwrite").objectStore('customizationData').clear();
globalIndexedDB.transaction([`journalData`], "readwrite").objectStore('journalData').clear();
}
});
campaign_banner.append(delete_button2);
}
function inject_dm_join_button() {
if (!is_campaign_page()) return;
if ($(".ddb-campaigns-detail-body-dm-notes-private").length === 0) return; // The owner of the campaign (the DM) is the only one with private notes on the campaign page
// The owner of the campaign (the DM) is the only one with private notes on the campaign page
console.log("inject_dm_join_button");
$(".ddb-campaigns-invite-container").append(`
<div class="above-vtt-warning-div" style="display: flex;flex-direction: column; align-items: center;justify-content: center; text-align: center;padding: 5px;border: 2px solid #c53131; border-radius: 4px;">
<div class="above-vtt-warning-secondary-div">
<a class="above-vtt-warning-secondary-div" style="color: #c53131; font-weight: 900; font-size: 16px; font-family: roboto;">WARNING FOR ABOVEVTT!!!</a>
</div>
<a class="ddb-campaigns-warning-div" style="color: #333;">If you press 'RESET INVITE LINK' you will lose your cloud data!<br>Players will also have to visit/join from the campaign page at least once after reset to sync.</a>
</div>
`);
let dmJoinButton = $("<a style='padding:10px 25px;' class='above-vtt-campaignscreen-blue-button above-vtt-right-margin-5px button joindm btn modal-link ddb-campaigns-detail-body-listing-campaign-link'>Join as DM</a>");
$(".above-vtt-content-div").append(dmJoinButton);
dmJoinButton.click(function(e) {
e.preventDefault();
tabCommunicationChannel.postMessage({
msgType: 'DMOpenAlready',
sendTo: false,
url: window.gameId
});
$(e.currentTarget).addClass("button-loading");
try{
window.open(`${window.document.location.href}?abovevtt=true&dm=true`, '_blank');
// pop up blockers can prevent us from opening in a new tab. Tell our users in case this happens to them
let oldText = $(".joindm").text();
$(".joindm").removeClass("button-loading");
$(".joindm").text("Check for blocked pop ups!");
// reset our join button text, so it looks normal the next time they're on this tab
setTimeout(function () {
$(".joindm").text(oldText);
}, 2000);
}
catch(error) {
showError(error, "Failed to start AboveVTT from dm join button");
}
$(e.currentTarget).removeClass("button-loading");
});
if(window.resetObserver)
window.resetObserver.disconnect();
window.resetObserver = new MutationObserver(async (mutationList, observer) => {
if($('.t-reset-campaign-modal').length>0 && $('.t-reset-campaign-modal #takeAbovevttExport').length == 0){
const avttExportContainer = $(`<div id="avttExportContainer" style="margin: 15px;
border: 1px solid #ddd;
display: flex;
flex-wrap: wrap;
max-width: 270px;
justify-content: center;
text-align: center;
padding: 5px;
">
<span style="color:#F00; margin:3px;">WARNING: You will lose your AboveVTT cloud data if you continue without having an export.</span>
<button class='button' id='takeAbovevttExport'>Download AboveVTT Export</button>
</div>`);
avttExportContainer.find('button').on('click.takeExport', (e)=> {export_file('#avttExportContainer')});
$('.ddb-modal-reset-invite-code').before(avttExportContainer);
const aboveApi = await new AboveApi();
window.JOURNAL = await new JournalManager(window.gameId);
window.ScenesHandler = new ScenesHandler();
window.ScenesHandler.scenes = await AboveApi.getSceneList();
await init_audio_mixer();
fetch_token_customizations();
}
})
resetObserver.observe(document.querySelector("body"), { childList: true, subtree: true });
}
function inject_player_join_buttons() {
if (!is_campaign_page()) return;
console.log("inject_campaign_page_buttons");
$(".ddb-campaigns-character-card-footer-links").each(function() {
const characterCard = $(this);
if(characterCard.find(".ddb-campaigns-character-card-footer-links-item-edit").length > 0) {
const characterPagePathname = characterCard.find(".ddb-campaigns-character-card-footer-links-item-view").attr('href');
characterCard.prepend(`<a style='color:white;background: #1b9af0;padding: 2px;' href='https://www.dndbeyond.com${characterPagePathname}?abovevtt=true' target='_blank' class='button ddb-campaigns-character-card-footer-links-item'>JOIN AboveVTT</a>`);
}
});
}