How to correctly pass xml to draw.io / embed.diagrams.net?

I tried to create some example html file that demonstrates how to send some xml content to embed.diagrams.net (see below) and get the error

Not a diagram file (error on line 1 at column 1: Start tag expected,
‘<‘ not found)

enter image description here

=> How to fix the code to correctly pass the xml content to embed.diagrams.net?

I already tried to remove line breaks and other whitespaces but did not get it working.

I also tried to encode the xml as uri and send it using the “#U” or “#R” argument to app.diagrams.net. But that did not work inside an iframe.

(My actual use case is to show some draw.io content in JupyterLab 4 using IPython.display and IPython.HTML functions. Before doing so, I need a working JavaScript example.)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Diagrams.net Embed Demo</title>
</head>
<body>
<iframe id="embed-diagram" src="https://embed.diagrams.net/" width="100%" height="600px"></iframe>

<script>
    // Example draw.io XML content
    var xml = `<mxfile host="app.diagrams.net">
            <diagram name="Page-1">
                <mxGraphModel dx="1000" dy="1000" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
                    <root>
                        <mxCell id="0"/>
                        <mxCell id="1" parent="0"/>
                        <mxCell id="2" value="hello world" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
                            <mxGeometry x="160" y="160" width="80" height="30" as="geometry"/>
                        </mxCell>
                    </root>
                </mxGraphModel>
            </diagram>
        </mxfile>
    `;          

    const iframe = document.getElementById('embed-diagram');

    window.addEventListener('message', function(event) {
        if (event.data === 'ready') {
            console.log('Iframe ready to receive data');

            var message = "{action: 'load', xml: '"+ xml + "'}";

            console.log(message);

            iframe.contentWindow.postMessage(message, '*');
        }
    });

    iframe.onload = function() {
        console.log('Iframe loaded');
        iframe.contentWindow.postMessage(JSON.stringify({
            action: 'init'
        }), '*');
    };
</script>
</body>
</html>

If I store the xml content as *.drawio file and open it in http://app.diagrams.net, it is displayed as expected.

enter image description here

<mxfile host="app.diagrams.net">
    <diagram name="Page-1">
        <mxGraphModel dx="1000" dy="1000" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
            <root>
                <mxCell id="0"/>
                <mxCell id="1" parent="0"/>
                <mxCell id="2" value="hello world" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
                    <mxGeometry x="160" y="160" width="80" height="30" as="geometry"/>
                </mxCell>
            </root>
        </mxGraphModel>
    </diagram>
</mxfile>

JS Conflict Between Custom Widget and Form Calendar Element

I made a widget to add a custom question to the source code from a form created by a drag and drop form builder (jotform) and it works inside a simple form.

However, when I add a jotform calendar element, the calendar doesnt work and the “Next: button is disabled so the form wont proceed to the next page (where I would like to keep my widget).

All of the code can be viewed in an online code editor with the links below.

Form 1 works- https://jsfiddle.net/FiddlerMMM/kne5071s/
Form 2 doesnt work-https://jsfiddle.net/FiddlerMMM/kne5071s/1/

The issue seems related to the inclusion of this script in the calendar form: <script src="https://cdn01.jotfor.ms/js/vendor/maskedinput_5.0.9.min.js?v=3.3.58718" type="text/javascript"></script> as compared to the form that works.

The calendar also introduces the following JavaScript logic:

JotForm.calendarMonths = ["January","February","March","April","May","June","July","August","September","October","November","December"];
if (!JotForm.calenderViewMonths) JotForm.calenderViewMonths = {}; JotForm.calenderViewMonths[6] = ["January","February","March","April","May","June","July","August","September","October","November","December"];
if (!JotForm.calenderViewDays) JotForm.calenderViewDays = {}; JotForm.calenderViewDays[6] = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"];
JotForm.calendarDays = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"];
JotForm.calendarOther = {"today":"Today"};
var languageOptions = document.querySelectorAll('#langList li');
for(var langIndex = 0; langIndex < languageOptions.length; langIndex++) {
languageOptions[langIndex].on('click', function(e) { setTimeout(function(){ JotForm.setCalendar("6", false, {"days":{"monday":true,"tuesday":true,"wednesday":true,"thursday":true,"friday":true,"saturday":true,"sunday":true},"future":true,"past":true,"custom":false,"ranges":false,"start":"","end":"","countSelectedDaysOnly":false}); }, 0); });
}
JotForm.onTranslationsFetch(function() { JotForm.setCalendar("6", false, {"days":{"monday":true,"tuesday":true,"wednesday":true,"thursday":true,"friday":true,"saturday":true,"sunday":true},"future":true,"past":true,"custom":false,"ranges":false,"start":"","end":"","countSelectedDaysOnly":false}); });

