Smugmug API Setting Thunbnails for albums/Removing Blurry Thunbnails

Hello I am currently coding to photo gallery website and Im using the Smumug API to get all my pulbic albums+photos in the album to show up on the gallery and the issue is that for the gallery to show the albums Im getting the placeholder.jpg as the thunbnails and the second issue is when going into the albums the photo thunbnails are extremely blurry and ive been trying everything to get rid of the blurry from the thunbnails but when I click on the img to do the viewmodel box the img perfectly fine looking.

(I am fairly new to coding Javascript and using API’s most of the javascript involving the API is helped from using AI’s and if someone could help me fix this and also give me some references online to where to find more exmaples of JS being used for API calling and how if im having issues where I can go to find the solution instead of using AI)
JavaScript Code:

`async loadAlbums() {
    try {
        this.isLoading = true;
        this.updateLoadingState();

        const response = await 
  axios.get('https://api.smugmug.com/api/v2/user/jdstudiophotography!albums', {
            params: {
                APIKey: this.API_KEY,
                count: 100,
                _expand: 'HighlightImage,HighlightImage.ImageSizes'
            },
            headers: {
                'Accept': 'application/json',
                'X-Smug-Version': 'v2'
            }
        });

        if (!response.data.Response || !response.data.Response.Album) {
            throw new Error('Invalid albums response');
        }

        this.albums = response.data.Response.Album.map(album => {
            let coverImage = './images/albums/placeholder.jpg';
            // In loadAlbums method, update the coverImage selection in the map 
  function:
            coverImage = '';
            if (album.HighlightImage && album.HighlightImage.ImageSizes) {
                const imageSizes = album.HighlightImage.ImageSizes;
                coverImage = imageSizes.LargeImageUrl ||
                            imageSizes.MediumImageUrl ||
                            imageSizes.SmallImageUrl ||
                            album.HighlightImage.ThumbnailUrl;
            }

            return {
                id: album.AlbumKey,
                title: album.Title || 'Untitled Album',
                imageCount: album.ImageCount || 0,
                coverImage
            };
        });

        this.isLoading = false;
        this.renderAlbums();
    } catch (error) {
        console.error('Error loading albums:', error);
        this.isLoading = false;
        this.updateLoadingState('Error loading albums.');
    }
 }`




`async loadAlbumImages(albumId) {
    try {
        this.isLoading = true;
        this.updateLoadingState();
        const response = await    
      axios.get(`https://api.smugmug.com/api/v2/album/${albumId}!images`, {
            params: {
                APIKey: this.API_KEY,
                count: 100,
                _expand: 'ImageSizes'
            },
            headers: {
                'Accept': 'application/json',
                'X-Smug-Version': 'v2',
                'X-Smug-ResponseType': 'JSON'
            }
        });

        if (!response.data.Response || !response.data.Response.AlbumImage) {
            throw new Error('Invalid album images response structure');
        }

        const images = response.data.Response.AlbumImage.map(image => {
            const imageSizes = image.ImageSizes || {};
            return {
                id: image.ImageKey,
                title: image.Title || image.FileName,

                thumbnail: imageSizes.MediumImageUrl || 
                          imageSizes.SmallImageUrl || 
                          image.ThumbnailUrl,
                // Keeps medium URL for grid view
                mediumUrl: imageSizes.MediumImageUrl || 
                          imageSizes.SmallImageUrl || 
                          image.ThumbnailUrl,
                // Keeps original for maximum quality when needed
                originalUrl: image.OriginalUrl || image.ArchivedUri
            };
        });

        this.currentImages = images;
        this.isLoading = false;
        this.renderImages();

    } catch (error) {
        console.error('Error loading album images:', error);
        this.isLoading = false;
        this.updateLoadingState('Error loading album images. Please try again 
       later.');
     }
  }`

`renderImages() {
const container = document.querySelector(‘.grid-albums’);
container.innerHTML = ”;

const placeholder = './images/albums/placeholder.jpg';

this.currentImages.forEach((image, index) => {
    const imageElement = document.createElement('div');
    imageElement.className = 'image-card';
    imageElement.innerHTML = `
        <div class="image-thumbnail">
            <img src="${image.thumbnail || placeholder}" alt="${image.title}"
                 loading="lazy"
                 onerror="this.onerror=null; this.src='${placeholder}';">
            <div class="image-info">
                <h3>${image.title}</h3>
            </div>
        </div>
    `;

    imageElement.addEventListener('click', () => {
        this.showLightbox(image, index);
    });

    container.appendChild(imageElement);
});

}`

`renderAlbums() {
const container = document.querySelector(‘.grid-albums’);
container.innerHTML = ”; // Clear the container

const placeholder = './images/albums/placeholder.jpg';

this.albums.forEach(album => {
    const albumElement = document.createElement('div');
    albumElement.className = 'album-card';
    albumElement.innerHTML = `
        <div class="album-thumbnail">
            <img src="${album.coverImage || placeholder}" alt="${album.title}"
                 loading="lazy"
                 onerror="this.onerror=null; this.src='${placeholder}';">
            <div class="album-info">
                <h3>${album.title}</h3>
                <p>${album.imageCount} photos</p>
            </div>
        </div>
    `;

    albumElement.addEventListener('click', () => {
        window.location.href = `gallery.html?albumId=${album.id}`;
    });

    container.appendChild(albumElement);
});

}`

Img Blurry
Gallery Album Thumbnail

I attemped to have the code where it gets all the sizes for the albums thunbnail and if Smugmug has any highligh imgs saved to also reterive that information and go from the biggest size to smallest and if all of those fail that it will as the final use the placeholder.jpg but im still getting that placeholder.jpg and the same was from the actual imgs in the album but the imgs thumbnail are still blurry

Selector excluding nested values

Basically, I want to create a selector, that would exclude nested elements – it should find only elements at the first level of nesting. I have this:

it('Test selector non-nested', () => {
  const mainAttribute = 'data-main';
  const itemAttribute = 'data-item';
  const sideAttribute = 'data-side';
  document.body.innerHTML = `
