How to update google apps script to apply to specific cells and not all cells

I have the following script which is doing exactly what I want (changing the currency symbol within cells depending on what is selected), except that it’s being applied to all cells, and I’d like it applied only to cells C9, C12, C13. I’m probably missing something painfully obvious, but I’m just not quite sure where I would put that in the script. Thank you!

function udtsymbol () {
    const s = SpreadsheetApp.getActiveSheet();
  const r = s.getDataRange();
  const symb = {"$":"$", "€":"€", "£":"£"};
  r.setNumberFormat(symb[s.getRange("C8").getValue()]+"###,##0.00");

I’ve tried editing the code in a number of different ways, including adding the range within getDataRange() and also putting in an if statement, but I keep getting errors, as I’m not familiar with javascript. Have been googling for hours so finally asking for help.

Click on YouTube button inside iframe using javascript

I have a YouTube playlist displayed inside an iframe on a webpage & want to automate clicking on the playlist’s ‘index button’ when the page loads so that the list of videos is displayed.

The button has the following classes: ytp-playlist-menu-button & ytp-button but no ID. It does however have an aria-owns ytp-id-22 which after Googling, I believe acts like an ID – is that right?

As I’m not sure whether aria-owns acts like (& can be used as) an ID, I’m trying document.getElementsByClassName instead but am aware that this is not a good practice & doesn’t work on some browsers.

I’m trying to work out by looking at examples online but haven’t found a clear way to achieve this. I’m currently using the script formula below but it doesn’t work & I’m not convinced it’s the right approach either.

document.addEventListener('DOMContentLoaded', () => {
    document.querySelector('#player_2').contentWindow
        document.getElementsByClassName('ytp-playlist-menu-button').trigger("click") ;
});

You can view the actual page where the YouTube playlist is embedded here

My knowledge of writing javascript / jQuery is extremely limited but as far as I understand it, in the above code:

  1. The 1st line ensures the page has fully loaded
  2. The 2nd line allows it work ‘inside’ an iframe (with the ID ‘player_2’)
  3. The 3rd line is the action that clicks on the button (with an ID ‘ytp-playlist-menu-button’)

Also just to say:

A. Above is the entire script & I was wondering does it need additional code to actually work properly?
B. I have enqueued the script into the header via this code:

function theme_enqueue_scripts() {
        if (is_page ('3055') ) {
            wp_enqueue_script ('youtubePlaylistButton_js', get_theme_file_uri() . '/wp-includes/js/youtubePlaylistButton_js.js', array(), false, false); }
        }
        add_action( 'wp_enqueue_scripts', 'theme_enqueue_scripts' );

Issue with Updating Iframe Source in HTML Based on Record Selection

function onloadalert(executionContext) {
    var formContext = executionContext.getFormContext();

    // Get the Case ID (assuming it's stored in the 'incidentid' field)
    var caseid = formContext.getAttribute("msdyn_subject").getValue();
    if (caseid) {
        // Call the onloadalert function and pass the Case ID
        console.log(caseid);
    } else {
        console.log("Case ID is not available.");
    }

    var sidePane = Xrm.App.sidePanes.getPane("ReservationList");
    if (sidePane) {//If the pane is already open, just navigate to the page
        var pageInput = {
            pageType: "webresource",
            webresourceName: "dd_dynamichtml",
            data: encodeURIComponent(`recordId=${caseid}`)
        };
        sidePane.navigate(pageInput);
        Xrm.App.sidePanes.state = 1;
        return;
    }
    
    // Create the side pane
    Xrm.App.sidePanes.createPane({
        title: "Copilot",
        imageSrc: "WebResources/dd_chatgpticon", // Image for the side pane
        paneId: "ReservationList",
        canClose: false
    }).then((pane) => {

        // Add the iframe content to the side pane
        pane.navigate({
            pageType: "webresource",
            webresourceName: "dd_dynamichtml", // The name of the web resource containing the HTML
            //data: iframeHtml // Pass the dynamically generated iframe HTML as data
            data: encodeURIComponent(`recordId=${caseid}`)
        });
    });

    Xrm.App.sidePanes.state = 1; // Ensure the pane is opened
}
<!DOCTYPE html>
<html>
<script src="ClientGlobalContext.js.aspx" type="text/javascript"></script>
<script>


    function getQueryParam(param) {
        const urlParams = new URLSearchParams(window.location.search);
        return urlParams.get(param);
    }

    function getDecodedQueryStringParameter(param) {

        const data = getQueryParam('data');

        if (data) {
            const decodedData = decodeURIComponent(data);
            const decodedParams = new URLSearchParams(decodedData);
            return decodedParams.get(param);
        }

        return null;
    }


    document.addEventListener('DOMContentLoaded', function () {
        // Function to get the value of a specific query parameter
        console.log("DOM fully loaded and parsed");
        configureCopilotURL();
    });


    async function configureCopilotURL() {
        const recordId = getDecodedQueryStringParameter('recordId').replace("{", "").replace("}", "");

        const copilotUrl = `https://copilotstudio.microsoft.com/environments/envid/bots/documentComparisionBot/webchat?__version__=2&caseId=${recordId}`

        // Set the iframe's src to the URL obtained from the query parameter
        if (copilotUrl) {
            console.log(copilotUrl);    
            document.getElementById('caseCopilot').src = copilotUrl;
        }
    }


</script>

<style>
    html,
    body {
        margin: 0;
        padding: 0;
        height: 100%;
        overflow: hidden;
    }

    iframe {
        width: 100%;
        height: 100%;
    }
</style>

<body>
    <iframe id="caseCopilot" frameborder="0" style="width: 100%; height: 100%;"></iframe>
</body>

</html>

Below are the webresources I am using for Javascript and HTML.

SetUp: Jscript resource is linked to onload event for a form, when I click on a record, the html gets called and copilot side panel open

Issue: When I open the first record, the correct URL parameters are called, and the chat displays correctly. However, when I go back and select a second record, the chat still shows the first record’s information. If I open the second record in a new tab, it loads correctly, but it fails to refresh in the same tab.

Why is the URL not opening correctly if open in same tab? if the second record is opened in new tab, it works fine.

first click sidepane as expencted

second record still showing old chat

Django SESSION_EXPIRE_AT_BROWSER_CLOSE not working in Microsoft Edge

I am trying to log out users automatically when they close the browser or a tab. I have set:

SESSION_EXPIRE_AT_BROWSER_CLOSE = True

in my Django settings, and it works as expected in most browsers. However, it does not seem to work in Microsoft Edge.

Is there a specific solution or workaround to make this functionality work in Edge?

I also tried using beforeunload, but it logs out the user even when the browser is refreshed:

$(document).ready(function() {         
    $(window).on("beforeunload", function(e) {
        $.ajax({
            url: "{% url 'logoutUser' %}",
            method: 'GET',
        });
    });
});

Div textcontent inconsistently returning string

I am simply querying a web page for specific text to save to local storage and use within Chrome extension pop-up.

contentscript.js – Code I inject to webpage

function findworkspaceName() {
  let target = '#name > .company';

  const observer = new MutationObserver((mutationsList, observer) => {
    if (document.querySelector(target)) {
      let name = getDetails();
      chrome.storage.local.set({ name });
      observer.disconnect();
    }
  });

  observer.observe(document.body, { childList: true, subtree: true });

  function getDetails() {
    let workspaceName = document.querySelector(target);

    console.log(workspaceName);
    console.log(workspaceName.textContent);
    return workspaceName.textContent;
  }

  // Initial check in case the element is already present
  if (document.querySelector(target)) {
    getWorkspaceDetails();
    observer.disconnect();
  }
}

findworkspaceName();

Now just focusing on getDetails function. Console logging workspaceName seems to return the div in the console consistently. However, console logging workspaceName.textContent does not always return the textcontent from the div. Sometimes it’s empty and sometimes it correctly shows the text:

function getDetails() {
 let workspaceName = document.querySelector(target);
 console.log(workspaceName); // works 100%
 console.log(workspaceName.textContent); // Is inconsistent
 return workspaceName.textContent;
}

Why could this be occuring?

Upgrading Webpack with npm and Angular

I am upgrading a legacy node/angular application (10 years old!) and have got everything compiled without error messages, etc. I am using an index.html folder at the server root to start off the application, through this code:

<body>
  <tc-app>Loading...</tc-app>
</body>

is a piece of Angular code. This invokes an appcomponent module, with the selector ‘tc-app’. This in turn loads a template in the file “app.html”, which in turn invokes yet further component modules, each with its own templates, and so it goes.

In the legacy application, using Webpack 1.15.0, the webpack generates three files for the /dist folder: app.bundle.js, app.css, vendor.bundle.js. The new application, using Webpack 5.94.0, happily generates app.bundle.js. However, it does NOT generate app.css. That is to be expected: the legacy application uses ExtractTextPlugin, now deprecated. However, my attempts to figure out how the replacement MiniCssExtractPlugin can be used to generate the app.css file in /dist have so far failed. Including tbe line

new MiniCssExtractPlugin("app.css"),

in the rules section of webpack.config.js generates an error. Omitting the parameter, thus new MiniCssExtractPlugin(), allows webpack to finish, but does not generate anything in /dist.

The second problem is generating the bundle for all the angular components, output in vendor.bundle.js by the legacy application. I have tried multiple different attempts, based on the documentation at https://webpack.js.org/guides/code-splitting/ and elsewhere but nothing is working. In the legacy file, the vendor.bundle.js was generated by this code, in the plug-ins array:

   new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor', filename: 'vendor.bundle.js',
      chunks: ['app'],
      minChunks: function(module, count) {
        return module.resource && module.resource.indexOf(clientRoot) === -1;
      }

However, in the new application this returns errors:

 at Module._compile (node:internal/modules/cjs/loader:1469:14)
 at Module._extensions..js (node:internal/modules/cjs/loader:1548:10)
 at Module.load (node:internal/modules/cjs/loader:1288:32)
 at Module._load (node:internal/modules/cjs/loader:1104:12)
 TypeError: webpack.optimize.CommonsChunkPlugin is not a constructor
    at Object.<anonymous (/Users/pmr906_1/venv/TCangular/tc/public/webpack.js:125:5)

Here is my current webpack.config.js:

var _ = require('lodash')
  , webpack = require('webpack')
  , ResolverPlugin = webpack.ResolverPlugin
  , ProvidePlugin = webpack.ProvidePlugin
  , IgnorePlugin = webpack.IgnorePlugin
//  , ExtractTextPlugin = require("extract-text-webpack-plugin")
  , path = require('path')
  , clientRoot = path.resolve(__dirname)
  , bowerRoot = path.resolve(clientRoot, '..', 'bower_components')
  , nodeRoot = path.resolve(clientRoot, '..', 'node_modules')
  , devtool = 'eval-source-map'
  , debug = true
  , MiniCssExtractPlugin = require("mini-css-extract-plugin")
;

switch (process.env.NODE_ENV) {
  case 'production':
    devtool = '#source-map';
    debug = false;
    break;
  case 'development':
    devtool = 'eval-source-map';
    debug = true;
    break;
}

var config = {
  context: clientRoot,
  mode: "development",
  entry: {
    app: path.join(clientRoot, 'app/boot.js'),
    t: path.join(clientRoot, 'app/t.js'),
  },
  output: {
    path: path.join(clientRoot, 'dist'),
    filename: '[name].bundle.js',
    devtoolModuleFilenameTemplate(info) {
     return `file:///${info.absoluteResourcePath.replace(/\/g, '/')}`;
   },
  },
  externals: {
    jquery: 'jQuery',
    rxjs: 'Rx',
    lodash: '_',
    bson: 'bson',
    'codemirror/lib/codemirror': 'CodeMirror',
    'codemirror/mode/xml/xml': false,
  },
  module: {
    rules: [
      {
        test: /.png(?v=d+.d+.d+)?$/,
        use: "url?limit=1000&minetype=image/jpg&prefix=dist/"
      }, {
        test: /.jpg(?v=d+.d+.d+)?$/,
        use: "url?limit=1000&minetype=image/jpg&prefix=dist/"
      }, {
        test: /.woff(?v=d+.d+.d+)?$/,
        use: "url?limit=1000&minetype=application/font-woff&prefix=dist/"
      }, {
        test: /.woff2(?v=d+.d+.d+)?$/,
        use: "url?limit=1000&minetype=application/font-woff&prefix=dist/"
      }, {
        test: /.ttf(?v=d+.d+.d+)?$/,
        use: "url?limit=1000&minetype=application/octet-stream&prefix=dist/"
      }, {
        test: /.eot(?v=d+.d+.d+)?$/,
        use: "url?limit=1000&minetype=application/vnd.ms-fontobject&prefix=dist/"
      }, {
        test: /.svg(?v=d+.d+.d+)?$/,
        use: "url?limit=1000&minetype=image/svg+xml&prefix=dist/"
      },
      {
        test: /.css$/i,
        use: [MiniCssExtractPlugin.loader, "css-loader"],
      },
      {
        test: /.less$/,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "less-loader",
            options: {
              lessOptions: {
    //          javascriptEnabled: true,
              },
            }, 
          },
        ],
      },
    ], /*,
    noParse: [
    ] */
  },
  resolve: {
 /*   root: [clientRoot], */
    modules: [clientRoot, 'web_modules', 'node_modules', 'bower_components', ],
    fallback: {
        "fs": false,
        "tls": false,
        "net": false,
        "path": false,
        "zlib": false,
        "http": false,
        "https": false,
        "stream": false,
        "crypto": false,
        "crypto-browserify": false, //if you want to use this module also don't forget npm i crypto-browserify 
      },
    alias: {
      bower: bowerRoot,
      node: nodeRoot,
    },
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor', filename: 'vendor.bundle.js',
      chunks: ['app'],
      minChunks: function(module, count) {
        return module.resource && module.resource.indexOf(clientRoot) === -1;
      }
      }), 
     new MiniCssExtractPlugin(), 
  ],
  devtool: devtool,
};

var compiler = webpack(config);

if (process.env.NODE_ENV === 'development') {
  compiler.watch({
    aggregateTimeout: 300,
    poll: 1000,
  }, handleError);
} else {
 compiler.watch({
    aggregateTimeout: 300,
    poll: 1000,
  }, handleError);
  //compiler.run(handleError);
}

Help..

Getting ERROR Error: Uncaught (in promise): NullInjectorError: No provider for eF, when I hit the route whose component uses the service

I am getting NullInjectorError error when I am trying to use a service in my angular app. Below are my app.module.ts, admin.service.ts, angular.json(I have made a few changes to the default configs here) and package.json

app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AngularEditorModule } from '@kolkov/angular-editor';


import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { AdminCrudComponent } from './components/admin-crud/admin-crud.component';
import { FormInputComponent } from './components/form-input/form-input.component';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';


@NgModule({
declarations: [
AppComponent,
AdminCrudComponent,
FormInputComponent
 ],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
AngularEditorModule,
HttpClientModule,
 ],
providers: [],
bootstrap: [AppComponent]
 })
export class AppModule { }

admin.service.ts

import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { URLConfig } from '../config/url.config';
import { environment } from '../../environments/environment';

@Injectable({ providedIn: 'root' })
export class AdminService {

constructor(private httpclient:HttpClient, private urlConfig: URLConfig) { }

createItem(item: any) {
const service = this.urlConfig.getConfig(environment.env);
const url = service.shreeArtsService + 'items';
const headers = new HttpHeaders();
headers.append('Content-Type', 'multipart/form-data');
return this.httpclient.post(url, item, {headers: headers});
}
}

angular.json

{
 "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
 "version": 1,
 "newProjectRoot": "projects",
 "projects": {
 "client": {
  "projectType": "application",
  "schematics": {
    "@schematics/angular:component": {
      "style": "scss"
    },
    "@schematics/angular:application": {
      "strict": true
    }
  },
  "root": "",
  "sourceRoot": "src",
  "prefix": "app",
  "architect": {
    "build": {
      "builder": "@angular-devkit/build-angular:browser",
      "options": {
        "outputPath": "dist/client",
        "index": "src/index.html",
        "main": "src/main.ts",
        "polyfills": "src/polyfills.ts",
        "tsConfig": "tsconfig.app.json",
        "inlineStyleLanguage": "scss",
        "assets": [
          "src/favicon.ico",
          "src/assets"
        ],
        "styles": [
          "src/styles.scss",
          "node_modules/bootstrap/dist/css/bootstrap.min.css"
        ],
        "scripts": ["node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"]
      },
      "configurations": {
        "prod": {
          "budgets": [
            {
              "type": "initial",
              "maximumWarning": "500kb",
              "maximumError": "1mb"
            },
            {
              "type": "anyComponentStyle",
              "maximumWarning": "2kb",
              "maximumError": "4kb"
            }
          ],
          "fileReplacements": [
            {
              "replace": "src/environments/environment.ts",
              "with": "src/environments/environment.prod.ts"
            }
          ],
          "outputHashing": "all"
        },
        "uat": {
          "budgets": [
            {
              "type": "initial",
              "maximumWarning": "500kb",
              "maximumError": "1mb"
            },
            {
              "type": "anyComponentStyle",
              "maximumWarning": "2kb",
              "maximumError": "4kb"
            }
          ],
          "fileReplacements": [
            {
              "replace": "src/environments/environment.ts",
              "with": "src/environments/environment.uat.ts"
            }
          ],
          "outputHashing": "all"
        }
      },
      "defaultConfiguration": "prod"
    },
    "serve": {
      "builder": "@angular-devkit/build-angular:dev-server",
      "configurations": {
        "prod": {
          "browserTarget": "client:build:prod"
        },
        "uat": {
          "browserTarget": "client:build:uat"
        }
      },
      "defaultConfiguration": "uat"
    },
    "extract-i18n": {
      "builder": "@angular-devkit/build-angular:extract-i18n",
      "options": {
        "browserTarget": "client:build"
      }
    },
    "test": {
      "builder": "@angular-devkit/build-angular:karma",
      "options": {
        "main": "src/test.ts",
        "polyfills": "src/polyfills.ts",
        "tsConfig": "tsconfig.spec.json",
        "karmaConfig": "karma.conf.js",
        "inlineStyleLanguage": "scss",
        "assets": [
          "src/favicon.ico",
          "src/assets"
        ],
        "styles": [
          "src/styles.scss"
        ],
        "scripts": []
      }
     }
    }
   }
  },
  "defaultProject": "client"
}

