Gulp changes reflects only on manual refreshing not automatically

I’m reaching out for some assistance regarding an issue I’ve encountered with my Gulpfile setup. I’ve configured the browser sync option in the file, and while changes are correctly getting reflected in the destination file, the browser does not auto-refresh. Instead, I have to manually refresh the browser to see the updates.I would really appreciate any help or guidance on how to fix this issue and get the auto-refresh working correctly.Thank you in advance for your time and support!

gulpfile.js

const gulp = require("gulp"),
  sass = require("gulp-sass")(require("sass")),
  plumber = require("gulp-plumber"),
  notify = require("gulp-notify"),
  sourcemaps = require("gulp-sourcemaps"),
  postcss = require("gulp-postcss"),
  autoprefixer = require("autoprefixer"),
  cssnano = require("gulp-cssnano"),
  uglify = require("gulp-uglify"),
  browserSync = require("browser-sync").create(),
  injectPartials = require("gulp-inject-partials"),
  del = require("del"),
  zip = require("gulp-zip"),
  concat = require("gulp-concat");

// PATHS
const paths = {
  styles: {
    src: "src/scss/**/*.scss",
  },
  mincss: {
    src: "src/mincss/*",
  },
  bundle: {
    dest: "assets/theme-css/",
    filename: "bundle.min.css",
  },
  minjs: {
    src: [
      "src/minjs/jquery.min.js",
      "src/minjs/bootstrap.bundle.min.js",
      "src/minjs/**/*.js",
      "src/js/**/*.js",
    ],
    dest: "assets/theme-js/",
  },
  image: {
    src: "src/img/**/*",
    dest: "assets/img/",
  },
  fonts: {
    src: "src/fonts/*",
    dest: "assets/fonts/",
  },
  html: {
    src: "src/templates/**/*.html",
    dest: "./",
  },
};

// WELCOME
gulp.task("hello", function (done) {
  console.log("WELCOME TO GULP");
  done();
});

// BUNDLE-CSS: SCSS + pre-minified CSS -> bundle.min.css
gulp.task("bundle-css", function () {
   console.log("SCSS file changed, recompiling...");
  return gulp
    .src([paths.mincss.src, paths.styles.src])
    .pipe(plumber({ errorHandler: notify.onError("CSS Error: <%= error.message %>") }))
    .pipe(sourcemaps.init())
    .pipe(sass().on("error", sass.logError))
    .pipe(postcss([
      autoprefixer({ overrideBrowserslist: ["last 2 versions"], cascade: false })
    ]))
    .pipe(cssnano())
    .pipe(concat(paths.bundle.filename))
    .pipe(sourcemaps.write("."))
    .pipe(gulp.dest(paths.bundle.dest))
    .pipe(browserSync.stream());
});

// MINIFY JS
gulp.task("minjs", function () {
   console.log("SCSS file changed, recompiling...");
  return gulp
    .src(paths.minjs.src)
    .pipe(plumber({ errorHandler: notify.onError("JS Error: <%= error.message %>") }))
    .pipe(uglify())
    .pipe(concat("single.min.js"))
    .pipe(gulp.dest(paths.minjs.dest));
});

// IMAGES
gulp.task("image", function () {
  return gulp.src(paths.image.src).pipe(gulp.dest(paths.image.dest));
});

// FONTS
gulp.task("fonts", function () {
  return gulp.src(paths.fonts.src).pipe(gulp.dest(paths.fonts.dest));
});

// HTML PARTIALS
gulp.task("ptl_render", function () {
  return gulp
    .src([paths.html.src, "!src/templates/partial/*.html"])
    .pipe(plumber({ errorHandler: notify.onError("HTML Error: <%= error.message %>") }))
    .pipe(injectPartials({ removeTags: true }))
    .pipe(gulp.dest(paths.html.dest));
});

// WATCH WITH BROWSER SYNC
gulp.task("watch", function () {
  browserSync.init({
    server: {
      baseDir: "./",
      notify:true
    },
    injectChanges: true,  // Ensures that CSS is injected
    reloadOnRestart: true, // Ensures the page is reloaded if necessary
  });

  gulp.watch([paths.styles.src, paths.mincss.src], gulp.series("bundle-css"));
  gulp.watch(paths.html.src, gulp.series("ptl_render"));
  gulp.watch(paths.minjs.src, gulp.series("minjs"));
  gulp.watch(paths.image.src, gulp.series("image"));
  gulp.watch(paths.fonts.src, gulp.series("fonts"));

  // Reload browser when any of these files are changed
  gulp.watch([
    "assets/theme-css/**/*.css",
    "assets/theme-js/**/*.js",
    "*.html",
    "assets/img/**/*",
    "assets/fonts/**/*"
  ]).on("change", browserSync.reload);
});

// SERVE
gulp.task("serve", gulp.parallel(["bundle-css", "ptl_render", "minjs","image","fonts"]));

// DEFAULT
gulp.task("default", gulp.series("serve", "watch"));

// CLEAN TASKS
gulp.task("clearAll", function () {
  return del(["assets", "./*.html", "./build"]);
});
gulp.task("clearBuild", function () {
  return del("./build");
});

// ZIP PROJECT
gulp.task("zip", function () {
  return gulp
    .src([
      "./**/*",
      "!./node_modules/**",
      "!./src/**",
      "!./gulpfile.js",
      "!./package-lock.json",
      "!./package.json",
    ])
    .pipe(zip("project.zip"))
    .pipe(gulp.dest("./zip"));
});

// BUILD TO /build FOLDER
gulp.task("build", function () {
  return gulp
    .src([
      "./**/*",
      "!./node_modules/**",
      "!./src/**",
      "!./gulpfile.js",
      "!./package-lock.json",
      "!./package.json",
    ])
    .pipe(gulp.dest("./build"));
});

How can I expand images using Mouse-Hover in a way that is not so visually jarring to the user? [closed]

Following on from How to expand on image on hover to full size?, I am still having many issues with it.

First and foremost, when I am attempting to hover over images a transition is supposed to play while the complete full-sized image is overlaid on top with a caption. No matter what I have done though, the images are snapping into place very suddenly, and the text boxes that are supposed to be hovering near them with the title and description are not resizing properly.

