diff --git a/core/client.js b/core/client.js index 81dcedf..6b2a70a 100644 --- a/core/client.js +++ b/core/client.js @@ -3,6 +3,7 @@ const buttonContainer = document.getElementById('button-container') const buttonCronoContainer = document.getElementById('button-container-crono') const buttonCdownContainer = document.getElementById('button-container-cdown') const buttonCdowntimeContainer = document.getElementById('button-container-cdowntime') +const buttonExtensibleContainer = document.getElementById('button-container-extensible') const buttonTimeContainer = document.getElementById('button-container-time') const buttonClose = document.getElementById('stop-code') const buttonWiki = document.getElementById('button-wiki') @@ -11,7 +12,7 @@ const switchTheme = document.getElementById('switch-theme') const titleCrono = document.getElementById('crono-title') const titleCdown = document.getElementById('cdown-title') const titleCdowntime = document.getElementById('cdowntime-title') -const titleTwitchExt = document.getElementById('twitchext-title') +const titleExtensible = document.getElementById('extensible-title') const titleTime = document.getElementById('time-title') // const test = document.getElementById('test') const socket = new WebSocket('ws://localhost:3000') @@ -63,7 +64,7 @@ socket.addEventListener('message', (event) => { titleCrono.textContent = translateElements.home.cronoTitle titleCdown.textContent = translateElements.home.cdownTitle titleCdowntime.textContent = translateElements.home.cdowntimeTitle - titleTwitchExt.textContent = translateElements.home.twitchextTitle + titleExtensible.textContent = translateElements.home.extensibleTitle titleTime.textContent = translateElements.home.timeTitle if (elementVariables && typeof elementVariables === 'object') { @@ -120,6 +121,10 @@ buttonContainer.addEventListener('click', (event) => { window.open(`/${data[0]}/view`, '_blank', 'width=800,height=600') } else if (data[1] === 'controlButton') { window.open(`/${data[0]}/control`, '_blank', 'width=800,height=600') + } else if (data[1] === 'viewButtonCrono') { + window.open(`/${data[0]}/viewCrono`, '_blank', 'width=800,height=600') + } else if (data[1] === 'viewButtonCdown') { + window.open(`/${data[0]}/viewCdown`, '_blank', 'width=800,height=600') } else if (data[1] === 'copyButton') { // Get the text to copy from the "data-copy-text" attribute const copyText = `http://localhost:3000/${data[0]}/view` @@ -128,7 +133,27 @@ buttonContainer.addEventListener('click', (event) => { copyTextToClipboard(copyText) // Display a notification message - showNotification(translateElements.home.notycopycrono, button) + showNotification(translateElements.home.notycopy, button) + } + } else if (data[1] === 'copyButtonCrono') { + // Get the text to copy from the "data-copy-text" attribute + const copyText = `http://localhost:3000/${data[0]}/viewCrono` + + if (copyText) { + copyTextToClipboard(copyText) + + // Display a notification message + showNotification(translateElements.home.notycopy, button) + } + } else if (data[1] === 'copyButtonCdown') { + // Get the text to copy from the "data-copy-text" attribute + const copyText = `http://localhost:3000/${data[0]}/viewCdown` + + if (copyText) { + copyTextToClipboard(copyText) + + // Display a notification message + showNotification(translateElements.home.notycopy, button) } } else if (data[1] === 'removeButton') { socket.send(JSON.stringify({ action: 'removeData', remove: data[0] })) @@ -178,6 +203,46 @@ function loadButtons (list) { copyButton.id = element + '-copyButton' blockSpan.appendChild(copyButton) + const controlButton = createIconButton('fas fa-gear') + controlButton.id = element + '-controlButton' + blockSpan.appendChild(controlButton) + } else if (element.startsWith('extensible')) { + const iconCrono = document.createElement('i') + iconCrono.className = 'fas fa-clock' + iconCrono.style.marginRight = '10px' + iconCrono.style.color = '#494949' + iconCrono.style.fontSize = '20px' + blockSpan.appendChild(iconCrono) + + const viewButtonCrono = createIconButton('fas fa-eye') + viewButtonCrono.id = element + '-viewButtonCrono' + blockSpan.appendChild(viewButtonCrono) + + const copyButtonCrono = createIconButton('fas fa-copy', 'OBS') + copyButtonCrono.className = 'button-copy' + copyButtonCrono.id = element + '-copyButtonCrono' + blockSpan.appendChild(copyButtonCrono) + + blockSpan.appendChild(document.createElement('br')) + + const iconCdown = document.createElement('i') + iconCdown.className = 'fas fa-stopwatch' + iconCdown.style.marginRight = '10px' + iconCdown.style.color = '#494949' + iconCdown.style.fontSize = '20px' + blockSpan.appendChild(iconCdown) + + const viewButtonCdown = createIconButton('fas fa-eye') + viewButtonCdown.id = element + '-viewButtonCdown' + blockSpan.appendChild(viewButtonCdown) + + const copyButtonCdown = createIconButton('fas fa-copy', 'OBS') + copyButtonCdown.className = 'button-copy' + copyButtonCdown.id = element + '-copyButtonCdown' + blockSpan.appendChild(copyButtonCdown) + + blockSpan.appendChild(document.createElement('br')) + const controlButton = createIconButton('fas fa-gear') controlButton.id = element + '-controlButton' blockSpan.appendChild(controlButton) @@ -194,6 +259,8 @@ function loadButtons (list) { buttonCdowntimeContainer.insertBefore(blockSpan, buttonCdowntimeContainer.firstChild) } else if (element.startsWith('cdown')) { buttonCdownContainer.insertBefore(blockSpan, buttonCdownContainer.firstChild) + } else if (element.startsWith('extensible')) { + buttonExtensibleContainer.insertBefore(blockSpan, buttonExtensibleContainer.firstChild) } else if (element.startsWith('time')) { buttonTimeContainer.insertBefore(blockSpan, buttonTimeContainer.firstChild) } diff --git a/core/formats.yaml b/core/formats.yaml index c0f31a6..78581ef 100644 --- a/core/formats.yaml +++ b/core/formats.yaml @@ -34,6 +34,17 @@ cdowntime: - 'MM:ss' - 'SS.000' - 'SS' +extensible: + - 'HH:mm:ss.000' + - 'HH:mm:ss' + - '(HH:)(mm:)ss.000' + - '(HH:)(mm:)ss' + - '(HH:)mm:ss.000' + - '(HH:)mm:ss' + - 'MM:ss.000' + - 'MM:ss' + - 'SS.000' + - 'SS' time: - 'DD/MM/YYYY hh:mm:ss' - 'DD/MM/YYYY hh:mm' diff --git a/core/index.html b/core/index.html index 0d9d96f..ce61dc5 100644 --- a/core/index.html +++ b/core/index.html @@ -22,22 +22,24 @@ - - + + + + + + @@ -79,9 +81,11 @@

-

-
- COMING SOON... +

+
+