package.json

{
  "name": "client",
  "version": "0.0.0",
  "scripts": {
  "ng": "ng",
  "start": "ng serve",
  "build": "ng build",
  "start:uat": "ng serve --configuration=uat",
  "start:prod": "ng serve --configuration=prod",
  "watch": "ng build --watch --configuration development",
  "test": "ng test"
  },
  "private": true,
  "dependencies": {
  "@angular/animations": "~13.2.0",
  "@angular/common": "~13.2.0",
  "@angular/compiler": "~13.2.0",
  "@angular/core": "~13.2.0",
  "@angular/forms": "~13.2.0",
  "@angular/platform-browser": "~13.2.0",
  "@angular/platform-browser-dynamic": "~13.2.0",
  "@angular/router": "~13.2.0",
  "@kolkov/angular-editor": "^3.0.0-beta.0",
  "angular-font-awesome": "^3.1.2",
  "bootstrap": "^5.3.3",
  "ngx-editor": "^13.0.0",
  "rxjs": "~7.5.0",
  "tslib": "^2.3.0",
  "zone.js": "~0.11.4"
  },
 "devDependencies": {
  "@angular-devkit/build-angular": "~13.2.0",
  "@angular/cli": "~13.2.0",
  "@angular/compiler-cli": "~13.2.0",
  "@types/jasmine": "~3.10.0",
  "@types/node": "^12.11.1",
  "jasmine-core": "~4.0.0",
  "karma": "~6.3.0",
  "karma-chrome-launcher": "~3.1.0",
  "karma-coverage": "~2.1.0",
  "karma-jasmine": "~4.0.0",
  "karma-jasmine-html-reporter": "~1.7.0",
  "typescript": "~4.5.2"
  }
}

Since I have made few config changes in angular.json that might be one of the reasons It is breaking.

Why is a ‘s text-align:center style property ignored once I use JavaScript to change the contents of an inner- ?

I have this html table (I use single-cells tables instead of any other tags so that vertical-align works) :

<table cellspacing=0 cellpadding=0 class='BloodyButtonTanText' id='CameraModeTable' style='display:none; position:absolute; z-index:2; left:30%;
top:20%; width:40%; height:6.25%; font-size:5vmin; opacity:0'>
<tr><td style='width:100%; height:100%; text-align:center; vertical-align:middle; cursor:default'>
    <span id='CameraModeHolder'></span>&nbsp;Mode Activated...
</td></tr></table>

the following JavaScript functions activated upon right-clicking anywhere in the document :

