Last element of a loop not getting acted as desired, for no apparent reason

In a scroll function, i want for a variable to get the id value of a element of a loop, under a certain condition, and after the loop, for that element to get its font-weight as bold. After another scroll event, the element choosen may change and the old one gets its font-weight back to normal.

The loop itself works well, the variable gets the id value, but after the loop, i cant get the last element of the loop to change its font weight when the variable gets its id value.

I can only get it to work if i hard-code it, but thats not a ideal solution.

I have tried other types of css, same problem. For some reason, if i take out the back to normal font-weight line, it does get to change its font-weight to bold. The debugger doesnt say anything.

This is the page code

<div id="barrl2">
    <span id="meta0b">properties</span>
    <span id="meta1b">properties</span>
    <span id="meta2b">properties</span>
    <span id="meta3b">properties</span>
    <span id="meta4b">properties</span>
    <span id="meta5b">properties</span>
</div>
<div id="main3">
    <div id="meta0" class="tit1">properties</div>   
    <div id="meta1" class="tit2">properties</div>
    <div id="meta2" class="tit2">properties</div>
    <div id="meta3" class="tit2">properties</div>   
    <div id="meta4" class="tit2">properties</div>
    <div id="meta5" class="tit2">properties</div>
</div>
        
<script>
    assinala(6);
</script>

This is the function, with the hard code part inactive

function assinala(n) {
    $(document).ready(function(){
    assi = "#meta0b";
    $(assi).css('font-weight', 'bold');
    $(window).scroll(function () {  
            for (let i = 0; i < n; i++) {           
                if ($(window).scrollTop() >= $("#meta" + i).offset().top) {
                    assi = "#meta" + i + "b";
                    }
                    $(assi).css('font-weight', 'bold');
                    if ($("#meta" + i + "b") != assi) {
                        $("#meta" + i + "b").css('font-weight', 'normal');        
                    }                       
        }
        /*
        if ($(window).scrollTop() >= $("#meta5").offset().top) {
                $("#meta5b").css('font-weight', 'bold');
                }
                */      
    })
    }); 
}

How to authenticate a script to use with Google Apps Script

I’m doing a project to send info gathered in an HTML form to a Google Spreadsheet. I’ve found a very nice tutorial on how to do so. These are the files and scripts I’m using:

1. HTML file

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="Google Sheet.css">
  </head>

  <body>
    <div class="container">
      <form method="post" action="URL of the Web App" name="contact-form">
        <h4>Contact Us</h4>
        <input type="text" name="your-name" placeholder="Name">
        <input type="text" name="your-number" placeholder="Number">
        <input type="email" name="your-email" placeholder="Email">
        <textarea name="message" rows="7" placeholder="Your Message"></textarea>
        <input type="submit" value="Submit" id="submit">
      </form>
    </div>
  </body>

  <script src="Google Sheet.js"></script>

</html>

2. JS file

const scriptURL = 'URL of the Web App'

const form = document.forms['contact-form']

form.addEventListener('submit', e => {
  
  e.preventDefault()
  
  fetch(scriptURL, { redirect: 'follow', method: 'POST', body: new FormData(form)})
  .then(response => alert("Thank you! Form is submitted" ))
  .then(() => { window.location.reload(); })
  .catch(error => console.error('Error!', error.message))
})

3. Script in Google Apps Scripts

const sheetName = ''
const scriptProp = PropertiesService.getScriptProperties()

function intialSetup () {
  const activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet()
  scriptProp.setProperty('key', activeSpreadsheet.getId())
}

function doPost (e) {
  const lock = LockService.getScriptLock()
  lock.tryLock(10000)

  try {
    const doc = SpreadsheetApp.openById(scriptProp.getProperty('key'))
    const sheet = doc.getSheetByName(sheetName)

    const headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0]
    const nextRow = sheet.getLastRow() + 1

    const newRow = headers.map(function(header) {
      return header === 'Date' ? new Date() : e.parameter[header]
    })

    sheet.getRange(nextRow, 1, 1, newRow.length).setValues([newRow])

    return ContentService
      .createTextOutput(JSON.stringify({ 'result': 'success', 'row': nextRow }))
      .setMimeType(ContentService.MimeType.JSON)
  }

  catch (e) {
    return ContentService
      .createTextOutput(JSON.stringify({ 'result': 'error', 'error': e }))
      .setMimeType(ContentService.MimeType.JSON)
  }

  finally {
    lock.releaseLock()
  }
}

Description of the issue

If I deploy the app as “Who has access” –> “Anyone”, everything works fine. But I want this form to be accesible only by me.

So I changed the deploy to be “Who has access” –> “Only Me” and the script doesn’t work.

If I remove the js part (that handles errors and displays a nice window in the screen when successful) I works again.

So my guess is that I need to pass some sort of authorization toket in the fetch. But I don’t know how or where to get this tokent.

Thanks for your help.

Is there a Firefox-compatible way to modify @attributes using Javascript?

I like to use CSS @attributes in my websites. Unfortunately, these don’t play well with JavaScript in Firefox; the standard way to modify them is document.documentElement.attributeStyleMap.set(‘–attributeName’, ‘value’), and Firefox doesn’t support attributeStyleMap (and probably never will, given that this has been a known issue for 9+ years.)

Does anyone know an alternative way to modify @attributes using JavaScript?

Sharepoint Lists’ “Image” Column generated by REST API Not Displaying Image Preview

I have the following method that creates a “hyperlinkOrPicture” column as it is referred to by the Graph API, which is essentially just a URL. The Sharepoint API refers to the column type by the FieldTypeKind value.

async function createHyperlinkOrImage(sharePointAPIaccessToken, listId, columnName, isImage) {
    const sharePointApiUrl = `${process.env.SITE_URL}/_api/web/lists(guid'${listId}')/fields`;

    // FieldTypeKind = 11 => URL type
    // DisplayFormat = 0 => Hyperlink, 1 => Image
    const sharePointPayload = {
        "__metadata": { "type": "SP.FieldUrl" },
        "Title": columnName,
        "FieldTypeKind": 11,
        "DisplayFormat": isImage ? 1 : 0,
    };

    try {
        const response = await fetch(sharePointApiUrl, {
            method: "POST",
            headers: {
                Authorization: `Bearer ${sharePointAPIaccessToken}`,
                Accept: "application/json;odata=verbose",
                "Content-Type": "application/json;odata=verbose",
            },
            body: JSON.stringify(sharePointPayload),
        });
        // error handling 
    }
       
}

The columns are created properly. It handles when the column is purely a hyperlink (with isImage set as 0), the problem is with Image columns (isImage set as 1): uploading an image, it is not rendered in the cell, which does happen when creating a column manually: “Add Column” -> “Image”. I’ve included a side by side comparison of the two below:

enter image description here

To the left, is the column generated via the REST API, and to the right is through the UI.

One big difference, which I believe is the reason for why this is happening is when viewing the properties of the columns, we see that the REST API generated images column does not specify the ‘type’.

When opening Column Settings I see the following:

enter image description here

And for the manually set column:

enter image description here

Lastly, I noticed that I am unable to add the images directly when on the Add new item page:
enter image description here
enter image description here

I cannot tell what Sharepoint is recognizing the column as, clearly from the image icon next to the column name it should be rendered as an Image Column. However, it is behaving as a hyperlink column.

Thank you!

uncaughtException: RangeError: Array buffer allocation failed Next.js

I got an error:

RangeError: Array buffer allocation failed
    at new ArrayBuffer (<anonymous>)
    at new Uint8Array (<anonymous>)
 ⨯ uncaughtException: RangeError: Array buffer allocation failed
    at new ArrayBuffer (<anonymous>)
    at new Uint8Array (<anonymous>)
 ⨯ uncaughtException:  RangeError: Array buffer allocation failed
    at new ArrayBuffer (<anonymous>)
    at new Uint8Array (<anonymous>)

It’s in a new next.js project i only coded the component Navbar, I already tried to make another nextjs application and update to the latest version. But that couldn’t fix my problem The code is below:

'use client';

import { useEffect } from 'react';
import Link from 'next/link';
import Image from 'next/image';

export default function Navbar() {
    useEffect(() => {
        const menuButton = document.querySelector('[aria-controls="mobile-menu"]');
        const mobileMenu = document.getElementById('mobile-menu');

        console.log('Menu button and mobile menu elements:', menuButton, mobileMenu);

        const toggleMenu = () => {
            console.log('Menu button clicked');
            mobileMenu.classList.toggle('hidden');
        };

        if (menuButton && mobileMenu) {
            menuButton.addEventListener('click', toggleMenu);
        }

        return () => {
            if (menuButton && mobileMenu) {
                menuButton.removeEventListener('click', toggleMenu);
            }
        };
    }, []);

    return (
        <div>
            <nav className="bg-primary-50">
                <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
                    <div className="flex items-center justify-between h-16">
                        <div className="flex items-center">
                            <Link className="text-xl font-semibold" href="/">
                                TimovC
                            </Link>
                        </div>
                        <div className="hidden md:block">
                            <div className="ml-10 flex items-baseline space-x-4">
                                <Link href="/portfolio">Portfolio</Link>
                                <Link href="/contact">Contact</Link>
                                <Link href="/klanten">Voor klanten</Link>
                            </div>
                        </div>
                        <div className="-mr-2 flex md:hidden">
                            <button
                                type="button"
                                className="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-white"
                                aria-controls="mobile-menu"
                                aria-expanded="false"
                            >
                                <span className="sr-only">Open menu</span>
                                <Image src="/mobileMenu.svg" alt="mobile menu" width={24} height={24} />
                            </button>
                        </div>
                    </div>
                </div>
                <div className="md:hidden hidden" id="mobile-menu">
                    <div className="px-2 pt-2 pb-3 space-y-1 space-x-4 sm:px-3">
                        <Link href="/portfolio">Portfolio</Link>
                        <Link href="/contact">Contact</Link>
                        <Link href="/klanten">Voor klanten</Link>
                    </div>
                </div>
            </nav>
        </div>
    );
};

I asked chatgtp for a solution but he said it has something to do with the memory but how could it, my friend is not having the problem.

I’m working on a laptop with the following specs:

  • Ram 16gb
  • CPU Ryzen 5 4000 series
  • 512 gb storage

I got the latest node installed.

It seems that the error appears when i get an error in my jsx i commented out my navbar so that isnt the main problem here i think

I’m out of solutions thats why this is my last resort.

SVG – Plotting a smooth path

I am trying to plot mathematical functions using SVG as the plotter by generating a path representing the function. Some of the functions, such as x^2 work fine, but more involved functions such as 1 / x tend to have issues with generating a smooth path. My objective is to keep on using SVG as the main plotter (i.e., not <canvas>) while generating smooth paths of any elementary function without an asymptote.

