Decoding gmail embedded images in ClickUp tasks description not working

I’m trying to do this workflow with Pipedream:

  • A Gmail account receives an email.
  • The message from the email is decoded, using the “text/plain” part (if it doesn’t exist, I use the “text/html”).
  • Create a ClickUp task or update an existing one with that message.
  • Download attachments (not the embedded images, if i include them and upload those too, the task ended up with signatures images, logos, etc as upload files, when i need them to be in the description of the task ).
  • Upload those attachments.

The thing is that decoding messages with embedded images is not working properly because embedded images can’t be decoded with base64.

Is there a way to create the task with the description being the exact same email, with embedded images and all those kinds of things? Like i said before, i’ve tried to download those images as attachments and upload them, but the task ended up with those images as uploaded files; I need them to be in the description as embedded images.

This is how I decode the email:

import { htmlToText } from "html-to-text";

const decodeBase64 = (data) => {
  const normalizedBase64 = data.replace(/-/g, '+').replace(/_/g, '/');
  const padding = normalizedBase64.length % 4;
  if (padding > 0) {
    normalizedBase64 += '='.repeat(4 - padding);
  }
  return Buffer.from(normalizedBase64, 'base64').toString('utf-8');
};

export default defineComponent({
  async run({ steps, $ }) {
    const email = steps.trigger.event.payload;
    const text = {
      mimeType: "",
      data: "",
    }
    const parts = email.parts;

    if(email.mimeType.includes("multipart")){
      function findEmailText(parts){
        for(const part of parts){
          const subParts = part.parts;
          if(subParts){
            findEmailText(subParts);
          }
          if(part.mimeType === "text/plain" || part.mimeType === "text.html"){
            text.mimeType = part.mimeType;
            text.data = part.body.data;
            break;
          }
        }
      }
      findEmailText(parts);
    } else {
      text.mimeType = email.mimeType;
      text.data = email.body.data; 
    }

    text.decodedMessage = text.mimeType !== "text/html" ? decodeBase64(text.data) : htmlToText(decodeBase64(text.data), { wordwrap: 130 });
    
    return text.decodedMessage;
  },
})

And how i upload the attachments:

import { axios } from "@pipedream/platform"
import fs from "fs";
import FormData from "form-data";

export default defineComponent({
  props: {
    clickup: {
      type: "app",
      app: "clickup",
    }
  },
  async run({ steps, $ }) {

    const { TMP_DIR } = steps.define_constants.$return_value;
    const taskId = steps.if_task.$return_value;
    const files = steps.download_attachments.$return_value;
    for (let i = 0; i < files.length; i++) {
      const file = files[i];
      const filePath = `${TMP_DIR}/${file.filename}`;
      const fileStream = fs.createReadStream(filePath);
      
      const formData = new FormData();
      formData.append(`attachment`, fileStream); 

      try {
        await axios($, {
          method: 'POST',
          url: `https://api.clickup.com/api/v2/task/${taskId}/attachment`,
          headers: {
            Authorization: `${this.clickup.$auth.oauth_access_token}`,
            ...formData.getHeaders(),
          },
          data: formData,
        });
      } catch (error) {
        console.error('Error message:', error.message);
      }
    }
  
    return `Uploaded ${files.length} files successfully.`;
  }
})

How to pass runtime test data to global.teardown.ts?

in fixtures.ts I perform some API calls that create objects in database and returns their ids.

After all tests are done, I need clean the created objects in database.

How do I pass the ids to global.teardown.ts?


What I have

I tries to import fixtures module with a singleton array from global.teardown.ts but the module is reinitialized.

global.teardown.ts

import { entityGuidsToDelete, api } from './fixtures'

async function globalTeardown() {
    //not working yet, because the array is always empty
    for(const entityGuid of entityGuidsToDelete) { 
        await api.deleteEntity(entityGuid);
    }
}

export default globalTeardown;

playwright.config.ts

export default defineConfig({
  ...
  /* Configure projects for major browsers */
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
  ],

  globalTeardown: require.resolve('./global-teardown')
});
type Fixtures = {
  userApi: Api;
  newEntity: LegalEntityModel;
};

export const entityGuidsToDelete = new Array<string>();

export const test = base.extend<Fixtures>({
 ...
 newEntity: async ({ userApi }, use) => {
    const newEntity = await createNewEntity()
    entityGuidsToDelete.push(newEntity.id); //this is being called
    await use(newEntity);
  }  
}

export { expect } from '@playwright/test';

Black background appearing on SVG when converted to PNG for mPDF library

I’m working on a feature that converts DOM content into a PDF using the mpdf/mpdf library from Composer/Packagist, and it generally works great. However, part of the DOM content is generated using C3.js to create charts. I convert the C3.js SVG to a PNG by drawing it onto a canvas so that it appears in the PDF file.

The conversion works, but the resulting chart has a black background, which makes the legends unreadable and doesn’t look good.

Chart with black background

Here’s the code I’m using to create the canvas:

document.getElementById('generatePDF').addEventListener('click', function(event) {
    event.preventDefault();

    // Récupérer le contenu HTML (données de la campagne)
    const campaignContent = document.querySelector('.container--campaigns').innerHTML;

    // Convertir le graphique C3.js en image base64
    const svg = document.querySelector('#chart svg');
    const svgData = new XMLSerializer().serializeToString(svg);
    
    // Créer une image base64 à partir du SVG
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    const img = new Image();

    const svgBase64 = 'data:image/svg+xml;base64,' + btoa(encodeURIComponent(svgData).replace(/%([0-9A-F]{2})/g, function(match, p1) {
        return String.fromCharCode(parseInt(p1, 16));
    }));
    
    img.onload = function() {
        canvas.width = svg.clientWidth;
        canvas.height = svg.clientHeight;
        ctx.drawImage(img, 0, 0);
        const chartImageBase64 = canvas.toDataURL('image/png');

        // Remplir les champs cachés avec les données récupérées
        document.getElementById('htmlContent').value = campaignContent;
        document.getElementById('chartImage').value = chartImageBase64;

        // Soumettre le formulaire
        document.getElementById('formPDF').submit();
    };

    img.src = svgBase64;  // Convertir le SVG en image
});

I’ve tried adding a rect element for a background, applying styles to the #chart svg via JS, and even setting the background in PHP with mPDF, but nothing seems to work.

Any ideas on how to fix this?

Thanks so much for your help!

Sharing a Language Array for a Translator Application in JavaScript [closed]

I’m developing a translator application using HTML, CSS, and JavaScript. The app requires a comprehensive set of languages to support translation features.

I compiled a JavaScript array containing various languages, including their names, native scripts, and codes. I believe this could help others who are working on similar projects. Here’s the array I’ve created:

const languages = [
    { no: "0", name: "Auto", native: "Detect", code: "auto" },
    { no: "1", name: "Afrikaans", native: "Afrikaans", code: "af" },
    { no: "2", name: "Albanian", native: "Shqip", code: "sq" },
    { no: "3", name: "Arabic", native: "عربي", code: "ar" },
    { no: "4", name: "Armenian", native: "Հայերէն", code: "hy" },
    { no: "5", name: "Azerbaijani", native: "آذربایجان دیلی", code: "az" },
    { no: "6", name: "Basque", native: "Euskara", code: "eu" },
    { no: "7", name: "Belarusian", native: "Беларуская", code: "be" },
    { no: "8", name: "Bulgarian", native: "Български", code: "bg" },
    { no: "9", name: "Catalan", native: "Català", code: "ca" },
    { no: "10", name: "Chinese (Simplified)", native: "中文简体", code: "zh-CN" },
    { no: "11", name: "Chinese (Traditional)", native: "中文繁體", code: "zh-TW" },
    { no: "12", name: "Croatian", native: "Hrvatski", code: "hr" },
    { no: "13", name: "Czech", native: "Čeština", code: "cs" },
    { no: "14", name: "Danish", native: "Dansk", code: "da" },
    { no: "15", name: "Dutch", native: "Nederlands", code: "nl" },
    { no: "16", name: "English", native: "English", code: "en" },
    { no: "17", name: "Estonian", native: "Eesti keel", code: "et" },
    { no: "18", name: "Filipino", native: "Filipino", code: "tl" },
    { no: "19", name: "Finnish", native: "Suomi", code: "fi" },
    { no: "20", name: "French", native: "Français", code: "fr" },
    { no: "21", name: "Galician", native: "Galego", code: "gl" },
    { no: "22", name: "Georgian", native: "ქართული", code: "ka" },
    { no: "23", name: "German", native: "Deutsch", code: "de" },
    { no: "24", name: "Greek", native: "Ελληνικά", code: "el" },
    { no: "25", name: "Haitian Creole", native: "Kreyòl ayisyen", code: "ht" },
    { no: "26", name: "Hebrew", native: "עברית", code: "iw" },
    { no: "27", name: "Hindi", native: "हिन्दी", code: "hi" },
    { no: "28", name: "Hungarian", native: "Magyar", code: "hu" },
    { no: "29", name: "Icelandic", native: "Íslenska", code: "is" },
    { no: "30", name: "Indonesian", native: "Bahasa Indonesia", code: "id" },
    { no: "31", name: "Irish", native: "Gaeilge", code: "ga" },
    { no: "32", name: "Italian", native: "Italiano", code: "it" },
    { no: "33", name: "Japanese", native: "日本語", code: "ja" },
    { no: "34", name: "Korean", native: "한국어", code: "ko" },
    { no: "35", name: "Latvian", native: "Latviešu", code: "lv" },
    { no: "36", name: "Lithuanian", native: "Lietuvių kalba", code: "lt" },
    { no: "37", name: "Macedonian", native: "Македонски", code: "mk" },
    { no: "38", name: "Malay", native: "Malay", code: "ms" },
    { no: "39", name: "Malayalam", native: "മലയാളം", code: "ml" },
    { no: "40", name: "Maltese", native: "Malti", code: "mt" },
    { no: "41", name: "Norwegian", native: "Norsk", code: "no" },
    { no: "42", name: "Persian", native: "فارسی", code: "fa" },
    { no: "43", name: "Polish", native: "Polski", code: "pl" },
    { no: "44", name: "Portuguese", native: "Português", code: "pt" },
    { no: "45", name: "Romanian", native: "Română", code: "ro" },
    { no: "46", name: "Russian", native: "Русский", code: "ru" },
    { no: "47", name: "Serbian", native: "Српски", code: "sr" },
    { no: "48", name: "Slovak", native: "Slovenčina", code: "sk" },
    { no: "49", name: "Slovenian", native: "Slovensko", code: "sl" },
    { no: "50", name: "Spanish", native: "Español", code: "es" },
    { no: "51", name: "Swahili", native: "Kiswahili", code: "sw" },
    { no: "52", name: "Swedish", native: "Svenska", code: "sv" },
    { no: "53", name: "Thai", native: "ไทย", code: "th" },
    { no: "54", name: "Turkish", native: "Türkçe", code: "tr" },
    { no: "55", name: "Ukrainian", native: "Українська", code: "uk" },
    { no: "56", name: "Urdu", native: "اردو", code: "ur" },
    { no: "57", name: "Vietnamese", native: "Tiếng Việt", code: "vi" },
    { no: "58", name: "Welsh", native: "Cymraeg", code: "cy" },
    { no: "59", name: "Yiddish", native: "ייִדיש", code: "yi" },
];

Problem with npm run dev missing script issues?

I am trying to use npm to run my application. I’m getting the error below:

npm run dev
npm error Missing script: "dev"
npm error
npm error To see a list of scripts, run:
npm error   npm run
npm error A complete log of this run can be found in: C:UsersFatiihAppDataLocalnpm-cache_logs2024-10-17T12_19_10_496Z-debug-0.log

Below is my package.json file:

{
    "name": "pay",
    "version": "1.0.0",
    "main": "index.js",
    "scripts": {
        "start": "node index.js",
        "dev": "nodemon index.js",
        "test": "jest"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "description": "",
    "dependencies": {
        "bcryptjs": "^2.4.3",
        "dotenv": "^16.4.5",
        "express": "^4.21.1",
        "jsonwebtoken": "^9.0.2",
        "passport": "^0.7.0",
        "passport-jwt": "^4.0.1",
        "passport-oauth2": "^1.8.0",
        "pg": "^8.13.0",
        "pg-hstore": "^2.3.4",
        "sequelize": "^6.37.4"
    },
    "devDependencies": {
        "nodemon": "^3.1.7"
    }
}

Because of this error, my localhost cannot run. How can I fix it?

TypeError: Cannot read properties of undefined (reading ‘type’) after eslint update

I try to update my project to use the newest 9.12.0 eslint instead of 8.54.0 which I currently use. I did the necessary config migration from .eslintrc.json to eslint.config.mjs. When I run eslint src on my local machine with node version 22.9.0 and yarn 1.22.22 it works perfectly fine – howver when I run exactly the same code on gitlab runner using docker node:22.9.0-slim image I get

$ eslint src
Warning: React version not specified in eslint-plugin-react settings. See https://github.com/jsx-eslint/eslint-plugin-react#configuration .
Oops! Something went wrong! :(
ESLint: 9.12.0
TypeError: Cannot read properties of undefined (reading 'type')
Occurred while linting /builds/xxx/voll/products/cc/simple/src/components/CampaignInfo.tsx:1
Rule: "@typescript-eslint/no-unused-vars"
    at isReadForItself (/builds/xxx/voll/products/cc/simple/node_modules/@typescript-eslint/eslint-plugin/dist/util/collectUnusedVariables.js:562:22)
    at /builds/xxx/voll/products/cc/simple/node_modules/@typescript-eslint/eslint-plugin/dist/util/collectUnusedVariables.js:583:27
    at Array.some (<anonymous>)
    at isUsedVariable (/builds/xxx/voll/products/cc/simple/node_modules/@typescript-eslint/eslint-plugin/dist/util/collectUnusedVariables.js:582:32)
    at UnusedVarsVisitor.collectUnusedVariables (/builds/xxx/voll/products/cc/simple/node_modules/@typescript-eslint/eslint-plugin/dist/util/collectUnusedVariables.js:124:21)
    at UnusedVarsVisitor.collectUnusedVariables (/builds/xxx/voll/products/cc/simple/node_modules/@typescript-eslint/eslint-plugin/dist/util/collectUnusedVariables.js:133:18)
    at UnusedVarsVisitor.collectUnusedVariables (/builds/xxx/voll/products/cc/simple/node_modules/@typescript-eslint/eslint-plugin/dist/util/collectUnusedVariables.js:50:36)
    at collectVariables (/builds/xxx/voll/products/cc/simple/node_modules/@typescript-eslint/eslint-plugin/dist/util/collectUnusedVariables.js:603:30)
    at collectUnusedVariables (/builds/xxx/voll/products/cc/simple/node_modules/@typescript-eslint/eslint-plugin/dist/rules/no-unused-vars.js:279:65)
    at Program:exit (/builds/xxx/voll/products/cc/simple/node_modules/@typescript-eslint/eslint-plugin/dist/rules/no-unused-vars.js:423:36)
error Command failed with exit code 2.

I compared all the deps versions using yarn list and all of them are the same; I checked that node/yarn version are the same.

How is it possible that it’s working on my local machine but it doesn’t work when I run it using gitlab runner ?

How to change a value of an array inside another array

Here is my student score json file :
(the idea is creating a function to change specific student score)

const classesData = [
  {
    name: 'A',
    books: [
      { name: 'math' },
      { name: 'chemistry' },
      { name: 'physic' }
    ],
    students: [
      {
        name: 'first student',
        results: [
          { name: 'math', score: '20' },
          { name: 'chemistry', score: '14' },
          { name: 'physic', score: '16' },
        ]
      },
      {
        name: 'second student',
        results: [
          { name: 'math', score: '15' },
          { name: 'chemistry', score: '10' },
          { name: 'physic', score: '12' },
        ]
      }
    ]
  },
  {
    name: 'B',
    books: [
      { name: 'math' },
      { name: 'chemistry' },
      { name: 'physic' }
    ],
    students: [
  {
        name: 'first student',
        results: [
          { name: 'math', score: '20' },
          { name: 'chemistry', score: '14' },
          { name: 'physic', score: '16' },
        ]
      },
      {
        name: 'second student',
        results: [
          { name: 'math', score: '15' },
          { name: 'chemistry', score: '10' },
          { name: 'physic', score: '12' },
        ]
      }
    ]
  }
]

How to do that?
For example
from class A change second student physic score to from 12 to 20
I’ve tried foreach and map but I didn’t get the result that I want

Getting maximum call stack for grunt

I am running grunt on my project as follows, I am new to grunt could some one please help me

ts% grunt copy-node-modules
Loading “Gruntfile.js” tasks…ERROR

RangeError: Maximum call stack size exceeded
Warning: Task “default” not found. Use –force to continue.

Aborted due to warnings.

Execution Time (2024-10-17 11:49:21 UTC)
loading tasks 30.1s ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 100%
Total 30.1s

my gruntfile.js,

nodeModulesDir: {
                files:[
                    {
                        expand: true,
                        cwd: 'node_modules', // source directory
                        src: [
                            'ng-file-upload/**/*.js', // add required npm moudles here
                            'angular-dynamic-locale/**/*',
                            'higcharts/**/*',
                            'highcharts-ng/**/*',
                            'respond.js/**/*',
                            'angular/**/*',
                        ],
                        dest: 'app/lib' // target directory
                    },
                    {
                        expand: true,
                        cwd: 'node_modules/froala-editor', // source directory
                        src: ['**'],
                         dest: 'app/lib/froala-wysiwyg-editor' // target directory
                    },
                    {
                        expand: true,
                        cwd: 'node_modules/@npm',
                        src: [                        
                            './angular-read-more/**/*'
                        ],
                        dest: 'app/lib'
                    },
                    {
                        expand: true,
                        cwd: 'node_modules/@npm',
                        src: [                        
                            './angular-event-delegate/**/*'
                        ],
                        dest: 'app/lib'
                    },
                    {
                        expand: true,
                        cwd: 'node_modules/angular-numeraljs/node_modules/numeral',
                        src: ['**'],
                        dest: 'app/lib/numeral'
                    },
                    {
                        expand: true,
                        cwd: 'node_modules/jquery-ui-sortable', // source directory
                        src: ['**'],
                         dest: 'app/lib/jquery-ui-sortable' // target directory
                    },
                    {
                        expand: true,
                        cwd: 'node_modules/lodash', // source directory
                        src: ['**'],
                         dest: 'app/lib/lodash' // target directory
                    },
                    {
                        expand: true,
                        cwd: 'node_modules/angular-md', // source directory
                        src: ['**'],
                        dest: 'app/lib/angular-md' // target directory
                    },
                    {
                        expand: true,
                        cwd: 'node_modules/angular-scroll', // source directory
                        src: ['**'],
                        dest: 'app/lib/angular-scroll' // target directory
                    },
                    {
                        expand: true,
                        cwd: 'node_modules/angular-touch', // source directory
                        src: ['**'],
                        dest: 'app/lib/angular-touch' // target directory
                    },
                    {
                        expand: true,
                        cwd: 'node_modules/bootstrap', // source directory
                        src: ['**'],
                        dest: 'app/lib/bootstrap' // target directory
                    },
                    {
                        expand: true,
                        cwd: 'node_modules/angular-ui-bootstrap', // source directory
                        src: ['**'],
                        dest: 'app/lib/angular-ui-bootstrap' // target directory
                    },
                    {
                        expand: true,
                        cwd: 'node_modules/angular-ui-sortable', // source directory
                        src: ['**'],
                        dest: 'app/lib/angular-ui-sortable' // target directory
                    },
                ]
            }

         grunt.registerTask('copy-node-modules', ['copy:nodeModulesDir']);

I am trying to run grunt copy-node-modules

Make dragged item ghost reverts to new position if dropped out of bounds

I have a list of items, I implemented Drag and Drop, when I move the item to a new location, it stays there, but when I move the Item to a new location and got out of bound with the dragged ghost item and end the drop there, the ghost returns to the initial position. How do I handle that?

Initial list:

Initial List

Dragged item to position 3 (index 2) and then out of bounds, Ghost will return to initial position, but I save the changed position as the new list:

enter image description here

I am using react and this is how I handle my drag and drop:

 const handleDragStart = ( e, index ) => {
    const draggedHotelKey = Object.keys( hotelList )[index];
    const draggedHotel = hotelList[draggedHotelKey];

    setDraggedItem( {
      hotel      : draggedHotel,
      startIndex : index,
    } );

    e.dataTransfer.effectAllowed = "move";
  };

  const handleDragOver = ( e, index ) => {
    e.preventDefault();
    if ( index === draggedItem.startIndex ) return;

    const hotelKeys = Object.keys( hotelList );
    const [ removedHotelKey ] = hotelKeys.splice( draggedItem.startIndex, 1 );
    hotelKeys.splice( index, 0, removedHotelKey );

    const updatedHotelList = hotelKeys.reduce( ( acc, key ) => {
      acc[key] = hotelList[key];
      return acc;
    }, {} );

    setHotelList( updatedHotelList );
    setDraggedItem( ( prev ) => ( {
      ...prev,
      startIndex : index,
    } ) );
  };

  const handleDrop = async ( e ) => {
    e.preventDefault();
    try {
      await dispatch( updateHotelList( selectedEventId, hotelList ) );
    } catch ( error ) {
      console.error( "Failed to update hotel list:", error );
      setHotelList( initialHotelList );
    }
  };

I need some advice how to redirect the ghost or prevent the ghost from appearing at all

How to map JSON in dropdown list

I want to map JSON when Level include some level then school include some schools but in one level not include any school and the program each level include program how to map and display data in dropdown or how to write condition.

JSON :

const programList :{
    level : [
            {levelName:"UG",school:[{schoolName:"XYZ",program : [{programName:"PQR"}]}]},
            {levelName:"PG",school:[{schoolName:"XYZ",program : [{programName:"PQR"}]}]},
            {levelName:"PHD",program : [{programName:"PQR"}]},
        ]
}

how to map JSON in dropdown when in the PHD level not include school
   How to map JSON data when Level--> PG,UG,PHD,DIPLOMA ,School-->include school in PG,UG,DIPLOMA but in PHD not include schools ,Program--> each level include programs how map this json

How to dynamically set readonly property for based on value in Vue.js?

I wanted that in ‘change’ if the value of the input-number becomes equal to, for example, ‘5’ I wanted it to assign the readonly property or at least have the same behavior as the property in that input-number, as it is now it is not working

<el-input-number
    v-model="q.values[a-1].value_numeric"
    :disabled="isParameterDisabled(q) || q.parameter.calculated"
    :readonly="isReadonly || isParameterReadonly(q)"
    :ref="'f_'+q.id+'_n'+a"
    :id="'f_'+q.id+'_n'+a"
    :key="q.id+'_n'+a"
    :placeholder="'n'+a"
    :precision="q.typeProps.precision ? parseInt(q.typeProps.precision) : defaultPrecision"
    @change="onNumericValueChanged($event, q, a, f.title)"
    @keydown.enter.native="focusNextInput(q.id, a)"
    :class="loadTrafficLightNumeric(q, q.values[a - 1].value_numeric)"
/>

onNumericValueChanged(value, q, a, className) {

    if (value === 5) {
       this.isReadonly = true;
    } else {
        this.isReadonly = false;
    }
}

Создание кастомного символа для моего сайта. CSS, fonts, symbols [closed]

Я видел синтаксис в HTML, где можно добавить символы в определённом синтаксисе, где &gt; – это >, &lt; – это <, и я хочу таким образом добавить свой собственный кастомный символ.

Я очень долго искал информацию про создание кастомных символов с помощью font’ов, с помощью HTML-сущностей, в итоге я ничего не нашёл. Поисковики выдают инструкцию по добавлению уже существующих специальных символов на страницу, но как создать кастомный символ, я так и не понял, хотя ищу эту информацию уже довольно долго.

Я поясняю: мне не нужно добавлять иконку или SVG-элемент, предполагается форум, где кастомные символы можно будет скопировать в буфер обмена, как и все остальные символы. Я хочу добавлять символы на сайт в формате &my_custom_symbol;.

Мой сайт предполагается, как тематический форум, где посетители сайта могут в сообщениях использовать кастомные символы, которых нет в стандартах Unicode.

Я искал информацию о создании кастомных символов в интернете, и в итоге не нашёл, я пользовался разными поисковиками и даже чат-ботами, но находил я лишь инструкции о добавлении эмоджи на сайт, но ничего не находил о том, как создать собственный, новый, кастомный символ.

CSS styling for dynamic video grid only shows fullscreen video

I tried programming a small interactive Website to show some Videos and Pictures in a dynamic grid. So far, the grid for the pictures works (mostly) like I want and shows all pictures in a grid.

However if I try the same thing for my Videos, I only get showed the first Video in giant.

I want to be able to open the Video in fullscreen when I click it, and I thought maybe that had something to do with why I only see one.

I’ve tried to change up the CSS, and also tried it without the JS, but neither have worked. I don’t know if I did something wrong or my thought process is wrong.

function openFullscreenVideo(video) {
  const overlay = document.createElement('div');
  overlay.className = 'fullscreen-overlay';

  const closeButton = document.createElement('button');
  closeButton.className = 'close-button';
  closeButton.innerHTML = 'Schließen';
  closeButton.onclick = function() {
    closeFullscreen(overlay);
  };

  const fullscreenVideo = document.createElement('video');
  fullscreenVideo.src = video.src;
  fullscreenVideo.controls = true;
  fullscreenVideo.autoplay = true;
  fullscreenVideo.muted = true;
  fullscreenVideo.style.maxWidth = '90%';
  fullscreenVideo.style.maxHeight = '90%';

  const fullScreenButton = document.createElement('button');
  fullScreenButton.innerHTML = 'Vollbild';
  fullScreenButton.onclick = function() {
    if (fullscreenVideo.requestFullscreen) {
      fullscreenVideo.requestFullscreen();
    } else if (fullscreenVideo.mozRequestFullScreen) {
      fullscreenVideo.mozRequestFullScreen();
    } else if (fullscreenVideo.webkitRequestFullscreen) {
      fullscreenVideo.webkitRequestFullscreen();
    } else if (fullscreenVideo.msRequestFullscreen) {
      fullscreenVideo.msRequestFullscreen();
    }
  };

  fullscreenVideo.onended = function() {
    closeFullscreen(overlay);
  };

  overlay.appendChild(closeButton);
  overlay.appendChild(fullscreenVideo);
  overlay.appendChild(fullScreenButton);
  document.body.appendChild(overlay);
}

function closeFullscreen() {
  const fullscreenImage = document.getElementById('fullscreen-image');
  const fullscreenVideo = document.getElementById('fullscreen-video');
  if (fullscreenImage) {
    document.body.removeChild(fullscreenImage);
  }
  if (fullscreenVideo) {
    document.body.removeChild(fullscreenVideo);
  }
  document.body.style.overflow = 'auto';
}
/* Stil für die Videos im Grid */

.video-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(150px, 1fr));
  gap: 10px;
  padding: 10px;
  max-width: calc(100% - 40px);
  margin: 0 auto;
}

.video-grid video {
  width: 100%;
  height: auto;
  border-radius: 8px;
}


/* Stil für das fullscreen Overlay */

.fullscreen-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.8);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
}

