How to implement a product catalog interface with multiple conditions

I have an Angular HTML document of a product catalog page.

products.componet.ts:

showCategories = true;
showProductsInCategoriesSwitcher = true;
showProductsAll = false;
showProductsInCategories = false;

fetchingProducts = false;

showProductsByCategory(categoryId: string) {
    this.showCategories = !this.showCategories;
    this.showProductsInCategoriesSwitcher = !this.showProductsInCategoriesSwitcher;
    this.showProductsInCategories = !this.showProductsInCategories;
    //further code
}

showAllProducts() {
    this.showCategories = !this.showCategories;
    this.showProductsAll = !this.showProductsAll;
    //further code
}

products.component.html:

<div *ngIf="showProductsInCategoriesSwitcher" class="mb-4">
  <input type="checkbox" checked (click)="showAllProducts()"/>
  <label class="ms-1">Show products in categories</label>  
</div>

<div *ngIf="showCategories">
  <div *ngIf="categories$ | async as categories; else loader">
    <div *ngIf="categories.length !== 0">
      <c-row [gutter]="2" class="mb-2" [lg]="6" [md]="4" [xs]="1">
        <c-card *ngFor="let category of categories" class="mx-1">
          <div *ngIf="category._id"            
            (click)="showProductByCategory(category._id)">
            <img cCardImg="top" [src]="category.imageSrc" />
            <c-card-body>
              <h2 cCardTitle>{{ category.name }}</h2>
            </c-card-body>
          </div></c-card>
      </c-row>
    </div>
  </div>
</div>

<ng-container *ngIf="
    (!showCategories && !showProductsInCategoriesSwitcher) ||
    (!showProductsAll && showProductsInCategories)">
  <ng-container *ngTemplateOutlet="
      ProductsByCategory; context: { categoryId: selectedCategoryId }">
   </ng-container>
</ng-container>

<ng-container *ngIf="!showCategories && !showProductsInCategories">
  <ng-container *ngTemplateOutlet="ProductsAll"></ng-container>
</ng-container>

<ng-template #ProductsByCategory let-categoryId="categoryId">
  <div *ngIf="!fetchingProducts; else loader">
    <ng-container *ngIf="productsInCategories.length !== 0">
      <a (click)="
         (showCategories = !showCategories) &&
         (showProductsInCategoriesSwitcher = !showProductsInCategoriesSwitcher)"
        >Back to categories</a>
    </ng-container>

<!-- Code for product card -->

    <ng-container *ngIf="!productsInCategories || productsInCategories.length === 0">
        <a href="javascript:void(0);"
        (click)="(showCategories = !showCategories) &&
            (showProductsInCategoriesSwitcher = !showProductsInCategoriesSwitcher)">
            Back to categories</a>
      <p>No products available for this category.</p>
    </ng-container>
  </div>
</ng-template>

<ng-template #ProductsAll><div *ngIf="!fetchingProducts; else loader">
    <ng-container *ngIf="productsAll.length !== 0">
    <!-- Code for product card -->
    </ng-container>
    <ng-container *ngIf="!productsAll || productsAll.length === 0">
      <p>No products available.</p>
    </ng-container>
  </div>
</ng-template>

<ng-template #loader>
  <div class="myspinner">
    <c-spinner></c-spinner>
  </div>
</ng-template>

As you can see, the page is loaded with templates for product categories and a switch for displaying types of products in categories or all products at once.

I need to implement this logic:

When you click on a category element, show products from this category and the “Return to categories” link, while hiding the “Show products by category” switch. When you click on the “Return to Categories” link, everything should return to its original state.

When you click the “Show products in categories” switch, show all products at once, while hiding the product categories template. When you press the switch again, everything should return to its original state.

I’m stuck trying out options for displaying templates, but the logic of their behavior changes every time.

Please explain to me how this logic is implemented, or tell me how to correctly ask in Google. Thank you.

How to add copy paste capabilities to Select2 with AJAX data source?

Currently, I’m working on the Admin side of a Django 4.2 site.
The current version of Django, uses Select2 to handle FK fields in forms.

I have the need to add copy paste capabilities to those forms, so they can copy data from an excel and paste it and fill a collection of Select2s. But it seems that selecting the data from a remote sourced data it’s more tricky than expected.

According to the Select2’s documentation

For Select2 controls that receive their data from an AJAX source, using .val() will not work.

Instead, they recommend fetching the data yourself and adding it as a new option.