For reference, the majority of the path logic is based of [enxaneta’s answer](https://stackoverflow.com/a/62857298/10082415.

let smooth = 0.1;
let container = document.getElementById("svg");
let width = container.getAttribute("width");
let height = container.getAttribute("height");
// let xmin = 0;
// let xmax = 2 * Math.PI;
let xmin = 0;
let xmax = 10;
let ymin = -1;
let ymax = 1;

function f(x) {
  return 1 / x; //works for any elementary function without asymptote
}

let points = generatePoints(-10, 10, 100);
let thePath = document.getElementById("thePath");

thePath.setAttribute("d", drawCurve(points));
thePath.setAttribute("stroke-width", 2);
thePath.setAttribute("opacity", 1);
// thePath.setAttribute("stroke-linejoin", "miter-clip");
thePath.setAttribute("stroke-linecap", "circle");
thePath.setAttribute("stroke-linejoin", "round");
// thePath.setAttribute("stroke-dasharray", "35,10");
thePath.setAttribute("shape-rendering", "geometricPrecision"); //geometricPrecision, crispEdges

points.forEach((point) => {
  //plotSinglePoint(point.x, point.y);//uncomment to see indiviual points
});

/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////

function generatePoints(xMin, xMax, samples = 50) {
  result = [];
  let xInc = (xMax - xMin) / samples;
  for (let x = xMin; x < xMax; x += xInc) {
    let xVal = coordX(x);
    let yVal = coordY(f(x));
    let point = { x: xVal, y: yVal };
    if (isValidPoint(point)) {
      result.push(point);
      if (x % 2 == 0) {
        result.push(point);
      }
    }
  }
  return result;
}

function isValidPoint(point) {
  return 0 <= point.x && point.x <= width && 0 <= point.y && point.y <= height;
}

function plotSinglePoint(x, y, r = 3) {
  let svgns = "http://www.w3.org/2000/svg";
  let circle = document.createElementNS(svgns, "circle");
  circle.setAttributeNS(null, "cx", x);
  circle.setAttributeNS(null, "cy", y);
  circle.setAttributeNS(null, "r", r);
  circle.setAttributeNS(
    null,
    "style",
    "fill: magenta; stroke: red; stroke-width: 0px;"
  );
  container.appendChild(circle);
}

function controlPoints(p) {
  // given the points array p calculate the control points for the cubic Bezier curves

  var pc = [];
  for (var i = 1; i < p.length - 1; i++) {
    var dx = p[i - 1].x - p[i + 1].x; // difference x
    var dy = p[i - 1].y - p[i + 1].y; // difference y
    // the first control point
    var x1 = p[i].x - dx * smooth;
    var y1 = p[i].y - dy * smooth;
    var o1 = {
      x: x1,
      y: y1,
    };

    // the second control point
    var x2 = p[i].x + dx * smooth;
    var y2 = p[i].y + dy * smooth;
    var o2 = {
      x: x2,
      y: y2,
    };

    // building the control points array
    pc[i] = [];
    pc[i].push(o1);
    pc[i].push(o2);
  }
  return pc;
}

function drawCurve(p) {
  var pc = controlPoints(p); // the control points array

  let d = `M${p[0].x},${p[0].y}
Q${pc[1][1].x},${pc[1][1].y}, ${p[1].x},${p[1].y}
`;
  if (p.length > 2) {
    // central curves are cubic Bezier
    for (var i = 1; i < p.length - 2; i++) {
      d += `C${pc[i][0].x}, ${pc[i][0].y}, ${pc[i + 1][1].x}, ${
        pc[i + 1][1].y
      }, ${p[i + 1].x},${p[i + 1].y}`;
    }

    // the first & the last curve are quadratic Bezier
    var n = p.length - 1;
    d += `Q${pc[n - 1][0].x}, ${pc[n - 1][0].y}, ${p[n].x}, ${p[n].y}`;
  }
  return d;
}

function coordX(x) {
  return Math.round((width * (x - xmin)) / (xmax - xmin));
}
function coordY(y) {
  return Math.round(height * (1 - (y - ymin) / (ymax - ymin)));
}
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title></title>
    <meta name="description" content="" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="stylesheet" href="" />
  </head>
  <body>
    <svg
      id="svg"
      width="500"
      height="500"
      style="border: solid; fill: none; stroke: black"
    >
      <path id="thePath" />
    </svg>
    <script src="script.js"></script>
  </body>
</html>

Get a list of a subset of keys of an interface in typescript

I’m bumping into an issue in my application where I neatly defined every interface for my models in the frontend.

I’m now building tables which have filters defined + column definitions as a subset of those interfaces.

Imagine following setup:

export interface Project {
  id?: string;
  name?: string;
  color?: string;
  notes?: string;
}

type ProjectColumns = Pick<ProjectObject, "id" | "name" | "color" | "notes">;
type ProjectFilterColumns = Pick<ProjectObject, "name" | "color">;

// What I want to do

ProjectColumns.map(column => i18n.t(`ProjectColumn.${column}`))
ProjectFilterColumns.map(column => i18n.t(`ProjectFilterColumn.${column}`))

What I want to accomplish is that I can iterate over the ProjectColumns as an array and display the available columns to the user. The user can add or remove the available columns.

Same for filters where I only allow the user to filter on a subset of the properties available from the interface defined by me.

The issue I’m bumping into is that only ENUMS can be iterated as an array, but I don’t want to redefine my properties again since they are already on the interface.

Am I tackling this problem the wrong way in typescript? Anything I’m missing?

React-native-vector-icons/Ionicons icons are not displayed

import React from 'react';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import Home from '../screens/home';
import Car from '../screens/Car';
import Services from '../screens/Services';
import Dialogs from '../screens/Dialogs';
import Profile from '../screens/Profile';
import Ionicons from 'react-native-vector-icons/Ionicons';

const Tab = createBottomTabNavigator();

export const HomeTabs = () => {
  return (
    <Tab.Navigator
      screenOptions={({ route }) => ({
        headerShown: false,
        tabBarShowLabel: false,
        tabBarActiveTintColor: '#007AFF',
        tabBarInactiveTintColor: 'black',
        tabBarIcon: ({ focused, color, size}) => {
          let iconName;
          if (route.name === 'HomeTabs') {
            iconName = focused ? 'home' : 'home-outline';
          } else if (route.name === 'Car') {
            iconName = focused ? 'car' : 'car-outline';
          } else if (route.name === 'Services') {
            iconName = focused ? 'construct' : 'construct-outline';
          } else if (route.name === 'Dialogs') {
            iconName = focused ? 'chatbubble' : 'chatbubble-outline';
          } else if (route.name === 'Profile') {
            iconName = focused ? 'person' : 'person-outline';
          }
          return <Ionicons name={iconName} size={focused? 25: size} color={color} />;
        }
      })}
    >
      <Tab.Screen name="HomeTabs" component={Home} />
      <Tab.Screen name="Car" component={Car} />
      <Tab.Screen name="Services" component={Services} />
      <Tab.Screen name="Dialogs" component={Dialogs} />
        <Tab.Screen name="Profile" component={Profile} />
    </Tab.Navigator>
  );
} 

I have such a code that is responsible for the bottom navigation, and I use the react-native-vector-icons and Ionicons library to get icons, but the icons are not displayed, instead they are just strikethrough squares. I must say right away that everything is spelled out correctly.

import type { Icon } from './index';

export type IoniconsGlyphs = 'accessibility' | 'accessibility-outline' | 'accessibility-sharp' | 'add' | 'add-circle' | 'add-circle-outlin...

declare export default Class<Icon<IoniconsGlyphs>>;

I decided to go downstairs to see what’s inside the Ionicons, and why there were errors:

1)TS7016: Could not find a declaration file for module ‘./index’. ‘C:/Users/Autoservice_front/node_modules/react-native-vector-icons/index.js’ implicitly has an ‘any’ type.
2)TS1120: An export assignment cannot have modifiers.
3)TS2552: Cannot find name ‘Class’. Did you mean ‘CSS’?
4)TS2714: The expression of an export assignment must be an identifier or qualified name in an ambient context.