function ToggleCameraTarget () {
    if (!CameraTarget) {
    RecordAction('Entered%20Cam%20Controls%20Mode');
    CameraTarget = 'SceneHolder';
    document.body.style.cursor = 'grab';
    document.body.title = `Mouse left/right to rotate around the 
`;
    DisplayCurrentCameraMode('Camera');
    } else {
    LastMouseX = false;
    LastMouseY = false;
        if (CameraTarget == 'SceneHolder') {
        RecordAction('Entered%20BuzzSaw%20Angle%20Control%20Mode');
        CameraTarget = 'BuzzSaw';
        document.body.title = `Mouse left/right to rotate around the 
`;
        DisplayCurrentCameraMode('BuzzSaw Angle');
        } else {
        RecordAction('Cancelled%20Angle%20Control%20Modes');
        CameraTarget = false;
        document.body.style.cursor = 'auto';
        document.body.title = `Right-click the document to enter Camera Mode`;
        DisplayCurrentCameraMode('Static');
        }
    } 
}


            // Displays the current Camera Mode (upon right-clicking the document)
        function DisplayCurrentCameraMode (CameraModeLabel) {
        document.getElementById('CameraModeHolder').innerHTML = CameraModeLabel;
            if (CameraModeLabel == 'Static') {
            document.getElementById('CameraModeTable').className = 'TanButtonBloodyText';
            } else {
            document.getElementById('CameraModeTable').className = 'BloodyButtonTanText';
            }
        FadeIn(document.getElementById('CameraModeTable'),12.5,0.1);
            var CameraModeDisplayTimeout = setTimeout(function () {
            FadeOut(document.getElementById('CameraModeTable'),12.5,0.1);
            },750);
        }

If I remove display:none and opacity:0 from the table’s style, i see ‘ Mode activated…’ which is neatly centered in the cell. As soon as I right click the document though, the box fades in with non-centered text. I’ve tried adding a <center> before the <span> in the <td>, but it didn’t solve the problem…

What super-duper-remote-nerdy rule am I forgetting about here? 🙂

How to disable vertical carousel scroll when items are over?

On mobile devices the carousel prevents natural page scroll

Is there a way to resume natural page scroll when items are over?

Code:

"use client"
import { useEffect, useState } from "react"
import Image from "next/image"
import { Button } from "@/components/ui/button"
import { Card, CardContent } from "@/components/ui/card"
import {
    Carousel,
    CarouselContent,
    CarouselItem,
    CarouselNext,
    CarouselPrevious,
    type CarouselApi,
} from "@/components/ui/carousel"
import { cn } from "@/lib/utils"
import { AiOutlineWhatsApp } from "react-icons/ai"
import { FaChevronLeft } from "react-icons/fa"
import AnimatedLink from "@/components/local/animated-link"
// Mock data for services
const services = [
    {
        id: 1,
        title: "صيانة الكهرباء",
        description:
            "في سوق مليء بالحلول المؤقتة والأيدي غير المؤهلة، نحن نقدم لك الاحترافية التي تستحقها...",
        image: "/service-1.png",
        price: "100",
    },
    {
        id: 2,
        title: "صيانة الكهرباء",
        description:
            "في سوق مليء بالحلول المؤقتة والأيدي غير المؤهلة، نحن نقدم لك الاحترافية التي تستحقها...",
        image: "/service-2.png",
        price: "150",
    },
    {
        id: 3,
        title: "صيانة الكهرباء",
        description:
            "في سوق مليء بالحلول المؤقتة والأيدي غير المؤهلة، نحن نقدم لك الاحترافية التي تستحقها...",
        image: "/service-3.png",
        price: "200",
    },
    // Add more services...
]

export default function ServicesSlider() {
    const [api, setApi] = useState<CarouselApi>()
    const [current, setCurrent] = useState(0)
    const [count, setCount] = useState(0)

    useEffect(() => {
        if (!api) return
        setCount(api.scrollSnapList().length)
        setCurrent(api.selectedScrollSnap() + 1)

        api.on("select", () => {
            setCurrent(api.selectedScrollSnap() + 1)
        })
    }, [api])

    return (
        <section
            id="services"
            className="w-full pb-10 md:py-16 bg-gradient-to-r from-black via-wine-700 to-wine-800 text-white"
        >
            <div className="px-4 md:px-6 mb-10 pt-10 md:pt-0">
                <h2 className="text-3xl font-bold tracking-tighter text-center sm:text-4xl md:text-5xl m-0">
                    خدمات آي فيكس
                </h2>
            </div>

            <Carousel
                opts={{ align: "start" }}
                orientation="vertical"
                className="w-full max-w-5xl mx-auto h-[500px] mt-16 mb-20 md:my-24 text-center md:text-right"
                setApi={setApi}
                dir="ltr"
            >
                <CarouselContent className="-mt-1 h-[500px]">
                    {services.map((service) => (
                        <CarouselItem
                            key={service.id}
                            className="pt-1 md:basis-3/4"
                        >
                            <div className="p-1">
                                <Card>
                                    <CardContent className="flex flex-col md:flex-row p-6 gap-2">
                                        <div className="flex flex-col justify-between md:w-1/2 md:pr-6">
                                            <div>
                                                <h3 className="text-3xl font-semibold mb-2">
                                                    {service.title}
                                                </h3>
                                                <p className="text-muted-foreground mb-4 text-xl">
                                                    {service.description}
                                                </p>

                                                <p
                                                    className="text-2xl font-bold text-wine-800 mb-2"
                                                    dir="rtl"
                                                >
                                                    ابتداءً من&nbsp;
                                                    {service.price} ر.س&nbsp;
                                                </p>
                                            </div>
                                            <Button className="w-1/2 mx-auto md:mr-0 text-lg bg-green-600">
                                                <AiOutlineWhatsApp />
                                                &nbsp; احجز الخدمة
                                            </Button>
                                        </div>
                                        <div className="md:w-1/2 mt-4 md:mt-0">
                                            <Image
                                                src={service.image}
                                                alt={service.title}
                                                width={400}
                                                height={300}
                                                className="rounded-lg object-cover w-full h-[200px] md:h-[300px]"
                                            />
                                        </div>
                                    </CardContent>
                                </Card>
                            </div>
                        </CarouselItem>
                    ))}
                </CarouselContent>
                {current > 1 && (
                    <CarouselPrevious
                        className={cn(
                            current === 1
                                ? "opacity-0 pointer-events-none"
                                : "opacity-100"
                        )}
                    />
                )}
                <CarouselNext
                    className={cn(
                        "transition-opacity duration-900 ease-in-out",
                        current === count ? "opacity-50" : "opacity-100",
                        count > 1 && "animate-pulse"
                    )}
                />
            </Carousel>

            <div className="flex justify-center mt-12">
                <AnimatedLink
                    color={"muted"}
                    textColor={"white"}
                    text={"كافة الخدمات"}
                    icon={<FaChevronLeft />}
                    href={"/services"}
                />
            </div>
        </section>
    )
}

jsPdf Export not Exporting class declared CSS

how do I apply a check on a class check?

I have the following html5 logic. My style applies the format to my razor page view.
I want to apply the css setting, can I add any ID fields into my somehow?

    

    <style>
    .billable {
        background-color: #e2efda; 
    }

    .nonbillable_row{
        background-color: #ddebf7;
    }

    .week_row{
        background-color: #fce4d6;
    }
   .title_row{
        background-color: #222222;
        color: #e7e7e9;
    }

</style> 

This class is then assigned to a table row.



    <div id="timesheetset1">
   
    <table  class="display nowrap table table-bordered" style="width:95%">
            <thead>
                <tr class="title_row">
                        <th>@Html.DisplayNameFor(model => Model.TimesheetSingle.code)</th>
                        <th>@Html.DisplayNameFor(model => Model.TimesheetSingle.billable)</th>
                    <th>Project</th>
                        <th>@Html.DisplayNameFor(model => Model.TimesheetSingle.taskName)</th>
                        <th>@Html.DisplayNameFor(model => Model.TimesheetSingle.comments)</th>
                    <th>@Html.DisplayNameFor(model => Model.TimesheetSingle.afterHours)</th>
                    <th>@Html.DisplayNameFor(model => Model.TimesheetSingle.work)</th>
                    <th>@Html.DisplayNameFor(model => Model.TimesheetSingle.assigneeDisplayName)</th>
                    <th>@Html.DisplayNameFor(model => Model.TimesheetSingle.start)</th>
                    <th>@Html.DisplayNameFor(model => Model.TimesheetSingle.billingTYPE)</th>
                    <th>@Html.DisplayNameFor(model => Model.TimesheetSingle.status)</th>
                    <th>@Html.DisplayNameFor(model => Model.TimesheetSingle.summaryRootCause)</th>
                    <th>@Html.DisplayNameFor(model => Model.TimesheetSingle.declinedReason)</th>
                </tr>
                <tr>
                    @if(Model.TitleTimesheet1 == null)
                    {
                    <th></th>
                    }
                    else 
                    {
                    <th colspan="13" class="week_row">@Model.TitleTimesheet1</th>
                    }
                </tr>
            </thead>
            <tbody style="font-size:x-small">
                @if (Model.BTimesheet1.Count > 0)
                {
                    <tr class="billable" data-row-type="billable">
                        <th>Billable</th>
                        <th>Billable</th>
                        <th>Billable</th>
                        <th>Billable</th>
                        <th>Total Billable timesheets: (@Model.BTimesheet1.Count)</th>                        
                        <th></th>
                        <th>
                            @{
                                double SumHours = Model.BTimesheet1.Sum(item => item.work);
                                <text>@SumHours.ToString("F2")</text>
                            }
                        </th>
                        <th></th>
                        <th></th>
                        <th>Billable</th>
                        <th>Billable</th>
                        <th>Billable</th>
                        <th>Billable</th>
                    </tr>
                    @foreach (var item in Model.BTimesheet1)
                    {
                        <tr>
                            <td>@Html.DisplayFor(modelItem => item.id)</td>
                            <td>@(item.billable ? "Billable" : "Non-Billable")</td>
                            <td>@Html.DisplayFor(modelItem => item.projectExternalName)</td>
                            <td>@Html.DisplayFor(modelItem => item.taskName)</td>
                            <td>@Html.DisplayFor(modelItem => item.comments)</td>
                            <td>@Html.DisplayFor(modelItem => item.afterHours)</td>
                            <td>@Html.DisplayFor(modelItem => item.work)</td>
                            <td>@Html.DisplayFor(modelItem => item.assigneeDisplayName)</td>
                            <td>@DateTime.Parse(item.start).ToString("yyyy-MM-dd")</td>
                            <td>@Html.DisplayFor(modelItem => item.billingTYPE)</td>
                            <td>@Html.DisplayFor(modelItem => item.status)</td>
                            <td>@Html.DisplayFor(modelItem => item.summaryRootCause)</td>
                            <td>@Html.DisplayFor(modelItem => item.declinedReason)</td>
                        </tr>
                    }
                }
                @if (Model.NBTimesheet1.Count > 0)
                {
                    <tr class="nonbillable" data-row-type="nonbillable">
                    <th>Non-Billable</th>
                    <th>Non-Billable</th>
                    <th>Non-Billable</th>
                    <th>Non-Billable</th>
                    <th>Total Billable timesheets: (@Model.NBTimesheet1.Count)</th>                    
                        <th></th>
                        <th>
                            @{
                                double SumHours = Model.NBTimesheet1.Sum(item => item.work);
                                <text>@SumHours.ToString("F2")</text>
                            }
                        </th>
                        <th></th>
                        <th></th>
                        <th>Non-Billable</th>
                        <th>Non-Billable</th>
                        <th>Non-Billable</th>
                        <th>Non-Billable</th>
                    </tr>
                    @foreach (var item in Model.NBTimesheet1)
                    {
                        <tr>
                            <td>@Html.DisplayFor(modelItem => item.id)</td>
                            <td>@(item.billable ? "Billable" : "Non-Billable")</td>
                            <td>@Html.DisplayFor(modelItem => item.projectExternalName)</td>
                            <td>@Html.DisplayFor(modelItem => item.taskName)</td>
                            <td>@Html.DisplayFor(modelItem => item.comments)</td>
                            <td>@Html.DisplayFor(modelItem => item.afterHours)</td>
                            <td>@Html.DisplayFor(modelItem => item.work)</td>
                            <td>@Html.DisplayFor(modelItem => item.assigneeDisplayName)</td>
                            <td>@DateTime.Parse(item.start).ToString("yyyy-MM-dd")</td>
                            <td>@Html.DisplayFor(modelItem => item.billingTYPE)</td>
                            <td>@Html.DisplayFor(modelItem => item.status)</td>
                            <td>@Html.DisplayFor(modelItem => item.summaryRootCause)</td>
                            <td>@Html.DisplayFor(modelItem => item.declinedReason)</td>
                        </tr>
                    }
                }
            </tbody>
        </table>
    