I tried modifying widget code unsuccessfully. I think use of an iframe might help but I am stuck on this. How can I resolve this error or work around it? If there is a way to modify my widget’s code that would be ideal.

Selenium Test with java problem org.openqa.selenium.TimeoutException: Expected condition failed

I have a problem with selenium test using java, I want to upload a profile photo but I found errors. Everything works well at first, the photo is downloaded but it does not appear on the screen and the validation button is not clickable knowing that all the paths are 100% correct. I tried several solutions like forcing the click, checking that the button is no longer deactivated,I increased the implicit time but still it doesn’t work. This is the response I receive when I run my code:
File sent : C:UsersKATANADesktop
Image loaded correctly: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQYV2NgAAIAAAUAAarVyFEAAAAASUVORK5CYII=

org.openqa.selenium.TimeoutException: Expected condition failed: waiting for wattzhub.account.UpdatePage$$Lambda/0x000001b40122a6f8@5a62b2a4 (tried for 10 second(s) with 500 milliseconds interval)

I hope you can help me resolve this problem and thank you very much in advance.

    public void changeProfilePicture(String imagePath) {
        WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));

        By modifyButton = By.xpath("//button[@class='p-element p-button-outlined p-button-secondary ml-auto mr-auto mt-3 mb-3 p-button p-component']");
        WebElement modifyButtonElement = wait.until(ExpectedConditions.elementToBeClickable(modifyButton));
        modifyButtonElement.click();

        By pictureDownload = By.xpath("//div[@class='modal-content']//span[@class='input-browse']");
        WebElement pictureDownloadElement = wait.until(ExpectedConditions.visibilityOfElementLocated(pictureDownload));
        pictureDownloadElement.click();

        By modalContent = By.xpath("//div[@class='modal-content']");
        WebElement modalElement = wait.until(ExpectedConditions.visibilityOfElementLocated(modalContent));
        delay(1000);

        By fileInput = By.id("file-upload");
        WebElement fileInputElement = wait.until(ExpectedConditions.presenceOfElementLocated(fileInput));
        JavascriptExecutor js = (JavascriptExecutor) driver;
        js.executeScript("arguments[0].style.display='block'; arguments[0].style.opacity='1';", fileInputElement);

        fileInputElement.sendKeys(imagePath);
        System.out.println("File sent : " + imagePath);

        By imageElement = By.xpath("//img[contains(@class, 'source-image')]");
        wait.until(ExpectedConditions.presenceOfElementLocated(imageElement));
        WebElement image = driver.findElement(imageElement);


        js.executeScript("arguments[0].style.visibility='visible';", image);


        wait.until(driver -> {
            String visibility = image.getCssValue("visibility");
            return visibility.equals("visible");
        });

        // Validez l'attribut src
        String srcValue = image.getAttribute("src");
        if (srcValue.startsWith("data:image/png;base64,")) {
            System.out.println("Image loaded correctly: " + srcValue);
        } else {
            System.out.println("Image not loaded or invalid src.");
        }
}

How do I pass command line parameters to a python prgram called from XMLHTTPRequest

I’m trying (unsuccessfully) to pass command line paramters to a python program called by javascript XMLHTTPRequest. In my python program I have used each of sys.argv, getopt and argparse, all of which work when run from the command line but not when called from the Javascript script. In my Javascript program I have tried:

xhr.open('GET', 'https://solarpredictor.co.uk/test.py?solcast&full&graph', true);
xhr.open('GET', 'https://solarpredictor.co.uk/test.py?s=solcast&f=full&g=graph', true);