And I thought maybe the problem was that there were errors and that’s why the icons weren’t displayed.

How to validate that 2 folders on the same level cannot have the same name in a recursive Angular form array

I’m not sure if my question title is clear enough but i will try to give more details. I try to create a folder hierarchy form using angular forms. The form can have unlimited nesting. My problem is that now I can add 2 folders with the same name on a certain level but this should not be possible and should warn the user. This is logical because in a normal file system 2 folders cannot have same name

I present a simplified version here for clarity. still a bit long to read but here is reproducible demo in stackblitz with same code

form component

@Component({
  selector: 'my-form',
  templateUrl: './form.component.html',
  styleUrls: ['./form.component.css'],
})
export class FormComponent implements OnInit {
  myForm!: FormGroup;
  isHierarchyVisible: boolean = false;

  constructor(private formBuilder: FormBuilder) {}

  ngOnInit() {
    this.myForm = this.formBuilder.group({
      folderHierarchy: this.formBuilder.array([]),
    });
    if (this.folderHierarchy.length === 0) this.isHierarchyVisible = false;
  }

  removeFolder(index: number): void {
    this.folderHierarchy.removeAt(index);
    if (this.folderHierarchy.length === 0) this.isHierarchyVisible = false;
  }

  addFolder(): void {
    this.folderHierarchy.push(
      this.formBuilder.group({
        name: [null, [Validators.required]],
        subFolders: this.formBuilder.array([]),
        level: 0,
      })
    );
    this.isHierarchyVisible = true;
  }

  getForm(control: AbstractControl): FormGroup {
    return control as FormGroup;
  }

  get folderHierarchy(): FormArray {
    return this.myForm.get('folderHierarchy') as FormArray;
  }
}
<p>folder form. type in form name and press enter</p>
<form [formGroup]="myForm">
  <div formArrayName="folderHierarchy">
    <label for="folderHierarchy">create folder</label>
    <div>
      <button type="button" class="btn btn-custom rounded-corners btn-circle mb-2" (click)="addFolder()" [disabled]="!folderHierarchy.valid">
        Add
      </button>
      <span class="pl-1">new folder</span>
    </div>
    <div>
      <div *ngIf="!folderHierarchy.valid" class="folder-hierarchy-error">invalid folder hierarchy</div>
      <div class="folderContainer">
        <div>
          <div *ngFor="let folder of folderHierarchy.controls; let i = index" [formGroupName]="i">
            <folder-hierarchy (remove)="removeFolder(i)" [folder]="getForm(folder)" [index]="i"></folder-hierarchy>
          </div>
        </div>
      </div>
    </div>
  </div>
</form>

form hierarchy component

@Component({
  selector: 'folder-hierarchy',
  templateUrl: './folder-hierarchy.component.html',
  styleUrls: ['./folder-hierarchy.component.css'],
})
export class FolderHierarchyComponent implements OnInit {
  constructor(private formBuilder: FormBuilder) {}
  @Output() remove = new EventEmitter();
  @Input() folder!: FormGroup;
  @Input() index!: number;
  tempName: string = '';

  ngOnInit() {}

  addSubFolder(folder: FormGroup): void {
    (folder.get('subFolders') as FormArray).push(
      this.formBuilder.group({
        name: [null, [Validators.required]],
        subFolders: this.formBuilder.array([]),
        level: folder.value.level + 1,
      })
    );
  }

  getControls(folder: FormGroup): FormGroup[] {
    return (folder.get('subFolders') as FormArray).controls as FormGroup[];
  }

  removeSubFolder(folder: FormGroup, index: number): void {
    (folder.get('subFolders') as FormArray).removeAt(index);
  }

  removeFolder(folder: { value: { subFolders: string | any[] } }): void {
    this.remove.emit(folder);
  }

  disableAdd(folder: { invalid: any }): void {
    return this.folder.invalid || folder.invalid;
  }
  onKeyup(event: KeyboardEvent): void {
    this.tempName = (event.target as HTMLInputElement).value;
  }
  updateName(folder: FormGroup, name: string): void {
    folder.get('name')?.setValue(name);
    if (this.isInvalid(folder)) {
      folder.get('name')?.updateValueAndValidity();
      return;
    }
  }

  isInvalid(folder: FormGroup): boolean {
    return !folder.get('name')?.valid;
  }
}
<div *ngIf="folder" #folderRow class="folder-row">
  <div class="folder-header">
    <div class="folder-name-container">
      <label for="folderName" class="folder-name-label">Name:</label>
      <input #folderName id="folderName" [ngClass]="isInvalid(folder) ? 'invalid-input' : ''" class="folder-name-input" placeholder="Folder Name" type="text" (keyup)="onKeyup($event)" maxlength="50" (keyup.enter)="updateName(folder, $any($event.target).value)" [value]="folder.value.name" autocomplete="off" />
    </div>
    <button type="button" class="btn-remove-folder" (click)="removeFolder(folder)">Remove</button>
    <button type="button" class="btn-add-subfolder" [disabled]="disableAdd(folder)" (click)="addSubFolder(folder)">Add Subfolder</button>
  </div>
  <div *ngIf="folder && folder.value.subFolders.length > 0" class="subfolder-container">
    <div *ngFor="let subFolder of getControls(folder); let i = index" class="subfolder-item">
      <folder-hierarchy (remove)="removeSubFolder(folder, i)" [folder]="subFolder"></folder-hierarchy>
    </div>
  </div>
</div>

Error registering service workers with tauri

I’m using tauri v2 and nuxt but I’m unable to install a service worker.

When launching the tauri app I just either see An unknown error occurred when fetching the script or a wrong MIME type answer (text) indicating that nuxt provided a 404 error page.

The service worker is placed in public/sw.js and also found in .tauri-build/dist/sw.js

This is the registration:

navigator.serviceWorker
  .register("/sw.js")
  .then((registration) => console.log("SW registered:", registration))
  .catch((err) => console.error("SW registration failed:", err));

Adding different scopes to .register() didn’t help.

The nuxt.config.ts:

import { defineNuxtConfig } from "nuxt/config";
import { baseURL, baseHost } from "./baseURL.config";

export default defineNuxtConfig({
  devtools: { enabled: true },
  ssr: false, // tauri needs this
  // Enables the development server to be discoverable by other devices when running on iOS physical devices
  devServer: { host: process.env.TAURI_DEV_HOST || baseHost },
  app: {
    head: {
      title: "tauri-sw",
      htmlAttrs: {
        lang: "en",
      },
    },
  },
  runtimeConfig: {
    public: {
      baseURL: baseURL,
    },
  },
  routeRules: {
    "/**": {
      cors: true,
      headers: {
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Headers": "*",
        "Access-Control-Allow-Methods": "*",
        "Access-Control-Allow-Credentials": "true",
        "Access-Control-Expose-Headers": "*",
        "Access-Control-Request-Method": "*",
        "Access-Control-Request-Headers": "*",
      },
    },
  },
  typescript: {
    strict: true,
  },
  vite: {
    clearScreen: false,
    envPrefix: ["VITE_", "TAURI_"],
    server: {
      // Tauri requires a consistent port
      strictPort: true,
    },
  },
  nitro: {
    sourceMap: process.env.NODE_ENV !== "production",
    esbuild: {
      options: {
        target: "esnext",
      },
    },
  },
});

In the tauri.config.json is this:

{
  "productName": "tauri-sw",
  "version": "1.0.0",
  "identifier": "com.test.tauri-sw",
  "build": {
    "beforeDevCommand": "pnpm build:server && pnpm dev",
    "beforeBuildCommand": "pnpm generate && pnpm build:server",
    "devUrl": "http://127.0.0.1:3000",
    "frontendDist": "../.tauri-build/dist"
  },
  "app": {
    "windows": [
      {
        "title": "tauri-sw",
        "label": "main",
        "url": "/",
        "width": 1280,
        "height": 720,
        "resizable": true
      }
    ],
    "security": {
      "csp": null,
      "headers": {
        "Access-Control-Allow-Headers": "*",
        "Access-Control-Allow-Methods": "*",
        "Access-Control-Allow-Credentials": "true",
        "Access-Control-Expose-Headers": "*"
      }
    }
  },
  "bundle": {
    "active": true,
    "targets": ["deb", "rpm", "appimage", "nsis", "app", "dmg"],
    "icon": [
      "../public/oceansky-logo30x30.png",
      "../public/oceansky-logo100x100.png",
      "../public/oceansky-logo.png",
      "../public/oceansky-logo.icns",
      "../public/oceansky-logo.ico"
    ]
  },
  "$schema": "../node_modules/@tauri-apps/cli/config.schema.json"
}

It seem to me like tauri doesn’t bundle the sw.js. Adding it to tauri’s bundle: resources: [] also didn’t help.

I appreciate all help! 🙂

How do I move a slide with a mouse and on my phone?

How can I implement a solution that allows users to navigate through slides using the mouse on desktop devices and using touch gestures (finger swipe) on mobile devices, without relying on third-party libraries? I need the navigation to be intuitive and smooth, with support for both mouse drag and touch events. The goal is to create a responsive slider that works seamlessly across different screen sizes and input methods

<div class="slider_robots">
    <div class="slider_robots_container">
        <div class="slider_btn_container btn_prev_position">
            <button class="slider_btn btn_prev"></button>
        </div>

        <div class="slider_robots_track">
            <div class="slider_robot_wrapper">
                <div class="slide_robot" style="background-color: #A8DADC;"></div>
            </div>

            <div class="slider_robot_wrapper">
                <div class="slide_robot" style="background-color: #457B9D;"></div>
            </div>

            <div class="slider_robot_wrapper">
                <div class="slide_robot" style="background-color: #F4A261;"></div>
            </div>

            <div class="slider_robot_wrapper">
                <div class="slide_robot" style="background-color: #2A9D8F;"></div>

            </div>

            <div class="slider_robot_wrapper">
                <div class="slide_robot" style="background-color: #E76F51;"></div>
            </div>

            <div class="slider_robot_wrapper">
                <div class="slide_robot" style="background-color: #264653;"></div>
            </div>
        </div>

        <div class="slider_btn_container btn_next_position">
            <button class="slider_btn btn_next"></button>
        </div>
    </div>

    <ol class="pagination_circles_container"></ol>
</div>

CSS:

ol {
    list-style: none;
}

.slider_robots {
    display: flex;
    flex-direction: column;
    align-items: center;

    padding: 80px 0 0 20px;
    margin: 0 20px 80px 0;
}

.slider_robots_container {
    position: relative;

    width: clamp(414px, 100%, 1282px);

    margin-bottom: 45px;

    overflow: hidden;
}