</div>

I then have a duplication of the above razor logic for timesheet set 1 through to 6.

I then need to merge this table set into 1 and run the following script set.



<script>
    // Function to get current timestamp in 'dd_MM_yyyy_hh:mm:ss' format
    function getFormattedTimestamp() {
        const now = new Date();
        const pad = (num) => (num < 10 ? '0' + num : num);

        const day = pad(now.getDate());
        const month = pad(now.getMonth() + 1); // Month is zero-based
        const year = now.getFullYear();
        const hours = pad(now.getHours());
        const minutes = pad(now.getMinutes());
        const seconds = pad(now.getSeconds());

        return `${day}_${month}_${year}_${hours}:${minutes}:${seconds}`;
    }

    // Function to concatenate the tables' contents
    function concatenateTables() {
        const tableSets = [
            "#timesheetset1 table",
            "#timesheetset2 table",
            "#timesheetset3 table",
            "#timesheetset4 table",
            "#timesheetset5 table",
            "#timesheetset6 table"
        ];
        const concatenatedTable = document.createElement("table");

        tableSets.forEach(selector => {
            const table = document.querySelector(selector).cloneNode(true);
            Array.from(table.rows).forEach(row => {
                const rowType = row.getAttribute('data-row-type');
                if (rowType === 'billable') {
                    row.style.backgroundColor = '#E2EFDA'; // Light green for billable
                } else if (rowType === 'nonbillable') {
                    row.style.backgroundColor = '#DDEBF7'; // Light blue for non-billable
                }
                concatenatedTable.appendChild(row);
            });
        });

        return concatenatedTable;
    }

    function exportToPDF() {
    const { jsPDF } = window.jspdf;
    const doc = new jsPDF({ orientation: "landscape" });

    const concatenatedTable = concatenateTables();
    const tableData = Array.from(concatenatedTable.rows).slice(1).map((row, rowIndex) => {
        return {
            cells: Array.from(row.cells).map(cell => {
                if (cell.colSpan === 13) {
                    return { content: cell.textContent.trim(), colSpan: 13 };
                }
                return cell.textContent.trim();
            }),
            type: row.getAttribute('data-row-type') // Add the row type for color processing
        };
    });

    const header = [
        ['CODE', 'Billing Type', 'Project', 'NAME', 'NOTE', 'SUPPORT HOURS', 'ACTUAL WORK', 'Assignee', 'START', 'BILLING TYPE', 'APPROVALS', 'SUMMARY ROOT CAUSE', 'DECLINED REASON']
    ];

    doc.autoTable({
        head: header,
        body: tableData.map(row => row.cells.map(cell => {
            if (typeof cell === 'object' && cell.colSpan === 13) {
                return {
                    content: cell.content,
                    colSpan: 13,
                    styles: { halign: 'left', fillColor: [252, 228, 218], textColor: [0, 0, 0], fontStyle: 'bold', fontSize: 6 }
                };
            }
            return cell;
        })),
        startY: 10,
        theme: 'grid',
        styles: {
            fontSize: 5,
            halign: 'left',
            lineWidth: 0.1,
            lineColor: [0, 0, 0]
        },
        headStyles: {
            fillColor: [0, 0, 0],
            textColor: [255, 255, 255],
            lineColor: [0, 0, 0]
        },
        margin: { top: 20, left: 10, right: 10, bottom:20 },
        didParseCell: function (data) {
            if (data.section === 'head') {
                data.cell.styles.fontSize = 6;
            }
        },
        didDrawCell: function (data) {
            const rowType = tableData[data.row.index]?.type; // Retrieve the row type metadata

            if (rowType === 'nonbillable') {
                data.cell.styles.fillColor = [221, 235, 247]; // Light blue for non-billable
            } else if (rowType === 'billable') {
                data.cell.styles.fillColor = [226, 239, 218]; // Light green for billable
            }
        },
        pageBreak: 'avoid',  // Avoid breaking rows across pages
        pageBreak: 'auto',   
    });

    let now = new Date();
    let hours = now.getHours().toString().padStart(2, '0');
    let minutes = now.getMinutes().toString().padStart(2, '0');
    let seconds = now.getSeconds().toString().padStart(2, '0');
    let formattedTime = `${hours}h${minutes}m${seconds}`;
    let filename = `@Model.FileName${formattedTime}.pdf`;

    doc.save(filename);
}


    // Export to Excel function with dynamic file name
    function exportToExcel() {
        const concatenatedTable = concatenateTables();
        const workbook = XLSX.utils.table_to_book(concatenatedTable, { sheet: "Sheet1" });
        // Get the current time
        let now = new Date();
        let hours = now.getHours().toString().padStart(2, '0');
        let minutes = now.getMinutes().toString().padStart(2, '0');
        let seconds = now.getSeconds().toString().padStart(2, '0');
        let formattedTime = `${hours}h${minutes}m${seconds}`;
        let filename = `@Model.FileName run_${formattedTime}.xlsx`;
        filename = filename.replace(/&#x2B;/g, '+');
        XLSX.writeFile(workbook, filename);
    }
</script>

Example Image of end result - redacted

However on the jspdf my colors are not holding for the billable lines to be green and the nonbillable headers to be blue.

Not sure where I am missing something that is causing the colors not to pull through?

For reference the billable rows are only the headers of the data and not every line.

MediaRecorder not firing event

I’ve been trying to get the data from the media stream of a microphone when a user speaks into it.
My goal is to continually send that data over to a web server as until the user closes the mic by a button.
I’ve tried a lot like this from mdn unfortunately its in javascript and I try to rewrite it in typescript which I think is where my problem arises. At the moment this is what I have

  mediaRecorder?: MediaRecorder
  chunks: any = []
  dest?: MediaStreamAudioDestinationNode
  constraints = { audio:true, video: false }

  async record_audio() {
    if (navigator.mediaDevices){
      var $this = this;
      navigator.mediaDevices.getUserMedia(this.constraints).then((stream)=>{
        this.mediaRecorder = new MediaRecorder(stream)
        this.mediaRecorder.start();
        //this.mediaRecorder.ondataavailable = this.pushChunks;

        this.mediaRecorder.ondataavailable = function (e) {
          console.log("pushing chunk")
          $this.chunks.push(e.data);
        };
        console.log('starting recorder...')
      })
     
    } else { alert('getUserMedia not supported.'); }
  }

The method is called but the mediaRecorder.ondataavailable is never called. I don’t know if the method gets destroyed after it exits or something.

How do I continually get the data in this stream so I can upload it to a web server?

Dropdowns stop working using Livewire and wire:navigate

I’m using Livewire components integrated with the botstrap 5.3 navbar.
Everything works fine but, when I add wire:navigate to the links in the navbar, all interactive elements stop working. There are no errors in the console. navbar toggle, dropdowns, everything stops working.

here’s the navlink example

<li><a class="dropdown-item" href="{{ route('home') }}" wire:navigate>Home</a></li>

Anyone to help me please

How to create a react app with typescript template on windows machine

I want to create a react application with typescript template.

npm version: 10.2.4

node version: 20.1.1

I tried the following commands but got errors:

First command npx create-react-app my-app --template typescript

Got error:

npm ERR! code ENOENT
npm ERR! syscall lstat
npm ERR! path D:usr
npm ERR! errno -4058
npm ERR! enoent ENOENT: no such file or directory, lstat 'D:usr'
npm ERR! enoent This is related to npm not being able to find a file.
npm ERR! enoent

Second command npm create-react-app my-app --template typescript

Got error:

Unknown command: "create-react-app"

To see a list of supported npm commands, run:
  npm help```

How to add onClick event to PopupMenuBarItem in Dojo?

I can’t figure out how to add an onclick event to a menu item, please help me solve this problem.

<script>
    require([
        "dijit/MenuBar",
        "dijit/PopupMenuBarItem",
        "dijit/Menu",
        "dijit/MenuItem",
        "dijit/DropDownMenu",
        "dojo/domReady!"
    ], function(MenuBar, PopupMenuBarItem, Menu, MenuItem, DropDownMenu){
        var pMenuBar = new MenuBar({});

        var pSubMenu = new DropDownMenu({});
        pMenuBar.addChild(new PopupMenuBarItem({
            label: "ItemMenu1",
            popup: pSubMenu
        }));

        var pSubMenu2 = new DropDownMenu({});
        pMenuBar.addChild(new PopupMenuBarItem({
            label: "ItemMenu2",
            popup: pSubMenu2,
        }));

        pMenuBar.placeAt("navigation");
        pMenuBar.startup();
    });
</script>

I added onClick to the code using this method, but it doesn’t work.

var pSubMenu = new DropDownMenu({});
pMenuBar.addChild(new PopupMenuBarItem({
    label: "ItemMenu1",
    popup: pSubMenu,
    onClick: function () {alert('ItemMenu1');}
}));

require is not defined in js file that compiled from typescript file

Hello,

I am currently working on a Firebase project, and it was working fine until I converted the JavaScript code to TypeScript. Since then, I’ve encountered many problems. I resolved most of the issues in the code, but there are still a couple of challenging ones that I can’t solve.

in this two lines of code:

// Import the functions you need from the SDKs you need
import { initializeApp } from "https://www.gstatic.com/firebasejs/10.13.0/firebase-app.js";
import {  getDatabase, ref, set,  onChildAdded , onValue } from "https://www.gstatic.com/firebasejs/10.13.0/firebase-database.js";

The first error was “exports is not defined at main.js:38:23”, which I fixed with this code: <script>var exports = {};</script> in HTML file.

The second error is “main.js:40: require is not defined”, and I don’t know how to fix it.

If anyone can help, it would be greatly appreciated.

I tried to install firebase locally to my project and try to download webpack.config.js but the problem remains unsolved.