Javascript create file in memory and post

I have to create a file in-memory and then upload it with a post.
I cannot write anything to disk as this is javascript code on a SAAS platform (xMatters)
I cannot use “forms” or any external libraries, just javascript

This just needs to be a simple text file, created in memory and then “uploaded” via post.

Can anyone help on this?

How to fix icons not displaying at first load?

**Problem
**
I have built an mobile repair website with a custom repair module where customers can select a type of device, brand and a repair. When he wants to register a repair he goes in the nav-bar “reparatie aanmelden”. In the next screen he can select a brand for example, when select it should display smartphone (iPhone), tablet (ipad), iWatch, iMac and Macbook. On the first load it displays only Iwatch, Smartphone and iMac. After reload it shows now iWatch, Tablet and Smartphone. The problems is that not all the icons for each type of device are loaded and randomly switch in order the ones which are displayed.

first load
enter image description here

Details Url of the website: (https://thesmartphone.nl/reparatie-aanmelden)

What i did do
I tried to add new types on the backend for example iPad en iPhone linked to devices. I doesn’t display this.
I tried to change the url of the url of Smartphone, Tablet the same issue.
Further I checked my expire headers, cache flushed still the same issue.

I expected that it fix my problem and the icons would load at first load and displayed correctly

How Can I fix that all the icons of categories (Smartphone etc) are loaded on the first load.

Does not show values and categories

This is a proposal calculator, the problem is this.
When you calculate manually, everything works, but when you choose a template, it doesn’t work:

  1. After selecting the template, it does not show values in input fields picked from product mysql table.
  2. Shows only one selected category and not all. (I cannot select other categories).
  3. It shows only one selected product not all what in category (I cannot select other products).
    But here it does not work properly only with the selection of templates.

I added photo for visual more explain.

my logic is not enough to complete this task.

index.php

session_start();
include_once 'config/database.php'; 
include 'languages/language.php'; 
include 'assets/session.php'; 



$query = "SELECT * FROM products";
$result = mysqli_query($conn, $query);


$products = array();


if ($result) {
    while ($row = mysqli_fetch_assoc($result)) {
        $products[] = $row;
    }
} else {
    
    echo "Error: " . mysqli_error($conn);
}



$products_json = json_encode($products);



$query = "SELECT DISTINCT template_name FROM proposal_templates";
$templateResult = mysqli_query($conn, $query);

$templates = array();
if ($templateResult) {
    while ($row = mysqli_fetch_assoc($templateResult)) {
        $templates[] = $row['template_name'];
    }
} else {
    echo "Error: " . mysqli_error($conn);
}

?>

<?php include 'assets/header.php'; ?>

<body class="bg-gray-100">
    <?php include 'assets/nav.php'; ?>

    <div class="container mx-auto mt-8 pl-2">
        <div class="mb-6">
            <h2 class="text-xl font-semibold mb-3">Proposal calculator</h2>
            <button class="mb-3 bg-green-500 hover:bg-green-700 text-white font-bold rounded add-row-btn py-1 px-3 rounded">Add</button>
            <select name="templates" class="rounded py-1 px-3 border border-gray-400 px-4 py-2" id="template-dropdown">
                <option disabled selected>Select template</option>
                <?php foreach ($templates as $template): ?>
                <option value="<?= htmlspecialchars($template) ?>"><?= htmlspecialchars($template) ?></option>
                <?php endforeach; ?>
            </select>

            <div class="overflow-x-auto">
                <div class="overflow-x-auto">
                    <table class="w-full table-auto" id="proposal-table">
                        <thead>
                            <tr class="bg-gray-200">
                                <th class="w-1/3 sm:w-1/6 lg:w-1/4 px-4 py-2 text-left border border-gray-400"><?php echo $lang['templates']['category']; ?></th>
                                <th class="w-1/2 sm:w-2/3 lg:w-3/4 px-4 py-2 text-left border border-gray-400"><?php echo $lang['templates']['product']; ?></th>
                                <th class="w-1/6 sm:w-1/6 lg:w-1/12 px-4 py-2 border border-gray-400"><?php echo $lang['templates']['quantity']; ?></th>
                                <th class="w-1/6 sm:w-1/6 lg:w-1/12 px-4 py-2 border border-gray-400"><?php echo $lang['templates']['unitprice']; ?></th>
                                <th class="w-1/6 sm:w-1/6 lg:w-1/12 px-4 py-2 border border-gray-400"><?php echo $lang['templates']['totalprice']; ?></th>
                                <th class="w-1/6 sm:w-1/6 lg:w-1/12 px-4 py-2 border border-gray-400"><?php echo $lang['templates']['withtax']; ?></th>
                                <th class="w-1/6 sm:w-1/6 lg:w-1/12 px-4 py-2 border border-gray-400"><?php echo $lang['templates']['discount']; ?></th>
                                <th class="w-1/6 sm:w-1/6 lg:w-1/12 px-4 py-2 border border-gray-400"><?php echo $lang['templates']['buyprice']; ?></th>
                                <th class="w-1/6 sm:w-1/6 lg:w-1/12 px-4 py-2 border border-gray-400"><?php echo $lang['templates']['b2bprice']; ?></th>
                                <th class="w-1/6 sm:w-1/6 lg:w-1/12 px-4 py-2 border border-gray-400"><?php echo $lang['templates']['specialprice']; ?></th>
                                <th class="w-1/6 sm:w-1/6 lg:w-1/12 px-4 py-2 border border-gray-400"><?php echo $lang['templates']['power']; ?></th>
                                <th class="w-1/6 sm:w-1/6 lg:w-1/12 px-4 py-2 border border-gray-400"><?php echo $lang['categories']['actions']; ?></th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr>
                                <td>
                                    <!-- category selection dropdown -->
                                    <select name="product_category" class="border border-gray-400 px-4 py-2 text-left w-full">
                                       <option disabled selected><?php echo $lang['products']['category_filter']; ?></option>
                                       <?php
                                        
                                        if (!empty($categories)) {
                                            foreach ($categories as $category) {
                                                echo '<option value="' . $category["name"] . '">' . $category["name"] . '</option>';
                                            }
                                        } else {
                                            echo '<option value="">' . $lang['products']['category_filter'] . '</option>';
                                        }
                                        ?>
                                    </select>
                                </td>
                                <td>
                                    <!-- Product selection dropdown -->
                                     <select class="form-select border border-gray-400 px-4 py-2 text-left w-full">
                                        
                                        <option disabled selected class="default-option"></option>
                                        <?php
                                        
                                        if (!empty($products)) {
                                            foreach ($products as $product) {
                                                echo '<option value="' . $product["id"] . '" class="product-option" style="display: none;">' . $product["product_name"] . '</option>';
                                            }
                                        }
                                        ?>
                                    </select>
                                </td>
                                <td class="px-1 py-2 text-center"><input type="text" class="quantity-input rounded w-16 text-center"></td>
                                <td class="px-1 py-2 text-center"><input type="text" class="sell-price-input rounded w-16 text-center bg-gray-200" readonly></td>
                                <td class="px-1 py-2 text-center"><input type="text" class="total-price-without-tax-input rounded w-24 text-center bg-gray-200" readonly></td>
                                <td class="px-1 py-2 text-center"><input type="text" class="total-price-with-tax-input rounded w-24 text-center bg-gray-200" readonly></td>
                                <td class="px-1 py-2 text-center"><input type="text" class="discount-input rounded w-24 text-center"></td>
                                <td class="px-1 py-2 text-center"><input type="text" class="buy-price-input rounded w-20 text-center bg-gray-200" readonly></td>
                                <td class="px-1 py-2 text-center"><input type="text" class="b2b-price-input rounded w-20 text-center bg-gray-200" readonly></td>
                                <td class="px-1 py-2 text-center"><input type="text" class="special-price-input rounded w-20 text-center bg-gray-200" readonly></td>
                                <td class="px-1 py-2 text-center"><input type="text" class="product-power-input rounded w-20 text-center bg-gray-200" readonly></td>
                                
                                <td class=" px-4 py-2 text-center">
                                    <button class="bg-red-500 hover:bg-red-700 text-white font-bold rounded delete-row-btn py-1 px-3 rounded">-</button>
                                </td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            </div>
            
<div class="mt-8 flex justify-start">
    <div>
        <label class="text-sm">Total Price Without Tax</label>
        <input type="text" class="total-price-without-tax rounded text-sm" readonly>
    </div>
    <div class="ml-2 sm:ml-4">
        <label class="text-sm">Total Tax (21%)</label>
        <input type="text" class="total-tax rounded text-sm" readonly>
    </div>
    <div class="ml-2 sm:ml-4">
        <label class="text-sm">Total Price With Tax</label>
        <input type="text" class="total-price-with-tax rounded text-sm" readonly>
    </div>    
    <div class="ml-2 sm:ml-4">
        <label class="text-sm">Support</label>
        <input type="text" class="support rounded text-sm" readonly>
    </div>
    <div class="ml-2 sm:ml-4">
        <label class="text-sm">Price with support</label>
        <input type="text" class="fullsupport rounded text-sm" readonly>
    </div>
    <div class="ml-2 sm:ml-4">
        <label class="text-sm">Total Discount</label>
        <input type="text" class="total-discount rounded text-sm" readonly>
    </div>
    <div class="ml-2 sm:ml-4">
        <label class="text-sm">Discount Percentage</label>
        <input type="text" class="total-discount-percentage rounded text-sm" readonly>
    </div>
    <div class="ml-2 sm:ml-4">
        <label class="text-sm">Total Power</label>
        <input type="text" class="total-power rounded text-sm" readonly>
    </div>
</div>


        </div>
    </div>

    <script src="assets/js/jquery.min.js"></script> <!-- jQuery v3.5.1 | (c) JS Foundation and other contributors | jquery.org/license */ -->
    <script src="assets/js/flowbite.min.js"></script>
    <script src="assets/js/session.js"></script>
    <script>
$(document).ready(function() {
    
    function storeOriginalSellPrice(row, originalSellPrice) {
        row.data('original-sell-price', originalSellPrice);
    }

    
    function fetchCategories(categoryDropdown) {
        $.ajax({
            type: "GET",
            url: "fetch_categories.php",
            success: function(response) {
                categoryDropdown.html(response);
                fetchProducts(categoryDropdown);
            }
        });
    }

    
    function fetchProducts(categoryDropdown) {
        var category = categoryDropdown.val();
        var productDropdown = categoryDropdown.closest('tr').find('select.form-select');

        $.ajax({
            type: "POST",
            url: "get_products_by_category.php",
            data: { category: category },
            success: function(response) {
                productDropdown.html(response);
                productDropdown.prop('disabled', false);
            }
        });
    }
    
$(document).ready(function() {
    $('#template-dropdown').change(function() {
        var templateName = $(this).val();
        $.ajax({
            type: "POST",
            url: "fetch_template_rows.php",
            dataType: "json",
            data: {templateName: templateName},
            success: function(rows) {
                $("#proposal-table tbody").empty();
                rows.forEach(function(row) {
                    var newRow = $('<tr>').append(
                        $('<td>').append(
                            $('<select>').attr({'name': 'product_category', 'class': 'border border-gray-400 px-4 py-2 text-left w-full'}).append($('<option>').val(row.product_category).text(row.product_category))
                        ),
                        $('<td>').append(
                            $('<select>').attr({'class': 'form-select border border-gray-400 px-4 py-2 text-left w-full'}).append($('<option>').val(row.product_name).text(row.product_name))
                        ),
                        $('<td>').append($('<input>').attr({'type': 'text', 'class': 'quantity-input rounded w-16 text-center'}).val(row.product_quantity)),
                        $('<td>').append($('<input>').attr({'type': 'text', 'class': 'unit-price-input rounded w-16 text-center'}).val(row.unit_price)), 
                        $('<td>').append($('<input>').attr({'type': 'text', 'class': 'total-price-without-tax-input rounded w-24 text-center bg-gray-200', 'readonly': true})), 
                        $('<td>').append($('<input>').attr({'type': 'text', 'class': 'total-price-with-tax-input rounded w-24 text-center bg-gray-200', 'readonly': true})), 
                        $('<td>').append($('<input>').attr({'type': 'text', 'class': 'discount-input rounded w-16 text-center'}).val(row.product_discount)),
                        $('<td>').append($('<input>').attr({'type': 'text', 'class': 'buy-price-input rounded w-16 text-center bg-gray-200', 'readonly': true}).val(row.buy_price)),
                        $('<td>').append($('<input>').attr({'type': 'text', 'class': 'b2b-price-input rounded w-16 text-center bg-gray-200', 'readonly': true}).val(row.b2b_price)),
                        $('<td>').append($('<input>').attr({'type': 'text', 'class': 'special-price-input rounded w-16 text-center bg-gray-200', 'readonly': true}).val(row.special_price)),
                        $('<td>').append($('<input>').attr({'type': 'text', 'class': 'product-power-input rounded w-16 text-center bg-gray-200', 'readonly': true}).val(row.product_power)),
                        $('<td>').append($('<button>').attr({'type': 'button', 'class': 'bg-red-500 hover:bg-red-700 text-white font-bold py-1 px-3 rounded delete-row-btn'}).text('-'))
                    );
                    $("#proposal-table tbody").append(newRow);
                });

                
                updateTotalCalculations();
            }
        });
    });

    function updateTotalCalculations() {
        
        
    }

    
    $(document).on('click', '.delete-row-btn', function() {
        $(this).closest('tr').remove();
        updateTotalCalculations();
    });
});

$(document).ready(function() {
    $('#template-dropdown').change(function() {
        var templateName = $(this).val();
        $.ajax({
            type: "POST",
            url: "fetch_template_rows.php",
            dataType: "json",
            data: {templateName: templateName},
            success: function(rows) {
                $("#proposal-table tbody").empty();
                rows.forEach(function(row) {
                    var newRow = $('<tr>').append(
                        $('<td>').append(
                            $('<select>').attr({'name': 'product_category', 'class': 'border border-gray-400 px-4 py-2 text-left w-full'}).append($('<option>').val(row.product_category).text(row.product_category))
                        ),
                        $('<td>').append(
                            $('<select>').attr({'class': 'form-select border border-gray-400 px-4 py-2 text-left w-full'}).append($('<option>').val(row.product_name).text(row.product_name))
                        ),
                        $('<td>').append($('<input>').attr({'type': 'text', 'class': 'quantity-input rounded w-16 text-center'}).val(row.product_quantity)),
                        $('<td>').append($('<input>').attr({'type': 'text', 'class': 'unit-price-input rounded w-16 text-center bg-gray-200', 'readonly': true}).val(row.unit_price)), 
                        $('<td>').append($('<input>').attr({'type': 'text', 'class': 'total-price-without-tax-input rounded w-24 text-center bg-gray-200', 'readonly': true})), 
                        $('<td>').append($('<input>').attr({'type': 'text', 'class': 'total-price-with-tax-input rounded w-24 text-center bg-gray-200', 'readonly': true})), 
                        $('<td>').append($('<input>').attr({'type': 'text', 'class': 'discount-input rounded w-16 text-center'}).val(row.product_discount)),
                        $('<td>').append($('<input>').attr({'type': 'text', 'class': 'buy-price-input rounded w-16 text-center bg-gray-200', 'readonly': true}).val(row.buy_price)),
                        $('<td>').append($('<input>').attr({'type': 'text', 'class': 'b2b-price-input rounded w-16 text-center bg-gray-200', 'readonly': true}).val(row.b2b_price)),
                        $('<td>').append($('<input>').attr({'type': 'text', 'class': 'special-price-input rounded w-16 text-center bg-gray-200', 'readonly': true}).val(row.special_price)),
                        $('<td>').append($('<input>').attr({'type': 'text', 'class': 'product-power-input rounded w-16 text-center bg-gray-200', 'readonly': true}).val(row.product_power)),
                        $('<td>').append($('<button>').attr({'type': 'button', 'class': 'bg-red-500 hover:bg-red-700 text-white font-bold py-1 px-3 rounded delete-row-btn'}).text('-'))
                    );
                    $("#proposal-table tbody").append(newRow);
                });

                
                updateTotalCalculations();

                
                fetchCategoriesAndProducts(templateName);
            }
        });
    });

    
    function fetchCategoriesAndProducts(templateName) {
        $.ajax({
            type: "POST",
            url: "fetch_categories_and_products.php", 
            dataType: "json",
            data: {templateName: templateName},
            success: function(data) {
                
                var categoryDropdown = $('select[name="product_category"]');
                categoryDropdown.empty();
                categoryDropdown.append($('<option disabled selected>').text('Select category'));
                data.categories.forEach(function(category) {
                    categoryDropdown.append($('<option>').val(category).text(category));
                });

                
                var productDropdown = $('select.form-select');
                productDropdown.empty();
                productDropdown.append($('<option disabled selected>').text('Select product'));
                data.products.forEach(function(product) {
                    productDropdown.append($('<option>').val(product.id).text(product.name));
                });
            }
        });
    }

    
});


$(document).on('change', 'select[name="product_category"]', function() {
    
    fetchProducts($(this));
});

$(document).on('input', '.quantity-input, .discount-input', function() {
    var row = $(this).closest('tr');
    updateTotals(row);
});

    
    function updateProductInfo(selectedOption) {
        var row = selectedOption.closest('tr');
        var sellPrice = parseFloat(selectedOption.data('sell-price'));

        
        storeOriginalSellPrice(row, sellPrice);

        
        row.find('.product-power-input').val(selectedOption.data('product-power'));
        row.find('.buy-price-input').val(selectedOption.data('buy-price'));
        row.find('.b2b-price-input').val(selectedOption.data('b2b-price'));
        row.find('.special-price-input').val(selectedOption.data('special-price'));
        row.find('.sell-price-input').val(sellPrice);

        
        updateTotals(row);
    }

    
    function updateTotals(row) {
        var quantity = parseInt(row.find('.quantity-input').val()) || 0;
        var sellPrice = parseFloat(row.find('.sell-price-input').val()) || 0;
        var discount = parseFloat(row.find('.discount-input').val()) || 0;

        
        var originalSellPrice = parseFloat(row.data('original-sell-price'));

        
        var discountedPrice = originalSellPrice - discount;

        
        var totalPriceWithoutTax = quantity * discountedPrice;

        
        var totalPriceWithTax = totalPriceWithoutTax * 1.21;

        
        row.find('.total-price-without-tax-input').val(totalPriceWithoutTax.toFixed(2));
        row.find('.total-price-with-tax-input').val(totalPriceWithTax.toFixed(2));
        row.find('.sell-price-input').val(discountedPrice.toFixed(2));

        
        updateTotalCalculations();
    }

    
    $(document).on('input', '.quantity-input, .discount-input', function() {
        var row = $(this).closest('tr');
        updateTotals(row);
    });

    
    $(document).on("change", "select.form-select", function() {
        updateProductInfo($(this).find('option:selected'));
    });

    
    $(document).on("change", "select[name='product_category']", function() {
        fetchProducts($(this));
    });

    
    $(".add-row-btn").click(function() {
        var newRow = '<tr>' +
                        '<td>' +
                            '<select name="product_category" class="border border-gray-400 px-4 py-2 text-left w-full">' +
                                '<option disabled selected><?php echo $lang['products']['category_filter']; ?></option>' +
                            '</select>' +
                        '</td>' +
                        '<td>' +
                            '<select class="form-select border border-gray-400 px-4 py-2 text-left w-full" disabled>' +
                                '<option disabled selected><?php echo $lang['products']['select_product']; ?></option>' +
                            '</select>' +
                        '</td>' +
                        '<td class="px-1 py-2 text-center"><input type="text" class="quantity-input rounded w-16 text-center"></td>' +
                        '<td class="px-1 py-2 text-center"><input type="text" class="rounded w-16 text-center sell-price-input bg-gray-200" readonly></td>' +
                        '<td class="px-1 py-2 text-center"><input type="text" class="total-price-without-tax-input rounded w-24 text-center bg-gray-200" readonly></td>' +
                        '<td class="px-1 py-2 text-center"><input type="text" class="total-price-with-tax-input rounded w-24 text-center bg-gray-200" readonly></td>' +
                        '<td class="px-1 py-2 text-center"><input type="text" class="discount-input rounded w-24 text-center"></td>' +
                        '<td class="px-1 py-2 text-center"><input type="text" class="buy-price-input rounded w-20 text-center bg-gray-200" readonly></td>' +
                        '<td class="px-1 py-2 text-center"><input type="text" class="rounded w-20 text-center b2b-price-input bg-gray-200" readonly></td>' +
                        '<td class="px-1 py-2 text-center"><input type="text" class="rounded w-20 text-center special-price-input bg-gray-200" readonly></td>' +
                        '<td class="px-1 py-2 text-center"><input type="text" class="rounded w-20 text-center product-power-input bg-gray-200" readonly></td>' +
                        '<td class="px-4 py-2 text-center">' +
                            '<button class="bg-red-500 hover:bg-red-700 text-white font-bold rounded delete-row-btn py-1 px-3 rounded">-</button>' +
                        '</td>' +
                    '</tr>';
        var newRowElement = $(newRow);
        $("#proposal-table tbody").append(newRowElement);

        
        var categoryDropdown = newRowElement.find('select[name="product_category"]');
        fetchCategories(categoryDropdown);
    });

    
    $(document).on("click", ".delete-row-btn", function() {
        $(this).closest("tr").remove();
        updateTotalCalculations(); 
    });

    
    $(document).on("change", ".support-checkbox", function() {
        updateTotalCalculations();
    });

    
    $("select[name='product_category']").each(function() {
        fetchCategories($(this));
    });

    
    updateTotalCalculations();
});


function updateTotalCalculations() {
    var totalWithoutTax = 0;
    var totalWithTax = 0;
    var totalTax = 0;
    var totalDiscount = 0;
    var totalPower = 0;
    var support = 0;

    $('#proposal-table tbody tr').each(function() {
        var totalPriceWithoutTax = parseFloat($(this).find('.total-price-without-tax-input').val()) || 0;
        var totalPriceWithTax = parseFloat($(this).find('.total-price-with-tax-input').val()) || 0;
        var discount = parseFloat($(this).find('.discount-input').val()) || 0;
        var power = parseFloat($(this).find('.product-power-input').val()) || 0;
        var quantity = parseFloat($(this).find('.quantity-input').val()) || 0;

        totalWithoutTax += totalPriceWithoutTax;
        totalWithTax += totalPriceWithTax;
        totalTax += totalPriceWithTax - totalPriceWithoutTax;
        totalDiscount += discount * quantity;
        totalPower += power * quantity / 1000;
    });

    

        support = (totalPower <= 10) ? totalPower * 323 : (10 * 323);

        
        $('.support').val(support.toFixed(2));


    
    $('.support').val(support.toFixed(2));

    
    var priceWithSupport = totalWithTax - support;

    
    $('.fullsupport').val(priceWithSupport.toFixed(2));

    $('.total-price-without-tax').val(totalWithoutTax.toFixed(2));
    $('.total-price-with-tax').val(totalWithTax.toFixed(2));
    $('.total-tax').val(totalTax.toFixed(2));
    $('.total-discount').val(totalDiscount.toFixed(2));
    $('.total-discount-percentage').val(((totalDiscount / (totalDiscount + totalWithTax)) * 100).toFixed(2) + '%');
    $('.total-power').val(totalPower.toFixed(2));
}



    </script>
</body>
</html>

mysql:

    Table: "proposal_templates"
    All columns:(
      `id` int(11) NOT NULL,
      `template_name` 
      `product_category` FOREIGN KEY (category table, name)
      `product_name` FOREIGN KEY (products table, product_name)
      `product_quantity` 
      `product_discount` 
    )

    Table: "products"
All columns: (
    id INT AUTO_INCREMENT PRIMARY KEY,
    product_code VARCHAR(255) NOT NULL,
    product_name VARCHAR(255) NOT NULL,
    product_power VARCHAR(255) NOT NULL,
    product_category VARCHAR(49) NOT NULL,
    product_quantity VARCHAR(49) NOT NULL,
    product_status VARCHAR(49) NOT NULL,
    buy_price DECIMAL(10, 2),
    sell_price DECIMAL(10, 2),
    b2b_price DECIMAL(10, 2),
    special_price DECIMAL(10, 2),
    product_description TEXT,
    FOREIGN KEY (product_category) REFERENCES categories(name)
)

Angular 11 – HostListener event listen for ctrl + mouse left click?

Is there a way to listen for ctrl + left mouse click event.

I’m able to capture the ctrl click but how do i combine it with the left mouse click.

 @HostListener('document:keyup', ['$event'])
    handleKeyboardEvent(event: KeyboardEvent) {
    console.log(event.key)
    if (event.key == 'Control'){
      console.log(true)
     }
    }

this is what I have for the ctrl click.
Thank you.

The .submit() function in JavaScript does not immediately submit the form on safari, leading to fields disabled after this is called not getting sent

I have a form on a website. Some of the html fields (they are <select> fields, if that is relevant) on this form are disabled to prevent the user sending changing the values in them, however, these need to be sent up to the server when the user submits the form. To do this, there is some JavaScript on the page that intercepts the submission event and stops it, enables the fields, submits the form, and then (for reasons I don’t think are relevant) disables the fields again:

function toggleDisableOnFields(areDisabled) {
  document.getElementsByName("x")[0].disabled = areDisabled;
  // other fields get enabled here too
}
const form = document.getElementById("form");

form.addEventListener("submit", (e) => {
  e.preventDefault();

  toggleDisableOnFields(false);
  form.submit();
  toggleDisableOnFields(true);
});

On Chrome and Firefox, this works fine. The fields get enabled, the form gets submitted with their data included, and then the fields are successfully disabled again afterwards.

The issue is on Safari. The fields are enabled, the form submission happens, and the fields are disabled, but it seems as though the form only actually gets sent after they are disabled. Thus, their data is not sent up to the server as they are disabled by the time the request is sent.

If I remove the penultimate line of code:

toggleDisableOnFields(true);

Then Safari sends the form complete with the data in these fields, confirming to me that the form is getting sent only after this line has run.

The question:
Why does the .submit() function send the form immediately on some browsers, but not on Safari?

Custom conditional file extensions in react project

I have a React project (specifically a React Native for Web with expo) that I’d like to have custom file extensions so that I can switch which files are compiled depending on a setting, e.g. an environment variable.

So I have three files

foo.ts
foo.company1.ts
foo.company2.ts

So for example, if CUSTOMER=company1, then only foo.company1.ts will be compiled and the other two will be ignored. import * from './foo' would import foo.company1.ts

What is the best way to achieve this?

Technique to prevent navigating back/forward in browser, or revealing Mac widgets panel, when swiping left/right to horizontally scroll?

When I swipe left or right with 2 fingers to scroll an HTML element left or right (on my Macbook Pro), like in this Google Ads Keyword Planner UI, more often than not (like 70-80% of the time), it either:

  1. Invokes and shows the Mac widgets panel on the right, if I swipe left (i.e. “pulling” it out from the right).
  2. Navigates back to the previous URL (if I try to scroll left), or navigates forward (if I try to swipe right).

enter image description here

It is really annoying, and I would like to prevent this behavior at the browser level ideally, so users of the website don’t have to, for example, turn off the Mac widgets panel from ever opening on scroll left. I would like to figure out what measures I can take in the browser to prevent this behavior from ruining the functionality of horizontal scroll.

My use case for horizontal scroll is a piano or guitar fretboard, stretching from left to right. It needs to be horizontal because I might show multiple fretboards stacked. Then you can see like 12 frets at a time (or less on mobile perhaps), and scroll left or right to see the 20+ total frets. It should be as easy as “swipe with 2 fingers left or right” to scroll, but this thing with the navigation back/forward or the widgets panel constantly popping up is really annoying and getting in the way.

The problem with disabling the widgets panel or navigation left/right, is that users may be used to that feature and rely on it for everything else (I in particular don’t, but who knows). So I think that only when you hover over the piano/fretboard should that “native feature” be disabled on scroll left/right. And if you get to the end of scrolling, it doesn’t ever trigger navigation or widgets panel popup.

  1. Navigation disabling seems possible so long as the scroll event is blocked within the browser.
  2. Is it possible to disable the widgets panel popup in particular? I am not sure I can block it from hitting the desktop functionality.

And after that, my question is, what events should I be watching and handling (in JavaScript), to make this happen in particular?

EditorJS. Telegram and TikTok embed does not working

Is there a way to insert embed from telegram or tiktok by straight url?

Right now my code looks like

function insertEmbed(service, link) {
    let embed = link

    if (service === "youtube") {
        const id = new URLSearchParams(new URL(link).search).get("v")
        embed = `https://www.youtube.com/embed/${id}`
    } else if (service === "instagram") {
        link = link.split("?").shift()
        embed = `${link}${link.endsWith("/") ? "embed" : "/embed"}`
    } else if (service === "twitter") {
        embed = `https://twitframe.com/show?url=${encodeURIComponent(link)}`
    }

    editor.blocks.insert("embed", {
        service: service,
        source: link,
        embed: embed,
    }, null, embedBlockId.value === -1 ? null : embedBlockId.value, true)

    embedBlock.value?.classList.remove("active")
}

Because Embed doesn’t have telegram and tiktok as internal services, documentation suggest to write them by your own

So, in config I have that:

embed: {
    class: Embed,
    inlineToolbar: true,
    config: {
        services: {
            youtube: true,
            twitter: true,
            instagram: true,
            telegram: {
                regex: /https?://t.me/([a-zA-Z0-9_]+)/(d+)/,
                embedUrl: "https://t.me/<%= remote_id %>",
                html: tgHtml,
                height: 600,
                width: 800,
            },
        }
    },
},

But in Editor block I don’t get iframe block with post or something, only caption

Is there any libs, plugins or anything else?
Maybe I missing something?

For loop is not being run

(I’m coding a basic version of the chrome dino game for context)
In my code, I have a 15 millisecond loop, and every six loops the following code is supposed to be run:

if(timer%6==0){
//changes the visible score value
    score++;sss.innerHTML=score;untilnextcactus=untilnextcactus-1;
//until next cactus is randomly generated elsewhere
    if(untilnextcactus==0){
        nextcactus = pickcactus();
        cactusonscreen++;
        document.getElementById("cactus"+cactusonscreen).style.right=-100;
    }
//this is the part that doesn't work
    for(let i = 1; i<cactusonscreen; i++){
        document.getElementById("cactus"+i).offsetRight =   document.getElementById("cactus"+i).offsetRight + speed;
    }
}
//no, this isn't supposed to be in the loop
timer++;

Everything up until the for loop is run properly, but the for loop doesn’t ever seem to run.
(I am on a school chromebook and cannot access console, please do not say “use a console.log in the loop”)

Any ideas?

(Edit: I’m in school right now so I won’t be able to respond until about 11:20a EST)

Push notification in ionic/angular

how can I implement push messages through onsignal, for an app made in ionic/angular, so that users can be notified when there is a status change in their order.
I have read the onsignal documentation and it says the following:

const notification = new OneSignal.Notification();
notification.app_id = app.id;
// Name property may be required in some case, for instance when sending an SMS.
notification.name = "test_notification_name";
notification.contents = {
  en: "Gig'em Ags"
}

// required for Huawei
notification.headings = {
  en: "Gig'em Ags"
}
const notification = await client.createNotification(notification); but it doesn't work

how to receive data from an async function in a different component [Next JS]

i am trying to use the new Gemini api, i am using server actions to get the user message from the input and sending that message to the gemini function which returns the response as text.

"use server";

import runChat from "@/utils/gemini";

export async function handleSubmit(formData) {
  const prompt = formData.get("promptInput");
  const res = await runChat(prompt);
  return res;
}

Now i am trying to return the response from the handleSubmit function and get the text in an html div

import React from 'react'

const PromptBox = () => {
  return (
    <div className="promptBox h-[80vh] bg-[#1E1E1E] m-4 rounded-lg p-4 font-medium">
      // I WANT THE RESPONSE TEXT TO COME HERE
    </div>
  );
}

export default PromptBox

This is what ive tried but its not working.

import { handleSubmit } from '@/actions/action';
import React from 'react'

const PromptBox = () => {
  const response = handleSubmit
  console.log(response)
  return (
    <div className="promptBox h-[80vh] bg-[#1E1E1E] m-4 rounded-lg p-4 font-medium">
      {response}
    </div>
  );
}

export default PromptBox

im very sorry if there are any stupid mistakes im very new to react/nextJs

Nightwatchjs zooming out of browser

I am trying to zoom out on the browser to have the browser size set to 50%. Is there anyway in Nightwatch that this can be done?

I have tried to use

browser.keys([browser.Keys.CONTROL, "browser.Keys.SUBTRACT", browser.Keys.NULL]) 

However this does not seem to work. Has anyone tried to do this before or know how to do this?

Data classes for Firebase and Firebase Admin

I was writing a project using firebase firestore, and I made some data classes, so that I could access the data in a better way. The problem I’m facing is that the firestore classes are not compatible with the admin ones (and vice versa I think).
Here is the code:

export class User {
    email: string;
    displayName?: string;
    tokens: DocumentReference<Token>[];
    admin: boolean = false;

    constructor({
        email,
        displayName,
        admin,
        tokens,
    }: {
        email: string;
        displayName?: string;
        admin?: boolean;
        tokens?: DocumentReference<Token>[];
    }) {
        this.email = email;
        this.displayName = displayName;
        this.tokens = tokens ?? [];
        this.admin = admin ?? false;
    }

    static collectionName = 'users';
    static converter: FirestoreDataConverter<User> = {
        toFirestore: (user: User) => {
            return { ...user };
        },
        fromFirestore: (snapshot): User => {
            const data = snapshot.data();
            return new User({
                email: data.email,
                displayName: data.displayName,
                tokens: data.tokens ?? [],
                admin: data.admin,
            });
        },
    };
}

export class Token {
    device?: number;
    devices: number;
    expiration?: Timestamp;
    owner: DocumentReference<User>;
    project: DocumentReference<Project>;
    tier: number;

    constructor({
        owner,
        project,
        device,
        devices,
        expiration,
        tier,
    }: {
        owner: DocumentReference<User>;
        project: DocumentReference<Project>;
        device?: number;
        devices: number;
        expiration?: Timestamp;
        tier: number;
    }) {
        this.owner = owner;
        this.project = project;
        this.device = device;
        this.devices = devices;
        this.expiration = expiration;
        this.tier = tier;
    }

    static collectionName = 'tokens';
    static converter = {
        toFirestore: (token: Token) => {
            return { ...token };
        },
        fromFirestore: (
            snapshot: QueryDocumentSnapshot<DocumentData, DocumentData>,
        ): Token => {
            const data = snapshot.data();
            console.log(data);
            return new Token({
                device: data.device,
                devices: data.devices,
                expiration: data.expiration,
                owner: data.owner,
                project: data.project,
                tier: data.tier,
            });
        },
    };
}

export class Project {
    name: string;
    version?: string;
    tokens: DocumentReference<Token>[];
    tiers: number;

    constructor({
        name,
        version,
        tokens,
        tiers,
    }: {
        name: string;
        version?: string;
        tokens?: DocumentReference<Token>[];
        tiers: number;
    }) {
        this.name = name;
        this.version = version;
        this.tokens = tokens ?? [];
        this.tiers = tiers;
    }

    static collectionName = 'projects';
    static converter: FirestoreDataConverter<Project> = {
        toFirestore: (project: Project) => {
            return { ...project };
        },
        fromFirestore: (snapshot): Project => {
            const data = snapshot.data();
            return new Project({
                name: data.name,
                version: data.version,
                tokens: data.tokens ?? [],
                tiers: data.tiers,
            });
        },
    };
}

What I’m trying to do is to write these classes once, instead of writing one version for the normal and one for the admin one.

What is the syntax [soemthing] and […something] supposed to do/mean

While studying about transpiling and how is
<div> <h1>Hello there</h1>  </div>
for example transpiled I met the arguments list for the React.createElement()
React.createElement( type, [props], [...children] )
Now, I thought props should be an object, and children should be a spread of objects. So I went to check what the syntax for [soemthing] does and found that it’s something else called destructuring assignment, and it does something different.

I tried testing it with simple arrays and objects and came up to the conclusion that it takes the first element of soemthing that has to be iteratable. And once you use the spread operator it takes everything. However, in the React.createElement, props should be an object.
So I hope someone explains to me what exactly is the [something] operator, and how is [props] a javascript object.