.slider_btn_container {
    position: absolute;
    z-index: 1000;

    display: flex;
    align-items: center;
    justify-content: center;

    background-color: #f7f7f7;
    border-radius: 100%;
    width: 54px;
    height: 54px;

    cursor: pointer;
}

.btn_prev_position {
    left: 0;
    top: 380px;
}
.btn_next_position {
    right: 0;
    top: 380px;
}

.slider_btn {
    width: 11px;
    height: 11px;
    border-top: 2px solid #6a768c;
    border-right: 2px solid #6a768c;
}
.btn_prev {
    transform: rotate(-135deg);
    margin-left: 3px;
}
.btn_next {
    transform: rotate(45deg);
    margin-right: 3px;
}


.slider_robots_track {
    display: flex;

    padding: 0 15px;

    transition: transform .5s;
}

.slider_robot_wrapper {
    display: flex;
    flex-direction: column;
    flex-grow: 0;
    flex-shrink: 0;
    flex-basis: calc((100% - 2 * 20px) / 3);

    gap: 25px;
    padding-right: 20px;

    pointer-events: none;
}

.slide_robot {
    width: 414px;
    height: 414px;
    border-radius: 12px;

    pointer-events: auto;
}

.pagination_circles_container {
    display: flex;
    justify-content: center;
    width: 100%;
    gap: 24px;
}

.pagination_circle {
    background-color: #b8edb7;
    border-radius: 100%;
    width: 10px;
    height: 10px;

    cursor: pointer;
}

.circle_active {
    background-color: #b8edb7;
    width: 10px;
    height: 10px;
    border-radius: 100%;
    box-shadow: 0 0 0 7px #447355;
}

@media screen and (max-width: 1024px) {

    .slider_robots_container {
        width: clamp(462px, 100%, 942px);
    }

    .slider_robot_wrapper {
        flex-basis: calc((100% - 20px) / 2);
    }

}

@media screen and (max-width: 768px) {

    .slider_robots_container {
        width: clamp(100px, 100%, 687px);
    }

    .slider_robot_wrapper {
        flex-basis: 100%;
    }

}

js:

const paginationCirclesContainerEl = document.querySelector('.pagination_circles_container');
const btnPrevPositionEl = document.querySelector('.btn_prev_position');
const btnNextPositionEl = document.querySelector('.btn_next_position');
const sliderRobotsTrackEl = document.querySelector('.slider_robots_track');
const sliderRobotWrapperEls = [...document.querySelectorAll('.slider_robot_wrapper')];

// Variables for working with slides
const visibleSlidesCount = 3;
let currentSlideIndex = visibleSlidesCount;
let isAnimating = false;

// Creating pagination circles equal to the number of slides
const paginationCircles = [];

const createPaginationCircles = () => {
    const li = document.createElement('li');
    li.className = 'pagination_circle';
    paginationCirclesContainerEl.appendChild(li);
    paginationCircles.push(li);
};

const addPagination = () => {
    sliderRobotWrapperEls.forEach(createPaginationCircles);
    paginationCircles[0].classList.add('circle_active');
};
addPagination();

// Base slide width
let slideWidth = sliderRobotWrapperEls[0].offsetWidth;

// Cloning the first three slides
const lastThreeSlides = sliderRobotWrapperEls.slice(0, visibleSlidesCount);
lastThreeSlides.forEach(slideEl => {
    const clone = slideEl.cloneNode(true);
    sliderRobotsTrackEl.append(clone);
});

// Cloning the last three slides
const firstThreeSlides = sliderRobotWrapperEls.slice(-visibleSlidesCount);
firstThreeSlides.forEach(slideEl => {
    const clone = slideEl.cloneNode(true);
    sliderRobotsTrackEl.insertBefore(clone, sliderRobotWrapperEls[0]);
});

// New list of slides (12)
const allSlides = [...document.querySelectorAll('.slider_robot_wrapper')];

let isDragging = false;
let startX = 0;
let currentTranslate = 0;
let prevTranslate = 0;

sliderRobotsTrackEl.addEventListener('mousedown', e => {
    isDragging = true;
    startX = e.clientX;
});

sliderRobotsTrackEl.addEventListener('mousemove', e => {
    if (!isDragging) return;

    const currentX = e.clientX;
    const diffX = currentX - startX;
    currentTranslate = prevTranslate + diffX;

    updateSliderPosition();
});

sliderRobotsTrackEl.addEventListener('mouseup', e => {
    if (!isDragging) return;

    isDragging = false;
    prevTranslate = currentTranslate;
});

// Dynamically update the slide width on resize
const updateSlideWidth = () => {
    slideWidth = allSlides[0].offsetWidth;
    updateSliderPosition();
};
window.addEventListener('resize', updateSlideWidth);

// Move the track with slides
const updateSliderPosition = (withTransition = true, index) => {

    if (index) {
        removeActiveClass(currentSlideIndex);
        currentSlideIndex = index;
        addActiveClass(currentSlideIndex);
    }

    const offset = -currentSlideIndex * slideWidth;

    sliderRobotsTrackEl.style.transition = withTransition ? 'transform .5s' : 'none';
    sliderRobotsTrackEl.style.transform = `translate3d(${offset}px, 0px, 0px)`;
};

// Navigation through pagination circles
paginationCircles.forEach((circleEl, index) => {
    circleEl.addEventListener('click', () => {
        updateSliderPosition(true, index + visibleSlidesCount);
    });
});

// Add active circle class to the current slide
const addActiveClass = (currentSlideIndexCircle) => {
    let normalizedIndex;

    if (currentSlideIndexCircle) {
        normalizedIndex = (currentSlideIndexCircle - visibleSlidesCount + paginationCircles.length) % paginationCircles.length;
    } else {
        normalizedIndex = (currentSlideIndex - visibleSlidesCount + paginationCircles.length) % paginationCircles.length;
    }

    paginationCircles[normalizedIndex].classList.add('circle_active');
};