<div>
    <div ${mainAttribute}>
        <div ${itemAttribute}>
            <div ${sideAttribute}>
                <div ${mainAttribute}>
                    <div ${itemAttribute}>
                        <div ${sideAttribute}></div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
`;

  const result = [];
  const foundElements = document.querySelectorAll(`[${mainAttribute}]`);
  for (const element of foundElements) {
    result.push(element);
  }

  for (const element of result) {
    const selector = `:scope [${sideAttribute}]:not(:scope [${itemAttribute}] [${itemAttribute}] [${sideAttribute}])`;
    element.innerHTML = element.innerHTML; // It makes it work!
    const results = element.querySelectorAll(selector);
    expect(results.length).toEqual(1);
  }
});

As you can see, I want to find elements having “sideAttribute”, but only in the top element having the “itemAttribute”. It means that in this case I want to have 1 result for both iterations of the loop.

It doesn’t work UNLESS I will throw element.innerHTML = element.innerHTML; in there, then it magically starts working. What’s going on here?

lz4 encoding and binary decoding

why does this decoding of firefox recovery fail?

const profilesPath = path.join(os.homedir(), 'AppData', 'Roaming', 'Mozilla', 'Firefox', 'Profiles');
const defaultProfile = fs.readdirSync(profilesPath).find(profile => profile.includes('.Default'));
const recoveryFile = path.join(profilesPath, defaultProfile, 'sessionstore-backups', 'recovery.jsonlz4');

const rawData = fs.readFileSync(recoveryFile);
const uncompressedSize = rawData.readUInt32LE(8);
const lz4Data = rawData.subarray(12);
const decompressed = Buffer.alloc(uncompressedSize);
lz4.decodeBlock(lz4Data, decompressed);

const jdata = JSON.parse(decompressed.toString('utf8'));
const selectedTab = jdata.windows[0].tabs[jdata.windows[0].selected - 1];
const currentUrl = selectedTab.entries[selectedTab.entries.length - 1].url;

res.json({ activeTabUrl: currentUrl });

same with the binary decoding of google chrome data

const chromeSessionsPath = path.join(os.homedir(), 'AppData', 'Local', 'Google', 'Chrome', 'User Data', 'Default', 'Sessions');

if (!fs.existsSync(chromeSessionsPath)) {
  return res.status(404).json({
    error: 'Chrome Sessions directory not found'
  });
}

const sessionFiles = fs.readdirSync(chromeSessionsPath);
const tabsFiles = sessionFiles.filter(file => file.startsWith('Tabs_'))
  .map(file => ({
    name: file,
    path: path.join(chromeSessionsPath, file),
    mtime: fs.statSync(path.join(chromeSessionsPath, file)).mtime
  }))
  .sort((a, b) => b.mtime - a.mtime);

if (tabsFiles.length === 0) {
  return res.status(404).json({
    error: 'No Chrome tabs files found'
  });
}

const sessionData = fs.readFileSync(tabsFiles[0].path);

const dataString = sessionData.toString('utf8', 0, Math.min(sessionData.length, 10000));
const urlMatches = dataString.match(/https?://[^sx00-x1fx7f-x9f"<>{}|\^`[]]+/g);

if (urlMatches && urlMatches.length > 0) {
  const currentUrl = urlMatches[urlMatches.length - 1];
  res.json({
    activeTabUrl: currentUrl
  });
} else {
  res.status(404).json({
    error: 'No URLs found in Chrome session'
  });
}

i wanted to make a combined active URL and history viewer for all my browsers but recovering the data from these files is cumbersome.

how to place the co-ordinates of View to the absolute View in react native