The website in question is located here on GitHub Pages (so you can see what the actual problem is) and the source code is located here.

EDIT: Minimum Replicable Example

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <title>Minimal Fullscreen Hover Example</title>
  <style>
    body {
      background: #222;
      margin: 0;
      min-height: 100vh;
    }

    .gallery {
      display: flex;
      gap: 2rem;
      padding: 2rem;
    }

    .img-ctr {
      width: 200px;
      cursor: pointer;
      position: relative;
    }

    .img-ctr img {
      width: 100%;
      display: block;
      border-radius: 8px;
    }

    #overlay {
      position: fixed;
      inset: 0;
      background: rgba(0, 0, 0, 0.7);
      opacity: 0;
      visibility: hidden;
      transition: opacity 0.3s;
      z-index: 10;
      pointer-events: none;
    }

    #overlay.show {
      opacity: 1;
      visibility: visible;
    }

    #previewOverlay {
      position: fixed;
      inset: 0;
      background: no-repeat center center;
      background-size: contain;
      opacity: 0;
      visibility: hidden;
      transition: opacity 0.3s;
      z-index: 20;
      pointer-events: none;
    }

    #previewOverlay.show {
      opacity: 1;
      visibility: visible;
    }

    #caption-box {
      position: absolute;
      background: #333;
      color: #fff;
      padding: 1rem;
      border-radius: 8px;
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
      opacity: 0;
      visibility: hidden;
      transition: opacity 0.3s;
      z-index: 30;
      min-width: 180px;
    }

    #caption-box.visible {
      opacity: 1;
      visibility: visible;
    }
  </style>
</head>

<body>
  <div class="gallery">
    <div class="img-ctr">
      <img src="https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=400" alt="Forest">
      <h3>Forest</h3>
      <p>Misty forest landscape</p>
    </div>
    <div class="img-ctr">
      <img src="https://images.unsplash.com/photo-1465101046530-73398c7f28ca?w=400" alt="Mountains">
      <h3>Mountains</h3>
      <p>Snowy mountain peaks</p>
    </div>
  </div>
  <div id="overlay"></div>
  <div id="previewOverlay"></div>
  <div id="caption-box">
    <h3></h3>
    <p></p>
  </div>
  <script>
    const overlay = document.getElementById('overlay');
    const preview = document.getElementById('previewOverlay');
    const caption = document.getElementById('caption-box');

    document.querySelectorAll('.img-ctr').forEach(card => {
      card.addEventListener('mouseenter', () => {
        overlay.classList.add('show');
        const src = card.querySelector('img').src;
        preview.style.background = `url('${src}') center/contain no-repeat`;
        preview.classList.add('show');
        // Update caption
        caption.querySelector('h3').textContent = card.querySelector('h3').textContent;
        caption.querySelector('p').textContent = card.querySelector('p').textContent;
        // Position caption box after DOM updates
        setTimeout(() => {
          const previewRect = preview.getBoundingClientRect();
          const captionHeight = caption.offsetHeight;
          const top = previewRect.top + window.scrollY + previewRect.height / 2 - captionHeight / 2;
          const left = previewRect.right + 20;
          const maxLeft = window.innerWidth - caption.offsetWidth - 20;
          caption.style.top = `${top}px`;
          caption.style.left = `${Math.min(left, maxLeft)}px`;
          caption.classList.add('visible');
        }, 30);
      });
      card.addEventListener('mouseleave', () => {
        overlay.classList.remove('show');
        preview.classList.remove('show');
        caption.classList.remove('visible');
        caption.style.top = '';
        caption.style.left = '';
      });
    });
  </script>
</body>

</html>

Note: The Code above was what was returned when using the integrated Copilot AI tool on VSCode returned. The actual code is quite messy unfortunately with a some things being hidden in the Style.css file, I’m doing my best to try and parse out exactly what works well!

My current understanding of how the code works is as follows;

  • Images get pre-loaded into cards objects with the best fit, typically cropping the image to an extent

    (section of the preloaded image cards)

  • When the mouse hovers over it for a given time, it expands slightly and a full-screen sized version of the hovered image gets overlaid on top of the screen:

    (image in the process of getting overlayed after mouse hover)

  • It then attempts to place a text box caption to the right of the full-screen image with a 20px offset (incredibly inconsistent):

    (expanded image)

  • When the mouse leaves it, the image then very suddenly disappears and the background slowly fades out.

Realistically I would prefer if the images did not create a full-screen overlay and instead expanded when hovered over so it is a smoother user experience. If that is not possible using Card objects I am more than willing to use something else that makes more sense in this scenario. Worst case I can just make it so that clicking on the image takes you to a separate tab with the full image and a title/caption with it.

Slot “default” invoked outside of the render function: this will not track dependencies used in the slot

Error and stack trace

app.js:73  [Vue warn]: Slot "default" invoked outside of the render function: this will not track dependencies used in the slot. Invoke the slot function inside the render function instead. 
  at <VDefaultsProvider key="content-defaults" defaults= {VImg: {…}, VIcon: {…}} > 
  at <VAvatar size=58 class="mt-4" > 
  at <VCard elevation="0" color="background" class="mt-8 ml-0 d-flex flex-column align-center justify-center v-card-profile rounded-lg"  ... > 
  at <VNavigationDrawer key=0 color="background" modelValue=true  ... > 
  at <Navbar key=0 navItems= (3) [{…}, {…}, {…}] userName="アレキサンダー デヴォア "  ... > 
  at <VApp> 
  at <VuetifyLayout api-token="pkJvMRbL9maJqRgcuNYmM1R1IMGuljWTFa92c5L3yejrCsNaCdLtMFYG7t3kFL9J965pk86CVXqDzfZK" user= {id: 1, name: 'アレキサンダー デヴォア', email: '[email protected]', language: 'en', is_super_admin: 0, …} is-supplier=0  ... > 
  at <App>

The part of the code that is causing the issue

<v-card elevation="0" color="background"
    class="mt-8 ml-0 d-flex flex-column align-center justify-center v-card-profile rounded-lg"
    :class="{ 'sidebar-profile': isProfilePage }"
    @click.stop="navigateToBackendRoute(isSupplier ? `user/${userId}` : `admin/${userId}`)">

    <v-avatar :size="58" class="mt-4" :class="{ 'mb-2': miniSideBar }">
        {{ userName.charAt(0) }}
    </v-avatar>
    
