//Start up code gId('curlUrl').value = location.host; let devMode = false; const urlParams = new URLSearchParams(window.location.search); if(urlParams.has('dev')){ devMode = true; } if(devMode){ console.log('Developer mode active. Experimental and unstable functions active.') } else{ console.log('Developer mode inactive. Append "?dev" to the URL.') } if(devMode){ gId("fileJSONledbutton").style.display = 'buttonclass' gId("gap2").style.display = 'gap' } else { gId("fileJSONledbutton").style.display = 'none' gId("gap2").style.display = 'none' } let httpArray = []; let fileJSON = ''; //On submit button pressed ======================= gId("convertbutton").addEventListener("click", () => { let base64Image = gId('preview').src; if (isValidBase64Gif(base64Image)) { gId('image').src = base64Image; getPixelRGBValues(base64Image); gId('image-container').style.display = "block"; gId("button-container").style.display = ""; } else { let infoDiv = gId('image-info'); let imageInfo = '

WARNING! File does not appear to be a valid image

'; infoDiv.innerHTML = imageInfo; infoDiv.style.display = "block"; gId('image-container').style.display = "none"; gId('JSONled').value = ''; if (devMode) console.log("The string '" + base64Image + "' is not a valid base64 image."); } }); // Code for copying the generated string to clipboard gId("copyJSONledbutton").addEventListener('click', async () => { let JSONled = gId('JSONled'); JSONled.select(); try { await navigator.clipboard.writeText(JSONled.value); } catch (err) { try { await d.execCommand("copy"); } catch (err) { console.error('Failed to copy text: ', err); } } }); gId("sendJSONledbutton").addEventListener('click', async () => { if (window.location.protocol === "https:") { alert('Will only be available when served over http (or WLED is run over https)'); } else { postPixels(); } }); gId("fileJSONledbutton").addEventListener('click', async () => { if (window.location.protocol === "https:") { alert('Will only be available when served over http (or WLED is run over https)'); } else { let JSONFileName = 'TheName.json'; let urlString = 'http://'+gId('curlUrl').value+'/upload'; sendAsFile(fileJSON, JSONFileName, urlString); } }); async function postPixels() { for (let i of httpArray) { try { if (devMode) console.log(i); if (devMode) console.log(i.length); const response = await fetch('http://'+gId('curlUrl').value+'/json/state', { method: 'POST', headers: { 'Content-Type': 'application/json' //'Content-Type': 'text/html; charset=UTF-8' }, body: i }); const data = await response.json(); if (devMode) console.log(data); } catch (error) { console.error(error); } } } //File uploader code const dropZone = gId('drop-zone'); const filePicker = gId('file-picker'); const preview = gId('preview'); // Listen for dragenter, dragover, and drop events dropZone.addEventListener('dragenter', dragEnter); dropZone.addEventListener('dragover', dragOver); dropZone.addEventListener('drop', dropped); dropZone.addEventListener('click', zoneClicked); // Listen for change event on file picker filePicker.addEventListener('change', filePicked); // Handle zone click function zoneClicked(e) { e.preventDefault(); //this.classList.add('drag-over'); //alert('Hej'); filePicker.click(); } // Handle dragenter function dragEnter(e) { e.preventDefault(); this.classList.add('drag-over'); } // Handle dragover function dragOver(e) { e.preventDefault(); } // Handle drop function dropped(e) { e.preventDefault(); this.classList.remove('drag-over'); // Get the dropped file const file = e.dataTransfer.files[0]; updatePreview(file); } // Handle file picked function filePicked(e) { // Get the picked file const file = e.target.files[0]; updatePreview(file); } // Update the preview image function updatePreview(file) { // Use FileReader to read the file const reader = new FileReader(); reader.onload = () => { // Update the preview image preview.src = reader.result; gId("submitConvertDiv").style.display = ""; gId("preview").style.display = ""; }; reader.readAsDataURL(file); } function isValidBase64Gif(string) { // Use a regular expression to check that the string is a valid base64 string /* const base64gifPattern = /^data:image\/gif;base64,([A-Za-z0-9+/:]{4})*([A-Za-z0-9+/:]{3}=|[A-Za-z0-9+/:]{2}==)?$/; const base64pngPattern = /^data:image\/png;base64,([A-Za-z0-9+/:]{4})*([A-Za-z0-9+/:]{3}=|[A-Za-z0-9+/:]{2}==)?$/; const base64jpgPattern = /^data:image\/jpg;base64,([A-Za-z0-9+/:]{4})*([A-Za-z0-9+/:]{3}=|[A-Za-z0-9+/:]{2}==)?$/; const base64webpPattern = /^data:image\/webp;base64,([A-Za-z0-9+/:]{4})*([A-Za-z0-9+/:]{3}=|[A-Za-z0-9+/:]{2}==)?$/; */ //REMOVED, Any image appear to work as long as it can be drawn to the canvas. Leaving code in for future use, possibly if (1==1 || base64gifPattern.test(string) || base64pngPattern.test(string) || base64jpgPattern.test(string) || base64webpPattern.test(string)) { return true; } else { //Not OK return false; } } gId("brightnessNumber").oninput = () => { let bn = gId("brightnessNumber"); gId("brightnessValue").textContent = bn.value; let perc = parseInt(bn.value)*100/255; var val = `linear-gradient(90deg, #bbb ${perc}%, #333 ${perc}%)`; bn.style.backgroundImage = val; } gId("colorLimitNumber").oninput = () => { let cln = gId("colorLimitNumber"); gId("colorLimitValue").textContent = cln.value; let perc = parseInt(cln.value)*100/512; var val = `linear-gradient(90deg, #bbb ${perc}%, #333 ${perc}%)`; cln.style.backgroundImage = val; } var hideableRows = d.querySelectorAll(".ha-hide"); for (var i = 0; i < hideableRows.length; i++) { hideableRows[i].classList.add("hide"); } gId("formatSelector").addEventListener("change", () => { for (var i = 0; i < hideableRows.length; i++) { hideableRows[i].classList.toggle("hide", gId("formatSelector").value !== "ha"); } }); function switchScale() { //let scalePath = gId("scaleDiv").children[1].children[0] let scaleTogglePath = gId("scaleDiv").children[0].children[0] let color = scaleTogglePath.getAttribute("fill"); let d = ''; if (color === accentColor) { color = accentTextColor; d = scaleToggleOffd; gId("sizeDiv").style.display = "none"; // Set values to actual XY of image, if possible } else { color = accentColor; d = scaleToggleOnd; gId("sizeDiv").style.display = ""; } //scalePath.setAttribute("fill", color); scaleTogglePath.setAttribute("fill", color); scaleTogglePath.setAttribute("d", d); } function sendAsFile(jsonStringInput, fileName, urlString) { //var jsonString = JSON.stringify({name: "value"}); var file = new Blob([jsonStringInput], {type: 'application/json'}); if (devMode) { console.log(jsonStringInput); console.log(fileName); console.log(urlString); } var formData = new FormData(); formData.append('file', file, fileName); var xhr = new XMLHttpRequest(); xhr.open('POST', urlString, true); xhr.onload = () => { if (xhr.status === 200) { if (devMode) console.log('File uploaded successfully!'); } else { if (devMode) console.log('File upload failed!'); } }; xhr.send(formData); } function generateSegmentOptions(array) { //This function is prepared for a name property on each segment for easier selection //Currently the name is generated generically based on index var select = gId("targetSegment"); select.innerHTML = ""; for (var i = 0; i < array.length; i++) { var option = cE("option"); option.value = array[i].value; option.text = array[i].text; select.appendChild(option); if(i === 0) { option.selected = true; } } } // Get segments from device async function getSegments() { try { var arr = []; const response = await fetch('http://'+gId('curlUrl').value+'/json/state'); const json = await response.json(); console.log(json); let ids = json.seg.map(segment => segment.id); console.log(ids); for (var i = 0; i < ids.length; i++) { arr.push({ value: ids[i], text: "Segment index " + ids[i] }); generateSegmentOptions(arr); gId('targetSegment').style.display = "flex"; gId('segID').style.display = "none"; var svg = gId("getSegmentsSVGpath"); svg.setAttribute("fill", greenColor); setTimeout(function(){ svg.setAttribute("fill", accentTextColor); }, 1000); } } catch (error) { console.error(error); var svgr = gId("getSegmentsSVGpath"); svgr.setAttribute("fill", redColor); setTimeout(function(){ svgr.setAttribute("fill", accentTextColor); }, 1000); gId('targetSegment').style.display = "none"; gId('segID').style.display = "flex"; } } //Initial population of segment selection function generateSegmentArray(noOfSegments) { var arr = []; for (var i = 0; i < noOfSegments; i++) { arr.push({ value: i, text: "Segment index " + i }); } return arr; } var segmentData = generateSegmentArray(10); generateSegmentOptions(segmentData); gId("getSegmentsDiv").innerHTML = '' gId("fileJSONledbutton").innerHTML = '  File to device' gId("convertbutton").innerHTML = '   Convert to WLED JSON '; gId("copyJSONledbutton").innerHTML = '   Copy to clipboard'; gId("sendJSONledbutton").innerHTML = '   Send to device';