diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..92cde39 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,3 @@ +{ + "singleQuote": true +} \ No newline at end of file diff --git a/README.md b/README.md index 384c89c..ca9cd62 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,4 @@ Web-based memos that support real-time collaboration. Inspired by scrumblr. -test Léo +Run 'bun install' for installing deps and 'redis-server --daemonize yes && bun run start' to start the servers diff --git a/bun.lockb b/bun.lockb index f520f8a..797cae2 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/client/script.js b/client/script.js index 7b3df3b..0abec71 100644 --- a/client/script.js +++ b/client/script.js @@ -1,56 +1,54 @@ function toggleFullScreen() { if (!document.fullscreenElement) { document.documentElement.requestFullscreen() - } else { - if (document.exitFullscreen) { - document.exitFullscreen() - } + } else if (document.exitFullscreen) { + document.exitFullscreen() } } -var cards = {} -var totalcolumns = 0 -var columns = [] -var currentTheme = "bigcards" -var boardInitialized = false -var keyTrap = null +let cards = {} +let totalcolumns = 0 +let columns = [] +let currentTheme = 'bigcards' +let boardInitialized = false +let keyTrap = null -var baseurl = location.pathname.substring(0, location.pathname.lastIndexOf("/")) -var socket = io.connect({ path: baseurl + "/socket.io" }) +const baseurl = location.pathname.substring(0, location.pathname.lastIndexOf('/')) +const socket = io.connect({ path: `${baseurl}/socket.io` }) moment.locale(navigator.language || navigator.languages[0]) marked.setOptions({ sanitize: true }) -//an action has happened, send it to the -//server +// an action has happened, send it to the +// server function sendAction(a, d) { - //console.log('--> ' + a); + // console.log('--> ' + a); - var message = { + const message = { action: a, - data: d, + data: d } socket.json.send(message) } -socket.on("connect", function () { - //console.log('successful socket.io connect'); +socket.on('connect', () => { + // console.log('successful socket.io connect'); - //let the final part of the path be the room name - var room = location.pathname.substring(location.pathname.lastIndexOf("/")) + // let the final part of the path be the room name + const room = location.pathname.substring(location.pathname.lastIndexOf('/')) - //imediately join the room which will trigger the initializations - sendAction("joinRoom", room) + // imediately join the room which will trigger the initializations + sendAction('joinRoom', room) }) -socket.on("disconnect", function () { - blockUI("Serveur déconnecté. Veuillez rafraîchir la page pour essayer de vous reconnecter…") - //$('.blockOverlay').on('click', $.unblockUI); +socket.on('disconnect', () => { + blockUI('Serveur déconnecté. Veuillez rafraîchir la page pour essayer de vous reconnecter…') + // $('.blockOverlay').on('click', $.unblockUI); }) -socket.on("message", function (data) { +socket.on('message', (data) => { getMessage(data) }) @@ -59,173 +57,172 @@ function unblockUI() { } function blockUI(message) { - message = message || "En attente…" + message = message || 'En attente…' $.blockUI({ - message: message, + message, css: { - border: "none", - padding: "15px", - backgroundColor: "#000", - "-webkit-border-radius": "10px", - "-moz-border-radius": "10px", + border: 'none', + padding: '15px', + backgroundColor: '#000', + '-webkit-border-radius': '10px', + '-moz-border-radius': '10px', opacity: 0.5, - color: "#fff", - fontSize: "20px", + color: '#fff', + fontSize: '20px' }, fadeOut: 0, - fadeIn: 10, + fadeIn: 10 }) } -//respond to an action event +// respond to an action event function getMessage(m) { - var message = m //JSON.parse(m); - var action = message.action - var data = message.data + const message = m // JSON.parse(m); + const { action } = message + const { data } = message - //console.log('<-- ' + action); + // console.log('<-- ' + action); switch (action) { - case "roomAccept": - //okay we're accepted, then request initialization - //(this is a bit of unnessary back and forth but that's okay for now) - sendAction("initializeMe", null) + case 'roomAccept': + // okay we're accepted, then request initialization + // (this is a bit of unnessary back and forth but that's okay for now) + sendAction('initializeMe', null) break - case "roomDeny": - //this doesn't happen yet + case 'roomDeny': + // this doesn't happen yet break - case "moveCard": - moveCard($("#" + data.id), data.position) + case 'moveCard': + moveCard($(`#${data.id}`), data.position) break - case "initCards": + case 'initCards': initCards(data) break - case "createCard": - //console.log(data); + case 'createCard': + // console.log(data); drawNewCard(data.id, data.text, data.x, data.y, data.rot, data.colour, null) break - case "deleteCard": - $("#" + data.id).fadeOut(500, function () { + case 'deleteCard': + $(`#${data.id}`).fadeOut(500, function() { $(this).remove() }) break - case "editCard": - $("#" + data.id) - .children(".content:first") - .attr("data-text", data.value) - $("#" + data.id) - .children(".content:first") + case 'editCard': + $(`#${data.id}`) + .children('.content:first') + .attr('data-text', data.value) + $(`#${data.id}`) + .children('.content:first') .html(marked(data.value)) break - case "initColumns": + case 'initColumns': initColumns(data) break - case "updateColumns": + case 'updateColumns': initColumns(data) break - case "changeTheme": + case 'changeTheme': changeThemeTo(data) break - case "join-announce": + case 'join-announce': displayUserJoined(data.sid, data.user_name) break - case "leave-announce": + case 'leave-announce': displayUserLeft(data.sid) break - case "initialUsers": + case 'initialUsers': displayInitialUsers(data) break - case "nameChangeAnnounce": + case 'nameChangeAnnounce': updateName(message.data.sid, message.data.user_name) break - case "addSticker": + case 'addSticker': addSticker(message.data.cardId, message.data.stickerId) break - case "setBoardSize": + case 'setBoardSize': resizeBoard(message.data) break - case "export": + case 'export': download(message.data.filename, message.data.text) break - case "addRevision": + case 'addRevision': addRevision(message.data) break - case "deleteRevision": - $("#revision-" + message.data).remove() + case 'deleteRevision': + $(`#revision-${message.data}`).remove() break - case "initRevisions": - $("#revisions-list").empty() - for (var i = 0; i < message.data.length; i++) { + case 'initRevisions': + $('#revisions-list').empty() + for (let i = 0; i < message.data.length; i++) { addRevision(message.data[i]) } break default: - //unknown message - alert("action inconnue : " + JSON.stringify(message)) + // unknown message + alert(`action inconnue : ${JSON.stringify(message)}`) break } } -$(document).on("keyup", function (event) { +$(document).on('keyup', (event) => { keyTrap = event.which }) -function drawNewCard(id, text, x, y, rot, colour, sticker, animationspeed, mx = 0 , my = 0) { - //cards[id] = {id: id, text: text, x: x, y: y, rot: rot, colour: colour}; +function drawNewCard(id, text, x, y, rot, colour, sticker, animationspeed, mx = 0, my = 0) { + // cards[id] = {id: id, text: text, x: x, y: y, rot: rot, colour: colour}; - var h = - '
\ \ -
' + - marked(text) + - '
\ -
' +
${ + marked(text) +}
\ + ` - var card = $(h) - card.appendTo("#board") - $("#" + id) - .children(".content:first") - .attr("data-text", text) + const card = $(h) + card.appendTo('#board') + $(`#${id}`) + .children('.content:first') + .attr('data-text', text) - //@TODO - //Draggable has a bug which prevents blur event - //http://bugs.jqueryui.com/ticket/4261 - //So we have to blur all the cards and editable areas when - //we click on a card - //The following doesn't work so we will do the bug - //fix recommended in the above bug report + // @TODO + // Draggable has a bug which prevents blur event + // http://bugs.jqueryui.com/ticket/4261 + // So we have to blur all the cards and editable areas when + // we click on a card + // The following doesn't work so we will do the bug + // fix recommended in the above bug report // card.on('click', function() { // $(this).focus(); // } ); @@ -234,182 +231,176 @@ function drawNewCard(id, text, x, y, rot, colour, sticker, animationspeed, mx = snap: false, snapTolerance: 5, containment: [0, 0, 2000, 2000], - stack: ".card", - start: function (event, ui) { + stack: '.card', + start(event, ui) { keyTrap = null }, - drag: function (event, ui) { + drag(event, ui) { if (keyTrap == 27) { ui.helper.css(ui.originalPosition) return false } }, - handle: "div.content", + handle: 'div.content' }) - //After a drag: - card.on("dragstop", function (event, ui) { + // After a drag: + card.on('dragstop', function(event, ui) { if (keyTrap == 27) { keyTrap = null return } - var data = { + const data = { id: this.id, position: ui.position, - oldposition: ui.originalPosition, + oldposition: ui.originalPosition } - sendAction("moveCard", data) + sendAction('moveCard', data) }) - card.children(".droppable").droppable({ - accept: ".sticker", - drop: function (event, ui) { - var stickerId = ui.draggable.attr("id") - var cardId = $(this).parent().attr("id") + card.children('.droppable').droppable({ + accept: '.sticker', + drop(event, ui) { + const stickerId = ui.draggable.attr('id') + const cardId = $(this).parent().attr('id') addSticker(cardId, stickerId) - var data = { - cardId: cardId, - stickerId: stickerId, + const data = { + cardId, + stickerId } - sendAction("addSticker", data) + sendAction('addSticker', data) - //remove hover state to everything on the board to prevent - //a jquery bug where it gets left around - $(".card-hover-draggable").removeClass("card-hover-draggable") + // remove hover state to everything on the board to prevent + // a jquery bug where it gets left around + $('.card-hover-draggable').removeClass('card-hover-draggable') }, - hoverClass: "card-hover-draggable", + hoverClass: 'card-hover-draggable' }) - var speed = Math.floor(Math.random() * 1000) - if (typeof animationspeed != "undefined") speed = animationspeed + let speed = Math.floor(Math.random() * 1000) + if (typeof animationspeed != 'undefined') speed = animationspeed if (mx == 0 && my == 0) { - var startPosition = $("#create-card").position() - mx = startPosition.left; - my = startPosition.top; + const startPosition = $('#create-card').position() + mx = startPosition.left + my = startPosition.top } - card.css("top", my) - card.css("left", mx) + card.css('top', my) + card.css('left', mx) card.animate( { - left: x + "px", - top: y + "px", + left: `${x}px`, + top: `${y}px` }, speed ) - - card.children(".delete-card-icon").on("click", function () { - $("#" + id).remove() - //notify server of delete - sendAction("deleteCard", { - id: id, - }) + card.children('.delete-card-icon').on('click', () => { + $(`#${id}`).remove() + // notify server of delete + sendAction('deleteCard', { id }) }) - card.children(".content").editable( - function (value, settings) { - $("#" + id) - .children(".content:first") - .attr("data-text", value) + card.children('.content').editable( + (value, settings) => { + $(`#${id}`) + .children('.content:first') + .attr('data-text', value) onCardChange(id, value) return marked(value) }, { - type: "textarea", - data: function () { - return $("#" + id) - .children(".content:first") - .attr("data-text") + type: 'textarea', + data() { + return $(`#${id}`) + .children('.content:first') + .attr('data-text') }, - submit: "OK", - style: "inherit", - cssclass: "card-edit-form", - placeholder: "Double cliquez pour m’éditer", - onblur: "submit", - event: "dblclick", //event: 'mouseover' + submit: 'OK', + style: 'inherit', + cssclass: 'card-edit-form', + placeholder: 'Double cliquez pour m’éditer', + onblur: 'submit', + event: 'dblclick' // event: 'mouseover' } ) - //add applicable sticker + // add applicable sticker if (sticker !== null) addSticker(id, sticker) } function onCardChange(id, text) { - sendAction("editCard", { - id: id, - value: text, + sendAction('editCard', { + id, + value: text }) } function moveCard(card, position) { card.animate( { - left: position.left + "px", - top: position.top + "px", + left: `${position.left}px`, + top: `${position.top}px` }, 500 ) } function addSticker(cardId, stickerId) { - stickerContainer = $("#" + cardId + " .filler") + stickerContainer = $(`#${cardId} .filler`) - if (stickerId === "nosticker") { - stickerContainer.html("") + if (stickerId === 'nosticker') { + stickerContainer.html('') return } if (Array.isArray(stickerId)) { - for (var i in stickerId) { - stickerContainer.prepend('') + for (const i in stickerId) { + stickerContainer.prepend(``) } - } else { - if (stickerContainer.html().indexOf(stickerId) < 0) - stickerContainer.prepend('') - } + } else if (stickerContainer.html().indexOf(stickerId) < 0) { stickerContainer.prepend(``) } } //---------------------------------- // cards //---------------------------------- -function createCard(id, text, x, y, rot, colour, mx = 0,my = 0) { +function createCard(id, text, x, y, rot, colour, mx = 0, my = 0) { drawNewCard(id, text, x, y, rot, colour, null, null, mx, my) - var action = "createCard" + const action = 'createCard' - var data = { - id: id, - text: text, - x: x, - y: y, - rot: rot, - colour: colour, + const data = { + id, + text, + x, + y, + rot, + colour } sendAction(action, data) } function randomCardColour() { - var colours = ["yellow", "green", "blue", "white"] + const colours = ['yellow', 'green', 'blue', 'white'] - var i = Math.floor(Math.random() * colours.length) + const i = Math.floor(Math.random() * colours.length) return colours[i] } function initCards(cardArray) { - //first delete any cards that exist - $(".card").remove() + // first delete any cards that exist + $('.card').remove() cards = cardArray - for (var i in cardArray) { + for (const i in cardArray) { card = cardArray[i] drawNewCard(card.id, card.text, card.x, card.y, card.rot, card.colour, card.sticker, 0) @@ -424,53 +415,53 @@ function initCards(cardArray) { //---------------------------------- function drawNewColumn(columnName) { - var cls = "col" + let cls = 'col' if (totalcolumns === 0) { - cls = "col first" + cls = 'col first' } - $("#icon-col").before( - '

