memo/client/script.js
Florian Schmitt 28071e585f wip refacto
2025-06-08 18:27:17 +03:00

1230 lines
29 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

function toggleFullScreen() {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen();
} else if (document.exitFullscreen) {
document.exitFullscreen();
}
}
let cards = {};
let totalcolumns = 0;
let columns = [];
let currentTheme = 'bigcards';
let boardInitialized = false;
let keyTrap = null;
const baseurl = location.pathname.substring(
0,
location.pathname.lastIndexOf('/'),
);
const socket = io.connect({ path: `${baseurl}/socket.io` });
console.log(socket);
moment.locale(navigator.language || navigator.languages[0]);
marked.setOptions({ sanitize: true });
// an action has happened, send it to the
// server
function sendAction(a, d) {
// console.log('--> ' + a);
const message = {
action: a,
data: d,
};
socket.emit(a, message);
}
socket.on('connect', () => {
// console.log('successful socket.io connect');
// 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);
});
socket.on('disconnect', () => {
blockUI(
'Serveur déconnecté. Veuillez rafraîchir la page pour essayer de vous reconnecter…',
);
// $('.blockOverlay').on('click', $.unblockUI);
});
socket.on('message', (data) => {
getMessage(data);
});
function unblockUI() {
$.unblockUI({ fadeOut: 50 });
}
function blockUI(message) {
message = message || 'En attente…';
$.blockUI({
message,
css: {
border: 'none',
padding: '15px',
backgroundColor: '#000',
'-webkit-border-radius': '10px',
'-moz-border-radius': '10px',
opacity: 0.5,
color: '#fff',
fontSize: '20px',
},
fadeOut: 0,
fadeIn: 10,
});
}
// respond to an action event
function getMessage(m) {
const message = m; // JSON.parse(m);
const { action } = message;
const { data } = message;
// 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);
break;
case 'roomDeny':
// this doesn't happen yet
break;
case 'editBoardMetas':
sendAction('editBoardMetas', { prop: 'opacity', value: 0.5 });
break;
case 'moveCard':
moveCard($(`#${data.id}`), data.position);
break;
case 'initCards':
initCards(data);
break;
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 () {
$(this).remove();
});
break;
case 'editCard':
$(`#${data.id}`).children('.content:first').attr('data-text', data.value);
$(`#${data.id}`).children('.content:first').html(marked(data.value));
break;
case 'initColumns':
initColumns(data);
break;
case 'updateColumns':
initColumns(data);
break;
case 'changeTheme':
changeThemeTo(data);
break;
case 'join-announce':
displayUserJoined(data.sid, data.user_name);
break;
case 'leave-announce':
displayUserLeft(data.sid);
break;
case 'initialUsers':
displayInitialUsers(data);
break;
case 'nameChangeAnnounce':
updateName(message.data.sid, message.data.user_name);
break;
case 'addSticker':
addSticker(message.data.cardId, message.data.stickerId);
break;
case 'setBoardSize':
resizeBoard(message.data);
break;
case 'export':
download(message.data.filename, message.data.text);
break;
case 'addRevision':
addRevision(message.data);
break;
case 'deleteRevision':
$(`#revision-${message.data}`).remove();
break;
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)}`);
break;
}
}
$(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};
const h = `<div id="${id}" class="card ${
colour
} draggable" style="-webkit-transform:rotate(${rot}deg);\
">\
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16" class="card-icon delete-card-icon bi bi-x-lg"><path d="M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8 2.146 2.854Z"></path></svg>\
<div id="content:${
id
}" class="content stickertarget droppable" data-text="">${marked(
text,
)}</div><span class="filler"></span>\
</div>`;
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
// card.on('click', function() {
// $(this).focus();
// } );
card.draggable({
snap: false,
snapTolerance: 5,
containment: [0, 0, 2000, 2000],
stack: '.card',
start(event, ui) {
keyTrap = null;
},
drag(event, ui) {
if (keyTrap == 27) {
ui.helper.css(ui.originalPosition);
return false;
}
},
handle: 'div.content',
});
// After a drag:
card.on('dragstop', function (event, ui) {
if (keyTrap == 27) {
keyTrap = null;
return;
}
const data = {
id: this.id,
position: ui.position,
oldposition: ui.originalPosition,
};
sendAction('moveCard', data);
});
card.children('.droppable').droppable({
accept: '.sticker',
drop(event, ui) {
const stickerId = ui.draggable.attr('id');
const cardId = $(this).parent().attr('id');
addSticker(cardId, stickerId);
const data = {
cardId,
stickerId,
};
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');
},
hoverClass: 'card-hover-draggable',
});
let speed = Math.floor(Math.random() * 1000);
if (typeof animationspeed !== 'undefined') speed = animationspeed;
if (mx == 0 && my == 0) {
const startPosition = $('#create-card').position();
mx = startPosition.left;
my = startPosition.top;
}
card.css('top', my);
card.css('left', mx);
card.animate(
{
left: `${x}px`,
top: `${y}px`,
},
speed,
);
card.children('.delete-card-icon').on('click', () => {
$(`#${id}`).remove();
// notify server of delete
sendAction('deleteCard', { id });
});
card.children('.content').editable(
(value, settings) => {
$(`#${id}`).children('.content:first').attr('data-text', value);
onCardChange(id, value);
return marked(value);
},
{
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'
},
);
// add applicable sticker
if (sticker !== null) addSticker(id, sticker);
}
function onCardChange(id, text) {
sendAction('editCard', {
id,
value: text,
});
}
function moveCard(card, position) {
card.animate(
{
left: `${position.left}px`,
top: `${position.top}px`,
},
500,
);
}
function addSticker(cardId, stickerId) {
stickerContainer = $(`#${cardId} .filler`);
if (stickerId === 'nosticker') {
stickerContainer.html('');
return;
}
if (Array.isArray(stickerId)) {
for (const i in stickerId) {
stickerContainer.prepend(
`<img src="images/stickers/${stickerId[i]}.png">`,
);
}
} else if (stickerContainer.html().indexOf(stickerId) < 0) {
stickerContainer.prepend(`<img src="images/stickers/${stickerId}.png">`);
}
}
//----------------------------------
// cards
//----------------------------------
function createCard(id, text, x, y, rot, colour, mx = 0, my = 0) {
drawNewCard(id, text, x, y, rot, colour, null, null, mx, my);
const action = 'createCard';
const data = {
id,
text,
x,
y,
rot,
colour,
};
sendAction(action, data);
}
function randomCardColour() {
const colours = ['yellow', 'green', 'blue', 'white'];
const i = Math.floor(Math.random() * colours.length);
return colours[i];
}
function initCards(cardArray) {
// first delete any cards that exist
$('.card').remove();
cards = 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,
);
}
boardInitialized = true;
unblockUI();
}
//----------------------------------
// cols
//----------------------------------
function drawNewColumn(columnName) {
let cls = 'col';
if (totalcolumns === 0) {
cls = 'col first';
}
$('#icon-col').before(
`<td class="${cls}" width="10%" style="display:none"><h2 id="col-${
totalcolumns + 1
}" class="editable">${columnName}</h2></td>`,
);
$('.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: '',
xindicator: '<span class="ajax-loader"></span>',
event: 'dblclick', // event: 'mouseover'
},
);
$('.col:last').fadeIn(500);
totalcolumns++;
}
function onColumnChange(id, text) {
const names = [];
// 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
const thisID = $(this).children('h2').attr('id');
if (id == thisID) {
names.push(text);
} else {
names.push($(this).text());
}
});
updateColumns(names);
}
function displayRemoveColumn() {
if (totalcolumns <= 0) return false;
$('.col:last').fadeOut(150, function () {
$(this).remove();
});
totalcolumns--;
}
function createColumn(name) {
if (totalcolumns >= 8) return false;
drawNewColumn(name);
columns.push(name);
const action = 'updateColumns';
const data = columns;
sendAction(action, data);
}
function deleteColumn() {
if (totalcolumns <= 0) return false;
displayRemoveColumn();
columns.pop();
const action = 'updateColumns';
const data = columns;
sendAction(action, data);
}
function updateColumns(c) {
columns = c;
const action = 'updateColumns';
const data = columns;
sendAction(action, data);
}
function deleteColumns(next) {
// delete all existing columns:
$('.col').fadeOut('slow', next());
}
function initColumns(columnArray) {
totalcolumns = 0;
columns = columnArray;
$('.col').remove();
for (const i in columnArray) {
column = columnArray[i];
drawNewColumn(column);
}
}
function changeThemeTo(theme) {
currentTheme = theme;
if (theme == 'bigcards') {
$('#board').removeClass('smallcards');
} else {
$('#board').removeClass('bigcards');
}
$('#board').addClass(theme);
}
/// ///////////////////////////////////////////////////////
/// /////// NAMES STUFF ///////////////////////////////////
/// ///////////////////////////////////////////////////////
function setCookie(c_name, value, exdays) {
const exdate = new Date();
exdate.setDate(exdate.getDate() + exdays);
const c_value = `${escape(value) + (exdays === null ? '' : `; expires=${exdate.toUTCString()}`)};SameSite=Strict`;
document.cookie = `${c_name}=${c_value}`;
}
function getCookie(c_name) {
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, '');
if (x == c_name) {
return unescape(y);
}
}
}
function setName(name) {
sendAction('setUserName', name);
setCookie('scrumscrum-username', name, 365);
}
function displayInitialUsers(users) {
for (const i in users) {
// console.log(users);
displayUserJoined(users[i].sid, users[i].user_name);
}
}
function displayUserJoined(sid, user_name) {
name = '';
if (user_name) name = user_name;
else name = sid.substring(0, 5);
$('#names-ul').append(`<li id="user-${sid}">${name}</li>`);
}
function displayUserLeft(sid) {
name = '';
if (name) name = user_name;
else name = sid;
const id = `#user-${sid.toString()}`;
$('#names-ul')
.children(id)
.fadeOut(1000, function () {
$(this).remove();
});
}
function updateName(sid, name) {
const id = `#user-${sid.toString()}`;
$('#names-ul').children(id).text(name);
}
/// ///////////////////////////////////////////////////////
/// ///////////////////////////////////////////////////////
function boardResizeHappened(event, ui) {
const newsize = ui.size;
sendAction('setBoardSize', newsize);
}
function resizeBoard(size) {
$('.board-outline').animate({
height: size.height,
width: size.width,
});
}
/// ///////////////////////////////////////////////////////
/// ///////////////////////////////////////////////////////
function calcCardOffset() {
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;
}
});
});
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
function adjustCard(offsets, doSync) {
$('.card').each(function () {
const card = $(this);
const offset = offsets[this.id];
if (offset) {
const data = {
id: this.id,
position: {
left: offset.col.position().left + offset.x * offset.col.outerWidth(),
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);
if (!doSync) {
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
moveCard(card, data.position);
sendAction('moveCard', data);
}
}
});
}
/// ///////////////////////////////////////////////////////
/// ///////////////////////////////////////////////////////
function download(filename, text) {
const element = document.createElement('a');
let mime = 'text/plain';
if (filename.match(/.csv$/)) {
mime = 'text/csv';
}
element.setAttribute(
'href',
`data:${mime};charset=utf-8,${encodeURIComponent(text)}`,
);
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
function addRevision(timestamp) {
const li = $(`<li id="revision-${timestamp}"></li>`);
const s1 = $('<span></span>');
const s2 = $(
'<img src="/images/stickers/sticker-deletestar.png" alt="delete revision">',
);
if (typeof timestamp === 'string') {
timestamp = parseInt(timestamp);
}
s1.text(moment(timestamp).format('LLLL'));
li.append(s1);
li.append(s2);
$('#revisions-list').append(li);
// $('body').on("click", s1, function () {
// socket.json.send({
// action: "exportRevision",
// data: timestamp,
// })
// })
// $('body').on("click", s2, function () {
// socket.json.send({
// action: "deleteRevision",
// data: timestamp,
// })
// })
}
/// ///////////////////////////////////////////////////////
/// ///////////////////////////////////////////////////////
$(() => {
// disable image dragging
// window.ondragstart = function() { return false; };
if (boardInitialized === false) blockUI('<span class="ajax-loader"></span>');
// setTimeout($.unblockUI, 2000);
$('.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', () => {
if (currentTheme == 'bigcards') {
changeThemeTo('smallcards');
} else if (currentTheme == 'smallcards') {
changeThemeTo('bigcards');
}
sendAction('changeTheme', currentTheme);
return false;
});
$('#icon-col').on(
'hover',
() => {
$('.col-icon').fadeIn(10);
},
() => {
$('.col-icon').fadeOut(150);
},
);
$('#add-col').on('click', () => {
createColumn('Nouvelle colonne');
return false;
});
$('#delete-col').on('click', () => {
deleteColumn();
return false;
});
const user_name = getCookie('scrumscrum-username');
$('#yourname-input').on('focus', function () {
if ($(this).val() == 'anonyme') {
$(this).val('');
}
$(this).addClass('focused');
});
$('#yourname-input').on('blur', function () {
if ($(this).val() === '') {
$(this).val('anonyme');
}
$(this).removeClass('focused');
setName($(this).val());
});
$('#yourname-input').val(user_name);
$('#yourname-input').trigger('blur');
$('#yourname-li').hide();
$('#yourname-input').on('keypress', function (e) {
code = e.keyCode ? e.keyCode : e.which;
if (code == 10 || code == 13) {
$(this).trigger('blur');
}
});
$('.sticker').draggable({
revert: true,
zIndex: 1000,
});
$('.board-outline').resizable({
ghost: false,
minWidth: 640,
minHeight: 480,
maxWidth: 1140,
maxHeight: 855,
});
// A new scope for precalculating
(function () {
let offsets;
$('.board-outline').on('resizestart', () => {
offsets = calcCardOffset();
});
$('.board-outline').on('resize', (event, ui) => {
adjustCard(offsets, false);
});
$('.board-outline').on('resizestop', (event, ui) => {
boardResizeHappened(event, ui);
adjustCard(offsets, true);
});
})();
$('#marker').draggable({
axis: 'x',
containment: 'parent',
});
$('#eraser').draggable({
axis: 'x',
containment: 'parent',
});
$('#export-txt').on('click', () => {
socket.json.send({
action: 'exportTxt',
data:
$('.col').length !== 0
? $('.col').css('width').replace('px', '')
: null,
});
});
$('#export-csv').on('click', () => {
socket.json.send({
action: 'exportCsv',
data:
$('.col').length !== 0
? $('.col').css('width').replace('px', '')
: null,
});
});
$('#export-json').on('click', () => {
socket.json.send({
action: 'exportJson',
data: {
width: $('.board-outline').css('width').replace('px', ''),
height: $('.board-outline').css('height').replace('px', ''),
},
});
});
$('#import-file').on('click', (evt) => {
evt.stopPropagation();
evt.preventDefault();
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),
});
};
fr.readAsText(f);
});
$('#create-revision').on('click', () => {
socket.json.send({
action: 'createRevision',
data: {
width: $('.board-outline').css('width').replace('px', ''),
height: $('.board-outline').css('height').replace('px', ''),
},
});
});
});
/** 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 * */
let clickTimer = null;
let clickTarget = null;
let editTarget = null;
function doubletapCards(selector) {
$(`${selector} .stickertarget`).addClass('doubletap'); // Escape multi bound
$(`${selector} .doubletap`).on('click', () => {
clickTarget = selector.replace('#', '');
if (clickTimer == null) {
clickTimer = setTimeout(() => {
clickTimer = null;
}, 1000);
} else {
// console.log('doubleclick : '+clickTimer+':'+editTarget);
clearTimeout(clickTimer);
clickTimer = null;
if (
editTarget == clickTarget &&
clickTarget !== undefined &&
clickTarget !== null
) {
$(`#${clickTarget.replace('content:', '')} .doubletap`).trigger(
'dblclick',
);
}
}
editTarget = clickTarget;
});
}
function doubletapTitle(selector) {
$(selector).addClass('doubletap'); // Escape multi bound
$(`${selector}.doubletap`).on('click', () => {
clickTarget = selector.replace('#', '');
if (clickTimer == null) {
clickTimer = setTimeout(() => {
clickTimer = null;
}, 1000);
} else {
// console.log('doubleclick : '+clickTimer+':'+editTarget);
clearTimeout(clickTimer);
clickTimer = null;
if (
editTarget == clickTarget &&
clickTarget !== undefined &&
clickTarget !== null
) {
$(`#${clickTarget}.doubletap`).trigger('dblclick');
}
}
editTarget = clickTarget;
});
}
setInterval(() => {
// Add periodically the doubletap event on new cards
$('.stickertarget:not(.doubletap)').each(function () {
doubletapCards(`#${$(this).attr('id').replace('content:', '')}`);
});
$('#board-table .col h2:not(.doubletap)').each(function () {
doubletapTitle(`#${$(this).attr('id')}`);
});
}, 500);
/** 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(() => {
if (boardInitialized) {
// when board is ready
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',
});
const data = {};
data.size = {
height: 466,
width: $('.board-outline.ui-resizable').width() + 16,
};
boardResizeHappened('resizestop', data); // using scrumblr function that keep size in db after a resize
}
clearInterval(boardReady);
}
}, 500);
// $("#scrumblr")
// .append($(".names, .stickers, .buttons"))
// .after(
// '<div role="tabpanel" class="tab-pane" id="export-import"></div>' +
// '<div role="tabpanel" class="tab-pane" id="share"></div>' +
// '<div role="tabpanel" class="tab-pane" id="revisions"></div>' +
// '<div role="tabpanel" class="tab-pane" id="about"></div>'
// )
// $("#export-import").append($(".export, .import"))
// $("#share").append($(".share"))
// $("#revisions").append($(".revisions"))
// $("#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');
} else {
$(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();
} else {
$(this).children('i').removeClass('fa-compress').addClass('fa-expand');
$('#header-bar').show();
}
toggleFullScreen();
});
/** Mode iframe * */
if (top.location != self.document.location) {
$('#header-bar').hide();
}
// put URL in share input
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', (e) => {
e.preventDefault();
const node = document.getElementById('taburl');
node.disabled = null;
node.select();
const success = document.execCommand('copy');
if (success) {
getSelection().removeAllRanges();
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).",
);
}
});
}
});
function go() {
let { value } = document.forms[0].elements.name;
value = value.replace(/[\/\?&#]/g, '');
window.location.href = value;
return false;
}
$(() => {
const headerBarUrl = $('#header-bar').data('url');
if (headerBarUrl) {
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 {
callback(status, xhr.response);
}
};
xhr.send();
};
getJSON(headerBarUrl, (err, data) => {
if (err !== null) {
console.log(`Something went wrong: ${err}`);
} else {
document.getElementById('header-bar').innerHTML = data.markup;
const styleElement = document.createElement('style');
styleElement.innerHTML = data.style;
document.getElementById('header-bar').appendChild(styleElement);
}
});
}
});
$(() => {
// 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 () {
let target = $(this).attr('href');
if (
target === '#' ||
($('#site-wrapper').hasClass('show-nav') &&
target == window.location.hash)
) {
target = false;
history.replaceState('', '', '#');
} else {
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',
(e) => {
history.replaceState('', '', '#');
toggleNav(false);
return false;
},
);
$('.backgrounds .bg').on('click', function () {
if ($(this).hasClass('selected')) {
$('body').css('background-image', 'none');
$(this).removeClass('selected');
} else {
$('.selected').removeClass('selected');
$('.bgurl').val('');
$('body').css('background-image', `url("/${$(this).attr('src')}")`);
$(this).addClass('selected');
}
});
$('.bgurl').on('change', function () {
const url = $(this).val();
if (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');
} else {
$('#share, #settings').hide();
if (target !== false) {
$(target).show();
}
$('#site-wrapper').addClass('show-nav');
}
return false;
}