.fullscreen-overlay video {
  max-width: 90%;
  max-height: 90%;
}
<div class="container">
  <div id="videos" class="content">
    <div class="video-grid">
      <video src="./Videos/video1.mp4" alt="Video 1" onclick="openFullscreenVideo(this)" controls></video>
      <video src="./Videos/video2.mp4" alt="Video 2" onclick="openFullscreenVideo(this)" controls></video>
      <video src="./Videos/video3.mp4" alt="Video 3" onclick="openFullscreenVideo(this)" controls></video>
    </div>
  </div>
</div>

How to get the attribute of an innerHTML?

I’m trying to get the value of a span attribute (data-red) inside a table cell.

<td class=" u-tL" headers="due-date" aria-labelledby="due-date"><span data-red="255" style="display: block; width: 75px;">19-JAN-2024</span></td> 

I’ve tried the code below but it’s giving me the error “Uncaught TypeError: spn.getAttribute is not a function”

spn = obj.innerHTML;
console.log(spn.getAttribute('data-red'));

Appreciate any help.

Regex that detects if the key has a missing character

const placeholders = {
    "Luke": "{{candidate_first_name}}",
    "[email protected]": "{{candidate_email}}",
}

const text = <div>Hi&nbsp; Luke ,</div><div><strong>Email: </strong>[email protected]</div>