and

xhr.open('GET', 'https://solarpredictor.co.uk/test.py?solcast', true);

none of which work. In every case the parameters are not being found by the py program.

How can I get the python program to retrieve parameters when called within XMLHTTPRequest?

Is it possible that stream mp3 as blob?

I wrote a simple code that PHP sends mp3 data as blob and in client side (JS) html5 audio object plays it but the problem is : first whole of file should be fetched and when base64 decoding finished, audio can be played.

function blob(uri){

    $.ajax({

        type: "POST",
        url:uri,


        success:function(result){

            let binary = convertDataURIToBinary(result);
            let blob = new Blob([binary], {type : 'audio/mp3'});
            let uri= URL.createObjectURL(blob);

            audio.src = uri;
            audio.load();

            audio.play().then(

            r => {
                
                //do something
            }

            ).catch((error) => {

                checkInternet();
            });
    

        }});

}

Blockquote

So my question : is it possible that I send data as blob and before sending whole file, audio plays? or I have to implement a client js player myself to do that?

Datagrid Mui wait for processRowUpdate to end before updating rowModeModel

I’m using datagrid-pro from MUI to create a table component. I want the user to be able to switch a row from view mode to edit mode by double-clicking on a row or by using an edit action-button on each row.

enter image description here

My problem is with the edit action-button and when there already is a row on edit mode. Basically I want to close and resolve the row in edit mode before opening a new one, however if the data are not valid I want to keep the current row in edit mode, display a tooltip with the errors, and the row that the user intended to open with the action-button must remain in view mode.

I managed to achieve this behaviour for the double-click. But I don’t really know how to do it in the function triggered by my edit action-button, my first attempt was to manually update the row mode model, but I need to know if the previous row was resolved with an error or not, which is determined in the processRowUpdate function.

So I guess I need to fire an event (I don’t know which one, a resolve event or something like that) which trigger processRowUpdate then await for the processRowUpdate to set my error to true or false, then use this error to change the row mode model. But I don’t find a way to do that.

I know my problem is a bit vague, but I just need a few clues to point me in the right direction.

Thank you

How to create horizontal scrolling with a locked y axis for Chart.js?

I have a floating chart that I am using as a scheduler and I am trying to make it so the y axis is sticky when scrolling through the chart. I found this site and a video that I was trying to follow it but I can’t get it to work, http://www.java2s.com/example/javascript/chart.js/create-a-horizontal-scrolling-chartjs-line-chart-with-a-locked-y-axis.html and https://youtu.be/IV6Qy5EQZlA?si=FjXcGK6W-4PjN0LP. Is there an easier way to make a sticky y axis than what I have found online or what am I missing that would make this code work? I was hoping there was an option to enable y axis sticky. I can see I have my Chart Axis up through the dev tools, but I can’t seem to get it populated with the labels.

HTML:

<div class="chartWrapper">
    <div class="chartAreaWrapper">
        <canvas id="myChart" height="300" width="3000%"></canvas>
    </div>
    <canvas id="myChartAxis" height="300" width="100px"></canvas>
</div>

CSS:

.chartWrapper {
  position: relative;
}
.chartWrapper > canvas {
  position: absolute;
  left: 0;
  top: 0;
  pointer-events:none;
}
.chartAreaWrapper {
  width: 600px;
  overflow-x: scroll;
}

JavaScript:

var ctx = document.getElementById("myChart").getContext("2d");
    const ctx2 = document.getElementById('myChartAxis');
    
    const chartData = {
        labels: ["Person 1", "Person 2"],
      datasets: [{
            data: [
                [new Date('2024-11-18T08:00:00'), new Date('2024-11-18T10:30:00')],
                [new Date('2024-11-18T07:00:00'), new Date('2024-11-18T09:45:00')]
            ],
            backgroundColor: ["#8A2BE2", "#007F5C"]
        },
        {
            data: [
                [new Date('2024-11-18T11:00:00'), new Date('2024-11-18T15:00:00')],
                [new Date('2024-11-18T10:15:00'), new Date('2024-11-18T13:00:00')]
            ],
            backgroundColor: ["#8A2BE2", "#007F5C"]
        },
        {
            data: [
                [new Date('2024-11-18T14:00:00'), new Date('2024-11-18T15:00:00')],
                [new Date('2024-11-18T15:15:00'), new Date('2024-11-18T17:00:00')]
            ],
            backgroundColor: ["#8A2BE2", "#007F5C"]
        },
        {
            data: [
                [new Date('2024-11-18T15:15:00'), new Date('2024-11-18T17:00:00')],
                null
            ],
            backgroundColor: ["#8A2BE2", "#007F5C"]
        },
        ],
    }

    var myChart = new Chart(ctx, {
        type: 'bar',
        data: chartData,
        options: {
            maintainAspectRatio: false,
            responsive: false,
            indexAxis: 'y',
            plugins: {
                legend: {
                    display: false
                },
                title: {
                    display: false
                },
                tooltip: {
                    enabled: false
                }
            },
            scales: {
                y: {
                    stacked: true,
                    grid: {
                        display: false
                    },
                },
                x: {
                    grid: {
                        display: false
                    },
                    type: 'time',
                    time: {
                        unit: 'minute',

                    },
                    ticks: {
                        stepSize: 15,
                    },
                    min: new Date('2024-11-18T06:00:00'),
                    max: new Date('2024-11-18T17:00:00'),
                }
            },
            animation: {
                onComplete: function () {
                    var sourceCanvas = this.chart.ctx.canvas;
                    var copyWidth = this.scale.xScalePaddingLeft - 5;
                    var copyHeight = this.scale.endPoint + 5;
                    var targetCtx = document.getElementById("myChartAxis").getContext("2d");
                    targetCtx.canvas.width = copyWidth;
                    targetCtx.drawImage(sourceCanvas, 0, 0, copyWidth, copyHeight, 0, 0, copyWidth, copyHeight);
                }
            }
        }
    });

Why the next textbox was fired keyup event after I press Enter on the button and focus on next textbox

I have a list of textbox and button:

<p>Please type Enter to move to the next element</p>
<input id="item-0" class="item" type="text" index="0" /><br/>
<button id="item-1" class="btn-item" type="button" index="1">Confirm</button><br/>
<input id="item-2" class="item" type="text" index="2" /><br/>
<input id="item-3" class="item" type="text" index="3" /><br/>
<input id="item-4" class="item" type="text" index="4" />

My purpose: when I hit Enter on a textbox or button, the next element will be focus on. But with the button, when I hit Enter it will move to the next element and that element continues to fire the keyup event (Enter) and move to the next one.

const selects = document.querySelectorAll('.item');
 selects.forEach(el => el.addEventListener('keyup', e => { 
    if (e.key === 'Enter' || e.keyCode === 13) {
        let idx = parseInt(e.currentTarget.getAttribute("index"));
    focusToTheNextControl(idx);
    }
}));
document.querySelector('.btn-item').addEventListener('click', e => { 
   let idx = parseInt(e.currentTarget.getAttribute("index"));
   focusToTheNextControl(idx);
});
function focusToTheNextControl(idx) {   
  document.querySelector("#item-" + (idx + 1)).focus();
}

const selects = document.querySelectorAll('.item');
selects.forEach(el => el.addEventListener('keyup', e => {
  if (e.key === 'Enter' || e.keyCode === 13) {
    let idx = parseInt(e.currentTarget.getAttribute("index"));
    focusToTheNextControl(idx);
  }
}));

document.querySelector('.btn-item').addEventListener('click', e => {
  let idx = parseInt(e.currentTarget.getAttribute("index"));
  focusToTheNextControl(idx);
});

function focusToTheNextControl(idx) {
  document.querySelector("#item-" + (idx + 1)).focus();
}
<p>Please type Enter to move to the next element</p>
<input id="item-0" class="item" type="text" index="0" /><br/>
<button id="item-1" class="btn-item" type="button" index="1">Confirm</button><br/>
<input id="item-2" class="item" type="text" index="2" /><br/>
<input id="item-3" class="item" type="text" index="3" /><br/>
<input id="item-4" class="item" type="text" index="4" />

I try to delay focus on the next element by using setTimeout in 1sec and it stops. I have no ideal how it works and the right way to stop it.
Thanks for you help.

Intermittent Google Maps and Autocomplete failure

I have a form page where users submit a post.

The location section of form

    <div class="section">
 <h2 class="section-title">
     Location
     
     <span class="tooltip">Your location will be displayed on your ad and determines what city it will be posted in.</span>
 </h2>

 <div class="map-container">
  <div id="map"></div>
</div>
<div class="location-section location-limited-width">
    <textarea class="form-control" 
        id="location" 
        name="listingaddress" 
        rows="1"
        placeholder="Type Address or Postal Code" 
        required 
        autocomplete="off" 
        style="width: 100%; max-width: 500px; margin-right: 10px; resize: none;"></textarea>
    <span class="info-text" style="font-size: 14px; font-weight: bold; color: #333;">
      <i class="fa fa-info-circle"></i> Type address or postal code and select from the options that appear.
    </span>

    <span id="error-message" style="color: red; display: none;">
        * Your selected address must include a minimum of City or Town.<br>
        * You must select from the options that appear in the dropdown box.
    </span>
    <input type="hidden" id="locality" name="locality" />
    <input type="hidden" id="administrative_area_level_1" name="administrative_area_level_1" />
</div>

<!-- Display locality if selected -->
<div id="locality-display" class="locality-display" style="display:none;">
    Your item will be listed in <strong><span id="locality-name"></span></strong> 
    <span class="info-icon"></span>
    <span class="tooltip">Your location will be displayed on your ad and determines what city it will be posted in.</span>
</div>

The script

    <script>
document.addEventListener('DOMContentLoaded', function() {
    let map;
    let marker;
    const input = document.getElementById('location');
    const localityInput = document.getElementById('locality'); 
    const provinceInput = document.getElementById('administrative_area_level_1'); 
    const errorMessage = document.getElementById('error-message');
    const localityDisplay = document.getElementById('locality-display');
    const localityName = document.getElementById('locality-name'); // Display element for locality
    let autocomplete; 
    let lastInputValue = ''; 

    function initMap() {
        map = new google.maps.Map(document.getElementById('map'), {
            center: { lat: 47.5615, lng: -52.7126 },  // Default to St. John's, Newfoundland
            zoom: 12  // Adjusted zoom level for a closer view
        });

        marker = new google.maps.Marker({
            position: { lat: 47.5615, lng: -52.7126 },  // Default marker position
            map: map
        });
    }

    function extractLocalityAndProvince(result) {
        const addressComponents = result.address_components;
        const locality = addressComponents.find(component => component.types.includes("locality"));
        const province = addressComponents.find(component => component.types.includes("administrative_area_level_1"));

        if (locality && locality.long_name) {
            localityInput.value = locality.long_name;
            localityName.textContent = locality.long_name;  // Display locality in the locality-name span
            localityDisplay.style.display = 'block';  // Show the locality-display div
            errorMessage.style.display = 'none';  // Hide the error message
        } else {
            clearLocationInput();
            showErrorMessage();
        }

        if (province) {
            provinceInput.value = province.long_name;
        }
    }

    function clearLocationInput() {
        input.value = '';  // Clear the input box
        localityInput.value = '';  // Clear the hidden locality field
        localityDisplay.style.display = 'none';  // Hide the locality display
    }

    function showErrorMessage() {
        errorMessage.style.display = 'block';  // Show the error message
    }

    function initAutocomplete() {
        autocomplete = new google.maps.places.Autocomplete(input);
        autocomplete.setFields(['address_components', 'geometry', 'formatted_address']);
        autocomplete.setComponentRestrictions({
            country: ['ca']  // Restrict to Canada
        });

        autocomplete.addListener('place_changed', function() {
            const place = autocomplete.getPlace();

            // Check if a place was actually selected from the dropdown
            if (!place || !place.geometry) {
                console.log("No details available for input: '" + input.value + "'");
                clearLocationInput();  // Clear any previously set values
                showErrorMessage();
                return;
            }

            // Update the map view and marker position
            if (place.geometry.viewport) {
                map.fitBounds(place.geometry.viewport);
            } else {
                map.setCenter(place.geometry.location);
                map.setZoom(17);
            }
            marker.setPosition(place.geometry.location);

            // Update the input box and hidden fields for locality and province
            input.value = place.formatted_address || '';
            extractLocalityAndProvince(place);
        });

        // Ensure fields update on Enter keypress when using keyboard to select
        input.addEventListener('keydown', function(event) {
            if (event.key === 'Enter') {
                event.preventDefault();  // Prevent form submission on Enter
                google.maps.event.trigger(autocomplete, 'place_changed');
            }
        });
    }

    initMap();
    initAutocomplete();

    input.addEventListener('focus', function() {
        this.value = '';  // Clear the input field when focused
    });

    document.querySelector('form').addEventListener('submit', function(event) {
        if (!input.value || input.value.toLowerCase() === 'null') {
            event.preventDefault();
            alert('Please select a valid location.');
        }
    });
});
</script>