// Set up the Select2 control
$('#mySelect2').select2({
    ajax: {
        url: '/api/students'
    }
});

// Fetch the preselected item, and add to the control
var studentSelect = $('#mySelect2');
$.ajax({
    type: 'GET',
    url: '/api/students/s/' + studentId
}).then(function (data) {
    // create the option and append to Select2
    var option = new Option(data.full_name, data.id, true, true);
    studentSelect.append(option).trigger('change');

    // manually trigger the `select2:select` event
    studentSelect.trigger({
        type: 'select2:select',
        params: {
            data: data
        }
    });
});

Since the Select2 already knows how to fetch it’s own data, since it already does for the autocomplete, duplicating whats already implemented seems to me like a waste of time.

<select name="form-0-multiplex_index" id="id_form-0-multiplex_index" class="admin-autocomplete" data-ajax--cache="true" data-ajax--delay="250" data-ajax--type="GET" data-ajax--url="/admin/autocomplete/" data-app-label="sequencing" data-model-name="uploadedlibrary" data-field-name="multiplex_index" data-theme="admin-autocomplete" data-allow-clear="true" data-placeholder="" lang="en">

So, in a nutshell, my question is. How to programmatically search and select the first result on a Select2 input with Ajax fetched data given a string from the clipboard without having to re-implement it from scrath? (Or at the very least, reuse the parameters already present on the dom).

Problem conditionally showing buttons based on sibling’s height

OBJECTIVE

I’m developing a UI chat interface as a project to learn React + TS. When a chat message is long enough and so provides enough vertical space, its action buttons (such as copy message, share, etc.) should appear vertically stacked to the right of the message’s container. When there isn’t enough space, meaning the stacked buttons would be taller than the message’s container, the buttons shouldn’t appear at all:

enter image description here

PROBLEM

The code below isn’t working. The buttons still appear as normal. Strangely, when the window is resized, the button’s visibility toggles and they either disappear/reappear depending on whether they are currently showing (because of React’s hot reload feature, either state can be the starting one).

WHAT I HAVE TRIED

  • Using Lodash to both throttle and debounce the function
  • Using useLayoutEffect instead of useEffect
  • Using resize observers instead
  • Adding a very long time/debounce/throttle delay
  • Using getClientRects instead of offsetHeight
  • Talking to ChatGPT 4, Phind, Gemini and Blackbox
import React, { useLayoutEffect, useRef, useState, useCallback } from "react";
import lodash from 'lodash';

// import statements removed for brevity
// props interface removed for brevity

const Message: React.FC<MessageProps> = ({ sender, messageContents, actionButtons, children }) => {
    const chatMessageRef = useRef<HTMLDivElement>(null);
    const sideButtonsRef = useRef<HTMLDivElement>(null);
    const [showSideButtons, setShowSideButtons] = useState(true);

    const checkAndSetButtonVisibility = useCallback(() => {
        const messageContainer = chatMessageRef.current;
        const sideButtons = sideButtonsRef.current;

        if (messageContainer && sideButtons) {
            setShowSideButtons(messageContainer.offsetHeight > sideButtons.offsetHeight);
        }
    }, []);

    // Using lodash's throttle function to limit how often the checkAndSetButtonVisibility function can be invoked
    const debouncedCheck = useCallback(lodash.debounce(checkAndSetButtonVisibility, 1500), [checkAndSetButtonVisibility]);

    useLayoutEffect(() => {
        window.addEventListener('resize', debouncedCheck);
        checkAndSetButtonVisibility(); // Initial check for the correct state

        return () => {
            window.removeEventListener('resize', debouncedCheck);
            debouncedCheck.cancel(); // Cancel any pending execution of the throttled function on cleanup
        };
    }, [debouncedCheck, checkAndSetButtonVisibility]);

    return (
        <div className={`chat-message-outer-container ${sender.toLowerCase()}`}>
            <div className="chat-message-inner-container">
                <div className="chat-message-info">
                    {sender === MessageSender.Agent ? (
                        <div className="chat-list-item-ai-model-logo-message">
                            <img className={"message-avatar"} src={aiLogo} alt="AI Model Logo" />
                        </div>
                    ) : (
                        <div className="account-avatar-message">
                            <img className={"message-avatar"} src={userAvatar} alt="User avatar" />
                        </div>
                    )}
                    <div className="chat-message-info-sender">{sender}</div>
                </div>

                <div className="chat-message-select-checkbox">
                    <label className="button checkbox-field">
                        <input type="checkbox"/>
                        <span>
                      <br/>
                    </span>
                    </label>
                </div>

                <div className="chat-message-wrapper">
                    <div ref={chatMessageRef} className={`chat-message ${sender.toLowerCase()}-message`}>
                        <div className="chat-message-contents">{messageContents}</div>
                    </div>
                </div>

                <div
                    ref={sideButtonsRef}
                    className="chat-message-buttons-side"
                    style={{ display: showSideButtons ? 'flex' : 'none' }} // Use the state to control visibility
                >
                    {actionButtons}
                </div>

                <div className="chat-message-bottom">
                    {children}

                    <div className="chat-message-action-row">
                        <div className="chat-message-tag-list">
                            <Tag tagName={'Tag name'}/>

                            <AddElementButton type={"new-tag-message"}/>
                        </div>

                        <div className="chat-message-buttons-bottom">
                            {actionButtons}
                        </div>
                    </div>
                </div>
            </div>
        </div>
    );
};

