ArtOfCode-/qpixel

View on GitHub
app/assets/javascripts/tags.js

Summary

Maintainability
A
1 hr
Test Coverage
$(() => {
  const sum = (ary) => ary.reduce((a, b) => a + b, 0);

  const splitWordsMaxLength = (text, max) => {
    const words = text.split(' ');
    const splat = [[]];
    words.forEach(word => {
      if (sum(splat[splat.length - 1].map(w => w.length + 1)) > max - word.length) {
        splat.push([]);
      }
      splat[splat.length - 1].push(word);
    });
    return splat.map(s => s.join(' '));
  };

  const template = (tag) => {
    const tagSpan = `<span>${tag.text}</span>`;
    let desc = !!tag.desc ? splitWordsMaxLength(tag.desc, 120) : '';
    const descSpan = !!tag.desc ?
      `<br/><span class="has-color-tertiary-900 has-font-size-caption">${desc[0]}${desc.length > 1 ? '...' : ''}</span>` :
      '';
    return $(tagSpan + descSpan);
  }

  $('.js-tag-select').each((i, el) => {
    const $tgt = $(el);
    let $this;
    const useIds = $tgt.attr('data-use-ids') === 'true';
    $tgt.select2({
      tags: $tgt.attr('data-create') !== 'false',
      ajax: {
        url: '/tags',
        data: function (params) {
          $this = $(this);
          // (for the tour)
          if ($this.data('tag-set') == "-1") {
            return Object.assign(params, { tag_set: "1" });
          }
          return Object.assign(params, { tag_set: $this.data('tag-set') });
        },
        headers: { 'Accept': 'application/json' },
        delay: 100,
        processResults: data => {
          // (for the tour)
          if ($this.data('tag-set') == "-1") {
            return {
              results: [
                { id: 1, text: "hot-red-firebreather", desc: "Very cute dragon" },
                { id: 2, text: "training", desc: "How to train a dragon" },
                { id: 3, text: "behavior", desc: "How a dragon behaves" },
                { id: 4, text: "sapphire-blue-waterspouter", desc: "Other cute dragon" }
              ]
            }
          }
          return {results: data.map(t => ({id: useIds ? t.id : t.name, text: t.name, desc: t.excerpt}))};
        },
      },
      templateResult: template
    });
  });

  $('.js-add-required-tag').on('click', ev => {
    const $tgt = $(ev.target);
    const useIds = $tgt.attr('data-use-ids') === 'true';
    const tagId = $tgt.attr('data-tag-id');
    const tagName = $tgt.attr('data-tag-name');
    const $select = $tgt.parents('.form-group').find('select');
    const existing = $select.find(`option[value=${tagId}]`);
    if (existing.length > 0) {
      $select.val([useIds ? tagId : tagName, ...($select.val() || [])]).trigger('change');
    }
    else {
      const option = new Option(tagName, useIds ? tagId : tagName, false, true);
      $tgt.parents('.form-group').find('select').append(option).trigger('change');
    }
  });

  $('.js-rename-tag').on('click', async ev => {
    const $tgt = $(ev.target).is('a') ? $(ev.target) : $(ev.target).parents('a');
    const categoryId = $tgt.attr('data-category');
    const tagId = $tgt.attr('data-tag');
    const tagName = $tgt.attr('data-name');

    const renameTo = prompt(`Rename tag ${tagName} to:`);
    if (!!renameTo) {
      const resp = await fetch(`/categories/${categoryId}/tags/${tagId}/rename`, {
        method: 'POST',
        credentials: 'include',
        headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': QPixel.csrfToken() },
        body: JSON.stringify({ name: renameTo })
      });
      const data = await resp.json();
      if (data.success) {
        location.reload();
      }
      else {
        console.error('Failed to rename tag, somehow');
      }
    }
  });
});