' + - columnName + - "

" + $('#icon-col').before( + `

${ + columnName + }

` ) - $(".editable").editable( - function (value, settings) { + $('.editable').editable( + function(value, settings) { onColumnChange(this.id, value) return value }, { - style: "inherit", - cssclass: "card-edit-form", - type: "textarea", - placeholder: "Nouveau", - onblur: "submit", - width: "", - height: "", + style: 'inherit', + cssclass: 'card-edit-form', + type: 'textarea', + placeholder: 'Nouveau', + onblur: 'submit', + width: '', + height: '', xindicator: '', - event: "dblclick", //event: 'mouseover' + event: 'dblclick' // event: 'mouseover' } ) - $(".col:last").fadeIn(500) + $('.col:last').fadeIn(500) totalcolumns++ } function onColumnChange(id, text) { - var names = Array() + const names = [] - //console.log(id + " " + text ); + // console.log(id + " " + text ); - //Get the names of all the columns right from the DOM - $(".col").each(function () { - //get ID of current column we are traversing over - var thisID = $(this).children("h2").attr("id") + // Get the names of all the columns right from the DOM + $('.col').each(function() { + // get ID of current column we are traversing over + const thisID = $(this).children('h2').attr('id') if (id == thisID) { names.push(text) @@ -485,7 +476,7 @@ function onColumnChange(id, text) { function displayRemoveColumn() { if (totalcolumns <= 0) return false - $(".col:last").fadeOut(150, function () { + $('.col:last').fadeOut(150, function() { $(this).remove() }) @@ -498,9 +489,9 @@ function createColumn(name) { drawNewColumn(name) columns.push(name) - var action = "updateColumns" + const action = 'updateColumns' - var data = columns + const data = columns sendAction(action, data) } @@ -511,9 +502,9 @@ function deleteColumn() { displayRemoveColumn() columns.pop() - var action = "updateColumns" + const action = 'updateColumns' - var data = columns + const data = columns sendAction(action, data) } @@ -521,25 +512,25 @@ function deleteColumn() { function updateColumns(c) { columns = c - var action = "updateColumns" + const action = 'updateColumns' - var data = columns + const data = columns sendAction(action, data) } function deleteColumns(next) { - //delete all existing columns: - $(".col").fadeOut("slow", next()) + // delete all existing columns: + $('.col').fadeOut('slow', next()) } function initColumns(columnArray) { totalcolumns = 0 columns = columnArray - $(".col").remove() + $('.col').remove() - for (var i in columnArray) { + for (const i in columnArray) { column = columnArray[i] drawNewColumn(column) @@ -549,33 +540,33 @@ function initColumns(columnArray) { function changeThemeTo(theme) { currentTheme = theme if (theme == 'bigcards') { - $("#board").removeClass('smallcards') + $('#board').removeClass('smallcards') } else { - $("#board").removeClass('bigcards') + $('#board').removeClass('bigcards') } - $("#board").addClass(theme) + $('#board').addClass(theme) } -////////////////////////////////////////////////////////// -////////// NAMES STUFF /////////////////////////////////// -////////////////////////////////////////////////////////// +/// /////////////////////////////////////////////////////// +/// /////// NAMES STUFF /////////////////////////////////// +/// /////////////////////////////////////////////////////// function setCookie(c_name, value, exdays) { - var exdate = new Date() + const exdate = new Date() exdate.setDate(exdate.getDate() + exdays) - var c_value = escape(value) + (exdays === null ? "" : "; expires=" + exdate.toUTCString()) + ';SameSite=Strict' - document.cookie = c_name + "=" + c_value + const c_value = `${escape(value) + (exdays === null ? '' : `; expires=${exdate.toUTCString()}`)};SameSite=Strict` + document.cookie = `${c_name}=${c_value}` } function getCookie(c_name) { - var i, - x, - y, - ARRcookies = document.cookie.split(";") + let i + let x + let y + const ARRcookies = document.cookie.split(';') for (i = 0; i < ARRcookies.length; i++) { - x = ARRcookies[i].substr(0, ARRcookies[i].indexOf("=")) - y = ARRcookies[i].substr(ARRcookies[i].indexOf("=") + 1) - x = x.replace(/^\s+|\s+$/g, "") + x = ARRcookies[i].substr(0, ARRcookies[i].indexOf('=')) + y = ARRcookies[i].substr(ARRcookies[i].indexOf('=') + 1) + x = x.replace(/^\s+|\s+$/g, '') if (x == c_name) { return unescape(y) } @@ -583,74 +574,74 @@ function getCookie(c_name) { } function setName(name) { - sendAction("setUserName", name) + sendAction('setUserName', name) - setCookie("scrumscrum-username", name, 365) + setCookie('scrumscrum-username', name, 365) } function displayInitialUsers(users) { - for (var i in users) { - //console.log(users); + for (const i in users) { + // console.log(users); displayUserJoined(users[i].sid, users[i].user_name) } } function displayUserJoined(sid, user_name) { - name = "" + name = '' if (user_name) name = user_name else name = sid.substring(0, 5) - $("#names-ul").append('
  • ' + name + "
  • ") + $('#names-ul').append(`
  • ${name}
  • `) } function displayUserLeft(sid) { - name = "" + name = '' if (name) name = user_name else name = sid - var id = "#user-" + sid.toString() + const id = `#user-${sid.toString()}` - $("#names-ul") + $('#names-ul') .children(id) - .fadeOut(1000, function () { + .fadeOut(1000, function() { $(this).remove() }) } function updateName(sid, name) { - var id = "#user-" + sid.toString() + const id = `#user-${sid.toString()}` - $("#names-ul").children(id).text(name) + $('#names-ul').children(id).text(name) } -////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////// +/// /////////////////////////////////////////////////////// +/// /////////////////////////////////////////////////////// function boardResizeHappened(event, ui) { - var newsize = ui.size + const newsize = ui.size - sendAction("setBoardSize", newsize) + sendAction('setBoardSize', newsize) } function resizeBoard(size) { - $(".board-outline").animate({ + $('.board-outline').animate({ height: size.height, - width: size.width, + width: size.width }) } -////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////// +/// /////////////////////////////////////////////////////// +/// /////////////////////////////////////////////////////// function calcCardOffset() { - var offsets = {} - $(".card").each(function () { - var card = $(this) - $(".col").each(function (i) { - var col = $(this) - if (col.offset().left + col.outerWidth() > card.offset().left + card.outerWidth() || i === $(".col").length - 1) { - offsets[card.attr("id")] = { - col: col, - x: (card.offset().left - col.offset().left) / col.outerWidth(), + const offsets = {} + $('.card').each(function() { + const card = $(this) + $('.col').each(function(i) { + const col = $(this) + if (col.offset().left + col.outerWidth() > card.offset().left + card.outerWidth() || i === $('.col').length - 1) { + offsets[card.attr('id')] = { + col, + x: (card.offset().left - col.offset().left) / col.outerWidth() } return false } @@ -659,70 +650,70 @@ function calcCardOffset() { return offsets } -//moves cards with a resize of the Board -//doSync is false if you don't want to synchronize -//with all the other users who are in this room +// moves cards with a resize of the Board +// doSync is false if you don't want to synchronize +// with all the other users who are in this room function adjustCard(offsets, doSync) { - $(".card").each(function () { - var card = $(this) - var offset = offsets[this.id] + $('.card').each(function() { + const card = $(this) + const offset = offsets[this.id] if (offset) { - var data = { + const data = { id: this.id, position: { left: offset.col.position().left + offset.x * offset.col.outerWidth(), - top: parseInt(card.css("top").slice(0, -2)), + top: parseInt(card.css('top').slice(0, -2)) }, oldposition: { - left: parseInt(card.css("left").slice(0, -2)), - top: parseInt(card.css("top").slice(0, -2)), - }, - } //use .css() instead of .position() because css' rotate - //console.log(data); + left: parseInt(card.css('left').slice(0, -2)), + top: parseInt(card.css('top').slice(0, -2)) + } + } // use .css() instead of .position() because css' rotate + // console.log(data); if (!doSync) { - card.css("left", data.position.left) - card.css("top", data.position.top) + card.css('left', data.position.left) + card.css('top', data.position.top) } else { - //note that in this case, data.oldposition isn't accurate since - //many moves have happened since the last sync - //but that's okay becuase oldPosition isn't used right now + // note that in this case, data.oldposition isn't accurate since + // many moves have happened since the last sync + // but that's okay becuase oldPosition isn't used right now moveCard(card, data.position) - sendAction("moveCard", data) + sendAction('moveCard', data) } } }) } -////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////// +/// /////////////////////////////////////////////////////// +/// /////////////////////////////////////////////////////// function download(filename, text) { - var element = document.createElement("a") - var mime = "text/plain" + const element = document.createElement('a') + let mime = 'text/plain' if (filename.match(/.csv$/)) { - mime = "text/csv" + mime = 'text/csv' } - element.setAttribute("href", "data:" + mime + ";charset=utf-8," + encodeURIComponent(text)) - element.setAttribute("download", filename) + element.setAttribute('href', `data:${mime};charset=utf-8,${encodeURIComponent(text)}`) + element.setAttribute('download', filename) - element.style.display = "none" + element.style.display = 'none' document.body.appendChild(element) element.click() document.body.removeChild(element) } function addRevision(timestamp) { - var li = $('
  • ') - var s1 = $("") - var s2 = $('delete revision') - if (typeof timestamp === "string") { + const li = $(`
  • `) + const s1 = $('') + const s2 = $('delete revision') + if (typeof timestamp === 'string') { timestamp = parseInt(timestamp) } - s1.text(moment(timestamp).format("LLLL")) + s1.text(moment(timestamp).format('LLLL')) li.append(s1) li.append(s2) - $("#revisions-list").append(li) + $('#revisions-list').append(li) // $('body').on("click", s1, function () { // socket.json.send({ @@ -738,207 +729,207 @@ function addRevision(timestamp) { // }) } -////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////// +/// /////////////////////////////////////////////////////// +/// /////////////////////////////////////////////////////// -$(function () { - //disable image dragging - //window.ondragstart = function() { return false; }; +$(() => { + // disable image dragging + // window.ondragstart = function() { return false; }; if (boardInitialized === false) blockUI('') - //setTimeout($.unblockUI, 2000); + // setTimeout($.unblockUI, 2000); - $(".add-post-it").on("click", function (e) { - var rotation = Math.random() * 10 - 5 //add a bit of random rotation (+/- 10deg) - var cardLeft = 150 + Math.random() * 400 - var cardTop = 20 + Math.random() * 50 - var uniqueID = Math.round(Math.random() * 99999999) //is this big enough to assure uniqueness? - console.log(e.clientX, e.clientY); - createCard("card" + uniqueID, "", cardLeft, cardTop, rotation, $(this).data("color"), e.clientX, e.clientY) + $('.add-post-it').on('click', function(e) { + const rotation = Math.random() * 10 - 5 // add a bit of random rotation (+/- 10deg) + const cardLeft = 150 + Math.random() * 400 + const cardTop = 20 + Math.random() * 50 + const uniqueID = Math.round(Math.random() * 99999999) // is this big enough to assure uniqueness? + console.log(e.clientX, e.clientY) + createCard(`card${uniqueID}`, '', cardLeft, cardTop, rotation, $(this).data('color'), e.clientX, e.clientY) }) // Style changer - $("#smallify").on("click", function () { - if (currentTheme == "bigcards") { - changeThemeTo("smallcards") - } else if (currentTheme == "smallcards") { - changeThemeTo("bigcards") + $('#smallify').on('click', () => { + if (currentTheme == 'bigcards') { + changeThemeTo('smallcards') + } else if (currentTheme == 'smallcards') { + changeThemeTo('bigcards') } - sendAction("changeTheme", currentTheme) + sendAction('changeTheme', currentTheme) return false }) - $("#icon-col").on( - "hover", - function () { - $(".col-icon").fadeIn(10) + $('#icon-col').on( + 'hover', + () => { + $('.col-icon').fadeIn(10) }, - function () { - $(".col-icon").fadeOut(150) + () => { + $('.col-icon').fadeOut(150) } ) - $("#add-col").on("click", function () { - createColumn("Nouvelle colonne") + $('#add-col').on('click', () => { + createColumn('Nouvelle colonne') return false }) - $("#delete-col").on("click", function () { + $('#delete-col').on('click', () => { deleteColumn() return false }) - var user_name = getCookie("scrumscrum-username") + const user_name = getCookie('scrumscrum-username') - $("#yourname-input").on("focus", function () { - if ($(this).val() == "anonyme") { - $(this).val("") + $('#yourname-input').on('focus', function() { + if ($(this).val() == 'anonyme') { + $(this).val('') } - $(this).addClass("focused") + $(this).addClass('focused') }) - $("#yourname-input").on("blur", function () { - if ($(this).val() === "") { - $(this).val("anonyme") + $('#yourname-input').on('blur', function() { + if ($(this).val() === '') { + $(this).val('anonyme') } - $(this).removeClass("focused") + $(this).removeClass('focused') setName($(this).val()) }) - $("#yourname-input").val(user_name) - $("#yourname-input").trigger("blur") + $('#yourname-input').val(user_name) + $('#yourname-input').trigger('blur') - $("#yourname-li").hide() + $('#yourname-li').hide() - $("#yourname-input").on("keypress", function (e) { + $('#yourname-input').on('keypress', function(e) { code = e.keyCode ? e.keyCode : e.which if (code == 10 || code == 13) { - $(this).trigger("blur") + $(this).trigger('blur') } }) - $(".sticker").draggable({ + $('.sticker').draggable({ revert: true, - zIndex: 1000, + zIndex: 1000 }) - $(".board-outline").resizable({ + $('.board-outline').resizable({ ghost: false, minWidth: 640, minHeight: 480, maxWidth: 1140, - maxHeight: 855, + maxHeight: 855 }) - //A new scope for precalculating - ;(function () { - var offsets + // A new scope for precalculating + ;(function() { + let offsets - $(".board-outline").on("resizestart", function () { + $('.board-outline').on('resizestart', () => { offsets = calcCardOffset() }) - $(".board-outline").on("resize", function (event, ui) { + $('.board-outline').on('resize', (event, ui) => { adjustCard(offsets, false) }) - $(".board-outline").on("resizestop", function (event, ui) { + $('.board-outline').on('resizestop', (event, ui) => { boardResizeHappened(event, ui) adjustCard(offsets, true) }) - })() + }()) - $("#marker").draggable({ - axis: "x", - containment: "parent", + $('#marker').draggable({ + axis: 'x', + containment: 'parent' }) - $("#eraser").draggable({ - axis: "x", - containment: "parent", + $('#eraser').draggable({ + axis: 'x', + containment: 'parent' }) - $("#export-txt").on("click", function () { + $('#export-txt').on('click', () => { socket.json.send({ - action: "exportTxt", - data: $(".col").length !== 0 ? $(".col").css("width").replace("px", "") : null, + action: 'exportTxt', + data: $('.col').length !== 0 ? $('.col').css('width').replace('px', '') : null }) }) - $("#export-csv").on("click", function () { + $('#export-csv').on('click', () => { socket.json.send({ - action: "exportCsv", - data: $(".col").length !== 0 ? $(".col").css("width").replace("px", "") : null, + action: 'exportCsv', + data: $('.col').length !== 0 ? $('.col').css('width').replace('px', '') : null }) }) - $("#export-json").on("click", function () { + $('#export-json').on('click', () => { socket.json.send({ - action: "exportJson", + action: 'exportJson', data: { - width: $(".board-outline").css("width").replace("px", ""), - height: $(".board-outline").css("height").replace("px", ""), - }, + width: $('.board-outline').css('width').replace('px', ''), + height: $('.board-outline').css('height').replace('px', '') + } }) }) - $("#import-file").on("click", function (evt) { + $('#import-file').on('click', (evt) => { evt.stopPropagation() evt.preventDefault() - var f = $("#import-input").get(0).files[0] - var fr = new FileReader() - fr.onloadend = function () { - var text = fr.result + const f = $('#import-input').get(0).files[0] + const fr = new FileReader() + fr.onloadend = function() { + const text = fr.result socket.json.send({ - action: "importJson", - data: JSON.parse(text), + action: 'importJson', + data: JSON.parse(text) }) } fr.readAsText(f) }) - $("#create-revision").on("click", function () { + $('#create-revision').on('click', () => { socket.json.send({ - action: "createRevision", + action: 'createRevision', data: { - width: $(".board-outline").css("width").replace("px", ""), - height: $(".board-outline").css("height").replace("px", ""), - }, + width: $('.board-outline').css('width').replace('px', ''), + height: $('.board-outline').css('height').replace('px', '') + } }) }) }) -/** Doubleclick on mobile + Layout Framemo with tabs **/ -$(document).ready(function () { - if (window.location.href != window.location.protocol + "//" + window.location.host + "/") { +/** Doubleclick on mobile + Layout Framemo with tabs * */ +$(document).ready(() => { + if (window.location.href != `${window.location.protocol}//${window.location.host}/`) { // Not on homepage - /** Double click on mobile interface **/ + /** Double click on mobile interface * */ - var clickTimer = null - var clickTarget = null - var editTarget = null + let clickTimer = null + let clickTarget = null + let editTarget = null function doubletapCards(selector) { - $(selector + " .stickertarget").addClass("doubletap") // Escape multi bound + $(`${selector} .stickertarget`).addClass('doubletap') // Escape multi bound - $(selector + " .doubletap").on("click", function () { - clickTarget = selector.replace("#", "") + $(`${selector} .doubletap`).on('click', () => { + clickTarget = selector.replace('#', '') if (clickTimer == null) { - clickTimer = setTimeout(function () { + clickTimer = setTimeout(() => { clickTimer = null }, 1000) } else { - //console.log('doubleclick : '+clickTimer+':'+editTarget); + // console.log('doubleclick : '+clickTimer+':'+editTarget); clearTimeout(clickTimer) clickTimer = null if (editTarget == clickTarget && clickTarget !== undefined && clickTarget !== null) { - $("#" + clickTarget.replace("content:", "") + " .doubletap").trigger("dblclick") + $(`#${clickTarget.replace('content:', '')} .doubletap`).trigger('dblclick') } } @@ -947,22 +938,22 @@ $(document).ready(function () { } function doubletapTitle(selector) { - $(selector).addClass("doubletap") // Escape multi bound + $(selector).addClass('doubletap') // Escape multi bound - $(selector + ".doubletap").on("click", function () { - clickTarget = selector.replace("#", "") + $(`${selector}.doubletap`).on('click', () => { + clickTarget = selector.replace('#', '') if (clickTimer == null) { - clickTimer = setTimeout(function () { + clickTimer = setTimeout(() => { clickTimer = null }, 1000) } else { - //console.log('doubleclick : '+clickTimer+':'+editTarget); + // console.log('doubleclick : '+clickTimer+':'+editTarget); clearTimeout(clickTimer) clickTimer = null if (editTarget == clickTarget && clickTarget !== undefined && clickTarget !== null) { - $("#" + clickTarget + ".doubletap").trigger("dblclick") + $(`#${clickTarget}.doubletap`).trigger('dblclick') } } @@ -970,36 +961,36 @@ $(document).ready(function () { }) } - setInterval(function () { + setInterval(() => { // Add periodically the doubletap event on new cards - $(".stickertarget:not(.doubletap)").each(function () { - doubletapCards("#" + $(this).attr("id").replace("content:", "")) + $('.stickertarget:not(.doubletap)').each(function() { + doubletapCards(`#${$(this).attr('id').replace('content:', '')}`) }) - $("#board-table .col h2:not(.doubletap)").each(function () { - doubletapTitle("#" + $(this).attr("id")) + $('#board-table .col h2:not(.doubletap)').each(function() { + doubletapTitle(`#${$(this).attr('id')}`) }) }, 500) - /** Layout Framemo - Tabs **/ + /** Layout Framemo - Tabs * */ // Defaut board real size (not 'auto' or 'inherit') saved in database // in order to be able to center it - var boardReady = setInterval(function () { + var boardReady = setInterval(() => { if (boardInitialized) { // when board is ready - if ($(".board-outline").attr("style") === undefined) { + if ($('.board-outline').attr('style') === undefined) { // check if size is imported from db - $(".board-outline").css({ - width: $(".board-outline.ui-resizable").width() + 16 + "px", - height: "466px", + $('.board-outline').css({ + width: `${$('.board-outline.ui-resizable').width() + 16}px`, + height: '466px' }) - var data = {} + const data = {} data.size = { height: 466, - width: $(".board-outline.ui-resizable").width() + 16, + width: $('.board-outline.ui-resizable').width() + 16 } - boardResizeHappened("resizestop", data) // using scrumblr function that keep size in db after a resize + boardResizeHappened('resizestop', data) // using scrumblr function that keep size in db after a resize } clearInterval(boardReady) } @@ -1020,45 +1011,45 @@ $(document).ready(function () { // $("#about").append($("#tuto-faq, #le-logiciel, #jardin")) // Style - $("#smallify").on("click", function () { - if (currentTheme == "bigcards") { - $(this).children("i").removeClass("fa-search-plus").addClass("fa-search-minus") + $('#smallify').on('click', function() { + if (currentTheme == 'bigcards') { + $(this).children('i').removeClass('fa-search-plus').addClass('fa-search-minus') } else { - $(this).children("i").removeClass("fa-search-minus").addClass("fa-search-plus") + $(this).children('i').removeClass('fa-search-minus').addClass('fa-search-plus') } }) - $("#full-page").on("click", function () { - if ($(this).children("i").hasClass("fa-expand")) { - $(this).children("i").removeClass("fa-expand").addClass("fa-compress") - $("#header-bar").hide() + $('#full-page').on('click', function() { + if ($(this).children('i').hasClass('fa-expand')) { + $(this).children('i').removeClass('fa-expand').addClass('fa-compress') + $('#header-bar').hide() } else { - $(this).children("i").removeClass("fa-compress").addClass("fa-expand") - $("#header-bar").show() + $(this).children('i').removeClass('fa-compress').addClass('fa-expand') + $('#header-bar').show() } toggleFullScreen() }) - /** Mode iframe **/ + /** Mode iframe * */ if (top.location != self.document.location) { - $("#header-bar").hide() + $('#header-bar').hide() } // put URL in share input - var mainurl = location.toString().split('#')[0] - $(".replace-url").val(mainurl) - $(".share-iframe").text($(".share-iframe").text().replace('{{replace-url}}', mainurl)) + const mainurl = location.toString().split('#')[0] + $('.replace-url').val(mainurl) + $('.share-iframe').text($('.share-iframe').text().replace('{{replace-url}}', mainurl)) // copy URL to clipboard - $("#copyurl").on("click", function (e) { + $('#copyurl').on('click', (e) => { e.preventDefault() - var node = document.getElementById("taburl") + const node = document.getElementById('taburl') node.disabled = null node.select() - var success = document.execCommand("copy") + const success = document.execCommand('copy') if (success) { getSelection().removeAllRanges() - node.disabled = "disabled" - alert("URL du tableau copiée dans votre presse-papier !") + node.disabled = 'disabled' + alert('URL du tableau copiée dans votre presse-papier !') } else { alert( "Impossible de copier l'URL du tableau dans votre presse-papier. Veuillez copier son adresse manuellement (Ctrl+C)." @@ -1069,20 +1060,20 @@ $(document).ready(function () { }) function go() { - var value = document.forms[0].elements["name"].value - value = value.replace(/[\/\?&#]/g, "") + let { value } = document.forms[0].elements.name + value = value.replace(/[\/\?&#]/g, '') window.location.href = value return false } -$(function () { - var headerBarUrl = $("#header-bar").data("url") +$(() => { + const headerBarUrl = $('#header-bar').data('url') if (headerBarUrl) { - var getJSON = function (url, callback) { - var xhr = new XMLHttpRequest() - xhr.open("GET", url, true) - xhr.responseType = "json" - xhr.onload = function () { - var status = xhr.status + const getJSON = function(url, callback) { + const xhr = new XMLHttpRequest() + xhr.open('GET', url, true) + xhr.responseType = 'json' + xhr.onload = function() { + const { status } = xhr if (status === 200) { callback(null, xhr.response) } else { @@ -1092,72 +1083,72 @@ $(function () { xhr.send() } - getJSON(headerBarUrl, function (err, data) { + getJSON(headerBarUrl, (err, data) => { if (err !== null) { - console.log("Something went wrong: " + err) + console.log(`Something went wrong: ${err}`) } else { - document.getElementById("header-bar").innerHTML = data.markup - var styleElement = document.createElement("style") + document.getElementById('header-bar').innerHTML = data.markup + const styleElement = document.createElement('style') styleElement.innerHTML = data.style - document.getElementById("header-bar").appendChild(styleElement) + document.getElementById('header-bar').appendChild(styleElement) } }) } }) -$(function () { +$(() => { // check if hash used to show informations if (window.location.hash == '#settings' || window.location.hash == '#share') { toggleNav(window.location.hash) } // Toggle Nav on Click - $(".toggle-nav").on("click", function () { - var target = $(this).attr("href") - + $('.toggle-nav').on('click', function() { + let target = $(this).attr('href') + if (target === '#' || ($('#site-wrapper').hasClass('show-nav') && target == window.location.hash)) { target = false - history.replaceState('', '', '#'); + history.replaceState('', '', '#') } else { - history.replaceState('', '', target); + history.replaceState('', '', target) } toggleNav(target) return false }) // When nav opened, a click on the canvas hides the menu - $("body").on("click", ".show-nav #site-canvas main, .show-nav .main-header", function (e) { - history.replaceState('', '', '#'); + $('body').on('click', '.show-nav #site-canvas main, .show-nav .main-header', (e) => { + history.replaceState('', '', '#') toggleNav(false) return false }) - $(".backgrounds .bg").on("click", function () { - if ($(this).hasClass("selected")) { - $("body").css("background-image", "none") - $(this).removeClass("selected") + $('.backgrounds .bg').on('click', function() { + if ($(this).hasClass('selected')) { + $('body').css('background-image', 'none') + $(this).removeClass('selected') } else { - $(".selected").removeClass("selected") + $('.selected').removeClass('selected') $('.bgurl').val('') - $("body").css("background-image", 'url("/' + $(this).attr("src") + '")') - $(this).addClass("selected") + $('body').css('background-image', `url("/${$(this).attr('src')}")`) + $(this).addClass('selected') } }) $('.bgurl').on('change', function() { - var url = $(this).val() + const url = $(this).val() if (url) { - $(".selected").removeClass("selected") - $("body").css("background-image", 'url("' + url + '")') + $('.selected').removeClass('selected') + $('body').css('background-image', `url("${url}")`) } }) }) function toggleNav(target) { - if ($("#site-wrapper").hasClass("show-nav") && target === false) { - $("#site-wrapper").removeClass("show-nav") + if ($('#site-wrapper').hasClass('show-nav') && target === false) { + $('#site-wrapper').removeClass('show-nav') } else { - $("#share, #settings").hide() + $('#share, #settings').hide() if (target !== false) { $(target).show() } - $("#site-wrapper").addClass("show-nav") + $('#site-wrapper').addClass('show-nav') } return false } diff --git a/config.js b/config.js index 5f48f99..0837e3a 100644 --- a/config.js +++ b/config.js @@ -1,4 +1,4 @@ -/*exports.database = { +/* exports.database = { type: 'mongodb', hostname: 'localhost', port: 27017, @@ -6,7 +6,7 @@ }; */ -var argv = require("yargs").usage( +const { argv } = require('yargs').usage( 'Usage: $0 [--port INTEGER [8080]] \ [--baseurl STRING ["/"]] \ [--redis STRING:INT [127.0.0.1:6379]] \ @@ -16,28 +16,27 @@ var argv = require("yargs").usage( [--logoUrl STRING] \ [--faviconUrl STRING] \ ' - -).argv +) exports.server = { port: argv.port || 8080, - baseurl: argv.baseurl || "/", + baseurl: argv.baseurl || '/' } exports.googleanalytics = { - enabled: argv["gaEnabled"] || false, - account: argv["gaAccount"] || "UA-2069672-4", + enabled: argv.gaEnabled || false, + account: argv.gaAccount || 'UA-2069672-4' } -var redis_conf = argv.redis || "127.0.0.1:6379" +const redis_conf = argv.redis || '127.0.0.1:6379' exports.database = { - sock: argv["sock"] || false, - type: "redis", - prefix: "#scrumblr#", - host: redis_conf.split(":")[0] || "127.0.0.1", - port: redis_conf.split(":")[1] || 6379, + sock: argv.sock || false, + type: 'redis', + prefix: '#scrumblr#', + host: redis_conf.split(':')[0] || '127.0.0.1', + port: redis_conf.split(':')[1] || 6379 } -exports.headerBarUrl = argv['headerBarUrl'] || null /* example url with appropriate json markup : 'https://colibris-lemouvement.org/archipel-markup?domain=colibris-outilslibres.org' */ -exports.logoUrl = argv['logoUrl'] || null /* example logo url : 'https://postit.colibris-outilslibres.org/images/logo-Post-it.svg' */ -exports.faviconUrl = argv['faviconUrl'] || null /* example favicon url : 'https://postit.colibris-outilslibres.org/images/favicon.png' */ \ No newline at end of file +exports.headerBarUrl = argv.headerBarUrl || null /* example url with appropriate json markup : 'https://colibris-lemouvement.org/archipel-markup?domain=colibris-outilslibres.org' */ +exports.logoUrl = argv.logoUrl || null /* example logo url : 'https://postit.colibris-outilslibres.org/images/logo-Post-it.svg' */ +exports.faviconUrl = argv.faviconUrl || null /* example favicon url : 'https://postit.colibris-outilslibres.org/images/favicon.png' */ diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..10806fd --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,49 @@ +import { defineConfig, globalIgnores } from 'eslint/config' +import globals from 'globals' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import js from '@eslint/js' +import { FlatCompat } from '@eslint/eslintrc' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, + allConfig: js.configs.all +}) + +export default defineConfig([globalIgnores([ + 'node_modules', + 'client/lib' +]), { + extends: compat.extends('airbnb-base'), + + languageOptions: { ecmaVersion: 13 }, + + rules: { + semi: ['error', 'never'], + + 'max-len': ['error', { code: 104 }], + + 'vars-on-top': 'off', + 'class-methods-use-this': 'off', + 'import/no-unresolved': 'off', + 'import/extensions': ['error', 'always'], + 'import/prefer-default-export': ['off'], + 'no-use-before-define': ['off'], + eqeqeq: ['error', 'smart'], + 'comma-dangle': ['error', 'never'], + + 'object-curly-newline': ['error', { multiline: true }], + + 'func-names': ['error', 'never'], + 'space-before-function-paren': ['error', 'never'], + + 'lines-between-class-members': ['error', 'always', { exceptAfterSingleLine: true }], + + 'no-new': 'off', + 'no-restricted-syntax': 'off', + 'guard-for-in': 'off' + } +}]) diff --git a/lib/data.js b/lib/data.js index d1cc2a6..b816336 100644 --- a/lib/data.js +++ b/lib/data.js @@ -1,6 +1,6 @@ -var conf = require('../config.js').database; +const conf = require('../config.js').database -exports.db = require('./data/'+conf.type+'.js').db; +exports.db = require(`./data/${conf.type}.js`).db /* var db = function(callback) { } diff --git a/lib/data/mongodb.js b/lib/data/mongodb.js index f0503b2..10d12ed 100644 --- a/lib/data/mongodb.js +++ b/lib/data/mongodb.js @@ -1,195 +1,181 @@ -var Db = require('mongodb').Db; - Server = require('mongodb').Server, - BSON = require('mongodb').BSONNative, - conf = require('../../config.js').database; +const { Db } = require('mongodb') +Server = require('mongodb').Server, +BSON = require('mongodb').BSONNative, +conf = require('../../config.js').database -var db = function(callback) -{ - this.rooms = false; - var t = this; +const db = function(callback) { + this.rooms = false + const t = this - var db = new Db(conf.database, new Server(conf.hostname, conf.port), {native_parser:true}); - db.open(function(err, db) { - db.collection('rooms', function(err, collection) { - // make sure we have an index on name - collection.ensureIndex([['name',1]],false,function() {}); - t.rooms = collection; - }); - callback(); - }); + const db = new Db(conf.database, new Server(conf.hostname, conf.port), { native_parser: true }) + db.open((err, db) => { + db.collection('rooms', (err, collection) => { + // make sure we have an index on name + collection.ensureIndex([['name', 1]], false, () => {}) + t.rooms = collection + }) + callback() + }) } db.prototype = { - clearRoom: function(room, callback) - { - this.rooms.remove({name:room},callback); - }, + clearRoom(room, callback) { + this.rooms.remove({ name: room }, callback) + }, - // theme commands - setTheme: function(room, theme) - { - this.rooms.update( - {name:room}, - {$set:{theme:theme}} - ); - }, + // theme commands + setTheme(room, theme) { + this.rooms.update( + { name: room }, + { $set: { theme } } + ) + }, - getTheme: function(room, callback) - { - this.rooms.findOne( - {name:room}, - {theme:true}, - function(err, room) { - if(room) { - callback(room.theme); - } else { - callback(); - } - } - ); - }, + getTheme(room, callback) { + this.rooms.findOne( + { name: room }, + { theme: true }, + (err, room) => { + if (room) { + callback(room.theme) + } else { + callback() + } + } + ) + }, - // revision commands - setRevisions: function(room, revisions) { - this.rooms.update( - {name:room}, - {$set:{revisions:revisions}} - ); - }, + // revision commands + setRevisions(room, revisions) { + this.rooms.update( + { name: room }, + { $set: { revisions } } + ) + }, - getRevisions: function(room, callback) { - this.rooms.findOne( - {name:room}, - {revisions:true}, - function(err, room) { - if(room) { - callback(room.revisions); - } else { - callback(); - } - } - ); - }, + getRevisions(room, callback) { + this.rooms.findOne( + { name: room }, + { revisions: true }, + (err, room) => { + if (room) { + callback(room.revisions) + } else { + callback() + } + } + ) + }, - // Column commands - createColumn: function(room, name, callback) - { - this.rooms.update( - {name:room}, - {$push:{columns:name}}, - {upsert:true} - ,callback - ); - }, + // Column commands + createColumn(room, name, callback) { + this.rooms.update( + { name: room }, + { $push: { columns: name } }, + { upsert: true }, + callback + ) + }, - getAllColumns: function(room, callback) - { - this.rooms.findOne({name:room},{columns:true},function(err, room) { - if(room) { - callback(room.columns); - } else { - callback(); - } - }); - }, + getAllColumns(room, callback) { + this.rooms.findOne({ name: room }, { columns: true }, (err, room) => { + if (room) { + callback(room.columns) + } else { + callback() + } + }) + }, - deleteColumn: function(room) - { - this.rooms.update( - {name:room}, - {$pop:{columns:1}} - ); - }, + deleteColumn(room) { + this.rooms.update( + { name: room }, + { $pop: { columns: 1 } } + ) + }, - setColumns: function(room, columns) - { - this.rooms.update( - {name:room}, - {$set:{columns:columns}}, - {upsert:true} - ); - }, + setColumns(room, columns) { + this.rooms.update( + { name: room }, + { $set: { columns } }, + { upsert: true } + ) + }, - // Card commands - createCard: function(room, id, card) - { - var doc = {}; - doc['cards.'+id] = card; - this.rooms.update( - {name:room}, - {$set:doc}, - {upsert:true} - ); - }, + // Card commands + createCard(room, id, card) { + const doc = {} + doc[`cards.${id}`] = card + this.rooms.update( + { name: room }, + { $set: doc }, + { upsert: true } + ) + }, - getAllCards: function(room, callback) - { - this.rooms.findOne({name:room},{cards:true},function(err, room) { - if(room) { - callback(room.cards); - } else { - callback(); - } - }); - }, + getAllCards(room, callback) { + this.rooms.findOne({ name: room }, { cards: true }, (err, room) => { + if (room) { + callback(room.cards) + } else { + callback() + } + }) + }, - cardEdit: function(room, id, text) - { - var doc = {}; - doc['cards.'+id+'.text'] = text; - this.rooms.update( - {name:room}, - {$set:doc} - ); - }, + cardEdit(room, id, text) { + const doc = {} + doc[`cards.${id}.text`] = text + this.rooms.update( + { name: room }, + { $set: doc } + ) + }, - cardSetXY: function(room, id, x, y) - { - var doc = {}; - doc['cards.'+id+'.x'] = x; - doc['cards.'+id+'.y'] = y; - this.rooms.update( - {name:room}, - {$set:doc} - ); - }, + cardSetXY(room, id, x, y) { + const doc = {} + doc[`cards.${id}.x`] = x + doc[`cards.${id}.y`] = y + this.rooms.update( + { name: room }, + { $set: doc } + ) + }, - deleteCard: function(room, id) - { - var doc = {}; - doc['cards.'+id] = true; - this.rooms.update( - {name:room}, - {$unset:doc} - ); - }, + deleteCard(room, id) { + const doc = {} + doc[`cards.${id}`] = true + this.rooms.update( + { name: room }, + { $unset: doc } + ) + }, - addSticker: function(room, cardId, stickerId) - { - var doc = {}; - doc['cards.'+cardId+'.sticker'] = stickerId; - this.rooms.update( - {name:room}, - {$set:doc} - ); - }, - getBoardSize: function(room, callback) { - this.rooms.findOne( - {name:room}, - function(err, room) { - if(room) { - callback(room.size); - } else { - callback(); - } - } - ); - }, - setBoardSize: function(room, size) { - this.rooms.update( - {name:room}, - {$set:{'size':size}} - ); - } -}; -exports.db = db; + addSticker(room, cardId, stickerId) { + const doc = {} + doc[`cards.${cardId}.sticker`] = stickerId + this.rooms.update( + { name: room }, + { $set: doc } + ) + }, + getBoardSize(room, callback) { + this.rooms.findOne( + { name: room }, + (err, room) => { + if (room) { + callback(room.size) + } else { + callback() + } + } + ) + }, + setBoardSize(room, size) { + this.rooms.update( + { name: room }, + { $set: { size } } + ) + } +} +exports.db = db diff --git a/lib/data/redis.js b/lib/data/redis.js index e672da2..5fd6027 100644 --- a/lib/data/redis.js +++ b/lib/data/redis.js @@ -1,202 +1,197 @@ -var conf = require('../../config.js').database; +const conf = require('../../config.js').database -var redis = require("redis"), - redisClient = null; //redis.createClient(); +const redis = require('redis') -var async = require("async"); -var sets = require('simplesets'); +let redisClient = null // redis.createClient(); + +const async = require('async') +const sets = require('simplesets') // If you want Memory Store instead... // var MemoryStore = require('connect/middleware/session/memory'); // var session_store = new MemoryStore(); -var REDIS_PREFIX = '#scrumblr#'; +const REDIS_PREFIX = '#scrumblr#' -//For Redis Debugging +// For Redis Debugging +const db = function(callback) { + if (conf.sock) { + console.log(`Opening redis connection to socket ${conf.host}`) + redisClient = redis.createClient(conf.host) + } else { + console.log(`Opening redis connection to ${conf.host}:${conf.port}`) + redisClient = redis.createClient(conf.port, conf.host, {}) + } + redisClient.on('connect', (err) => { + callback() + }) -var db = function(callback) { - if (conf.sock) { - console.log('Opening redis connection to socket ' + conf.host); - redisClient = redis.createClient(conf.host); - } else { - console.log('Opening redis connection to ' + conf.host + ':' + conf.port); - redisClient = redis.createClient(conf.port, conf.host, {}); - } - redisClient.on("connect", function (err) { - callback(); - }); - - redisClient.on("error", function (err) { - console.log("Redis error: " + err); - }); - -}; + redisClient.on('error', (err) => { + console.log(`Redis error: ${err}`) + }) +} db.prototype = { - clearRoom: function(room, callback) { - redisClient.del(REDIS_PREFIX + '-room:/demo-cards', function (err, res) { - redisClient.del(REDIS_PREFIX + '-room:/demo-columns', function (err, res) { - callback(); - }); - }); - }, + clearRoom(room, callback) { + redisClient.del(`${REDIS_PREFIX}-room:/demo-cards`, (err, res) => { + redisClient.del(`${REDIS_PREFIX}-room:/demo-columns`, (err, res) => { + callback() + }) + }) + }, - // theme commands - setTheme: function(room, theme) { - redisClient.set(REDIS_PREFIX + '-room:' + room + '-theme', theme); - }, + // theme commands + setTheme(room, theme) { + redisClient.set(`${REDIS_PREFIX}-room:${room}-theme`, theme) + }, - getTheme: function(room, callback) { - redisClient.get(REDIS_PREFIX + '-room:' + room + '-theme', function (err, res) { - callback(res); - }); - }, + getTheme(room, callback) { + redisClient.get(`${REDIS_PREFIX}-room:${room}-theme`, (err, res) => { + callback(res) + }) + }, - // revision commands - setRevisions: function(room, revisions) { - if (Object.keys(revisions).length === 0) { - redisClient.del(REDIS_PREFIX + '-room:' + room + '-revisions'); - } else { - redisClient.set(REDIS_PREFIX + '-room:' + room + '-revisions', JSON.stringify(revisions)); - } - }, + // revision commands + setRevisions(room, revisions) { + if (Object.keys(revisions).length === 0) { + redisClient.del(`${REDIS_PREFIX}-room:${room}-revisions`) + } else { + redisClient.set(`${REDIS_PREFIX}-room:${room}-revisions`, JSON.stringify(revisions)) + } + }, - getRevisions: function(room, callback) { - redisClient.get(REDIS_PREFIX + '-room:' + room + '-revisions', function (err, res) { - callback(JSON.parse(res)); - }); - }, + getRevisions(room, callback) { + redisClient.get(`${REDIS_PREFIX}-room:${room}-revisions`, (err, res) => { + callback(JSON.parse(res)) + }) + }, - // Column commands - createColumn: function(room, name, callback) { - redisClient.rpush(REDIS_PREFIX + '-room:' + room + '-columns', name, - function (err, res) { - if (typeof callback != "undefined" && callback !== null) callback(); - } - ); - }, + // Column commands + createColumn(room, name, callback) { + redisClient.rpush( + `${REDIS_PREFIX}-room:${room}-columns`, + name, + (err, res) => { + if (typeof callback != 'undefined' && callback !== null) callback() + } + ) + }, - getAllColumns: function(room, callback) { - redisClient.lrange(REDIS_PREFIX + '-room:' + room + '-columns', 0, -1, function(err, res) { - callback(res); - }); - }, + getAllColumns(room, callback) { + redisClient.lrange(`${REDIS_PREFIX}-room:${room}-columns`, 0, -1, (err, res) => { + callback(res) + }) + }, - deleteColumn: function(room) { - redisClient.rpop(REDIS_PREFIX + '-room:' + room + '-columns'); - }, + deleteColumn(room) { + redisClient.rpop(`${REDIS_PREFIX}-room:${room}-columns`) + }, - setColumns: function(room, columns) { - //1. first delete all columns - redisClient.del(REDIS_PREFIX + '-room:' + room + '-columns', function () { - //2. now add columns for each thingy - async.forEachSeries( - columns, - function( item, callback ) { - //console.log('rpush: ' + REDIS_PREFIX + '-room:' + room + '-columns' + ' -- ' + item); - redisClient.rpush(REDIS_PREFIX + '-room:' + room + '-columns', item, - function (err, res) { - callback(); - } - ); - }, - function() { - //this happens when the series is complete - } - ); - }); - }, + setColumns(room, columns) { + // 1. first delete all columns + redisClient.del(`${REDIS_PREFIX}-room:${room}-columns`, () => { + // 2. now add columns for each thingy + async.forEachSeries( + columns, + (item, callback) => { + // console.log('rpush: ' + REDIS_PREFIX + '-room:' + room + '-columns' + ' -- ' + item); + redisClient.rpush( + `${REDIS_PREFIX}-room:${room}-columns`, + item, + (err, res) => { + callback() + } + ) + }, + () => { + // this happens when the series is complete + } + ) + }) + }, - // Card commands - createCard: function(room, id, card) { - var cardString = JSON.stringify(card); - redisClient.hset( - REDIS_PREFIX + '-room:' + room + '-cards', - id, - cardString - ); - }, + // Card commands + createCard(room, id, card) { + const cardString = JSON.stringify(card) + redisClient.hset( + `${REDIS_PREFIX}-room:${room}-cards`, + id, + cardString + ) + }, - getAllCards: function(room, callback) { - redisClient.hgetall(REDIS_PREFIX + '-room:' + room + '-cards', function (err, res) { + getAllCards(room, callback) { + redisClient.hgetall(`${REDIS_PREFIX}-room:${room}-cards`, (err, res) => { + const cards = [] - var cards = []; + for (const i in res) { + cards.push(JSON.parse(res[i])) + } + // console.dir(cards); - for (var i in res) { - cards.push( JSON.parse(res[i]) ); - } - //console.dir(cards); + callback(cards) + }) + }, - callback(cards); - }); - }, + cardEdit(room, id, text) { + redisClient.hget(`${REDIS_PREFIX}-room:${room}-cards`, id, (err, res) => { + const card = JSON.parse(res) + if (card !== null) { + card.text = text + redisClient.hset(`${REDIS_PREFIX}-room:${room}-cards`, id, JSON.stringify(card)) + } + }) + }, - cardEdit: function(room, id, text) { - redisClient.hget(REDIS_PREFIX + '-room:' + room + '-cards', id, function(err, res) { - var card = JSON.parse(res); - if (card !== null) { - card.text = text; - redisClient.hset(REDIS_PREFIX + '-room:' + room + '-cards', id, JSON.stringify(card)); - } - }); - }, + cardSetXY(room, id, x, y) { + redisClient.hget(`${REDIS_PREFIX}-room:${room}-cards`, id, (err, res) => { + const card = JSON.parse(res) + if (card !== null) { + card.x = x + card.y = y + redisClient.hset(`${REDIS_PREFIX}-room:${room}-cards`, id, JSON.stringify(card)) + } + }) + }, - cardSetXY: function(room, id, x, y) { - redisClient.hget(REDIS_PREFIX + '-room:' + room + '-cards', id, function(err, res) { - var card = JSON.parse(res); - if (card !== null) { - card.x = x; - card.y = y; - redisClient.hset(REDIS_PREFIX + '-room:' + room + '-cards', id, JSON.stringify(card)); - } - }); - }, + deleteCard(room, id) { + redisClient.hdel( + `${REDIS_PREFIX}-room:${room}-cards`, + id + ) + }, - deleteCard: function(room, id) { - redisClient.hdel( - REDIS_PREFIX + '-room:' + room + '-cards', - id - ); - }, + addSticker(room, cardId, stickerId) { + redisClient.hget(`${REDIS_PREFIX}-room:${room}-cards`, cardId, (err, res) => { + const card = JSON.parse(res) + if (card !== null) { + if (stickerId === 'nosticker') { + card.sticker = null - addSticker: function(room, cardId, stickerId) { - redisClient.hget(REDIS_PREFIX + '-room:' + room + '-cards', cardId, function(err, res) { - var card = JSON.parse(res); - if (card !== null) { - if (stickerId === "nosticker") - { - card.sticker = null; + redisClient.hset(`${REDIS_PREFIX}-room:${room}-cards`, cardId, JSON.stringify(card)) + } else { + if (card.sticker !== null) { stickerSet = new sets.Set(card.sticker) } else { stickerSet = new sets.Set() } - redisClient.hset(REDIS_PREFIX + '-room:' + room + '-cards', cardId, JSON.stringify(card)); - } - else - { - if (card.sticker !== null) - stickerSet = new sets.Set( card.sticker ); - else - stickerSet = new sets.Set(); + stickerSet.add(stickerId) - stickerSet.add(stickerId); + card.sticker = stickerSet.array() - card.sticker = stickerSet.array(); + redisClient.hset(`${REDIS_PREFIX}-room:${room}-cards`, cardId, JSON.stringify(card)) + } + } + }) + }, - redisClient.hset(REDIS_PREFIX + '-room:' + room + '-cards', cardId, JSON.stringify(card)); - } + setBoardSize(room, size) { + redisClient.set(`${REDIS_PREFIX}-room:${room}-size`, JSON.stringify(size)) + }, - } - }); - }, + getBoardSize(room, callback) { + redisClient.get(`${REDIS_PREFIX}-room:${room}-size`, (err, res) => { + callback(JSON.parse(res)) + }) + } - setBoardSize: function(room, size) { - redisClient.set(REDIS_PREFIX + '-room:' + room + '-size', JSON.stringify(size)); - }, - - getBoardSize: function(room, callback) { - redisClient.get(REDIS_PREFIX + '-room:' + room + '-size', function (err, res) { - callback(JSON.parse(res)); - }); - } - -}; -exports.db = db; +} +exports.db = db diff --git a/lib/rooms.js b/lib/rooms.js index 0648212..7682077 100644 --- a/lib/rooms.js +++ b/lib/rooms.js @@ -3,153 +3,137 @@ // PubSubCore: Simple pub/sub library for Node.js and Socket.IO -var util = require('util'); -var sets = require('simplesets'); -var io = require('socket.io'); -var net = require('net'); +const util = require('util') +const sets = require('simplesets') +const io = require('socket.io') +const net = require('net') -////////////////////////////// +/// /////////////////////////// // Tracking who's in what room -////////////////////////////// +/// /////////////////////////// // Dict mapping room names with people to sets of client objects. -var rooms = {}; +const rooms = {} // Dict mapping room names with people to sets of usernames. -var room_users = {}; +const room_users = {} // Dict mapping sids to sets of rooms. -var sid_rooms = {}; - +const sid_rooms = {} // Add a client to a room and return the sid:client mapping. -exports.add_to_room = function (client, room, callback) { - //console.log('Client ' + client.username + ' (' + client.id + ') added to room ' + room); +exports.add_to_room = function(client, room, callback) { + // console.log('Client ' + client.username + ' (' + client.id + ') added to room ' + room); - if (!(sid_rooms.hasOwnProperty(client.id))) sid_rooms[client.id] = new sets.Set(); - sid_rooms[client.id].add(room); + if (!(sid_rooms.hasOwnProperty(client.id))) sid_rooms[client.id] = new sets.Set() + sid_rooms[client.id].add(room) - if (!(rooms.hasOwnProperty(room))) rooms[room] = new sets.Set(); - rooms[room].add(client); + if (!(rooms.hasOwnProperty(room))) rooms[room] = new sets.Set() + rooms[room].add(client) - if (!(room_users.hasOwnProperty(room))) room_users[room] = new sets.Set(); - room_users[room].add(client.username); + if (!(room_users.hasOwnProperty(room))) room_users[room] = new sets.Set() + room_users[room].add(client.username) - callback(rooms[room].array()); -}; + callback(rooms[room].array()) +} // Remove a client from all rooms and return the username:client // mapping for everybody in those rooms. -exports.remove_from_all_rooms = function (client, callback) { - var affected_clients = new sets.Set(); - if (sid_rooms.hasOwnProperty(client.id)) { - var client_rooms = sid_rooms[client.id].array(); - for (var i = 0; i < client_rooms.length; i++) { - var room = client_rooms[i]; +exports.remove_from_all_rooms = function(client, callback) { + const affected_clients = new sets.Set() + if (sid_rooms.hasOwnProperty(client.id)) { + const client_rooms = sid_rooms[client.id].array() + for (let i = 0; i < client_rooms.length; i++) { + const room = client_rooms[i] if (rooms.hasOwnProperty(room)) { - rooms[room].remove(client); - if (rooms[room].size() === 0) - delete rooms[room]; + rooms[room].remove(client) + if (rooms[room].size() === 0) { delete rooms[room] } } if (room_users.hasOwnProperty(room)) { - room_users[room].remove(client.username); - if (room_users[room].size() === 0) - delete room_users[room]; + room_users[room].remove(client.username) + if (room_users[room].size() === 0) { delete room_users[room] } } if (rooms.hasOwnProperty(room)) { - var this_room = rooms[room].array(); - for (var j = 0; j < this_room.length; j++) - affected_clients.add(this_room[j]); + const this_room = rooms[room].array() + for (let j = 0; j < this_room.length; j++) { affected_clients.add(this_room[j]) } } - } } - //console.log('Client ' + client.username + ' (' + client.id + ') disconnected.'); - delete sid_rooms[client.id]; - callback(affected_clients.array()); -}; + } + // console.log('Client ' + client.username + ' (' + client.id + ') disconnected.'); + delete sid_rooms[client.id] + callback(affected_clients.array()) +} // Remove a client from a room and return the username:client mapping // for everybody in that room. Returns [] if the room does not exist, // or if the client was not in the room to begin with. function remove_from_room(client, room, callback) { - if (!rooms.hasOwnProperty(room) || !rooms[room].has(client)) { - callback([]); - return; - } + if (!rooms.hasOwnProperty(room) || !rooms[room].has(client)) { + callback([]) + return + } - // Delete from the room - rooms[room].remove(client); - if (rooms[room].size() === 0) - delete rooms[room]; - if (room_users.hasOwnProperty(room)) { - room_users[room].remove(client.username); - if (room_users[room].size() === 0) - delete room_users[room]; - } + // Delete from the room + rooms[room].remove(client) + if (rooms[room].size() === 0) { delete rooms[room] } + if (room_users.hasOwnProperty(room)) { + room_users[room].remove(client.username) + if (room_users[room].size() === 0) { delete room_users[room] } + } - callback(exports.room_clients(room)); + callback(exports.room_clients(room)) } // Return list of clients in the given room. exports.room_clients = function(room) { - return rooms.hasOwnProperty(room) ? rooms[room].array() : []; -}; + return rooms.hasOwnProperty(room) ? rooms[room].array() : [] +} // Return true if room contains the given client, false otherwise. exports.client_in_room = function(room, client) { - return rooms.hasOwnProperty(room) && rooms[room].has(client); -}; + return rooms.hasOwnProperty(room) && rooms[room].has(client) +} // Return list of usernames in given room exports.users_in_room = function(room) { - return room_users.hasOwnProperty(room) ? room_users[room].array() : []; -}; + return room_users.hasOwnProperty(room) ? room_users[room].array() : [] +} // Return list of usernames in given room exports.room_clients_other_than_me = function(room, client) { - if (rooms.hasOwnProperty(room)) - { - var clients = rooms[room]; - //console.dir(clients.array()); + if (rooms.hasOwnProperty(room)) { + const clients = rooms[room] + // console.dir(clients.array()); - clients.remove(client); - //console.dir(clients.array()); - return clients.array(); - } - else - { - return []; - } -}; + clients.remove(client) + // console.dir(clients.array()); + return clients.array() + } -//gets the current room of the client (assumes one room -- will select first one if in multiple) -exports.get_room = function (client) { - var client_rooms = null; + return [] +} - if (sid_rooms.hasOwnProperty(client.id)) - { - client_rooms = sid_rooms[client.id].array(); - } +// gets the current room of the client (assumes one room -- will select first one if in multiple) +exports.get_room = function(client) { + let client_rooms = null - if ( client_rooms !== null ) - return client_rooms[0]; - else - return null; -}; + if (sid_rooms.hasOwnProperty(client.id)) { + client_rooms = sid_rooms[client.id].array() + } + if (client_rooms !== null) { return client_rooms[0] } + return null +} // Generic server code -exports.add_to_room_and_announce = function (client, room, msg) { - - // Add user info to the current dramatis personae - exports.add_to_room(client, room, function(clients) { +exports.add_to_room_and_announce = function(client, room, msg) { + // Add user info to the current dramatis personae + exports.add_to_room(client, room, (clients) => { // Broadcast new-user notification - for (var i = 0; i < clients.length; i++) - { - if (clients[i].id != client.id) - clients[i].json.send(msg); - } - }); -}; + for (let i = 0; i < clients.length; i++) { + if (clients[i].id != client.id) { clients[i].json.send(msg) } + } + }) +} /* exports.on_leave_room = function (client, room) { @@ -165,67 +149,58 @@ exports.on_leave_room = function (client, room) { }); }); -}*/ +} */ -//remember that this announces to all rooms that this client was a member of -exports.remove_from_all_rooms_and_announce = function (client, msg) { - exports.remove_from_all_rooms(client, function(clients) { - for (var i = 0; i < clients.length; i++) - { - if (clients[i].id != client.id) - clients[i].json.send(msg); - } - }); -}; +// remember that this announces to all rooms that this client was a member of +exports.remove_from_all_rooms_and_announce = function(client, msg) { + exports.remove_from_all_rooms(client, (clients) => { + for (let i = 0; i < clients.length; i++) { + if (clients[i].id != client.id) { clients[i].json.send(msg) } + } + }) +} -////////////////////////////// +/// /////////////////////////// // Broadcasting functions -////////////////////////////// +/// /////////////////////////// // Broadcast message to all clients exports.broadcast = function(msg) { - if (socket) socket.broadcast(msg); - net_server_streams.each(function(stream) { - stream.write(JSON.stringify(msg)+'\r\n'); - }); -}; + if (socket) socket.broadcast(msg) + net_server_streams.each((stream) => { + stream.write(`${JSON.stringify(msg)}\r\n`) + }) +} // Broadcast message to all clients in a given room. exports.broadcast_room = function(room, msg) { - var clients = exports.room_clients(room); - for (var i = 0; i < clients.length; i++) - clients[i].json.send(msg); -}; + const clients = exports.room_clients(room) + for (let i = 0; i < clients.length; i++) { clients[i].json.send(msg) } +} // Broadcast message to all the other clients that are in rooms with this client -exports.broadcast_to_roommates = function (client, msg) { - var roommates = new sets.Set(); +exports.broadcast_to_roommates = function(client, msg) { + let roommates = new sets.Set() - if (sid_rooms.hasOwnProperty(client.id)) - { - var client_rooms = sid_rooms[client.id].array(); - for (var i = 0; i < client_rooms.length; i++) - { - var room = client_rooms[i]; - if (rooms.hasOwnProperty(room)) - { - var this_room = rooms[room].array(); - for (var j = 0; j < this_room.length; j++) - roommates.add(this_room[j]); + if (sid_rooms.hasOwnProperty(client.id)) { + const client_rooms = sid_rooms[client.id].array() + for (let i = 0; i < client_rooms.length; i++) { + const room = client_rooms[i] + if (rooms.hasOwnProperty(room)) { + const this_room = rooms[room].array() + for (let j = 0; j < this_room.length; j++) { roommates.add(this_room[j]) } } - } - } + } + } - //remove self from the set - roommates.remove(client); - roommates = roommates.array(); + // remove self from the set + roommates.remove(client) + roommates = roommates.array() - //console.log('client: ' + client.id + " is broadcasting to: "); + // console.log('client: ' + client.id + " is broadcasting to: "); - - for (var k = 0; k < roommates.length; k++) - { - //console.log(' - ' + roommates[i].id); - roommates[k].json.send(msg); - } -}; + for (let k = 0; k < roommates.length; k++) { + // console.log(' - ' + roommates[i].id); + roommates[k].json.send(msg) + } +} diff --git a/package.json b/package.json index bc4652b..abe2fd4 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ }, "author": "Florian Schmitt", "scripts": { + "lint-js": "eslint --fix --ext .js,.ts .", "start": "nodemon server.js -e js,css,jade,json" }, "nodemonConfig": { @@ -34,6 +35,13 @@ "yargs": "~2.3.0" }, "devDependencies": { + "@eslint/eslintrc": "^3.3.0", + "@eslint/js": "^9.22.0", + "eslint": "^9.22.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-plugin-import": "^2.31", + "globals": "^16.0.0", + "prettier": "^3.5", "forever": "^0.15.3", "nodemon": "^2.0.16" } diff --git a/server.js b/server.js index 3ebeb54..299ed02 100644 --- a/server.js +++ b/server.js @@ -1,188 +1,190 @@ // vim:set noexpandtab: -/************** +/** ************ SYSTEM INCLUDES -**************/ -var http = require("http"); -var reload = require("reload"); -var sanitizer = require("sanitizer"); -var compression = require("compression"); -var express = require("express"); -var conf = require("./config.js").server; -var headerBarUrl = require("./config.js").headerBarUrl; -var logoUrl = require("./config.js").logoUrl; +************* */ +const http = require('http') +const reload = require('reload') +const sanitizer = require('sanitizer') +const compression = require('compression') +const express = require('express') +const conf = require('./config.js').server +const { headerBarUrl } = require('./config.js') +const { logoUrl } = require('./config.js') -/************** +/** ************ LOCAL INCLUDES -**************/ -var rooms = require("./lib/rooms.js"); -var data = require("./lib/data.js").db; +************* */ +const rooms = require('./lib/rooms.js') +let data = require('./lib/data.js').db -/************** +/** ************ GLOBALS -**************/ -//Map of sids to user_names -var sids_to_user_names = []; +************* */ +// Map of sids to user_names +const sids_to_user_names = [] -/************** +/** ************ SETUP EXPRESS -**************/ -var app = express(); -var router = express.Router(); +************* */ +const app = express() +const router = express.Router() -app.use(compression()); -app.use(conf.baseurl, router); +app.use(compression()) +app.use(conf.baseurl, router) + +router.use(express.static(`${__dirname}/node_modules`)) +router.use(express.static(`${__dirname}/client`)) + +const server = http.createServer(app) -router.use(express.static(__dirname + "/node_modules")); -router.use(express.static(__dirname + "/client")); -var server = http.createServer(app); // Reload code here reload(app) - .then(function (reloadReturned) { + .then((reloadReturned) => { // reloadReturned is documented in the returns API in the README // Reload started, start web server - server.listen(conf.port, function () { - console.log("Web server available on http://127.0.0.1:" + conf.port); - }); + server.listen(conf.port, () => { + console.log(`Web server available on http://127.0.0.1:${conf.port}`) + }) }) - .catch(function (err) { + .catch((err) => { console.error( - "Reload could not start, could not start server/sample app", + 'Reload could not start, could not start server/sample app', err - ); - }); + ) + }) -/************** +/** ************ SETUP Socket.IO -**************/ -var io = require("socket.io")(server, { - path: conf.baseurl == "/" ? "" : conf.baseurl + "/socket.io", +************* */ + +const io = require('socket.io')(server, { + path: conf.baseurl == '/' ? '' : `${conf.baseurl}/socket.io`, cookie: false -}); +}) -/************** +/** ************ ROUTES -**************/ -router.get("/", function (req, res) { - //console.log(req.header('host')); - url = req.header("host") + req.baseUrl; - var connected = io.sockets.connected; - clientsCount = Object.keys(connected).length; - res.render("home.jade", { - url: url, - headerBarUrl: headerBarUrl, - logoUrl: logoUrl, +************* */ +router.get('/', (req, res) => { + // console.log(req.header('host')); + url = req.header('host') + req.baseUrl + const { connected } = io.sockets + clientsCount = Object.keys(connected).length + res.render('home.jade', { + url, + headerBarUrl, + logoUrl, connected: clientsCount, - home: true, - }); -}); + home: true + }) +}) -router.get("/demo", function (req, res) { - url = req.header("host") + req.baseUrl; - res.render("index.jade", { - pageTitle: "Post-it - demo", - headerBarUrl: headerBarUrl, - logoUrl: logoUrl, - url: url, - demo: true, - }); -}); +router.get('/demo', (req, res) => { + url = req.header('host') + req.baseUrl + res.render('index.jade', { + pageTitle: 'Post-it - demo', + headerBarUrl, + logoUrl, + url, + demo: true + }) +}) -router.get("/:id", function (req, res) { - url = req.header("host") + req.baseUrl; - res.render("index.jade", { - pageTitle: "Post-it - " + req.params.id, - headerBarUrl: headerBarUrl, - logoUrl: logoUrl, - url: url, - }); -}); +router.get('/:id', (req, res) => { + url = req.header('host') + req.baseUrl + res.render('index.jade', { + pageTitle: `Post-it - ${req.params.id}`, + headerBarUrl, + logoUrl, + url + }) +}) -router.get("/stats", function (req, res) { - console.log("TODO: stats"); -}); +router.get('/stats', (req, res) => { + console.log('TODO: stats') +}) -/************** +/** ************ SOCKET.I0 -**************/ -//sanitizes text +************* */ +// sanitizes text function scrub(text) { - if (typeof text != "undefined" && text !== null) { - //clip the string if it is too long + if (typeof text != 'undefined' && text !== null) { + // clip the string if it is too long if (text.length > 65535) { - text = text.substr(0, 65535); + text = text.substr(0, 65535) } - return sanitizer.sanitize(text); - } else { - return null; + return sanitizer.sanitize(text) } + return null } -io.sockets.on("connection", function (client) { - client.on("message", function (message) { - //console.log(message.action + " -- " + sys.inspect(message.data) ); +io.sockets.on('connection', (client) => { + client.on('message', (message) => { + // console.log(message.action + " -- " + sys.inspect(message.data) ); - var clean_data = {}; - var clean_message = {}; - var message_out = {}; + let clean_data = {} + let clean_message = {} + let message_out = {} - if (!message.action) return; + if (!message.action) return switch (message.action) { - case "initializeMe": - initClient(client); - break; + case 'initializeMe': + initClient(client) + break - case "joinRoom": - joinRoom(client, message.data, function (clients) { - client.json.send({ action: "roomAccept", data: "" }); - }); + case 'joinRoom': + joinRoom(client, message.data, (clients) => { + client.json.send({ action: 'roomAccept', data: '' }) + }) - break; + break - case "moveCard": - //report to all other browsers + case 'moveCard': + // report to all other browsers message_out = { action: message.action, data: { id: scrub(message.data.id), position: { left: scrub(message.data.position.left), - top: scrub(message.data.position.top), - }, - }, - }; + top: scrub(message.data.position.top) + } + } + } - broadcastToRoom(client, message_out); + broadcastToRoom(client, message_out) // console.log("-----" + message.data.id); // console.log(JSON.stringify(message.data)); - getRoom(client, function (room) { + getRoom(client, (room) => { db.cardSetXY( room, message.data.id, message.data.position.left, message.data.position.top - ); - }); + ) + }) - break; + break - case "createCard": - data = message.data; - clean_data = {}; - clean_data.text = scrub(data.text); - clean_data.id = scrub(data.id); - clean_data.x = scrub(data.x); - clean_data.y = scrub(data.y); - clean_data.rot = scrub(data.rot); - clean_data.colour = scrub(data.colour); + case 'createCard': + data = message.data + clean_data = {} + clean_data.text = scrub(data.text) + clean_data.id = scrub(data.id) + clean_data.x = scrub(data.x) + clean_data.y = scrub(data.y) + clean_data.rot = scrub(data.rot) + clean_data.colour = scrub(data.colour) - getRoom(client, function (room) { + getRoom(client, (room) => { createCard( room, clean_data.id, @@ -191,681 +193,677 @@ io.sockets.on("connection", function (client) { clean_data.y, clean_data.rot, clean_data.colour - ); - }); + ) + }) message_out = { - action: "createCard", - data: clean_data, - }; - - //report to all other browsers - broadcastToRoom(client, message_out); - break; - - case "editCard": - clean_data = {}; - clean_data.value = scrub(message.data.value); - clean_data.id = scrub(message.data.id); - - //send update to database - getRoom(client, function (room) { - db.cardEdit(room, clean_data.id, clean_data.value); - }); - - message_out = { - action: "editCard", - data: clean_data, - }; - - broadcastToRoom(client, message_out); - - break; - - case "deleteCard": - clean_message = { - action: "deleteCard", - data: { id: scrub(message.data.id) }, - }; - - getRoom(client, function (room) { - db.deleteCard(room, clean_message.data.id); - }); - - //report to all other browsers - broadcastToRoom(client, clean_message); - - break; - - case "createColumn": - clean_message = { data: scrub(message.data) }; - - getRoom(client, function (room) { - db.createColumn(room, clean_message.data, function () {}); - }); - - broadcastToRoom(client, clean_message); - - break; - - case "deleteColumn": - getRoom(client, function (room) { - db.deleteColumn(room); - }); - broadcastToRoom(client, { action: "deleteColumn" }); - - break; - - case "updateColumns": - var columns = message.data; - - if (!(columns instanceof Array)) break; - - var clean_columns = []; - - for (var i in columns) { - clean_columns[i] = scrub(columns[i]); + action: 'createCard', + data: clean_data } - getRoom(client, function (room) { - db.setColumns(room, clean_columns); - }); + + // report to all other browsers + broadcastToRoom(client, message_out) + break + + case 'editCard': + clean_data = {} + clean_data.value = scrub(message.data.value) + clean_data.id = scrub(message.data.id) + + // send update to database + getRoom(client, (room) => { + db.cardEdit(room, clean_data.id, clean_data.value) + }) + + message_out = { + action: 'editCard', + data: clean_data + } + + broadcastToRoom(client, message_out) + + break + + case 'deleteCard': + clean_message = { + action: 'deleteCard', + data: { id: scrub(message.data.id) } + } + + getRoom(client, (room) => { + db.deleteCard(room, clean_message.data.id) + }) + + // report to all other browsers + broadcastToRoom(client, clean_message) + + break + + case 'createColumn': + clean_message = { data: scrub(message.data) } + + getRoom(client, (room) => { + db.createColumn(room, clean_message.data, () => {}) + }) + + broadcastToRoom(client, clean_message) + + break + + case 'deleteColumn': + getRoom(client, (room) => { + db.deleteColumn(room) + }) + broadcastToRoom(client, { action: 'deleteColumn' }) + + break + + case 'updateColumns': + var columns = message.data + + if (!(columns instanceof Array)) break + + var clean_columns = [] + + for (const i in columns) { + clean_columns[i] = scrub(columns[i]) + } + getRoom(client, (room) => { + db.setColumns(room, clean_columns) + }) broadcastToRoom(client, { - action: "updateColumns", - data: clean_columns, - }); + action: 'updateColumns', + data: clean_columns + }) - break; + break - case "changeTheme": - clean_message = {}; - clean_message.data = scrub(message.data); + case 'changeTheme': + clean_message = {} + clean_message.data = scrub(message.data) - getRoom(client, function (room) { - db.setTheme(room, clean_message.data); - }); + getRoom(client, (room) => { + db.setTheme(room, clean_message.data) + }) - clean_message.action = "changeTheme"; + clean_message.action = 'changeTheme' - broadcastToRoom(client, clean_message); - break; + broadcastToRoom(client, clean_message) + break - case "setUserName": - clean_message = {}; + case 'setUserName': + clean_message = {} - clean_message.data = scrub(message.data); + clean_message.data = scrub(message.data) - setUserName(client, clean_message.data); + setUserName(client, clean_message.data) - var msg = {}; - msg.action = "nameChangeAnnounce"; - msg.data = { sid: client.id, user_name: clean_message.data }; - broadcastToRoom(client, msg); - break; + var msg = {} + msg.action = 'nameChangeAnnounce' + msg.data = { sid: client.id, user_name: clean_message.data } + broadcastToRoom(client, msg) + break - case "addSticker": - var cardId = scrub(message.data.cardId); - var stickerId = scrub(message.data.stickerId); + case 'addSticker': + var cardId = scrub(message.data.cardId) + var stickerId = scrub(message.data.stickerId) - getRoom(client, function (room) { - db.addSticker(room, cardId, stickerId); - }); + getRoom(client, (room) => { + db.addSticker(room, cardId, stickerId) + }) broadcastToRoom(client, { - action: "addSticker", - data: { cardId: cardId, stickerId: stickerId }, - }); - break; + action: 'addSticker', + data: { cardId, stickerId } + }) + break - case "setBoardSize": - var size = {}; - size.width = scrub(message.data.width); - size.height = scrub(message.data.height); + case 'setBoardSize': + var size = {} + size.width = scrub(message.data.width) + size.height = scrub(message.data.height) - getRoom(client, function (room) { - db.setBoardSize(room, size); - }); + getRoom(client, (room) => { + db.setBoardSize(room, size) + }) - broadcastToRoom(client, { action: "setBoardSize", data: size }); - break; + broadcastToRoom(client, { action: 'setBoardSize', data: size }) + break - case "exportTxt": - exportBoard("txt", client, message.data); - break; + case 'exportTxt': + exportBoard('txt', client, message.data) + break - case "exportCsv": - exportBoard("csv", client, message.data); - break; + case 'exportCsv': + exportBoard('csv', client, message.data) + break - case "exportJson": - exportJson(client, message.data); - break; + case 'exportJson': + exportJson(client, message.data) + break - case "importJson": - importJson(client, message.data); - break; + case 'importJson': + importJson(client, message.data) + break - case "createRevision": - createRevision(client, message.data); - break; + case 'createRevision': + createRevision(client, message.data) + break - case "deleteRevision": - deleteRevision(client, message.data); - break; + case 'deleteRevision': + deleteRevision(client, message.data) + break - case "exportRevision": - exportRevision(client, message.data); - break; + case 'exportRevision': + exportRevision(client, message.data) + break default: - //console.log('unknown action'); - break; + // console.log('unknown action'); + break } - }); + }) - client.on("disconnect", function () { - leaveRoom(client); - }); + client.on('disconnect', () => { + leaveRoom(client) + }) - //tell all others that someone has connected - //client.broadcast('someone has connected'); -}); + // tell all others that someone has connected + // client.broadcast('someone has connected'); +}) -/************** +/** ************ FUNCTIONS -**************/ +************* */ function initClient(client) { - //console.log ('initClient Started'); - getRoom(client, function (room) { - db.getAllCards(room, function (cards) { + // console.log ('initClient Started'); + getRoom(client, (room) => { + db.getAllCards(room, (cards) => { client.json.send({ - action: "initCards", - data: cards, - }); - }); + action: 'initCards', + data: cards + }) + }) - db.getAllColumns(room, function (columns) { + db.getAllColumns(room, (columns) => { client.json.send({ - action: "initColumns", - data: columns, - }); - }); + action: 'initColumns', + data: columns + }) + }) - db.getRevisions(room, function (revisions) { + db.getRevisions(room, (revisions) => { client.json.send({ - action: "initRevisions", - data: revisions !== null ? Object.keys(revisions) : new Array(), - }); - }); + action: 'initRevisions', + data: revisions !== null ? Object.keys(revisions) : [] + }) + }) - db.getTheme(room, function (theme) { - if (theme === null) theme = "bigcards"; + db.getTheme(room, (theme) => { + if (theme === null) theme = 'bigcards' client.json.send({ - action: "changeTheme", - data: theme, - }); - }); + action: 'changeTheme', + data: theme + }) + }) - db.getBoardSize(room, function (size) { + db.getBoardSize(room, (size) => { if (size !== null) { client.json.send({ - action: "setBoardSize", - data: size, - }); + action: 'setBoardSize', + data: size + }) } - }); + }) - roommates_clients = rooms.room_clients(room); - roommates = []; + roommates_clients = rooms.room_clients(room) + roommates = [] - var j = 0; - for (var i in roommates_clients) { + let j = 0 + for (const i in roommates_clients) { if (roommates_clients[i].id != client.id) { roommates[j] = { sid: roommates_clients[i].id, - user_name: sids_to_user_names[roommates_clients[i].id], - }; - j++; + user_name: sids_to_user_names[roommates_clients[i].id] + } + j++ } } - //console.log('initialusers: ' + roommates); + // console.log('initialusers: ' + roommates); client.json.send({ - action: "initialUsers", - data: roommates, - }); - }); + action: 'initialUsers', + data: roommates + }) + }) } function joinRoom(client, room, successFunction) { - var msg = {}; - msg.action = "join-announce"; - msg.data = { sid: client.id, user_name: client.user_name }; + const msg = {} + msg.action = 'join-announce' + msg.data = { sid: client.id, user_name: client.user_name } - rooms.add_to_room_and_announce(client, room, msg); - successFunction(); + rooms.add_to_room_and_announce(client, room, msg) + successFunction() } function leaveRoom(client) { - //console.log (client.id + ' just left'); - var msg = {}; - msg.action = "leave-announce"; - msg.data = { sid: client.id }; - rooms.remove_from_all_rooms_and_announce(client, msg); + // console.log (client.id + ' just left'); + const msg = {} + msg.action = 'leave-announce' + msg.data = { sid: client.id } + rooms.remove_from_all_rooms_and_announce(client, msg) - delete sids_to_user_names[client.id]; + delete sids_to_user_names[client.id] } function broadcastToRoom(client, message) { - rooms.broadcast_to_roommates(client, message); + rooms.broadcast_to_roommates(client, message) } -//----------------CARD FUNCTIONS +// ----------------CARD FUNCTIONS function createCard(room, id, text, x, y, rot, colour) { - var card = { - id: id, - colour: colour, - rot: rot, - x: x, - y: y, - text: text, - sticker: null, - }; + const card = { + id, + colour, + rot, + x, + y, + text, + sticker: null + } - db.createCard(room, id, card); + db.createCard(room, id, card) } function roundRand(max) { - return Math.floor(Math.random() * max); + return Math.floor(Math.random() * max) } -//------------ROOM STUFF +// ------------ROOM STUFF // Get Room name for the given Session ID function getRoom(client, callback) { - room = rooms.get_room(client); - //console.log( 'client: ' + client.id + " is in " + room); - callback(room); + room = rooms.get_room(client) + // console.log( 'client: ' + client.id + " is in " + room); + callback(room) } function setUserName(client, name) { - client.user_name = name; - sids_to_user_names[client.id] = name; - //console.log('sids to user names: '); - console.dir(sids_to_user_names); + client.user_name = name + sids_to_user_names[client.id] = name + // console.log('sids to user names: '); + console.dir(sids_to_user_names) } function cleanAndInitializeDemoRoom() { // DUMMY DATA - db.clearRoom("/demo", function () { - db.createColumn("/demo", "Pas commencé"); - db.createColumn("/demo", "Commencé"); - db.createColumn("/demo", "En test"); - db.createColumn("/demo", "Validation"); - db.createColumn("/demo", "Terminé"); + db.clearRoom('/demo', () => { + db.createColumn('/demo', 'Pas commencé') + db.createColumn('/demo', 'Commencé') + db.createColumn('/demo', 'En test') + db.createColumn('/demo', 'Validation') + db.createColumn('/demo', 'Terminé') createCard( - "/demo", - "card1", + '/demo', + 'card1', "Salut, c'est fun", roundRand(600), roundRand(300), Math.random() * 10 - 5, - "yellow" - ); + 'yellow' + ) createCard( - "/demo", - "card2", + '/demo', + 'card2', "Salut, c'est une nouvelle histoire.", roundRand(600), roundRand(300), Math.random() * 10 - 5, - "white" - ); + 'white' + ) createCard( - "/demo", - "card3", - ".", + '/demo', + 'card3', + '.', roundRand(600), roundRand(300), Math.random() * 10 - 5, - "blue" - ); + 'blue' + ) createCard( - "/demo", - "card4", - ".", + '/demo', + 'card4', + '.', roundRand(600), roundRand(300), Math.random() * 10 - 5, - "green" - ); + 'green' + ) createCard( - "/demo", - "card5", + '/demo', + 'card5', "Salut, c'est fun", roundRand(600), roundRand(300), Math.random() * 10 - 5, - "yellow" - ); + 'yellow' + ) createCard( - "/demo", - "card6", + '/demo', + 'card6', "Salut, c'est un nouveau mémo.", roundRand(600), roundRand(300), Math.random() * 10 - 5, - "yellow" - ); + 'yellow' + ) createCard( - "/demo", - "card7", - ".", + '/demo', + 'card7', + '.', roundRand(600), roundRand(300), Math.random() * 10 - 5, - "blue" - ); + 'blue' + ) createCard( - "/demo", - "card8", - ".", + '/demo', + 'card8', + '.', roundRand(600), roundRand(300), Math.random() * 10 - 5, - "green" - ); - }); + 'green' + ) + }) } // Export board in txt or csv function exportBoard(format, client, data) { - var result = new Array(); - getRoom(client, function (room) { - db.getAllCards(room, function (cards) { - db.getAllColumns(room, function (columns) { - var text = new Array(); - var cols = {}; + const result = [] + getRoom(client, (room) => { + db.getAllCards(room, (cards) => { + db.getAllColumns(room, (columns) => { + const text = [] + const cols = {} if (columns.length > 0) { for (var i = 0; i < columns.length; i++) { - cols[columns[i]] = new Array(); + cols[columns[i]] = [] for (var j = 0; j < cards.length; j++) { if (i === 0) { - if (cards[j]["x"] < (i + 1) * data) { - cols[columns[i]].push(cards[j]); + if (cards[j].x < (i + 1) * data) { + cols[columns[i]].push(cards[j]) } } else if (i + 1 === columns.length) { - if (cards[j]["x"] >= i * data) { - cols[columns[i]].push(cards[j]); + if (cards[j].x >= i * data) { + cols[columns[i]].push(cards[j]) } } else if ( - cards[j]["x"] >= i * data && - cards[j]["x"] < (i + 1) * data + cards[j].x >= i * data + && cards[j].x < (i + 1) * data ) { - cols[columns[i]].push(cards[j]); + cols[columns[i]].push(cards[j]) } } - cols[columns[i]].sort(function (a, b) { - if (a["y"] === b["y"]) { - return a["x"] - b["x"]; - } else { - return a["y"] - b["y"]; + cols[columns[i]].sort((a, b) => { + if (a.y === b.y) { + return a.x - b.x } - }); + return a.y - b.y + }) } - if (format === "txt") { + if (format === 'txt') { for (var i = 0; i < columns.length; i++) { if (i === 0) { - text.push("# " + columns[i]); + text.push(`# ${columns[i]}`) } else { - text.push("\n# " + columns[i]); + text.push(`\n# ${columns[i]}`) } for (var j = 0; j < cols[columns[i]].length; j++) { - text.push("- " + cols[columns[i]][j]["text"]); + text.push(`- ${cols[columns[i]][j].text}`) } } - } else if (format === "csv") { - var max = 0; - var line = new Array(); - var patt_vuln = new RegExp("^[=+-@]"); + } else if (format === 'csv') { + let max = 0 + let line = [] + const patt_vuln = new RegExp('^[=+-@]') for (var i = 0; i < columns.length; i++) { if (cols[columns[i]].length > max) { - max = cols[columns[i]].length; + max = cols[columns[i]].length } - var val = columns[i].replace(/"/g, '""'); + var val = columns[i].replace(/"/g, '""') if (patt_vuln.test(val)) { // prevent CSV Formula Injection - var val = "'" + val; + var val = `'${val}` } - line.push('"' + val + '"'); + line.push(`"${val}"`) } - text.push(line.join(",")); + text.push(line.join(',')) for (var j = 0; j < max; j++) { - line = new Array(); + line = [] for (var i = 0; i < columns.length; i++) { - var val = - cols[columns[i]][j] !== undefined - ? cols[columns[i]][j]["text"].replace(/"/g, '""') - : ""; + var val = cols[columns[i]][j] !== undefined + ? cols[columns[i]][j].text.replace(/"/g, '""') + : '' if (patt_vuln.test(val)) { // prevent CSV Formula Injection - var val = "'" + val; + var val = `'${val}` } - line.push('"' + val + '"'); + line.push(`"${val}"`) } - text.push(line.join(",")); + text.push(line.join(',')) } } } else { for (var j = 0; j < cards.length; j++) { - if (format === "txt") { - text.push("- " + cards[j]["text"]); - } else if (format === "csv") { - text.push('"' + cards[j]["text"].replace(/"/g, '""') + '"\n'); + if (format === 'txt') { + text.push(`- ${cards[j].text}`) + } else if (format === 'csv') { + text.push(`"${cards[j].text.replace(/"/g, '""')}"\n`) } } } - var result; - if (format === "txt" || format === "csv") { - result = text.join("\n"); - } else if (format === "json") { - result = JSON.stringify(cols); + let result + if (format === 'txt' || format === 'csv') { + result = text.join('\n') + } else if (format === 'json') { + result = JSON.stringify(cols) } client.json.send({ - action: "export", + action: 'export', data: { - filename: room.replace("/", "") + "." + format, - text: result, - }, - }); - }); - }); - }); + filename: `${room.replace('/', '')}.${format}`, + text: result + } + }) + }) + }) + }) } // Export board in json, suitable for import function exportJson(client, data) { - var result = new Array(); - getRoom(client, function (room) { - db.getAllCards(room, function (cards) { - db.getAllColumns(room, function (columns) { - db.getTheme(room, function (theme) { - db.getBoardSize(room, function (size) { - if (theme === null) theme = "bigcards"; - if (size === null) - size = { width: data.width, height: data.height }; + let result = [] + getRoom(client, (room) => { + db.getAllCards(room, (cards) => { + db.getAllColumns(room, (columns) => { + db.getTheme(room, (theme) => { + db.getBoardSize(room, (size) => { + if (theme === null) theme = 'bigcards' + if (size === null) { size = { width: data.width, height: data.height } } result = JSON.stringify({ - cards: cards, - columns: columns, - theme: theme, - size: size, - }); + cards, + columns, + theme, + size + }) client.json.send({ - action: "export", + action: 'export', data: { - filename: room.replace("/", "") + ".json", - text: result, - }, - }); - }); - }); - }); - }); - }); + filename: `${room.replace('/', '')}.json`, + text: result + } + }) + }) + }) + }) + }) + }) } // Import board from json function importJson(client, data) { - getRoom(client, function (room) { - db.clearRoom(room, function () { - db.getAllCards(room, function (cards) { + getRoom(client, (room) => { + db.clearRoom(room, () => { + db.getAllCards(room, (cards) => { for (var i = 0; i < cards.length; i++) { - db.deleteCard(room, cards[i].id); + db.deleteCard(room, cards[i].id) } - cards = data.cards; - var cards2 = new Array(); + cards = data.cards + const cards2 = [] for (var i = 0; i < cards.length; i++) { - var card = cards[i]; + const card = cards[i] if ( - card.id !== undefined && - card.colour !== undefined && - card.rot !== undefined && - card.x !== undefined && - card.y !== undefined && - card.text !== undefined && - card.sticker !== undefined + card.id !== undefined + && card.colour !== undefined + && card.rot !== undefined + && card.x !== undefined + && card.y !== undefined + && card.text !== undefined + && card.sticker !== undefined ) { - var c = { + const c = { id: card.id, colour: card.colour, rot: card.rot, x: card.x, y: card.y, text: scrub(card.text), - sticker: card.sticker, - }; - db.createCard(room, c.id, c); - cards2.push(c); + sticker: card.sticker + } + db.createCard(room, c.id, c) + cards2.push(c) } } - var msg = { action: "initCards", data: cards2 }; - broadcastToRoom(client, msg); - client.json.send(msg); - }); + const msg = { action: 'initCards', data: cards2 } + broadcastToRoom(client, msg) + client.json.send(msg) + }) - db.getAllColumns(room, function (columns) { + db.getAllColumns(room, (columns) => { for (var i = 0; i < columns.length; i++) { - db.deleteColumn(room); + db.deleteColumn(room) } - columns = data.columns; - var columns2 = new Array(); + columns = data.columns + const columns2 = [] for (var i = 0; i < columns.length; i++) { - var column = scrub(columns[i]); - if (typeof column === "string") { - db.createColumn(room, column); - columns2.push(column); + const column = scrub(columns[i]) + if (typeof column === 'string') { + db.createColumn(room, column) + columns2.push(column) } } - msg = { action: "initColumns", data: columns2 }; - broadcastToRoom(client, msg); - client.json.send(msg); - }); + msg = { action: 'initColumns', data: columns2 } + broadcastToRoom(client, msg) + client.json.send(msg) + }) - var size = data.size; + let { size } = data if (size.width !== undefined && size.height !== undefined) { - size = { width: scrub(size.width), height: scrub(size.height) }; - db.setBoardSize(room, size); - msg = { action: "setBoardSize", data: size }; - broadcastToRoom(client, msg); - client.json.send(msg); + size = { width: scrub(size.width), height: scrub(size.height) } + db.setBoardSize(room, size) + msg = { action: 'setBoardSize', data: size } + broadcastToRoom(client, msg) + client.json.send(msg) } - data.theme = scrub(data.theme); - if (data.theme === "smallcards" || data.theme === "bigcards") { - db.setTheme(room, data.theme); - msg = { action: "changeTheme", data: data.theme }; - broadcastToRoom(client, msg); - client.json.send(msg); + data.theme = scrub(data.theme) + if (data.theme === 'smallcards' || data.theme === 'bigcards') { + db.setTheme(room, data.theme) + msg = { action: 'changeTheme', data: data.theme } + broadcastToRoom(client, msg) + client.json.send(msg) } - }); - }); + }) + }) } // function createRevision(client, data) { - var result = new Array(); - getRoom(client, function (room) { - db.getAllCards(room, function (cards) { - db.getAllColumns(room, function (columns) { - db.getTheme(room, function (theme) { - db.getBoardSize(room, function (size) { - if (theme === null) theme = "bigcards"; - if (size === null) - size = { width: data.width, height: data.height }; + let result = [] + getRoom(client, (room) => { + db.getAllCards(room, (cards) => { + db.getAllColumns(room, (columns) => { + db.getTheme(room, (theme) => { + db.getBoardSize(room, (size) => { + if (theme === null) theme = 'bigcards' + if (size === null) { size = { width: data.width, height: data.height } } result = { - cards: cards, - columns: columns, - theme: theme, - size: size, - }; - var timestamp = Date.now(); - db.getRevisions(room, function (revisions) { - if (revisions === null) revisions = {}; - revisions[timestamp + ""] = result; - db.setRevisions(room, revisions); - msg = { action: "addRevision", data: timestamp }; - broadcastToRoom(client, msg); - client.json.send(msg); - }); - }); - }); - }); - }); - }); + cards, + columns, + theme, + size + } + const timestamp = Date.now() + db.getRevisions(room, (revisions) => { + if (revisions === null) revisions = {} + revisions[`${timestamp}`] = result + db.setRevisions(room, revisions) + msg = { action: 'addRevision', data: timestamp } + broadcastToRoom(client, msg) + client.json.send(msg) + }) + }) + }) + }) + }) + }) } function deleteRevision(client, timestamp) { - getRoom(client, function (room) { - db.getRevisions(room, function (revisions) { - if (revisions !== null && revisions[timestamp + ""] !== undefined) { - delete revisions[timestamp + ""]; - db.setRevisions(room, revisions); + getRoom(client, (room) => { + db.getRevisions(room, (revisions) => { + if (revisions !== null && revisions[`${timestamp}`] !== undefined) { + delete revisions[`${timestamp}`] + db.setRevisions(room, revisions) } - msg = { action: "deleteRevision", data: timestamp }; - broadcastToRoom(client, msg); - client.json.send(msg); - }); - }); + msg = { action: 'deleteRevision', data: timestamp } + broadcastToRoom(client, msg) + client.json.send(msg) + }) + }) } function exportRevision(client, timestamp) { - getRoom(client, function (room) { - db.getRevisions(room, function (revisions) { - if (revisions !== null && revisions[timestamp + ""] !== undefined) { + getRoom(client, (room) => { + db.getRevisions(room, (revisions) => { + if (revisions !== null && revisions[`${timestamp}`] !== undefined) { client.json.send({ - action: "export", + action: 'export', data: { - filename: room.replace("/", "") + "-" + timestamp + ".json", - text: JSON.stringify(revisions[timestamp + ""]), - }, - }); + filename: `${room.replace('/', '')}-${timestamp}.json`, + text: JSON.stringify(revisions[`${timestamp}`]) + } + }) } else { client.json.send({ - action: "message", - data: "Unable to find revision " + timestamp + ".", - }); + action: 'message', + data: `Unable to find revision ${timestamp}.` + }) } - }); - }); + }) + }) } -/************** +/** ************ SETUP DATABASE ON FIRST RUN -**************/ +************* */ // (runs only once on startup) -var db = new data(function () { - cleanAndInitializeDemoRoom(); -}); +var db = new data(() => { + cleanAndInitializeDemoRoom() +}) diff --git a/views/home.jade b/views/home.jade index 910e508..594e206 100644 --- a/views/home.jade +++ b/views/home.jade @@ -17,4 +17,4 @@ block body input.text(type="text", name="name") a#go(onclick="return go();") OK p.home Exemple : - p.home!= '' + locals.url + '/demo' + p.home!= '' + locals.url + '/demo' \ No newline at end of file