This form and script works for most users, they are able to select and submit. But some users are getting the “Oops, something went wrong error on the google maps and autocomplete”

Google error message

I have added logic to capture javascript errors on page and log them to server, such that when it happens again I will have more information. For the time being, I was wondering if anyone knows what the issue could be?

Thanks for reading my question.

React Framer Motion Sidebar animation jumpy

I’m new to a framer motion, and right now I’m trying to build Sidebar navigation that have animation when expending/collapsing, but I’m facing a bug where everything on the right side of the sidebar is jumpy when I expend or collapse my sidebar, and what I want to achieve is that topbar and content “sticks” to the sidebar.
Note: I would love to keep state inside the sidebar component, and not move it to upper level to the parent component, so i can avoid re-rendering of the whole content every time I resize my sidebar.

This is how the app is structured right now:

const PageContent = () => {
  return (
    <main className="flex bg-base">
      <Sidebar />
      <div className={'w-full'}>
        <Topbar />
          Content
      </div>
    </main>
  );
};

This is my sidebar component:

const Sidebar = () => {
  const [isExpanded, setIsExpanded] = useState(true);
  const [selected, setSelected] = useState('Dashboard');

  const navigationWidth = isExpanded ? 'w-72' : 'w-fit';

  return (
    <motion.aside layout className={'flex h-screen flex-col gap-4 bg-white px-6 ' + navigationWidth}>
      <SidebarTitleSection isExpanded={isExpanded} />
      <SidebarItem Icon={FiGrid} title={'Dashboard'} selected={selected} setSelected={setSelected} isExpanded={isExpanded} />
      <SidebarItem Icon={FiPackage} title={'Orders'} selected={selected} setSelected={setSelected} isExpanded={isExpanded} />
      <SidebarItem Icon={FiUsers} title={'Customers'} selected={selected} setSelected={setSelected} isExpanded={isExpanded} />
      <SidebarItem Icon={FiFolder} title={'Inventory'} selected={selected} setSelected={setSelected} isExpanded={isExpanded} />
      <SidebarToggle isExpanded={isExpanded} setIsExpanded={setIsExpanded} />
    </motion.aside>
  );
};

The only motion properties inside SidebarTitleSection and SidebarItem are layout, initial, animate and transition.

Topbar component looks like this:

const Topbar = () => {
  return (
    <motion.div layout className={'h-20 bg-white pl-6 pt-7 font-bold'}>
      <span>Dashboard</span>
    </motion.div>
  );
};

React: target dynamic HTML elements with Intro.js

I have been using Intro.js for React for a while now, and reallt like it.
However, I am not able to fix the one issue that is keeping me from continuing with the tours. That is the fact that I cannot seem to be able to target dynamic HTML elements that are either refreshed or loaded after a certain state change. I discovered Intro.js has a static array of HTML target elements on boot, but does not update this state when something changes. Is there any solution to change this to allow for resetting Intro.js during the tour for example? So the array of targetted HTML elements is refreshed.

I am using the following setup:

let steps: {
    intro: string,
    element?: string
}[] = [];

/* Construct Intro.js steps for digital specimen page */
digitalSpecimenSteps.forEach((step, index) => {
    if ([0, 1, 2, 3, 4, 5].includes(index) || (KeycloakService.IsLoggedIn() && KeycloakService.GetParsedToken()?.orcid)) {
        steps.push({
            intro: step,
            element: `.tourAnnotate${index + 1}`
        });
    }
});

<Steps enabled={tourTopic === 'annotate'}
    steps={steps}
    initialStep={0}
    onBeforeChange={(nextIndex) => {
        return new Promise((resolve) => {
            OnStepChange(nextIndex + 1, resolve);
        });
    }}
    onStart={() => {
        dispatch(setAnnotationWizardToggle(false));
    }}
    onExit={() => {
        dispatch(setTourTopic(undefined));
        dispatch(setAnnotationWizardToggle(false));
    }}
    options={options}
/>

/**
 * Function that checks what to do on a step change
 * @param nextIndex The next (selected) index in the step chain
 * @param resolve Function to resolve the step promise 
 */
const OnStepChange = async (nextIndex: number, resolve: Function) => {
    if ([1, 2, 3].includes(nextIndex) && annotationMode) {
        SetAnnotationMode(false);

        await new Promise((resolve) => {
            setTimeout(() => {
                resolve(true);
            }, 500);
        });
    } else if (![1, 2, 3].includes(nextIndex) && !annotationMode) {
        SetAnnotationMode(true);

        await new Promise((resolve) => {
            setTimeout(() => {
                resolve(true);
            }, 500);
        });
    }

    if (nextIndex < 7 && tourAnnotationWizardToggle) {
        dispatch(setAnnotationWizardSelectedIndex(undefined));
        dispatch(setAnnotationWizardToggle(false));

        setTimeout(() => {
            resolve();
        }, 500);
    } else if (nextIndex === 7) {
        dispatch(setAnnotationWizardToggle(true));

        resolve();
    } else {
        resolve();
    }
}

The function OnStepChange function changes some state variables in the global state, determining if certain HTML elements should be rendered or not. Step 6 targets a dynamic element, it is visible at first and registered by Intro.js, so the tour acts normal. At step 7, the element gets removed from the DOM, returning to step 6, it is rendered again. In this return step, Intro.js loses its focus to the element and does not target it with the tooltip lay-over.

Any clues on how I can make Intro.js recognize the dynamic HTML element that was removed, but later again added to the DOM?

Thanks!

How can I change the default return value of a constructor?

I am trying to return a specific value when calling a constructor variable instead of “this” without removing the values defined with “this.”

class Matrix {
    constructor(x, y) {
        this.width = x;
        this.height = y;
        this.size = x * y;
        this.value = Array.from({length: y}, () => new Array(x).fill(0));
        return {"hello": 1}
    }
    getIndex(x, y) {
        return y * this.width + x
    }
    getCoords(index) {
        return [index % this.width, Math.floor(index / this.width)]
    }
    getValue() {
        return this.value
    }
}

const matrix1 = new Matrix(5, 5);
console.log(matrix1);
console.log(matrix1.width);

The problem is that if I change the return value, the other values are deleted. I previously had a new object that had the desired return value, but I would like to avoid calling matrix1.value to get it. Instead, I want matrix1 to return matrix1.value.

Progress bars aren’t showing or dynamically filling (JS & HTML)

I am using Shopify to create a custom reviews section..
1-Filtering reviews is working fine and clicking on a star group filters the visible reviews.
2-Updating progress-fill width is also working based on the percentage of reviews for each star rating, however, there’s no render view or visible output on my website .. it is indeed updating fine when I inspect the elements but no visible results :

