Source: src/js/views/citations/CitationModalView.js

/*global define */
define([
  "jquery",
  "underscore",
  "backbone",
  "clipboard",
  "models/CitationModel",
  "views/CitationView",
  "text!templates/citations/citationModal.html",
], function ($, _, Backbone, Clipboard, Citation, CitationView, Template) {
  "use strict";

  /**
   * @class CitationModalView
   * @classdesc The CitationModalView shows a citation information displayed as
   * a modal, along with a copy citation button. This view will eventually allow
   * switching between different citation styles.
   * @classcategory Views
   * @extends Backbone.View
   */
  var CitationModalView = Backbone.View.extend(
    /** @lends CitationModalView.prototype */ {
      /**
       * Classes to add to the modal
       * @type {string}
       */
      className: "modal fade hide",

      /**
       * The underscore template for the main part of this view (modal)
       * @type {Underscore.Template}
       */
      template: _.template(Template),

      /**
       * The underscore template for the copy citation button. This will render
       * the inner HTML for the button, which will be added to the template and
       * also used to update the button when the citation is copied.
       * @type {Underscore.Template}
       */
      innerButtonTemplate: _.template(
        "<i class='icon <%=icon%> icon-on-left'></i> <%=text%>"
      ),

      /**
       * The citation model that contains the citation data
       * @type {CitationModel}
       */
      model: null,

      /**
       * The citation style to use
       * @type {string}
       * @default "apa"
       * @see {@link CitationView#styles}
       */
      style: "apaAllAuthors",

      /**
       * The events this view will listen for. See
       * {@link https://backbonejs.org/#View-events}
       * @type {Object}
       */
      events: {
        hidden: "teardown",
      },

      /**
       * The font awesome icons to use for this view
       * @type {Object}
       * @property {string} title - The icon to use in the modal title
       * @property {string} button - The icon to use in the copy citation button
       * @property {string} buttonSuccess - The icon to use in the copy citation
       * button when the citation has been copied
       */
      icons: {
        title: "icon-quote-right",
        button: "icon-copy",
        buttonSuccess: "icon-ok success",
      },

      /**
       * The ids to use for this view
       * @type {Object}
       * @property {string} citationContainer - The id to use for the citation
       * container
       * @property {string} copyButton - The id to use for the copy citation
       * button
       */
      ids: {
        citationContainer: "cmv_citation-container",
        copyButton: "cmv_copy-button",
      },

      /**
       * The text to use for this view
       * @type {Object}
       * @property {string} title - The title to use in the modal
       * @property {string} copyButton - The text to use in the copy citation
       * button
       * @property {string} copySuccess - The text to use in the copy citation
       * button when the citation has been copied
       */
      text: {
        title: "Cite this Dataset",
        copyButton: "Copy To Clipboard",
        copySuccess: "Copied!",
      },

      /**
       * Initialize a new CitationModalView
       * @param {Object} options - A literal object with options to pass to the
       * view
       * @param {CitationModel} options.model - The citation model, or other
       * model accepted by the CitationView, that contains the citation data
       * @param {string} options.style - The citation style to use. This will be
       * passed to the CitationView
       */
      initialize: function (options) {
        if (typeof options === "undefined") {
          var options = {};
        }

        this.model = options.model || new Citation();
        this.style = options.style || this.style;
      },

      /**
       * Render the view
       */
      render: function () {
        // Set listeners
        this.$el.off("shown");
        this.$el.on("shown", this.renderView.bind(this));
        this.show();
        return this;
      },

      /**
       * Render the view
       * @returns {CitationModalView} - Returns this view
       */
      renderView: function () {
        try {
          const ids = this.ids;

          // Make the inner HTML for the copy button. This will be added in the
          // template and after the button has been clicked and the citation has
          // been copied
          this.buttonInnerHTML = this.innerButtonTemplate({
            icon: this.icons.button,
            text: this.text.copyButton,
          });

          // Make the inner HTML for the copy button when the citation has been
          // copied
          this.buttonSuccessInnerHTML = this.innerButtonTemplate({
            icon: this.icons.buttonSuccess,
            text: this.text.copySuccess,
          });

          // Render the modal
          this.el.innerHTML = this.template({
            icons: this.icons,
            ids: ids,
            text: this.text,
            buttonInnerHTML: this.buttonInnerHTML,
          });

          // Find the citation container
          this.citationContainer = this.el.querySelector(
            "#" + ids.citationContainer
          );

          // Find the citation button
          this.copyButton = this.el.querySelector("#" + ids.copyButton);

          this.insertCitation();
          this.listenForCopy();
        } catch (e) {
          console.error("Failed to render the Citation Modal View: ", e);
          MetacatUI.appView.showAlert({
            message: `Something went wrong displaying the citation for this dataset.`,
            classes: "alert-info",
            container: this.$el,
            replaceContents: true,
            includeEmail: true,
          });
        } finally {
          this.$el.modal({ show: false }); // don't show modal on instantiation
        }
      },

      /**
       * Insert the citation view into the modal
       */
      insertCitation: function () {
        const container = this.citationContainer;
        if (!container) return;

        // Create a new CitationView
        var citationView = new CitationView({
          model: this.model,
          style: this.style,
          createTitleLink: false,
        });

        // Render the CitationView
        citationView.render();

        // Insert the CitationView into the modal
        container.appendChild(citationView.el);
      },

      /**
       * Listen for the copy button to be clicked, and copy the citation to the
       * clipboard
       */
      listenForCopy: function () {
        const view = this;
        const btn = view.copyButton;
        if (!btn) return;

        //Create a copy citation button
        var clipboard = new Clipboard(btn);
        clipboard.on("success", function (e) {
          var originalWidth = $(e.trigger).width();
          $(e.trigger)
            .html(view.buttonSuccessInnerHTML)
            .addClass("success")
            .css("width", originalWidth + "px");
          setTimeout(function () {
            $(e.trigger)
              .html(view.buttonInnerHTML)
              .removeClass("success")
              .css("width", "auto");
          }, 500);
        });
        clipboard.on("error", function (e) {
          if (!$(e.trigger).prev("input.copy").length) {
            var textarea = $(document.createElement("input"))
              .val($(e.trigger).attr("data-clipboard-text"))
              .addClass("copy")
              .css("width", "0");
            textarea.tooltip({
              title: "Press ctrl+C or command+C to copy",
              placement: "top",
            });
            $(e.trigger).before(textarea);
          } else {
            var textarea = $(e.trigger).prev("input.copy");
          }
          textarea.animate(
            { width: "100px" },
            {
              duration: "slow",
              complete: function () {
                textarea.trigger("focus");
                textarea.tooltip("show");
              },
            }
          );
          textarea.focusout(function () {
            textarea.animate({ width: "0px" }, function () {
              textarea.remove();
            });
          });
        });
        this.$(".tooltip-this").tooltip();
      },

      /**
       * Make the modal visible
       */
      show: function () {
        this.$el.modal("show");
      },

      /**
       * Remove the modal from the DOM
       */
      teardown: function () {
        this.$el.modal("hide");
        this.$el.data("modal", null);
        this.remove();
      },

      /**
       * Cleans up and removes all artifacts created for view
       */
      onClose: function () {
        this.teardown();
      },
    }
  );

  return CitationModalView;
});