I’m trying to create shared-element transition. Using ref i’m accessing the View location (height, width, pageX, pageY) from measure method and i have another View with absolute position where i’m passing this data so that transition start from that place

but instead after adding the pageX and pageY to respective left and top – the absolute view is not on the exact location

import { Image } from "expo-image";
import React, { useRef } from "react";
import { Button, StyleSheet, Text, View } from "react-native";
import Animated, {
    useAnimatedStyle,
    useSharedValue,
} from "react-native-reanimated";

const AnimatedExpoImage = Animated.createAnimatedComponent(Image);

const Example = () => {
    const imageViewRef = useRef<View>(null);
    const rootViewRef = useRef<View>(null);

    const position = useSharedValue({ x: 0, y: 0 });
    const size = useSharedValue({ width: 0, height: 0 });

    const activeImagePositionStyle = useAnimatedStyle(() => {
        return {
            top: position.value.y,
            left: position.value.x,
        };
    });

    const activeImageSizeStyle = useAnimatedStyle(() => {
        return {
            height: size.value.height,
            width: size.value.width,
        };
    });

    return (
        <View ref={rootViewRef} style={{ flex: 1, backgroundColor: "white" }}>
            <View>
                <View
                    style={{
                        justifyContent: "center",
                        alignItems: "center",
                        height: 50,
                    }}
                >
                    <Text>Paul Jarvis</Text>
                </View>
                <View
                    ref={imageViewRef}
                    style={{
                        height: 200,
                        width: "85%",
                        alignSelf: "center",
                    }}
                >
                    <Image
                        contentFit="cover"
                        style={{ height: "100%", width: "100%" }}
                        source={{
                            uri: "https://picsum.photos/id/16/2500/1667",
                        }}
                    />
                </View>
                <Button
                    title="Get Details"
                    onPress={() => {
                        imageViewRef.current?.measure(
                            (x, y, width, height, pageX, pageY) => {
                                position.value = { x: pageX, y: pageY };
                                size.value = { width, height };
                            }
                        );
                    }}
                />
            </View>

            <View style={[StyleSheet.absoluteFill]}>
                <View style={{ flex: 1 }}>
                    <AnimatedExpoImage
                        contentFit="cover"
                        style={[
                            styles.image,
                            activeImagePositionStyle,
                            activeImageSizeStyle,
                        ]}
                        source={{
                            uri: "https://picsum.photos/id/17/2500/1667",
                        }}
                    />
                </View>
            </View>
        </View>
    );
};

export default Example;

const styles = StyleSheet.create({
    image: {
        width: null,
        height: null,
        position: "absolute",
        top: 0,
        left: 0,
    },
});

GIF error example

Group an array of objects with a tolerance factor

I have an array of objects with a name and a value that looks like this (sorted by values):

var array = [ 
    { Name: "F", Value: 320 },
    { Name: "E", Value: 321 },
    { Name: "C", Value: 340 },
    { Name: "G", Value: 340 },
    { Name: "A", Value: 400 },
    { Name: "D", Value: 403 },
    { Name: "B", Value: 404 }
]

I want to combine objects with the same value plus a tolerance. Grouping can be done like this:

var groupedArray = Object.groupBy(array, e => e.Value ); // Is it possible to add a tolerance factor here?

This creates groups that have exactly the same values. But what I actually want is a grouping with a certain tolerance. So, if values ​​are just slightly larger than the previous value, they should still be included in the group. The result could then look like this:

{
  320: [{
    Name: "F",
    Value: 320
  }, {
    Name: "E",
    Value: 321
  }],
  340: [{
    Name: "C",
    Value: 340
  }, {
    Name: "G",
    Value: 340
  }],
  400: [{
    Name: "A",
    Value: 400
  }, {
    Name: "D",
    Value: 403
  }, {
    Name: "B",
    Value: 404
  }]
}

… so all values ​​with a tolerance of, for example, +5 are in one group. Is it possible to add such a tolerance factor?

React Virtualized MultiGrid: Box shadow on first fixed column appears on left instead of right

I’m using React Virtualized MultiGrid and trying to add a box shadow to the first fixed column. I am able to apply the box shadow, but it always appears on the left side, whereas I need it on the right side (opposite).

I’ve tried multiple approaches in CSS, but nothing seems to work. I’ve attached a CodeSandbox link with the full code, including the CSS in style.css.

Can someone please help me fix this so the shadow appears on the right side of the first column?

image

WebView2 in wpf application makes crash the app

I am using the Microsoft.Web.WebView2component in my WPF c# application.
Nuget version is 1.0.3405.78.
It is a great solution to manipulate html content in a WPF application.
Except an error that I can not handle. I must miss something.

I am generating some dynamic Htmls and openning them in the WebView2. If the page contains a Fileupload, when I upload some files and show it in the page, randomly, the whole application crashes without any error message.

