I am getting the following error:
Uncaught ReferenceError: oldId is not defined
On this line:
oldId = this.target.dataset.widgetId + "-" + (this.carousel.prevPage + 1);
That error makes no sense to me. I am defining oldId in that line.
Blancer.com Tutorials and projects
Freelance Projects, Design and Programming Tutorials
Category Added in a WPeMatico Campaign
I am getting the following error:
Uncaught ReferenceError: oldId is not defined
On this line:
oldId = this.target.dataset.widgetId + "-" + (this.carousel.prevPage + 1);
That error makes no sense to me. I am defining oldId in that line.
i created a context to start up the socket
but before that it validate the token sending a request to the server.
there is an issue that i can’t really figure it out.
if the app is closed and i open it i receive this error
ERROR Error validating token: [TypeError: Cannot read property 'getString' of undefined
if i keep the app open, and i Reload the app i see all the logs and data correctly.
i tried setting up a timeout of 1minute since the app opens and i have no errors.
but this approach is not ok.
so i thought the context loaded before the client actually was actually setted up ? no idea
useEffect(() => {
const validateToken = async () => {
try {
const { data } = await client.query({
query: VALIDATE_TOKEN,
fetchPolicy: 'network-only',
});
console.log('HEREHEREHERE');
console.log(data);
if (data && data.ValidateToken) {
setSenderID(data.ValidateToken._id);
setSenderUserName(data.ValidateToken.userName);
setIsTokenValid(true);
} else {
console.error('Token validation failed');
setIsTokenValid(false);
}
} catch (error) {
console.error('Error validating token:', error);
setIsTokenValid(false);
}
};
validateToken();
}, []);
import { ApolloClient, HttpLink, ApolloLink } from '@apollo/client';
import { InMemoryCache } from '@apollo/client/cache';
import { storage } from './storage'
import { SERVER } from '@env';
const httpLink = new HttpLink({ uri: `http://${SERVER}:5552/graphql` });
const authLink = new ApolloLink((operation, forward) => {
const token = storage.getString('UID');
operation.setContext({
headers: {
Authorization: token ? `Bearer ${token}` : '',
}
});
return forward(operation);
});
const client = new ApolloClient({
//uri: 'http://10.0.2.2:5552/graphql',
link: authLink.concat(httpLink),
cache: new InMemoryCache({}),
});
export default client
const Root = () => {
return (
<ApolloProvider client={client}>
<WebSocketProvider>
<App />
</WebSocketProvider>
</ApolloProvider>
);
};
I’m setting up Cypress to run component tests on a React-based app. The app uses multiple libraries, which I cannot change in any way. Although the app runs perfectly well, I’m unable to get any Cypress tests to run as an object ‘palette’ is not available in one of the libraries, and I get this error message:
(uncaught exception)TypeError: Cannot read properties of undefined (reading 'silver')
This is the code in the library that is failing:
export default ({ palette }: Theme) => ({
offBackground: palette.colors.silver,
etc...
I’m using cypress/support/component.js for setting up the configuration, and the component being tested is nested inside a number of context providers:
<I18nContext.Provider value={i18n.english}>
<ThemeProvider theme={theme}>
{component}
</ThemeProvider>
</I18nContext.Provider>
I can import the palette object into the component.js file – is there a way of making it globally available so that it is useable by the library when it is imported?
I am building a web component input which looks like this with Vue 3:
<my-input value="Search"></my-input>
How can I make sure that the value attribute is always equivalent to the current internal value?
Given a Vue 3 component
<template>
<input id="input" type="text" @focus="handleOnFocus($event)" />
</template>
<script setup type="ts">
const handleOnFocus = () => {
console.log('Component document.activeElement:', document.activeElement)
}
</script>
And test:
import { mount } from '@vue/test-utils'
import { expect } from 'vitest'
import AarghOmg from './AarghOmg.vue'
describe('AarghOmg', () => {
let wrapper: any
beforeEach(() => {
wrapper = mount<typeof AarghOmg>(AarghOmg, {
attachTo: document.body
})
})
it('outputs activeElement', () => {
wrapper.find('#input').trigger('focus')
console.log('Test document.body.innerHTML:', document.body.innerHTML)
expect(true).toBe(true)
})
})
console.log
Component document.activeElement: HTMLBodyElement {}
Test document.body.innerHTML: <div data-v-app=""><input id="input" type="text"></div>
I would expect for the document.activeElement to be the input, not the body element. This works correctly in a browser, so is an issue with the wrapper and the test framework.
I want to mock a static method defined outside a component.
Here is my component:
import Authenticate from '/api/Authenticate';
export default class MyComponent extends React.Component {
render() {
if (Authenticate.hasGroup()) {
return (<div>Has group</div>);
} else {
return (<div>No group</div>);
}
}
}
hasGroup is a static method defined in Authenticate and returns boolean.
Here is my test file
describe('Has Group', () => {
jest.doMock('/api/Authenticate', () => ({
__esModule:true,
hasGroup: jest.fn(()=>true)
});
);
it('render has group', ()=>{
const wrapper = render(<MyComponent/>);
expect(toJson(wrapper)).toMatchSnapshot();
})
}
When I run the test, hasGroup method is not mocked. What am I missing?
I want to show the points and to write data inside. Problem is that the data (numbers) are shown for the points behind instead of the ones in front.
I would also like for smaller number circles to disappear on zoom lvl xx.
This is my code:
useEffect(() => {
if (mapRef.current) return;
mapboxgl.accessToken =
"pk.eyJ1IjoibHVrYXZpNDQiLCJhIjoiY2xieGlkMDl1MDdhbTNvcm1sbThoa2N3ZSJ9.xRmYD6lKyJrGlwUUrzHZFA";
mapRef.current = new mapboxgl.Map({
container: mapContainerRef.current,
style: "mapbox://styles/mapbox/light-v10",
center: [lng, lat],
zoom: zoom,
});
mapRef.current.on("load", async () => {
const coordinatesPromises = institutions.map((institution) =>
getCoordinates(institution.address)
);
const coordinates = await Promise.all(coordinatesPromises);
const geojsonData = {
type: "FeatureCollection",
features: institutions.map((institution, index) => ({
type: "Feature",
properties: {
institutionName: institution.name,
site: institution.address,
employees: institution.employees,
type: institution.type,
network: institution.network,
category: institution.category,
speciality: institution.speciality,
},
geometry: {
type: "Point",
coordinates: [coordinates[index]?.lng, coordinates[index]?.lat],
},
})),
};
mapRef.current.addSource("points", {
type: "geojson",
data: geojsonData,
});
mapRef.current.addLayer({
id: "circle",
type: "circle",
source: "points",
paint: {
"circle-color": "#82c5f1",
"circle-radius": [
"interpolate",
["linear"],
["get", "employees"],
0,
5,
100,
10,
200,
15,
500,
20,
1000,
25,
2000,
30,
],
"circle-stroke-width": 2,
"circle-stroke-color": "#ffffff",
"circle-opacity": [
"interpolate",
["linear"],
["zoom"],
0,
["case", ["<", ["get", "employees"], 500], 0, 0],
10,
["case", [">", ["get", "employees"], 500], 1, 1],
],
},
layout: {},
});
mapRef.current.addLayer({
id: "labels",
type: "symbol",
source: "points",
layout: {
"text-field": ["get", "employees"],
"text-font": ["DIN Offc Pro Bold", "Arial Unicode MS Bold"],
"text-weight": "bold",
"text-size": 12,
"text-align": "center",
"text-anchor": "center",
"text-justify": "center",
"text-offset": [0, 0],
"symbol-z-order": "auto",
"icon-allow-overlap": false,
"icon-ignore-placement": false,
"text-optional": true,
"symbol-sort-key": ["get", "employees"],
},
paint: {
"text-color": "#ffffff",
},
});
mapRef.current.on("click", "circle", (e: any) => {
mapRef.current.flyTo({
center: e.features[0].geometry.coordinates,
zoom: 15,
essential: true,
});
console.log(e.features[0]);
setSelectedFeature(e.features[0]);
});
mapRef.current.on("mouseenter", "circle", () => {
mapRef.current.getCanvas().style.cursor = "pointer";
});
mapRef.current.on("mouseleave", "circle", () => {
mapRef.current.getCanvas().style.cursor = "";
});
});
}, [lng, lat, zoom]);
I have tried multiple combinations of properties in layout and nothing led to success.
I have an ag grid with row spanning and I am able to do row span for first and second column. Can anyone please help me for row span logic for rest of the columns (notes, votes)?
I think row span should be calculate/manipulate dynamically it can be multiple columns in future, so right now my logic is wrong i think.
Here is the stackblitz.
Can anyone please help me here for the same
Thanks
My index.html uses a svg in this way:
<button class="button--settings" id="button_settings">
<svg role="img">
<use href="assets/images/icons.svg#settings-icon"></use>
</svg>
</button>
I’m using Webpack to bundle my project. I need to have the svg inline in the compiled index.html.
So <use href="assets/images/icons.svg#settings-icon"></use> should be replaced with the actual svg data. How do I achieve this?
This is my current webpack.config setup:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
entry: './src/scripts/index.ts', // Entry point of your application
devtool: 'inline-source-map',
output: {
filename: 'scripts/[name].bundle.js', // Output bundle file name
path: path.resolve(__dirname, 'dist'), // Output directory
clean: true,
},
module: {
rules: [
{
test: /.ts$/,
use: 'ts-loader',
exclude: /node_modules/,
},
{
test: /.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /.svg$/,
type: 'asset/resource',
generator: {
filename: 'assets/images/[name][ext]',
},
},
{
test: /.(woff|woff2|eot|ttf|otf)$/,
type: 'asset/resource',
generator: {
filename: 'assets/fonts/[name][ext]',
},
},
{
test: /.html$/,
use: 'html-loader',
},
],
},
resolve: {
extensions: ['.ts', '.js'],
},
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
format: {
comments: false, // Remove comments
},
},
extractComments: false, // Disable extracting comments into a separate file
}),
],
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: './public/index.html', // Template HTML file
filename: 'index.html', // Output HTML file name
}),
],
};
I’m already researching for 4 hours now but I can’t make it work.
I’m trying to create a component that will have an input and a button. In input, the user enters his nickname. This nickname, that is, the input value, must be stored in a variable. This variable is needed for a function that creates a link to which the user will be redirected by the button.
My component (next.js)
'use client'
import { Button } from '@nextui-org/react';
import Link from 'next/link';
import React, { useState } from 'react';
let inputValue: any;
let setInputValue: any;
const InputComponent = () => {
[inputValue, setInputValue] = useState('');
const handleInputChange = (event: any) => {
setInputValue(event.target.value);
};
return (
<div className='flex flex-col gap-2'>
<input id='areaNick' type="text" value={inputValue} onChange={handleInputChange} placeholder='Введите никнейм' className='bg-transparent border-b-2 border-blue-300 text-white placeholder:text-blue-300 focus:outline-none' />
<Button radius="lg" className='bg-white text-blue-500 uppercase font-semibold' type="submit" as={Link} href="https://cubeinside.easydonate.ru/">Купить</Button>
<p>{inputValue}</p>
</div>
);
};
export default InputComponent;
Function
client.getPaymentLink(customer, serverID, products, url, email, coupon).then((link) => console.log('link ', link));
All function variables are constant, except for the “customer” and “email” variables. I get the email from the session, but the “customer” should take the value from input. The problem is that the function that reads the value from the input requires the client component, but the function that generates the link does not work in the client component. How can I transfer a variable from a client component to a server component, or how can I place this function in a client component.
I searched the internet for how to declare a variable globally for the entire project, but it uses functions that the client component requires, and in my case it doesn’t work.
I have GrpahMailer for sending e-mails handled like this:
GraphMailer:
<?php
class graphMailer {
var $tenantID;
var $clientID;
var $clientSecret;
var $Token;
var $baseURL;
function __construct($sTenantID, $sClientID, $sClientSecret) {
$this->tenantID = $sTenantID;
$this->clientID = $sClientID;
$this->clientSecret = $sClientSecret;
$this->baseURL = 'https://graph.microsoft.com/v1.0/';
$this->Token = $this->getToken();
}
function getToken() {
$oauthRequest = 'client_id=' . $this->clientID . '&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_secret=' . $this->clientSecret . '&grant_type=client_credentials';
$reply = $this->sendPostRequest('https://login.microsoftonline.com/' . $this->tenantID . '/oauth2/v2.0/token', $oauthRequest);
$reply = json_decode($reply['data']);
return $reply->access_token;
}
function createMessageJSON($messageArgs, $addMessageEnvelope = False) {
/*
$messageArgs[ subject,
replyTo{'name', 'address'},
toRecipients[]{'name', 'address'},
ccRecipients[]{'name', 'address'},
importance,
conversationId,
body,
images[],
attachments[]
]
*/
$messageArray = array();
if (array_key_exists('toRecipients', $messageArgs)) {
foreach ($messageArgs['toRecipients'] as $recipient) {
if (array_key_exists('name', $recipient)) {
$messageArray['toRecipients'][] = array('emailAddress' => array('name' => $recipient['name'], 'address' => $recipient['address']));
} else {
$messageArray['toRecipients'][] = array('emailAddress' => array('address' => $recipient['address']));
}
}
}
if (array_key_exists('ccRecipients', $messageArgs)) {
foreach ($messageArgs['ccRecipients'] as $recipient) {
if (array_key_exists('name', $recipient)) {
$messageArray['ccRecipients'][] = array('emailAddress' => array('name' => $recipient['name'], 'address' => $recipient['address']));
} else {
$messageArray['ccRecipients'][] = array('emailAddress' => array('address' => $recipient['address']));
}
}
}
if (array_key_exists('bccRecipients', $messageArgs)) {
foreach ($messageArgs['bccRecipients'] as $recipient) {
if (array_key_exists('name', $recipient)) {
$messageArray['bccRecipients'][] = array('emailAddress' => array('name' => $recipient['name'], 'address' => $recipient['address']));
} else {
$messageArray['bccRecipients'][] = array('emailAddress' => array('address' => $recipient['address']));
}
}
}
if (array_key_exists('subject', $messageArgs)) $messageArray['subject'] = $messageArgs['subject'];
if (array_key_exists('importance', $messageArgs)) $messageArray['importance'] = $messageArgs['importance'];
if (isset($messageArgs['replyTo'])) $messageArray['replyTo'] = array(array('emailAddress' => array('name' => $messageArgs['replyTo']['name'], 'address' => $messageArgs['replyTo']['address'])));
if (array_key_exists('body', $messageArgs)) $messageArray['body'] = array('contentType' => 'HTML', 'content' => $messageArgs['body']);
if ($addMessageEnvelope) {
$messageArray = array('message'=>$messageArray);
if (array_key_exists('comment', $messageArgs)) {
$messageArray['comment'] = $messageArgs['comment'];
}
if (count($messageArray['message']) == 0) unset($messageArray['message']);
}
return json_encode($messageArray);
}
function getFolderId($mailbox, $folderName) {
$response = $this->sendGetRequest($this->baseURL .'users/'.$mailbox.'/mailFolders?$select=displayName&$top=100');
$folderList = json_decode($response)->value;
foreach ($folderList as $folder) {
//echo $folder->displayName.PHP_EOL;
if ($folder->displayName == $folderName) {
return $folder->id;
}
}
// Now try subfolders
foreach ($folderList as $folder) {
//echo $folder->displayName.PHP_EOL;
$response = $this->sendGetRequest($this->baseURL .'users/'.$mailbox.'/mailFolders/'.$folder->id.'/childFolders?$select=displayName&$top=100');
$childFolderList = json_decode($response)->value;
foreach ($childFolderList as $childFolder) {
//echo $childFolder->displayName.PHP_EOL;
if ($childFolder->displayName == $folderName) {
return $childFolder->id;
}
}
}
return false;
}
function sendMail($mailbox, $messageArgs, $deleteAfterSend = false) {
if (!$this->Token) {
throw new Exception('No token defined');
}
/*
$messageArgs[ subject,
replyTo{'name', 'address'},
toRecipients[]{'name', 'address'},
ccRecipients[]{'name', 'address'},
importance,
conversationId,
body,
images[],
attachments[]
]
*/
$messageJSON = $this->createMessageJSON($messageArgs);
$response = $this->sendPostRequest($this->baseURL . 'users/' . $mailbox . '/messages', $messageJSON, array('Content-type: application/json'));
//var_dump($response);
$responsedata = json_decode($response['data']);
$messageID = $responsedata->id;
foreach ($messageArgs['images'] as $image) {
$messageJSON = json_encode(array('@odata.type' => '#microsoft.graph.fileAttachment', 'name' => $image['Name'], 'contentBytes' => base64_encode($image['Content']), 'contentType' => $image['ContentType'], 'isInline' => true, 'contentId' => $image['ContentID']));
$response = $this->sendPostRequest($this->baseURL . 'users/' . $mailbox . '/messages/' . $messageID . '/attachments', $messageJSON, array('Content-type: application/json'));
}
foreach ($messageArgs['attachments'] as $attachment) {
$messageJSON = json_encode(array('@odata.type' => '#microsoft.graph.fileAttachment', 'name' => $attachment['Name'], 'contentBytes' => base64_encode($attachment['Content']), 'contentType' => $attachment['ContentType'], 'isInline' => false));
$response = $this->sendPostRequest($this->baseURL . 'users/' . $mailbox . '/messages/' . $messageID . '/attachments', $messageJSON, array('Content-type: application/json'));
}
//Send
$response = $this->sendPostRequest($this->baseURL . 'users/' . $mailbox . '/messages/' . $messageID . '/send', '', array('Content-Length: 0'));
if ($deleteAfterSend) {
//Delete the message if $deleteAfterSend
$this->deleteEmail($mailbox, $messageID, False, "sentitems");
$messageID = true;
}
if ($response['code'] == '202') return $messageID;
return false;
}
To this class I am sending data from my PHP in this format:
<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Allow-Headers: Content-Type");
error_reporting(E_ALL);
ini_set('display_errors', 1);
require_once '_servername.php';
require_once '_config.php';
require_once 'mailer.php';
require_once 'git.php';
require_once __DIR__ . '/vendor/autoload.php';
try {
dibi::connect($con_arr);
} catch (Exception $ex) {
echo json_encode(['success' => false, 'message' => 'Database connection failed: ' . $ex->getMessage()]);
exit;
}
$github = new Github();
$tenantId = "tenantId";
$clientId = "clientId";
$secret = "secret";
$graphMailer = new graphMailer($tenantId, $clientId, $secret);
try {
$data = $_POST;
$data_db = null;
// Check if an email ID was provided, to retrieve previous data if needed
if (isset($data["email_id"])) {
$data_db = dibi::select('*')->from('sd_email')->where('id = %i', $data['email_id'])->fetch();
$dataFrom = $data_db['fromEmail'];
$dataSubject = $data_db['subject'];
} else {
$dataFrom = null;
$dataSubject = null;
}
// Determine the recipient and subject for the email
$recipient = $data["to"] ?? $dataFrom;
$subject = $data["subject"] ?? $dataSubject;
if (!$recipient) {
echo json_encode(['success' => false, 'message' => 'No recipient specified.']);
exit;
}
// Handle CC recipients
$cc = [];
if (isset($data["cc"])) {
foreach (json_decode($data["cc"]) as $copy) {
$cc[] = ['name' => '', 'address' => $copy];
}
}
// Prepare attachments
$attachments = [];
foreach ($_FILES as $file) {
$attachments[] = [
'Name' => $file['name'],
'ContentType' => $file['type'],
'Content' => file_get_contents($file['tmp_name'])
];
}
// Construct mail arguments
$mailArgs = [
'subject' => $subject,
'replyTo' => ['name' => '', 'address' => $recipient],
'toRecipients' => [['name' => '', 'address' => $recipient]],
'ccRecipients' => $cc,
'importance' => 'normal',
'conversationId' => $data_db['conversationId'] ?? null,
'body' => $data["body"],
'attachments' => $attachments,
];
// Save email data to the database
dibi::insert('sd_email', [
'subject' => $subject,
'conversationId' => $data_db['conversationId'] ?? null,
'body' => $data["body"],
'fromEmail' => 'mail',
'toEmail' => $recipient,
'issue_number' => $data_db['issue_number'] ?? null,
])->execute();
$new_id = dibi::getInsertId();
$messID = $graphMailer->sendMail('mail', $mailArgs);
// Handle success or failure of the email sending
if ($messID && $data_db) {
$github->github_create_comment($data_db['issue_number'], "<html><body><p>ID " . $new_id . ", answer to " . $recipient . "</p></body></html> " . $data["body"]);
echo json_encode(['success' => true, 'message' => 'Email sent successfully.']);
} else {
echo json_encode(['success' => false, 'message' => 'Failed to send email.']);
}
} catch (Exception $ex) {
echo json_encode(['success' => false, 'message' => 'An error occurred: ' . $ex->getMessage()]);
}
From client I use JS to communicate with php like this:
document.addEventListener('DOMContentLoaded', () => {
const editor = new Editor('editor-container', 'body_input');
console.log(editor.quill); // Check if quill is properly initialized
const emailForm = new EmailForm('form_mail', 'body_input', editor);
emailForm.initializeTooltips();
document.getElementById('btn-add-attachment').onclick = () => emailForm.selectAttachment();
});
class Editor {
constructor(editorContainerId, bodyInputId) {
this.bodyInputId = bodyInputId;
this.quill = new Quill(`#${editorContainerId}`, {
theme: 'snow',
modules: {
toolbar: //toolbar
},
placeholder: 'Vytvořte e-mail...',
formats: [//formats]
});
this.initializeAccessibility(editorContainerId);
this.quill.on('text-change', () => this.handleTextChange());
}
initializeAccessibility(editorContainerId) {
const editor = document.querySelector(`#${editorContainerId} .ql-editor`);
if (editor) {
Object.assign(editor, {
role: 'textbox',
'aria-multiline': true,
'aria-label': 'Vytvořte e-mail',
'aria-describedby': 'editor-instructions'
});
} else console.error('Quill editor element not found.');
}
handleTextChange() {
const bodyInput = document.getElementById(this.bodyInputId);
if (bodyInput) {
bodyInput.value = this.quill.root.innerHTML;
} else {
console.error('Body input element not found.');
}
}
clearEditor() {
this.quill.root.innerHTML = '';
}
}
class EmailForm {
constructor(formId, bodyInputId, editor) {
this.form = document.getElementById(formId);
this.bodyInputId = bodyInputId;
this.editor = editor;
this.attachments = []; // Store attachments here
this.inlineImages = []; // Store inline images for processing
this.form.addEventListener('submit', async (event) => {
event.preventDefault();
if (this.validateForm()) await this.handleFormSubmission();
});
}
selectAttachment() {
this.createFileInput((file) => {
if (file) {
this.insertAttachment(file, 'file'); // Specify the type as 'file'
}
});
}
createFileInput(callback) {
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.style.display = 'none';
fileInput.addEventListener('change', event => {
const file = event.target.files[0];
callback(file);
});
document.body.appendChild(fileInput);
fileInput.click();
document.body.removeChild(fileInput);
}
insertAttachment(attachment, type) {
const container = document.getElementById("attachments");
const div = document.createElement("div");
div.className = 'attachment-item';
// Handle different types of attachments
if (type === 'file') {
const img = document.createElement("img");
img.src = URL.createObjectURL(attachment);
img.style.maxWidth = "10%";
img.style.height = "auto";
const button = document.createElement("button");
button.type = 'button';
button.className = 'btn btn-outline-danger btn-sm ms-2';
button.innerHTML = '<span>Remove</span>';
button.onclick = () => {
div.remove();
this.attachments = this.attachments.filter(att => att.name !== attachment.name); // Remove from attachments list
};
div.append(img, button);
container.appendChild(div);
this.attachments.push(attachment); // Add file to attachments array
} else if (type === 'base64') {
this.insertAttachmentWithBase64(attachment);
} else if (type === 'cid') {
this.insertAttachmentWithFile(attachment);
}
}
async handleFormSubmission() {
const bodyContent = this.editor.quill.root.innerHTML;
const { updatedBody } = await this.processEmailBody(bodyContent);
const transformedContent = await this.transformQuillContent(updatedBody); // Transform the content if needed
this.setBodyInputValue(transformedContent);
await this.submitForm(await this.prepareFormData());
}
async processEmailBody(body) {
const imgRegex = /<img.*?src="data:image/(jpeg|png|jpg);base64,([^"]*)".*?>/g;
let updatedBody = body;
for (let match; (match = imgRegex.exec(body)); ) {
const base64Image = match[0]; // The entire <img> tag
await this.insertAttachment(base64Image, 'base64'); // Insert as base64
// Generate a CID for the inline image
const cid = await this.generateUniqueCID();
updatedBody = updatedBody.replace(match[0], `<img src="cid:${cid}" alt="Inline Image">`);
}
return { updatedBody };
}
async insertAttachmentWithFile(file) {
const cid = await this.generateUniqueCID();
const formData = new FormData();
formData.append('attachment', file);
formData.append('cid', cid); // Optionally, include CID
const response = await fetch(this.form.action, {
method: 'POST',
body: formData
});
const result = await response.json();
if (result.filePath) {
console.log(`File saved at: ${result.filePath}`);
} else {
console.error('Failed to save image on server:', result.error);
}
}
async insertAttachmentWithBase64(base64Image) {
const cid = await this.generateUniqueCID();
const response = await fetch(this.form.action, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
base64Data: base64Image,
outputFile: `${cid}.jpg` // Save with a CID-based filename
})
});
const result = await response.json();
if (result.filePath) {
console.log(`File saved at: ${result.filePath}`);
} else {
console.error('Failed to save image on server:', result.error);
}
}
async submitForm(formData) {
try {
const response = await fetch(this.form.action, { method: 'POST', body: formData });
const result = await response.json();
alert(result.success ? 'Email sent successfully.' : `Failed to send email: ${result.message}`);
if (result.success) this.editor.clearEditor();
} catch (error) {
console.error('Submission error:', error);
alert('An error occurred while sending the email.');
}
}
setBodyInputValue(bodyContent) {
document.getElementById(this.bodyInputId).value = bodyContent;
}
async transformQuillContent(content) {
try {
const transformedBody = await this.processEmailBody(content);
const container = document.createElement('div');
container.innerHTML = transformedBody;
const transformations = [
//paternsforrelaements
];
for (const transformation of transformations) {
if (transformation.replacement instanceof Function) {
let matches;
while ((matches = transformation.pattern.exec(container.innerHTML)) !== null) {
const replacement = await transformation.replacement(...matches);
container.innerHTML = container.innerHTML.replace(matches[0], replacement);
}
} else {
container.innerHTML = container.innerHTML.replace(transformation.pattern, transformation.replacement);
}
}
return container.innerHTML;
} catch (error) {
this.logError('Error transforming Quill content:', error);
throw error;
}
}
validateForm() {
//bolean e-mail validator handler
}
validateInput(inputElement, errorElement, validationFn) {
//validate
}
validateEditorContent() {
//validate
}
toggleErrorDisplay(element, show) {
//error display
}
isValidEmail(email) {
return /^[^s@]+@[^s@]+.[^s@]+$/.test(email);
}
async generateUniqueCID() {
//generate uniqueCID
}
initializeTooltips() {
//tooltip init
}
async prepareFormData() {
const formData = new FormData(this.form);
for (const attachment of this.attachments) {
formData.append('attachments[]', attachment);
}
return formData;
}
}
And input forms looks like this:
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Emailový Formulář</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="../mailer_portal/css/bootstrap.min.css">
<!-- Custom CSS -->
<link rel="stylesheet" href="../mailer_portal/css/main.css">
<!-- Quill CSS -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/quill.snow.css" rel="stylesheet">
<style>
</style>
</head>
<body>
<div class="container">
<div class="email-container">
<h1 class="text-center mb-4">Emailový Formulář</h1>
<form id="form_mail" enctype="multipart/form-data" action="http://gtfoto.localhost/_proreporty/mailer_portal/sender.php">
<div class="mb-3">
<label for="to" class="form-label">Příjemce:</label>
<input id="to" name="to" type="email" class="form-control" required
aria-describedby="to-error"
aria-label="E-mailová adresa příjemce"
title="Zadejte e-mailovou adresu příjemce"
data-tooltip2="Tip: [email protected]"
placeholder="Zadejte e-mailovou adresu příjemce">
<div id="to-error" class="error-message" style="display:none;color:red;">
<p>Prosím zadejte platnou emailovou adresu ve
<span class="tooltip2" id="to-tooltip">
tvaru:
<span class="tooltip2-text">[email protected]</span>.
</span>
</p>
</div>
</div>
<div class="mb-3">
<label for="cc" class="form-label">Kopie pro příjemce:</label>
<input id="cc" name="cc" type="email" class="form-control"
title="Zadejte e-mailovou adresu příjemců kopií"
placeholder="Zadejte emailové adresy pro kopie oddělené čárkou"
aria-label="E-mailové adresy pro kopie"
multiple>
<div id="cc-error" class="error-message" style="display:none;color:red;">Zadejte emailové adresy pro kopie oddělené čárkou.</div>
</div>
<div class="mb-3">
<label for="subject" class="form-label">Předmět:</label>
<input id="subject" name="subject" type="text" class="form-control" required
aria-label="Předmět e-mailu"
placeholder="Zadejte předmět e-mailu">
<div id="subject-error" class="error-message" style="display:none;color:red;">Please enter a subject for the email.</div>
</div>
<div class="mb-3">
<label for="editor-container" class="form-label">Text:</label>
<div id="editor-container" class="form-control" aria-label="Editor textu e-mailu"></div>
<textarea id="body_input" name="body" style="display:none;" aria-hidden="true"></textarea>
<div id="body-error" class="error-message" style="display:none;color:red;">Please enter at least 5 characters in the email content.</div>
</div>
<!-- Form-wide error message -->
<div id="form-error" class="error-message" style="display:none;color:red;"></div>
<button type="button" id="btn-add-attachment" onclick="selectAttachment(insertAttachment)" class="btn btn-success mb-3">
<span>Přidat přílohu</span>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-paperclip" viewBox="0 0 16 16">
<path d="M6.5 3a2.5 2.5 0 1 1 5 0 2.5 2.5 0 0 1-5 0zM3.273 8.048a4.5 4.5 0 1 1 9 0 1 1 0 0 1-1.537 1.82c-.49.297-.946.459-1.41.569a2 2 0 1 0-3.9 0 1.396 1.396 0 0 0 .002.13 1 1 0 0 1-1.537-1.82zM3 7a3 3 0 0 1 6 0 1 1 0 0 1-2 0 1 1 0 0 0-2 0 3 3 0 0 0 6 0 2 2 0 0 0-4 0 1 1 0 0 1-2 0z"/>
</svg>
</button>
<div id="attachments"></div>
<button type="submit" class="btn btn-primary" aria-label="Odeslat e-mail">Odeslat e-mail</button>
</form>
</div>
</div>
<!-- Quill JS -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/quill.min.js"></script>
<script src="quill-editor.js"></script>
<script src="https://unpkg.com/[email protected]/dist/quill.imageCompressor.min.js"></script>
<script>
Quill.register("modules/imageCompressor", imageCompressor);
</script>
</body>
</html>
The problem which I am facing is that, I am trying to process and send even inlined images and I have already tryed multiple ways, but still wasn’t able to properly handle such solution.
So atm I have decided to save images base64 string which I am recieving from quill into coresponding image files.
To save images into files I am using php:
<?php
// Handle CORS
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
header('Content-Type: application/json');
// Handle OPTIONS request for CORS preflight
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit;
}
// Function to handle base64 image data and save it
function saveBase64Image($base64Image, $outputFile, $imageType) {
// Remove data URI scheme
$imageBase64 = preg_replace('/^data:image/w+;base64,/', '', $base64Image);
$imageBase64 = base64_decode($imageBase64);
// Check if decoding was successful
if ($imageBase64 === false) {
throw new Exception('Base64 decode failed');
}
// Use a unique filename if none provided
if (empty($outputFile)) {
$outputFile = uniqid() . '.' . $imageType;
}
// Define the file path
$filePath = __DIR__ . '/' . $outputFile;
// Write the image data to the file
if (file_put_contents($filePath, $imageBase64) === false) {
throw new Exception('Failed to write file');
}
return $filePath;
}
try {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$data = null;
// Handle application/json input
if (isset($_SERVER['CONTENT_TYPE']) && $_SERVER['CONTENT_TYPE'] === 'application/json') {
$data = json_decode(file_get_contents('php://input'), true);
// Check for JSON parsing errors
if (json_last_error() !== JSON_ERROR_NONE) {
http_response_code(400);
echo json_encode(['error' => 'Invalid JSON format']);
exit;
}
} else {
// Handle FormData
$data = [
'base64Data' => $_POST['data'] ?? null,
'outputFile' => $_POST['outputFile'] ?? ''
];
}
// Validate and process base64Data
if (isset($data['base64Data']) && !empty($data['base64Data'])) {
$base64Image = $data['base64Data'];
$outputFile = isset($data['outputFile']) ? basename($data['outputFile']) : '';
// Sanitize output file name
$outputFile = preg_replace('/[/\:*?"<>|]/', '', $outputFile);
// Determine image type from base64 string
if (preg_match('/data:image/(png|jpeg|jpg);base64,/', $base64Image, $matches)) {
$imageType = $matches[1];
} else {
$imageType = 'jpeg'; // Default to 'jpeg' if not determined
}
// Save the image and respond with its file path
$filePath = saveBase64Image($base64Image, $outputFile, $imageType);
echo json_encode(['filePath' => $filePath]);
} else {
// Respond with an error if no base64 image data is provided
http_response_code(400); // Bad Request
echo json_encode(['error' => 'No base64 image data provided.']);
exit;
}
} else {
// Respond with method not allowed if the request method is not POST
http_response_code(405);
echo json_encode(['error' => 'Method not allowed']);
}
} catch (Exception $e) {
// Handle any exceptions that occur during processing
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
error_log('Error: ' . $e->getMessage());
}
?>
I made a chart with the library chart.js, and next to the chart are the data numbers, so if I have a chart with the data of 150, it will display 150 next to the horizontal chart, but that number isn’t vector based, so I had to remove it and place an h2 “on top” of the canvas, so that its also vector based. Now I need to get the bar width so that I can correctly place my h2’s directly next to the bar graph.
The function createChart36Monate creates a chart for me, and inside the plugins I tried to get the with but it doesn’t work:
export function createChart36Monate(canvasId, containerClass, firstdata36Monate, secondData36Monate) {
var labels = ["36 Monate"];
var barColors1 = ["#348200"]; // Fill color for the first bar
var barColors2 = ["#98CB35"]; // Fill color for the second bar
var borderColors1 = ["#A3D33A"]; // Border color for the first bar
var borderColors2 = ["#348200"]; // Border color for the second bar
var valueRange36Monate = [0, firstdata36Monate[0] + secondData36Monate[0]]; // Min and max values for the x-axis
var canvas = document.getElementById(canvasId); // Canvas for graphs
var autobahnclusterDiv = document.querySelector(containerClass); // Projektcluster Div
// Adjust the canvas width to match the "autobahn" div width
if (autobahnclusterDiv) {
canvas.width = autobahnclusterDiv.offsetWidth + 40; // Adjusting for some padding
canvas.height = canvas.height - 11
} else {
console.log('No element with class "autobahn" found.');
}
// Create a new chart instance
var chart = new Chart(canvas, {
type: "horizontalBar",
data: {
labels: labels,
datasets: [
{
label: 'Graph1-36Monate',
backgroundColor: barColors1,
borderColor: borderColors1,
borderWidth: 1,
data: firstdata36Monate
},
{
label: 'Graph2-36Monate',
backgroundColor: barColors2,
borderColor: borderColors2,
borderWidth: 0.5,
data: secondData36Monate
}
]
},
options: {
responsive: false, // Make sure the chart is not responsive to fit the fixed dimensions
maintainAspectRatio: false,
legend: { display: false }, // Hides the legend
scales: {
xAxes: [{
ticks: {
display: false,
min: valueRange36Monate[0], // Use the first element of valueRange as the min value
max: valueRange36Monate[1] // Use the second element of valueRange as the max value
},
gridLines: {
display: false,
drawOnChartArea: false,
drawTicks: false,
color: "transparent"
},
drawBorder: true,
borderColor: "transparent"
}],
yAxes: [{
gridLines: {
display: false,
},
drawBorder: true,
borderColor: "transparent"
}]
},
plugins: {
datalabels: {
display: false
}
},
layout: {
padding: {
right: 70, // Add padding to the right to prevent text cut off
left: 10
}
}
},
plugins: [
{
afterDraw: function(chart) {
var meta = chart.getDatasetMeta(0);
var width = meta.data[0]._model.height;
console.log(width)
console.log(meta)
}
}]
});
// Generate IDs for value elements based on the chartCounter
var valueId1 = `value${chartCounter}_1`;
var valueId2 = `value${chartCounter}_2`;
// Update the corresponding <h2> elements with the chart values
document.getElementById(valueId1).innerText = firstdata36Monate[0];
document.getElementById(valueId2).innerText = secondData36Monate[0];
// Increment the chartCounter for the next call
chartCounter++;
}
I already tried _model.widt, but that just gives me an undefined.
I’m making a REST service using javascript and express. I have some endpoints and I wanna create a swagger file to serve along with it. I’m using swagger-autogen to generate the swagger file. Even though it does a decent job, the schemas part is the main problem.
I have various models in my service and I wanna autogenerate the schemas part of the swagger file. I’m also using JSDoc and have documented with Types every model and their properties.
From my understanding I will have to create the schemas part by using JSDoc and then use that in order to have the schemas part. The problem is that if I have to go and create “by hand” the swagger definition of each model, might as well create the file myself.
Here is the current swagger.js file that I use to create the swagger file.
const swaggerAutogen = require('swagger-autogen')({openapi: '3.0.0'});
const doc = {
info: {
version: '1.0.0',
title: 'Bookstore REST API',
description: 'REST API documentation for bookstore app.'
},
servers: [
{
url: 'http://localhost:3000'
},
],
consumes: ['application/json'],
produces: ['application/json'],
tags: [
{
name: 'Bookstore',
description: ''
},
],
components: {}
};
const outputFile = './swagger-output.json';
// I only have one route file.
const routes = ['../routes/routes.js'];
swaggerAutogen(outputFile, routes, doc);
I have also tried swagger-jsdoc but I have the same problem there too. Does anyone know how to auto generate the entire swagger file?
How do I set the key for select v2 to prevent the entire visual list from being refreshed during virtual scrolling and reuse the dom using vue’s diff algorithm