export default Message;

How to get file extension on dragenter, before drop?

I am trying to check the type/extension of a file on dragover (before drop) and cannot seem to do this. For some reason the files array has a length of zero on dragover. I have tried using a dragenter event as well with the same result. A lot of people on similar posts say how it is now possible to check the file type after some browser updates but I cannot seem to figure out how.

function checkFile(event: dragEvent){ 
    event.stopPropagation(); 
    event.preventDefault(); 
    const files = event.dataTransfer?.files; 
    console.log(files)
    } 

This function is called from a drop area.

<div ..... @dragover = 'checkFile'>

How to disable HTML attributes with js?

I have a menu with hover dropdown menus. On mobile I want to disable the href attribute so that clicking the link doesn’t redirect, but opens the dropdown. I am currently using removeAttribute() to do that. But the problem is that if the user uses the site in a smaller window which triggers the mobile version and then makes the window bigger I need to add back the href. I could use setAttribute() but then I have to keep track of the links to add them back and I don’t feel like that’s the best solution. Is there a way to just disable the href attribute with js?

Handling Color display on the grid

I’m moving blue boxes from left to right (on the grid) after clicking Move Text Content! button. Here are the steps I follow:

  1. Select one option from Select options dropdown.

  2. Select a color from the dropdown.

  3. Click Show Options button

  4. Enter a row and column (For example A and 1) and then click calculate

  5. Hit the Move Text Content! button to move blue boxes on the grid.

Here’s an example with blue color move:

enter image description here

As can be seen, it’s very hard to read the text when it comes to blue color. Also, I have Black color in the dropdown list (which doesn’t work for some reason) but if it would have worked, it would have disappeared the text as background and text color are both black. Hence, I am wondering how can I handle the text color using CSS such that whatever color I select for the move, is readable by the user easily. Here’s my code:

/*

Requires jquery + UI

https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js

https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js

*/

$('[name="optionSelection"]').change(function () {
      //clean up the divs inside div with id phrase
    $("#phrase").empty();
  });