Here is my C# code and Html sample :

C# part :

  await wv2.EnsureCoreWebView2Async();

  //Loads javascript content.
  wv2.CoreWebView2.DOMContentLoaded += async (sender, e) =>
  {
     if (javascriptGenerated == false)
     {
       // Inject the JavaScript code
       await    wv2.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(GenerateJSPart());
       javascriptGenerated = true;
     }
  };
  

    var htmlPath = GenerateHtml();
    wv2.Source = new Uri(htmlPath, UriKind.Absolute);


    wv2.CoreWebView2.PermissionRequested += (sender, e) =>
    {
       if (e.PermissionKind == CoreWebView2PermissionKind.FileReadWrite || e.PermissionKind == CoreWebView2PermissionKind.UnknownPermission)
         {
           e.State = CoreWebView2PermissionState.Allow;
          }
    };




    private string GenerateJSPart()
    {
     //Script to add file uploads.
     string js = "document.addEventListener('DOMContentLoaded', function() {   " +

       "const fileInputs = document.querySelectorAll('input[type="file"]');      " +
       " fileInputs.forEach(input => {       " +
       " input.addEventListener('change', function(e) {           " +
       " handleFileUpload(e.target);       " +
       " });   " +
       " });" +
       "});" +
       "" +
       "function handleFileUpload(fileInput) {  " +
       "  const file = fileInput.files[0];       " +
       " if (!file) {       " +
       " return;  " +
       "  }        " +
       "" +

       "if (!file.type.startsWith('image/')) {       " +
       " alert('Please select an image file.');       " +
       " fileInput.value = ''; " +

       "    return;   " +
       " }        " +
       "" +

       "const parentDiv = fileInput.closest('div');      " +
       "  if (!parentDiv) {        " +
       "console.error('Parent div not found');        return;    " +
       "}        " +
       "" +
       "const reader = new FileReader();        " +
       "reader.onload = function(e) {       " +
       " const existingImg = parentDiv.querySelector('img');        " +
       "if (existingImg) {            existingImg.remove();        " +
       "}" +
       "const img = document.createElement('img');      " +
       "img.src = e.target.result;        " +
       "img.style.maxWidth = '100%';        " +
       "img.style.height = 'auto';       " +
       " img.style.display = 'block';     " +
       "img.style.margin = '10px 0';       " +
       " img.style.border = '1px solid #ddd';        " +
       "img.style.borderRadius = '4px';              " +

       "  fileInput.parentNode.insertBefore(img, fileInput.nextSibling);              " +
       " fileInput.style.display = 'none';       " +
       " const label = parentDiv.querySelector('label');       " +
       " if (label) {            " +
       "label.style.display = 'none';        " +
       "}              " +
       "  addRemoveButton(parentDiv, fileInput, label, img); " +
       "   };       " +
       " reader.onerror = function() {       " +
       " alert('Error reading file. Please try again.');      " +
       "  fileInput.value = '';    " +
       "};        " +
       "reader.readAsDataURL(file);" +
       "}" +
       "function addRemoveButton(parentDiv, fileInput, label, img) {    " +
       "const removeBtn = document.createElement('button');   " +
       " removeBtn.textContent = "" + "Remove Image" + "";    " +
       "removeBtn.type = 'button';    " +
       "removeBtn.style.cssText = 'background-color: #dc3545;       " +
       " color: white;       " +
       " border: none;       " +
       " padding: 5px 10px;        " +
       "border-radius: 4px;        " +
       "cursor: pointer;        " +
       "margin-top: 5px;       " +
       " font-size: 12px;';       " +
       " removeBtn.onclick = function() {        " +
       "img.remove();       " +
       " removeBtn.remove();                " +
       "fileInput.style.display = 'none'; " +
       "if (label) {           " +
       " label.style.display = 'inline-block';       " +
       " }               " +
       "  fileInput.value = '';   " +
       " };       " +
       " img.parentNode.insertBefore(removeBtn, img.nextSibling);" +
       "}";

   return js ;
 }

Html part :

