Why can’t I click this button in the ChatGPT UI using standard JavaScript?

I want to script Safari to automate some actions in ChatGPT. To achieve that I need to click plus-button in the input field:

enter image description here

Usually when I try to do something like this I use JavaScript like

var button = document.evaluate("//div/div/div[2]/form/div[1]/div/div[2]/div/div[1]/div[1]/div/div/div/span[2]", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; button.click();

but for some reason this snippet doesn’t work – nothing happens – with the ChatGPT UI.

How do I click this button using JavaScript?

  1. I am aware of the ChatGPT API but it is not useful for my purpose.
  2. Safari has a do JavaScript method in its AppleScript dictionary that I use.

How to Implement Conference Call Feature Using JsSIP with FusionPBX/Freeswitch

I’m currently developing a SIP phone using the JsSIP library and would appreciate some guidance on implementing a conference call feature.

So far, I’ve successfully implemented the basic call controls such as mute, unmute, hold, unhold, and call transfer. I’m now looking to add support for conference calling.

I’m using FusionPBX with FreeSWITCH as the backend SIP server. Has anyone implemented conference calling with this setup using JsSIP? I’m specifically looking for advice or best practices on how to:

Merge multiple calls into a single conference

Manage audio streams appropriately

Handle SIP signaling and media negotiation

Use FreeSWITCH’s conference modules (if applicable)

Any examples, references, or tips would be really helpful!

Thanks in advance!

Tableau embed report asking for login instead of directly loading the report in safari browser

I am working on a project in ReactJs in which I have embedded tableau reports. I have use connected apps direct trust with JWT so the reports does not require signin before loading and they are loading without signin in chrome and firefox however they require signin to tableau cloud in safari browser.

This is the error I get in console.
[Error] Failed to load resource: the server responded with a status of 404 () (tableau.embedding.3.12.0-pre.25.min.js.map, line 0)
[Error] Failed to load resource: the server responded with a status of 401 () (viewing, line 0)

import TableauViz from "@/components/TableauViz/TableauViz";
import { useEffect, useState } from "react";
import { useSelector } from "react-redux";

const Report = () => {
   const [device, setDevice] = useState("desktop");

   const { selectedReport = null, reportToken = "" } = useSelector(
      (state) => state.reports
   );

   const { isLargeScreenSidebarOpen } = useSelector((state) => state.ui);

   useEffect(() => {
      const handleResize = () => {
         if (window.innerWidth < 768) {
            setDevice("mobile");
         } else {
            setDevice("desktop");
         }
      };

      // Initial check
      handleResize();

      // Add event listener for window resize
      window.addEventListener("resize", handleResize);

      // Clean up the event listener on component unmount
      return () => {
         window.removeEventListener("resize", handleResize);
      };
   }, []);

   if (!selectedReport) return <></>;

   const options = {
      toolbar: "bottom",
      "hide-tabs": true,
      device,
      "hide-edit-button": true,
      width: "100%",
   };

   return (
      <TableauViz
         src={selectedReport.embeddedLink}
         options={options}
         token={reportToken}
      />
   );
};

export default Report;
import React, { useEffect, useRef, useState } from "react";
import { TableauEventType } from "https://public.tableau.com/javascripts/api/tableau.embedding.3.latest.min.js";
import { ErrorMessage } from "@/components/ErrorMessage/ErrorMessage";

const TableauViz = ({ src, options, token }) => {
   const vizContainer = useRef(null);
   const [error, setError] = useState("");

   function handleError(err) {
      try {
         if (err.detail) {
            const details = JSON.parse(err.detail.message);
            console.error(details);
            if (details.statusCode === 401) {
               setError("You are not authorized to view this report.");
               emptyVizContainer();
            } else {
               setError("Something went wrong.");
               emptyVizContainer();
            }
         }
      } catch (error) {
         console.error("handleError", error);
         setError("Something went wrong.");
         emptyVizContainer();
      }
   }

   function emptyVizContainer() {
      if (vizContainer.current) {
         vizContainer.current.innerHTML = "";
      }
   }

   useEffect(() => {
      // Initialize the Tableau Viz web component
      const vizElement = document.createElement("tableau-viz");
      vizElement.id = "tableauViz";
      vizElement.src = src;
      vizElement.token = token;

      // Add options as attributes
      for (const [key, value] of Object.entries(options)) {
         vizElement.setAttribute(key, value);
      }

      // Append the viz element to the container
      if (vizContainer.current) {
         vizContainer.current.innerHTML = "";
         vizContainer.current.appendChild(vizElement);
      }

      // Add event listeners
      vizElement.addEventListener(TableauEventType.VizLoadError, handleError);


      // Cleanup event listeners on unmount
      return () => {
         vizElement.removeEventListener(
            TableauEventType.VizLoadError,
            handleError
         );
      };
   }, [src, options]);

   if (error)
      return (
         <div className="h-100 d-flex align-items-center justify-content-center">
            <ErrorMessage message={error} />
         </div>
      );

   return <div ref={vizContainer} className="tableau-viz-container m-auto" />;
};

export default TableauViz;

In the official documentation they say it is because safari blocks third party cookies the report is asking for signin but they don’t provide a solution. I tried block third party cookies in chrome but still the report were loading fine.

Browser-based gTag OSINT tool does not run, is not fully functional, and returns no scan results after form submission

`I’m building a browser-based gTag OSINT tool to monitor spoofed user-agents using Puppeteer and a WebSocket/Express backend.

The frontend dashboard renders correctly, and the form accepts input, but submitting the form does not trigger scans or produce any data. I also notice that some WebGL options don’t behave as expected, though I’m not sure if that’s related.

There are:

  • No JS console errors
  • No backend logs showing incoming POSTs or WebSocket activity
  • No chart data or scan results rendering

Any help would be appreciated. I’m a novice and just want to get form→scan→result working before scaling up.


What I expect:

  • Form submission should call /api/scan (via fetch() or WebSocket)
  • Backend should run scanTag(tag, url) and return result
  • UI should update with new scan data and chart stats

What I’ve tried:

  • Verified endpoint /api/scan exists and works when hit manually (Postman)
  • Checked dashboard.js to confirm form handler is present and fetch() call exists
  • Backend logs show nothing when form is submitted
  • scanTag() works correctly if triggered from backend during startup

Code (frontend)

form.addEventListener('submit', async (e) => {
      e.preventDefault();
      const submitBtn = form.querySelector('button[type="submit"]');
      if (submitBtn) submitBtn.disabled = true;

      try {
        const formData = new FormData(form);
        const data = {
          tag: formData.get('tag'),
          url: formData.get('url') || this.config.defaultUrl,
          webglPreset: formData.get('webglPreset'),
          timezone: formData.get('timezone'),
          language: formData.get('language'),
          proxy: formData.get('proxy')
        };

        if (!data.tag) throw new Error('Tag is required');

        const response = await fetch('/api/scan', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(data)
        });

        if (!response.ok) {
          const error = await response.json();
          throw new Error(error.message || 'Scan failed');
        }

        const result = await response.json();
        this.showToast(
          'Scan Complete',
          result.status === 'LIVE' ? 'success' : 'danger',
          `${data.tag}: ${result.status}`
        );

        this.updateScanUI({
          tag: data.tag,
          status: result.status,
          confidence: result.confidence || 0
        });

      } catch (error) {
        this.showToast('Scan Failed', 'danger', error.message);
      } finally {
        if (submitBtn) submitBtn.disabled = false;
      }
    });
  }

Base 3 chunked encoder off by 1 bug

I’m trying to write an arbitrary base N chunked encoder. This is different than a mathematical encoder where the entire buffer is converted to an integer and then that integer is converted into a number. It’s supposed to work like how base 64 reads the buffer in chunks of 3 bytes and outputs 4 chars per chunk.

Non powers of 2 bases “waste” bits because the the # of bits in N bytes never align with M chars.

For base 3 in particular, I’ve computed that 12 bytes can be encoded into 61 chars with a wastage of 0.683 bits because 3**61=96.68 and 12*8=96, so 0.683 bits will be left unused.

What this looks like is:

expect(base3encoder.encode([0,0,0,0,0,0,0,0,0,0,0,1])).toBe('0000000000000000000000000000000000000000000000000000000000001')
expect(base3encoder.encode([0,0,0,0,0,0,0,0,0,0,0,2])).toBe('0000000000000000000000000000000000000000000000000000000000002')
expect(base3encoder.encode([0,0,0,0,0,0,0,0,0,0,0,3])).toBe('0000000000000000000000000000000000000000000000000000000000010')
expect(base3encoder.encode([0,0,0,0,0,0,0,0,0,0,1,0]),"256 = 1*3**5 + 1*3**2 + 1*3**1 + 1*3**0").toBe('0000000000000000000000000000000000000000000000000000000100111')

When the input is not a multiple of 12 bytes, we have to add some padding.

I’ve got this working perfectly with base 64 (it matches the native impl), but for base 3 my algo is a little off, but I can’t quite put my finger on where the problem is.

I’ve modified the code and test to run in StackOverflow. I believe the bug is in ChunkedBufferEncoder.decode but it could be in ChunkedBufferEncoder.encode. I know encode works for input bytes that are multiples of 12 (as shown above), but for anything else it gets a little crazy.

I’ve included a base64encoder in the test. That currently passes all tests and should continue to pass.

Where is the bug?

function getView(buffer) {
    if (ArrayBuffer.isView(buffer)) {
        return new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
    }
    if (buffer instanceof ArrayBuffer) {
        return new DataView(buffer, buffer.byteLength, buffer.byteLength);
    }
    return new DataView(Uint8Array.from(buffer).buffer);
}

function bufToInt(buffer) {
    if (buffer.length <= 1) {
        if (buffer.length === 0) {
            return 0n;
        }
        return BigInt(buffer[0]);
    }
    if (buffer.length >= 8) {
        let i = 0;
        let result = 0n;
        const view = getView(buffer);
        const end = buffer.length - 8;
        for (;;) {
            result |= BigInt(view.getBigUint64(i, false));
            i += 8;
            if (i >= end) {
                break;
            }
            result <<= 64n;
        }
        for (;i < buffer.length; ++i) {
            result = result << 8n | BigInt(buffer[i]);
        }
        return result;
    }
    let result = BigInt(buffer[0]);
    for (let i = 1; i < buffer.length; ++i) {
        result = result << 8n | BigInt(buffer[i]);
    }
    return result;
}

function calcCharsPerChunk(bytesPerChunk, base) {
    const min = 2n ** BigInt(8 * bytesPerChunk);
    let c = 1;
    let val = base;
    for (;;) {
        if (val >= min) return c;
        val *= base;
        ++c;
    }
}

function toArray(arr) {
    return Array.isArray(arr) ? arr : Array.from(arr);
}

class ChunkedBufferEncoder {
    alphabet;
    reverse;
    base;
    bytesPerChunk;
    charsPerChunk;
    constructor(alphabet, bytesPerChunk, charsPerChunk) {
        this.alphabet = toArray(alphabet);
        console.assert(this.alphabet.length >= 2);
        this.reverse = new Map(this.alphabet.map(((ch, i) => [ ch, BigInt(i) ])));
        this.base = BigInt(this.alphabet.length);
        this.bytesPerChunk = bytesPerChunk;
        if (charsPerChunk == null) {
            this.charsPerChunk = calcCharsPerChunk(bytesPerChunk, this.base);
        } else {
            this.charsPerChunk = charsPerChunk;
            console.assert(this.alphabet.length ** this.charsPerChunk >= 2 ** (8 * bytesPerChunk));
        }
    }
    encode(arr) {
        if (!arr?.length) {
            return "";
        }
        const buf = Uint8Array.from(arr);
        let i = 0;
        let result = "";
        do {
            const chunk = buf.slice(i, i + this.bytesPerChunk);
            let val = bufToInt(chunk);
            if (chunk.length < this.bytesPerChunk) {
                const missingBytes = this.bytesPerChunk - chunk.length;
                val <<= 8n * BigInt(missingBytes);
                result += this.intToArr(val).slice(0, -missingBytes).join("");
                return result;
            }
            result += this.intToStr(val);
            i += this.bytesPerChunk;
        } while (i < buf.length);
        return result;
    }
    padEnd(chunk) {
        if (chunk.length >= this.charsPerChunk) return chunk;
        return chunk.concat(Array(this.charsPerChunk - chunk.length).fill(this.alphabet[0]));
    }
    decode(str) {
        if (!str?.length) return new Uint8Array;
        const out = [];
        let i = 0;
        const arr = toArray(str);
        while (i < arr.length) {
            const chunk = arr.slice(i, i + this.charsPerChunk);
            if (chunk.length === this.charsPerChunk) {
                const num = this.arrToInt(chunk);
                for (let j = this.bytesPerChunk - 1; j >= 0; j--) {
                    out.push(Number(num >> BigInt(8 * j) & 0xffn));
                }
            } else {
                const missing = this.charsPerChunk - chunk.length;
                let num = this.arrToInt(this.padEnd(chunk));
                num >>= BigInt(8 * missing);
                const byteCount = this.bytesPerChunk - missing;
                for (let j = byteCount - 1; j >= 0; --j) {
                    out.push(Number(num >> BigInt(8 * j) & 0xffn));
                }
                break;
            }
            i += chunk.length;
        }
        return new Uint8Array(out);
    }
    arrToInt(arr) {
        let num = 0n;
        for (const ch of arr) {
            num = num * this.base + this.reverse.get(ch);
        }
        return num;
    }
    strToInt(str) {
        return this.arrToInt(toArray(str));
    }
    intToStr(num) {
        if (!num) {
            return this.alphabet[0].repeat(this.charsPerChunk);
        }
        let n = BigInt(num);
        let result = "";
        do {
            const rem = n % this.base;
            result = this.alphabet[Number(rem)] + result;
            n /= this.base;
        } while (n > 0n);
        return result.padStart(this.charsPerChunk, this.alphabet[0]);
    }
    intToArr(num) {
        if (!num) {
            return Array(this.charsPerChunk).fill(this.alphabet[0]);
        }
        let n = BigInt(num);
        let result = [];
        do {
            const rem = n % this.base;
            result.unshift(this.alphabet[Number(rem)]);
            n /= this.base;
        } while (n > 0n);
        while (result.length < this.charsPerChunk) {
            result.unshift(this.alphabet[0]);
        }
        return result;
    }
}

// ---------- TEST ----------

function randomUint8Array(minLen, maxLen) {
    return crypto.getRandomValues(new Uint8Array(Math.floor(Math.random() * (maxLen - minLen + 1)) + minLen))
}


const base64encoder = new ChunkedBufferEncoder('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',3)
const base3encoder = new ChunkedBufferEncoder('012', 12, 61)

const NUM_TESTS = 10000
const MIN_BYTES = 1
const MAX_BYTES = 17

function arrEq(a, b) {
    if (a.length !== b.length) return false;
    for (let i = 0; i < a.length; i++) {
        if (a[i] !== b[i]) return false;
    }
    return true;
}

function uint8ArrayToHex(arr) {
    return Array.from(arr, b => b.toString(16).toUpperCase().padStart(2, '0')).join(' ')
}


for(const encoder of [base64encoder,base3encoder]) {
    for(let i = 0; i < NUM_TESTS; i++) {
        const buf = randomUint8Array(MIN_BYTES, MAX_BYTES)
        const encoded = encoder.encode(buf)
        const decoded = encoder.decode(encoded)
        if(!arrEq(buf, decoded)) throw new Error(
            `Buf: ${uint8ArrayToHex(buf)} Encoded: ${encoded} Decoded: ${uint8ArrayToHex(decoded)}`
        )
    }
}

It might be the .slice(0,-missingBytes).

[0,0,0,0,0,0,0,0,0,0,1] (11 elements) should be padded such that it becomes [0,0,0,0,0,0,0,0,0,0,1,0] which encodes to 0000000000000000000000000000000000000000000000000000000100111, but when decoded again it’ll come out [0,0,0,0,0,0,0,0,0,0,1,0] with the “missing byte” appended. I don’t want that. Base64 uses = as padding, but it’s not really necessary because you can figure out how many bytes/chars it’s supposed to be with a bit of math. I’m not actually positive if it’s possible to do something similar with non powers of 2.

Site created with Blogger does not have the sitemap updated on Search Console and has custom codes

The site https://yoursupergames.blogspot.com/ created with Blogger has the Contempo Light theme and is customized. I noticed that the custom codes I inserted have problems. They do not seem to work properly.

Search Console has not detected the sitemap for 3 months. I have reset the theme and disabled all codes in widgets. I do not understand what the problem is.

I even lost the indexing of the home page and now I have 0 pages indexed after 5 months.

I created some text on the home page and inserted the appropriate keywords, but nothing has changed.

I do not understand the nature of the problems on my website.

<!-- Disable the blogger.com cookie banner -->
<script>/*<![CDATA[*/ cookieChoices = {}; /*]]>*/</script>
    
<!-- Google tag (gtag.js) -->
<script async='async' src='https://www.googletagmanager.com/gtag/js?id=G-SZ20W1F1MR'/>
<script> 
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag(&#39;js&#39;, new Date());

  gtag(&#39;config&#39;, &#39;G-SZ20W1F1MR&#39;);
</script>

<!-- Publish consent banner -->    
<script type='text/javascript'>
var _iub = _iub || [];
_iub.csConfiguration = {&quot;siteId&quot;:3941908,&quot;cookiePolicyId&quot;:85220213,&quot;lang&quot;:&quot;en&quot;,&quot;storage&quot;:{&quot;useSiteId&quot;:true}};
</script>
<script src='https://cs.iubenda.com/autoblocking/3941908.js' type='text/javascript'/>
<script src='//cdn.iubenda.com/cs/gpp/stub.js' type='text/javascript'/>
<script async='async' charset='UTF-8' src='//cdn.iubenda.com/cs/iubenda_cs.js' type='text/javascript'/>

<!-- Aggiunta di Font Awesome -->
<link crossorigin='anonymous' href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css' integrity='sha512-Evv84Mr4kqVGRNSgIGL/F/aIDqQb7xQ2vcrdIwxfjThSH8CSR7PBEakCr51Ck+w+/U6swU2Im1vVX0SVk9ABhg==' referrerpolicy='no-referrer' rel='stylesheet'/>
<meta content='width=device-width, initial-scale=1' name='viewport'/>

<!-- Pubblicità automatica Adsense -->    
<script async='async' crossorigin='anonymous' src='https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3142475692533377'>
</script>

<!-- Titoli delle pagine e post --> 
<title>
  <b:if cond='data:blog.pageType == &quot;index&quot;'>
    <data:blog.pageTitle/>
  <b:else/>
  
    <b:if cond='data:blog.pageType == &quot;item&quot;'>
      <data:view.title.escaped/> - Online Game
    <b:else/>
  
      <b:if cond='data:blog.pageType == &quot;static_page&quot;'>
        <b:if cond='data:view.title.escaped == &quot;About Us&quot;'>About Us - Your Super Games</b:if>
        <b:if cond='data:view.title.escaped == &quot;Contact Us&quot;'>Contact Us - Your Super Games</b:if>
        <b:if cond='data:view.title.escaped == &quot;Privacy Policy&quot;'>Privacy Policy - Your Super Games</b:if>
        <b:if cond='data:view.title.escaped == &quot;Terms of Service&quot;'>Terms of Service - Your Super Games</b:if>
        <b:if cond='data:view.title.escaped == &quot;FAQ&quot;'>FAQs - Your Super Games</b:if>
        <b:if cond='data:view.title.escaped == &quot;Accessibility&quot;'>Accessibility - Your Super Games</b:if>
        <b:if cond='data:view.title.escaped == &quot;Disclaimer&quot;'>Disclaimer - Your Super Games</b:if>
        <b:if cond='data:view.title.escaped == &quot;Cookie Policy&quot;'>Cookie Policy - Your Super Games</b:if>

        <b:if cond='data:view.title.escaped != &quot;About Us&quot;                      and data:view.title.escaped != &quot;Contact Us&quot;                     and data:view.title.escaped != &quot;Privacy Policy&quot;                     and data:view.title.escaped != &quot;Terms of Service&quot;                     and data:view.title.escaped != &quot;FAQ&quot;                     and data:view.title.escaped != &quot;Accessibility&quot;                     and data:view.title.escaped != &quot;Disclaimer&quot;                     and data:view.title.escaped != &quot;Cookie Policy&quot;'>
          <data:view.title.escaped/> - Your Super Games
        </b:if>
      <b:else/>
        <data:view.title.escaped/> - Your Super Games
      </b:if>
    </b:if>
  </b:if>
</title>

Extending nodes: Lexical node does not exist in active editor

I’m running a React Vite project with a Lexical editor. I’m trying to extend the list node, to make it styleable (square, circle, roman numerals, etc.). Here is my extended node file:

    import { ElementNode, createCommand } from 'lexical';
    import { ListNode } from '@lexical/list';

    export const INSERT_UNORDERED_CUSTOM_LIST_COMMAND = createCommand('INSERT_UNORDERED_CUSTOM_LIST_COMMAND');

    export class ExtendedListNode extends ListNode {
        __listStyleType;
        __key;

        static getType() {
            return 'custom-list'
        }

        static clone(node) {
            console.log("ExtendedListNode: clone(): node", node);
            return new ExtendedListNode(node.__listStyleType, node.__key);
        }

        consructor(listStyleType, key) {
            console.log("ExtendedListNode: constructor(): listStyleType", listStyleType);
            console.log("ExtendedListNode: constructor(): key", key);
            super('bullet', 1, key)
            this.__listStyleType = listStyleType || 'circle';
            this.__key = key;
        }

        createDOM(config) {
            const dom = document.createElement(this.getTag());
            dom.style.listStyleType = this.__listStyleType;
            return dom;
        }

        updateDOM(prevNode, dom, config) {
            if (prevNode.__listStyleType !== this.__listStyleType) {
                dom.style.listStyleType = this.__listStyleType;
            }
            return false;
        }

        static importJSON(serializeNode) {
            return {
                ...super.importJSON(serializedNode),
                listStyleType: serializedNode.listStyleType
            };
        }

        exportJSON() {
            return {
                ...super.exportJSON(),
                listStyleType: this.__listStyleType
            };
        }

        getTag() {
            return 'ul';
        }

        getListStyleType(listStyleType) {
            return this.__listStyleType;
        }

        setListStyleType(listStyleType) {
            this.__listStyleType = listStyleType;
        }

        export function $createExtendedListNode(listStyleType, key) {
            console.log(`$createExtendedListNode('${listStyleType}')`);
            return new ExtendedListNode(listStyleType, key);
        }

        export function $isExtendedListNode(node) {
            return node instanceof ExtendedListNode;
        }
    }

Here is my config that replaces the ListNode with the ExtendedListNode:

    import { ListItemNode, ListNode } from '@lexical/list';
    import { ExtendedListNode } from '/src/components/lexical/ExtendedListNode';

    const editorConfig = {
        namespace: 'MyApp',
        nodes: [
            ListItemNode,  //other nodes left out of this snippet to keep it simple
            { 
                replace: ListNode, with: (listNode) => {
                    console.log("this listNode node", listNode);
                    const newNode = new ExtendedListNode('square');  //, listNode.__key  , listNode.getKey()
                    console.log("this newNode node", newNode);
                    return newNode;
                },
                withKlass: ExtendedListNode,
            },
        ],
        onError(error) {
            throw error;
        },
        theme: LexicalTheme,
    }

The error message I’m getting (line numbers may be off, as I can’t post all the code):
screenshot of error message

Text of error message (line numbers may be off, as I can’t post all the code):

Uncaught Error: Lexical node does not edist in active editor stage. Avoid using the same node references between nested closures from editorState.read/editor.update.
    at editor.update.discrete (lexicalUtil.js:42:29)

Uncaught Error: Lexical node does not edist in active editor stage. Avoid using the same node references between nested closures from editorState.read/editor.update.
    at ExtndedListNode.getLatest
     at ExtndedListNode.getWritable
     at ExtndedListNode.markDirty
     at editor._pendingEditorState.tag
     at $beginUpdate
     at updateEditor
     at markAllNodesAsDirty
     at LexicalEditor.registerNodeTransform
     at @lexical_react_Lexic...js
     at commitHookEfectListMount

I can see my editor flash on the screen or a split second, but then the page goes blank white. If I comment out the extended list node replace in the editorConfig, the page and editor render fine, so I’m guessing I’ve got something coded wrong in that, or in the extended node file. Any ideas? Thanks!

Delaying 2 setIntervals using setTimeout doesn’t work

I’ve been writing a userscript for a site and I want to show an update notification while the user is tabbed off of the site, and I came up with an idea to use the site title for that.

This is my current code:

let str = "Please update your script!"
let str2 = "[insert previous site title]"
setInterval(function(){document.title = str}, 1000)
setTimeout(function(){setInterval(function(){document.title = str2}, 1000)}, 1000)

the code should work in theory but instead flashes str for way less than 1000 ms, and goes back to str2 when done, and the routine never repeats, even with the setInterval.

I’ve tried moving the code to a function and using setInterval() on that too, but it does the same thing.
The code in question:

function updateDialog(str, str2) {
    document.title = str
    setTimeout(function(){document.title = str2}, 1000)
}
setInterval(updateDialog("Please update your script!", "[insert previous site name]"), 1000)

I’ve already got the update check code for that, by the way.

Any reason for why this doesn’t work the expected way?

How to hide other element when I click on one?

I’m trying to hide the other buttons that are created with my for loop when I click on one of the element I created.

Here is the loop where my button elements are created:

//diplay the fixed bar product by name
for (let i = 0; i < barType.fixedBar.length; i++) {
  barNameButton = document.createElement("button");
  barNameButton.setAttribute("classe", `${barType.fixedBar[i].name}`);
  document.body.appendChild(barNameButton);
  barNameButton.innerHTML = `${barType.fixedBar[i].name}`;
}

When one of the names has been clicked on I want to hide the others and display some options for that specific type that has been selected.

Using Framer Motion add class to div after scrolling fully past it

I have an element that becomes visible when it enters the viewport, with scroll animated child elements, I need for it to stay visible after scrolling past, with the animations done after, but reverses animations with scrolling up and reverts to being invisible when scrolled back up again.

I was able to achieve that using GSAP using the scrolltrigger toggleClass, onLeave and onEnterBack

const tl = gsap.timeline({
         scrollTrigger: {
           trigger: section,
           scrub: true,
        start: "top 80%",
         end: "center center",
            toggleClass: "isVisible",
          onLeave: () => section.classList.add("isScrolled"),
           onEnterBack: () => section.classList.remove("isScrolled"),
         },
       });

but I had to move from gsap to framer motion since I have quite a bit of animations that require dom-manpulation and elements entering and exiting it plus between route loading animations, which unfortunately GSAP can’t do.

So with Framer Motion, I’m assuming this is possible to do but the documentation isn’t that great so I couldn’t find what I was looking for.

And I wanted to have that done using Framer Motion because I think it’s better to have the code relating to these elements in one place and is done using one library.

PHP not updating global variable DURING loop? [duplicate]

I have a javascript file that sends XMLHttpRequests to a PHP file. The javascript file is something like this:

let formData = new FormData();
formData.append("field1", ["mockdata1", "mockdata2"]);

let xhr = new XMLHttpRequest();
xhr.open("POST", "../phpscripts/agent.php");
xhr.send(formData);

And the PHP file is something like this:

//globals 
$globalResult = "undefined";


if( !empty( $_POST['field1'] )){
  
   $localResult; 

   for($x=0; $x<someLimit; $x++){
      //update $localResult with cURL calls
      
      //also set the globalResult
      set_globalResult($localResult);

    }

    return $result;
}

function get_globalResult(){
  global $globalResult;
  return $globalResult;
}

function set_globalResult($param){
   global $globalResult;
   $globalResult = $param;
}

The cURL calls that occur within the loop in my PHP file take some time. Each one can take between 0.5 to 2 seconds. I find that it takes about 10 seconds or so for my xhr object in Javascript to finally get the response.

What I want to do is create a kind of listening system so that it can read the progress that is occuring within the loop. i.e. read the result after each cURL call.

So I have created a global variable in my php file called $globalResult. Which is supposed to get updated from inside the loop. I have also created a getter and setter for this variable.

So to use this global variable, I have created a second XHR object in my javascript file that makes requests to this same PHP file every 1 second (using setInterval). Something like this:

setInterval( function() {
  let form2 = new FormData();
  form2 .append("listen", ["mockdata1", "mockdata2"]);

  let xhr_listener = new XMLHttpRequest();
  xhr_listener.open("POST", "../phpscripts/agent.php");
  xhr_listener.send(form2 );
}, 1000);

xhr_listener.onreadystatechange = function (){
            if (xhr_listener.readyState === XMLHttpRequest.DONE){
               //inject xhr_listener.response into a div
              }

And the PHP file has an additional part like this:

if( !empty( $_POST['listen'] )){
      $result = get_globalResult();
    
    $returnPackage = array("Result" => $result);

   echo       json_encode($returnPackage);  
}

Even with a setup like this, I find that the response of that xhr_listener is always “undefined” (the initial value of the global variable). Even though I am setting a new value to the global variable from inside the loop?

Why?

It seems that the new value assignment to the global value finalizes only after that loop is finished in PHP. Is that really how it works? Or is the updated value accessible after each iteration of the loop?

TypeScript: Complex conditional form field type system with dynamic validation based on multiple option flags

I’m building a TypeScript form library with conditional fields that need to be dynamically typed based on form type and several option flags. I need a robust type system that shows the correct field names based on multiple conditions.

Base Types

export type FormType = "bank" | "card" | "token";

export type CardFieldName = "name" | "number" | "expiration_date" | "security_code";
export type BankFieldName = "account_number" | "bank_code" | "account_type";
export type AddressFieldName = "address_line1" | "address_line2" | "address_city" | "address_state" | "address_region" | "address_country" | "address_postal_code";

export type FieldName = CardFieldName | BankFieldName | AddressFieldName;

Form Creation API

// Basic form creation
const tokenForm = createForm({ formType: 'token' }) // Shows both bank and card fields
const bankForm = createForm({ formType: 'bank' })   // Shows only bank fields
const cardForm = createForm({ formType: 'card' })   // Shows only card fields

// Advanced usage with options
const advancedForm = createForm({
  formType: 'card',
  showAddress: true,
  showLabels: true,
  labels: {
    name: 'Full Name on Card',
    number: 'Card Number',
    address_line1: 'Address Line 1' // Only valid when showAddress is true
  },
  requiredFields: ['name', 'number'] // Should only allow valid field names
})

Form Option Type

type FormOptions = {
  formType: FormType; /* If card show CardFieldName's - If bank show BankFieldName's - If token show both CardFieldName's and BankFieldName's */
  showAddress?: boolean; /* If showAddress is true, it should include all of the AddressFieldName's */
  showLabels?: boolean;
  showPlaceholders?: boolean;
  hideErrorMessages?: boolean;
  labels?: Record<FieldName, string>; /* If showLabels is true, a user should be able based off of the field types so we know which field names we can set labels for */
  placeholders?: Record<FieldName, string>; /* If showPlaceholders is true, a user should be able based off of the field types so we know which field names we can set placeholders for */
  errorMessages?: Record<FieldName, string>; /* If hideErrorMessages is false, a user should be able based off of the field types so we know which field names we can set error messages for */
  defaultValues?: Record<FieldName, string>; /* We need to know all the field names available so we know which fields we can set default values for. Some fields DO NOT allow default values though even if they are present in field names */
  requiredFields?: Array<FieldName>; /* We need to know all the field names available so we know which fields we can set as required. Some fields are required NO MATTER WHAT so we can only set some fields as required */
  hideFields?: Array<FieldName>; /* We need to know all the field names available so we know which fields we can hide. Some fields are can NOT be hidden though even if they are available in field names */
}

Desired Type Behavior

I need TypeScript to enforce the following complex rules:

  1. Form Type Restrictions:

    • If formType: 'card', only CardFieldName values should be valid
    • If formType: 'bank', only BankFieldName values should be valid
    • If formType: 'token', both CardFieldName and BankFieldName values should be valid
  2. Conditional Address Fields:

    • If showAddress: true, then AddressFieldName values should also be valid
    • If showAddress is falsy, AddressFieldName values should be invalid
  3. Option-Dependent Record Types:

    • labels should only allow keys from the available field names, and only if showLabels: true
    • placeholders should only allow keys from the available field names, and only if showPlaceholders: true
    • errorMessages should only allow keys from the available field names, and only if hideErrorMessages: false
  4. Field Restrictions with Business Logic:

    • defaultValues should only allow keys from the available field names, but exclude fields that don’t support default values
    • requiredFields should only allow values from the available field names, but exclude fields that are always required
    • hideFields should only allow values from the available field names, but exclude fields that cannot be hidden

Example Scenarios That Should Type-Check Correctly

// Valid: card fields only
const cardForm = createForm({
  formType: 'card',
  labels: {
    name: 'Name on Card',
    number: 'Card Number'
  }
});

// Invalid: includes bank field with card form
const invalidForm1 = createForm({
  formType: 'card',
  labels: {
    name: 'Name on Card',
    account_number: 'Account Number' // Error: not valid for card form
  }
});

// Invalid: includes address field without showAddress
const invalidForm2 = createForm({
  formType: 'card',
  labels: {
    name: 'Name on Card',
    address_line1: 'Street Address' // Error: showAddress not true
  }
});

// Valid: address fields with showAddress true
const cardWithAddressForm = createForm({
  formType: 'card',
  showAddress: true,
  placeholders: {
    name: 'John Doe',
    address_line1: '123 Main St' // Valid because showAddress is true
  }
});

// Invalid: using errorMessages when hideErrorMessages is true
const invalidForm3 = createForm({
  formType: 'bank',
  hideErrorMessages: true,
  errorMessages: { // Error: errorMessages not allowed when hideErrorMessages is true
    account_number: 'Invalid account number'
  }
});

// Invalid: trying to make a non-configurable field required
const invalidForm4 = createForm({
  formType: 'card',
  requiredFields: [
    'security_code' // Error: security_code is always required and cannot be in requiredFields
  ]
});

// Invalid: trying to hide a field that cannot be hidden
const invalidForm5 = createForm({
  formType: 'card',
  hideFields: [
    'number' // Error: card number cannot be hidden
  ]
});

// Invalid: trying to set default for a field that doesn't allow defaults
const invalidForm6 = createForm({
  formType: 'card',
  defaultValues: {
    security_code: '123' // Error: security_code cannot have a default value
  }
});

What I’m Looking For

I need a comprehensive type solution that:

  1. Handles all conditional field types based on formType and showAddress
  2. Enforces the presence/absence of option-dependent fields like labels, placeholders, and errorMessages based on their corresponding boolean flags
  3. Implements business logic restrictions for defaultValues, requiredFields, and hideFields
  4. Provides helpful TypeScript error messages
  5. Achieves proper type inference so developers get autocomplete for the correct fields only

What would be the best approach? Should I use:

  • Discriminated unions with conditional types?
  • Generics with mapped types?
  • Custom utility types?
  • A combination of these?

Also, how would you recommend handling runtime validation alongside static typing?

PHP not updating global variable DURING loop?

I have a javascript file that sends XMLHttpRequests to a PHP file. The javascript file is something like this:

let formData = new FormData();
formData.append("field1", ["mockdata1", "mockdata2"]);

let xhr = new XMLHttpRequest();
xhr.open("POST", "../phpscripts/agent.php");
xhr.send(formData);

And the PHP file is something like this:

//globals 
$globalResult = "undefined";


if( !empty( $_POST['field1'] )){
  
   $localResult; 

   for($x=0; $x<someLimit; $x++){
      //update $localResult with cURL calls
      
      //also set the globalResult
      set_globalResult($localResult);

    }

    return $result;
}

function get_globalResult(){
  global $globalResult;
  return $globalResult;
}

function set_globalResult($param){
   global $globalResult;
   $globalResult = $param;
}

The cURL calls that occur within the loop in my PHP file take some time. Each one can take between 0.5 to 2 seconds. I find that it takes about 10 seconds or so for my xhr object in Javascript to finally get the response.

What I want to do is create a kind of listening system so that it can read the progress that is occuring within the loop. i.e. read the result after each cURL call.

So I have created a global variable in my php file called $globalResult. Which is supposed to get updated from inside the loop. I have also created a getter and setter for this variable.

So to use this global variable, I have created a second XHR object in my javascript file that makes requests to this same PHP file every 1 second (using setInterval). Something like this:

setInterval( function() {
  let form2 = new FormData();
  form2 .append("listen", ["mockdata1", "mockdata2"]);

  let xhr_listener = new XMLHttpRequest();
  xhr_listener.open("POST", "../phpscripts/agent.php");
  xhr_listener.send(form2 );
}, 1000);

xhr_listener.onreadystatechange = function (){
            if (xhr_listener.readyState === XMLHttpRequest.DONE){
               //inject xhr_listener.response into a div
              }

And the PHP file has an additional part like this:

if( !empty( $_POST['listen'] )){
      $result = get_globalResult();
    
    $returnPackage = array("Result" => $result);

   echo       json_encode($returnPackage);  
}

Even with a setup like this, I find that the response of that xhr_listener is always “undefined” (the initial value of the global variable). Even though I am setting a new value to the global variable from inside the loop?

Why?

It seems that the new value assignment to the global value finalizes only after that loop is finished in PHP. Is that really how it works? Or is the updated value accessible after each iteration of the loop?