memo/client/script.js
2025-06-04 12:35:04 +03:00

1158 lines
28 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` })
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.json.send(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: '<img src="images/ajax-loader.gif">',
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('<img src="images/ajax-loader.gif" width=43 height=11/>')
// 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
}