let selectedColor;
  function showOptions() {
    console.log("hii");
    console.log($("#optionSelection").val());
    selectedColor = $('#lineupColors').val();
    var html;
    if ($("#optionSelection").val() == 1) {
      for (i = 0; i < 3; i++) {
         
            html = "<div data-id="+i+"><span class='words' data-id="+i+">OptionOne#"+i+"</span></div>";
            $("#phrase").append(html);
      }
      
    }
    else {
      for (j = 0; j < 5; j++) {
         
        html = "<div data-id="+j+"><span class='words' data-id="+j+">OptionTwo#"+j+"</span></div>";
       $("#phrase").append(html);
    }
   // $("#phrase").append(html);
  }
}


  $(".words").draggable({
    revert: function (event, ui) {
      var bRevertingPhrase = this.closest("#drop-em");

      if (!bRevertingPhrase.length) {
        var phraseID = $(this).data("id");
        var phraseHomeID = $(this).parent().data("id");

        //If the child and parent ids don't match, we move the child to the correct parent
        if (phraseID !== phraseHomeID) {
          var correctCell = $("#phrase").find(
            "div[data-id='" + phraseID + "']"
          );
          correctCell.prepend(this);
        }
      }
      return !event;
    },
  });
  $("#drop-em > div").droppable({
    drop: function (ev, ui) {
      $(ui.draggable)
        .detach()
        .css({ top: 0, left: 0 })
        .appendTo($(this).find(".content:empty"));
      //$("#move-text").addClass("disabled");
    },
  });
  $("#phrase > div").droppable({
    drop: function (ev, ui) {
      $(ui.draggable).detach().css({ top: 0, left: 0 }).prependTo(this);
    },
  });

  const myButton = document.querySelector("#move-text");
  myButton.addEventListener(
    "click",
    () => {
      fill();
    },
   /* {
      once: true,
    }*/
  );

  var reOrder = [];
  function fill() {
    const cells = document.querySelectorAll("#phrase > div > span");
    var newLoc = "";
    //myButton.classList.add("disabled");

    cells.forEach((cell, index) => {
      newLoc = document.querySelector(
        ".item:nth-child(" + reOrder[index + startPos - 1] + ") .content "
      );
      newLoc.append(cell);
      newLoc.classList.add("moved");
       newLoc.classList.add("color-"+selectedColor);
      $('.color-'+selectedColor).css('background-color',selectedColor);
      
    });
  }
  function reArrange() {
    var limit1 = 85;
    var limit2 = 91;

    for (let loop = 0; loop < 8; loop++) {
      for (let i = 0; i < 6; i++) {
        reOrder.push(limit1 + i);
      }
      limit1 = limit1 - 12;
    }
    for (let loop = 0; loop < 8; loop++) {
      for (let j = 0; j < 6; j++) {
        reOrder.push(limit2 + j);
      }
      limit2 = limit2 - 12;
    }
  }
  reArrange();

  /* get cell number */

  const myRow = document.querySelector("#inp1");
  const myCol = document.querySelector("#inp2");
  var startPos = 0;
  const myCalculateButton = document.querySelector("#calculate");
  const myAnswer = document.querySelector("#cellnum");
  myCalculateButton.addEventListener("click", () => {
    var rowNumber = myRow.value.toUpperCase();
    var colNumber = myCol.value;
    var result = 0;
    switch (rowNumber) {
      case "A":
        rowNumber = 42;
        break;
      case "B":
        rowNumber = 36;
        break;
      case "C":
        rowNumber = 30;
        break;
      case "D":
        rowNumber = 24;
        break;
      case "E":
        rowNumber = 18;
        break;
      case "F":
        rowNumber = 12;
        break;
      case "G":
        rowNumber = 6;
        break;
      case "H":
        rowNumber = 0;
        break;
    }

    if (colNumber < 7) {
      result = rowNumber + parseInt(colNumber);
    } else {
      result = rowNumber + 42 + parseInt(colNumber);
    }
    myAnswer.innerHTML = result;
    startPos = result;
  });
  
 