export default function removeTextPlaceholders(
  text: string,
  placeholders: any
) {
  try {
    for (const [key, value] of Object.entries(placeholders)) {
      if (value) {
        const regex = new RegExp(`^${key}(?:\s*|.{0,1})$`, 'g');

        // Check if the key is a complete match before replacing
        if (!text.includes(key)) {
          text = text.replace(regex, '');
        }
      }
    }

    return text;
  } catch (e) {
    return text;
  }
}



function cleanPlaceholders(input: any) {
                // Regular expression to match any incomplete placeholders
                const regex = /{{w+}(?!})|(?<!{){w+}}/g;

                // Replace incomplete placeholders with an empty string
                return input.replace(regex, '');
              }

const handleBodyChange = (e: any) => {
                if (previewOpen) {
                  const value = removeTextPlaceholder(e);
                  setPreviewBody(textToplacholders(value));
                  setFieldValue('body', textToplacholders(value));
                } else {
                  const value = cleanPlaceholders(e);
                  setPreviewBody(value);
                  setFieldValue('body', value);
                }
              };

this is the return ui:

{!previewOpen ? (
    <AtsEmailBody
     value={values.body}
     onChange={(e: any) => handleBodyChange(e)}
    />) :
    <AtsEmailBody
     value={placholders(previewBody)}
     onChange={(e: any) => handleBodyChange(e)}
    />)
}

The thing is, I’m creating a text editor that changes the placeholder to its value and vise-versa.

For example,

the value on the editor is:

Hi  {{candidate_first_name}} ,
Email: {{candidate_email}}

if the {{}} is not complete format, it automatically remove all of its word. So for example, if i delete the } in {{candidate_first_name}} and it became {{candidate_first_name}, the function cleanPlaceholders will remove the whole {{candidate_first_name}}. I already have a function with that.

If the previewOpen is true, the placeholder will be converted to its value.

Hi  Luke ,
Email: [email protected]

Currently, my issue now is if I delete a char of the placeholder value, it should remove all of the words.

For example, if I removed the e and it will became Luk, Luke whole word should be automatically remove since it is a placeholder.

same with if i remove m in [email protected], it should remove the whole word.

for (const [key, value] of Object.entries(placeholders)) {
      if (value) {
        const regex = new RegExp(`${key}(?:\s*|.{0,1})`, 'g');
     text = text.replace(regex, '');
    }
    }

this is my current condition, but this only detect the whole value. and it removed all of the text content since this regex matches the exact key value.