import keymage from "keymage"; import { io } from "socket.io-client"; import whiteboard from "./whiteboard.js"; import keybinds from "./keybinds.js"; import Picker from "vanilla-picker"; import { dom } from "@fortawesome/fontawesome-svg-core"; import shortcutFunctions from "./shortcutFunctions.js"; import ReadOnlyService from "./services/ReadOnlyService.js"; import InfoService from "./services/InfoService.js"; import { getSubDir } from "./utils.js"; import ConfigService from "./services/ConfigService.js"; import { v4 as uuidv4 } from "uuid"; import * as pdfjsLib from 'pdfjs-dist/webpack.mjs'; const urlParams = new URLSearchParams(window.location.search); let whiteboardId = urlParams.get("whiteboardid"); const randomid = urlParams.get("randomid"); if (randomid) { whiteboardId = uuidv4(); urlParams.delete("randomid"); window.location.search = urlParams; } if (!whiteboardId) { whiteboardId = "myNewWhiteboard"; } whiteboardId = unescape(encodeURIComponent(whiteboardId)).replace(/[^a-zA-Z0-9\-]/g, ""); if (urlParams.get("whiteboardid") !== whiteboardId) { urlParams.set("whiteboardid", whiteboardId); window.location.search = urlParams; } const myUsername = urlParams.get("username") || "unknown" + (Math.random() + "").substring(2, 6); const accessToken = urlParams.get("accesstoken") || ""; const copyfromwid = urlParams.get("copyfromwid") || ""; // Custom Html Title const title = urlParams.get("title"); if (title) { document.title = decodeURIComponent(title); } const subdir = getSubDir(); let signaling_socket; function main() { signaling_socket = io("", { path: subdir + "/ws-api" }); // Connect even if we are in a subdir behind a reverse proxy signaling_socket.on("connect", function () { console.log("Websocket connected!"); signaling_socket.on("whiteboardConfig", (serverResponse) => { ConfigService.initFromServer(serverResponse); // Inti whiteboard only when we have the config from the server initWhiteboard(); }); signaling_socket.on("whiteboardInfoUpdate", (info) => { InfoService.updateInfoFromServer(info); whiteboard.updateSmallestScreenResolution(); }); signaling_socket.on("drawToWhiteboard", function (content) { whiteboard.handleEventsAndData(content, true); InfoService.incrementNbMessagesReceived(); }); signaling_socket.on("refreshUserBadges", function () { whiteboard.refreshUserBadges(); }); let accessDenied = false; signaling_socket.on("wrongAccessToken", function () { if (!accessDenied) { accessDenied = true; showBasicAlert("Access denied! Wrong accessToken!"); } }); signaling_socket.emit("joinWhiteboard", { wid: whiteboardId, at: accessToken, windowWidthHeight: { w: $(window).width(), h: $(window).height() }, }); }); } function showBasicAlert(html, newOptions) { var options = { header: "INFO MESSAGE", okBtnText: "Ok", headercolor: "#d25d5d", hideAfter: false, onOkClick: false, }; if (newOptions) { for (var i in newOptions) { options[i] = newOptions[i]; } } var alertHtml = $( '
' + '
' + '
' + options["header"] + '
x
' + '
' + '
" + "
" + "
" ); alertHtml.find(".htmlcontent").append(html); $("body").append(alertHtml); alertHtml .find(".okbtn") .off("click") .click(function () { if (options.onOkClick) { options.onOkClick(); } alertHtml.remove(); }); alertHtml .find(".closeAlert") .off("click") .click(function () { alertHtml.remove(); }); if (options.hideAfter) { setTimeout(function () { alertHtml.find(".okbtn").click(); }, 1000 * options.hideAfter); } } function initWhiteboard() { $(document).ready(function () { // by default set in readOnly mode ReadOnlyService.activateReadOnlyMode(); if (urlParams.get("webdav") === "true") { $("#uploadWebDavBtn").show(); } whiteboard.loadWhiteboard("#whiteboardContainer", { //Load the whiteboard whiteboardId: whiteboardId, username: btoa(encodeURIComponent(myUsername)), backgroundGridUrl: "./images/" + ConfigService.backgroundGridImage, sendFunction: function (content) { if (ReadOnlyService.readOnlyActive) return; //ADD IN LATER THROUGH CONFIG // if (content.t === 'cursor') { // if (whiteboard.drawFlag) return; // } content["at"] = accessToken; signaling_socket.emit("drawToWhiteboard", content); InfoService.incrementNbMessagesSent(); }, }); // request whiteboard from server $.get(subdir + "/api/loadwhiteboard", { wid: whiteboardId, at: accessToken }).done( function (data) { //console.log(data); whiteboard.loadData(data); if (copyfromwid && data.length == 0) { //Copy from witheboard if current is empty and get parameter is given $.get(subdir + "/api/loadwhiteboard", { wid: copyfromwid, at: accessToken, }).done(function (data) { whiteboard.loadData(data); }); } } ); $(window).resize(function () { signaling_socket.emit("updateScreenResolution", { at: accessToken, windowWidthHeight: { w: $(window).width(), h: $(window).height() }, }); }); /*----------------/ Whiteboard actions /----------------*/ var tempLineTool = false; var strgPressed = false; //Handle key actions $(document).on("keydown", function (e) { if (e.which == 16) { if (whiteboard.tool == "pen" && !strgPressed) { tempLineTool = true; whiteboard.ownCursor.hide(); if (whiteboard.drawFlag) { whiteboard.mouseup({ offsetX: whiteboard.prevPos.x, offsetY: whiteboard.prevPos.y, }); shortcutFunctions.setTool_line(); whiteboard.mousedown({ offsetX: whiteboard.prevPos.x, offsetY: whiteboard.prevPos.y, }); } else { shortcutFunctions.setTool_line(); } } whiteboard.pressedKeys["shift"] = true; //Used for straight lines... } else if (e.which == 17) { strgPressed = true; } //console.log(e.which); }); $(document).on("keyup", function (e) { if (e.which == 16) { if (tempLineTool) { tempLineTool = false; shortcutFunctions.setTool_pen(); whiteboard.ownCursor.show(); } whiteboard.pressedKeys["shift"] = false; } else if (e.which == 17) { strgPressed = false; } }); //Load keybindings from keybinds.js to given functions Object.entries(keybinds).forEach(([key, functionName]) => { const associatedShortcutFunction = shortcutFunctions[functionName]; if (associatedShortcutFunction) { keymage(key, associatedShortcutFunction, { preventDefault: true }); } else { console.error( "Function you want to keybind on key:", key, "named:", functionName, "is not available!" ); } }); // whiteboard clear button $("#whiteboardTrashBtn") .off("click") .click(function () { $("#whiteboardTrashBtnConfirm").show().focus(); $(this).hide(); }); $("#whiteboardTrashBtnConfirm").mouseout(function () { $(this).hide(); $("#whiteboardTrashBtn").show(); }); $("#whiteboardTrashBtnConfirm") .off("click") .click(function () { $(this).hide(); $("#whiteboardTrashBtn").show(); whiteboard.clearWhiteboard(); }); // undo button $("#whiteboardUndoBtn") .off("click") .click(function () { whiteboard.undoWhiteboardClick(); }); // redo button $("#whiteboardRedoBtn") .off("click") .click(function () { whiteboard.redoWhiteboardClick(); }); // view only $("#whiteboardLockBtn") .off("click") .click(() => { ReadOnlyService.deactivateReadOnlyMode(); }); $("#whiteboardUnlockBtn") .off("click") .click(() => { ReadOnlyService.activateReadOnlyMode(); }); $("#whiteboardUnlockBtn").hide(); $("#whiteboardLockBtn").show(); // switch tool $(".whiteboard-tool") .off("click") .click(function () { $(".whiteboard-tool").removeClass("active"); $(this).addClass("active"); var activeTool = $(this).attr("tool"); whiteboard.setTool(activeTool); if (activeTool == "mouse" || activeTool == "recSelect") { $(".activeToolIcon").empty(); } else { $(".activeToolIcon").html($(this).html()); //Set Active icon the same as the button icon } if (activeTool == "text" || activeTool == "stickynote") { $("#textboxBackgroundColorPickerBtn").show(); } else { $("#textboxBackgroundColorPickerBtn").hide(); } let savedThickness = localStorage.getItem("item_thickness_" + activeTool); if (savedThickness) { whiteboard.setStrokeThickness(savedThickness); $("#whiteboardThicknessSlider").val(savedThickness); } }); // upload image button $("#addImgToCanvasBtn") .off("click") .click(function () { if (ReadOnlyService.readOnlyActive) return; showBasicAlert(`Please drag the image into the browser.
Or upload here: `); document.getElementById("manualFileUpload").addEventListener( "change", function (e) { $(".basicalert").remove(); if (ReadOnlyService.readOnlyActive) return; e.originalEvent = { dataTransfer: { files: e.target.files } }; handleFileUploadEvent(e); }, false ); }); // save image as imgae $("#saveAsImageBtn") .off("click") .click(function () { whiteboard.getImageDataBase64( { imageFormat: ConfigService.imageDownloadFormat, drawBackgroundGrid: ConfigService.drawBackgroundGrid, }, function (imgData) { var w = window.open("about:blank"); //Firefox will not allow downloads without extra window setTimeout(function () { //FireFox seems to require a setTimeout for this to work. var a = document.createElement("a"); a.href = imgData; a.download = "whiteboard." + ConfigService.imageDownloadFormat; w.document.body.appendChild(a); a.click(); w.document.body.removeChild(a); setTimeout(function () { w.close(); }, 100); }, 0); } ); }); // save image to json containing steps $("#saveAsJSONBtn") .off("click") .click(function () { var imgData = whiteboard.getImageDataJson(); var w = window.open("about:blank"); //Firefox will not allow downloads without extra window setTimeout(function () { //FireFox seems to require a setTimeout for this to work. var a = document.createElement("a"); a.href = window.URL.createObjectURL(new Blob([imgData], { type: "text/json" })); a.download = "whiteboard.json"; w.document.body.appendChild(a); a.click(); w.document.body.removeChild(a); setTimeout(function () { w.close(); }, 100); }, 0); }); $("#uploadWebDavBtn") .off("click") .click(function () { if ($(".webdavUploadBtn").length > 0) { return; } var webdavserver = localStorage.getItem("webdavserver") || ""; var webdavpath = localStorage.getItem("webdavpath") || "/"; var webdavusername = localStorage.getItem("webdavusername") || ""; var webdavpassword = localStorage.getItem("webdavpassword") || ""; var webDavHtml = $( `
Server URL:
Path: path always have to start & end with "/"
Username:
Password:
Note: You have to generate and use app credentials if you have 2 Factor Auth activated on your dav/nextcloud server!
` ); webDavHtml .find(".webdavUploadBtn") .off("click") .click(function () { var webdavserver = webDavHtml.find(".webdavserver").val(); localStorage.setItem("webdavserver", webdavserver); var webdavpath = webDavHtml.find(".webdavpath").val(); localStorage.setItem("webdavpath", webdavpath); var webdavusername = webDavHtml.find(".webdavusername").val(); localStorage.setItem("webdavusername", webdavusername); var webdavpassword = webDavHtml.find(".webdavpassword").val(); localStorage.setItem("webdavpassword", webdavpassword); whiteboard.getImageDataBase64( { imageFormat: ConfigService.imageDownloadFormat, drawBackgroundGrid: ConfigService.drawBackgroundGrid, }, function (base64data) { var webdavaccess = { webdavserver: webdavserver, webdavpath: webdavpath, webdavusername: webdavusername, webdavpassword: webdavpassword, }; webDavHtml.find(".loadingWebdavText").show(); webDavHtml.find(".webdavUploadBtn").hide(); saveWhiteboardToWebdav(base64data, webdavaccess, function (err) { if (err) { webDavHtml.find(".loadingWebdavText").hide(); webDavHtml.find(".webdavUploadBtn").show(); } else { webDavHtml.parents(".basicalert").remove(); } }); } ); }); showBasicAlert(webDavHtml, { header: "Save to Webdav", okBtnText: "cancel", headercolor: "#0082c9", }); // render newly added icons dom.i2svg(); }); // upload json containing steps $("#uploadJsonBtn") .off("click") .click(function () { $("#myFile").click(); }); $("#shareWhiteboardBtn") .off("click") .click(() => { function urlToClipboard(whiteboardId = null) { const { protocol, host, pathname, search } = window.location; const basePath = `${protocol}//${host}${pathname}`; const getParams = new URLSearchParams(search); // Clear ursername from get parameters getParams.delete("username"); if (whiteboardId) { // override whiteboardId value in URL getParams.set("whiteboardid", whiteboardId); } const url = `${basePath}?${getParams.toString()}`; $("