html {
    box-sizing: border-box;
  }
  *,
  *:before,
  *:after {
    box-sizing: inherit;
  }
  body {
    counter-reset: columnCount 1 alphaCount cellCount;
  }
  h1 {
    text-align: center;
  }
  .wrap {
    display: flex;
    gap: 2rem;
    position: relative;
    padding-left: 220px;
  }

  .grid {
    margin: auto;
    display: grid;
    flex: 1 0 0;
    grid-template-columns: repeat(12, 1fr);
    padding-top: 1.5rem;
  }

  .item {
    position: relative;
    background-color: #f9f9f9;
    border: 1px solid grey;
    aspect-ratio: 1/1;
    counter-increment: columnCount;
    min-width: 0;
    transition: background 1s ease;
  }
  .item:nth-of-type(12n + 1) {
    counter-increment: alphaCount;
  }
  .item:nth-of-type(12n + 1)::before {
    content: counter(alphaCount, upper-alpha);
    position: absolute;
    display: flex;
    align-items: center;
    top: 0;
    bottom: 0;
    left: -1.75rem;
    color: red;
    pointer-events: none;
  }
  .item:nth-of-type(n + 13)::after {
    display: none;
  }
  .item::after {
    content: counter(columnCount);
    position: absolute;
    left: 0;
    right: 0;
    text-align: center;
    top: -1.75rem;
    color: red;
    pointer-events: none;
  }
  .content {
    display: flex;
    flex-direction: column;
    justify-content: center;
    width: 100%;
    height: 100%;
    overflow: auto;
    color: #000;
    padding: 1rem;
    word-wrap: break-word;
    counter-increment: cellCount;
  }

  .words {
    cursor: move;
    transition: padding 0.5s ease;
  }
  .content:has(.ui-draggable-dragging) {
    overflow: visible;
  }
  .ui-droppable-active .content {
    overflow: visible;
  }
  .words.ui-draggable-dragging {
    background: blue;
    padding: 5px 10px;
    border-radius: 6px;
    z-index: 999;
    color: #fff;
    display: block;
    width: 50px;
    height: 50px;
    overflow: hidden;
  }
  #phrase {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    color: #fff;
    width: 150px;
    overflow: auto;
    z-index: 2;
    display: flex;
    flex-direction: column;
    margin: 1rem 0 0.5rem;
  }
  #phrase > div {
    margin: 0 0 10px;
    width: 150px;
    padding: 5px 10px;
    background: #007bff;
    border: 2px solid #007bff;
    border-radius: 6px;
    color: #fff;
  }
  #phrase > div:empty {
    background: #fff;
    border-style: dashed;
    padding: 0px 25px;
    min-height: 30px;
  }

  .moved {
    animation: fade 3s ease;
  }
  @keyframes fade {
    0% {
      opacity: 0;
    }
    50% {
      opacity: 1;
      background: red;
    }
  }

  .item .content::before {
    content: counter(cellCount);
    position: absolute;
    top: 2px;
    left: 2px;
    font-size: smaller;
    color: #666;
    border-radius: 50%;
    border: 1px solid red;
    background: white;
    width: 1.2rem;
    height: 1, 2rem;
    display: grid;
    place-items: center;
  }

  #move-text.disabled {
    cursor: none;
    pointer-events: none;
    opacity: 0.5;
  }
  #phrase:has(.ui-droppable-active) {
    overflow: visible;
  }

  input,
  button,
  label,
  p.target {
    display: block;
    margin: 0 0 0.4rem;
    color: #000;
  }
  p.target {
    margin: 0 0 1rem;
  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
  <!-- You'd need to set up something different for touch devices though -->

  <h1>Move testings</h1>
  <div class="wrap">
    <div>
      <label for="optionSelection">Select options</label>
      <select name="optionSelection" id="optionSelection">
        <option value="1">OptionOne</option>
        <option value="2">OptionTwo</option>
      </select>
    </div>
    <div>
    <label for="lineupColors">Colors:<br /></label>
    <select id="lineupColors">
       <option value="-">select</option>
      <option value="blue">Blue</option>
      <option value="orange">Orange</option>
      <option value="red">Red</option>
      <option value="green">Green</option>
      <option value="purple">Purple</option>
      <option value="brown">Brown</option>
      <option value="black">Black</option>
      <option value="magenta">Magenta</option>
    </select>
  </div>
    <div>
      <button id="showOptions" onclick="showOptions()" type="button">
        Show Options
      </button>
    </div>
    <div>
      <label for="inp1">Enter a row A - H</label>
      <input id="inp1" placeholder="Enter Row" />
      <label for="inp2">Enter a column 1 - 12</label>
      <input id="inp2" placeholder="Enter Column" />
      <button id="calculate">Calculate</button>
      <p class="target">The cell number is <b id="cellnum">?</b></p>
      <button id="move-text" type="button">Move Text Content!</button>
    </div>
    <div id="phrase">
      <!-- remove whitespace from  inside div html and then we can use :empty in css to change background -->
      <!-- <div data-id="1"><span class="words" data-id="1">H1 text</span></div>
      <div data-id="2"><span class="words" data-id="2">H2 text</span></div>
      <div data-id="3"><span class="words" data-id="3">H3 text</span></div>
      <div data-id="4"><span class="words" data-id="4">H4 text</span></div>
      <div data-id="5"><span class="words" data-id="5">H5 text</span></div>
      <div data-id="6"><span class="words" data-id="6">H6 text</span></div>
      <div data-id="7"><span class="words" data-id="7">G1 text</span></div>
      <div data-id="8"><span class="words" data-id="8">G2 text</span></div>
      <div data-id="9"><span class="words" data-id="9">G3 text</span></div>
      <div data-id="10"><span class="words" data-id="10">G4 text</span></div> -->
    </div>

    <div id="drop-em" class="grid">
      <div class="item">
        <div class="content"></div>
        <!-- must have no spaces inside .content -->
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
      <div class="item">
        <div class="content"></div>
      </div>
    </div>
  </div>

Javascript using global variables in another script

Script1.js is attached to both MyWebsite1.html and MyWebsite2.html, Script2.js is only attached to MyWebsite2.html. Script1.js is attached first in of MyWebsite2.html.

Script1.js

var global_var;
function open() {
    global_var = 1;
    window.open("MyWebsite2.html", "_self");
}

Script2.js

$(document).ready(function(){
    console.log(global_var);
});

When calling the open() function of my first script (via onclick of MyWebsite1.html) it sets global_var to 1 and opens MyWebsite2.html correctly. But for Script2.js global_var is still undefined.
If I set global_var to 1 outside of the open() function in Script1.js, then for Script2.js global_var is 1.

If you are wondering why I’m using $(document).ready(function(){}: because I want to append html code with it later to MyWebsite2.html.

NVDA is not announcing “dialog” when Modal opens

In this simple modal example, role is set to dialog and focus is received on dialog container when it opens, but NVDA won’t announce the word ‘dialog’ in the beginning. I notice there is potential NVDA issue on this https://github.com/nvaccess/nvda/issues/8620, but I could find several other accessible modal examples where NVDA announces ‘dialog’ such as https://stackblitz.com/edit/stackblitz-starters-tkpczr?file=src%2Fcomponents%2FModal%2FModal.jsx,src%2Fcomponents%2FNewsletterModal%2FNewsletterModal.jsx, https://codesandbox.io/p/sandbox/react-accessible-modal-dialog-forked-ypw7q8?file=%2Fsrc%2FModal%2Findex.js%3A62%2C1-65%2C25 and w3c Modal https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/examples/dialog/. So what’s is wrong with this modal that is preventing NVDA from announcing ‘dialog’?

HTML

<button id="test_button2">
  Open Dialog
</button>


<div tabindex="-1" id="test_dialog2" role="dialog" aria-labelledby="test2">
  <h2 id="test2">example</h2>
  <p>a test paragraph</p>
  <button>close</button>
</div>

CSS

#test_dialog2 {
  visibility: hidden;
}

#test_dialog2.show {
  visibility: visible;
  padding: 1em;
  box-shadow: 0 0 300px
}