diff --git a/core/template/cdown/control/control.js b/core/template/cdown/control/control.js index 2ad652f..7f23421 100644 --- a/core/template/cdown/control/control.js +++ b/core/template/cdown/control/control.js @@ -86,7 +86,7 @@ socket.addEventListener('message', (event) => { resetButton.textContent = translateElements.timer.buttons.reset if (elementVariables && typeof elementVariables === 'object') { - checkTextTime = MsToText(elementVariables.textmilliseconds) + checkTextTime = MsToText(elementVariables.textMilliseconds) checkHexColor = elementVariables.colorText // Format selector options @@ -101,10 +101,10 @@ socket.addEventListener('message', (event) => { // Perform necessary actions with the variables here textMsg.textContent = elementVariables.msgEnd if (elementVariables.msgEnd === '') { - textMsg.textContent = translateElements.timer.ph_msgend + textMsg.textContent = translateElements.timer.phMsgEnd textMsg.style.color = '#555' } else { textMsg.style.color = '#000' } - timeText.value = MsToText(elementVariables.textmilliseconds) + timeText.value = MsToText(elementVariables.textMilliseconds) formatSelector.value = elementVariables.formatTime fontSelect.value = elementVariables.font fontSize.value = elementVariables.size @@ -122,10 +122,10 @@ socket.addEventListener('message', (event) => { if (message[classElement].status !== 'started') { textMsg.textContent = message[classElement].msgEnd if (message[classElement].msgEnd === '') { - textMsg.textContent = translateElements.timer.ph_msgend + textMsg.textContent = translateElements.timer.phMsgEnd textMsg.style.color = '#555' } else { textMsg.style.color = '#000' } - timeText.value = MsToText(message[classElement].textmilliseconds) + timeText.value = MsToText(message[classElement].textMilliseconds) formatSelector.value = message[classElement].formatTime fontSelect.value = message[classElement].font fontSize.value = message[classElement].size @@ -172,7 +172,7 @@ timeText.addEventListener('change', () => { const textTime = timeText.value.trim() // Regular expression to check the correct time format - const timeRegex = /^([0-9]+):([0-5]?[0-9]):([0-5]?[0-9])$/ + const timeRegex = /^(\d+):([0-5]?\d):([0-5]?\d)$/ if (timeRegex.test(textTime)) { checkTextTime = textTime @@ -218,7 +218,7 @@ subContainer.addEventListener('click', (event) => { }) textMsg.addEventListener('focus', () => { - if (textMsg.textContent === translateElements.timer.ph_msgend) { + if (textMsg.textContent === translateElements.timer.phMsgEnd) { textMsg.textContent = '' textMsg.style.color = '#000' } @@ -227,17 +227,17 @@ textMsg.addEventListener('focus', () => { textMsg.addEventListener('blur', () => { socket.send(JSON.stringify({ action: 'editMsgCdown', msg: textMsg.textContent, classElement })) if (textMsg.textContent === '') { - textMsg.textContent = translateElements.timer.ph_msgend + textMsg.textContent = translateElements.timer.phMsgEnd textMsg.style.color = '#555' } else { textMsg.style.color = '#000' } }) formatSelector.addEventListener('change', () => { - socket.send(JSON.stringify({ action: 'changeFormatCdown', format: formatSelector.value, classElement })) + socket.send(JSON.stringify({ action: 'changeFormat', format: formatSelector.value, classElement })) }) fontSelect.addEventListener('change', () => { - socket.send(JSON.stringify({ action: 'changeFontCdown', font: fontSelect.value, classElement })) + socket.send(JSON.stringify({ action: 'changeFont', font: fontSelect.value, classElement })) }) fontSize.addEventListener('change', () => { @@ -255,37 +255,37 @@ fontSize.addEventListener('change', () => { } // Send the new size to the server - socket.send(JSON.stringify({ action: 'changeSizeCdown', size: newSize, classElement })) + socket.send(JSON.stringify({ action: 'changeSize', size: newSize, classElement })) }) boldButton.addEventListener('click', () => { - socket.send(JSON.stringify({ action: 'textFormatCdown', format: 'bold', classElement })) + socket.send(JSON.stringify({ action: 'textFormat', format: 'bold', classElement })) }) italicButton.addEventListener('click', () => { - socket.send(JSON.stringify({ action: 'textFormatCdown', format: 'italic', classElement })) + socket.send(JSON.stringify({ action: 'textFormat', format: 'italic', classElement })) }) underlineButton.addEventListener('click', () => { - socket.send(JSON.stringify({ action: 'textFormatCdown', format: 'underline', classElement })) + socket.send(JSON.stringify({ action: 'textFormat', format: 'underline', classElement })) }) alignLeftButton.addEventListener('click', () => { - socket.send(JSON.stringify({ action: 'alignCdown', align: 'left', classElement })) + socket.send(JSON.stringify({ action: 'align', align: 'left', classElement })) }) alignCenterButton.addEventListener('click', () => { - socket.send(JSON.stringify({ action: 'alignCdown', align: 'center', classElement })) + socket.send(JSON.stringify({ action: 'align', align: 'center', classElement })) }) alignRightButton.addEventListener('click', () => { - socket.send(JSON.stringify({ action: 'alignCdown', align: 'right', classElement })) + socket.send(JSON.stringify({ action: 'align', align: 'right', classElement })) }) colorPicker.addEventListener('change', () => { checkHexColor = colorPicker.value.toUpperCase() // If the hexadecimal code is valid, send the color to the server - socket.send(JSON.stringify({ action: 'changeColorCdown', color: colorPicker.value.toUpperCase(), classElement })) + socket.send(JSON.stringify({ action: 'changeColor', color: colorPicker.value.toUpperCase(), classElement })) colorHex.value = checkHexColor }) @@ -298,7 +298,7 @@ colorHex.addEventListener('change', () => { if (hexRegex.test(hexColor)) { checkHexColor = hexColor.toUpperCase() // If the hexadecimal code is valid, send the color to the server - socket.send(JSON.stringify({ action: 'changeColorCdown', color: checkHexColor, classElement })) + socket.send(JSON.stringify({ action: 'changeColor', color: checkHexColor, classElement })) colorPicker.value = checkHexColor colorHex.value = checkHexColor } else { diff --git a/core/template/cdown/view/client.js b/core/template/cdown/view/client.js index 492550e..a57883c 100644 --- a/core/template/cdown/view/client.js +++ b/core/template/cdown/view/client.js @@ -39,7 +39,7 @@ socket.addEventListener('message', (event) => { } formatTimeVar = message[classElement].formatTime - if (message[classElement].status === 'stopped') { + if (message[classElement].status === 'ended') { if (message[classElement].milliseconds !== 0) { updateTimeDisplay(formatTimeVar, message[classElement].milliseconds) } else if (message[classElement].msgEnd !== '') { diff --git a/core/template/cdowntime/control/control.js b/core/template/cdowntime/control/control.js index db161c9..1943afb 100644 --- a/core/template/cdowntime/control/control.js +++ b/core/template/cdowntime/control/control.js @@ -107,7 +107,7 @@ socket.addEventListener('message', (event) => { // Perform necessary actions with the variables here textMsg.textContent = elementVariables.msgEnd if (elementVariables.msgEnd === '') { - textMsg.textContent = translateElements.timer.ph_msgend + textMsg.textContent = translateElements.timer.phMsgEnd textMsg.style.color = '#555' } else { textMsg.style.color = '#000' } timeData.value = new Date(elementVariables.endDatetime).toLocaleString('en-CA', { timeZone: elementVariables.timezone, hour12: false }).replace(/,\s/, 'T') @@ -189,7 +189,7 @@ subContainer.addEventListener('click', (event) => { }) textMsg.addEventListener('focus', () => { - if (textMsg.textContent === translateElements.timer.ph_msgend) { + if (textMsg.textContent === translateElements.timer.phMsgEnd) { textMsg.textContent = '' textMsg.style.color = '#000' } @@ -198,17 +198,17 @@ textMsg.addEventListener('focus', () => { textMsg.addEventListener('blur', () => { socket.send(JSON.stringify({ action: 'editMsgCdownTime', msg: textMsg.textContent, classElement })) if (textMsg.textContent === '') { - textMsg.textContent = translateElements.timer.ph_msgend + textMsg.textContent = translateElements.timer.phMsgEnd textMsg.style.color = '#555' } else { textMsg.style.color = '#000' } }) formatSelector.addEventListener('change', () => { - socket.send(JSON.stringify({ action: 'changeFormatCdownTime', format: formatSelector.value, classElement })) + socket.send(JSON.stringify({ action: 'changeFormat', format: formatSelector.value, classElement })) }) fontSelect.addEventListener('change', () => { - socket.send(JSON.stringify({ action: 'changeFontCdownTime', font: fontSelect.value, classElement })) + socket.send(JSON.stringify({ action: 'changeFont', font: fontSelect.value, classElement })) }) fontSize.addEventListener('change', () => { @@ -226,37 +226,37 @@ fontSize.addEventListener('change', () => { } // Send the new size to the server - socket.send(JSON.stringify({ action: 'changeSizeCdownTime', size: newSize, classElement })) + socket.send(JSON.stringify({ action: 'changeSize', size: newSize, classElement })) }) boldButton.addEventListener('click', () => { - socket.send(JSON.stringify({ action: 'textFormatCdownTime', format: 'bold', classElement })) + socket.send(JSON.stringify({ action: 'textFormat', format: 'bold', classElement })) }) italicButton.addEventListener('click', () => { - socket.send(JSON.stringify({ action: 'textFormatCdownTime', format: 'italic', classElement })) + socket.send(JSON.stringify({ action: 'textFormat', format: 'italic', classElement })) }) underlineButton.addEventListener('click', () => { - socket.send(JSON.stringify({ action: 'textFormatCdownTime', format: 'underline', classElement })) + socket.send(JSON.stringify({ action: 'textFormat', format: 'underline', classElement })) }) alignLeftButton.addEventListener('click', () => { - socket.send(JSON.stringify({ action: 'alignCdownTime', align: 'left', classElement })) + socket.send(JSON.stringify({ action: 'align', align: 'left', classElement })) }) alignCenterButton.addEventListener('click', () => { - socket.send(JSON.stringify({ action: 'alignCdownTime', align: 'center', classElement })) + socket.send(JSON.stringify({ action: 'align', align: 'center', classElement })) }) alignRightButton.addEventListener('click', () => { - socket.send(JSON.stringify({ action: 'alignCdownTime', align: 'right', classElement })) + socket.send(JSON.stringify({ action: 'align', align: 'right', classElement })) }) colorPicker.addEventListener('change', () => { checkHexColor = colorPicker.value.toUpperCase() // If the hexadecimal code is valid, send the color to the server - socket.send(JSON.stringify({ action: 'changeColorCdownTime', color: colorPicker.value.toUpperCase(), classElement })) + socket.send(JSON.stringify({ action: 'changeColor', color: colorPicker.value.toUpperCase(), classElement })) colorHex.value = checkHexColor }) @@ -269,7 +269,7 @@ colorHex.addEventListener('change', () => { if (hexRegex.test(hexColor)) { checkHexColor = hexColor.toUpperCase() // If the hexadecimal code is valid, send the color to the server - socket.send(JSON.stringify({ action: 'changeColorCdownTime', color: checkHexColor, classElement })) + socket.send(JSON.stringify({ action: 'changeColor', color: checkHexColor, classElement })) colorPicker.value = checkHexColor colorHex.value = checkHexColor } else { diff --git a/core/template/crono/control/control.js b/core/template/crono/control/control.js index e5606c1..bd8270c 100644 --- a/core/template/crono/control/control.js +++ b/core/template/crono/control/control.js @@ -184,11 +184,11 @@ subContainer.addEventListener('click', (event) => { }) formatSelector.addEventListener('change', () => { - socket.send(JSON.stringify({ action: 'changeFormatCrono', format: formatSelector.value, classElement })) + socket.send(JSON.stringify({ action: 'changeFormat', format: formatSelector.value, classElement })) }) fontSelect.addEventListener('change', () => { - socket.send(JSON.stringify({ action: 'changeFontCrono', font: fontSelect.value, classElement })) + socket.send(JSON.stringify({ action: 'changeFont', font: fontSelect.value, classElement })) }) fontSize.addEventListener('change', () => { @@ -200,36 +200,36 @@ fontSize.addEventListener('change', () => { fontSize.value = maxSize } - socket.send(JSON.stringify({ action: 'changeSizeCrono', size: newSize, classElement })) + socket.send(JSON.stringify({ action: 'changeSize', size: newSize, classElement })) }) boldButton.addEventListener('click', () => { - socket.send(JSON.stringify({ action: 'textFormatCrono', format: 'bold', classElement })) + socket.send(JSON.stringify({ action: 'textFormat', format: 'bold', classElement })) }) italicButton.addEventListener('click', () => { - socket.send(JSON.stringify({ action: 'textFormatCrono', format: 'italic', classElement })) + socket.send(JSON.stringify({ action: 'textFormat', format: 'italic', classElement })) }) underlineButton.addEventListener('click', () => { - socket.send(JSON.stringify({ action: 'textFormatCrono', format: 'underline', classElement })) + socket.send(JSON.stringify({ action: 'textFormat', format: 'underline', classElement })) }) alignLeftButton.addEventListener('click', () => { - socket.send(JSON.stringify({ action: 'alignCrono', align: 'left', classElement })) + socket.send(JSON.stringify({ action: 'align', align: 'left', classElement })) }) alignCenterButton.addEventListener('click', () => { - socket.send(JSON.stringify({ action: 'alignCrono', align: 'center', classElement })) + socket.send(JSON.stringify({ action: 'align', align: 'center', classElement })) }) alignRightButton.addEventListener('click', () => { - socket.send(JSON.stringify({ action: 'alignCrono', align: 'right', classElement })) + socket.send(JSON.stringify({ action: 'align', align: 'right', classElement })) }) colorPicker.addEventListener('change', () => { checkHexColor = colorPicker.value.toUpperCase() - socket.send(JSON.stringify({ action: 'changeColorCrono', color: checkHexColor, classElement })) + socket.send(JSON.stringify({ action: 'changeColor', color: checkHexColor, classElement })) colorHex.value = checkHexColor }) @@ -239,7 +239,7 @@ colorHex.addEventListener('change', () => { if (hexRegex.test(hexColor)) { checkHexColor = hexColor.toUpperCase() - socket.send(JSON.stringify({ action: 'changeColorCrono', color: checkHexColor, classElement })) + socket.send(JSON.stringify({ action: 'changeColor', color: checkHexColor, classElement })) colorPicker.value = checkHexColor colorHex.value = checkHexColor } else { diff --git a/core/template/extensible/control/blank.html b/core/template/extensible/control/blank.html new file mode 100644 index 0000000..1e32f96 --- /dev/null +++ b/core/template/extensible/control/blank.html @@ -0,0 +1,16 @@ + + + + + + URL Action + + + + + + diff --git a/core/template/extensible/control/control.js b/core/template/extensible/control/control.js new file mode 100644 index 0000000..5ee63fd --- /dev/null +++ b/core/template/extensible/control/control.js @@ -0,0 +1,456 @@ +const controlButton = document.getElementById('controlButton') +const resetButton = document.getElementById('resetButton') +const timeText = document.getElementById('timeText') +const addContainer = document.getElementById('buttonsaddtime') +const subContainer = document.getElementById('buttonssubtime') +const checkboxStopAdd = document.getElementById('checkboxStopAdd') +const checkboxLabelStopAdd = document.getElementById('checkboxLabelStopAdd') +const checkboxPauseAdd = document.getElementById('checkboxPauseAdd') +const checkboxLabelPauseAdd = document.getElementById('checkboxLabelPauseAdd') +const textMsg = document.getElementById('text-endmsg') +const formatSelectorCrono = document.getElementById('formatSelectorCrono') +const formatSelectorCdown = document.getElementById('formatSelectorCdown') +const fontSelect = document.getElementById('fontSelect') // Font selector +const fontSize = document.getElementById('fontSize') +const boldButton = document.getElementById('boldButton') +const italicButton = document.getElementById('italicButton') +const underlineButton = document.getElementById('underlineButton') +const alignLeftButton = document.getElementById('alignLeft') +const alignCenterButton = document.getElementById('alignCenter') +const alignRightButton = document.getElementById('alignRight') +const colorPicker = document.getElementById('colorPicker') +const colorHex = document.getElementById('colorHex') +const titlePage = document.getElementById('titlePage') +const selectorLang = document.getElementById('language-selector') +const switchTheme = document.getElementById('switch-theme') +// const test = document.getElementById('test'); +const socket = new WebSocket('ws://localhost:3000') + +const classElement = window.location.href.split('/')[3] +titlePage.textContent = classElement + ' - Control' +let translateElements + +let checkTextTime +let checkHexColor + +socket.addEventListener('open', (event) => { + console.log('WebSocket Connection Opened') + + // Ask the WebSocket server to send variable data + socket.send(JSON.stringify({ action: 'getVariables', classElement })) +}) + +socket.addEventListener('message', (event) => { + const message = JSON.parse(event.data) + + if (message.action === 'reload') { + window.location.reload() + } + + if (message.fonts) { + // If the message contains a list of fonts + updateFontSelector(message.fonts) + } + if (fontSelect.innerHTML !== '') { + // Call the function to get the maximum font size width + const maxWidth = getMaxSizeWidth() + + // Set the calculated width as the CSS style for the font size selector + fontSize.style.width = maxWidth + + if (message.action === 'sendVariables' && message.classElement === classElement) { + // If the message contains variable data + const elementVariables = message.variables + translateElements = message.translateElements + + // Config and translates + switchTheme.checked = message.config.themedark + if (message.config.themedark) { + document.body.classList.remove('light-theme') + document.body.classList.add('dark-theme') + } else { + document.body.classList.remove('dark-theme') + document.body.classList.add('light-theme') + } + + selectorLang.innerHTML = '' + Object.keys(message.formats.langs).forEach((format) => { + const option = document.createElement('option') + option.value = format + option.textContent = message.formats.langs[format] + selectorLang.appendChild(option) + }) + selectorLang.value = Object.keys(message.formats.langs).includes(message.config.lang) + ? message.config.lang + : 'en' + document.documentElement.lang = Object.keys(message.formats.langs).includes(message.config.lang) + ? message.config.lang + : 'en' + + controlButton.textContent = translateElements.timer.buttons.start + resetButton.textContent = translateElements.timer.buttons.reset + checkboxLabelStopAdd.textContent = translateElements.timer.enableStopAdd + checkboxLabelPauseAdd.textContent = translateElements.timer.enablePauseAdd + + if (elementVariables && typeof elementVariables === 'object') { + checkTextTime = MsToText(elementVariables.textMilliseconds) + checkHexColor = elementVariables.colorText + + // Format selector options + formatSelectorCrono.innerHTML = '' + message.formats[classElement.replace(/\d/g, '')].forEach((format) => { + const option = document.createElement('option') + option.value = format + option.textContent = format + formatSelectorCrono.appendChild(option) + }) + + formatSelectorCdown.innerHTML = '' + message.formats[classElement.replace(/\d/g, '')].forEach((format) => { + const option = document.createElement('option') + option.value = format + option.textContent = format + formatSelectorCdown.appendChild(option) + }) + + // Perform necessary actions with the variables here + textMsg.textContent = elementVariables.msgEnd + if (elementVariables.msgEnd === '') { + textMsg.textContent = translateElements.timer.phMsgEnd + textMsg.style.color = '#555' + } else { textMsg.style.color = '#000' } + timeText.value = MsToText(elementVariables.textMilliseconds) + // checkboxStopAdd.checked = elementVariables.enableStopAdd + // checkboxPauseAdd.checked = elementVariables.enablePauseAdd + formatSelectorCrono.value = elementVariables.formatTimeCrono + formatSelectorCdown.value = elementVariables.formatTimeCdown + fontSelect.value = elementVariables.font + fontSize.value = elementVariables.size + textFormat(elementVariables) + formatAlign(elementVariables.align) + colorPicker.value = elementVariables.colorText + colorHex.value = elementVariables.colorText + if (translateElements) { + updateControlButton(elementVariables.status) + } + } else { + console.log('The server did not return valid data.') + } + } else { + if (message[classElement].status !== 'started') { + textMsg.textContent = message[classElement].msgEnd + if (message[classElement].msgEnd === '') { + textMsg.textContent = translateElements.timer.phMsgEnd + textMsg.style.color = '#555' + } else { textMsg.style.color = '#000' } + timeText.value = MsToText(message[classElement].textMilliseconds) + checkboxStopAdd.checked = message[classElement].enableStopAdd + checkboxPauseAdd.checked = message[classElement].enablePauseAdd + formatSelectorCrono.value = message[classElement].formatTimeCrono + formatSelectorCdown.value = message[classElement].formatTimeCdown + fontSelect.value = message[classElement].font + fontSize.value = message[classElement].size + colorPicker.value = message[classElement].colorText + colorHex.value = message[classElement].colorText + } + formatAlign(message[classElement].align) + textFormat(message[classElement]) + // Update the control button and other elements based on the received message + updateControlButton(message[classElement].status) + formatSelectorCrono.value = message[classElement].formatTimeCrono + formatSelectorCdown.value = message[classElement].formatTimeCdown + } + } else { + window.location.reload() + } + twemoji.parse(document.body) +}) + +socket.addEventListener('close', (event) => { + console.log('WebSocket Connection Closed') +}) + +switchTheme.addEventListener('change', () => { + socket.send(JSON.stringify({ action: 'themeChange', themedark: switchTheme.checked })) +}) + +selectorLang.addEventListener('change', () => { + socket.send(JSON.stringify({ action: 'langChange', lang: selectorLang.value })) +}) + +controlButton.addEventListener('click', () => { + if (controlButton.textContent === translateElements.timer.buttons.start) { + socket.send(JSON.stringify({ action: 'startExtensible', classElement })) + } else { + socket.send(JSON.stringify({ action: 'pauseExtensible', classElement })) + } +}) + +resetButton.addEventListener('click', () => { + socket.send(JSON.stringify({ action: 'resetExtensible', classElement })) +}) + +timeText.addEventListener('change', () => { + const textTime = timeText.value.trim() + + // Regular expression to check the correct time format + const timeRegex = /^(\d+):([0-5]?\d):([0-5]?\d)$/ + + if (timeRegex.test(textTime)) { + checkTextTime = textTime + // If the time format is valid, send the time to the server + socket.send(JSON.stringify({ action: 'changeTimeExtensible', time: TextToMs(checkTextTime), classElement })) + timeText.value = MsToText(TextToMs(checkTextTime)) + } else { + timeText.value = checkTextTime + } +}) + +// Add an event listener to the main container +addContainer.addEventListener('click', (event) => { + const target = event.target + + // Find the nearest button to the clicked element (including icons and text) + const button = target.closest('button') + + if (button) { + // A button was clicked + const data = button.id.split('-') + + if (button.id.startsWith('addtime-')) { + socket.send(JSON.stringify({ action: 'editTimeExtensible', time: `+${data[1]}`, classElement })) + } + } +}) + +subContainer.addEventListener('click', (event) => { + const target = event.target + + // Find the nearest button to the clicked element (including icons and text) + const button = target.closest('button') + + if (button) { + // A button was clicked + const data = button.id.split('-') + + if (button.id.startsWith('subtime-')) { + socket.send(JSON.stringify({ action: 'editTimeExtensible', time: `-${data[1]}`, classElement })) + } + } +}) + +checkboxStopAdd.addEventListener('change', () => { + socket.send(JSON.stringify({ action: 'checkboxStopAdd', value: checkboxStopAdd.checked, classElement })) +}) + +checkboxPauseAdd.addEventListener('change', () => { + socket.send(JSON.stringify({ action: 'checkboxPauseAdd', value: checkboxPauseAdd.checked, classElement })) +}) + +textMsg.addEventListener('focus', () => { + if (textMsg.textContent === translateElements.timer.phMsgEnd) { + textMsg.textContent = '' + textMsg.style.color = '#000' + } +}) + +textMsg.addEventListener('blur', () => { + socket.send(JSON.stringify({ action: 'editMsgExtensible', msg: textMsg.textContent, classElement })) + if (textMsg.textContent === '') { + textMsg.textContent = translateElements.timer.phMsgEnd + textMsg.style.color = '#555' + } else { textMsg.style.color = '#000' } +}) + +formatSelectorCrono.addEventListener('change', () => { + socket.send(JSON.stringify({ action: 'changeFormatExtCrono', format: formatSelectorCrono.value, classElement })) +}) + +formatSelectorCdown.addEventListener('change', () => { + socket.send(JSON.stringify({ action: 'changeFormatExtCdown', format: formatSelectorCdown.value, classElement })) +}) + +fontSelect.addEventListener('change', () => { + socket.send(JSON.stringify({ action: 'changeFont', font: fontSelect.value, classElement })) +}) + +fontSize.addEventListener('change', () => { + // Get the maximum allowed value from the 'max' attribute + const maxSize = parseFloat(fontSize.getAttribute('max')) + + // Get the manually entered value as a number + let newSize = parseFloat(fontSize.value) + + // Check if the entered value is greater than the maximum value + if (newSize > maxSize) { + // If it's greater, set the value to the maximum allowed + newSize = maxSize + fontSize.value = maxSize + } + + // Send the new size to the server + socket.send(JSON.stringify({ action: 'changeSize', size: newSize, classElement })) +}) + +boldButton.addEventListener('click', () => { + socket.send(JSON.stringify({ action: 'textFormat', format: 'bold', classElement })) +}) + +italicButton.addEventListener('click', () => { + socket.send(JSON.stringify({ action: 'textFormat', format: 'italic', classElement })) +}) + +underlineButton.addEventListener('click', () => { + socket.send(JSON.stringify({ action: 'textFormat', format: 'underline', classElement })) +}) + +alignLeftButton.addEventListener('click', () => { + socket.send(JSON.stringify({ action: 'align', align: 'left', classElement })) +}) + +alignCenterButton.addEventListener('click', () => { + socket.send(JSON.stringify({ action: 'align', align: 'center', classElement })) +}) + +alignRightButton.addEventListener('click', () => { + socket.send(JSON.stringify({ action: 'align', align: 'right', classElement })) +}) + +colorPicker.addEventListener('change', () => { + checkHexColor = colorPicker.value.toUpperCase() + // If the hexadecimal code is valid, send the color to the server + socket.send(JSON.stringify({ action: 'changeColor', color: colorPicker.value.toUpperCase(), classElement })) + colorHex.value = checkHexColor +}) + +colorHex.addEventListener('change', () => { + const hexColor = colorHex.value.trim() + + // Regular expression to check the correct hexadecimal color code format + const hexRegex = /^#([0-9A-Fa-f]{6})$/ + + if (hexRegex.test(hexColor)) { + checkHexColor = hexColor.toUpperCase() + // If the hexadecimal code is valid, send the color to the server + socket.send(JSON.stringify({ action: 'changeColorExtensible', color: checkHexColor, classElement })) + colorPicker.value = checkHexColor + colorHex.value = checkHexColor + } else { + colorHex.value = checkHexColor + } +}) + +// Function to update the font selector +function updateFontSelector (fonts) { + // Clear the font selector + fontSelect.innerHTML = '' + + // Add font options to the selector without quotes + fonts.forEach((font) => { + // Remove double quotes at the beginning and end of the font name + font = font.replace(/^"(.*)"$/, '$1') + + const option = document.createElement('option') + option.value = font + option.textContent = font + fontSelect.appendChild(option) + }) +} + +function updateControlButton (status) { + const maxWidth = getMaxButtonWidth() + controlButton.style.width = maxWidth + + if (status === 'started') { + controlButton.textContent = translateElements.timer.buttons.pause + } else { + controlButton.textContent = translateElements.timer.buttons.start + } +} + +function getMaxButtonWidth () { + const widths = [] + + Object.keys(translateElements.timer.buttons).forEach((value) => { + controlButton.textContent = translateElements.timer.buttons[value] + widths.push(parseFloat(window.getComputedStyle(controlButton).getPropertyValue('width'))) + }) + // Get the maximum of the two widths + return Math.max(...widths) + 'px' +} + +function getMaxSizeWidth () { + const maxvalue = fontSize.getAttribute('max') // Get the maximum value from the 'max' attribute + + // Get the maximum of the two widths + return maxvalue.length * 20 + 'px' +} + +function formatAlign (align) { + // List of buttons and their corresponding alignments + const buttons = [ + { button: alignLeftButton, align: 'left' }, + { button: alignCenterButton, align: 'center' }, + { button: alignRightButton, align: 'right' } + ] + + // Reset the format of all buttons + buttons.forEach((btn) => { + btn.button.style.backgroundColor = '#ccc' + btn.button.style.color = '#333' + btn.button.style.border = '2px solid #ccc' + }) + + // Find and highlight the selected button + const selectedButton = buttons.find((btn) => btn.align === align) + if (selectedButton) { + selectedButton.button.style.backgroundColor = '#777' + selectedButton.button.style.color = 'white' + selectedButton.button.style.border = '2px solid #777' + } +} + +function textFormat (message) { + // List of buttons and their corresponding formats + const buttons = [ + { button: boldButton, format: message.bold }, + { button: italicButton, format: message.italic }, + { button: underlineButton, format: message.underline } + ] + + // Set the format for all buttons + buttons.forEach((btn) => { + if (btn.format) { + btn.button.style.backgroundColor = '#777' + btn.button.style.color = 'white' + btn.button.style.border = '2px solid #777' + } else { + btn.button.style.backgroundColor = '#ccc' + btn.button.style.color = '#333' + btn.button.style.border = '2px solid #ccc' + } + }) +} + +function TextToMs (text) { + const timeComponents = text.split(':') + + const hours = parseInt(timeComponents[0], 10) + const minutes = parseInt(timeComponents[1], 10) + const seconds = parseInt(timeComponents[2], 10) + + return (hours * 3600 + minutes * 60 + seconds) * 1000 +} + +function MsToText (ms) { + const total = ms / 1000 + const hours = Math.floor(total / 3600) + const minutes = Math.floor((total % 3600) / 60) + const seconds = total % 60 + + const formattedHours = String(hours).padStart(2, '0') + const formattedMinutes = String(minutes).padStart(2, '0') + const formattedSeconds = String(seconds).padStart(2, '0') + + return `${formattedHours}:${formattedMinutes}:${formattedSeconds}` +} diff --git a/core/template/extensible/control/index.html b/core/template/extensible/control/index.html new file mode 100644 index 0000000..e244809 --- /dev/null +++ b/core/template/extensible/control/index.html @@ -0,0 +1,121 @@ + + + + + + + + + + + + + +
+ + + + + + + +
+ +
+
+ + +
+
+
+ + + + + + +
+
+ +
+
+ + + + + + +
+
+ + +
+
+ + +
+
+
+
+
+
+
+ + +
+
+ + +
+
+
+ + +
+
+ + + + + + + + + + +
+
+ + + + +
+
+ + + diff --git a/core/template/extensible/control/styles.css b/core/template/extensible/control/styles.css new file mode 100644 index 0000000..ded1b60 --- /dev/null +++ b/core/template/extensible/control/styles.css @@ -0,0 +1,236 @@ +/* Estilos para crono01/control */ + +body { + margin: 0; + padding: 0; + font-family: Arial, sans-serif; + justify-content: center; + align-items: center; +} + +.light-theme { + background-color: #fff; +} + +/* Estilos para el tema oscuro */ +.dark-theme { + background-color: #555; +} + +#icon-fa-clock, +#icon-fa-stopwatch { + margin-right: 10px; + color: #000; + font-size: 30px; +} + +.container { + text-align: center; + margin-top: 50px; +} + +.start-button { + background-color: #4caf50; + color: white; + font-size: 24px; + padding: 10px 20px; + border: 2px solid #4caf50; /* Borde */ + border-radius: 5px; /* Borde redondeado */ + cursor: pointer; + margin-right: 10px; + margin-left: 10px; +} + +.start-button:hover { + background-color: #388e3c; /* Fondo gris más oscuro al pasar el ratón */ + border: 2px solid #388e3c; +} + +.reset-button { + background-color: #f44336; + color: white; + font-size: 24px; + padding: 10px 20px; + border: 2px solid #f44336; /* Borde */ + border-radius: 5px; /* Borde redondeado */ + cursor: pointer; + margin-right: 10px; + margin-left: 10px; +} + +.reset-button:hover { + background-color: #d9362e; /* Fondo gris más oscuro al pasar el ratón */ + border: 2px solid #d9362e; +} + +.space-between { + margin-top: 5px; /* La mitad de 20px (espacio entre divs) */ +} + +#timeText { + background-color: #cccccc88; + font-size: 24px; /* Tamaño de fuente */ + padding: 10px 20px; /* Espaciado interno */ + text-align: right; + border: 2px solid #cccccc88; /* Borde */ + border-radius: 5px; /* Borde redondeado */ + width: 150px; +} + +.addtime-button { + background-color: #4caf50aa; + color: white; + font-size: 18px; + padding: 5px 10px; + border: 2px solid #4caf50aa; /* Borde */ + border-radius: 5px; /* Borde redondeado */ + cursor: pointer; + margin-right: 2.5px; + margin-left: 2.5px; + width: 70px; +} + +.addtime-button:hover { + background-color: #388e3caa; /* Fondo gris más oscuro al pasar el ratón */ + border: 2px solid #388e3caa; +} + +.subtime-button { + background-color: #f44336aa; + color: white; + font-size: 18px; + padding: 5px 10px; + border: 2px solid #f44336aa; /* Borde */ + border-radius: 5px; /* Borde redondeado */ + cursor: pointer; + margin-right: 2.5px; + margin-left: 2.5px; + width: 70px; +} + +.subtime-button:hover { + background-color: #d9362eaa; /* Fondo gris más oscuro al pasar el ratón */ + border: 2px solid #d9362eaa; +} + +.checkboxBox { + background-color: #cccccc88; + border: 2px solid #cccccc88; /* Borde */ + border-radius: 5px; /* Borde redondeado */ + cursor: pointer; + width: 18px; /* Ancho personalizado */ + height: 18px; /* Alto personalizado */ +} + +.checkboxText { + font-size: 18px; /* Tamaño de fuente */ +} + +.text-input-container { + display: flex; + justify-content: center; /* Centra horizontalmente */ + align-items: flex-start; +} + +.paragraph { + background-color: #cccccc88; + font-size: 24px; /* Tamaño de fuente */ + padding: 10px 20px; /* Espaciado interno */ + border: 2px solid #cccccc88; /* Borde */ + border-radius: 5px; /* Borde redondeado */ + margin-right: 10px; + margin-left: 10px; + width: 500px; + height: auto; + min-height: 28px; /* Altura mínima para que sea visible */ +} + +/* Estilos para el selector */ +#formatSelectorCrono, +#formatSelectorCdown, +#fontSelect { + background-color: #cccccc88; + font-size: 24px; /* Tamaño de fuente */ + padding: 10px 20px; /* Espaciado interno */ + border: 2px solid #cccccc88; /* Borde */ + border-radius: 5px; /* Borde redondeado */ + margin-right: 10px; + margin-left: 10px; + cursor: pointer; + width: auto; +} + +#fontSize { + background-color: #cccccc88; + font-size: 24px; /* Tamaño de fuente */ + padding: 10px 20px; /* Espaciado interno */ + border: 2px solid #cccccc88; /* Borde */ + border-radius: 5px; /* Borde redondeado */ + margin-right: 10px; + margin-left: 10px; + width: auto; +} + +/* Estilos para los botones de alineación */ +#boldButton, +#italicButton, +#underlineButton, +#alignLeft, +#alignCenter, +#alignRight { + background-color: #ccc; /* Fondo gris claro */ + color: #333; /* Texto gris oscuro */ + font-size: 24px; /* Tamaño de fuente */ + padding: 10px 20px; /* Espaciado interno */ + border: 2px solid #ccc; /* Borde */ + border-radius: 5px; /* Borde redondeado */ + cursor: pointer; + width: 65px; +} + +#boldButton:hover, +#italicButton:hover, +#underlineButton:hover, +#alignLeft:hover, +#alignCenter:hover, +#alignRight:hover { + background-color: #999; /* Fondo gris más oscuro al pasar el ratón */ + border: 2px solid #999; +} + +#colorPicker { + background-color: #cccccc88; + border: 2px solid #cccccc88; + border-radius: 5px; + cursor: pointer; + height: 52px; + vertical-align: bottom; +} + +#colorPicker:hover { + border: 2px solid #999; /* Cambia el borde al pasar el ratón */ + cursor: pointer; +} + +#colorHex { + background-color: #cccccc88; + font-size: 24px; /* Tamaño de fuente */ + padding: 10px 20px; /* Espaciado interno */ + border: 2px solid #cccccc88; /* Borde */ + border-radius: 5px; /* Borde redondeado */ + width: 120px; +} + +#textFormatBlock, +#alingblock, +#colorblock { + margin-right: 10px; + margin-left: 10px; +} + +img.emoji { + height: 1em; + width: 1em; + margin: 0 0.05em 0 0.1em; + vertical-align: -0.1em; +} diff --git a/core/template/extensible/control/topbar.css b/core/template/extensible/control/topbar.css new file mode 100644 index 0000000..ffc660c --- /dev/null +++ b/core/template/extensible/control/topbar.css @@ -0,0 +1,94 @@ +.top-bar { + background-color: #e5e5e5; + display: flex; + justify-content: right; + align-items: right; + padding: 10px 20px; +} + +.language-span { + font-size: 30px; /* Tamaño de fuente */ + margin-right: 10px; + margin-left: 10px; +} + +.language-selector { + font-family: Arial, sans-serif; + font-size: 17px; /* Tamaño de fuente */ + border: 2px solid #ccc; /* Borde */ + border-radius: 5px; /* Borde redondeado */ + vertical-align: top; + margin-top: 3.5px; + width: auto; +} + +.theme-span { + font-size: 22px; /* Tamaño de fuente */ + margin-right: 10px; + margin-left: 10px; + margin-top: 3.5px; +} + +/* The switch - the box around the slider */ +.switch { + position: relative; + display: inline-block; + width: 40px; + height: 25px; +} + +/* Hide default HTML checkbox */ +.switch input { + opacity: 0; + width: 0; + height: 0; +} + +/* The slider */ +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; + -webkit-transition: 0.4s; + transition: 0.4s; +} + +.slider:before { + position: absolute; + content: ""; + height: 20px; + width: 20px; + top: 2px; + left: 2px; + bottom: 4px; + background-color: white; + -webkit-transition: 0.4s; + transition: 0.4s; +} + +input:checked + .slider { + background-color: #ccc; +} + +input:focus + .slider { + box-shadow: 0 0 1px #ccc; +} + +input:checked + .slider:before { + -webkit-transform: translateX(16px); + -ms-transform: translateX(16px); + transform: translateX(16px); +} + +/* Rounded sliders */ +.slider.round { + border-radius: 20px; +} + +.slider.round:before { + border-radius: 50%; +} diff --git a/core/template/extensible/viewCdown/client.js b/core/template/extensible/viewCdown/client.js new file mode 100644 index 0000000..c315ad0 --- /dev/null +++ b/core/template/extensible/viewCdown/client.js @@ -0,0 +1,165 @@ +// Elements +const timeElement = document.getElementById('time') +const containers = document.querySelectorAll('.container') +const titlePage = document.getElementById('titlePage') +// const test = document.getElementById('test'); // Commented out unused variable +const socket = new WebSocket('ws://localhost:3000') + +// Extract class element from URL +const classElement = window.location.href.split('/')[3] +titlePage.textContent = classElement + ' - View - Countdown' + +let intervalId = null +let formatTimeVar + +socket.addEventListener('open', (event) => { + console.log('WebSocket Connection Opened') + + // Request the WebSocket server to send variable data + socket.send(JSON.stringify({ action: 'getVariables', classElement })) +}) + +socket.addEventListener('message', (event) => { + const message = JSON.parse(event.data) + + if (message.action === 'reload') { + window.location.reload() + } + + if (message.action === 'sendVariables' && message.classElement === classElement && message.config) { + document.documentElement.lang = Object.keys(message.formats.langs).includes(message.config.lang) + ? message.config.lang + : 'en' + } + + if (message[classElement].milliseconds !== undefined) { + if (formatTimeVar !== message[classElement].formatTimeCdown && intervalId) { + clearInterval(intervalId) + intervalId = null + } + + formatTimeVar = message[classElement].formatTimeCdown + if (message[classElement].status === 'ended') { + if (message[classElement].milliseconds !== 0) { + updateTimeDisplay(formatTimeVar, message[classElement].milliseconds) + } else if (message[classElement].msgEnd !== '') { + timeElement.textContent = message[classElement].msgEnd + twemoji.parse(document.body) + } else { + updateTimeDisplay(formatTimeVar, 0) + } + } else { + updateTimeDisplay(formatTimeVar, message[classElement].milliseconds) + } + + // Update the timer based on the received message + timeElement.style.fontFamily = `"${message[classElement].font}"` + timeElement.style.fontSize = message[classElement].size + 'px' + timeElement.style.color = message[classElement].colorText + + if (message[classElement].bold) { + timeElement.style.fontWeight = 'bold' + } else { + timeElement.style.fontWeight = 'normal' + } + if (message[classElement].italic) { + timeElement.style.fontStyle = 'italic' + } else { + timeElement.style.fontStyle = 'normal' + } + if (message[classElement].underline) { + timeElement.style.textDecoration = 'underline' + } else { + timeElement.style.textDecoration = 'none' + } + containers.forEach((container) => { + container.style.textAlign = message[classElement].align + }) + + // If the timer is in "started" state, start the interval + if (message[classElement].status === 'started') { + if (!intervalId) { + intervalId = setInterval(() => { + if (message[classElement].startTime + message[classElement].milliseconds > Date.now()) { + updateTimeDisplay(formatTimeVar, message[classElement].startTime + message[classElement].milliseconds - Date.now()) + } else { + socket.send(JSON.stringify({ action: 'stopExtensible', classElement })) + } + }, 1) // Update every 1 millisecond + } + } else { + // If the timer is not in "started" state, stop the interval + clearInterval(intervalId) + intervalId = null + } + } +}) + +socket.addEventListener('close', (event) => { + console.log('WebSocket Connection Closed') +}) + +// Update the time display based on format and milliseconds +function updateTimeDisplay (format, milliseconds) { + if (isNaN(milliseconds)) { + milliseconds = 0 + } + + const totalMilliseconds = Math.floor(milliseconds) + const totalSeconds = Math.floor(totalMilliseconds / 1000) + const hours = Math.floor(totalSeconds / 3600) + const minutes = Math.floor((totalSeconds % 3600) / 60) + const remainingSeconds = totalSeconds % 60 + const remainingMilliseconds = totalMilliseconds % 1000 + + const formattedTime = formatTime(format, hours, minutes, remainingSeconds, remainingMilliseconds) + timeElement.textContent = formattedTime +} + +// Format time based on the provided format +function formatTime (format, hours, minutes, seconds, milliseconds) { + switch (format) { + case 'HH:mm:ss.000': + return `${formatTimeComponent(hours)}:${formatTimeComponent(minutes)}:${formatTimeComponent(seconds)}.${formatMilliseconds(milliseconds)}` + case 'HH:mm:ss': + return `${formatTimeComponent(hours)}:${formatTimeComponent(minutes)}:${formatTimeComponent(seconds)}` + case '(HH:)(mm:)ss.000': + return `${hours !== 0 ? formatTimeComponent(hours) + ':' : ''}${(hours !== 0 || minutes !== 0) ? formatTimeComponent(minutes) + ':' : ''}${formatTimeComponent(seconds)}.${formatMilliseconds(milliseconds)}` + case '(HH:)(mm:)ss': + return `${hours !== 0 ? formatTimeComponent(hours) + ':' : ''}${(hours !== 0 || minutes !== 0) ? formatTimeComponent(minutes) + ':' : ''}${formatTimeComponent(seconds)}` + case '(HH:)mm:ss.000': + return `${hours !== 0 ? formatTimeComponent(hours) + ':' : ''}${formatTimeComponent(minutes)}:${formatTimeComponent(seconds)}.${formatMilliseconds(milliseconds)}` + case '(HH:)mm:ss': + return `${hours !== 0 ? formatTimeComponent(hours) + ':' : ''}${formatTimeComponent(minutes)}:${formatTimeComponent(seconds)}` + case 'MM:ss.000': + return `${formatTimeComponent(minutes + hours * 60)}:${formatTimeComponent(seconds)}.${formatMilliseconds(milliseconds)}` + case 'MM:ss': + return `${formatTimeComponent(minutes + hours * 60)}:${formatTimeComponent(seconds)}` + case 'SS.000': + return `${formatTimeComponent(seconds + minutes * 60 + hours * 3600)}.${formatMilliseconds(milliseconds)}` + case 'SS': + return `${formatTimeComponent(seconds + minutes * 60 + hours * 3600)}` + default: + return '' // Return an empty string if the format does not match + } +} + +// Format time component with leading zero if less than 10 +function formatTimeComponent (component) { + return component < 10 ? `0${component}` : component +} + +// Format milliseconds to 3 digits +function formatMilliseconds (milliseconds) { + let result + + if (milliseconds < 10) { + result = `00${milliseconds}` + } else if (milliseconds < 100) { + result = `0${milliseconds}` + } else { + result = milliseconds + } + + return result +} diff --git a/core/template/extensible/viewCdown/index.html b/core/template/extensible/viewCdown/index.html new file mode 100644 index 0000000..240ceab --- /dev/null +++ b/core/template/extensible/viewCdown/index.html @@ -0,0 +1,27 @@ + + + + + + + + + + + + +
+
+ +
+
+ + + diff --git a/core/template/extensible/viewCdown/styles.css b/core/template/extensible/viewCdown/styles.css new file mode 100644 index 0000000..1d44a0d --- /dev/null +++ b/core/template/extensible/viewCdown/styles.css @@ -0,0 +1,10 @@ +/* Estilos para crono/view */ + +img.emoji { + height: 1em; + width: 1em; + margin: 0 0.05em 0 0.1em; + vertical-align: -0.1em; +} + +/* Puedes agregar más estilos según tus necesidades */ diff --git a/core/template/extensible/viewCrono/client.js b/core/template/extensible/viewCrono/client.js new file mode 100644 index 0000000..240d2e9 --- /dev/null +++ b/core/template/extensible/viewCrono/client.js @@ -0,0 +1,147 @@ +const timeElement = document.getElementById('time') +const containers = document.querySelectorAll('.container') +const titlePage = document.getElementById('titlePage') +// const test = document.getElementById('test') +const socket = new WebSocket('ws://localhost:3000') + +const classElement = window.location.href.split('/')[3] +titlePage.textContent = classElement + ' - View - Crono' + +let intervalId = null +let formatTimeVar + +socket.addEventListener('open', (event) => { + console.log('WebSocket Connection Opened') + + // Request the WebSocket server to send variable data + socket.send(JSON.stringify({ action: 'getVariables', classElement })) +}) + +socket.addEventListener('message', (event) => { + const message = JSON.parse(event.data) + + if (message.action === 'reload') { + window.location.reload() + } + + if (message.action === 'sendVariables' && message.classElement === classElement && message.config) { + document.documentElement.lang = Object.keys(message.formats.langs).includes(message.config.lang) + ? message.config.lang + : 'en' + } + + if (message[classElement].millisecondsTotal !== undefined) { + if (formatTimeVar !== message[classElement].formatTimeCrono && intervalId) { + clearInterval(intervalId) + intervalId = null + } + + formatTimeVar = message[classElement].formatTimeCrono + updateTimeDisplay(formatTimeVar, message[classElement].millisecondsTotal) + + // Update the timer based on the received message + timeElement.style.fontFamily = `"${message[classElement].font}"` + timeElement.style.fontSize = message[classElement].size + 'px' + timeElement.style.color = message[classElement].colorText + + if (message[classElement].bold) { + timeElement.style.fontWeight = 'bold' + } else { + timeElement.style.fontWeight = 'normal' + } + if (message[classElement].italic) { + timeElement.style.fontStyle = 'italic' + } else { + timeElement.style.fontStyle = 'normal' + } + if (message[classElement].underline) { + timeElement.style.textDecoration = 'underline' + } else { + timeElement.style.textDecoration = 'none' + } + containers.forEach((container) => { + container.style.textAlign = message[classElement].align + }) + + // If the timer is in "started" state, start the interval + if (message[classElement].status === 'started') { + if (!intervalId) { + intervalId = setInterval(() => { + updateTimeDisplay(formatTimeVar, Date.now() - message[classElement].startTime + message[classElement].millisecondsTotal) + }, 1) // Update every 1 millisecond + } + } else { + // If the timer is not in "started" state, stop the interval + clearInterval(intervalId) + intervalId = null + if (message[classElement].status === 'ended') { + updateTimeDisplay(formatTimeVar, message[classElement].millisecondsTotal) + } + } + } +}) + +socket.addEventListener('close', (event) => { + console.log('WebSocket Connection Closed') +}) + +function updateTimeDisplay (format, millisecondsTotal) { + if (isNaN(millisecondsTotal)) { + millisecondsTotal = 0 + } + + const totalmillisecondsTotal = Math.floor(millisecondsTotal) + const totalSeconds = Math.floor(totalmillisecondsTotal / 1000) + const hours = Math.floor(totalSeconds / 3600) + const minutes = Math.floor((totalSeconds % 3600) / 60) + const remainingSeconds = totalSeconds % 60 + const remainingmillisecondsTotal = totalmillisecondsTotal % 1000 + + const formattedTime = formatTime(format, hours, minutes, remainingSeconds, remainingmillisecondsTotal) + timeElement.textContent = formattedTime +} + +function formatTime (format, hours, minutes, seconds, millisecondsTotal) { + switch (format) { + case 'HH:mm:ss.000': + return `${formatTimeComponent(hours)}:${formatTimeComponent(minutes)}:${formatTimeComponent(seconds)}.${formatmillisecondsTotal(millisecondsTotal)}` + case 'HH:mm:ss': + return `${formatTimeComponent(hours)}:${formatTimeComponent(minutes)}:${formatTimeComponent(seconds)}` + case '(HH:)(mm:)ss.000': + return `${hours !== 0 ? formatTimeComponent(hours) + ':' : ''}${(hours !== 0 || minutes !== 0) ? formatTimeComponent(minutes) + ':' : ''}${formatTimeComponent(seconds)}.${formatmillisecondsTotal(millisecondsTotal)}` + case '(HH:)(mm:)ss': + return `${hours !== 0 ? formatTimeComponent(hours) + ':' : ''}${(hours !== 0 || minutes !== 0) ? formatTimeComponent(minutes) + ':' : ''}${formatTimeComponent(seconds)}` + case '(HH:)mm:ss.000': + return `${hours !== 0 ? formatTimeComponent(hours) + ':' : ''}${formatTimeComponent(minutes)}:${formatTimeComponent(seconds)}.${formatmillisecondsTotal(millisecondsTotal)}` + case '(HH:)mm:ss': + return `${hours !== 0 ? formatTimeComponent(hours) + ':' : ''}${formatTimeComponent(minutes)}:${formatTimeComponent(seconds)}` + case 'MM:ss.000': + return `${formatTimeComponent(minutes + hours * 60)}:${formatTimeComponent(seconds)}.${formatmillisecondsTotal(millisecondsTotal)}` + case 'MM:ss': + return `${formatTimeComponent(minutes + hours * 60)}:${formatTimeComponent(seconds)}` + case 'SS.000': + return `${formatTimeComponent(seconds + minutes * 60 + hours * 3600)}.${formatmillisecondsTotal(millisecondsTotal)}` + case 'SS': + return `${formatTimeComponent(seconds + minutes * 60 + hours * 3600)}` + default: + return '' // Return an empty string if the format doesn't match + } +} + +function formatTimeComponent (component) { + return component < 10 ? `0${component}` : component +} + +function formatmillisecondsTotal (millisecondsTotal) { + let result + + if (millisecondsTotal < 10) { + result = `00${millisecondsTotal}` + } else if (millisecondsTotal < 100) { + result = `0${millisecondsTotal}` + } else { + result = millisecondsTotal + } + + return result +} diff --git a/core/template/extensible/viewCrono/index.html b/core/template/extensible/viewCrono/index.html new file mode 100644 index 0000000..6009ce0 --- /dev/null +++ b/core/template/extensible/viewCrono/index.html @@ -0,0 +1,24 @@ + + + + + + + + + + + + +
+
+ +
+
+ + + diff --git a/core/template/extensible/viewCrono/styles.css b/core/template/extensible/viewCrono/styles.css new file mode 100644 index 0000000..05dd7b4 --- /dev/null +++ b/core/template/extensible/viewCrono/styles.css @@ -0,0 +1,3 @@ +/* Estilos para crono/view */ + +/* Puedes agregar más estilos según tus necesidades */ diff --git a/core/template/time/control/control.js b/core/template/time/control/control.js index 4c8f059..31b4d47 100644 --- a/core/template/time/control/control.js +++ b/core/template/time/control/control.js @@ -141,11 +141,11 @@ timezoneSelector.addEventListener('change', () => { }) formatSelector.addEventListener('change', () => { - socket.send(JSON.stringify({ action: 'changeFormatTime', format: formatSelector.value, classElement })) + socket.send(JSON.stringify({ action: 'changeFormat', format: formatSelector.value, classElement })) }) fontSelect.addEventListener('change', () => { - socket.send(JSON.stringify({ action: 'changeFontTime', font: fontSelect.value, classElement })) + socket.send(JSON.stringify({ action: 'changeFont', font: fontSelect.value, classElement })) }) fontSize.addEventListener('change', () => { @@ -163,37 +163,37 @@ fontSize.addEventListener('change', () => { } // Send the new size to the server - socket.send(JSON.stringify({ action: 'changeSizeTime', size: newSize, classElement })) + socket.send(JSON.stringify({ action: 'changeSize', size: newSize, classElement })) }) boldButton.addEventListener('click', () => { - socket.send(JSON.stringify({ action: 'textFormatTime', format: 'bold', classElement })) + socket.send(JSON.stringify({ action: 'textFormat', format: 'bold', classElement })) }) italicButton.addEventListener('click', () => { - socket.send(JSON.stringify({ action: 'textFormatTime', format: 'italic', classElement })) + socket.send(JSON.stringify({ action: 'textFormat', format: 'italic', classElement })) }) underlineButton.addEventListener('click', () => { - socket.send(JSON.stringify({ action: 'textFormatTime', format: 'underline', classElement })) + socket.send(JSON.stringify({ action: 'textFormat', format: 'underline', classElement })) }) alignLeftButton.addEventListener('click', () => { - socket.send(JSON.stringify({ action: 'alignTime', align: 'left', classElement })) + socket.send(JSON.stringify({ action: 'align', align: 'left', classElement })) }) alignCenterButton.addEventListener('click', () => { - socket.send(JSON.stringify({ action: 'alignTime', align: 'center', classElement })) + socket.send(JSON.stringify({ action: 'align', align: 'center', classElement })) }) alignRightButton.addEventListener('click', () => { - socket.send(JSON.stringify({ action: 'alignTime', align: 'right', classElement })) + socket.send(JSON.stringify({ action: 'align', align: 'right', classElement })) }) colorPicker.addEventListener('change', () => { checkHexColor = colorPicker.value.toUpperCase() // If the hexadecimal code is valid, send the color to the server - socket.send(JSON.stringify({ action: 'changeColorTime', color: colorPicker.value.toUpperCase(), classElement })) + socket.send(JSON.stringify({ action: 'changeColor', color: colorPicker.value.toUpperCase(), classElement })) colorHex.value = checkHexColor }) @@ -206,7 +206,7 @@ colorHex.addEventListener('change', () => { if (hexRegex.test(hexColor)) { checkHexColor = hexColor.toUpperCase() // If the hexadecimal code is valid, send the color to the server - socket.send(JSON.stringify({ action: 'changeColorTime', color: checkHexColor, classElement })) + socket.send(JSON.stringify({ action: 'changeColor', color: checkHexColor, classElement })) colorPicker.value = checkHexColor colorHex.value = checkHexColor } else { diff --git a/core/topbar.css b/core/topbar.css index e938070..1dc1897 100644 --- a/core/topbar.css +++ b/core/topbar.css @@ -37,6 +37,8 @@ margin-top: 3.5px; cursor: pointer; flex-grow: 1; + margin-right: 2.5px; + margin-left: 2.5px; } .link-button:hover { diff --git a/core/translates/en.yaml b/core/translates/en.yaml index 879cb42..fdfc1d9 100644 --- a/core/translates/en.yaml +++ b/core/translates/en.yaml @@ -1,15 +1,17 @@ home: close: Close the window and stop the code wiki: Documentation - cronoTitle: CLOCKS - cdownTitle: TIMERS + cronoTitle: CHRONOMETERS + cdownTitle: COUNTDOWNS cdowntimeTitle: TIME UNTIL... - twitchextTitle: EXTENSIBLE TWITCH + extensibleTitle: STREAM EXTENSIBLE timeTitle: CURRENT TIME - notycopycrono: URL copied to clipboard + notycopy: URL copied to clipboard timer: buttons: start: Start pause: Pause reset: Reset - ph_msgend: Message to display when time expires \ No newline at end of file + phMsgEnd: Message to display when time expires + enablePauseAdd: Enabled permission to add time when time is paused + enableStopAdd: Enabled permission to add time when time has not yet started \ No newline at end of file diff --git a/core/translates/es.yaml b/core/translates/es.yaml index a759cd5..b6c2536 100644 --- a/core/translates/es.yaml +++ b/core/translates/es.yaml @@ -4,12 +4,14 @@ home: cronoTitle: CRONÓMETROS cdownTitle: TEMPORIZADORES cdowntimeTitle: TIEMPO HASTA... - twitchextTitle: EXTENSIBLE TWITCH + extensibleTitle: STREAM EXTENSIBLE timeTitle: HORA ACTUAL - notycopycrono: URL copiada al portapapeles + notycopy: URL copiada al portapapeles timer: buttons: start: Iniciar pause: Pausar reset: Reiniciar - ph_msgend: Mensaje a mostrar cuando finalice el tiempo \ No newline at end of file + phMsgEnd: Mensaje a mostrar cuando finalice el tiempo + enablePauseAdd: Habilitado el permiso para añadir tiempo cuando el tiempo está pausado + enableStopAdd: Habilitado el permiso para añadir tiempo cuando el tiempo aún no se ha iniciado diff --git a/functions.js b/functions.js index 2281d0b..ca9a408 100644 --- a/functions.js +++ b/functions.js @@ -223,7 +223,7 @@ exports.createDataYAML = (GlobalVariables, classType) => { GlobalVariables[newKey].status = 'stopped' GlobalVariables[newKey].startTime = 0 GlobalVariables[newKey].milliseconds = 60000 - GlobalVariables[newKey].textmilliseconds = 60000 + GlobalVariables[newKey].textMilliseconds = 60000 GlobalVariables[newKey].formatTime = 'MM:ss' GlobalVariables[newKey].font = 'Arial' GlobalVariables[newKey].size = 50 @@ -245,6 +245,24 @@ exports.createDataYAML = (GlobalVariables, classType) => { GlobalVariables[newKey].align = 'center' GlobalVariables[newKey].colorText = '#000000' GlobalVariables[newKey].msgEnd = '' + } else if (classType === 'extensible') { + GlobalVariables[newKey].status = 'stopped' + GlobalVariables[newKey].startTime = 0 + GlobalVariables[newKey].millisecondsTotal = 0 + GlobalVariables[newKey].milliseconds = 60000 + GlobalVariables[newKey].textMilliseconds = 60000 + GlobalVariables[newKey].formatTimeCrono = 'HH:mm:ss' + GlobalVariables[newKey].formatTimeCdown = 'HH:mm:ss' + GlobalVariables[newKey].font = 'Arial' + GlobalVariables[newKey].size = 50 + GlobalVariables[newKey].bold = false + GlobalVariables[newKey].italic = false + GlobalVariables[newKey].underline = false + GlobalVariables[newKey].align = 'center' + GlobalVariables[newKey].colorText = '#000000' + GlobalVariables[newKey].msgEnd = '' + GlobalVariables[newKey].enablePauseAdd = false + GlobalVariables[newKey].enableStopAdd = false } else if (classType === 'time') { GlobalVariables[newKey].timezone = Intl.DateTimeFormat().resolvedOptions().timeZone GlobalVariables[newKey].formatTime = 'hh:mm:ss' @@ -329,6 +347,24 @@ exports.pauseCdown = (wss, GlobalVariables, classElement) => { } } +// Pause the extensible +exports.pauseExtensible = (wss, GlobalVariables, classElement) => { + if (GlobalVariables[classElement].status === 'started') { + GlobalVariables[classElement].status = 'paused' + GlobalVariables[classElement].millisecondsTotal += Date.now() - GlobalVariables[classElement].startTime + GlobalVariables[classElement].milliseconds -= Date.now() - GlobalVariables[classElement].startTime + + // Update all WebSocket clients with countdown status + wss.clients.forEach((client) => { + if (client.readyState === WebSocket.OPEN) { + client.send(JSON.stringify(GlobalVariables)) + } + }) + + this.saveVariablesToYAML(GlobalVariables) + } +} + // Reset the stopwatch exports.resetCrono = (wss, GlobalVariables, classElement) => { GlobalVariables[classElement].status = 'stopped' @@ -348,7 +384,24 @@ exports.resetCrono = (wss, GlobalVariables, classElement) => { // Reset the countdown exports.resetCdown = (wss, GlobalVariables, classElement) => { GlobalVariables[classElement].status = 'stopped' - GlobalVariables[classElement].milliseconds = GlobalVariables[classElement].textmilliseconds + GlobalVariables[classElement].milliseconds = GlobalVariables[classElement].textMilliseconds + GlobalVariables[classElement].startTime = 0 + + // Update all WebSocket clients with countdown status + wss.clients.forEach((client) => { + if (client.readyState === WebSocket.OPEN) { + client.send(JSON.stringify(GlobalVariables)) + } + }) + + this.saveVariablesToYAML(GlobalVariables) +} + +// Reset the extensible +exports.resetExtensible = (wss, GlobalVariables, classElement) => { + GlobalVariables[classElement].status = 'stopped' + GlobalVariables[classElement].millisecondsTotal = 0 + GlobalVariables[classElement].milliseconds = GlobalVariables[classElement].textMilliseconds GlobalVariables[classElement].startTime = 0 // Update all WebSocket clients with countdown status @@ -363,8 +416,25 @@ exports.resetCdown = (wss, GlobalVariables, classElement) => { // Stop the countdown exports.stopCdown = (wss, GlobalVariables, classElement) => { - GlobalVariables[classElement].status = 'stopped' + GlobalVariables[classElement].status = 'ended' + GlobalVariables[classElement].milliseconds = 0 + + // Update all WebSocket clients with countdown status + wss.clients.forEach((client) => { + if (client.readyState === WebSocket.OPEN) { + client.send(JSON.stringify(GlobalVariables)) + } + }) + + this.saveVariablesToYAML(GlobalVariables) +} + +// Stop the countdown +exports.stopExtensible = (wss, GlobalVariables, classElement) => { + GlobalVariables[classElement].status = 'ended' GlobalVariables[classElement].milliseconds = 0 + GlobalVariables[classElement].millisecondsTotal += Date.now() - GlobalVariables[classElement].startTime + GlobalVariables[classElement].millisecondsTotal = Math.round(GlobalVariables[classElement].millisecondsTotal / 1000) * 1000 // Update all WebSocket clients with countdown status wss.clients.forEach((client) => { diff --git a/package.json b/package.json index 99a895a..81b0416 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "obs-timer-controller", - "version": "1.0.2", + "version": "1.0.3", "description": "Handling browser fonts for OBS related to timers and countdowns.", "main": "server.js", "repository": { @@ -22,7 +22,7 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "node": "node . test", - "pkg-win": "electron-packager . OBS-Timer-Controller --platform=win32 --arch=x64 --out=dist --overwrite --icon=icon.ico --app-version=1.0.2 --author=\"XtoManuel\" --description=\"Handling browser fonts for OBS related to timers and countdowns.\"" + "pkg-win": "electron-packager . OBS-Timer-Controller --platform=win32 --arch=x64 --app-version=1.0.3 --out=dist --overwrite --icon=icon.ico --author=\"XtoManuel\" --description=\"Handling browser fonts for OBS related to timers and countdowns.\"" }, "author": "XtoManuel", "license": "ISC", diff --git a/server.js b/server.js index 9e92bde..55986ef 100644 --- a/server.js +++ b/server.js @@ -25,9 +25,12 @@ const { startTimer, pauseCrono, pauseCdown, + pauseExtensible, resetCrono, resetCdown, stopCdown, + stopExtensible, + resetExtensible, sendVariableData, initConfig, saveConfig, @@ -95,7 +98,7 @@ wss.on('connection', (ws) => { client.send(JSON.stringify({ action: 'reload' })) } }) - } else if (data.action === 'startCrono' || data.action === 'startCdown') { + } else if (data.action === 'startCrono' || data.action === 'startCdown' || data.action === 'startExtensible') { // Start the timer when receiving the "start" action startTimer(wss, GlobalVariables, data.classElement) } else if (data.action === 'pauseCrono') { @@ -104,15 +107,24 @@ wss.on('connection', (ws) => { } else if (data.action === 'pauseCdown') { // Pause the countdown when receiving the "pause" action pauseCdown(wss, GlobalVariables, data.classElement) + } else if (data.action === 'pauseExtensible') { + // Pause the countdown when receiving the "pause" action + pauseExtensible(wss, GlobalVariables, data.classElement) } else if (data.action === 'resetCrono') { // Reset the timer when receiving the "reset" action resetCrono(wss, GlobalVariables, data.classElement) } else if (data.action === 'resetCdown') { // Reset the countdown when receiving the "reset" action resetCdown(wss, GlobalVariables, data.classElement) + } else if (data.action === 'resetExtensible') { + // Reset the countdown when receiving the "reset" action + resetExtensible(wss, GlobalVariables, data.classElement) } else if (data.action === 'stopCdown') { // Stop the countdown when receiving the "stop" action stopCdown(wss, GlobalVariables, data.classElement) + } else if (data.action === 'stopExtensible') { + // Stop the countdown when receiving the "stop" action + stopExtensible(wss, GlobalVariables, data.classElement) } else if (data.action === 'changeTimeCdown' && data.time) { // Change the time format when receiving the "changeFormat" action GlobalVariables[data.classElement].textMilliseconds = data.time @@ -123,7 +135,7 @@ wss.on('connection', (ws) => { } }) saveVariablesToYAML(GlobalVariables) - if (GlobalVariables[data.classElement].status === 'stopped') { + if (GlobalVariables[data.classElement].status === 'ended') { resetCdown(wss, GlobalVariables, data.classElement) } } else if (data.action === 'changeTimeCdownTime' && data.time) { @@ -136,6 +148,19 @@ wss.on('connection', (ws) => { } }) saveVariablesToYAML(GlobalVariables) + } else if (data.action === 'changeTimeExtensible' && data.time) { + // Change the time format when receiving the "changeFormat" action + GlobalVariables[data.classElement].textMilliseconds = data.time + // Transmit the updated format to all WebSocket clients + wss.clients.forEach((client) => { + if (client.readyState === WebSocket.OPEN) { + client.send(JSON.stringify(GlobalVariables)) + } + }) + saveVariablesToYAML(GlobalVariables) + if (GlobalVariables[data.classElement].status === 'ended') { + resetExtensible(wss, GlobalVariables, data.classElement) + } } else if ( data.action === 'changeTimezoneCdownTime' || data.action === 'changeTimezoneTime' @@ -149,7 +174,9 @@ wss.on('connection', (ws) => { client.send(JSON.stringify({ action: 'reload' })) } }) - } else if (data.action === 'editMsgCdown' || data.action === 'editMsgCdownTime') { + } else if (data.action === 'editMsgCdown' || + data.action === 'editMsgCdownTime' || + data.action === 'editMsgExtensible') { GlobalVariables[data.classElement].msgEnd = data.msg // Transmit the updated format to all WebSocket clients wss.clients.forEach((client) => { @@ -158,15 +185,38 @@ wss.on('connection', (ws) => { } }) saveVariablesToYAML(GlobalVariables) - } else if ( - (data.action === 'changeFormatCrono' || - data.action === 'changeFormatCdown' || - data.action === 'changeFormatCdownTime' || - data.action === 'changeFormatTime') && - data.format - ) { + } else if (data.action === 'checkboxStopAdd') { + // Change the text format when receiving the "changeFormat" + GlobalVariables[data.classElement].enableStopAdd = data.value + // Transmit the updated format to all WebSocket clients + wss.clients.forEach((client) => { + if (client.readyState === WebSocket.OPEN) { + client.send(JSON.stringify(GlobalVariables)) + } + }) + saveVariablesToYAML(GlobalVariables) + } else if (data.action === 'checkboxPauseAdd') { + // Change the text format when receiving the "changeFormat" + GlobalVariables[data.classElement].enablePauseAdd = data.value + // Transmit the updated format to all WebSocket clients + wss.clients.forEach((client) => { + if (client.readyState === WebSocket.OPEN) { + client.send(JSON.stringify(GlobalVariables)) + } + }) + saveVariablesToYAML(GlobalVariables) + } else if ((data.action === 'changeFormat' || + data.action === 'changeFormatExtCrono' || + data.action === 'changeFormatExtCdown' + ) && data.format) { const classElement = data.classElement - GlobalVariables[classElement].formatTime = data.format + if (data.action === 'changeFormatExtCrono') { + GlobalVariables[classElement].formatTimeCrono = data.format + } else if (data.action === 'changeFormatExtCdown') { + GlobalVariables[classElement].formatTimeCdown = data.format + } else { + GlobalVariables[classElement].formatTime = data.format + } wss.clients.forEach((client) => { if (client.readyState === WebSocket.OPEN) { @@ -177,19 +227,19 @@ wss.on('connection', (ws) => { saveVariablesToYAML(GlobalVariables) } else if ( data.action === 'editTimeCrono' || - data.action === 'editTimeCdown' + (data.action === 'editTimeCdown' && GlobalVariables[data.classElement].status === 'ended') ) { editTimeTimer(wss, GlobalVariables, data.time, data.classElement) } else if (data.action === 'editTimeCdownTime') { editTimeCdowntime(wss, GlobalVariables, data.time, data.classElement) - } else if ( - (data.action === 'changeFontCrono' || - data.action === 'changeFontCdown' || - data.action === 'changeFontCdownTime' || - data.action === 'changeFontTime') && - data.font + } else if (data.action === 'editTimeExtensible' && ( + GlobalVariables[data.classElement].status === 'started' || + (GlobalVariables[data.classElement].status === 'paused' && GlobalVariables[data.classElement].enablePauseAdd) || + (GlobalVariables[data.classElement].status === 'stopped' && GlobalVariables[data.classElement].enableStopAdd)) ) { - // Change the font format when receiving the "changeFormatTimer" + editTimeTimer(wss, GlobalVariables, data.time, data.classElement) + } else if (data.action === 'changeFont' && data.font) { + // Change the font format when receiving the "changeFormatr" GlobalVariables[data.classElement].font = data.font // Transmit the updated format to all WebSocket clients @@ -199,13 +249,7 @@ wss.on('connection', (ws) => { } }) saveVariablesToYAML(GlobalVariables) - } else if ( - (data.action === 'changeSizeCrono' || - data.action === 'changeSizeCdown' || - data.action === 'changeSizeCdownTime' || - data.action === 'changeSizeTime') && - data.size - ) { + } else if (data.action === 'changeSize' && data.size) { // Change the font size when receiving the "changeFormat" GlobalVariables[data.classElement].size = data.size @@ -216,12 +260,7 @@ wss.on('connection', (ws) => { } }) saveVariablesToYAML(GlobalVariables) - } else if ( - data.action === 'textFormatCrono' || - data.action === 'textFormatCdown' || - data.action === 'textFormatCdownTime' || - data.action === 'textFormatTime' - ) { + } else if (data.action === 'textFormat') { // Change the text format when receiving the "changeFormat" switch (data.format) { case 'bold': @@ -241,12 +280,7 @@ wss.on('connection', (ws) => { } }) saveVariablesToYAML(GlobalVariables) - } else if ( - data.action === 'alignCrono' || - data.action === 'alignCdown' || - data.action === 'alignCdownTime' || - data.action === 'alignTime' - ) { + } else if (data.action === 'align') { // Change the text alignment when receiving the "changeFormat" GlobalVariables[data.classElement].align = data.align @@ -257,12 +291,7 @@ wss.on('connection', (ws) => { } }) saveVariablesToYAML(GlobalVariables) - } else if ( - data.action === 'changeColorCrono' || - data.action === 'changeColorCdown' || - data.action === 'changeColorCdownTime' || - data.action === 'changeColorTime' - ) { + } else if (data.action === 'changeColor') { // Change the text color when receiving the "changeFormat" GlobalVariables[data.classElement].colorText = data.color