</v-card>

Tried removing the v-avatar component which fixes the issue, but I can’t do that as I need it

How to build a Dynamic Svelte Component with correct typing?

I’m working in a project group and our current task is to make a Survey app. We’re building the frontend in Svelte with TypeScript, and I’m trying to build a component that will take some JSON data and an input type and render an input field based on that.

So far I have this:

<script lang="ts">
    import TextQuestion from './question_types/TextQuestion.svelte';
    import NumberQuestion from './question_types/NumberQuestion.svelte';
    import SingleChoiceQuestion from './question_types/SingleChoiceQuestion.svelte';
    import MultipleChoiceQuestion from './question_types/MultipleChoiceQuestion.svelte';
    import OpinionMatrix from './question_types/OpinionMatrix.svelte';
    import ClassDropdown from './question_types/ClassDropdown.svelte';
    import SliderQuestion from './question_types/SliderQuestion.svelte';
    import ConditionalQuestion from '../../teacher/components/question-types/ConditionalQuestion.svelte';
    import type {
        ClassDropdownProps, ConditionalQuestionProps, MultipleChoiceQuestionProps,
        NumberQuestionProps, OpinionMatrixProps, SingleChoiceQuestionProps, SliderQuestionProps,
        TextQuestionProps
    } from "./question_types/QuestionTypeProps";

    // Union of all question types
    type QuestionProps =
        { type: 'text'; element: typeof TextQuestion; props: TextQuestionProps }
        | { type: 'number'; element: typeof NumberQuestion; props: NumberQuestionProps }
        | { type: 'slider'; element: typeof SliderQuestion; props: SliderQuestionProps }
        | { type: 'single_choice'; element: typeof SingleChoiceQuestion; props: SingleChoiceQuestionProps }
        | { type: 'multiple_choice'; element: typeof MultipleChoiceQuestion; props: MultipleChoiceQuestionProps }
        | { type: 'opinion_matrix'; element: typeof OpinionMatrix; props: OpinionMatrixProps }
        | { type: 'class_dropdown'; element: typeof ClassDropdown; props: ClassDropdownProps }
        | { type: 'conditional_question'; element: typeof ConditionalQuestion; props: ConditionalQuestionProps };

    // Retrieve props dynamically (this is using $props() in your context)
    let { type, ...props }: { type: QuestionProps['type'] } = $props();

    // Infer the correct component based on type
    let Component : QuestionProps['element'];

    // Determine the correct component to use based on the `type`
    switch (type) {
        case 'text':
            Component = TextQuestion;
            props = props as TextQuestionProps;  // Type assertion for the props
            break;
        case 'number':
            Component = NumberQuestion;
            props = props as NumberQuestionProps;
            break;
        case 'slider':
            Component = SliderQuestion;
            props = props as SliderQuestionProps;
            break;
        case 'single_choice':
            Component = SingleChoiceQuestion;
            props = props as SingleChoiceQuestionProps;
            break;
        case 'multiple_choice':
            Component = MultipleChoiceQuestion;
            props = props as MultipleChoiceQuestionProps;
            break;
        case 'opinion_matrix':
            Component = OpinionMatrix;
            props = props as OpinionMatrixProps;
            break;
        case 'class_dropdown':
            Component = ClassDropdown;
            props = props as ClassDropdownProps;
            break;
        case 'conditional_question':
            Component = ConditionalQuestion;
            props = props as ConditionalQuestionProps;
            break;
        default:
            throw new Error('Unknown question type');
    }
</script>

<div class="question">
    <!-- Dynamically render the component with the correctly typed props -->
    <Component {...props}/>
</div>

<style>
    .question {
        margin-bottom: 20px;
    }
</style>

I don’t really like it and it doesn’t work properly. The typing currently accepts any value for type, element and props, regardless of the others’ input. But they should be hard coupled together.

Does anyone have any insights in how this would be doable? I’ve had a hell of a time researching this because the runes system is relatively new, and I’m kinda burnt out trying to get this to work.

If a child component consumers a context provider, do its parents also re-render?

Although the docs for context say “React automatically re-renders all the children that use a particular context starting from the provider that receives a different value.”, from my testing it appears that the parents that contain that child also re-render because their prop children changes.

In the following example I created a context that holds a counter value. That value comes from a state variable that is incremented on click of a button at the top level. is composed within two parent components.

When running the profiler, on click the parents rerender because children has changed.

Does that mean the doc is inaccurate?

import React, { createContext, memo, useContext } from 'react';

const Parent1 = memo((props: any) => {
  return props.children;
});
Parent1.displayName = 'Parent1';

const Parent2 = memo((props: any) => {
  return props.children;
});

Parent2.displayName = 'Parent2';

const Child = memo((props: any) => {
  const counterFromContext = useContext(TestContext);

  return (<div>
    {counterFromContext}
  </div>);
});

Child.displayName = 'Child';

const TestContext = createContext(0);

const Test = () => {

  const [counter, setCounter] = React.useState(1);

  return (
    <>
      <TestContext.Provider value={counter}>
        <Parent1>
          <Parent2>
            <Child></Child>
          </Parent2>
        </Parent1>
      </TestContext.Provider>
      <button onClick={() => setCounter((prev) => prev + 1)}>
      Update counter
      </button>
    </>
  );

};

export default memo(Test);

I find the text from a txt file and then try to update the text box but it doesn’t update

I am attempting to grab a line of text out of a file and put it on the screen. This works so far and does what is expected but I would like it to be able to change every time we are “WaitingForUser”. However it never changes:

export function animate(scene, camera) {
  if (!priceText) return;
  if (!active) return;
  let displayPrice = currentPrice.toFixed(1).padStart(5, ' ');

  //console.log(targetPrice);
  if(waitingForUser){
    if(!userResponded){
      displayPrice = currentPrice.toFixed(1);
      //console.log("!userresponded");
      return;
    }
    //console.log("userresponded");
    userResponded = false;
    waitingForUser = false;
    STOCKPROMPT.setText(imageBlock); // here is the function call to change the textblock to a different 
export function setText(textNode) {
  const client = new XMLHttpRequest();
  client.open('GET', '/funnyprompts.txt', true);
  client.onreadystatechange = () => {
    if (client.readyState === 4 && client.status === 200) {
      const lines = client.responseText
        .split('n')
        .map(l => l.trim())
        .filter(l => l !== '');
      const funnyprompt = lines[Math.floor(Math.random() * lines.length)];

      console.log('⤴️ setting prompt:', funnyprompt);
      // THIS actually updates the UI text
      textNode.set({ content: funnyprompt });
    }
  };
  client.send();
}

This code is for the actual setup of the prompts.

I tried to split up the functions for the changing of the text into two functions one to get the text and the other to handle the file read. No changes.

Angular HttpErrorResponse blob error response doesn’t trigger FileReader

When requesting a file and an error is returned I get the error response in a Blob instance

error: Blob {size: 97, type: 'application/json'}
headers: HttpHeaders {normalizedNames: Map(0), lazyUpdate: null, lazyInit: ƒ}
message: "Http failure response for redacted: 404 OK"
name: "HttpErrorResponse"
ok: false
status: 404
statusText: "OK"
url: "redacted"

Given that, I can’t do my standard check in the error property for a message. I’m attempting to read the response as the response itself is the correct format, just a blob:

if (requestError.type === 'application/json') {
  console.log('start parsing');
  const reader = new FileReader();
  reader.onload  = (event) => {
    console.log(event);
    console.log('reader.result', reader.result);
    try {
      requestError = JSON.parse(reader.result as string);
      console.log('Parsed JSON response:', requestError);
    } catch (e) {
      console.log('Error parsing JSON response:', e);
    }
  }
  return;
}

"start parsing" is fired but the onload event isn’t. I’ve tried onloadend as well as setting the event trigger as reader.addEventListener('loadend', (event) => { but nothing inside the loading events fires. I’m checking the response I can confirm it’s a blob and the response is in json.

Not sure why the FileReader event’s are being triggered.

Prevent Page Refresh When Bootstrap 5 Autocomplete Dropdown is Selected [closed]

I have a bootstrap autocomplete form working in my project. The issue is that once an autocomplete dropdown item is selected, the page refreshes. The autocomplete values are ids that point to specific areas within the parent page.

HTML:

<div id="searchbar">
  <form class="form-inline">
    <input type="search" class="form-control" id="autosuggest" placeholder="Search" aria-label="Search" autocomplete="off"><i class="bi bi-search"></i>
  </form>
</div>

Initiate the autocomplete:

  <script>
    var datasrc = [
      {label: 'Section One', value: '#section%20one'},
      {label: 'Section Two', value: '#section%20two'},
    ]
    const ac = new Autocomplete(document.getElementById('autosuggest'), {
      data: datasrc,
      treshold: 1,
      maximumItems: 8,
      onSelectItem: ({label, value}) => {
        console.log("user selected:", label, value);
      }
    });
  </script>

Autocomplete js:

/* Bootstrap 5 - Autocomplete
  https://www.cssscript.com/demo/autocomplete-typeahead-bootstrap-5/
*/

const DEFAULTS = {
  treshold: 2,
  maximumItems: 5,
  highlightTyped: true,
  highlightClass: 'text-primary',
};

class Autocomplete {
  constructor(field, options) {
    this.field = field;
    this.options = Object.assign({}, DEFAULTS, options);
    this.dropdown = null;

    field.parentNode.classList.add('dropdown');
    field.setAttribute('data-toggle', 'dropdown');
    field.classList.add('dropdown-toggle');

    const dropdown = ce(`<div class="dropdown-menu" ></div>`);
    if (this.options.dropdownClass)
      dropdown.classList.add(this.options.dropdownClass);

    insertAfter(dropdown, field);

    this.dropdown = new bootstrap.Dropdown(field, this.options.dropdownOptions)

    field.addEventListener('click', (e) => {
      if (this.createItems() === 0) {
        e.stopPropagation();
        this.dropdown.hide();
      }
    });

    field.addEventListener('input', () => {
      if (this.options.onInput)
        this.options.onInput(this.field.value);
      this.renderIfNeeded();
    });

    field.addEventListener('keydown', (e) => {
      if (e.keyCode === 27) {
        this.dropdown.hide();
        return;
      }
    });
  }

  setData(data) {
    this.options.data = data;
  }

  renderIfNeeded() {
    if (this.createItems() > 0)
      this.dropdown.show();
    else
      this.field.click();
  }

  createItem(lookup, item) {
    let label;
    if (this.options.highlightTyped) {
      const idx = item.label.toLowerCase().indexOf(lookup.toLowerCase());
      const className = Array.isArray(this.options.highlightClass) ? this.options.highlightClass.join(' ')
        : (typeof this.options.highlightClass == 'string' ? this.options.highlightClass : '')
      label = item.label.substring(0, idx)
        + `<span class="${className}">${item.label.substring(idx, idx + lookup.length)}</span>`
        + item.label.substring(idx + lookup.length, item.label.length);
    } else
      label = item.label;
    return ce(`<a class="dropdown-item" href="${item.value}">${label}</a>`);
  }

  createItems() {
    const lookup = this.field.value;
    if (lookup.length < this.options.treshold) {
      this.dropdown.hide();
      return 0;
    }

    const items = this.field.nextSibling;
    items.innerHTML = '';

    let count = 0;
    for (let i = 0; i < this.options.data.length; i++) {
      const {label, value} = this.options.data[i];
      const item = {label, value};
      if (item.label.toLowerCase().indexOf(lookup.toLowerCase()) >= 0) {
        items.appendChild(this.createItem(lookup, item));
        if (this.options.maximumItems > 0 && ++count >= this.options.maximumItems)
          break;
      }
    }

    this.field.nextSibling.querySelectorAll('.dropdown-item').forEach((item) => {
      item.addEventListener('click', (e) => {
        let dataValue = e.target.getAttribute('data-value');
        this.field.value = e.target.innerText;
        if (this.options.onSelectItem)
          this.options.onSelectItem({
            value: e.target.value,
            label: e.target.innerText,
          });
        this.dropdown.hide();
        location.href = e.target.href;
        location.reload();
      })
    });

    return items.childNodes.length;
  }
}

/**
 * @param html
 * @returns {Node}
 */
function ce(html) {
  let div = document.createElement('div');
  div.innerHTML = html;
  return div.firstChild;
}

/**
 * @param elem
 * @param refElem
 * @returns {*}
 */
function insertAfter(elem, refElem) {
  return refElem.parentNode.insertBefore(elem, refElem.nextSibling)
}

Testing in Webkit browsers, I have tried using “event.preventDefault();” in a function and also onsubmit=”return false” inline, but nothing seems to prevent the page from refreshing when an item in the autocomplete dropdown is selected. The selection does correctly target the corresponding id, but after the id is targeted and the url changes, the page then refreshes last. I would like to stop the page from refreshing when any id is targeted/clicked from the autocomplete list.

How to maintain the scroll position in FullCalendar with ResourceTimeline after the data is refreshed? [closed]

Required:
When using FullCalendar.Calendar 4.4.0 with the plugins

['interaction', 'resourceTimeline'], 

I need to maintain the scroll position so that it stays on a specific resource after refreshing the page or after reinitializing the calendar due to loading new data (resources or events) from the server using JavaScript and PHP in Laravel.

Objective:
When refreshing FullCalendar due to a change in the number of resources or events (adding or removing), I don’t want the scroll to return to the top of the resources. Instead, I want it to remain on the resource that was visible before the update.

Maintaining Scroll Position in FullCalendar with ResourceTimeline After Data Refresh (Laravel/PHP/JavaScript)

Required:
When using FullCalendar.Calendar 4.4.0 with the plugins [‘interaction’, ‘resourceTimeline’], I need to maintain the scroll position so that it stays on a specific resource after refreshing the page or after reinitializing the calendar due to loading new data (resources or events) from the server using JavaScript and PHP in Laravel.

Objective:
When refreshing FullCalendar due to a change in the number of resources or events (adding or removing), I don’t want the scroll to return to the top of the resources. Instead, I want it to remain on the resource that was visible before the update.

Make d3-geoPath with a different fillStyle in svelte-canvas

Actually the basic are already answered here, but I can’t translate the method if I use svelte-canvas.

<script>
    import { onMount } from 'svelte'
    import { Canvas, Layer } from "svelte-canvas";
    import { feature } from "topojson-client";
    import { geoOrthographic, geoPath, geoGraticule10 } from "d3-geo";
    
    let map, color="red"

    const projection = geoOrthographic(), 
                path = geoPath(projection);
    
    onMount(() => {
        fetch("https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json")
            .then(data => data.json())
            .then(data => {
                map = feature(data, 'countries')
            })
        })
        
    $: graticule = ({ context, width, time }) => {
        projection
            .fitSize([width, width], { type: "Sphere" })
            .rotate([0, -10]);
        
    context.strokeStyle = "#ccc";
    context.beginPath(), path(geoGraticule10()), context.stroke();
  };

  $: globe = ({ context }) => {
    // this set the fill style of all countries,
    // If i use `map.features.forEach` it will lag very much
    // and only set the color based on the last condition
    context.fillStyle = "red";

    // I tried path(map.features[10].geometry...) or similar,
    // but doesn't work, It gives error
    context.beginPath(), path(map), context.fill();
  };
</script>

    <Canvas autoplay>
        <Layer render={bg} />
        <Layer setup={({ context }) => path.context(context)} render={graticule} />
        <Layer render={globe} />
    </Canvas>

what I’ve already tried to do

$: globe = ({ context }) => {
    map.features.forEach(d => {
       if (d.properties.name == "Chile") {
           color = "green"
       } else {
           color = "red"
       }
    })
  
    context.fillStyle = color;
    context.beginPath(), path(map), context.fill();
  };

How does this pop-under js technique work?

The following js code is given openly by an ad company (which I’d rather not name, though it’s not difficult to find). I just formatted it for readability. It is supposed to allow the website owner to display popunder ads.

I want to know how it works, but I’m not a js expert and this is a bit over my head, though I have basic js knowledge. Can someone please break down how it works step by step, when using firefox for example, and explain how it can circumvent adblock filters and browser settings (to block popups) ?

(function() {

    //version 6.0.0
  
    var adConfig = {
      "ads_host": "a.pemsrv.com",
      "syndication_host": "s.pemsrv.com",
      "idzone": 1234567,
      "popup_fallback": false,
      "popup_force": false,
      "chrome_enabled": true,
      "new_tab": false,
      "frequency_period": 1,
      "frequency_count": 1,
      "trigger_method": 3,
      "trigger_class": "",
      "trigger_delay": 0,
      "capping_enabled": true,
      "tcf_enabled": true,
      "only_inline": false,
      "tags": "cartoon"
    };
  
    window.document.querySelectorAll || (document.querySelectorAll = document.body.querySelectorAll = Object.querySelectorAll = function(e, o, t, i, n) {
      var r = document,
        a = r.createStyleSheet();
      for (n = r.all, o = [], t = (e = e.replace(/[forb/gi, "[htmlFor").split(",")).length; t--;) {
        for (a.addRule(e[t], "k:v"), i = n.length; i--;) n[i].currentStyle.k && o.push(n[i]);
        a.removeRule(0)
      }
      return o
    });
    var popMagic = {
      version: 6,
      cookie_name: "",
      url: "",
      config: {},
      open_count: 0,
      top: null,
      browser: null,
      venor_loaded: !1,
      venor: !1,
      tcfData: null,
      configTpl: {
        ads_host: "",
        syndication_host: "",
        idzone: "",
        frequency_period: 720,
        frequency_count: 1,
        trigger_method: 1,
        trigger_class: "",
        popup_force: !1,
        popup_fallback: !1,
        chrome_enabled: !0,
        new_tab: !1,
        cat: "",
        tags: "",
        el: "",
        sub: "",
        sub2: "",
        sub3: "",
        only_inline: !1,
        trigger_delay: 0,
        capping_enabled: !0,
        tcf_enabled: !1,
        cookieconsent: !0,
        should_fire: function() {
          return !0
        }
      },
      init: function(e) {
        if (void 0 !== e.idzone && e.idzone) {
          void 0 === e.customTargeting && (e.customTargeting = []), window.customTargeting = e.customTargeting || null;
          var o = Object.keys(e.customTargeting).filter((function(e) {
            return e.search("ex_") >= 0
          }));
          for (var t in o.length && o.forEach(function(e) {
              return this.configTpl[e] = null
            }.bind(this)), this.configTpl) Object.prototype.hasOwnProperty.call(this.configTpl, t) && (void 0 !== e[t] ? this.config[t] = e[t] : this.config[t] = this.configTpl[t]);
          if (void 0 !== this.config.idzone && "" !== this.config.idzone) {
            !0 !== this.config.only_inline && this.loadHosted();
            var i = this;
            this.checkTCFConsent((function() {
              "complete" === document.readyState ? i.preparePopWait() : i.addEventToElement(window, "load", i.preparePop)
            }))
          }
        }
      },
      getCountFromCookie: function() {
        if (!this.config.cookieconsent) return 0;
        var e = popMagic.getCookie(popMagic.cookie_name),
          o = void 0 === e ? 0 : parseInt(e);
        return isNaN(o) && (o = 0), o
      },
      getLastOpenedTimeFromCookie: function() {
        var e = popMagic.getCookie(popMagic.cookie_name),
          o = null;
        if (void 0 !== e) {
          var t = e.split(";")[1];
          o = t > 0 ? parseInt(t) : 0
        }
        return isNaN(o) && (o = null), o
      },
      shouldShow: function() {
        if (!popMagic.config.capping_enabled) {
          var e = !0,
            o = popMagic.config.should_fire;
          try {
            "function" == typeof o && (e = Boolean(o()))
          } catch (e) {
            console.error("Error executing should fire callback function:", e)
          }
          return e && 0 === popMagic.open_count
        }
        if (popMagic.open_count >= popMagic.config.frequency_count) return !1;
        var t = popMagic.getCountFromCookie(),
          i = popMagic.getLastOpenedTimeFromCookie(),
          n = Math.floor(Date.now() / 1e3),
          r = i + popMagic.config.trigger_delay;
        return !(i && r > n) && (popMagic.open_count = t, !(t >= popMagic.config.frequency_count))
      },
      venorShouldShow: function() {
        return popMagic.venor_loaded && "0" === popMagic.venor
      },
      setAsOpened: function(e) {
        var o = e ? e.target || e.srcElement : null,
          t = {
            id: "",
            tagName: "",
            classes: "",
            text: "",
            href: "",
            elm: ""
          };
        void 0 !== o && null != o && (t = {
          id: void 0 !== o.id && null != o.id ? o.id : "",
          tagName: void 0 !== o.tagName && null != o.tagName ? o.tagName : "",
          classes: void 0 !== o.classList && null != o.classList ? o.classList : "",
          text: void 0 !== o.outerText && null != o.outerText ? o.outerText : "",
          href: void 0 !== o.href && null != o.href ? o.href : "",
          elm: o
        });
        var i = new CustomEvent("creativeDisplayed-" + popMagic.config.idzone, {
          detail: t
        });
        if (document.dispatchEvent(i), popMagic.config.capping_enabled) {
          var n = 1;
          n = 0 !== popMagic.open_count ? popMagic.open_count + 1 : popMagic.getCountFromCookie() + 1;
          var r = Math.floor(Date.now() / 1e3);
          popMagic.config.cookieconsent && popMagic.setCookie(popMagic.cookie_name, n + ";" + r, popMagic.config.frequency_period)
        } else ++popMagic.open_count
      },
      loadHosted: function() {
        var e = document.createElement("script");
        for (var o in e.type = "application/javascript", e.async = !0, e.src = "//" + this.config.ads_host + "/popunder1000.js", e.id = "popmagicldr", this.config) Object.prototype.hasOwnProperty.call(this.config, o) && "ads_host" !== o && "syndication_host" !== o && e.setAttribute("data-exo-" + o, this.config[o]);
        var t = document.getElementsByTagName("body").item(0);
        t.firstChild ? t.insertBefore(e, t.firstChild) : t.appendChild(e)
      },
      preparePopWait: function() {
        setTimeout(popMagic.preparePop, 400)
      },
      preparePop: function() {
        if ("object" != typeof exoJsPop101 || !Object.prototype.hasOwnProperty.call(exoJsPop101, "add")) {
          if (popMagic.top = self, popMagic.top !== self) try {
            top.document.location.toString() && (popMagic.top = top)
          } catch (e) {}
          if (popMagic.cookie_name = "zone-cap-" + popMagic.config.idzone, popMagic.config.capping_enabled || (document.cookie = popMagic.cookie_name + "=;expires=Thu, 01 Jan 1970 00:00:01 GMT; path=/"), popMagic.shouldShow()) {
            var e = new XMLHttpRequest;
            e.onreadystatechange = function() {
              e.readyState == XMLHttpRequest.DONE && (popMagic.venor_loaded = !0, 200 == e.status ? popMagic.venor = e.responseText : popMagic.venor = "0")
            };
            var o = "https:" !== document.location.protocol && "http:" !== document.location.protocol ? "https:" : document.location.protocol;
            e.open("GET", o + "//" + popMagic.config.syndication_host + "/venor.php", !0);
            try {
              e.send()
            } catch (e) {
              popMagic.venor_loaded = !0
            }
          }
          if (popMagic.buildUrl(), popMagic.browser = popMagic.browserDetector.getBrowserInfo(), popMagic.config.chrome_enabled || !popMagic.browser.isChrome) {
            var t = popMagic.getPopMethod(popMagic.browser);
            popMagic.addEvent("click", t)
          }
        }
      },
      getPopMethod: function(e) {
        return popMagic.config.popup_force || popMagic.config.popup_fallback && e.isChrome && e.version >= 68 && !e.isMobile ? popMagic.methods.popup : e.isMobile ? popMagic.methods.default : e.isChrome ? popMagic.methods.chromeTab : popMagic.methods.default
      },
      checkTCFConsent: function(e) {
        if (this.config.tcf_enabled && "function" == typeof window.__tcfapi) {
          var o = this;
          window.__tcfapi("addEventListener", 2, (function(t, i) {
            i && (o.tcfData = t, "tcloaded" !== t.eventStatus && "useractioncomplete" !== t.eventStatus || (window.__tcfapi("removeEventListener", 2, (function() {}), t.listenerId), e()))
          }))
        } else e()
      },
      buildUrl: function() {
        var e, o = "https:" !== document.location.protocol && "http:" !== document.location.protocol ? "https:" : document.location.protocol,
          t = top === self ? document.URL : document.referrer,
          i = {
            type: "inline",
            name: "popMagic",
            ver: this.version
          },
          n = "";
        customTargeting && Object.keys(customTargeting).length && ("object" == typeof customTargeting ? Object.keys(customTargeting) : customTargeting).forEach((function(o) {
          "object" == typeof customTargeting ? e = customTargeting[o] : Array.isArray(customTargeting) && (e = scriptEl.getAttribute(o));
          var t = o.replace("data-exo-", "");
          n += "&" + t + "=" + e
        }));
        var r = this.tcfData && this.tcfData.gdprApplies && !0 === this.tcfData.gdprApplies ? 1 : 0;
        this.url = o + "//" + this.config.syndication_host + "/v1/link.php?cat=" + this.config.cat + "&idzone=" + this.config.idzone + "&type=8&p=" + encodeURIComponent(t) + "&sub=" + this.config.sub + ("" !== this.config.sub2 ? "&sub2=" + this.config.sub2 : "") + ("" !== this.config.sub3 ? "&sub3=" + this.config.sub3 : "") + "&block=1&el=" + this.config.el + "&tags=" + this.config.tags + "&scr_info=" + function(e) {
          var o = e.type + "|" + e.name + "|" + e.ver;
          return encodeURIComponent(btoa(o))
        }(i) + n + "&gdpr=" + r + "&cb=" + Math.floor(1e9 * Math.random()), this.tcfData && this.tcfData.tcString ? this.url += "&gdpr_consent=" + encodeURIComponent(this.tcfData.tcString) : this.url += "&cookieconsent=" + this.config.cookieconsent
      },
      addEventToElement: function(e, o, t) {
        e.addEventListener ? e.addEventListener(o, t, !1) : e.attachEvent ? (e["e" + o + t] = t, e[o + t] = function() {
          e["e" + o + t](window.event)
        }, e.attachEvent("on" + o, e[o + t])) : e["on" + o] = e["e" + o + t]
      },
      getTriggerClasses: function() {
        var e, o = []; - 1 === popMagic.config.trigger_class.indexOf(",") ? e = popMagic.config.trigger_class.split(" ") : e = popMagic.config.trigger_class.replace(/s/g, "").split(",");
        for (var t = 0; t < e.length; t++) "" !== e[t] && o.push("." + e[t]);
        return o
      },
      addEvent: function(e, o) {
        var t;
        if ("3" != popMagic.config.trigger_method)
          if ("2" != popMagic.config.trigger_method || "" == popMagic.config.trigger_method)
            if ("4" != popMagic.config.trigger_method || "" == popMagic.config.trigger_method) popMagic.addEventToElement(document, e, o);
            else {
              var n = popMagic.getTriggerClasses();
              popMagic.addEventToElement(document, e, (function(e) {
                n.some((function(o) {
                  return null !== e.target.closest(o)
                })) || o.call(e.target, e)
              }))
            }
        else {
          var r = popMagic.getTriggerClasses();
          for (t = document.querySelectorAll(r.join(", ")), i = 0; i < t.length; i++) popMagic.addEventToElement(t[i], e, o)
        } else
          for (t = document.querySelectorAll("a"), i = 0; i < t.length; i++) popMagic.addEventToElement(t[i], e, o)
      },
      setCookie: function(e, o, t) {
        if (!this.config.cookieconsent) return !1;
        t = parseInt(t, 10);
        var i = new Date;
        i.setMinutes(i.getMinutes() + parseInt(t));
        var n = encodeURIComponent(o) + "; expires=" + i.toUTCString() + "; path=/";
        document.cookie = e + "=" + n
      },
      getCookie: function(e) {
        if (!this.config.cookieconsent) return !1;
        var o, t, i, n = document.cookie.split(";");
        for (o = 0; o < n.length; o++)
          if (t = n[o].substr(0, n[o].indexOf("=")), i = n[o].substr(n[o].indexOf("=") + 1), (t = t.replace(/^s+|s+$/g, "")) === e) return decodeURIComponent(i)
      },
      randStr: function(e, o) {
        for (var t = "", i = o || "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", n = 0; n < e; n++) t += i.charAt(Math.floor(Math.random() * i.length));
        return t
      },
      isValidUserEvent: function(e) {
        return !(!("isTrusted" in e) || !e.isTrusted || "ie" === popMagic.browser.name || "safari" === popMagic.browser.name) || 0 != e.screenX && 0 != e.screenY
      },
      isValidHref: function(e) {
        if (void 0 === e || "" == e) return !1;
        return !/s?javascripts?:/i.test(e)
      },
      findLinkToOpen: function(e) {
        var o = e,
          t = !1;
        try {
          for (var i = 0; i < 20 && !o.getAttribute("href") && o !== document && "html" !== o.nodeName.toLowerCase();) o = o.parentNode, i++;
          var n = o.getAttribute("target");
          n && -1 !== n.indexOf("_blank") || (t = o.getAttribute("href"))
        } catch (e) {}
        return popMagic.isValidHref(t) || (t = !1), t || window.location.href
      },
      getPuId: function() {
        return "ok_" + Math.floor(89999999 * Math.random() + 1e7)
      },
      browserDetector: {
        browserDefinitions: [
          ["firefox", /Firefox/([0-9.]+)(?:s|$)/],
          ["opera", /Opera/([0-9.]+)(?:s|$)/],
          ["opera", /OPR/([0-9.]+)(:?s|$)$/],
          ["edge", /Edg(?:e|)/([0-9._]+)/],
          ["ie", /Trident/7.0.*rv:([0-9.]+)).*Gecko$/],
          ["ie", /MSIEs([0-9.]+);.*Trident/[4-7].0/],
          ["ie", /MSIEs(7.0)/],
          ["safari", /Version/([0-9._]+).*Safari/],
          ["chrome", /(?!Chrom.*Edg(?:e|))Chrom(?:e|ium)/([0-9.]+)(:?s|$)/],
          ["chrome", /(?!Chrom.*OPR)Chrom(?:e|ium)/([0-9.]+)(:?s|$)/],
          ["bb10", /BB10;sTouch.*Version/([0-9.]+)/],
          ["android", /Androids([0-9.]+)/],
          ["ios", /Version/([0-9._]+).*Mobile.*Safari.*/],
          ["yandexbrowser", /YaBrowser/([0-9._]+)/],
          ["crios", /CriOS/([0-9.]+)(:?s|$)/]
        ],
        isChromeOrChromium: function() {
          var e = window.navigator,
            o = (e.userAgent || "").toLowerCase(),
            t = e.vendor || "";
          if (-1 !== o.indexOf("crios")) return !0;
          if (e.userAgentData && Array.isArray(e.userAgentData.brands) && e.userAgentData.brands.length > 0) {
            var i = e.userAgentData.brands,
              n = i.some((function(e) {
                return "Google Chrome" === e.brand
              })),
              r = i.some((function(e) {
                return "Chromium" === e.brand
              })) && 2 === i.length;
            return n || r
          }
          var a = !!window.chrome,
            c = -1 !== o.indexOf("edg"),
            p = !!window.opr || -1 !== o.indexOf("opr"),
            s = !(!e.brave || !e.brave.isBrave),
            g = -1 !== o.indexOf("vivaldi"),
            l = -1 !== o.indexOf("yabrowser"),
            d = -1 !== o.indexOf("samsungbrowser"),
            u = -1 !== o.indexOf("ucbrowser");
          return a && "Google Inc." === t && !c && !p && !s && !g && !l && !d && !u
        },
        getBrowserInfo: function() {
          var e = window.navigator.userAgent,
            o = {
              name: "other",
              version: "1.0",
              versionNumber: 1,
              isChrome: this.isChromeOrChromium(),
              isMobile: !!e.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile|WebOS|Windows Phone/i)
            };
          for (var t in this.browserDefinitions) {
            var i = this.browserDefinitions[t];
            if (i[1].test(e)) {
              var n = i[1].exec(e),
                r = n && n[1].split(/[._]/).slice(0, 3),
                a = Array.prototype.slice.call(r, 1).join("") || "0";
              r && r.length < 3 && Array.prototype.push.apply(r, 1 === r.length ? [0, 0] : [0]), o.name = i[0], o.version = r.join("."), o.versionNumber = parseFloat(r[0] + "." + a);
              break
            }
          }
          return o
        }
      },
      methods: {
        default: function(e) {
          if (!popMagic.shouldShow() || !popMagic.venorShouldShow() || !popMagic.isValidUserEvent(e)) return !0;
          var o = e.target || e.srcElement,
            t = popMagic.findLinkToOpen(o);
          return window.open(t, "_blank"), popMagic.setAsOpened(e), popMagic.top.document.location = popMagic.url, void 0 !== e.preventDefault && (e.preventDefault(), e.stopPropagation()), !0
        },
        chromeTab: function(e) {
          if (!popMagic.shouldShow() || !popMagic.venorShouldShow() || !popMagic.isValidUserEvent(e)) return !0;
          if (void 0 === e.preventDefault) return !0;
          e.preventDefault(), e.stopPropagation();
          var o = top.window.document.createElement("a"),
            t = e.target || e.srcElement;
          o.href = popMagic.findLinkToOpen(t), document.getElementsByTagName("body")[0].appendChild(o);
          var i = new MouseEvent("click", {
            bubbles: !0,
            cancelable: !0,
            view: window,
            screenX: 0,
            screenY: 0,
            clientX: 0,
            clientY: 0,
            ctrlKey: !0,
            altKey: !1,
            shiftKey: !1,
            metaKey: !0,
            button: 0
          });
          i.preventDefault = void 0, o.dispatchEvent(i), o.parentNode.removeChild(o), window.open(popMagic.url, "_self"), popMagic.setAsOpened(e)
        },
        popup: function(e) {
          if (!popMagic.shouldShow() || !popMagic.venorShouldShow() || !popMagic.isValidUserEvent(e)) return !0;
          var o = "";
          if (popMagic.config.popup_fallback && !popMagic.config.popup_force) {
            var t = Math.max(Math.round(.8 * window.innerHeight), 300);
            o = "menubar=1,resizable=1,width=" + Math.max(Math.round(.7 * window.innerWidth), 300) + ",height=" + t + ",top=" + (window.screenY + 100) + ",left=" + (window.screenX + 100)
          }
          var i = document.location.href,
            n = window.open(i, popMagic.getPuId(), o);
          setTimeout((function() {
            n.location.href = popMagic.url
          }), 200), popMagic.setAsOpened(e), void 0 !== e.preventDefault && (e.preventDefault(), e.stopPropagation())
        }
      }
    };
    popMagic.init(adConfig);
  })();

Laravel TwillCMS: CSS and JS do not load twill in sub-directory

I’m trying to install Twill on a Laravel project hosted in a subdirectory, for example:
https://example.org/sub/

However, the CSS and JS assets from Twill are not loading properly. The application is trying to load them from the root domain like:

https://example.org/assets/twill/abc.js

But they should actually load from:

https://example.org/sub/assets/twill/abc.js

It seems that Twill is not respecting the subdirectory path when generating asset URLs.

What I’ve tried:
Updated .htaccess to handle the subdirectory path.

Attempted to configure Laravel’s APP_URL and asset() helper accordingly.

Checked Twill’s config files for any base URL setting.

My setup:

  • Laravel is installed in a subdirectory (/sub)
  • Apache2 on Ubuntu
  • Twill installed via Composer
  • I have tried adding /public to ASSET_URL still doesn’t works as the URL accessed by twill is different.

No issues with the main Laravel routing, just with Twill’s assets.

How can I make Twill correctly generate asset paths when Laravel is installed in a subdirectory?