button[aria-hidden] {
  opacity: .2;
}

*:focus {
  box-shadow: none;
  outline: 2px solid blue;
}

JS

var btn2 = document.getElementById('test_button2');
var dialog2 = document.getElementById('test_dialog2');
var btnClose2 = dialog2.querySelector('button');

btn2.addEventListener('click', function () {
  dialog2.classList.add('show');
  dialog2.focus();
  this.setAttribute('aria-hidden', true);
  this.setAttribute('tabindex', '-1');
});

btnClose2.addEventListener('click', function () {
  dialog2.classList.remove('show');
  btn2.removeAttribute('aria-hidden');
  btn2.removeAttribute('tabindex');
  btn2.focus();      
});

Get all CSS variables on an HTML element with JavaScript when you don’t know the names of the CSS Variables?

If I know the name of a CSS variable eg --thing I can get it’s value with JavaScript:

  const elem = document.querySelector("html");
  if (!elem) return;
  const style = getComputedStyle(elem);
  const myVariable = style.getPropertyValue("--thing");
  console.log({ myVariable });

I’ve tried iterating over the properties and looking for names that start with -- however it doesn’t work.

  for (let i = 0; i < style.length; i++) {
    const propertyName = style[i];
    if (propertyName.startsWith("--")) {
      console.log(propertyName);
    }
  }

Correctly capturing client-side errors in JavaScript, issues with extensions and cache

I’m working on a project where I need to capture client-side JavaScript errors accurately. My goal is to get the exact location or file where the error occurred. However, I’m encountering issues based on whether browser extensions are active or the cache is not cleared. Here’s what happens:

  • With extensions turned on and cache not cleared, I tend to capture
    information from my extensions instead of the actual error from my
    code.

  • When I clear the cache and turn off all extensions, the error is not
    captured as expected.

I’m trying to find a way to consistently capture the actual error regardless of the browser state. Below is the code snippet that handles error capturing and reporting:

getSourceCode(lineNumber) {
    return this.getInlineSourceCode(lineNumber) || this.getFullSourceWithHighlight(lineNumber);
}

getInlineSourceCode(lineNumber) {
    const scripts = document.querySelectorAll('script');
    for (let script of scripts) {
        if (!script.src) { 
            const scriptLines = script.textContent.split("n");
            const scriptPosition = this.getErrorPosition(script);
            if (lineNumber >= scriptPosition.startLine && lineNumber <= scriptPosition.endLine) {
                return this.highlightSource(scriptLines, lineNumber - scriptPosition.startLine);
            }
        }
    }
    return null;
}

getFullSourceWithHighlight(lineNumber) {
    const lines = document.documentElement.outerHTML.split("n");
    return this.highlightSource(lines, lineNumber - 1);
}

highlightSource(lines, lineNumber) {
    const start = Math.max(lineNumber - 2, 0);
    const end = Math.min(lineNumber + 2, lines.length - 1);
    lines[lineNumber] = '>> ' + lines[lineNumber] + ' <<'; 
    return lines.slice(start, end + 1).join("n");
}

getErrorPosition(script) {
    let totalLines = 0;
    let element = script.previousElementSibling;
    while (element) {
        totalLines += (element.outerHTML || element.textContent).split("n").length;
        element = element.previousElementSibling;
    }
    return {
        startLine: totalLines + 1,
        endLine: totalLines + script.textContent.split("n").length
    };
}

catchError() {
    window.onerror = (message, url, lineNumber, column, error) => {
        this.reportError(message, url, lineNumber, column, error.stack, 'JavaScript Error');
        return false;
    };

    window.addEventListener('unhandledrejection', event => {
        this.reportError(event.reason.toString(), document.location.href, 0, 0, event.reason.stack, 'Promise Rejection');
    });
}

reportError(message, url, lineNumber, column, stack, type = 'JavaScript Error') {
    fetch(this.url ? `${location.protocol}//${this.url}/${this.apikey}` : window.location.href, {
        method: "post",
        headers: {
            'Accept': "application/json",
            'Content-Type': "application/json"
        },
        body: JSON.stringify({
            type,
            message,
            url,
            lineNumber,
            column,
            stack,
            location: window.location.href,
            source: this.getSourceCode(lineNumber)
        })
    }).then(response => response.json()).then(console.info);
}

Why is Hacker-Rank not Considering the proper Answer for the Regular Expression Question [closed]

Here is the Question: You have a test string S.
Your task is to write a regular expression that matches only and exactly strings of form: abc.def.ghi.jkx , where each variable: a,b,c,d,e,f,g,h,i,j,k,x can be any single character except the newline.

Here is the Regular Expression I wrote:

/((w+)?(d+d+)?).((w+)?(d+d+)?).((w+)?(d+d+)?).((w+)?(d+d+)?)(.d+d+)?(.d+d+)?/g

I wrote this Regex as I discovered the different cases for the Hackerrank question. The interesting part is that I cases when tested using Regexer Website Tool, The cases are matching but they are not Matching on the Hackerrank website. Here is the Picture of both Working on Regexer and Not Working on Hackerrank:

Image of The Working Regex on Regexr Website

Case 1 not working, even it was working with the same input in Regexr

Similar With Case 4

Case 6 Also

I was trying to match the Regex Expression with the given Input. I wrote the Regex Expression for Every Case that was not working. Even If my all Regex is not Correct for all cases it should show for the ones that are Correct, but it is showing for some other comman cases. I tested all using Regexr Tool for thier given Input and its Matching there, but this Hackerrank is Not considering it.

Is there any way to make an exception in getElementsByTagName() Method in JavaScript?

These are the codes —

type here

 let buttons = document.getElementsByTagName("button" )

 
let buttonsArr = Array.from(buttons) ;

buttonsArr.forEach( (button) => {
    button.addEventListener("click", () => {
        console.log("clicked");
    } ) } ) ;

I want to exclude the reset-button but have no idea .
please suggest if you have any idea about how to make it work .

i was trying to make forEach method work on the buttons variable . It didnt work with the querySelector for classes . Any suggestion is Welcomed.

My DataTable becomes stuck when navigating between the table pages

I’m using server-side processing with DataTables to handle a substantial dataset. However, I’m encountering an issue specifically when navigating backward through the pages. Strangely, when I click the “Next” button, the table behaves correctly and displays the subsequent rows.

Yet, upon clicking the “Previous” button, although the data object loads in the network tab of the browser, the table remains stuck with the Processing... message displayed atop it. Has anyone else encountered a similar issue while utilizing the DataTables library? Any insights or solutions would be greatly appreciated.

I should be able to click previous and see the data on the previous page displayed