Задать вопрос
Ответы пользователя по тегу JavaScript
  • Замена onmousemove?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Добавляем pointer-events: none; элементу .bigImage - всё окей, никаких скачков.
    Ответ написан
    Комментировать
  • Как скопировать наименования классов всех input элементов в отдельном блоке в массив?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Откуда надо получить классы:

    const inputs = document.querySelectorAll('ol input');

    Получаем уникализированный массив классов:

    const classes = [...new Set(Array.prototype.flatMap.call(
      inputs,
      n => [...n.classList]
    ))];

    Или, получаем всё, что есть:

    const classes = Array
      .from(inputs, n => Array.from(n.classList))
      .flat();
    
    // или
    
    const classes = [].concat.apply(
      [],
      [].map.call(inputs, n => n.className.split(' '))
    );
    
    // или
    
    const classes = [];
    for (const n of inputs) {
      for (const m of n.classList) {
        classes.push(m);
      }
    }
    
    // или
    
    const classes = [];
    for (let i = 0; i < inputs.length; i++) {
      for (let j = 0; j < inputs[i].classList.length; j++) {
        classes[classes.length] = inputs[i].classList[j];
      }
    }
    
    // или
    
    const getClasses = (classList, i, n = classList.item(i)) =>
      n ? [ n, ...getClasses(classList, -~i) ] : [];
    
    const classes = (function get(i, n = inputs.item(i)) {
      return n ? [ ...getClasses(n.classList, 0), ...get(++i) ] : [];
    })(0);
    Ответ написан
    4 комментария
  • Как решить задачу с Promise?

    0xD34F
    @0xD34F Куратор тега JavaScript
    В конструкторе создаём promise, делаем его свойством экземпляра, также делаем свойством экземпляра функцию, разрешающую promise; метод then - вызываем метод then у сохранённого promise, пробрасывая ему полученный параметр, результат вызова кладём на место сохранённого promise:

    class deferred {
      constructor() {
        this.promise = new Promise(resolve => this.resolve = resolve);
      }
    
      then(f) {
        this.promise = this.promise.then(f);
      }
    }

    Но вообще, можно добиться того же поведения и без использования promise. Сохраняем в массив все передаваемые в then функции, при вызове resolve перебираем этот массив, вызываем функции, результат вызова предыдущий используем как параметр следующей:

    class deferred {
      constructor() {
        this.callbacks = [];
      }
    
      then(f) {
        this.callbacks.push(f);
      }
    
      resolve(val) {
        this.callbacks.reduce((res, f) => f(res), val);
      }
    }
    Ответ написан
    1 комментарий
  • Как манипулировать svg, который подключен через тэг object?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Не получается обратиться к элементу по его id.

    А как вы это делаете? Вдруг неправильно? Почему не показали?

    Просто по id (или с помощью любого другого селектора) обращаться нельзя, у внешних SVG отдельное DOM-дерево, оно доступно через свойство contentDocument соответствующего object'а, т.е.:

    const svgDocument = document.querySelector('object').contentDocument;
    const element = svgDocument.querySelector('здесь указываете нужный id или что там вам надо');
    Ответ написан
    Комментировать
  • Как определить событие клика event.target элемента?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Замените click на mousedown. А то сейчас у вас получается так: нажали на выбранный пункт, фокус с .select-list ушёл, и к тому моменту, когда вы отпускаете кнопку мыши, список уже скрылся, соответственно, клик получается по элементу, который был под списком.
    Ответ написан
    Комментировать
  • Как скачать файлы по url?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Нет, так просто не получится - тянуть файлы со сторонних доменов через a[download] нельзя.

    Можно загрузить файл, перегнать его FileReader'ом в data url, и уже в таком виде подсунуть в ссылку. Как-то так.
    Ответ написан
    3 комментария
  • Как пронумеровать список в textarea?

    0xD34F
    @0xD34F Куратор тега JavaScript
    textareaEl.addEventListener('paste', function() {
      setTimeout(() => {
        this.value = this.value.split('\n').map((n, i) => {
          const line = i + 1;
          return `${line}. ${n.replace(RegExp(`^${line}\\. `), '')}`;
        }).join('\n');
      });
    });
    Ответ написан
    1 комментарий
  • Как эмулировать клик по элементу после того, как он отрендерился?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Элемент - представленный в примере - это FileInput (кликать нужно на него, что бы вызвать диалог выбора файлов)

    Нет, ничего у вас не получится. Этот диалог может быть открыт только в результате настоящих действий пользователя (и то не всех: клик, нажатие клавиши - окей; скролл, движение мыши, вызов контекстного меню - нет), а не их имитации. По крайней мере, в Хроме. В Фаерфоксе имитировать можно (UPD. Теперь тоже нельзя).
    Ответ написан
  • Как написать такое регулярное выражение?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Не нужны здесь регулярные выражения:

    const imgs = document.querySelectorAll('img[src*="/test/"]');

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

    это не в dom, а в строке

    Всё равно регулярные выражения не нужны. Парсим строку, ищем нужные элементы, получаем их разметку:

    const div = document.createElement('div');
    div.innerHTML = str;
    const imgsStr = ''.concat(...[].map.call(
      div.querySelectorAll('img[src*="/test/"]'),
      n => n.outerHTML
    ));

    или

    const imgsStr = Array
      .from(
        new DOMParser().parseFromString(str, 'text/html').querySelectorAll('img[src*="/test/"]'),
        n => n.outerHTML)
      .join('');

    или

    const imgsStr = Array.prototype.reduce.call(
      document.createRange().createContextualFragment(str).querySelectorAll('img[src*="/test/"]'),
      (acc, n) => acc + n.outerHTML,
      ''
    );

    UPD. Нет, со второго раза тоже не получилось. Всплыли ещё подробности:

    мне нужно удалить из этой строки все картинки, которые...

    Удалить, так удалить:

    const div = document.createElement('div');
    div.innerHTML = str;
    const imgs = div.querySelectorAll('img[src*="/test/"]');
    for (let i = 0; i < imgs.length; i++) {
      imgs[i].outerHTML = '';
    }
    str = div.innerHTML;

    или

    const { body } = new DOMParser().parseFromString(str, 'text/html');
    body.querySelectorAll('img[src*="/test/"]').forEach(n => n.remove());
    str = body.innerHTML;

    или

    const fragment = document.createRange().createContextualFragment(str);
    for (const n of fragment.querySelectorAll('img[src*="/test/"]')) {
      n.parentNode.removeChild(n);
    }
    str = Array.from(fragment.childNodes, n => n.outerHTML || n.nodeValue).join('');
    Ответ написан
    6 комментариев
  • Как определить принадлежность элемента по data value?

    0xD34F
    @0xD34F Куратор тега JavaScript
    function onlyOne({ value, dataset: { group } }) {
      document.querySelectorAll(`[data-group="${group}"]`).forEach(n => {
        n.checked = n.checked && n.value === value;
      });
    }
    Ответ написан
    2 комментария
  • Почему дублируется вывод массива?

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

    Замените

    todoList.forEach(function(element) {
      document.getElementById('out').innerHTML += '<p>'+element+'</p>';
    });

    на

    document.getElementById('out').innerHTML = todoList.map(n => `<p>${n}</p>`).join('');
    Ответ написан
    3 комментария
  • Как удалить определённые html теги из строки?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Создать элементы на основе строки, найти и удалить ненужные, получить разметку оставшихся:

    const div = document.createElement('div');
    div.innerHTML = html;
    div.querySelectorAll('a[href*="/test/"]').forEach(n => n.outerHTML = '');
    html = div.innerHTML;

    или

    const { body } = new DOMParser().parseFromString(html, 'text/html');
    body.querySelectorAll('a[href*="/test/"]').forEach(n => n.remove());
    html = body.innerHTML;

    или

    const fragment = document.createRange().createContextualFragment(html);
    fragment.querySelectorAll('a[href*="/test/"]').forEach(n => n.parentNode.removeChild(n));
    html = Array.from(fragment.childNodes, n => n.outerHTML || n.nodeValue).join('');
    Ответ написан
    Комментировать
  • Как сортировать option по атрибуту?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Значения атрибутов - это строки. Надо при сравнении преобразовывать их в числа.

    UPD. Ну и в целом - многословно как-то у вас. Можно же гораздо короче:

    function sort(desc, attr) {
      const select = document.querySelector('#search-sort-field');
      select.append(...Array
        .from(select.children, n => [ n, n.getAttribute(attr) * (desc ? 1 : -1) ])
        .sort((a, b) => a[1] - b[1])
        .map(n => n[0])
      );
    }
    Ответ написан
    1 комментарий
  • Как создать таблицу из массива?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Куда будем добавлять строки:

    const tbody = document.querySelector('#table tbody');
    
    // или
    
    const [ tbody ] = document.getElementById('table').tBodies;

    Добавляем:

    tbody.innerHTML = arr
      .map(n => `
        <tr>
          <td><a href="${n.link}">${n.city}</a></td>
          <td>${n.country}</td>
        </tr>`)
      .join('');

    или

    for (const n of arr) {
      const tr = tbody.insertRow();
      const a = document.createElement('a');
      a.href = n.link;
      a.text = n.city;
      tr.insertCell().append(a);
      tr.insertCell().textContent = n.country;
    }
    Ответ написан
    Комментировать
  • Добавить/удалить дочерний элемент по клику?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const dialog = new DOMParser().parseFromString(`
      <div id="add-note__quick">
        <i id="close">&times;</i>
        <input type="text" class="field" placeholder="Событие">
        <input type="text" class="field" placeholder="День, месяц, год">
        <input type="text" class="field" placeholder="Участники">
        <button>Создать</button>
      </div>
    `, 'text/html').body.querySelector('#add-note__quick');
    
    dialog.querySelector('#close').addEventListener('click', () => {
      dialog.parentNode.removeChild(dialog);
    });
    
    let selectedTd = null;
    
    document.querySelector('#calendar-body').addEventListener('click', ({ target }) => {
      if (target.tagName !== 'TH') {
        return;
      }
    
      if (selectedTd) {
        selectedTd.classList.remove('note');
      }
    
      if (selectedTd === target) {
        target.removeChild(dialog);
        selectedTd = null;
      } else {
        dialog.querySelectorAll('input').forEach(n => n.value = '');
        target.appendChild(dialog);
        target.classList.add('note');
        selectedTd = target;
      }
    });
    Ответ написан
    Комментировать
  • Ошибка в коде при переключении месяца в календаре?

    0xD34F
    @0xD34F Куратор тега JavaScript
    В консоле выдает Uncaught TypeError: next is not a function

    Вы обработчики подключили инлайново, а по умолчанию jsfiddle оборачивает код в window.onload - вот они и отсутствуют в глобальной области видимости. Назначайте обработчики с помощью addEventListener; или, в верхней части окна с js кодом есть выпадающее меню, открываете его, находите пункт "load type", выставляете значение "No wrap - bottom of < body >". UPD. Неактуально, исправили эту дичь с onload, теперь js код всегда добавляется как есть.

    Как выделить при помощи класса текущее число, не выходит
    добавляю...

    Это безумие - currDay является датой, а вы пытаетесь работать с ней как с DOM нодой, classList.add, бред какой-то. Ну и само условие неправильное - год и месяц вы всегда при проверке используете одни и те же, где тут currDay? Должен быть. А проверка числа - ещё одно безумие, вы его сравниваете с объектом даты. Ну и наконец, почему всё это происходит после цикла, откуда там будет доступна ячейка с сегодняшней датой? - проверяйте дату при создании разметки ячейки таблицы, и в зависимости от результата прямо туда, в разметку, добавляйте атрибут class.

    Есть и ещё косяки:

    Не очищаете содержимое #calendar-body при переключении месяца. Не хватает tbl.innerHTML = ''; перед циклом.

    Условие продолжения цикла - currDay.getMonth() <= month. Представьте, что следующий месяц - январь, год кончается. Что будет с вашим условием? Правильно, оно останется истинным. Навсегда. Лучше сделать так: проверяете равенство, без "меньше", а while заменяете на do-while - тогда числа предыдущего месяца, формально не подходящие под условие, всё равно будут обработаны, так как тело цикла выполняется до проверки условия.

    UPD. Зачем дни недели вписаны в первую неделю? - я бы их в заголовок таблицы (thead) вынес.

    Неочевидный косяк - переменный размер календаря. В зависимости от количества дней в месяце и дня недели первого числа количество недель может быть равно 4, 5 или 6. Пусть всегда будет 6. Да, будет показываться больше дней из соседних месяцев, но высота календаря перестанет изменяться при переключении месяца.

    https://jsfiddle.net/v4fwn8dx/
    Ответ написан
    2 комментария
  • Как написать регулярное выражение для удаление всех символов до первого пробела?

    0xD34F
    @0xD34F Куратор тега JavaScript
    str.replace(/^\S+ /, '')
    
    // или
    
    str.match(/(?<= ).+/)[0]
    
    // или
    
    str.split(' ').slice(1).join(' ')
    
    // или
    
    str.slice(str.indexOf(' ') + 1)
    Ответ написан
    3 комментария
  • Как пронумеровать уже назначенные ID?

    0xD34F
    @0xD34F Куратор тега JavaScript
    О каких элементах идёт речь, какая у них должна быть общая часть id:

    const elements = document.querySelectorAll('.restab');
    const baseId = 'responsivetable';

    Как назначать id в зависимости от индекса:

    const setId = (el, index) => el.id = `${baseId}${-~index}`;
    
    // или
    
    const setId = (el, index) => el.setAttribute('id', baseId + ++index);
    
    // или
    
    const setId = (el, index) => {
      const id = document.createAttribute('id');
      id.value = baseId.concat(index + 1);
      el.attributes.setNamedItem(id);
    };

    Назначаем:

    elements.forEach(setId);
    
    // или
    
    for (const [ i, n ] of elements.entries()) {
      setId(n, i);
    }
    
    // или
    
    for (let i = 0; i < elements.length; i++) {
      setId(elements[i], i);
    }
    
    // или
    
    (function next(i, n = elements.item(i)) {
      n && (setId(n, i), next(-~i));
    })(0);
    Ответ написан
    Комментировать
  • Как передать параметры в статический метод через конструктор?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Чтобы не выглядеть сумасшедшим, вам следует дополнить вопрос рассказом о том, зачем вам потребовалось делать метод статическим - сейчас является очевидным, что у него нет причин быть таковым.

    Ну а непосредственно отвечая на ваш вопрос - Basket.totalPrice.call(data). Но, повторюсь, это безумие.
    Ответ написан