document.addEventListener('DOMContentLoaded', function() {   const fileInputs = document.querySelectorAll('input[type="file"]');       fileInputs.forEach(input => {        input.addEventListener('change', function(e) {            handleFileUpload(e.target);        });    });});function handleFileUpload(fileInput) {    const file = fileInput.files[0];        if (!file) {        return;    }        if (!file.type.startsWith('image/')) {        alert('Please select an image file.');        fileInput.value = '';     return;    }        const parentDiv = fileInput.closest('div');        if (!parentDiv) {        console.error('Parent div not found');        return;    }        const reader = new FileReader();        reader.onload = function(e) {        const existingImg = parentDiv.querySelector('img');        if (existingImg) {            existingImg.remove();        }const img = document.createElement('img');      img.src = e.target.result;        img.style.maxWidth = '100%';        img.style.height = 'auto';        img.style.display = 'block';     img.style.margin = '10px 0';        img.style.border = '1px solid #ddd';        img.style.borderRadius = '4px';                fileInput.parentNode.insertBefore(img, fileInput.nextSibling);               fileInput.style.display = 'none';        const label = parentDiv.querySelector('label');        if (label) {            label.style.display = 'none';        }                addRemoveButton(parentDiv, fileInput, label, img);    };        reader.onerror = function() {        alert('Error reading file. Please try again.');        fileInput.value = '';    };        reader.readAsDataURL(file);}function addRemoveButton(parentDiv, fileInput, label, img) {    const removeBtn = document.createElement('button');    removeBtn.textContent = "Remove image";    removeBtn.type = 'button';    removeBtn.style.cssText = 'background-color: #dc3545;        color: white;        border: none;        padding: 5px 10px;        border-radius: 4px;        cursor: pointer;        margin-top: 5px;        font-size: 12px;';        removeBtn.onclick = function() {        img.remove();        removeBtn.remove();                fileInput.style.display = 'none'; if (label) {            label.style.display = 'inline-block';        }                 fileInput.value = '';    };        img.parentNode.insertBefore(removeBtn, img.nextSibling);}
<html xmlns="http://www.w3.org/1999/xhtml"><head><style> .tcenter {text-align: center;margin-bottom: 10px;}span {cursor: pointer;}.custom-file-upload {border:1px solid dodgerblue;border-radius: 8px;padding:10px;padding-top:3px;padding-bottom:3px;cursor:pointer;font-size:12px;}.editing-textarea {font-family: inherit;font-size: inherit;font-weight: inherit; font-style: inherit;color: inherit;background-color: rgb(250, 250, 250);border: 1px solid dodgerblue;padding: 2px;margin: 0;resize: vertical;min-height: 20px;width: auto;min-width: 100px;display: inline-block;vertical-align: middle;}span.editable-span {cursor: pointer;transition: background-color 0.3s;}span.editable-span:hover {background -color: #f0f0f0;border -radius: 3px;}span:hover {background -color: #f0f0f0;border -radius: 3px;}.footer-div {margin-top:100px;}@media print {button {display: none !important;}.image-container {position: relative;display: inline-block; }.remove-btn:hover {background-color: #c82333 !important;}.uploaded-image {max-width: 100%; height: auto; display: block; margin: 10px 0; border: 1px solid #ddd;border -radius: 4px; box -shadow: 0 2px 4px rgba(0,0,0,0.1); }.custom-file-upload {display: none;}.footer-div {bottom:0;page-break-after: always; } .pagebreak{page-break-before: always;border:0 !important;}.content-block, p { page-break-inside: avoid; } body {}}textarea {resize:none;overflow:hidden;height:auto;min-height:50px;field-sizing:content;}textarea:focus {outline: none !important; border:1px dashed dodgerblue;box-shadow: 0 0 10px #719ECE;}.pagebreak{height:30px;margin-bottom:45px;}.pathologie-images{margin-bottom:-4px;}@media print {textarea {background-color: transparent !important;resize:none;}}</style><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>CADELIO</title><style type="text/css">
p { margin-top: 0px;margin-bottom: 12px;line-height: 1.15; } 
body { font-family: 'Verdana';font-style: Normal;font-weight: normal;font-size: 16px; } 
.Normal { telerik-style-type: paragraph;telerik-style-name: Normal;border-collapse: collapse; } 
.TableNormal { telerik-style-type: table;telerik-style-name: TableNormal;border-collapse: collapse; } </style></head><body><p class="Normal "><span class="editable-span">&nbsp;</span></p><p class="Normal "> </p><div class="tcenter" id="upload-div-1"><label for="fileUpload1" class="custom-file-upload">Select an image</label><input type="file" accept="image/*" class="fu-label" style="display:none;" name="fileUpload1" id="fileUpload1"></div><p></p></body></html>

Any idea?

CEF (Chromium Embedded Framework) in Application loses keyboard focus after mouse clicks on Ubuntu 22.04

I’m experiencing a critical keyboard focus issue with CEF (Chromium Embedded Framework) running on Ubuntu 22.04. After any mouse click within the CEF window, all keyboard events stop being captured, making keyboard shortcuts like Ctrl++ completely non-functional.

System Information:

  • OS: Ubuntu 22.04 LTS
  • CEF Version: Chrome/104.0.5112.102 (based on user agent)
  • Hardware: 12-core CPU, 8GB RAM, Linux x86_64
  • Browser Engine: WebKit/537.36 (KHTML, like Gecko)

Initial State (Working):

  • The page loads correctly with keyboard focus.
  • Keyboard shortcuts (Ctrl++, Space, etc.) work as expected.
  • All key events are captured and processed.

After Mouse Click (Broken):

  • Any mouse click within the CEF window causes a complete loss of keyboard focus.
  • No keyboard events (keydown/keyup) are received.
  • Keyboard shortcuts stop working entirely.
  • The focus indicator shows the page as “not focused.”

Focus Recovery Observations:

  • ✅ WORKS: Minimizing or maximizing the window restores keyboard focus.
  • ✅ WORKS: Switching windows with Alt+Tab restores keyboard focus.
  • ❌ FAILS: Using JavaScript methods like document.body.focus(), document.documentElement.focus(), or window.focus().
  • ❌ FAILS: Setting tabIndex=-1 on body/html elements.
  • ❌ FAILS: All standard DOM focus management techniques.

Technical Details from Event Logs:

System Info: {
  "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.102 Safari/537.36",
  "platform": "Linux x86_64",
  "language": "en",
  "cookieEnabled": true,
  "onLine": true,
  "hardwareConcurrency": 12,
  "deviceMemory": 8
}

Typical event sequence:
[1] Page loaded - keyboard events working
[2] Click on DIV - focus lost immediately
[3] Ctrl++ pressed - no keyboard event received
[4] document.hasFocus() returns false
[5] Alt+Tab away and back - focus restored
[6] Ctrl++ pressed - keyboard event received and working

Questions:

  • Has anyone encountered similar CEF keyboard focus issues on Ubuntu?
  • Are there Ubuntu-specific window manager settings that could help?
  • Could this be related to X11 vs Wayland display server differences?

What I’m Looking For:

  • Ubuntu/Linux-specific workarounds for CEF focus management.
  • Any insights into the root cause of this focus loss behavior.
  • Alternative approaches to maintain keyboard event capture in CEF on Linux using JS.

Any help or suggestions would be greatly appreciated!

How can I place the carousel arrows and navigation dots inside each slide on the right?

I’m building a carousel using USWDS and custom JavaScript. I want each slide to have arrows and navigation dots on the right sides. The dots and arrows show on the first slide only, but the dots do not show on rest of the slides. How can I make this work such that dots and arrows show on all the slides?

Here is my code

document.addEventListener("DOMContentLoaded", function() {
  const root = document.getElementById('ABCCarousel');
  if (!root) return;

  const LOOP = false;

  const track = root.querySelector('.ABC-carousel__viewport');
  const slides = Array.from(root.querySelectorAll('.ABC-slide'));

  // Get *all* controls
  const prevButtons = root.querySelectorAll('.carousel-button.prev');
  const nextButtons = root.querySelectorAll('.carousel-button.next');
  const nav = root.querySelector('.carousel-nav');

  // Ensure no slide has "hidden" attribute
  slides.forEach(s => s.removeAttribute('hidden'));

  // Build dots
  nav.innerHTML = '';
  const indicators = slides.map((_, i) => {
    const dot = document.createElement('span');
    dot.className = 'carousel-indicator';
    dot.addEventListener('click', () => goTo(i));
    nav.appendChild(dot);
    return dot;
  });

  let index = 0;

  function clamp(i) {
    const n = slides.length;
    return (i % n + n) % n;
  }

  function goTo(i) {
    index = LOOP ? clamp(i) : Math.max(0, Math.min(slides.length - 1, i));
    const offsetPct = -index * 100;
    track.style.transform = `translateX(${offsetPct}%)`;

    // Update dots
    indicators.forEach((dot, j) => dot.classList.toggle('active', j === index));

    // Enable/disable arrows
    if (!LOOP) {
      prevButtons.forEach(btn => btn.disabled = index === 0);
      nextButtons.forEach(btn => btn.disabled = index === slides.length - 1);
    } else {
      prevButtons.forEach(btn => btn.disabled = false);
      nextButtons.forEach(btn => btn.disabled = false);
    }

    // a11y
    slides.forEach((s, j) => s.setAttribute('aria-hidden', j === index ? 'false' : 'true'));
  }

  // Attach listeners to *all* controls
  prevButtons.forEach(btn => btn.addEventListener('click', () => goTo(index - 1)));
  nextButtons.forEach(btn => btn.addEventListener('click', () => goTo(index + 1)));

  // Keyboard nav
  root.addEventListener('keydown', (e) => {
    if (e.key === 'ArrowLeft') {
      e.preventDefault();
      goTo(index - 1);
    }
    if (e.key === 'ArrowRight') {
      e.preventDefault();
      goTo(index + 1);
    }
  });

  // Resize handling
  window.addEventListener('resize', () => {
    track.style.transform = `translateX(${-index * 100}%)`;
  });

  // Init
  goTo(0);
});
.carousel-controls {
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 10px 0;
  background: #fff;
  width: 50%;
  max-width: 500px;
  margin: 0 auto;
}

.carousel-button {
  font-size: 54px;
  color: #1a4480;
  background: transparent;
  border: none;
  cursor: pointer;
  padding: 10px;
}

.carousel-button:disabled {
  color: #919191;
  pointer-events: none;
}

.carousel-nav {
  text-align: center;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  width: 150px;
  min-width: 150px;
}

.carousel-indicator {
  display: inline-block;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  margin: 0 5px;
  cursor: pointer;
  border: 2px solid #1a4480;
}

.carousel-indicator.active {
  background: #1a4480 !important;
}

.ellipsis {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 24px;
  cursor: pointer;
  color: #1a4480;
  user-select: none;
  width: 24px;
  height: 24px;
  margin: 0 5px;
}

#ABCCarousel .ABC-carousel__viewport {
  display: flex;
  transition: transform 0.5s ease-in-out;
  will-change: transform;
}