// Remove active circle class from the previous slide
const removeActiveClass = (currentSlideIndexCircle) => {
    let normalizedIndex;

    if (currentSlideIndexCircle) {
        normalizedIndex = (currentSlideIndexCircle - visibleSlidesCount + paginationCircles.length) % paginationCircles.length;
    } else {
        normalizedIndex = (currentSlideIndex - visibleSlidesCount + paginationCircles.length) % paginationCircles.length;
    }
    paginationCircles[normalizedIndex].classList.remove('circle_active');
};

// Show the next slide
const nextSlide = () => {
    // Block click until animation is finished
    if (isAnimating) return;
    isAnimating = true;
    setTimeout(() => {
        isAnimating = false;
    }, 500);

    removeActiveClass();

    currentSlideIndex++;
    updateSliderPosition();

    addActiveClass();

    // Quick rewind when reaching the last clone
    if (currentSlideIndex === allSlides.length - visibleSlidesCount) {
        setTimeout(() => {
            currentSlideIndex = visibleSlidesCount;
            updateSliderPosition(false);

        }, 500);
    }
};

// Show the previous slide
const prevSlide = () => {
    // Block click until animation is finished
    if (isAnimating) return;
    isAnimating = true;
    setTimeout(() => {
        isAnimating = false;
    }, 500);

    removeActiveClass();

    currentSlideIndex--;
    updateSliderPosition();

    addActiveClass();

    // Quick rewind when reaching the first clone
    if (currentSlideIndex === 0) {
        setTimeout(() => {
            currentSlideIndex = allSlides.length - visibleSlidesCount * 2;
            updateSliderPosition(false);

        }, 500);
    }
};

// Event handlers for the buttons
btnNextPositionEl.addEventListener('click', nextSlide);
btnPrevPositionEl.addEventListener('click', prevSlide);

// Initialize the initial position of the slider
updateSliderPosition(false);

BootStrap 5 container content not full width when printing

I have trouble with BootStrap layout system when printing a page.

Suppose there is a button

  • <button class="btn btn-outline-dark" onclick="window.print()">Drukuj</button>

which allows me to print a window and where information must take full page width (I want people to easily print out GDPR content for their use). I also want to avoid downloading any files from my page.

However, I’ve developed a static web page with no URLs by using tab-pane classes, which simply toggle static id content when navbar tab is clicked on:

<body>
<div id="navbar" class="container-fluid">
            
    <ul class="navbar nav nav-tabs nav-fill">
        <li class="nav-item">
            <a class="navbar-brand" data-bs-toggle="tab" href="#home-page">
            <img id="logo" alt="logo" src="adwokatura-polska-blank.png"></a>
        </li>
        <li class="nav-item">
            <a class="nav-link" data-bs-toggle="tab" href="#lawyers-page">Prawnicy</a>
        </li>
        <li class="nav-item">
             <a class="nav-link" data-bs-toggle="tab" href="#services-page">Usługi</a>
        </li>
        <li class="nav-item">
             <a class="nav-link" data-bs-toggle="tab" href="#contact-page">Kontakt</a>
        </li>
        <li class="nav-item">
             <a class="nav-link" data-bs-toggle="tab" href="#rodo-page">Polityka prywatności</a>
        </li>
    </ul>
</div>
<article id="content" class="container">
<!-- ...More tab content... -->
<div class="tab-pane container fade min-vh-100" id="rodo-page">
    <h1 class="display-4">Informacja RODO</h1>
    <button class="btn btn-outline-dark" onclick="window.print()">Drukuj</button>
    <hr>
    <p><em>Szczegółowe informacje dotyczące przetwarzania danych osobowych klientów kancelarii</em></p>
    <ol>
        <li>
        <p>Administrator danych osobowych</p>
        <p>Administratorem Pani/Pana danych osobowych będzie Adwokat Milena Gostyńska
        prowadząca Kancelarię Prawną Adwokat Mileny Gostyńskiej z siedzibą w ...
        przy .... Może Pani/Pan  się z nami skontaktować w następujący sposób:
        <ul>
            <li>listownie na adres: ...</li>
            <li>telefonicznie: ... lub ...</li>
        </ul>
        </li>
    </ol>
</div>
<!-- ...More tab content... -->
</article>
<!-- ...Some footers etc... -->
</body>

The problem is: BootStrap uses special styling for containers (which have margin and pad for content to nicely center).
However, this useful feature messes my printing since it includes the whole window:

How can I use CSS to print out article content with no BootStrap containers padding and margin?
My HTML head:

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Kancelaria Prawna - Adw. Milena Gostyńska</title>
    <link rel="stylesheet" href="../assets/css/styles.css" />
    <link rel="stylesheet" type="text/css" href="../assets/bootstrap-5.3.3-dist/css/bootstrap.css">
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>

    <!-- was testing Alipne.js, don't judge -->
    <!--<script src="script.js"></script>-->
    <script src="//unpkg.com/alpinejs" defer></script>
</head>

I’m not that good at CSS, but this is what I’ve managed to do so far:

/*-----------My problem----------------*/
@media print {
    body {
        visibility: hidden;
        display: contents;
    }
    #navbar, footer {
        display: none;
    }
    #rodo-page {
        margin: 0 0 0 0 !important;
        padding: 0 0 0 0 !important;
        width: 100% !important;
        visibility: visible;
        text-align: left;
    }
}
/*-------------------------------------*/
/* Obviously I have more CSS, such as: */
#content {
    background-color: lightgrey;
    border: solid;
    border-color: dimgrey;
}

.tab-pane .display-4 {
    text-align: center;
    margin-bottom: 1em;
}
.tab-pane p, .tab-pane ul{
    font-size: larger;
}

body{
    background-image: linear-gradient(#006241,#32913a);
    background-attachment: fixed;
}

!important keyword doesn’t seem to work. I’ve managed to push all the text to the top, but text is still centered horizontally.
top: 0 with left:0 didn’t work either.
Changing container to container-fluid isn’t for me either: it’s about printing behaviour only.
Any advice?

Mapbox-gl: Scale markers along with map efficiently

Demo:

I have created a simple demo project to help demonstrate and solve this problem.

Project: https://github.com/zimonitrome/mapbox-scale-problem

Page: https://zimonitrome.github.io/mapbox-scale-problem/

enter image description here

Description:

My project requirements is twofold:

  • Requirement 1: I want to show a large amount of markers (e.g. 1000) in Mapbox-gl.
  • Requirement 2: I want them to scale along with the map and it’s projection/zoom/perspective.

To solve requirement 1:

Ideally I would use their built in Marker() class (reference) which adds an HTML element for each marker and transforms it with CSS. I have demonstrated this in what I call MarkerMap on my demo. But transforming this many objects in the DOM seems inherently laggy on many computers and phones when displaying 1000 markers.

Another option is to use a “symbol layer”. Following an official tutorial, a layer is added with the ID “points”, which can later be referenced and updated. I demo this as LayerMap in my repo. A symbol layer is faster (no lag) as it leverages open-gl and is not a HTML element, but they seem more difficult to control.

To solve requirement 2:

Scaling markers (Marker() or Symbol layers) seems to be an unsolved problem in the Mapbox community and I have seen several questions without answers.

In short I want markers to scale with the underlying projection surface, i.e. in globe projection, markers in the middle of the screen are larger than the ones closer to the edges. For Mercator, markers along the bottom/top are larger because of the projection.

They way I have solved it is unorthodox and probably slow:

Given a map coordinate c0, create N new coordinates (c1, c2,… cN) at a real world distance d from c0 in different angles. Then, project all coordinates (c0, …, cN) to get on-screen pixel points (p0, …, pN), and get the average distance of all new pixel points (p1, …, pN) to p0. This way, we will get a local scale for any given coordinate in any given map projection.

I’ve tried to describe it more visually here:
enter image description here

This code is used by both maps through the function calculateDistScale() and other helper functions found in src/helpers.ts.

Problem

Things are slow. I would prefer to use the Marker Map, but it seems slow even without this scaling enabled. I don’t think this can be sped up, but it would be great if it could. But the scaling updates without transition or big delay.

The Layer Map has better performance but updating the scale has a transition delay. I think some delay would still exist even if I could get rid of the transition, somehow.

In summary: I would like a map that can scale markers according to the projection, but that can do it fast and quickly without lag.

getElementbyId() does not correctly get td Elements from my table

I have a table that represents a chess board in my html per the following code:

    <table id="chess-board" class="board">
        {% for row in range(8) %}
            <tr>
                {% for col in range(8) %}
                    <td id="{{ 'ABCDEFGH'[col] }}{{ 1+row }}" onclick="handleClick('{{ 'ABCDEFGH'[col] }}{{ 1+row }}')">{{ 'ABCDEFGH'[col] }}{{ 1+row }}</td>
                {% endfor %}
            </tr>
        {% endfor %}
    </table>

I want to access the fields of the table to populate it with the pieces per this function in js:

function renderBoard(gameState) {
        const chessBoard = document.getElementById("chess-board");
        chessBoard.innerHTML = '';  // Clear the board before re-rendering

        // Loop through the rows of the board (gameState.board is an 8x8 array)
        Object.entries(gameState.board).forEach(([key, pieceData]) => {
            const [rowIndex, colIndex] = key.split(',').map(Number);
            const squareId = `${'ABCDEFGH'[colIndex]}${1 + rowIndex}`;  // Calculate the cell ID (e.g., A1, B2, ...)
            const cellElement = document.getElementById(squareId);  // Get the corresponding <td> element

            console.log(cellElement)

            if (cellElement) {
                // If there is a piece in this square, add it
                if (pieceData && pieceData.type !== null) {
                    const pieceImage = document.createElement("img");

                    // Set the piece image based on the type and color
                    const pieceType = pieceData.type;
                    pieceImage.src = `static/pieces/${pieceType}.png`;
                    pieceImage.alt = `${pieceData.color} ${pieceType}`;
                    pieceImage.classList.add("piece");  // Optional: add CSS class to style the pieces

                    // Clear any existing piece (in case the square was previously occupied)
                    cellElement.innerHTML = '';  // Clear previous content

                    // Append the new piece image to the <td> element
                    cellElement.appendChild(pieceImage);
                } else {
                    // If there is no piece, make sure the <td> is empty
                    cellElement.innerHTML = '';
                }
            } else {
                console.log(`Error: Could not find element with ID: ${squareId}`);
            }
        });
    }

The squareId is calculated correctly but then the cellElement becomes null and i do not get why

I tried to implement the chess board in html without a loop by manually putting every tr and td, and all the Ids so they are 100% correct, but still it did not work

I tried to access the ids of the tds in css with #A1 and so on. That worked so i know the ids are given correctly.

I tried calling the functions after DOMContentLoades as well as after window.onload but both did not solve the issue.

Thank you for your help!

JS function works only when hard refreshing page

I’m sure this has something to do with the timing of things loading, but I can’t figure it out.

I’m using Oracle’s Jet charting libraries and trying to convert the y-axis to a percent

When I run this code on page load, it works only when I hard refresh the page as opposed to just hitting f5. But my understanding is it’s in a callback here and should only run once the resources are loaded.

When it doesn’t work, it tells me oj.IntlNumberConverter is not a constructor.

require(["ojs/ojcore", "ojs/ojconverter", "ojs/ojchart", "ojs/ojpictochart"], function (oj) {
    $('.dyn-chart').each(function () {
        var chart = $(this);
        c  = new oj.IntlNumberConverter({ style : "percent" });
        chart.ojChart(chart.data("chartJson"));
        chart.ojChart( "option", "yAxis.tickLabel.converter", c );
    });
});

I’ve tried reducing the resources used, but all end up being necessary for it to function.

If I set a timeout of 100ms, it works fine, but seems like that shouldn’t need to be done