<template>
<el-select-v2
:options="fun(props.valueKey, props.label, props.value)"
:label="props.label"
:value="props.value"
:value-key="props.valueKey">
</el-select-v2>
</template>
<script lang="ts" setup>
import { defineProps, ref,reactive } from 'vue';
const props = reactive({
optionsList: [],
label: 'name',
value: 'id',
valueKey:'id'
});
// 创建100个假数据项
const createFakeData = () => {
return Array.from({ length: 100 }, (_, index) => ({
id: index + 1, // 唯一标识符
name: `Item ${index + 1}`, // 显示名称
otherProperty: `Value ${index + 1}` // 其他可能的属性
}));
};
createFakeData()
// 将生成的假数据存入响应式引用
const optionsList = ref();
// 将原先的 props.optionsList 替换为我们创建的响应式引用
props.optionsList = optionsList;
const fun = (key: string, selectLabel: string, selectValue: string) => {
console.log("props",props);
return props.optionsList.map((item: any) => ({
label: item[selectLabel],
value: key ? item : item[selectValue]
}));
};
</script>
In Firefox browser, when opened in normal form all data moves towards right, while it appears correctly in Chrome and Edge. Also when I tried to minimize the resolution in edge or chrome all data moves towards right.
When opened in Firefox Normally:
When Resolution is changed:
My CSS and other data:
<style>
/* Ensure consistent box-sizing across all elements */
* {
box-sizing: border-box;
}
/* Adjust the layout of the DataTables top and bottom sections */
.dataTables_wrapper .top,
.dataTables_wrapper .bottom {
width: 100%;
}
/* Add custom styles for the container */
.container {
/* display: flex;
justify-content: space-between; */
display: flex;
justify-content: space-between;
align-items: center; /* Center vertically */
}
.table-container {
margin-top: 20px;
width: 100%; /* Ensure the container spans the full width */
overflow-x: auto; /* Enable horizontal scrolling if necessary */
}
.table-container table {
width: 100%; /* Ensure the table spans the full width of its container */
border-collapse: collapse;
}
.table-container th,
.table-container td {
padding: 5px;
text-align: left;
border-bottom: 1px solid #ddd;
/*white-space: nowrap; /* Prevents text from wrapping */
}
.table-container th {
background-color: #f2f2f2;
font-weight: bold;
/*white-space: nowrap; /* Prevents text from wrapping */
}
.table-container tr:nth-child(even) {
background-color: #f2f2f2;
}
.table-container tr:hover {
background-color: #ddd;
}
#chart-container {
border: 2px solid #ddd; /* Border width, style, and color */
padding: 10px; /* Add some padding inside the container */
border-radius: 15px; /* Make the edges rounded (adjust the value as needed) */
display: flex;
justify-content: space-between;
align-items: center;
gap: 20px;
margin-left: 0px;
}
canvas {
width: 250px !important;
height: 100px !important;
}
/* Style for the filter container */
.filter-container {
display: flex;
justify-content: space-between;
align-items: center; /* Center vertically */
}
/* Style for the filter div */
.filter {
display: flex;
align-items: center; /* Center vertically */
}
.table-container th:first-child,
.table-container td:first-child {
width: 50px; /* Adjust based on your checkbox width */
text-align: center;
}
.table-container td.wave-number {
text-align: center !important; /* Center align wave number cells */
}
</style>
My filter and table contents:
<div class="filter-container">
<div id="chart-container">
<h5 style="font-weight: bold;">Overall Counts</h5>
<!--<canvas id="statusChart"></canvas>-->
<!-- Add this div to display the counts -->
<div id="statusCountsContainer">
<div class="status-item">
<span class="circle yellow"></span> Not Started: <span id="notStartedCount">0</span>
</div>
<div class="status-item">
<span class="circle blue"></span> In Progress: <span id="inProgressCount">0</span>
</div>
<div class="status-item">
<span class="circle green"></span> Completed: <span id="completedCount">0</span>
</div>
<!--<div class="status-item">
<span class="circle greenyellow"></span> Completed Manually: <span id="completedManuallyCount">0</span>
</div>-->
<div class="status-item">
<span class="circle red"></span> Failed: <span id="failedCount">0</span>
</div>
<!-- Search Field -->
</div>
</div>
</div>
<div class="table-container">
<table class="table" id="deviceTable">
<thead>
<tr>
<th><input type="checkbox" id="selectAll"></th>
<th>Device Serial</th>
</tr>
</thead>
<tbody id="deviceTableBody">
@foreach (var item in Model)
{
<tr>
<td><input type="checkbox" class="row-checkbox" data-id="@item.DeviceSerial"></td>
<td>@item.DeviceSerial</td>
</tbody>
</table>
</div>
In javaScript I have made applyResponsiveStyles() to handle it but not working also provided specific style for firefox but not working( navigator.userAgent.indexOf(‘Firefox’) )
My JavaScript Code:
@section Scripts {
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.16.2/xlsx.full.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.datatables.net/1.11.5/js/jquery.dataTables.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
var table; // Declare the table variable globally
$(document).ready(function () {
// Initialize DataTable
table = $('#deviceTable').DataTable({
searching: true,
lengthChange: false,
dom: '<"top"lf<"clear">>rt<"bottom"ip<"clear">>',
order: [[7, 'desc']],
paging: true, // Enable pagination
columnDefs: [
{ orderable: false, targets: 0 } // Disable sorting on the first column
]
});
updateStatusCounts();
populateWaveFilter();
// Apply styles on page load
applyResponsiveStyles();
// Add event listener for window resize
$(window).on('resize', applyResponsiveStyles);
// Inject Firefox-specific styles
if (navigator.userAgent.indexOf('Firefox') !== -1) {
$('<style>').text(`
/* Firefox specific adjustments */
.table-container table {
table-layout: auto; /* Adjust table layout for Firefox */
}
`).appendTo('head');
}
}
// Function to apply responsive styles
function applyResponsiveStyles() {
var windowWidth = $(window).width();
if (windowWidth <= 768) {
// Apply responsive styles
$('#chart-container').css({
'flex-direction': 'column',
'gap': '10px'
});
$('.filter-container').css({
'flex-direction': 'column',
'gap': '10px'
});
$('.search-container').css({
'margin-left': '0',
'padding-top': '5px'
});
// Adjust table styles
$('.table-container').css({
'overflow-x': 'auto',
'margin-top': '20px'
});
$('#deviceTable').css({
'width': '100%'
});
$('.table-container td').css({
'padding': '5px',
'text-align': 'left',
'border-bottom': '1px solid #ddd'
});
$('.table-container th').css({
'background-color': '#f2f2f2',
'font-weight': 'bold'
});
} else {
// Revert to default styles
$('#chart-container').css({
'flex-direction': '',
'gap': ''
});
$('.filter-container').css({
'flex-direction': '',
'gap': ''
});
$('.search-container').css({
'margin-left': '',
'padding-top': ''
});
// Reset table styles
$('.table-container').css({
'overflow-x': '',
'margin-top': ''
});
$('#deviceTable').css({
'width': ''
});
$('.table-container td').css({
'padding': '',
'text-align': '',
'border-bottom': ''
});
$('.table-container th').css({
'background-color': '',
'font-weight': ''
});
}
}
}
Any help will be thankful, and let me know if any changes are required in above query