#ABCCarousel .ABC-slide {
  flex: 0 0 100%;
}

#ABCCarousel {
  overflow: hidden;
  /* hide the overflow */
  width: 100%;
  /* full width */
}

#ABCCarousel .ABC-carousel__viewport {
  display: flex;
  /* line up slides horizontally */
  transition: transform 0.5s ease-in-out;
  /* smooth animation */
  will-change: transform;
}

#ABCCarousel .ABC-slide {
  flex: 0 0 100%;
  /* each slide takes full width of viewport */
}
<link rel="stylesheet" href="https://unpkg.com/uswds@latest/dist/css/uswds.min.css">
<section class="bg-base-lightest">
  <div class="grid-container">
    <div class="grid-row">
      <div class="grid-col-12 tablet:grid-col-8 tablet:grid-offset-2">
        <h2 class="text-center">FuyuuyuyC</h2>
        <div class="bg-white shadow-3 radius-md padding-3 margin-bottom-2" style=" border: 1px solid #919191;"><!-- Header -->
          <h3 class="text-center margin-bottom-0">Latest Posts</h3>
          <hr class="border-gray-30 margin-bottom-2" />
          <div id="ABCCarousel" class="ABC-carousel" aria-roledescription="carousel" aria-label="Latest posts">
            <div class="ABC-carousel__viewport" role="group" aria-live="polite" style=" transform: translateX(0%);"><!-- Slide 1 -->
              <section class="ABC-slide" role="group" aria-roledescription="slide" aria-label="1 of 5" aria-hidden="false">
                <div class="grid-row grid-gap-4 margin-bottom-3"><!-- Left card -->
                  <div class="tablet:grid-col-6"><img alt="" src="https://cdn.britannica.com/62/156362-050-4E8FE282/Acacia-tree-savanna-Zimbabwe.jpg?" /></div> <!-- Right post -->
                  <div class="tablet:grid-col-6">
                    <p>ABCD</a></p>
                    <div class="carousel-controls"><button class="carousel-button prev" disabled="">❮</button>
                      <div class="carousel-nav"></div> <button class="carousel-button next">❯</button>
                    </div>
                  </div>
                </div>
              </section> <!-- Slide 2 -->
              <section class="ABC-slide" role="group" aria-roledescription="slide" aria-label="2 of 5" aria-hidden="true">
                <div class="grid-row grid-gap-4 margin-bottom-3">
                  <div class="tablet:grid-col-6"><img alt="" src="https://cdn.britannica.com/62/156362-050-4E8FE282/Acacia-tree-savanna-Zimbabwe.jpg?" /></div>
                  <div class="tablet:grid-col-6">
                    <p>ytyty <a href="#">dffdfd.</a></p>
                    <div class="carousel-controls"><button class="carousel-button prev" disabled="">❮</button>
                      <div class="carousel-nav"></div> <button class="carousel-button next">❯</button>
                    </div>
                  </div>
                </div>
              </section>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>

React Router Nested Routes

I’m having issues configuring react-router-dom with nested routes loaded by sub-modules.
In my application I need to dynamically load modules that have their own nested routes. One of the requirement is to have the modules completely independent from the parent application. The loaded modules use relative routes to define their own navigation. The problem is that the relative navigation continue to append URL segments. I’m obviously missing something but I cannot figure it out.

I made a Codesandbox that shows the issue.


export default function App() {
  return (
    <BrowserRouter>
      <div className='App'>
        <h1>React Router Nested Routes</h1>
      </div>

      <Routes>
        <Route element={<OuterLayout />}>
          <Route
            element={<Home />}
            index
            path='home'
          />
          <Route
            element={<Nested />}
            path='nested/*'
          />
          <Route
            element={<Unknown />}
            path='*'
          />
        </Route>
      </Routes>
    </BrowserRouter>
  )
}

function OuterLayout() {
  return (
    <div>
      <ul>
        <li>
          <Link to='/home'>Home</Link>
        </li>
        <li>
          <Link to='/nested'>Nested</Link>
        </li>
      </ul>

      <Outlet />
    </div>
  )
}

function Home() {
  return <section>Home</section>
}

function Unknown() {
  return <section>Unknown</section>
}

function Nested() {
  return (
    <Routes>
      <Route element={<NestedLayout />}>
        <Route
          element={<Sub />}
          index
        />
        <Route
          element={<Sub />}
          path='sub'
        />
        <Route
          element={<Other />}
          path='other'
        />
      </Route>
    </Routes>
  )
}

