Задать вопрос
  • Как валидировать пароль?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Складываем в массив описания проверок, которым должен быть подвергнут пароль - это будут объекты, состоящие из функции, проверяющей соответствие пароля одному конкретному условию, и сообщения, демонстрируемого пользователю в случае, если проверка прошла неудачно.

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

    Как посчитать процент успеха в деле сочинения пароля - это будет отношение количества успешно пройденных проверок к общему количеству проверок, умноженное на сто.

    Ну и всё, дальше остаётся только вывести результаты.

    <div>
      <input id="password">
    </div>
    <div>
      <div>Сложность пароля: <span id="strength_percent">0</span>%</div>
      <progress id="strength_progress" max="100" value="0"></progress>
    </div>
    <div id="errors"></div>

    const validations = [
      {
        test: val => val.length >= 8,
        message: 'пароль должен содержать хотя бы 8 символов',
      },
      {
        test: val => /[A-ZА-ЯЁ]/.test(val),
        message: 'пароль должен содержать хотя бы 1 большую букву',
      },
      {
        test: val => /[a-zа-яё]/.test(val),
        message: 'пароль должен содержать хотя бы 1 маленькую букву',
      },
      {
        test: val => /[^\s\da-zа-яё]/i.test(val),
        message: 'пароль должен содержать хотя бы 1 специальный символ (не пробел, букву или цифру)',
      },
      {
        test: val => /\d/.test(val),
        message: 'пароль должен содержать хотя бы 1 цифру',
      },
    ];
    
    document.querySelector('#password').addEventListener('input', ({ target: { value } }) => {
      const errors = validations.reduce((acc, n) => (
        n.test(value) || acc.push(n.message),
        acc
      ), []);
    
      const strength = (validations.length - errors.length) / validations.length * 100;
    
      document.querySelector('#strength_progress').value = strength;
      document.querySelector('#strength_percent').innerText = strength | 0;
      document.querySelector('#errors').innerHTML = errors
        .map(n => `<p>${n}</p>`)
        .join('');
    });
    Ответ написан
    1 комментарий
  • Как добавить общую обёртку дочерним узлам?

    0xD34F
    @0xD34F Куратор тега JavaScript
    оборачивается не полностью

    Почему так: childNodes представляет собой динамическую коллекцию, т.е., при добавлении или удалении узлов она обновляется без каких-либо действий с вашей стороны. Поэтому, когда вы добавляете в wrapper нулевой узел, он тут же пропадает из item.childNodes, а у оставшихся узлов позиция уменьшается на единицу - тот, что был первым, становится нулевым, второй первым и так далее. Так что когда for...of переходит к следующему узлу, им оказывается не тот, что изначально имел индекс 1, а расположенный за ним. Бывший первый, а теперь нулевой, оказывается пропущен. Аналогичным образом будут пропущены и все последующие узлы, изначально имевшие нечётные индексы.

    Что тут можно сделать:

    Вариант раз - вместо перебора узлов всегда работать с тем, что имеет нулевой индекс:

    while (item.childNodes.length) {
      wrapper.appendChild(item.childNodes[0]);
    }

    Два - перебирать childNodes от конца к началу:

    for (let i = item.childNodes.length; i--;) {
      wrapper.prepend(item.childNodes[i]);
    }

    Три - перебирать не childNodes, а массив:

    for (const n of [...item.childNodes]) {
      wrapper.append(n);
    }

    А вообще, нет необходимости работать с каждым узлом индивидуально, метод append может принимать несколько параметров, так что переносим сразу всё:

    document.querySelectorAll('.www').forEach(n => {
      const wrapper = document.createElement('div');
      wrapper.classList.add('red');
      wrapper.append(...n.childNodes);
      n.append(wrapper);
    });

    Или, можно и вовсе узлы не трогать, если перезаписывать разметку:

    for (const n of document.getElementsByClassName('www')) {
      n.innerHTML = `<div class="red">${n.innerHTML}</div>`;
    }
    Ответ написан
    Комментировать
  • Как сделать такой стилевой эффект?

    0xD34F
    @0xD34F Куратор тега CSS
    Комментировать
  • Как достать параметр из массива, полученного из выбранных чекбоксов?

    0xD34F
    @0xD34F Куратор тега Vue.js
    computed: {
      summary() {
        return (this.choosenSize?.cost ?? 0) + this.choosenTopping.reduce((acc, n) => acc + n.cost, 0);
      },
    },
    Ответ написан
  • Как генерировать строку такого формата на python?

    0xD34F
    @0xD34F
    from random import choice
    
    chars = '0123456789abcdefghijklmnopqrstuvwxyz'
    section_size = 4
    sections_num = 5
    
    string = '-'.join(''.join(choice(chars) for j in range(section_size)) for i in range(sections_num))
    Ответ написан
    3 комментария
  • Как отсортировать массив DOM-элементов в зависимости от значений атрибута вложенных элементов?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const sorted = arr
      .map(n => [
        n,
        +new URLSearchParams(n.querySelector('a').href.split('?').pop()).get('value') || Infinity,
      ])
      .sort((a, b) => a[1] - b[1])
      .map(n => n[0]);

    UPD. А точно массив? Если всё-таки сортировать надо элементы внутри их родителя, то

    parentEl.append(...Array
      .from(parentEl.querySelectorAll('a'), n => [
        n.parentNode,
        Number(n.getAttribute('href').match(/(?<=value=)\d+/)) || Infinity,
      ])
      .sort((a, b) => a[1] - b[1])
      .map(n => n[0])
    );
    Ответ написан
    4 комментария
  • Как передать функцию, чтобы заработал онклик в react?

    0xD34F
    @0xD34F Куратор тега React
    const Figure = ({ type, ...props }) => <div className={type} {...props}></div>;
    
    class App extends React.Component {
      state = {
        types: [ 'circle', 'square', 'triangle' ],
        figures: [],
      }
    
      add(type) {
        this.setState(({ figures }) => ({
          figures: [ ...figures, type ],
        }));
      }
    
      render() {
        const { types, figures } = this.state;
    
        return (
          <div>
            <div>
              {types.map(n => <Figure type={n} onClick={() => this.add(n)} />)}
            </div>
            <div>
              {figures.map(n => <Figure type={n} />)}
            </div>
          </div>
        );
      }
    }
    Ответ написан
    6 комментариев
  • Как из компонента Child добавить родителю нужный класс?

    0xD34F
    @0xD34F Куратор тега React
    Так делать не принято, и вам это не нужно.

    Раз у всех этих элементов должен быть один класс, это должны быть корневые элементы экземпляров компонента Preloader. Тэг можно передать через props, как и те элементы, что сейчас являются соседними:

    function Preloader({ Tag = 'h1', children }) {
      return (
        <Tag className={s.wrapper}>
          <div className={s.preloader}></div>
          {children}
        </Tag>
      );
    }

    <div className="App">
      <Preloader>hello, world!!</Preloader>
      <Preloader Tag="h2">fuck the world</Preloader>
    </div>
    Ответ написан
    1 комментарий
  • Как заменить шесть "function" на одну?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Сделать функцию, принимающую input, находящую соответствующий input'у span и обновляющую его содержимое:

    const updateValue = input =>
      input.previousElementSibling.querySelector('.p_value').innerText = input.value;

    У input'ов вырезать инлайновые обработчики, добавить общий класс, например: class="xxx".

    Дальше можно повесить делегированный обработчик, внутри которого проверять наличие этого класса:

    document.addEventListener('input', ({ target: t }) => {
      if (t.classList.contains('xxx')) {
        updateValue(t);
      }
    });

    Или назначить обработчик каждому input'у индивидуально:

    document.querySelectorAll('.xxx').forEach(function(n) {
      n.addEventListener('input', this);
    }, e => updateValue(e.target));
    Ответ написан
    4 комментария
  • Как получить предыдущее состояние массива в watch?

    0xD34F
    @0xD34F Куратор тега Vue.js
    watch: {
      cloneItems(old, cur) {
        this.prevItems = old;
      },

    Вот что бывает, когда не читаешь документацию.
    Параметры местами перепутаны - сначала новое значение, потом старое.

    computed: {
      cloneItems: () => this.items.slice(),

    Вот что бывает, когда не знаешь язык.
    Контекст внутри cloneItems - это не экземпляр компонента. Заменить стрелочную функцию на обычную.

    prev items:
    <div v-for="item in items" :key="item">

    Вот что бывает, когда бездумно копипастишь .
    Заголовок поменяли, а про выводимые данные забыли.

    this.items = [...this.items, Date.now()];

    Нет необходимости создавать новый массив, достаточно делать push - вызовы мутирующих методов тоже отслеживаются.

    Ну а если всё же намерены и дальше перезаписывать массив целиком, то нет необходимости делать копию - можно следить сразу за оригиналом, раз он заменяется целиком.
    Ответ написан
    Комментировать
  • Как задать класс элементам с одинаковыми порядковыми номерами?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const cols = document.querySelectorAll('.col');
    
    cols.forEach(n => {
      n.addEventListener('mouseover', onHover);
      n.addEventListener('mouseout', onHover);
    });
    
    function onHover(e) {
      const index = [...this.children].findIndex(n => n.contains(e.target));
      if (index !== -1) {
        const t = e.type === 'mouseover';
        cols.forEach(n => n.children[index].classList.toggle('hovered', t));
      }
    }
    Ответ написан
    Комментировать
  • Как можно отсортировать объект или map, чтобы после преобразовать в массив?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Не надо пытаться заниматься ерундой, сортируют массивы, а не объекты.

    Object
      .entries(arr.reduce((acc, n) => (acc[n] = (acc[n] ?? 0) + 1, acc), {}))
      .sort((a, b) => b[1] - a[1])
      .forEach(n => console.log(n.join(': ')));
    Ответ написан
    Комментировать
  • Как пронумеровать ссылки?

    0xD34F
    @0xD34F Куратор тега JavaScript
    document.querySelectorAll('.nav-about a').forEach((n, i) => n.attributes.href.value += i + 1);
    Ответ написан
    1 комментарий
  • Как в select выставить первое значение по событию?

    0xD34F
    @0xD34F Куратор тега JavaScript
    $('button').click(() => $('select').prop('selectedIndex', 0));

    или, к чёрту jquery:

    document.querySelector('button').addEventListener('click', () => {
      document.querySelectorAll('select').forEach(n => {
        // Какие тут есть варианты:
    
        // 1. Установить индекс выбранного option'а
        n.selectedIndex = 0;
    
        // 2. Установить select'у значение option'а, который должен быть выбран
        //    (чтобы заработало, надо будет добавить value="" option'ам)
        n.value = '';
    
        // 3. Назначить true свойству selected того option'а, на который надо переключиться
        n[0].selected = true;
        // или
        // n.options[0].selected = true;
        // n.children[0].selected = true;
        // n.firstElementChild.selected = true;
        // n.querySelector('option').selected = true;
      });
    });
    Ответ написан
    Комментировать
  • Как объединить массив массивов?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Массивы сложить в массив (const arrs = [ arr1, arr2 ];), дальше есть варианты:

    const result = arrs[0].map((_, i) => arrs.flatMap(arr => arr[i]));

    или

    const result = arrs.reduce((acc, arr) => (
      arr.forEach((n, i) => (acc[i] ??= []).push(...n)),
      acc
    ), []);

    или

    const result = [];
    
    for (const arr of arrs) {
      for (const [ i, n ] of arr.entries()) {
        if (!result[i]) {
          result[i] = [];
        }
    
        for (const m of n) {
          result[i][result[i].length] = m;
        }
      }
    }
    Ответ написан
    1 комментарий
  • Как сделать валидацию инпута c типом number Vue.js?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Что такое product?

    Если это одиночный объект, то проще всего будет установить наблюдение за интересующим вас свойством:

    watch: {
      'product.qty'(val) {
        this.product.qty = Math.max(1, Math.min(99, val | 0));
      },
    },

    Если у вас там v-for и это элемент массива, то можно установить глубокое наблюдение за всем массивом:

    watch: {
      products: {
        deep: true,
        handler: val => val.forEach(n => n.qty = Math.max(1, Math.min(99, n.qty | 0))),
      },
    },

    Если не нравится watch - исправляйте непосредственно пользовательский ввод:

    methods: {
      onInput(e) {
        if (e.isTrusted) {
          e.target.value = Math.max(1, Math.min(99, e.target.value | 0));
          e.target.dispatchEvent(new Event('input'));
        }
      },
    },

    <input
      @input="onInput"
      ...

    Можно даже это дело оформить в виде директивы:

    function onInput({ isTrusted, target: t }) {
      if (isTrusted) {
        t.value = Math.max(t.min, Math.min(t.max, t.value | 0));
        t.dispatchEvent(new Event('input'));
      }
    }
    
    const minmaxDirective = {
      mounted: el => el.addEventListener('input', onInput),
      unbind: el => el.removeEventListener('input', onInput),
    };

    app.directive('minmax', minmaxDirective);

    <input
      v-minmax
      min="1"
      max="99"
      ...
    Ответ написан
  • Как можно менять у элемента атрибут приоритета при drag'n'drop?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Добавить в обработчик dragend:

    document.querySelectorAll('.item').forEach((n, i) => n.dataset.priority = ++i);
    
    // или
    
    for (const [ i, n ] of document.querySelectorAll('.item').entries()) {
      n.setAttribute('data-priority', i + 1);
    }
    
    // или
    
    const items = document.getElementsByClassName('item');
    for (let i = 0; i < items.length; i++) {
      items[i].attributes['data-priority'].value = -~i;
    }
    Ответ написан
    Комментировать