Translate Select Value

Hi @Max,
the JS code works for the first dropdown. I have another one. How does the code need to be extended for this?

2 Likes

Hi @Sina :wave:

In your 2nd widget you’re using the ID of the 1st widget. So, you just should replace it with the ID of the 2nd widget:


Check it out and let me know if it worked :slightly_smiling_face:

2 Likes

Hi @Max,
its not a second widget but a second dropdown in a widget.

2 Likes

Sorry, haven’t noticed the 2nd dropdown because of the conditional display!

I’ve passed it on to the devs and will update you once the solution is ready :slightly_smiling_face:

2 Likes

Thank you for waiting, @Sina :wave:

We’ve adjusted the script in your widget and now everything is working fine:


const CUSTOM_SELECT_VALUE = 'Nuance wählen';
const WIDGET_CLASS = 'elfsight-app-95f91737-ccc2-4beb-8a81-cd3641c4f302';

const LISTEN_TYPES = {
  one: {
    select: (selector, root) => root.querySelector(selector),
    validate: (node) => !!node,
  },
  all: {
    select: (selector, root) => root.querySelectorAll(selector),
    validate: (node) => node?.length > 0,
  },
};

function listenStep(args) {
  args.node = args.select(args.selector, args.root);
  if (!args.validate(args.node)) {
    args.step++;
    if (args.step < args.limit)
      setTimeout(() => {
        listenStep(args);
      }, args.delay);
    else args.reject();
  } else {
    args.resolve(args.node);
  }
}

async function asyncListenFor(selector, type = 'one', customArgs = {}) {
  const args = {
    root: document,
    node: undefined,
    selector,
    delay: 100,
    limit: 50,
    step: 0,
    select: LISTEN_TYPES[type].select,
    validate: LISTEN_TYPES[type].validate,
    ...customArgs,
  };
  if (type === 'one' || type === 'all') {
    return new Promise((resolve, reject) => {
      listenStep({ ...args, resolve, reject });
    });
  }
}

const createInput = (placeholder) => {
  const input = document.createElement('input');
  input.type = 'text';
  input.placeholder = placeholder;

  input.style.cssText = `
    width: calc(98% - 24px) !important;
    box-sizing: border-box !important;
    padding: 10px 29px 10px 15px !important;
    margin: 0px 12px !important;
    border: 1px solid rgba(17, 17, 17, 0.6) !important;
    border-radius: 4px !important;
    position: fixed  !important;
    top: 10px !important;
    left: 0 !important;
    background: inherit !important;
    z-index: 2 !important;
  `;

  return input;
};

const processDropdown = (dropdown) => {
  if (dropdown.hasAttribute('data-processed')) {
    return;
  }

  dropdown.setAttribute('data-processed', 'true');

  const select = dropdown.querySelector("[class*='dropdown__Select-sc']");
  select.textContent = CUSTOM_SELECT_VALUE;

  const mutationObserver = new MutationObserver(([{ addedNodes }]) => {
    if (addedNodes.length) {
      const container = addedNodes[0];
      const dropdownContainer = container.querySelector(
        '[class*="Dropdown__DropdownContainer-sc"]'
      );

      const firstValue = dropdownContainer.querySelector(
        "[class*='DropdownItem__ItemContainer-sc']:first-child [class*='DropdownItem__Item-sc']"
      );
      firstValue.textContent = CUSTOM_SELECT_VALUE;

      const withFilters = dropdownContainer.childNodes.length > 12;

      if (withFilters) {
        const filter = createInput('Search...');
        dropdownContainer.prepend(filter);

        dropdownContainer.style.position = 'relative';
        dropdownContainer.style.paddingTop = '60px';

        filter.addEventListener('input', (e) => {
          const value = e.target.value.trim();

          if (value) {
            dropdownContainer.childNodes.forEach((node) => {
              if (node.nodeName === 'INPUT') {
                return;
              }

              const isTarget = node.textContent
                .toLowerCase()
                .includes(value.toLowerCase());

              if (isTarget) {
                node.style.display = 'flex';
              } else {
                node.style.display = 'none';
              }
            });
          } else {
            dropdownContainer.childNodes.forEach((node) => {
              if (node.nodeName === 'INPUT') {
                return;
              }

              return (node.style.display = 'flex');
            });
          }
        });
      }
    }
  });

  mutationObserver.observe(dropdown, { childList: true });
};

asyncListenFor(`.${WIDGET_CLASS} [class*="form__Container-sc"]`).then((formContainer) => {
  const dropdowns = formContainer.querySelectorAll('[class*="dropdown__Container-sc"]');
  dropdowns.forEach(processDropdown);

  const formObserver = new MutationObserver((mutationsList) => {
    for (const mutation of mutationsList) {
      if (mutation.type === 'childList') {
        mutation.addedNodes.forEach((node) => {
          if (node.nodeType === Node.ELEMENT_NODE) {
            setTimeout(function() {
            	const newDropdowns = node.querySelectorAll('[class*="dropdown__Container-sc"]');
            newDropdowns.forEach(processDropdown);
            }, 50);
          }
        });
      }
    }
  });

  formObserver.observe(formContainer, { childList: true, subtree: true });
});

Please check your widgets and let me know if it works :slightly_smiling_face:

2 Likes

Hi @Max

I have the JS code for the translation and a CSS code scrollbar for the options list in the dropdown.
https://community.elfsight.com/t/add-scroll-for-the-options-list-in-the-dropdown/73343?u=sina
How can I set it up so that when I use the dropdown again it automatically scrolls to the already selected value?

1 Like

Hi there, @Sina :wave:

Could you please elaborate on what you mean under “use the dropdown again”?

@Max :upside_down_face: ok. use the dropdown again to select another value.

this ist selected
grafik

and now I want to choose something else

now it should scroll to what is already selected

1 Like

Got it, thank you!

I’ve forwarded your request to the devs and will let you know once the code is ready :slightly_smiling_face:

Hi @Sina :wave:

Please try to use this code in the Custom JS section and let me know if it worked:

function observeChanges(containerSelector, callback) {
  const observer = new MutationObserver((mutations) => {
    mutations.forEach(({ addedNodes }) => {
      addedNodes.forEach((node) => {
        if (
          node.nodeType === Node.ELEMENT_NODE &&
          (node.matches(containerSelector) || node.querySelector(containerSelector))
        ) {
          callback(node.matches(containerSelector) ? node : node.querySelector(containerSelector));
        }
      });
    });
  });

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

observeChanges('[class*="Dropdown__DropdownContainer-sc"]', (container) => {
  requestAnimationFrame(() => {
    const icon = container.querySelector(
      '[class*="DropdownItem__ItemContainer-sc"] [class*="Icon__IconContainer-sc"] svg'
    );

    if (!icon) return;

    const selectedItem = icon.closest('[class*="DropdownItem__ItemContainer-sc"]');
    if (!selectedItem) return;

    const containerRect = container.getBoundingClientRect();
    const itemRect = selectedItem.getBoundingClientRect();

    if (itemRect.top >= containerRect.top && itemRect.bottom <= containerRect.bottom) return;

    container.scrollTo({
      top: selectedItem.offsetTop,
      behavior: 'auto'
    });
  });
});
1 Like

Hi @Max ooohh thank you. Works perfect.

1 Like

Amazing, you’re always welcome :wink:

1 Like

My goodness, you guys are really good at what you’ve done, and in such a short time. I feel honored. My thanks also to the devs. Please pass them on!!

2 Likes

Wow, thanks a ton for such an amazing feedback :heart:

I’ll definitely pass your words to the dev team :wink: