hi i am creating a website and i am experiencing a scrolling glinch. I cant seem to pin-point the problem and I was hoping someone could help me. Currently its taking me 2 scrolls to get to the bottom of the page when it should only take one smooth scroll. For some reason, it always stops at the “about me” section before I have to scroll again to reach the bottom. Same problem when I scroll from the bottom to the top. How do I solve this? What are some things I should look out for?
Category: javascript
Category Added in a WPeMatico Campaign
Sperated Strings not picked up in javascript
I’m Using this code to merge two updates. Col c contains current status of a tenant in each cell its for a different tenant. My team ads in col F the update. At the moment code is running but no issues.
function mergeColumnsCAndF() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
// Get all data in columns C and F
const data = sheet.getRange(1, 3, sheet.getLastRow(), 2).getValues(); // Column C (Status) and Column F (Updates)
// Define categories
const categories = {
problems: “Problems”,
payments: “Payments”,
tenantCommitments: “Tenant Commitments”,
landlordObligations: “Landlord Obligations”,
ebm: “EBM Codes”
};
// Loop through each row and merge updates into the status
const mergedData = data.map(([status, update], index) => {
if (!update.trim()) return [status]; // No update, keep the original status
let updatedStatus = status || ""; // Start with existing status
let extractedCategories = {}; // Object to log categories and updates for debugging
// Normalize update string: remove extra spaces and standardize formatting
const normalizedUpdate = update.replace(/s+:s+/g, ":").trim();
// Split updates from F into individual categories
const updates = normalizedUpdate.split(/(?=b(?:Problems|Payments|Tenant Commitments|Landlord Obligations|EBM Codes):)/i);
// Helper function to update a specific category
function updateCategory(category, newInfo) {
const regex = new RegExp(`${category}:.*?(\n|$)`, "gi"); // Match category in the existing status
const cleanedStatus = updatedStatus.replace(regex, "").trim(); // Remove existing category info
return `${cleanedStatus}n${category}: ${newInfo}`.trim(); // Append new category info
}
// Process each update and match it to its category
updates.forEach((item) => {
const lowerItem = item.toLowerCase();
if (lowerItem.includes("problems")) {
updatedStatus = updateCategory(categories.problems, item.split(":")[1].trim());
extractedCategories[categories.problems] = item.split(":")[1].trim(); // Log Problems
} else if (lowerItem.includes("payments")) {
updatedStatus = updateCategory(categories.payments, item.split(":")[1].trim());
extractedCategories[categories.payments] = item.split(":")[1].trim(); // Log Payments
} else if (lowerItem.includes("tenant commitments")) {
updatedStatus = updateCategory(categories.tenantCommitments, item.split(":")[1].trim());
extractedCategories[categories.tenantCommitments] = item.split(":")[1].trim(); // Log Tenant Commitments
} else if (lowerItem.includes("landlord")) {
updatedStatus = updateCategory(categories.landlordObligations, item.split(":")[1].trim());
extractedCategories[categories.landlordObligations] = item.split(":")[1].trim(); // Log Landlord Obligations
} else if (lowerItem.includes("ebm")) {
updatedStatus = updateCategory(categories.ebm, item.split(":")[1].trim());
extractedCategories[categories.ebm] = item.split(":")[1].trim(); // Log EBM Codes
}
});
// Log the extracted categories for debugging
Logger.log(`Row ${index + 1}: Extracted Categories: ${JSON.stringify(extractedCategories)}`);
// Remove duplicate lines from the final status
const uniqueLines = [...new Set(updatedStatus.split("n"))].join("n").trim();
return [uniqueLines]; // Return the updated status
});
// Write merged data back into Column C
sheet.getRange(1, 3, mergedData.length, 1).setValues(mergedData);
// Clear all updates in Column F after processing
sheet.getRange(1, 6, data.length, 1).clearContent();
SpreadsheetApp.getUi().alert(“Columns C have been updated with merged statuses, and Column F has been cleared.”);
}
What is the significance of the spread operator in this code?
I am a React newbie. Please help me understand why a spread operator is used in the following. I’ve tried to run the same code without using it and I get all sorts of errors.
App.js contains:
import { useFormInput } from './useFormInput.js';
export default function Form() {
const firstNameProps = useFormInput('Mary');
const lastNameProps = useFormInput('Poppins');
return (
<>
<label>
First name:
<input {...firstNameProps} />
</label>
<label>
Last name:
<input {...lastNameProps} />
</label>
<p><b>Good morning, {firstNameProps.value} {lastNameProps.value}.</b></p>
</>
);
}
The referenced file contains:
import { useState } from 'react';
export function useFormInput(initialValue) {
const [value, setValue] = useState(initialValue);
function handleChange(e) {
setValue(e.target.value);
}
const inputProps = {
value: value,
onChange: handleChange
};
return inputProps;
}
From the little I understand, the spread operator copies/uses slices of arrays. But, I don’t follow how that applies here.
Detect focus enter direction
I need to detect if an element received focus as a result of the user requesting to focus the next element or previous element ( TAB or SHIFT + TAB navigation ).
Is there any native solution for this ?
Using a keydown listener to check if tab or shift was pressed only works as long as the focus doesn’t leave the “document”.
If the element is the first or last focusable element and tab navigation is used the focus will jump to the browser toolbar and the key down listener will not longer work to detect the focus direction.
For accessibility reasons I need to keep the default focus navigation behavior ( Focus jumping to browser toolbar )
Forwarding a discord message with a bot (Javascript)
Discord recently implemented functionality for forwarding messages from one channel (or server) to another. Is there a way for bots to forward messages?
In particular I would like to write a command, say it’s called !forward, where if I reply to a particular message with !forward, it will then forward that message to a specified channel.
I’ve been running this bot for about a year so I’m not brand new to this, but I can’t seem to find any documentation on how/if it’s possible to forward messages with a bot.
Any guidance is appreciated. Thank you!
How to load an LDR file using THREE.js
I am attempting to display an .ldr file in a web page using THREE.js. An .ldr file is a LEGO version of a .mpd file. The THREE.js documentation says to convert the .ldr file to a packed .mpd file, which I have done successfully.
Note: .ldr is a LEGO LDraw file, and a .mpd is a 3D Models to Print file.
I then used the .ldr example from the LDrawLoader documentation and this works. However, I want the simplest version of displaying the .mpd file. The example code has a preloader, a small GUI, and the option to select from a list of .mpd files.
I have attempted to remove the GUI and preloader but it stops everything from working. I’ve tried the code from the documentation (not the examples page) and a similar set of code from the LDraw forum.
I have had limited experience with THREE.js and anything related to 3D animation.
Here is my current working code:
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - LDrawLoader</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
<style>
body {
color: #444;
}
a {
color: #08f;
}
</style>
</head>
<body>
<script type="importmap">
{
"imports": {
"three": "../build/three.module.js",
"three/addons/": "./jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js';
import { LDrawLoader } from 'three/addons/loaders/LDrawLoader.js';
import { LDrawUtils } from 'three/addons/utils/LDrawUtils.js';
import { LDrawConditionalLineMaterial } from 'three/addons/materials/LDrawConditionalLineMaterial.js';
let container, progressBarDiv;
let camera, scene, renderer, controls, gui, guiData;
let model;
const ldrawPath = 'models/';
const modelFileList = {
'Car': 'car.ldr_Packed.mpd',
'Block': 'block.ldr_Packed.mpd',
};
init();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set( 150, 200, 250 );
//
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setAnimationLoop( animate );
renderer.toneMapping = THREE.ACESFilmicToneMapping;
container.appendChild( renderer.domElement );
// scene
const pmremGenerator = new THREE.PMREMGenerator( renderer );
scene = new THREE.Scene();
scene.background = new THREE.Color( 0xdeebed );
scene.environment = pmremGenerator.fromScene( new RoomEnvironment() ).texture;
controls = new OrbitControls( camera, renderer.domElement );
controls.enableDamping = true;
//
guiData = {
modelFileName: modelFileList[ 'Car' ],
displayLines: true,
conditionalLines: true,
smoothNormals: true,
buildingStep: 0,
noBuildingSteps: 'No steps.',
flatColors: false,
mergeModel: false
};
window.addEventListener( 'resize', onWindowResize );
progressBarDiv = document.createElement( 'div' );
progressBarDiv.innerText = 'Loading...';
progressBarDiv.style.fontSize = '3em';
progressBarDiv.style.color = '#888';
progressBarDiv.style.display = 'block';
progressBarDiv.style.position = 'absolute';
progressBarDiv.style.top = '50%';
progressBarDiv.style.width = '100%';
progressBarDiv.style.textAlign = 'center';
// load materials and then the model
reloadObject( true );
}
function updateObjectsVisibility() {
model.traverse( c => {
if ( c.isLineSegments ) {
if ( c.isConditionalLine ) {
c.visible = guiData.conditionalLines;
} else {
c.visible = guiData.displayLines;
}
} else if ( c.isGroup ) {
// Hide objects with building step > gui setting
c.visible = c.userData.buildingStep <= guiData.buildingStep;
}
} );
}
function reloadObject( resetCamera ) {
if ( model ) {
scene.remove( model );
}
model = null;
updateProgressBar( 0 );
showProgressBar();
// only smooth when not rendering with flat colors to improve processing time
const lDrawLoader = new LDrawLoader();
const loader = new LDrawLoader();
lDrawLoader.setConditionalLineMaterial( LDrawConditionalLineMaterial );
lDrawLoader.smoothNormals = guiData.smoothNormals && ! guiData.flatColors;
lDrawLoader
.setPath( ldrawPath )
.load( guiData.modelFileName, function ( group2 ) {
if ( model ) {
scene.remove( model );
}
model = group2;
// demonstrate how to use convert to flat colors to better mimic the lego instructions look
if ( guiData.flatColors ) {
function convertMaterial( material ) {
const newMaterial = new THREE.MeshBasicMaterial();
newMaterial.color.copy( material.color );
newMaterial.polygonOffset = material.polygonOffset;
newMaterial.polygonOffsetUnits = material.polygonOffsetUnits;
newMaterial.polygonOffsetFactor = material.polygonOffsetFactor;
newMaterial.opacity = material.opacity;
newMaterial.transparent = material.transparent;
newMaterial.depthWrite = material.depthWrite;
newMaterial.toneMapping = false;
return newMaterial;
}
model.traverse( c => {
if ( c.isMesh ) {
if ( Array.isArray( c.material ) ) {
c.material = c.material.map( convertMaterial );
} else {
c.material = convertMaterial( c.material );
}
}
} );
}
// Merge model geometries by material
if ( guiData.mergeModel ) model = LDrawUtils.mergeObject( model );
// Convert from LDraw coordinates: rotate 180 degrees around OX
model.rotation.x = Math.PI;
scene.add( model );
guiData.buildingStep = model.userData.numBuildingSteps - 1;
updateObjectsVisibility();
// Adjust camera and light
const bbox = new THREE.Box3().setFromObject( model );
const size = bbox.getSize( new THREE.Vector3() );
const radius = Math.max( size.x, Math.max( size.y, size.z ) ) * 0.5;
if ( resetCamera ) {
controls.target0.copy( bbox.getCenter( new THREE.Vector3() ) );
controls.position0.set( - 2.3, 1, 2 ).multiplyScalar( radius ).add( controls.target0 );
controls.reset();
}
createGUI();
hideProgressBar();
}, onProgress, onError );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function createGUI() {
if ( gui ) {
gui.destroy();
}
gui = new GUI();
gui.add( guiData, 'modelFileName', modelFileList ).name( 'Model' ).onFinishChange( function () {
reloadObject( true );
} );
gui.add( guiData, 'flatColors' ).name( 'Flat Colors' ).onChange( function () {
reloadObject( false );
} );
gui.add( guiData, 'mergeModel' ).name( 'Merge model' ).onChange( function () {
reloadObject( false );
} );
if ( model.userData.numBuildingSteps > 1 ) {
gui.add( guiData, 'buildingStep', 0, model.userData.numBuildingSteps - 1 ).step( 1 ).name( 'Building step' ).onChange( updateObjectsVisibility );
} else {
gui.add( guiData, 'noBuildingSteps' ).name( 'Building step' ).onChange( updateObjectsVisibility );
}
gui.add( guiData, 'smoothNormals' ).name( 'Smooth Normals' ).onChange( function changeNormals() {
reloadObject( false );
} );
gui.add( guiData, 'displayLines' ).name( 'Display Lines' ).onChange( updateObjectsVisibility );
gui.add( guiData, 'conditionalLines' ).name( 'Conditional Lines' ).onChange( updateObjectsVisibility );
}
//
function animate() {
controls.update();
render();
}
function render() {
renderer.render( scene, camera );
}
function onProgress( xhr ) {
if ( xhr.lengthComputable ) {
updateProgressBar( xhr.loaded / xhr.total );
console.log( Math.round( xhr.loaded / xhr.total * 100, 2 ) + '% downloaded' );
}
}
function onError( error ) {
const message = 'Error loading model';
progressBarDiv.innerText = message;
console.log( message );
console.error( error );
}
function showProgressBar() {
document.body.appendChild( progressBarDiv );
}
function hideProgressBar() {
document.body.removeChild( progressBarDiv );
}
function updateProgressBar( fraction ) {
progressBarDiv.innerText = 'Loading... ' + Math.round( fraction * 100, 2 ) + '%';
}
</script>
</body>
</html>
I have a GitHub repo with different attempts here:
https://github.com/codeadamca/nodejs-three-ldr
The best code is one called working.html.
To summarize, I want to remove the GUI and preloader from the THREE.js LDrawLoader example.
loading content thru PHP to simplify or is there a way to load it in a div?
I have my header/css and part of the body including the <div tag for the cell the content is in as one file and then the footer with the and and segment as another file and then have the following code:
How do I make it so it will load content per a PHP page with the content in it… it’s all supposed to go in one div on the page and then the header and footer (the parts of the page that stay the same which is everything except that div) saved as separate files to minimize loading time…
<!DOCTYPE html>
<html lang="en">
<?php
$PageTitle="Havent // Heavent Made // Hellt Mindedt // Manualt";
function customPageHeader(){?>
<!--Arbitrary HTML Tags-->
<?php }
include_once('file:///home/chronos/u-57608984ca0e6dfae1c20c6c0ed79e71e9626f08/MyFiles/Downloads/header.php');
include_once("content");
include_once('file:///home/chronos/u-57608984ca0e6dfae1c20c6c0ed79e71e9626f08/MyFiles/Downloads/footer.php');
?>
Why am I getting the errors “dyld: Library not loaded:” and “zsh: command not found: electron” when making the electron quick start project?
I am trying to learn how to build an electron app, so I decided to try making the quickstart project found on the official website here.
However, I quickly ran into problems because I keep getting errors, and I cannot even begin to build the app because electron won’t run.
I downloaded the latest LTS version of Node.js, and then I ran the following commands in the terminal:
npm init -y
npm i --save-dev electron
touch main.js
I did not modify the main.js file, so it is blank.
I then changed the default scripts in package.json into:
"start": "electron ."
After this, I then ran npm start, but it gave me the following error:
dyld: Library not loaded: /System/Library/Frameworks/UniformTypeIdentifiers.framework/Versions/A/UniformTypeIdentifiers
and it also said Reason: image not found
I tried deleting all the files and restarting from scratch, thinking that I might have made a mistake somewhere.
I tried putting in console.log("Hello World") in the main.js file, and then running npm start again.
I tried shutting down my computer and turning it on again.
None of these things worked.
I also tried to run electron . directly in the command line, and that’s when I got the error zsh: command not found: electron.
I also tried starting over again and making electron a dependency instead of dev dependency, but I still got all the same errors.
I tried googling different keywords and phrases from the errors I received, but I could not find anything that I could try to use as a possible solution.
The only way I could get my main.js to run was if I put node main.js in the command line, and it properly logged Hello World in the terminal.
I’m not sure if it is relevant, but for reference I am using a 2019 16-inch Macbook Pro on macOS Catalina 10.15.7.
If there is already a similar case out there, I apologize that I couldn’t find it due to my lack of experience. I am an absolute beginner in electron and I’m just starting to figure things out. I would appreciate any help on this. Thank you.
Is it possible to create an npm library that uses service workers without requiring end-user script configuration?
The Problem
I want to create an npm library that uses service workers under the hood, where the end user does not need to configure anything—ideally, not even place or reference a sw.js file.
The main challenge I’m facing is that navigator.serviceWorker.register('somePath') requires the somePath to be relative to the final HTML file where the code is executed. This depends on the framework being used, for example:
- In Next.js, service workers need to be placed in the
public/folder. - In Vite, they belong in the project’s root directory.
Since my library lives in node_modules, I don’t have control over these paths.
What I’d like:
- Zero setup: by simply running a function, the library takes care of everything else, including registering service workers. The user does not need to configure any path or add files to any specific location in their project.
- Fallback option (if zero setup isn’t possible): Provide a simplified setup process to reduce user effort. For example, I considered using
type: 'module'during registration:
navigator.serviceWorker.register('somePath', {
scope: '/',
type: 'module',
});
Then my idea was for the user to import the library’s service worker script in their framework-specific file (e.g., public/sw.js in Next.js):
// public/sw.js for Next.js or sw.js for Vite
import { serviceWorkerScript } from 'myLibrary';
serviceWorkerScript();
But even this approach has issues. The import path must be relative to the script and does not support libraries installed in node_modules. So that code will throw an error.
I have also found that bypassing the restriction of placing the script in a separate file (e.g. with a string or Blob) is not a valid option.[ 1 ][ 2 ]
My question:
- Is it possible to achieve a zero-setup solution where the service worker script is registered and functional without requiring user intervention?
- If not, what’s the simplest way to guide users in configuring the service worker, minimizing complexity and effort?
I’m open to alternative approaches or best practices to handle this scenario efficiently. Any help is appreciated!
ReferenceError: dotenv is not defined in Node.js with PM2
I’m encountering a ReferenceError: dotenv is not defined issue in my Node.js backend application managed by PM2. Here’s the breakdown:
Environment Details:
Node.js version: 18.20.5
PM2 version: 5.x
Backend framework: Express.js
Problem Description:
When I try to run my application with PM2, I see the following error in the logs:
ReferenceError: dotenv is not defined
at Object.<anonymous> (/root/DevTrust/backend/server.js:20:1)
at Module._compile (node:internal/modules/cjs/loader:1364:14)
What I've Tried So Far:
Installed dotenv using: npm install dotenv –force
Verified it’s in node_modules using npm list dotenv
Ensured the top of server.js has:
javascript
require('dotenv').config();
Verified .env exists in the backend folder and contains required variables:
makefile
OPENAI_API_KEY=your_actual_api_key
Restarted PM2 with:
bash
pm2 restart backend
pm2 save
Tried running the server directly using node server.js (it works fine).
Logs from PM2:
When running pm2 logs backend –lines 50, I see repeated ReferenceError: dotenv is not defined.
Expected Behavior:
The backend server should load environment variables from the .env file without any errors when started with PM2.
Actual Behavior:
It keeps failing with ReferenceError: dotenv is not defined.
How can I ensure that dotenv is properly loaded and recognized by PM2 when running the backend server?
Any insights or suggestions are appreciated. Thanks in advance!
How to reliably check Casper (CSPR) balance in Electron js application?
I’m building an Electron app (Node 18) to check cryptocurrency balances, including Casper (CSPR). However, I’m getting “No working endpoints found” errors when trying to check CSPR balances.
**Error Message:**
javascript
Testing available endpoints...
Testing endpoint: https://rpc.mainnet.casperlabs.io
Testing endpoint: https://casper-node.services.dev.z7x.org
// ... more endpoints ...
Endpoint https://casper-node.services.dev.z7x.org failed: getaddrinfo ENOTFOUND
Found 0 working endpoints
CSPR balance check failed: Error: No working endpoints found
Here the code to check the CSPR enpoint
async function testEndpoint(url) {
try {
console.log(`Testing endpoint: ${url}`);
const response = await axios.post(`${url}/rpc`, {
jsonrpc: "2.0",
id: "0",
method: "info_get_status",
params: []
}, {
timeout: 10000,
headers: { 'Content-Type': 'application/json' },
validateStatus: status => status < 500,
httpsAgent: new require('https').Agent({
rejectUnauthorized: false,
timeout: 10000
})
});
if (response.data && !response.data.error) {
console.log(`Endpoint ${url} is working`);
return true;
}
console.log(`Endpoint ${url} returned invalid data:`, response.data);
return false;
} catch (error) {
console.log(`Endpoint ${url} failed:`, error.message);
return false;
}
}
and balance checking function
async function getCSPRBalance(key) {
try {
const formattedKey = normalizePublicKey(key);
const endpoints = Array.isArray(config.casper.apiUrl)
? config.casper.apiUrl
: [config.casper.apiUrl];
// Test endpoints in parallel
const endpointTests = endpoints.map(endpoint => testEndpoint(endpoint));
const results = await Promise.allSettled(endpointTests);
const workingEndpoints = endpoints.filter((endpoint, index) =>
results[index].status === 'fulfilled' && results[index].value === true
);
if (workingEndpoints.length === 0) {
throw new Error('No working endpoints found');
}
// Try each working endpoint
for (const baseUrl of workingEndpoints) {
try {
const url = `${baseUrl}/rpc`;
const rpcKey = `01${formattedKey}`;
const accountResponse = await axios.post(url, {
jsonrpc: "2.0",
id: "1",
method: "state_get_account_info",
params: {
public_key: rpcKey
}
});
// ... rest of balance checking logic ...
} catch (endpointError) {
// Continue to next endpoint
}
}
} catch (error) {
return {
success: false,
error: error.message || 'Failed to check CSPR balance',
address: key
};
}
}
the endpoints
const endpoints = [
'https://rpc.mainnet.casperlabs.io',
'https://casper-node.services.dev.z7x.org',
'https://casper-proxy.liquidstaking.com',
'https://casper-node-proxy.dev.z7x.org',
'https://node.casper.network.dev.z7x.org'
];
I’ve tried:
Using different Casper RPC endpoints
Adding SSL/TLS error handling
Implementing timeout and retry mechanisms
Disabling SSL verification for testing
The sample public key I’m testing with: 0203d9f49b0d76a3f14482ab11926f0d5f792e933f3df824dc1e0b07104474c4c3b3
Questions:
Are there more reliable Casper RPC endpoints I should be using?
Is there something wrong with my endpoint testing approach?
Are there specific considerations for making RPC calls to Casper nodes from an Electron app?
Environment:
Electron
Node.js 18
axios for HTTP requests
casper-js-sdk for key handling
Any help would be greatly appreciated!
In javascript, can I assign iframe doc to document variable?
I have a Java Script code that works inside Iframe. I’d like to save the Iframe context so that my next script can work in the same context.
The following is my code
// Get the iframe element
const iframe = document.evaluate("/html[1]/body[1]/iframe[1]", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
// Access the iframe's document object
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
// use iframe doc directly
var e1 = iframeDoc.evaluate("id('shadow_host')", iframeDoc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
console.log(`e1=${e1}`);
// can I assign iframeDoc to document?
document = iframeDoc;
var e2 = document.evaluate("id('shadow_host')", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
console.log(`e2=${e2}`);
I got the following result
e1=[object HTMLDivElement]
e2=null
Looks like if I use Iframe doc directly, I able able to search inside the Iframe context. I did this with e1.
But If I assign the Iframe doc to ‘document” variable, I am not able to search inside the Iframe context. I did this with e2.
Why my e2 example doesn’t work?
I really wanted to use ‘document’ variable because it is global and I don’t have to pass a variable to my next call.
Thank you for any help
Receiving duplicate FCM notifications on Android phone, works normally on desktop
I am making a Flask web app that uses the Google Sheets API to scan a school bus position spreadsheet and determine which section a bus is in. Then, it sends a notification with the user’s bus number, quadrant/section, and the buses it’s in between. The app works fine on desktop devices, but on Android, it sends duplicate notifications. One contains the site favicon, while the other doesn’t.
I thought this was a problem with ngrok, the tunneling service I was using to connect my phone to my laptop which is hosting the app over HTTPS, but as it turns out, connecting from a desktop device still doesn’t send duplicate notifications and works as expected, so I don’t think this is a problem with ngrok.Here is an extremely simplified version of my code, with all the irrelevant parts removed. It has the same issue as the extensive code.
Flask app:
from flask import Flask, request, jsonify, render_template, send_from_directory
import firebase_admin
from firebase_admin import credentials, messaging
from flask_cors import CORS
import os
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
app = Flask(__name__,
template_folder='templates',
static_folder='static',
static_url_path=''
)
CORS(app)
# Initialize Firebase Admin SDK
cred = credentials.Certificate('Core/firetoken.json') # Your Firebase credentials file
firebase_admin.initialize_app(cred)
@app.route('/firebase-messaging-sw.js')
def sw():
response = send_from_directory(app.static_folder, 'firebase-messaging-sw.js')
response.headers['Content-Type'] = 'application/javascript'
response.headers['Service-Worker-Allowed'] = '/'
return response
@app.route('/')
def home():
return render_template('index.html',
firebase_config=dict(
api_key=os.getenv('FIREBASE_API_KEY'),
auth_domain=os.getenv('FIREBASE_AUTH_DOMAIN'),
project_id=os.getenv('FIREBASE_PROJECT_ID'),
storage_bucket=os.getenv('FIREBASE_STORAGE_BUCKET'),
messaging_sender_id=os.getenv('FIREBASE_MESSAGING_SENDER_ID'),
app_id=os.getenv('FIREBASE_APP_ID'),
measurement_id=os.getenv('FIREBASE_MEASUREMENT_ID')
),
vapid_key=os.getenv('VAPID_KEY')
)
@app.route('/store_token', methods=['POST'])
def store_token():
data = request.json
token = data.get('token')
if not token:
return jsonify({'error': 'Token is required'}), 400
try:
# Send a test notification
message = messaging.Message(
notification=messaging.Notification(
title="Test Notification",
body="This is a test notification!"
),
token=token
)
messaging.send(message)
return jsonify({'status': 'Notification sent successfully'})
except Exception as e:
return jsonify({'error': str(e)}), 500
if __name__ == '__main__':
app.run(debug=True)
HTML Template:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Simple Notification Test</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.container {
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
button {
background-color: #4CAF50;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
margin: 10px 0;
}
#status {
margin: 20px 0;
padding: 10px;
border-radius: 4px;
}
.success { background-color: #dff0d8; color: #3c763d; }
.error { background-color: #f2dede; color: #a94442; }
</style>
</head>
<body>
<div class="container">
<h1>Notification Test</h1>
<button id="send-notification">Send Test Notification</button>
<p id="status"></p>
</div>
<script type="module">
import { initializeApp } from "https://www.gstatic.com/firebasejs/11.0.1/firebase-app.js";
import { getMessaging, getToken, onMessage } from "https://www.gstatic.com/firebasejs/11.0.1/firebase-messaging.js";
const firebaseConfig = {
apiKey: "{{ firebase_config.api_key }}",
authDomain: "{{ firebase_config.auth_domain }}",
projectId: "{{ firebase_config.project_id }}",
storageBucket: "{{ firebase_config.storage_bucket }}",
messagingSenderId: "{{ firebase_config.messaging_sender_id }}",
appId: "{{ firebase_config.app_id }}",
measurementId: "{{ firebase_config.measurement_id }}"
};
const vapidKey = "{{ vapid_key }}";
try {
const app = initializeApp(firebaseConfig);
const messaging = getMessaging(app);
// Register service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/firebase-messaging-sw.js')
.then(registration => console.log('Service Worker registered'))
.catch(err => console.error('Service Worker registration failed:', err));
}
document.getElementById('send-notification').addEventListener('click', async () => {
try {
const permission = await Notification.requestPermission();
if (permission === 'granted') {
const currentRegistration = await navigator.serviceWorker.getRegistration();
const token = await getToken(messaging, {
vapidKey: vapidKey,
serviceWorkerRegistration: currentRegistration
});
const response = await fetch('/store_token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token: token })
});
const result = await response.json();
if (!response.ok) throw new Error(result.error);
document.getElementById('status').innerText = 'Notification sent successfully!';
document.getElementById('status').className = 'success';
} else {
throw new Error('Notification permission denied');
}
} catch (error) {
document.getElementById('status').innerText = `Error: ${error.message}`;
document.getElementById('status').className = 'error';
}
});
// Listen for messages
onMessage(messaging, (payload) => {
document.getElementById('status').innerText = `Received: ${payload.notification.title} - ${payload.notification.body}`;
document.getElementById('status').className = 'success';
});
} catch (error) {
console.error('Initialization error:', error);
document.getElementById('status').innerText = `Error: ${error.message}`;
document.getElementById('status').className = 'error';
}
</script>
</body>
</html>
Here is a screenshot of the problem:
Screenshot of duplicate Android notifications
The dropdown menu is not expanding. CSS and JS are connected correctly
I am a beginner in web development. I need some help. The dropdown menu is not expanding. CSS and JS are connected correctly. What could be the reason?
I checked the CSS/JS classes and connected files. Everything seems to be correct, I even used GPT, but no results. 🙁 I can provide other project files if needed. Here is the code from the main file layout.html.
{% load static %}
<!DOCTYPE html>
<html lang="uk">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Головна{% endblock %}</title>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/5.1.3/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<link rel="stylesheet" href="{% static 'main/css/main.css' %}">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/5.10.1/main.min.css">
</head>
<body>
<button class="btn btn-primary" id="sidebarToggle">
<i class="fas fa-bars"></i>
</button>
<div class="d-flex">
<aside class="flex-shrink-0 p-3 bg-dark text-white sidebar" id="sidebar">
<a href="/" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-white text-decoration-none">
<img src="{% static 'main/img/2.png' %}" alt="Logo" class="small-logo">
</a>
<hr>
<ul class="nav nav-pills flex-column mb-auto">
<li class="nav-item">
<a href="{% url 'layout' %}" class="nav-link text-white {% if request.resolver_match.url_name == 'layout' %}active{% endif %}" aria-current="page">
<i class="fas fa-heart"></i> Головна
</a>
</li>
<li>
<a href="{% url 'staff' %}" class="nav-link text-white {% if request.resolver_match.url_name == 'staff' %}active{% endif %}">
<i class="fas fa-users"></i> Особовий склад
</a>
</li>
<li>
<a href="{% url 'calendar' %}" class="nav-link text-white {% if request.resolver_match.url_name == 'duty' %}active{% endif %}">
<i class="fas fa-list"></i> Подати наряд
</a>
</li>
<li>
<a href="{% url 'profile' %}" class="nav-link text-white {% if request.resolver_match.url_name == 'profile' %}active{% endif %}">
<i class="fas fa-user"></i> Профіль
</a>
</li>
<li>
<a href="{% url 'calendar' %}" class="nav-link text-white {% if request.resolver_match.url_name == 'calendar' %}active{% endif %}">
<i class="fas fa-calendar"></i> Календар
</a>
</li>
</ul>
<li class="nav-item">
<a class="nav-link dropdown-toggle text-white" href="#" id="dropdownMenuLink" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</a>
<ul class="dropdown-menu" aria-labelledby="dropdownMenuLink">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
</ul>
</li>
</ul>
</aside>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/5.1.3/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/5.10.1/main.min.js"></script>
<script src='https://cdn.jsdelivr.net/npm/@fullcalendar/[email protected]/index.global.min.js'></script>
<script src='https://cdn.jsdelivr.net/npm/@fullcalendar/[email protected]/index.global.min.js'></script>
<script src='https://cdn.jsdelivr.net/npm/@fullcalendar/[email protected]/index.global.min.js'></script>
<script>
document.getElementById('sidebarToggle').addEventListener('click', function () {
document.getElementById('sidebar').classList.toggle('active');
this.classList.toggle('active');
});
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
if (calendarEl) {
var calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'dayGridMonth',
locale: 'uk',
editable: true,
selectable: true,
events: '/get_duties/', // Завантаження нарядів з сервера
select: function(info) {
var dutyDateInput = document.getElementById('dutyDate');
dutyDateInput.value = info.startStr;
var dutyFormModal = new bootstrap.Modal(document.getElementById('dutyFormModal'));
dutyFormModal.show();
calendar.unselect();
},
eventClick: function(info) {
if (confirm('Ви впевнені, що хочете видалити цю подію?')) {
$.ajax({
type: 'POST',
url: '{% url "delete_duty" %}',
data: {
'id': info.event.id,
'csrfmiddlewaretoken': '{{ csrf_token }}'
},
success: function(response) {
if (response.status === 'success') {
info.event.remove();
} else {
alert('Сталася помилка при видаленні наряду.');
}
},
error: function(response) {
alert('Сталася помилка при видаленні наряду.');
}
});
}
}
});
calendar.render();
}
$('#dutyForm').on('submit', function(event) {
event.preventDefault();
$.ajax({
type: 'POST',
url: $(this).attr('action'),
data: $(this).serialize(),
success: function(response) {
$('#dutyFormModal').modal('hide');
calendar.refetchEvents();
},
error: function(response) {
var errors = response.responseJSON.errors;
var errorMessage = 'Сталася помилка при подачі наряду:n';
for (var field in errors) {
errorMessage += field + ': ' + errors[field].join(', ') + 'n';
}
alert(errorMessage);
}
});
});
});
</script>
</body>
</html>
Vue JS event listeners don’t work and vanilla work ( composition api+ script setup )
Problem: I created a custom component that works as a searchable selection which via vue’s dom event handlers (@input, @focus, watch) detects client input and performs the search on the server.
My component works perfectly (maybe it could be perfected) on all devices except my phone (Xiamo Redmi 12) in which I use a custom keyboard for convenience. i thought that was the problem instead not.
Trying to detect the input with a vanilla javascript eventListener works while with vue handlers, the input is detected only when I ‘unselect’ the input.
<template>
<div ref="inputContainer" class="input-select-container" >
<label v-if="label">{{ label }}</label>
<input
v-model="model"
:type
id="search-input"
:placeholder
:required="required"
@focus="handleShowList"
@input="handleShowList"
autocomplete="off"
:class="class"
/>
<div class="input-select-list" v-if="insideList">
<ul v-if="showList" ref="selectList">
<slot></slot>
</ul>
</div>
</div>
</template>
<script setup>
import { ref, onUnmounted, onMounted, watch } from 'vue';
const model = defineModel();
const emits = defineEmits(['show-list']);
const props = defineProps({
type: {
type: String,
default: 'search'
},
id: {
type: String,
default: 'input'
},
label: {
type: String,
default: null
},
placeholder: {
type: String,
default: ''
},
required: {
type: Boolean,
default: false
},
class: {
type: String,
default: ''
},
insideList: {
type: Boolean,
default: true
}
});
const showList = ref(false);
const inputContainer = ref(null);
const selectList = ref(null);
function handleClickOutside(event) {
if (inputContainer.value && !inputContainer.value.contains(event.target)) {
handleHideList();
}
}
function handleShowList(){
showList.value = true;
}
function handleHideList(){
showList.value = false;
}
//not work
watch(showList, (value) => {
emits('show-list', value);
});
//not work
watch(model, (newValue, oldValue) => {
console.log('Input value changed:', newValue); // Log per debug
showList.value = true; // Mostra la lista ogni volta che l'input cambia
});
onMounted(() => {
document.addEventListener('click', handleClickOutside);
//WORK
document.getElementById('search-input').addEventListener('input', function(){
console.log('Input value changed:', this.value);
});
});
onUnmounted(() => {
document.removeEventListener('click', handleClickOutside);
});
defineExpose({
handleHideList
});
</script>