• CMS для создания сайта, если он будет содержать следующие функции?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Практически любая.
    Однако вам этот ответ не поможет. По крайней мере я, давая такое тестовое задание, предполагал бы, что вы прочитаете про CMS, найдёте сравнительную оценку их функцинальных возможностей в сети, попробуете использовать парочку...
    По мне, так вы уже завалили тест.
    Ответ написан
    Комментировать
  • Приделывать Git на сайт это хорошо?

    git - это система контроля версий.
    Это не "локальное хранилище" и не нечто, что можно "приделать" сбоку.

    Предположу, что под словом "приделать" вы имеете в виду использование git для доставки обновлений на продуктивный сервер.
    Моё мнение - так делать не стоит.
    Серверу совершенно не нужно хранить у себя всю историю версий.

    А вот локально да - лучше вести разработку в git.
    Ещё по хорошему следует хранить копию репозитория на каком-нибудь ещё сервере, например в собственном экземпляре gitlab и синхронизировать её с локальной при помощи git pull/push.

    Ну и помни, что не надо все файлы в git запихивать. В git должны храниться только исходные файлы. Всякие картинки - в git-lfs.
    Пароли - в каком-то другом хранилище.
    Артефакты, которые создаёт компилятор или препроцессор - в .gitignore
    Ответ написан
    1 комментарий
  • Как через цикл вложить элементы DOM один в другой?

    RAX7
    @RAX7
    var arr = ['div', 'p', 'span'];
    var main = document.querySelector('.main');
    
    for (let i = 0, container = main; i < arr.length; i++) {
      let el = document.createElement(arr[i]);
      container.append(el);
      container = el;
    }
    Ответ написан
    Комментировать
  • Как через цикл вложить элементы DOM один в другой?

    0xD34F
    @0xD34F Куратор тега JavaScript
    main.innerHTML = arr.reduceRight((acc, n) => `<${n}>${acc}</${n}>`, '');
    Ответ написан
    Комментировать
  • Как через цикл вложить элементы DOM один в другой?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Можно изнутри наружу идти:
    создавать очередной элемент и вкладывать в него предыдущий.
    Ответ написан
    Комментировать
  • Как сложить значения input'ов?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Кого складываем:

    const elements = document.querySelectorAll('[name^=AR_AMOUNT]');

    Нормальный способ - перебираем коллекцию элементов (цикл в явном виде или с помощью методов массива), достаём значения, складываем:

    const sum = Array.prototype.reduce.call(
      elements,
      (acc, n) => acc + +n.value,
      0
    );
    
    // или
    
    let sum = 0;
    for (const { value } of elements) {
      sum += Number(value);
    }

    Ненормальный способ - рекурсия. Функция получает коллекцию элементов и индекс, если элемент с указанным индексом существует, возвращаем его значение плюс результат рекурсивного вызова с индексом, увеличенным на единицу; если элемента нет - возвращаем 0:

    const sum = (function sum(arr, i) {
      return arr[i] ? parseFloat(arr[i].value) + sum(arr, i + 1) : 0;
    })(elements, 0);

    Дикий способ - сами ничего считать не будем. Выдёргиваем из коллекции элементов значения; склеиваем их, используя в качестве разделителя символ +, в строку; строку отдаём в eval; всё, сумма получена (ну, почти, если исходная коллекция элементов была пуста, то строка тоже будет пустой, так что надо не забыть подставить 0 вместо возможного undefined, который является результатом выполнения пустой строки):

    const sum = eval(Array.from(elements, n => n.value).join('+')) ?? 0;
    Ответ написан
    Комментировать
  • Как достать из массива индекс удаленного объекта?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Массивы с пустыми слотами называются sparse arrays. Разные методы массивов по-разному обходятся с пустыми слотами: более новые их считают undefined, старые методы пропускают.

    Топорное решение: собрать индексы присутствующих элементов, и сравнить с полным диапазоном индексов:
    const arr = [1,2,3,4,5,6,7,8,9];
    delete arr[1];
    delete arr[3];
    delete arr[5];
    // arr == [ 1, <1 empty slot>, 3, <1 empty slot>, 5, <1 empty slot>, 7, 8, 9 ]
    
    const present = [];
    arr.forEach((_, i) => present.push(i));
    // present == [ 0, 2, 4, 6, 7, 8 ]
    
    const empty = Array.from({ length: arr.length }, (_, i) => i) // [0,1,2,3,4,5,6,7,8]
      .filter(i => !present.includes(i));
    // empty == [ 1, 3, 5 ]
    Ответ написан
    Комментировать
  • Как вставить текст туда куда мне нужно?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    В первой строке лишний бэк-тик в конце:
    textpayload = message.user.bonusNew ? `"{\"button\": \"дуэль\"}"` : "{\"button\": \"бонус_новичка\"}`"

    См. последние 2 символа: удалите `
    Бэк-тики (обратные кавычки) там вообще-то все не нужны, т.к. не используются их преимущества.

    Неблагодарное дело вручную писать JSON со всем эти кавычками – тут обычными, тут экранированные обратными слешами. Лучше сделать обычный объект, и потом его перевести в строку JSON:
    const bonusButton = { button: message.user.bonusNew ? 'дуэль' : 'бонус_новичка' };
    textpayload = JSON.stringify(bonusButton);
    Ответ написан
    Комментировать
  • Как избавиться от большого количества else if?

    Adamos
    @Adamos
    let variants = [
      { condition: (tries === 0), alert: 'У вас закончились попытки' },
      { condition: (value == number), alert: 'Поздравляю, вы угадали', returnValue: true },
      { decreaseTries: true }
    ];
    for(let i = 0; i < variants.length; ++i) {
      let v = variants[i];
      if(typeof v.condition === 'undefined' || v.condition) {
        if(v.alert) {
          alert(v.alert);
        }
        if(v.decreaseTries) {
          tries--;
          triesSpan.textContent = declOfNum(tries, ['попытка', 'попытки', 'попыток']);
          triesTitle.textContent = `У вас осталось ${tries} ${triesSpan.textContent}`;
        }
        return v.returnValue || false;
      }
    }

    Все варианты перечислять не стал, нужные добавляются по аналогии.
    Ответ написан
    Комментировать
  • Как объединить несколько объектов в один?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const merge = (target, ...sources) =>
      sources.reduce((acc, n) => (
        Object.entries(n).forEach(([ k, v ]) =>
          acc[k] = v instanceof Object
            ? merge(acc[k] instanceof Object ? acc[k] : {}, v)
            : v
        ),
        acc
      ), target);
    
    
    const result = merge({}, ...arrayObj);
    Ответ написан
    3 комментария
  • Как избавиться от неспособности придумать адекватное название блокам?

    mayton2019
    @mayton2019
    Bigdata Engineer
    Я где-то читал что астрономы уже давно не дают названия планетам и звездам. Закончились у них названия. Они их нумеруют. Может быть в какой-то степени это оправдано. Если для блоков веб-дизайна нет названий то возможно им стоит давать хотя-бы номера из sequence. Или если есть указание на относительную ориентацию (север-юг или слева внизу) то можно добавлять там какой-то символ. Вот. А если у автора возникнет именно задача тесной работы со слайдером - то тогда он его просто переименует в slider и будет работать. Похоже конечно на обфускацию больше чем на конвенцию по именам. Но может быть имена не так уж важны в данном процессе.
    Ответ написан
    Комментировать
  • Как в js указать все числа находящиеся в определенном диапазоне?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    В JS есть клевая штука: генераторы.
    Чтобы не забивать сразу память всеми значениями (что, если понадобится от 1 до 1050), можно их получать по одному:
    // эта функция - Генератор. Он создаёт итерируемые штуки
    function* makeRangeIterator(start = 0, end = 100, step = 1) {
        let iterationCount = 0;
        for (let i = start; i < end; i += step) {
            iterationCount++;
            yield i;
        }
        return iterationCount;
    }
    
    // вот сделаем итератор от 1 и до 10 (исключая конец)
    var r1_10 = makeRangeIterator(1, 10);
    
    // в цикле получим из итератора значения
    for (i of r1_10) {
      console.log(i); // выведет от 1 до 9
    }
    Ответ написан
    Комментировать
  • Какой набор библиотек используют в веб-геймдве?

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

    А почему обязательно JavaScript? Браузерные игры вполне могут делаться и на юнити.

    Что-то может и под Wasm делаться, а там уже и C++ и Rust живут со своими экосистемами.

    А некоторые браузерки и не требуют 3d вообще - там может использоваться и какой-нибудь кастомный 2д движок, а часть логики может обрабатываться на сервере, который вообще написано на php.
    Ответ написан
    Комментировать
  • Как выводить варианты ответов в случайном порядке?

    0xD34F
    @0xD34F Куратор тега Vue.js
    function shuffle(arr) {
      for (let i = arr.length; i > 1;) {
        const j = Math.random() * (i--) | 0;
        [ arr[i], arr[j] ] = [ arr[j], arr[i] ];
      }
    
      return arr;
    }

    computed: {
      shuffledAnswers() {
        return shuffle(Object.entries(this.questions[this.idx].answers));
      },
      ...

    <div v-for="[ key, answer ] in shuffledAnswers">
      ...

    UPD. Конечно, вопрос был не об этом, но есть ряд замечаний по поводу показанного кода.

    "answers": {

    Пусть это будет массив. Соответственно, правильный ответ будет обозначаться через индекс.

    import usersData from "../questions.json";

    Не надо импортировать вопросы в компоненте теста, пусть они передаются в него через props.

    selectedAnswer: "",

    Всего один? Этого мало, надо запоминать все полученные ответы.

    count: 5,

    <div v-if="idx < count">

    Если завтра добавятся новые вопросы или удалятся какие-то из существующих, побежите изменять значение этого свойства? Оно не нужно, надо смотреть на длину массива с вопросами. Или, можно сделать вычисляемое свойство, представляющее текущий вопрос (просто извлекаем элемент из массива с вопросами по индексу текущего вопроса), и проверять, существует ли он.

    computed:{
      randomQuestions () {
        usersData.sort(() => Math.random() - 0.5)

    Во-первых, вычисляемые свойства не должны изменять данные. Во-вторых, почему не надо так сортировать. Поскольку массив вопросов никак не изменяется, делать тут вычисляемое свойство смысла нет, пусть оно будет обычным. Перемешанная копия массива с вопросами, у вопросов перемешанные массивы ответов, а также добавлено свойство под ответ, выбранный пользователем.

    :disabled="selectedAnswer != ''"

    Блокировать выбор ответа не надо - вдруг пользователь случайно не туда нажал. Пусть будет возможность изменить сделанный выбор. Это касается не только ответов на текущий вопрос, а всех, т.е., в дополнение к

    <button
      @click="nextQuestion"

    надо сделать такую же кнопку для перехода к предыдущему вопросу.

    document.querySelectorAll("input").forEach((el) => (el.checked = false));

    Не надо лезть в DOM руками. Чтобы при переходе к следующему вопросу сбрасывать выбор, достаточно пересоздавать элементы, назначив их общему предку ключ, зависящий от индекса (:key="индекс_вопроса"). Но это, конечно, костыльное решение. Правильно будет управлять радиокнопками основываясь на данных, через v-model.

    @change="answered($event)"

    answered(e) {
      this.selectedAnswer = e.target.value;
      if (this.selectedAnswer == this.questions[this.idx].correctAnswer) {
        this.correctAnswers++;

    Никаких событий слушать не надо, оформляем подсчёт результатов в виде вычисляемого свойства.

    https://jsfiddle.net/0L9ayx1u/1/
    Ответ написан
    1 комментарий
  • Как провалидировать форму в которой несколько инпутов и селектов?

    0xD34F
    @0xD34F Куратор тега JavaScript
    document.querySelector('form').addEventListener('input', e => {
      document.querySelector('button').disabled = ![
        [  'input', el => el.value         ],
        [ 'select', el => el.selectedIndex ],
      ].every(([ selector, validator ]) => {
        return [...e.currentTarget.querySelectorAll(selector)].every(validator);
      });
    });
    Ответ написан
    2 комментария
  • Какая есть библиотека для создания кастомных круглых диаграмм?

    0xD34F
    @0xD34F Куратор тега React
    Ответ написан
    Комментировать
  • Как заменить данные карты на звездочки?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const hidden = (str, count = 4) => '*'.repeat(count) + str.slice(-4);

    или

    const hidden = (str, count = 4) => str.replace(/.*?(?=.{0,4}$)/, Array(count + 1).join('*'));
    Ответ написан
    1 комментарий
  • Как реализовать фильтрацию на vue.js по нескольким параметрам одновременно?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Сделаем описания столбцов, по которым допускается фильтрация, и способов фильтрации - имя, русифицированный вариант имени (чтобы показывать его в select'ах), и, у столбцов, тип данных:

    data: () => ({
      filterColumns: [
        [     'name',        'имя', 'string' ],
        [    'count', 'количество', 'number' ],
        [ 'distance', 'расстояние', 'number' ],
      ],
      operations: [
        [    'equal',    'равно' ],
        [ 'contains', 'содержит' ],
        [  'greater',   'больше' ],
        [     'less',   'меньше' ],
      ],
      ...

    Тип данных указываем потому, что значения различных типов сравниваются по-разному. Кстати, определим, как именно:

    data: () => ({
      types: {
        string: {
          equal: (a, b) => a.toLowerCase() === b,
          contains: (a, b) => a.toLowerCase().includes(b),
          greater: (a, b) => a.toLowerCase() > b,
          less: (a, b) => a.toLowerCase() < b,
        },
        number: {
          equal: (a, b) => a === +b,
          contains: (a, b) => `${a}`.includes(b),
          greater: (a, b) => a > +b,
          less: (a, b) => a < +b,
        },
      },
      ...

    На основе описаний столбцов и способов фильтрации создадим select'ы:

    <select v-model="column">
      <option v-for="n in filterColumns" :value="n[0]">{{ n[1] }}</option>
    </select>
    <select v-model="operation">
      <option v-for="n in operations" :value="n[0]">{{ n[1] }}</option>
    </select>

    Наконец, собственно фильтрация - конечно же оформляем в виде вычисляемого свойства. По имени столбца, по которому надо фильтровать, извлекаем его описание и, соответственно, тип его данных. На основе типа данных и способа фильтрации извлекаем функцию фильтрации. Если таковая существует, и значение по которому надо фильтровать непустое, то выполняем фильтрацию, в противном случае возвращаем полные данные:

    computed: {
      filteredItems() {
        const { items, column } = this;
        const type = this.filterColumns.find(n => n[0] === column)?.[2];
        const filterFn = this.types[type]?.[this.operation];
        const filterVal = this.filterVal.toLowerCase();
    
        return filterFn && filterVal
          ? items.filter(n => filterFn(n[column], filterVal))
          : items;
      },
      ...

    https://jsfiddle.net/8df3z1un/1/
    Ответ написан
    Комментировать
  • Как повторить каждый символ, чтобы количество повторений было равно его позиции в строке?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const xxx = str => Array
      .from(str, (n, i) => n.toUpperCase() + n.toLowerCase().repeat(i))
      .join('-');

    или

    const xxx = str => str
      .toUpperCase()
      .split('')
      .reduce((acc, n, i) => `${acc}${i ? '-' : ''}${n}${Array(-~i).join(n.toLowerCase())}`, '');

    или

    const xxx = str => str
      .toUpperCase()
      .replace(/(?<=.)./g, (m, i) => '-'.concat(m, ...Array(i).fill(m.toLowerCase())));
    Ответ написан
    Комментировать
  • Почему при перезагрузке страницы мои данные пропадают?

    0xD34F
    @0xD34F Куратор тега React
    Встречный вопрос: почему вы решили, что должно быть иначе? Код, который бы доставал данные из localStorage и клал их в todos, где он, почему его нет? Должен быть, например:

    const [ todos, setTodos ] = useState(() => {
      let todos = null;
    
      try {
        todos = JSON.parse(localStorage.getItem('todos'));
      } catch (e) {};
    
      return Array.isArray(todos) ? todos : [];
    });

    Уверен, здесь вы ждёте, что добавляемый объект окажется в localStorage:

    setTodos([
      ...todos,
      {
        id: Date.now(),
        complete: false,
        title: value,
      },
    ]);
    localStorage.setItem("todos", JSON.stringify(todos));

    Этого происходить не будет (ну, пока ещё что-то не добавите, и это "ещё что-то" тоже попадёт в localStorage не сразу). Вы не понимаете, что происходит при вызове setTodos. Откройте документацию и разберитесь. Сохранение в localStorage следует делать через useEffect:

    useEffect(() => {
      localStorage.setItem('todos', JSON.stringify(todos));
    }, [ todos ]);
    Ответ написан
    7 комментариев