User:Zvpunry/CreateNewItem.js

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
// This file is maintained at https://gitlab.wikimedia.org/migr/mediawiki_userscripts
jQuery(async () => {
  /* global preloadDependency, Vue, mw */
  performance.mark('CreateNewItem init start');
  const host = location.host;
  if (typeof preloadDependency === 'undefined') {
    await mw.loader.getScript(
      `https://${host}/w/index.php?title=User:Zvpunry/require.js&action=raw&ctype=text/javascript`,
    );
  }

  await Promise.all([
    mw.loader.using(['vue', '@wikimedia/codex']),
    preloadDependency('User:Zvpunry/repositories/SearchEntitiesRepository.js'),
    preloadDependency('User:Zvpunry/repositories/NewEntityRepository.js'),
    preloadDependency('User:Zvpunry/components/LabelInput.vue'),
    preloadDependency('User:Zvpunry/components/DescriptionInput.vue'),
    preloadDependency('User:Zvpunry/components/AliasesInput.vue'),
    preloadDependency('User:Zvpunry/app/CreateNewItem/CNIForm.vue'),
    preloadDependency('User:Zvpunry/app/CreateNewItem/OntologyItemLookup.vue'),
    preloadDependency('User:Zvpunry/app/CreateNewItem/PropertySwitch.vue'),
  ]);

  const CNIForm = require('User:Zvpunry/app/CreateNewItem/CNIForm.vue');
  const api = new mw.Api({
    parameters: {
      format: 'json',
      formatversion: 2,
      errorformat: 'plaintext', // FIXME: is this actually what we want?
      uselang: 'en', // FIXME wgUserLanguage,
    },
  });
  const SearchEntitiesRepository = require('User:Zvpunry/repositories/SearchEntitiesRepository.js');
  const searchEntitiesRepository = new SearchEntitiesRepository(
    api,
    'en', // FIXME: wgUserLanguage,
  );
  const NewEntityRepository = require('User:Zvpunry/repositories/NewEntityRepository.js');
  const newEntityRepository = new NewEntityRepository(api);

  $('#mw-content-text').on(
    'focusin.Zvpunry_CreateNewItem',
    '.valueview-expert-wikibaseitem textarea',
    (event) => {
      const $textareaParent = $(event.target).parent();
      const $textarea = $(event.target);

      if ($textareaParent.find('#createNewItemGadgetMountPoint').length !== 0) {
        return;
      }

      const perWikiConfig = {
        'www.wikidata.org': {
          instanceOfProperty: 'P31',
          subclassOfProperty: 'P279',
        },
        'test.wikidata.org': {
          instanceOfProperty: 'P82',
          subclassOfProperty: 'P10208',
        },
        'wikidata.beta.wmflabs.org': {
          instanceOfProperty: 'P694',
          subclassOfProperty: 'P253138',
        },
      };
      const config = perWikiConfig[host];
      if (!config) {
        throw new Error(`No configuration for host ${host}`);
      }

      async function closeWithNewItem(newItemId) {
        $mountPoint.remove();
        await $textarea.val(newItemId);
        await $textarea.focus();
        const keyDown = jQuery.Event('keydown');
        keyDown.which = 32; // space
        $textarea.trigger(keyDown);
      }

      function cancelModal() {
        console.log('cancel modal');
        $mountPoint.remove();
      }

      const $newItemButton = $(
        '<button class="cdx-button">Create New Item</button>',
      );
      const $mountPoint = $(
        '<span id="createNewItemGadgetMountPoint"><span id="cni-app-mount-point"></span></span>',
      );
      $mountPoint.append($newItemButton);
      $textarea.parent().prepend($mountPoint);
      $textareaParent.on('focusout', (event) => {
        const relatedTarget = event.relatedTarget;
        if (!$textareaParent[0].contains(relatedTarget)) {
          if (relatedTarget === null) {
            setTimeout(() => {
              // Timeout is needed because Safari has null as the relatedTarget when clicking on the button
              $mountPoint.remove();
              $textareaParent.off('focusout.Zvpunry_CreateNewItem');
            }, 200);
          } else {
            $mountPoint.remove();
            $textareaParent.off('focusout.Zvpunry_CreateNewItem');
          }
        }
      });

      $newItemButton.css({
        width: '100%',
        position: 'absolute',
        'min-height': '22px',
      });
      $newItemButton.css(
        'top',
        `-${parseInt($newItemButton.css('height')) + 2}px`,
      );
      $newItemButton.on(
        'click.Zvpunry_NewItemGadget',
        $(event.target)[0],
        (clickEvent) => {
          const currentInputText = clickEvent.data.value;

          const app = Vue.createMwApp(CNIForm);
          app.provide('config', config);
          app.provide('searchEntitiesRepository', searchEntitiesRepository);
          app.provide('newEntityRepository', newEntityRepository);
          app.provide('closingMethods', { closeWithNewItem, cancelModal });
          app.provide('currentInputText', currentInputText);
          app.mount('#cni-app-mount-point');
        },
      );
    },
  );
});