function NestedLayout() {
  return (
    <div>
      <ul>
        <li>
          <Link to='sub'>Sub</Link>
        </li>
        <li>
          <Link to='other'>Other</Link>
        </li>
      </ul>

      <Outlet />
    </div>
  )
}

function Sub() {
  return <section>Sub</section>
}

function Other() {
  return <section>Other</section>
}

Is there way to use Symbol in React JS like base for key in map function

By the React docs is specified that key value in React lists should be unique. So, in that way, best choice is use ids from our database on client side like a key when we use map for our lists.

But if have some data that would be generated on our client side we can use UUID (thit is from React doc), but can we use Symbol instead?

Maybe are there any other good reasons to use Symbol in React (just like second additional question; u can answer it in short)?

Borrow/return system logic in JS [closed]

Users will also be able to borrow books from the library. Each borrowed book will have a loan date and a return date. When there is only one day left before the return date, the system must send the user an email reminder and also show them a notification on the website. If the book is not returned on time, the Admin will receive a notification message about the overdue book, and the Admin can place restrictions on that user

How to write this logic in JavaScript

Regex replace with /g/ is replacing the value twice

I have a simple regex replace – user provides find string and replace string. I’m using originalString.replace(new RegExp(find, 'gi'), replace) and it’s been working mostly fine. Recently I noticed that one of the edge cases where the replace string is applied twice when the find string is a match all.

For example:

const first =   'bat, batman, manbat'.replace(new RegExp('bat', 'gi'), 'cat');
console.log('first: ', first);
// => 'cat, catman, mancat'  // Every bat is replaced with cat, thanks to the global switch


const second = "bat, batman, manbat".replace(new RegExp('(.*)', 'gi'), '$1, cat');
console.log('second: ', second);
// => 'bat, batman, manbat, cat, cat'  // here, the 'cat' is replaced twice because of 'g'

Why is the ‘cat’ being applied twice for the second result? I would have expected it to just be bat, batman, manbat, cat – I just want to add , cat to multiple instances of strings, but they all have , cat twice at the end now.

The problem goes away in the second case if I take away the global switch, but then the first case would fail. How to fix this?

Line with curves on each side creates background problems?

I am trying to create a line that “flows” from the left side of the screen to the right side with curves at the sides, will post a pictures for clarification. I however don’t know a native way to create an upwards/inwards curving line on the bottom of a div. This creates the problem that I still need everything above the line to be black so the black div to the left named (.start) is needed to make the background black and then a div below it to cover the black and make the line curve with a simple border radius.

This interferes with any background below the line that is not a plain color, like an image or such, since the cover block is not transparent.

What I am trying to create, with the ability to place images and such below it

Current problem, see how the cover piece sticks down a bit into the grey. Ignore how the text is cut off that is simply solved with a transparent background on the container, but its covering the black as of now.

Different colors on all the divs to see how this is built.

Different colors and with the cover piece transparent.

Snippet too see it in action:

      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      html,
      body {
        overflow-x: hidden;
      }

      .container {
        width: 100%;
        height: 200px;
        display: flex;
        background-color: white;
        position: relative;
      }

      .start {
        width: calc(100px - 2rem);
        height: calc(200px - 2rem);
        background-color: black;
      }
      .start-cover {
        width: 120px;
        height: 110px;
        background-color: white;
        position: absolute;
        left: -2.9rem;
        bottom: -1px;
        border-left: 1.2rem solid #ffff00;
        border-top: 1.2rem solid #ffff00;
        border-radius: 100% 0 0;
      }
      .mid {
        width: calc(100% - 200px + 4rem);
        height: 110px;
        background-color: black;
        border-bottom: 1.2rem solid #ffff00;
      }
      .end {
        width: 120px;
        height: 110px;
        position: absolute;
        top: 0;
        right: -2.8rem;
        background-color: black;
        border-bottom: 1.2rem solid #ffff00;
        border-right: 1.2rem solid #ffff00;
        border-radius: 0 0 100%;
      }
    <div class="container">
      <div class="start"></div>
      <div class="mid"></div>
      <div class="end"></div>
      <div class="start-cover"></div>
    </div>

I have tried switching the divs with both a PNG and SVG but none worked as good as I want them to with responsibility. And therefore I’ve stuck with this solution.
If you have a alternative solution feel free to help me but also if it is just a simple fix I haven’t thought of.