document.addEventListener("DOMContentLoaded", function() {
  const reviews = document.querySelectorAll(".review-item");
  const starGroups = document.querySelectorAll(".star-group");

  // Initialize counts for each star rating
  const starCounts = {
    5: 0,
    4: 0,
    3: 0,
    2: 0,
    1: 0
  };
  const totalReviews = reviews.length;

  // Step 1: Count how many reviews correspond to each star rating
  reviews.forEach((review) => {
    const rating = parseInt(review.getAttribute("data-rating"), 10);
    if (starCounts[rating] !== undefined) {
      starCounts[rating]++;
    }
  });

  console.log("Star Counts:", starCounts); // Debugging log

  // Step 2: Update progress bars and review counts
  starGroups.forEach((group) => {
    const stars = parseInt(group.getAttribute("data-stars"), 10);
    const count = starCounts[stars] || 0;
    const countElement = group.querySelector(".review-count");
    countElement.textContent = `(${count})`;

    // Calculate percentage of reviews for this star rating
    const percentage = totalReviews > 0 ? (count / totalReviews) * 100 : 0;
    const progressFill = group.querySelector(".progress-fill");

    // Ensure percentage is being applied correctly
    progressFill.style.width = `${percentage}%`;
    progressFill.offsetWidth; // Trigger reflow to ensure rendering


    // Debugging logs for progress bar calculation
    console.log(`Star Group: ${stars}, Count: ${count}, Percentage: ${percentage}%`);

    // Filtering functionality on click
    group.addEventListener("click", function() {
      reviews.forEach((review) => {
        const reviewRating = parseInt(review.getAttribute("data-rating"), 10);
        if (reviewRating === stars) {
          review.style.display = "block";
        } else {
          review.style.display = "none";
        }
      });
    });
  });
}, 100); // Small delay ensures all elements are fully rendered
**CSS:** ``` .star-summary {
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-size: 14px;
  font-family: Arial, sans-serif;
  color: #333;
}

.star-group {
  display: flex;
  align-items: center;
  gap: 10px;
  justify-content: space-between;
}

.star-label {
  font-size: 14px;
  font-weight: bold;
}

.progress-bar {
  display: block;
  visibility: visible;
  opacity: 1;
  width: 100%;
  /* or 100% for responsive design */
  height: 20px;
  background-color: #e0e0e0;
  position: relative;
  overflow: hidden;
  /* Ensures child stays inside */
}

.progress-fill {
  display: block;
  visibility: visible;
  opacity: 1;
  width: 0%;
  /* Dynamically updated */
  height: 100%;
  background-color: #f5b001;
  transition: width 0.3s ease;
  /* Smooth transition */
}

.review-count {
  font-size: 12px;
  color: #555;
}
<div class="star-summary">
  <div class="star-group" data-stars="5">
    <span class="star-label">5 <span class="star filled">★</span></span>
    <div class="progress-bar">
      <div class="progress-fill"></div>
    </div>
    <span class="review-count">(0)</span>
  </div>
  <div class="star-group" data-stars="4">
    <span class="star-label">4 <span class="star filled">★</span></span>
    <div class="progress-bar">
      <div class="progress-fill"></div>
    </div>
    <span class="review-count">(0)</span>
  </div>
  <div class="star-group" data-stars="3">
    <span class="star-label">3 <span class="star filled">★</span></span>
    <div class="progress-bar">
      <div class="progress-fill"></div>
    </div>
    <span class="review-count">(0)</span>
  </div>
  <div class="star-group" data-stars="2">
    <span class="star-label">2 <span class="star filled">★</span></span>
    <div class="progress-bar">
      <div class="progress-fill"></div>
    </div>
    <span class="review-count">(0)</span>
  </div>
  <div class="star-group" data-stars="1">
    <span class="star-label">1 <span class="star filled">★</span> </span>
    <div class="progress-bar">
      <div class="progress-fill"></div>
    </div>
    <span class="review-count">(0)</span>
  </div>
</div>

I tried debbugging and here’s what I got in my console:
Console
Here’s output on website

How can I create a box where I can simulate different screen sizes with Tailwind CSS and Next JS

I am working on creating a website builder, and I want to be able to see what the page would look like on a phone, without having to always open the web inspector and changing the width of it. I looked it up, and I couldn’t find anything that worked. I want to be able to switch from desktop to tablet to phone size screens in a div (not the whole screen). I would appreciate any advice (ideas) you may have.